Merge branches 'pm-devfreq', 'pm-qos', 'pm-tools' and 'pm-docs'
[linux-2.6-block.git] / tools / testing / selftests / net / forwarding / lib.sh
CommitLineData
73bae673
IS
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4##############################################################################
5# Defines
6
7844ec21
PHL
7# Kselftest framework requirement - SKIP code is 4.
8ksft_skip=4
9
73bae673
IS
10# Can be overridden by the configuration file.
11PING=${PING:=ping}
12PING6=${PING6:=ping6}
d4deb014 13MZ=${MZ:=mausezahn}
ca70a562 14ARPING=${ARPING:=arping}
9d9e6bde 15TEAMD=${TEAMD:=teamd}
73bae673
IS
16WAIT_TIME=${WAIT_TIME:=5}
17PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
18PAUSE_ON_CLEANUP=${PAUSE_ON_CLEANUP:=no}
59be45c3
IS
19NETIF_TYPE=${NETIF_TYPE:=veth}
20NETIF_CREATE=${NETIF_CREATE:=yes}
6d4efada
ND
21MCD=${MCD:=smcrouted}
22MC_CLI=${MC_CLI:=smcroutectl}
0cd0b1f7 23PING_COUNT=${PING_COUNT:=10}
b6a4fd68 24PING_TIMEOUT=${PING_TIMEOUT:=5}
8f72a9cf
AC
25WAIT_TIMEOUT=${WAIT_TIMEOUT:=20}
26INTERFACE_TIMEOUT=${INTERFACE_TIMEOUT:=600}
08119759 27LOW_AGEING_TIME=${LOW_AGEING_TIME:=1000}
d70b51f2
VO
28REQUIRE_JQ=${REQUIRE_JQ:=yes}
29REQUIRE_MZ=${REQUIRE_MZ:=yes}
f23cddc7 30REQUIRE_MTOOLS=${REQUIRE_MTOOLS:=no}
b343734e 31STABLE_MAC_ADDRS=${STABLE_MAC_ADDRS:=no}
fe32dffd 32TCPDUMP_EXTRA_FLAGS=${TCPDUMP_EXTRA_FLAGS:=}
73bae673 33
87d8fb18
YM
34relative_path="${BASH_SOURCE%/*}"
35if [[ "$relative_path" == "${BASH_SOURCE}" ]]; then
36 relative_path="."
37fi
38
39if [[ -f $relative_path/forwarding.config ]]; then
40 source "$relative_path/forwarding.config"
73bae673
IS
41fi
42
43##############################################################################
44# Sanity checks
45
198979be
DA
46check_tc_version()
47{
48 tc -j &> /dev/null
49 if [[ $? -ne 0 ]]; then
50 echo "SKIP: iproute2 too old; tc is missing JSON support"
7844ec21 51 exit $ksft_skip
198979be 52 fi
7f333cbf 53}
198979be 54
203ee5cd
GN
55# Old versions of tc don't understand "mpls_uc"
56check_tc_mpls_support()
57{
58 local dev=$1; shift
59
60 tc filter add dev $dev ingress protocol mpls_uc pref 1 handle 1 \
61 matchall action pipe &> /dev/null
62 if [[ $? -ne 0 ]]; then
63 echo "SKIP: iproute2 too old; tc is missing MPLS support"
7844ec21 64 return $ksft_skip
203ee5cd
GN
65 fi
66 tc filter del dev $dev ingress protocol mpls_uc pref 1 handle 1 \
67 matchall
68}
69
c09bfd9a
GN
70# Old versions of tc produce invalid json output for mpls lse statistics
71check_tc_mpls_lse_stats()
72{
73 local dev=$1; shift
74 local ret;
75
76 tc filter add dev $dev ingress protocol mpls_uc pref 1 handle 1 \
77 flower mpls lse depth 2 \
78 action continue &> /dev/null
79
80 if [[ $? -ne 0 ]]; then
81 echo "SKIP: iproute2 too old; tc-flower is missing extended MPLS support"
7844ec21 82 return $ksft_skip
c09bfd9a
GN
83 fi
84
85 tc -j filter show dev $dev ingress protocol mpls_uc | jq . &> /dev/null
86 ret=$?
87 tc filter del dev $dev ingress protocol mpls_uc pref 1 handle 1 \
88 flower
89
90 if [[ $ret -ne 0 ]]; then
91 echo "SKIP: iproute2 too old; tc-flower produces invalid json output for extended MPLS filters"
7844ec21 92 return $ksft_skip
c09bfd9a
GN
93 fi
94}
95
7f333cbf
JP
96check_tc_shblock_support()
97{
198979be
DA
98 tc filter help 2>&1 | grep block &> /dev/null
99 if [[ $? -ne 0 ]]; then
100 echo "SKIP: iproute2 too old; tc is missing shared block support"
7844ec21 101 exit $ksft_skip
198979be
DA
102 fi
103}
104
2d73c887
JP
105check_tc_chain_support()
106{
107 tc help 2>&1|grep chain &> /dev/null
108 if [[ $? -ne 0 ]]; then
109 echo "SKIP: iproute2 too old; tc is missing chain support"
7844ec21 110 exit $ksft_skip
2d73c887
JP
111 fi
112}
113
ee4848ac
JP
114check_tc_action_hw_stats_support()
115{
116 tc actions help 2>&1 | grep -q hw_stats
117 if [[ $? -ne 0 ]]; then
118 echo "SKIP: iproute2 too old; tc is missing action hw_stats support"
7844ec21 119 exit $ksft_skip
ee4848ac
JP
120 fi
121}
122
f72e2f48
DR
123check_ethtool_lanes_support()
124{
125 ethtool --help 2>&1| grep lanes &> /dev/null
126 if [[ $? -ne 0 ]]; then
127 echo "SKIP: ethtool too old; it is missing lanes support"
7844ec21 128 exit $ksft_skip
f72e2f48
DR
129 fi
130}
131
b2b681a4
HS
132check_locked_port_support()
133{
134 if ! bridge -d link show | grep -q " locked"; then
135 echo "SKIP: iproute2 too old; Locked port feature not supported."
136 return $ksft_skip
137 fi
138}
139
73bae673
IS
140if [[ "$(id -u)" -ne 0 ]]; then
141 echo "SKIP: need root privileges"
7844ec21 142 exit $ksft_skip
73bae673
IS
143fi
144
198979be
DA
145if [[ "$CHECK_TC" = "yes" ]]; then
146 check_tc_version
4908e24b
JP
147fi
148
e094574f
PM
149require_command()
150{
151 local cmd=$1; shift
73bae673 152
e094574f
PM
153 if [[ ! -x "$(command -v "$cmd")" ]]; then
154 echo "SKIP: $cmd not installed"
7844ec21 155 exit $ksft_skip
e094574f
PM
156 fi
157}
158
d70b51f2
VO
159if [[ "$REQUIRE_JQ" = "yes" ]]; then
160 require_command jq
161fi
162if [[ "$REQUIRE_MZ" = "yes" ]]; then
163 require_command $MZ
164fi
f23cddc7
VO
165if [[ "$REQUIRE_MTOOLS" = "yes" ]]; then
166 # https://github.com/vladimiroltean/mtools/
167 # patched for IPv6 support
168 require_command msend
169 require_command mreceive
170fi
d4deb014 171
73bae673
IS
172if [[ ! -v NUM_NETIFS ]]; then
173 echo "SKIP: importer does not define \"NUM_NETIFS\""
7844ec21 174 exit $ksft_skip
73bae673
IS
175fi
176
781fe631
JP
177##############################################################################
178# Command line options handling
179
180count=0
181
182while [[ $# -gt 0 ]]; do
183 if [[ "$count" -eq "0" ]]; then
184 unset NETIFS
185 declare -A NETIFS
186 fi
187 count=$((count + 1))
188 NETIFS[p$count]="$1"
189 shift
190done
191
73bae673
IS
192##############################################################################
193# Network interfaces configuration
194
190f887c
DA
195create_netif_veth()
196{
197 local i
198
601bc1c1 199 for ((i = 1; i <= NUM_NETIFS; ++i)); do
190f887c
DA
200 local j=$((i+1))
201
202 ip link show dev ${NETIFS[p$i]} &> /dev/null
203 if [[ $? -ne 0 ]]; then
204 ip link add ${NETIFS[p$i]} type veth \
205 peer name ${NETIFS[p$j]}
206 if [[ $? -ne 0 ]]; then
207 echo "Failed to create netif"
208 exit 1
209 fi
210 fi
211 i=$j
212 done
213}
214
215create_netif()
216{
217 case "$NETIF_TYPE" in
218 veth) create_netif_veth
219 ;;
220 *) echo "Can not create interfaces of type \'$NETIF_TYPE\'"
221 exit 1
222 ;;
223 esac
224}
225
b343734e
VO
226declare -A MAC_ADDR_ORIG
227mac_addr_prepare()
228{
229 local new_addr=
230 local dev=
231
232 for ((i = 1; i <= NUM_NETIFS; ++i)); do
233 dev=${NETIFS[p$i]}
234 new_addr=$(printf "00:01:02:03:04:%02x" $i)
235
236 MAC_ADDR_ORIG["$dev"]=$(ip -j link show dev $dev | jq -e '.[].address')
237 # Strip quotes
238 MAC_ADDR_ORIG["$dev"]=${MAC_ADDR_ORIG["$dev"]//\"/}
239 ip link set dev $dev address $new_addr
240 done
241}
242
243mac_addr_restore()
244{
245 local dev=
246
247 for ((i = 1; i <= NUM_NETIFS; ++i)); do
248 dev=${NETIFS[p$i]}
249 ip link set dev $dev address ${MAC_ADDR_ORIG["$dev"]}
250 done
251}
252
190f887c
DA
253if [[ "$NETIF_CREATE" = "yes" ]]; then
254 create_netif
255fi
256
b343734e
VO
257if [[ "$STABLE_MAC_ADDRS" = "yes" ]]; then
258 mac_addr_prepare
259fi
260
601bc1c1 261for ((i = 1; i <= NUM_NETIFS; ++i)); do
73bae673
IS
262 ip link show dev ${NETIFS[p$i]} &> /dev/null
263 if [[ $? -ne 0 ]]; then
264 echo "SKIP: could not find all required interfaces"
7844ec21 265 exit $ksft_skip
73bae673
IS
266 fi
267done
268
269##############################################################################
270# Helpers
271
272# Exit status to return at the end. Set in case one of the tests fails.
273EXIT_STATUS=0
274# Per-test return value. Clear at the beginning of each test.
275RET=0
276
277check_err()
278{
279 local err=$1
280 local msg=$2
281
282 if [[ $RET -eq 0 && $err -ne 0 ]]; then
283 RET=$err
284 retmsg=$msg
285 fi
286}
287
288check_fail()
289{
290 local err=$1
291 local msg=$2
292
293 if [[ $RET -eq 0 && $err -eq 0 ]]; then
294 RET=1
295 retmsg=$msg
296 fi
297}
298
96fa91d2
PM
299check_err_fail()
300{
301 local should_fail=$1; shift
302 local err=$1; shift
303 local what=$1; shift
304
305 if ((should_fail)); then
306 check_fail $err "$what succeeded, but should have failed"
307 else
308 check_err $err "$what failed"
309 fi
310}
311
73bae673
IS
312log_test()
313{
314 local test_name=$1
315 local opt_str=$2
316
317 if [[ $# -eq 2 ]]; then
318 opt_str="($opt_str)"
319 fi
320
321 if [[ $RET -ne 0 ]]; then
322 EXIT_STATUS=1
323 printf "TEST: %-60s [FAIL]\n" "$test_name $opt_str"
324 if [[ ! -z "$retmsg" ]]; then
325 printf "\t%s\n" "$retmsg"
326 fi
327 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
328 echo "Hit enter to continue, 'q' to quit"
329 read a
330 [ "$a" = "q" ] && exit 1
331 fi
332 return 1
333 fi
334
3cab0de9 335 printf "TEST: %-60s [ OK ]\n" "$test_name $opt_str"
73bae673
IS
336 return 0
337}
338
b8bfafe4
PM
339log_test_skip()
340{
341 local test_name=$1
342 local opt_str=$2
343
344 printf "TEST: %-60s [SKIP]\n" "$test_name $opt_str"
345 return 0
346}
347
3d578d87
IS
348log_info()
349{
350 local msg=$1
351
352 echo "INFO: $msg"
353}
354
c5341bcc
PM
355busywait()
356{
357 local timeout=$1; shift
358
359 local start_time="$(date -u +%s%3N)"
360 while true
361 do
362 local out
363 out=$("$@")
364 local ret=$?
365 if ((!ret)); then
366 echo -n "$out"
367 return 0
368 fi
369
370 local current_time="$(date -u +%s%3N)"
371 if ((current_time - start_time > timeout)); then
372 echo -n "$out"
373 return 1
374 fi
375 done
376}
377
05ef614c
DR
378not()
379{
380 "$@"
381 [[ $? != 0 ]]
382}
383
f72e2f48
DR
384get_max()
385{
386 local arr=("$@")
387
388 max=${arr[0]}
389 for cur in ${arr[@]}; do
390 if [[ $cur -gt $max ]]; then
391 max=$cur
392 fi
393 done
394
395 echo $max
396}
397
05ef614c
DR
398grep_bridge_fdb()
399{
400 local addr=$1; shift
401 local word
402 local flag
403
404 if [ "$1" == "self" ] || [ "$1" == "master" ]; then
405 word=$1; shift
406 if [ "$1" == "-v" ]; then
407 flag=$1; shift
408 fi
409 fi
410
411 $@ | grep $addr | grep $flag "$word"
412}
413
f72e2f48
DR
414wait_for_port_up()
415{
416 "$@" | grep -q "Link detected: yes"
417}
418
0c22f993
DR
419wait_for_offload()
420{
421 "$@" | grep -q offload
422}
423
ffd3e9b0
IS
424wait_for_trap()
425{
426 "$@" | grep -q trap
427}
428
4121d947
PM
429until_counter_is()
430{
844f0556 431 local expr=$1; shift
4121d947
PM
432 local current=$("$@")
433
434 echo $((current))
844f0556 435 ((current $expr))
4121d947
PM
436}
437
438busywait_for_counter()
439{
440 local timeout=$1; shift
441 local delta=$1; shift
442
443 local base=$("$@")
844f0556 444 busywait "$timeout" until_counter_is ">= $((base + delta))" "$@"
4121d947
PM
445}
446
010079ba
PM
447setup_wait_dev()
448{
449 local dev=$1; shift
8f72a9cf 450 local wait_time=${1:-$WAIT_TIME}; shift
010079ba 451
8f72a9cf
AC
452 setup_wait_dev_with_timeout "$dev" $INTERFACE_TIMEOUT $wait_time
453
454 if (($?)); then
455 check_err 1
456 log_test setup_wait_dev ": Interface $dev does not come up."
457 exit 1
458 fi
459}
460
461setup_wait_dev_with_timeout()
462{
463 local dev=$1; shift
464 local max_iterations=${1:-$WAIT_TIMEOUT}; shift
465 local wait_time=${1:-$WAIT_TIME}; shift
466 local i
467
468 for ((i = 1; i <= $max_iterations; ++i)); do
010079ba
PM
469 ip link show dev $dev up \
470 | grep 'state UP' &> /dev/null
471 if [[ $? -ne 0 ]]; then
472 sleep 1
473 else
8f72a9cf
AC
474 sleep $wait_time
475 return 0
010079ba
PM
476 fi
477 done
8f72a9cf
AC
478
479 return 1
010079ba
PM
480}
481
73bae673
IS
482setup_wait()
483{
68d9cea5 484 local num_netifs=${1:-$NUM_NETIFS}
8f72a9cf 485 local i
68d9cea5
PM
486
487 for ((i = 1; i <= num_netifs; ++i)); do
8f72a9cf 488 setup_wait_dev ${NETIFS[p$i]} 0
73bae673
IS
489 done
490
491 # Make sure links are ready.
492 sleep $WAIT_TIME
493}
494
d87e5edb
JP
495cmd_jq()
496{
497 local cmd=$1
498 local jq_exp=$2
c04d71b5 499 local jq_opts=$3
d87e5edb
JP
500 local ret
501 local output
502
503 output="$($cmd)"
504 # it the command fails, return error right away
505 ret=$?
506 if [[ $ret -ne 0 ]]; then
507 return $ret
508 fi
c04d71b5
JP
509 output=$(echo $output | jq -r $jq_opts "$jq_exp")
510 ret=$?
511 if [[ $ret -ne 0 ]]; then
512 return $ret
513 fi
d87e5edb
JP
514 echo $output
515 # return success only in case of non-empty output
516 [ ! -z "$output" ]
517}
518
989133bf
PM
519lldpad_app_wait_set()
520{
521 local dev=$1; shift
522
37280905 523 while lldptool -t -i $dev -V APP -c app | grep -Eq "pending|unknown"; do
989133bf
PM
524 echo "$dev: waiting for lldpad to push pending APP updates"
525 sleep 5
526 done
527}
528
529lldpad_app_wait_del()
530{
531 # Give lldpad a chance to push down the changes. If the device is downed
532 # too soon, the updates will be left pending. However, they will have
533 # been struck off the lldpad's DB already, so we won't be able to tell
534 # they are pending. Then on next test iteration this would cause
535 # weirdness as newly-added APP rules conflict with the old ones,
536 # sometimes getting stuck in an "unknown" state.
537 sleep 5
538}
539
73bae673
IS
540pre_cleanup()
541{
542 if [ "${PAUSE_ON_CLEANUP}" = "yes" ]; then
543 echo "Pausing before cleanup, hit any key to continue"
544 read
545 fi
b343734e
VO
546
547 if [[ "$STABLE_MAC_ADDRS" = "yes" ]]; then
548 mac_addr_restore
549 fi
73bae673
IS
550}
551
552vrf_prepare()
553{
554 ip -4 rule add pref 32765 table local
555 ip -4 rule del pref 0
556 ip -6 rule add pref 32765 table local
557 ip -6 rule del pref 0
558}
559
560vrf_cleanup()
561{
562 ip -6 rule add pref 0 table local
563 ip -6 rule del pref 32765
564 ip -4 rule add pref 0 table local
565 ip -4 rule del pref 32765
566}
567
568__last_tb_id=0
569declare -A __TB_IDS
570
571__vrf_td_id_assign()
572{
573 local vrf_name=$1
574
575 __last_tb_id=$((__last_tb_id + 1))
576 __TB_IDS[$vrf_name]=$__last_tb_id
577 return $__last_tb_id
578}
579
580__vrf_td_id_lookup()
581{
582 local vrf_name=$1
583
584 return ${__TB_IDS[$vrf_name]}
585}
586
587vrf_create()
588{
589 local vrf_name=$1
590 local tb_id
591
592 __vrf_td_id_assign $vrf_name
593 tb_id=$?
594
595 ip link add dev $vrf_name type vrf table $tb_id
596 ip -4 route add table $tb_id unreachable default metric 4278198272
597 ip -6 route add table $tb_id unreachable default metric 4278198272
598}
599
600vrf_destroy()
601{
602 local vrf_name=$1
603 local tb_id
604
605 __vrf_td_id_lookup $vrf_name
606 tb_id=$?
607
608 ip -6 route del table $tb_id unreachable default metric 4278198272
609 ip -4 route del table $tb_id unreachable default metric 4278198272
610 ip link del dev $vrf_name
611}
612
613__addr_add_del()
614{
615 local if_name=$1
616 local add_del=$2
617 local array
618
619 shift
620 shift
621 array=("${@}")
622
623 for addrstr in "${array[@]}"; do
624 ip address $add_del $addrstr dev $if_name
625 done
626}
627
3368b223
PM
628__simple_if_init()
629{
630 local if_name=$1; shift
631 local vrf_name=$1; shift
632 local addrs=("${@}")
633
634 ip link set dev $if_name master $vrf_name
635 ip link set dev $if_name up
636
637 __addr_add_del $if_name add "${addrs[@]}"
638}
639
640__simple_if_fini()
641{
642 local if_name=$1; shift
643 local addrs=("${@}")
644
645 __addr_add_del $if_name del "${addrs[@]}"
646
647 ip link set dev $if_name down
648 ip link set dev $if_name nomaster
649}
650
73bae673
IS
651simple_if_init()
652{
653 local if_name=$1
654 local vrf_name
655 local array
656
657 shift
658 vrf_name=v$if_name
659 array=("${@}")
660
661 vrf_create $vrf_name
73bae673 662 ip link set dev $vrf_name up
3368b223 663 __simple_if_init $if_name $vrf_name "${array[@]}"
73bae673
IS
664}
665
666simple_if_fini()
667{
668 local if_name=$1
669 local vrf_name
670 local array
671
672 shift
673 vrf_name=v$if_name
674 array=("${@}")
675
3368b223 676 __simple_if_fini $if_name "${array[@]}"
73bae673
IS
677 vrf_destroy $vrf_name
678}
679
7d4cbae0
PM
680tunnel_create()
681{
682 local name=$1; shift
683 local type=$1; shift
684 local local=$1; shift
685 local remote=$1; shift
686
687 ip link add name $name type $type \
688 local $local remote $remote "$@"
689 ip link set dev $name up
690}
691
692tunnel_destroy()
693{
694 local name=$1; shift
695
696 ip link del dev $name
697}
698
0e7a504c
PM
699vlan_create()
700{
701 local if_name=$1; shift
702 local vid=$1; shift
703 local vrf=$1; shift
704 local ips=("${@}")
705 local name=$if_name.$vid
706
707 ip link add name $name link $if_name type vlan id $vid
708 if [ "$vrf" != "" ]; then
709 ip link set dev $name master $vrf
710 fi
711 ip link set dev $name up
712 __addr_add_del $name add "${ips[@]}"
713}
714
715vlan_destroy()
716{
717 local if_name=$1; shift
718 local vid=$1; shift
719 local name=$if_name.$vid
720
721 ip link del dev $name
722}
723
9d9e6bde
PM
724team_create()
725{
726 local if_name=$1; shift
727 local mode=$1; shift
728
729 require_command $TEAMD
730 $TEAMD -t $if_name -d -c '{"runner": {"name": "'$mode'"}}'
731 for slave in "$@"; do
732 ip link set dev $slave down
733 ip link set dev $slave master $if_name
734 ip link set dev $slave up
735 done
736 ip link set dev $if_name up
737}
738
739team_destroy()
740{
741 local if_name=$1; shift
742
743 $TEAMD -t $if_name -k
744}
745
73bae673
IS
746master_name_get()
747{
748 local if_name=$1
749
750 ip -j link show dev $if_name | jq -r '.[]["master"]'
751}
752
d1038cd0
PM
753link_stats_get()
754{
755 local if_name=$1; shift
756 local dir=$1; shift
757 local stat=$1; shift
758
759 ip -j -s link show dev $if_name \
760 | jq '.[]["stats64"]["'$dir'"]["'$stat'"]'
761}
762
3d578d87
IS
763link_stats_tx_packets_get()
764{
d1038cd0
PM
765 link_stats_get $1 tx packets
766}
3d578d87 767
d1038cd0
PM
768link_stats_rx_errors_get()
769{
770 link_stats_get $1 rx errors
3d578d87
IS
771}
772
7d4cbae0
PM
773tc_rule_stats_get()
774{
775 local dev=$1; shift
776 local pref=$1; shift
a66d62d8 777 local dir=$1; shift
c143139b 778 local selector=${1:-.packets}; shift
7d4cbae0 779
a66d62d8 780 tc -j -s filter show dev $dev ${dir:-ingress} pref $pref \
c143139b 781 | jq ".[1].options.actions[].stats$selector"
7d4cbae0
PM
782}
783
84ea1f85
PM
784tc_rule_handle_stats_get()
785{
786 local id=$1; shift
787 local handle=$1; shift
788 local selector=${1:-.packets}; shift
789
790 tc -j -s filter show $id \
791 | jq ".[] | select(.options.handle == $handle) | \
792 .options.actions[0].stats$selector"
793}
794
3136a369
PM
795ethtool_stats_get()
796{
797 local dev=$1; shift
798 local stat=$1; shift
799
800 ethtool -S $dev | grep "^ *$stat:" | head -n 1 | cut -d: -f2
801}
802
3de611b5
PM
803qdisc_stats_get()
804{
805 local dev=$1; shift
806 local handle=$1; shift
807 local selector=$1; shift
808
809 tc -j -s qdisc show dev "$dev" \
810 | jq '.[] | select(.handle == "'"$handle"'") | '"$selector"
811}
812
b9b72999
PM
813qdisc_parent_stats_get()
814{
815 local dev=$1; shift
816 local parent=$1; shift
817 local selector=$1; shift
818
819 tc -j -s qdisc show dev "$dev" invisible \
820 | jq '.[] | select(.parent == "'"$parent"'") | '"$selector"
821}
822
0857d6f8
SS
823ipv6_stats_get()
824{
825 local dev=$1; shift
826 local stat=$1; shift
827
828 cat /proc/net/dev_snmp6/$dev | grep "^$stat" | cut -f2
829}
830
32fb67a3
PM
831hw_stats_get()
832{
833 local suite=$1; shift
834 local if_name=$1; shift
835 local dir=$1; shift
836 local stat=$1; shift
837
838 ip -j stats show dev $if_name group offload subgroup $suite |
839 jq ".[0].stats64.$dir.$stat"
840}
841
adc6c7ec
PM
842humanize()
843{
844 local speed=$1; shift
845
846 for unit in bps Kbps Mbps Gbps; do
847 if (($(echo "$speed < 1024" | bc))); then
848 break
849 fi
850
851 speed=$(echo "scale=1; $speed / 1024" | bc)
852 done
853
854 echo "$speed${unit}"
855}
856
857rate()
858{
859 local t0=$1; shift
860 local t1=$1; shift
861 local interval=$1; shift
862
863 echo $((8 * (t1 - t0) / interval))
864}
865
53b61f29
BZ
866packets_rate()
867{
868 local t0=$1; shift
869 local t1=$1; shift
870 local interval=$1; shift
871
872 echo $(((t1 - t0) / interval))
873}
874
4e4272d2
JP
875mac_get()
876{
877 local if_name=$1
878
879 ip -j link show dev $if_name | jq -r '.[]["address"]'
880}
881
a5114df6
VO
882ipv6_lladdr_get()
883{
884 local if_name=$1
885
886 ip -j addr show dev $if_name | \
887 jq -r '.[]["addr_info"][] | select(.scope == "link").local' | \
888 head -1
889}
890
d4deb014
IS
891bridge_ageing_time_get()
892{
893 local bridge=$1
894 local ageing_time
895
896 # Need to divide by 100 to convert to seconds.
897 ageing_time=$(ip -j -d link show dev $bridge \
898 | jq '.[]["linkinfo"]["info_data"]["ageing_time"]')
899 echo $((ageing_time / 100))
900}
901
f5ae5778
PM
902declare -A SYSCTL_ORIG
903sysctl_set()
904{
905 local key=$1; shift
906 local value=$1; shift
907
908 SYSCTL_ORIG[$key]=$(sysctl -n $key)
909 sysctl -qw $key=$value
910}
911
912sysctl_restore()
913{
914 local key=$1; shift
915
916 sysctl -qw $key=${SYSCTL_ORIG["$key"]}
917}
918
7b7bc875
IS
919forwarding_enable()
920{
d51d10aa
PM
921 sysctl_set net.ipv4.conf.all.forwarding 1
922 sysctl_set net.ipv6.conf.all.forwarding 1
7b7bc875
IS
923}
924
925forwarding_restore()
926{
d51d10aa
PM
927 sysctl_restore net.ipv6.conf.all.forwarding
928 sysctl_restore net.ipv4.conf.all.forwarding
7b7bc875
IS
929}
930
a381ed12
PM
931declare -A MTU_ORIG
932mtu_set()
933{
934 local dev=$1; shift
935 local mtu=$1; shift
936
937 MTU_ORIG["$dev"]=$(ip -j link show dev $dev | jq -e '.[].mtu')
938 ip link set dev $dev mtu $mtu
939}
940
941mtu_restore()
942{
943 local dev=$1; shift
944
945 ip link set dev $dev mtu ${MTU_ORIG["$dev"]}
946}
947
2f19f212
JP
948tc_offload_check()
949{
68d9cea5
PM
950 local num_netifs=${1:-$NUM_NETIFS}
951
952 for ((i = 1; i <= num_netifs; ++i)); do
2f19f212
JP
953 ethtool -k ${NETIFS[p$i]} \
954 | grep "hw-tc-offload: on" &> /dev/null
955 if [[ $? -ne 0 ]]; then
956 return 1
957 fi
958 done
959
960 return 0
961}
962
87c0c046 963trap_install()
7d4cbae0
PM
964{
965 local dev=$1; shift
966 local direction=$1; shift
967
ac0fcadf
PM
968 # Some devices may not support or need in-hardware trapping of traffic
969 # (e.g. the veth pairs that this library creates for non-existent
970 # loopbacks). Use continue instead, so that there is a filter in there
971 # (some tests check counters), and so that other filters are still
972 # processed.
973 tc filter add dev $dev $direction pref 1 \
974 flower skip_sw action trap 2>/dev/null \
975 || tc filter add dev $dev $direction pref 1 \
976 flower action continue
7d4cbae0
PM
977}
978
87c0c046 979trap_uninstall()
7d4cbae0
PM
980{
981 local dev=$1; shift
982 local direction=$1; shift
983
ac0fcadf 984 tc filter del dev $dev $direction pref 1 flower
87c0c046
PM
985}
986
987slow_path_trap_install()
988{
ac0fcadf
PM
989 # For slow-path testing, we need to install a trap to get to
990 # slow path the packets that would otherwise be switched in HW.
87c0c046
PM
991 if [ "${tcflags/skip_hw}" != "$tcflags" ]; then
992 trap_install "$@"
993 fi
994}
995
996slow_path_trap_uninstall()
997{
7d4cbae0 998 if [ "${tcflags/skip_hw}" != "$tcflags" ]; then
87c0c046 999 trap_uninstall "$@"
7d4cbae0
PM
1000 fi
1001}
1002
1003__icmp_capture_add_del()
1004{
1005 local add_del=$1; shift
1006 local pref=$1; shift
1007 local vsuf=$1; shift
1008 local tundev=$1; shift
1009 local filter=$1; shift
1010
1011 tc filter $add_del dev "$tundev" ingress \
1012 proto ip$vsuf pref $pref \
1013 flower ip_proto icmp$vsuf $filter \
1014 action pass
1015}
1016
1017icmp_capture_install()
1018{
1019 __icmp_capture_add_del add 100 "" "$@"
1020}
1021
1022icmp_capture_uninstall()
1023{
1024 __icmp_capture_add_del del 100 "" "$@"
1025}
1026
1027icmp6_capture_install()
1028{
1029 __icmp_capture_add_del add 100 v6 "$@"
1030}
1031
1032icmp6_capture_uninstall()
1033{
1034 __icmp_capture_add_del del 100 v6 "$@"
1035}
1036
2004a9bc
PM
1037__vlan_capture_add_del()
1038{
1039 local add_del=$1; shift
1040 local pref=$1; shift
1041 local dev=$1; shift
1042 local filter=$1; shift
1043
1044 tc filter $add_del dev "$dev" ingress \
1045 proto 802.1q pref $pref \
1046 flower $filter \
1047 action pass
1048}
1049
1050vlan_capture_install()
1051{
1052 __vlan_capture_add_del add 100 "$@"
1053}
1054
1055vlan_capture_uninstall()
1056{
1057 __vlan_capture_add_del del 100 "$@"
1058}
1059
cf608698
PM
1060__dscp_capture_add_del()
1061{
1062 local add_del=$1; shift
1063 local dev=$1; shift
1064 local base=$1; shift
1065 local dscp;
1066
1067 for prio in {0..7}; do
1068 dscp=$((base + prio))
1069 __icmp_capture_add_del $add_del $((dscp + 100)) "" $dev \
1070 "skip_hw ip_tos $((dscp << 2))"
1071 done
1072}
1073
1074dscp_capture_install()
1075{
1076 local dev=$1; shift
1077 local base=$1; shift
1078
1079 __dscp_capture_add_del add $dev $base
1080}
1081
1082dscp_capture_uninstall()
1083{
1084 local dev=$1; shift
1085 local base=$1; shift
1086
1087 __dscp_capture_add_del del $dev $base
1088}
1089
1090dscp_fetch_stats()
1091{
1092 local dev=$1; shift
1093 local base=$1; shift
1094
1095 for prio in {0..7}; do
1096 local dscp=$((base + prio))
1097 local t=$(tc_rule_stats_get $dev $((dscp + 100)))
1098 echo "[$dscp]=$t "
1099 done
1100}
1101
7d4cbae0
PM
1102matchall_sink_create()
1103{
1104 local dev=$1; shift
1105
1106 tc qdisc add dev $dev clsact
1107 tc filter add dev $dev ingress \
1108 pref 10000 \
1109 matchall \
1110 action drop
1111}
1112
0eb8053c
IS
1113tests_run()
1114{
1115 local current_test
1116
1117 for current_test in ${TESTS:-$ALL_TESTS}; do
1118 $current_test
1119 done
1120}
1121
b2c47872
PM
1122multipath_eval()
1123{
1b86fa3b
PM
1124 local desc="$1"
1125 local weight_rp12=$2
1126 local weight_rp13=$3
1127 local packets_rp12=$4
1128 local packets_rp13=$5
1129 local weights_ratio packets_ratio diff
1130
1131 RET=0
1132
1133 if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
1134 weights_ratio=$(echo "scale=2; $weight_rp12 / $weight_rp13" \
1135 | bc -l)
1136 else
1137 weights_ratio=$(echo "scale=2; $weight_rp13 / $weight_rp12" \
1138 | bc -l)
1139 fi
1140
1141 if [[ "$packets_rp12" -eq "0" || "$packets_rp13" -eq "0" ]]; then
1142 check_err 1 "Packet difference is 0"
1143 log_test "Multipath"
1144 log_info "Expected ratio $weights_ratio"
1145 return
1146 fi
1147
1148 if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
1149 packets_ratio=$(echo "scale=2; $packets_rp12 / $packets_rp13" \
1150 | bc -l)
1151 else
1152 packets_ratio=$(echo "scale=2; $packets_rp13 / $packets_rp12" \
1153 | bc -l)
1154 fi
1155
1156 diff=$(echo $weights_ratio - $packets_ratio | bc -l)
1157 diff=${diff#-}
1158
1159 test "$(echo "$diff / $weights_ratio > 0.15" | bc -l)" -eq 0
1160 check_err $? "Too large discrepancy between expected and measured ratios"
1161 log_test "$desc"
1162 log_info "Expected ratio $weights_ratio Measured ratio $packets_ratio"
b2c47872
PM
1163}
1164
d0540d17
PM
1165in_ns()
1166{
1167 local name=$1; shift
1168
1169 ip netns exec $name bash <<-EOF
1170 NUM_NETIFS=0
1171 source lib.sh
1172 $(for a in "$@"; do printf "%q${IFS:0:1}" "$a"; done)
1173 EOF
1174}
1175
73bae673
IS
1176##############################################################################
1177# Tests
1178
967450c5 1179ping_do()
73bae673
IS
1180{
1181 local if_name=$1
1182 local dip=$2
d20b0f21 1183 local args=$3
73bae673
IS
1184 local vrf_name
1185
73bae673 1186 vrf_name=$(master_name_get $if_name)
b6a4fd68 1187 ip vrf exec $vrf_name \
0cd0b1f7
AC
1188 $PING $args $dip -c $PING_COUNT -i 0.1 \
1189 -w $PING_TIMEOUT &> /dev/null
967450c5
NA
1190}
1191
1192ping_test()
1193{
1194 RET=0
1195
1196 ping_do $1 $2
73bae673 1197 check_err $?
58c7a2d1 1198 log_test "ping$3"
73bae673
IS
1199}
1200
967450c5 1201ping6_do()
73bae673
IS
1202{
1203 local if_name=$1
1204 local dip=$2
d20b0f21 1205 local args=$3
73bae673
IS
1206 local vrf_name
1207
73bae673 1208 vrf_name=$(master_name_get $if_name)
b6a4fd68 1209 ip vrf exec $vrf_name \
0cd0b1f7
AC
1210 $PING6 $args $dip -c $PING_COUNT -i 0.1 \
1211 -w $PING_TIMEOUT &> /dev/null
967450c5
NA
1212}
1213
1214ping6_test()
1215{
1216 RET=0
1217
1218 ping6_do $1 $2
73bae673 1219 check_err $?
58c7a2d1 1220 log_test "ping6$3"
73bae673 1221}
d4deb014
IS
1222
1223learning_test()
1224{
1225 local bridge=$1
1226 local br_port1=$2 # Connected to `host1_if`.
1227 local host1_if=$3
1228 local host2_if=$4
1229 local mac=de:ad:be:ef:13:37
1230 local ageing_time
1231
1232 RET=0
1233
1234 bridge -j fdb show br $bridge brport $br_port1 \
1235 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1236 check_fail $? "Found FDB record when should not"
1237
1238 # Disable unknown unicast flooding on `br_port1` to make sure
1239 # packets are only forwarded through the port after a matching
1240 # FDB entry was installed.
1241 bridge link set dev $br_port1 flood off
1242
1a635d3e 1243 ip link set $host1_if promisc on
d4deb014
IS
1244 tc qdisc add dev $host1_if ingress
1245 tc filter add dev $host1_if ingress protocol ip pref 1 handle 101 \
1246 flower dst_mac $mac action drop
1247
1248 $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q
1249 sleep 1
1250
1251 tc -j -s filter show dev $host1_if ingress \
1252 | jq -e ".[] | select(.options.handle == 101) \
1253 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
83844aac 1254 check_fail $? "Packet reached first host when should not"
d4deb014
IS
1255
1256 $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
1257 sleep 1
1258
1259 bridge -j fdb show br $bridge brport $br_port1 \
1260 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1261 check_err $? "Did not find FDB record when should"
1262
1263 $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q
1264 sleep 1
1265
1266 tc -j -s filter show dev $host1_if ingress \
1267 | jq -e ".[] | select(.options.handle == 101) \
1268 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1269 check_err $? "Packet did not reach second host when should"
1270
1271 # Wait for 10 seconds after the ageing time to make sure FDB
1272 # record was aged-out.
1273 ageing_time=$(bridge_ageing_time_get $bridge)
1274 sleep $((ageing_time + 10))
1275
1276 bridge -j fdb show br $bridge brport $br_port1 \
1277 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1278 check_fail $? "Found FDB record when should not"
1279
1280 bridge link set dev $br_port1 learning off
1281
1282 $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
1283 sleep 1
1284
1285 bridge -j fdb show br $bridge brport $br_port1 \
1286 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1287 check_fail $? "Found FDB record when should not"
1288
1289 bridge link set dev $br_port1 learning on
1290
1291 tc filter del dev $host1_if ingress protocol ip pref 1 handle 101 flower
1292 tc qdisc del dev $host1_if ingress
1a635d3e 1293 ip link set $host1_if promisc off
d4deb014
IS
1294
1295 bridge link set dev $br_port1 flood on
1296
1297 log_test "FDB learning"
1298}
236dd50b
IS
1299
1300flood_test_do()
1301{
1302 local should_flood=$1
1303 local mac=$2
1304 local ip=$3
1305 local host1_if=$4
1306 local host2_if=$5
1307 local err=0
1308
1309 # Add an ACL on `host2_if` which will tell us whether the packet
1310 # was flooded to it or not.
b8e629b0 1311 ip link set $host2_if promisc on
236dd50b
IS
1312 tc qdisc add dev $host2_if ingress
1313 tc filter add dev $host2_if ingress protocol ip pref 1 handle 101 \
1314 flower dst_mac $mac action drop
1315
1316 $MZ $host1_if -c 1 -p 64 -b $mac -B $ip -t ip -q
1317 sleep 1
1318
1319 tc -j -s filter show dev $host2_if ingress \
1320 | jq -e ".[] | select(.options.handle == 101) \
1321 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1322 if [[ $? -ne 0 && $should_flood == "true" || \
1323 $? -eq 0 && $should_flood == "false" ]]; then
1324 err=1
1325 fi
1326
1327 tc filter del dev $host2_if ingress protocol ip pref 1 handle 101 flower
1328 tc qdisc del dev $host2_if ingress
b8e629b0 1329 ip link set $host2_if promisc off
236dd50b
IS
1330
1331 return $err
1332}
1333
1334flood_unicast_test()
1335{
1336 local br_port=$1
1337 local host1_if=$2
1338 local host2_if=$3
1339 local mac=de:ad:be:ef:13:37
1340 local ip=192.0.2.100
1341
1342 RET=0
1343
1344 bridge link set dev $br_port flood off
1345
1346 flood_test_do false $mac $ip $host1_if $host2_if
1347 check_err $? "Packet flooded when should not"
1348
1349 bridge link set dev $br_port flood on
1350
1351 flood_test_do true $mac $ip $host1_if $host2_if
1352 check_err $? "Packet was not flooded when should"
1353
1354 log_test "Unknown unicast flood"
1355}
1356
1357flood_multicast_test()
1358{
1359 local br_port=$1
1360 local host1_if=$2
1361 local host2_if=$3
1362 local mac=01:00:5e:00:00:01
1363 local ip=239.0.0.1
1364
1365 RET=0
1366
1367 bridge link set dev $br_port mcast_flood off
1368
1369 flood_test_do false $mac $ip $host1_if $host2_if
1370 check_err $? "Packet flooded when should not"
1371
1372 bridge link set dev $br_port mcast_flood on
1373
1374 flood_test_do true $mac $ip $host1_if $host2_if
1375 check_err $? "Packet was not flooded when should"
1376
1377 log_test "Unregistered multicast flood"
1378}
1379
1380flood_test()
1381{
1382 # `br_port` is connected to `host2_if`
1383 local br_port=$1
1384 local host1_if=$2
1385 local host2_if=$3
1386
1387 flood_unicast_test $br_port $host1_if $host2_if
1388 flood_multicast_test $br_port $host1_if $host2_if
1389}
4cf9b8f9 1390
4113b048 1391__start_traffic()
4cf9b8f9 1392{
1531cc63 1393 local pktsize=$1; shift
4113b048 1394 local proto=$1; shift
4cf9b8f9
PM
1395 local h_in=$1; shift # Where the traffic egresses the host
1396 local sip=$1; shift
1397 local dip=$1; shift
1398 local dmac=$1; shift
1399
1531cc63 1400 $MZ $h_in -p $pktsize -A $sip -B $dip -c 0 \
4113b048 1401 -a own -b $dmac -t "$proto" -q "$@" &
4cf9b8f9
PM
1402 sleep 1
1403}
1404
1531cc63
PM
1405start_traffic_pktsize()
1406{
1407 local pktsize=$1; shift
1408
1409 __start_traffic $pktsize udp "$@"
1410}
1411
1412start_tcp_traffic_pktsize()
1413{
1414 local pktsize=$1; shift
1415
1416 __start_traffic $pktsize tcp "$@"
1417}
1418
4113b048
PM
1419start_traffic()
1420{
1531cc63 1421 start_traffic_pktsize 8000 "$@"
4113b048
PM
1422}
1423
1424start_tcp_traffic()
1425{
1531cc63 1426 start_tcp_traffic_pktsize 8000 "$@"
4113b048
PM
1427}
1428
4cf9b8f9
PM
1429stop_traffic()
1430{
1431 # Suppress noise from killing mausezahn.
1432 { kill %% && wait %%; } 2>/dev/null
1433}
8cd6b020 1434
6182c5c5
JW
1435declare -A cappid
1436declare -A capfile
1437declare -A capout
1438
8cd6b020
VO
1439tcpdump_start()
1440{
1441 local if_name=$1; shift
1442 local ns=$1; shift
1443
6182c5c5
JW
1444 capfile[$if_name]=$(mktemp)
1445 capout[$if_name]=$(mktemp)
8cd6b020
VO
1446
1447 if [ -z $ns ]; then
1448 ns_cmd=""
1449 else
1450 ns_cmd="ip netns exec ${ns}"
1451 fi
1452
1453 if [ -z $SUDO_USER ] ; then
1454 capuser=""
1455 else
1456 capuser="-Z $SUDO_USER"
1457 fi
1458
fe32dffd 1459 $ns_cmd tcpdump $TCPDUMP_EXTRA_FLAGS -e -n -Q in -i $if_name \
6182c5c5
JW
1460 -s 65535 -B 32768 $capuser -w ${capfile[$if_name]} \
1461 > "${capout[$if_name]}" 2>&1 &
1462 cappid[$if_name]=$!
8cd6b020
VO
1463
1464 sleep 1
1465}
1466
1467tcpdump_stop()
1468{
6182c5c5
JW
1469 local if_name=$1
1470 local pid=${cappid[$if_name]}
1471
1472 $ns_cmd kill "$pid" && wait "$pid"
8cd6b020
VO
1473 sleep 1
1474}
1475
1476tcpdump_cleanup()
1477{
6182c5c5
JW
1478 local if_name=$1
1479
1480 rm ${capfile[$if_name]} ${capout[$if_name]}
8cd6b020
VO
1481}
1482
1483tcpdump_show()
1484{
6182c5c5
JW
1485 local if_name=$1
1486
1487 tcpdump -e -n -r ${capfile[$if_name]} 2>&1
8cd6b020 1488}
537e4825
NA
1489
1490# return 0 if the packet wasn't seen on host2_if or 1 if it was
1491mcast_packet_test()
1492{
1493 local mac=$1
1494 local src_ip=$2
1495 local ip=$3
1496 local host1_if=$4
1497 local host2_if=$5
1498 local seen=0
450b0b84
NA
1499 local tc_proto="ip"
1500 local mz_v6arg=""
1501
1502 # basic check to see if we were passed an IPv4 address, if not assume IPv6
1503 if [[ ! $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
1504 tc_proto="ipv6"
1505 mz_v6arg="-6"
1506 fi
537e4825
NA
1507
1508 # Add an ACL on `host2_if` which will tell us whether the packet
1509 # was received by it or not.
1510 tc qdisc add dev $host2_if ingress
450b0b84 1511 tc filter add dev $host2_if ingress protocol $tc_proto pref 1 handle 101 \
537e4825
NA
1512 flower ip_proto udp dst_mac $mac action drop
1513
450b0b84 1514 $MZ $host1_if $mz_v6arg -c 1 -p 64 -b $mac -A $src_ip -B $ip -t udp "dp=4096,sp=2048" -q
537e4825
NA
1515 sleep 1
1516
1517 tc -j -s filter show dev $host2_if ingress \
1518 | jq -e ".[] | select(.options.handle == 101) \
1519 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1520 if [[ $? -eq 0 ]]; then
1521 seen=1
1522 fi
1523
450b0b84 1524 tc filter del dev $host2_if ingress protocol $tc_proto pref 1 handle 101 flower
537e4825
NA
1525 tc qdisc del dev $host2_if ingress
1526
1527 return $seen
1528}
95e6f430
NA
1529
1530brmcast_check_sg_entries()
1531{
1532 local report=$1; shift
1533 local slist=("$@")
1534 local sarg=""
1535
1536 for src in "${slist[@]}"; do
1537 sarg="${sarg} and .source_list[].address == \"$src\""
1538 done
1539 bridge -j -d -s mdb show dev br0 \
1540 | jq -e ".[].mdb[] | \
1541 select(.grp == \"$TEST_GROUP\" and .source_list != null $sarg)" &>/dev/null
1542 check_err $? "Wrong *,G entry source list after $report report"
1543
1544 for sgent in "${slist[@]}"; do
1545 bridge -j -d -s mdb show dev br0 \
1546 | jq -e ".[].mdb[] | \
1547 select(.grp == \"$TEST_GROUP\" and .src == \"$sgent\")" &>/dev/null
1548 check_err $? "Missing S,G entry ($sgent, $TEST_GROUP)"
1549 done
1550}
1551
1552brmcast_check_sg_fwding()
1553{
1554 local should_fwd=$1; shift
1555 local sources=("$@")
1556
1557 for src in "${sources[@]}"; do
1558 local retval=0
1559
1560 mcast_packet_test $TEST_GROUP_MAC $src $TEST_GROUP $h2 $h1
1561 retval=$?
1562 if [ $should_fwd -eq 1 ]; then
1563 check_fail $retval "Didn't forward traffic from S,G ($src, $TEST_GROUP)"
1564 else
1565 check_err $retval "Forwarded traffic for blocked S,G ($src, $TEST_GROUP)"
1566 fi
1567 done
1568}
1569
1570brmcast_check_sg_state()
1571{
1572 local is_blocked=$1; shift
1573 local sources=("$@")
1574 local should_fail=1
1575
1576 if [ $is_blocked -eq 1 ]; then
1577 should_fail=0
1578 fi
1579
1580 for src in "${sources[@]}"; do
1581 bridge -j -d -s mdb show dev br0 \
1582 | jq -e ".[].mdb[] | \
1583 select(.grp == \"$TEST_GROUP\" and .source_list != null) |
1584 .source_list[] |
1585 select(.address == \"$src\") |
1586 select(.timer == \"0.00\")" &>/dev/null
1587 check_err_fail $should_fail $? "Entry $src has zero timer"
1588
1589 bridge -j -d -s mdb show dev br0 \
1590 | jq -e ".[].mdb[] | \
1591 select(.grp == \"$TEST_GROUP\" and .src == \"$src\" and \
1592 .flags[] == \"blocked\")" &>/dev/null
1593 check_err_fail $should_fail $? "Entry $src has blocked flag"
1594 done
1595}
9b18942e 1596
f23cddc7
VO
1597mc_join()
1598{
1599 local if_name=$1
1600 local group=$2
1601 local vrf_name=$(master_name_get $if_name)
1602
1603 # We don't care about actual reception, just about joining the
1604 # IP multicast group and adding the L2 address to the device's
1605 # MAC filtering table
1606 ip vrf exec $vrf_name \
1607 mreceive -g $group -I $if_name > /dev/null 2>&1 &
1608 mreceive_pid=$!
1609
1610 sleep 1
1611}
1612
1613mc_leave()
1614{
1615 kill "$mreceive_pid" && wait "$mreceive_pid"
1616}
1617
1618mc_send()
1619{
1620 local if_name=$1
1621 local groups=$2
1622 local vrf_name=$(master_name_get $if_name)
1623
1624 ip vrf exec $vrf_name \
1625 msend -g $groups -I $if_name -c 1 > /dev/null 2>&1
1626}
1627
9b18942e
PM
1628start_ip_monitor()
1629{
1630 local mtype=$1; shift
1631 local ip=${1-ip}; shift
1632
1633 # start the monitor in the background
1634 tmpfile=`mktemp /var/run/nexthoptestXXX`
1635 mpid=`($ip monitor $mtype > $tmpfile & echo $!) 2>/dev/null`
1636 sleep 0.2
1637 echo "$mpid $tmpfile"
1638}
1639
1640stop_ip_monitor()
1641{
1642 local mpid=$1; shift
1643 local tmpfile=$1; shift
1644 local el=$1; shift
1645 local what=$1; shift
1646
1647 sleep 0.2
1648 kill $mpid
1649 local lines=`grep '^\w' $tmpfile | wc -l`
1650 test $lines -eq $el
1651 check_err $? "$what: $lines lines of events, expected $el"
1652 rm -rf $tmpfile
1653}
1654
1655hw_stats_monitor_test()
1656{
1657 local dev=$1; shift
1658 local type=$1; shift
1659 local make_suitable=$1; shift
1660 local make_unsuitable=$1; shift
1661 local ip=${1-ip}; shift
1662
1663 RET=0
1664
1665 # Expect a notification about enablement.
1666 local ipmout=$(start_ip_monitor stats "$ip")
1667 $ip stats set dev $dev ${type}_stats on
1668 stop_ip_monitor $ipmout 1 "${type}_stats enablement"
1669
1670 # Expect a notification about offload.
1671 local ipmout=$(start_ip_monitor stats "$ip")
1672 $make_suitable
1673 stop_ip_monitor $ipmout 1 "${type}_stats installation"
1674
1675 # Expect a notification about loss of offload.
1676 local ipmout=$(start_ip_monitor stats "$ip")
1677 $make_unsuitable
1678 stop_ip_monitor $ipmout 1 "${type}_stats deinstallation"
1679
1680 # Expect a notification about disablement
1681 local ipmout=$(start_ip_monitor stats "$ip")
1682 $ip stats set dev $dev ${type}_stats off
1683 stop_ip_monitor $ipmout 1 "${type}_stats disablement"
1684
1685 log_test "${type}_stats notifications"
1686}