1379b061fSWilliam A. Kennington III#!/bin/bash
2379b061fSWilliam A. Kennington III# Copyright 2021 Google LLC
3379b061fSWilliam A. Kennington III#
4379b061fSWilliam A. Kennington III# Licensed under the Apache License, Version 2.0 (the "License");
5379b061fSWilliam A. Kennington III# you may not use this file except in compliance with the License.
6379b061fSWilliam A. Kennington III# You may obtain a copy of the License at
7379b061fSWilliam A. Kennington III#
8379b061fSWilliam A. Kennington III#      http://www.apache.org/licenses/LICENSE-2.0
9379b061fSWilliam A. Kennington III#
10379b061fSWilliam A. Kennington III# Unless required by applicable law or agreed to in writing, software
11379b061fSWilliam A. Kennington III# distributed under the License is distributed on an "AS IS" BASIS,
12379b061fSWilliam A. Kennington III# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13379b061fSWilliam A. Kennington III# See the License for the specific language governing permissions and
14379b061fSWilliam A. Kennington III# limitations under the License.
15379b061fSWilliam A. Kennington III
16379b061fSWilliam A. Kennington IIIsource "$(dirname "${BASH_SOURCE[0]}")"/ncsid_lib.sh
17379b061fSWilliam A. Kennington III
18246bcaa4SWilliam A. Kennington IIINCSI_IF="$1"
19379b061fSWilliam A. Kennington III
20a9b1822bSWilliam A. Kennington III# We would prefer empty string but it's easier for associative array handling
21a9b1822bSWilliam A. Kennington III# to use invalid
22a9b1822bSWilliam A. Kennington IIIold_rtr=invalid
23246bcaa4SWilliam A. Kennington IIIold_mac=
24246bcaa4SWilliam A. Kennington III
25a9bd43e7SWilliam A. Kennington IIIfunction apply_rtr() {
26a9bd43e7SWilliam A. Kennington III    local rtr="$1"
27a9bd43e7SWilliam A. Kennington III    local mac="$2"
28a9bd43e7SWilliam A. Kennington III    # Don't force networkd to reload as this can break phosphor-networkd
29a9bd43e7SWilliam A. Kennington III    # Fall back to reload only if ip link commands fail
30a9bd43e7SWilliam A. Kennington III    (ip -6 route replace default via "$rtr" dev "$NCSI_IF" && \
31a9bd43e7SWilliam A. Kennington III        ip -6 neigh replace "$rtr" dev "$NCSI_IF" lladdr "$mac") || \
32a9bd43e7SWilliam A. Kennington III        (networkctl reload && networkctl reconfigure "$NCSI_IF") || true
33a9bd43e7SWilliam A. Kennington III}
34a9bd43e7SWilliam A. Kennington III
3559486679SPatrick Williamsfunction set_rtr() {
36246bcaa4SWilliam A. Kennington III    [ "$rtr" != "$old_rtr" -a "$mac" != "$old_mac" ] || return
37246bcaa4SWilliam A. Kennington III
38246bcaa4SWilliam A. Kennington III    echo "Setting default router: $rtr at $mac" >&2
395034c566SWilliam A. Kennington III
405034c566SWilliam A. Kennington III    # Delete and static gateways and neighbors
415034c566SWilliam A. Kennington III    while read entry; do
425034c566SWilliam A. Kennington III        eval "$(echo "$entry" | JSONToVars)" || return
435034c566SWilliam A. Kennington III        echo "Deleting neighbor $object"
445034c566SWilliam A. Kennington III        DeleteObject "$service" "$object" || true
455034c566SWilliam A. Kennington III    done < <(GetNeighborObjects "$netdev" 2>/dev/null)
465034c566SWilliam A. Kennington III
475034c566SWilliam A. Kennington III    busctl set-property xyz.openbmc_project.Network "$(EthObjRoot "$NCSI_IF")" \
485034c566SWilliam A. Kennington III        xyz.openbmc_project.Network.EthernetInterface DefaultGateway6 s "" || true
495034c566SWilliam A. Kennington III
505034c566SWilliam A. Kennington III    # In case we don't have a base network file, make one
515034c566SWilliam A. Kennington III    net_file=/run/systemd/network/00-bmc-$NCSI_IF.network
525034c566SWilliam A. Kennington III    printf '[Match]\nName=%s\n[Network]\nDHCP=false\nIPv6AcceptRA=false\nLinkLocalAddressing=yes' \
535034c566SWilliam A. Kennington III        "$NCSI_IF" >$net_file
545034c566SWilliam A. Kennington III
555034c566SWilliam A. Kennington III    # Override any existing gateway info
565034c566SWilliam A. Kennington III    mkdir -p $net_file.d
575034c566SWilliam A. Kennington III    printf '[Network]\nGateway=%s\n[Neighbor]\nMACAddress=%s\nAddress=%s' \
585034c566SWilliam A. Kennington III        "$rtr" "$mac" "$rtr" >$net_file.d/10-gateway.conf
595034c566SWilliam A. Kennington III
60a9bd43e7SWilliam A. Kennington III    apply_rtr "$rtr" "$mac"
61246bcaa4SWilliam A. Kennington III
62246bcaa4SWilliam A. Kennington III    retries=-1
63246bcaa4SWilliam A. Kennington III    old_mac="$mac"
64246bcaa4SWilliam A. Kennington III    old_rtr="$rtr"
65246bcaa4SWilliam A. Kennington III}
66246bcaa4SWilliam A. Kennington III
67a9bd43e7SWilliam A. Kennington IIIfunction fixup_router() {
68a9bd43e7SWilliam A. Kennington III    [ -z "$old_mac" ] && return
69a9bd43e7SWilliam A. Kennington III    ip -6 route show | grep -q "^default .*dev $NCSI_IF" && return
70a9bd43e7SWilliam A. Kennington III    echo 'Default route missing, reconfiguring...' >&2
71a9bd43e7SWilliam A. Kennington III    apply_rtr "$old_rtr" "$old_mac"
72a9bd43e7SWilliam A. Kennington III}
73a9bd43e7SWilliam A. Kennington III
74246bcaa4SWilliam A. Kennington IIIretries=1
75a9b1822bSWilliam A. Kennington IIImin_w=10
76a9b1822bSWilliam A. Kennington IIIdeclare -A rtrs
77a9b1822bSWilliam A. Kennington IIIrtrs=()
78246bcaa4SWilliam A. Kennington IIIwhile true; do
79a9b1822bSWilliam A. Kennington III    data=(${rtrs["${old_rtr}"]-})
80*177e7270SYuxiao Zhang    curr_dl="${data[1]-$(( min_w + SECONDS ))}"
81a9b1822bSWilliam A. Kennington III    args=(-m "$NCSI_IF" -w $(( (curr_dl - SECONDS) * 1000 )))
82246bcaa4SWilliam A. Kennington III    if (( retries > 0 )); then
83246bcaa4SWilliam A. Kennington III        args+=(-r "$retries")
84246bcaa4SWilliam A. Kennington III    else
85246bcaa4SWilliam A. Kennington III        args+=(-d)
86379b061fSWilliam A. Kennington III    fi
87246bcaa4SWilliam A. Kennington III    while read line; do
88d36d9ef6SWilliam A. Kennington III        # `script` terminates all lines with a CRLF, remove it
89d36d9ef6SWilliam A. Kennington III        line="${line:0:-1}"
90246bcaa4SWilliam A. Kennington III        if [ -z "$line" ]; then
91a9b1822bSWilliam A. Kennington III            lifetime=-1
92246bcaa4SWilliam A. Kennington III            mac=
93246bcaa4SWilliam A. Kennington III        elif [[ "$line" =~ ^Router' 'lifetime' '*:' '*([0-9]*) ]]; then
94246bcaa4SWilliam A. Kennington III            lifetime="${BASH_REMATCH[1]}"
95246bcaa4SWilliam A. Kennington III        elif [[ "$line" =~ ^Source' 'link-layer' 'address' '*:' '*([a-fA-F0-9:]*)$ ]]; then
96246bcaa4SWilliam A. Kennington III            mac="${BASH_REMATCH[1]}"
97246bcaa4SWilliam A. Kennington III        elif [[ "$line" =~ ^from' '(.*)$ ]]; then
98246bcaa4SWilliam A. Kennington III            rtr="${BASH_REMATCH[1]}"
99a9b1822bSWilliam A. Kennington III            # Only valid default routers can be considered, 0 lifetime implies
100a9b1822bSWilliam A. Kennington III            # a non-default router
101a9b1822bSWilliam A. Kennington III            if (( lifetime > 0 )); then
102a9b1822bSWilliam A. Kennington III                dl=$((lifetime + SECONDS))
103a9b1822bSWilliam A. Kennington III                rtrs["$rtr"]="$mac $dl"
1041e2289c8SWilliam A. Kennington III                # We have some notoriously noisy lab environments with many routers being broadcast
1051e2289c8SWilliam A. Kennington III                # We always prefer "fe80::1" in prod and labs for routing, so prefer that gateway.
1061e2289c8SWilliam A. Kennington III                # We also want to take the first router we find to speed up acquisition on boot.
10708988f3dSWilliam A. Kennington III                if [ "$rtr" = "fe80::1" -o "$old_rtr" = "invalid" ]; then
108246bcaa4SWilliam A. Kennington III                    set_rtr || true
109a9b1822bSWilliam A. Kennington III                fi
110a9b1822bSWilliam A. Kennington III            fi
111a9b1822bSWilliam A. Kennington III            lifetime=-1
112246bcaa4SWilliam A. Kennington III            mac=
113a9bd43e7SWilliam A. Kennington III            # We sometimes lose the router configuration on some of our platforms
114a9bd43e7SWilliam A. Kennington III            # Run a fixup whenever we receive a valid RA to ensure it's set correctly
115a9bd43e7SWilliam A. Kennington III            fixup_router || true
116246bcaa4SWilliam A. Kennington III        fi
117d36d9ef6SWilliam A. Kennington III    done < <(exec script -q -c "rdisc6 ${args[*]}" /dev/null 2>/dev/null)
118a9b1822bSWilliam A. Kennington III    # Purge any expired routers
119a9b1822bSWilliam A. Kennington III    for rtr in "${!rtrs[@]}"; do
120a9b1822bSWilliam A. Kennington III        data=(${rtrs["$rtr"]})
121a9b1822bSWilliam A. Kennington III        dl=${data[1]}
122a9b1822bSWilliam A. Kennington III        if (( dl <= SECONDS )); then
123a9b1822bSWilliam A. Kennington III            unset rtrs["$rtr"]
124a9b1822bSWilliam A. Kennington III        fi
125a9b1822bSWilliam A. Kennington III    done
126a9b1822bSWilliam A. Kennington III    # Consider changing the gateway if the old one doesn't send RAs for the entire period
127a9b1822bSWilliam A. Kennington III    # This ensures we don't flip flop between multiple defaults if they exist.
128a9b1822bSWilliam A. Kennington III    if [ -z "${rtrs["$old_rtr"]-}" ]; then
129a9b1822bSWilliam A. Kennington III        echo "Old router $old_rtr disappeared" >&2
130a9b1822bSWilliam A. Kennington III        for rtr in "${!rtrs[@]}"; do
131a9b1822bSWilliam A. Kennington III            data=(${rtrs["$rtr"]})
132a9b1822bSWilliam A. Kennington III            mac=${data[0]}
133a9b1822bSWilliam A. Kennington III            dl=${data[1]}
134a9b1822bSWilliam A. Kennington III            set_rtr && break
135a9b1822bSWilliam A. Kennington III        done
136a9b1822bSWilliam A. Kennington III    fi
137a9b1822bSWilliam A. Kennington III
138a9b1822bSWilliam A. Kennington III    # If rdisc6 exits early we still want to wait for the deadline before retrying
139a9b1822bSWilliam A. Kennington III    (( timeout = curr_dl - SECONDS ))
140246bcaa4SWilliam A. Kennington III    sleep $(( timeout < 0 ? 0 : timeout ))
141379b061fSWilliam A. Kennington IIIdone
142