1#!/bin/bash 2# Copyright 2021 Google LLC 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16[[ -n ${gbmc_br_gw_src_lib-} ]] && return 17 18# shellcheck source=meta-google/recipes-google/networking/network-sh/lib.sh 19source /usr/share/network/lib.sh || exit 20 21gbmc_br_gw_src_ip_stateful= 22gbmc_br_gw_src_ip_stateless= 23declare -A gbmc_br_gw_src_routes=() 24gbmc_br_gw_defgw= 25 26gbmc_br_set_router() { 27 local defgw= 28 local route 29 for route in "${!gbmc_br_gw_src_routes[@]}"; do 30 if [[ $route != *' dev gbmcbr '* ]]; then 31 defgw=1 32 break 33 fi 34 done 35 [[ $defgw == "$gbmc_br_gw_defgw" ]] && return 36 gbmc_br_gw_defgw="$defgw" 37 38 local files=(/run/systemd/network/{00,}-bmc-gbmcbr.network.d/50-defgw.conf) 39 if [[ -n $defgw ]]; then 40 local file 41 for file in "${files[@]}"; do 42 mkdir -p "$(dirname "$file")" 43 printf '[IPv6PrefixDelegation]\nRouterLifetimeSec=30\n' >"$file" 44 done 45 else 46 rm -f "${files[@]}" 47 fi 48 49 if [[ $(systemctl is-active systemd-networkd) != inactive ]]; then 50 networkctl reload && networkctl reconfigure gbmcbr 51 fi 52} 53 54gbmc_br_gw_src_update() { 55 local gbmc_br_gw_src_ip="${gbmc_br_gw_src_ip_stateful:-$gbmc_br_gw_src_ip_stateless}" 56 [[ -n $gbmc_br_gw_src_ip ]] || return 57 58 local route 59 for route in "${!gbmc_br_gw_src_routes[@]}"; do 60 [[ $route != *" src $gbmc_br_gw_src_ip "* ]] || continue 61 echo "gBMC Bridge Updating GW source [$gbmc_br_gw_src_ip]: $route" >&2 62 # shellcheck disable=SC2086 63 ip route change $route src "$gbmc_br_gw_src_ip" && \ 64 unset 'gbmc_br_gw_src_routes[$route]' 65 done 66} 67 68gbmc_br_gw_src_hook() { 69 # We only want to match default gateway routes that are dynamic 70 # (have an expiration time). These will be updated with our preferred 71 # source. 72 # shellcheck disable=SC2154 73 if [[ $change == route && $route == 'default '*':'* ]]; then 74 if [[ $route =~ ^(.*)( +expires +[^ ]+)(.*)$ ]]; then 75 route="${BASH_REMATCH[1]}${BASH_REMATCH[3]}" 76 fi 77 if [[ $action == add && -z ${gbmc_br_gw_src_routes["$route"]} ]]; then 78 gbmc_br_gw_src_routes["$route"]=1 79 gbmc_br_gw_src_update 80 gbmc_br_set_router 81 elif [[ $action == del && -n "${gbmc_br_gw_src_routes["$route"]}" ]]; then 82 unset 'gbmc_br_gw_src_routes[$route]' 83 gbmc_br_gw_src_update 84 gbmc_br_set_router 85 fi 86 # Match only global IP addresses on the bridge that match the BMC stateless 87 # prefix (<mpfx>:fd00:). So 2002:af4:3480:2248:fd00:6345:3069:9186 would be 88 # matched as the preferred source IP for outoging traffic. 89 elif [[ $change == addr && $intf == gbmcbr && $scope == global ]] && 90 [[ $fam == inet6 && $flags != *tentative* ]]; then 91 local ip_bytes=() 92 if ! ip_to_bytes ip_bytes "$ip"; then 93 echo "gBMC Bridge Ensure RA Invalid IP: $ip" >&2 94 return 1 95 fi 96 # Ignore ULAs and non-gBMC addresses 97 if (( (ip_bytes[0] & 0xfe) == 0xfc || ip_bytes[8] != 0xfd )); then 98 return 0 99 fi 100 if (( (ip_bytes[9] & 0xf) != 0 )); then 101 local -n gbmc_br_gw_src_ip=gbmc_br_gw_src_ip_stateful 102 else 103 local -n gbmc_br_gw_src_ip=gbmc_br_gw_src_ip_stateless 104 fi 105 if [[ $action == add && $ip != "$gbmc_br_gw_src_ip" ]]; then 106 gbmc_br_gw_src_ip="$ip" 107 gbmc_br_gw_src_update 108 fi 109 if [[ $action == del && $ip == "$gbmc_br_gw_src_ip" ]]; then 110 gbmc_br_gw_src_ip= 111 fi 112 fi 113} 114 115GBMC_IP_MONITOR_HOOKS+=(gbmc_br_gw_src_hook) 116 117gbmc_br_gw_src_lib=1 118