OpenBSD - veb's, vport's and vlan's

Posted on Oct 28, 2022
tl;dr: how to set up veb, vports, and vlans on OpenBSD to seperate your traffic

openbsd - veb’s, vport’s and vlan’s

Inspired by a question on reddit from someone who wanted to create another wireless network for guests to the house, here’s a short how-to on how I’ve got things set up at home.

My main router/firewall is an OpenBSD box, with multiple nics. A few of those nics’ connect to some Wireless AP’s, running OpenWRT. The OpenWRT AP’s run a few different SSID’s for things, for example I’ve got one for guests to the house, one for the AV kit, one for the IoT devices…

Once you start segregating, it’s hard to stop 😄.

These are all logically seperated using vlan’s.

Overview

I run multiple VLAN’s over the same cables down to an OpenBSD firewall/router appliance to seperate network traffic, increase security, and control the flow of devices being able to talk to each other. In times past, I had a single wireless AP with a single SSID, but slowly and surely more and more ’things’ started to appear on the network. Every visitor to my house usually asks for the wireless password, which meant my wireless credentials were propogating across the internet into all manner of keychains, password managers, device backups, etc. This needed to change, and this is how I regained control over my ’trusted’ networks.

My current setup is thus:

  • Two Physical Access Points which are BT HomeHub 5.0a’s running OpenWRT
  • Four SSID’s on each the AP’s, one for ’trusted’, one for IoT devices, another for Audio Visual kit and an untrusted Guest network
  • One cable for each of the AP’s connects into one port of a 4 port Intel NIC
  • A NAS/General Purpose server connects into another port of the 4 port Intel NIC
  • The last port of the Intel NIC is currently unused

Let’s go through this setup, step by step. Please note you cannot blindly go running these commands - you could lock yourself out of the device. If at all possible keep one network port available for you to manage this stuff via. Once it’s all setup, you can simply add that port to the ‘pool’.

As is usual in OpenBSD, this configuration all takes place via /etc/hostname.if files. Here’s what we’re looking at today:

zsh/2 1027 % ls -l /etc/hostname.v*  
- rw-r-----  root wheel     63B 12.Oct'22 18:26  hostname.veb0
- rw-r-----  root wheel    181B 12.Oct'22 18:26  hostname.vlan100
- rw-r-----  root wheel    129B 12.Oct'22 18:26  hostname.vlan200
- rw-r-----  root wheel    178B 12.Oct'22 18:26  hostname.vlan210
- rw-r-----  root wheel    176B 12.Oct'22 18:26  hostname.vlan220
- rw-r-----  root wheel    146B 12.Oct'22 18:26  hostname.vport0
- rw-r-----  root wheel     66B 12.Oct'22 18:26  hostname.vport1

We’ll start with the hostname.veb0 file.

veb

Taken from the OpenBSD man page, the “…veb pseudo-device supports the creation of a single layer 2 Ethernet network between multiple ports. Ethernet interfaces are added to the veb bridge to be used as ports. Unlike bridge(4), veb takes over the operation of the interfaces that are added as ports. They are then independent of the host network stack: the individual Ethernet ports no longer function as independent devices and cannot be configured with inet(4) or inet6(4) addresses or other layer-3 features themselves

In essence, this means we can effectively concatenate devices into one layer 2 device.

To do this, we create an /etc/hostname.veb0 file. The contents of this file are:

fw0# cat /etc/hostname.veb0
add em0
add em1
add em2
add em3
add vport0
add vport1
link0
up

Simply put, we are adding in the ‘raw’ ethernet devices {em0...em3}. As indicated in the manpage, veb will take over operation of these for us now. This means they will be effectively unusuable by us now, so we need to configure the members hostname.if files. For brevity, here’s the first one - the others are all the same.

fw0# cat /etc/hostname.em0                                                                                                                                                                                   
mtu 9000
up

