blob: 74df6aa38be3c951b4478da3e0e256b984e04444 [file] [log] [blame]
William A. Kennington IIIe33ec592021-03-10 17:43:48 -08001#!/bin/bash
William A. Kennington IIIb06ae502023-06-05 14:35:17 -07002# shellcheck disable=SC2034
3# shellcheck disable=SC2317
William A. Kennington IIIe33ec592021-03-10 17:43:48 -08004# 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.
20GBMC_IP_MONITOR_HOOKS=()
21
22# Load configurations from a known location in the filesystem to populate
23# hooks that are executed after each event.
24shopt -s nullglob
25for conf in /usr/share/gbmc-ip-monitor/*.sh; do
William A. Kennington IIIb06ae502023-06-05 14:35:17 -070026 # shellcheck source=/dev/null
William A. Kennington IIIe33ec592021-03-10 17:43:48 -080027 source "$conf"
28done
29
30gbmc_ip_monitor_run_hooks() {
31 local hook
32 for hook in "${GBMC_IP_MONITOR_HOOKS[@]}"; do
33 "$hook" || continue
34 done
35}
36
37gbmc_ip_monitor_generate_init() {
38 ip link | sed 's,^[^ ],[LINK]\0,'
39 local intf=
40 local line
William A. Kennington IIIb06ae502023-06-05 14:35:17 -070041 while read -r line; do
William A. Kennington IIIe33ec592021-03-10 17:43:48 -080042 [[ "$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 IIIcefbd1c2021-11-05 03:52:53 -070050GBMC_IP_MONITOR_DEFER_OUTSTANDING=
51gbmc_ip_monitor_defer_() {
52 sleep 1
William A. Kennington IIIb06ae502023-06-05 14:35:17 -070053 printf '[DEFER]\n' >&"$GBMC_IP_MONITOR_DEFER"
William A. Kennington IIIcefbd1c2021-11-05 03:52:53 -070054}
55gbmc_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 IIIe33ec592021-03-10 17:43:48 -080061gbmc_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 IIIf4ce04c2022-05-20 09:39:45 -070072 addr_re='([^/]+)/[0-9]+[[:space:]]+'
73 metric_re='(metric[[:space:]]+[^ ]+[[:space:]]+)?'
74 brd_re='(brd[[:space:]]+[^ ]+[[:space:]]+)?'
William A. Kennington IIIe33ec592021-03-10 17:43:48 -080075 scope_re='scope[[:space:]]+([^ ]+)[[:space:]]*(.*)'
William A. Kennington IIIf4ce04c2022-05-20 09:39:45 -070076 combined_re="${pfx_re}${intf_re}${fam_re}${addr_re}${metric_re}${brd_re}${scope_re}"
William A. Kennington IIIe33ec592021-03-10 17:43:48 -080077 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 IIIf4ce04c2022-05-20 09:39:45 -070087 scope="${BASH_REMATCH[7]}"
88 flags="${BASH_REMATCH[8]}"
William A. Kennington IIIe33ec592021-03-10 17:43:48 -080089 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 IIIb06ae502023-06-05 14:35:17 -0700102 change='link'
William A. Kennington IIIe33ec592021-03-10 17:43:48 -0800103 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 IIIb06ae502023-06-05 14:35:17 -0700114 read -ra data || return
William A. Kennington IIIe33ec592021-03-10 17:43:48 -0800115 mac="${data[1]}"
William A. Kennington IIIcefbd1c2021-11-05 03:52:53 -0700116 elif [[ "$line" == '[DEFER]'* ]]; then
117 GBMC_IP_MONITOR_DEFER_OUTSTANDING=
118 change=defer
William A. Kennington IIIe33ec592021-03-10 17:43:48 -0800119 else
120 return 2
121 fi
122}
123
William A. Kennington IIIcefbd1c2021-11-05 03:52:53 -0700124return 0 2>/dev/null
125
William A. Kennington IIIe33ec592021-03-10 17:43:48 -0800126cleanup() {
127 local st="$?"
128 trap - HUP INT QUIT ABRT TERM EXIT
129 jobs -l -p | xargs -r kill || true
William A. Kennington IIIb06ae502023-06-05 14:35:17 -0700130 exit "$st"
William A. Kennington IIIe33ec592021-03-10 17:43:48 -0800131}
132trap cleanup HUP INT QUIT ABRT TERM EXIT
133
William A. Kennington IIIcefbd1c2021-11-05 03:52:53 -0700134FIFODIR="$(mktemp -d)"
135mkfifo "$FIFODIR"/fifo
136exec {GBMC_IP_MONITOR_DEFER}<>"$FIFODIR"/fifo
137rm -rf "$FIFODIR"
William A. Kennington IIIe33ec592021-03-10 17:43:48 -0800138
William A. Kennington IIIb06ae502023-06-05 14:35:17 -0700139while read -r line; do
William A. Kennington III593f2bd2021-04-26 13:31:45 -0700140 gbmc_ip_monitor_parse_line "$line" || continue
William A. Kennington IIIe33ec592021-03-10 17:43:48 -0800141 gbmc_ip_monitor_run_hooks || continue
142 if [ "$change" = 'init' ]; then
143 systemd-notify --ready
144 fi
William A. Kennington IIIb06ae502023-06-05 14:35:17 -0700145done < <(gbmc_ip_monitor_generate_init; ip monitor link addr route label & cat <&"$GBMC_IP_MONITOR_DEFER")