blob: baeff9a85a48e316d785d8cb2a42ba856c94dc90 [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
47gbmc_ip_monitor_parse_line() {
48 local line="$1"
49 if [[ "$line" == '[INIT]'* ]]; then
50 change=init
51 echo "Initialized" >&2
52 elif [[ "$line" == '[ADDR]'* ]]; then
53 change=addr
54 action=add
55 pfx_re='^\[ADDR\](Deleted )?[0-9]+:[[:space:]]*'
56 intf_re='([^ ]+)[[:space:]]+'
57 fam_re='([^ ]+)[[:space:]]+'
58 addr_re='([^/]+)/[0-9]+[[:space:]]+(brd[[:space:]]+[^ ]+[[:space:]]+)?'
59 scope_re='scope[[:space:]]+([^ ]+)[[:space:]]*(.*)'
60 combined_re="${pfx_re}${intf_re}${fam_re}${addr_re}${scope_re}"
61 if ! [[ "$line" =~ ${combined_re} ]]; then
62 echo "Failed to parse addr: $line" >&2
63 return 1
64 fi
65 if [ -n "${BASH_REMATCH[1]}" ]; then
66 action=del
67 fi
68 intf="${BASH_REMATCH[2]}"
69 fam="${BASH_REMATCH[3]}"
70 ip="${BASH_REMATCH[4]}"
71 scope="${BASH_REMATCH[6]}"
72 flags="${BASH_REMATCH[7]}"
73 elif [[ "$line" == '[ROUTE]'* ]]; then
74 line="${line#[ROUTE]}"
75 change=route
76 action=add
77 if ! [[ "$line" =~ ^\[ROUTE\](Deleted )?(.*)$ ]]; then
78 echo "Failed to parse link: $line" >&2
79 return 1
80 fi
81 if [ -n "${BASH_REMATCH[1]}" ]; then
82 action=del
83 fi
84 route="${BASH_REMATCH[2]}"
85 elif [[ "$line" == '[LINK]'* ]]; then
86 change=link
87 action=add
88 pfx_re='^\[LINK\](Deleted )?[0-9]+:[[:space:]]*'
89 intf_re='([^:]+):[[:space:]]+'
90 if ! [[ "$line" =~ ${pfx_re}${intf_re} ]]; 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 intf="${BASH_REMATCH[2]}"
98 read line || break
99 data=($line)
100 mac="${data[1]}"
101 else
102 return 2
103 fi
104}
105
106cleanup() {
107 local st="$?"
108 trap - HUP INT QUIT ABRT TERM EXIT
109 jobs -l -p | xargs -r kill || true
110 exit $st
111}
112trap cleanup HUP INT QUIT ABRT TERM EXIT
113
114return 0 2>/dev/null
115
116while read line; do
117 gbmc_ip_monitor_parse_line || continue
118 gbmc_ip_monitor_run_hooks || continue
119 if [ "$change" = 'init' ]; then
120 systemd-notify --ready
121 fi
122done < <(gbmc_ip_monitor_generate_init; exec ip monitor link addr route label)