Note, I’m setting the mtu in this file also - I’d advise you to omit this line, so the file just contains the word `‘up’``. I’ve left it here in case you later wonder where you would set it….

At this point, if you were to run (don’t, yet!) ‘sh /etc/netstart veb0’ you’d have the veb device configured.

However, veb devices operate at layer 2. IP is a layer 3 technology, which means we need to do some further configuration to get the veb device to route our IP addresses, etc. We achieve this via a vport device.

note, the veb device is completely functional - you could plug two devices into it, and they would be able to see each other and communicate using whatever they wished - the vport device is needed to expose additional functionality we will need!

vport

The vport device will allow us to create a virtual NIC which we can attach to a veb, as was show above. As before, we configure it using a hostname.if file, in this example hostname.vport0. Here’s a complete example of mine.

fw0# more /etc/hostname.vport0 
inet 192.168.0.250 255.255.255.0
inet6 2001::::250/64
group trusted
mtu 9000
description "Local LAN Interface"
lladdr 00:20:91:00:0a:bc
up 

A minimal configuration could be as simple as:

inet 192.168.0.250 255.255.255.0
up

As you can see, it’s the same format as you will be using already for your existing configuration. Indeed, you could copy your existing configuration to this file.

The lines in the file are used like this:

  • the inet line adds the ip address to the interface
  • the inet6 line does similar for ipv6
  • we mark this device as ’trusted’ via a 'group' label. The name is arbitary (but we’ll see later how we can use it)
  • bump up the mtu to use jumbo packets
  • add an arbitary description - this helps when I’m trying to figure out what is used for what network…
  • lladdr effectively sets the mac address of the interface to one I have chosen
  • up, simply marks the interface as up

At this point, assuming you have all those files in place, it should be functional enough to be brought up. You’d be advised to do that before continuing with the VLAN setup we will cover next. However, you might have some circular dependencies if your interface is currently in use, and a reboot might be required here. I wish you the best of luck in it all working first time!

vlan - creating a vport interface to route traffic via

Before we continue with setting up some VLAN networks, lets create one more vport interface we will use for the VLAN traffic.

Create a hostname.vport1 file, with the contents similar to this.

fw0# more hostname.vport1 
group vlan-interface
mtu 9000
description "VLAN Terminations"
up 

Again, I advise you to omit the mtu line at this stage. As before we are defining a 'group' and also assigning a description to the interface. The descriptions are useful, for example:

vport0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 9000
        lladdr 00:20:91:00:0a:bc
        description: Local LAN Interface
        index 17 priority 0 llprio 3
        groups: vport trusted
        inet6 fe80::fce1:baff:fed0:2ed1%vport0 prefixlen 64 scopeid 0x11
        inet6 2001:::250 prefixlen 64
        inet 192.168.0.250 netmask 0xffffff00 broadcast 192.168.0.255

Note also, that under 'groups' we have our 'trusted' label we added to the config file, but also another one for 'vport' which OpenBSD added for us. These 'groups' are extremely useful, as we’ll see in part 2 of this writeup.

enabling routing

I’ve assumed you’ve already enabled your OpenBSD to perform routing and forwarding - if not you will need to do this, via editing the /etc/sysctl.conf file, enabling these options:

fw0# grep forwarding /etc/sysctl.conf                                                                                                                                                                        
net.inet.ip.forwarding=1        # 1=Permit forwarding (routing) of IPv4 packets
net.inet.ip.mforwarding=1       # 1=Permit forwarding (routing) of IPv4 multicast packets
net.inet6.ip6.forwarding=1      # 1=Permit forwarding (routing) of IPv6 packets
net.inet6.ip6.mforwarding=1     # 1=Permit forwarding (routing) of IPv6 multicast packets

You may or may not need multicast forwarding. The chance of you needing it increases when you have AV devices such as TV’s on your networks. If things don’t work and you have this disabled, try giving it a toggle to see if it alleviates things.

vlan - creating the vlan’s

At this point, we can start to create some vlan’s. You can have as many as you need (they are N limited, but you won’t run out) for as many things as you like - get creative!

Unsurprisingly, these are also created via hostname.if files. Here’s an example:

fw0# more /etc/hostname.vlan220                                                                                                                                                                              
inet 192.168.220.2 255.255.255.0 192.168.220.255 
inet6 2001::220::250/64
parent vport1
vlan 220 
description "VLAN 220 - Untrusted Devices"
lladdr 00:20:91:22:0a:bc
up 

At this point, you need to either reboot (easiest and cleanest) or run 'sh /netstart', or possibly if you’ve part configured as above, perhaps even 'sh /etc/netstart vport1 && sh /etc/netstart vlan220' - as you can see you have a excellent granularity of control over network configuration with OpenBSD tooling.

Unfortunately at this point I have to leave you - you will need to set up the other manufacturers corresponding AP’s or switches to perform vlan tagging. In a pinch, you can set up a Linux debian host connected via the same network as previously used to perform vlan tagging quite simply, for example:

simonb@homebridge:/etc/network$ cat /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
allow-hotplug enp0s2
iface enp0s2 inet dhcp

auto enp0s2.210
     iface enp0s2.210 inet static 
     address 192.168.210.3
     netmask 255.255.255.0

I like to keep my networking IP addressing to correlate with the vlan id to make things easier to see, in the above we’re using vlan210 and IP addresses are in the x.x.210.x range.

debugging using (tcpdump)[]

tcpdump is a useful tool in debugging - for example using the interface vport1 we created dedicated to vlan traffic, you can run something like this to check if packets are arriving and tagged correctly.

fw0# tcpdump -c5 -i vport1 -nn -e  vlan
tcpdump: listening on vport1, link-type EN10MB
08:22:43.797422 00:20:91:10:0a:bc 18:3e:ef:c0:72:bb 8100 146: 802.1Q vid 100 pri 3 172.16.0.250.22 > 172.16.100.180.63180: P 1224428350:1224428426(76) ack 3584186661 win 271 <nop,nop,timestamp 8752341 894374021> [tos 0x48]
08:22:43.797587 00:20:91:10:0a:bc 18:3e:ef:c0:72:bb 8100 154: 802.1Q vid 100 pri 3 172.16.0.250.22 > 172.16.100.180.63180: P 76:160(84) ack 1 win 271 <nop,nop,timestamp 8752341 894374021> [tos 0x48]
08:22:43.802033 18:3e:ef:c0:72:bb 00:20:91:10:0a:bc 8100 70: 802.1Q vid 100 pri 1 172.16.100.180.63180 > 172.16.0.250.22: . ack 160 win 2814 <nop,nop,timestamp 894374041 8752341> (DF) [tos 0x48]
08:22:43.831095 00:20:91:21:0a:bc dc:a6:32:4d:9a:4c 8100 1469: 802.1Q vid 210 pri 3 172.16.0.4.41248 > 172.16.210.13.6003: udp 1423
08:22:43.831312 00:20:91:21:0a:bc dc:a6:32:4d:9a:4c 8100 1469: 802.1Q vid 210 pri 3 172.16.0.4.41248 > 172.16.210.13.6003: udp 1423

conclusion

We’ve got pretty far at setting up our vlan networks - but we’ve not done anything in terms of controlling those packets, using pf. This will be part 2 of this article….