Initial commit

This commit is contained in:
Your Name
2026-04-23 17:07:55 +08:00
commit b7e39e063b
16725 changed files with 1625565 additions and 0 deletions
@@ -0,0 +1,8 @@
[Match]
Property=ID_BUS=usb ID_VENDOR_ID=18d1 ID_MODEL_ID=022b
[Network]
Bridge=gbmcbr
[Bridge]
# USB speeds tend to be better than 100mbit (100 cost) but worse
# than 1gbit (10 cost). Generally around 200mbit.
Cost=85
@@ -0,0 +1,5 @@
[NetDev]
Name=gbmcbr
Kind=bridge
[Bridge]
STP=true
@@ -0,0 +1,15 @@
[Match]
Name=gbmcbr
[Network]
@ADDR@
DHCP=false
IPv6AcceptRA=true
LLMNR=true
MulticastDNS=true
LinkLocalAddressing=ipv6
IPv6PrefixDelegation=yes
[IPv6AcceptRA]
DHCPv6Client=false
RouteMetric=1056
[IPv6PrefixDelegation]
RouterLifetimeSec=0
@@ -0,0 +1,3 @@
[NetDev]
Name=gbmcbrdummy
Kind=dummy
@@ -0,0 +1,4 @@
[Match]
Name=gbmcbrdummy
[Network]
Bridge=gbmcbr
@@ -0,0 +1,24 @@
table bridge filter {
chain gbmcbr_mark {
type filter hook prerouting priority -300;
iifname == "cn0" mark set 1 return
iifname == "cn1" mark set 2 return
}
}
table inet raw {
chain gbmcbr_nat_input {
type filter hook prerouting priority -300;
# client should only use 10166 for this purpose and
# it should NOT use service port directly
# otherwise drop later if the packets goes into input
tcp dport 10167-10168 mark set 0xff
mark 1 tcp dport 10166 tcp dport set 10167 notrack
mark 2 tcp dport 10166 tcp dport set 10168 notrack
}
chain gbmcbr_nat_output {
type filter hook output priority -300;
tcp sport 10167 tcp sport set 10166 notrack
tcp sport 10168 tcp sport set 10166 notrack
}
}
@@ -0,0 +1,38 @@
table bridge filter {
chain gbmc_br_prerouting {
type filter hook prerouting priority 0;
iifname != gbmcbr accept
# Sometimes our links are over NCSI and we don't want to broadcast
# those packets over the entire bridge. They are only relevant P2P.
ether type 0x88F8 drop
}
}
table inet filter {
chain gbmc_br_input {
type filter hook input priority 0; policy drop;
iifname != gbmcbr accept
mark 0xff drop
ct state established accept
jump gbmc_br_int_input
jump gbmc_br_pub_input
reject
}
set gbmc_br_int_addrs {
type ipv6_addr;
flags interval
elements = {
ff00::/8,
fe80::/64,
fdb5:0481:10ce::/64,
}
}
chain gbmc_br_int_input {
ip6 daddr @gbmc_br_int_addrs accept
ip6 saddr @gbmc_br_int_addrs accept
}
chain gbmc_br_pub_input {
ip6 nexthdr icmpv6 accept
}
}
@@ -0,0 +1,37 @@
#!/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_psu_hardreset-}" ] && return
gbmc_psu_hardreset_needed=
gbmc_psu_hardreset_hook() {
# We don't always need a powercycle, allow skipping
if [ -z "${gbmc_psu_hardreset_needed-}" ]; then
echo "Skipping tray powercycle" >&2
return 0
fi
echo "Powercycling" >&2
systemctl start gbmc-psu-hardreset.target || return
# Ensure that we don't continue the DHCP process while waiting for the
# powercycle.
exit 0
}
GBMC_BR_DHCP_HOOKS+=(gbmc_psu_hardreset_hook)
gbmc_psu_hardreset=1
@@ -0,0 +1,13 @@
[Unit]
Description=gBMC DHCP Client terminator
After=network.target
StartLimitIntervalSec=10
StartLimitBurst=3
[Service]
Restart=on-failure
RestartSec=5
ExecStart=/usr/libexec/gbmc-br-dhcp-term.sh
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,106 @@
#!/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.
# shellcheck source=meta-google/recipes-google/networking/network-sh/lib.sh
source /usr/share/network/lib.sh || exit
# Wait until a well known service is network available
echo 'Waiting for network reachability' >&2
while true; do
before=$SECONDS
addrs="$(ip addr show gbmcbr | grep '^ *inet6' | awk '{print $2}')"
for addr in $addrs; do
# Remove the prefix length
ip="${addr%/*}"
ip_to_bytes ip_bytes "$ip" || continue
# Ignore ULAs and non-gBMC addresses
(( ip_bytes[0] & 0xfc == 0xfc || ip_bytes[8] != 0xfd )) && continue
# Only allow for the short, well known addresses <pfx>:fd01:: and not
# <pfx>:fd00:83c1:292d:feef. Otherwise, powercycle may be unavailable.
(( ip_bytes[9] == 0 )) && continue
for i in {10..15}; do
(( ip_bytes[i] != 0 )) && continue 2
done
echo "Trying reachability from $ip" >&2
for i in {0..5}; do
ping -I "$ip" -c 1 -W 1 2001:4860:4860::8888 >/dev/null 2>&1 && break 3
sleep 1
done
done
# Ensure we only complete the addr lookup loop every 10s
tosleep=$((before + 10 - SECONDS))
if (( tosleep > 0 )); then
sleep "$tosleep"
fi
done
# We need to guarantee we wait at least 5 minutes from reachable in
# case networking just came up
wait_min=5
echo "Network is reachable, waiting $wait_min min" >&2
sleep $((60 * wait_min))
get_dhcp_unit_json() {
busctl -j call \
org.freedesktop.systemd1 \
/org/freedesktop/systemd1/unit/gbmc_2dbr_2ddhcp_2eservice \
org.freedesktop.DBus.Properties \
GetAll s org.freedesktop.systemd1.Unit
}
# Follow the process and make sure it idles for at least 5 minutes before
# shutting down. This allows for failures and retries to happen.
while true; do
json="$(get_dhcp_unit_json)" || exit
last_ms="$(echo "$json" | jq -r '.data[0].StateChangeTimestampMonotonic.data')"
if pid="$(cat /run/gbmc-br-dhcp.pid 2>/dev/null)"; then
# If the DHCP configuration process is running, wait for it to finish
echo "DHCP still running ($pid), waiting" >&2
while [[ -e /proc/$pid ]]; do
sleep 1
done
# Wait for systemd to detect the process state change
while true; do
json="$(get_dhcp_unit_json)" || exit
ms="$(echo "$json" | jq -r '.data[0].StateChangeTimestampMonotonic.data')"
(( ms != last_ms )) && break
sleep 1
done
fi
echo 'Checking DHCP Active State' >&2
json="$(get_dhcp_unit_json)" || exit
activestr="$(echo "$json" | jq -r '.data[0].ActiveState.data')"
# The process is already stopped, we are done
[[ "$activestr" == 'inactive' ]] && exit
# If the process is running, give it at least 5 minutes from when it started
cur_s="$(cut -d' ' -f1 /proc/uptime)"
# Remove floating point if applied since bash can't perform float arithmetic
cur_s="${cur_s%.*}"
if [[ "$activestr" == 'active' ]]; then
active_ms="$(echo "$json" | jq -r '.data[0].ActiveEnterTimestampMonotonic.data')"
else
active_ms=$((cur_s*1000*1000))
fi
w=$((active_ms/1000/1000 + (wait_min*60) - cur_s))
[ "$w" -lt 0 ] && break
echo "Waiting ${w}s for DHCP process" >&2
sleep "$w"
done
echo "Stopping DHCP processing" >&2
systemctl stop --no-block gbmc-br-dhcp
@@ -0,0 +1,14 @@
[Unit]
Description=gBMC DHCP Client
After=network.target
StartLimitIntervalSec=10
StartLimitBurst=3
[Service]
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
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,80 @@
#!/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.
# 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=()
# A dict of outstanding items that should prevent DHCP completion
declare -A GBMC_BR_DHCP_OUTSTANDING=()
# 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
echo "$$" >/run/gbmc-br-dhcp.pid
if [ "$1" = bound ]; then
# Variable is from the environment via udhcpc6
# shellcheck disable=SC2154
echo "DHCPv6(gbmcbr): $ipv6/128" >&2
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
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 1
fi
done
pfx="$(ip_bytes_to_str pfx_bytes)"
gbmc_br_set_ip "$pfx" || exit
if [ -n "${fqdn-}" ]; then
echo "Using hostname $fqdn" >&2
hostnamectl set-hostname "$fqdn" || true
fi
gbmc_br_run_hooks GBMC_BR_DHCP_HOOKS || exit
# 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
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
fi
@@ -0,0 +1,5 @@
[Service]
ExecStart=/usr/libexec/gbmc-br-ensure-ra.sh
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,27 @@
#!/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.
# 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
@@ -0,0 +1,102 @@
#!/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.
[[ -n ${gbmc_br_from_ra_lib-} ]] && return
# shellcheck source=meta-google/recipes-google/networking/network-sh/lib.sh
source /usr/share/network/lib.sh || exit
gbmc_br_from_ra_init=
gbmc_br_from_ra_mac=
declare -A gbmc_br_from_ra_pfxs=()
declare -A gbmc_br_from_ra_prev_addrs=()
gbmc_br_from_ra_update() {
[[ -n $gbmc_br_from_ra_init && -n $gbmc_br_from_ra_mac ]] || return
local pfx
for pfx in "${!gbmc_br_from_ra_pfxs[@]}"; do
local cidr
if ! cidr="$(ip_pfx_to_cidr "$pfx")"; then
unset 'gbmc_br_from_ra_pfxs[$pfx]'
continue
fi
if (( cidr == 80 )); then
local sfx
if ! sfx="$(mac_to_eui48 "$gbmc_br_from_ra_mac")"; then
unset 'gbmc_br_from_ra_pfxs[$pfx]'
continue
fi
local addr
if ! addr="$(ip_pfx_concat "$pfx" "$sfx")"; then
unset 'gbmc_br_from_ra_pfxs[$pfx]'
continue
fi
else
unset 'gbmc_br_from_ra_pfxs[$pfx]'
continue
fi
local valid="${gbmc_br_from_ra_pfxs["$pfx"]}"
if (( valid > 0 )); then
if [[ -z ${gbmc_br_from_ra_prev_addrs["$addr"]-} ]]; then
echo "gBMC Bridge RA Addr Add: $addr" >&2
gbmc_br_from_ra_prev_addrs["$addr"]=1
fi
ip addr replace "$addr" dev gbmcbr noprefixroute
else
if [[ -n ${gbmc_br_from_ra_prev_addrs["$addr"]-} ]]; then
echo "gBMC Bridge RA Addr Del: $addr" >&2
unset 'gbmc_br_from_ra_prev_addrs[$addr]'
fi
ip addr del "$addr" dev gbmcbr
unset 'gbmc_br_from_ra_pfxs[$pfx]'
fi
done
}
gbmc_br_from_ra_hook() {
# shellcheck disable=SC2154
if [[ $change == init ]]; then
gbmc_br_from_ra_init=1
gbmc_ip_monitor_defer
elif [[ $change == defer ]]; then
gbmc_br_from_ra_update
elif [[ $change == route && $route != *' via '* ]] &&
[[ $route =~ ^(.* dev gbmcbr proto ra .*)( +expires +([^ ]+)sec).*$ ]]; then
pfx="${route%% *}"
# shellcheck disable=SC2154
if [[ $action == add ]]; then
gbmc_br_from_ra_pfxs["$pfx"]="${BASH_REMATCH[3]}"
gbmc_ip_monitor_defer
elif [[ $action == del ]]; then
gbmc_br_from_ra_pfxs["$pfx"]=0
gbmc_ip_monitor_defer
fi
elif [[ $change == link && $intf == gbmcbr ]]; then
rdisc6 -m gbmcbr -r 1 -w 100 >/dev/null 2>&1
if [[ $action == add && $mac != "$gbmc_br_from_ra_mac" ]]; then
gbmc_br_from_ra_mac="$mac"
gbmc_ip_monitor_defer
fi
if [[ $action == del && $mac == "$gbmc_br_from_ra_mac" ]]; then
gbmc_br_from_ra_mac=
gbmc_ip_monitor_defer
fi
fi
}
GBMC_IP_MONITOR_HOOKS+=(gbmc_br_from_ra_hook)
gbmc_br_from_ra_lib=1
@@ -0,0 +1,117 @@
#!/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.
[[ -n ${gbmc_br_gw_src_lib-} ]] && return
# shellcheck source=meta-google/recipes-google/networking/network-sh/lib.sh
source /usr/share/network/lib.sh || exit
gbmc_br_gw_src_ip_stateful=
gbmc_br_gw_src_ip_stateless=
declare -A gbmc_br_gw_src_routes=()
gbmc_br_gw_defgw=
gbmc_br_set_router() {
local defgw=
local route
for route in "${!gbmc_br_gw_src_routes[@]}"; do
if [[ $route != *' dev gbmcbr '* ]]; then
defgw=1
break
fi
done
[[ $defgw == "$gbmc_br_gw_defgw" ]] && return
gbmc_br_gw_defgw="$defgw"
local files=(/run/systemd/network/{00,}-bmc-gbmcbr.network.d/50-defgw.conf)
if [[ -n $defgw ]]; then
local file
for file in "${files[@]}"; do
mkdir -p "$(dirname "$file")"
printf '[IPv6PrefixDelegation]\nRouterLifetimeSec=30\n' >"$file"
done
else
rm -f "${files[@]}"
fi
if [[ $(systemctl is-active systemd-networkd) != inactive ]]; then
networkctl reload && networkctl reconfigure gbmcbr
fi
}
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
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
# shellcheck disable=SC2086
ip route change $route src "$gbmc_br_gw_src_ip" && \
unset 'gbmc_br_gw_src_routes[$route]'
done
}
gbmc_br_gw_src_hook() {
# We only want to match default gateway routes that are dynamic
# (have an expiration time). These will be updated with our preferred
# source.
# shellcheck disable=SC2154
if [[ $change == route && $route == 'default '*':'* ]]; then
if [[ $route =~ ^(.*)( +expires +[^ ]+)(.*)$ ]]; then
route="${BASH_REMATCH[1]}${BASH_REMATCH[3]}"
fi
if [[ $action == add && -z ${gbmc_br_gw_src_routes["$route"]} ]]; then
gbmc_br_gw_src_routes["$route"]=1
gbmc_br_gw_src_update
gbmc_br_set_router
elif [[ $action == del && -n "${gbmc_br_gw_src_routes["$route"]}" ]]; then
unset 'gbmc_br_gw_src_routes[$route]'
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
# matched as the preferred source IP for outoging traffic.
elif [[ $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 and non-gBMC addresses
if (( ip_bytes[0] & 0xfe == 0xfc || ip_bytes[8] != 0xfd )); then
return 0
fi
if (( ip_bytes[9] & 0x0f != 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=
fi
fi
}
GBMC_IP_MONITOR_HOOKS+=(gbmc_br_gw_src_hook)
gbmc_br_gw_src_lib=1
@@ -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
# Remove legacy network configuration
rm -rf /etc/systemd/network/{00,}-bmc-gbmcbr.network.d
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-}"
local old_ip=
if [ -n "$ip" ]; then
old_ip="$(cat /var/google/gbmc-br-ip 2>/dev/null)"
[ "$old_ip" == "$ip" ] && return
mkdir -p /var/google || return
echo "$ip" >/var/google/gbmc-br-ip || return
else
[ ! -f "/var/google/gbmc-br-ip" ] && return
rm -rf /var/google/gbmc-br-ip
fi
gbmc_br_run_hooks GBMC_BR_LIB_SET_IP_HOOKS "$ip" || return
gbmc_br_reload_ip "$ip"
}
gbmc_br_lib_init=1
@@ -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
@@ -0,0 +1,74 @@
#!/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.
[[ -n ${gbmc_br_nft_lib-} ]] && return
# shellcheck source=meta-google/recipes-google/networking/network-sh/lib.sh
source /usr/share/network/lib.sh || exit
gbmc_br_nft_pfx=
gbmc_br_nft_update() {
printf 'gBMC Bridge input firewall for %s\n' \
"${gbmc_br_nft_pfx:-(deleted)}" >&2
local contents=
contents+='table inet filter {'$'\n'
contents+=' chain gbmc_br_int_input {'$'\n'
if [[ -n ${gbmc_br_nft_pfx-} ]]; then
contents+=" ip6 saddr $gbmc_br_nft_pfx"
contents+=" ip6 daddr $gbmc_br_nft_pfx accept"$'\n'
fi
contents+=' }'$'\n'
contents+='}'$'\n'
local rfile=/run/nftables/40-gbmc-br-int.rules
mkdir -p "$(dirname "$rfile")"
printf '%s' "$contents" >"$rfile"
# shellcheck disable=SC2015
systemctl reset-failed nftables && systemctl --no-block reload-or-restart nftables || true
}
gbmc_br_nft_hook() {
# Match only global IP addresses on the bridge that match the BMC prefix
# (<mpfx>:fdxx:). So 2002:af4:3480:2248:fd02:6345:3069:9186 would become
# a 2002:af4:3480:2248:fd00/76 rule.
# 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 NFT Invalid IP: $ip" >&2
return 1
fi
if (( ip_bytes[8] != 0xfd )); then
return 0
fi
local i
for (( i=9; i<16; i++ )); do
ip_bytes["$i"]=0
done
pfx="$(ip_bytes_to_str ip_bytes)/76"
if [[ $action == add && $pfx != "$gbmc_br_nft_pfx" ]]; then
gbmc_br_nft_pfx="$pfx"
gbmc_br_nft_update
fi
fi
}
GBMC_IP_MONITOR_HOOKS+=(gbmc_br_nft_hook)
gbmc_br_nft_lib=1
@@ -0,0 +1,74 @@
#!/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.
[[ -n ${gbmc_br_ula_lib-} ]] && return
# 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=
gbmc_br_ula_update() {
[[ -n $gbmc_br_ula_init ]] || return
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'
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
if [[ $(systemctl is-active systemd-networkd) != inactive ]]; then
networkctl reload
networkctl reconfigure gbmcbr
fi
}
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
fi
if [[ $action == del && $mac == "$gbmc_br_ula_mac" ]]; then
gbmc_br_ula_mac=
gbmc_br_ula_update
fi
fi
}
GBMC_IP_MONITOR_HOOKS+=(gbmc_br_ula_hook)
gbmc_br_ula_lib=1
@@ -0,0 +1,20 @@
#!/bin/bash
# Copyright 2023 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.
# stop dhcp term service to prevent race condition
systemctl is-active --quiet gbmc-br-dhcp-term && systemctl stop gbmc-br-dhcp-term
# start the dhcp service
systemctl start gbmc-br-dhcp
@@ -0,0 +1,11 @@
<?xml version="1.0" ?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
<name>@NAME@</name>
<service>
<type>_ipmi._udp</type>
<port>623</port>
<txt-record>Machine=@MACHINE@</txt-record>
@EXTRA_ATTRS@
</service>
</service-group>