1#!/bin/bash 2# Copyright 2022 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# shellcheck source=meta-google/recipes-google/networking/network-sh/lib.sh 17source /usr/share/network/lib.sh || exit 18 19# Wait until a well known service is network available 20echo 'Waiting for network reachability' >&2 21while true; do 22 before=$SECONDS 23 addrs="$(ip addr show gbmcbr | grep '^ *inet6' | awk '{print $2}')" 24 for addr in $addrs; do 25 # Remove the prefix length 26 ip="${addr%/*}" 27 ip_to_bytes ip_bytes "$ip" || continue 28 # Ignore ULAs and non-gBMC addresses 29 (( (ip_bytes[0] & 0xfc) == 0xfc || ip_bytes[8] != 0xfd )) && continue 30 # Only allow for the short, well known addresses <pfx>:fd01:: and not 31 # <pfx>:fd00:83c1:292d:feef. Otherwise, powercycle may be unavailable. 32 (( (ip_bytes[9] & 0x0f) == 0 )) && continue 33 for i in {10..15}; do 34 (( ip_bytes[i] != 0 )) && continue 2 35 done 36 echo "Trying reachability from $ip" >&2 37 for i in {0..5}; do 38 ping -I "$ip" -c 1 -W 1 2001:4860:4860::8888 >/dev/null 2>&1 && break 3 39 sleep 1 40 done 41 done 42 # Ensure we only complete the addr lookup loop every 10s 43 tosleep=$((before + 10 - SECONDS)) 44 if (( tosleep > 0 )); then 45 sleep "$tosleep" 46 fi 47done 48 49# We need to guarantee we wait at least 10 minutes from reachable in 50# case networking just came up 51wait_min=10 52echo "Network is reachable, waiting $wait_min min" >&2 53sleep $((60 * wait_min)) 54 55get_dhcp_unit_json() { 56 busctl -j call \ 57 org.freedesktop.systemd1 \ 58 /org/freedesktop/systemd1/unit/system_2dgbmc_5cx2dbr_5cx2ddhcp_2eslice \ 59 org.freedesktop.DBus.Properties \ 60 GetAll s org.freedesktop.systemd1.Unit 61} 62 63# Follow the process and make sure it idles for at least 10 minutes before 64# shutting down. This allows for failures and retries to happen. 65while true; do 66 json="$(get_dhcp_unit_json)" || exit 67 last_ms="$(echo "$json" | jq -r '.data[0].StateChangeTimestampMonotonic.data')" 68 if pid="$(cat /run/gbmc-br-dhcp.pid 2>/dev/null)" && [ -n "$pid" ]; then 69 # If the DHCP configuration process is running, wait for it to finish 70 echo "DHCP still running ($pid), waiting" >&2 71 while [[ -e /proc/$pid ]]; do 72 sleep 1 73 done 74 # Wait for systemd to detect the process state change 75 while true; do 76 json="$(get_dhcp_unit_json)" || exit 77 ms="$(echo "$json" | jq -r '.data[0].StateChangeTimestampMonotonic.data')" 78 (( ms != last_ms )) && break 79 sleep 1 80 done 81 fi 82 83 echo 'Checking DHCP Active State' >&2 84 json="$(get_dhcp_unit_json)" || exit 85 activestr="$(echo "$json" | jq -r '.data[0].ActiveState.data')" 86 87 # The process is already stopped, we are done 88 [[ "$activestr" == 'inactive' ]] && exit 89 90 # If the process is running, give it at least 10 minutes from when it started 91 cur_s="$(cut -d' ' -f1 /proc/uptime)" 92 # Remove floating point if applied since bash can't perform float arithmetic 93 cur_s="${cur_s%.*}" 94 if [[ "$activestr" == 'active' ]]; then 95 active_ms="$(echo "$json" | jq -r '.data[0].ActiveEnterTimestampMonotonic.data')" 96 else 97 active_ms=$((cur_s*1000*1000)) 98 fi 99 w=$((active_ms/1000/1000 + (wait_min*60) - cur_s)) 100 [ "$w" -lt 0 ] && break 101 echo "Waiting ${w}s for DHCP process" >&2 102 sleep "$w" 103done 104 105echo "Stopping DHCP processing" >&2 106systemctl stop --no-block gbmc-br-dhcp@'*' 107