OpenBSD Journal

Making the veb(4) virtual Ethernet bridge VLAN aware

Contributed by Peter N. M. Hansteen on from the virtually bridging the LANs, really dept.

As some readers tell us whenever they have the chance, the veb(4) virtual Ethernet bridge device is an OpenBSD feature that can make certain setups a lot more manageable than otherwise possible.

Now David Gwynne (dlg@) is fielding a patch on tech@ that would make veb(4) even more capable, by making the device vlan(4) aware.

In the message to tech@, David explains:

List:       openbsd-tech
Subject:    make veb(4) VLAN aware
From:       David Gwynne <david () gwynne ! id ! au>
Date:       2025-10-29 5:54:42

veb(4) is currently vlan unaware, meaning that it assumes that there's a
single "namespace" for the mac addresses used by packets handled by the
bridge. by default it blocks vlan (and svlan) packets, but if you allow
it carry vlan packets it ignores the vlan tag when doing the mac address
lookups.

adding vlan awareness means that every mac address the bridge learns
is now associated with a vlan identifier (vid). ie, the same mac
in two different vlans will get separate entries in the forwarding
database.
this means ports in a veb now get vlan configuration. if you're used to
operating vlans on switches with "industry standard" style config, this
should feel pretty familiar to you.

when an interface is added to a veb as a port, it is configured with a
default vid. this vid is assigned to "untagged" packets (packets on
the wire without a VLAN tag) received by this port inside the veb, and
then stripped again when transmitted on another port with the same vid.

veb can also handle vlan tagged packets directly now by adding "tagged"
vid configuration to ports. this means you don't need to configure
vlan(4) interfaces and add them as ports on a veb to handle tagged
traffic.

if you only want to handle tagged traffic on a port, you can disable
"untagged" packet handling too.

the result of all this is that you can implement vlan aware switching
without a ton of boilerplate now. previously you were supposed to create
a veb(4) per VLAN you wanted to wire up. if you wanted to handle tagged
packets you had to create vlan(4) interfaces and add them to their
respective veb(4)s. if you're using the same VIDs consistently on every
port, this basically all collapses down to a single veb(4) with the
approriate set of "tagged" vids on each port.

vlan(4) still gets the first run at packets in ethernet input though.
if you do want to remap vlan tags on the wire to a vlan within a
veb(4), you can still create a vlan(4) interface to catch that vid
and add it as an untagged port to that VLAN in the bridge.

the actual implementation of this in the kernel was surprisingly simple.
the etherbridge code was extended to include a vid next to the ethernet
address it does lookups against, and Just Works(tm). the other users of
the etherbridge code hardcode 0 as the vid they use. the veb(4)
forwarding path was extended to figure out the right vid for the packet
and carry it around.

the majority of the changes are in the ioctl and ifconfig changes needed
to support it. ive tried to keep the changes as unintrusive as possible,
and as backwards compatible as possible.

the main changes to ifconfig are the addition of "untagged" and
"+tagged" commands and variations of them to manage which vids a
port can use and how, and extending the mac addresses in "static",
"deladdr" and the display of the address cache with @vid.

if you have a simple veb(4) setup now, the config you have now should
still work with the new code. simple means you haven't enabled link0.
if you have enabled link0, this will be a breaking change that requires
you to explicitly add tagged vids to the ports you want to carry vlans
on.

as a quick and dirty example here's a config i've been using, part of
which replaces a vlan(4) interface on vmx0 with vnetid 871 with a
tagged vid on the physical port and a vport interface:

$ doas cat /etc/hostname.veb0
add vmx0
-untagged vmx0
+tagged vmx0 871
+tagged vmx0 780
+tagged vmx0 781
add vport0
untagged vport0 871
add tap0
untagged vport0 780
add tap1
untagged vport0 781
up
$ ifconfig veb0                                               
veb0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST>
	index 7 llprio 3
	encap: vnetid 1 txprio packet rxprio outer
	groups: veb
	vmx0 flags=3<LEARNING,DISCOVER>
		port 1 ifpriority 0 ifcost 0 -untagged
		tagged: 780,781,871
	vport0 flags=3<LEARNING,DISCOVER>
		port 8 ifpriority 0 ifcost 0 untagged 871
	tap0 flags=3<LEARNING,DISCOVER>
		port 5 ifpriority 0 ifcost 0 untagged 780
		tagged: none
	tap1 flags=3<LEARNING,DISCOVER>
		port 6 ifpriority 0 ifcost 0 untagged 781
		tagged: none
	tap2 flags=3<LEARNING,DISCOVER>
		port 9 ifpriority 0 ifcost 0 untagged 780
		tagged: none
	Addresses (max cache: 100, timeout: 240):
		00:00:5e:00:01:50@780 vmx0 created 167591 used 0 flags=0<>
		8c:04:ba:cf:60:c0@780 vmx0 created 167590 used 1 flags=0<>
		00:00:5e:00:01:51@781 vmx0 created 167591 used 0 flags=0<>
		8c:04:ba:cf:60:c0@781 vmx0 created 167591 used 1 flags=0<>
		00:00:5e:00:01:11@871 vmx0 created 167591 used 1 flags=0<>
		00:00:5e:00:01:47@871 vmx0 created 167591 used 1 flags=0<>
		00:50:56:a1:75:f0@871 vport0 created 167592 used 0 flags=0<>
		fe:e1:ba:d0:74:ef@871 vmx0 created 86776 used 9 flags=0<>

you can add a static entry (and delete them) with "static" and
"deladdr", you just have to add @vid to the address. eg

# ifconfig veb0 deladdr 00:50:56:a1:75:f0@871 vport0
# ifconfig veb0 static 00:50:56:a1:75:f0@871 vport0

it is possible to add static entries pointing at ports that do not
have the relevant vid configured. in that situation the tagged/untagged
config takes precedence and packets using that address entry will
be dropped.

i dont think it makes sense to allow tagged packets over vport
interfaces so the ability to configure that is blocked. vport
interfaces plug the ip stack into the bridge, which requires untagged
traffic. if you want to plug the stack into different VLANs on the
same bridge, rather than create vlan interfaces on top of a vport,
just create vport interfaces associated with the right vids.

the ifconfig changes are pretty simplistic, there's some improvements
around handling sets of vids that should be made, but the diff is
big enough.

finally, the main reason i wanted this was to improve the semantics
of handling vlans on bridges. flipping the link0 flag is too easy
and makes the network too open, and setting up a ton of veb(4)s and
vlan(4)s per VLAN is too much boilerplate. i also need to properly
get my head around PVLANs as per RFC 5517, which i find is easiest
if i can actually implement it. being able to hack it into veb(4)
on top of this diff is my current plan for that.

followed by the patch itself (against a recent -current) to implement the code.

If you need this, you probably want to fetch the patch, apply to a test system and poke the result properly.

Feedback via tech@ or here will be appreciated.


Credits

Copyright © - Daniel Hartmeier. All rights reserved. Articles and comments are copyright their respective authors, submission implies license to publish on this web site. Contents of the archive prior to as well as images and HTML templates were copied from the fabulous original deadly.org with Jose's and Jim's kind permission. This journal runs as CGI with httpd(8) on OpenBSD, the source code is BSD licensed. undeadly \Un*dead"ly\, a. Not subject to death; immortal. [Obs.]