Initial commit
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
#!/bin/bash
|
||||
# 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.
|
||||
|
||||
cd "$(dirname "$0")" || exit
|
||||
if [ -e ../gbmc-ip-monitor.bb ]; then
|
||||
# shellcheck source=meta-google/recipes-google/test/test-sh/lib.sh
|
||||
source '../../test/test-sh/lib.sh'
|
||||
else
|
||||
# shellcheck source=meta-google/recipes-google/test/test-sh/lib.sh
|
||||
source "$SYSROOT/usr/share/test/lib.sh"
|
||||
fi
|
||||
# shellcheck source=meta-google/recipes-google/networking/files/gbmc-ip-monitor.sh
|
||||
source gbmc-ip-monitor.sh
|
||||
|
||||
test_init_empty() {
|
||||
ip() {
|
||||
return 0
|
||||
}
|
||||
str="$(gbmc_ip_monitor_generate_init)" || fail
|
||||
expect_streq "$str" '[INIT]'
|
||||
}
|
||||
|
||||
test_init_link_populated() {
|
||||
ip() {
|
||||
if [ "$1" = 'link' ]; then
|
||||
cat <<EOF
|
||||
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
|
||||
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
||||
2: eno2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
|
||||
link/ether aa:aa:aa:aa:aa:aa brd ff:ff:ff:ff:ff:ff
|
||||
altname enp0s31f6
|
||||
EOF
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
str="$(gbmc_ip_monitor_generate_init)" || fail
|
||||
expect_streq "$str" <<EOF
|
||||
[LINK]1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
|
||||
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
||||
[LINK]2: eno2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
|
||||
link/ether aa:aa:aa:aa:aa:aa brd ff:ff:ff:ff:ff:ff
|
||||
altname enp0s31f6
|
||||
[INIT]
|
||||
EOF
|
||||
}
|
||||
|
||||
test_init_addr_populated() {
|
||||
ip() {
|
||||
if [ "$1" = 'addr' ]; then
|
||||
cat <<EOF
|
||||
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
|
||||
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
||||
inet 127.0.0.1/8 scope host lo
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 ::1/128 scope host
|
||||
valid_lft forever preferred_lft forever
|
||||
2: eno2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
|
||||
link/ether aa:aa:aa:aa:aa:aa brd ff:ff:ff:ff:ff:ff
|
||||
altname enp0s31f6
|
||||
inet 192.168.242.57/23 brd 192.168.243.255 scope global dynamic noprefixroute eno2
|
||||
valid_lft 83967sec preferred_lft 83967sec
|
||||
inet6 fd01:ff2:5687:4:cf03:45f3:983a:96eb/64 scope global temporary dynamic
|
||||
valid_lft 518788sec preferred_lft 183sec
|
||||
EOF
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
str="$(gbmc_ip_monitor_generate_init)" || fail
|
||||
expect_streq "$str" <<EOF
|
||||
[ADDR]1: lo inet 127.0.0.1/8 scope host lo
|
||||
[ADDR]1: lo inet6 ::1/128 scope host
|
||||
[ADDR]2: eno2 inet 192.168.242.57/23 brd 192.168.243.255 scope global dynamic noprefixroute eno2
|
||||
[ADDR]2: eno2 inet6 fd01:ff2:5687:4:cf03:45f3:983a:96eb/64 scope global temporary dynamic
|
||||
[INIT]
|
||||
EOF
|
||||
}
|
||||
|
||||
test_init_route_populated() {
|
||||
ip() {
|
||||
if [[ "$1" == "-4" && "${2-}" == 'route' ]]; then
|
||||
cat <<EOF
|
||||
default via 192.168.243.254 dev eno2 proto dhcp metric 100
|
||||
192.168.242.0/23 dev eno2 proto kernel scope link src 192.168.242.57 metric 100
|
||||
EOF
|
||||
elif [[ "$1" == "-6" && "${2-}" == 'route' ]]; then
|
||||
cat <<EOF
|
||||
::1 dev lo proto kernel metric 256 pref medium
|
||||
fd01:ff2:5687:4::/64 dev eno2 proto ra metric 100 pref medium
|
||||
fe80::/64 dev eno2 proto kernel metric 100 pref medium
|
||||
EOF
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
str="$(gbmc_ip_monitor_generate_init)" || fail
|
||||
expect_streq "$str" <<EOF
|
||||
[ROUTE]default via 192.168.243.254 dev eno2 proto dhcp metric 100
|
||||
[ROUTE]192.168.242.0/23 dev eno2 proto kernel scope link src 192.168.242.57 metric 100
|
||||
[ROUTE]::1 dev lo proto kernel metric 256 pref medium
|
||||
[ROUTE]fd01:ff2:5687:4::/64 dev eno2 proto ra metric 100 pref medium
|
||||
[ROUTE]fe80::/64 dev eno2 proto kernel metric 100 pref medium
|
||||
[INIT]
|
||||
EOF
|
||||
}
|
||||
|
||||
testParseNonTag() {
|
||||
expect_err 2 gbmc_ip_monitor_parse_line ''
|
||||
expect_err 2 gbmc_ip_monitor_parse_line ' '
|
||||
expect_err 2 gbmc_ip_monitor_parse_line ' Data'
|
||||
expect_err 2 gbmc_ip_monitor_parse_line ' [LINK]'
|
||||
expect_err 2 gbmc_ip_monitor_parse_line ' [ROUTE]'
|
||||
}
|
||||
|
||||
testParseInit() {
|
||||
expect_err 0 gbmc_ip_monitor_parse_line '[INIT]'
|
||||
expect_streq "$change" 'init'
|
||||
}
|
||||
|
||||
testParseAddrAdd() {
|
||||
expect_err 0 gbmc_ip_monitor_parse_line '[ADDR]2: eno2 inet6 fd01:ff2:5687:4:cf03:45f3:983a:96eb/128 metric 1024 scope global temporary dynamic'
|
||||
expect_streq "$change" 'addr'
|
||||
expect_streq "$action" 'add'
|
||||
expect_streq "$intf" 'eno2'
|
||||
expect_streq "$fam" 'inet6'
|
||||
expect_streq "$ip" 'fd01:ff2:5687:4:cf03:45f3:983a:96eb'
|
||||
expect_streq "$scope" 'global'
|
||||
expect_streq "$flags" 'temporary dynamic'
|
||||
}
|
||||
|
||||
testParseAddrDel() {
|
||||
expect_err 0 gbmc_ip_monitor_parse_line '[ADDR]Deleted 2: eno2 inet6 fe80::aaaa:aaff:feaa:aaaa/64 scope link'
|
||||
expect_streq "$change" 'addr'
|
||||
expect_streq "$action" 'del'
|
||||
expect_streq "$intf" 'eno2'
|
||||
expect_streq "$fam" 'inet6'
|
||||
expect_streq "$ip" 'fe80::aaaa:aaff:feaa:aaaa'
|
||||
expect_streq "$scope" 'link'
|
||||
expect_streq "$flags" ''
|
||||
}
|
||||
|
||||
testParseRouteAdd() {
|
||||
expect_err 0 gbmc_ip_monitor_parse_line "[ROUTE]fd01:ff2:5687:4::/64 dev eno2 proto ra metric 100 pref medium"
|
||||
expect_streq "$change" 'route'
|
||||
expect_streq "$action" 'add'
|
||||
expect_streq "$route" 'fd01:ff2:5687:4::/64 dev eno2 proto ra metric 100 pref medium'
|
||||
}
|
||||
|
||||
testParseRouteDel() {
|
||||
expect_err 0 gbmc_ip_monitor_parse_line "[ROUTE]Deleted fd01:ff2:5687:4::/64 dev eno2 proto ra metric 100 pref medium"
|
||||
expect_streq "$change" 'route'
|
||||
expect_streq "$action" 'del'
|
||||
expect_streq "$route" 'fd01:ff2:5687:4::/64 dev eno2 proto ra metric 100 pref medium'
|
||||
}
|
||||
|
||||
testParseLinkAdd() {
|
||||
expect_err 0 gbmc_ip_monitor_parse_line "[LINK]2: eno2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000" \
|
||||
< <(echo 'link/ether aa:aa:aa:aa:aa:aa brd ff:ff:ff:ff:ff:ff')
|
||||
expect_streq "$change" 'link'
|
||||
expect_streq "$action" 'add'
|
||||
expect_streq "$intf" 'eno2'
|
||||
expect_streq "$mac" 'aa:aa:aa:aa:aa:aa'
|
||||
}
|
||||
|
||||
testParseLinkDel() {
|
||||
expect_err 0 gbmc_ip_monitor_parse_line "[LINK]Deleted 2: eno2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000" \
|
||||
< <(echo 'link/ether aa:aa:aa:aa:aa:aa brd ff:ff:ff:ff:ff:ff')
|
||||
expect_streq "$change" 'link'
|
||||
expect_streq "$action" 'del'
|
||||
expect_streq "$intf" 'eno2'
|
||||
expect_streq "$mac" 'aa:aa:aa:aa:aa:aa'
|
||||
}
|
||||
|
||||
main
|
||||
@@ -0,0 +1,10 @@
|
||||
[Unit]
|
||||
Before=systemd-networkd.service
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
ExecStart=/usr/libexec/gbmc-ip-monitor.sh
|
||||
TimeoutStartSec=5min
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -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")
|
||||
@@ -0,0 +1,10 @@
|
||||
[Unit]
|
||||
Before=systemd-networkd.service
|
||||
|
||||
[Service]
|
||||
Restart=on-failure
|
||||
Type=oneshot
|
||||
ExecStart=/usr/libexec/gbmc-mac-config.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,91 @@
|
||||
#!/bin/bash
|
||||
# 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.
|
||||
|
||||
# shellcheck source=meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh
|
||||
source /usr/share/ipmi-fru/lib.sh || exit
|
||||
|
||||
ipmi_fru_alloc '@EEPROM@' eeprom || exit
|
||||
|
||||
header=()
|
||||
read_header "$eeprom" header || exit
|
||||
internal_offset=${header[$IPMI_FRU_COMMON_HEADER_INTERNAL_OFFSET_IDX]}
|
||||
if (( internal_offset == 0 )); then
|
||||
echo "Internal offset invalid for eeprom" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Our MAC Address configuration lives in the internal area with a format
|
||||
# Offset Data
|
||||
# 0 Version (Always 1)
|
||||
# 1 Type (Always 1 for MAC Address)
|
||||
# 2 Area Length in bytes (Always 32 bytes or 4 IPMI FRU sectors)
|
||||
# 3-8 MAC Address Base Octets
|
||||
# 9 Num Allocate MACs from Base
|
||||
# 10-30 Padding (Always 0xFF)
|
||||
# 31 IPMI FRU Checksum
|
||||
internal=()
|
||||
read_area "$eeprom" "$internal_offset" internal 4 || exit
|
||||
if (( internal[1] != 1 || internal[2] != 32 )); then
|
||||
echo "Not a MAC internal region" >&2
|
||||
exit 1
|
||||
fi
|
||||
mac=("${internal[@]:3:6}")
|
||||
num="${internal[9]}"
|
||||
macstr=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' "${mac[@]}")
|
||||
echo "Base MAC $macstr num $num" >&2
|
||||
|
||||
rc=0
|
||||
|
||||
# Pre-Determine if we will miss an allocation due to the number of
|
||||
# addresses the FRU actually supports.
|
||||
# shellcheck disable=SC2190
|
||||
declare -A num_to_intfs=(@NUM_TO_INTFS@)
|
||||
for key in "${!num_to_intfs[@]}"; do
|
||||
if (( key >= num )); then
|
||||
echo "${num_to_intfs[$key]} at $key is out of range" >&2
|
||||
rc=1
|
||||
fi
|
||||
done
|
||||
|
||||
# Write out each MAC override to the runtime networkd configuration
|
||||
for (( i=0; i<num; i++ )); do
|
||||
if (( mac[5] > 0xff )); then
|
||||
echo "MAC assignment too large: ${mac[*]}" >&2
|
||||
rc=2
|
||||
break
|
||||
fi
|
||||
for intf in ${num_to_intfs[$i]}; do
|
||||
macstr=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' "${mac[@]}")
|
||||
echo "Setting $intf to $macstr" >&2
|
||||
for override in /run/systemd/network/{00,}-bmc-$intf.network.d; do
|
||||
mkdir -p "$override"
|
||||
printf '[Link]\nMACAddress=%s\n' "$macstr" >"$override"/50-mac.conf
|
||||
done
|
||||
for override in /run/systemd/network/{00,}-bmc-$intf.netdev.d; do
|
||||
mkdir -p "$override"
|
||||
printf '[NetDev]\nMACAddress=%s\n' "$macstr" >"$override"/50-mac.conf
|
||||
done
|
||||
# In case we don't have any interface configs, set the MAC directly
|
||||
# This is safe to apply, as systemd-networkd will always override this
|
||||
# value based on written configs.
|
||||
if ip link show "$intf" >/dev/null 2>&1 && \
|
||||
! ip link set dev "$intf" address "$macstr"; then
|
||||
echo "Setting MAC($macstr) on $intf failed" >&2
|
||||
fi
|
||||
done
|
||||
(( ++mac[5] ))
|
||||
done
|
||||
|
||||
exit $rc
|
||||
@@ -0,0 +1,21 @@
|
||||
[Unit]
|
||||
Description=IPERF3 Server
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/iperf3 -s
|
||||
#Hardening
|
||||
PrivateTmp=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
ProtectKernelModules=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectControlGroups=true
|
||||
MountFlags=private
|
||||
NoNewPrivileges=true
|
||||
PrivateDevices=true
|
||||
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
|
||||
MemoryDenyWriteExecute=true
|
||||
DynamicUser=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user