2 # SPDX-License-Identifier: GPL-2.0
4 ##############################################################################
7 # Kselftest framework requirement - SKIP code is 4.
10 # Can be overridden by the configuration file.
14 ARPING=${ARPING:=arping}
16 WAIT_TIME=${WAIT_TIME:=5}
17 PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
18 PAUSE_ON_CLEANUP=${PAUSE_ON_CLEANUP:=no}
19 NETIF_TYPE=${NETIF_TYPE:=veth}
20 NETIF_CREATE=${NETIF_CREATE:=yes}
22 MC_CLI=${MC_CLI:=smcroutectl}
23 PING_COUNT=${PING_COUNT:=10}
24 PING_TIMEOUT=${PING_TIMEOUT:=5}
25 WAIT_TIMEOUT=${WAIT_TIMEOUT:=20}
26 INTERFACE_TIMEOUT=${INTERFACE_TIMEOUT:=600}
27 LOW_AGEING_TIME=${LOW_AGEING_TIME:=1000}
28 REQUIRE_JQ=${REQUIRE_JQ:=yes}
29 REQUIRE_MZ=${REQUIRE_MZ:=yes}
30 REQUIRE_MTOOLS=${REQUIRE_MTOOLS:=no}
31 STABLE_MAC_ADDRS=${STABLE_MAC_ADDRS:=no}
32 TCPDUMP_EXTRA_FLAGS=${TCPDUMP_EXTRA_FLAGS:=}
34 relative_path="${BASH_SOURCE%/*}"
35 if [[ "$relative_path" == "${BASH_SOURCE}" ]]; then
39 if [[ -f $relative_path/forwarding.config ]]; then
40 source "$relative_path/forwarding.config"
43 ##############################################################################
49 if [[ $? -ne 0 ]]; then
50 echo "SKIP: iproute2 too old; tc is missing JSON support"
55 # Old versions of tc don't understand "mpls_uc"
56 check_tc_mpls_support()
60 tc filter add dev $dev ingress protocol mpls_uc pref 1 handle 1 \
61 matchall action pipe &> /dev/null
62 if [[ $? -ne 0 ]]; then
63 echo "SKIP: iproute2 too old; tc is missing MPLS support"
66 tc filter del dev $dev ingress protocol mpls_uc pref 1 handle 1 \
70 # Old versions of tc produce invalid json output for mpls lse statistics
71 check_tc_mpls_lse_stats()
76 tc filter add dev $dev ingress protocol mpls_uc pref 1 handle 1 \
77 flower mpls lse depth 2 \
78 action continue &> /dev/null
80 if [[ $? -ne 0 ]]; then
81 echo "SKIP: iproute2 too old; tc-flower is missing extended MPLS support"
85 tc -j filter show dev $dev ingress protocol mpls_uc | jq . &> /dev/null
87 tc filter del dev $dev ingress protocol mpls_uc pref 1 handle 1 \
90 if [[ $ret -ne 0 ]]; then
91 echo "SKIP: iproute2 too old; tc-flower produces invalid json output for extended MPLS filters"
96 check_tc_shblock_support()
98 tc filter help 2>&1 | grep block &> /dev/null
99 if [[ $? -ne 0 ]]; then
100 echo "SKIP: iproute2 too old; tc is missing shared block support"
105 check_tc_chain_support()
107 tc help 2>&1|grep chain &> /dev/null
108 if [[ $? -ne 0 ]]; then
109 echo "SKIP: iproute2 too old; tc is missing chain support"
114 check_tc_action_hw_stats_support()
116 tc actions help 2>&1 | grep -q hw_stats
117 if [[ $? -ne 0 ]]; then
118 echo "SKIP: iproute2 too old; tc is missing action hw_stats support"
123 check_tc_fp_support()
125 tc qdisc add dev lo mqprio help 2>&1 | grep -q "fp "
126 if [[ $? -ne 0 ]]; then
127 echo "SKIP: iproute2 too old; tc is missing frame preemption support"
132 check_ethtool_lanes_support()
134 ethtool --help 2>&1| grep lanes &> /dev/null
135 if [[ $? -ne 0 ]]; then
136 echo "SKIP: ethtool too old; it is missing lanes support"
141 check_ethtool_mm_support()
143 ethtool --help 2>&1| grep -- '--show-mm' &> /dev/null
144 if [[ $? -ne 0 ]]; then
145 echo "SKIP: ethtool too old; it is missing MAC Merge layer support"
150 check_locked_port_support()
152 if ! bridge -d link show | grep -q " locked"; then
153 echo "SKIP: iproute2 too old; Locked port feature not supported."
158 check_port_mab_support()
160 if ! bridge -d link show | grep -q "mab"; then
161 echo "SKIP: iproute2 too old; MacAuth feature not supported."
166 if [[ "$(id -u)" -ne 0 ]]; then
167 echo "SKIP: need root privileges"
171 if [[ "$CHECK_TC" = "yes" ]]; then
179 if [[ ! -x "$(command -v "$cmd")" ]]; then
180 echo "SKIP: $cmd not installed"
185 if [[ "$REQUIRE_JQ" = "yes" ]]; then
188 if [[ "$REQUIRE_MZ" = "yes" ]]; then
191 if [[ "$REQUIRE_MTOOLS" = "yes" ]]; then
192 # https://github.com/vladimiroltean/mtools/
193 # patched for IPv6 support
194 require_command msend
195 require_command mreceive
198 if [[ ! -v NUM_NETIFS ]]; then
199 echo "SKIP: importer does not define \"NUM_NETIFS\""
203 ##############################################################################
204 # Command line options handling
208 while [[ $# -gt 0 ]]; do
209 if [[ "$count" -eq "0" ]]; then
218 ##############################################################################
219 # Network interfaces configuration
225 for ((i = 1; i <= NUM_NETIFS; ++i)); do
228 ip link show dev ${NETIFS[p$i]} &> /dev/null
229 if [[ $? -ne 0 ]]; then
230 ip link add ${NETIFS[p$i]} type veth \
231 peer name ${NETIFS[p$j]}
232 if [[ $? -ne 0 ]]; then
233 echo "Failed to create netif"
243 case "$NETIF_TYPE" in
244 veth) create_netif_veth
246 *) echo "Can not create interfaces of type \'$NETIF_TYPE\'"
252 declare -A MAC_ADDR_ORIG
258 for ((i = 1; i <= NUM_NETIFS; ++i)); do
260 new_addr=$(printf "00:01:02:03:04:%02x" $i)
262 MAC_ADDR_ORIG["$dev"]=$(ip -j link show dev $dev | jq -e '.[].address')
264 MAC_ADDR_ORIG["$dev"]=${MAC_ADDR_ORIG["$dev"]//\"/}
265 ip link set dev $dev address $new_addr
273 for ((i = 1; i <= NUM_NETIFS; ++i)); do
275 ip link set dev $dev address ${MAC_ADDR_ORIG["$dev"]}
279 if [[ "$NETIF_CREATE" = "yes" ]]; then
283 if [[ "$STABLE_MAC_ADDRS" = "yes" ]]; then
287 for ((i = 1; i <= NUM_NETIFS; ++i)); do
288 ip link show dev ${NETIFS[p$i]} &> /dev/null
289 if [[ $? -ne 0 ]]; then
290 echo "SKIP: could not find all required interfaces"
295 ##############################################################################
298 # Exit status to return at the end. Set in case one of the tests fails.
300 # Per-test return value. Clear at the beginning of each test.
308 if [[ $RET -eq 0 && $err -ne 0 ]]; then
319 if [[ $RET -eq 0 && $err -eq 0 ]]; then
327 local should_fail=$1; shift
331 if ((should_fail)); then
332 check_fail $err "$what succeeded, but should have failed"
334 check_err $err "$what failed"
343 if [[ $# -eq 2 ]]; then
347 if [[ $RET -ne 0 ]]; then
349 printf "TEST: %-60s [FAIL]\n" "$test_name $opt_str"
350 if [[ ! -z "$retmsg" ]]; then
351 printf "\t%s\n" "$retmsg"
353 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
354 echo "Hit enter to continue, 'q' to quit"
356 [ "$a" = "q" ] && exit 1
361 printf "TEST: %-60s [ OK ]\n" "$test_name $opt_str"
370 printf "TEST: %-60s [SKIP]\n" "$test_name $opt_str"
383 local timeout=$1; shift
385 local start_time="$(date -u +%s%3N)"
396 local current_time="$(date -u +%s%3N)"
397 if ((current_time - start_time > timeout)); then
415 for cur in ${arr[@]}; do
416 if [[ $cur -gt $max ]]; then
430 if [ "$1" == "self" ] || [ "$1" == "master" ]; then
432 if [ "$1" == "-v" ]; then
437 $@ | grep $addr | grep $flag "$word"
442 "$@" | grep -q "Link detected: yes"
447 "$@" | grep -q offload
458 local current=$("$@")
464 busywait_for_counter()
466 local timeout=$1; shift
467 local delta=$1; shift
470 busywait "$timeout" until_counter_is ">= $((base + delta))" "$@"
476 local wait_time=${1:-$WAIT_TIME}; shift
478 setup_wait_dev_with_timeout "$dev" $INTERFACE_TIMEOUT $wait_time
482 log_test setup_wait_dev ": Interface $dev does not come up."
487 setup_wait_dev_with_timeout()
490 local max_iterations=${1:-$WAIT_TIMEOUT}; shift
491 local wait_time=${1:-$WAIT_TIME}; shift
494 for ((i = 1; i <= $max_iterations; ++i)); do
495 ip link show dev $dev up \
496 | grep 'state UP' &> /dev/null
497 if [[ $? -ne 0 ]]; then
510 local num_netifs=${1:-$NUM_NETIFS}
513 for ((i = 1; i <= num_netifs; ++i)); do
514 setup_wait_dev ${NETIFS[p$i]} 0
517 # Make sure links are ready.
530 # it the command fails, return error right away
532 if [[ $ret -ne 0 ]]; then
535 output=$(echo $output | jq -r $jq_opts "$jq_exp")
537 if [[ $ret -ne 0 ]]; then
541 # return success only in case of non-empty output
547 if [ "${PAUSE_ON_CLEANUP}" = "yes" ]; then
548 echo "Pausing before cleanup, hit any key to continue"
552 if [[ "$STABLE_MAC_ADDRS" = "yes" ]]; then
559 ip -4 rule add pref 32765 table local
560 ip -4 rule del pref 0
561 ip -6 rule add pref 32765 table local
562 ip -6 rule del pref 0
567 ip -6 rule add pref 0 table local
568 ip -6 rule del pref 32765
569 ip -4 rule add pref 0 table local
570 ip -4 rule del pref 32765
580 __last_tb_id=$((__last_tb_id + 1))
581 __TB_IDS[$vrf_name]=$__last_tb_id
589 return ${__TB_IDS[$vrf_name]}
597 __vrf_td_id_assign $vrf_name
600 ip link add dev $vrf_name type vrf table $tb_id
601 ip -4 route add table $tb_id unreachable default metric 4278198272
602 ip -6 route add table $tb_id unreachable default metric 4278198272
610 __vrf_td_id_lookup $vrf_name
613 ip -6 route del table $tb_id unreachable default metric 4278198272
614 ip -4 route del table $tb_id unreachable default metric 4278198272
615 ip link del dev $vrf_name
628 for addrstr in "${array[@]}"; do
629 ip address $add_del $addrstr dev $if_name
635 local if_name=$1; shift
636 local vrf_name=$1; shift
639 ip link set dev $if_name master $vrf_name
640 ip link set dev $if_name up
642 __addr_add_del $if_name add "${addrs[@]}"
647 local if_name=$1; shift
650 __addr_add_del $if_name del "${addrs[@]}"
652 ip link set dev $if_name down
653 ip link set dev $if_name nomaster
667 ip link set dev $vrf_name up
668 __simple_if_init $if_name $vrf_name "${array[@]}"
681 __simple_if_fini $if_name "${array[@]}"
682 vrf_destroy $vrf_name
689 local local=$1; shift
690 local remote=$1; shift
692 ip link add name $name type $type \
693 local $local remote $remote "$@"
694 ip link set dev $name up
701 ip link del dev $name
706 local if_name=$1; shift
710 local name=$if_name.$vid
712 ip link add name $name link $if_name type vlan id $vid
713 if [ "$vrf" != "" ]; then
714 ip link set dev $name master $vrf
716 ip link set dev $name up
717 __addr_add_del $name add "${ips[@]}"
722 local if_name=$1; shift
724 local name=$if_name.$vid
726 ip link del dev $name
731 local if_name=$1; shift
734 require_command $TEAMD
735 $TEAMD -t $if_name -d -c '{"runner": {"name": "'$mode'"}}'
736 for slave in "$@"; do
737 ip link set dev $slave down
738 ip link set dev $slave master $if_name
739 ip link set dev $slave up
741 ip link set dev $if_name up
746 local if_name=$1; shift
748 $TEAMD -t $if_name -k
755 ip -j link show dev $if_name | jq -r '.[]["master"]'
760 local if_name=$1; shift
764 ip -j -s link show dev $if_name \
765 | jq '.[]["stats64"]["'$dir'"]["'$stat'"]'
768 link_stats_tx_packets_get()
770 link_stats_get $1 tx packets
773 link_stats_rx_errors_get()
775 link_stats_get $1 rx errors
783 local selector=${1:-.packets}; shift
785 tc -j -s filter show dev $dev ${dir:-ingress} pref $pref \
786 | jq ".[1].options.actions[].stats$selector"
789 tc_rule_handle_stats_get()
792 local handle=$1; shift
793 local selector=${1:-.packets}; shift
795 tc -j -s filter show $id \
796 | jq ".[] | select(.options.handle == $handle) | \
797 .options.actions[0].stats$selector"
805 ethtool -S $dev | grep "^ *$stat:" | head -n 1 | cut -d: -f2
808 ethtool_std_stats_get()
815 ethtool --json -S $dev --groups $grp -- --src $src | \
816 jq '.[]."'"$grp"'"."'$name'"'
822 local handle=$1; shift
823 local selector=$1; shift
825 tc -j -s qdisc show dev "$dev" \
826 | jq '.[] | select(.handle == "'"$handle"'") | '"$selector"
829 qdisc_parent_stats_get()
832 local parent=$1; shift
833 local selector=$1; shift
835 tc -j -s qdisc show dev "$dev" invisible \
836 | jq '.[] | select(.parent == "'"$parent"'") | '"$selector"
844 cat /proc/net/dev_snmp6/$dev | grep "^$stat" | cut -f2
849 local suite=$1; shift
850 local if_name=$1; shift
854 ip -j stats show dev $if_name group offload subgroup $suite |
855 jq ".[0].stats64.$dir.$stat"
860 local speed=$1; shift
862 for unit in bps Kbps Mbps Gbps; do
863 if (($(echo "$speed < 1024" | bc))); then
867 speed=$(echo "scale=1; $speed / 1024" | bc)
877 local interval=$1; shift
879 echo $((8 * (t1 - t0) / interval))
886 local interval=$1; shift
888 echo $(((t1 - t0) / interval))
895 ip -j link show dev $if_name | jq -r '.[]["address"]'
902 ip -j addr show dev $if_name | \
903 jq -r '.[]["addr_info"][] | select(.scope == "link").local' | \
907 bridge_ageing_time_get()
912 # Need to divide by 100 to convert to seconds.
913 ageing_time=$(ip -j -d link show dev $bridge \
914 | jq '.[]["linkinfo"]["info_data"]["ageing_time"]')
915 echo $((ageing_time / 100))
918 declare -A SYSCTL_ORIG
922 local value=$1; shift
924 SYSCTL_ORIG[$key]=$(sysctl -n $key)
925 sysctl -qw $key="$value"
932 sysctl -qw $key="${SYSCTL_ORIG[$key]}"
937 sysctl_set net.ipv4.conf.all.forwarding 1
938 sysctl_set net.ipv6.conf.all.forwarding 1
943 sysctl_restore net.ipv6.conf.all.forwarding
944 sysctl_restore net.ipv4.conf.all.forwarding
953 MTU_ORIG["$dev"]=$(ip -j link show dev $dev | jq -e '.[].mtu')
954 ip link set dev $dev mtu $mtu
961 ip link set dev $dev mtu ${MTU_ORIG["$dev"]}
966 local num_netifs=${1:-$NUM_NETIFS}
968 for ((i = 1; i <= num_netifs; ++i)); do
969 ethtool -k ${NETIFS[p$i]} \
970 | grep "hw-tc-offload: on" &> /dev/null
971 if [[ $? -ne 0 ]]; then
982 local direction=$1; shift
984 # Some devices may not support or need in-hardware trapping of traffic
985 # (e.g. the veth pairs that this library creates for non-existent
986 # loopbacks). Use continue instead, so that there is a filter in there
987 # (some tests check counters), and so that other filters are still
989 tc filter add dev $dev $direction pref 1 \
990 flower skip_sw action trap 2>/dev/null \
991 || tc filter add dev $dev $direction pref 1 \
992 flower action continue
998 local direction=$1; shift
1000 tc filter del dev $dev $direction pref 1 flower
1003 slow_path_trap_install()
1005 # For slow-path testing, we need to install a trap to get to
1006 # slow path the packets that would otherwise be switched in HW.
1007 if [ "${tcflags/skip_hw}" != "$tcflags" ]; then
1012 slow_path_trap_uninstall()
1014 if [ "${tcflags/skip_hw}" != "$tcflags" ]; then
1019 __icmp_capture_add_del()
1021 local add_del=$1; shift
1022 local pref=$1; shift
1023 local vsuf=$1; shift
1024 local tundev=$1; shift
1025 local filter=$1; shift
1027 tc filter $add_del dev "$tundev" ingress \
1028 proto ip$vsuf pref $pref \
1029 flower ip_proto icmp$vsuf $filter \
1033 icmp_capture_install()
1035 __icmp_capture_add_del add 100 "" "$@"
1038 icmp_capture_uninstall()
1040 __icmp_capture_add_del del 100 "" "$@"
1043 icmp6_capture_install()
1045 __icmp_capture_add_del add 100 v6 "$@"
1048 icmp6_capture_uninstall()
1050 __icmp_capture_add_del del 100 v6 "$@"
1053 __vlan_capture_add_del()
1055 local add_del=$1; shift
1056 local pref=$1; shift
1058 local filter=$1; shift
1060 tc filter $add_del dev "$dev" ingress \
1061 proto 802.1q pref $pref \
1066 vlan_capture_install()
1068 __vlan_capture_add_del add 100 "$@"
1071 vlan_capture_uninstall()
1073 __vlan_capture_add_del del 100 "$@"
1076 __dscp_capture_add_del()
1078 local add_del=$1; shift
1080 local base=$1; shift
1083 for prio in {0..7}; do
1084 dscp=$((base + prio))
1085 __icmp_capture_add_del $add_del $((dscp + 100)) "" $dev \
1086 "skip_hw ip_tos $((dscp << 2))"
1090 dscp_capture_install()
1093 local base=$1; shift
1095 __dscp_capture_add_del add $dev $base
1098 dscp_capture_uninstall()
1101 local base=$1; shift
1103 __dscp_capture_add_del del $dev $base
1109 local base=$1; shift
1111 for prio in {0..7}; do
1112 local dscp=$((base + prio))
1113 local t=$(tc_rule_stats_get $dev $((dscp + 100)))
1118 matchall_sink_create()
1122 tc qdisc add dev $dev clsact
1123 tc filter add dev $dev ingress \
1133 for current_test in ${TESTS:-$ALL_TESTS}; do
1141 local weight_rp12=$2
1142 local weight_rp13=$3
1143 local packets_rp12=$4
1144 local packets_rp13=$5
1145 local weights_ratio packets_ratio diff
1149 if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
1150 weights_ratio=$(echo "scale=2; $weight_rp12 / $weight_rp13" \
1153 weights_ratio=$(echo "scale=2; $weight_rp13 / $weight_rp12" \
1157 if [[ "$packets_rp12" -eq "0" || "$packets_rp13" -eq "0" ]]; then
1158 check_err 1 "Packet difference is 0"
1159 log_test "Multipath"
1160 log_info "Expected ratio $weights_ratio"
1164 if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
1165 packets_ratio=$(echo "scale=2; $packets_rp12 / $packets_rp13" \
1168 packets_ratio=$(echo "scale=2; $packets_rp13 / $packets_rp12" \
1172 diff=$(echo $weights_ratio - $packets_ratio | bc -l)
1175 test "$(echo "$diff / $weights_ratio > 0.15" | bc -l)" -eq 0
1176 check_err $? "Too large discrepancy between expected and measured ratios"
1178 log_info "Expected ratio $weights_ratio Measured ratio $packets_ratio"
1183 local name=$1; shift
1185 ip netns exec $name bash <<-EOF
1188 $(for a in "$@"; do printf "%q${IFS:0:1}" "$a"; done)
1192 ##############################################################################
1202 vrf_name=$(master_name_get $if_name)
1203 ip vrf exec $vrf_name \
1204 $PING $args $dip -c $PING_COUNT -i 0.1 \
1205 -w $PING_TIMEOUT &> /dev/null
1224 vrf_name=$(master_name_get $if_name)
1225 ip vrf exec $vrf_name \
1226 $PING6 $args $dip -c $PING_COUNT -i 0.1 \
1227 -w $PING_TIMEOUT &> /dev/null
1242 local br_port1=$2 # Connected to `host1_if`.
1245 local mac=de:ad:be:ef:13:37
1250 bridge -j fdb show br $bridge brport $br_port1 \
1251 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1252 check_fail $? "Found FDB record when should not"
1254 # Disable unknown unicast flooding on `br_port1` to make sure
1255 # packets are only forwarded through the port after a matching
1256 # FDB entry was installed.
1257 bridge link set dev $br_port1 flood off
1259 ip link set $host1_if promisc on
1260 tc qdisc add dev $host1_if ingress
1261 tc filter add dev $host1_if ingress protocol ip pref 1 handle 101 \
1262 flower dst_mac $mac action drop
1264 $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q
1267 tc -j -s filter show dev $host1_if ingress \
1268 | jq -e ".[] | select(.options.handle == 101) \
1269 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1270 check_fail $? "Packet reached first host when should not"
1272 $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
1275 bridge -j fdb show br $bridge brport $br_port1 \
1276 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1277 check_err $? "Did not find FDB record when should"
1279 $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q
1282 tc -j -s filter show dev $host1_if ingress \
1283 | jq -e ".[] | select(.options.handle == 101) \
1284 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1285 check_err $? "Packet did not reach second host when should"
1287 # Wait for 10 seconds after the ageing time to make sure FDB
1288 # record was aged-out.
1289 ageing_time=$(bridge_ageing_time_get $bridge)
1290 sleep $((ageing_time + 10))
1292 bridge -j fdb show br $bridge brport $br_port1 \
1293 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1294 check_fail $? "Found FDB record when should not"
1296 bridge link set dev $br_port1 learning off
1298 $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
1301 bridge -j fdb show br $bridge brport $br_port1 \
1302 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1303 check_fail $? "Found FDB record when should not"
1305 bridge link set dev $br_port1 learning on
1307 tc filter del dev $host1_if ingress protocol ip pref 1 handle 101 flower
1308 tc qdisc del dev $host1_if ingress
1309 ip link set $host1_if promisc off
1311 bridge link set dev $br_port1 flood on
1313 log_test "FDB learning"
1318 local should_flood=$1
1325 # Add an ACL on `host2_if` which will tell us whether the packet
1326 # was flooded to it or not.
1327 ip link set $host2_if promisc on
1328 tc qdisc add dev $host2_if ingress
1329 tc filter add dev $host2_if ingress protocol ip pref 1 handle 101 \
1330 flower dst_mac $mac action drop
1332 $MZ $host1_if -c 1 -p 64 -b $mac -B $ip -t ip -q
1335 tc -j -s filter show dev $host2_if ingress \
1336 | jq -e ".[] | select(.options.handle == 101) \
1337 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1338 if [[ $? -ne 0 && $should_flood == "true" || \
1339 $? -eq 0 && $should_flood == "false" ]]; then
1343 tc filter del dev $host2_if ingress protocol ip pref 1 handle 101 flower
1344 tc qdisc del dev $host2_if ingress
1345 ip link set $host2_if promisc off
1350 flood_unicast_test()
1355 local mac=de:ad:be:ef:13:37
1356 local ip=192.0.2.100
1360 bridge link set dev $br_port flood off
1362 flood_test_do false $mac $ip $host1_if $host2_if
1363 check_err $? "Packet flooded when should not"
1365 bridge link set dev $br_port flood on
1367 flood_test_do true $mac $ip $host1_if $host2_if
1368 check_err $? "Packet was not flooded when should"
1370 log_test "Unknown unicast flood"
1373 flood_multicast_test()
1378 local mac=01:00:5e:00:00:01
1383 bridge link set dev $br_port mcast_flood off
1385 flood_test_do false $mac $ip $host1_if $host2_if
1386 check_err $? "Packet flooded when should not"
1388 bridge link set dev $br_port mcast_flood on
1390 flood_test_do true $mac $ip $host1_if $host2_if
1391 check_err $? "Packet was not flooded when should"
1393 log_test "Unregistered multicast flood"
1398 # `br_port` is connected to `host2_if`
1403 flood_unicast_test $br_port $host1_if $host2_if
1404 flood_multicast_test $br_port $host1_if $host2_if
1409 local pktsize=$1; shift
1410 local proto=$1; shift
1411 local h_in=$1; shift # Where the traffic egresses the host
1414 local dmac=$1; shift
1416 $MZ $h_in -p $pktsize -A $sip -B $dip -c 0 \
1417 -a own -b $dmac -t "$proto" -q "$@" &
1421 start_traffic_pktsize()
1423 local pktsize=$1; shift
1425 __start_traffic $pktsize udp "$@"
1428 start_tcp_traffic_pktsize()
1430 local pktsize=$1; shift
1432 __start_traffic $pktsize tcp "$@"
1437 start_traffic_pktsize 8000 "$@"
1442 start_tcp_traffic_pktsize 8000 "$@"
1447 # Suppress noise from killing mausezahn.
1448 { kill %% && wait %%; } 2>/dev/null
1457 local if_name=$1; shift
1460 capfile[$if_name]=$(mktemp)
1461 capout[$if_name]=$(mktemp)
1466 ns_cmd="ip netns exec ${ns}"
1469 if [ -z $SUDO_USER ] ; then
1472 capuser="-Z $SUDO_USER"
1475 $ns_cmd tcpdump $TCPDUMP_EXTRA_FLAGS -e -n -Q in -i $if_name \
1476 -s 65535 -B 32768 $capuser -w ${capfile[$if_name]} \
1477 > "${capout[$if_name]}" 2>&1 &
1486 local pid=${cappid[$if_name]}
1488 $ns_cmd kill "$pid" && wait "$pid"
1496 rm ${capfile[$if_name]} ${capout[$if_name]}
1503 tcpdump -e -n -r ${capfile[$if_name]} 2>&1
1506 # return 0 if the packet wasn't seen on host2_if or 1 if it was
1518 # basic check to see if we were passed an IPv4 address, if not assume IPv6
1519 if [[ ! $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
1524 # Add an ACL on `host2_if` which will tell us whether the packet
1525 # was received by it or not.
1526 tc qdisc add dev $host2_if ingress
1527 tc filter add dev $host2_if ingress protocol $tc_proto pref 1 handle 101 \
1528 flower ip_proto udp dst_mac $mac action drop
1530 $MZ $host1_if $mz_v6arg -c 1 -p 64 -b $mac -A $src_ip -B $ip -t udp "dp=4096,sp=2048" -q
1533 tc -j -s filter show dev $host2_if ingress \
1534 | jq -e ".[] | select(.options.handle == 101) \
1535 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1536 if [[ $? -eq 0 ]]; then
1540 tc filter del dev $host2_if ingress protocol $tc_proto pref 1 handle 101 flower
1541 tc qdisc del dev $host2_if ingress
1546 brmcast_check_sg_entries()
1548 local report=$1; shift
1552 for src in "${slist[@]}"; do
1553 sarg="${sarg} and .source_list[].address == \"$src\""
1555 bridge -j -d -s mdb show dev br0 \
1556 | jq -e ".[].mdb[] | \
1557 select(.grp == \"$TEST_GROUP\" and .source_list != null $sarg)" &>/dev/null
1558 check_err $? "Wrong *,G entry source list after $report report"
1560 for sgent in "${slist[@]}"; do
1561 bridge -j -d -s mdb show dev br0 \
1562 | jq -e ".[].mdb[] | \
1563 select(.grp == \"$TEST_GROUP\" and .src == \"$sgent\")" &>/dev/null
1564 check_err $? "Missing S,G entry ($sgent, $TEST_GROUP)"
1568 brmcast_check_sg_fwding()
1570 local should_fwd=$1; shift
1571 local sources=("$@")
1573 for src in "${sources[@]}"; do
1576 mcast_packet_test $TEST_GROUP_MAC $src $TEST_GROUP $h2 $h1
1578 if [ $should_fwd -eq 1 ]; then
1579 check_fail $retval "Didn't forward traffic from S,G ($src, $TEST_GROUP)"
1581 check_err $retval "Forwarded traffic for blocked S,G ($src, $TEST_GROUP)"
1586 brmcast_check_sg_state()
1588 local is_blocked=$1; shift
1589 local sources=("$@")
1592 if [ $is_blocked -eq 1 ]; then
1596 for src in "${sources[@]}"; do
1597 bridge -j -d -s mdb show dev br0 \
1598 | jq -e ".[].mdb[] | \
1599 select(.grp == \"$TEST_GROUP\" and .source_list != null) |
1601 select(.address == \"$src\") |
1602 select(.timer == \"0.00\")" &>/dev/null
1603 check_err_fail $should_fail $? "Entry $src has zero timer"
1605 bridge -j -d -s mdb show dev br0 \
1606 | jq -e ".[].mdb[] | \
1607 select(.grp == \"$TEST_GROUP\" and .src == \"$src\" and \
1608 .flags[] == \"blocked\")" &>/dev/null
1609 check_err_fail $should_fail $? "Entry $src has blocked flag"
1617 local vrf_name=$(master_name_get $if_name)
1619 # We don't care about actual reception, just about joining the
1620 # IP multicast group and adding the L2 address to the device's
1621 # MAC filtering table
1622 ip vrf exec $vrf_name \
1623 mreceive -g $group -I $if_name > /dev/null 2>&1 &
1631 kill "$mreceive_pid" && wait "$mreceive_pid"
1638 local vrf_name=$(master_name_get $if_name)
1640 ip vrf exec $vrf_name \
1641 msend -g $groups -I $if_name -c 1 > /dev/null 2>&1
1646 local mtype=$1; shift
1647 local ip=${1-ip}; shift
1649 # start the monitor in the background
1650 tmpfile=`mktemp /var/run/nexthoptestXXX`
1651 mpid=`($ip monitor $mtype > $tmpfile & echo $!) 2>/dev/null`
1653 echo "$mpid $tmpfile"
1658 local mpid=$1; shift
1659 local tmpfile=$1; shift
1661 local what=$1; shift
1665 local lines=`grep '^\w' $tmpfile | wc -l`
1667 check_err $? "$what: $lines lines of events, expected $el"
1671 hw_stats_monitor_test()
1674 local type=$1; shift
1675 local make_suitable=$1; shift
1676 local make_unsuitable=$1; shift
1677 local ip=${1-ip}; shift
1681 # Expect a notification about enablement.
1682 local ipmout=$(start_ip_monitor stats "$ip")
1683 $ip stats set dev $dev ${type}_stats on
1684 stop_ip_monitor $ipmout 1 "${type}_stats enablement"
1686 # Expect a notification about offload.
1687 local ipmout=$(start_ip_monitor stats "$ip")
1689 stop_ip_monitor $ipmout 1 "${type}_stats installation"
1691 # Expect a notification about loss of offload.
1692 local ipmout=$(start_ip_monitor stats "$ip")
1694 stop_ip_monitor $ipmout 1 "${type}_stats deinstallation"
1696 # Expect a notification about disablement
1697 local ipmout=$(start_ip_monitor stats "$ip")
1698 $ip stats set dev $dev ${type}_stats off
1699 stop_ip_monitor $ipmout 1 "${type}_stats disablement"
1701 log_test "${type}_stats notifications"
1708 printf '%02x:' ${IP//./ } |
1712 # Convert a given IPv6 address, `IP' such that the :: token, if present, is
1713 # expanded, and each 16-bit group is padded with zeroes to be 4 hexadecimal
1714 # digits. An optional `BYTESEP' parameter can be given to further separate
1715 # individual bytes of each 16-bit group.
1719 local bytesep=$1; shift
1721 local cvt_ip=${IP/::/_}
1722 local colons=${cvt_ip//[^:]/}
1723 local allcol=:::::::
1724 # IP where :: -> the appropriate number of colons:
1725 local allcol_ip=${cvt_ip/_/${allcol:${#colons}}}
1727 echo $allcol_ip | tr : '\n' |
1729 sed 's/.*\(..\)\(..\)/\1'"$bytesep"'\2/' |
1745 printf "%04x" $u16 | sed 's/^/000/;s/^.*\(..\)\(..\)$/\1:\2/'
1748 # Given a mausezahn-formatted payload (colon-separated bytes given as %02x),
1749 # possibly with a keyword CHECKSUM stashed where a 16-bit checksum should be,
1750 # calculate checksum as per RFC 1071, assuming the CHECKSUM field (if any)
1752 payload_template_calc_checksum()
1754 local payload=$1; shift
1759 # Push zero for the initial checksum.
1762 # Pad the payload with a terminating 00: in case we get an odd
1764 echo "${payload%:}:00:" |
1765 sed 's/CHECKSUM/00:00/g' |
1766 tr '[:lower:]' '[:upper:]' |
1767 # Add the word to the checksum.
1768 sed 's/\(..\):\(..\):/\1\2+\n/g' |
1769 # Strip the extra odd byte we pushed if left unconverted.
1772 echo "10000 ~ +" # Calculate and add carry.
1773 echo "FFFF r - p" # Bit-flip and print.
1776 tr '[:upper:]' '[:lower:]'
1779 payload_template_expand_checksum()
1781 local payload=$1; shift
1782 local checksum=$1; shift
1784 local ckbytes=$(u16_to_bytes $checksum)
1786 echo "$payload" | sed "s/CHECKSUM/$ckbytes/g"
1789 payload_template_nbytes()
1791 local payload=$1; shift
1793 payload_template_expand_checksum "${payload%:}" 0 |
1794 sed 's/:/\n/g' | wc -l
1800 local sources=("$@")
1803 local nsources=$(u16_to_bytes ${#sources[@]})
1805 # IS_IN ( $sources )
1807 )"22:"$( : Type - Membership Report
1809 )"CHECKSUM:"$( : Checksum
1810 )"00:00:"$( : Reserved
1811 )"00:01:"$( : Number of Group Records
1812 )"01:"$( : Record Type - IS_IN
1813 )"00:"$( : Aux Data Len
1814 )"${nsources}:"$( : Number of Sources
1815 )"$(ipv4_to_bytes $GRP):"$( : Multicast Address
1816 )"$(for src in "${sources[@]}"; do
1819 done)"$( : Source Addresses
1821 local checksum=$(payload_template_calc_checksum "$igmpv3")
1823 payload_template_expand_checksum "$igmpv3" $checksum
1831 )"17:"$( : Type - Leave Group
1832 )"00:"$( : Max Resp Time - not meaningful
1833 )"CHECKSUM:"$( : Checksum
1834 )"$(ipv4_to_bytes $GRP)"$( : Group Address
1836 local checksum=$(payload_template_calc_checksum "$payload")
1838 payload_template_expand_checksum "$payload" $checksum
1845 local sources=("$@")
1849 local nsources=$(u16_to_bytes ${#sources[@]})
1852 )"3a:"$( : Next Header - ICMPv6
1853 )"00:"$( : Hdr Ext Len
1854 )"00:00:00:00:00:00:"$( : Options and Padding
1858 )"8f:"$( : Type - MLDv2 Report
1860 )"CHECKSUM:"$( : Checksum
1861 )"00:00:"$( : Reserved
1862 )"00:01:"$( : Number of Group Records
1863 )"01:"$( : Record Type - IS_IN
1864 )"00:"$( : Aux Data Len
1865 )"${nsources}:"$( : Number of Sources
1866 )"$(ipv6_to_bytes $GRP):"$( : Multicast address
1867 )"$(for src in "${sources[@]}"; do
1870 done)"$( : Source Addresses
1873 local len=$(u16_to_bytes $(payload_template_nbytes $icmpv6))
1875 )"$(ipv6_to_bytes $SIP):"$( : SIP
1876 )"$(ipv6_to_bytes $GRP):"$( : DIP is multicast address
1877 )"${len}:"$( : Upper-layer length
1878 )"00:3a:"$( : Zero and next-header
1880 local checksum=$(payload_template_calc_checksum ${sudohdr}${icmpv6})
1882 payload_template_expand_checksum "$hbh$icmpv6" $checksum
1894 )"3a:"$( : Next Header - ICMPv6
1895 )"00:"$( : Hdr Ext Len
1896 )"00:00:00:00:00:00:"$( : Options and Padding
1900 )"84:"$( : Type - MLDv1 Done
1902 )"CHECKSUM:"$( : Checksum
1903 )"00:00:"$( : Max Resp Delay - not meaningful
1904 )"00:00:"$( : Reserved
1905 )"$(ipv6_to_bytes $GRP):"$( : Multicast address
1908 local len=$(u16_to_bytes $(payload_template_nbytes $icmpv6))
1910 )"$(ipv6_to_bytes $SIP):"$( : SIP
1911 )"$(ipv6_to_bytes $GRP):"$( : DIP is multicast address
1912 )"${len}:"$( : Upper-layer length
1913 )"00:3a:"$( : Zero and next-header
1915 local checksum=$(payload_template_calc_checksum ${sudohdr}${icmpv6})
1917 payload_template_expand_checksum "$hbh$icmpv6" $checksum
1922 local reason1="$1"; shift
1923 local reason2="$1"; shift
1925 if systemctl is-active --quiet lldpad; then
1927 cat >/dev/stderr <<-EOF
1928 WARNING: lldpad is running
1930 lldpad will likely $reason1, and this test will
1931 $reason2. Both are not supported at the same time,
1932 one of them is arbitrarily going to overwrite the
1933 other. That will cause spurious failures (or, unlikely,
1934 passes) of this test.
1937 if [[ -z $ALLOW_LLDPAD ]]; then
1938 cat >/dev/stderr <<-EOF
1940 If you want to run the test anyway, please set
1941 an environment variable ALLOW_LLDPAD to a