From ec139644a1bd52aa293d845e46988ab7b0320595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jake=20Buchholz=20G=C3=B6kt=C3=BCrk?= Date: Sun, 7 May 2023 23:49:50 +0000 Subject: [PATCH] Set Default interfaces --- lib/tiny-cloud/init | 82 ++++++++++++++++++++++++++++++++++++++++++- tests/init-early.test | 55 ++++++++++++++++++++++++++++- tests/test_env.sh | 10 ++++++ 3 files changed, 145 insertions(+), 2 deletions(-) diff --git a/lib/tiny-cloud/init b/lib/tiny-cloud/init index ee3fdbc..21d09a9 100644 --- a/lib/tiny-cloud/init +++ b/lib/tiny-cloud/init @@ -13,6 +13,7 @@ INIT_ACTIONS_EARLY=" expand_root install_hotplugs + set_interfaces_default " INIT_ACTIONS_MAIN=" save_userdata @@ -59,7 +60,7 @@ init__install_hotplugs() { . "$LIBDIR/tiny-cloud/$HOTPLUG_TYPE" fi - printf ' :' >&2 + printf ': ' >&2 for module in $HOTPLUG_MODULES; do result='?' level='err' @@ -80,6 +81,85 @@ init__install_hotplugs() { return $rc } +# collect ethernet interfaces, sorted by index +ethernets() { + for i in "$ROOT/sys/class/net/"*; do + local iface="${i##*/}" + case "$iface" in + eth*) echo "$(cat "$i/ifindex") $iface";; + esac + done | sort -n | awk '{print $2}' +} + +# find the interface that is has operstate up +find_first_interface_up() { + local n=0 + [ $# -eq 0 ] && return + while [ $n -le ${TINY_CLOUD_LINK_WAIT_MAX:-10} ]; do + for i in "$@"; do + if [ "$(cat "$ROOT/sys/class/net/$i/operstate")" = "up" ]; then + echo "$i" + return + fi + done + sleep 0.1 + n=$((n+1)) + done +} + +# auto detect which network interface to auto configure +# check which is connected or fallback to first +# This will set link to down to all eth* except the found +auto_detect_ethernet_interface() { + local ifaces="$(ethernets)" + [ -z "$ifaces" ] && return + + # find first connected interface + for i in $ifaces; do + $MOCK ip link set dev $i up >/dev/null + done + local iface="$(find_first_interface_up $ifaces)" + + # use first if all are disconnected + if [ -z "$iface" ]; then + set -- $ifaces + iface="$1" + fi + + # we will use the found interface later so lets keep it up + for i in $ifaces; do + if [ "$i" != "$iface" ]; then + $MOCK ip link set dev $i down >/dev/null + fi + done + echo "$iface" +} + +init__set_interfaces_default() { + if [ -f "$ROOT"/etc/network/interfaces ]; then + echo "already set up" >&2 + log info "$phase $ACTION - already set up" + return + fi + + mkdir -p "$ROOT/etc/network" + printf "%s\n%s\n\n" \ + "auto lo" \ + "iface lo inet loopback" \ + > "$ROOT/etc/network/interfaces" + + local iface="$(auto_detect_ethernet_interface)" + if [ -z "$iface" ]; then + # TODO: message/log? + return + fi + printf "%s\n%s\n\t%s\n\n" \ + "auto $iface" \ + "iface $iface" \ + "use dhcp" >> "$ROOT/etc/network/interfaces" +} + + ### init-main functions init__set_hostname() { diff --git a/tests/init-early.test b/tests/init-early.test index d640ace..cfbbb4a 100755 --- a/tests/init-early.test +++ b/tests/init-early.test @@ -9,7 +9,11 @@ lib="$srcdir"/lib/tiny-cloud/init init_tests \ expand_root \ expand_root_partition \ - install_hotplugs_fail + install_hotplugs_fail \ + ethernets \ + find_first_interface_up \ + auto_detect_ethernet_interface \ + set_interfaces_default PROVIDERS="aws azure gcp nocloud oci" @@ -46,3 +50,52 @@ install_hotplugs_fail_body() { -e match:"vnic_eth_hotplug\(!\)" \ sh -c ". $lib; HOTPLUG_MODULES='vnic_eth_hotplug'; init__install_hotplugs" } + +ethernets_body() { + fake_interfaces lo br0 eth0 eth2 eth11 + + # check that they are sorted by ifindex, not name + # and that br0 and lo are excluded + atf_check \ + -o match:"eth0 eth2 eth11" \ + -o not-match:"br0" \ + -o not-match:"lo" \ + sh -c ". $lib; ethernets | tr '\n' ' '" +} + +find_first_interface_up_body() { + fake_interfaces eth0 eth1 + echo up > sys/class/net/eth1/operstate + + atf_check \ + -o match:"eth1" \ + sh -c ". $lib; find_first_interface_up eth0 eth1" +} + +auto_detect_ethernet_interface_body() { + fake_interfaces eth0 eth1 + echo up > sys/class/net/eth1/operstate + + atf_check \ + -o match:"^eth1$" \ + sh -c ". $lib; auto_detect_ethernet_interface" + + # test that we pick first if all are down + echo down > sys/class/net/eth1/operstate + atf_check \ + -o match:"^eth0$" \ + sh -c ". $lib; TINY_CLOUD_LINK_WAIT_MAX=1; auto_detect_ethernet_interface" +} + +set_interfaces_default_body() { + fake_interfaces eth0 eth1 + echo up > sys/class/net/eth1/operstate + + atf_check \ + sh -c ". $lib; init__set_interfaces_default" + atf_check \ + -o match:"auto lo" \ + -o match:"iface eth1" \ + -o match:"use dhcp" \ + cat etc/network/interfaces +} diff --git a/tests/test_env.sh b/tests/test_env.sh index e958fd2..f197bb8 100644 --- a/tests/test_env.sh +++ b/tests/test_env.sh @@ -67,3 +67,13 @@ fake_metadata_nocloud() { mkdir -p mnt fake_umount } + +fake_interfaces() { + local n=1 + for i; do + mkdir -p sys/class/net/$i + echo $n > sys/class/net/$i/ifindex + echo down >sys/class/net/$i/operstate + n=$((n+1)) + done +}