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