2 # SPDX-License-Identifier: GPL-2.0
4 ##############################################################################
5 # Topology description. p1 looped back to p2, p3 to p4 and so on.
20 # Port that does not have a cable connected.
21 : "${NETIF_NO_CABLE:=eth8}"
23 ##############################################################################
26 # Networking utilities.
28 : "${PING6:=ping6}" # Some distros just use ping.
30 : "${TROUTE6:=traceroute6}"
33 : "${MZ:=mausezahn}" # Some distributions use 'mz'.
36 # Host configuration tools.
39 : "${MC_CLI:=smcroutectl}"
41 # Constants for netdevice bring-up:
42 # Default time in seconds to wait for an interface to come up before giving up
43 # and bailing out. Used during initial setup.
44 : "${INTERFACE_TIMEOUT:=600}"
45 # Like INTERFACE_TIMEOUT, but default for ad-hoc waiting in testing scripts.
46 : "${WAIT_TIMEOUT:=20}"
47 # Time to wait after interfaces participating in the test are all UP.
50 # Whether to pause on, respectively, after a failure and before cleanup.
51 : "${PAUSE_ON_CLEANUP:=no}"
53 # Whether to create virtual interfaces, and what netdevice type they should be.
54 : "${NETIF_CREATE:=yes}"
55 : "${NETIF_TYPE:=veth}"
57 # Constants for ping tests:
58 # How many packets should be sent.
60 # Timeout (in seconds) before ping exits regardless of how many packets have
61 # been sent or received
62 : "${PING_TIMEOUT:=5}"
64 # Minimum ageing_time (in centiseconds) supported by hardware
65 : "${LOW_AGEING_TIME:=1000}"
67 # Whether to check for availability of certain tools.
68 : "${REQUIRE_JQ:=yes}"
69 : "${REQUIRE_MZ:=yes}"
70 : "${REQUIRE_MTOOLS:=no}"
71 : "${REQUIRE_TEAMD:=no}"
73 # Whether to override MAC addresses on interfaces participating in the test.
74 : "${STABLE_MAC_ADDRS:=no}"
77 : "${TCPDUMP_EXTRA_FLAGS:=}"
79 # Flags for TC filters.
80 : "${TC_FLAG:=skip_hw}"
82 # Whether the machine is "slow" -- i.e. might be incapable of running tests
83 # involving heavy traffic. This might be the case on a debug kernel, a VM, or
84 # e.g. a low-power board.
85 : "${KSFT_MACHINE_SLOW:=no}"
87 ##############################################################################
88 # Find netifs by test-specified driver name
93 local driver_path="/sys/class/net/$dev/device/driver"
95 if [[ -L $driver_path ]]; then
96 basename `realpath $driver_path`
102 local ifnames=`ip -j link show | jq -r ".[].ifname"`
105 for ifname in $ifnames
107 local driver_name=`driver_name_get $ifname`
108 if [[ ! -z $driver_name && $driver_name == $NETIF_FIND_DRIVER ]]; then
110 NETIFS[p$count]="$ifname"
115 # Whether to find netdevice according to the driver speficied by the importer
116 : "${NETIF_FIND_DRIVER:=}"
118 if [[ $NETIF_FIND_DRIVER ]]; then
124 net_forwarding_dir=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")
126 if [[ -f $net_forwarding_dir/forwarding.config ]]; then
127 source "$net_forwarding_dir/forwarding.config"
130 source "$net_forwarding_dir/../lib.sh"
132 ##############################################################################
138 if [[ $? -ne 0 ]]; then
139 echo "SKIP: iproute2 too old; tc is missing JSON support"
144 # Old versions of tc don't understand "mpls_uc"
145 check_tc_mpls_support()
149 tc filter add dev $dev ingress protocol mpls_uc pref 1 handle 1 \
150 matchall action pipe &> /dev/null
151 if [[ $? -ne 0 ]]; then
152 echo "SKIP: iproute2 too old; tc is missing MPLS support"
155 tc filter del dev $dev ingress protocol mpls_uc pref 1 handle 1 \
159 # Old versions of tc produce invalid json output for mpls lse statistics
160 check_tc_mpls_lse_stats()
165 tc filter add dev $dev ingress protocol mpls_uc pref 1 handle 1 \
166 flower mpls lse depth 2 \
167 action continue &> /dev/null
169 if [[ $? -ne 0 ]]; then
170 echo "SKIP: iproute2 too old; tc-flower is missing extended MPLS support"
174 tc -j filter show dev $dev ingress protocol mpls_uc | jq . &> /dev/null
176 tc filter del dev $dev ingress protocol mpls_uc pref 1 handle 1 \
179 if [[ $ret -ne 0 ]]; then
180 echo "SKIP: iproute2 too old; tc-flower produces invalid json output for extended MPLS filters"
185 check_tc_shblock_support()
187 tc filter help 2>&1 | grep block &> /dev/null
188 if [[ $? -ne 0 ]]; then
189 echo "SKIP: iproute2 too old; tc is missing shared block support"
194 check_tc_chain_support()
196 tc help 2>&1|grep chain &> /dev/null
197 if [[ $? -ne 0 ]]; then
198 echo "SKIP: iproute2 too old; tc is missing chain support"
203 check_tc_action_hw_stats_support()
205 tc actions help 2>&1 | grep -q hw_stats
206 if [[ $? -ne 0 ]]; then
207 echo "SKIP: iproute2 too old; tc is missing action hw_stats support"
212 check_tc_fp_support()
214 tc qdisc add dev lo mqprio help 2>&1 | grep -q "fp "
215 if [[ $? -ne 0 ]]; then
216 echo "SKIP: iproute2 too old; tc is missing frame preemption support"
221 check_ethtool_lanes_support()
223 ethtool --help 2>&1| grep lanes &> /dev/null
224 if [[ $? -ne 0 ]]; then
225 echo "SKIP: ethtool too old; it is missing lanes support"
230 check_ethtool_mm_support()
232 ethtool --help 2>&1| grep -- '--show-mm' &> /dev/null
233 if [[ $? -ne 0 ]]; then
234 echo "SKIP: ethtool too old; it is missing MAC Merge layer support"
239 check_ethtool_counter_group_support()
241 ethtool --help 2>&1| grep -- '--all-groups' &> /dev/null
242 if [[ $? -ne 0 ]]; then
243 echo "SKIP: ethtool too old; it is missing standard counter group support"
248 check_ethtool_pmac_std_stats_support()
253 [ 0 -ne $(ethtool --json -S $dev --all-groups --src pmac 2>/dev/null \
254 | jq ".[].\"$grp\" | length") ]
257 check_locked_port_support()
259 if ! bridge -d link show | grep -q " locked"; then
260 echo "SKIP: iproute2 too old; Locked port feature not supported."
265 check_port_mab_support()
267 if ! bridge -d link show | grep -q "mab"; then
268 echo "SKIP: iproute2 too old; MacAuth feature not supported."
273 if [[ "$(id -u)" -ne 0 ]]; then
274 echo "SKIP: need root privileges"
281 local expected=$1; shift
282 local driver_name=`driver_name_get $dev`
284 if [[ $driver_name != $expected ]]; then
285 echo "SKIP: expected driver $expected for $dev, got $driver_name instead"
290 if [[ "$CHECK_TC" = "yes" ]]; then
298 if [[ ! -x "$(command -v "$cmd")" ]]; then
299 echo "SKIP: $cmd not installed"
304 # IPv6 support was added in v3.0
305 check_mtools_version()
307 local version="$(msend -v)"
310 version=${version##msend version }
311 major=$(echo $version | cut -d. -f1)
313 if [ $major -lt 3 ]; then
314 echo "SKIP: expected mtools version 3.0, got $version"
319 if [[ "$REQUIRE_JQ" = "yes" ]]; then
322 if [[ "$REQUIRE_MZ" = "yes" ]]; then
325 if [[ "$REQUIRE_TEAMD" = "yes" ]]; then
326 require_command $TEAMD
328 if [[ "$REQUIRE_MTOOLS" = "yes" ]]; then
329 # https://github.com/troglobit/mtools
330 require_command msend
331 require_command mreceive
335 ##############################################################################
336 # Command line options handling
340 while [[ $# -gt 0 ]]; do
341 if [[ "$count" -eq "0" ]]; then
350 ##############################################################################
351 # Network interfaces configuration
353 if [[ ! -v NUM_NETIFS ]]; then
354 echo "SKIP: importer does not define \"NUM_NETIFS\""
358 if (( NUM_NETIFS > ${#NETIFS[@]} )); then
359 echo "SKIP: Importer requires $NUM_NETIFS NETIFS, but only ${#NETIFS[@]} are defined (${NETIFS[@]})"
363 for i in $(seq ${#NETIFS[@]}); do
364 if [[ ! ${NETIFS[p$i]} ]]; then
365 echo "SKIP: NETIFS[p$i] not given"
374 for ((i = 1; i <= NUM_NETIFS; ++i)); do
377 if [ -z ${NETIFS[p$i]} ]; then
378 echo "SKIP: Cannot create interface. Name not specified"
382 ip link show dev ${NETIFS[p$i]} &> /dev/null
383 if [[ $? -ne 0 ]]; then
384 ip link add ${NETIFS[p$i]} type veth \
385 peer name ${NETIFS[p$j]}
386 if [[ $? -ne 0 ]]; then
387 echo "Failed to create netif"
397 case "$NETIF_TYPE" in
398 veth) create_netif_veth
400 *) echo "Can not create interfaces of type \'$NETIF_TYPE\'"
406 declare -A MAC_ADDR_ORIG
412 for ((i = 1; i <= NUM_NETIFS; ++i)); do
414 new_addr=$(printf "00:01:02:03:04:%02x" $i)
416 MAC_ADDR_ORIG["$dev"]=$(ip -j link show dev $dev | jq -e '.[].address')
418 MAC_ADDR_ORIG["$dev"]=${MAC_ADDR_ORIG["$dev"]//\"/}
419 ip link set dev $dev address $new_addr
427 for ((i = 1; i <= NUM_NETIFS; ++i)); do
429 ip link set dev $dev address ${MAC_ADDR_ORIG["$dev"]}
433 if [[ "$NETIF_CREATE" = "yes" ]]; then
437 if [[ "$STABLE_MAC_ADDRS" = "yes" ]]; then
441 for ((i = 1; i <= NUM_NETIFS; ++i)); do
442 ip link show dev ${NETIFS[p$i]} &> /dev/null
443 if [[ $? -ne 0 ]]; then
444 echo "SKIP: could not find all required interfaces"
449 ##############################################################################
463 for cur in ${arr[@]}; do
464 if [[ $cur -gt $max ]]; then
478 if [ "$1" == "self" ] || [ "$1" == "master" ]; then
480 if [ "$1" == "-v" ]; then
485 $@ | grep $addr | grep $flag "$word"
490 "$@" | grep -q "Link detected: yes"
495 "$@" | grep -q offload
506 local wait_time=${1:-$WAIT_TIME}; shift
508 setup_wait_dev_with_timeout "$dev" $INTERFACE_TIMEOUT $wait_time
512 log_test setup_wait_dev ": Interface $dev does not come up."
517 setup_wait_dev_with_timeout()
520 local max_iterations=${1:-$WAIT_TIMEOUT}; shift
521 local wait_time=${1:-$WAIT_TIME}; shift
524 for ((i = 1; i <= $max_iterations; ++i)); do
525 ip link show dev $dev up \
526 | grep 'state UP' &> /dev/null
527 if [[ $? -ne 0 ]]; then
540 local num_netifs=${1:-$NUM_NETIFS}
543 for ((i = 1; i <= num_netifs; ++i)); do
544 setup_wait_dev ${NETIFS[p$i]} 0
547 # Make sure links are ready.
554 local timeout=${1:-$WAIT_TIMEOUT}; shift
556 slowwait $timeout ip link show dev $dev &> /dev/null
559 log_test wait_for_dev "Interface $dev did not appear."
573 # it the command fails, return error right away
575 if [[ $ret -ne 0 ]]; then
578 output=$(echo $output | jq -r $jq_opts "$jq_exp")
580 if [[ $ret -ne 0 ]]; then
584 # return success only in case of non-empty output
590 if [ "${PAUSE_ON_CLEANUP}" = "yes" ]; then
591 echo "Pausing before cleanup, hit any key to continue"
595 if [[ "$STABLE_MAC_ADDRS" = "yes" ]]; then
602 ip -4 rule add pref 32765 table local
603 ip -4 rule del pref 0
604 ip -6 rule add pref 32765 table local
605 ip -6 rule del pref 0
610 ip -6 rule add pref 0 table local
611 ip -6 rule del pref 32765
612 ip -4 rule add pref 0 table local
613 ip -4 rule del pref 32765
623 __last_tb_id=$((__last_tb_id + 1))
624 __TB_IDS[$vrf_name]=$__last_tb_id
632 return ${__TB_IDS[$vrf_name]}
640 __vrf_td_id_assign $vrf_name
643 ip link add dev $vrf_name type vrf table $tb_id
644 ip -4 route add table $tb_id unreachable default metric 4278198272
645 ip -6 route add table $tb_id unreachable default metric 4278198272
653 __vrf_td_id_lookup $vrf_name
656 ip -6 route del table $tb_id unreachable default metric 4278198272
657 ip -4 route del table $tb_id unreachable default metric 4278198272
658 ip link del dev $vrf_name
671 for addrstr in "${array[@]}"; do
672 ip address $add_del $addrstr dev $if_name
678 local if_name=$1; shift
679 local vrf_name=$1; shift
682 ip link set dev $if_name master $vrf_name
683 ip link set dev $if_name up
685 __addr_add_del $if_name add "${addrs[@]}"
690 local if_name=$1; shift
693 __addr_add_del $if_name del "${addrs[@]}"
695 ip link set dev $if_name down
696 ip link set dev $if_name nomaster
710 ip link set dev $vrf_name up
711 __simple_if_init $if_name $vrf_name "${array[@]}"
724 __simple_if_fini $if_name "${array[@]}"
725 vrf_destroy $vrf_name
732 local local=$1; shift
733 local remote=$1; shift
735 ip link add name $name type $type \
736 local $local remote $remote "$@"
737 ip link set dev $name up
744 ip link del dev $name
749 local if_name=$1; shift
753 local name=$if_name.$vid
755 ip link add name $name link $if_name type vlan id $vid
756 if [ "$vrf" != "" ]; then
757 ip link set dev $name master $vrf
759 ip link set dev $name up
760 __addr_add_del $name add "${ips[@]}"
765 local if_name=$1; shift
767 local name=$if_name.$vid
769 ip link del dev $name
774 local if_name=$1; shift
777 require_command $TEAMD
778 $TEAMD -t $if_name -d -c '{"runner": {"name": "'$mode'"}}'
779 for slave in "$@"; do
780 ip link set dev $slave down
781 ip link set dev $slave master $if_name
782 ip link set dev $slave up
784 ip link set dev $if_name up
789 local if_name=$1; shift
791 $TEAMD -t $if_name -k
798 ip -j link show dev $if_name | jq -r '.[]["master"]'
803 local if_name=$1; shift
807 ip -j -s link show dev $if_name \
808 | jq '.[]["stats64"]["'$dir'"]["'$stat'"]'
811 link_stats_tx_packets_get()
813 link_stats_get $1 tx packets
816 link_stats_rx_errors_get()
818 link_stats_get $1 rx errors
826 ethtool -S $dev | grep "^ *$stat:" | head -n 1 | cut -d: -f2
829 ethtool_std_stats_get()
836 ethtool --json -S $dev --groups $grp -- --src $src | \
837 jq '.[]."'"$grp"'"."'$name'"'
843 local handle=$1; shift
844 local selector=$1; shift
846 tc -j -s qdisc show dev "$dev" \
847 | jq '.[] | select(.handle == "'"$handle"'") | '"$selector"
850 qdisc_parent_stats_get()
853 local parent=$1; shift
854 local selector=$1; shift
856 tc -j -s qdisc show dev "$dev" invisible \
857 | jq '.[] | select(.parent == "'"$parent"'") | '"$selector"
865 cat /proc/net/dev_snmp6/$dev | grep "^$stat" | cut -f2
870 local suite=$1; shift
871 local if_name=$1; shift
875 ip -j stats show dev $if_name group offload subgroup $suite |
876 jq ".[0].stats64.$dir.$stat"
882 local group_id=$1; shift
883 local member_id=$1; shift
885 ip -j -s -s nexthop show id $group_id |
886 jq --argjson member_id "$member_id" --arg key "$key" \
887 '.[].group_stats[] | select(.id == $member_id) | .[$key]'
892 local group_id=$1; shift
893 local member_id=$1; shift
895 __nh_stats_get packets "$group_id" "$member_id"
900 local group_id=$1; shift
901 local member_id=$1; shift
903 __nh_stats_get packets_hw "$group_id" "$member_id"
908 local speed=$1; shift
910 for unit in bps Kbps Mbps Gbps; do
911 if (($(echo "$speed < 1024" | bc))); then
915 speed=$(echo "scale=1; $speed / 1024" | bc)
925 local interval=$1; shift
927 echo $((8 * (t1 - t0) / interval))
934 local interval=$1; shift
936 echo $(((t1 - t0) / interval))
942 local order="$((1 << 40))"
948 for byte in $addr; do
950 val=$((val + order * byte))
951 order=$((order >> 8))
963 for ((i = 40; i >= 0; i -= 8)); do
964 byte=$(((val & (0xff << i)) >> i))
966 if [ $i -ne 0 ]; then
976 ip -j addr show dev $if_name | \
977 jq -r '.[]["addr_info"][] | select(.scope == "link").local' | \
981 bridge_ageing_time_get()
986 # Need to divide by 100 to convert to seconds.
987 ageing_time=$(ip -j -d link show dev $bridge \
988 | jq '.[]["linkinfo"]["info_data"]["ageing_time"]')
989 echo $((ageing_time / 100))
992 declare -A SYSCTL_ORIG
997 SYSCTL_ORIG[$key]=$(sysctl -n $key)
1003 local value=$1; shift
1006 sysctl -qw $key="$value"
1013 sysctl -qw $key="${SYSCTL_ORIG[$key]}"
1018 sysctl_set net.ipv4.conf.all.forwarding 1
1019 sysctl_set net.ipv6.conf.all.forwarding 1
1022 forwarding_restore()
1024 sysctl_restore net.ipv6.conf.all.forwarding
1025 sysctl_restore net.ipv4.conf.all.forwarding
1034 MTU_ORIG["$dev"]=$(ip -j link show dev $dev | jq -e '.[].mtu')
1035 ip link set dev $dev mtu $mtu
1042 ip link set dev $dev mtu ${MTU_ORIG["$dev"]}
1047 local num_netifs=${1:-$NUM_NETIFS}
1049 for ((i = 1; i <= num_netifs; ++i)); do
1050 ethtool -k ${NETIFS[p$i]} \
1051 | grep "hw-tc-offload: on" &> /dev/null
1052 if [[ $? -ne 0 ]]; then
1063 local direction=$1; shift
1065 # Some devices may not support or need in-hardware trapping of traffic
1066 # (e.g. the veth pairs that this library creates for non-existent
1067 # loopbacks). Use continue instead, so that there is a filter in there
1068 # (some tests check counters), and so that other filters are still
1070 tc filter add dev $dev $direction pref 1 \
1071 flower skip_sw action trap 2>/dev/null \
1072 || tc filter add dev $dev $direction pref 1 \
1073 flower action continue
1079 local direction=$1; shift
1081 tc filter del dev $dev $direction pref 1 flower
1084 __icmp_capture_add_del()
1086 local add_del=$1; shift
1087 local pref=$1; shift
1088 local vsuf=$1; shift
1089 local tundev=$1; shift
1090 local filter=$1; shift
1092 tc filter $add_del dev "$tundev" ingress \
1093 proto ip$vsuf pref $pref \
1094 flower ip_proto icmp$vsuf $filter \
1098 icmp_capture_install()
1100 local tundev=$1; shift
1101 local filter=$1; shift
1103 __icmp_capture_add_del add 100 "" "$tundev" "$filter"
1106 icmp_capture_uninstall()
1108 local tundev=$1; shift
1109 local filter=$1; shift
1111 __icmp_capture_add_del del 100 "" "$tundev" "$filter"
1114 icmp6_capture_install()
1116 local tundev=$1; shift
1117 local filter=$1; shift
1119 __icmp_capture_add_del add 100 v6 "$tundev" "$filter"
1122 icmp6_capture_uninstall()
1124 local tundev=$1; shift
1125 local filter=$1; shift
1127 __icmp_capture_add_del del 100 v6 "$tundev" "$filter"
1130 __vlan_capture_add_del()
1132 local add_del=$1; shift
1133 local pref=$1; shift
1135 local filter=$1; shift
1137 tc filter $add_del dev "$dev" ingress \
1138 proto 802.1q pref $pref \
1143 vlan_capture_install()
1146 local filter=$1; shift
1148 __vlan_capture_add_del add 100 "$dev" "$filter"
1151 vlan_capture_uninstall()
1154 local filter=$1; shift
1156 __vlan_capture_add_del del 100 "$dev" "$filter"
1159 __dscp_capture_add_del()
1161 local add_del=$1; shift
1163 local base=$1; shift
1166 for prio in {0..7}; do
1167 dscp=$((base + prio))
1168 __icmp_capture_add_del $add_del $((dscp + 100)) "" $dev \
1169 "skip_hw ip_tos $((dscp << 2))"
1173 dscp_capture_install()
1176 local base=$1; shift
1178 __dscp_capture_add_del add $dev $base
1181 dscp_capture_uninstall()
1184 local base=$1; shift
1186 __dscp_capture_add_del del $dev $base
1192 local base=$1; shift
1194 for prio in {0..7}; do
1195 local dscp=$((base + prio))
1196 local t=$(tc_rule_stats_get $dev $((dscp + 100)))
1201 matchall_sink_create()
1205 tc qdisc add dev $dev clsact
1206 tc filter add dev $dev ingress \
1215 defer_scopes_cleanup
1221 local weight_rp12=$2
1222 local weight_rp13=$3
1223 local packets_rp12=$4
1224 local packets_rp13=$5
1225 local weights_ratio packets_ratio diff
1229 if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
1230 weights_ratio=$(echo "scale=2; $weight_rp12 / $weight_rp13" \
1233 weights_ratio=$(echo "scale=2; $weight_rp13 / $weight_rp12" \
1237 if [[ "$packets_rp12" -eq "0" || "$packets_rp13" -eq "0" ]]; then
1238 check_err 1 "Packet difference is 0"
1239 log_test "Multipath"
1240 log_info "Expected ratio $weights_ratio"
1244 if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
1245 packets_ratio=$(echo "scale=2; $packets_rp12 / $packets_rp13" \
1248 packets_ratio=$(echo "scale=2; $packets_rp13 / $packets_rp12" \
1252 diff=$(echo $weights_ratio - $packets_ratio | bc -l)
1255 test "$(echo "$diff / $weights_ratio > 0.15" | bc -l)" -eq 0
1256 check_err $? "Too large discrepancy between expected and measured ratios"
1258 log_info "Expected ratio $weights_ratio Measured ratio $packets_ratio"
1263 local name=$1; shift
1265 ip netns exec $name bash <<-EOF
1268 $(for a in "$@"; do printf "%q${IFS:0:1}" "$a"; done)
1272 ##############################################################################
1282 vrf_name=$(master_name_get $if_name)
1283 ip vrf exec $vrf_name \
1284 $PING $args $dip -c $PING_COUNT -i 0.1 \
1285 -w $PING_TIMEOUT &> /dev/null
1303 log_test "ping fails$3"
1313 vrf_name=$(master_name_get $if_name)
1314 ip vrf exec $vrf_name \
1315 $PING6 $args $dip -c $PING_COUNT -i 0.1 \
1316 -w $PING_TIMEOUT &> /dev/null
1334 log_test "ping6 fails$3"
1340 local br_port1=$2 # Connected to `host1_if`.
1343 local mac=de:ad:be:ef:13:37
1348 bridge -j fdb show br $bridge brport $br_port1 \
1349 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1350 check_fail $? "Found FDB record when should not"
1352 # Disable unknown unicast flooding on `br_port1` to make sure
1353 # packets are only forwarded through the port after a matching
1354 # FDB entry was installed.
1355 bridge link set dev $br_port1 flood off
1357 ip link set $host1_if promisc on
1358 tc qdisc add dev $host1_if ingress
1359 tc filter add dev $host1_if ingress protocol ip pref 1 handle 101 \
1360 flower dst_mac $mac action drop
1362 $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q
1365 tc -j -s filter show dev $host1_if ingress \
1366 | jq -e ".[] | select(.options.handle == 101) \
1367 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1368 check_fail $? "Packet reached first host when should not"
1370 $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
1373 bridge -j fdb show br $bridge brport $br_port1 \
1374 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1375 check_err $? "Did not find FDB record when should"
1377 $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q
1380 tc -j -s filter show dev $host1_if ingress \
1381 | jq -e ".[] | select(.options.handle == 101) \
1382 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1383 check_err $? "Packet did not reach second host when should"
1385 # Wait for 10 seconds after the ageing time to make sure FDB
1386 # record was aged-out.
1387 ageing_time=$(bridge_ageing_time_get $bridge)
1388 sleep $((ageing_time + 10))
1390 bridge -j fdb show br $bridge brport $br_port1 \
1391 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1392 check_fail $? "Found FDB record when should not"
1394 bridge link set dev $br_port1 learning off
1396 $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
1399 bridge -j fdb show br $bridge brport $br_port1 \
1400 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1401 check_fail $? "Found FDB record when should not"
1403 bridge link set dev $br_port1 learning on
1405 tc filter del dev $host1_if ingress protocol ip pref 1 handle 101 flower
1406 tc qdisc del dev $host1_if ingress
1407 ip link set $host1_if promisc off
1409 bridge link set dev $br_port1 flood on
1411 log_test "FDB learning"
1416 local should_flood=$1
1423 # Add an ACL on `host2_if` which will tell us whether the packet
1424 # was flooded to it or not.
1425 ip link set $host2_if promisc on
1426 tc qdisc add dev $host2_if ingress
1427 tc filter add dev $host2_if ingress protocol ip pref 1 handle 101 \
1428 flower dst_mac $mac action drop
1430 $MZ $host1_if -c 1 -p 64 -b $mac -B $ip -t ip -q
1433 tc -j -s filter show dev $host2_if ingress \
1434 | jq -e ".[] | select(.options.handle == 101) \
1435 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1436 if [[ $? -ne 0 && $should_flood == "true" || \
1437 $? -eq 0 && $should_flood == "false" ]]; then
1441 tc filter del dev $host2_if ingress protocol ip pref 1 handle 101 flower
1442 tc qdisc del dev $host2_if ingress
1443 ip link set $host2_if promisc off
1448 flood_unicast_test()
1453 local mac=de:ad:be:ef:13:37
1454 local ip=192.0.2.100
1458 bridge link set dev $br_port flood off
1460 flood_test_do false $mac $ip $host1_if $host2_if
1461 check_err $? "Packet flooded when should not"
1463 bridge link set dev $br_port flood on
1465 flood_test_do true $mac $ip $host1_if $host2_if
1466 check_err $? "Packet was not flooded when should"
1468 log_test "Unknown unicast flood"
1471 flood_multicast_test()
1476 local mac=01:00:5e:00:00:01
1481 bridge link set dev $br_port mcast_flood off
1483 flood_test_do false $mac $ip $host1_if $host2_if
1484 check_err $? "Packet flooded when should not"
1486 bridge link set dev $br_port mcast_flood on
1488 flood_test_do true $mac $ip $host1_if $host2_if
1489 check_err $? "Packet was not flooded when should"
1491 log_test "Unregistered multicast flood"
1496 # `br_port` is connected to `host2_if`
1501 flood_unicast_test $br_port $host1_if $host2_if
1502 flood_multicast_test $br_port $host1_if $host2_if
1507 local pktsize=$1; shift
1508 local proto=$1; shift
1509 local h_in=$1; shift # Where the traffic egresses the host
1512 local dmac=$1; shift
1513 local -a mz_args=("$@")
1515 $MZ $h_in -p $pktsize -A $sip -B $dip -c 0 \
1516 -a own -b $dmac -t "$proto" -q "${mz_args[@]}" &
1520 start_traffic_pktsize()
1522 local pktsize=$1; shift
1523 local h_in=$1; shift
1526 local dmac=$1; shift
1527 local -a mz_args=("$@")
1529 __start_traffic $pktsize udp "$h_in" "$sip" "$dip" "$dmac" \
1533 start_tcp_traffic_pktsize()
1535 local pktsize=$1; shift
1536 local h_in=$1; shift
1539 local dmac=$1; shift
1540 local -a mz_args=("$@")
1542 __start_traffic $pktsize tcp "$h_in" "$sip" "$dip" "$dmac" \
1548 local h_in=$1; shift
1551 local dmac=$1; shift
1552 local -a mz_args=("$@")
1554 start_traffic_pktsize 8000 "$h_in" "$sip" "$dip" "$dmac" \
1560 local h_in=$1; shift
1563 local dmac=$1; shift
1564 local -a mz_args=("$@")
1566 start_tcp_traffic_pktsize 8000 "$h_in" "$sip" "$dip" "$dmac" \
1572 local pid=${1-%%}; shift
1583 local if_name=$1; shift
1586 capfile[$if_name]=$(mktemp)
1587 capout[$if_name]=$(mktemp)
1592 ns_cmd="ip netns exec ${ns}"
1595 if [ -z $SUDO_USER ] ; then
1598 capuser="-Z $SUDO_USER"
1601 $ns_cmd tcpdump $TCPDUMP_EXTRA_FLAGS -e -n -Q in -i $if_name \
1602 -s 65535 -B 32768 $capuser -w ${capfile[$if_name]} \
1603 > "${capout[$if_name]}" 2>&1 &
1612 local pid=${cappid[$if_name]}
1614 $ns_cmd kill "$pid" && wait "$pid"
1622 rm ${capfile[$if_name]} ${capout[$if_name]}
1629 tcpdump -e -n -r ${capfile[$if_name]} 2>&1
1632 # return 0 if the packet wasn't seen on host2_if or 1 if it was
1644 # basic check to see if we were passed an IPv4 address, if not assume IPv6
1645 if [[ ! $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
1650 # Add an ACL on `host2_if` which will tell us whether the packet
1651 # was received by it or not.
1652 tc qdisc add dev $host2_if ingress
1653 tc filter add dev $host2_if ingress protocol $tc_proto pref 1 handle 101 \
1654 flower ip_proto udp dst_mac $mac action drop
1656 $MZ $host1_if $mz_v6arg -c 1 -p 64 -b $mac -A $src_ip -B $ip -t udp "dp=4096,sp=2048" -q
1659 tc -j -s filter show dev $host2_if ingress \
1660 | jq -e ".[] | select(.options.handle == 101) \
1661 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1662 if [[ $? -eq 0 ]]; then
1666 tc filter del dev $host2_if ingress protocol $tc_proto pref 1 handle 101 flower
1667 tc qdisc del dev $host2_if ingress
1672 brmcast_check_sg_entries()
1674 local report=$1; shift
1678 for src in "${slist[@]}"; do
1679 sarg="${sarg} and .source_list[].address == \"$src\""
1681 bridge -j -d -s mdb show dev br0 \
1682 | jq -e ".[].mdb[] | \
1683 select(.grp == \"$TEST_GROUP\" and .source_list != null $sarg)" &>/dev/null
1684 check_err $? "Wrong *,G entry source list after $report report"
1686 for sgent in "${slist[@]}"; do
1687 bridge -j -d -s mdb show dev br0 \
1688 | jq -e ".[].mdb[] | \
1689 select(.grp == \"$TEST_GROUP\" and .src == \"$sgent\")" &>/dev/null
1690 check_err $? "Missing S,G entry ($sgent, $TEST_GROUP)"
1694 brmcast_check_sg_fwding()
1696 local should_fwd=$1; shift
1697 local sources=("$@")
1699 for src in "${sources[@]}"; do
1702 mcast_packet_test $TEST_GROUP_MAC $src $TEST_GROUP $h2 $h1
1704 if [ $should_fwd -eq 1 ]; then
1705 check_fail $retval "Didn't forward traffic from S,G ($src, $TEST_GROUP)"
1707 check_err $retval "Forwarded traffic for blocked S,G ($src, $TEST_GROUP)"
1712 brmcast_check_sg_state()
1714 local is_blocked=$1; shift
1715 local sources=("$@")
1718 if [ $is_blocked -eq 1 ]; then
1722 for src in "${sources[@]}"; do
1723 bridge -j -d -s mdb show dev br0 \
1724 | jq -e ".[].mdb[] | \
1725 select(.grp == \"$TEST_GROUP\" and .source_list != null) |
1727 select(.address == \"$src\") |
1728 select(.timer == \"0.00\")" &>/dev/null
1729 check_err_fail $should_fail $? "Entry $src has zero timer"
1731 bridge -j -d -s mdb show dev br0 \
1732 | jq -e ".[].mdb[] | \
1733 select(.grp == \"$TEST_GROUP\" and .src == \"$src\" and \
1734 .flags[] == \"blocked\")" &>/dev/null
1735 check_err_fail $should_fail $? "Entry $src has blocked flag"
1743 local vrf_name=$(master_name_get $if_name)
1745 # We don't care about actual reception, just about joining the
1746 # IP multicast group and adding the L2 address to the device's
1747 # MAC filtering table
1748 ip vrf exec $vrf_name \
1749 mreceive -g $group -I $if_name > /dev/null 2>&1 &
1757 kill "$mreceive_pid" && wait "$mreceive_pid"
1764 local vrf_name=$(master_name_get $if_name)
1766 ip vrf exec $vrf_name \
1767 msend -g $groups -I $if_name -c 1 > /dev/null 2>&1
1772 local mtype=$1; shift
1773 local ip=${1-ip}; shift
1775 # start the monitor in the background
1776 tmpfile=`mktemp /var/run/nexthoptestXXX`
1777 mpid=`($ip monitor $mtype > $tmpfile & echo $!) 2>/dev/null`
1779 echo "$mpid $tmpfile"
1784 local mpid=$1; shift
1785 local tmpfile=$1; shift
1787 local what=$1; shift
1791 local lines=`grep '^\w' $tmpfile | wc -l`
1793 check_err $? "$what: $lines lines of events, expected $el"
1797 hw_stats_monitor_test()
1800 local type=$1; shift
1801 local make_suitable=$1; shift
1802 local make_unsuitable=$1; shift
1803 local ip=${1-ip}; shift
1807 # Expect a notification about enablement.
1808 local ipmout=$(start_ip_monitor stats "$ip")
1809 $ip stats set dev $dev ${type}_stats on
1810 stop_ip_monitor $ipmout 1 "${type}_stats enablement"
1812 # Expect a notification about offload.
1813 local ipmout=$(start_ip_monitor stats "$ip")
1815 stop_ip_monitor $ipmout 1 "${type}_stats installation"
1817 # Expect a notification about loss of offload.
1818 local ipmout=$(start_ip_monitor stats "$ip")
1820 stop_ip_monitor $ipmout 1 "${type}_stats deinstallation"
1822 # Expect a notification about disablement
1823 local ipmout=$(start_ip_monitor stats "$ip")
1824 $ip stats set dev $dev ${type}_stats off
1825 stop_ip_monitor $ipmout 1 "${type}_stats disablement"
1827 log_test "${type}_stats notifications"
1834 printf '%02x:' ${IP//./ } |
1838 # Convert a given IPv6 address, `IP' such that the :: token, if present, is
1839 # expanded, and each 16-bit group is padded with zeroes to be 4 hexadecimal
1840 # digits. An optional `BYTESEP' parameter can be given to further separate
1841 # individual bytes of each 16-bit group.
1845 local bytesep=$1; shift
1847 local cvt_ip=${IP/::/_}
1848 local colons=${cvt_ip//[^:]/}
1849 local allcol=:::::::
1850 # IP where :: -> the appropriate number of colons:
1851 local allcol_ip=${cvt_ip/_/${allcol:${#colons}}}
1853 echo $allcol_ip | tr : '\n' |
1855 sed 's/.*\(..\)\(..\)/\1'"$bytesep"'\2/' |
1871 printf "%04x" $u16 | sed 's/^/000/;s/^.*\(..\)\(..\)$/\1:\2/'
1874 # Given a mausezahn-formatted payload (colon-separated bytes given as %02x),
1875 # possibly with a keyword CHECKSUM stashed where a 16-bit checksum should be,
1876 # calculate checksum as per RFC 1071, assuming the CHECKSUM field (if any)
1878 payload_template_calc_checksum()
1880 local payload=$1; shift
1885 # Push zero for the initial checksum.
1888 # Pad the payload with a terminating 00: in case we get an odd
1890 echo "${payload%:}:00:" |
1891 sed 's/CHECKSUM/00:00/g' |
1892 tr '[:lower:]' '[:upper:]' |
1893 # Add the word to the checksum.
1894 sed 's/\(..\):\(..\):/\1\2+\n/g' |
1895 # Strip the extra odd byte we pushed if left unconverted.
1898 echo "10000 ~ +" # Calculate and add carry.
1899 echo "FFFF r - p" # Bit-flip and print.
1902 tr '[:upper:]' '[:lower:]'
1905 payload_template_expand_checksum()
1907 local payload=$1; shift
1908 local checksum=$1; shift
1910 local ckbytes=$(u16_to_bytes $checksum)
1912 echo "$payload" | sed "s/CHECKSUM/$ckbytes/g"
1915 payload_template_nbytes()
1917 local payload=$1; shift
1919 payload_template_expand_checksum "${payload%:}" 0 |
1920 sed 's/:/\n/g' | wc -l
1926 local sources=("$@")
1929 local nsources=$(u16_to_bytes ${#sources[@]})
1931 # IS_IN ( $sources )
1933 )"22:"$( : Type - Membership Report
1935 )"CHECKSUM:"$( : Checksum
1936 )"00:00:"$( : Reserved
1937 )"00:01:"$( : Number of Group Records
1938 )"01:"$( : Record Type - IS_IN
1939 )"00:"$( : Aux Data Len
1940 )"${nsources}:"$( : Number of Sources
1941 )"$(ipv4_to_bytes $GRP):"$( : Multicast Address
1942 )"$(for src in "${sources[@]}"; do
1945 done)"$( : Source Addresses
1947 local checksum=$(payload_template_calc_checksum "$igmpv3")
1949 payload_template_expand_checksum "$igmpv3" $checksum
1957 )"17:"$( : Type - Leave Group
1958 )"00:"$( : Max Resp Time - not meaningful
1959 )"CHECKSUM:"$( : Checksum
1960 )"$(ipv4_to_bytes $GRP)"$( : Group Address
1962 local checksum=$(payload_template_calc_checksum "$payload")
1964 payload_template_expand_checksum "$payload" $checksum
1971 local sources=("$@")
1975 local nsources=$(u16_to_bytes ${#sources[@]})
1978 )"3a:"$( : Next Header - ICMPv6
1979 )"00:"$( : Hdr Ext Len
1980 )"00:00:00:00:00:00:"$( : Options and Padding
1984 )"8f:"$( : Type - MLDv2 Report
1986 )"CHECKSUM:"$( : Checksum
1987 )"00:00:"$( : Reserved
1988 )"00:01:"$( : Number of Group Records
1989 )"01:"$( : Record Type - IS_IN
1990 )"00:"$( : Aux Data Len
1991 )"${nsources}:"$( : Number of Sources
1992 )"$(ipv6_to_bytes $GRP):"$( : Multicast address
1993 )"$(for src in "${sources[@]}"; do
1996 done)"$( : Source Addresses
1999 local len=$(u16_to_bytes $(payload_template_nbytes $icmpv6))
2001 )"$(ipv6_to_bytes $SIP):"$( : SIP
2002 )"$(ipv6_to_bytes $GRP):"$( : DIP is multicast address
2003 )"${len}:"$( : Upper-layer length
2004 )"00:3a:"$( : Zero and next-header
2006 local checksum=$(payload_template_calc_checksum ${sudohdr}${icmpv6})
2008 payload_template_expand_checksum "$hbh$icmpv6" $checksum
2020 )"3a:"$( : Next Header - ICMPv6
2021 )"00:"$( : Hdr Ext Len
2022 )"00:00:00:00:00:00:"$( : Options and Padding
2026 )"84:"$( : Type - MLDv1 Done
2028 )"CHECKSUM:"$( : Checksum
2029 )"00:00:"$( : Max Resp Delay - not meaningful
2030 )"00:00:"$( : Reserved
2031 )"$(ipv6_to_bytes $GRP):"$( : Multicast address
2034 local len=$(u16_to_bytes $(payload_template_nbytes $icmpv6))
2036 )"$(ipv6_to_bytes $SIP):"$( : SIP
2037 )"$(ipv6_to_bytes $GRP):"$( : DIP is multicast address
2038 )"${len}:"$( : Upper-layer length
2039 )"00:3a:"$( : Zero and next-header
2041 local checksum=$(payload_template_calc_checksum ${sudohdr}${icmpv6})
2043 payload_template_expand_checksum "$hbh$icmpv6" $checksum
2048 local reason1="$1"; shift
2049 local reason2="$1"; shift
2050 local caller=${FUNCNAME[1]}
2051 local src=${BASH_SOURCE[1]}
2053 if systemctl is-active --quiet lldpad; then
2055 cat >/dev/stderr <<-EOF
2056 WARNING: lldpad is running
2058 lldpad will likely $reason1, and this test will
2059 $reason2. Both are not supported at the same time,
2060 one of them is arbitrarily going to overwrite the
2061 other. That will cause spurious failures (or, unlikely,
2062 passes) of this test.
2065 if [[ -z $ALLOW_LLDPAD ]]; then
2066 cat >/dev/stderr <<-EOF
2068 If you want to run the test anyway, please set
2069 an environment variable ALLOW_LLDPAD to a
2072 log_test_skip $src:$caller
2084 echo $((v > 0 ? v : -v))
2090 local mac_addr=$(mac_get $dev)
2091 local tmp=$(ether_addr_to_u64 $mac_addr)
2095 ip link add link $dev name macvlan-tmp type macvlan mode private
2096 ip link set macvlan-tmp address $(u64_to_ether_addr $((tmp + 1)))
2097 ip link set macvlan-tmp up
2099 promisc=$(ip -j -d link show dev $dev | jq -r '.[].promiscuity')
2101 ip link del macvlan-tmp
2103 [[ $promisc == 1 ]] && echo "no" || echo "yes"