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_FAIL:=no}"
52 : "${PAUSE_ON_CLEANUP:=no}"
54 # Whether to create virtual interfaces, and what netdevice type they should be.
55 : "${NETIF_CREATE:=yes}"
56 : "${NETIF_TYPE:=veth}"
58 # Constants for ping tests:
59 # How many packets should be sent.
61 # Timeout (in seconds) before ping exits regardless of how many packets have
62 # been sent or received
63 : "${PING_TIMEOUT:=5}"
65 # Minimum ageing_time (in centiseconds) supported by hardware
66 : "${LOW_AGEING_TIME:=1000}"
68 # Whether to check for availability of certain tools.
69 : "${REQUIRE_JQ:=yes}"
70 : "${REQUIRE_MZ:=yes}"
71 : "${REQUIRE_MTOOLS:=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_MTOOLS" = "yes" ]]; then
326 # https://github.com/troglobit/mtools
327 require_command msend
328 require_command mreceive
332 ##############################################################################
333 # Command line options handling
337 while [[ $# -gt 0 ]]; do
338 if [[ "$count" -eq "0" ]]; then
347 ##############################################################################
348 # Network interfaces configuration
350 if [[ ! -v NUM_NETIFS ]]; then
351 echo "SKIP: importer does not define \"NUM_NETIFS\""
355 if (( NUM_NETIFS > ${#NETIFS[@]} )); then
356 echo "SKIP: Importer requires $NUM_NETIFS NETIFS, but only ${#NETIFS[@]} are defined (${NETIFS[@]})"
360 for i in $(seq ${#NETIFS[@]}); do
361 if [[ ! ${NETIFS[p$i]} ]]; then
362 echo "SKIP: NETIFS[p$i] not given"
371 for ((i = 1; i <= NUM_NETIFS; ++i)); do
374 if [ -z ${NETIFS[p$i]} ]; then
375 echo "SKIP: Cannot create interface. Name not specified"
379 ip link show dev ${NETIFS[p$i]} &> /dev/null
380 if [[ $? -ne 0 ]]; then
381 ip link add ${NETIFS[p$i]} type veth \
382 peer name ${NETIFS[p$j]}
383 if [[ $? -ne 0 ]]; then
384 echo "Failed to create netif"
394 case "$NETIF_TYPE" in
395 veth) create_netif_veth
397 *) echo "Can not create interfaces of type \'$NETIF_TYPE\'"
403 declare -A MAC_ADDR_ORIG
409 for ((i = 1; i <= NUM_NETIFS; ++i)); do
411 new_addr=$(printf "00:01:02:03:04:%02x" $i)
413 MAC_ADDR_ORIG["$dev"]=$(ip -j link show dev $dev | jq -e '.[].address')
415 MAC_ADDR_ORIG["$dev"]=${MAC_ADDR_ORIG["$dev"]//\"/}
416 ip link set dev $dev address $new_addr
424 for ((i = 1; i <= NUM_NETIFS; ++i)); do
426 ip link set dev $dev address ${MAC_ADDR_ORIG["$dev"]}
430 if [[ "$NETIF_CREATE" = "yes" ]]; then
434 if [[ "$STABLE_MAC_ADDRS" = "yes" ]]; then
438 for ((i = 1; i <= NUM_NETIFS; ++i)); do
439 ip link show dev ${NETIFS[p$i]} &> /dev/null
440 if [[ $? -ne 0 ]]; then
441 echo "SKIP: could not find all required interfaces"
446 ##############################################################################
449 # Exit status to return at the end. Set in case one of the tests fails.
451 # Per-test return value. Clear at the beginning of each test.
454 ret_set_ksft_status()
456 local ksft_status=$1; shift
459 RET=$(ksft_status_merge $RET $ksft_status)
465 # Whether FAILs should be interpreted as XFAILs. Internal.
474 if [[ $FAIL_TO_XFAIL = yes ]]; then
475 ret_set_ksft_status $ksft_xfail "$msg"
477 ret_set_ksft_status $ksft_fail "$msg"
487 check_err $((!err)) "$msg"
492 local should_fail=$1; shift
496 if ((should_fail)); then
497 check_fail $err "$what succeeded, but should have failed"
499 check_err $err "$what failed"
505 if [[ $KSFT_MACHINE_SLOW = yes ]]; then
506 FAIL_TO_XFAIL=yes "$@"
517 kind=$(ip -j -d link show dev $dev |
518 jq -r '.[].linkinfo.info_kind')
519 if [[ $kind = veth ]]; then
520 FAIL_TO_XFAIL=yes "$@"
528 local test_name=$1; shift
529 local opt_str=$1; shift
530 local result=$1; shift
531 local retmsg=$1; shift
533 printf "TEST: %-60s [%s]\n" "$test_name $opt_str" "$result"
534 if [[ $retmsg ]]; then
535 printf "\t%s\n" "$retmsg"
541 if [[ $PAUSE_ON_FAIL == yes ]]; then
542 echo "Hit enter to continue, 'q' to quit"
544 [[ $a == q ]] && exit 1
548 handle_test_result_pass()
550 local test_name=$1; shift
551 local opt_str=$1; shift
553 log_test_result "$test_name" "$opt_str" " OK "
556 handle_test_result_fail()
558 local test_name=$1; shift
559 local opt_str=$1; shift
561 log_test_result "$test_name" "$opt_str" FAIL "$retmsg"
565 handle_test_result_xfail()
567 local test_name=$1; shift
568 local opt_str=$1; shift
570 log_test_result "$test_name" "$opt_str" XFAIL "$retmsg"
574 handle_test_result_skip()
576 local test_name=$1; shift
577 local opt_str=$1; shift
579 log_test_result "$test_name" "$opt_str" SKIP "$retmsg"
587 if [[ $# -eq 2 ]]; then
591 if ((RET == ksft_pass)); then
592 handle_test_result_pass "$test_name" "$opt_str"
593 elif ((RET == ksft_xfail)); then
594 handle_test_result_xfail "$test_name" "$opt_str"
595 elif ((RET == ksft_skip)); then
596 handle_test_result_skip "$test_name" "$opt_str"
598 handle_test_result_fail "$test_name" "$opt_str"
601 EXIT_STATUS=$(ksft_exit_status_merge $EXIT_STATUS $RET)
607 RET=$ksft_skip retmsg= log_test "$@"
612 RET=$ksft_xfail retmsg= log_test "$@"
633 for cur in ${arr[@]}; do
634 if [[ $cur -gt $max ]]; then
648 if [ "$1" == "self" ] || [ "$1" == "master" ]; then
650 if [ "$1" == "-v" ]; then
655 $@ | grep $addr | grep $flag "$word"
660 "$@" | grep -q "Link detected: yes"
665 "$@" | grep -q offload
676 local wait_time=${1:-$WAIT_TIME}; shift
678 setup_wait_dev_with_timeout "$dev" $INTERFACE_TIMEOUT $wait_time
682 log_test setup_wait_dev ": Interface $dev does not come up."
687 setup_wait_dev_with_timeout()
690 local max_iterations=${1:-$WAIT_TIMEOUT}; shift
691 local wait_time=${1:-$WAIT_TIME}; shift
694 for ((i = 1; i <= $max_iterations; ++i)); do
695 ip link show dev $dev up \
696 | grep 'state UP' &> /dev/null
697 if [[ $? -ne 0 ]]; then
710 local num_netifs=${1:-$NUM_NETIFS}
713 for ((i = 1; i <= num_netifs; ++i)); do
714 setup_wait_dev ${NETIFS[p$i]} 0
717 # Make sure links are ready.
724 local timeout=${1:-$WAIT_TIMEOUT}; shift
726 slowwait $timeout ip link show dev $dev &> /dev/null
729 log_test wait_for_dev "Interface $dev did not appear."
743 # it the command fails, return error right away
745 if [[ $ret -ne 0 ]]; then
748 output=$(echo $output | jq -r $jq_opts "$jq_exp")
750 if [[ $ret -ne 0 ]]; then
754 # return success only in case of non-empty output
760 if [ "${PAUSE_ON_CLEANUP}" = "yes" ]; then
761 echo "Pausing before cleanup, hit any key to continue"
765 if [[ "$STABLE_MAC_ADDRS" = "yes" ]]; then
772 ip -4 rule add pref 32765 table local
773 ip -4 rule del pref 0
774 ip -6 rule add pref 32765 table local
775 ip -6 rule del pref 0
780 ip -6 rule add pref 0 table local
781 ip -6 rule del pref 32765
782 ip -4 rule add pref 0 table local
783 ip -4 rule del pref 32765
793 __last_tb_id=$((__last_tb_id + 1))
794 __TB_IDS[$vrf_name]=$__last_tb_id
802 return ${__TB_IDS[$vrf_name]}
810 __vrf_td_id_assign $vrf_name
813 ip link add dev $vrf_name type vrf table $tb_id
814 ip -4 route add table $tb_id unreachable default metric 4278198272
815 ip -6 route add table $tb_id unreachable default metric 4278198272
823 __vrf_td_id_lookup $vrf_name
826 ip -6 route del table $tb_id unreachable default metric 4278198272
827 ip -4 route del table $tb_id unreachable default metric 4278198272
828 ip link del dev $vrf_name
841 for addrstr in "${array[@]}"; do
842 ip address $add_del $addrstr dev $if_name
848 local if_name=$1; shift
849 local vrf_name=$1; shift
852 ip link set dev $if_name master $vrf_name
853 ip link set dev $if_name up
855 __addr_add_del $if_name add "${addrs[@]}"
860 local if_name=$1; shift
863 __addr_add_del $if_name del "${addrs[@]}"
865 ip link set dev $if_name down
866 ip link set dev $if_name nomaster
880 ip link set dev $vrf_name up
881 __simple_if_init $if_name $vrf_name "${array[@]}"
894 __simple_if_fini $if_name "${array[@]}"
895 vrf_destroy $vrf_name
902 local local=$1; shift
903 local remote=$1; shift
905 ip link add name $name type $type \
906 local $local remote $remote "$@"
907 ip link set dev $name up
914 ip link del dev $name
919 local if_name=$1; shift
923 local name=$if_name.$vid
925 ip link add name $name link $if_name type vlan id $vid
926 if [ "$vrf" != "" ]; then
927 ip link set dev $name master $vrf
929 ip link set dev $name up
930 __addr_add_del $name add "${ips[@]}"
935 local if_name=$1; shift
937 local name=$if_name.$vid
939 ip link del dev $name
944 local if_name=$1; shift
947 require_command $TEAMD
948 $TEAMD -t $if_name -d -c '{"runner": {"name": "'$mode'"}}'
949 for slave in "$@"; do
950 ip link set dev $slave down
951 ip link set dev $slave master $if_name
952 ip link set dev $slave up
954 ip link set dev $if_name up
959 local if_name=$1; shift
961 $TEAMD -t $if_name -k
968 ip -j link show dev $if_name | jq -r '.[]["master"]'
973 local if_name=$1; shift
977 ip -j -s link show dev $if_name \
978 | jq '.[]["stats64"]["'$dir'"]["'$stat'"]'
981 link_stats_tx_packets_get()
983 link_stats_get $1 tx packets
986 link_stats_rx_errors_get()
988 link_stats_get $1 rx errors
996 ethtool -S $dev | grep "^ *$stat:" | head -n 1 | cut -d: -f2
999 ethtool_std_stats_get()
1003 local name=$1; shift
1006 ethtool --json -S $dev --groups $grp -- --src $src | \
1007 jq '.[]."'"$grp"'"."'$name'"'
1013 local handle=$1; shift
1014 local selector=$1; shift
1016 tc -j -s qdisc show dev "$dev" \
1017 | jq '.[] | select(.handle == "'"$handle"'") | '"$selector"
1020 qdisc_parent_stats_get()
1023 local parent=$1; shift
1024 local selector=$1; shift
1026 tc -j -s qdisc show dev "$dev" invisible \
1027 | jq '.[] | select(.parent == "'"$parent"'") | '"$selector"
1033 local stat=$1; shift
1035 cat /proc/net/dev_snmp6/$dev | grep "^$stat" | cut -f2
1040 local suite=$1; shift
1041 local if_name=$1; shift
1043 local stat=$1; shift
1045 ip -j stats show dev $if_name group offload subgroup $suite |
1046 jq ".[0].stats64.$dir.$stat"
1052 local group_id=$1; shift
1053 local member_id=$1; shift
1055 ip -j -s -s nexthop show id $group_id |
1056 jq --argjson member_id "$member_id" --arg key "$key" \
1057 '.[].group_stats[] | select(.id == $member_id) | .[$key]'
1062 local group_id=$1; shift
1063 local member_id=$1; shift
1065 __nh_stats_get packets "$group_id" "$member_id"
1070 local group_id=$1; shift
1071 local member_id=$1; shift
1073 __nh_stats_get packets_hw "$group_id" "$member_id"
1078 local speed=$1; shift
1080 for unit in bps Kbps Mbps Gbps; do
1081 if (($(echo "$speed < 1024" | bc))); then
1085 speed=$(echo "scale=1; $speed / 1024" | bc)
1088 echo "$speed${unit}"
1095 local interval=$1; shift
1097 echo $((8 * (t1 - t0) / interval))
1104 local interval=$1; shift
1106 echo $(((t1 - t0) / interval))
1113 ip -j link show dev $if_name | jq -r '.[]["address"]'
1120 ip -j addr show dev $if_name | \
1121 jq -r '.[]["addr_info"][] | select(.scope == "link").local' | \
1125 bridge_ageing_time_get()
1130 # Need to divide by 100 to convert to seconds.
1131 ageing_time=$(ip -j -d link show dev $bridge \
1132 | jq '.[]["linkinfo"]["info_data"]["ageing_time"]')
1133 echo $((ageing_time / 100))
1136 declare -A SYSCTL_ORIG
1141 SYSCTL_ORIG[$key]=$(sysctl -n $key)
1147 local value=$1; shift
1150 sysctl -qw $key="$value"
1157 sysctl -qw $key="${SYSCTL_ORIG[$key]}"
1162 sysctl_set net.ipv4.conf.all.forwarding 1
1163 sysctl_set net.ipv6.conf.all.forwarding 1
1166 forwarding_restore()
1168 sysctl_restore net.ipv6.conf.all.forwarding
1169 sysctl_restore net.ipv4.conf.all.forwarding
1178 MTU_ORIG["$dev"]=$(ip -j link show dev $dev | jq -e '.[].mtu')
1179 ip link set dev $dev mtu $mtu
1186 ip link set dev $dev mtu ${MTU_ORIG["$dev"]}
1191 local num_netifs=${1:-$NUM_NETIFS}
1193 for ((i = 1; i <= num_netifs; ++i)); do
1194 ethtool -k ${NETIFS[p$i]} \
1195 | grep "hw-tc-offload: on" &> /dev/null
1196 if [[ $? -ne 0 ]]; then
1207 local direction=$1; shift
1209 # Some devices may not support or need in-hardware trapping of traffic
1210 # (e.g. the veth pairs that this library creates for non-existent
1211 # loopbacks). Use continue instead, so that there is a filter in there
1212 # (some tests check counters), and so that other filters are still
1214 tc filter add dev $dev $direction pref 1 \
1215 flower skip_sw action trap 2>/dev/null \
1216 || tc filter add dev $dev $direction pref 1 \
1217 flower action continue
1223 local direction=$1; shift
1225 tc filter del dev $dev $direction pref 1 flower
1228 __icmp_capture_add_del()
1230 local add_del=$1; shift
1231 local pref=$1; shift
1232 local vsuf=$1; shift
1233 local tundev=$1; shift
1234 local filter=$1; shift
1236 tc filter $add_del dev "$tundev" ingress \
1237 proto ip$vsuf pref $pref \
1238 flower ip_proto icmp$vsuf $filter \
1242 icmp_capture_install()
1244 local tundev=$1; shift
1245 local filter=$1; shift
1247 __icmp_capture_add_del add 100 "" "$tundev" "$filter"
1250 icmp_capture_uninstall()
1252 local tundev=$1; shift
1253 local filter=$1; shift
1255 __icmp_capture_add_del del 100 "" "$tundev" "$filter"
1258 icmp6_capture_install()
1260 local tundev=$1; shift
1261 local filter=$1; shift
1263 __icmp_capture_add_del add 100 v6 "$tundev" "$filter"
1266 icmp6_capture_uninstall()
1268 local tundev=$1; shift
1269 local filter=$1; shift
1271 __icmp_capture_add_del del 100 v6 "$tundev" "$filter"
1274 __vlan_capture_add_del()
1276 local add_del=$1; shift
1277 local pref=$1; shift
1279 local filter=$1; shift
1281 tc filter $add_del dev "$dev" ingress \
1282 proto 802.1q pref $pref \
1287 vlan_capture_install()
1290 local filter=$1; shift
1292 __vlan_capture_add_del add 100 "$dev" "$filter"
1295 vlan_capture_uninstall()
1298 local filter=$1; shift
1300 __vlan_capture_add_del del 100 "$dev" "$filter"
1303 __dscp_capture_add_del()
1305 local add_del=$1; shift
1307 local base=$1; shift
1310 for prio in {0..7}; do
1311 dscp=$((base + prio))
1312 __icmp_capture_add_del $add_del $((dscp + 100)) "" $dev \
1313 "skip_hw ip_tos $((dscp << 2))"
1317 dscp_capture_install()
1320 local base=$1; shift
1322 __dscp_capture_add_del add $dev $base
1325 dscp_capture_uninstall()
1328 local base=$1; shift
1330 __dscp_capture_add_del del $dev $base
1336 local base=$1; shift
1338 for prio in {0..7}; do
1339 local dscp=$((base + prio))
1340 local t=$(tc_rule_stats_get $dev $((dscp + 100)))
1345 matchall_sink_create()
1349 tc qdisc add dev $dev clsact
1350 tc filter add dev $dev ingress \
1360 for current_test in ${TESTS:-$ALL_TESTS}; do
1368 local weight_rp12=$2
1369 local weight_rp13=$3
1370 local packets_rp12=$4
1371 local packets_rp13=$5
1372 local weights_ratio packets_ratio diff
1376 if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
1377 weights_ratio=$(echo "scale=2; $weight_rp12 / $weight_rp13" \
1380 weights_ratio=$(echo "scale=2; $weight_rp13 / $weight_rp12" \
1384 if [[ "$packets_rp12" -eq "0" || "$packets_rp13" -eq "0" ]]; then
1385 check_err 1 "Packet difference is 0"
1386 log_test "Multipath"
1387 log_info "Expected ratio $weights_ratio"
1391 if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
1392 packets_ratio=$(echo "scale=2; $packets_rp12 / $packets_rp13" \
1395 packets_ratio=$(echo "scale=2; $packets_rp13 / $packets_rp12" \
1399 diff=$(echo $weights_ratio - $packets_ratio | bc -l)
1402 test "$(echo "$diff / $weights_ratio > 0.15" | bc -l)" -eq 0
1403 check_err $? "Too large discrepancy between expected and measured ratios"
1405 log_info "Expected ratio $weights_ratio Measured ratio $packets_ratio"
1410 local name=$1; shift
1412 ip netns exec $name bash <<-EOF
1415 $(for a in "$@"; do printf "%q${IFS:0:1}" "$a"; done)
1419 ##############################################################################
1429 vrf_name=$(master_name_get $if_name)
1430 ip vrf exec $vrf_name \
1431 $PING $args $dip -c $PING_COUNT -i 0.1 \
1432 -w $PING_TIMEOUT &> /dev/null
1450 log_test "ping fails$3"
1460 vrf_name=$(master_name_get $if_name)
1461 ip vrf exec $vrf_name \
1462 $PING6 $args $dip -c $PING_COUNT -i 0.1 \
1463 -w $PING_TIMEOUT &> /dev/null
1481 log_test "ping6 fails$3"
1487 local br_port1=$2 # Connected to `host1_if`.
1490 local mac=de:ad:be:ef:13:37
1495 bridge -j fdb show br $bridge brport $br_port1 \
1496 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1497 check_fail $? "Found FDB record when should not"
1499 # Disable unknown unicast flooding on `br_port1` to make sure
1500 # packets are only forwarded through the port after a matching
1501 # FDB entry was installed.
1502 bridge link set dev $br_port1 flood off
1504 ip link set $host1_if promisc on
1505 tc qdisc add dev $host1_if ingress
1506 tc filter add dev $host1_if ingress protocol ip pref 1 handle 101 \
1507 flower dst_mac $mac action drop
1509 $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q
1512 tc -j -s filter show dev $host1_if ingress \
1513 | jq -e ".[] | select(.options.handle == 101) \
1514 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1515 check_fail $? "Packet reached first host when should not"
1517 $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
1520 bridge -j fdb show br $bridge brport $br_port1 \
1521 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1522 check_err $? "Did not find FDB record when should"
1524 $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q
1527 tc -j -s filter show dev $host1_if ingress \
1528 | jq -e ".[] | select(.options.handle == 101) \
1529 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1530 check_err $? "Packet did not reach second host when should"
1532 # Wait for 10 seconds after the ageing time to make sure FDB
1533 # record was aged-out.
1534 ageing_time=$(bridge_ageing_time_get $bridge)
1535 sleep $((ageing_time + 10))
1537 bridge -j fdb show br $bridge brport $br_port1 \
1538 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1539 check_fail $? "Found FDB record when should not"
1541 bridge link set dev $br_port1 learning off
1543 $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
1546 bridge -j fdb show br $bridge brport $br_port1 \
1547 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1548 check_fail $? "Found FDB record when should not"
1550 bridge link set dev $br_port1 learning on
1552 tc filter del dev $host1_if ingress protocol ip pref 1 handle 101 flower
1553 tc qdisc del dev $host1_if ingress
1554 ip link set $host1_if promisc off
1556 bridge link set dev $br_port1 flood on
1558 log_test "FDB learning"
1563 local should_flood=$1
1570 # Add an ACL on `host2_if` which will tell us whether the packet
1571 # was flooded to it or not.
1572 ip link set $host2_if promisc on
1573 tc qdisc add dev $host2_if ingress
1574 tc filter add dev $host2_if ingress protocol ip pref 1 handle 101 \
1575 flower dst_mac $mac action drop
1577 $MZ $host1_if -c 1 -p 64 -b $mac -B $ip -t ip -q
1580 tc -j -s filter show dev $host2_if ingress \
1581 | jq -e ".[] | select(.options.handle == 101) \
1582 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1583 if [[ $? -ne 0 && $should_flood == "true" || \
1584 $? -eq 0 && $should_flood == "false" ]]; then
1588 tc filter del dev $host2_if ingress protocol ip pref 1 handle 101 flower
1589 tc qdisc del dev $host2_if ingress
1590 ip link set $host2_if promisc off
1595 flood_unicast_test()
1600 local mac=de:ad:be:ef:13:37
1601 local ip=192.0.2.100
1605 bridge link set dev $br_port flood off
1607 flood_test_do false $mac $ip $host1_if $host2_if
1608 check_err $? "Packet flooded when should not"
1610 bridge link set dev $br_port flood on
1612 flood_test_do true $mac $ip $host1_if $host2_if
1613 check_err $? "Packet was not flooded when should"
1615 log_test "Unknown unicast flood"
1618 flood_multicast_test()
1623 local mac=01:00:5e:00:00:01
1628 bridge link set dev $br_port mcast_flood off
1630 flood_test_do false $mac $ip $host1_if $host2_if
1631 check_err $? "Packet flooded when should not"
1633 bridge link set dev $br_port mcast_flood on
1635 flood_test_do true $mac $ip $host1_if $host2_if
1636 check_err $? "Packet was not flooded when should"
1638 log_test "Unregistered multicast flood"
1643 # `br_port` is connected to `host2_if`
1648 flood_unicast_test $br_port $host1_if $host2_if
1649 flood_multicast_test $br_port $host1_if $host2_if
1654 local pktsize=$1; shift
1655 local proto=$1; shift
1656 local h_in=$1; shift # Where the traffic egresses the host
1659 local dmac=$1; shift
1660 local -a mz_args=("$@")
1662 $MZ $h_in -p $pktsize -A $sip -B $dip -c 0 \
1663 -a own -b $dmac -t "$proto" -q "${mz_args[@]}" &
1667 start_traffic_pktsize()
1669 local pktsize=$1; shift
1670 local h_in=$1; shift
1673 local dmac=$1; shift
1674 local -a mz_args=("$@")
1676 __start_traffic $pktsize udp "$h_in" "$sip" "$dip" "$dmac" \
1680 start_tcp_traffic_pktsize()
1682 local pktsize=$1; shift
1683 local h_in=$1; shift
1686 local dmac=$1; shift
1687 local -a mz_args=("$@")
1689 __start_traffic $pktsize tcp "$h_in" "$sip" "$dip" "$dmac" \
1695 local h_in=$1; shift
1698 local dmac=$1; shift
1699 local -a mz_args=("$@")
1701 start_traffic_pktsize 8000 "$h_in" "$sip" "$dip" "$dmac" \
1707 local h_in=$1; shift
1710 local dmac=$1; shift
1711 local -a mz_args=("$@")
1713 start_tcp_traffic_pktsize 8000 "$h_in" "$sip" "$dip" "$dmac" \
1719 # Suppress noise from killing mausezahn.
1720 { kill %% && wait %%; } 2>/dev/null
1729 local if_name=$1; shift
1732 capfile[$if_name]=$(mktemp)
1733 capout[$if_name]=$(mktemp)
1738 ns_cmd="ip netns exec ${ns}"
1741 if [ -z $SUDO_USER ] ; then
1744 capuser="-Z $SUDO_USER"
1747 $ns_cmd tcpdump $TCPDUMP_EXTRA_FLAGS -e -n -Q in -i $if_name \
1748 -s 65535 -B 32768 $capuser -w ${capfile[$if_name]} \
1749 > "${capout[$if_name]}" 2>&1 &
1758 local pid=${cappid[$if_name]}
1760 $ns_cmd kill "$pid" && wait "$pid"
1768 rm ${capfile[$if_name]} ${capout[$if_name]}
1775 tcpdump -e -n -r ${capfile[$if_name]} 2>&1
1778 # return 0 if the packet wasn't seen on host2_if or 1 if it was
1790 # basic check to see if we were passed an IPv4 address, if not assume IPv6
1791 if [[ ! $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
1796 # Add an ACL on `host2_if` which will tell us whether the packet
1797 # was received by it or not.
1798 tc qdisc add dev $host2_if ingress
1799 tc filter add dev $host2_if ingress protocol $tc_proto pref 1 handle 101 \
1800 flower ip_proto udp dst_mac $mac action drop
1802 $MZ $host1_if $mz_v6arg -c 1 -p 64 -b $mac -A $src_ip -B $ip -t udp "dp=4096,sp=2048" -q
1805 tc -j -s filter show dev $host2_if ingress \
1806 | jq -e ".[] | select(.options.handle == 101) \
1807 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1808 if [[ $? -eq 0 ]]; then
1812 tc filter del dev $host2_if ingress protocol $tc_proto pref 1 handle 101 flower
1813 tc qdisc del dev $host2_if ingress
1818 brmcast_check_sg_entries()
1820 local report=$1; shift
1824 for src in "${slist[@]}"; do
1825 sarg="${sarg} and .source_list[].address == \"$src\""
1827 bridge -j -d -s mdb show dev br0 \
1828 | jq -e ".[].mdb[] | \
1829 select(.grp == \"$TEST_GROUP\" and .source_list != null $sarg)" &>/dev/null
1830 check_err $? "Wrong *,G entry source list after $report report"
1832 for sgent in "${slist[@]}"; do
1833 bridge -j -d -s mdb show dev br0 \
1834 | jq -e ".[].mdb[] | \
1835 select(.grp == \"$TEST_GROUP\" and .src == \"$sgent\")" &>/dev/null
1836 check_err $? "Missing S,G entry ($sgent, $TEST_GROUP)"
1840 brmcast_check_sg_fwding()
1842 local should_fwd=$1; shift
1843 local sources=("$@")
1845 for src in "${sources[@]}"; do
1848 mcast_packet_test $TEST_GROUP_MAC $src $TEST_GROUP $h2 $h1
1850 if [ $should_fwd -eq 1 ]; then
1851 check_fail $retval "Didn't forward traffic from S,G ($src, $TEST_GROUP)"
1853 check_err $retval "Forwarded traffic for blocked S,G ($src, $TEST_GROUP)"
1858 brmcast_check_sg_state()
1860 local is_blocked=$1; shift
1861 local sources=("$@")
1864 if [ $is_blocked -eq 1 ]; then
1868 for src in "${sources[@]}"; do
1869 bridge -j -d -s mdb show dev br0 \
1870 | jq -e ".[].mdb[] | \
1871 select(.grp == \"$TEST_GROUP\" and .source_list != null) |
1873 select(.address == \"$src\") |
1874 select(.timer == \"0.00\")" &>/dev/null
1875 check_err_fail $should_fail $? "Entry $src has zero timer"
1877 bridge -j -d -s mdb show dev br0 \
1878 | jq -e ".[].mdb[] | \
1879 select(.grp == \"$TEST_GROUP\" and .src == \"$src\" and \
1880 .flags[] == \"blocked\")" &>/dev/null
1881 check_err_fail $should_fail $? "Entry $src has blocked flag"
1889 local vrf_name=$(master_name_get $if_name)
1891 # We don't care about actual reception, just about joining the
1892 # IP multicast group and adding the L2 address to the device's
1893 # MAC filtering table
1894 ip vrf exec $vrf_name \
1895 mreceive -g $group -I $if_name > /dev/null 2>&1 &
1903 kill "$mreceive_pid" && wait "$mreceive_pid"
1910 local vrf_name=$(master_name_get $if_name)
1912 ip vrf exec $vrf_name \
1913 msend -g $groups -I $if_name -c 1 > /dev/null 2>&1
1918 local mtype=$1; shift
1919 local ip=${1-ip}; shift
1921 # start the monitor in the background
1922 tmpfile=`mktemp /var/run/nexthoptestXXX`
1923 mpid=`($ip monitor $mtype > $tmpfile & echo $!) 2>/dev/null`
1925 echo "$mpid $tmpfile"
1930 local mpid=$1; shift
1931 local tmpfile=$1; shift
1933 local what=$1; shift
1937 local lines=`grep '^\w' $tmpfile | wc -l`
1939 check_err $? "$what: $lines lines of events, expected $el"
1943 hw_stats_monitor_test()
1946 local type=$1; shift
1947 local make_suitable=$1; shift
1948 local make_unsuitable=$1; shift
1949 local ip=${1-ip}; shift
1953 # Expect a notification about enablement.
1954 local ipmout=$(start_ip_monitor stats "$ip")
1955 $ip stats set dev $dev ${type}_stats on
1956 stop_ip_monitor $ipmout 1 "${type}_stats enablement"
1958 # Expect a notification about offload.
1959 local ipmout=$(start_ip_monitor stats "$ip")
1961 stop_ip_monitor $ipmout 1 "${type}_stats installation"
1963 # Expect a notification about loss of offload.
1964 local ipmout=$(start_ip_monitor stats "$ip")
1966 stop_ip_monitor $ipmout 1 "${type}_stats deinstallation"
1968 # Expect a notification about disablement
1969 local ipmout=$(start_ip_monitor stats "$ip")
1970 $ip stats set dev $dev ${type}_stats off
1971 stop_ip_monitor $ipmout 1 "${type}_stats disablement"
1973 log_test "${type}_stats notifications"
1980 printf '%02x:' ${IP//./ } |
1984 # Convert a given IPv6 address, `IP' such that the :: token, if present, is
1985 # expanded, and each 16-bit group is padded with zeroes to be 4 hexadecimal
1986 # digits. An optional `BYTESEP' parameter can be given to further separate
1987 # individual bytes of each 16-bit group.
1991 local bytesep=$1; shift
1993 local cvt_ip=${IP/::/_}
1994 local colons=${cvt_ip//[^:]/}
1995 local allcol=:::::::
1996 # IP where :: -> the appropriate number of colons:
1997 local allcol_ip=${cvt_ip/_/${allcol:${#colons}}}
1999 echo $allcol_ip | tr : '\n' |
2001 sed 's/.*\(..\)\(..\)/\1'"$bytesep"'\2/' |
2017 printf "%04x" $u16 | sed 's/^/000/;s/^.*\(..\)\(..\)$/\1:\2/'
2020 # Given a mausezahn-formatted payload (colon-separated bytes given as %02x),
2021 # possibly with a keyword CHECKSUM stashed where a 16-bit checksum should be,
2022 # calculate checksum as per RFC 1071, assuming the CHECKSUM field (if any)
2024 payload_template_calc_checksum()
2026 local payload=$1; shift
2031 # Push zero for the initial checksum.
2034 # Pad the payload with a terminating 00: in case we get an odd
2036 echo "${payload%:}:00:" |
2037 sed 's/CHECKSUM/00:00/g' |
2038 tr '[:lower:]' '[:upper:]' |
2039 # Add the word to the checksum.
2040 sed 's/\(..\):\(..\):/\1\2+\n/g' |
2041 # Strip the extra odd byte we pushed if left unconverted.
2044 echo "10000 ~ +" # Calculate and add carry.
2045 echo "FFFF r - p" # Bit-flip and print.
2048 tr '[:upper:]' '[:lower:]'
2051 payload_template_expand_checksum()
2053 local payload=$1; shift
2054 local checksum=$1; shift
2056 local ckbytes=$(u16_to_bytes $checksum)
2058 echo "$payload" | sed "s/CHECKSUM/$ckbytes/g"
2061 payload_template_nbytes()
2063 local payload=$1; shift
2065 payload_template_expand_checksum "${payload%:}" 0 |
2066 sed 's/:/\n/g' | wc -l
2072 local sources=("$@")
2075 local nsources=$(u16_to_bytes ${#sources[@]})
2077 # IS_IN ( $sources )
2079 )"22:"$( : Type - Membership Report
2081 )"CHECKSUM:"$( : Checksum
2082 )"00:00:"$( : Reserved
2083 )"00:01:"$( : Number of Group Records
2084 )"01:"$( : Record Type - IS_IN
2085 )"00:"$( : Aux Data Len
2086 )"${nsources}:"$( : Number of Sources
2087 )"$(ipv4_to_bytes $GRP):"$( : Multicast Address
2088 )"$(for src in "${sources[@]}"; do
2091 done)"$( : Source Addresses
2093 local checksum=$(payload_template_calc_checksum "$igmpv3")
2095 payload_template_expand_checksum "$igmpv3" $checksum
2103 )"17:"$( : Type - Leave Group
2104 )"00:"$( : Max Resp Time - not meaningful
2105 )"CHECKSUM:"$( : Checksum
2106 )"$(ipv4_to_bytes $GRP)"$( : Group Address
2108 local checksum=$(payload_template_calc_checksum "$payload")
2110 payload_template_expand_checksum "$payload" $checksum
2117 local sources=("$@")
2121 local nsources=$(u16_to_bytes ${#sources[@]})
2124 )"3a:"$( : Next Header - ICMPv6
2125 )"00:"$( : Hdr Ext Len
2126 )"00:00:00:00:00:00:"$( : Options and Padding
2130 )"8f:"$( : Type - MLDv2 Report
2132 )"CHECKSUM:"$( : Checksum
2133 )"00:00:"$( : Reserved
2134 )"00:01:"$( : Number of Group Records
2135 )"01:"$( : Record Type - IS_IN
2136 )"00:"$( : Aux Data Len
2137 )"${nsources}:"$( : Number of Sources
2138 )"$(ipv6_to_bytes $GRP):"$( : Multicast address
2139 )"$(for src in "${sources[@]}"; do
2142 done)"$( : Source Addresses
2145 local len=$(u16_to_bytes $(payload_template_nbytes $icmpv6))
2147 )"$(ipv6_to_bytes $SIP):"$( : SIP
2148 )"$(ipv6_to_bytes $GRP):"$( : DIP is multicast address
2149 )"${len}:"$( : Upper-layer length
2150 )"00:3a:"$( : Zero and next-header
2152 local checksum=$(payload_template_calc_checksum ${sudohdr}${icmpv6})
2154 payload_template_expand_checksum "$hbh$icmpv6" $checksum
2166 )"3a:"$( : Next Header - ICMPv6
2167 )"00:"$( : Hdr Ext Len
2168 )"00:00:00:00:00:00:"$( : Options and Padding
2172 )"84:"$( : Type - MLDv1 Done
2174 )"CHECKSUM:"$( : Checksum
2175 )"00:00:"$( : Max Resp Delay - not meaningful
2176 )"00:00:"$( : Reserved
2177 )"$(ipv6_to_bytes $GRP):"$( : Multicast address
2180 local len=$(u16_to_bytes $(payload_template_nbytes $icmpv6))
2182 )"$(ipv6_to_bytes $SIP):"$( : SIP
2183 )"$(ipv6_to_bytes $GRP):"$( : DIP is multicast address
2184 )"${len}:"$( : Upper-layer length
2185 )"00:3a:"$( : Zero and next-header
2187 local checksum=$(payload_template_calc_checksum ${sudohdr}${icmpv6})
2189 payload_template_expand_checksum "$hbh$icmpv6" $checksum
2194 local reason1="$1"; shift
2195 local reason2="$1"; shift
2196 local caller=${FUNCNAME[1]}
2197 local src=${BASH_SOURCE[1]}
2199 if systemctl is-active --quiet lldpad; then
2201 cat >/dev/stderr <<-EOF
2202 WARNING: lldpad is running
2204 lldpad will likely $reason1, and this test will
2205 $reason2. Both are not supported at the same time,
2206 one of them is arbitrarily going to overwrite the
2207 other. That will cause spurious failures (or, unlikely,
2208 passes) of this test.
2211 if [[ -z $ALLOW_LLDPAD ]]; then
2212 cat >/dev/stderr <<-EOF
2214 If you want to run the test anyway, please set
2215 an environment variable ALLOW_LLDPAD to a
2218 log_test_skip $src:$caller
2230 echo $((v > 0 ? v : -v))