]> Git Repo - J-linux.git/blob - tools/testing/selftests/net/forwarding/lib.sh
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / tools / testing / selftests / net / forwarding / lib.sh
1 #!/bin/bash
2 # SPDX-License-Identifier: GPL-2.0
3
4 ##############################################################################
5 # Topology description. p1 looped back to p2, p3 to p4 and so on.
6
7 declare -A NETIFS=(
8     [p1]=veth0
9     [p2]=veth1
10     [p3]=veth2
11     [p4]=veth3
12     [p5]=veth4
13     [p6]=veth5
14     [p7]=veth6
15     [p8]=veth7
16     [p9]=veth8
17     [p10]=veth9
18 )
19
20 # Port that does not have a cable connected.
21 : "${NETIF_NO_CABLE:=eth8}"
22
23 ##############################################################################
24 # Defines
25
26 # Networking utilities.
27 : "${PING:=ping}"
28 : "${PING6:=ping6}"     # Some distros just use ping.
29 : "${ARPING:=arping}"
30 : "${TROUTE6:=traceroute6}"
31
32 # Packet generator.
33 : "${MZ:=mausezahn}"    # Some distributions use 'mz'.
34 : "${MZ_DELAY:=0}"
35
36 # Host configuration tools.
37 : "${TEAMD:=teamd}"
38 : "${MCD:=smcrouted}"
39 : "${MC_CLI:=smcroutectl}"
40
41 # Constants for netdevice bring-up:
42 # Default time in seconds to wait for an interface to come up before giving up
43 # and bailing out. Used during initial setup.
44 : "${INTERFACE_TIMEOUT:=600}"
45 # Like INTERFACE_TIMEOUT, but default for ad-hoc waiting in testing scripts.
46 : "${WAIT_TIMEOUT:=20}"
47 # Time to wait after interfaces participating in the test are all UP.
48 : "${WAIT_TIME:=5}"
49
50 # Whether to pause on, respectively, after a failure and before cleanup.
51 : "${PAUSE_ON_CLEANUP:=no}"
52
53 # Whether to create virtual interfaces, and what netdevice type they should be.
54 : "${NETIF_CREATE:=yes}"
55 : "${NETIF_TYPE:=veth}"
56
57 # Constants for ping tests:
58 # How many packets should be sent.
59 : "${PING_COUNT:=10}"
60 # Timeout (in seconds) before ping exits regardless of how many packets have
61 # been sent or received
62 : "${PING_TIMEOUT:=5}"
63
64 # Minimum ageing_time (in centiseconds) supported by hardware
65 : "${LOW_AGEING_TIME:=1000}"
66
67 # Whether to check for availability of certain tools.
68 : "${REQUIRE_JQ:=yes}"
69 : "${REQUIRE_MZ:=yes}"
70 : "${REQUIRE_MTOOLS:=no}"
71
72 # Whether to override MAC addresses on interfaces participating in the test.
73 : "${STABLE_MAC_ADDRS:=no}"
74
75 # Flags for tcpdump
76 : "${TCPDUMP_EXTRA_FLAGS:=}"
77
78 # Flags for TC filters.
79 : "${TC_FLAG:=skip_hw}"
80
81 # Whether the machine is "slow" -- i.e. might be incapable of running tests
82 # involving heavy traffic. This might be the case on a debug kernel, a VM, or
83 # e.g. a low-power board.
84 : "${KSFT_MACHINE_SLOW:=no}"
85
86 ##############################################################################
87 # Find netifs by test-specified driver name
88
89 driver_name_get()
90 {
91         local dev=$1; shift
92         local driver_path="/sys/class/net/$dev/device/driver"
93
94         if [[ -L $driver_path ]]; then
95                 basename `realpath $driver_path`
96         fi
97 }
98
99 netif_find_driver()
100 {
101         local ifnames=`ip -j link show | jq -r ".[].ifname"`
102         local count=0
103
104         for ifname in $ifnames
105         do
106                 local driver_name=`driver_name_get $ifname`
107                 if [[ ! -z $driver_name && $driver_name == $NETIF_FIND_DRIVER ]]; then
108                         count=$((count + 1))
109                         NETIFS[p$count]="$ifname"
110                 fi
111         done
112 }
113
114 # Whether to find netdevice according to the driver speficied by the importer
115 : "${NETIF_FIND_DRIVER:=}"
116
117 if [[ $NETIF_FIND_DRIVER ]]; then
118         unset NETIFS
119         declare -A NETIFS
120         netif_find_driver
121 fi
122
123 net_forwarding_dir=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")
124
125 if [[ -f $net_forwarding_dir/forwarding.config ]]; then
126         source "$net_forwarding_dir/forwarding.config"
127 fi
128
129 source "$net_forwarding_dir/../lib.sh"
130
131 ##############################################################################
132 # Sanity checks
133
134 check_tc_version()
135 {
136         tc -j &> /dev/null
137         if [[ $? -ne 0 ]]; then
138                 echo "SKIP: iproute2 too old; tc is missing JSON support"
139                 exit $ksft_skip
140         fi
141 }
142
143 # Old versions of tc don't understand "mpls_uc"
144 check_tc_mpls_support()
145 {
146         local dev=$1; shift
147
148         tc filter add dev $dev ingress protocol mpls_uc pref 1 handle 1 \
149                 matchall action pipe &> /dev/null
150         if [[ $? -ne 0 ]]; then
151                 echo "SKIP: iproute2 too old; tc is missing MPLS support"
152                 return $ksft_skip
153         fi
154         tc filter del dev $dev ingress protocol mpls_uc pref 1 handle 1 \
155                 matchall
156 }
157
158 # Old versions of tc produce invalid json output for mpls lse statistics
159 check_tc_mpls_lse_stats()
160 {
161         local dev=$1; shift
162         local ret;
163
164         tc filter add dev $dev ingress protocol mpls_uc pref 1 handle 1 \
165                 flower mpls lse depth 2                                 \
166                 action continue &> /dev/null
167
168         if [[ $? -ne 0 ]]; then
169                 echo "SKIP: iproute2 too old; tc-flower is missing extended MPLS support"
170                 return $ksft_skip
171         fi
172
173         tc -j filter show dev $dev ingress protocol mpls_uc | jq . &> /dev/null
174         ret=$?
175         tc filter del dev $dev ingress protocol mpls_uc pref 1 handle 1 \
176                 flower
177
178         if [[ $ret -ne 0 ]]; then
179                 echo "SKIP: iproute2 too old; tc-flower produces invalid json output for extended MPLS filters"
180                 return $ksft_skip
181         fi
182 }
183
184 check_tc_shblock_support()
185 {
186         tc filter help 2>&1 | grep block &> /dev/null
187         if [[ $? -ne 0 ]]; then
188                 echo "SKIP: iproute2 too old; tc is missing shared block support"
189                 exit $ksft_skip
190         fi
191 }
192
193 check_tc_chain_support()
194 {
195         tc help 2>&1|grep chain &> /dev/null
196         if [[ $? -ne 0 ]]; then
197                 echo "SKIP: iproute2 too old; tc is missing chain support"
198                 exit $ksft_skip
199         fi
200 }
201
202 check_tc_action_hw_stats_support()
203 {
204         tc actions help 2>&1 | grep -q hw_stats
205         if [[ $? -ne 0 ]]; then
206                 echo "SKIP: iproute2 too old; tc is missing action hw_stats support"
207                 exit $ksft_skip
208         fi
209 }
210
211 check_tc_fp_support()
212 {
213         tc qdisc add dev lo mqprio help 2>&1 | grep -q "fp "
214         if [[ $? -ne 0 ]]; then
215                 echo "SKIP: iproute2 too old; tc is missing frame preemption support"
216                 exit $ksft_skip
217         fi
218 }
219
220 check_ethtool_lanes_support()
221 {
222         ethtool --help 2>&1| grep lanes &> /dev/null
223         if [[ $? -ne 0 ]]; then
224                 echo "SKIP: ethtool too old; it is missing lanes support"
225                 exit $ksft_skip
226         fi
227 }
228
229 check_ethtool_mm_support()
230 {
231         ethtool --help 2>&1| grep -- '--show-mm' &> /dev/null
232         if [[ $? -ne 0 ]]; then
233                 echo "SKIP: ethtool too old; it is missing MAC Merge layer support"
234                 exit $ksft_skip
235         fi
236 }
237
238 check_ethtool_counter_group_support()
239 {
240         ethtool --help 2>&1| grep -- '--all-groups' &> /dev/null
241         if [[ $? -ne 0 ]]; then
242                 echo "SKIP: ethtool too old; it is missing standard counter group support"
243                 exit $ksft_skip
244         fi
245 }
246
247 check_ethtool_pmac_std_stats_support()
248 {
249         local dev=$1; shift
250         local grp=$1; shift
251
252         [ 0 -ne $(ethtool --json -S $dev --all-groups --src pmac 2>/dev/null \
253                 | jq ".[].\"$grp\" | length") ]
254 }
255
256 check_locked_port_support()
257 {
258         if ! bridge -d link show | grep -q " locked"; then
259                 echo "SKIP: iproute2 too old; Locked port feature not supported."
260                 return $ksft_skip
261         fi
262 }
263
264 check_port_mab_support()
265 {
266         if ! bridge -d link show | grep -q "mab"; then
267                 echo "SKIP: iproute2 too old; MacAuth feature not supported."
268                 return $ksft_skip
269         fi
270 }
271
272 if [[ "$(id -u)" -ne 0 ]]; then
273         echo "SKIP: need root privileges"
274         exit $ksft_skip
275 fi
276
277 check_driver()
278 {
279         local dev=$1; shift
280         local expected=$1; shift
281         local driver_name=`driver_name_get $dev`
282
283         if [[ $driver_name != $expected ]]; then
284                 echo "SKIP: expected driver $expected for $dev, got $driver_name instead"
285                 exit $ksft_skip
286         fi
287 }
288
289 if [[ "$CHECK_TC" = "yes" ]]; then
290         check_tc_version
291 fi
292
293 require_command()
294 {
295         local cmd=$1; shift
296
297         if [[ ! -x "$(command -v "$cmd")" ]]; then
298                 echo "SKIP: $cmd not installed"
299                 exit $ksft_skip
300         fi
301 }
302
303 # IPv6 support was added in v3.0
304 check_mtools_version()
305 {
306         local version="$(msend -v)"
307         local major
308
309         version=${version##msend version }
310         major=$(echo $version | cut -d. -f1)
311
312         if [ $major -lt 3 ]; then
313                 echo "SKIP: expected mtools version 3.0, got $version"
314                 exit $ksft_skip
315         fi
316 }
317
318 if [[ "$REQUIRE_JQ" = "yes" ]]; then
319         require_command jq
320 fi
321 if [[ "$REQUIRE_MZ" = "yes" ]]; then
322         require_command $MZ
323 fi
324 if [[ "$REQUIRE_MTOOLS" = "yes" ]]; then
325         # https://github.com/troglobit/mtools
326         require_command msend
327         require_command mreceive
328         check_mtools_version
329 fi
330
331 ##############################################################################
332 # Command line options handling
333
334 count=0
335
336 while [[ $# -gt 0 ]]; do
337         if [[ "$count" -eq "0" ]]; then
338                 unset NETIFS
339                 declare -A NETIFS
340         fi
341         count=$((count + 1))
342         NETIFS[p$count]="$1"
343         shift
344 done
345
346 ##############################################################################
347 # Network interfaces configuration
348
349 if [[ ! -v NUM_NETIFS ]]; then
350         echo "SKIP: importer does not define \"NUM_NETIFS\""
351         exit $ksft_skip
352 fi
353
354 if (( NUM_NETIFS > ${#NETIFS[@]} )); then
355         echo "SKIP: Importer requires $NUM_NETIFS NETIFS, but only ${#NETIFS[@]} are defined (${NETIFS[@]})"
356         exit $ksft_skip
357 fi
358
359 for i in $(seq ${#NETIFS[@]}); do
360         if [[ ! ${NETIFS[p$i]} ]]; then
361                 echo "SKIP: NETIFS[p$i] not given"
362                 exit $ksft_skip
363         fi
364 done
365
366 create_netif_veth()
367 {
368         local i
369
370         for ((i = 1; i <= NUM_NETIFS; ++i)); do
371                 local j=$((i+1))
372
373                 if [ -z ${NETIFS[p$i]} ]; then
374                         echo "SKIP: Cannot create interface. Name not specified"
375                         exit $ksft_skip
376                 fi
377
378                 ip link show dev ${NETIFS[p$i]} &> /dev/null
379                 if [[ $? -ne 0 ]]; then
380                         ip link add ${NETIFS[p$i]} type veth \
381                                 peer name ${NETIFS[p$j]}
382                         if [[ $? -ne 0 ]]; then
383                                 echo "Failed to create netif"
384                                 exit 1
385                         fi
386                 fi
387                 i=$j
388         done
389 }
390
391 create_netif()
392 {
393         case "$NETIF_TYPE" in
394         veth) create_netif_veth
395               ;;
396         *) echo "Can not create interfaces of type \'$NETIF_TYPE\'"
397            exit 1
398            ;;
399         esac
400 }
401
402 declare -A MAC_ADDR_ORIG
403 mac_addr_prepare()
404 {
405         local new_addr=
406         local dev=
407
408         for ((i = 1; i <= NUM_NETIFS; ++i)); do
409                 dev=${NETIFS[p$i]}
410                 new_addr=$(printf "00:01:02:03:04:%02x" $i)
411
412                 MAC_ADDR_ORIG["$dev"]=$(ip -j link show dev $dev | jq -e '.[].address')
413                 # Strip quotes
414                 MAC_ADDR_ORIG["$dev"]=${MAC_ADDR_ORIG["$dev"]//\"/}
415                 ip link set dev $dev address $new_addr
416         done
417 }
418
419 mac_addr_restore()
420 {
421         local dev=
422
423         for ((i = 1; i <= NUM_NETIFS; ++i)); do
424                 dev=${NETIFS[p$i]}
425                 ip link set dev $dev address ${MAC_ADDR_ORIG["$dev"]}
426         done
427 }
428
429 if [[ "$NETIF_CREATE" = "yes" ]]; then
430         create_netif
431 fi
432
433 if [[ "$STABLE_MAC_ADDRS" = "yes" ]]; then
434         mac_addr_prepare
435 fi
436
437 for ((i = 1; i <= NUM_NETIFS; ++i)); do
438         ip link show dev ${NETIFS[p$i]} &> /dev/null
439         if [[ $? -ne 0 ]]; then
440                 echo "SKIP: could not find all required interfaces"
441                 exit $ksft_skip
442         fi
443 done
444
445 ##############################################################################
446 # Helpers
447
448 not()
449 {
450         "$@"
451         [[ $? != 0 ]]
452 }
453
454 get_max()
455 {
456         local arr=("$@")
457
458         max=${arr[0]}
459         for cur in ${arr[@]}; do
460                 if [[ $cur -gt $max ]]; then
461                         max=$cur
462                 fi
463         done
464
465         echo $max
466 }
467
468 grep_bridge_fdb()
469 {
470         local addr=$1; shift
471         local word
472         local flag
473
474         if [ "$1" == "self" ] || [ "$1" == "master" ]; then
475                 word=$1; shift
476                 if [ "$1" == "-v" ]; then
477                         flag=$1; shift
478                 fi
479         fi
480
481         $@ | grep $addr | grep $flag "$word"
482 }
483
484 wait_for_port_up()
485 {
486         "$@" | grep -q "Link detected: yes"
487 }
488
489 wait_for_offload()
490 {
491         "$@" | grep -q offload
492 }
493
494 wait_for_trap()
495 {
496         "$@" | grep -q trap
497 }
498
499 setup_wait_dev()
500 {
501         local dev=$1; shift
502         local wait_time=${1:-$WAIT_TIME}; shift
503
504         setup_wait_dev_with_timeout "$dev" $INTERFACE_TIMEOUT $wait_time
505
506         if (($?)); then
507                 check_err 1
508                 log_test setup_wait_dev ": Interface $dev does not come up."
509                 exit 1
510         fi
511 }
512
513 setup_wait_dev_with_timeout()
514 {
515         local dev=$1; shift
516         local max_iterations=${1:-$WAIT_TIMEOUT}; shift
517         local wait_time=${1:-$WAIT_TIME}; shift
518         local i
519
520         for ((i = 1; i <= $max_iterations; ++i)); do
521                 ip link show dev $dev up \
522                         | grep 'state UP' &> /dev/null
523                 if [[ $? -ne 0 ]]; then
524                         sleep 1
525                 else
526                         sleep $wait_time
527                         return 0
528                 fi
529         done
530
531         return 1
532 }
533
534 setup_wait()
535 {
536         local num_netifs=${1:-$NUM_NETIFS}
537         local i
538
539         for ((i = 1; i <= num_netifs; ++i)); do
540                 setup_wait_dev ${NETIFS[p$i]} 0
541         done
542
543         # Make sure links are ready.
544         sleep $WAIT_TIME
545 }
546
547 wait_for_dev()
548 {
549         local dev=$1; shift
550         local timeout=${1:-$WAIT_TIMEOUT}; shift
551
552         slowwait $timeout ip link show dev $dev &> /dev/null
553         if (( $? )); then
554                 check_err 1
555                 log_test wait_for_dev "Interface $dev did not appear."
556                 exit $EXIT_STATUS
557         fi
558 }
559
560 cmd_jq()
561 {
562         local cmd=$1
563         local jq_exp=$2
564         local jq_opts=$3
565         local ret
566         local output
567
568         output="$($cmd)"
569         # it the command fails, return error right away
570         ret=$?
571         if [[ $ret -ne 0 ]]; then
572                 return $ret
573         fi
574         output=$(echo $output | jq -r $jq_opts "$jq_exp")
575         ret=$?
576         if [[ $ret -ne 0 ]]; then
577                 return $ret
578         fi
579         echo $output
580         # return success only in case of non-empty output
581         [ ! -z "$output" ]
582 }
583
584 pre_cleanup()
585 {
586         if [ "${PAUSE_ON_CLEANUP}" = "yes" ]; then
587                 echo "Pausing before cleanup, hit any key to continue"
588                 read
589         fi
590
591         if [[ "$STABLE_MAC_ADDRS" = "yes" ]]; then
592                 mac_addr_restore
593         fi
594 }
595
596 vrf_prepare()
597 {
598         ip -4 rule add pref 32765 table local
599         ip -4 rule del pref 0
600         ip -6 rule add pref 32765 table local
601         ip -6 rule del pref 0
602 }
603
604 vrf_cleanup()
605 {
606         ip -6 rule add pref 0 table local
607         ip -6 rule del pref 32765
608         ip -4 rule add pref 0 table local
609         ip -4 rule del pref 32765
610 }
611
612 __last_tb_id=0
613 declare -A __TB_IDS
614
615 __vrf_td_id_assign()
616 {
617         local vrf_name=$1
618
619         __last_tb_id=$((__last_tb_id + 1))
620         __TB_IDS[$vrf_name]=$__last_tb_id
621         return $__last_tb_id
622 }
623
624 __vrf_td_id_lookup()
625 {
626         local vrf_name=$1
627
628         return ${__TB_IDS[$vrf_name]}
629 }
630
631 vrf_create()
632 {
633         local vrf_name=$1
634         local tb_id
635
636         __vrf_td_id_assign $vrf_name
637         tb_id=$?
638
639         ip link add dev $vrf_name type vrf table $tb_id
640         ip -4 route add table $tb_id unreachable default metric 4278198272
641         ip -6 route add table $tb_id unreachable default metric 4278198272
642 }
643
644 vrf_destroy()
645 {
646         local vrf_name=$1
647         local tb_id
648
649         __vrf_td_id_lookup $vrf_name
650         tb_id=$?
651
652         ip -6 route del table $tb_id unreachable default metric 4278198272
653         ip -4 route del table $tb_id unreachable default metric 4278198272
654         ip link del dev $vrf_name
655 }
656
657 __addr_add_del()
658 {
659         local if_name=$1
660         local add_del=$2
661         local array
662
663         shift
664         shift
665         array=("${@}")
666
667         for addrstr in "${array[@]}"; do
668                 ip address $add_del $addrstr dev $if_name
669         done
670 }
671
672 __simple_if_init()
673 {
674         local if_name=$1; shift
675         local vrf_name=$1; shift
676         local addrs=("${@}")
677
678         ip link set dev $if_name master $vrf_name
679         ip link set dev $if_name up
680
681         __addr_add_del $if_name add "${addrs[@]}"
682 }
683
684 __simple_if_fini()
685 {
686         local if_name=$1; shift
687         local addrs=("${@}")
688
689         __addr_add_del $if_name del "${addrs[@]}"
690
691         ip link set dev $if_name down
692         ip link set dev $if_name nomaster
693 }
694
695 simple_if_init()
696 {
697         local if_name=$1
698         local vrf_name
699         local array
700
701         shift
702         vrf_name=v$if_name
703         array=("${@}")
704
705         vrf_create $vrf_name
706         ip link set dev $vrf_name up
707         __simple_if_init $if_name $vrf_name "${array[@]}"
708 }
709
710 simple_if_fini()
711 {
712         local if_name=$1
713         local vrf_name
714         local array
715
716         shift
717         vrf_name=v$if_name
718         array=("${@}")
719
720         __simple_if_fini $if_name "${array[@]}"
721         vrf_destroy $vrf_name
722 }
723
724 tunnel_create()
725 {
726         local name=$1; shift
727         local type=$1; shift
728         local local=$1; shift
729         local remote=$1; shift
730
731         ip link add name $name type $type \
732            local $local remote $remote "$@"
733         ip link set dev $name up
734 }
735
736 tunnel_destroy()
737 {
738         local name=$1; shift
739
740         ip link del dev $name
741 }
742
743 vlan_create()
744 {
745         local if_name=$1; shift
746         local vid=$1; shift
747         local vrf=$1; shift
748         local ips=("${@}")
749         local name=$if_name.$vid
750
751         ip link add name $name link $if_name type vlan id $vid
752         if [ "$vrf" != "" ]; then
753                 ip link set dev $name master $vrf
754         fi
755         ip link set dev $name up
756         __addr_add_del $name add "${ips[@]}"
757 }
758
759 vlan_destroy()
760 {
761         local if_name=$1; shift
762         local vid=$1; shift
763         local name=$if_name.$vid
764
765         ip link del dev $name
766 }
767
768 team_create()
769 {
770         local if_name=$1; shift
771         local mode=$1; shift
772
773         require_command $TEAMD
774         $TEAMD -t $if_name -d -c '{"runner": {"name": "'$mode'"}}'
775         for slave in "$@"; do
776                 ip link set dev $slave down
777                 ip link set dev $slave master $if_name
778                 ip link set dev $slave up
779         done
780         ip link set dev $if_name up
781 }
782
783 team_destroy()
784 {
785         local if_name=$1; shift
786
787         $TEAMD -t $if_name -k
788 }
789
790 master_name_get()
791 {
792         local if_name=$1
793
794         ip -j link show dev $if_name | jq -r '.[]["master"]'
795 }
796
797 link_stats_get()
798 {
799         local if_name=$1; shift
800         local dir=$1; shift
801         local stat=$1; shift
802
803         ip -j -s link show dev $if_name \
804                 | jq '.[]["stats64"]["'$dir'"]["'$stat'"]'
805 }
806
807 link_stats_tx_packets_get()
808 {
809         link_stats_get $1 tx packets
810 }
811
812 link_stats_rx_errors_get()
813 {
814         link_stats_get $1 rx errors
815 }
816
817 ethtool_stats_get()
818 {
819         local dev=$1; shift
820         local stat=$1; shift
821
822         ethtool -S $dev | grep "^ *$stat:" | head -n 1 | cut -d: -f2
823 }
824
825 ethtool_std_stats_get()
826 {
827         local dev=$1; shift
828         local grp=$1; shift
829         local name=$1; shift
830         local src=$1; shift
831
832         ethtool --json -S $dev --groups $grp -- --src $src | \
833                 jq '.[]."'"$grp"'"."'$name'"'
834 }
835
836 qdisc_stats_get()
837 {
838         local dev=$1; shift
839         local handle=$1; shift
840         local selector=$1; shift
841
842         tc -j -s qdisc show dev "$dev" \
843             | jq '.[] | select(.handle == "'"$handle"'") | '"$selector"
844 }
845
846 qdisc_parent_stats_get()
847 {
848         local dev=$1; shift
849         local parent=$1; shift
850         local selector=$1; shift
851
852         tc -j -s qdisc show dev "$dev" invisible \
853             | jq '.[] | select(.parent == "'"$parent"'") | '"$selector"
854 }
855
856 ipv6_stats_get()
857 {
858         local dev=$1; shift
859         local stat=$1; shift
860
861         cat /proc/net/dev_snmp6/$dev | grep "^$stat" | cut -f2
862 }
863
864 hw_stats_get()
865 {
866         local suite=$1; shift
867         local if_name=$1; shift
868         local dir=$1; shift
869         local stat=$1; shift
870
871         ip -j stats show dev $if_name group offload subgroup $suite |
872                 jq ".[0].stats64.$dir.$stat"
873 }
874
875 __nh_stats_get()
876 {
877         local key=$1; shift
878         local group_id=$1; shift
879         local member_id=$1; shift
880
881         ip -j -s -s nexthop show id $group_id |
882             jq --argjson member_id "$member_id" --arg key "$key" \
883                '.[].group_stats[] | select(.id == $member_id) | .[$key]'
884 }
885
886 nh_stats_get()
887 {
888         local group_id=$1; shift
889         local member_id=$1; shift
890
891         __nh_stats_get packets "$group_id" "$member_id"
892 }
893
894 nh_stats_get_hw()
895 {
896         local group_id=$1; shift
897         local member_id=$1; shift
898
899         __nh_stats_get packets_hw "$group_id" "$member_id"
900 }
901
902 humanize()
903 {
904         local speed=$1; shift
905
906         for unit in bps Kbps Mbps Gbps; do
907                 if (($(echo "$speed < 1024" | bc))); then
908                         break
909                 fi
910
911                 speed=$(echo "scale=1; $speed / 1024" | bc)
912         done
913
914         echo "$speed${unit}"
915 }
916
917 rate()
918 {
919         local t0=$1; shift
920         local t1=$1; shift
921         local interval=$1; shift
922
923         echo $((8 * (t1 - t0) / interval))
924 }
925
926 packets_rate()
927 {
928         local t0=$1; shift
929         local t1=$1; shift
930         local interval=$1; shift
931
932         echo $(((t1 - t0) / interval))
933 }
934
935 mac_get()
936 {
937         local if_name=$1
938
939         ip -j link show dev $if_name | jq -r '.[]["address"]'
940 }
941
942 ether_addr_to_u64()
943 {
944         local addr="$1"
945         local order="$((1 << 40))"
946         local val=0
947         local byte
948
949         addr="${addr//:/ }"
950
951         for byte in $addr; do
952                 byte="0x$byte"
953                 val=$((val + order * byte))
954                 order=$((order >> 8))
955         done
956
957         printf "0x%x" $val
958 }
959
960 u64_to_ether_addr()
961 {
962         local val=$1
963         local byte
964         local i
965
966         for ((i = 40; i >= 0; i -= 8)); do
967                 byte=$(((val & (0xff << i)) >> i))
968                 printf "%02x" $byte
969                 if [ $i -ne 0 ]; then
970                         printf ":"
971                 fi
972         done
973 }
974
975 ipv6_lladdr_get()
976 {
977         local if_name=$1
978
979         ip -j addr show dev $if_name | \
980                 jq -r '.[]["addr_info"][] | select(.scope == "link").local' | \
981                 head -1
982 }
983
984 bridge_ageing_time_get()
985 {
986         local bridge=$1
987         local ageing_time
988
989         # Need to divide by 100 to convert to seconds.
990         ageing_time=$(ip -j -d link show dev $bridge \
991                       | jq '.[]["linkinfo"]["info_data"]["ageing_time"]')
992         echo $((ageing_time / 100))
993 }
994
995 declare -A SYSCTL_ORIG
996 sysctl_save()
997 {
998         local key=$1; shift
999
1000         SYSCTL_ORIG[$key]=$(sysctl -n $key)
1001 }
1002
1003 sysctl_set()
1004 {
1005         local key=$1; shift
1006         local value=$1; shift
1007
1008         sysctl_save "$key"
1009         sysctl -qw $key="$value"
1010 }
1011
1012 sysctl_restore()
1013 {
1014         local key=$1; shift
1015
1016         sysctl -qw $key="${SYSCTL_ORIG[$key]}"
1017 }
1018
1019 forwarding_enable()
1020 {
1021         sysctl_set net.ipv4.conf.all.forwarding 1
1022         sysctl_set net.ipv6.conf.all.forwarding 1
1023 }
1024
1025 forwarding_restore()
1026 {
1027         sysctl_restore net.ipv6.conf.all.forwarding
1028         sysctl_restore net.ipv4.conf.all.forwarding
1029 }
1030
1031 declare -A MTU_ORIG
1032 mtu_set()
1033 {
1034         local dev=$1; shift
1035         local mtu=$1; shift
1036
1037         MTU_ORIG["$dev"]=$(ip -j link show dev $dev | jq -e '.[].mtu')
1038         ip link set dev $dev mtu $mtu
1039 }
1040
1041 mtu_restore()
1042 {
1043         local dev=$1; shift
1044
1045         ip link set dev $dev mtu ${MTU_ORIG["$dev"]}
1046 }
1047
1048 tc_offload_check()
1049 {
1050         local num_netifs=${1:-$NUM_NETIFS}
1051
1052         for ((i = 1; i <= num_netifs; ++i)); do
1053                 ethtool -k ${NETIFS[p$i]} \
1054                         | grep "hw-tc-offload: on" &> /dev/null
1055                 if [[ $? -ne 0 ]]; then
1056                         return 1
1057                 fi
1058         done
1059
1060         return 0
1061 }
1062
1063 trap_install()
1064 {
1065         local dev=$1; shift
1066         local direction=$1; shift
1067
1068         # Some devices may not support or need in-hardware trapping of traffic
1069         # (e.g. the veth pairs that this library creates for non-existent
1070         # loopbacks). Use continue instead, so that there is a filter in there
1071         # (some tests check counters), and so that other filters are still
1072         # processed.
1073         tc filter add dev $dev $direction pref 1 \
1074                 flower skip_sw action trap 2>/dev/null \
1075             || tc filter add dev $dev $direction pref 1 \
1076                        flower action continue
1077 }
1078
1079 trap_uninstall()
1080 {
1081         local dev=$1; shift
1082         local direction=$1; shift
1083
1084         tc filter del dev $dev $direction pref 1 flower
1085 }
1086
1087 __icmp_capture_add_del()
1088 {
1089         local add_del=$1; shift
1090         local pref=$1; shift
1091         local vsuf=$1; shift
1092         local tundev=$1; shift
1093         local filter=$1; shift
1094
1095         tc filter $add_del dev "$tundev" ingress \
1096            proto ip$vsuf pref $pref \
1097            flower ip_proto icmp$vsuf $filter \
1098            action pass
1099 }
1100
1101 icmp_capture_install()
1102 {
1103         local tundev=$1; shift
1104         local filter=$1; shift
1105
1106         __icmp_capture_add_del add 100 "" "$tundev" "$filter"
1107 }
1108
1109 icmp_capture_uninstall()
1110 {
1111         local tundev=$1; shift
1112         local filter=$1; shift
1113
1114         __icmp_capture_add_del del 100 "" "$tundev" "$filter"
1115 }
1116
1117 icmp6_capture_install()
1118 {
1119         local tundev=$1; shift
1120         local filter=$1; shift
1121
1122         __icmp_capture_add_del add 100 v6 "$tundev" "$filter"
1123 }
1124
1125 icmp6_capture_uninstall()
1126 {
1127         local tundev=$1; shift
1128         local filter=$1; shift
1129
1130         __icmp_capture_add_del del 100 v6 "$tundev" "$filter"
1131 }
1132
1133 __vlan_capture_add_del()
1134 {
1135         local add_del=$1; shift
1136         local pref=$1; shift
1137         local dev=$1; shift
1138         local filter=$1; shift
1139
1140         tc filter $add_del dev "$dev" ingress \
1141            proto 802.1q pref $pref \
1142            flower $filter \
1143            action pass
1144 }
1145
1146 vlan_capture_install()
1147 {
1148         local dev=$1; shift
1149         local filter=$1; shift
1150
1151         __vlan_capture_add_del add 100 "$dev" "$filter"
1152 }
1153
1154 vlan_capture_uninstall()
1155 {
1156         local dev=$1; shift
1157         local filter=$1; shift
1158
1159         __vlan_capture_add_del del 100 "$dev" "$filter"
1160 }
1161
1162 __dscp_capture_add_del()
1163 {
1164         local add_del=$1; shift
1165         local dev=$1; shift
1166         local base=$1; shift
1167         local dscp;
1168
1169         for prio in {0..7}; do
1170                 dscp=$((base + prio))
1171                 __icmp_capture_add_del $add_del $((dscp + 100)) "" $dev \
1172                                        "skip_hw ip_tos $((dscp << 2))"
1173         done
1174 }
1175
1176 dscp_capture_install()
1177 {
1178         local dev=$1; shift
1179         local base=$1; shift
1180
1181         __dscp_capture_add_del add $dev $base
1182 }
1183
1184 dscp_capture_uninstall()
1185 {
1186         local dev=$1; shift
1187         local base=$1; shift
1188
1189         __dscp_capture_add_del del $dev $base
1190 }
1191
1192 dscp_fetch_stats()
1193 {
1194         local dev=$1; shift
1195         local base=$1; shift
1196
1197         for prio in {0..7}; do
1198                 local dscp=$((base + prio))
1199                 local t=$(tc_rule_stats_get $dev $((dscp + 100)))
1200                 echo "[$dscp]=$t "
1201         done
1202 }
1203
1204 matchall_sink_create()
1205 {
1206         local dev=$1; shift
1207
1208         tc qdisc add dev $dev clsact
1209         tc filter add dev $dev ingress \
1210            pref 10000 \
1211            matchall \
1212            action drop
1213 }
1214
1215 cleanup()
1216 {
1217         pre_cleanup
1218         defer_scopes_cleanup
1219 }
1220
1221 multipath_eval()
1222 {
1223         local desc="$1"
1224         local weight_rp12=$2
1225         local weight_rp13=$3
1226         local packets_rp12=$4
1227         local packets_rp13=$5
1228         local weights_ratio packets_ratio diff
1229
1230         RET=0
1231
1232         if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
1233                 weights_ratio=$(echo "scale=2; $weight_rp12 / $weight_rp13" \
1234                                 | bc -l)
1235         else
1236                 weights_ratio=$(echo "scale=2; $weight_rp13 / $weight_rp12" \
1237                                 | bc -l)
1238         fi
1239
1240         if [[ "$packets_rp12" -eq "0" || "$packets_rp13" -eq "0" ]]; then
1241                check_err 1 "Packet difference is 0"
1242                log_test "Multipath"
1243                log_info "Expected ratio $weights_ratio"
1244                return
1245         fi
1246
1247         if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
1248                 packets_ratio=$(echo "scale=2; $packets_rp12 / $packets_rp13" \
1249                                 | bc -l)
1250         else
1251                 packets_ratio=$(echo "scale=2; $packets_rp13 / $packets_rp12" \
1252                                 | bc -l)
1253         fi
1254
1255         diff=$(echo $weights_ratio - $packets_ratio | bc -l)
1256         diff=${diff#-}
1257
1258         test "$(echo "$diff / $weights_ratio > 0.15" | bc -l)" -eq 0
1259         check_err $? "Too large discrepancy between expected and measured ratios"
1260         log_test "$desc"
1261         log_info "Expected ratio $weights_ratio Measured ratio $packets_ratio"
1262 }
1263
1264 in_ns()
1265 {
1266         local name=$1; shift
1267
1268         ip netns exec $name bash <<-EOF
1269                 NUM_NETIFS=0
1270                 source lib.sh
1271                 $(for a in "$@"; do printf "%q${IFS:0:1}" "$a"; done)
1272         EOF
1273 }
1274
1275 ##############################################################################
1276 # Tests
1277
1278 ping_do()
1279 {
1280         local if_name=$1
1281         local dip=$2
1282         local args=$3
1283         local vrf_name
1284
1285         vrf_name=$(master_name_get $if_name)
1286         ip vrf exec $vrf_name \
1287                 $PING $args $dip -c $PING_COUNT -i 0.1 \
1288                 -w $PING_TIMEOUT &> /dev/null
1289 }
1290
1291 ping_test()
1292 {
1293         RET=0
1294
1295         ping_do $1 $2
1296         check_err $?
1297         log_test "ping$3"
1298 }
1299
1300 ping_test_fails()
1301 {
1302         RET=0
1303
1304         ping_do $1 $2
1305         check_fail $?
1306         log_test "ping fails$3"
1307 }
1308
1309 ping6_do()
1310 {
1311         local if_name=$1
1312         local dip=$2
1313         local args=$3
1314         local vrf_name
1315
1316         vrf_name=$(master_name_get $if_name)
1317         ip vrf exec $vrf_name \
1318                 $PING6 $args $dip -c $PING_COUNT -i 0.1 \
1319                 -w $PING_TIMEOUT &> /dev/null
1320 }
1321
1322 ping6_test()
1323 {
1324         RET=0
1325
1326         ping6_do $1 $2
1327         check_err $?
1328         log_test "ping6$3"
1329 }
1330
1331 ping6_test_fails()
1332 {
1333         RET=0
1334
1335         ping6_do $1 $2
1336         check_fail $?
1337         log_test "ping6 fails$3"
1338 }
1339
1340 learning_test()
1341 {
1342         local bridge=$1
1343         local br_port1=$2       # Connected to `host1_if`.
1344         local host1_if=$3
1345         local host2_if=$4
1346         local mac=de:ad:be:ef:13:37
1347         local ageing_time
1348
1349         RET=0
1350
1351         bridge -j fdb show br $bridge brport $br_port1 \
1352                 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1353         check_fail $? "Found FDB record when should not"
1354
1355         # Disable unknown unicast flooding on `br_port1` to make sure
1356         # packets are only forwarded through the port after a matching
1357         # FDB entry was installed.
1358         bridge link set dev $br_port1 flood off
1359
1360         ip link set $host1_if promisc on
1361         tc qdisc add dev $host1_if ingress
1362         tc filter add dev $host1_if ingress protocol ip pref 1 handle 101 \
1363                 flower dst_mac $mac action drop
1364
1365         $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q
1366         sleep 1
1367
1368         tc -j -s filter show dev $host1_if ingress \
1369                 | jq -e ".[] | select(.options.handle == 101) \
1370                 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1371         check_fail $? "Packet reached first host when should not"
1372
1373         $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
1374         sleep 1
1375
1376         bridge -j fdb show br $bridge brport $br_port1 \
1377                 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1378         check_err $? "Did not find FDB record when should"
1379
1380         $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q
1381         sleep 1
1382
1383         tc -j -s filter show dev $host1_if ingress \
1384                 | jq -e ".[] | select(.options.handle == 101) \
1385                 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1386         check_err $? "Packet did not reach second host when should"
1387
1388         # Wait for 10 seconds after the ageing time to make sure FDB
1389         # record was aged-out.
1390         ageing_time=$(bridge_ageing_time_get $bridge)
1391         sleep $((ageing_time + 10))
1392
1393         bridge -j fdb show br $bridge brport $br_port1 \
1394                 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1395         check_fail $? "Found FDB record when should not"
1396
1397         bridge link set dev $br_port1 learning off
1398
1399         $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
1400         sleep 1
1401
1402         bridge -j fdb show br $bridge brport $br_port1 \
1403                 | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
1404         check_fail $? "Found FDB record when should not"
1405
1406         bridge link set dev $br_port1 learning on
1407
1408         tc filter del dev $host1_if ingress protocol ip pref 1 handle 101 flower
1409         tc qdisc del dev $host1_if ingress
1410         ip link set $host1_if promisc off
1411
1412         bridge link set dev $br_port1 flood on
1413
1414         log_test "FDB learning"
1415 }
1416
1417 flood_test_do()
1418 {
1419         local should_flood=$1
1420         local mac=$2
1421         local ip=$3
1422         local host1_if=$4
1423         local host2_if=$5
1424         local err=0
1425
1426         # Add an ACL on `host2_if` which will tell us whether the packet
1427         # was flooded to it or not.
1428         ip link set $host2_if promisc on
1429         tc qdisc add dev $host2_if ingress
1430         tc filter add dev $host2_if ingress protocol ip pref 1 handle 101 \
1431                 flower dst_mac $mac action drop
1432
1433         $MZ $host1_if -c 1 -p 64 -b $mac -B $ip -t ip -q
1434         sleep 1
1435
1436         tc -j -s filter show dev $host2_if ingress \
1437                 | jq -e ".[] | select(.options.handle == 101) \
1438                 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1439         if [[ $? -ne 0 && $should_flood == "true" || \
1440               $? -eq 0 && $should_flood == "false" ]]; then
1441                 err=1
1442         fi
1443
1444         tc filter del dev $host2_if ingress protocol ip pref 1 handle 101 flower
1445         tc qdisc del dev $host2_if ingress
1446         ip link set $host2_if promisc off
1447
1448         return $err
1449 }
1450
1451 flood_unicast_test()
1452 {
1453         local br_port=$1
1454         local host1_if=$2
1455         local host2_if=$3
1456         local mac=de:ad:be:ef:13:37
1457         local ip=192.0.2.100
1458
1459         RET=0
1460
1461         bridge link set dev $br_port flood off
1462
1463         flood_test_do false $mac $ip $host1_if $host2_if
1464         check_err $? "Packet flooded when should not"
1465
1466         bridge link set dev $br_port flood on
1467
1468         flood_test_do true $mac $ip $host1_if $host2_if
1469         check_err $? "Packet was not flooded when should"
1470
1471         log_test "Unknown unicast flood"
1472 }
1473
1474 flood_multicast_test()
1475 {
1476         local br_port=$1
1477         local host1_if=$2
1478         local host2_if=$3
1479         local mac=01:00:5e:00:00:01
1480         local ip=239.0.0.1
1481
1482         RET=0
1483
1484         bridge link set dev $br_port mcast_flood off
1485
1486         flood_test_do false $mac $ip $host1_if $host2_if
1487         check_err $? "Packet flooded when should not"
1488
1489         bridge link set dev $br_port mcast_flood on
1490
1491         flood_test_do true $mac $ip $host1_if $host2_if
1492         check_err $? "Packet was not flooded when should"
1493
1494         log_test "Unregistered multicast flood"
1495 }
1496
1497 flood_test()
1498 {
1499         # `br_port` is connected to `host2_if`
1500         local br_port=$1
1501         local host1_if=$2
1502         local host2_if=$3
1503
1504         flood_unicast_test $br_port $host1_if $host2_if
1505         flood_multicast_test $br_port $host1_if $host2_if
1506 }
1507
1508 __start_traffic()
1509 {
1510         local pktsize=$1; shift
1511         local proto=$1; shift
1512         local h_in=$1; shift    # Where the traffic egresses the host
1513         local sip=$1; shift
1514         local dip=$1; shift
1515         local dmac=$1; shift
1516         local -a mz_args=("$@")
1517
1518         $MZ $h_in -p $pktsize -A $sip -B $dip -c 0 \
1519                 -a own -b $dmac -t "$proto" -q "${mz_args[@]}" &
1520         sleep 1
1521 }
1522
1523 start_traffic_pktsize()
1524 {
1525         local pktsize=$1; shift
1526         local h_in=$1; shift
1527         local sip=$1; shift
1528         local dip=$1; shift
1529         local dmac=$1; shift
1530         local -a mz_args=("$@")
1531
1532         __start_traffic $pktsize udp "$h_in" "$sip" "$dip" "$dmac" \
1533                         "${mz_args[@]}"
1534 }
1535
1536 start_tcp_traffic_pktsize()
1537 {
1538         local pktsize=$1; shift
1539         local h_in=$1; shift
1540         local sip=$1; shift
1541         local dip=$1; shift
1542         local dmac=$1; shift
1543         local -a mz_args=("$@")
1544
1545         __start_traffic $pktsize tcp "$h_in" "$sip" "$dip" "$dmac" \
1546                         "${mz_args[@]}"
1547 }
1548
1549 start_traffic()
1550 {
1551         local h_in=$1; shift
1552         local sip=$1; shift
1553         local dip=$1; shift
1554         local dmac=$1; shift
1555         local -a mz_args=("$@")
1556
1557         start_traffic_pktsize 8000 "$h_in" "$sip" "$dip" "$dmac" \
1558                               "${mz_args[@]}"
1559 }
1560
1561 start_tcp_traffic()
1562 {
1563         local h_in=$1; shift
1564         local sip=$1; shift
1565         local dip=$1; shift
1566         local dmac=$1; shift
1567         local -a mz_args=("$@")
1568
1569         start_tcp_traffic_pktsize 8000 "$h_in" "$sip" "$dip" "$dmac" \
1570                                   "${mz_args[@]}"
1571 }
1572
1573 stop_traffic()
1574 {
1575         local pid=${1-%%}; shift
1576
1577         kill_process "$pid"
1578 }
1579
1580 declare -A cappid
1581 declare -A capfile
1582 declare -A capout
1583
1584 tcpdump_start()
1585 {
1586         local if_name=$1; shift
1587         local ns=$1; shift
1588
1589         capfile[$if_name]=$(mktemp)
1590         capout[$if_name]=$(mktemp)
1591
1592         if [ -z $ns ]; then
1593                 ns_cmd=""
1594         else
1595                 ns_cmd="ip netns exec ${ns}"
1596         fi
1597
1598         if [ -z $SUDO_USER ] ; then
1599                 capuser=""
1600         else
1601                 capuser="-Z $SUDO_USER"
1602         fi
1603
1604         $ns_cmd tcpdump $TCPDUMP_EXTRA_FLAGS -e -n -Q in -i $if_name \
1605                 -s 65535 -B 32768 $capuser -w ${capfile[$if_name]} \
1606                 > "${capout[$if_name]}" 2>&1 &
1607         cappid[$if_name]=$!
1608
1609         sleep 1
1610 }
1611
1612 tcpdump_stop()
1613 {
1614         local if_name=$1
1615         local pid=${cappid[$if_name]}
1616
1617         $ns_cmd kill "$pid" && wait "$pid"
1618         sleep 1
1619 }
1620
1621 tcpdump_cleanup()
1622 {
1623         local if_name=$1
1624
1625         rm ${capfile[$if_name]} ${capout[$if_name]}
1626 }
1627
1628 tcpdump_show()
1629 {
1630         local if_name=$1
1631
1632         tcpdump -e -n -r ${capfile[$if_name]} 2>&1
1633 }
1634
1635 # return 0 if the packet wasn't seen on host2_if or 1 if it was
1636 mcast_packet_test()
1637 {
1638         local mac=$1
1639         local src_ip=$2
1640         local ip=$3
1641         local host1_if=$4
1642         local host2_if=$5
1643         local seen=0
1644         local tc_proto="ip"
1645         local mz_v6arg=""
1646
1647         # basic check to see if we were passed an IPv4 address, if not assume IPv6
1648         if [[ ! $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
1649                 tc_proto="ipv6"
1650                 mz_v6arg="-6"
1651         fi
1652
1653         # Add an ACL on `host2_if` which will tell us whether the packet
1654         # was received by it or not.
1655         tc qdisc add dev $host2_if ingress
1656         tc filter add dev $host2_if ingress protocol $tc_proto pref 1 handle 101 \
1657                 flower ip_proto udp dst_mac $mac action drop
1658
1659         $MZ $host1_if $mz_v6arg -c 1 -p 64 -b $mac -A $src_ip -B $ip -t udp "dp=4096,sp=2048" -q
1660         sleep 1
1661
1662         tc -j -s filter show dev $host2_if ingress \
1663                 | jq -e ".[] | select(.options.handle == 101) \
1664                 | select(.options.actions[0].stats.packets == 1)" &> /dev/null
1665         if [[ $? -eq 0 ]]; then
1666                 seen=1
1667         fi
1668
1669         tc filter del dev $host2_if ingress protocol $tc_proto pref 1 handle 101 flower
1670         tc qdisc del dev $host2_if ingress
1671
1672         return $seen
1673 }
1674
1675 brmcast_check_sg_entries()
1676 {
1677         local report=$1; shift
1678         local slist=("$@")
1679         local sarg=""
1680
1681         for src in "${slist[@]}"; do
1682                 sarg="${sarg} and .source_list[].address == \"$src\""
1683         done
1684         bridge -j -d -s mdb show dev br0 \
1685                 | jq -e ".[].mdb[] | \
1686                          select(.grp == \"$TEST_GROUP\" and .source_list != null $sarg)" &>/dev/null
1687         check_err $? "Wrong *,G entry source list after $report report"
1688
1689         for sgent in "${slist[@]}"; do
1690                 bridge -j -d -s mdb show dev br0 \
1691                         | jq -e ".[].mdb[] | \
1692                                  select(.grp == \"$TEST_GROUP\" and .src == \"$sgent\")" &>/dev/null
1693                 check_err $? "Missing S,G entry ($sgent, $TEST_GROUP)"
1694         done
1695 }
1696
1697 brmcast_check_sg_fwding()
1698 {
1699         local should_fwd=$1; shift
1700         local sources=("$@")
1701
1702         for src in "${sources[@]}"; do
1703                 local retval=0
1704
1705                 mcast_packet_test $TEST_GROUP_MAC $src $TEST_GROUP $h2 $h1
1706                 retval=$?
1707                 if [ $should_fwd -eq 1 ]; then
1708                         check_fail $retval "Didn't forward traffic from S,G ($src, $TEST_GROUP)"
1709                 else
1710                         check_err $retval "Forwarded traffic for blocked S,G ($src, $TEST_GROUP)"
1711                 fi
1712         done
1713 }
1714
1715 brmcast_check_sg_state()
1716 {
1717         local is_blocked=$1; shift
1718         local sources=("$@")
1719         local should_fail=1
1720
1721         if [ $is_blocked -eq 1 ]; then
1722                 should_fail=0
1723         fi
1724
1725         for src in "${sources[@]}"; do
1726                 bridge -j -d -s mdb show dev br0 \
1727                         | jq -e ".[].mdb[] | \
1728                                  select(.grp == \"$TEST_GROUP\" and .source_list != null) |
1729                                  .source_list[] |
1730                                  select(.address == \"$src\") |
1731                                  select(.timer == \"0.00\")" &>/dev/null
1732                 check_err_fail $should_fail $? "Entry $src has zero timer"
1733
1734                 bridge -j -d -s mdb show dev br0 \
1735                         | jq -e ".[].mdb[] | \
1736                                  select(.grp == \"$TEST_GROUP\" and .src == \"$src\" and \
1737                                  .flags[] == \"blocked\")" &>/dev/null
1738                 check_err_fail $should_fail $? "Entry $src has blocked flag"
1739         done
1740 }
1741
1742 mc_join()
1743 {
1744         local if_name=$1
1745         local group=$2
1746         local vrf_name=$(master_name_get $if_name)
1747
1748         # We don't care about actual reception, just about joining the
1749         # IP multicast group and adding the L2 address to the device's
1750         # MAC filtering table
1751         ip vrf exec $vrf_name \
1752                 mreceive -g $group -I $if_name > /dev/null 2>&1 &
1753         mreceive_pid=$!
1754
1755         sleep 1
1756 }
1757
1758 mc_leave()
1759 {
1760         kill "$mreceive_pid" && wait "$mreceive_pid"
1761 }
1762
1763 mc_send()
1764 {
1765         local if_name=$1
1766         local groups=$2
1767         local vrf_name=$(master_name_get $if_name)
1768
1769         ip vrf exec $vrf_name \
1770                 msend -g $groups -I $if_name -c 1 > /dev/null 2>&1
1771 }
1772
1773 start_ip_monitor()
1774 {
1775         local mtype=$1; shift
1776         local ip=${1-ip}; shift
1777
1778         # start the monitor in the background
1779         tmpfile=`mktemp /var/run/nexthoptestXXX`
1780         mpid=`($ip monitor $mtype > $tmpfile & echo $!) 2>/dev/null`
1781         sleep 0.2
1782         echo "$mpid $tmpfile"
1783 }
1784
1785 stop_ip_monitor()
1786 {
1787         local mpid=$1; shift
1788         local tmpfile=$1; shift
1789         local el=$1; shift
1790         local what=$1; shift
1791
1792         sleep 0.2
1793         kill $mpid
1794         local lines=`grep '^\w' $tmpfile | wc -l`
1795         test $lines -eq $el
1796         check_err $? "$what: $lines lines of events, expected $el"
1797         rm -rf $tmpfile
1798 }
1799
1800 hw_stats_monitor_test()
1801 {
1802         local dev=$1; shift
1803         local type=$1; shift
1804         local make_suitable=$1; shift
1805         local make_unsuitable=$1; shift
1806         local ip=${1-ip}; shift
1807
1808         RET=0
1809
1810         # Expect a notification about enablement.
1811         local ipmout=$(start_ip_monitor stats "$ip")
1812         $ip stats set dev $dev ${type}_stats on
1813         stop_ip_monitor $ipmout 1 "${type}_stats enablement"
1814
1815         # Expect a notification about offload.
1816         local ipmout=$(start_ip_monitor stats "$ip")
1817         $make_suitable
1818         stop_ip_monitor $ipmout 1 "${type}_stats installation"
1819
1820         # Expect a notification about loss of offload.
1821         local ipmout=$(start_ip_monitor stats "$ip")
1822         $make_unsuitable
1823         stop_ip_monitor $ipmout 1 "${type}_stats deinstallation"
1824
1825         # Expect a notification about disablement
1826         local ipmout=$(start_ip_monitor stats "$ip")
1827         $ip stats set dev $dev ${type}_stats off
1828         stop_ip_monitor $ipmout 1 "${type}_stats disablement"
1829
1830         log_test "${type}_stats notifications"
1831 }
1832
1833 ipv4_to_bytes()
1834 {
1835         local IP=$1; shift
1836
1837         printf '%02x:' ${IP//./ } |
1838             sed 's/:$//'
1839 }
1840
1841 # Convert a given IPv6 address, `IP' such that the :: token, if present, is
1842 # expanded, and each 16-bit group is padded with zeroes to be 4 hexadecimal
1843 # digits. An optional `BYTESEP' parameter can be given to further separate
1844 # individual bytes of each 16-bit group.
1845 expand_ipv6()
1846 {
1847         local IP=$1; shift
1848         local bytesep=$1; shift
1849
1850         local cvt_ip=${IP/::/_}
1851         local colons=${cvt_ip//[^:]/}
1852         local allcol=:::::::
1853         # IP where :: -> the appropriate number of colons:
1854         local allcol_ip=${cvt_ip/_/${allcol:${#colons}}}
1855
1856         echo $allcol_ip | tr : '\n' |
1857             sed s/^/0000/ |
1858             sed 's/.*\(..\)\(..\)/\1'"$bytesep"'\2/' |
1859             tr '\n' : |
1860             sed 's/:$//'
1861 }
1862
1863 ipv6_to_bytes()
1864 {
1865         local IP=$1; shift
1866
1867         expand_ipv6 "$IP" :
1868 }
1869
1870 u16_to_bytes()
1871 {
1872         local u16=$1; shift
1873
1874         printf "%04x" $u16 | sed 's/^/000/;s/^.*\(..\)\(..\)$/\1:\2/'
1875 }
1876
1877 # Given a mausezahn-formatted payload (colon-separated bytes given as %02x),
1878 # possibly with a keyword CHECKSUM stashed where a 16-bit checksum should be,
1879 # calculate checksum as per RFC 1071, assuming the CHECKSUM field (if any)
1880 # stands for 00:00.
1881 payload_template_calc_checksum()
1882 {
1883         local payload=$1; shift
1884
1885         (
1886             # Set input radix.
1887             echo "16i"
1888             # Push zero for the initial checksum.
1889             echo 0
1890
1891             # Pad the payload with a terminating 00: in case we get an odd
1892             # number of bytes.
1893             echo "${payload%:}:00:" |
1894                 sed 's/CHECKSUM/00:00/g' |
1895                 tr '[:lower:]' '[:upper:]' |
1896                 # Add the word to the checksum.
1897                 sed 's/\(..\):\(..\):/\1\2+\n/g' |
1898                 # Strip the extra odd byte we pushed if left unconverted.
1899                 sed 's/\(..\):$//'
1900
1901             echo "10000 ~ +"    # Calculate and add carry.
1902             echo "FFFF r - p"   # Bit-flip and print.
1903         ) |
1904             dc |
1905             tr '[:upper:]' '[:lower:]'
1906 }
1907
1908 payload_template_expand_checksum()
1909 {
1910         local payload=$1; shift
1911         local checksum=$1; shift
1912
1913         local ckbytes=$(u16_to_bytes $checksum)
1914
1915         echo "$payload" | sed "s/CHECKSUM/$ckbytes/g"
1916 }
1917
1918 payload_template_nbytes()
1919 {
1920         local payload=$1; shift
1921
1922         payload_template_expand_checksum "${payload%:}" 0 |
1923                 sed 's/:/\n/g' | wc -l
1924 }
1925
1926 igmpv3_is_in_get()
1927 {
1928         local GRP=$1; shift
1929         local sources=("$@")
1930
1931         local igmpv3
1932         local nsources=$(u16_to_bytes ${#sources[@]})
1933
1934         # IS_IN ( $sources )
1935         igmpv3=$(:
1936                 )"22:"$(                        : Type - Membership Report
1937                 )"00:"$(                        : Reserved
1938                 )"CHECKSUM:"$(                  : Checksum
1939                 )"00:00:"$(                     : Reserved
1940                 )"00:01:"$(                     : Number of Group Records
1941                 )"01:"$(                        : Record Type - IS_IN
1942                 )"00:"$(                        : Aux Data Len
1943                 )"${nsources}:"$(               : Number of Sources
1944                 )"$(ipv4_to_bytes $GRP):"$(     : Multicast Address
1945                 )"$(for src in "${sources[@]}"; do
1946                         ipv4_to_bytes $src
1947                         echo -n :
1948                     done)"$(                    : Source Addresses
1949                 )
1950         local checksum=$(payload_template_calc_checksum "$igmpv3")
1951
1952         payload_template_expand_checksum "$igmpv3" $checksum
1953 }
1954
1955 igmpv2_leave_get()
1956 {
1957         local GRP=$1; shift
1958
1959         local payload=$(:
1960                 )"17:"$(                        : Type - Leave Group
1961                 )"00:"$(                        : Max Resp Time - not meaningful
1962                 )"CHECKSUM:"$(                  : Checksum
1963                 )"$(ipv4_to_bytes $GRP)"$(      : Group Address
1964                 )
1965         local checksum=$(payload_template_calc_checksum "$payload")
1966
1967         payload_template_expand_checksum "$payload" $checksum
1968 }
1969
1970 mldv2_is_in_get()
1971 {
1972         local SIP=$1; shift
1973         local GRP=$1; shift
1974         local sources=("$@")
1975
1976         local hbh
1977         local icmpv6
1978         local nsources=$(u16_to_bytes ${#sources[@]})
1979
1980         hbh=$(:
1981                 )"3a:"$(                        : Next Header - ICMPv6
1982                 )"00:"$(                        : Hdr Ext Len
1983                 )"00:00:00:00:00:00:"$(         : Options and Padding
1984                 )
1985
1986         icmpv6=$(:
1987                 )"8f:"$(                        : Type - MLDv2 Report
1988                 )"00:"$(                        : Code
1989                 )"CHECKSUM:"$(                  : Checksum
1990                 )"00:00:"$(                     : Reserved
1991                 )"00:01:"$(                     : Number of Group Records
1992                 )"01:"$(                        : Record Type - IS_IN
1993                 )"00:"$(                        : Aux Data Len
1994                 )"${nsources}:"$(               : Number of Sources
1995                 )"$(ipv6_to_bytes $GRP):"$(     : Multicast address
1996                 )"$(for src in "${sources[@]}"; do
1997                         ipv6_to_bytes $src
1998                         echo -n :
1999                     done)"$(                    : Source Addresses
2000                 )
2001
2002         local len=$(u16_to_bytes $(payload_template_nbytes $icmpv6))
2003         local sudohdr=$(:
2004                 )"$(ipv6_to_bytes $SIP):"$(     : SIP
2005                 )"$(ipv6_to_bytes $GRP):"$(     : DIP is multicast address
2006                 )"${len}:"$(                    : Upper-layer length
2007                 )"00:3a:"$(                     : Zero and next-header
2008                 )
2009         local checksum=$(payload_template_calc_checksum ${sudohdr}${icmpv6})
2010
2011         payload_template_expand_checksum "$hbh$icmpv6" $checksum
2012 }
2013
2014 mldv1_done_get()
2015 {
2016         local SIP=$1; shift
2017         local GRP=$1; shift
2018
2019         local hbh
2020         local icmpv6
2021
2022         hbh=$(:
2023                 )"3a:"$(                        : Next Header - ICMPv6
2024                 )"00:"$(                        : Hdr Ext Len
2025                 )"00:00:00:00:00:00:"$(         : Options and Padding
2026                 )
2027
2028         icmpv6=$(:
2029                 )"84:"$(                        : Type - MLDv1 Done
2030                 )"00:"$(                        : Code
2031                 )"CHECKSUM:"$(                  : Checksum
2032                 )"00:00:"$(                     : Max Resp Delay - not meaningful
2033                 )"00:00:"$(                     : Reserved
2034                 )"$(ipv6_to_bytes $GRP):"$(     : Multicast address
2035                 )
2036
2037         local len=$(u16_to_bytes $(payload_template_nbytes $icmpv6))
2038         local sudohdr=$(:
2039                 )"$(ipv6_to_bytes $SIP):"$(     : SIP
2040                 )"$(ipv6_to_bytes $GRP):"$(     : DIP is multicast address
2041                 )"${len}:"$(                    : Upper-layer length
2042                 )"00:3a:"$(                     : Zero and next-header
2043                 )
2044         local checksum=$(payload_template_calc_checksum ${sudohdr}${icmpv6})
2045
2046         payload_template_expand_checksum "$hbh$icmpv6" $checksum
2047 }
2048
2049 bail_on_lldpad()
2050 {
2051         local reason1="$1"; shift
2052         local reason2="$1"; shift
2053         local caller=${FUNCNAME[1]}
2054         local src=${BASH_SOURCE[1]}
2055
2056         if systemctl is-active --quiet lldpad; then
2057
2058                 cat >/dev/stderr <<-EOF
2059                 WARNING: lldpad is running
2060
2061                         lldpad will likely $reason1, and this test will
2062                         $reason2. Both are not supported at the same time,
2063                         one of them is arbitrarily going to overwrite the
2064                         other. That will cause spurious failures (or, unlikely,
2065                         passes) of this test.
2066                 EOF
2067
2068                 if [[ -z $ALLOW_LLDPAD ]]; then
2069                         cat >/dev/stderr <<-EOF
2070
2071                                 If you want to run the test anyway, please set
2072                                 an environment variable ALLOW_LLDPAD to a
2073                                 non-empty string.
2074                         EOF
2075                         log_test_skip $src:$caller
2076                         exit $EXIT_STATUS
2077                 else
2078                         return
2079                 fi
2080         fi
2081 }
2082
2083 absval()
2084 {
2085         local v=$1; shift
2086
2087         echo $((v > 0 ? v : -v))
2088 }
2089
2090 has_unicast_flt()
2091 {
2092         local dev=$1; shift
2093         local mac_addr=$(mac_get $dev)
2094         local tmp=$(ether_addr_to_u64 $mac_addr)
2095         local promisc
2096
2097         ip link set $dev up
2098         ip link add link $dev name macvlan-tmp type macvlan mode private
2099         ip link set macvlan-tmp address $(u64_to_ether_addr $((tmp + 1)))
2100         ip link set macvlan-tmp up
2101
2102         promisc=$(ip -j -d link show dev $dev | jq -r '.[].promiscuity')
2103
2104         ip link del macvlan-tmp
2105
2106         [[ $promisc == 1 ]] && echo "no" || echo "yes"
2107 }
This page took 0.149703 seconds and 4 git commands to generate.