Initial commit
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
#!/bin/bash
|
||||
# shellcheck disable=SC2034
|
||||
# shellcheck disable=SC2317
|
||||
# Copyright 2021 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# A list of functions which get executed for each netlink event received.
|
||||
# These are configured by the files included below.
|
||||
GBMC_IP_MONITOR_HOOKS=()
|
||||
|
||||
# Load configurations from a known location in the filesystem to populate
|
||||
# hooks that are executed after each event.
|
||||
shopt -s nullglob
|
||||
for conf in /usr/share/gbmc-ip-monitor/*.sh; do
|
||||
# shellcheck source=/dev/null
|
||||
source "$conf"
|
||||
done
|
||||
|
||||
gbmc_ip_monitor_run_hooks() {
|
||||
local hook
|
||||
for hook in "${GBMC_IP_MONITOR_HOOKS[@]}"; do
|
||||
"$hook" || continue
|
||||
done
|
||||
}
|
||||
|
||||
gbmc_ip_monitor_generate_init() {
|
||||
ip link | sed 's,^[^ ],[LINK]\0,'
|
||||
local intf=
|
||||
local line
|
||||
while read -r line; do
|
||||
[[ "$line" =~ ^([0-9]+:[[:space:]][^:]+) ]] && intf="${BASH_REMATCH[1]}"
|
||||
[[ "$line" =~ ^[[:space:]]*inet ]] && echo "[ADDR]$intf $line"
|
||||
done < <(ip addr)
|
||||
ip -4 route | sed 's,^,[ROUTE],'
|
||||
ip -6 route | sed 's,^,[ROUTE],'
|
||||
echo '[INIT]'
|
||||
}
|
||||
|
||||
GBMC_IP_MONITOR_DEFER_OUTSTANDING=
|
||||
gbmc_ip_monitor_defer_() {
|
||||
sleep 1
|
||||
printf '[DEFER]\n' >&"$GBMC_IP_MONITOR_DEFER"
|
||||
}
|
||||
gbmc_ip_monitor_defer() {
|
||||
[ -z "$GBMC_IP_MONITOR_DEFER_OUTSTANDING" ] || return 0
|
||||
gbmc_ip_monitor_defer_ &
|
||||
GBMC_IP_MONITOR_DEFER_OUTSTANDING=1
|
||||
}
|
||||
|
||||
gbmc_ip_monitor_parse_line() {
|
||||
local line="$1"
|
||||
if [[ "$line" == '[INIT]'* ]]; then
|
||||
change=init
|
||||
echo "Initialized" >&2
|
||||
elif [[ "$line" == '[ADDR]'* ]]; then
|
||||
change=addr
|
||||
action=add
|
||||
pfx_re='^\[ADDR\](Deleted )?[0-9]+:[[:space:]]*'
|
||||
intf_re='([^ ]+)[[:space:]]+'
|
||||
fam_re='([^ ]+)[[:space:]]+'
|
||||
addr_re='([^/]+)/[0-9]+[[:space:]]+'
|
||||
metric_re='(metric[[:space:]]+[^ ]+[[:space:]]+)?'
|
||||
brd_re='(brd[[:space:]]+[^ ]+[[:space:]]+)?'
|
||||
scope_re='scope[[:space:]]+([^ ]+)[[:space:]]*(.*)'
|
||||
combined_re="${pfx_re}${intf_re}${fam_re}${addr_re}${metric_re}${brd_re}${scope_re}"
|
||||
if ! [[ "$line" =~ ${combined_re} ]]; then
|
||||
echo "Failed to parse addr: $line" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ -n "${BASH_REMATCH[1]}" ]; then
|
||||
action=del
|
||||
fi
|
||||
intf="${BASH_REMATCH[2]}"
|
||||
fam="${BASH_REMATCH[3]}"
|
||||
ip="${BASH_REMATCH[4]}"
|
||||
scope="${BASH_REMATCH[7]}"
|
||||
flags="${BASH_REMATCH[8]}"
|
||||
elif [[ "$line" == '[ROUTE]'* ]]; then
|
||||
line="${line#[ROUTE]}"
|
||||
change=route
|
||||
action=add
|
||||
if ! [[ "$line" =~ ^\[ROUTE\](Deleted )?(.*)$ ]]; then
|
||||
echo "Failed to parse link: $line" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ -n "${BASH_REMATCH[1]}" ]; then
|
||||
action=del
|
||||
fi
|
||||
route="${BASH_REMATCH[2]}"
|
||||
elif [[ "$line" == '[LINK]'* ]]; then
|
||||
change='link'
|
||||
action=add
|
||||
pfx_re='^\[LINK\](Deleted )?[0-9]+:[[:space:]]*'
|
||||
intf_re='([^:]+):[[:space:]]+'
|
||||
if ! [[ "$line" =~ ${pfx_re}${intf_re} ]]; then
|
||||
echo "Failed to parse link: $line" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ -n "${BASH_REMATCH[1]}" ]; then
|
||||
action=del
|
||||
fi
|
||||
intf="${BASH_REMATCH[2]}"
|
||||
read -ra data || return
|
||||
mac="${data[1]}"
|
||||
elif [[ "$line" == '[DEFER]'* ]]; then
|
||||
GBMC_IP_MONITOR_DEFER_OUTSTANDING=
|
||||
change=defer
|
||||
else
|
||||
return 2
|
||||
fi
|
||||
}
|
||||
|
||||
return 0 2>/dev/null
|
||||
|
||||
cleanup() {
|
||||
local st="$?"
|
||||
trap - HUP INT QUIT ABRT TERM EXIT
|
||||
jobs -l -p | xargs -r kill || true
|
||||
exit "$st"
|
||||
}
|
||||
trap cleanup HUP INT QUIT ABRT TERM EXIT
|
||||
|
||||
FIFODIR="$(mktemp -d)"
|
||||
mkfifo "$FIFODIR"/fifo
|
||||
exec {GBMC_IP_MONITOR_DEFER}<>"$FIFODIR"/fifo
|
||||
rm -rf "$FIFODIR"
|
||||
|
||||
while read -r line; do
|
||||
gbmc_ip_monitor_parse_line "$line" || continue
|
||||
gbmc_ip_monitor_run_hooks || continue
|
||||
if [ "$change" = 'init' ]; then
|
||||
systemd-notify --ready
|
||||
fi
|
||||
done < <(gbmc_ip_monitor_generate_init; ip monitor link addr route label & cat <&"$GBMC_IP_MONITOR_DEFER")
|
||||
Reference in New Issue
Block a user