====== Systemd Networking ======
systemd-networkd should be the future. That being said it is somewhat arcane to say the least.
The desire: Create a BONDED LAG, and attach a bunch of bridged VLANs to it.
The script below should create a folder /tmp/systemd-networkd and dump all the needed configuration. Despite what I continually read, order does not seem to be important. This works on Debian Bullseye. I built this because I keep rebuilding my LAB KVM/QEMU server, and typing in all these files is tedious at best. This used to be about 15 or so lines in /etc/network/interfaces. This ranks right up there with using m4 to compile sendmail.cf. The more layers of obfuscation the better.
NOTE TO SYSTEMD DEVELOPERS:
I get the drop a file to configure idea. Makes sense for a number of things. Not so much with networking. This is like the RedHat sysconfig/network-scripts only worse. The fan-out here is outrageous. I could actually write a script using iproute2 and accomplish this with a fraction of the effort. I should be able to trivially define a VLAN on any interface, building a stack up from the physical interfaces:
From 15 lines to **18 Files** to create 4 bridged vlans
[root@nas-7] /nas-3/admin/install/systemd-networkd<351>ls /tmp/systemd-network/
bond1.1099.netdev bond1.1100.network bond1.1102.netdev bond1.netdev br0.1099.network br0.1101.netdev br0.1102.network
bond1.1099.network bond1.1101.netdev bond1.1102.network bond1.network br0.1100.netdev br0.1101.network br0.netdev
bond1.1100.netdev bond1.1101.network bond1.br0.network br0.1099.netdev br0.1100.network br0.1102.netdev br0.network
[root@nas-7] /nas-3/admin/install/systemd-networkd<354>iflist
Interface |IP Address |Broadcast |Point-Point|Netmask |
----------|----------------|-------------|-----------|-------------|
lo |127.0.0.1/8 | | |255.0.0.0 |
eth0 | | | | |
eth1 | | | | |
eth2 | | | | |
eth3 | | | | |
bond1 | | | | |
br0.1099 |10.29.99.254/24 |10.29.99.255 | |255.255.255.0|
br0.1100 |10.29.100.254/24|10.29.100.255| |255.255.255.0|
br0.1101 |10.29.101.254/24|10.29.101.255| |255.255.255.0|
br0.1102 |10.29.102.254/24|10.29.102.255| |255.255.255.0|
br0 |10.29.0.9/24 |10.29.0.255 | |255.255.255.0|
bond1.1099| | | | |
bond1.1100| | | | |
bond1.1101| | | | |
bond1.1102| | | | |
I suggest you remove all the other networking cruft:
* apt-get -y purge ifupdown network-manager avahi-daemon . . .
I hacked in "line" for a line_edit binary I wrote/use if it can't find it. Might give you grief, just comment out the cmd_ok at the bottom and manually move the files if it doesn't fly. There are surely some issues with this, I have done a file-by-file comparison, seems to be pretty close. Not sure if LLDP should be on the bridge or the physical with a bond or whatever. The setup seems to match my working manual configs almost to the letter. I haven't fully verified any of this from scratch, as there are some manual additions to some of the working files. It should produce working output.
Hack up the variables at the top of the script to meet your needs.
#!/bin/sh
#
# Script: create_network
#
# Create the necessary files for systemd to create bridged vlan interfaces
# against a LAG or an interface. Not super pretty
#
# Last Modified: 2023-04-06 16:09:48
# Pick A scenario:
# To LAG multiple interfaces use these two
BRIDGE_DEV="bond1"
BOND_IFACES="eth0 eth1 eth2 eth3"
# -- OR --
# To just use a single interface for the bridge
#BRIDGE_DEV="eth0"
#
BRIDGE_PREFIX="br0"
VLAN_LIST="1099 1100 1101 1102"
# Bind addresses as desired to the various bridges, front end of variable should match prefix
# Format is BRIDGE_VLAN_WORD
br0__address="10.29.0.13/24"
br0__gateway="10.29.0.1"
br0_1099_address="10.29.99.253/24"
br0_1100_address="10.29.100.253/24"
br0_1101_address="10.29.101.253/24"
br0_1102_address="10.29.102.253/24"
br0_1102_gateway="10.29.102.1"
# Some default cruft to the primary bridge interface
DOMAIN_LIST="i.ksmith.com i.cfns.net ksmith.com cfns.net"
DNS_LIST="10.29.0.30 10.29.1.20 10.29.0.1"
# Salt and pepper
TMP_FOLDER=/tmp/systemd-network
NETWORK_FOLDER=/etc/systemd/network
#----------------------------------------------------------------------
# CMD_OK
# Run command with confirmation
#----------------------------------------------------------------------
cmd_ok() {
echo "$1"
if [ -x /usr/local/bin/line_edit ]
then
ok=`line_edit 1 -u -p "OK (Y/N)? "`
else
/bin/echo "OK (Y/N)?" && ok=`line`
fi
case "$ok" in
Y) eval "$1" ;;
N) : ;;
esac
}
#----------------------------------------------------------------------
# CREATE_BASE
#----------------------------------------------------------------------
create_base() {
cat - < /$TMP_FOLDER/$base.network
#
# File: $base.network
#
[Match]
Name=$base
[Network]
Bridge=$bridge
LLDP=true
EmitLLDP=true
EOF_BASE
}
#----------------------------------------------------------------------
# CREATE_BOND
#----------------------------------------------------------------------
create_bond() {
cat - < $TMP_FOLDER/$base.netdev
#
# $base.netdev
#
[NetDev]
Name=$base
Description=Primary LAN LAG
Kind=bond
[Bond]
Mode=802.3ad
EOF_BOND_NETDEV
(
echo "#"
echo "# $base.network"
echo "#"
echo "[Match]"
for iface in $BOND_IFACES
do
echo "Name=$iface"
done
echo ""
echo "[Network]"
echo "Bond=$base"
) > $TMP_FOLDER/$base.network
cat - < /$TMP_FOLDER/$base.${BRIDGE_PREFIX}.network
#
# File: $base.${BRIDGE_PREFIX}.network
#
[Match]
Name=$base
[Network]
Bridge=$bridge
LLDP=true
EmitLLDP=true
EOF_BASE
}
#----------------------------------------------------------------------
# CREATE_BRIDGE
#----------------------------------------------------------------------
create_bridge() {
cat - < $TMP_FOLDER/$bridge.netdev
[NetDev]
Name=$bridge
Kind=bridge
EOF_BRIDGE_NETDEV
cat - < $TMP_FOLDER/$bridge.network
[Match]
Name=$bridge
[Network]
EOF_BRIDGE_NETWORK
eval "address=\$${BRIDGE_PREFIX}_${vlan_id}_address"
[ "$address" != "" ] && echo "Address=$address" >> $TMP_FOLDER/$bridge.network
eval "gateway=\$${BRIDGE_PREFIX}_${vlan_id}_gateway"
[ "$gateway" != "" ] && echo "Gateway=$gateway" >> $TMP_FOLDER/$bridge.network
# DNS/DOMAIN only on primary bridge ?
if [ "$vlan_id" = "" ]
then
echo "Domains=$DOMAIN_LIST" >> $TMP_FOLDER/$bridge.network
for dns in $DNS_LIST
do
echo "DNS=$dns" >> $TMP_FOLDER/$bridge.network
done
fi
}
#----------------------------------------------------------------------
# CREATE_VLAN
#----------------------------------------------------------------------
create_vlan() {
# First the Device definition
cat - < $TMP_FOLDER/$base.$vlan_id.netdev
#
# $base.$vlan_id.netdev
#
[NetDev]
Name=$base.$vlan_id
Kind=vlan
[VLAN]
Id=$vlan_id
EOF_VLAN_NETDEV
# Then the Network definition
cat - < $TMP_FOLDER/$base.$vlan_id.network
#
# $base.$vlan_id.network
#
[Match]
Name=$base.$vlan_id
[Network]
Bridge=$bridge
EOF_VLAN_NETWORK
}
#----------------------------------------------------------------------
# MAIN
#----------------------------------------------------------------------
arg="$1"
rm -rf $TMP_FOLDER
mkdir $TMP_FOLDER || exit 255
vlan_id=
for base in $BRIDGE_DEV
do
bridge=$BRIDGE_PREFIX
case "$base" in
bond*) create_bond ; base_path=$TMP_FOLDER/$base.${BRIDGE_PREFIX}.network ;;
eth*) create_base ; base_path=$TMP_FOLDER/$base.network ;;
esac
create_bridge
for vlan_id in $VLAN_LIST
do
bridge=$BRIDGE_PREFIX.$vlan_id
echo "VLAN=$base.$vlan_id" >> $base_path
create_vlan $vlan_id
bridge="$BRIDGE_PREFIX.$vlan_id"
create_bridge
done
done
echo ""
ls $TMP_FOLDER
echo ""
echo ""
cmd="mv $NETWORK_FOLDER $NETWORK_FOLDER.old"
cmd="$cmd && cp -va $TMP_FOLDER $NETWORK_FOLDER"
cmd_ok "$cmd"