summaryrefslogtreecommitdiff
path: root/meta-google/recipes-google/networking/gbmc-bridge
diff options
context:
space:
mode:
Diffstat (limited to 'meta-google/recipes-google/networking/gbmc-bridge')
-rw-r--r--meta-google/recipes-google/networking/gbmc-bridge/+-bmc-gbmcbrusb.network8
-rw-r--r--meta-google/recipes-google/networking/gbmc-bridge/-bmc-gbmcbr.netdev5
-rw-r--r--meta-google/recipes-google/networking/gbmc-bridge/-bmc-gbmcbr.network.in9
-rw-r--r--meta-google/recipes-google/networking/gbmc-bridge/-bmc-gbmcbrdummy.netdev3
-rw-r--r--meta-google/recipes-google/networking/gbmc-bridge/-bmc-gbmcbrdummy.network4
-rw-r--r--meta-google/recipes-google/networking/gbmc-bridge/50-gbmc-br.rules27
-rw-r--r--meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ensure-ra.service5
-rw-r--r--meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ensure-ra.sh27
-rw-r--r--meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-from-ra.sh96
-rw-r--r--meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-gw-src.sh74
-rw-r--r--meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-nft.sh76
-rw-r--r--meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ula.sh71
-rw-r--r--meta-google/recipes-google/networking/gbmc-bridge/ipmi.service.in11
13 files changed, 416 insertions, 0 deletions
diff --git a/meta-google/recipes-google/networking/gbmc-bridge/+-bmc-gbmcbrusb.network b/meta-google/recipes-google/networking/gbmc-bridge/+-bmc-gbmcbrusb.network
new file mode 100644
index 000000000..e403334b4
--- /dev/null
+++ b/meta-google/recipes-google/networking/gbmc-bridge/+-bmc-gbmcbrusb.network
@@ -0,0 +1,8 @@
+[Match]
+Name=usb*
+[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
diff --git a/meta-google/recipes-google/networking/gbmc-bridge/-bmc-gbmcbr.netdev b/meta-google/recipes-google/networking/gbmc-bridge/-bmc-gbmcbr.netdev
new file mode 100644
index 000000000..d890ef9ff
--- /dev/null
+++ b/meta-google/recipes-google/networking/gbmc-bridge/-bmc-gbmcbr.netdev
@@ -0,0 +1,5 @@
+[NetDev]
+Name=gbmcbr
+Kind=bridge
+[Bridge]
+STP=true
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
new file mode 100644
index 000000000..c6097bbdb
--- /dev/null
+++ b/meta-google/recipes-google/networking/gbmc-bridge/-bmc-gbmcbr.network.in
@@ -0,0 +1,9 @@
+[Match]
+Name=gbmcbr
+[Network]
+@ADDR@
+DHCP=false
+IPv6AcceptRA=true
+LLMNR=true
+MulticastDNS=true
+LinkLocalAddressing=ipv6
diff --git a/meta-google/recipes-google/networking/gbmc-bridge/-bmc-gbmcbrdummy.netdev b/meta-google/recipes-google/networking/gbmc-bridge/-bmc-gbmcbrdummy.netdev
new file mode 100644
index 000000000..97c725812
--- /dev/null
+++ b/meta-google/recipes-google/networking/gbmc-bridge/-bmc-gbmcbrdummy.netdev
@@ -0,0 +1,3 @@
+[NetDev]
+Name=gbmcbrdummy
+Kind=dummy
diff --git a/meta-google/recipes-google/networking/gbmc-bridge/-bmc-gbmcbrdummy.network b/meta-google/recipes-google/networking/gbmc-bridge/-bmc-gbmcbrdummy.network
new file mode 100644
index 000000000..7d3f07197
--- /dev/null
+++ b/meta-google/recipes-google/networking/gbmc-bridge/-bmc-gbmcbrdummy.network
@@ -0,0 +1,4 @@
+[Match]
+Name=gbmcbrdummy
+[Network]
+Bridge=gbmcbr
diff --git a/meta-google/recipes-google/networking/gbmc-bridge/50-gbmc-br.rules b/meta-google/recipes-google/networking/gbmc-bridge/50-gbmc-br.rules
new file mode 100644
index 000000000..1a5e6331d
--- /dev/null
+++ b/meta-google/recipes-google/networking/gbmc-bridge/50-gbmc-br.rules
@@ -0,0 +1,27 @@
+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
+ jump gbmc_br_int_input
+ jump gbmc_br_pub_input
+ reject
+ }
+ chain gbmc_br_int_input {
+ ip6 daddr ff00::/8 accept
+ ip6 daddr fe80::/64 accept
+ ip6 daddr fdb5:0481:10ce::/64 accept
+ }
+ chain gbmc_br_pub_input {
+ ip6 nexthdr icmpv6 accept
+ }
+}
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
new file mode 100644
index 000000000..7f97cea48
--- /dev/null
+++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ensure-ra.service
@@ -0,0 +1,5 @@
+[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-ensure-ra.sh b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ensure-ra.sh
new file mode 100644
index 000000000..60e33d89b
--- /dev/null
+++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ensure-ra.sh
@@ -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
diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-from-ra.sh b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-from-ra.sh
new file mode 100644
index 000000000..18341fefb
--- /dev/null
+++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-from-ra.sh
@@ -0,0 +1,96 @@
+# 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.
+
+[ -z "${gbmc_br_from_ra_lib-}" ] || return
+
+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" -a -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() {
+ if [ "$change" = 'init' ]; then
+ gbmc_br_from_ra_init=1
+ gbmc_br_from_ra_update
+ elif [[ "$change" == 'route' && "$route" != *' via '* ]] &&
+ [[ "$route" =~ ^(.* dev gbmcbr proto ra .*)( +expires +([^ ]+)sec).*$ ]]; then
+ pfx="${route%% *}"
+ if [ "$action" = 'add' ]; then
+ gbmc_br_from_ra_pfxs["$pfx"]="${BASH_REMATCH[3]}"
+ gbmc_br_from_ra_update
+ elif [ "$action" = 'del' ]; then
+ gbmc_br_from_ra_pfxs["$pfx"]=0
+ gbmc_br_from_ra_update
+ fi
+ elif [ "$change" = 'link' -a "$intf" = 'gbmcbr' ]; then
+ rdisc6 -m gbmcbr -r 1 -w 100 >/dev/null 2>&1
+ if [ "$action" = 'add' -a "$mac" != "$gbmc_br_from_ra_mac" ]; then
+ gbmc_br_from_ra_mac="$mac"
+ gbmc_br_from_ra_update
+ fi
+ if [ "$action" = 'del' -a "$mac" = "$gbmc_br_from_ra_mac" ]; then
+ gbmc_br_from_ra_mac=
+ gbmc_br_from_ra_update
+ fi
+ fi
+}
+
+GBMC_IP_MONITOR_HOOKS+=(gbmc_br_from_ra_hook)
+
+gbmc_br_from_ra_lib=1
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
new file mode 100644
index 000000000..cfe993f28
--- /dev/null
+++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-gw-src.sh
@@ -0,0 +1,74 @@
+# 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.
+
+[ -z "${gbmc_br_gw_src_lib-}" ] || return
+
+source /usr/share/network/lib.sh || exit
+
+gbmc_br_gw_src_ip=
+declare -A gbmc_br_gw_src_routes=()
+
+gbmc_br_gw_src_update() {
+ [ -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
+ 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.
+ if [[ "$change" == 'route' && "$route" == 'default '*':'* ]]; then
+ if [[ "$route" =~ ^(.*)( +expires +[^ ]+)(.*)$ ]]; then
+ route="${BASH_REMATCH[1]}${BASH_REMATCH[3]}"
+ fi
+ if [ "$action" = 'add' -a -z "${gbmc_br_gw_src_routes["$route"]}" ]; then
+ gbmc_br_gw_src_routes["$route"]=1
+ gbmc_br_gw_src_update
+ elif [ "$action" = 'del' -a -n "${gbmc_br_gw_src_routes["$route"]}" ]; then
+ unset 'gbmc_br_gw_src_routes[$route]'
+ gbmc_br_gw_src_update
+ 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' -a "$intf" = 'gbmcbr' -a "$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
+ if (( ip_bytes[8] != 0xfd || ip_bytes[9] != 0 )); then
+ return 0
+ fi
+ if [ "$action" = 'add' -a "$ip" != "$gbmc_br_gw_src_ip" ]; then
+ gbmc_br_gw_src_ip="$ip"
+ gbmc_br_gw_src_update
+ fi
+ if [ "$action" = 'del' -a "$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
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
new file mode 100644
index 000000000..19b8f64a1
--- /dev/null
+++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-nft.sh
@@ -0,0 +1,76 @@
+# 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.
+
+[ -z "${gbmc_br_nft_lib-}" ] || return
+
+source /usr/share/network/lib.sh || exit
+
+gbmc_br_nft_init=
+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 -m 755 "$(dirname "$rfile")"
+ printf '%s' "$contents" >"$rfile"
+
+ echo 'Restarting nftables' >&2
+ systemctl reset-failed nftables
+ systemctl --no-block restart nftables
+}
+
+gbmc_br_nft_hook() {
+ if [ "$change" = 'init' ]; then
+ gbmc_br_nft_init=1
+ gbmc_br_nft_update
+ # 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/72 rule.
+ elif [ "$change" = 'addr' -a "$intf" = 'gbmcbr' -a "$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)/72"
+ if [ "$action" = "add" -a "$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
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
new file mode 100644
index 000000000..8e28d3956
--- /dev/null
+++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ula.sh
@@ -0,0 +1,71 @@
+# 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.
+
+[ -z "${gbmc_br_ula_lib-}" ] || return
+
+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 -m 755 "$(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() {
+ if [ "$change" = 'init' ]; then
+ gbmc_br_ula_init=1
+ gbmc_br_ula_update
+ elif [ "$change" = 'link' -a "$intf" = 'gbmcbr' ]; then
+ if [ "$action" = 'add' -a "$mac" != "$gbmc_br_ula_mac" ]; then
+ gbmc_br_ula_mac="$mac"
+ gbmc_br_ula_update
+ fi
+ if [ "$action" = 'del' -a "$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
diff --git a/meta-google/recipes-google/networking/gbmc-bridge/ipmi.service.in b/meta-google/recipes-google/networking/gbmc-bridge/ipmi.service.in
new file mode 100644
index 000000000..0b940fa2d
--- /dev/null
+++ b/meta-google/recipes-google/networking/gbmc-bridge/ipmi.service.in
@@ -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>