2 # SPDX-License-Identifier: GPL-2.0
4 ##############################################################################
7 # Can be overridden by the configuration file.
11 ARPING
=${ARPING:=arping}
13 WAIT_TIME
=${WAIT_TIME:=5}
14 PAUSE_ON_FAIL
=${PAUSE_ON_FAIL:=no}
15 PAUSE_ON_CLEANUP
=${PAUSE_ON_CLEANUP:=no}
16 NETIF_TYPE
=${NETIF_TYPE:=veth}
17 NETIF_CREATE
=${NETIF_CREATE:=yes}
19 relative_path
="${BASH_SOURCE%/*}"
20 if [[ "$relative_path" == "${BASH_SOURCE}" ]]; then
24 if [[ -f $relative_path/forwarding.config
]]; then
25 source "$relative_path/forwarding.config"
28 ##############################################################################
34 if [[ $?
-ne 0 ]]; then
35 echo "SKIP: iproute2 too old; tc is missing JSON support"
40 check_tc_shblock_support
()
42 tc filter
help 2>&1 |
grep block
&> /dev
/null
43 if [[ $?
-ne 0 ]]; then
44 echo "SKIP: iproute2 too old; tc is missing shared block support"
49 check_tc_chain_support
()
51 tc
help 2>&1|
grep chain
&> /dev
/null
52 if [[ $?
-ne 0 ]]; then
53 echo "SKIP: iproute2 too old; tc is missing chain support"
58 if [[ "$(id -u)" -ne 0 ]]; then
59 echo "SKIP: need root privileges"
63 if [[ "$CHECK_TC" = "yes" ]]; then
71 if [[ ! -x "$(command -v "$cmd")" ]]; then
72 echo "SKIP: $cmd not installed"
80 if [[ ! -v NUM_NETIFS
]]; then
81 echo "SKIP: importer does not define \"NUM_NETIFS\""
85 ##############################################################################
86 # Command line options handling
90 while [[ $# -gt 0 ]]; do
91 if [[ "$count" -eq "0" ]]; then
100 ##############################################################################
101 # Network interfaces configuration
107 for i
in $
(eval echo {1..
$NUM_NETIFS}); do
110 ip link show dev
${NETIFS[p$i]} &> /dev
/null
111 if [[ $?
-ne 0 ]]; then
112 ip link add
${NETIFS[p$i]} type veth \
113 peer name
${NETIFS[p$j]}
114 if [[ $?
-ne 0 ]]; then
115 echo "Failed to create netif"
125 case "$NETIF_TYPE" in
126 veth
) create_netif_veth
128 *) echo "Can not create interfaces of type \'$NETIF_TYPE\'"
134 if [[ "$NETIF_CREATE" = "yes" ]]; then
138 for i
in $
(eval echo {1..
$NUM_NETIFS}); do
139 ip link show dev
${NETIFS[p$i]} &> /dev
/null
140 if [[ $?
-ne 0 ]]; then
141 echo "SKIP: could not find all required interfaces"
146 ##############################################################################
149 # Exit status to return at the end. Set in case one of the tests fails.
151 # Per-test return value. Clear at the beginning of each test.
159 if [[ $RET -eq 0 && $err -ne 0 ]]; then
170 if [[ $RET -eq 0 && $err -eq 0 ]]; then
178 local should_fail
=$1; shift
182 if ((should_fail
)); then
183 check_fail
$err "$what succeeded, but should have failed"
185 check_err
$err "$what failed"
194 if [[ $# -eq 2 ]]; then
198 if [[ $RET -ne 0 ]]; then
200 printf "TEST: %-60s [FAIL]\n" "$test_name $opt_str"
201 if [[ ! -z "$retmsg" ]]; then
202 printf "\t%s\n" "$retmsg"
204 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
205 echo "Hit enter to continue, 'q' to quit"
207 [ "$a" = "q" ] && exit 1
212 printf "TEST: %-60s [PASS]\n" "$test_name $opt_str"
228 ip link show dev
$dev up \
229 |
grep 'state UP' &> /dev
/null
230 if [[ $?
-ne 0 ]]; then
240 local num_netifs
=${1:-$NUM_NETIFS}
242 for ((i
= 1; i
<= num_netifs
; ++i
)); do
243 setup_wait_dev
${NETIFS[p$i]}
246 # Make sure links are ready.
250 lldpad_app_wait_set
()
254 while lldptool
-t -i $dev -V APP
-c app |
grep -Eq "pending|unknown"; do
255 echo "$dev: waiting for lldpad to push pending APP updates"
260 lldpad_app_wait_del
()
262 # Give lldpad a chance to push down the changes. If the device is downed
263 # too soon, the updates will be left pending. However, they will have
264 # been struck off the lldpad's DB already, so we won't be able to tell
265 # they are pending. Then on next test iteration this would cause
266 # weirdness as newly-added APP rules conflict with the old ones,
267 # sometimes getting stuck in an "unknown" state.
273 if [ "${PAUSE_ON_CLEANUP}" = "yes" ]; then
274 echo "Pausing before cleanup, hit any key to continue"
281 ip
-4 rule add pref
32765 table
local
282 ip
-4 rule del pref
0
283 ip
-6 rule add pref
32765 table
local
284 ip
-6 rule del pref
0
289 ip
-6 rule add pref
0 table
local
290 ip
-6 rule del pref
32765
291 ip
-4 rule add pref
0 table
local
292 ip
-4 rule del pref
32765
302 __last_tb_id
=$
((__last_tb_id
+ 1))
303 __TB_IDS
[$vrf_name]=$__last_tb_id
311 return ${__TB_IDS[$vrf_name]}
319 __vrf_td_id_assign
$vrf_name
322 ip link add dev
$vrf_name type vrf table
$tb_id
323 ip
-4 route add table
$tb_id unreachable default metric
4278198272
324 ip
-6 route add table
$tb_id unreachable default metric
4278198272
332 __vrf_td_id_lookup
$vrf_name
335 ip
-6 route del table
$tb_id unreachable default metric
4278198272
336 ip
-4 route del table
$tb_id unreachable default metric
4278198272
337 ip link del dev
$vrf_name
350 for addrstr
in "${array[@]}"; do
351 ip address
$add_del $addrstr dev
$if_name
357 local if_name
=$1; shift
358 local vrf_name
=$1; shift
361 ip link
set dev
$if_name master
$vrf_name
362 ip link
set dev
$if_name up
364 __addr_add_del
$if_name add
"${addrs[@]}"
369 local if_name
=$1; shift
372 __addr_add_del
$if_name del
"${addrs[@]}"
374 ip link
set dev
$if_name down
375 ip link
set dev
$if_name nomaster
389 ip link
set dev
$vrf_name up
390 __simple_if_init
$if_name $vrf_name "${array[@]}"
403 __simple_if_fini
$if_name "${array[@]}"
404 vrf_destroy
$vrf_name
411 local local=$1; shift
412 local remote
=$1; shift
414 ip link add name
$name type $type \
415 local $local remote
$remote "$@"
416 ip link
set dev
$name up
423 ip link del dev
$name
428 local if_name
=$1; shift
432 local name
=$if_name.
$vid
434 ip link add name
$name link
$if_name type vlan id
$vid
435 if [ "$vrf" != "" ]; then
436 ip link
set dev
$name master
$vrf
438 ip link
set dev
$name up
439 __addr_add_del
$name add
"${ips[@]}"
444 local if_name
=$1; shift
446 local name
=$if_name.
$vid
448 ip link del dev
$name
453 local if_name
=$1; shift
456 require_command
$TEAMD
457 $TEAMD -t $if_name -d -c '{"runner": {"name": "'$mode'"}}'
458 for slave
in "$@"; do
459 ip link
set dev
$slave down
460 ip link
set dev
$slave master
$if_name
461 ip link
set dev
$slave up
463 ip link
set dev
$if_name up
468 local if_name
=$1; shift
470 $TEAMD -t $if_name -k
477 ip
-j link show dev
$if_name | jq
-r '.[]["master"]'
480 link_stats_tx_packets_get
()
484 ip
-j -s link show dev
$if_name | jq
'.[]["stats64"]["tx"]["packets"]'
493 tc
-j -s filter show dev
$dev ${dir:-ingress} pref
$pref \
494 | jq
'.[1].options.actions[].stats.packets'
501 ip
-j link show dev
$if_name | jq
-r '.[]["address"]'
504 bridge_ageing_time_get
()
509 # Need to divide by 100 to convert to seconds.
510 ageing_time
=$
(ip
-j -d link show dev
$bridge \
511 | jq
'.[]["linkinfo"]["info_data"]["ageing_time"]')
512 echo $
((ageing_time
/ 100))
515 declare -A SYSCTL_ORIG
519 local value
=$1; shift
521 SYSCTL_ORIG
[$key]=$
(sysctl
-n $key)
522 sysctl
-qw $key=$value
529 sysctl
-qw $key=${SYSCTL_ORIG["$key"]}
534 sysctl_set net.ipv4.conf.all.forwarding
1
535 sysctl_set net.ipv6.conf.all.forwarding
1
540 sysctl_restore net.ipv6.conf.all.forwarding
541 sysctl_restore net.ipv4.conf.all.forwarding
546 local num_netifs
=${1:-$NUM_NETIFS}
548 for ((i
= 1; i
<= num_netifs
; ++i
)); do
549 ethtool
-k ${NETIFS[p$i]} \
550 |
grep "hw-tc-offload: on" &> /dev
/null
551 if [[ $?
-ne 0 ]]; then
562 local direction
=$1; shift
564 # Some devices may not support or need in-hardware trapping of traffic
565 # (e.g. the veth pairs that this library creates for non-existent
566 # loopbacks). Use continue instead, so that there is a filter in there
567 # (some tests check counters), and so that other filters are still
569 tc filter add dev
$dev $direction pref
1 \
570 flower skip_sw action
trap 2>/dev
/null \
571 || tc filter add dev
$dev $direction pref
1 \
572 flower action
continue
578 local direction
=$1; shift
580 tc filter del dev
$dev $direction pref
1 flower
583 slow_path_trap_install
()
585 # For slow-path testing, we need to install a trap to get to
586 # slow path the packets that would otherwise be switched in HW.
587 if [ "${tcflags/skip_hw}" != "$tcflags" ]; then
592 slow_path_trap_uninstall
()
594 if [ "${tcflags/skip_hw}" != "$tcflags" ]; then
599 __icmp_capture_add_del
()
601 local add_del
=$1; shift
604 local tundev
=$1; shift
605 local filter
=$1; shift
607 tc filter
$add_del dev
"$tundev" ingress \
608 proto ip
$vsuf pref
$pref \
609 flower ip_proto icmp
$vsuf $filter \
613 icmp_capture_install
()
615 __icmp_capture_add_del add
100 "" "$@"
618 icmp_capture_uninstall
()
620 __icmp_capture_add_del del
100 "" "$@"
623 icmp6_capture_install
()
625 __icmp_capture_add_del add
100 v6
"$@"
628 icmp6_capture_uninstall
()
630 __icmp_capture_add_del del
100 v6
"$@"
633 __vlan_capture_add_del
()
635 local add_del
=$1; shift
638 local filter
=$1; shift
640 tc filter
$add_del dev
"$dev" ingress \
641 proto
802.1q pref
$pref \
646 vlan_capture_install
()
648 __vlan_capture_add_del add
100 "$@"
651 vlan_capture_uninstall
()
653 __vlan_capture_add_del del
100 "$@"
656 __dscp_capture_add_del
()
658 local add_del
=$1; shift
663 for prio
in {0.
.7}; do
664 dscp
=$
((base
+ prio
))
665 __icmp_capture_add_del
$add_del $
((dscp
+ 100)) "" $dev \
666 "skip_hw ip_tos $((dscp << 2))"
670 dscp_capture_install
()
675 __dscp_capture_add_del add
$dev $base
678 dscp_capture_uninstall
()
683 __dscp_capture_add_del del
$dev $base
691 for prio
in {0.
.7}; do
692 local dscp
=$
((base
+ prio
))
693 local t
=$
(tc_rule_stats_get
$dev $
((dscp
+ 100)))
698 matchall_sink_create
()
702 tc qdisc add dev
$dev clsact
703 tc filter add dev
$dev ingress \
713 for current_test
in ${TESTS:-$ALL_TESTS}; do
723 local packets_rp12
=$4
724 local packets_rp13
=$5
725 local weights_ratio packets_ratio
diff
729 if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
730 weights_ratio
=$
(echo "scale=2; $weight_rp12 / $weight_rp13" \
733 weights_ratio
=$
(echo "scale=2; $weight_rp13 / $weight_rp12" \
737 if [[ "$packets_rp12" -eq "0" ||
"$packets_rp13" -eq "0" ]]; then
738 check_err
1 "Packet difference is 0"
740 log_info
"Expected ratio $weights_ratio"
744 if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
745 packets_ratio
=$
(echo "scale=2; $packets_rp12 / $packets_rp13" \
748 packets_ratio
=$
(echo "scale=2; $packets_rp13 / $packets_rp12" \
752 diff=$
(echo $weights_ratio - $packets_ratio |
bc -l)
755 test "$(echo "$diff / $weights_ratio > 0.15" | bc -l)" -eq 0
756 check_err $?
"Too large discrepancy between expected and measured ratios"
758 log_info
"Expected ratio $weights_ratio Measured ratio $packets_ratio"
761 ##############################################################################
770 vrf_name
=$
(master_name_get
$if_name)
771 ip vrf
exec $vrf_name $PING $dip -c 10 -i 0.1 -w 2 &> /dev
/null
789 vrf_name
=$
(master_name_get
$if_name)
790 ip vrf
exec $vrf_name $PING6 $dip -c 10 -i 0.1 -w 2 &> /dev
/null
805 local br_port1
=$2 # Connected to `host1_if`.
808 local mac
=de
:ad
:be
:ef
:13:37
813 bridge
-j fdb show br
$bridge brport
$br_port1 \
814 | jq
-e ".[] | select(.mac == \"$mac\")" &> /dev
/null
815 check_fail $?
"Found FDB record when should not"
817 # Disable unknown unicast flooding on `br_port1` to make sure
818 # packets are only forwarded through the port after a matching
819 # FDB entry was installed.
820 bridge link
set dev
$br_port1 flood off
822 tc qdisc add dev
$host1_if ingress
823 tc filter add dev
$host1_if ingress protocol ip pref
1 handle
101 \
824 flower dst_mac
$mac action drop
826 $MZ $host2_if -c 1 -p 64 -b $mac -t ip
-q
829 tc
-j -s filter show dev
$host1_if ingress \
830 | jq
-e ".[] | select(.options.handle == 101) \
831 | select(.options.actions[0].stats.packets == 1)" &> /dev
/null
832 check_fail $?
"Packet reached second host when should not"
834 $MZ $host1_if -c 1 -p 64 -a $mac -t ip
-q
837 bridge
-j fdb show br
$bridge brport
$br_port1 \
838 | jq
-e ".[] | select(.mac == \"$mac\")" &> /dev
/null
839 check_err $?
"Did not find FDB record when should"
841 $MZ $host2_if -c 1 -p 64 -b $mac -t ip
-q
844 tc
-j -s filter show dev
$host1_if ingress \
845 | jq
-e ".[] | select(.options.handle == 101) \
846 | select(.options.actions[0].stats.packets == 1)" &> /dev
/null
847 check_err $?
"Packet did not reach second host when should"
849 # Wait for 10 seconds after the ageing time to make sure FDB
850 # record was aged-out.
851 ageing_time
=$
(bridge_ageing_time_get
$bridge)
852 sleep $
((ageing_time
+ 10))
854 bridge
-j fdb show br
$bridge brport
$br_port1 \
855 | jq
-e ".[] | select(.mac == \"$mac\")" &> /dev
/null
856 check_fail $?
"Found FDB record when should not"
858 bridge link
set dev
$br_port1 learning off
860 $MZ $host1_if -c 1 -p 64 -a $mac -t ip
-q
863 bridge
-j fdb show br
$bridge brport
$br_port1 \
864 | jq
-e ".[] | select(.mac == \"$mac\")" &> /dev
/null
865 check_fail $?
"Found FDB record when should not"
867 bridge link
set dev
$br_port1 learning on
869 tc filter del dev
$host1_if ingress protocol ip pref
1 handle
101 flower
870 tc qdisc del dev
$host1_if ingress
872 bridge link
set dev
$br_port1 flood on
874 log_test
"FDB learning"
879 local should_flood
=$1
886 # Add an ACL on `host2_if` which will tell us whether the packet
887 # was flooded to it or not.
888 tc qdisc add dev
$host2_if ingress
889 tc filter add dev
$host2_if ingress protocol ip pref
1 handle
101 \
890 flower dst_mac
$mac action drop
892 $MZ $host1_if -c 1 -p 64 -b $mac -B $ip -t ip
-q
895 tc
-j -s filter show dev
$host2_if ingress \
896 | jq
-e ".[] | select(.options.handle == 101) \
897 | select(.options.actions[0].stats.packets == 1)" &> /dev
/null
898 if [[ $?
-ne 0 && $should_flood == "true" || \
899 $?
-eq 0 && $should_flood == "false" ]]; then
903 tc filter del dev
$host2_if ingress protocol ip pref
1 handle
101 flower
904 tc qdisc del dev
$host2_if ingress
914 local mac
=de
:ad
:be
:ef
:13:37
919 bridge link
set dev
$br_port flood off
921 flood_test_do false
$mac $ip $host1_if $host2_if
922 check_err $?
"Packet flooded when should not"
924 bridge link
set dev
$br_port flood on
926 flood_test_do true
$mac $ip $host1_if $host2_if
927 check_err $?
"Packet was not flooded when should"
929 log_test
"Unknown unicast flood"
932 flood_multicast_test
()
937 local mac
=01:00:5e
:00:00:01
942 bridge link
set dev
$br_port mcast_flood off
944 flood_test_do false
$mac $ip $host1_if $host2_if
945 check_err $?
"Packet flooded when should not"
947 bridge link
set dev
$br_port mcast_flood on
949 flood_test_do true
$mac $ip $host1_if $host2_if
950 check_err $?
"Packet was not flooded when should"
952 log_test
"Unregistered multicast flood"
957 # `br_port` is connected to `host2_if`
962 flood_unicast_test
$br_port $host1_if $host2_if
963 flood_multicast_test
$br_port $host1_if $host2_if