lib.sh 18 KB

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