William A. Kennington III | e33ec59 | 2021-03-10 17:43:48 -0800 | [diff] [blame] | 1 | #!/bin/bash |
William A. Kennington III | b06ae50 | 2023-06-05 14:35:17 -0700 | [diff] [blame] | 2 | # shellcheck disable=SC2034 |
| 3 | # shellcheck disable=SC2317 |
William A. Kennington III | e33ec59 | 2021-03-10 17:43:48 -0800 | [diff] [blame] | 4 | # Copyright 2021 Google LLC |
| 5 | # |
| 6 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 7 | # you may not use this file except in compliance with the License. |
| 8 | # You may obtain a copy of the License at |
| 9 | # |
| 10 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | # |
| 12 | # Unless required by applicable law or agreed to in writing, software |
| 13 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 15 | # See the License for the specific language governing permissions and |
| 16 | # limitations under the License. |
| 17 | |
| 18 | # A list of functions which get executed for each netlink event received. |
| 19 | # These are configured by the files included below. |
| 20 | GBMC_IP_MONITOR_HOOKS=() |
| 21 | |
| 22 | # Load configurations from a known location in the filesystem to populate |
| 23 | # hooks that are executed after each event. |
| 24 | shopt -s nullglob |
| 25 | for conf in /usr/share/gbmc-ip-monitor/*.sh; do |
William A. Kennington III | b06ae50 | 2023-06-05 14:35:17 -0700 | [diff] [blame] | 26 | # shellcheck source=/dev/null |
William A. Kennington III | e33ec59 | 2021-03-10 17:43:48 -0800 | [diff] [blame] | 27 | source "$conf" |
| 28 | done |
| 29 | |
| 30 | gbmc_ip_monitor_run_hooks() { |
| 31 | local hook |
| 32 | for hook in "${GBMC_IP_MONITOR_HOOKS[@]}"; do |
| 33 | "$hook" || continue |
| 34 | done |
| 35 | } |
| 36 | |
| 37 | gbmc_ip_monitor_generate_init() { |
| 38 | ip link | sed 's,^[^ ],[LINK]\0,' |
| 39 | local intf= |
| 40 | local line |
William A. Kennington III | b06ae50 | 2023-06-05 14:35:17 -0700 | [diff] [blame] | 41 | while read -r line; do |
William A. Kennington III | e33ec59 | 2021-03-10 17:43:48 -0800 | [diff] [blame] | 42 | [[ "$line" =~ ^([0-9]+:[[:space:]][^:]+) ]] && intf="${BASH_REMATCH[1]}" |
| 43 | [[ "$line" =~ ^[[:space:]]*inet ]] && echo "[ADDR]$intf $line" |
| 44 | done < <(ip addr) |
| 45 | ip -4 route | sed 's,^,[ROUTE],' |
| 46 | ip -6 route | sed 's,^,[ROUTE],' |
| 47 | echo '[INIT]' |
| 48 | } |
| 49 | |
William A. Kennington III | cefbd1c | 2021-11-05 03:52:53 -0700 | [diff] [blame] | 50 | GBMC_IP_MONITOR_DEFER_OUTSTANDING= |
| 51 | gbmc_ip_monitor_defer_() { |
| 52 | sleep 1 |
William A. Kennington III | b06ae50 | 2023-06-05 14:35:17 -0700 | [diff] [blame] | 53 | printf '[DEFER]\n' >&"$GBMC_IP_MONITOR_DEFER" |
William A. Kennington III | cefbd1c | 2021-11-05 03:52:53 -0700 | [diff] [blame] | 54 | } |
| 55 | gbmc_ip_monitor_defer() { |
| 56 | [ -z "$GBMC_IP_MONITOR_DEFER_OUTSTANDING" ] || return 0 |
| 57 | gbmc_ip_monitor_defer_ & |
| 58 | GBMC_IP_MONITOR_DEFER_OUTSTANDING=1 |
| 59 | } |
| 60 | |
William A. Kennington III | e33ec59 | 2021-03-10 17:43:48 -0800 | [diff] [blame] | 61 | gbmc_ip_monitor_parse_line() { |
| 62 | local line="$1" |
| 63 | if [[ "$line" == '[INIT]'* ]]; then |
| 64 | change=init |
| 65 | echo "Initialized" >&2 |
| 66 | elif [[ "$line" == '[ADDR]'* ]]; then |
| 67 | change=addr |
| 68 | action=add |
| 69 | pfx_re='^\[ADDR\](Deleted )?[0-9]+:[[:space:]]*' |
| 70 | intf_re='([^ ]+)[[:space:]]+' |
| 71 | fam_re='([^ ]+)[[:space:]]+' |
William A. Kennington III | f4ce04c | 2022-05-20 09:39:45 -0700 | [diff] [blame] | 72 | addr_re='([^/]+)/[0-9]+[[:space:]]+' |
| 73 | metric_re='(metric[[:space:]]+[^ ]+[[:space:]]+)?' |
| 74 | brd_re='(brd[[:space:]]+[^ ]+[[:space:]]+)?' |
William A. Kennington III | e33ec59 | 2021-03-10 17:43:48 -0800 | [diff] [blame] | 75 | scope_re='scope[[:space:]]+([^ ]+)[[:space:]]*(.*)' |
William A. Kennington III | f4ce04c | 2022-05-20 09:39:45 -0700 | [diff] [blame] | 76 | combined_re="${pfx_re}${intf_re}${fam_re}${addr_re}${metric_re}${brd_re}${scope_re}" |
William A. Kennington III | e33ec59 | 2021-03-10 17:43:48 -0800 | [diff] [blame] | 77 | if ! [[ "$line" =~ ${combined_re} ]]; then |
| 78 | echo "Failed to parse addr: $line" >&2 |
| 79 | return 1 |
| 80 | fi |
| 81 | if [ -n "${BASH_REMATCH[1]}" ]; then |
| 82 | action=del |
| 83 | fi |
| 84 | intf="${BASH_REMATCH[2]}" |
| 85 | fam="${BASH_REMATCH[3]}" |
| 86 | ip="${BASH_REMATCH[4]}" |
William A. Kennington III | f4ce04c | 2022-05-20 09:39:45 -0700 | [diff] [blame] | 87 | scope="${BASH_REMATCH[7]}" |
| 88 | flags="${BASH_REMATCH[8]}" |
William A. Kennington III | e33ec59 | 2021-03-10 17:43:48 -0800 | [diff] [blame] | 89 | elif [[ "$line" == '[ROUTE]'* ]]; then |
| 90 | line="${line#[ROUTE]}" |
| 91 | change=route |
| 92 | action=add |
| 93 | if ! [[ "$line" =~ ^\[ROUTE\](Deleted )?(.*)$ ]]; then |
| 94 | echo "Failed to parse link: $line" >&2 |
| 95 | return 1 |
| 96 | fi |
| 97 | if [ -n "${BASH_REMATCH[1]}" ]; then |
| 98 | action=del |
| 99 | fi |
| 100 | route="${BASH_REMATCH[2]}" |
| 101 | elif [[ "$line" == '[LINK]'* ]]; then |
William A. Kennington III | b06ae50 | 2023-06-05 14:35:17 -0700 | [diff] [blame] | 102 | change='link' |
William A. Kennington III | e33ec59 | 2021-03-10 17:43:48 -0800 | [diff] [blame] | 103 | action=add |
| 104 | pfx_re='^\[LINK\](Deleted )?[0-9]+:[[:space:]]*' |
| 105 | intf_re='([^:]+):[[:space:]]+' |
| 106 | if ! [[ "$line" =~ ${pfx_re}${intf_re} ]]; then |
| 107 | echo "Failed to parse link: $line" >&2 |
| 108 | return 1 |
| 109 | fi |
| 110 | if [ -n "${BASH_REMATCH[1]}" ]; then |
| 111 | action=del |
| 112 | fi |
| 113 | intf="${BASH_REMATCH[2]}" |
William A. Kennington III | b06ae50 | 2023-06-05 14:35:17 -0700 | [diff] [blame] | 114 | read -ra data || return |
William A. Kennington III | e33ec59 | 2021-03-10 17:43:48 -0800 | [diff] [blame] | 115 | mac="${data[1]}" |
William A. Kennington III | cefbd1c | 2021-11-05 03:52:53 -0700 | [diff] [blame] | 116 | elif [[ "$line" == '[DEFER]'* ]]; then |
| 117 | GBMC_IP_MONITOR_DEFER_OUTSTANDING= |
| 118 | change=defer |
William A. Kennington III | e33ec59 | 2021-03-10 17:43:48 -0800 | [diff] [blame] | 119 | else |
| 120 | return 2 |
| 121 | fi |
| 122 | } |
| 123 | |
William A. Kennington III | cefbd1c | 2021-11-05 03:52:53 -0700 | [diff] [blame] | 124 | return 0 2>/dev/null |
| 125 | |
William A. Kennington III | e33ec59 | 2021-03-10 17:43:48 -0800 | [diff] [blame] | 126 | cleanup() { |
| 127 | local st="$?" |
| 128 | trap - HUP INT QUIT ABRT TERM EXIT |
| 129 | jobs -l -p | xargs -r kill || true |
William A. Kennington III | b06ae50 | 2023-06-05 14:35:17 -0700 | [diff] [blame] | 130 | exit "$st" |
William A. Kennington III | e33ec59 | 2021-03-10 17:43:48 -0800 | [diff] [blame] | 131 | } |
| 132 | trap cleanup HUP INT QUIT ABRT TERM EXIT |
| 133 | |
William A. Kennington III | cefbd1c | 2021-11-05 03:52:53 -0700 | [diff] [blame] | 134 | FIFODIR="$(mktemp -d)" |
| 135 | mkfifo "$FIFODIR"/fifo |
| 136 | exec {GBMC_IP_MONITOR_DEFER}<>"$FIFODIR"/fifo |
| 137 | rm -rf "$FIFODIR" |
William A. Kennington III | e33ec59 | 2021-03-10 17:43:48 -0800 | [diff] [blame] | 138 | |
William A. Kennington III | b06ae50 | 2023-06-05 14:35:17 -0700 | [diff] [blame] | 139 | while read -r line; do |
William A. Kennington III | 593f2bd | 2021-04-26 13:31:45 -0700 | [diff] [blame] | 140 | gbmc_ip_monitor_parse_line "$line" || continue |
William A. Kennington III | e33ec59 | 2021-03-10 17:43:48 -0800 | [diff] [blame] | 141 | gbmc_ip_monitor_run_hooks || continue |
| 142 | if [ "$change" = 'init' ]; then |
| 143 | systemd-notify --ready |
| 144 | fi |
William A. Kennington III | b06ae50 | 2023-06-05 14:35:17 -0700 | [diff] [blame] | 145 | done < <(gbmc_ip_monitor_generate_init; ip monitor link addr route label & cat <&"$GBMC_IP_MONITOR_DEFER") |