| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182 |
- #!/bin/bash
- # SPDX-License-Identifier: GPL-2.0
- ##############################################################################
- # Topology description. p1 looped back to p2, p3 to p4 and so on.
- declare -A NETIFS=(
- [p1]=veth0
- [p2]=veth1
- [p3]=veth2
- [p4]=veth3
- [p5]=veth4
- [p6]=veth5
- [p7]=veth6
- [p8]=veth7
- [p9]=veth8
- [p10]=veth9
- )
- # Port that does not have a cable connected.
- : "${NETIF_NO_CABLE:=eth8}"
- ##############################################################################
- # Defines
- # Networking utilities.
- : "${PING:=ping}"
- : "${PING6:=ping6}" # Some distros just use ping.
- : "${ARPING:=arping}"
- : "${TROUTE6:=traceroute6}"
- # Packet generator.
- : "${MZ:=mausezahn}" # Some distributions use 'mz'.
- : "${MZ_DELAY:=0}"
- # Host configuration tools.
- : "${TEAMD:=teamd}"
- : "${MCD:=smcrouted}"
- : "${MC_CLI:=smcroutectl}"
- # Constants for netdevice bring-up:
- # Default time in seconds to wait for an interface to come up before giving up
- # and bailing out. Used during initial setup.
- : "${INTERFACE_TIMEOUT:=600}"
- # Like INTERFACE_TIMEOUT, but default for ad-hoc waiting in testing scripts.
- : "${WAIT_TIMEOUT:=20}"
- # Time to wait after interfaces participating in the test are all UP.
- : "${WAIT_TIME:=5}"
- # Whether to pause on, respectively, after a failure and before cleanup.
- : "${PAUSE_ON_CLEANUP:=no}"
- # Whether to create virtual interfaces, and what netdevice type they should be.
- : "${NETIF_CREATE:=yes}"
- : "${NETIF_TYPE:=veth}"
- # Constants for ping tests:
- # How many packets should be sent.
- : "${PING_COUNT:=10}"
- # Timeout (in seconds) before ping exits regardless of how many packets have
- # been sent or received
- : "${PING_TIMEOUT:=5}"
- # Minimum ageing_time (in centiseconds) supported by hardware
- : "${LOW_AGEING_TIME:=1000}"
- # Whether to check for availability of certain tools.
- : "${REQUIRE_JQ:=yes}"
- : "${REQUIRE_MZ:=yes}"
- : "${REQUIRE_MTOOLS:=no}"
- # Whether to override MAC addresses on interfaces participating in the test.
- : "${STABLE_MAC_ADDRS:=no}"
- # Flags for tcpdump
- : "${TCPDUMP_EXTRA_FLAGS:=}"
- # Flags for TC filters.
- : "${TC_FLAG:=skip_hw}"
- # Whether the machine is "slow" -- i.e. might be incapable of running tests
- # involving heavy traffic. This might be the case on a debug kernel, a VM, or
- # e.g. a low-power board.
- : "${KSFT_MACHINE_SLOW:=no}"
- ##############################################################################
- # Find netifs by test-specified driver name
- driver_name_get()
- {
- local dev=$1; shift
- local driver_path="/sys/class/net/$dev/device/driver"
- if [[ -L $driver_path ]]; then
- basename `realpath $driver_path`
- fi
- }
- netif_find_driver()
- {
- local ifnames=`ip -j link show | jq -r ".[].ifname"`
- local count=0
- for ifname in $ifnames
- do
- local driver_name=`driver_name_get $ifname`
- if [[ ! -z $driver_name && $driver_name == $NETIF_FIND_DRIVER ]]; then
- count=$((count + 1))
- NETIFS[p$count]="$ifname"
- fi
- done
- }
- # Whether to find netdevice according to the driver speficied by the importer
- : "${NETIF_FIND_DRIVER:=}"
- if [[ $NETIF_FIND_DRIVER ]]; then
- unset NETIFS
- declare -A NETIFS
- netif_find_driver
- fi
- net_forwarding_dir=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")
- if [[ -f $net_forwarding_dir/forwarding.config ]]; then
- source "$net_forwarding_dir/forwarding.config"
- fi
- source "$net_forwarding_dir/../lib.sh"
- ##############################################################################
- # Sanity checks
- check_tc_version()
- {
- tc -j &> /dev/null
- if [[ $? -ne 0 ]]; then
- echo "SKIP: iproute2 too old; tc is missing JSON support"
- exit $ksft_skip
- fi
- }
- # Old versions of tc don't understand "mpls_uc"
- check_tc_mpls_support()
- {
- local dev=$1; shift
- tc filter add dev $dev ingress protocol mpls_uc pref 1 handle 1 \
- matchall action pipe &> /dev/null
- if [[ $? -ne 0 ]]; then
- echo "SKIP: iproute2 too old; tc is missing MPLS support"
- return $ksft_skip
- fi
- tc filter del dev $dev ingress protocol mpls_uc pref 1 handle 1 \
- matchall
- }
- # Old versions of tc produce invalid json output for mpls lse statistics
- check_tc_mpls_lse_stats()
- {
- local dev=$1; shift
- local ret;
- tc filter add dev $dev ingress protocol mpls_uc pref 1 handle 1 \
- flower mpls lse depth 2 \
- action continue &> /dev/null
- if [[ $? -ne 0 ]]; then
- echo "SKIP: iproute2 too old; tc-flower is missing extended MPLS support"
- return $ksft_skip
- fi
- tc -j filter show dev $dev ingress protocol mpls_uc | jq . &> /dev/null
- ret=$?
- tc filter del dev $dev ingress protocol mpls_uc pref 1 handle 1 \
- flower
- if [[ $ret -ne 0 ]]; then
- echo "SKIP: iproute2 too old; tc-flower produces invalid json output for extended MPLS filters"
- return $ksft_skip
- fi
- }
- check_tc_shblock_support()
- {
- tc filter help 2>&1 | grep block &> /dev/null
- if [[ $? -ne 0 ]]; then
- echo "SKIP: iproute2 too old; tc is missing shared block support"
- exit $ksft_skip
- fi
- }
- check_tc_chain_support()
- {
- tc help 2>&1|grep chain &> /dev/null
- if [[ $? -ne 0 ]]; then
- echo "SKIP: iproute2 too old; tc is missing chain support"
- exit $ksft_skip
- fi
- }
- check_tc_action_hw_stats_support()
- {
- tc actions help 2>&1 | grep -q hw_stats
- if [[ $? -ne 0 ]]; then
- echo "SKIP: iproute2 too old; tc is missing action hw_stats support"
- exit $ksft_skip
- fi
- }
- check_tc_fp_support()
- {
- tc qdisc add dev lo mqprio help 2>&1 | grep -q "fp "
- if [[ $? -ne 0 ]]; then
- echo "SKIP: iproute2 too old; tc is missing frame preemption support"
- exit $ksft_skip
- fi
- }
- check_ethtool_lanes_support()
- {
- ethtool --help 2>&1| grep lanes &> /dev/null
- if [[ $? -ne 0 ]]; then
- echo "SKIP: ethtool too old; it is missing lanes support"
- exit $ksft_skip
- fi
- }
- check_ethtool_mm_support()
- {
- ethtool --help 2>&1| grep -- '--show-mm' &> /dev/null
- if [[ $? -ne 0 ]]; then
- echo "SKIP: ethtool too old; it is missing MAC Merge layer support"
- exit $ksft_skip
- fi
- }
- check_ethtool_counter_group_support()
- {
- ethtool --help 2>&1| grep -- '--all-groups' &> /dev/null
- if [[ $? -ne 0 ]]; then
- echo "SKIP: ethtool too old; it is missing standard counter group support"
- exit $ksft_skip
- fi
- }
- check_ethtool_pmac_std_stats_support()
- {
- local dev=$1; shift
- local grp=$1; shift
- [ 0 -ne $(ethtool --json -S $dev --all-groups --src pmac 2>/dev/null \
- | jq ".[].\"$grp\" | length") ]
- }
- check_locked_port_support()
- {
- if ! bridge -d link show | grep -q " locked"; then
- echo "SKIP: iproute2 too old; Locked port feature not supported."
- return $ksft_skip
- fi
- }
- check_port_mab_support()
- {
- if ! bridge -d link show | grep -q "mab"; then
- echo "SKIP: iproute2 too old; MacAuth feature not supported."
- return $ksft_skip
- fi
- }
- if [[ "$(id -u)" -ne 0 ]]; then
- echo "SKIP: need root privileges"
- exit $ksft_skip
- fi
- check_driver()
- {
- local dev=$1; shift
- local expected=$1; shift
- local driver_name=`driver_name_get $dev`
- if [[ $driver_name != $expected ]]; then
- echo "SKIP: expected driver $expected for $dev, got $driver_name instead"
- exit $ksft_skip
- fi
- }
- if [[ "$CHECK_TC" = "yes" ]]; then
- check_tc_version
- fi
- require_command()
- {
- local cmd=$1; shift
- if [[ ! -x "$(command -v "$cmd")" ]]; then
- echo "SKIP: $cmd not installed"
- exit $ksft_skip
- fi
- }
- # IPv6 support was added in v3.0
- check_mtools_version()
- {
- local version="$(msend -v)"
- local major
- version=${version##msend version }
- major=$(echo $version | cut -d. -f1)
- if [ $major -lt 3 ]; then
- echo "SKIP: expected mtools version 3.0, got $version"
- exit $ksft_skip
- fi
- }
- if [[ "$REQUIRE_JQ" = "yes" ]]; then
- require_command jq
- fi
- if [[ "$REQUIRE_MZ" = "yes" ]]; then
- require_command $MZ
- fi
- if [[ "$REQUIRE_MTOOLS" = "yes" ]]; then
- # https://github.com/troglobit/mtools
- require_command msend
- require_command mreceive
- check_mtools_version
- fi
- ##############################################################################
- # Command line options handling
- count=0
- while [[ $# -gt 0 ]]; do
- if [[ "$count" -eq "0" ]]; then
- unset NETIFS
- declare -A NETIFS
- fi
- count=$((count + 1))
- NETIFS[p$count]="$1"
- shift
- done
- ##############################################################################
- # Network interfaces configuration
- if [[ ! -v NUM_NETIFS ]]; then
- echo "SKIP: importer does not define \"NUM_NETIFS\""
- exit $ksft_skip
- fi
- if (( NUM_NETIFS > ${#NETIFS[@]} )); then
- echo "SKIP: Importer requires $NUM_NETIFS NETIFS, but only ${#NETIFS[@]} are defined (${NETIFS[@]})"
- exit $ksft_skip
- fi
- for i in $(seq ${#NETIFS[@]}); do
- if [[ ! ${NETIFS[p$i]} ]]; then
- echo "SKIP: NETIFS[p$i] not given"
- exit $ksft_skip
- fi
- done
- create_netif_veth()
- {
- local i
- for ((i = 1; i <= NUM_NETIFS; ++i)); do
- local j=$((i+1))
- if [ -z ${NETIFS[p$i]} ]; then
- echo "SKIP: Cannot create interface. Name not specified"
- exit $ksft_skip
- fi
- ip link show dev ${NETIFS[p$i]} &> /dev/null
- if [[ $? -ne 0 ]]; then
- ip link add ${NETIFS[p$i]} type veth \
- peer name ${NETIFS[p$j]}
- if [[ $? -ne 0 ]]; then
- echo "Failed to create netif"
- exit 1
- fi
- fi
- i=$j
- done
- }
- create_netif()
- {
- case "$NETIF_TYPE" in
- veth) create_netif_veth
- ;;
- *) echo "Can not create interfaces of type \'$NETIF_TYPE\'"
- exit 1
- ;;
- esac
- }
- declare -A MAC_ADDR_ORIG
- mac_addr_prepare()
- {
- local new_addr=
- local dev=
- for ((i = 1; i <= NUM_NETIFS; ++i)); do
- dev=${NETIFS[p$i]}
- new_addr=$(printf "00:01:02:03:04:%02x" $i)
- MAC_ADDR_ORIG["$dev"]=$(ip -j link show dev $dev | jq -e '.[].address')
- # Strip quotes
- MAC_ADDR_ORIG["$dev"]=${MAC_ADDR_ORIG["$dev"]//\"/}
- ip link set dev $dev address $new_addr
- done
- }
- mac_addr_restore()
- {
- local dev=
- for ((i = 1; i <= NUM_NETIFS; ++i)); do
- dev=${NETIFS[p$i]}
- ip link set dev $dev address ${MAC_ADDR_ORIG["$dev"]}
- done
- }
- if [[ "$NETIF_CREATE" = "yes" ]]; then
- create_netif
- fi
- if [[ "$STABLE_MAC_ADDRS" = "yes" ]]; then
- mac_addr_prepare
- fi
- for ((i = 1; i <= NUM_NETIFS; ++i)); do
- ip link show dev ${NETIFS[p$i]} &> /dev/null
- if [[ $? -ne 0 ]]; then
- echo "SKIP: could not find all required interfaces"
- exit $ksft_skip
- fi
- done
- ##############################################################################
- # Helpers
- # Whether FAILs should be interpreted as XFAILs. Internal.
- FAIL_TO_XFAIL=
- check_err()
- {
- local err=$1
- local msg=$2
- if ((err)); then
- if [[ $FAIL_TO_XFAIL = yes ]]; then
- ret_set_ksft_status $ksft_xfail "$msg"
- else
- ret_set_ksft_status $ksft_fail "$msg"
- fi
- fi
- }
- check_fail()
- {
- local err=$1
- local msg=$2
- check_err $((!err)) "$msg"
- }
- check_err_fail()
- {
- local should_fail=$1; shift
- local err=$1; shift
- local what=$1; shift
- if ((should_fail)); then
- check_fail $err "$what succeeded, but should have failed"
- else
- check_err $err "$what failed"
- fi
- }
- xfail()
- {
- FAIL_TO_XFAIL=yes "$@"
- }
- xfail_on_slow()
- {
- if [[ $KSFT_MACHINE_SLOW = yes ]]; then
- FAIL_TO_XFAIL=yes "$@"
- else
- "$@"
- fi
- }
- omit_on_slow()
- {
- if [[ $KSFT_MACHINE_SLOW != yes ]]; then
- "$@"
- fi
- }
- xfail_on_veth()
- {
- local dev=$1; shift
- local kind
- kind=$(ip -j -d link show dev $dev |
- jq -r '.[].linkinfo.info_kind')
- if [[ $kind = veth ]]; then
- FAIL_TO_XFAIL=yes "$@"
- else
- "$@"
- fi
- }
- not()
- {
- "$@"
- [[ $? != 0 ]]
- }
- get_max()
- {
- local arr=("$@")
- max=${arr[0]}
- for cur in ${arr[@]}; do
- if [[ $cur -gt $max ]]; then
- max=$cur
- fi
- done
- echo $max
- }
- grep_bridge_fdb()
- {
- local addr=$1; shift
- local word
- local flag
- if [ "$1" == "self" ] || [ "$1" == "master" ]; then
- word=$1; shift
- if [ "$1" == "-v" ]; then
- flag=$1; shift
- fi
- fi
- $@ | grep $addr | grep $flag "$word"
- }
- wait_for_port_up()
- {
- "$@" | grep -q "Link detected: yes"
- }
- wait_for_offload()
- {
- "$@" | grep -q offload
- }
- wait_for_trap()
- {
- "$@" | grep -q trap
- }
- setup_wait_dev()
- {
- local dev=$1; shift
- local wait_time=${1:-$WAIT_TIME}; shift
- setup_wait_dev_with_timeout "$dev" $INTERFACE_TIMEOUT $wait_time
- if (($?)); then
- check_err 1
- log_test setup_wait_dev ": Interface $dev does not come up."
- exit 1
- fi
- }
- setup_wait_dev_with_timeout()
- {
- local dev=$1; shift
- local max_iterations=${1:-$WAIT_TIMEOUT}; shift
- local wait_time=${1:-$WAIT_TIME}; shift
- local i
- for ((i = 1; i <= $max_iterations; ++i)); do
- ip link show dev $dev up \
- | grep 'state UP' &> /dev/null
- if [[ $? -ne 0 ]]; then
- sleep 1
- else
- sleep $wait_time
- return 0
- fi
- done
- return 1
- }
- setup_wait()
- {
- local num_netifs=${1:-$NUM_NETIFS}
- local i
- for ((i = 1; i <= num_netifs; ++i)); do
- setup_wait_dev ${NETIFS[p$i]} 0
- done
- # Make sure links are ready.
- sleep $WAIT_TIME
- }
- wait_for_dev()
- {
- local dev=$1; shift
- local timeout=${1:-$WAIT_TIMEOUT}; shift
- slowwait $timeout ip link show dev $dev &> /dev/null
- if (( $? )); then
- check_err 1
- log_test wait_for_dev "Interface $dev did not appear."
- exit $EXIT_STATUS
- fi
- }
- cmd_jq()
- {
- local cmd=$1
- local jq_exp=$2
- local jq_opts=$3
- local ret
- local output
- output="$($cmd)"
- # it the command fails, return error right away
- ret=$?
- if [[ $ret -ne 0 ]]; then
- return $ret
- fi
- output=$(echo $output | jq -r $jq_opts "$jq_exp")
- ret=$?
- if [[ $ret -ne 0 ]]; then
- return $ret
- fi
- echo $output
- # return success only in case of non-empty output
- [ ! -z "$output" ]
- }
- pre_cleanup()
- {
- if [ "${PAUSE_ON_CLEANUP}" = "yes" ]; then
- echo "Pausing before cleanup, hit any key to continue"
- read
- fi
- if [[ "$STABLE_MAC_ADDRS" = "yes" ]]; then
- mac_addr_restore
- fi
- }
- vrf_prepare()
- {
- ip -4 rule add pref 32765 table local
- ip -4 rule del pref 0
- ip -6 rule add pref 32765 table local
- ip -6 rule del pref 0
- }
- vrf_cleanup()
- {
- ip -6 rule add pref 0 table local
- ip -6 rule del pref 32765
- ip -4 rule add pref 0 table local
- ip -4 rule del pref 32765
- }
- __last_tb_id=0
- declare -A __TB_IDS
- __vrf_td_id_assign()
- {
- local vrf_name=$1
- __last_tb_id=$((__last_tb_id + 1))
- __TB_IDS[$vrf_name]=$__last_tb_id
- return $__last_tb_id
- }
- __vrf_td_id_lookup()
- {
- local vrf_name=$1
- return ${__TB_IDS[$vrf_name]}
- }
- vrf_create()
- {
- local vrf_name=$1
- local tb_id
- __vrf_td_id_assign $vrf_name
- tb_id=$?
- ip link add dev $vrf_name type vrf table $tb_id
- ip -4 route add table $tb_id unreachable default metric 4278198272
- ip -6 route add table $tb_id unreachable default metric 4278198272
- }
- vrf_destroy()
- {
- local vrf_name=$1
- local tb_id
- __vrf_td_id_lookup $vrf_name
- tb_id=$?
- ip -6 route del table $tb_id unreachable default metric 4278198272
- ip -4 route del table $tb_id unreachable default metric 4278198272
- ip link del dev $vrf_name
- }
- __addr_add_del()
- {
- local if_name=$1
- local add_del=$2
- local array
- shift
- shift
- array=("${@}")
- for addrstr in "${array[@]}"; do
- ip address $add_del $addrstr dev $if_name
- done
- }
- __simple_if_init()
- {
- local if_name=$1; shift
- local vrf_name=$1; shift
- local addrs=("${@}")
- ip link set dev $if_name master $vrf_name
- ip link set dev $if_name up
- __addr_add_del $if_name add "${addrs[@]}"
- }
- __simple_if_fini()
- {
- local if_name=$1; shift
- local addrs=("${@}")
- __addr_add_del $if_name del "${addrs[@]}"
- ip link set dev $if_name down
- ip link set dev $if_name nomaster
- }
- simple_if_init()
- {
- local if_name=$1
- local vrf_name
- local array
- shift
- vrf_name=v$if_name
- array=("${@}")
- vrf_create $vrf_name
- ip link set dev $vrf_name up
- __simple_if_init $if_name $vrf_name "${array[@]}"
- }
- simple_if_fini()
- {
- local if_name=$1
- local vrf_name
- local array
- shift
- vrf_name=v$if_name
- array=("${@}")
- __simple_if_fini $if_name "${array[@]}"
- vrf_destroy $vrf_name
- }
- tunnel_create()
- {
- local name=$1; shift
- local type=$1; shift
- local local=$1; shift
- local remote=$1; shift
- ip link add name $name type $type \
- local $local remote $remote "$@"
- ip link set dev $name up
- }
- tunnel_destroy()
- {
- local name=$1; shift
- ip link del dev $name
- }
- vlan_create()
- {
- local if_name=$1; shift
- local vid=$1; shift
- local vrf=$1; shift
- local ips=("${@}")
- local name=$if_name.$vid
- ip link add name $name link $if_name type vlan id $vid
- if [ "$vrf" != "" ]; then
- ip link set dev $name master $vrf
- fi
- ip link set dev $name up
- __addr_add_del $name add "${ips[@]}"
- }
- vlan_destroy()
- {
- local if_name=$1; shift
- local vid=$1; shift
- local name=$if_name.$vid
- ip link del dev $name
- }
- team_create()
- {
- local if_name=$1; shift
- local mode=$1; shift
- require_command $TEAMD
- $TEAMD -t $if_name -d -c '{"runner": {"name": "'$mode'"}}'
- for slave in "$@"; do
- ip link set dev $slave down
- ip link set dev $slave master $if_name
- ip link set dev $slave up
- done
- ip link set dev $if_name up
- }
- team_destroy()
- {
- local if_name=$1; shift
- $TEAMD -t $if_name -k
- }
- master_name_get()
- {
- local if_name=$1
- ip -j link show dev $if_name | jq -r '.[]["master"]'
- }
- link_stats_get()
- {
- local if_name=$1; shift
- local dir=$1; shift
- local stat=$1; shift
- ip -j -s link show dev $if_name \
- | jq '.[]["stats64"]["'$dir'"]["'$stat'"]'
- }
- link_stats_tx_packets_get()
- {
- link_stats_get $1 tx packets
- }
- link_stats_rx_errors_get()
- {
- link_stats_get $1 rx errors
- }
- ethtool_stats_get()
- {
- local dev=$1; shift
- local stat=$1; shift
- ethtool -S $dev | grep "^ *$stat:" | head -n 1 | cut -d: -f2
- }
- ethtool_std_stats_get()
- {
- local dev=$1; shift
- local grp=$1; shift
- local name=$1; shift
- local src=$1; shift
- ethtool --json -S $dev --groups $grp -- --src $src | \
- jq '.[]."'"$grp"'"."'$name'"'
- }
- qdisc_stats_get()
- {
- local dev=$1; shift
- local handle=$1; shift
- local selector=$1; shift
- tc -j -s qdisc show dev "$dev" \
- | jq '.[] | select(.handle == "'"$handle"'") | '"$selector"
- }
- qdisc_parent_stats_get()
- {
- local dev=$1; shift
- local parent=$1; shift
- local selector=$1; shift
- tc -j -s qdisc show dev "$dev" invisible \
- | jq '.[] | select(.parent == "'"$parent"'") | '"$selector"
- }
- ipv6_stats_get()
- {
- local dev=$1; shift
- local stat=$1; shift
- cat /proc/net/dev_snmp6/$dev | grep "^$stat" | cut -f2
- }
- hw_stats_get()
- {
- local suite=$1; shift
- local if_name=$1; shift
- local dir=$1; shift
- local stat=$1; shift
- ip -j stats show dev $if_name group offload subgroup $suite |
- jq ".[0].stats64.$dir.$stat"
- }
- __nh_stats_get()
- {
- local key=$1; shift
- local group_id=$1; shift
- local member_id=$1; shift
- ip -j -s -s nexthop show id $group_id |
- jq --argjson member_id "$member_id" --arg key "$key" \
- '.[].group_stats[] | select(.id == $member_id) | .[$key]'
- }
- nh_stats_get()
- {
- local group_id=$1; shift
- local member_id=$1; shift
- __nh_stats_get packets "$group_id" "$member_id"
- }
- nh_stats_get_hw()
- {
- local group_id=$1; shift
- local member_id=$1; shift
- __nh_stats_get packets_hw "$group_id" "$member_id"
- }
- humanize()
- {
- local speed=$1; shift
- for unit in bps Kbps Mbps Gbps; do
- if (($(echo "$speed < 1024" | bc))); then
- break
- fi
- speed=$(echo "scale=1; $speed / 1024" | bc)
- done
- echo "$speed${unit}"
- }
- rate()
- {
- local t0=$1; shift
- local t1=$1; shift
- local interval=$1; shift
- echo $((8 * (t1 - t0) / interval))
- }
- packets_rate()
- {
- local t0=$1; shift
- local t1=$1; shift
- local interval=$1; shift
- echo $(((t1 - t0) / interval))
- }
- mac_get()
- {
- local if_name=$1
- ip -j link show dev $if_name | jq -r '.[]["address"]'
- }
- ether_addr_to_u64()
- {
- local addr="$1"
- local order="$((1 << 40))"
- local val=0
- local byte
- addr="${addr//:/ }"
- for byte in $addr; do
- byte="0x$byte"
- val=$((val + order * byte))
- order=$((order >> 8))
- done
- printf "0x%x" $val
- }
- u64_to_ether_addr()
- {
- local val=$1
- local byte
- local i
- for ((i = 40; i >= 0; i -= 8)); do
- byte=$(((val & (0xff << i)) >> i))
- printf "%02x" $byte
- if [ $i -ne 0 ]; then
- printf ":"
- fi
- done
- }
- ipv6_lladdr_get()
- {
- local if_name=$1
- ip -j addr show dev $if_name | \
- jq -r '.[]["addr_info"][] | select(.scope == "link").local' | \
- head -1
- }
- bridge_ageing_time_get()
- {
- local bridge=$1
- local ageing_time
- # Need to divide by 100 to convert to seconds.
- ageing_time=$(ip -j -d link show dev $bridge \
- | jq '.[]["linkinfo"]["info_data"]["ageing_time"]')
- echo $((ageing_time / 100))
- }
- declare -A SYSCTL_ORIG
- sysctl_save()
- {
- local key=$1; shift
- SYSCTL_ORIG[$key]=$(sysctl -n $key)
- }
- sysctl_set()
- {
- local key=$1; shift
- local value=$1; shift
- sysctl_save "$key"
- sysctl -qw $key="$value"
- }
- sysctl_restore()
- {
- local key=$1; shift
- sysctl -qw $key="${SYSCTL_ORIG[$key]}"
- }
- forwarding_enable()
- {
- sysctl_set net.ipv4.conf.all.forwarding 1
- sysctl_set net.ipv6.conf.all.forwarding 1
- }
- forwarding_restore()
- {
- sysctl_restore net.ipv6.conf.all.forwarding
- sysctl_restore net.ipv4.conf.all.forwarding
- }
- declare -A MTU_ORIG
- mtu_set()
- {
- local dev=$1; shift
- local mtu=$1; shift
- MTU_ORIG["$dev"]=$(ip -j link show dev $dev | jq -e '.[].mtu')
- ip link set dev $dev mtu $mtu
- }
- mtu_restore()
- {
- local dev=$1; shift
- ip link set dev $dev mtu ${MTU_ORIG["$dev"]}
- }
- tc_offload_check()
- {
- local num_netifs=${1:-$NUM_NETIFS}
- for ((i = 1; i <= num_netifs; ++i)); do
- ethtool -k ${NETIFS[p$i]} \
- | grep "hw-tc-offload: on" &> /dev/null
- if [[ $? -ne 0 ]]; then
- return 1
- fi
- done
- return 0
- }
- trap_install()
- {
- local dev=$1; shift
- local direction=$1; shift
- # Some devices may not support or need in-hardware trapping of traffic
- # (e.g. the veth pairs that this library creates for non-existent
- # loopbacks). Use continue instead, so that there is a filter in there
- # (some tests check counters), and so that other filters are still
- # processed.
- tc filter add dev $dev $direction pref 1 \
- flower skip_sw action trap 2>/dev/null \
- || tc filter add dev $dev $direction pref 1 \
- flower action continue
- }
- trap_uninstall()
- {
- local dev=$1; shift
- local direction=$1; shift
- tc filter del dev $dev $direction pref 1 flower
- }
- __icmp_capture_add_del()
- {
- local add_del=$1; shift
- local pref=$1; shift
- local vsuf=$1; shift
- local tundev=$1; shift
- local filter=$1; shift
- tc filter $add_del dev "$tundev" ingress \
- proto ip$vsuf pref $pref \
- flower ip_proto icmp$vsuf $filter \
- action pass
- }
- icmp_capture_install()
- {
- local tundev=$1; shift
- local filter=$1; shift
- __icmp_capture_add_del add 100 "" "$tundev" "$filter"
- }
- icmp_capture_uninstall()
- {
- local tundev=$1; shift
- local filter=$1; shift
- __icmp_capture_add_del del 100 "" "$tundev" "$filter"
- }
- icmp6_capture_install()
- {
- local tundev=$1; shift
- local filter=$1; shift
- __icmp_capture_add_del add 100 v6 "$tundev" "$filter"
- }
- icmp6_capture_uninstall()
- {
- local tundev=$1; shift
- local filter=$1; shift
- __icmp_capture_add_del del 100 v6 "$tundev" "$filter"
- }
- __vlan_capture_add_del()
- {
- local add_del=$1; shift
- local pref=$1; shift
- local dev=$1; shift
- local filter=$1; shift
- tc filter $add_del dev "$dev" ingress \
- proto 802.1q pref $pref \
- flower $filter \
- action pass
- }
- vlan_capture_install()
- {
- local dev=$1; shift
- local filter=$1; shift
- __vlan_capture_add_del add 100 "$dev" "$filter"
- }
- vlan_capture_uninstall()
- {
- local dev=$1; shift
- local filter=$1; shift
- __vlan_capture_add_del del 100 "$dev" "$filter"
- }
- __dscp_capture_add_del()
- {
- local add_del=$1; shift
- local dev=$1; shift
- local base=$1; shift
- local dscp;
- for prio in {0..7}; do
- dscp=$((base + prio))
- __icmp_capture_add_del $add_del $((dscp + 100)) "" $dev \
- "skip_hw ip_tos $((dscp << 2))"
- done
- }
- dscp_capture_install()
- {
- local dev=$1; shift
- local base=$1; shift
- __dscp_capture_add_del add $dev $base
- }
- dscp_capture_uninstall()
- {
- local dev=$1; shift
- local base=$1; shift
- __dscp_capture_add_del del $dev $base
- }
- dscp_fetch_stats()
- {
- local dev=$1; shift
- local base=$1; shift
- for prio in {0..7}; do
- local dscp=$((base + prio))
- local t=$(tc_rule_stats_get $dev $((dscp + 100)))
- echo "[$dscp]=$t "
- done
- }
- matchall_sink_create()
- {
- local dev=$1; shift
- tc qdisc add dev $dev clsact
- tc filter add dev $dev ingress \
- pref 10000 \
- matchall \
- action drop
- }
- tests_run()
- {
- local current_test
- for current_test in ${TESTS:-$ALL_TESTS}; do
- $current_test
- done
- }
- multipath_eval()
- {
- local desc="$1"
- local weight_rp12=$2
- local weight_rp13=$3
- local packets_rp12=$4
- local packets_rp13=$5
- local weights_ratio packets_ratio diff
- RET=0
- if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
- weights_ratio=$(echo "scale=2; $weight_rp12 / $weight_rp13" \
- | bc -l)
- else
- weights_ratio=$(echo "scale=2; $weight_rp13 / $weight_rp12" \
- | bc -l)
- fi
- if [[ "$packets_rp12" -eq "0" || "$packets_rp13" -eq "0" ]]; then
- check_err 1 "Packet difference is 0"
- log_test "Multipath"
- log_info "Expected ratio $weights_ratio"
- return
- fi
- if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
- packets_ratio=$(echo "scale=2; $packets_rp12 / $packets_rp13" \
- | bc -l)
- else
- packets_ratio=$(echo "scale=2; $packets_rp13 / $packets_rp12" \
- | bc -l)
- fi
- diff=$(echo $weights_ratio - $packets_ratio | bc -l)
- diff=${diff#-}
- test "$(echo "$diff / $weights_ratio > 0.15" | bc -l)" -eq 0
- check_err $? "Too large discrepancy between expected and measured ratios"
- log_test "$desc"
- log_info "Expected ratio $weights_ratio Measured ratio $packets_ratio"
- }
- in_ns()
- {
- local name=$1; shift
- ip netns exec $name bash <<-EOF
- NUM_NETIFS=0
- source lib.sh
- $(for a in "$@"; do printf "%q${IFS:0:1}" "$a"; done)
- EOF
- }
- ##############################################################################
- # Tests
- ping_do()
- {
- local if_name=$1
- local dip=$2
- local args=$3
- local vrf_name
- vrf_name=$(master_name_get $if_name)
- ip vrf exec $vrf_name \
- $PING $args $dip -c $PING_COUNT -i 0.1 \
- -w $PING_TIMEOUT &> /dev/null
- }
- ping_test()
- {
- RET=0
- ping_do $1 $2
- check_err $?
- log_test "ping$3"
- }
- ping_test_fails()
- {
- RET=0
- ping_do $1 $2
- check_fail $?
- log_test "ping fails$3"
- }
- ping6_do()
- {
- local if_name=$1
- local dip=$2
- local args=$3
- local vrf_name
- vrf_name=$(master_name_get $if_name)
- ip vrf exec $vrf_name \
- $PING6 $args $dip -c $PING_COUNT -i 0.1 \
- -w $PING_TIMEOUT &> /dev/null
- }
- ping6_test()
- {
- RET=0
- ping6_do $1 $2
- check_err $?
- log_test "ping6$3"
- }
- ping6_test_fails()
- {
- RET=0
- ping6_do $1 $2
- check_fail $?
- log_test "ping6 fails$3"
- }
- learning_test()
- {
- local bridge=$1
- local br_port1=$2 # Connected to `host1_if`.
- local host1_if=$3
- local host2_if=$4
- local mac=de:ad:be:ef:13:37
- local ageing_time
- RET=0
- bridge -j fdb show br $bridge brport $br_port1 \
- | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
- check_fail $? "Found FDB record when should not"
- # Disable unknown unicast flooding on `br_port1` to make sure
- # packets are only forwarded through the port after a matching
- # FDB entry was installed.
- bridge link set dev $br_port1 flood off
- ip link set $host1_if promisc on
- tc qdisc add dev $host1_if ingress
- tc filter add dev $host1_if ingress protocol ip pref 1 handle 101 \
- flower dst_mac $mac action drop
- $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q
- sleep 1
- tc -j -s filter show dev $host1_if ingress \
- | jq -e ".[] | select(.options.handle == 101) \
- | select(.options.actions[0].stats.packets == 1)" &> /dev/null
- check_fail $? "Packet reached first host when should not"
- $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
- sleep 1
- bridge -j fdb show br $bridge brport $br_port1 \
- | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
- check_err $? "Did not find FDB record when should"
- $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q
- sleep 1
- tc -j -s filter show dev $host1_if ingress \
- | jq -e ".[] | select(.options.handle == 101) \
- | select(.options.actions[0].stats.packets == 1)" &> /dev/null
- check_err $? "Packet did not reach second host when should"
- # Wait for 10 seconds after the ageing time to make sure FDB
- # record was aged-out.
- ageing_time=$(bridge_ageing_time_get $bridge)
- sleep $((ageing_time + 10))
- bridge -j fdb show br $bridge brport $br_port1 \
- | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
- check_fail $? "Found FDB record when should not"
- bridge link set dev $br_port1 learning off
- $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
- sleep 1
- bridge -j fdb show br $bridge brport $br_port1 \
- | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null
- check_fail $? "Found FDB record when should not"
- bridge link set dev $br_port1 learning on
- tc filter del dev $host1_if ingress protocol ip pref 1 handle 101 flower
- tc qdisc del dev $host1_if ingress
- ip link set $host1_if promisc off
- bridge link set dev $br_port1 flood on
- log_test "FDB learning"
- }
- flood_test_do()
- {
- local should_flood=$1
- local mac=$2
- local ip=$3
- local host1_if=$4
- local host2_if=$5
- local err=0
- # Add an ACL on `host2_if` which will tell us whether the packet
- # was flooded to it or not.
- ip link set $host2_if promisc on
- tc qdisc add dev $host2_if ingress
- tc filter add dev $host2_if ingress protocol ip pref 1 handle 101 \
- flower dst_mac $mac action drop
- $MZ $host1_if -c 1 -p 64 -b $mac -B $ip -t ip -q
- sleep 1
- tc -j -s filter show dev $host2_if ingress \
- | jq -e ".[] | select(.options.handle == 101) \
- | select(.options.actions[0].stats.packets == 1)" &> /dev/null
- if [[ $? -ne 0 && $should_flood == "true" || \
- $? -eq 0 && $should_flood == "false" ]]; then
- err=1
- fi
- tc filter del dev $host2_if ingress protocol ip pref 1 handle 101 flower
- tc qdisc del dev $host2_if ingress
- ip link set $host2_if promisc off
- return $err
- }
- flood_unicast_test()
- {
- local br_port=$1
- local host1_if=$2
- local host2_if=$3
- local mac=de:ad:be:ef:13:37
- local ip=192.0.2.100
- RET=0
- bridge link set dev $br_port flood off
- flood_test_do false $mac $ip $host1_if $host2_if
- check_err $? "Packet flooded when should not"
- bridge link set dev $br_port flood on
- flood_test_do true $mac $ip $host1_if $host2_if
- check_err $? "Packet was not flooded when should"
- log_test "Unknown unicast flood"
- }
- flood_multicast_test()
- {
- local br_port=$1
- local host1_if=$2
- local host2_if=$3
- local mac=01:00:5e:00:00:01
- local ip=239.0.0.1
- RET=0
- bridge link set dev $br_port mcast_flood off
- flood_test_do false $mac $ip $host1_if $host2_if
- check_err $? "Packet flooded when should not"
- bridge link set dev $br_port mcast_flood on
- flood_test_do true $mac $ip $host1_if $host2_if
- check_err $? "Packet was not flooded when should"
- log_test "Unregistered multicast flood"
- }
- flood_test()
- {
- # `br_port` is connected to `host2_if`
- local br_port=$1
- local host1_if=$2
- local host2_if=$3
- flood_unicast_test $br_port $host1_if $host2_if
- flood_multicast_test $br_port $host1_if $host2_if
- }
- __start_traffic()
- {
- local pktsize=$1; shift
- local proto=$1; shift
- local h_in=$1; shift # Where the traffic egresses the host
- local sip=$1; shift
- local dip=$1; shift
- local dmac=$1; shift
- local -a mz_args=("$@")
- $MZ $h_in -p $pktsize -A $sip -B $dip -c 0 \
- -a own -b $dmac -t "$proto" -q "${mz_args[@]}" &
- sleep 1
- }
- start_traffic_pktsize()
- {
- local pktsize=$1; shift
- local h_in=$1; shift
- local sip=$1; shift
- local dip=$1; shift
- local dmac=$1; shift
- local -a mz_args=("$@")
- __start_traffic $pktsize udp "$h_in" "$sip" "$dip" "$dmac" \
- "${mz_args[@]}"
- }
- start_tcp_traffic_pktsize()
- {
- local pktsize=$1; shift
- local h_in=$1; shift
- local sip=$1; shift
- local dip=$1; shift
- local dmac=$1; shift
- local -a mz_args=("$@")
- __start_traffic $pktsize tcp "$h_in" "$sip" "$dip" "$dmac" \
- "${mz_args[@]}"
- }
- start_traffic()
- {
- local h_in=$1; shift
- local sip=$1; shift
- local dip=$1; shift
- local dmac=$1; shift
- local -a mz_args=("$@")
- start_traffic_pktsize 8000 "$h_in" "$sip" "$dip" "$dmac" \
- "${mz_args[@]}"
- }
- start_tcp_traffic()
- {
- local h_in=$1; shift
- local sip=$1; shift
- local dip=$1; shift
- local dmac=$1; shift
- local -a mz_args=("$@")
- start_tcp_traffic_pktsize 8000 "$h_in" "$sip" "$dip" "$dmac" \
- "${mz_args[@]}"
- }
- stop_traffic()
- {
- # Suppress noise from killing mausezahn.
- { kill %% && wait %%; } 2>/dev/null
- }
- declare -A cappid
- declare -A capfile
- declare -A capout
- tcpdump_start()
- {
- local if_name=$1; shift
- local ns=$1; shift
- capfile[$if_name]=$(mktemp)
- capout[$if_name]=$(mktemp)
- if [ -z $ns ]; then
- ns_cmd=""
- else
- ns_cmd="ip netns exec ${ns}"
- fi
- if [ -z $SUDO_USER ] ; then
- capuser=""
- else
- capuser="-Z $SUDO_USER"
- fi
- $ns_cmd tcpdump $TCPDUMP_EXTRA_FLAGS -e -n -Q in -i $if_name \
- -s 65535 -B 32768 $capuser -w ${capfile[$if_name]} \
- > "${capout[$if_name]}" 2>&1 &
- cappid[$if_name]=$!
- sleep 1
- }
- tcpdump_stop()
- {
- local if_name=$1
- local pid=${cappid[$if_name]}
- $ns_cmd kill "$pid" && wait "$pid"
- sleep 1
- }
- tcpdump_cleanup()
- {
- local if_name=$1
- rm ${capfile[$if_name]} ${capout[$if_name]}
- }
- tcpdump_show()
- {
- local if_name=$1
- tcpdump -e -n -r ${capfile[$if_name]} 2>&1
- }
- # return 0 if the packet wasn't seen on host2_if or 1 if it was
- mcast_packet_test()
- {
- local mac=$1
- local src_ip=$2
- local ip=$3
- local host1_if=$4
- local host2_if=$5
- local seen=0
- local tc_proto="ip"
- local mz_v6arg=""
- # basic check to see if we were passed an IPv4 address, if not assume IPv6
- if [[ ! $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
- tc_proto="ipv6"
- mz_v6arg="-6"
- fi
- # Add an ACL on `host2_if` which will tell us whether the packet
- # was received by it or not.
- tc qdisc add dev $host2_if ingress
- tc filter add dev $host2_if ingress protocol $tc_proto pref 1 handle 101 \
- flower ip_proto udp dst_mac $mac action drop
- $MZ $host1_if $mz_v6arg -c 1 -p 64 -b $mac -A $src_ip -B $ip -t udp "dp=4096,sp=2048" -q
- sleep 1
- tc -j -s filter show dev $host2_if ingress \
- | jq -e ".[] | select(.options.handle == 101) \
- | select(.options.actions[0].stats.packets == 1)" &> /dev/null
- if [[ $? -eq 0 ]]; then
- seen=1
- fi
- tc filter del dev $host2_if ingress protocol $tc_proto pref 1 handle 101 flower
- tc qdisc del dev $host2_if ingress
- return $seen
- }
- brmcast_check_sg_entries()
- {
- local report=$1; shift
- local slist=("$@")
- local sarg=""
- for src in "${slist[@]}"; do
- sarg="${sarg} and .source_list[].address == \"$src\""
- done
- bridge -j -d -s mdb show dev br0 \
- | jq -e ".[].mdb[] | \
- select(.grp == \"$TEST_GROUP\" and .source_list != null $sarg)" &>/dev/null
- check_err $? "Wrong *,G entry source list after $report report"
- for sgent in "${slist[@]}"; do
- bridge -j -d -s mdb show dev br0 \
- | jq -e ".[].mdb[] | \
- select(.grp == \"$TEST_GROUP\" and .src == \"$sgent\")" &>/dev/null
- check_err $? "Missing S,G entry ($sgent, $TEST_GROUP)"
- done
- }
- brmcast_check_sg_fwding()
- {
- local should_fwd=$1; shift
- local sources=("$@")
- for src in "${sources[@]}"; do
- local retval=0
- mcast_packet_test $TEST_GROUP_MAC $src $TEST_GROUP $h2 $h1
- retval=$?
- if [ $should_fwd -eq 1 ]; then
- check_fail $retval "Didn't forward traffic from S,G ($src, $TEST_GROUP)"
- else
- check_err $retval "Forwarded traffic for blocked S,G ($src, $TEST_GROUP)"
- fi
- done
- }
- brmcast_check_sg_state()
- {
- local is_blocked=$1; shift
- local sources=("$@")
- local should_fail=1
- if [ $is_blocked -eq 1 ]; then
- should_fail=0
- fi
- for src in "${sources[@]}"; do
- bridge -j -d -s mdb show dev br0 \
- | jq -e ".[].mdb[] | \
- select(.grp == \"$TEST_GROUP\" and .source_list != null) |
- .source_list[] |
- select(.address == \"$src\") |
- select(.timer == \"0.00\")" &>/dev/null
- check_err_fail $should_fail $? "Entry $src has zero timer"
- bridge -j -d -s mdb show dev br0 \
- | jq -e ".[].mdb[] | \
- select(.grp == \"$TEST_GROUP\" and .src == \"$src\" and \
- .flags[] == \"blocked\")" &>/dev/null
- check_err_fail $should_fail $? "Entry $src has blocked flag"
- done
- }
- mc_join()
- {
- local if_name=$1
- local group=$2
- local vrf_name=$(master_name_get $if_name)
- # We don't care about actual reception, just about joining the
- # IP multicast group and adding the L2 address to the device's
- # MAC filtering table
- ip vrf exec $vrf_name \
- mreceive -g $group -I $if_name > /dev/null 2>&1 &
- mreceive_pid=$!
- sleep 1
- }
- mc_leave()
- {
- kill "$mreceive_pid" && wait "$mreceive_pid"
- }
- mc_send()
- {
- local if_name=$1
- local groups=$2
- local vrf_name=$(master_name_get $if_name)
- ip vrf exec $vrf_name \
- msend -g $groups -I $if_name -c 1 > /dev/null 2>&1
- }
- start_ip_monitor()
- {
- local mtype=$1; shift
- local ip=${1-ip}; shift
- # start the monitor in the background
- tmpfile=`mktemp /var/run/nexthoptestXXX`
- mpid=`($ip monitor $mtype > $tmpfile & echo $!) 2>/dev/null`
- sleep 0.2
- echo "$mpid $tmpfile"
- }
- stop_ip_monitor()
- {
- local mpid=$1; shift
- local tmpfile=$1; shift
- local el=$1; shift
- local what=$1; shift
- sleep 0.2
- kill $mpid
- local lines=`grep '^\w' $tmpfile | wc -l`
- test $lines -eq $el
- check_err $? "$what: $lines lines of events, expected $el"
- rm -rf $tmpfile
- }
- hw_stats_monitor_test()
- {
- local dev=$1; shift
- local type=$1; shift
- local make_suitable=$1; shift
- local make_unsuitable=$1; shift
- local ip=${1-ip}; shift
- RET=0
- # Expect a notification about enablement.
- local ipmout=$(start_ip_monitor stats "$ip")
- $ip stats set dev $dev ${type}_stats on
- stop_ip_monitor $ipmout 1 "${type}_stats enablement"
- # Expect a notification about offload.
- local ipmout=$(start_ip_monitor stats "$ip")
- $make_suitable
- stop_ip_monitor $ipmout 1 "${type}_stats installation"
- # Expect a notification about loss of offload.
- local ipmout=$(start_ip_monitor stats "$ip")
- $make_unsuitable
- stop_ip_monitor $ipmout 1 "${type}_stats deinstallation"
- # Expect a notification about disablement
- local ipmout=$(start_ip_monitor stats "$ip")
- $ip stats set dev $dev ${type}_stats off
- stop_ip_monitor $ipmout 1 "${type}_stats disablement"
- log_test "${type}_stats notifications"
- }
- ipv4_to_bytes()
- {
- local IP=$1; shift
- printf '%02x:' ${IP//./ } |
- sed 's/:$//'
- }
- # Convert a given IPv6 address, `IP' such that the :: token, if present, is
- # expanded, and each 16-bit group is padded with zeroes to be 4 hexadecimal
- # digits. An optional `BYTESEP' parameter can be given to further separate
- # individual bytes of each 16-bit group.
- expand_ipv6()
- {
- local IP=$1; shift
- local bytesep=$1; shift
- local cvt_ip=${IP/::/_}
- local colons=${cvt_ip//[^:]/}
- local allcol=:::::::
- # IP where :: -> the appropriate number of colons:
- local allcol_ip=${cvt_ip/_/${allcol:${#colons}}}
- echo $allcol_ip | tr : '\n' |
- sed s/^/0000/ |
- sed 's/.*\(..\)\(..\)/\1'"$bytesep"'\2/' |
- tr '\n' : |
- sed 's/:$//'
- }
- ipv6_to_bytes()
- {
- local IP=$1; shift
- expand_ipv6 "$IP" :
- }
- u16_to_bytes()
- {
- local u16=$1; shift
- printf "%04x" $u16 | sed 's/^/000/;s/^.*\(..\)\(..\)$/\1:\2/'
- }
- # Given a mausezahn-formatted payload (colon-separated bytes given as %02x),
- # possibly with a keyword CHECKSUM stashed where a 16-bit checksum should be,
- # calculate checksum as per RFC 1071, assuming the CHECKSUM field (if any)
- # stands for 00:00.
- payload_template_calc_checksum()
- {
- local payload=$1; shift
- (
- # Set input radix.
- echo "16i"
- # Push zero for the initial checksum.
- echo 0
- # Pad the payload with a terminating 00: in case we get an odd
- # number of bytes.
- echo "${payload%:}:00:" |
- sed 's/CHECKSUM/00:00/g' |
- tr '[:lower:]' '[:upper:]' |
- # Add the word to the checksum.
- sed 's/\(..\):\(..\):/\1\2+\n/g' |
- # Strip the extra odd byte we pushed if left unconverted.
- sed 's/\(..\):$//'
- echo "10000 ~ +" # Calculate and add carry.
- echo "FFFF r - p" # Bit-flip and print.
- ) |
- dc |
- tr '[:upper:]' '[:lower:]'
- }
- payload_template_expand_checksum()
- {
- local payload=$1; shift
- local checksum=$1; shift
- local ckbytes=$(u16_to_bytes $checksum)
- echo "$payload" | sed "s/CHECKSUM/$ckbytes/g"
- }
- payload_template_nbytes()
- {
- local payload=$1; shift
- payload_template_expand_checksum "${payload%:}" 0 |
- sed 's/:/\n/g' | wc -l
- }
- igmpv3_is_in_get()
- {
- local GRP=$1; shift
- local sources=("$@")
- local igmpv3
- local nsources=$(u16_to_bytes ${#sources[@]})
- # IS_IN ( $sources )
- igmpv3=$(:
- )"22:"$( : Type - Membership Report
- )"00:"$( : Reserved
- )"CHECKSUM:"$( : Checksum
- )"00:00:"$( : Reserved
- )"00:01:"$( : Number of Group Records
- )"01:"$( : Record Type - IS_IN
- )"00:"$( : Aux Data Len
- )"${nsources}:"$( : Number of Sources
- )"$(ipv4_to_bytes $GRP):"$( : Multicast Address
- )"$(for src in "${sources[@]}"; do
- ipv4_to_bytes $src
- echo -n :
- done)"$( : Source Addresses
- )
- local checksum=$(payload_template_calc_checksum "$igmpv3")
- payload_template_expand_checksum "$igmpv3" $checksum
- }
- igmpv2_leave_get()
- {
- local GRP=$1; shift
- local payload=$(:
- )"17:"$( : Type - Leave Group
- )"00:"$( : Max Resp Time - not meaningful
- )"CHECKSUM:"$( : Checksum
- )"$(ipv4_to_bytes $GRP)"$( : Group Address
- )
- local checksum=$(payload_template_calc_checksum "$payload")
- payload_template_expand_checksum "$payload" $checksum
- }
- mldv2_is_in_get()
- {
- local SIP=$1; shift
- local GRP=$1; shift
- local sources=("$@")
- local hbh
- local icmpv6
- local nsources=$(u16_to_bytes ${#sources[@]})
- hbh=$(:
- )"3a:"$( : Next Header - ICMPv6
- )"00:"$( : Hdr Ext Len
- )"00:00:00:00:00:00:"$( : Options and Padding
- )
- icmpv6=$(:
- )"8f:"$( : Type - MLDv2 Report
- )"00:"$( : Code
- )"CHECKSUM:"$( : Checksum
- )"00:00:"$( : Reserved
- )"00:01:"$( : Number of Group Records
- )"01:"$( : Record Type - IS_IN
- )"00:"$( : Aux Data Len
- )"${nsources}:"$( : Number of Sources
- )"$(ipv6_to_bytes $GRP):"$( : Multicast address
- )"$(for src in "${sources[@]}"; do
- ipv6_to_bytes $src
- echo -n :
- done)"$( : Source Addresses
- )
- local len=$(u16_to_bytes $(payload_template_nbytes $icmpv6))
- local sudohdr=$(:
- )"$(ipv6_to_bytes $SIP):"$( : SIP
- )"$(ipv6_to_bytes $GRP):"$( : DIP is multicast address
- )"${len}:"$( : Upper-layer length
- )"00:3a:"$( : Zero and next-header
- )
- local checksum=$(payload_template_calc_checksum ${sudohdr}${icmpv6})
- payload_template_expand_checksum "$hbh$icmpv6" $checksum
- }
- mldv1_done_get()
- {
- local SIP=$1; shift
- local GRP=$1; shift
- local hbh
- local icmpv6
- hbh=$(:
- )"3a:"$( : Next Header - ICMPv6
- )"00:"$( : Hdr Ext Len
- )"00:00:00:00:00:00:"$( : Options and Padding
- )
- icmpv6=$(:
- )"84:"$( : Type - MLDv1 Done
- )"00:"$( : Code
- )"CHECKSUM:"$( : Checksum
- )"00:00:"$( : Max Resp Delay - not meaningful
- )"00:00:"$( : Reserved
- )"$(ipv6_to_bytes $GRP):"$( : Multicast address
- )
- local len=$(u16_to_bytes $(payload_template_nbytes $icmpv6))
- local sudohdr=$(:
- )"$(ipv6_to_bytes $SIP):"$( : SIP
- )"$(ipv6_to_bytes $GRP):"$( : DIP is multicast address
- )"${len}:"$( : Upper-layer length
- )"00:3a:"$( : Zero and next-header
- )
- local checksum=$(payload_template_calc_checksum ${sudohdr}${icmpv6})
- payload_template_expand_checksum "$hbh$icmpv6" $checksum
- }
- bail_on_lldpad()
- {
- local reason1="$1"; shift
- local reason2="$1"; shift
- local caller=${FUNCNAME[1]}
- local src=${BASH_SOURCE[1]}
- if systemctl is-active --quiet lldpad; then
- cat >/dev/stderr <<-EOF
- WARNING: lldpad is running
- lldpad will likely $reason1, and this test will
- $reason2. Both are not supported at the same time,
- one of them is arbitrarily going to overwrite the
- other. That will cause spurious failures (or, unlikely,
- passes) of this test.
- EOF
- if [[ -z $ALLOW_LLDPAD ]]; then
- cat >/dev/stderr <<-EOF
- If you want to run the test anyway, please set
- an environment variable ALLOW_LLDPAD to a
- non-empty string.
- EOF
- log_test_skip $src:$caller
- exit $EXIT_STATUS
- else
- return
- fi
- fi
- }
- absval()
- {
- local v=$1; shift
- echo $((v > 0 ? v : -v))
- }
- has_unicast_flt()
- {
- local dev=$1; shift
- local mac_addr=$(mac_get $dev)
- local tmp=$(ether_addr_to_u64 $mac_addr)
- local promisc
- ip link set $dev up
- ip link add link $dev name macvlan-tmp type macvlan mode private
- ip link set macvlan-tmp address $(u64_to_ether_addr $((tmp + 1)))
- ip link set macvlan-tmp up
- promisc=$(ip -j -d link show dev $dev | jq -r '.[].promiscuity')
- ip link del macvlan-tmp
- [[ $promisc == 1 ]] && echo "no" || echo "yes"
- }
|