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