meta-google: gbmc-bridge: Refactor ip from bridge script
This refactors the RA querying and parsing logic so that other script
can leverage the functionality if they want to discover hostname and IP
information from RAs. There are no functional changes in this commit.
Tested: Verified that the script still determines the NCSI hostname and
IP correctly on machines using the script.
Change-Id: I751048440f2e9eab1628600a9bdc3701f07adf76
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/meta-google/recipes-google/ncsi/files/gbmc-ncsi-ip-from-ra.sh.in b/meta-google/recipes-google/ncsi/files/gbmc-ncsi-ip-from-ra.sh.in
index 4aae5c8..ed1ca6a 100755
--- a/meta-google/recipes-google/ncsi/files/gbmc-ncsi-ip-from-ra.sh.in
+++ b/meta-google/recipes-google/ncsi/files/gbmc-ncsi-ip-from-ra.sh.in
@@ -15,83 +15,27 @@
[ ! -e /usr/share/gbmc-br-lib.sh ] && exit
-# shellcheck source=meta-google/recipes-google/networking/network-sh/lib.sh
-source /usr/share/network/lib.sh || exit
# shellcheck source=meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-lib.sh
source /usr/share/gbmc-br-lib.sh || exit
-NCSI_IF='@NCSI_IF@'
-
-old_pfx=
-old_fqdn=
-old_rtr=
-
-set_host() {
- [[ -n "$host" && -n "$domain" && -n "$hextet" ]] || return
-
- local fqdn="$host-n$hextet.$domain"
- [ "$fqdn" != "$old_fqdn" ] || return
- old_fqdn="$fqdn"
-
- echo "Found hostname $fqdn" >&2
- hostnamectl set-hostname "$fqdn" || true
+update_fqdn() {
+ hostnamectl set-hostname "$1" || true
}
-set_net() {
- [[ -n "$pfx" && -n "$rtr" ]] || return
- [[ "$pfx" != "$old_pfx" || "$rtr" != "$old_rtr" ]] || return
- old_pfx="$pfx"
- old_rtr="$rtr"
-
- echo "Found prefix $pfx from $rtr" >&2
-
+update_pfx() {
# We no longer need NCSId if we are in this configuration
systemctl stop --no-block ncsid@"$NCSI_IF" || true
# Save the IP address for the interface
- gbmc_br_set_ip "$pfx" || true
+ gbmc_br_set_ip "$1" || true
# DHCP Relay workaround until alternate source port is supported
# TODO: Remove this once internal relaying cleanups land
gbmc-ncsi-smartnic-wa.sh || true
}
-w=60
-while true; do
- start=$SECONDS
- while read -r line; do
- # `script` terminates all lines with a CRLF, remove it
- line="${line:0:-1}"
- if [ -z "$line" ]; then
- hextet=
- pfx=
- host=
- domain=
- elif [[ "$line" =~ ^Prefix' '*:' '*(.*)/([0-9]+)$ ]]; then
- t_pfx="${BASH_REMATCH[1]}"
- t_pfx_len="${BASH_REMATCH[2]}"
- ip_to_bytes t_pfx_b "$t_pfx" || continue
- (( t_pfx_len == 76 && (t_pfx_b[8] & 0xfd) == 0xfd )) || continue
- (( t_pfx_b[9] |= 1 ))
- hextet="fd$(printf '%02x' "${t_pfx_b[9]}")"
- pfx="$(ip_bytes_to_str t_pfx_b)"
- elif [[ "$line" =~ ^'DNS search list'' '*:' '*([^.]+)(.*[.]google[.]com)' '*$ ]]; then
- # Ideally, we use PCRE and with lookahead and can do this in a single regex
- # ^([a-zA-Z0-9-]+(?=-n[a-fA-F0-9]{1,4})|[a-zA-Z0-9-]+(?!-n[a-fA-F0-9]{1,4}))[^.]*[.]((?:[a-zA-Z0-9]*[.])*google[.]com)$
- # Instead we do multiple steps to extract the needed info
- host="${BASH_REMATCH[1]}"
- domain="${BASH_REMATCH[2]#.}"
- if [[ "$host" =~ (-n[a-fA-F0-9]{1,4})$ ]]; then
- host="${host%"${BASH_REMATCH[1]}"}"
- fi
- elif [[ "$line" =~ ^from' '(.*)$ ]]; then
- rtr="${BASH_REMATCH[1]}"
- set_net || true
- set_host || true
- fi
- done < <(exec script -q -c "rdisc6 -d -m $NCSI_IF -w $(( w * 1000 ))" /dev/null 2>/dev/null)
- # If rdisc6 exits early we still want to wait the full `w` time before
- # starting again.
- (( timeout = start + w - SECONDS ))
- sleep $(( timeout < 0 ? 0 : timeout ))
-done
+RA_IF=@NCSI_IF@
+IP_OFFSET=1
+
+# shellcheck source=meta-google/recipes-google/networking/gbmc-bridge/gbmc-ip-from-ra.sh
+source /usr/share/gbmc-ip-from-ra.sh || exit
diff --git a/meta-google/recipes-google/networking/gbmc-bridge.bb b/meta-google/recipes-google/networking/gbmc-bridge.bb
index ba4b691..a9f2761 100644
--- a/meta-google/recipes-google/networking/gbmc-bridge.bb
+++ b/meta-google/recipes-google/networking/gbmc-bridge.bb
@@ -19,6 +19,7 @@
file://gbmc-br-ensure-ra.service \
file://gbmc-br-hostname.sh \
file://gbmc-br-hostname.service \
+ file://gbmc-ip-from-ra.sh \
file://gbmc-br-gw-src.sh \
file://gbmc-br-nft.sh \
file://gbmc-br-dhcp.sh \
@@ -36,6 +37,7 @@
${datadir}/gbmc-ip-monitor \
${datadir}/gbmc-br-dhcp \
${datadir}/gbmc-br-lib.sh \
+ ${datadir}/gbmc-ip-from-ra.sh \
${systemd_unitdir}/network \
${sysconfdir}/nftables \
"
@@ -139,6 +141,7 @@
install -m0644 ${WORKDIR}/50-gbmc-psu-hardreset.sh ${D}${datadir}/gbmc-br-dhcp/
install -m0644 ${WORKDIR}/gbmc-br-lib.sh ${D}${datadir}/
+ install -m0644 ${WORKDIR}/gbmc-ip-from-ra.sh ${D}${datadir}/
install -d ${D}/${bindir}
install -m0755 ${WORKDIR}/gbmc-start-dhcp.sh ${D}${bindir}/
diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-ip-from-ra.sh b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-ip-from-ra.sh
new file mode 100755
index 0000000..206f49f
--- /dev/null
+++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-ip-from-ra.sh
@@ -0,0 +1,75 @@
+#!/bin/bash
+# Copyright 2021 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.
+
+# shellcheck source=meta-google/recipes-google/networking/network-sh/lib.sh
+source /usr/share/network/lib.sh || exit
+
+: "${RA_IF:?No RA interface set}"
+: "${IP_OFFSET:?No IP offset set}"
+
+old_pfx=
+old_fqdn=
+
+w=60
+while true; do
+ start=$SECONDS
+ while read -r line; do
+ # `script` terminates all lines with a CRLF, remove it
+ line="${line:0:-1}"
+ if [ -z "$line" ]; then
+ hextet=
+ pfx=
+ host=
+ domain=
+ elif [[ "$line" =~ ^Prefix' '*:' '*(.*)/([0-9]+)$ ]]; then
+ t_pfx="${BASH_REMATCH[1]}"
+ t_pfx_len="${BASH_REMATCH[2]}"
+ ip_to_bytes t_pfx_b "$t_pfx" || continue
+ (( (t_pfx_len == 76 || t_pfx_len == 80) && (t_pfx_b[8] & 0xfd) == 0xfd )) || continue
+ (( t_pfx_b[9] &= 0xf0 ))
+ (( t_pfx_b[9] |= IP_OFFSET ))
+ hextet="fd$(printf '%02x' "${t_pfx_b[9]}")"
+ pfx="$(ip_bytes_to_str t_pfx_b)"
+ elif [[ "$line" =~ ^'DNS search list'' '*:' '*([^.]+)(.*[.]google[.]com)' '*$ ]]; then
+ # Ideally, we use PCRE and with lookahead and can do this in a single regex
+ # ^([a-zA-Z0-9-]+(?=-n[a-fA-F0-9]{1,4})|[a-zA-Z0-9-]+(?!-n[a-fA-F0-9]{1,4}))[^.]*[.]((?:[a-zA-Z0-9]*[.])*google[.]com)$
+ # Instead we do multiple steps to extract the needed info
+ host="${BASH_REMATCH[1]}"
+ domain="${BASH_REMATCH[2]#.}"
+ if [[ "$host" =~ (-n[a-fA-F0-9]{1,4})$ ]]; then
+ host="${host%"${BASH_REMATCH[1]}"}"
+ fi
+ elif [[ "$line" =~ ^from' '(.*)$ ]]; then
+ rtr="${BASH_REMATCH[1]}"
+ if [[ -n $pfx && $pfx != "$old_pfx" ]]; then
+ echo "Updating PFX($pfx) from $rtr" >&2
+ old_pfx="$pfx"
+ update_pfx "$pfx" || true
+ fi
+ if [[ -n $host && -n $hextet && -n $domain ]]; then
+ fqdn="$host-n$hextet.$domain"
+ if [[ $fqdn != "$old_fqdn" ]]; then
+ echo "Updating FQDN($fqdn) from $rtr" >&2
+ old_fqdn="$fqdn"
+ update_fqdn "$fqdn" || true
+ fi
+ fi
+ fi
+ done < <(exec script -q -c "rdisc6 -d -m $RA_IF -w $(( w * 1000 ))" /dev/null 2>/dev/null)
+ # If rdisc6 exits early we still want to wait the full `w` time before
+ # starting again.
+ (( timeout = start + w - SECONDS ))
+ sleep $(( timeout < 0 ? 0 : timeout ))
+done