Configure VLANs

To retrofit the native LAN config into a VLAN config you need to do the following:

  • Rename the lan interface to trunk which now will carry all of our VLAN traffic.
  • Create new virtual interfaces for each desired VLAN: lan@trunk, work@trunk, apps@trunk, iot@trunk.
  • Configure one or more ports on the managed switch to use specific VLANs.
Info

There are 4095 usable VLAN numeric IDs in the range 1 -> 4095.

The number you choose is arbitrary, but by convention you can use the first 255 to represent specific subnets, for example VLAN 10 represents the subnet 192.168.10.0/24, which is provisioned for the lan@trunk VLAN, 11 for 192.168.11.0/24 provisioned for the work@trunk VLAN, etc.

Remove the lan interface config

The existing lan config needs to be removed:

Run this on the Router VM
rm -f /etc/systemd/network/10-lan.{link,network}

Create the trunk interface config

Run this on the Router VM
## Get the mac address for the exsting lan interface:
mac_address=$(ip link show "lan" | awk '/ether/ {print $2}')

## Rename it to trunk:
link=/etc/systemd/network/10-trunk.link
cat < ${link}
[Match]
MACAddress=${mac_address}

[Link]
Name=trunk
MACVLAN=on
EOF

echo -e "\n## Link: ${link}"
cat ${link}

Reboot the router for the interface name change to take effect:

Run this on the Router VM
reboot

Wait for it to reboot, log back in, and verify the name change for trunk:

Run this on the Router VM
ip link
(stdout)
...
3: trunk:  mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 1c:fd:08:ca:fe:bb brd ff:ff:ff:ff:ff:ff

Create the trunk network

List all of the VLAN names you need in the trunk interface config:

Run this on the Router VM
network=/etc/systemd/network/20-trunk.network
cat <<EOF > ${network}
[Match]
Name=trunk
Type=ether

[Network]
Description=trunk for all VLAN traffic
VLAN=lan
VLAN=work
VLAN=apps
VLAN=iot
EOF

Create VLAN networks

Run this on the Router VM
declare -A vlan_names
vlan_names=(
  [10]="lan"
  [11]="work"
  [12]="apps"
  [13]="iot"
)

for vlan in "${!vlan_names[@]}"; do
  netdev="/etc/systemd/network/20-${vlan_names[$vlan]}.netdev"
  network="/etc/systemd/network/20-${vlan_names[$vlan]}.network"
  cat <<EOF > ${netdev}
[NetDev]
Name=${vlan_names[$vlan]}
Kind=vlan

[VLAN]
Id=${vlan}
EOF
  cat <<EOF > ${network}
[Match]
Name=${vlan_names[$vlan]}
Type=vlan

[Network]
Description=The interface for ${vlan_names[$vlan]}

[Address]
Address=192.168.${vlan}.1/24
EOF
  echo -e "\n## VLAN ${vlan} netdev: ${netdev}"
  cat ${netdev}
  echo -e "\n## VLAN ${vlan} network: ${network}"
  cat ${network}
done

Restart network

Run this on the Router VM
systemctl restart systemd-networkd

Show interfaces

Run this on the Router VM
ip addr
(stdout)
[root@router network]# ip addr
...
3: trunk:  mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 1c:fd:08:7c:74:b6 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::1efd:8ff:fe7c:74b6/64 scope link proto kernel_ll
       valid_lft forever preferred_lft forever
5: lan@trunk:  mtu 1500 qdisc noqueue state UP group default qlen 1000
    inet 192.168.10.1/24 brd 192.168.10.255 scope global lan
6: work@trunk:  mtu 1500 qdisc noqueue state UP group default qlen 1000
    inet 192.168.11.1/24 brd 192.168.11.255 scope global work
7: iot@trunk:  mtu 1500 qdisc noqueue state UP group default qlen 1000
    inet 192.168.13.1/24 brd 192.168.13.255 scope global iot
8: apps@trunk:  mtu 1500 qdisc noqueue state UP group default qlen 1000
    inet 192.168.12.1/24 brd 192.168.12.255 scope global apps

Review each of the VLAN configs:

Run this on the Router VM
ip -d link show dev lan
ip -d link show dev work
ip -d link show dev apps
ip -d link show dev iot
(stdout)
...
vlan protocol 802.1Q id 10
...
vlan protocol 802.1Q id 11
...
vlan protocol 802.1Q id 12
...
vlan protocol 802.1Q id 13
...