lib.sh 43 KB

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