Initial commit
This commit is contained in:
@@ -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>
|
||||
Reference in New Issue
Block a user