blob: 90986e3068fb8f1f4596cbe1c626e5fcc566aec8 [file] [log] [blame]
William A. Kennington IIIe33ec592021-03-10 17:43:48 -08001#!/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.
18GBMC_IP_MONITOR_HOOKS=()
19
20# Load configurations from a known location in the filesystem to populate
21# hooks that are executed after each event.
22shopt -s nullglob
23for conf in /usr/share/gbmc-ip-monitor/*.sh; do
24 source "$conf"
25done
26
27gbmc_ip_monitor_run_hooks() {
28 local hook
29 for hook in "${GBMC_IP_MONITOR_HOOKS[@]}"; do
30 "$hook" || continue
31 done
32}
33
34gbmc_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 IIIcefbd1c2021-11-05 03:52:53 -070047GBMC_IP_MONITOR_DEFER_OUTSTANDING=
48gbmc_ip_monitor_defer_() {
49 sleep 1
50 printf '[DEFER]\n' >&$GBMC_IP_MONITOR_DEFER
51}
52gbmc_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 IIIe33ec592021-03-10 17:43:48 -080058gbmc_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 IIIf4ce04c2022-05-20 09:39:45 -070069 addr_re='([^/]+)/[0-9]+[[:space:]]+'
70 metric_re='(metric[[:space:]]+[^ ]+[[:space:]]+)?'
71 brd_re='(brd[[:space:]]+[^ ]+[[:space:]]+)?'
William A. Kennington IIIe33ec592021-03-10 17:43:48 -080072 scope_re='scope[[:space:]]+([^ ]+)[[:space:]]*(.*)'
William A. Kennington IIIf4ce04c2022-05-20 09:39:45 -070073 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 -080074 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 IIIf4ce04c2022-05-20 09:39:45 -070084 scope="${BASH_REMATCH[7]}"
85 flags="${BASH_REMATCH[8]}"
William A. Kennington IIIe33ec592021-03-10 17:43:48 -080086 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 IIIcefbd1c2021-11-05 03:52:53 -0700114 elif [[ "$line" == '[DEFER]'* ]]; then
115 GBMC_IP_MONITOR_DEFER_OUTSTANDING=
116 change=defer
William A. Kennington IIIe33ec592021-03-10 17:43:48 -0800117 else
118 return 2
119 fi
120}
121
William A. Kennington IIIcefbd1c2021-11-05 03:52:53 -0700122return 0 2>/dev/null
123
William A. Kennington IIIe33ec592021-03-10 17:43:48 -0800124cleanup() {
125 local st="$?"
126 trap - HUP INT QUIT ABRT TERM EXIT
127 jobs -l -p | xargs -r kill || true
128 exit $st
129}
130trap cleanup HUP INT QUIT ABRT TERM EXIT
131
William A. Kennington IIIcefbd1c2021-11-05 03:52:53 -0700132FIFODIR="$(mktemp -d)"
133mkfifo "$FIFODIR"/fifo
134exec {GBMC_IP_MONITOR_DEFER}<>"$FIFODIR"/fifo
135rm -rf "$FIFODIR"
William A. Kennington IIIe33ec592021-03-10 17:43:48 -0800136
137while read line; do
William A. Kennington III593f2bd2021-04-26 13:31:45 -0700138 gbmc_ip_monitor_parse_line "$line" || continue
William A. Kennington IIIe33ec592021-03-10 17:43:48 -0800139 gbmc_ip_monitor_run_hooks || continue
140 if [ "$change" = 'init' ]; then
141 systemd-notify --ready
142 fi
William A. Kennington IIIcefbd1c2021-11-05 03:52:53 -0700143done < <(gbmc_ip_monitor_generate_init; ip monitor link addr route label & cat <&$GBMC_IP_MONITOR_DEFER)