I'm trying to set up a system that joins an untagged Ethernet network to a TAP tunnel, adding a VLAN tag as the traffic moves to the tunnel.

So far I have:

  • eth0 - the physical Ethernet interface carrying untagged traffic.
  • tap1 - the TAP tunnel interface.
  • br0 - a bridge that contains tap1 (and some other physical interfaces)

I know I can add a VLAN tag on the Ethernet side by doing this:

$ ip link add link eth0 name eth0.5 type vlan id 5
$ brctl addif br0 eth0.5

But how can I do the reverse?

Edit I've figured out I can do this:

$ ip link add veth0 type veth peer name veth1
$ ip link add link veth0 name veth0.5 type vlan id 5
$ brctl addif br0 veth0.5
$ brctl addbr br1
$ brctl addif br1 eth0
$ brctl addif br1 veth1

I think this does what I want - it creates two bridges, with a virtual ethernet device connecting them, and adds/removes the VLAN tag as the traffic passes between the bridges. Is there anything simpler?

1 Answer 1


Yes: you can set the bridge to be VLAN aware.

The bridge will then handle VLAN IDs attached to frames crossing it, including tagging and untagging them according to configuration, and will send a frame belonging to a given VLAN only to ports configured to accept it. This moves all the settings to the bridge itself rather than having to use VLAN sub interfaces (those sub interfaces can still be used in some settings of course).

This feature is not available through the obsolete brctl command, but requires the newer replacement bridge command (along with the usual ip link command). It is a simpler setup (one bridge, no sub-interface).

The method is to configure tap1 as a tagged bridge port with VLAN ID (VID) 5, and eth0 also with VID 5, but set as untagged: output gets untagged, and with this VID as PVID (Port VLAN ID): input gets tagged with it inside the bridge. There can be only one PVID per port.

At the same time optionally remove VLAN ID of 1 assigned by default to each port (unless a more complex setup would require multiple VLANs of course) to keep a clean configuration.

your setup, so far, with newer commands only should look like this:

ip link set eth0 up
ip link set tap1 up

# the following line could have directly included at bridge creation the additional parameter `vlan_filtering 1`
ip link add name br0 type bridge

ip link set tap1 master br0
ip link set eth0 master br0

The specific VLAN aware bridge settings, starting by activating the feature:

ip link set dev br0 type bridge vlan_filtering 1

bridge vlan del dev tap1 vid 1
bridge vlan del dev eth0 vid 1

bridge vlan add dev tap1 vid 5
bridge vlan add dev eth0 vid 5 pvid untagged

ip link set br0 up

Note that the bridge's self implicit port is still using VID 1, so assigning an IP directly on the bridge as is done on some settings will now fail to communicate properly. If such configuration is really needed, you can set the bridge's self port in VLAN 5 too, with a slightly different syntax (self) because it's the bridge itself:

bridge vlan del dev br0 vid 1 self
bridge vlan add dev br0 vid 5 pvid untagged self

It's usually cleaner to (still delete the default VID 1 of the bridge to prevent it from any possible interaction,) add a veth pair, plug one end on the bridge, configure its bridge vlan settings the same as eth0 and assign an IP on the other end.

Good blog series on this topic:

Fun with veth-devices, Linux bridges and VLANs in unnamed Linux network namespaces

  • Thanks for this amazing and detailed explanation + the bonus blog posts! :)
    – tftd
    Aug 6, 2021 at 22:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.