# Write startup script on Ubuntu 22.04 ###### tags: `linux` `network` An example of systemd startup script. The script configures a network interface (eno2) to be attached on a linux bridge (virbr1) created by libvirt. This could be done by using "netplan", but it has issue on libvirt to start virtual network of the bridge. ``` root@nuc112:/etc/netplan# cat 00-installer-config.yaml # This is the network config written by 'subiquity' network: ethernets: eno1: dhcp4: true eno2: dhcp4: false link-local: [] match: macaddress: c8:4d:44:22:01:ee set-name: eno2 #enxc84d442201ee: # dhcp4: true bridges: virbr1: interfaces: [eno2] macaddress: 52:54:00:fe:cc:b7 dhcp4: false dhcp6: false version: 2 root@nuc112:/etc/netplan# brctl show virbr1 bridge name bridge id STP enabled interfaces virbr1 8000.525400feccb7 no eno2 root@nuc112:/etc/netplan# virsh net-list --all Name State Autostart Persistent ----------------------------------------------- default active yes yes external inactive yes yes root@nuc112:/etc/netplan# virsh net-info external Name: external UUID: 0a6d6648-8fac-477a-b129-66fbe65bd9b4 Active: no Persistent: yes Autostart: yes Bridge: virbr1 root@nuc112:/etc/netplan# virsh net-start external error: Failed to start network external error: error creating bridge interface virbr1: File exists ``` A workaround is to have a systemd service to run a script which attach the interface to the bridge instead of using netplan. #### Steps ##### 1. write systemd service file ``` root@nuc112:~# cd /etc/systemd/system/ root@nuc112:/etc/systemd/system# vim attach-interface-to-linux-bridge.service [Unit] After=libvirtd.service [Service] ExecStart=/usr/local/bin/attach-interface-to-linux-bridge.sh virbr1 eno2 [Install] WantedBy=default.target ``` ##### 2. write script to be executed on system startup ``` root@nuc112:/etc/systemd/system# vim /usr/local/bin/attach-interface-to-linux-bridge.sh #!/bin/bash BR=$1 IF=$2 STOP_FILE='/tmp/stop-attach-interface-to-linux-bridge' if [ "$#" != 2 ]; then echo "Invalid arguments, exit." exit 2 fi # prevent attaching interface has IP assigned ret=$(ip -4 addr show ${IF}) if [ "${ret}" != "" ]; then echo "Interface ${IF} has IP address assigned, exit." exit 2 fi while true; do ret=$(brctl show ${BR} | grep ${IF} &> /dev/null; echo $?) if [ "${ret}" == "0" ]; then echo "Already attached, continue. (sleep 60 seconds)" sleep 60 continue fi ret=$(brctl show ${BR} &> /dev/null; echo $?) if [ "${ret}" == "0" ]; then ret=$(ip link show ${IF} &> /dev/null; echo $?) if [ "${ret}" == "0" ]; then echo "Attach ${IF} to ${BR}." brctl addif ${BR} ${IF} else echo "Interface ${IF} not exit." fi else echo "Bridge ${BR} not exit." fi if [ -f "$STOP_FILE" ]; then echo "Stop script." break fi sleep 10 done ``` ##### 3. set permission ``` root@nuc112:/etc/systemd/system# chmod 744 /usr/local/bin/attach-interface-to-linux-bridge.sh root@nuc112:/etc/systemd/system# chmod 644 /etc/systemd/system/attach-interface-to-linux-bridge.service ``` ##### 4. enable and start the systemd service ``` root@nuc112:/etc/systemd/system# systemctl daemon-reload root@nuc112:/etc/systemd/system# systemctl enable attach-interface-to-linux-bridge.service Created symlink /etc/systemd/system/default.target.wants/attach-interface-to-linux-bridge.service → /etc/systemd/system/attach-interface-to-linux-bridge.service. root@nuc112:/etc/systemd/system# systemctl start attach-interface-to-linux-bridge.service root@nuc112:/etc/systemd/system# systemctl status attach-interface-to-linux-bridge.service ● attach-interface-to-linux-bridge.service Loaded: loaded (/etc/systemd/system/attach-interface-to-linux-bridge.service; enabled; vendor preset: enabled) Active: active (running) since Sun 2023-01-01 16:42:07 AEDT; 2s ago Main PID: 506436 (attach-interfac) Tasks: 2 (limit: 38086) Memory: 536.0K CPU: 22ms CGroup: /system.slice/attach-interface-to-linux-bridge.service ├─506436 /bin/bash /usr/local/bin/attach-interface-to-linux-bridge.sh virbr1 eno2 └─506448 sleep 10 Jan 01 16:42:07 nuc112 systemd[1]: Started attach-interface-to-linux-bridge.service. Jan 01 16:42:07 nuc112 attach-interface-to-linux-bridge.sh[506436]: Attach eno2 to virbr1. root@nuc112:/etc/systemd/system# brctl show virbr1 bridge name bridge id STP enabled interfaces virbr1 8000.525400feccb7 yes eno2 ``` ##### 5. reboot & check ``` ubuntu@nuc112:~$ brctl show bridge name bridge id STP enabled interfaces docker0 8000.0242b6edc974 no virbr0 8000.52540046ab1a yes virbr1 8000.525400feccb7 yes eno2 ubuntu@nuc112:~$ virsh net-list Name State Autostart Persistent --------------------------------------------- default active yes yes external active yes yes ubuntu@nuc112:~$ systemctl status attach-interface-to-linux-bridge ● attach-interface-to-linux-bridge.service Loaded: loaded (/etc/systemd/system/attach-interface-to-linux-bridge.service; enabled; vendor preset: enabled) Active: active (running) since Sun 2023-01-01 16:45:28 AEDT; 1min 56s ago Main PID: 932 (attach-interfac) Tasks: 2 (limit: 38086) Memory: 680.0K CPU: 51ms CGroup: /system.slice/attach-interface-to-linux-bridge.service ├─ 932 /bin/bash /usr/local/bin/attach-interface-to-linux-bridge.sh virbr1 eno2 └─1578 sleep 60 Jan 01 16:45:28 nuc112 systemd[1]: Started attach-interface-to-linux-bridge.service. Jan 01 16:45:28 nuc112 attach-interface-to-linux-bridge.sh[936]: bridge virbr1 does not exist! Jan 01 16:45:28 nuc112 attach-interface-to-linux-bridge.sh[932]: Bridge virbr1 not exit. Jan 01 16:45:38 nuc112 attach-interface-to-linux-bridge.sh[932]: Attach eno2 to virbr1. Jan 01 16:45:48 nuc112 attach-interface-to-linux-bridge.sh[932]: Already attached, continue. (sleep 60 seconds) Jan 01 16:46:48 nuc112 attach-interface-to-linux-bridge.sh[932]: Already attached, continue. (sleep 60 seconds) ``` # reference https://linuxconfig.org/how-to-run-script-on-startup-on-ubuntu-22-04-jammy-jellyfish-server-desktop https://wiki.archlinux.org/title/Systemd