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