Adding VLANs to OpenWRT 18.06.1 on a TP-Link TL-WR810N

Welcome back to Project Overkill. This instalment covers, as suggested by the title, configuring OpenWRT 18.06.1 to support 802.1q VLANs on a TP-Link TL-WR810N.

There are two pre-requisites: the network chipset in the router must support VLANs (some don’t), and OpenWRT’s configuration files must contain some instructions defining the switch and associated VLANs.

The TL-WR810N meets the first pre-requisite already (see later), but not the second. It can cope with VLANs, but the current OpenWRT build for this device does not include any switch or VLAN definitions.

The OpenWRT GUI, called LuCI, contains a component for managing switches. The menu option is Network -> Switch. But… that option isn’t visible on the TL-WR810N. Or, rather, it’s not visible yet. LuCI will show menu options for features which are defined and for which it has corresponding plugins to generate an appropriate web page.

Screenshot from 2018-08-27 12-17-58

The corresponding plugin is already present, but the feature is not yet defined. This is why the menu option isn’t there.

So, I need to define the switch feature. But I don’t know how to do it. I can see some switch definitions in /etc/config/network on other devices I have which run OpenWRT, but I don’t know what those definitions mean. I don’t know the syntax, and some guesswork and trial-and-error – more error than trial – has caused my TP-Link to become unresponsive, requiring a factory reset.

As with most things, there’s a good chance someone else on the Internet has already done the same thing and so I can cheat. Why reinvent the wheel? Well, I couldn’t find anything pertaining exactly to my situation, but I did find a web page about configuring switch definitions for VLANs on the TP-Link TL-WR841N, and a video about configuring OpenWRT for trunking/uplinks. All I had to do was adapt the information for my needs.

For testing, I have a laptop, the TP-Link TL-WR810N I want to configure, a GL-iNet GL-MT300N, and a Cisco WS-C2960C-8TC-L switch to connect everything together.

I want to create two VLANs: 4 and 5. The laptop will be on the subnet in VLAN 4, the GL-iNet GL-MT300N will be on the subnet in VLAN 5, and I want to connect to the GL-MT300N from the laptop, using a single physical Ethernet port on the TL-WR810N (which is where 802.1q VLANs come into play). This is what I want it to look like:

Screenshot from 2018-08-27 12-59-14

So, first up: proving that my TL-WR810N does have a VLAN-capable switch. That page about the TL-WR841N shows how to do so.

What network device is present?

root@OpenWrt:~# swconfig list
Found: switch0 - eth1

What capabilities does it have?

root@OpenWrt:~# swconfig dev switch0 help
switch0: eth1(AR934X built-in switch), ports: 5 (cpu @ 0), vlans: 16
    Attribute 1 (int): enable_vlan (Enable VLAN mode)
    Attribute 2 (int): mirror_monitor_port (Mirror monitor port)
    Attribute 3 (none): apply (Activate changes in the hardware)
    Attribute 4 (none): reset (Reset the switch)
    Attribute 1 (int): vid (VLAN ID)
    Attribute 2 (ports): ports (VLAN port mapping)
    Attribute 1 (int): enable_mirror_rx (Enable mirroring of RX packets)
    Attribute 2 (int): enable_mirror_tx (Enable mirroring of TX packets)
    Attribute 3 (int): pvid (Primary VLAN ID)
    Attribute 4 (unknown): link (Get port link information)

Five ports? But the box only has two Ethernet sockets. Evidently the network controller can cope with more than this device actually has, so which ports are in use? The above example shows that the router’s CPU, where the routing magic happens, is on port 0 (cpu @ 0). But which port is used by the Ethernet cable?

root@OpenWrt:~# swconfig dev switch0 show
Global attributes:
    enable_vlan: 0
    mirror_monitor_port: 15
Port 0:
    enable_mirror_rx: 0
    enable_mirror_tx: 0
    pvid: 0
    link: port:0 link:up speed:1000baseT full-duplex txflow rxflow 
Port 1:
    enable_mirror_rx: 0
    enable_mirror_tx: 0
    pvid: 0
    link: port:1 link:down
Port 2:
    enable_mirror_rx: 0
    enable_mirror_tx: 0
    pvid: 0
    link: port:2 link:down
Port 3:
    enable_mirror_rx: 0
    enable_mirror_tx: 0
    pvid: 0
    link: port:3 link:down
Port 4:
    enable_mirror_rx: 0
    enable_mirror_tx: 0
    pvid: 0
    link: port:4 link:up speed:100baseT full-duplex auto
    vid: 0
    ports: 0 1 2 3 4

