blob: 9da090f47ec15ba8244cead2fa9fe5119b0fad88 [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:]]+'
69 addr_re='([^/]+)/[0-9]+[[:space:]]+(brd[[:space:]]+[^ ]+[[:space:]]+)?'
70 scope_re='scope[[:space:]]+([^ ]+)[[:space:]]*(.*)'
71 combined_re="${pfx_re}${intf_re}${fam_re}${addr_re}${scope_re}"
72 if ! [[ "$line" =~ ${combined_re} ]]; then
73 echo "Failed to parse addr: $line" >&2
74 return 1
75 fi
76 if [ -n "${BASH_REMATCH[1]}" ]; then
77 action=del
78 fi
79 intf="${BASH_REMATCH[2]}"
80 fam="${BASH_REMATCH[3]}"
81 ip="${BASH_REMATCH[4]}"
82 scope="${BASH_REMATCH[6]}"
83 flags="${BASH_REMATCH[7]}"
84 elif [[ "$line" == '[ROUTE]'* ]]; then
85 line="${line#[ROUTE]}"
86 change=route
87 action=add
88 if ! [[ "$line" =~ ^\[ROUTE\](Deleted )?(.*)$ ]]; then
89 echo "Failed to parse link: $line" >&2
90 return 1
91 fi
92 if [ -n "${BASH_REMATCH[1]}" ]; then
93 action=del
94 fi
95 route="${BASH_REMATCH[2]}"
96 elif [[ "$line" == '[LINK]'* ]]; then
97 change=link
98 action=add
99 pfx_re='^\[LINK\](Deleted )?[0-9]+:[[:space:]]*'
100 intf_re='([^:]+):[[:space:]]+'
101 if ! [[ "$line" =~ ${pfx_re}${intf_re} ]]; then
102 echo "Failed to parse link: $line" >&2
103 return 1
104 fi
105 if [ -n "${BASH_REMATCH[1]}" ]; then
106 action=del
107 fi
108 intf="${BASH_REMATCH[2]}"
109 read line || break
110 data=($line)
111 mac="${data[1]}"
William A. Kennington IIIcefbd1c2021-11-05 03:52:53 -0700112 elif [[ "$line" == '[DEFER]'* ]]; then
113 GBMC_IP_MONITOR_DEFER_OUTSTANDING=
114 change=defer
William A. Kennington IIIe33ec592021-03-10 17:43:48 -0800115 else
116 return 2
117 fi
118}
119
William A. Kennington IIIcefbd1c2021-11-05 03:52:53 -0700120return 0 2>/dev/null
121
William A. Kennington IIIe33ec592021-03-10 17:43:48 -0800122cleanup() {
123 local st="$?"
124 trap - HUP INT QUIT ABRT TERM EXIT
125 jobs -l -p | xargs -r kill || true
126 exit $st
127}
128trap cleanup HUP INT QUIT ABRT TERM EXIT
129
William A. Kennington IIIcefbd1c2021-11-05 03:52:53 -0700130FIFODIR="$(mktemp -d)"
131mkfifo "$FIFODIR"/fifo
132exec {GBMC_IP_MONITOR_DEFER}<>"$FIFODIR"/fifo
133rm -rf "$FIFODIR"
William A. Kennington IIIe33ec592021-03-10 17:43:48 -0800134
135while read line; do
William A. Kennington III593f2bd2021-04-26 13:31:45 -0700136 gbmc_ip_monitor_parse_line "$line" || continue
William A. Kennington IIIe33ec592021-03-10 17:43:48 -0800137 gbmc_ip_monitor_run_hooks || continue
138 if [ "$change" = 'init' ]; then
139 systemd-notify --ready
140 fi
William A. Kennington IIIcefbd1c2021-11-05 03:52:53 -0700141done < <(gbmc_ip_monitor_generate_init; ip monitor link addr route label & cat <&$GBMC_IP_MONITOR_DEFER)