#!/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 declare -A gbmc_br_ulas=() # BITs set for address suffixes GBMC_BR_ULA_SFX_HAS_LL=1 GBMC_BR_ULA_SFX_HAS_ULA=2 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 done } 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 )) } 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_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 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 } GBMC_IP_MONITOR_HOOKS+=(gbmc_br_ula_hook) gbmc_br_ula_lib=1