I already know that port 0 is the internal link to the router’s CPU. The only other active port is port 4. It’s up, and running at a speed of 100Mbps, which corresponds to the wire speed of the Cisco 2960-C switch. So, the two switch ports I need to configure are 0 and 4.

By default, OpenWRT defines two interfaces on the TL-WR810N: eth0 and eth1. eth0 is used for the upstream WAN and eth1 is used for the LAN. So I want to configure the 802.1q VLANs on interface eth1.

WARNING: the following steps will alter the TL-WR810N’s behaviour. Do not reboot the device or restart the network service until all steps are completed. It is possible to cut yourself off from the router if the network service is restarted prematurely. Make all configuration changes on the command line; do not use the LuCI web interface. Be prepared to do lots of factory resets while practicing…

The first step is to define the switch and subinterfaces. Modify /etc/config/network and add the following:

config switch
  option name 'switch0'
  option reset '1'
  option enable_vlan '1'

config switch_vlan 'eth1_4'
  option device 'switch0'
  option vlan '4'
  option ports '0t 4t'

config switch_vlan 'eth1_5'
  option device 'switch0'
  option vlan '5'
  option ports '0t 4t'

The first section defines the switch. The next two sections define the VLANs and which ports they use. This also creates the logic for the subinterface devices (see later). Now LuCI will show a Switch entry in the Network menu.

Screenshot from 2018-08-27 12-25-22

Now, at the moment the Switch web page does not display the switch ports accurately. This is a cosmetic issue on this device and will not affect the VLAN behaviour. The important bit is that the CPU port (“Port 1” in the picture, even though it’s wrong) and Ethernet port (“Port 5” in the picture, also wrong) both participate in the VLANs and both are “tagged” so that network packets enter and exit the correct VLAN.

Screenshot from 2018-08-27 12-30-52.png

The tagging is important. It’s how 802.1q works. The Ethernet port needs to be able to carry packets on both VLAN 4 and VLAN 5. It needs to be a trunk/uplink. Every tagged VLAN will be carried on the specified port. Thanks again to David Crumpton for his YouTube video explaining this. In this example we have only two ports and two VLANs.

The above steps merely prepare the VLANs and switch. The next step is to create the routing subinterfaces and configure them. The default interface configuration is:

config interface 'lan'
  option type 'bridge'
  option ifname 'eth1'
  option proto 'static'
  option ipaddr ''
  option netmask ''

The important bit is the “ifname” directive, which maps the “lan” interface directly to the device “eth1”. Changing it to accomodate VLANs is a simple matter of changing the “ifname” to the specific VLAN subinterface:

config interface 'lan1'
  option ifname 'eth1.4'
  option proto 'static'
  option ipaddr ''
  option netmask ''

config interface 'lan2'
  option ifname 'eth1.5'
  option proto 'static'
  option ipaddr ''
  option netmask ''

In the above example I have removed the “bridge” option; it’s usually used to join the wireless and Ethernet interfaces into a single network (convenient for most users). In this piece I don’t need wireless and I don’t need to bridge any interfaces together so I’ve taken it out.

OpenWRT comes with a zone-based firewall, which already knows about the default “lan” and “wan” networks. I need to adapt it to accommodate the new VLAN-aware changes. I don’t need to filter traffic between the VLANs so I’m happy for both VLANs to be part of the same zone. If I wanted to apply traffic filters then I’d need to create a new zone and configure rules accordingly. But the same zone is fine for my needs. Modify /etc/config/firewall:

config zone
  option name 'lan'
  list network 'lan1'
  list network 'lan2'
  option input 'ACCEPT'
  option output 'ACCEPT'
  option forward 'ACCEPT'

Now to test whether or not it all works, or if I need to factory-reset the TL-WR810N and start again…

I’ve made all the changes I need to make, so reboot the TL-WR810N. Wait for it to come back online, and then attempt to connect to it.

From the laptop:

$ ping
PING ( 56(84) bytes of data.
64 bytes from icmp_seq=1 ttl=64 time=0.650 ms
64 bytes from icmp_seq=2 ttl=64 time=0.660 ms
--- ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1006ms
rtt min/avg/max/mdev = 0.650/0.655/0.660/0.005 ms

Okay, so I can still reach the TL-WR810N. What about the GL-MT300N beyond it?

 $ ping
PING ( 56(84) bytes of data.
64 bytes from icmp_seq=1 ttl=63 time=1.01 ms
64 bytes from icmp_seq=2 ttl=63 time=0.826 ms
--- ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.826/0.921/1.017/0.100 ms

Success! A point to note: the GL-MT300N doesn’t automatically know about the return route back to the subnet; I had to add a static route entry on the GL-MT300N. Your own situation may differ.

And that’s it! Now the TL-WR810N can route between subnets on a single Ethernet port.