Skip to main content
  1. Blog/

uif: creating untagged (VLAN) network subinterfaces in Linux

·3 mins
Ever wanted to have VLAN untagged subinterface in Linux? Meet uif.

Untagged subinterfaces: why? #

Linux has a very comprehensive Layer-2 networking model.

One thing I’ve always found slight slightly annoying in Linux, though, is the inability to create network subinterfaces that demultiplex and multiplex untagged traffic only (no VLAN). This is possible in some switches and routers, which cleanly models how untagged and VLAN tagged traffic is handled by the system.

This also has some undesirable side-effects:

  • When using bridges with vlan_filtering=0, it’s not possible to only bridge untagged traffic without using L2 ACLs.
  • Programs that deal with network packets via RAW sockets, or higher level libraries such as libpcap (e.g. tcpdump, wireshark), need to manually discard tagged packets if they are only interested in untagged traffic (e.g. using PCAP filters).

Any chance we can leverage 🐝 eBPF to hack something out?

Introducing uif #

uif is as small tool to create (emulate) untagged network subinterfaces in Linux. These interfaces receive and send untagged (no VLAN) traffic only, much like VLAN subinterfaces do. It uses eBPF.

Project picture
Featured Project
uif - creating 'untagged' (VLAN) network subinterfaces in Linux

uif enables us to:

  • Restrict bridging and learning to untagged traffic only on bridges with vlan_filtering=0.
  • Restrict traffic ingested by applications sniffing on interfaces to untagged traffic only.
  • Make them compatible with TC/TCX BPF programs.
  • Have them modeled as a subinterface, with its own ifindex, etc.

How to use it? #

To create an untagged subinterface eth0.ut over eth0:

../output/uif create eth0

eth0.ut can now be managed using standard Linux tools (e.g. ip), as any other network device.

As with a VLAN subinterface, if you want IP connectivity for untagged traffic, IP addresses will (now) need to be added to the eth0.ut instead of eth0.

How does it work? #

uif creates a VLAN 0 subinterface over the target interface with the name <iface>.ut, and it attaches two small 🐝 eBPF TCX programs on the ingress and egress paths of <iface>.

These programs push a VLAN 0 tag on ingress and pop the VLAN 0 tag on egress respectively, to make sure untagged traffic is muxed/demuxed to <iface>.ut correctly.

Because of the place where TCX eBPF hooks execute, programs such as tcpdump and wireshark work as expected, transparently, seeing all untagged and tagged unmodified traffic on <iface>, and only untagged traffic in <iface>.ut.

Compatibility with VLAN 0 priority tagging #

Since VLAN 0 is (ab)used as a means to mux/demux to/from the main interface, VLAN 0 priority tagging is not supported on <iface>.

Next steps #

Some network switches use VLAN 1 for untagged traffic.

VLAN 1: some switches simplify their Hardware pipeline by having traffic always tagged at ingress. In these switches, VLAN 1 is “a special” tag (native VLAN), and it’s discouraged to be used as a regular VLAN, as it’s (generally) used by the egress part of the pipeline to recognise untagged traffic and pop the tag.

It’s possible to sacrifice VLAN 1, or any other VLAN ID for that matter, to “emulate” the untagged subinterface. Most of the work is already done in  vlan1 branch. The remaining bit is to - likely - modify the VLAN tag value within the BPF program at load time, instead of recompiling the program on every execution.

Final remarks #

Full disclosure, while writing this puff I realised someone had been using a similar trick using plain TC commands here. The approach is similar, but using eBPF TCX hooks make it easier and more compatible with other eBPF programs.