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_from_ra_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_from_ra_init=
22gbmc_br_from_ra_mac=
23declare -A gbmc_br_from_ra_pfxs=()
24declare -A gbmc_br_from_ra_prev_addrs=()
25
26gbmc_br_from_ra_update() {
27  [[ -n $gbmc_br_from_ra_init && -n $gbmc_br_from_ra_mac ]] || return
28
29  local pfx
30  for pfx in "${!gbmc_br_from_ra_pfxs[@]}"; do
31    local cidr
32    if ! cidr="$(ip_pfx_to_cidr "$pfx")"; then
33      unset 'gbmc_br_from_ra_pfxs[$pfx]'
34      continue
35    fi
36    if (( cidr == 80 )); then
37      local sfx
38      if ! sfx="$(mac_to_eui48 "$gbmc_br_from_ra_mac")"; then
39        unset 'gbmc_br_from_ra_pfxs[$pfx]'
40        continue
41      fi
42      local addr
43      if ! addr="$(ip_pfx_concat "$pfx" "$sfx")"; then
44        unset 'gbmc_br_from_ra_pfxs[$pfx]'
45        continue
46      fi
47    else
48      unset 'gbmc_br_from_ra_pfxs[$pfx]'
49      continue
50    fi
51    local valid="${gbmc_br_from_ra_pfxs["$pfx"]}"
52    if (( valid > 0 )); then
53      if [[ -z ${gbmc_br_from_ra_prev_addrs["$addr"]-} ]]; then
54        echo "gBMC Bridge RA Addr Add: $addr" >&2
55        gbmc_br_from_ra_prev_addrs["$addr"]=1
56      fi
57      ip addr replace "$addr" dev gbmcbr noprefixroute
58    else
59      if [[ -n ${gbmc_br_from_ra_prev_addrs["$addr"]-} ]]; then
60        echo "gBMC Bridge RA Addr Del: $addr" >&2
61        unset 'gbmc_br_from_ra_prev_addrs[$addr]'
62      fi
63      ip addr del "$addr" dev gbmcbr
64      unset 'gbmc_br_from_ra_pfxs[$pfx]'
65    fi
66  done
67}
68
69gbmc_br_from_ra_hook() {
70  # shellcheck disable=SC2154
71  if [[ $change == init ]]; then
72    gbmc_br_from_ra_init=1
73    gbmc_ip_monitor_defer
74  elif [[ $change == defer ]]; then
75    gbmc_br_from_ra_update
76  elif [[ $change == route && $route != *' via '* ]] &&
77       [[ $route =~ ^(.* dev gbmcbr proto ra .*)( +expires +([^ ]+)sec).*$ ]]; then
78    pfx="${route%% *}"
79    # shellcheck disable=SC2154
80    if [[ $action == add ]]; then
81      gbmc_br_from_ra_pfxs["$pfx"]="${BASH_REMATCH[3]}"
82      gbmc_ip_monitor_defer
83    elif [[ $action == del ]]; then
84      gbmc_br_from_ra_pfxs["$pfx"]=0
85      gbmc_ip_monitor_defer
86    fi
87  elif [[ $change == link && $intf == gbmcbr ]]; then
88    rdisc6 -m gbmcbr -r 1 -w 100 >/dev/null 2>&1
89    if [[ $action == add && $mac != "$gbmc_br_from_ra_mac" ]]; then
90      gbmc_br_from_ra_mac="$mac"
91      gbmc_ip_monitor_defer
92    fi
93    if [[ $action == del && $mac == "$gbmc_br_from_ra_mac" ]]; then
94      gbmc_br_from_ra_mac=
95      gbmc_ip_monitor_defer
96    fi
97  fi
98}
99
100GBMC_IP_MONITOR_HOOKS+=(gbmc_br_from_ra_hook)
101
102gbmc_br_from_ra_lib=1
103