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
794 local netns=${1:-""}; shift
796 tc $netns -j -s filter show $id \
797 | jq ".[] | select(.options.handle == $handle) | \
798 .options.actions[0].stats$selector"
806 ethtool -S $dev | grep "^ *$stat:" | head -n 1 | cut -d: -f2
809 ethtool_std_stats_get()
816 ethtool --json -S $dev --groups $grp -- --src $src | \
817 jq '.[]."'"$grp"'"."'$name'"'
823 local handle=$1; shift
824 local selector=$1; shift
826 tc -j -s qdisc show dev "$dev" \
827 | jq '.[] | select(.handle == "'"$handle"'") | '"$selector"
830 qdisc_parent_stats_get()
833 local parent=$1; shift
834 local selector=$1; shift
836 tc -j -s qdisc show dev "$dev" invisible \
837 | jq '.[] | select(.parent == "'"$parent"'") | '"$selector"
845 cat /proc/net/dev_snmp6/$dev | grep "^$stat" | cut -f2
850 local suite=$1; shift
851 local if_name=$1; shift
855 ip -j stats show dev $if_name group offload subgroup $suite |
856 jq ".[0].stats64.$dir.$stat"
861 local speed=$1; shift
863 for unit in bps Kbps Mbps Gbps; do
864 if (($(echo "$speed < 1024" | bc))); then
868 speed=$(echo "scale=1; $speed / 1024" | bc)
878 local interval=$1; shift
880 echo $((8 * (t1 - t0) / interval))
887 local interval=$1; shift
889 echo $(((t1 - t0) / interval))
896 ip -j link show dev $if_name | jq -r '.[]["address"]'
903 ip -j addr show dev $if_name | \
904 jq -r '.[]["addr_info"][] | select(.scope == "link").local' | \
908 bridge_ageing_time_get()
913 # Need to divide by 100 to convert to seconds.
914 ageing_time=$(ip -j -d link show dev $bridge \
915 | jq '.[]["linkinfo"]["info_data"]["ageing_time"]')
916 echo $((ageing_time / 100))
919 declare -A SYSCTL_ORIG
923 local value=$1; shift
925 SYSCTL_ORIG[$key]=$(sysctl -n $key)
926 sysctl -qw $key="$value"
933 sysctl -qw $key="${SYSCTL_ORIG[$key]}"
938 sysctl_set net.ipv4.conf.all.forwarding 1
939 sysctl_set net.ipv6.conf.all.forwarding 1
944 sysctl_restore net.ipv6.conf.all.forwarding
945 sysctl_restore net.ipv4.conf.all.forwarding
954 MTU_ORIG["$dev"]=$(ip -j link show dev $dev | jq -e '.[].mtu')
955 ip link set dev $dev mtu $mtu
962 ip link set dev $dev mtu ${MTU_ORIG["$dev"]}
967 local num_netifs=${1:-$NUM_NETIFS}
969 for ((i = 1; i <= num_netifs; ++i)); do
970 ethtool -k ${NETIFS[p$i]} \
971 | grep "hw-tc-offload: on" &> /dev/null
972 if [[ $? -ne 0 ]]; then
983 local direction=$1; shift
985 # Some devices may not support or need in-hardware trapping of traffic
986 # (e.g. the veth pairs that this library creates for non-existent
987 # loopbacks). Use continue instead, so that there is a filter in there
988 # (some tests check counters), and so that other filters are still
990 tc filter add dev $dev $direction pref 1 \
991 flower skip_sw action trap 2>/dev/null \
992 || tc filter add dev $dev $direction pref 1 \
993 flower action continue
999 local direction=$1; shift
1001 tc filter del dev $dev $direction pref 1 flower
1004 slow_path_trap_install()
1006 # For slow-path testing, we need to install a trap to get to
1007 # slow path the packets that would otherwise be switched in HW.
1008 if [ "${tcflags/skip_hw}" != "$tcflags" ]; then
1013 slow_path_trap_uninstall()
1015 if [ "${tcflags/skip_hw}" != "$tcflags" ]; then
1020 __icmp_capture_add_del()
1022 local add_del=$1; shift
1023 local pref=$1; shift
1024 local vsuf=$1; shift
1025 local tundev=$1; shift
1026 local filter=$1; shift
1028 tc filter $add_del dev "$tundev" ingress \
1029 proto ip$vsuf pref $pref \
1030 flower ip_proto icmp$vsuf $filter \
1034 icmp_capture_install()
1036 __icmp_capture_add_del add 100 "" "$@"
1039 icmp_capture_uninstall()
1041 __icmp_capture_add_del del 100 "" "$@"
1044 icmp6_capture_install()
1046 __icmp_capture_add_del add 100 v6 "$@"
1049 icmp6_capture_uninstall()
1051 __icmp_capture_add_del del 100 v6 "$@"
1054 __vlan_capture_add_del()
1056 local add_del=$1; shift
1057 local pref=$1; shift
1059 local filter=$1; shift
1061 tc filter $add_del dev "$dev" ingress \
1062 proto 802.1q pref $pref \
1067 vlan_capture_install()
1069 __vlan_capture_add_del add 100 "$@"
1072 vlan_capture_uninstall()
1074 __vlan_capture_add_del del 100 "$@"
1077 __dscp_capture_add_del()
1079 local add_del=$1; shift
1081 local base=$1; shift
1084 for prio in {0..7}; do
1085 dscp=$((base + prio))
1086 __icmp_capture_add_del $add_del $((dscp + 100)) "" $dev \
1087 "skip_hw ip_tos $((dscp << 2))"
1091 dscp_capture_install()
1094 local base=$1; shift
1096 __dscp_capture_add_del add $dev $base
1099 dscp_capture_uninstall()
1102 local base=$1; shift
1104 __dscp_capture_add_del del $dev $base
1110 local base=$1; shift
1112 for prio in {0..7}; do
1113 local dscp=$((base + prio))
1114 local t=$(tc_rule_stats_get $dev $((dscp + 100)))
1119 matchall_sink_create()
1123 tc qdisc add dev $dev clsact
1124 tc filter add dev $dev ingress \
1134 for current_test in ${TESTS:-$ALL_TESTS}; do
1142 local weight_rp12=$2
1143 local weight_rp13=$3
1144 local packets_rp12=$4
1145 local packets_rp13=$5
1146 local weights_ratio packets_ratio diff
1150 if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
1151 weights_ratio=$(echo "scale=2; $weight_rp12 / $weight_rp13" \
1154 weights_ratio=$(echo "scale=2; $weight_rp13 / $weight_rp12" \
1158 if [[ "$packets_rp12" -eq "0" || "$packets_rp13" -eq "0" ]]; then
1159 check_err 1 "Packet difference is 0"
1160 log_test "Multipath"
1161 log_info "Expected ratio $weights_ratio"
1165 if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
1166 packets_ratio=$(echo "scale=2; $packets_rp12 / $packets_rp13" \
1169 packets_ratio=$(echo "scale=2; $packets_rp13 / $packets_rp12" \
1173 diff=$(echo $weights_ratio - $packets_ratio | bc -l)
1176 test "$(echo "$diff / $weights_ratio > 0.15" | bc -l)" -eq 0
1177 check_err $? "Too large discrepancy between expected and measured ratios"
1179 log_info "Expected ratio $weights_ratio Measured ratio $packets_ratio"
1184 local name=$1; shift
1186 ip netns exec $name bash <<-EOF
1189 $(for a in "$@"; do printf "%q${IFS:0:1}" "$a"; done)
1193 ##############################################################################
1203 vrf_name=$(master_name_get $if_name)
1204 ip vrf exec $vrf_name \
1205 $PING $args $dip -c $PING_COUNT -i 0.1 \
1206 -w $PING_TIMEOUT &> /dev/null
1225 vrf_name=$(master_name_get $if_name)
1226 ip vrf exec $vrf_name \
1227 $PING6 $args $dip -c $PING_COUNT -i 0.1 \
1228 -w $PING_TIMEOUT &> /dev/null
1243 local br_port1=$2 # Connected to `host1_if`.
1246 local mac=de:ad:be:ef:13:37
1251 bridge -j fdb show br $bridge brport $br_port1 \
1252 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1253 check_fail $? "Found FDB record when should not"
1255 # Disable unknown unicast flooding on `br_port1` to make sure
1256 # packets are only forwarded through the port after a matching
1257 # FDB entry was installed.
1258 bridge link set dev $br_port1 flood off
1260 ip link set $host1_if promisc on
1261 tc qdisc add dev $host1_if ingress
1262 tc filter add dev $host1_if ingress protocol ip pref 1 handle 101 \
1263 flower dst_mac $mac action drop
1265 $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q
1268 tc -j -s filter show dev $host1_if ingress \
1269 | jq -e ".[] | select(.options.handle == 101) \
1270 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1271 check_fail $? "Packet reached first host when should not"
1273 $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
1276 bridge -j fdb show br $bridge brport $br_port1 \
1277 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1278 check_err $? "Did not find FDB record when should"
1280 $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q
1283 tc -j -s filter show dev $host1_if ingress \
1284 | jq -e ".[] | select(.options.handle == 101) \
1285 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1286 check_err $? "Packet did not reach second host when should"
1288 # Wait for 10 seconds after the ageing time to make sure FDB
1289 # record was aged-out.
1290 ageing_time=$(bridge_ageing_time_get $bridge)
1291 sleep $((ageing_time + 10))
1293 bridge -j fdb show br $bridge brport $br_port1 \
1294 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1295 check_fail $? "Found FDB record when should not"
1297 bridge link set dev $br_port1 learning off
1299 $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
1302 bridge -j fdb show br $bridge brport $br_port1 \
1303 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1304 check_fail $? "Found FDB record when should not"
1306 bridge link set dev $br_port1 learning on
1308 tc filter del dev $host1_if ingress protocol ip pref 1 handle 101 flower
1309 tc qdisc del dev $host1_if ingress
1310 ip link set $host1_if promisc off
1312 bridge link set dev $br_port1 flood on
1314 log_test "FDB learning"
1319 local should_flood=$1
1326 # Add an ACL on `host2_if` which will tell us whether the packet
1327 # was flooded to it or not.
1328 ip link set $host2_if promisc on
1329 tc qdisc add dev $host2_if ingress
1330 tc filter add dev $host2_if ingress protocol ip pref 1 handle 101 \
1331 flower dst_mac $mac action drop
1333 $MZ $host1_if -c 1 -p 64 -b $mac -B $ip -t ip -q
1336 tc -j -s filter show dev $host2_if ingress \
1337 | jq -e ".[] | select(.options.handle == 101) \
1338 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1339 if [[ $? -ne 0 && $should_flood == "true" || \
1340 $? -eq 0 && $should_flood == "false" ]]; then
1344 tc filter del dev $host2_if ingress protocol ip pref 1 handle 101 flower
1345 tc qdisc del dev $host2_if ingress
1346 ip link set $host2_if promisc off
1351 flood_unicast_test()
1356 local mac=de:ad:be:ef:13:37
1357 local ip=192.0.2.100
1361 bridge link set dev $br_port flood off
1363 flood_test_do false $mac $ip $host1_if $host2_if
1364 check_err $? "Packet flooded when should not"
1366 bridge link set dev $br_port flood on
1368 flood_test_do true $mac $ip $host1_if $host2_if
1369 check_err $? "Packet was not flooded when should"
1371 log_test "Unknown unicast flood"
1374 flood_multicast_test()
1379 local mac=01:00:5e:00:00:01
1384 bridge link set dev $br_port mcast_flood off
1386 flood_test_do false $mac $ip $host1_if $host2_if
1387 check_err $? "Packet flooded when should not"
1389 bridge link set dev $br_port mcast_flood on
1391 flood_test_do true $mac $ip $host1_if $host2_if
1392 check_err $? "Packet was not flooded when should"
1394 log_test "Unregistered multicast flood"
1399 # `br_port` is connected to `host2_if`
1404 flood_unicast_test $br_port $host1_if $host2_if
1405 flood_multicast_test $br_port $host1_if $host2_if
1410 local pktsize=$1; shift
1411 local proto=$1; shift
1412 local h_in=$1; shift # Where the traffic egresses the host
1415 local dmac=$1; shift
1417 $MZ $h_in -p $pktsize -A $sip -B $dip -c 0 \
1418 -a own -b $dmac -t "$proto" -q "$@" &
1422 start_traffic_pktsize()
1424 local pktsize=$1; shift
1426 __start_traffic $pktsize udp "$@"
1429 start_tcp_traffic_pktsize()
1431 local pktsize=$1; shift
1433 __start_traffic $pktsize tcp "$@"
1438 start_traffic_pktsize 8000 "$@"
1443 start_tcp_traffic_pktsize 8000 "$@"
1448 # Suppress noise from killing mausezahn.
1449 { kill %% && wait %%; } 2>/dev/null
1458 local if_name=$1; shift
1461 capfile[$if_name]=$(mktemp)
1462 capout[$if_name]=$(mktemp)
1467 ns_cmd="ip netns exec ${ns}"
1470 if [ -z $SUDO_USER ] ; then
1473 capuser="-Z $SUDO_USER"
1476 $ns_cmd tcpdump $TCPDUMP_EXTRA_FLAGS -e -n -Q in -i $if_name \
1477 -s 65535 -B 32768 $capuser -w ${capfile[$if_name]} \
1478 > "${capout[$if_name]}" 2>&1 &
1487 local pid=${cappid[$if_name]}
1489 $ns_cmd kill "$pid" && wait "$pid"
1497 rm ${capfile[$if_name]} ${capout[$if_name]}
1504 tcpdump -e -n -r ${capfile[$if_name]} 2>&1
1507 # return 0 if the packet wasn't seen on host2_if or 1 if it was
1519 # basic check to see if we were passed an IPv4 address, if not assume IPv6
1520 if [[ ! $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
1525 # Add an ACL on `host2_if` which will tell us whether the packet
1526 # was received by it or not.
1527 tc qdisc add dev $host2_if ingress
1528 tc filter add dev $host2_if ingress protocol $tc_proto pref 1 handle 101 \
1529 flower ip_proto udp dst_mac $mac action drop
1531 $MZ $host1_if $mz_v6arg -c 1 -p 64 -b $mac -A $src_ip -B $ip -t udp "dp=4096,sp=2048" -q
1534 tc -j -s filter show dev $host2_if ingress \
1535 | jq -e ".[] | select(.options.handle == 101) \
1536 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1537 if [[ $? -eq 0 ]]; then
1541 tc filter del dev $host2_if ingress protocol $tc_proto pref 1 handle 101 flower
1542 tc qdisc del dev $host2_if ingress
1547 brmcast_check_sg_entries()
1549 local report=$1; shift
1553 for src in "${slist[@]}"; do
1554 sarg="${sarg} and .source_list[].address == \"$src\""
1556 bridge -j -d -s mdb show dev br0 \
1557 | jq -e ".[].mdb[] | \
1558 select(.grp == \"$TEST_GROUP\" and .source_list != null $sarg)" &>/dev/null
1559 check_err $? "Wrong *,G entry source list after $report report"
1561 for sgent in "${slist[@]}"; do
1562 bridge -j -d -s mdb show dev br0 \
1563 | jq -e ".[].mdb[] | \
1564 select(.grp == \"$TEST_GROUP\" and .src == \"$sgent\")" &>/dev/null
1565 check_err $? "Missing S,G entry ($sgent, $TEST_GROUP)"
1569 brmcast_check_sg_fwding()
1571 local should_fwd=$1; shift
1572 local sources=("$@")
1574 for src in "${sources[@]}"; do
1577 mcast_packet_test $TEST_GROUP_MAC $src $TEST_GROUP $h2 $h1
1579 if [ $should_fwd -eq 1 ]; then
1580 check_fail $retval "Didn't forward traffic from S,G ($src, $TEST_GROUP)"
1582 check_err $retval "Forwarded traffic for blocked S,G ($src, $TEST_GROUP)"
1587 brmcast_check_sg_state()
1589 local is_blocked=$1; shift
1590 local sources=("$@")
1593 if [ $is_blocked -eq 1 ]; then
1597 for src in "${sources[@]}"; do
1598 bridge -j -d -s mdb show dev br0 \
1599 | jq -e ".[].mdb[] | \
1600 select(.grp == \"$TEST_GROUP\" and .source_list != null) |
1602 select(.address == \"$src\") |
1603 select(.timer == \"0.00\")" &>/dev/null
1604 check_err_fail $should_fail $? "Entry $src has zero timer"
1606 bridge -j -d -s mdb show dev br0 \
1607 | jq -e ".[].mdb[] | \
1608 select(.grp == \"$TEST_GROUP\" and .src == \"$src\" and \
1609 .flags[] == \"blocked\")" &>/dev/null
1610 check_err_fail $should_fail $? "Entry $src has blocked flag"
1618 local vrf_name=$(master_name_get $if_name)
1620 # We don't care about actual reception, just about joining the
1621 # IP multicast group and adding the L2 address to the device's
1622 # MAC filtering table
1623 ip vrf exec $vrf_name \
1624 mreceive -g $group -I $if_name > /dev/null 2>&1 &
1632 kill "$mreceive_pid" && wait "$mreceive_pid"
1639 local vrf_name=$(master_name_get $if_name)
1641 ip vrf exec $vrf_name \
1642 msend -g $groups -I $if_name -c 1 > /dev/null 2>&1
1647 local mtype=$1; shift
1648 local ip=${1-ip}; shift
1650 # start the monitor in the background
1651 tmpfile=`mktemp /var/run/nexthoptestXXX`
1652 mpid=`($ip monitor $mtype > $tmpfile & echo $!) 2>/dev/null`
1654 echo "$mpid $tmpfile"
1659 local mpid=$1; shift
1660 local tmpfile=$1; shift
1662 local what=$1; shift
1666 local lines=`grep '^\w' $tmpfile | wc -l`
1668 check_err $? "$what: $lines lines of events, expected $el"
1672 hw_stats_monitor_test()
1675 local type=$1; shift
1676 local make_suitable=$1; shift
1677 local make_unsuitable=$1; shift
1678 local ip=${1-ip}; shift
1682 # Expect a notification about enablement.
1683 local ipmout=$(start_ip_monitor stats "$ip")
1684 $ip stats set dev $dev ${type}_stats on
1685 stop_ip_monitor $ipmout 1 "${type}_stats enablement"
1687 # Expect a notification about offload.
1688 local ipmout=$(start_ip_monitor stats "$ip")
1690 stop_ip_monitor $ipmout 1 "${type}_stats installation"
1692 # Expect a notification about loss of offload.
1693 local ipmout=$(start_ip_monitor stats "$ip")
1695 stop_ip_monitor $ipmout 1 "${type}_stats deinstallation"
1697 # Expect a notification about disablement
1698 local ipmout=$(start_ip_monitor stats "$ip")
1699 $ip stats set dev $dev ${type}_stats off
1700 stop_ip_monitor $ipmout 1 "${type}_stats disablement"
1702 log_test "${type}_stats notifications"
1709 printf '%02x:' ${IP//./ } |
1713 # Convert a given IPv6 address, `IP' such that the :: token, if present, is
1714 # expanded, and each 16-bit group is padded with zeroes to be 4 hexadecimal
1715 # digits. An optional `BYTESEP' parameter can be given to further separate
1716 # individual bytes of each 16-bit group.
1720 local bytesep=$1; shift
1722 local cvt_ip=${IP/::/_}
1723 local colons=${cvt_ip//[^:]/}
1724 local allcol=:::::::
1725 # IP where :: -> the appropriate number of colons:
1726 local allcol_ip=${cvt_ip/_/${allcol:${#colons}}}
1728 echo $allcol_ip | tr : '\n' |
1730 sed 's/.*\(..\)\(..\)/\1'"$bytesep"'\2/' |
1746 printf "%04x" $u16 | sed 's/^/000/;s/^.*\(..\)\(..\)$/\1:\2/'
1749 # Given a mausezahn-formatted payload (colon-separated bytes given as %02x),
1750 # possibly with a keyword CHECKSUM stashed where a 16-bit checksum should be,
1751 # calculate checksum as per RFC 1071, assuming the CHECKSUM field (if any)
1753 payload_template_calc_checksum()
1755 local payload=$1; shift
1760 # Push zero for the initial checksum.
1763 # Pad the payload with a terminating 00: in case we get an odd
1765 echo "${payload%:}:00:" |
1766 sed 's/CHECKSUM/00:00/g' |
1767 tr '[:lower:]' '[:upper:]' |
1768 # Add the word to the checksum.
1769 sed 's/\(..\):\(..\):/\1\2+\n/g' |
1770 # Strip the extra odd byte we pushed if left unconverted.
1773 echo "10000 ~ +" # Calculate and add carry.
1774 echo "FFFF r - p" # Bit-flip and print.
1777 tr '[:upper:]' '[:lower:]'
1780 payload_template_expand_checksum()
1782 local payload=$1; shift
1783 local checksum=$1; shift
1785 local ckbytes=$(u16_to_bytes $checksum)
1787 echo "$payload" | sed "s/CHECKSUM/$ckbytes/g"
1790 payload_template_nbytes()
1792 local payload=$1; shift
1794 payload_template_expand_checksum "${payload%:}" 0 |
1795 sed 's/:/\n/g' | wc -l
1801 local sources=("$@")
1804 local nsources=$(u16_to_bytes ${#sources[@]})
1806 # IS_IN ( $sources )
1808 )"22:"$( : Type - Membership Report
1810 )"CHECKSUM:"$( : Checksum
1811 )"00:00:"$( : Reserved
1812 )"00:01:"$( : Number of Group Records
1813 )"01:"$( : Record Type - IS_IN
1814 )"00:"$( : Aux Data Len
1815 )"${nsources}:"$( : Number of Sources
1816 )"$(ipv4_to_bytes $GRP):"$( : Multicast Address
1817 )"$(for src in "${sources[@]}"; do
1820 done)"$( : Source Addresses
1822 local checksum=$(payload_template_calc_checksum "$igmpv3")
1824 payload_template_expand_checksum "$igmpv3" $checksum
1832 )"17:"$( : Type - Leave Group
1833 )"00:"$( : Max Resp Time - not meaningful
1834 )"CHECKSUM:"$( : Checksum
1835 )"$(ipv4_to_bytes $GRP)"$( : Group Address
1837 local checksum=$(payload_template_calc_checksum "$payload")
1839 payload_template_expand_checksum "$payload" $checksum
1846 local sources=("$@")
1850 local nsources=$(u16_to_bytes ${#sources[@]})
1853 )"3a:"$( : Next Header - ICMPv6
1854 )"00:"$( : Hdr Ext Len
1855 )"00:00:00:00:00:00:"$( : Options and Padding
1859 )"8f:"$( : Type - MLDv2 Report
1861 )"CHECKSUM:"$( : Checksum
1862 )"00:00:"$( : Reserved
1863 )"00:01:"$( : Number of Group Records
1864 )"01:"$( : Record Type - IS_IN
1865 )"00:"$( : Aux Data Len
1866 )"${nsources}:"$( : Number of Sources
1867 )"$(ipv6_to_bytes $GRP):"$( : Multicast address
1868 )"$(for src in "${sources[@]}"; do
1871 done)"$( : Source Addresses
1874 local len=$(u16_to_bytes $(payload_template_nbytes $icmpv6))
1876 )"$(ipv6_to_bytes $SIP):"$( : SIP
1877 )"$(ipv6_to_bytes $GRP):"$( : DIP is multicast address
1878 )"${len}:"$( : Upper-layer length
1879 )"00:3a:"$( : Zero and next-header
1881 local checksum=$(payload_template_calc_checksum ${sudohdr}${icmpv6})
1883 payload_template_expand_checksum "$hbh$icmpv6" $checksum
1895 )"3a:"$( : Next Header - ICMPv6
1896 )"00:"$( : Hdr Ext Len
1897 )"00:00:00:00:00:00:"$( : Options and Padding
1901 )"84:"$( : Type - MLDv1 Done
1903 )"CHECKSUM:"$( : Checksum
1904 )"00:00:"$( : Max Resp Delay - not meaningful
1905 )"00:00:"$( : Reserved
1906 )"$(ipv6_to_bytes $GRP):"$( : Multicast address
1909 local len=$(u16_to_bytes $(payload_template_nbytes $icmpv6))
1911 )"$(ipv6_to_bytes $SIP):"$( : SIP
1912 )"$(ipv6_to_bytes $GRP):"$( : DIP is multicast address
1913 )"${len}:"$( : Upper-layer length
1914 )"00:3a:"$( : Zero and next-header
1916 local checksum=$(payload_template_calc_checksum ${sudohdr}${icmpv6})
1918 payload_template_expand_checksum "$hbh$icmpv6" $checksum
1923 local reason1="$1"; shift
1924 local reason2="$1"; shift
1926 if systemctl is-active --quiet lldpad; then
1928 cat >/dev/stderr <<-EOF
1929 WARNING: lldpad is running
1931 lldpad will likely $reason1, and this test will
1932 $reason2. Both are not supported at the same time,
1933 one of them is arbitrarily going to overwrite the
1934 other. That will cause spurious failures (or, unlikely,
1935 passes) of this test.
1938 if [[ -z $ALLOW_LLDPAD ]]; then
1939 cat >/dev/stderr <<-EOF
1941 If you want to run the test anyway, please set
1942 an environment variable ALLOW_LLDPAD to a