Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4##############################################################################
5# Defines
6
7# Can be overridden by the configuration file.
8PING=${PING:=ping}
9PING6=${PING6:=ping6}
10MZ=${MZ:=mausezahn}
11ARPING=${ARPING:=arping}
12TEAMD=${TEAMD:=teamd}
13WAIT_TIME=${WAIT_TIME:=5}
14PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
15PAUSE_ON_CLEANUP=${PAUSE_ON_CLEANUP:=no}
16NETIF_TYPE=${NETIF_TYPE:=veth}
17NETIF_CREATE=${NETIF_CREATE:=yes}
18MCD=${MCD:=smcrouted}
19MC_CLI=${MC_CLI:=smcroutectl}
20PING_TIMEOUT=${PING_TIMEOUT:=5}
21
22relative_path="${BASH_SOURCE%/*}"
23if [[ "$relative_path" == "${BASH_SOURCE}" ]]; then
24 relative_path="."
25fi
26
27if [[ -f $relative_path/forwarding.config ]]; then
28 source "$relative_path/forwarding.config"
29fi
30
31##############################################################################
32# Sanity checks
33
34check_tc_version()
35{
36 tc -j &> /dev/null
37 if [[ $? -ne 0 ]]; then
38 echo "SKIP: iproute2 too old; tc is missing JSON support"
39 exit 1
40 fi
41}
42
43check_tc_shblock_support()
44{
45 tc filter help 2>&1 | grep block &> /dev/null
46 if [[ $? -ne 0 ]]; then
47 echo "SKIP: iproute2 too old; tc is missing shared block support"
48 exit 1
49 fi
50}
51
52check_tc_chain_support()
53{
54 tc help 2>&1|grep chain &> /dev/null
55 if [[ $? -ne 0 ]]; then
56 echo "SKIP: iproute2 too old; tc is missing chain support"
57 exit 1
58 fi
59}
60
61if [[ "$(id -u)" -ne 0 ]]; then
62 echo "SKIP: need root privileges"
63 exit 0
64fi
65
66if [[ "$CHECK_TC" = "yes" ]]; then
67 check_tc_version
68fi
69
70require_command()
71{
72 local cmd=$1; shift
73
74 if [[ ! -x "$(command -v "$cmd")" ]]; then
75 echo "SKIP: $cmd not installed"
76 exit 1
77 fi
78}
79
80require_command jq
81require_command $MZ
82
83if [[ ! -v NUM_NETIFS ]]; then
84 echo "SKIP: importer does not define \"NUM_NETIFS\""
85 exit 1
86fi
87
88##############################################################################
89# Command line options handling
90
91count=0
92
93while [[ $# -gt 0 ]]; do
94 if [[ "$count" -eq "0" ]]; then
95 unset NETIFS
96 declare -A NETIFS
97 fi
98 count=$((count + 1))
99 NETIFS[p$count]="$1"
100 shift
101done
102
103##############################################################################
104# Network interfaces configuration
105
106create_netif_veth()
107{
108 local i
109
110 for ((i = 1; i <= NUM_NETIFS; ++i)); do
111 local j=$((i+1))
112
113 ip link show dev ${NETIFS[p$i]} &> /dev/null
114 if [[ $? -ne 0 ]]; then
115 ip link add ${NETIFS[p$i]} type veth \
116 peer name ${NETIFS[p$j]}
117 if [[ $? -ne 0 ]]; then
118 echo "Failed to create netif"
119 exit 1
120 fi
121 fi
122 i=$j
123 done
124}
125
126create_netif()
127{
128 case "$NETIF_TYPE" in
129 veth) create_netif_veth
130 ;;
131 *) echo "Can not create interfaces of type \'$NETIF_TYPE\'"
132 exit 1
133 ;;
134 esac
135}
136
137if [[ "$NETIF_CREATE" = "yes" ]]; then
138 create_netif
139fi
140
141for ((i = 1; i <= NUM_NETIFS; ++i)); do
142 ip link show dev ${NETIFS[p$i]} &> /dev/null
143 if [[ $? -ne 0 ]]; then
144 echo "SKIP: could not find all required interfaces"
145 exit 1
146 fi
147done
148
149##############################################################################
150# Helpers
151
152# Exit status to return at the end. Set in case one of the tests fails.
153EXIT_STATUS=0
154# Per-test return value. Clear at the beginning of each test.
155RET=0
156
157check_err()
158{
159 local err=$1
160 local msg=$2
161
162 if [[ $RET -eq 0 && $err -ne 0 ]]; then
163 RET=$err
164 retmsg=$msg
165 fi
166}
167
168check_fail()
169{
170 local err=$1
171 local msg=$2
172
173 if [[ $RET -eq 0 && $err -eq 0 ]]; then
174 RET=1
175 retmsg=$msg
176 fi
177}
178
179check_err_fail()
180{
181 local should_fail=$1; shift
182 local err=$1; shift
183 local what=$1; shift
184
185 if ((should_fail)); then
186 check_fail $err "$what succeeded, but should have failed"
187 else
188 check_err $err "$what failed"
189 fi
190}
191
192log_test()
193{
194 local test_name=$1
195 local opt_str=$2
196
197 if [[ $# -eq 2 ]]; then
198 opt_str="($opt_str)"
199 fi
200
201 if [[ $RET -ne 0 ]]; then
202 EXIT_STATUS=1
203 printf "TEST: %-60s [FAIL]\n" "$test_name $opt_str"
204 if [[ ! -z "$retmsg" ]]; then
205 printf "\t%s\n" "$retmsg"
206 fi
207 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
208 echo "Hit enter to continue, 'q' to quit"
209 read a
210 [ "$a" = "q" ] && exit 1
211 fi
212 return 1
213 fi
214
215 printf "TEST: %-60s [ OK ]\n" "$test_name $opt_str"
216 return 0
217}
218
219log_info()
220{
221 local msg=$1
222
223 echo "INFO: $msg"
224}
225
226setup_wait_dev()
227{
228 local dev=$1; shift
229
230 while true; do
231 ip link show dev $dev up \
232 | grep 'state UP' &> /dev/null
233 if [[ $? -ne 0 ]]; then
234 sleep 1
235 else
236 break
237 fi
238 done
239}
240
241setup_wait()
242{
243 local num_netifs=${1:-$NUM_NETIFS}
244
245 for ((i = 1; i <= num_netifs; ++i)); do
246 setup_wait_dev ${NETIFS[p$i]}
247 done
248
249 # Make sure links are ready.
250 sleep $WAIT_TIME
251}
252
253lldpad_app_wait_set()
254{
255 local dev=$1; shift
256
257 while lldptool -t -i $dev -V APP -c app | grep -Eq "pending|unknown"; do
258 echo "$dev: waiting for lldpad to push pending APP updates"
259 sleep 5
260 done
261}
262
263lldpad_app_wait_del()
264{
265 # Give lldpad a chance to push down the changes. If the device is downed
266 # too soon, the updates will be left pending. However, they will have
267 # been struck off the lldpad's DB already, so we won't be able to tell
268 # they are pending. Then on next test iteration this would cause
269 # weirdness as newly-added APP rules conflict with the old ones,
270 # sometimes getting stuck in an "unknown" state.
271 sleep 5
272}
273
274pre_cleanup()
275{
276 if [ "${PAUSE_ON_CLEANUP}" = "yes" ]; then
277 echo "Pausing before cleanup, hit any key to continue"
278 read
279 fi
280}
281
282vrf_prepare()
283{
284 ip -4 rule add pref 32765 table local
285 ip -4 rule del pref 0
286 ip -6 rule add pref 32765 table local
287 ip -6 rule del pref 0
288}
289
290vrf_cleanup()
291{
292 ip -6 rule add pref 0 table local
293 ip -6 rule del pref 32765
294 ip -4 rule add pref 0 table local
295 ip -4 rule del pref 32765
296}
297
298__last_tb_id=0
299declare -A __TB_IDS
300
301__vrf_td_id_assign()
302{
303 local vrf_name=$1
304
305 __last_tb_id=$((__last_tb_id + 1))
306 __TB_IDS[$vrf_name]=$__last_tb_id
307 return $__last_tb_id
308}
309
310__vrf_td_id_lookup()
311{
312 local vrf_name=$1
313
314 return ${__TB_IDS[$vrf_name]}
315}
316
317vrf_create()
318{
319 local vrf_name=$1
320 local tb_id
321
322 __vrf_td_id_assign $vrf_name
323 tb_id=$?
324
325 ip link add dev $vrf_name type vrf table $tb_id
326 ip -4 route add table $tb_id unreachable default metric 4278198272
327 ip -6 route add table $tb_id unreachable default metric 4278198272
328}
329
330vrf_destroy()
331{
332 local vrf_name=$1
333 local tb_id
334
335 __vrf_td_id_lookup $vrf_name
336 tb_id=$?
337
338 ip -6 route del table $tb_id unreachable default metric 4278198272
339 ip -4 route del table $tb_id unreachable default metric 4278198272
340 ip link del dev $vrf_name
341}
342
343__addr_add_del()
344{
345 local if_name=$1
346 local add_del=$2
347 local array
348
349 shift
350 shift
351 array=("${@}")
352
353 for addrstr in "${array[@]}"; do
354 ip address $add_del $addrstr dev $if_name
355 done
356}
357
358__simple_if_init()
359{
360 local if_name=$1; shift
361 local vrf_name=$1; shift
362 local addrs=("${@}")
363
364 ip link set dev $if_name master $vrf_name
365 ip link set dev $if_name up
366
367 __addr_add_del $if_name add "${addrs[@]}"
368}
369
370__simple_if_fini()
371{
372 local if_name=$1; shift
373 local addrs=("${@}")
374
375 __addr_add_del $if_name del "${addrs[@]}"
376
377 ip link set dev $if_name down
378 ip link set dev $if_name nomaster
379}
380
381simple_if_init()
382{
383 local if_name=$1
384 local vrf_name
385 local array
386
387 shift
388 vrf_name=v$if_name
389 array=("${@}")
390
391 vrf_create $vrf_name
392 ip link set dev $vrf_name up
393 __simple_if_init $if_name $vrf_name "${array[@]}"
394}
395
396simple_if_fini()
397{
398 local if_name=$1
399 local vrf_name
400 local array
401
402 shift
403 vrf_name=v$if_name
404 array=("${@}")
405
406 __simple_if_fini $if_name "${array[@]}"
407 vrf_destroy $vrf_name
408}
409
410tunnel_create()
411{
412 local name=$1; shift
413 local type=$1; shift
414 local local=$1; shift
415 local remote=$1; shift
416
417 ip link add name $name type $type \
418 local $local remote $remote "$@"
419 ip link set dev $name up
420}
421
422tunnel_destroy()
423{
424 local name=$1; shift
425
426 ip link del dev $name
427}
428
429vlan_create()
430{
431 local if_name=$1; shift
432 local vid=$1; shift
433 local vrf=$1; shift
434 local ips=("${@}")
435 local name=$if_name.$vid
436
437 ip link add name $name link $if_name type vlan id $vid
438 if [ "$vrf" != "" ]; then
439 ip link set dev $name master $vrf
440 fi
441 ip link set dev $name up
442 __addr_add_del $name add "${ips[@]}"
443}
444
445vlan_destroy()
446{
447 local if_name=$1; shift
448 local vid=$1; shift
449 local name=$if_name.$vid
450
451 ip link del dev $name
452}
453
454team_create()
455{
456 local if_name=$1; shift
457 local mode=$1; shift
458
459 require_command $TEAMD
460 $TEAMD -t $if_name -d -c '{"runner": {"name": "'$mode'"}}'
461 for slave in "$@"; do
462 ip link set dev $slave down
463 ip link set dev $slave master $if_name
464 ip link set dev $slave up
465 done
466 ip link set dev $if_name up
467}
468
469team_destroy()
470{
471 local if_name=$1; shift
472
473 $TEAMD -t $if_name -k
474}
475
476master_name_get()
477{
478 local if_name=$1
479
480 ip -j link show dev $if_name | jq -r '.[]["master"]'
481}
482
483link_stats_get()
484{
485 local if_name=$1; shift
486 local dir=$1; shift
487 local stat=$1; shift
488
489 ip -j -s link show dev $if_name \
490 | jq '.[]["stats64"]["'$dir'"]["'$stat'"]'
491}
492
493link_stats_tx_packets_get()
494{
495 link_stats_get $1 tx packets
496}
497
498link_stats_rx_errors_get()
499{
500 link_stats_get $1 rx errors
501}
502
503tc_rule_stats_get()
504{
505 local dev=$1; shift
506 local pref=$1; shift
507 local dir=$1; shift
508
509 tc -j -s filter show dev $dev ${dir:-ingress} pref $pref \
510 | jq '.[1].options.actions[].stats.packets'
511}
512
513ethtool_stats_get()
514{
515 local dev=$1; shift
516 local stat=$1; shift
517
518 ethtool -S $dev | grep "^ *$stat:" | head -n 1 | cut -d: -f2
519}
520
521mac_get()
522{
523 local if_name=$1
524
525 ip -j link show dev $if_name | jq -r '.[]["address"]'
526}
527
528bridge_ageing_time_get()
529{
530 local bridge=$1
531 local ageing_time
532
533 # Need to divide by 100 to convert to seconds.
534 ageing_time=$(ip -j -d link show dev $bridge \
535 | jq '.[]["linkinfo"]["info_data"]["ageing_time"]')
536 echo $((ageing_time / 100))
537}
538
539declare -A SYSCTL_ORIG
540sysctl_set()
541{
542 local key=$1; shift
543 local value=$1; shift
544
545 SYSCTL_ORIG[$key]=$(sysctl -n $key)
546 sysctl -qw $key=$value
547}
548
549sysctl_restore()
550{
551 local key=$1; shift
552
553 sysctl -qw $key=${SYSCTL_ORIG["$key"]}
554}
555
556forwarding_enable()
557{
558 sysctl_set net.ipv4.conf.all.forwarding 1
559 sysctl_set net.ipv6.conf.all.forwarding 1
560}
561
562forwarding_restore()
563{
564 sysctl_restore net.ipv6.conf.all.forwarding
565 sysctl_restore net.ipv4.conf.all.forwarding
566}
567
568declare -A MTU_ORIG
569mtu_set()
570{
571 local dev=$1; shift
572 local mtu=$1; shift
573
574 MTU_ORIG["$dev"]=$(ip -j link show dev $dev | jq -e '.[].mtu')
575 ip link set dev $dev mtu $mtu
576}
577
578mtu_restore()
579{
580 local dev=$1; shift
581
582 ip link set dev $dev mtu ${MTU_ORIG["$dev"]}
583}
584
585tc_offload_check()
586{
587 local num_netifs=${1:-$NUM_NETIFS}
588
589 for ((i = 1; i <= num_netifs; ++i)); do
590 ethtool -k ${NETIFS[p$i]} \
591 | grep "hw-tc-offload: on" &> /dev/null
592 if [[ $? -ne 0 ]]; then
593 return 1
594 fi
595 done
596
597 return 0
598}
599
600trap_install()
601{
602 local dev=$1; shift
603 local direction=$1; shift
604
605 # Some devices may not support or need in-hardware trapping of traffic
606 # (e.g. the veth pairs that this library creates for non-existent
607 # loopbacks). Use continue instead, so that there is a filter in there
608 # (some tests check counters), and so that other filters are still
609 # processed.
610 tc filter add dev $dev $direction pref 1 \
611 flower skip_sw action trap 2>/dev/null \
612 || tc filter add dev $dev $direction pref 1 \
613 flower action continue
614}
615
616trap_uninstall()
617{
618 local dev=$1; shift
619 local direction=$1; shift
620
621 tc filter del dev $dev $direction pref 1 flower
622}
623
624slow_path_trap_install()
625{
626 # For slow-path testing, we need to install a trap to get to
627 # slow path the packets that would otherwise be switched in HW.
628 if [ "${tcflags/skip_hw}" != "$tcflags" ]; then
629 trap_install "$@"
630 fi
631}
632
633slow_path_trap_uninstall()
634{
635 if [ "${tcflags/skip_hw}" != "$tcflags" ]; then
636 trap_uninstall "$@"
637 fi
638}
639
640__icmp_capture_add_del()
641{
642 local add_del=$1; shift
643 local pref=$1; shift
644 local vsuf=$1; shift
645 local tundev=$1; shift
646 local filter=$1; shift
647
648 tc filter $add_del dev "$tundev" ingress \
649 proto ip$vsuf pref $pref \
650 flower ip_proto icmp$vsuf $filter \
651 action pass
652}
653
654icmp_capture_install()
655{
656 __icmp_capture_add_del add 100 "" "$@"
657}
658
659icmp_capture_uninstall()
660{
661 __icmp_capture_add_del del 100 "" "$@"
662}
663
664icmp6_capture_install()
665{
666 __icmp_capture_add_del add 100 v6 "$@"
667}
668
669icmp6_capture_uninstall()
670{
671 __icmp_capture_add_del del 100 v6 "$@"
672}
673
674__vlan_capture_add_del()
675{
676 local add_del=$1; shift
677 local pref=$1; shift
678 local dev=$1; shift
679 local filter=$1; shift
680
681 tc filter $add_del dev "$dev" ingress \
682 proto 802.1q pref $pref \
683 flower $filter \
684 action pass
685}
686
687vlan_capture_install()
688{
689 __vlan_capture_add_del add 100 "$@"
690}
691
692vlan_capture_uninstall()
693{
694 __vlan_capture_add_del del 100 "$@"
695}
696
697__dscp_capture_add_del()
698{
699 local add_del=$1; shift
700 local dev=$1; shift
701 local base=$1; shift
702 local dscp;
703
704 for prio in {0..7}; do
705 dscp=$((base + prio))
706 __icmp_capture_add_del $add_del $((dscp + 100)) "" $dev \
707 "skip_hw ip_tos $((dscp << 2))"
708 done
709}
710
711dscp_capture_install()
712{
713 local dev=$1; shift
714 local base=$1; shift
715
716 __dscp_capture_add_del add $dev $base
717}
718
719dscp_capture_uninstall()
720{
721 local dev=$1; shift
722 local base=$1; shift
723
724 __dscp_capture_add_del del $dev $base
725}
726
727dscp_fetch_stats()
728{
729 local dev=$1; shift
730 local base=$1; shift
731
732 for prio in {0..7}; do
733 local dscp=$((base + prio))
734 local t=$(tc_rule_stats_get $dev $((dscp + 100)))
735 echo "[$dscp]=$t "
736 done
737}
738
739matchall_sink_create()
740{
741 local dev=$1; shift
742
743 tc qdisc add dev $dev clsact
744 tc filter add dev $dev ingress \
745 pref 10000 \
746 matchall \
747 action drop
748}
749
750tests_run()
751{
752 local current_test
753
754 for current_test in ${TESTS:-$ALL_TESTS}; do
755 $current_test
756 done
757}
758
759multipath_eval()
760{
761 local desc="$1"
762 local weight_rp12=$2
763 local weight_rp13=$3
764 local packets_rp12=$4
765 local packets_rp13=$5
766 local weights_ratio packets_ratio diff
767
768 RET=0
769
770 if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
771 weights_ratio=$(echo "scale=2; $weight_rp12 / $weight_rp13" \
772 | bc -l)
773 else
774 weights_ratio=$(echo "scale=2; $weight_rp13 / $weight_rp12" \
775 | bc -l)
776 fi
777
778 if [[ "$packets_rp12" -eq "0" || "$packets_rp13" -eq "0" ]]; then
779 check_err 1 "Packet difference is 0"
780 log_test "Multipath"
781 log_info "Expected ratio $weights_ratio"
782 return
783 fi
784
785 if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
786 packets_ratio=$(echo "scale=2; $packets_rp12 / $packets_rp13" \
787 | bc -l)
788 else
789 packets_ratio=$(echo "scale=2; $packets_rp13 / $packets_rp12" \
790 | bc -l)
791 fi
792
793 diff=$(echo $weights_ratio - $packets_ratio | bc -l)
794 diff=${diff#-}
795
796 test "$(echo "$diff / $weights_ratio > 0.15" | bc -l)" -eq 0
797 check_err $? "Too large discrepancy between expected and measured ratios"
798 log_test "$desc"
799 log_info "Expected ratio $weights_ratio Measured ratio $packets_ratio"
800}
801
802in_ns()
803{
804 local name=$1; shift
805
806 ip netns exec $name bash <<-EOF
807 NUM_NETIFS=0
808 source lib.sh
809 $(for a in "$@"; do printf "%q${IFS:0:1}" "$a"; done)
810 EOF
811}
812
813##############################################################################
814# Tests
815
816ping_do()
817{
818 local if_name=$1
819 local dip=$2
820 local args=$3
821 local vrf_name
822
823 vrf_name=$(master_name_get $if_name)
824 ip vrf exec $vrf_name \
825 $PING $args $dip -c 10 -i 0.1 -w $PING_TIMEOUT &> /dev/null
826}
827
828ping_test()
829{
830 RET=0
831
832 ping_do $1 $2
833 check_err $?
834 log_test "ping$3"
835}
836
837ping6_do()
838{
839 local if_name=$1
840 local dip=$2
841 local args=$3
842 local vrf_name
843
844 vrf_name=$(master_name_get $if_name)
845 ip vrf exec $vrf_name \
846 $PING6 $args $dip -c 10 -i 0.1 -w $PING_TIMEOUT &> /dev/null
847}
848
849ping6_test()
850{
851 RET=0
852
853 ping6_do $1 $2
854 check_err $?
855 log_test "ping6$3"
856}
857
858learning_test()
859{
860 local bridge=$1
861 local br_port1=$2 # Connected to `host1_if`.
862 local host1_if=$3
863 local host2_if=$4
864 local mac=de:ad:be:ef:13:37
865 local ageing_time
866
867 RET=0
868
869 bridge -j fdb show br $bridge brport $br_port1 \
870 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
871 check_fail $? "Found FDB record when should not"
872
873 # Disable unknown unicast flooding on `br_port1` to make sure
874 # packets are only forwarded through the port after a matching
875 # FDB entry was installed.
876 bridge link set dev $br_port1 flood off
877
878 tc qdisc add dev $host1_if ingress
879 tc filter add dev $host1_if ingress protocol ip pref 1 handle 101 \
880 flower dst_mac $mac action drop
881
882 $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q
883 sleep 1
884
885 tc -j -s filter show dev $host1_if ingress \
886 | jq -e ".[] | select(.options.handle == 101) \
887 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
888 check_fail $? "Packet reached second host when should not"
889
890 $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
891 sleep 1
892
893 bridge -j fdb show br $bridge brport $br_port1 \
894 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
895 check_err $? "Did not find FDB record when should"
896
897 $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q
898 sleep 1
899
900 tc -j -s filter show dev $host1_if ingress \
901 | jq -e ".[] | select(.options.handle == 101) \
902 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
903 check_err $? "Packet did not reach second host when should"
904
905 # Wait for 10 seconds after the ageing time to make sure FDB
906 # record was aged-out.
907 ageing_time=$(bridge_ageing_time_get $bridge)
908 sleep $((ageing_time + 10))
909
910 bridge -j fdb show br $bridge brport $br_port1 \
911 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
912 check_fail $? "Found FDB record when should not"
913
914 bridge link set dev $br_port1 learning off
915
916 $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
917 sleep 1
918
919 bridge -j fdb show br $bridge brport $br_port1 \
920 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
921 check_fail $? "Found FDB record when should not"
922
923 bridge link set dev $br_port1 learning on
924
925 tc filter del dev $host1_if ingress protocol ip pref 1 handle 101 flower
926 tc qdisc del dev $host1_if ingress
927
928 bridge link set dev $br_port1 flood on
929
930 log_test "FDB learning"
931}
932
933flood_test_do()
934{
935 local should_flood=$1
936 local mac=$2
937 local ip=$3
938 local host1_if=$4
939 local host2_if=$5
940 local err=0
941
942 # Add an ACL on `host2_if` which will tell us whether the packet
943 # was flooded to it or not.
944 tc qdisc add dev $host2_if ingress
945 tc filter add dev $host2_if ingress protocol ip pref 1 handle 101 \
946 flower dst_mac $mac action drop
947
948 $MZ $host1_if -c 1 -p 64 -b $mac -B $ip -t ip -q
949 sleep 1
950
951 tc -j -s filter show dev $host2_if ingress \
952 | jq -e ".[] | select(.options.handle == 101) \
953 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
954 if [[ $? -ne 0 && $should_flood == "true" || \
955 $? -eq 0 && $should_flood == "false" ]]; then
956 err=1
957 fi
958
959 tc filter del dev $host2_if ingress protocol ip pref 1 handle 101 flower
960 tc qdisc del dev $host2_if ingress
961
962 return $err
963}
964
965flood_unicast_test()
966{
967 local br_port=$1
968 local host1_if=$2
969 local host2_if=$3
970 local mac=de:ad:be:ef:13:37
971 local ip=192.0.2.100
972
973 RET=0
974
975 bridge link set dev $br_port flood off
976
977 flood_test_do false $mac $ip $host1_if $host2_if
978 check_err $? "Packet flooded when should not"
979
980 bridge link set dev $br_port flood on
981
982 flood_test_do true $mac $ip $host1_if $host2_if
983 check_err $? "Packet was not flooded when should"
984
985 log_test "Unknown unicast flood"
986}
987
988flood_multicast_test()
989{
990 local br_port=$1
991 local host1_if=$2
992 local host2_if=$3
993 local mac=01:00:5e:00:00:01
994 local ip=239.0.0.1
995
996 RET=0
997
998 bridge link set dev $br_port mcast_flood off
999
1000 flood_test_do false $mac $ip $host1_if $host2_if
1001 check_err $? "Packet flooded when should not"
1002
1003 bridge link set dev $br_port mcast_flood on
1004
1005 flood_test_do true $mac $ip $host1_if $host2_if
1006 check_err $? "Packet was not flooded when should"
1007
1008 log_test "Unregistered multicast flood"
1009}
1010
1011flood_test()
1012{
1013 # `br_port` is connected to `host2_if`
1014 local br_port=$1
1015 local host1_if=$2
1016 local host2_if=$3
1017
1018 flood_unicast_test $br_port $host1_if $host2_if
1019 flood_multicast_test $br_port $host1_if $host2_if
1020}