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