diff options
Diffstat (limited to 'meta-google/recipes-google')
48 files changed, 1028 insertions, 344 deletions
diff --git a/meta-google/recipes-google/google-misc/google-misc.inc b/meta-google/recipes-google/google-misc/google-misc.inc index 477009357d..75c6606735 100644 --- a/meta-google/recipes-google/google-misc/google-misc.inc +++ b/meta-google/recipes-google/google-misc/google-misc.inc @@ -6,7 +6,7 @@ LICENSE = "Apache-2.0" LIC_FILES_CHKSUM = "file://../../LICENSE;md5=34400b68072d710fecd0a2940a0d1658" SRC_URI += "git://github.com/openbmc/google-misc;branch=master;protocol=https" -SRCREV = "4dba220d361271859f824aaa2c7861ceb63ca2dd" +SRCREV = "a06304b02fa5c4cd9f576a2191994a8259900cba" S = "${WORKDIR}/git/subprojects/${GOOGLE_MISC_PROJ}" inherit meson pkgconfig diff --git a/meta-google/recipes-google/ipmi/google-ipmi-sys_git.bb b/meta-google/recipes-google/ipmi/google-ipmi-sys_git.bb index 850d9b4715..d09eaae05a 100644 --- a/meta-google/recipes-google/ipmi/google-ipmi-sys_git.bb +++ b/meta-google/recipes-google/ipmi/google-ipmi-sys_git.bb @@ -23,7 +23,7 @@ RDEPENDS:${PN} += " \ S = "${WORKDIR}/git" SRC_URI = "git://github.com/openbmc/google-ipmi-sys;branch=master;protocol=https" -SRCREV = "9846023c7e811d6f831941d37270b10046916fef" +SRCREV = "e89296998b00d3e92361fdb37152a18566cf4505" FILES:${PN} += "${libdir}/ipmid-providers" diff --git a/meta-google/recipes-google/nanopb/nanopb-generator_0.4.8.bb b/meta-google/recipes-google/nanopb/nanopb-generator_0.4.8.bb deleted file mode 100644 index c86750f8b6..0000000000 --- a/meta-google/recipes-google/nanopb/nanopb-generator_0.4.8.bb +++ /dev/null @@ -1,14 +0,0 @@ -require nanopb.inc - -inherit python3-dir - -DEPENDS = "protobuf-native" -RDEPENDS:${PN} += "python3-protobuf" - -EXTRA_OECMAKE += " \ - -Dnanopb_PYTHON_INSTDIR_OVERRIDE=${PYTHON_SITEPACKAGES_DIR} \ - -Dnanopb_BUILD_RUNTIME=OFF \ - -Dnanopb_BUILD_GENERATOR=ON \ - " - -FILES:${PN} += "${PYTHON_SITEPACKAGES_DIR}" diff --git a/meta-google/recipes-google/nanopb/nanopb-runtime_0.4.8.bb b/meta-google/recipes-google/nanopb/nanopb-runtime_0.4.8.bb deleted file mode 100644 index e43931a4ec..0000000000 --- a/meta-google/recipes-google/nanopb/nanopb-runtime_0.4.8.bb +++ /dev/null @@ -1,17 +0,0 @@ -require nanopb.inc - -EXTRA_OECMAKE += " \ - -Dnanopb_PROTOC_PATH=/bin/false \ - -DBUILD_SHARED_LIBS=ON \ - -Dnanopb_BUILD_RUNTIME=ON \ - -Dnanopb_BUILD_GENERATOR=OFF \ - " - -# Maintain compatability with old header locations for packages -# which haven't yet migrated to `nanopb/pb*.h` -do_install:append() { - for hdr in ${D}${includedir}/nanopb/*; do - ln -sv nanopb/$(basename "$hdr") ${D}${includedir}/ - done -} - diff --git a/meta-google/recipes-google/nanopb/nanopb.bb b/meta-google/recipes-google/nanopb/nanopb.bb deleted file mode 100644 index 7ad6a32782..0000000000 --- a/meta-google/recipes-google/nanopb/nanopb.bb +++ /dev/null @@ -1,17 +0,0 @@ -SUMMARY = "Combined nanopb package" -PV = "1.0" -PR = "r1" - -PACKAGE_ARCH = "${MACHINE_ARCH}" - -inherit packagegroup - -DEPENDS = " \ - nanopb-generator \ - nanopb-runtime \ -" - -RDEPENDS:${PN} = " \ - nanopb-generator \ - nanopb-runtime \ -" diff --git a/meta-google/recipes-google/nanopb/nanopb.inc b/meta-google/recipes-google/nanopb/nanopb.inc deleted file mode 100644 index 87dbc73e63..0000000000 --- a/meta-google/recipes-google/nanopb/nanopb.inc +++ /dev/null @@ -1,13 +0,0 @@ -DESCRIPTION="Protocol Buffers with small code size" -LICENSE="Zlib" -LIC_FILES_CHKSUM = "file://LICENSE.txt;md5=9db4b73a55a3994384112efcdb37c01f" - -SRC_URI = "git://github.com/nanopb/nanopb.git;branch=master;protocol=https" -SRCREV = "6cfe48d6f1593f8fa5c0f90437f5e6522587745e" - -S = "${WORKDIR}/git" - -inherit cmake - -BBCLASSEXTEND = "native nativesdk" - diff --git a/meta-google/recipes-google/ncsi/files/gbmc-ncsi-br-deprecated-ips.sh.in b/meta-google/recipes-google/ncsi/files/gbmc-ncsi-br-deprecated-ips.sh.in index b392176483..c2783be525 100644 --- a/meta-google/recipes-google/ncsi/files/gbmc-ncsi-br-deprecated-ips.sh.in +++ b/meta-google/recipes-google/ncsi/files/gbmc-ncsi-br-deprecated-ips.sh.in @@ -15,6 +15,7 @@ [ -n "${gbmc_ncsi_br_deprecated_ips_lib-}" ] && return source /usr/share/network/lib.sh || exit +source /usr/share/gbmc-net-lib.sh || exit gbmc_ncsi_br_deprecated_ips_init= gbmc_ncsi_br_deprecated_ips_confip= @@ -22,6 +23,8 @@ gbmc_ncsi_br_deprecated_ips_lastip= gbmc_ncsi_br_deprecated_ips_lastncsi= gbmc_ncsi_br_deprecated_ips_confncsi= +GBMC_NCSI_ROUTE_TABLE=900 + gbmc_ncsi_br_deprecated_ips_update() { [ -n "$gbmc_ncsi_br_deprecated_ips_init" ] || return [ "$gbmc_ncsi_br_deprecated_ips_confip" != "$gbmc_ncsi_br_deprecated_ips_lastip" ] || \ @@ -62,6 +65,10 @@ IPv6ProxyNDPAddress=$pfx IPv6ProxyNDPAddress=$stateless_pfx ${host_pfx:+IPv6ProxyNDPAddress=}$host_pfx ${stateless_ip:+IPv6ProxyNDPAddress=}$stateless_ip +[RoutingPolicyRule] +From=$pfx/76 +Table=$GBMC_NCSI_ROUTE_TABLE +Priority=$GBMC_NCSI_ROUTE_TABLE EOF read -r -d '' nfcontents <<EOF table inet filter { @@ -86,14 +93,31 @@ EOF fi done - # Ensure that systemd-networkd performs a reconfiguration as it doesn't - # currently check the mtime of drop-in files. - touch -c /etc/systemd/network/*-bmc-@NCSI_IF@.network + # Remove all old ncsi neighbor proxied entries, since we solely + # manage all of these entries and we don't want any that are stale + local entry + while read -r entry; do + ip -6 neigh del proxy ${entry%% *} dev @NCSI_IF@ || true + done < <(ip -6 neigh show proxy dev @NCSI_IF@) + ip -6 rule del pref $GBMC_NCSI_ROUTE_TABLE 2>/dev/null || true - if [ "$(systemctl is-active systemd-networkd)" != 'inactive' ]; then - networkctl reload && networkctl reconfigure @NCSI_IF@ + local st=0 + if [ -n "$gbmc_ncsi_br_deprecated_ips_lastip" ]; then + sysctl net.ipv6.conf.@NCSI_IF@.proxy_ndp=1 >/dev/null || st=$? + ip -6 neigh add proxy $pfx dev @NCSI_IF@ || st=$? + ip -6 neigh add proxy $stateless_pfx dev @NCSI_IF@ || st=$? + if [ -n "$host_pfx" ]; then + ip -6 neigh add proxy $host_pfx dev @NCSI_IF@ || st=$? + fi + if [ -n "$stateless_ip" ]; then + ip -6 neigh add proxy $stateless_ip dev @NCSI_IF@ || st=$? + fi + ip -6 rule add pref $GBMC_NCSI_ROUTE_TABLE from $pfx/76 \ + lookup $GBMC_NCSI_ROUTE_TABLE || st=$? fi + (( st == 0 )) || gbmc_net_networkd_reload @NCSI_IF@ + local rfile=/run/nftables/40-gbmc-ncsi-br.rules mkdir -p -m 755 "$(dirname "$rfile")" if [ -z "$nfcontents" ]; then diff --git a/meta-google/recipes-google/ncsi/files/gbmc-ncsi-dhcrelay.service.in b/meta-google/recipes-google/ncsi/files/gbmc-ncsi-dhcrelay.service.in index 62a519a2da..c085cbcdec 100644 --- a/meta-google/recipes-google/ncsi/files/gbmc-ncsi-dhcrelay.service.in +++ b/meta-google/recipes-google/ncsi/files/gbmc-ncsi-dhcrelay.service.in @@ -3,11 +3,15 @@ Description=gBMC DHCP Relay Agent Daemon After=network.target StartLimitIntervalSec=10 StartLimitBurst=3 +LogRateLimitIntervalSec=120 +LogRateLimitBurst=100 [Service] +Environment="RP_FLAG=-rp 3967" +EnvironmentFile=-/run/gbmc-ncsi-dhcrelay.env Restart=always RestartSec=5 -ExecStart=/usr/sbin/dhcrelay -d --no-pid -rp 3967 -l gbmcncsidhcp -u ff02::1:2%%@NCSI_IF@ +ExecStart=/usr/sbin/dhcrelay -d --no-pid $RP_FLAG -l gbmcncsidhcp -u ff02::1:2%%@NCSI_IF@ [Install] WantedBy=multi-user.target diff --git a/meta-google/recipes-google/ncsi/files/gbmc-ncsi-ip-from-ra.service.in b/meta-google/recipes-google/ncsi/files/gbmc-ncsi-ip-from-ra.service.in deleted file mode 100644 index 82972fffce..0000000000 --- a/meta-google/recipes-google/ncsi/files/gbmc-ncsi-ip-from-ra.service.in +++ /dev/null @@ -1,15 +0,0 @@ -[Unit] -Description=gBMC NCSI RA Discovery -After=network.target -StartLimitIntervalSec=10 -StartLimitBurst=3 -Conflicts=nic-hostless@@NCSI_IF@.target -Conflicts=nic-hostful@@NCSI_IF@.target - -[Service] -Restart=always -RestartSec=5 -ExecStart=/usr/libexec/gbmc-ncsi-ip-from-ra.sh - -[Install] -WantedBy=multi-user.target 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 deleted file mode 100755 index 4aae5c86b3..0000000000 --- a/meta-google/recipes-google/ncsi/files/gbmc-ncsi-ip-from-ra.sh.in +++ /dev/null @@ -1,97 +0,0 @@ -#!/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. - -[ ! -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 -} - -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 - - # 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 - - # 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 diff --git a/meta-google/recipes-google/ncsi/files/gbmc-ncsi-ra.service.in b/meta-google/recipes-google/ncsi/files/gbmc-ncsi-ra.service.in new file mode 100644 index 0000000000..d389740b1f --- /dev/null +++ b/meta-google/recipes-google/ncsi/files/gbmc-ncsi-ra.service.in @@ -0,0 +1,15 @@ +[Unit] +Description=RA Gateway Updater +Wants=mapper-wait@-xyz-openbmc_project-network-@NCSI_IF@.service +After=mapper-wait@-xyz-openbmc_project-network-@NCSI_IF@.service +After=ncsid@NCSI_IF@.service +StartLimitIntervalSec=1min +StartLimitBurst=5 + +[Service] +Restart=always +RestartSec=5 +ExecStart=/usr/libexec/gbmc-ncsi-ra.sh @NCSI_IF@ + +[Install] +WantedBy=multi-user.target diff --git a/meta-google/recipes-google/ncsi/files/gbmc-ncsi-ra.sh b/meta-google/recipes-google/ncsi/files/gbmc-ncsi-ra.sh new file mode 100644 index 0000000000..ca8fa05caa --- /dev/null +++ b/meta-google/recipes-google/ncsi/files/gbmc-ncsi-ra.sh @@ -0,0 +1,91 @@ +#!/bin/bash +# Copyright 2024 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/gbmc-net-common/gbmc-net-lib.sh +source /usr/share/gbmc-net-lib.sh || exit + +RA_IF=$1 +IP_OFFSET=1 +# NCSI is known to be closer to the ToR than bridge routes. Prefer over bridge routes. +ROUTE_METRIC=900 +ROUTE_TABLE=900 + +update_rtr() { + busctl set-property xyz.openbmc_project.Network /xyz/openbmc_project/network/"$RA_IF" \ + xyz.openbmc_project.Network.EthernetInterface DefaultGateway6 s "" || true + + default_update_rtr "$@" + + # Add additional gateway information + for file in /run/systemd/network/{00,}-bmc-$RA_IF.network; do + mkdir -p "$file.d" + printf '[Route]\nGateway=%s\nGatewayOnLink=true\nTable=%d' \ + "$rtr" "$ROUTE_TABLE" >"$file.d"/10-gateway-table.conf + done + + ip -6 route replace default via "$rtr" onlink dev "$RA_IF" table "$ROUTE_TABLE" || \ + gbmc_net_networkd_reload "$RA_IF" +} + +ncsi_is_active() { + systemctl is-active -q nic-hostless@"$RA_IF".target && return + systemctl is-active -q nic-hostful@"$RA_IF".target && return + return 1 +} + +update_fqdn() { + true +} + +old_ncsi_pfx= + +update_pfx() { + local pfx="$1" + + # We only do this for smartNICs (which don't use NCSI) + ncsi_is_active && return + + # Don't change anything for an empty prefix + [ -z "$pfx" ] && return + + # We no longer need NCSId if we are in this configuration + systemctl stop --no-block ncsid@"$RA_IF" || true + + # DHCP Relay workaround until alternate source port is supported + # TODO: Remove this once internal relaying cleanups land + gbmc-ncsi-smartnic-wa.sh || true + + # Override any existing address information within files + # Make sure we cover `00-*` and `-*` files + for file in /run/systemd/network/{00,}-bmc-gbmcbr.network; do + mkdir -p "$file.d" + printf '[Network]\nAddress=%s/128' \ + "$pfx" >"$file.d"/10-ncsi-addr.conf + done + + # Don't force networkd to reload as this can break phosphor-networkd + # Fall back to reload only if ip link commands fail + if [ -n "$old_ncsi_pfx" ]; then + ip -6 addr del "$old_ncsi_pfx/128" dev gbmcbr || true + fi + ip -6 addr replace "$pfx/128" dev gbmcbr || \ + gbmc_net_networkd_reload gbmcbr || true + old_ncsi_pfx=$pfx + + echo "Set NCSI addr $pfx on gbmcbr" >&2 +} + +# shellcheck source=meta-google/recipes-google/networking/gbmc-net-common/gbmc-ra.sh +source /usr/share/gbmc-ra.sh || exit diff --git a/meta-google/recipes-google/ncsi/files/gbmc-ncsi-smartnic-wa.sh.in b/meta-google/recipes-google/ncsi/files/gbmc-ncsi-smartnic-wa.sh.in index 88f52d38e8..c05e239f7f 100644 --- a/meta-google/recipes-google/ncsi/files/gbmc-ncsi-smartnic-wa.sh.in +++ b/meta-google/recipes-google/ncsi/files/gbmc-ncsi-smartnic-wa.sh.in @@ -13,34 +13,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -HAS_DHCRELAY='@GBMC_NCSI_DHCP_RELAY@' +HAS_DHCRELAY='@GBMC_DHCP_RELAY@' if [ "$HAS_DHCRELAY" = 1 ]; then - override=/run/systemd/system/gbmc-ncsi-dhcrelay.service.d/10-nosp.conf - mkdir -p "$(dirname "$override")" - echo '[Service]' >"$override" - echo 'ExecStart=' >>"$override" # Remove the source relay port from the relay, bringing it back to run on # the default port 547. Our relays don't support the source port option needed # to run on 3967 for our legacy NICs. - grep '^ExecStart=' /lib/systemd/system/gbmc-ncsi-dhcrelay.service | \ - sed 's, -rp 3967,,' >>"$override" -fi - -override=/run/systemd/system/gbmc-br-dhcp.service.d/10-direct.conf -mkdir -p "$(dirname "$override")" -echo '[Service]' >"$override" -echo 'ExecStart=' >>"$override" -# Switch the gbmcbr interface for the NCSI one to avoid passing the SOLICIT -# message through the BMC relay. -grep '^ExecStart=' /lib/systemd/system/gbmc-br-dhcp.service | \ - sed 's, -i gbmcbr, -i @NCSI_IF@,' >>"$override" - -systemctl daemon-reload -if [ "$HAS_DHCRELAY" = 1 ]; then + echo 'RP_FLAG=' >/run/gbmc-ncsi-dhcrelay.env systemctl reset-failed gbmc-ncsi-dhcrelay systemctl restart --no-block gbmc-ncsi-dhcrelay fi + +echo 'INTF=@NCSI_IF@' >/run/gbmc-br-dhcp.env systemctl reset-failed gbmc-br-dhcp systemctl restart --no-block gbmc-br-dhcp diff --git a/meta-google/recipes-google/ncsi/gbmc-ncsi-config.bb b/meta-google/recipes-google/ncsi/gbmc-ncsi-config.bb index 29ec5bd19e..aac9935642 100644 --- a/meta-google/recipes-google/ncsi/gbmc-ncsi-config.bb +++ b/meta-google/recipes-google/ncsi/gbmc-ncsi-config.bb @@ -5,20 +5,20 @@ LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5 inherit systemd -GBMC_NCSI_DHCP_RELAY ??= "${@'' if int(d.getVar('FLASH_SIZE')) < 65536 else '1'}" +GBMC_DHCP_RELAY ??= "${@'' if int(d.getVar('FLASH_SIZE')) < 65536 else '1'}" GBMC_NCSI_IF_OLD ??= "" GBMC_NCSI_PURGE_ETC ??= "" GBMC_NCSI_DHCP_IMPERSONATE_HOST ??= "1" SRC_URI += " \ - ${@'' if d.getVar('GBMC_NCSI_DHCP_RELAY') != '1' else 'file://-bmc-gbmcbrncsidhcp.netdev'} \ - ${@'' if d.getVar('GBMC_NCSI_DHCP_RELAY') != '1' else 'file://-bmc-gbmcbrncsidhcp.network'} \ - ${@'' if d.getVar('GBMC_NCSI_DHCP_RELAY') != '1' else 'file://-bmc-gbmcncsidhcp.netdev'} \ - ${@'' if d.getVar('GBMC_NCSI_DHCP_RELAY') != '1' else 'file://-bmc-gbmcncsidhcp.network'} \ + ${@'' if d.getVar('GBMC_DHCP_RELAY') != '1' else 'file://-bmc-gbmcbrncsidhcp.netdev'} \ + ${@'' if d.getVar('GBMC_DHCP_RELAY') != '1' else 'file://-bmc-gbmcbrncsidhcp.network'} \ + ${@'' if d.getVar('GBMC_DHCP_RELAY') != '1' else 'file://-bmc-gbmcncsidhcp.netdev'} \ + ${@'' if d.getVar('GBMC_DHCP_RELAY') != '1' else 'file://-bmc-gbmcncsidhcp.network'} \ file://50-gbmc-ncsi.rules.in \ - ${@'' if d.getVar('GBMC_NCSI_DHCP_RELAY') != '1' else 'file://gbmc-ncsi-dhcrelay.service.in'} \ - file://gbmc-ncsi-ip-from-ra.service.in \ - file://gbmc-ncsi-ip-from-ra.sh.in \ + ${@'' if d.getVar('GBMC_DHCP_RELAY') != '1' else 'file://gbmc-ncsi-dhcrelay.service.in'} \ + file://gbmc-ncsi-ra.service.in \ + file://gbmc-ncsi-ra.sh \ file://gbmc-ncsi-smartnic-wa.sh.in \ file://gbmc-ncsi-sslh.socket.in \ file://gbmc-ncsi-sslh.service \ @@ -36,13 +36,13 @@ S = "${WORKDIR}" RDEPENDS:${PN} += " \ bash \ - ${@'' if d.getVar('GBMC_NCSI_DHCP_RELAY') != '1' else 'dhcp-relay'} \ + ${@'' if d.getVar('GBMC_DHCP_RELAY') != '1' else 'dhcp-relay'} \ gbmc-ip-monitor \ + gbmc-net-common \ ncsid \ network-sh \ nftables-systemd \ sslh \ - ndisc6-rdisc6 \ " FILES:${PN} += " \ @@ -52,11 +52,11 @@ FILES:${PN} += " \ " SYSTEMD_SERVICE:${PN} += " \ - ${@'' if d.getVar('GBMC_NCSI_DHCP_RELAY') != '1' else 'gbmc-ncsi-dhcrelay.service'} \ + ${@'' if d.getVar('GBMC_DHCP_RELAY') != '1' else 'gbmc-ncsi-dhcrelay.service'} \ gbmc-ncsi-sslh.service \ gbmc-ncsi-sslh.socket \ gbmc-ncsi-set-nicenabled.service \ - gbmc-ncsi-ip-from-ra.service \ + gbmc-ncsi-ra.service \ ${@'' if d.getVar('GBMC_NCSI_IF_OLD') == '' else 'gbmc-ncsi-old.service'} \ ${@'' if d.getVar('GBMC_NCSI_PURGE_ETC') == '' else 'gbmc-ncsi-purge.service'} \ " @@ -74,7 +74,7 @@ do_install:append() { echo "net.ipv6.conf.$if_name.dad_transmits=0" \ >>${D}${sysconfdir}/sysctl.d/25-gbmc-ncsi.conf - if [ "${GBMC_NCSI_DHCP_RELAY}" = 1 ]; then + if [ "${GBMC_DHCP_RELAY}" = 1 ]; then install -d -m0755 ${D}${systemd_unitdir}/network install -m0644 ${WORKDIR}/-bmc-gbmcbrncsidhcp.netdev \ ${D}${systemd_unitdir}/network/ @@ -136,7 +136,7 @@ do_install:append() { sed "s,@NCSI_IF@,$if_name,g" ${WORKDIR}/gbmc-ncsi-set-nicenabled.service.in \ >${D}${systemd_system_unitdir}/gbmc-ncsi-set-nicenabled.service - if [ "${GBMC_NCSI_DHCP_RELAY}" = "1" ]; then + if [ "${GBMC_DHCP_RELAY}" = "1" ]; then sed "s,@NCSI_IF@,$if_name,g" ${WORKDIR}/gbmc-ncsi-dhcrelay.service.in \ >${D}${systemd_system_unitdir}/gbmc-ncsi-dhcrelay.service fi @@ -151,15 +151,13 @@ do_install:append() { >${D}${systemd_system_unitdir}/gbmc-ncsi-purge.service fi - sed "s,@NCSI_IF@,$if_name,g" ${WORKDIR}/gbmc-ncsi-ip-from-ra.service.in \ - >${WORKDIR}/gbmc-ncsi-ip-from-ra.service - install -m0644 ${WORKDIR}/gbmc-ncsi-ip-from-ra.service ${D}${systemd_system_unitdir} - sed "s,@NCSI_IF@,$if_name,g" ${WORKDIR}/gbmc-ncsi-ip-from-ra.sh.in \ - >${WORKDIR}/gbmc-ncsi-ip-from-ra.sh + sed "s,@NCSI_IF@,$if_name,g" ${WORKDIR}/gbmc-ncsi-ra.service.in \ + >${WORKDIR}/gbmc-ncsi-ra.service + install -m0644 ${WORKDIR}/gbmc-ncsi-ra.service ${D}${systemd_system_unitdir} install -d -m0755 ${D}${libexecdir} - install -m0755 ${WORKDIR}/gbmc-ncsi-ip-from-ra.sh ${D}${libexecdir}/ + install -m0755 ${WORKDIR}/gbmc-ncsi-ra.sh ${D}${libexecdir}/ - sed -e "s,@NCSI_IF@,$if_name,g" -e "s,@GBMC_NCSI_DHCP_RELAY@,${GBMC_NCSI_DHCP_RELAY},g" \ + sed -e "s,@NCSI_IF@,$if_name,g" -e "s,@GBMC_DHCP_RELAY@,${GBMC_DHCP_RELAY},g" \ ${WORKDIR}/gbmc-ncsi-smartnic-wa.sh.in >${WORKDIR}/gbmc-ncsi-smartnic-wa.sh install -d -m0755 ${D}${bindir} install -m0755 ${WORKDIR}/gbmc-ncsi-smartnic-wa.sh ${D}${bindir}/ diff --git a/meta-google/recipes-google/ncsi/ncsid_git.bb b/meta-google/recipes-google/ncsi/ncsid_git.bb index 12a8d03407..d746c278cd 100644 --- a/meta-google/recipes-google/ncsi/ncsid_git.bb +++ b/meta-google/recipes-google/ncsi/ncsid_git.bb @@ -11,16 +11,9 @@ EXTRA_OEMESON = " \ " SYSTEMD_SERVICE:${PN} += " \ - dhcp4@.service \ - dhcp6@.service \ ncsid@.service \ nic-hostful@.target \ nic-hostless@.target \ - update-ra-gw@.service \ - update-ra-neighbor@.service \ - update-ra-neighbor@.timer \ - update-static-neighbors@.service \ - update-static-neighbors@.timer \ " DEPENDS += " \ @@ -37,3 +30,9 @@ RDEPENDS:${PN} += " \ ndisc6-rdisc6 \ systemd \ " + +# TODO: Remove when package is bumped to formally delete this service +do_install:append() { + rm ${D}${systemd_system_unitdir}/update-ra-gw@.service + rm ${D}${libexecdir}/update_ra_gw.sh +} diff --git a/meta-google/recipes-google/networking/dhcp-done_git.bb b/meta-google/recipes-google/networking/dhcp-done_git.bb index 12e3903837..2cc9b95c88 100644 --- a/meta-google/recipes-google/networking/dhcp-done_git.bb +++ b/meta-google/recipes-google/networking/dhcp-done_git.bb @@ -4,9 +4,12 @@ GOOGLE_MISC_PROJ = "dhcp-done" require ../google-misc/google-misc.inc +EXTRA_OEMESON = " \ + -Dtests=disabled \ + " inherit systemd -SYSTEMD_SERVICE:${PN} += "dhcp-done@.service" +SYSTEMD_SERVICE:${PN} += "dhcp-done.service" DEPENDS += " \ sdeventplus \ diff --git a/meta-google/recipes-google/networking/gbmc-bridge.bb b/meta-google/recipes-google/networking/gbmc-bridge.bb index 3f20530291..0a6f40eda7 100644 --- a/meta-google/recipes-google/networking/gbmc-bridge.bb +++ b/meta-google/recipes-google/networking/gbmc-bridge.bb @@ -15,12 +15,15 @@ SRC_URI += " \ file://50-gbmc-br.rules \ file://gbmc-br-ula.sh \ file://gbmc-br-from-ra.sh \ - file://gbmc-br-ensure-ra.sh \ - file://gbmc-br-ensure-ra.service \ + file://gbmc-br-hostname.sh \ + file://gbmc-br-hostname.service \ + file://gbmc-br-ra.sh.in \ + file://gbmc-br-ra.service \ file://gbmc-br-gw-src.sh \ file://gbmc-br-nft.sh \ file://gbmc-br-dhcp.sh \ - file://50-gbmc-psu-hardreset.sh \ + file://50-gbmc-psu-hardreset.sh.in \ + file://51-gbmc-reboot.sh \ file://gbmc-br-dhcp.service \ file://gbmc-br-dhcp-term.sh \ file://gbmc-br-dhcp-term.service \ @@ -42,25 +45,38 @@ RDEPENDS:${PN}:append = " \ bash \ dhcp-done \ gbmc-ip-monitor \ + gbmc-net-common \ network-sh \ ndisc6-rdisc6 \ nftables-systemd \ " SYSTEMD_SERVICE:${PN} += " \ - gbmc-br-ensure-ra.service \ + gbmc-br-hostname.service \ gbmc-br-dhcp.service \ gbmc-br-dhcp-term.service \ gbmc-br-load-ip.service \ + gbmc-br-ra.service \ " GBMC_BR_MAC_ADDR ?= "" +# Enables the assignment of IP address and hostname by discovering the +# machine name and BMC prefix from another BMC on the bridge network. +# This is intended only to be used when there is a single expansion tray +# on the BMC network. If more than one machine uses this feature with the +# same offset in the same machine network, it will collide with others. +# A value of 0 implies that this feature is disabled. +GBMC_BR_FIXED_OFFSET ?= "0" + # Generated via https://cd34.com/rfc4193/ based on a MAC from a machine I own # and we allocated it downstream. Intended to only be used within a complete # system of multiple network endpoints. GBMC_ULA_PREFIX = "fdb5:0481:10ce:0" +# coordinated powercycle +GBMC_COORDINATED_POWERCYCLE ?= "true" + def mac_to_eui64(mac): if not mac: return '' @@ -122,21 +138,28 @@ do_install() { install -m0644 ${WORKDIR}/gbmc-br-nft.sh "$mondir"/ install -d -m0755 ${D}${libexecdir} - install -m0755 ${WORKDIR}/gbmc-br-ensure-ra.sh ${D}${libexecdir}/ + install -m0755 ${WORKDIR}/gbmc-br-hostname.sh ${D}${libexecdir}/ install -m0755 ${WORKDIR}/gbmc-br-dhcp.sh ${D}${libexecdir}/ install -m0755 ${WORKDIR}/gbmc-br-dhcp-term.sh ${D}${libexecdir}/ install -d -m0755 ${D}${systemd_system_unitdir} - install -m0644 ${WORKDIR}/gbmc-br-ensure-ra.service ${D}${systemd_system_unitdir}/ + install -m0644 ${WORKDIR}/gbmc-br-hostname.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 + + sed 's,@COORDINATED_POWERCYCLE@,${GBMC_COORDINATED_POWERCYCLE},' ${WORKDIR}/50-gbmc-psu-hardreset.sh.in >${WORKDIR}/50-gbmc-psu-hardreset.sh install -m0644 ${WORKDIR}/50-gbmc-psu-hardreset.sh ${D}${datadir}/gbmc-br-dhcp/ + install -m0644 ${WORKDIR}/51-gbmc-reboot.sh ${D}${datadir}/gbmc-br-dhcp/ install -m0644 ${WORKDIR}/gbmc-br-lib.sh ${D}${datadir}/ install -d ${D}/${bindir} install -m0755 ${WORKDIR}/gbmc-start-dhcp.sh ${D}${bindir}/ + + sed 's,@IP_OFFSET@,${GBMC_BR_FIXED_OFFSET},' ${WORKDIR}/gbmc-br-ra.sh.in >${WORKDIR}/gbmc-br-ra.sh + install -m0755 ${WORKDIR}/gbmc-br-ra.sh ${D}${libexecdir}/ + install -m0644 ${WORKDIR}/gbmc-br-ra.service ${D}${systemd_system_unitdir}/ } 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 d77557e8e3..dab65a91b2 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 @@ -6,10 +6,18 @@ IPv6AcceptRA=true LLMNR=true MulticastDNS=true LinkLocalAddressing=ipv6 -IPv6PrefixDelegation=yes +IPv6SendRA=yes @ADDR@ [IPv6AcceptRA] DHCPv6Client=false RouteMetric=1056 -[IPv6PrefixDelegation] +[IPv6SendRA] RouterLifetimeSec=0 +[RoutingPolicyRule] +To=fdb5:481:10ce::/64 +Table=main +Priority=500 +[RoutingPolicyRule] +To=fe80::/64 +Table=main +Priority=500 diff --git a/meta-google/recipes-google/networking/gbmc-bridge/50-gbmc-psu-hardreset.sh b/meta-google/recipes-google/networking/gbmc-bridge/50-gbmc-psu-hardreset.sh.in index c0974a00d1..588efcb351 100644 --- a/meta-google/recipes-google/networking/gbmc-bridge/50-gbmc-psu-hardreset.sh +++ b/meta-google/recipes-google/networking/gbmc-bridge/50-gbmc-psu-hardreset.sh.in @@ -17,6 +17,8 @@ gbmc_psu_hardreset_needed= +COORDINATED_POWERCYCLE=@COORDINATED_POWERCYCLE@ + gbmc_psu_hardreset_hook() { # We don't always need a powercycle, allow skipping if [ -z "${gbmc_psu_hardreset_needed-}" ]; then @@ -24,8 +26,13 @@ gbmc_psu_hardreset_hook() { return 0 fi - echo "Powercycling" >&2 - systemctl start gbmc-psu-hardreset.target || return + if [[ "${COORDINATED_POWERCYCLE}" == "true" ]]; then + echo "Requesting powercycle" >&2 + update-dhcp-status 'POWERCYCLE' "netboot powercycle" || return + else + echo "Powercycling" >&2 + systemctl start gbmc-psu-hardreset.target || return + fi # Ensure that we don't continue the DHCP process while waiting for the # powercycle. diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ensure-ra.sh b/meta-google/recipes-google/networking/gbmc-bridge/51-gbmc-reboot.sh index 60e33d89b3..41dd883d06 100644 --- a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ensure-ra.sh +++ b/meta-google/recipes-google/networking/gbmc-bridge/51-gbmc-reboot.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2021 Google LLC +# Copyright 2024 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,15 +13,23 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Every 30 seconds, send out an RA so that the kernel will receive a response. -# This ensures that all BMCs (even ones that think they are routers) get updated -# information from the other systems on the network. -w=30 -while true; do - start=$SECONDS - rdisc6 -m gbmcbr -r 1 -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 +[ -n "${gbmc_reboot-}" ] && return + +gbmc_reboot_needed= + +gbmc_reboot_hook() { + # We don't always need a warm reset, allow skipping + if [ -z "${gbmc_reboot_needed-}" ]; then + echo "Skipping bmc reboot" >&2 + return 0 + fi + + update-dhcp-status 'ONGOING' "triggerring bmc reboot" + + reboot -f + exit 0 +} + +GBMC_BR_DHCP_HOOKS+=(gbmc_reboot_hook) + +gbmc_reboot=1 diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-dhcp.service b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-dhcp.service index 60ea0fb9ea..48f53abde7 100644 --- a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-dhcp.service +++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-dhcp.service @@ -1,14 +1,17 @@ [Unit] Description=gBMC DHCP Client -After=network.target +After=network.target dhcp-done.service +Wants=dhcp-done.service StartLimitIntervalSec=10 StartLimitBurst=3 [Service] +Environment=INTF=gbmcbr +EnvironmentFile=-/run/gbmc-br-dhcp.env Restart=on-failure RestartSec=5 -ExecCondition=/bin/bash -c "! /bin/systemctl is-active -q dhcp-done@*" -ExecStart=/usr/bin/udhcpc6 -f -q -O fqdn -O bootfile_url -O bootfile_param -i gbmcbr -s /usr/libexec/gbmc-br-dhcp.sh +ExecStartPre=/usr/bin/update-dhcp-status 'ONGOING' 'Starting dhcp process' +ExecStart=/usr/bin/udhcpc6 -f -q -O fqdn -O bootfile_url -O bootfile_param -i $INTF -s /usr/libexec/gbmc-br-dhcp.sh [Install] WantedBy=multi-user.target 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 4360e11277..c31090b656 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 @@ -42,21 +42,26 @@ if [ "$1" = bound ]; then # shellcheck disable=SC2154 echo "DHCPv6(gbmcbr): $ipv6/128" >&2 + update-dhcp-status 'ONGOING' "Received dhcp response ${ipv6}" pfx_bytes=() ip_to_bytes pfx_bytes "$ipv6" # 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 + echo "Invalid address prefix ${ipv6}" >&2 + update-dhcp-status 'ONGOING' "Invalid address prefix ${ipv6}" 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 + echo "Invalid address ${ipv6}" >&2 + update-dhcp-status 'ONGOING' "Invalid address ${ipv6}" exit 1 fi done + update-dhcp-status 'ONGOING' "Setting hostname ${fqdn} and ip ${ipv6}" + pfx="$(ip_bytes_to_str pfx_bytes)" gbmc_br_set_ip "$pfx" || exit @@ -70,11 +75,13 @@ if [ "$1" = bound ]; then # If any of our hooks had expectations we should fail here if [ "${#GBMC_BR_DHCP_OUTSTANDING[@]}" -gt 0 ]; then echo "Not done with DHCP process: ${!GBMC_BR_DHCP_OUTSTANDING[*]}" >&2 + update-dhcp-status 'ONGOING' "Outstanding DHCP hooks ${!GBMC_BR_DHCP_OUTSTANDING[*]}" exit 1 fi # Ensure that the installer knows we have completed processing DHCP by # running a service that reports completion - echo 'Start DHCP Done' >&2 - systemctl start dhcp-done@DONE --no-block + echo 'Signaling dhcp done' >&2 + update-dhcp-status 'DONE' "Netboot finished" + fi diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ensure-ra.service b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ensure-ra.service deleted file mode 100644 index 7f97cea48d..0000000000 --- a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ensure-ra.service +++ /dev/null @@ -1,5 +0,0 @@ -[Service] -ExecStart=/usr/libexec/gbmc-br-ensure-ra.sh - -[Install] -WantedBy=multi-user.target diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-gw-src.sh b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-gw-src.sh index 3c57b66af3..5865946e04 100644 --- a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-gw-src.sh +++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-gw-src.sh @@ -17,9 +17,10 @@ # 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-net-common/gbmc-net-lib.sh +source /usr/share/gbmc-net-lib.sh || exit -gbmc_br_gw_src_ip_stateful= -gbmc_br_gw_src_ip_stateless= +declare -A gbmc_br_gw_src_ips=() declare -A gbmc_br_gw_src_routes=() gbmc_br_gw_defgw= @@ -32,6 +33,11 @@ gbmc_br_set_router() { break fi done + # Make becoming a router sticky, if we ever have a default route we are + # always treated as a router. Otherwise, we end up reloading unnecessarily + # a number of times. The reload causes the network configuration to be + # reappplied with packet drops for a short amount of time. + [[ -z $defgw ]] && return [[ $defgw == "$gbmc_br_gw_defgw" ]] && return gbmc_br_gw_defgw="$defgw" @@ -40,27 +46,44 @@ gbmc_br_set_router() { local file for file in "${files[@]}"; do mkdir -p "$(dirname "$file")" - printf '[IPv6PrefixDelegation]\nRouterLifetimeSec=30\n' >"$file" + printf '[IPv6SendRA]\nRouterLifetimeSec=120\n' >"$file" done else rm -f "${files[@]}" fi - if [[ $(systemctl is-active systemd-networkd) != inactive ]]; then - networkctl reload && networkctl reconfigure gbmcbr - fi + # shellcheck disable=SC2119 + gbmc_net_networkd_reload } gbmc_br_gw_src_update() { - local gbmc_br_gw_src_ip="${gbmc_br_gw_src_ip_stateful:-$gbmc_br_gw_src_ip_stateless}" - [[ -n $gbmc_br_gw_src_ip ]] || return + # Pick the shortest address, we always want to use the most root level + # The order of preference looks roughly like + # 1. Root /64 address (2620:15c:2c3:aaae::/64) + # This is generally used by the OOB RJ45 port and is our primary preference + # 2. BMC subordonate root (2620:15c:2c3:aaae:fd01::/80) + # From the NIC over NCSI with the /64 shared with the CN + # 3. BMC stateless (2620:15c:2c3:aaae:fd00:3c8d:20dc:263e/80) + # From the NIC, but derived from the MAC and typically never used + # + local new_src= + local new_len=16 + local ip + for ip in "${!gbmc_br_gw_src_ips[@]}"; do + local ip_len="${gbmc_br_gw_src_ips["$ip"]}" + if (( ip_len < new_len )); then + new_src="$ip" + new_len="$ip_len" + fi + done + (( new_len >= 16 )) && return local route for route in "${!gbmc_br_gw_src_routes[@]}"; do - [[ $route != *" src $gbmc_br_gw_src_ip "* ]] || continue - echo "gBMC Bridge Updating GW source [$gbmc_br_gw_src_ip]: $route" >&2 + [[ $route != *" src $new_src "* ]] || continue + echo "gBMC Bridge Updating GW source [$new_src]: $route" >&2 # shellcheck disable=SC2086 - ip route change $route src "$gbmc_br_gw_src_ip" && \ + ip route change $route src "$new_src" && \ unset 'gbmc_br_gw_src_routes[$route]' done } @@ -83,8 +106,8 @@ gbmc_br_gw_src_hook() { gbmc_br_gw_src_update gbmc_br_set_router fi - # Match only global IP addresses on the bridge that match the BMC stateless - # prefix (<mpfx>:fd00:). So 2002:af4:3480:2248:fd00:6345:3069:9186 would be + # Match only global IP addresses on the bridge that are non-ULA addresses. + # So 2002:af4:3480:2248:fd00:6345:3069:9186 would be # matched as the preferred source IP for outoging traffic. elif [[ $change == addr && $intf == gbmcbr && $scope == global ]] && [[ $fam == inet6 && $flags != *tentative* ]]; then @@ -93,22 +116,23 @@ gbmc_br_gw_src_hook() { echo "gBMC Bridge Ensure RA Invalid IP: $ip" >&2 return 1 fi - # Ignore ULAs and non-gBMC addresses - if (( (ip_bytes[0] & 0xfe) == 0xfc || ip_bytes[8] != 0xfd )); then + # Ignore ULAs + if (( (ip_bytes[0] & 0xfe) == 0xfc )); then return 0 fi - if (( (ip_bytes[9] & 0xf) != 0 )); then - local -n gbmc_br_gw_src_ip=gbmc_br_gw_src_ip_stateful - else - local -n gbmc_br_gw_src_ip=gbmc_br_gw_src_ip_stateless - fi - if [[ $action == add && $ip != "$gbmc_br_gw_src_ip" ]]; then - gbmc_br_gw_src_ip="$ip" - gbmc_br_gw_src_update - fi - if [[ $action == del && $ip == "$gbmc_br_gw_src_ip" ]]; then - gbmc_br_gw_src_ip= + if [[ $action == add ]]; then + local i=0 + local non_zero=0 + for (( i=0; i<16; ++i )); do + if (( ip_bytes[i] != 0 )); then + non_zero="$i" + fi + done + gbmc_br_gw_src_ips["$ip"]="$non_zero" + elif [[ $action == del ]]; then + unset 'gbmc_br_gw_src_ips[$ip]' fi + gbmc_br_gw_src_update fi } diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-hostname.service b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-hostname.service new file mode 100644 index 0000000000..9841419454 --- /dev/null +++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-hostname.service @@ -0,0 +1,8 @@ +[Unit] +Before=systemd-networkd.service + +[Service] +ExecStart=/usr/libexec/gbmc-br-hostname.sh + +[Install] +WantedBy=multi-user.target diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-hostname.sh b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-hostname.sh new file mode 100755 index 0000000000..d680e148f4 --- /dev/null +++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-hostname.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# Copyright 2024 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/gbmc-net-common/gbmc-net-lib.sh +source /usr/share/gbmc-net-lib.sh || exit + +oldname= +while read -r _; do + # Don't bother parsing the output, just read the final hostname + name="$(</etc/hostname)" || continue + [[ "$oldname" == "$name" ]] && continue + oldname="$name" + echo "Updating BMC RA Hostname $name" >&2 + + contents='[IPv6SendRA]'$'\n'"Domains=$name" + for netfile in /run/systemd/network/{00,}-bmc-gbmcbr.network.d/60-domains.conf; do + mkdir -p "$(dirname "$netfile")" + printf '%s' "$contents" >"$netfile" + done + + # shellcheck disable=SC2119 + gbmc_net_networkd_reload +done < <(dbus-monitor --system "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',arg0='org.freedesktop.hostname1'") 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 index 1b31ef9f6f..912a3c119d 100644 --- a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-lib.sh +++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-lib.sh @@ -15,9 +15,10 @@ [ -n "${gbmc_br_lib_init-}" ] && return -# SC can't find this path during repotest -# shellcheck disable=SC1091 +# 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-net-common/gbmc-net-lib.sh +source /usr/share/gbmc-net-lib.sh || exit # A list of functions which get executed for each configured IP. # These are configured by the files included below. @@ -49,16 +50,10 @@ gbmc_br_run_hooks() { 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_net_networkd_reload gbmcbr } gbmc_br_reload_ip() { @@ -91,11 +86,11 @@ gbmc_br_reload_ip() { Address=$pfx/128 [IPv6Prefix] Prefix=$stateless_pfx/80 -PreferredLifetimeSec=60 -ValidLifetimeSec=60 +PreferredLifetimeSec=120 +ValidLifetimeSec=120 [IPv6RoutePrefix] Route=$pfx/80 -LifetimeSec=60 +LifetimeSec=120 [Route] Destination=$stateless_pfx/76 Type=unreachable @@ -109,7 +104,7 @@ EOF printf '%s' "$contents" >"$file" done - gbmc_br_reload + gbmc_net_networkd_reload gbmcbr } gbmc_br_set_ip() { diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-nft.sh b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-nft.sh index 7aa2158989..79ea76f974 100644 --- a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-nft.sh +++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-nft.sh @@ -57,8 +57,11 @@ gbmc_br_nft_hook() { if (( ip_bytes[8] != 0xfd )); then return 0 fi + + (( ip_bytes[9] &= 0xf0 )) + local i - for (( i=9; i<16; i++ )); do + for (( i=10; i<16; i++ )); do ip_bytes["$i"]=0 done pfx="$(ip_bytes_to_str ip_bytes)/76" diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ra.service b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ra.service new file mode 100644 index 0000000000..08fd15fa4f --- /dev/null +++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ra.service @@ -0,0 +1,13 @@ +[Unit] +Description=gBMC Bridge RA Discovery +After=network.target +StartLimitIntervalSec=10 +StartLimitBurst=3 + +[Service] +Restart=always +RestartSec=5 +ExecStart=/usr/libexec/gbmc-br-ra.sh + +[Install] +WantedBy=multi-user.target diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ra.sh.in b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ra.sh.in new file mode 100755 index 0000000000..66d7a7d2da --- /dev/null +++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ra.sh.in @@ -0,0 +1,42 @@ +#!/bin/bash +# Copyright 2024 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/gbmc-bridge/gbmc-br-lib.sh +source /usr/share/gbmc-br-lib.sh || exit + +update_rtr() { + true +} + +update_fqdn() { + (( IP_OFFSET == 0 )) && return + default_update_fqdn "$@" +} + +update_pfx() { + local pfx="$1" + (( IP_OFFSET == 0 )) && return + gbmc_br_set_ip "$pfx" || true + echo "IP $pfx set on $RA_IF" >&2 +} + +RA_IF=gbmcbr +IP_OFFSET=@IP_OFFSET@ +# Use the lowest priority, except for kernel RA discovered routes. +# We want closer NICs to provide a default route if existing. +ROUTE_METRIC=1000 + +# shellcheck source=meta-google/recipes-google/networking/gbmc-net-common/gbmc-ra.sh +source /usr/share/gbmc-ra.sh || exit diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ula.sh b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ula.sh index 42bb566c8a..b79e25fe4a 100644 --- a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ula.sh +++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ula.sh @@ -18,53 +18,81 @@ # shellcheck source=meta-google/recipes-google/networking/network-sh/lib.sh source /usr/share/network/lib.sh || exit -gbmc_br_ula_init= -gbmc_br_ula_mac= +declare -A gbmc_br_ulas=() -gbmc_br_ula_update() { - [[ -n $gbmc_br_ula_init ]] || return +# BITs set for address suffixes +GBMC_BR_ULA_SFX_HAS_LL=1 +GBMC_BR_ULA_SFX_HAS_ULA=2 - echo "gBMC Bridge ULA MAC: ${gbmc_br_ula_mac:-(deleted)}" >&2 - - local addr= - contents='[Network]'$'\n' - if [[ -n $gbmc_br_ula_mac ]]; then - local sfx - if sfx="$(mac_to_eui64 "$gbmc_br_ula_mac")" && - addr="$(ip_pfx_concat "fdb5:0481:10ce::/64" "$sfx")"; then - contents+="Address=$addr"$'\n' +gbmc_br_ula_cleanup() { + local addr + for addr in "${!gbmc_br_ulas[@]}"; do + local val="${gbmc_br_ulas["$addr"]}" + if (( val & GBMC_BR_ULA_SFX_HAS_LL == 0 )); then + echo "Removing Stale ULA: $addr" >&2 + ip addr del "$addr"/64 dev gbmcbr || true fi - fi - - local netfile - for netfile in /run/systemd/network/{00,}-bmc-gbmcbr.network.d/60-ula.conf; do - mkdir -p "$(dirname "$netfile")" - printf '%s' "$contents" >"$netfile" 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 +gbmc_br_ula_is_ll() { + # shellcheck disable=SC2178 + local -n bytes="$1" + (( bytes[0] == 0xfe && bytes[1] == 0x80 && bytes[2] == 0x00 && + bytes[3] == 0x00 && bytes[4] == 0x00 && bytes[5] == 0x00 && + bytes[6] == 0x00 && bytes[7] == 0x00 )) +} - if [[ $(systemctl is-active systemd-networkd) != inactive ]]; then - networkctl reload - networkctl reconfigure gbmcbr - fi +gbmc_br_ula_is_ula() { + # shellcheck disable=SC2178 + local -n bytes="$1" + (( bytes[0] == 0xfd && bytes[1] == 0xb5 && bytes[2] == 0x04 && + bytes[3] == 0x81 && bytes[4] == 0x10 && bytes[5] == 0xce && + bytes[6] == 0x00 && bytes[7] == 0x00 )) } gbmc_br_ula_hook() { # shellcheck disable=SC2154 if [[ $change == init ]]; then - gbmc_br_ula_init=1 - gbmc_br_ula_update - elif [[ $change == link && $intf == gbmcbr ]]; then - if [[ $action == add && $mac != "$gbmc_br_ula_mac" ]]; then - gbmc_br_ula_mac="$mac" - gbmc_br_ula_update + gbmc_br_ula_cleanup + elif [[ $change == addr && $intf == gbmcbr && $fam == inet6 ]]; then + local pfx_bytes=() + ip_to_bytes pfx_bytes "$ip" || return + local val=0 + if gbmc_br_ula_is_ll pfx_bytes; then + val="$GBMC_BR_ULA_SFX_HAS_LL" + elif gbmc_br_ula_is_ula pfx_bytes; then + val="$GBMC_BR_ULA_SFX_HAS_ULA" + else + return 0 + fi + # Force all addresses into what they would be as a ULA so that we can + # store bits about the assigned addresses on the interface + pfx_bytes[0]=0xfd + pfx_bytes[1]=0xb5 + pfx_bytes[2]=0x04 + pfx_bytes[3]=0x81 + pfx_bytes[4]=0x10 + pfx_bytes[5]=0xce + addr="$(ip_bytes_to_str pfx_bytes)" + local old=${gbmc_br_ulas["$addr"]-0} + if [[ $action == add ]]; then + val=$((old | val)) + elif [[ $action == del ]]; then + val=$((old & ~val)) fi - if [[ $action == del && $mac == "$gbmc_br_ula_mac" ]]; then - gbmc_br_ula_mac= - gbmc_br_ula_update + gbmc_br_ulas["$addr"]=$val + if (( val == GBMC_BR_ULA_SFX_HAS_LL )); then + # We have a link local address but no ULA, so we need to add the ULA + echo "Adding ULA: $addr" >&2 + ip addr replace "$addr"/64 dev gbmcbr + elif (( val == GBMC_BR_ULA_SFX_HAS_ULA )); then + # We have a ULA without a link local, so we should not longer have this ULA + echo "Removing ULA: $addr" >&2 + ip addr del "$addr"/64 dev gbmcbr || true + elif (( val == 0 )); then + # Cleanup the map if we no longer have any addresses for the suffix + unset 'gbmc_br_ulas[$addr]' fi fi } diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-start-dhcp.sh b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-start-dhcp.sh index c6fddbb9cf..b968573daf 100644 --- a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-start-dhcp.sh +++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-start-dhcp.sh @@ -15,10 +15,6 @@ systemctl stop gbmc-br-dhcp -# in some cases dhcp-done might be run already, in this case we want -# a powercycle for a clean install -systemctl is-active -q dhcp-done@* && exit 1 - # stop dhcp term service to prevent race condition systemctl is-active --quiet gbmc-br-dhcp-term && systemctl stop gbmc-br-dhcp-term diff --git a/meta-google/recipes-google/networking/gbmc-net-common.bb b/meta-google/recipes-google/networking/gbmc-net-common.bb new file mode 100644 index 0000000000..1a3ca7722c --- /dev/null +++ b/meta-google/recipes-google/networking/gbmc-net-common.bb @@ -0,0 +1,27 @@ +SUMMARY = "gBMC common networking components" +PR = "r1" +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10" + +SRC_URI += " \ + file://gbmc-net-lib.sh \ + file://gbmc-ra.sh \ + " +S = "${WORKDIR}" + +FILES:${PN} += " \ + ${datadir}/ \ + " + +RDEPENDS:${PN}:append = " \ + bash \ + network-sh \ + ndisc6-rdisc6 \ + " + +do_install() { + install -d -m0755 ${D}${datadir} + install -m0644 ${S}/gbmc-net-lib.sh ${D}${datadir}/ + install -m0644 ${S}/gbmc-ra.sh ${D}${datadir}/ +} + diff --git a/meta-google/recipes-google/networking/gbmc-net-common/gbmc-net-lib.sh b/meta-google/recipes-google/networking/gbmc-net-common/gbmc-net-lib.sh new file mode 100644 index 0000000000..6e4ba365e0 --- /dev/null +++ b/meta-google/recipes-google/networking/gbmc-net-common/gbmc-net-lib.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# Copyright 2024 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_net_lib_init-}" ] && return + +gbmc_net_networkd_reload() { + if [ "$(systemctl is-active systemd-networkd)" != 'inactive' ]; then + echo "Reloading networkd + reconfiguring ($*) from $(caller 0)" >&2 + networkctl reload || return + local st=0 + local intf + for intf in "$@"; do + networkctl reconfigure "$intf" || st=$? + done + return $st + fi +} + +gbmc_net_lib_init=1 diff --git a/meta-google/recipes-google/networking/gbmc-net-common/gbmc-ra.sh b/meta-google/recipes-google/networking/gbmc-net-common/gbmc-ra.sh new file mode 100644 index 0000000000..280083a8c9 --- /dev/null +++ b/meta-google/recipes-google/networking/gbmc-net-common/gbmc-ra.sh @@ -0,0 +1,188 @@ +#!/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 +# shellcheck source=meta-google/recipes-google/networking/gbmc-net-common/gbmc-net-lib.sh +source /usr/share/gbmc-net-lib.sh || exit + +: "${RA_IF:?No RA interface set}" +: "${IP_OFFSET=?1}" +: "${ROUTE_METRIC:?No Metric set}" + +# We would prefer empty string but it's easier for associative array handling +# to use invalid +old_rtr=invalid +old_mac=invalid +old_pfx=invalid +old_fqdn=invalid + +default_update_rtr() { + local rtr="$1" + local mac="$2" + + if ip addr show | grep -q "^[ ]*inet6 $rtr/"; then + echo "Router is ourself, ignoring" >&2 + return 0 + fi + + # In case we don't have a base network file, make one + # this is intentionally 00- as it will not preceed /etc/systemd/network/00-* + # or /lib/systemd/network/-* files. + local file=/run/systemd/network/00-bmc-$RA_IF.network + printf '[Match]\nName=%s\n[Network]\nDHCP=false\nIPv6AcceptRA=false\nLinkLocalAddressing=yes' \ + "$RA_IF" >"$file" + + # Override any existing gateway information within files + # Make sure we cover `00-*` and `-*` files + for file in /run/systemd/network/{00,}-bmc-$RA_IF.network; do + mkdir -p "$file.d" + printf '[Route]\nGateway=%s\nGatewayOnLink=true\nMetric=%d\n[Neighbor]\nMACAddress=%s\nAddress=%s' \ + "$rtr" "$ROUTE_METRIC" "$mac" "$rtr" >"$file.d"/10-gateway.conf + done + + # Don't force networkd to reload as this can break phosphor-networkd + # Fall back to reload only if ip link commands fail + (ip -6 route replace default via "$rtr" onlink dev "$RA_IF" metric "$ROUTE_METRIC" && \ + ip -6 neigh replace "$rtr" dev "$RA_IF" lladdr "$mac") || \ + gbmc_net_networkd_reload "$RA_IF" || true + + echo "Set router $rtr on $RA_IF" >&2 +} + +default_update_fqdn() { + local fqdn="$1" + [ -z "$fqdn" ] && return + hostnamectl set-hostname "$fqdn" || true + echo "Set hostname $fqdn on $RA_IF" >&2 +} + +retries=1 +min_w=10 +declare -A rtrs +rtrs=() +while true; do + # shellcheck disable=SC2206 + data=(${rtrs["${old_rtr}"]-}) + curr_dl="${data[1]-$(( min_w + SECONDS ))}" + args=(-m "$RA_IF" -w $(( (curr_dl - SECONDS) * 1000 ))) + if (( retries > 0 )); then + args+=(-r "$retries") + else + args+=(-d) + fi + while read -r line; do + # `script` terminates all lines with a CRLF, remove it + line="${line:0:-1}" + # shellcheck disable=SC2026 + if [ -z "$line" ]; then + lifetime=-1 + mac= + hextet= + pfx= + host= + domain= + elif [[ "$line" =~ ^Router' 'lifetime' '*:' '*([0-9]*) ]]; then + lifetime="${BASH_REMATCH[1]}" + elif [[ "$line" =~ ^Source' 'link-layer' 'address' '*:' '*([a-fA-F0-9:]*)$ ]]; then + mac="${BASH_REMATCH[1]}" + 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]}" + # Only valid default routers can be considered, 0 lifetime implies + # a non-default router + (( lifetime > 0 )) || continue + + dl=$((lifetime + SECONDS)) + fqdn= + if [[ -n $host && -n $hextet && -n $domain ]]; then + fqdn="$host-n$hextet.$domain" + fi + rtrs["$rtr"]="$mac $dl $pfx $fqdn" + # We have some notoriously noisy lab environments with many routers being broadcast + # We always prefer "fe80::1" in prod and labs for routing, so prefer that gateway. + # We also want to take the first router we find to speed up acquisition on boot. + if [[ "$rtr" = "fe80::1" || "$old_rtr" = "invalid" ]]; then + if [[ "$rtr" != "$old_rtr" && "$mac" != "$old_mac" ]]; then + echo "Got defgw $rtr at $mac on $RA_IF" >&2 + update_rtr "$rtr" "$mac" || true + retries=-1 + old_mac="$mac" + old_rtr="$rtr" + fi + fi + # Only update router properties if we use this router + [[ "$rtr" == "$old_rtr" ]] || continue + if [[ $pfx != "$old_pfx" ]]; then + echo "Got PFX $pfx from $rtr on $RA_IF" >&2 + old_pfx="$pfx" + update_pfx "$pfx" || true + fi + if [[ $fqdn != "$old_fqdn" ]]; then + echo "Got FQDN $fqdn from $rtr on $RA_IF" >&2 + old_fqdn="$fqdn" + update_fqdn "$fqdn" || true + fi + fi + done < <(exec script -q -c "rdisc6 ${args[*]}" /dev/null 2>/dev/null) + # Purge any expired routers + for rtr in "${!rtrs[@]}"; do + # shellcheck disable=SC2206 + data=(${rtrs["$rtr"]}) + dl=${data[1]} + if (( dl <= SECONDS )); then + unset "rtrs[$rtr]" + fi + done + # Consider changing the gateway if the old one doesn't send RAs for the entire period + # This ensures we don't flip flop between multiple defaults if they exist. + if [[ "$old_rtr" != "invalid" && -z "${rtrs["$old_rtr"]-}" ]]; then + echo "Old router $old_rtr disappeared" >&2 + old_rtr=invalid + for rtr in "${!rtrs[@]}"; do + # shellcheck disable=SC2206 + data=(${rtrs["$rtr"]}) + mac=${data[0]} + dl=${data[1]} + pfx=${data[2]} + fqdn=${data[3]} + update_rtr "$rtr" "$mac" || true + update_pfx "$pfx" || true + update_fqdn "$fqdn" || true + break + done + fi + + # If rdisc6 exits early we still want to wait for the deadline before retrying + (( timeout = curr_dl - SECONDS )) + sleep $(( timeout < 0 ? 0 : timeout )) +done diff --git a/meta-google/recipes-google/networking/gbmc-nic-config.bb b/meta-google/recipes-google/networking/gbmc-nic-config.bb new file mode 100644 index 0000000000..e804e2628d --- /dev/null +++ b/meta-google/recipes-google/networking/gbmc-nic-config.bb @@ -0,0 +1,79 @@ +SUMMARY = "Configured gBMC non-NCSI interface" +PR = "r1" +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10" + +GBMC_EXT_NICS ?= "" +GBMC_DHCP_RELAY ??= "${@'' if int(d.getVar('FLASH_SIZE')) < 65536 else '1'}" + +inherit systemd + +SRC_URI += " \ + file://50-gbmc-nic.rules \ + file://50-gbmc-nic.rules.in \ + file://-bmc-nic.network.in \ + file://gbmc-nic-neigh.sh.in \ + file://gbmc-nic-ra.sh \ + file://gbmc-nic-ra@.service \ + ${@'' if d.getVar('GBMC_DHCP_RELAY') != '1' else 'file://-bmc-gbmcbrnicdhcp.netdev'} \ + ${@'' if d.getVar('GBMC_DHCP_RELAY') != '1' else 'file://-bmc-gbmcbrnicdhcp.network'} \ + ${@'' if d.getVar('GBMC_DHCP_RELAY') != '1' else 'file://-bmc-gbmcnicdhcp.netdev'} \ + ${@'' if d.getVar('GBMC_DHCP_RELAY') != '1' else 'file://-bmc-gbmcnicdhcp.network'} \ + ${@'' if d.getVar('GBMC_DHCP_RELAY') != '1' else 'file://gbmc-nic-dhcrelay.service.in'} \ + " +S = "${WORKDIR}" + +FILES:${PN} += " \ + ${systemd_unitdir}/network \ + ${sysconfdir}/nftables \ + ${systemd_system_unitdir} \ + ${datadir}/gbmc-ip-monitor \ + " + +RDEPENDS:${PN}:append = " \ + bash \ + gbmc-ip-monitor \ + gbmc-net-common \ + nftables-systemd \ + " + +do_install() { + netdir=${D}${systemd_unitdir}/network + install -d -m0755 $netdir + nftdir=${D}${sysconfdir}/nftables + install -d -m0755 $nftdir + unitdir=${D}${systemd_system_unitdir} + install -d -m0755 $unitdir + wantdir=$unitdir/multi-user.target.wants + install -d -m0755 $wantdir + + install -d -m0755 ${D}${libexecdir} + install -m0755 ${WORKDIR}/gbmc-nic-ra.sh ${D}${libexecdir}/ + install -m0644 ${WORKDIR}/gbmc-nic-ra@.service $unitdir/ + + mondir=${D}${datadir}/gbmc-ip-monitor + install -d -m0755 $mondir + sed 's,@IFS@,${GBMC_EXT_NICS},g' <${WORKDIR}/gbmc-nic-neigh.sh.in \ + >$mondir/gbmc-nic-neigh.sh + + uppers= + for intf in ${GBMC_EXT_NICS}; do + sed "s,@IF@,$intf,g" <${WORKDIR}/50-gbmc-nic.rules.in >$nftdir/50-gbmc-$intf.rules + sed "s,@IF@,$intf,g" <${WORKDIR}/-bmc-nic.network.in >$netdir/-bmc-$intf.network + uppers="$uppers -u ff02::1:2%%$intf" + ln -sv ../gbmc-nic-ra@.service $wantdir/gbmc-nic-ra@$intf.service + done + + if [ "${GBMC_DHCP_RELAY}" = 1 ]; then + install -m0644 ${WORKDIR}/-bmc-gbmcbrnicdhcp.network $netdir/ + install -m0644 ${WORKDIR}/-bmc-gbmcbrnicdhcp.netdev $netdir/ + install -m0644 ${WORKDIR}/-bmc-gbmcnicdhcp.network $netdir/ + install -m0644 ${WORKDIR}/-bmc-gbmcnicdhcp.netdev $netdir/ + install -m0644 ${WORKDIR}/50-gbmc-nic.rules $nftdir/ + + sed "s,@UPPERS@,$uppers,g" <${WORKDIR}/gbmc-nic-dhcrelay.service.in \ + >$unitdir/gbmc-nic-dhcrelay.service + ln -sv ../gbmc-nic-dhcrelay.service $wantdir/ + fi +} + diff --git a/meta-google/recipes-google/networking/gbmc-nic-config/-bmc-gbmcbrnicdhcp.netdev b/meta-google/recipes-google/networking/gbmc-nic-config/-bmc-gbmcbrnicdhcp.netdev new file mode 100644 index 0000000000..1d9ca4a734 --- /dev/null +++ b/meta-google/recipes-google/networking/gbmc-nic-config/-bmc-gbmcbrnicdhcp.netdev @@ -0,0 +1,5 @@ +[NetDev] +Name=gbmcbrnicdhcp +Kind=veth +[Peer] +Name=gbmcnicdhcp diff --git a/meta-google/recipes-google/networking/gbmc-nic-config/-bmc-gbmcbrnicdhcp.network b/meta-google/recipes-google/networking/gbmc-nic-config/-bmc-gbmcbrnicdhcp.network new file mode 100644 index 0000000000..73212db0c3 --- /dev/null +++ b/meta-google/recipes-google/networking/gbmc-nic-config/-bmc-gbmcbrnicdhcp.network @@ -0,0 +1,4 @@ +[Match] +Name=gbmcbrnicdhcp +[Network] +Bridge=gbmcbr diff --git a/meta-google/recipes-google/networking/gbmc-nic-config/-bmc-gbmcnicdhcp.netdev b/meta-google/recipes-google/networking/gbmc-nic-config/-bmc-gbmcnicdhcp.netdev new file mode 100644 index 0000000000..24a78fbfa4 --- /dev/null +++ b/meta-google/recipes-google/networking/gbmc-nic-config/-bmc-gbmcnicdhcp.netdev @@ -0,0 +1,5 @@ +[NetDev] +Name=gbmcnicdhcp +Kind=veth +[Peer] +Name=gbmcbrnicdhcp diff --git a/meta-google/recipes-google/networking/gbmc-nic-config/-bmc-gbmcnicdhcp.network b/meta-google/recipes-google/networking/gbmc-nic-config/-bmc-gbmcnicdhcp.network new file mode 100644 index 0000000000..1eae55a662 --- /dev/null +++ b/meta-google/recipes-google/networking/gbmc-nic-config/-bmc-gbmcnicdhcp.network @@ -0,0 +1,9 @@ +[Match] +Name=gbmcnicdhcp +[Network] +DHCP=false +IPv6AcceptRA=false +LLMNR=false +MulticastDNS=false +LinkLocalAddressing=ipv6 +Address=fdb5:0481:10ce::3/64 diff --git a/meta-google/recipes-google/networking/gbmc-nic-config/-bmc-nic.network.in b/meta-google/recipes-google/networking/gbmc-nic-config/-bmc-nic.network.in new file mode 100644 index 0000000000..08c2eee178 --- /dev/null +++ b/meta-google/recipes-google/networking/gbmc-nic-config/-bmc-nic.network.in @@ -0,0 +1,8 @@ +[Match] +Name=@IF@ +[Network] +DHCP=false +IPv6AcceptRA=false +LLMNR=false +MulticastDNS=false +LinkLocalAddressing=ipv6 diff --git a/meta-google/recipes-google/networking/gbmc-nic-config/50-gbmc-nic.rules b/meta-google/recipes-google/networking/gbmc-nic-config/50-gbmc-nic.rules new file mode 100644 index 0000000000..cbedfb9710 --- /dev/null +++ b/meta-google/recipes-google/networking/gbmc-nic-config/50-gbmc-nic.rules @@ -0,0 +1,8 @@ +table inet filter { + chain nic_dhcp_input { + type filter hook input priority 0; policy drop; + iifname != gbmcnicdhcp accept + ip6 nexthdr icmpv6 accept + udp dport 547 accept + } +} diff --git a/meta-google/recipes-google/networking/gbmc-nic-config/50-gbmc-nic.rules.in b/meta-google/recipes-google/networking/gbmc-nic-config/50-gbmc-nic.rules.in new file mode 100644 index 0000000000..feba64d292 --- /dev/null +++ b/meta-google/recipes-google/networking/gbmc-nic-config/50-gbmc-nic.rules.in @@ -0,0 +1,19 @@ +table inet filter { + chain @IF@_input { + type filter hook input priority 0; policy drop; + iifname != @IF@ accept + ct state established accept + udp dport 547 accept + jump gbmc_br_pub_input + } + chain gbmc_br_pub_input { + ip6 nexthdr icmpv6 accept + } + chain @IF@_forward { + type filter hook forward priority 0; policy drop; + iifname != @IF@ accept + oifname != gbmcbr drop + ip6 daddr fdb5:0481:10ce::/64 drop + ip6 saddr fdb5:0481:10ce::/64 drop + } +} diff --git a/meta-google/recipes-google/networking/gbmc-nic-config/gbmc-nic-dhcrelay.service.in b/meta-google/recipes-google/networking/gbmc-nic-config/gbmc-nic-dhcrelay.service.in new file mode 100644 index 0000000000..8571ae1e67 --- /dev/null +++ b/meta-google/recipes-google/networking/gbmc-nic-config/gbmc-nic-dhcrelay.service.in @@ -0,0 +1,13 @@ +[Unit] +Description=gBMC DHCP Relay Agent Daemon +After=network.target +StartLimitIntervalSec=10 +StartLimitBurst=3 + +[Service] +Restart=always +RestartSec=5 +ExecStart=/usr/sbin/dhcrelay -d --no-pid -l gbmcnicdhcp @UPPERS@ + +[Install] +WantedBy=multi-user.target diff --git a/meta-google/recipes-google/networking/gbmc-nic-config/gbmc-nic-neigh.sh.in b/meta-google/recipes-google/networking/gbmc-nic-config/gbmc-nic-neigh.sh.in new file mode 100644 index 0000000000..d7c0f023b7 --- /dev/null +++ b/meta-google/recipes-google/networking/gbmc-nic-config/gbmc-nic-neigh.sh.in @@ -0,0 +1,98 @@ +#!/bin/bash +# Copyright 2024 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_nic_neigh_lib-} ]] && return + +# 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-net-common/gbmc-net-lib.sh +source /usr/share/gbmc-net-lib.sh || exit + +gbmc_nic_neigh_intfs=(@IFS@) +gbmc_nic_neigh_addr= + +gbmc_nic_neigh_set() { + local act="$1" + local ip="$2" + + echo "gBMC NIC Neigh $act $ip: ${gbmc_nic_neigh_intfs[*]}" >&2 + + local intf + local failed_intfs=() + for intf in "${gbmc_nic_neigh_intfs[@]}"; do + # In case we don't have a base network file, make one + # this is intentionally 00- as it will not preceed /etc/systemd/network/00-* + # or /lib/systemd/network/-* files. + local file=/run/systemd/network/00-bmc-$intf.network + printf '[Match]\nName=%s\n[Network]\nDHCP=false\nIPv6AcceptRA=false\nLinkLocalAddressing=yes' \ + "$intf" >"$file" + + # Override any existing gateway information within files + # Make sure we cover `00-*` and `-*` files + for file in /run/systemd/network/{00,}-bmc-"$intf".network; do + mkdir -p "$file.d" + if [[ "$act" == add ]]; then + printf '[Network]\nIPv6ProxyNDP=yes\nIPv6ProxyNDPAddress=%s\n' \ + "$ip" >"$file.d"/10-nic-neigh.conf + else + rm -f "$file.d"/10-nic-neigh.conf + fi + done + + sysctl net.ipv6.conf."$intf".proxy_ndp=1 >/dev/null && \ + ip -6 neigh "$act" proxy "$ip" dev "$intf" || \ + failed_intfs+=("$intf") + done + [[ "$act" == del ]] && return + if (( "${#failed_intfs[@]}" > 0 )); then + gbmc_net_networkd_reload "${failed_intfs[@]}" + fi +} + +gbmc_nic_neigh_hook() { + # shellcheck disable=SC2154 + if [[ $change == addr && $intf == gbmcbr && $scope == global ]] && + [[ $fam == inet6 && $flags != *tentative* ]]; then + local ip_bytes=() + if ! ip_to_bytes ip_bytes "$ip"; then + echo "gBMC Bridge Ensure RA Invalid IP: $ip" >&2 + return 1 + fi + # Ignore ULAs + if (( (ip_bytes[0] & 0xfe) == 0xfc )); then + return 0 + fi + # Addresses must be /64 to the upstack switch + for (( i = 8; i < 16; ++i )); do + if (( ip_bytes[i] != 0 )); then + return 0 + fi + done + if [[ $action == add && "$gbmc_nic_neigh_addr" != "$ip" ]]; then + if [ -n "$gbmc_nic_neigh_addr" ]; then + gbmc_nic_neigh_set del "$gbmc_nic_neigh_addr" + fi + gbmc_nic_neigh_addr="$ip" + gbmc_nic_neigh_set add "$ip" + elif [[ $action == del && "$gbmc_nic_neigh_addr" == "$ip" ]]; then + gbmc_nic_neigh_addr= + gbmc_nic_neigh_set del "$ip" + fi + fi +} + +GBMC_IP_MONITOR_HOOKS+=(gbmc_nic_neigh_hook) + +gbmc_nic_neigh_lib=1 diff --git a/meta-google/recipes-google/networking/gbmc-nic-config/gbmc-nic-ra.sh b/meta-google/recipes-google/networking/gbmc-nic-config/gbmc-nic-ra.sh new file mode 100755 index 0000000000..98239c33f6 --- /dev/null +++ b/meta-google/recipes-google/networking/gbmc-nic-config/gbmc-nic-ra.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# Copyright 2024 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. + +update_rtr() { + default_update_rtr "$@" +} + +update_fqdn() { + true +} + +update_pfx() { + true +} + +RA_IF=$1 +IP_OFFSET=0 +# This is guaranteed to be closer to the ToR than NCSI, for reliability +# and bandwidth we want to prefer this path. +ROUTE_METRIC=800 + +# shellcheck source=meta-google/recipes-google/networking/gbmc-net-common/gbmc-ra.sh +source /usr/share/gbmc-ra.sh || exit diff --git a/meta-google/recipes-google/networking/gbmc-nic-config/gbmc-nic-ra@.service b/meta-google/recipes-google/networking/gbmc-nic-config/gbmc-nic-ra@.service new file mode 100644 index 0000000000..54d77dfeb7 --- /dev/null +++ b/meta-google/recipes-google/networking/gbmc-nic-config/gbmc-nic-ra@.service @@ -0,0 +1,13 @@ +[Unit] +Description=gBMC %i RA Discovery +After=network.target +StartLimitIntervalSec=10 +StartLimitBurst=3 + +[Service] +Restart=always +RestartSec=5 +ExecStart=/usr/libexec/gbmc-nic-ra.sh %i + +[Install] +WantedBy=multi-user.target diff --git a/meta-google/recipes-google/systemd/files/40-gbmc-sysctl.conf b/meta-google/recipes-google/systemd/files/40-gbmc-sysctl.conf index ee4b4859a7..5b3fa9e43d 100644 --- a/meta-google/recipes-google/systemd/files/40-gbmc-sysctl.conf +++ b/meta-google/recipes-google/systemd/files/40-gbmc-sysctl.conf @@ -1 +1,3 @@ kernel.oops_all_cpu_backtrace = 1 +# limit PID numbers to 32k for metrics collector +kernel.pid_max = 32768 |