meta-google: gbmc-bridge: Rework IP address persistence
This consolidates all of the mechanisms which write out a persistent IP
into a single place. It also transitions to writing a very simple
persistent file instead of systemd style network units.
Change-Id: Ib99d7646178d2c5383cf23b09248bf24544c1d9e
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/meta-google/recipes-google/networking/gbmc-bridge.bb b/meta-google/recipes-google/networking/gbmc-bridge.bb
index 850b14a..3f2857b 100644
--- a/meta-google/recipes-google/networking/gbmc-bridge.bb
+++ b/meta-google/recipes-google/networking/gbmc-bridge.bb
@@ -25,11 +25,14 @@
file://gbmc-br-dhcp.service \
file://gbmc-br-dhcp-term.sh \
file://gbmc-br-dhcp-term.service \
+ file://gbmc-br-lib.sh \
+ file://gbmc-br-load-ip.service \
"
FILES:${PN}:append = " \
${datadir}/gbmc-ip-monitor \
${datadir}/gbmc-br-dhcp \
+ ${datadir}/gbmc-br-lib.sh \
${systemd_unitdir}/network \
${sysconfdir}/nftables \
${sysconfdir}/avahi/services \
@@ -48,6 +51,7 @@
gbmc-br-ensure-ra.service \
gbmc-br-dhcp.service \
gbmc-br-dhcp-term.service \
+ gbmc-br-load-ip.service \
"
GBMC_BR_MAC_ADDR ?= ""
@@ -111,8 +115,11 @@
install -m0644 ${WORKDIR}/gbmc-br-ensure-ra.service ${D}${systemd_system_unitdir}/
install -m0644 ${WORKDIR}/gbmc-br-dhcp.service ${D}${systemd_system_unitdir}/
install -m0644 ${WORKDIR}/gbmc-br-dhcp-term.service ${D}${systemd_system_unitdir}/
+ install -m0644 ${WORKDIR}/gbmc-br-load-ip.service ${D}${systemd_system_unitdir}/
install -d -m0755 ${D}${datadir}/gbmc-br-dhcp
install -m0644 ${WORKDIR}/50-gbmc-psu-hardreset.sh ${D}${datadir}/gbmc-br-dhcp/
+
+ install -m0644 ${WORKDIR}/gbmc-br-lib.sh ${D}${datadir}/
}
do_rm_work:prepend() {
diff --git a/meta-google/recipes-google/networking/gbmc-bridge/-bmc-gbmcbr.network.in b/meta-google/recipes-google/networking/gbmc-bridge/-bmc-gbmcbr.network.in
index afea5cc..09ef620 100644
--- a/meta-google/recipes-google/networking/gbmc-bridge/-bmc-gbmcbr.network.in
+++ b/meta-google/recipes-google/networking/gbmc-bridge/-bmc-gbmcbr.network.in
@@ -7,5 +7,8 @@
LLMNR=true
MulticastDNS=true
LinkLocalAddressing=ipv6
+IPv6PrefixDelegation=yes
[IPv6AcceptRA]
DHCPv6Client=false
+[IPv6PrefixDelegation]
+RouterLifetimeSec=30
diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-dhcp.sh b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-dhcp.sh
index 19fa7b1..9c61036 100644
--- a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-dhcp.sh
+++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-dhcp.sh
@@ -15,27 +15,20 @@
# A list of functions which get executed for each bound DHCP lease.
# These are configured by the files included below.
+# Shellcheck does not understand how this gets referenced
+# shellcheck disable=SC2034
GBMC_BR_DHCP_HOOKS=()
-# Load configurations from a known location in the filesystem to populate
-# hooks that are executed after each event.
-shopt -s nullglob
-for conf in /usr/share/gbmc-br-dhcp/*.sh; do
- # SC doesn't like dynamic source loading
- # shellcheck disable=SC1090
- source "$conf"
-done
-
-gbmc_br_dhcp_run_hooks() {
- local hook
- for hook in "${GBMC_BR_DHCP_HOOKS[@]}"; do
- "$hook" || return
- done
-}
-
# SC can't find this path during repotest
# shellcheck disable=SC1091
source /usr/share/network/lib.sh || exit
+# SC can't find this path during repotest
+# shellcheck disable=SC1091
+source /usr/share/gbmc-br-lib.sh || exit
+
+# Load configurations from a known location in the filesystem to populate
+# hooks that are executed after each event.
+gbmc_br_source_dir /usr/share/gbmc-br-dhcp || exit
# Write out the current PID and cleanup when complete
trap 'rm -f /run/gbmc-br-dhcp.pid' EXIT
@@ -51,57 +44,25 @@
# Ensure we are a BMC and have a suffix nibble, the 0th index is reserved
if (( pfx_bytes[8] != 0xfd || pfx_bytes[9] & 0xf == 0 )); then
echo "Invalid address" >&2
- exit
+ exit 1
fi
# Ensure we don't have more than a /80 address
for (( i = 10; i < 16; ++i )); do
if (( pfx_bytes[i] != 0 )); then
echo "Invalid address" >&2
- exit
+ exit 1
fi
done
pfx="$(ip_bytes_to_str pfx_bytes)"
- (( pfx_bytes[9] &= 0xf0 ))
- stateless_pfx="$(ip_bytes_to_str pfx_bytes)"
- read -r -d '' contents <<EOF
-[Network]
-Address=$pfx/128
-IPv6PrefixDelegation=yes
-[IPv6PrefixDelegation]
-RouterLifetimeSec=60
-[IPv6Prefix]
-Prefix=$stateless_pfx/80
-PreferredLifetimeSec=60
-ValidLifetimeSec=60
-[IPv6RoutePrefix]
-Route=$pfx/80
-LifetimeSec=60
-[Route]
-Destination=$stateless_pfx/76
-Type=unreachable
-Metric=1024
-EOF
-
- for file in /etc/systemd/network/{00,}-bmc-gbmcbr.network.d/50-public.conf; do
- mkdir -p "$(dirname "$file")"
- printf '%s' "$contents" >"$file"
- done
-
- # Ensure that systemd-networkd performs a reconfiguration as it doesn't
- # currently check the mtime of drop-in files.
- touch -c /lib/systemd/network/*-bmc-gbmcbr.network
-
- if [ "$(systemctl is-active systemd-networkd)" != 'inactive' ]; then
- networkctl reload && networkctl reconfigure gbmcbr
- fi
+ gbmc_br_set_ip "$pfx" || exit
if [ -n "${fqdn-}" ]; then
echo "Using hostname $fqdn" >&2
hostnamectl set-hostname "$fqdn" || true
fi
- gbmc_br_dhcp_run_hooks || exit
+ gbmc_br_run_hooks GBMC_BR_DHCP_HOOKS || exit
# Ensure that the installer knows we have completed processing DHCP by
# running a service that reports completion
diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-lib.sh b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-lib.sh
new file mode 100644
index 0000000..7ccee8e
--- /dev/null
+++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-lib.sh
@@ -0,0 +1,133 @@
+#!/bin/bash
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+[ -n "${gbmc_br_lib_init-}" ] && return
+
+# SC can't find this path during repotest
+# shellcheck disable=SC1091
+source /usr/share/network/lib.sh || exit
+
+# A list of functions which get executed for each configured IP.
+# These are configured by the files included below.
+# Shellcheck does not understand how this gets referenced
+# shellcheck disable=SC2034
+GBMC_BR_LIB_SET_IP_HOOKS=()
+
+gbmc_br_source_dir() {
+ local dir="$1"
+
+ local file
+ while read -r -d $'\0' file; do
+ # SC doesn't like dynamic source loading
+ # shellcheck disable=SC1090
+ source "$file" || return
+ done < <(shopt -s nullglob; for f in "$dir"/*.sh; do printf '%s\0' "$f"; done)
+}
+
+# Load configurations from a known location in the filesystem to populate
+# hooks that are executed after each event.
+gbmc_br_source_dir /usr/share/gbmc-br-lib || exit
+
+gbmc_br_run_hooks() {
+ local -n hookvar="$1"
+ shift
+ local hook
+ for hook in "${hookvar[@]}"; do
+ "$hook" "$@" || return
+ done
+}
+
+gbmc_br_reload() {
+ if [ "$(systemctl is-active systemd-networkd)" != 'inactive' ]; then
+ networkctl reload && networkctl reconfigure gbmcbr
+ fi
+}
+
+gbmc_br_no_ip() {
+ echo "Runtime removing gbmcbr IP" >&2
+ rm -f /run/systemd/network/{00,}-bmc-gbmcbr.network.d/50-public.conf
+ gbmc_br_reload
+}
+
+gbmc_br_reload_ip() {
+ local ip="${1-}"
+
+ if [ -z "$ip" ] && ! ip="$(cat /var/google/gbmc-br-ip 2>/dev/null)"; then
+ echo "Ignoring unconfigured IP" >&2
+ gbmc_br_no_ip
+ return 0
+ fi
+
+ local pfx_bytes=()
+ if ! ip_to_bytes pfx_bytes "$ip"; then
+ echo "Ignoring Invalid IPv6: $ip" >&2
+ gbmc_br_no_ip
+ return 0
+ fi
+
+ local pfx
+ pfx="$(ip_bytes_to_str pfx_bytes)"
+ (( pfx_bytes[9] &= 0xf0 ))
+ local stateless_pfx
+ stateless_pfx="$(ip_bytes_to_str pfx_bytes)"
+ local contents
+ read -r -d '' contents <<EOF
+[Network]
+Address=$pfx/128
+[IPv6Prefix]
+Prefix=$stateless_pfx/80
+PreferredLifetimeSec=60
+ValidLifetimeSec=60
+[IPv6RoutePrefix]
+Route=$pfx/80
+LifetimeSec=60
+[Route]
+Destination=$stateless_pfx/76
+Type=unreachable
+Metric=1024
+EOF
+ echo "Runtime setting gbmcbr IP: $pfx" >&2
+
+ local file
+ for file in /run/systemd/network/{00,}-bmc-gbmcbr.network.d/50-public.conf; do
+ mkdir -p "$(dirname "$file")"
+ printf '%s' "$contents" >"$file"
+ done
+
+ gbmc_br_reload
+}
+
+gbmc_br_set_ip() {
+ local ip="${1-}"
+
+ if [ -n "$ip" ]; then
+ mkdir -p /var/google || return
+ echo "$ip" >/var/google/gbmc-br-ip || return
+ else
+ rm -rf /var/google/gbmc-br-ip
+ fi
+
+ # Remove legacy network configuration
+ rm -rf /etc/systemd/network/{00,}-bmc-gbmcbr.network.d
+
+ gbmc_br_run_hooks GBMC_BR_LIB_SET_IP_HOOKS "$ip" || return
+
+ gbmc_br_reload_ip "$ip"
+}
+
+gbmc_br_lib_init=1
+return 0 2>/dev/null
+echo "gbmc-br-lib is a library, not executed directly" >&2
+exit 1
diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-load-ip.service b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-load-ip.service
new file mode 100644
index 0000000..51c68eb
--- /dev/null
+++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-load-ip.service
@@ -0,0 +1,9 @@
+[Unit]
+Before=gbmc-ip-monitor.service
+Before=systemd-networkd.service
+
+[Service]
+ExecStart=/bin/bash -c 'source /usr/share/gbmc-br-lib.sh && gbmc_br_reload_ip'
+
+[Install]
+WantedBy=multi-user.target