Virtual Switch with systemd-networkd

They call it a bridge, but I like to call it a virtual switch: Linux bridges are a really interesting concept I've come across recently.

Here was the use case: Through wifi interface wlp3s0 my laptop (archlinux btw) was connected to a network that had internet access. Had I enabled the default network interface in virt-manager the guest windows machine would get access to the internet: you all know what happens when windows gets internet access; it downloads updates and forces you to update. So I didn't want the guest windows vm to access the internet, but I did want it to access my IP camera network which wasn't connected to the internet. My laptop was connected to this network via ethernet —this means my laptop ethernet interface enp5s0 had a LAN IP address assigned to it just like the other client cameras in the network. I wanted the windows guest vm to access this network so I could install the software that could initialize my IP cameras (SmartPSS, SmartPSS Lite, and ODM: Onvif Device Manager): 3 of the cameras needed this software for configuration but the other 3 had a convenient web interface. Still, I'm not complaining because when there is good old Linux on your side you can always find a way .

The solution here is to use a Linux bridge (or a "virtual switch"). This setup turns our ethernet interface into an ethernet port on a switch. The ethernet port on a switch doesn't have its own ip address like the ethernet interface does, the port just links you to the things connected on other port.

In this case the connection to the ethernet port just puts two more devices in the network: br0 and the VM's virtual interface.

┌─────────────────────────────────────┐
│           br0 (Virtual Switch)      │
│  ┌─────────────────────────────────┐│
│  │ Port 1: enp5s0 (Physical)      ││ ← Connected to 10.0.0.0/24 network
│  │ Port 2: VM's virtual interface ││ ← Your Windows VM will connect here
│  │ Port 3: Host's br0 interface   ││ ← Your host's network access
│  └─────────────────────────────────┘│
└─────────────────────────────────────┘

The config files that make it happen (if you've ever worked with systemd before you'd be familiar with the /etc/systemd/system directory where you usually place .service files)

/etc/systemd/network/br0.netdev
1
2
3
[NetDev]
Name=br0
Kind=bridge
/etc/systemd/network/br0.network
1
2
3
4
5
[Match]
Name=br0

[Network]
DHCP=yes

DHCP=yes

Our bridge interface will automatically get an IP addressed assigned to it by the DHCP server running on 10.0.0.1

/etc/systemd/network/enp5s0.network
1
2
3
4
5
6
7
[Match]
Name=enp5s0

[Network]
Bridge=br0
DHCP=no
IPForward=yes

With all this in place, once you execute sudo systemctl restart systemd-networkd you should see a new br0 interface in the output of ip addr command. However, you might also see that enp5s0 interfaces gets an IP address too —this isn't what we expected since enp5s0 is now just a "port" or replaced by a new br0 interface. When enp5s0 has an ip address you might find that you can't ping other devices on the IP camera network.

I found out that it was dhcpcd.service that was assigning an IP address to enp5s0. To prevent it from getting an address I did:

sudo nvim /etc/dhcpcd.conf

Add this line at the top or bottom of the file:

denyinterfaces enp5s0

Restart dhcpcd:

sudo systemctl restart dhcpcd

Flush the Current IP and Restart systemd-networkd:

# Remove the current IP from enp5s0
sudo ip addr flush dev enp5s0

# Restart systemd-networkd to properly configure the bridge
sudo systemctl restart systemd-networkd

Now enp5s0 has no IP address and now it no longer interferes with connecting to other devices on the network.


Comments