# 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