blob: 371a7cc46e4257b8f01577c0b06c702dc1738cd2 [file] [log] [blame]
William A. Kennington III379b0612021-11-04 02:42:30 -07001#!/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
16source "$(dirname "${BASH_SOURCE[0]}")"/ncsid_lib.sh
17
William A. Kennington III246bcaa2022-02-11 02:53:28 -080018NCSI_IF="$1"
William A. Kennington III379b0612021-11-04 02:42:30 -070019
William A. Kennington IIIa9b18222024-06-17 14:15:42 -070020# We would prefer empty string but it's easier for associative array handling
21# to use invalid
22old_rtr=invalid
William A. Kennington III246bcaa2022-02-11 02:53:28 -080023old_mac=
24
William A. Kennington IIIa9bd43e2024-06-20 16:43:38 -070025function apply_rtr() {
26 local rtr="$1"
27 local mac="$2"
28 # Don't force networkd to reload as this can break phosphor-networkd
29 # Fall back to reload only if ip link commands fail
30 (ip -6 route replace default via "$rtr" dev "$NCSI_IF" && \
31 ip -6 neigh replace "$rtr" dev "$NCSI_IF" lladdr "$mac") || \
32 (networkctl reload && networkctl reconfigure "$NCSI_IF") || true
33}
34
Patrick Williams59486672022-12-08 06:23:47 -060035function set_rtr() {
Patrick Williams59486672022-12-08 06:23:47 -060036 [ "$rtr" != "$old_rtr" -a "$mac" != "$old_mac" ] || return
William A. Kennington III246bcaa2022-02-11 02:53:28 -080037
Patrick Williams59486672022-12-08 06:23:47 -060038 echo "Setting default router: $rtr at $mac" >&2
William A. Kennington III5034c562024-03-19 14:00:52 -070039
40 # Delete and static gateways and neighbors
41 while read entry; do
42 eval "$(echo "$entry" | JSONToVars)" || return
43 echo "Deleting neighbor $object"
44 DeleteObject "$service" "$object" || true
45 done < <(GetNeighborObjects "$netdev" 2>/dev/null)
46
47 busctl set-property xyz.openbmc_project.Network "$(EthObjRoot "$NCSI_IF")" \
48 xyz.openbmc_project.Network.EthernetInterface DefaultGateway6 s "" || true
49
50 # In case we don't have a base network file, make one
51 net_file=/run/systemd/network/00-bmc-$NCSI_IF.network
52 printf '[Match]\nName=%s\n[Network]\nDHCP=false\nIPv6AcceptRA=false\nLinkLocalAddressing=yes' \
53 "$NCSI_IF" >$net_file
54
55 # Override any existing gateway info
56 mkdir -p $net_file.d
57 printf '[Network]\nGateway=%s\n[Neighbor]\nMACAddress=%s\nAddress=%s' \
58 "$rtr" "$mac" "$rtr" >$net_file.d/10-gateway.conf
59
William A. Kennington IIIa9bd43e2024-06-20 16:43:38 -070060 apply_rtr "$rtr" "$mac"
William A. Kennington III246bcaa2022-02-11 02:53:28 -080061
Patrick Williams59486672022-12-08 06:23:47 -060062 retries=-1
63 old_mac="$mac"
64 old_rtr="$rtr"
William A. Kennington III246bcaa2022-02-11 02:53:28 -080065}
66
William A. Kennington IIIa9bd43e2024-06-20 16:43:38 -070067function fixup_router() {
68 [ -z "$old_mac" ] && return
69 ip -6 route show | grep -q "^default .*dev $NCSI_IF" && return
70 echo 'Default route missing, reconfiguring...' >&2
71 apply_rtr "$old_rtr" "$old_mac"
72}
73
William A. Kennington III246bcaa2022-02-11 02:53:28 -080074retries=1
William A. Kennington IIIa9b18222024-06-17 14:15:42 -070075min_w=10
76declare -A rtrs
77rtrs=()
William A. Kennington III246bcaa2022-02-11 02:53:28 -080078while true; do
William A. Kennington IIIa9b18222024-06-17 14:15:42 -070079 data=(${rtrs["${old_rtr}"]-})
80 curr_dl="${data[1]-$min_w}"
81 args=(-m "$NCSI_IF" -w $(( (curr_dl - SECONDS) * 1000 )))
Patrick Williams59486672022-12-08 06:23:47 -060082 if (( retries > 0 )); then
83 args+=(-r "$retries")
84 else
85 args+=(-d)
William A. Kennington III379b0612021-11-04 02:42:30 -070086 fi
Patrick Williams59486672022-12-08 06:23:47 -060087 while read line; do
William A. Kennington IIId36d9ef2024-03-19 14:02:42 -070088 # `script` terminates all lines with a CRLF, remove it
89 line="${line:0:-1}"
Patrick Williams59486672022-12-08 06:23:47 -060090 if [ -z "$line" ]; then
William A. Kennington IIIa9b18222024-06-17 14:15:42 -070091 lifetime=-1
Patrick Williams59486672022-12-08 06:23:47 -060092 mac=
93 elif [[ "$line" =~ ^Router' 'lifetime' '*:' '*([0-9]*) ]]; then
94 lifetime="${BASH_REMATCH[1]}"
95 elif [[ "$line" =~ ^Source' 'link-layer' 'address' '*:' '*([a-fA-F0-9:]*)$ ]]; then
96 mac="${BASH_REMATCH[1]}"
97 elif [[ "$line" =~ ^from' '(.*)$ ]]; then
98 rtr="${BASH_REMATCH[1]}"
William A. Kennington IIIa9b18222024-06-17 14:15:42 -070099 # Only valid default routers can be considered, 0 lifetime implies
100 # a non-default router
101 if (( lifetime > 0 )); then
102 dl=$((lifetime + SECONDS))
103 rtrs["$rtr"]="$mac $dl"
William A. Kennington III1e2289c2024-06-17 14:57:25 -0700104 # We have some notoriously noisy lab environments with many routers being broadcast
105 # We always prefer "fe80::1" in prod and labs for routing, so prefer that gateway.
106 # We also want to take the first router we find to speed up acquisition on boot.
107 if [ "$rtr" = "fe80::1" -o -z "$old_rtr" ]; then
William A. Kennington IIIa9b18222024-06-17 14:15:42 -0700108 set_rtr || true
109 fi
110 fi
111 lifetime=-1
Patrick Williams59486672022-12-08 06:23:47 -0600112 mac=
William A. Kennington IIIa9bd43e2024-06-20 16:43:38 -0700113 # We sometimes lose the router configuration on some of our platforms
114 # Run a fixup whenever we receive a valid RA to ensure it's set correctly
115 fixup_router || true
Patrick Williams59486672022-12-08 06:23:47 -0600116 fi
William A. Kennington IIId36d9ef2024-03-19 14:02:42 -0700117 done < <(exec script -q -c "rdisc6 ${args[*]}" /dev/null 2>/dev/null)
William A. Kennington IIIa9b18222024-06-17 14:15:42 -0700118 # Purge any expired routers
119 for rtr in "${!rtrs[@]}"; do
120 data=(${rtrs["$rtr"]})
121 dl=${data[1]}
122 if (( dl <= SECONDS )); then
123 unset rtrs["$rtr"]
124 fi
125 done
126 # Consider changing the gateway if the old one doesn't send RAs for the entire period
127 # This ensures we don't flip flop between multiple defaults if they exist.
128 if [ -z "${rtrs["$old_rtr"]-}" ]; then
129 echo "Old router $old_rtr disappeared" >&2
130 for rtr in "${!rtrs[@]}"; do
131 data=(${rtrs["$rtr"]})
132 mac=${data[0]}
133 dl=${data[1]}
134 set_rtr && break
135 done
136 fi
137
138 # If rdisc6 exits early we still want to wait for the deadline before retrying
139 (( timeout = curr_dl - SECONDS ))
Patrick Williams59486672022-12-08 06:23:47 -0600140 sleep $(( timeout < 0 ? 0 : timeout ))
William A. Kennington III246bcaa2022-02-11 02:53:28 -0800141done