1*4882a593Smuzhiyun#!/bin/bash 2*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0 3*4882a593Smuzhiyun 4*4882a593Smuzhiyun############################################################################## 5*4882a593Smuzhiyun# Defines 6*4882a593Smuzhiyun 7*4882a593Smuzhiyun# Can be overridden by the configuration file. 8*4882a593SmuzhiyunPING=${PING:=ping} 9*4882a593SmuzhiyunPING6=${PING6:=ping6} 10*4882a593SmuzhiyunMZ=${MZ:=mausezahn} 11*4882a593SmuzhiyunARPING=${ARPING:=arping} 12*4882a593SmuzhiyunTEAMD=${TEAMD:=teamd} 13*4882a593SmuzhiyunWAIT_TIME=${WAIT_TIME:=5} 14*4882a593SmuzhiyunPAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} 15*4882a593SmuzhiyunPAUSE_ON_CLEANUP=${PAUSE_ON_CLEANUP:=no} 16*4882a593SmuzhiyunNETIF_TYPE=${NETIF_TYPE:=veth} 17*4882a593SmuzhiyunNETIF_CREATE=${NETIF_CREATE:=yes} 18*4882a593SmuzhiyunMCD=${MCD:=smcrouted} 19*4882a593SmuzhiyunMC_CLI=${MC_CLI:=smcroutectl} 20*4882a593SmuzhiyunPING_TIMEOUT=${PING_TIMEOUT:=5} 21*4882a593SmuzhiyunWAIT_TIMEOUT=${WAIT_TIMEOUT:=20} 22*4882a593SmuzhiyunINTERFACE_TIMEOUT=${INTERFACE_TIMEOUT:=600} 23*4882a593Smuzhiyun 24*4882a593Smuzhiyunrelative_path="${BASH_SOURCE%/*}" 25*4882a593Smuzhiyunif [[ "$relative_path" == "${BASH_SOURCE}" ]]; then 26*4882a593Smuzhiyun relative_path="." 27*4882a593Smuzhiyunfi 28*4882a593Smuzhiyun 29*4882a593Smuzhiyunif [[ -f $relative_path/forwarding.config ]]; then 30*4882a593Smuzhiyun source "$relative_path/forwarding.config" 31*4882a593Smuzhiyunfi 32*4882a593Smuzhiyun 33*4882a593Smuzhiyun############################################################################## 34*4882a593Smuzhiyun# Sanity checks 35*4882a593Smuzhiyun 36*4882a593Smuzhiyuncheck_tc_version() 37*4882a593Smuzhiyun{ 38*4882a593Smuzhiyun tc -j &> /dev/null 39*4882a593Smuzhiyun if [[ $? -ne 0 ]]; then 40*4882a593Smuzhiyun echo "SKIP: iproute2 too old; tc is missing JSON support" 41*4882a593Smuzhiyun exit 1 42*4882a593Smuzhiyun fi 43*4882a593Smuzhiyun} 44*4882a593Smuzhiyun 45*4882a593Smuzhiyuncheck_tc_shblock_support() 46*4882a593Smuzhiyun{ 47*4882a593Smuzhiyun tc filter help 2>&1 | grep block &> /dev/null 48*4882a593Smuzhiyun if [[ $? -ne 0 ]]; then 49*4882a593Smuzhiyun echo "SKIP: iproute2 too old; tc is missing shared block support" 50*4882a593Smuzhiyun exit 1 51*4882a593Smuzhiyun fi 52*4882a593Smuzhiyun} 53*4882a593Smuzhiyun 54*4882a593Smuzhiyuncheck_tc_chain_support() 55*4882a593Smuzhiyun{ 56*4882a593Smuzhiyun tc help 2>&1|grep chain &> /dev/null 57*4882a593Smuzhiyun if [[ $? -ne 0 ]]; then 58*4882a593Smuzhiyun echo "SKIP: iproute2 too old; tc is missing chain support" 59*4882a593Smuzhiyun exit 1 60*4882a593Smuzhiyun fi 61*4882a593Smuzhiyun} 62*4882a593Smuzhiyun 63*4882a593Smuzhiyuncheck_tc_action_hw_stats_support() 64*4882a593Smuzhiyun{ 65*4882a593Smuzhiyun tc actions help 2>&1 | grep -q hw_stats 66*4882a593Smuzhiyun if [[ $? -ne 0 ]]; then 67*4882a593Smuzhiyun echo "SKIP: iproute2 too old; tc is missing action hw_stats support" 68*4882a593Smuzhiyun exit 1 69*4882a593Smuzhiyun fi 70*4882a593Smuzhiyun} 71*4882a593Smuzhiyun 72*4882a593Smuzhiyunif [[ "$(id -u)" -ne 0 ]]; then 73*4882a593Smuzhiyun echo "SKIP: need root privileges" 74*4882a593Smuzhiyun exit 0 75*4882a593Smuzhiyunfi 76*4882a593Smuzhiyun 77*4882a593Smuzhiyunif [[ "$CHECK_TC" = "yes" ]]; then 78*4882a593Smuzhiyun check_tc_version 79*4882a593Smuzhiyunfi 80*4882a593Smuzhiyun 81*4882a593Smuzhiyunrequire_command() 82*4882a593Smuzhiyun{ 83*4882a593Smuzhiyun local cmd=$1; shift 84*4882a593Smuzhiyun 85*4882a593Smuzhiyun if [[ ! -x "$(command -v "$cmd")" ]]; then 86*4882a593Smuzhiyun echo "SKIP: $cmd not installed" 87*4882a593Smuzhiyun exit 1 88*4882a593Smuzhiyun fi 89*4882a593Smuzhiyun} 90*4882a593Smuzhiyun 91*4882a593Smuzhiyunrequire_command jq 92*4882a593Smuzhiyunrequire_command $MZ 93*4882a593Smuzhiyun 94*4882a593Smuzhiyunif [[ ! -v NUM_NETIFS ]]; then 95*4882a593Smuzhiyun echo "SKIP: importer does not define \"NUM_NETIFS\"" 96*4882a593Smuzhiyun exit 1 97*4882a593Smuzhiyunfi 98*4882a593Smuzhiyun 99*4882a593Smuzhiyun############################################################################## 100*4882a593Smuzhiyun# Command line options handling 101*4882a593Smuzhiyun 102*4882a593Smuzhiyuncount=0 103*4882a593Smuzhiyun 104*4882a593Smuzhiyunwhile [[ $# -gt 0 ]]; do 105*4882a593Smuzhiyun if [[ "$count" -eq "0" ]]; then 106*4882a593Smuzhiyun unset NETIFS 107*4882a593Smuzhiyun declare -A NETIFS 108*4882a593Smuzhiyun fi 109*4882a593Smuzhiyun count=$((count + 1)) 110*4882a593Smuzhiyun NETIFS[p$count]="$1" 111*4882a593Smuzhiyun shift 112*4882a593Smuzhiyundone 113*4882a593Smuzhiyun 114*4882a593Smuzhiyun############################################################################## 115*4882a593Smuzhiyun# Network interfaces configuration 116*4882a593Smuzhiyun 117*4882a593Smuzhiyuncreate_netif_veth() 118*4882a593Smuzhiyun{ 119*4882a593Smuzhiyun local i 120*4882a593Smuzhiyun 121*4882a593Smuzhiyun for ((i = 1; i <= NUM_NETIFS; ++i)); do 122*4882a593Smuzhiyun local j=$((i+1)) 123*4882a593Smuzhiyun 124*4882a593Smuzhiyun ip link show dev ${NETIFS[p$i]} &> /dev/null 125*4882a593Smuzhiyun if [[ $? -ne 0 ]]; then 126*4882a593Smuzhiyun ip link add ${NETIFS[p$i]} type veth \ 127*4882a593Smuzhiyun peer name ${NETIFS[p$j]} 128*4882a593Smuzhiyun if [[ $? -ne 0 ]]; then 129*4882a593Smuzhiyun echo "Failed to create netif" 130*4882a593Smuzhiyun exit 1 131*4882a593Smuzhiyun fi 132*4882a593Smuzhiyun fi 133*4882a593Smuzhiyun i=$j 134*4882a593Smuzhiyun done 135*4882a593Smuzhiyun} 136*4882a593Smuzhiyun 137*4882a593Smuzhiyuncreate_netif() 138*4882a593Smuzhiyun{ 139*4882a593Smuzhiyun case "$NETIF_TYPE" in 140*4882a593Smuzhiyun veth) create_netif_veth 141*4882a593Smuzhiyun ;; 142*4882a593Smuzhiyun *) echo "Can not create interfaces of type \'$NETIF_TYPE\'" 143*4882a593Smuzhiyun exit 1 144*4882a593Smuzhiyun ;; 145*4882a593Smuzhiyun esac 146*4882a593Smuzhiyun} 147*4882a593Smuzhiyun 148*4882a593Smuzhiyunif [[ "$NETIF_CREATE" = "yes" ]]; then 149*4882a593Smuzhiyun create_netif 150*4882a593Smuzhiyunfi 151*4882a593Smuzhiyun 152*4882a593Smuzhiyunfor ((i = 1; i <= NUM_NETIFS; ++i)); do 153*4882a593Smuzhiyun ip link show dev ${NETIFS[p$i]} &> /dev/null 154*4882a593Smuzhiyun if [[ $? -ne 0 ]]; then 155*4882a593Smuzhiyun echo "SKIP: could not find all required interfaces" 156*4882a593Smuzhiyun exit 1 157*4882a593Smuzhiyun fi 158*4882a593Smuzhiyundone 159*4882a593Smuzhiyun 160*4882a593Smuzhiyun############################################################################## 161*4882a593Smuzhiyun# Helpers 162*4882a593Smuzhiyun 163*4882a593Smuzhiyun# Exit status to return at the end. Set in case one of the tests fails. 164*4882a593SmuzhiyunEXIT_STATUS=0 165*4882a593Smuzhiyun# Per-test return value. Clear at the beginning of each test. 166*4882a593SmuzhiyunRET=0 167*4882a593Smuzhiyun 168*4882a593Smuzhiyuncheck_err() 169*4882a593Smuzhiyun{ 170*4882a593Smuzhiyun local err=$1 171*4882a593Smuzhiyun local msg=$2 172*4882a593Smuzhiyun 173*4882a593Smuzhiyun if [[ $RET -eq 0 && $err -ne 0 ]]; then 174*4882a593Smuzhiyun RET=$err 175*4882a593Smuzhiyun retmsg=$msg 176*4882a593Smuzhiyun fi 177*4882a593Smuzhiyun} 178*4882a593Smuzhiyun 179*4882a593Smuzhiyuncheck_fail() 180*4882a593Smuzhiyun{ 181*4882a593Smuzhiyun local err=$1 182*4882a593Smuzhiyun local msg=$2 183*4882a593Smuzhiyun 184*4882a593Smuzhiyun if [[ $RET -eq 0 && $err -eq 0 ]]; then 185*4882a593Smuzhiyun RET=1 186*4882a593Smuzhiyun retmsg=$msg 187*4882a593Smuzhiyun fi 188*4882a593Smuzhiyun} 189*4882a593Smuzhiyun 190*4882a593Smuzhiyuncheck_err_fail() 191*4882a593Smuzhiyun{ 192*4882a593Smuzhiyun local should_fail=$1; shift 193*4882a593Smuzhiyun local err=$1; shift 194*4882a593Smuzhiyun local what=$1; shift 195*4882a593Smuzhiyun 196*4882a593Smuzhiyun if ((should_fail)); then 197*4882a593Smuzhiyun check_fail $err "$what succeeded, but should have failed" 198*4882a593Smuzhiyun else 199*4882a593Smuzhiyun check_err $err "$what failed" 200*4882a593Smuzhiyun fi 201*4882a593Smuzhiyun} 202*4882a593Smuzhiyun 203*4882a593Smuzhiyunlog_test() 204*4882a593Smuzhiyun{ 205*4882a593Smuzhiyun local test_name=$1 206*4882a593Smuzhiyun local opt_str=$2 207*4882a593Smuzhiyun 208*4882a593Smuzhiyun if [[ $# -eq 2 ]]; then 209*4882a593Smuzhiyun opt_str="($opt_str)" 210*4882a593Smuzhiyun fi 211*4882a593Smuzhiyun 212*4882a593Smuzhiyun if [[ $RET -ne 0 ]]; then 213*4882a593Smuzhiyun EXIT_STATUS=1 214*4882a593Smuzhiyun printf "TEST: %-60s [FAIL]\n" "$test_name $opt_str" 215*4882a593Smuzhiyun if [[ ! -z "$retmsg" ]]; then 216*4882a593Smuzhiyun printf "\t%s\n" "$retmsg" 217*4882a593Smuzhiyun fi 218*4882a593Smuzhiyun if [ "${PAUSE_ON_FAIL}" = "yes" ]; then 219*4882a593Smuzhiyun echo "Hit enter to continue, 'q' to quit" 220*4882a593Smuzhiyun read a 221*4882a593Smuzhiyun [ "$a" = "q" ] && exit 1 222*4882a593Smuzhiyun fi 223*4882a593Smuzhiyun return 1 224*4882a593Smuzhiyun fi 225*4882a593Smuzhiyun 226*4882a593Smuzhiyun printf "TEST: %-60s [ OK ]\n" "$test_name $opt_str" 227*4882a593Smuzhiyun return 0 228*4882a593Smuzhiyun} 229*4882a593Smuzhiyun 230*4882a593Smuzhiyunlog_info() 231*4882a593Smuzhiyun{ 232*4882a593Smuzhiyun local msg=$1 233*4882a593Smuzhiyun 234*4882a593Smuzhiyun echo "INFO: $msg" 235*4882a593Smuzhiyun} 236*4882a593Smuzhiyun 237*4882a593Smuzhiyunbusywait() 238*4882a593Smuzhiyun{ 239*4882a593Smuzhiyun local timeout=$1; shift 240*4882a593Smuzhiyun 241*4882a593Smuzhiyun local start_time="$(date -u +%s%3N)" 242*4882a593Smuzhiyun while true 243*4882a593Smuzhiyun do 244*4882a593Smuzhiyun local out 245*4882a593Smuzhiyun out=$("$@") 246*4882a593Smuzhiyun local ret=$? 247*4882a593Smuzhiyun if ((!ret)); then 248*4882a593Smuzhiyun echo -n "$out" 249*4882a593Smuzhiyun return 0 250*4882a593Smuzhiyun fi 251*4882a593Smuzhiyun 252*4882a593Smuzhiyun local current_time="$(date -u +%s%3N)" 253*4882a593Smuzhiyun if ((current_time - start_time > timeout)); then 254*4882a593Smuzhiyun echo -n "$out" 255*4882a593Smuzhiyun return 1 256*4882a593Smuzhiyun fi 257*4882a593Smuzhiyun done 258*4882a593Smuzhiyun} 259*4882a593Smuzhiyun 260*4882a593Smuzhiyunnot() 261*4882a593Smuzhiyun{ 262*4882a593Smuzhiyun "$@" 263*4882a593Smuzhiyun [[ $? != 0 ]] 264*4882a593Smuzhiyun} 265*4882a593Smuzhiyun 266*4882a593Smuzhiyungrep_bridge_fdb() 267*4882a593Smuzhiyun{ 268*4882a593Smuzhiyun local addr=$1; shift 269*4882a593Smuzhiyun local word 270*4882a593Smuzhiyun local flag 271*4882a593Smuzhiyun 272*4882a593Smuzhiyun if [ "$1" == "self" ] || [ "$1" == "master" ]; then 273*4882a593Smuzhiyun word=$1; shift 274*4882a593Smuzhiyun if [ "$1" == "-v" ]; then 275*4882a593Smuzhiyun flag=$1; shift 276*4882a593Smuzhiyun fi 277*4882a593Smuzhiyun fi 278*4882a593Smuzhiyun 279*4882a593Smuzhiyun $@ | grep $addr | grep $flag "$word" 280*4882a593Smuzhiyun} 281*4882a593Smuzhiyun 282*4882a593Smuzhiyunwait_for_offload() 283*4882a593Smuzhiyun{ 284*4882a593Smuzhiyun "$@" | grep -q offload 285*4882a593Smuzhiyun} 286*4882a593Smuzhiyun 287*4882a593Smuzhiyununtil_counter_is() 288*4882a593Smuzhiyun{ 289*4882a593Smuzhiyun local expr=$1; shift 290*4882a593Smuzhiyun local current=$("$@") 291*4882a593Smuzhiyun 292*4882a593Smuzhiyun echo $((current)) 293*4882a593Smuzhiyun ((current $expr)) 294*4882a593Smuzhiyun} 295*4882a593Smuzhiyun 296*4882a593Smuzhiyunbusywait_for_counter() 297*4882a593Smuzhiyun{ 298*4882a593Smuzhiyun local timeout=$1; shift 299*4882a593Smuzhiyun local delta=$1; shift 300*4882a593Smuzhiyun 301*4882a593Smuzhiyun local base=$("$@") 302*4882a593Smuzhiyun busywait "$timeout" until_counter_is ">= $((base + delta))" "$@" 303*4882a593Smuzhiyun} 304*4882a593Smuzhiyun 305*4882a593Smuzhiyunsetup_wait_dev() 306*4882a593Smuzhiyun{ 307*4882a593Smuzhiyun local dev=$1; shift 308*4882a593Smuzhiyun local wait_time=${1:-$WAIT_TIME}; shift 309*4882a593Smuzhiyun 310*4882a593Smuzhiyun setup_wait_dev_with_timeout "$dev" $INTERFACE_TIMEOUT $wait_time 311*4882a593Smuzhiyun 312*4882a593Smuzhiyun if (($?)); then 313*4882a593Smuzhiyun check_err 1 314*4882a593Smuzhiyun log_test setup_wait_dev ": Interface $dev does not come up." 315*4882a593Smuzhiyun exit 1 316*4882a593Smuzhiyun fi 317*4882a593Smuzhiyun} 318*4882a593Smuzhiyun 319*4882a593Smuzhiyunsetup_wait_dev_with_timeout() 320*4882a593Smuzhiyun{ 321*4882a593Smuzhiyun local dev=$1; shift 322*4882a593Smuzhiyun local max_iterations=${1:-$WAIT_TIMEOUT}; shift 323*4882a593Smuzhiyun local wait_time=${1:-$WAIT_TIME}; shift 324*4882a593Smuzhiyun local i 325*4882a593Smuzhiyun 326*4882a593Smuzhiyun for ((i = 1; i <= $max_iterations; ++i)); do 327*4882a593Smuzhiyun ip link show dev $dev up \ 328*4882a593Smuzhiyun | grep 'state UP' &> /dev/null 329*4882a593Smuzhiyun if [[ $? -ne 0 ]]; then 330*4882a593Smuzhiyun sleep 1 331*4882a593Smuzhiyun else 332*4882a593Smuzhiyun sleep $wait_time 333*4882a593Smuzhiyun return 0 334*4882a593Smuzhiyun fi 335*4882a593Smuzhiyun done 336*4882a593Smuzhiyun 337*4882a593Smuzhiyun return 1 338*4882a593Smuzhiyun} 339*4882a593Smuzhiyun 340*4882a593Smuzhiyunsetup_wait() 341*4882a593Smuzhiyun{ 342*4882a593Smuzhiyun local num_netifs=${1:-$NUM_NETIFS} 343*4882a593Smuzhiyun local i 344*4882a593Smuzhiyun 345*4882a593Smuzhiyun for ((i = 1; i <= num_netifs; ++i)); do 346*4882a593Smuzhiyun setup_wait_dev ${NETIFS[p$i]} 0 347*4882a593Smuzhiyun done 348*4882a593Smuzhiyun 349*4882a593Smuzhiyun # Make sure links are ready. 350*4882a593Smuzhiyun sleep $WAIT_TIME 351*4882a593Smuzhiyun} 352*4882a593Smuzhiyun 353*4882a593Smuzhiyuncmd_jq() 354*4882a593Smuzhiyun{ 355*4882a593Smuzhiyun local cmd=$1 356*4882a593Smuzhiyun local jq_exp=$2 357*4882a593Smuzhiyun local jq_opts=$3 358*4882a593Smuzhiyun local ret 359*4882a593Smuzhiyun local output 360*4882a593Smuzhiyun 361*4882a593Smuzhiyun output="$($cmd)" 362*4882a593Smuzhiyun # it the command fails, return error right away 363*4882a593Smuzhiyun ret=$? 364*4882a593Smuzhiyun if [[ $ret -ne 0 ]]; then 365*4882a593Smuzhiyun return $ret 366*4882a593Smuzhiyun fi 367*4882a593Smuzhiyun output=$(echo $output | jq -r $jq_opts "$jq_exp") 368*4882a593Smuzhiyun ret=$? 369*4882a593Smuzhiyun if [[ $ret -ne 0 ]]; then 370*4882a593Smuzhiyun return $ret 371*4882a593Smuzhiyun fi 372*4882a593Smuzhiyun echo $output 373*4882a593Smuzhiyun # return success only in case of non-empty output 374*4882a593Smuzhiyun [ ! -z "$output" ] 375*4882a593Smuzhiyun} 376*4882a593Smuzhiyun 377*4882a593Smuzhiyunlldpad_app_wait_set() 378*4882a593Smuzhiyun{ 379*4882a593Smuzhiyun local dev=$1; shift 380*4882a593Smuzhiyun 381*4882a593Smuzhiyun while lldptool -t -i $dev -V APP -c app | grep -Eq "pending|unknown"; do 382*4882a593Smuzhiyun echo "$dev: waiting for lldpad to push pending APP updates" 383*4882a593Smuzhiyun sleep 5 384*4882a593Smuzhiyun done 385*4882a593Smuzhiyun} 386*4882a593Smuzhiyun 387*4882a593Smuzhiyunlldpad_app_wait_del() 388*4882a593Smuzhiyun{ 389*4882a593Smuzhiyun # Give lldpad a chance to push down the changes. If the device is downed 390*4882a593Smuzhiyun # too soon, the updates will be left pending. However, they will have 391*4882a593Smuzhiyun # been struck off the lldpad's DB already, so we won't be able to tell 392*4882a593Smuzhiyun # they are pending. Then on next test iteration this would cause 393*4882a593Smuzhiyun # weirdness as newly-added APP rules conflict with the old ones, 394*4882a593Smuzhiyun # sometimes getting stuck in an "unknown" state. 395*4882a593Smuzhiyun sleep 5 396*4882a593Smuzhiyun} 397*4882a593Smuzhiyun 398*4882a593Smuzhiyunpre_cleanup() 399*4882a593Smuzhiyun{ 400*4882a593Smuzhiyun if [ "${PAUSE_ON_CLEANUP}" = "yes" ]; then 401*4882a593Smuzhiyun echo "Pausing before cleanup, hit any key to continue" 402*4882a593Smuzhiyun read 403*4882a593Smuzhiyun fi 404*4882a593Smuzhiyun} 405*4882a593Smuzhiyun 406*4882a593Smuzhiyunvrf_prepare() 407*4882a593Smuzhiyun{ 408*4882a593Smuzhiyun ip -4 rule add pref 32765 table local 409*4882a593Smuzhiyun ip -4 rule del pref 0 410*4882a593Smuzhiyun ip -6 rule add pref 32765 table local 411*4882a593Smuzhiyun ip -6 rule del pref 0 412*4882a593Smuzhiyun} 413*4882a593Smuzhiyun 414*4882a593Smuzhiyunvrf_cleanup() 415*4882a593Smuzhiyun{ 416*4882a593Smuzhiyun ip -6 rule add pref 0 table local 417*4882a593Smuzhiyun ip -6 rule del pref 32765 418*4882a593Smuzhiyun ip -4 rule add pref 0 table local 419*4882a593Smuzhiyun ip -4 rule del pref 32765 420*4882a593Smuzhiyun} 421*4882a593Smuzhiyun 422*4882a593Smuzhiyun__last_tb_id=0 423*4882a593Smuzhiyundeclare -A __TB_IDS 424*4882a593Smuzhiyun 425*4882a593Smuzhiyun__vrf_td_id_assign() 426*4882a593Smuzhiyun{ 427*4882a593Smuzhiyun local vrf_name=$1 428*4882a593Smuzhiyun 429*4882a593Smuzhiyun __last_tb_id=$((__last_tb_id + 1)) 430*4882a593Smuzhiyun __TB_IDS[$vrf_name]=$__last_tb_id 431*4882a593Smuzhiyun return $__last_tb_id 432*4882a593Smuzhiyun} 433*4882a593Smuzhiyun 434*4882a593Smuzhiyun__vrf_td_id_lookup() 435*4882a593Smuzhiyun{ 436*4882a593Smuzhiyun local vrf_name=$1 437*4882a593Smuzhiyun 438*4882a593Smuzhiyun return ${__TB_IDS[$vrf_name]} 439*4882a593Smuzhiyun} 440*4882a593Smuzhiyun 441*4882a593Smuzhiyunvrf_create() 442*4882a593Smuzhiyun{ 443*4882a593Smuzhiyun local vrf_name=$1 444*4882a593Smuzhiyun local tb_id 445*4882a593Smuzhiyun 446*4882a593Smuzhiyun __vrf_td_id_assign $vrf_name 447*4882a593Smuzhiyun tb_id=$? 448*4882a593Smuzhiyun 449*4882a593Smuzhiyun ip link add dev $vrf_name type vrf table $tb_id 450*4882a593Smuzhiyun ip -4 route add table $tb_id unreachable default metric 4278198272 451*4882a593Smuzhiyun ip -6 route add table $tb_id unreachable default metric 4278198272 452*4882a593Smuzhiyun} 453*4882a593Smuzhiyun 454*4882a593Smuzhiyunvrf_destroy() 455*4882a593Smuzhiyun{ 456*4882a593Smuzhiyun local vrf_name=$1 457*4882a593Smuzhiyun local tb_id 458*4882a593Smuzhiyun 459*4882a593Smuzhiyun __vrf_td_id_lookup $vrf_name 460*4882a593Smuzhiyun tb_id=$? 461*4882a593Smuzhiyun 462*4882a593Smuzhiyun ip -6 route del table $tb_id unreachable default metric 4278198272 463*4882a593Smuzhiyun ip -4 route del table $tb_id unreachable default metric 4278198272 464*4882a593Smuzhiyun ip link del dev $vrf_name 465*4882a593Smuzhiyun} 466*4882a593Smuzhiyun 467*4882a593Smuzhiyun__addr_add_del() 468*4882a593Smuzhiyun{ 469*4882a593Smuzhiyun local if_name=$1 470*4882a593Smuzhiyun local add_del=$2 471*4882a593Smuzhiyun local array 472*4882a593Smuzhiyun 473*4882a593Smuzhiyun shift 474*4882a593Smuzhiyun shift 475*4882a593Smuzhiyun array=("${@}") 476*4882a593Smuzhiyun 477*4882a593Smuzhiyun for addrstr in "${array[@]}"; do 478*4882a593Smuzhiyun ip address $add_del $addrstr dev $if_name 479*4882a593Smuzhiyun done 480*4882a593Smuzhiyun} 481*4882a593Smuzhiyun 482*4882a593Smuzhiyun__simple_if_init() 483*4882a593Smuzhiyun{ 484*4882a593Smuzhiyun local if_name=$1; shift 485*4882a593Smuzhiyun local vrf_name=$1; shift 486*4882a593Smuzhiyun local addrs=("${@}") 487*4882a593Smuzhiyun 488*4882a593Smuzhiyun ip link set dev $if_name master $vrf_name 489*4882a593Smuzhiyun ip link set dev $if_name up 490*4882a593Smuzhiyun 491*4882a593Smuzhiyun __addr_add_del $if_name add "${addrs[@]}" 492*4882a593Smuzhiyun} 493*4882a593Smuzhiyun 494*4882a593Smuzhiyun__simple_if_fini() 495*4882a593Smuzhiyun{ 496*4882a593Smuzhiyun local if_name=$1; shift 497*4882a593Smuzhiyun local addrs=("${@}") 498*4882a593Smuzhiyun 499*4882a593Smuzhiyun __addr_add_del $if_name del "${addrs[@]}" 500*4882a593Smuzhiyun 501*4882a593Smuzhiyun ip link set dev $if_name down 502*4882a593Smuzhiyun ip link set dev $if_name nomaster 503*4882a593Smuzhiyun} 504*4882a593Smuzhiyun 505*4882a593Smuzhiyunsimple_if_init() 506*4882a593Smuzhiyun{ 507*4882a593Smuzhiyun local if_name=$1 508*4882a593Smuzhiyun local vrf_name 509*4882a593Smuzhiyun local array 510*4882a593Smuzhiyun 511*4882a593Smuzhiyun shift 512*4882a593Smuzhiyun vrf_name=v$if_name 513*4882a593Smuzhiyun array=("${@}") 514*4882a593Smuzhiyun 515*4882a593Smuzhiyun vrf_create $vrf_name 516*4882a593Smuzhiyun ip link set dev $vrf_name up 517*4882a593Smuzhiyun __simple_if_init $if_name $vrf_name "${array[@]}" 518*4882a593Smuzhiyun} 519*4882a593Smuzhiyun 520*4882a593Smuzhiyunsimple_if_fini() 521*4882a593Smuzhiyun{ 522*4882a593Smuzhiyun local if_name=$1 523*4882a593Smuzhiyun local vrf_name 524*4882a593Smuzhiyun local array 525*4882a593Smuzhiyun 526*4882a593Smuzhiyun shift 527*4882a593Smuzhiyun vrf_name=v$if_name 528*4882a593Smuzhiyun array=("${@}") 529*4882a593Smuzhiyun 530*4882a593Smuzhiyun __simple_if_fini $if_name "${array[@]}" 531*4882a593Smuzhiyun vrf_destroy $vrf_name 532*4882a593Smuzhiyun} 533*4882a593Smuzhiyun 534*4882a593Smuzhiyuntunnel_create() 535*4882a593Smuzhiyun{ 536*4882a593Smuzhiyun local name=$1; shift 537*4882a593Smuzhiyun local type=$1; shift 538*4882a593Smuzhiyun local local=$1; shift 539*4882a593Smuzhiyun local remote=$1; shift 540*4882a593Smuzhiyun 541*4882a593Smuzhiyun ip link add name $name type $type \ 542*4882a593Smuzhiyun local $local remote $remote "$@" 543*4882a593Smuzhiyun ip link set dev $name up 544*4882a593Smuzhiyun} 545*4882a593Smuzhiyun 546*4882a593Smuzhiyuntunnel_destroy() 547*4882a593Smuzhiyun{ 548*4882a593Smuzhiyun local name=$1; shift 549*4882a593Smuzhiyun 550*4882a593Smuzhiyun ip link del dev $name 551*4882a593Smuzhiyun} 552*4882a593Smuzhiyun 553*4882a593Smuzhiyunvlan_create() 554*4882a593Smuzhiyun{ 555*4882a593Smuzhiyun local if_name=$1; shift 556*4882a593Smuzhiyun local vid=$1; shift 557*4882a593Smuzhiyun local vrf=$1; shift 558*4882a593Smuzhiyun local ips=("${@}") 559*4882a593Smuzhiyun local name=$if_name.$vid 560*4882a593Smuzhiyun 561*4882a593Smuzhiyun ip link add name $name link $if_name type vlan id $vid 562*4882a593Smuzhiyun if [ "$vrf" != "" ]; then 563*4882a593Smuzhiyun ip link set dev $name master $vrf 564*4882a593Smuzhiyun fi 565*4882a593Smuzhiyun ip link set dev $name up 566*4882a593Smuzhiyun __addr_add_del $name add "${ips[@]}" 567*4882a593Smuzhiyun} 568*4882a593Smuzhiyun 569*4882a593Smuzhiyunvlan_destroy() 570*4882a593Smuzhiyun{ 571*4882a593Smuzhiyun local if_name=$1; shift 572*4882a593Smuzhiyun local vid=$1; shift 573*4882a593Smuzhiyun local name=$if_name.$vid 574*4882a593Smuzhiyun 575*4882a593Smuzhiyun ip link del dev $name 576*4882a593Smuzhiyun} 577*4882a593Smuzhiyun 578*4882a593Smuzhiyunteam_create() 579*4882a593Smuzhiyun{ 580*4882a593Smuzhiyun local if_name=$1; shift 581*4882a593Smuzhiyun local mode=$1; shift 582*4882a593Smuzhiyun 583*4882a593Smuzhiyun require_command $TEAMD 584*4882a593Smuzhiyun $TEAMD -t $if_name -d -c '{"runner": {"name": "'$mode'"}}' 585*4882a593Smuzhiyun for slave in "$@"; do 586*4882a593Smuzhiyun ip link set dev $slave down 587*4882a593Smuzhiyun ip link set dev $slave master $if_name 588*4882a593Smuzhiyun ip link set dev $slave up 589*4882a593Smuzhiyun done 590*4882a593Smuzhiyun ip link set dev $if_name up 591*4882a593Smuzhiyun} 592*4882a593Smuzhiyun 593*4882a593Smuzhiyunteam_destroy() 594*4882a593Smuzhiyun{ 595*4882a593Smuzhiyun local if_name=$1; shift 596*4882a593Smuzhiyun 597*4882a593Smuzhiyun $TEAMD -t $if_name -k 598*4882a593Smuzhiyun} 599*4882a593Smuzhiyun 600*4882a593Smuzhiyunmaster_name_get() 601*4882a593Smuzhiyun{ 602*4882a593Smuzhiyun local if_name=$1 603*4882a593Smuzhiyun 604*4882a593Smuzhiyun ip -j link show dev $if_name | jq -r '.[]["master"]' 605*4882a593Smuzhiyun} 606*4882a593Smuzhiyun 607*4882a593Smuzhiyunlink_stats_get() 608*4882a593Smuzhiyun{ 609*4882a593Smuzhiyun local if_name=$1; shift 610*4882a593Smuzhiyun local dir=$1; shift 611*4882a593Smuzhiyun local stat=$1; shift 612*4882a593Smuzhiyun 613*4882a593Smuzhiyun ip -j -s link show dev $if_name \ 614*4882a593Smuzhiyun | jq '.[]["stats64"]["'$dir'"]["'$stat'"]' 615*4882a593Smuzhiyun} 616*4882a593Smuzhiyun 617*4882a593Smuzhiyunlink_stats_tx_packets_get() 618*4882a593Smuzhiyun{ 619*4882a593Smuzhiyun link_stats_get $1 tx packets 620*4882a593Smuzhiyun} 621*4882a593Smuzhiyun 622*4882a593Smuzhiyunlink_stats_rx_errors_get() 623*4882a593Smuzhiyun{ 624*4882a593Smuzhiyun link_stats_get $1 rx errors 625*4882a593Smuzhiyun} 626*4882a593Smuzhiyun 627*4882a593Smuzhiyuntc_rule_stats_get() 628*4882a593Smuzhiyun{ 629*4882a593Smuzhiyun local dev=$1; shift 630*4882a593Smuzhiyun local pref=$1; shift 631*4882a593Smuzhiyun local dir=$1; shift 632*4882a593Smuzhiyun local selector=${1:-.packets}; shift 633*4882a593Smuzhiyun 634*4882a593Smuzhiyun tc -j -s filter show dev $dev ${dir:-ingress} pref $pref \ 635*4882a593Smuzhiyun | jq ".[1].options.actions[].stats$selector" 636*4882a593Smuzhiyun} 637*4882a593Smuzhiyun 638*4882a593Smuzhiyuntc_rule_handle_stats_get() 639*4882a593Smuzhiyun{ 640*4882a593Smuzhiyun local id=$1; shift 641*4882a593Smuzhiyun local handle=$1; shift 642*4882a593Smuzhiyun local selector=${1:-.packets}; shift 643*4882a593Smuzhiyun 644*4882a593Smuzhiyun tc -j -s filter show $id \ 645*4882a593Smuzhiyun | jq ".[] | select(.options.handle == $handle) | \ 646*4882a593Smuzhiyun .options.actions[0].stats$selector" 647*4882a593Smuzhiyun} 648*4882a593Smuzhiyun 649*4882a593Smuzhiyunethtool_stats_get() 650*4882a593Smuzhiyun{ 651*4882a593Smuzhiyun local dev=$1; shift 652*4882a593Smuzhiyun local stat=$1; shift 653*4882a593Smuzhiyun 654*4882a593Smuzhiyun ethtool -S $dev | grep "^ *$stat:" | head -n 1 | cut -d: -f2 655*4882a593Smuzhiyun} 656*4882a593Smuzhiyun 657*4882a593Smuzhiyunqdisc_stats_get() 658*4882a593Smuzhiyun{ 659*4882a593Smuzhiyun local dev=$1; shift 660*4882a593Smuzhiyun local handle=$1; shift 661*4882a593Smuzhiyun local selector=$1; shift 662*4882a593Smuzhiyun 663*4882a593Smuzhiyun tc -j -s qdisc show dev "$dev" \ 664*4882a593Smuzhiyun | jq '.[] | select(.handle == "'"$handle"'") | '"$selector" 665*4882a593Smuzhiyun} 666*4882a593Smuzhiyun 667*4882a593Smuzhiyunqdisc_parent_stats_get() 668*4882a593Smuzhiyun{ 669*4882a593Smuzhiyun local dev=$1; shift 670*4882a593Smuzhiyun local parent=$1; shift 671*4882a593Smuzhiyun local selector=$1; shift 672*4882a593Smuzhiyun 673*4882a593Smuzhiyun tc -j -s qdisc show dev "$dev" invisible \ 674*4882a593Smuzhiyun | jq '.[] | select(.parent == "'"$parent"'") | '"$selector" 675*4882a593Smuzhiyun} 676*4882a593Smuzhiyun 677*4882a593Smuzhiyunipv6_stats_get() 678*4882a593Smuzhiyun{ 679*4882a593Smuzhiyun local dev=$1; shift 680*4882a593Smuzhiyun local stat=$1; shift 681*4882a593Smuzhiyun 682*4882a593Smuzhiyun cat /proc/net/dev_snmp6/$dev | grep "^$stat" | cut -f2 683*4882a593Smuzhiyun} 684*4882a593Smuzhiyun 685*4882a593Smuzhiyunhumanize() 686*4882a593Smuzhiyun{ 687*4882a593Smuzhiyun local speed=$1; shift 688*4882a593Smuzhiyun 689*4882a593Smuzhiyun for unit in bps Kbps Mbps Gbps; do 690*4882a593Smuzhiyun if (($(echo "$speed < 1024" | bc))); then 691*4882a593Smuzhiyun break 692*4882a593Smuzhiyun fi 693*4882a593Smuzhiyun 694*4882a593Smuzhiyun speed=$(echo "scale=1; $speed / 1024" | bc) 695*4882a593Smuzhiyun done 696*4882a593Smuzhiyun 697*4882a593Smuzhiyun echo "$speed${unit}" 698*4882a593Smuzhiyun} 699*4882a593Smuzhiyun 700*4882a593Smuzhiyunrate() 701*4882a593Smuzhiyun{ 702*4882a593Smuzhiyun local t0=$1; shift 703*4882a593Smuzhiyun local t1=$1; shift 704*4882a593Smuzhiyun local interval=$1; shift 705*4882a593Smuzhiyun 706*4882a593Smuzhiyun echo $((8 * (t1 - t0) / interval)) 707*4882a593Smuzhiyun} 708*4882a593Smuzhiyun 709*4882a593Smuzhiyunmac_get() 710*4882a593Smuzhiyun{ 711*4882a593Smuzhiyun local if_name=$1 712*4882a593Smuzhiyun 713*4882a593Smuzhiyun ip -j link show dev $if_name | jq -r '.[]["address"]' 714*4882a593Smuzhiyun} 715*4882a593Smuzhiyun 716*4882a593Smuzhiyunbridge_ageing_time_get() 717*4882a593Smuzhiyun{ 718*4882a593Smuzhiyun local bridge=$1 719*4882a593Smuzhiyun local ageing_time 720*4882a593Smuzhiyun 721*4882a593Smuzhiyun # Need to divide by 100 to convert to seconds. 722*4882a593Smuzhiyun ageing_time=$(ip -j -d link show dev $bridge \ 723*4882a593Smuzhiyun | jq '.[]["linkinfo"]["info_data"]["ageing_time"]') 724*4882a593Smuzhiyun echo $((ageing_time / 100)) 725*4882a593Smuzhiyun} 726*4882a593Smuzhiyun 727*4882a593Smuzhiyundeclare -A SYSCTL_ORIG 728*4882a593Smuzhiyunsysctl_set() 729*4882a593Smuzhiyun{ 730*4882a593Smuzhiyun local key=$1; shift 731*4882a593Smuzhiyun local value=$1; shift 732*4882a593Smuzhiyun 733*4882a593Smuzhiyun SYSCTL_ORIG[$key]=$(sysctl -n $key) 734*4882a593Smuzhiyun sysctl -qw $key=$value 735*4882a593Smuzhiyun} 736*4882a593Smuzhiyun 737*4882a593Smuzhiyunsysctl_restore() 738*4882a593Smuzhiyun{ 739*4882a593Smuzhiyun local key=$1; shift 740*4882a593Smuzhiyun 741*4882a593Smuzhiyun sysctl -qw $key=${SYSCTL_ORIG["$key"]} 742*4882a593Smuzhiyun} 743*4882a593Smuzhiyun 744*4882a593Smuzhiyunforwarding_enable() 745*4882a593Smuzhiyun{ 746*4882a593Smuzhiyun sysctl_set net.ipv4.conf.all.forwarding 1 747*4882a593Smuzhiyun sysctl_set net.ipv6.conf.all.forwarding 1 748*4882a593Smuzhiyun} 749*4882a593Smuzhiyun 750*4882a593Smuzhiyunforwarding_restore() 751*4882a593Smuzhiyun{ 752*4882a593Smuzhiyun sysctl_restore net.ipv6.conf.all.forwarding 753*4882a593Smuzhiyun sysctl_restore net.ipv4.conf.all.forwarding 754*4882a593Smuzhiyun} 755*4882a593Smuzhiyun 756*4882a593Smuzhiyundeclare -A MTU_ORIG 757*4882a593Smuzhiyunmtu_set() 758*4882a593Smuzhiyun{ 759*4882a593Smuzhiyun local dev=$1; shift 760*4882a593Smuzhiyun local mtu=$1; shift 761*4882a593Smuzhiyun 762*4882a593Smuzhiyun MTU_ORIG["$dev"]=$(ip -j link show dev $dev | jq -e '.[].mtu') 763*4882a593Smuzhiyun ip link set dev $dev mtu $mtu 764*4882a593Smuzhiyun} 765*4882a593Smuzhiyun 766*4882a593Smuzhiyunmtu_restore() 767*4882a593Smuzhiyun{ 768*4882a593Smuzhiyun local dev=$1; shift 769*4882a593Smuzhiyun 770*4882a593Smuzhiyun ip link set dev $dev mtu ${MTU_ORIG["$dev"]} 771*4882a593Smuzhiyun} 772*4882a593Smuzhiyun 773*4882a593Smuzhiyuntc_offload_check() 774*4882a593Smuzhiyun{ 775*4882a593Smuzhiyun local num_netifs=${1:-$NUM_NETIFS} 776*4882a593Smuzhiyun 777*4882a593Smuzhiyun for ((i = 1; i <= num_netifs; ++i)); do 778*4882a593Smuzhiyun ethtool -k ${NETIFS[p$i]} \ 779*4882a593Smuzhiyun | grep "hw-tc-offload: on" &> /dev/null 780*4882a593Smuzhiyun if [[ $? -ne 0 ]]; then 781*4882a593Smuzhiyun return 1 782*4882a593Smuzhiyun fi 783*4882a593Smuzhiyun done 784*4882a593Smuzhiyun 785*4882a593Smuzhiyun return 0 786*4882a593Smuzhiyun} 787*4882a593Smuzhiyun 788*4882a593Smuzhiyuntrap_install() 789*4882a593Smuzhiyun{ 790*4882a593Smuzhiyun local dev=$1; shift 791*4882a593Smuzhiyun local direction=$1; shift 792*4882a593Smuzhiyun 793*4882a593Smuzhiyun # Some devices may not support or need in-hardware trapping of traffic 794*4882a593Smuzhiyun # (e.g. the veth pairs that this library creates for non-existent 795*4882a593Smuzhiyun # loopbacks). Use continue instead, so that there is a filter in there 796*4882a593Smuzhiyun # (some tests check counters), and so that other filters are still 797*4882a593Smuzhiyun # processed. 798*4882a593Smuzhiyun tc filter add dev $dev $direction pref 1 \ 799*4882a593Smuzhiyun flower skip_sw action trap 2>/dev/null \ 800*4882a593Smuzhiyun || tc filter add dev $dev $direction pref 1 \ 801*4882a593Smuzhiyun flower action continue 802*4882a593Smuzhiyun} 803*4882a593Smuzhiyun 804*4882a593Smuzhiyuntrap_uninstall() 805*4882a593Smuzhiyun{ 806*4882a593Smuzhiyun local dev=$1; shift 807*4882a593Smuzhiyun local direction=$1; shift 808*4882a593Smuzhiyun 809*4882a593Smuzhiyun tc filter del dev $dev $direction pref 1 flower 810*4882a593Smuzhiyun} 811*4882a593Smuzhiyun 812*4882a593Smuzhiyunslow_path_trap_install() 813*4882a593Smuzhiyun{ 814*4882a593Smuzhiyun # For slow-path testing, we need to install a trap to get to 815*4882a593Smuzhiyun # slow path the packets that would otherwise be switched in HW. 816*4882a593Smuzhiyun if [ "${tcflags/skip_hw}" != "$tcflags" ]; then 817*4882a593Smuzhiyun trap_install "$@" 818*4882a593Smuzhiyun fi 819*4882a593Smuzhiyun} 820*4882a593Smuzhiyun 821*4882a593Smuzhiyunslow_path_trap_uninstall() 822*4882a593Smuzhiyun{ 823*4882a593Smuzhiyun if [ "${tcflags/skip_hw}" != "$tcflags" ]; then 824*4882a593Smuzhiyun trap_uninstall "$@" 825*4882a593Smuzhiyun fi 826*4882a593Smuzhiyun} 827*4882a593Smuzhiyun 828*4882a593Smuzhiyun__icmp_capture_add_del() 829*4882a593Smuzhiyun{ 830*4882a593Smuzhiyun local add_del=$1; shift 831*4882a593Smuzhiyun local pref=$1; shift 832*4882a593Smuzhiyun local vsuf=$1; shift 833*4882a593Smuzhiyun local tundev=$1; shift 834*4882a593Smuzhiyun local filter=$1; shift 835*4882a593Smuzhiyun 836*4882a593Smuzhiyun tc filter $add_del dev "$tundev" ingress \ 837*4882a593Smuzhiyun proto ip$vsuf pref $pref \ 838*4882a593Smuzhiyun flower ip_proto icmp$vsuf $filter \ 839*4882a593Smuzhiyun action pass 840*4882a593Smuzhiyun} 841*4882a593Smuzhiyun 842*4882a593Smuzhiyunicmp_capture_install() 843*4882a593Smuzhiyun{ 844*4882a593Smuzhiyun __icmp_capture_add_del add 100 "" "$@" 845*4882a593Smuzhiyun} 846*4882a593Smuzhiyun 847*4882a593Smuzhiyunicmp_capture_uninstall() 848*4882a593Smuzhiyun{ 849*4882a593Smuzhiyun __icmp_capture_add_del del 100 "" "$@" 850*4882a593Smuzhiyun} 851*4882a593Smuzhiyun 852*4882a593Smuzhiyunicmp6_capture_install() 853*4882a593Smuzhiyun{ 854*4882a593Smuzhiyun __icmp_capture_add_del add 100 v6 "$@" 855*4882a593Smuzhiyun} 856*4882a593Smuzhiyun 857*4882a593Smuzhiyunicmp6_capture_uninstall() 858*4882a593Smuzhiyun{ 859*4882a593Smuzhiyun __icmp_capture_add_del del 100 v6 "$@" 860*4882a593Smuzhiyun} 861*4882a593Smuzhiyun 862*4882a593Smuzhiyun__vlan_capture_add_del() 863*4882a593Smuzhiyun{ 864*4882a593Smuzhiyun local add_del=$1; shift 865*4882a593Smuzhiyun local pref=$1; shift 866*4882a593Smuzhiyun local dev=$1; shift 867*4882a593Smuzhiyun local filter=$1; shift 868*4882a593Smuzhiyun 869*4882a593Smuzhiyun tc filter $add_del dev "$dev" ingress \ 870*4882a593Smuzhiyun proto 802.1q pref $pref \ 871*4882a593Smuzhiyun flower $filter \ 872*4882a593Smuzhiyun action pass 873*4882a593Smuzhiyun} 874*4882a593Smuzhiyun 875*4882a593Smuzhiyunvlan_capture_install() 876*4882a593Smuzhiyun{ 877*4882a593Smuzhiyun __vlan_capture_add_del add 100 "$@" 878*4882a593Smuzhiyun} 879*4882a593Smuzhiyun 880*4882a593Smuzhiyunvlan_capture_uninstall() 881*4882a593Smuzhiyun{ 882*4882a593Smuzhiyun __vlan_capture_add_del del 100 "$@" 883*4882a593Smuzhiyun} 884*4882a593Smuzhiyun 885*4882a593Smuzhiyun__dscp_capture_add_del() 886*4882a593Smuzhiyun{ 887*4882a593Smuzhiyun local add_del=$1; shift 888*4882a593Smuzhiyun local dev=$1; shift 889*4882a593Smuzhiyun local base=$1; shift 890*4882a593Smuzhiyun local dscp; 891*4882a593Smuzhiyun 892*4882a593Smuzhiyun for prio in {0..7}; do 893*4882a593Smuzhiyun dscp=$((base + prio)) 894*4882a593Smuzhiyun __icmp_capture_add_del $add_del $((dscp + 100)) "" $dev \ 895*4882a593Smuzhiyun "skip_hw ip_tos $((dscp << 2))" 896*4882a593Smuzhiyun done 897*4882a593Smuzhiyun} 898*4882a593Smuzhiyun 899*4882a593Smuzhiyundscp_capture_install() 900*4882a593Smuzhiyun{ 901*4882a593Smuzhiyun local dev=$1; shift 902*4882a593Smuzhiyun local base=$1; shift 903*4882a593Smuzhiyun 904*4882a593Smuzhiyun __dscp_capture_add_del add $dev $base 905*4882a593Smuzhiyun} 906*4882a593Smuzhiyun 907*4882a593Smuzhiyundscp_capture_uninstall() 908*4882a593Smuzhiyun{ 909*4882a593Smuzhiyun local dev=$1; shift 910*4882a593Smuzhiyun local base=$1; shift 911*4882a593Smuzhiyun 912*4882a593Smuzhiyun __dscp_capture_add_del del $dev $base 913*4882a593Smuzhiyun} 914*4882a593Smuzhiyun 915*4882a593Smuzhiyundscp_fetch_stats() 916*4882a593Smuzhiyun{ 917*4882a593Smuzhiyun local dev=$1; shift 918*4882a593Smuzhiyun local base=$1; shift 919*4882a593Smuzhiyun 920*4882a593Smuzhiyun for prio in {0..7}; do 921*4882a593Smuzhiyun local dscp=$((base + prio)) 922*4882a593Smuzhiyun local t=$(tc_rule_stats_get $dev $((dscp + 100))) 923*4882a593Smuzhiyun echo "[$dscp]=$t " 924*4882a593Smuzhiyun done 925*4882a593Smuzhiyun} 926*4882a593Smuzhiyun 927*4882a593Smuzhiyunmatchall_sink_create() 928*4882a593Smuzhiyun{ 929*4882a593Smuzhiyun local dev=$1; shift 930*4882a593Smuzhiyun 931*4882a593Smuzhiyun tc qdisc add dev $dev clsact 932*4882a593Smuzhiyun tc filter add dev $dev ingress \ 933*4882a593Smuzhiyun pref 10000 \ 934*4882a593Smuzhiyun matchall \ 935*4882a593Smuzhiyun action drop 936*4882a593Smuzhiyun} 937*4882a593Smuzhiyun 938*4882a593Smuzhiyuntests_run() 939*4882a593Smuzhiyun{ 940*4882a593Smuzhiyun local current_test 941*4882a593Smuzhiyun 942*4882a593Smuzhiyun for current_test in ${TESTS:-$ALL_TESTS}; do 943*4882a593Smuzhiyun $current_test 944*4882a593Smuzhiyun done 945*4882a593Smuzhiyun} 946*4882a593Smuzhiyun 947*4882a593Smuzhiyunmultipath_eval() 948*4882a593Smuzhiyun{ 949*4882a593Smuzhiyun local desc="$1" 950*4882a593Smuzhiyun local weight_rp12=$2 951*4882a593Smuzhiyun local weight_rp13=$3 952*4882a593Smuzhiyun local packets_rp12=$4 953*4882a593Smuzhiyun local packets_rp13=$5 954*4882a593Smuzhiyun local weights_ratio packets_ratio diff 955*4882a593Smuzhiyun 956*4882a593Smuzhiyun RET=0 957*4882a593Smuzhiyun 958*4882a593Smuzhiyun if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then 959*4882a593Smuzhiyun weights_ratio=$(echo "scale=2; $weight_rp12 / $weight_rp13" \ 960*4882a593Smuzhiyun | bc -l) 961*4882a593Smuzhiyun else 962*4882a593Smuzhiyun weights_ratio=$(echo "scale=2; $weight_rp13 / $weight_rp12" \ 963*4882a593Smuzhiyun | bc -l) 964*4882a593Smuzhiyun fi 965*4882a593Smuzhiyun 966*4882a593Smuzhiyun if [[ "$packets_rp12" -eq "0" || "$packets_rp13" -eq "0" ]]; then 967*4882a593Smuzhiyun check_err 1 "Packet difference is 0" 968*4882a593Smuzhiyun log_test "Multipath" 969*4882a593Smuzhiyun log_info "Expected ratio $weights_ratio" 970*4882a593Smuzhiyun return 971*4882a593Smuzhiyun fi 972*4882a593Smuzhiyun 973*4882a593Smuzhiyun if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then 974*4882a593Smuzhiyun packets_ratio=$(echo "scale=2; $packets_rp12 / $packets_rp13" \ 975*4882a593Smuzhiyun | bc -l) 976*4882a593Smuzhiyun else 977*4882a593Smuzhiyun packets_ratio=$(echo "scale=2; $packets_rp13 / $packets_rp12" \ 978*4882a593Smuzhiyun | bc -l) 979*4882a593Smuzhiyun fi 980*4882a593Smuzhiyun 981*4882a593Smuzhiyun diff=$(echo $weights_ratio - $packets_ratio | bc -l) 982*4882a593Smuzhiyun diff=${diff#-} 983*4882a593Smuzhiyun 984*4882a593Smuzhiyun test "$(echo "$diff / $weights_ratio > 0.15" | bc -l)" -eq 0 985*4882a593Smuzhiyun check_err $? "Too large discrepancy between expected and measured ratios" 986*4882a593Smuzhiyun log_test "$desc" 987*4882a593Smuzhiyun log_info "Expected ratio $weights_ratio Measured ratio $packets_ratio" 988*4882a593Smuzhiyun} 989*4882a593Smuzhiyun 990*4882a593Smuzhiyunin_ns() 991*4882a593Smuzhiyun{ 992*4882a593Smuzhiyun local name=$1; shift 993*4882a593Smuzhiyun 994*4882a593Smuzhiyun ip netns exec $name bash <<-EOF 995*4882a593Smuzhiyun NUM_NETIFS=0 996*4882a593Smuzhiyun source lib.sh 997*4882a593Smuzhiyun $(for a in "$@"; do printf "%q${IFS:0:1}" "$a"; done) 998*4882a593Smuzhiyun EOF 999*4882a593Smuzhiyun} 1000*4882a593Smuzhiyun 1001*4882a593Smuzhiyun############################################################################## 1002*4882a593Smuzhiyun# Tests 1003*4882a593Smuzhiyun 1004*4882a593Smuzhiyunping_do() 1005*4882a593Smuzhiyun{ 1006*4882a593Smuzhiyun local if_name=$1 1007*4882a593Smuzhiyun local dip=$2 1008*4882a593Smuzhiyun local args=$3 1009*4882a593Smuzhiyun local vrf_name 1010*4882a593Smuzhiyun 1011*4882a593Smuzhiyun vrf_name=$(master_name_get $if_name) 1012*4882a593Smuzhiyun ip vrf exec $vrf_name \ 1013*4882a593Smuzhiyun $PING $args $dip -c 10 -i 0.1 -w $PING_TIMEOUT &> /dev/null 1014*4882a593Smuzhiyun} 1015*4882a593Smuzhiyun 1016*4882a593Smuzhiyunping_test() 1017*4882a593Smuzhiyun{ 1018*4882a593Smuzhiyun RET=0 1019*4882a593Smuzhiyun 1020*4882a593Smuzhiyun ping_do $1 $2 1021*4882a593Smuzhiyun check_err $? 1022*4882a593Smuzhiyun log_test "ping$3" 1023*4882a593Smuzhiyun} 1024*4882a593Smuzhiyun 1025*4882a593Smuzhiyunping6_do() 1026*4882a593Smuzhiyun{ 1027*4882a593Smuzhiyun local if_name=$1 1028*4882a593Smuzhiyun local dip=$2 1029*4882a593Smuzhiyun local args=$3 1030*4882a593Smuzhiyun local vrf_name 1031*4882a593Smuzhiyun 1032*4882a593Smuzhiyun vrf_name=$(master_name_get $if_name) 1033*4882a593Smuzhiyun ip vrf exec $vrf_name \ 1034*4882a593Smuzhiyun $PING6 $args $dip -c 10 -i 0.1 -w $PING_TIMEOUT &> /dev/null 1035*4882a593Smuzhiyun} 1036*4882a593Smuzhiyun 1037*4882a593Smuzhiyunping6_test() 1038*4882a593Smuzhiyun{ 1039*4882a593Smuzhiyun RET=0 1040*4882a593Smuzhiyun 1041*4882a593Smuzhiyun ping6_do $1 $2 1042*4882a593Smuzhiyun check_err $? 1043*4882a593Smuzhiyun log_test "ping6$3" 1044*4882a593Smuzhiyun} 1045*4882a593Smuzhiyun 1046*4882a593Smuzhiyunlearning_test() 1047*4882a593Smuzhiyun{ 1048*4882a593Smuzhiyun local bridge=$1 1049*4882a593Smuzhiyun local br_port1=$2 # Connected to `host1_if`. 1050*4882a593Smuzhiyun local host1_if=$3 1051*4882a593Smuzhiyun local host2_if=$4 1052*4882a593Smuzhiyun local mac=de:ad:be:ef:13:37 1053*4882a593Smuzhiyun local ageing_time 1054*4882a593Smuzhiyun 1055*4882a593Smuzhiyun RET=0 1056*4882a593Smuzhiyun 1057*4882a593Smuzhiyun bridge -j fdb show br $bridge brport $br_port1 \ 1058*4882a593Smuzhiyun | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null 1059*4882a593Smuzhiyun check_fail $? "Found FDB record when should not" 1060*4882a593Smuzhiyun 1061*4882a593Smuzhiyun # Disable unknown unicast flooding on `br_port1` to make sure 1062*4882a593Smuzhiyun # packets are only forwarded through the port after a matching 1063*4882a593Smuzhiyun # FDB entry was installed. 1064*4882a593Smuzhiyun bridge link set dev $br_port1 flood off 1065*4882a593Smuzhiyun 1066*4882a593Smuzhiyun ip link set $host1_if promisc on 1067*4882a593Smuzhiyun tc qdisc add dev $host1_if ingress 1068*4882a593Smuzhiyun tc filter add dev $host1_if ingress protocol ip pref 1 handle 101 \ 1069*4882a593Smuzhiyun flower dst_mac $mac action drop 1070*4882a593Smuzhiyun 1071*4882a593Smuzhiyun $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q 1072*4882a593Smuzhiyun sleep 1 1073*4882a593Smuzhiyun 1074*4882a593Smuzhiyun tc -j -s filter show dev $host1_if ingress \ 1075*4882a593Smuzhiyun | jq -e ".[] | select(.options.handle == 101) \ 1076*4882a593Smuzhiyun | select(.options.actions[0].stats.packets == 1)" &> /dev/null 1077*4882a593Smuzhiyun check_fail $? "Packet reached first host when should not" 1078*4882a593Smuzhiyun 1079*4882a593Smuzhiyun $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q 1080*4882a593Smuzhiyun sleep 1 1081*4882a593Smuzhiyun 1082*4882a593Smuzhiyun bridge -j fdb show br $bridge brport $br_port1 \ 1083*4882a593Smuzhiyun | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null 1084*4882a593Smuzhiyun check_err $? "Did not find FDB record when should" 1085*4882a593Smuzhiyun 1086*4882a593Smuzhiyun $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q 1087*4882a593Smuzhiyun sleep 1 1088*4882a593Smuzhiyun 1089*4882a593Smuzhiyun tc -j -s filter show dev $host1_if ingress \ 1090*4882a593Smuzhiyun | jq -e ".[] | select(.options.handle == 101) \ 1091*4882a593Smuzhiyun | select(.options.actions[0].stats.packets == 1)" &> /dev/null 1092*4882a593Smuzhiyun check_err $? "Packet did not reach second host when should" 1093*4882a593Smuzhiyun 1094*4882a593Smuzhiyun # Wait for 10 seconds after the ageing time to make sure FDB 1095*4882a593Smuzhiyun # record was aged-out. 1096*4882a593Smuzhiyun ageing_time=$(bridge_ageing_time_get $bridge) 1097*4882a593Smuzhiyun sleep $((ageing_time + 10)) 1098*4882a593Smuzhiyun 1099*4882a593Smuzhiyun bridge -j fdb show br $bridge brport $br_port1 \ 1100*4882a593Smuzhiyun | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null 1101*4882a593Smuzhiyun check_fail $? "Found FDB record when should not" 1102*4882a593Smuzhiyun 1103*4882a593Smuzhiyun bridge link set dev $br_port1 learning off 1104*4882a593Smuzhiyun 1105*4882a593Smuzhiyun $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q 1106*4882a593Smuzhiyun sleep 1 1107*4882a593Smuzhiyun 1108*4882a593Smuzhiyun bridge -j fdb show br $bridge brport $br_port1 \ 1109*4882a593Smuzhiyun | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null 1110*4882a593Smuzhiyun check_fail $? "Found FDB record when should not" 1111*4882a593Smuzhiyun 1112*4882a593Smuzhiyun bridge link set dev $br_port1 learning on 1113*4882a593Smuzhiyun 1114*4882a593Smuzhiyun tc filter del dev $host1_if ingress protocol ip pref 1 handle 101 flower 1115*4882a593Smuzhiyun tc qdisc del dev $host1_if ingress 1116*4882a593Smuzhiyun ip link set $host1_if promisc off 1117*4882a593Smuzhiyun 1118*4882a593Smuzhiyun bridge link set dev $br_port1 flood on 1119*4882a593Smuzhiyun 1120*4882a593Smuzhiyun log_test "FDB learning" 1121*4882a593Smuzhiyun} 1122*4882a593Smuzhiyun 1123*4882a593Smuzhiyunflood_test_do() 1124*4882a593Smuzhiyun{ 1125*4882a593Smuzhiyun local should_flood=$1 1126*4882a593Smuzhiyun local mac=$2 1127*4882a593Smuzhiyun local ip=$3 1128*4882a593Smuzhiyun local host1_if=$4 1129*4882a593Smuzhiyun local host2_if=$5 1130*4882a593Smuzhiyun local err=0 1131*4882a593Smuzhiyun 1132*4882a593Smuzhiyun # Add an ACL on `host2_if` which will tell us whether the packet 1133*4882a593Smuzhiyun # was flooded to it or not. 1134*4882a593Smuzhiyun ip link set $host2_if promisc on 1135*4882a593Smuzhiyun tc qdisc add dev $host2_if ingress 1136*4882a593Smuzhiyun tc filter add dev $host2_if ingress protocol ip pref 1 handle 101 \ 1137*4882a593Smuzhiyun flower dst_mac $mac action drop 1138*4882a593Smuzhiyun 1139*4882a593Smuzhiyun $MZ $host1_if -c 1 -p 64 -b $mac -B $ip -t ip -q 1140*4882a593Smuzhiyun sleep 1 1141*4882a593Smuzhiyun 1142*4882a593Smuzhiyun tc -j -s filter show dev $host2_if ingress \ 1143*4882a593Smuzhiyun | jq -e ".[] | select(.options.handle == 101) \ 1144*4882a593Smuzhiyun | select(.options.actions[0].stats.packets == 1)" &> /dev/null 1145*4882a593Smuzhiyun if [[ $? -ne 0 && $should_flood == "true" || \ 1146*4882a593Smuzhiyun $? -eq 0 && $should_flood == "false" ]]; then 1147*4882a593Smuzhiyun err=1 1148*4882a593Smuzhiyun fi 1149*4882a593Smuzhiyun 1150*4882a593Smuzhiyun tc filter del dev $host2_if ingress protocol ip pref 1 handle 101 flower 1151*4882a593Smuzhiyun tc qdisc del dev $host2_if ingress 1152*4882a593Smuzhiyun ip link set $host2_if promisc off 1153*4882a593Smuzhiyun 1154*4882a593Smuzhiyun return $err 1155*4882a593Smuzhiyun} 1156*4882a593Smuzhiyun 1157*4882a593Smuzhiyunflood_unicast_test() 1158*4882a593Smuzhiyun{ 1159*4882a593Smuzhiyun local br_port=$1 1160*4882a593Smuzhiyun local host1_if=$2 1161*4882a593Smuzhiyun local host2_if=$3 1162*4882a593Smuzhiyun local mac=de:ad:be:ef:13:37 1163*4882a593Smuzhiyun local ip=192.0.2.100 1164*4882a593Smuzhiyun 1165*4882a593Smuzhiyun RET=0 1166*4882a593Smuzhiyun 1167*4882a593Smuzhiyun bridge link set dev $br_port flood off 1168*4882a593Smuzhiyun 1169*4882a593Smuzhiyun flood_test_do false $mac $ip $host1_if $host2_if 1170*4882a593Smuzhiyun check_err $? "Packet flooded when should not" 1171*4882a593Smuzhiyun 1172*4882a593Smuzhiyun bridge link set dev $br_port flood on 1173*4882a593Smuzhiyun 1174*4882a593Smuzhiyun flood_test_do true $mac $ip $host1_if $host2_if 1175*4882a593Smuzhiyun check_err $? "Packet was not flooded when should" 1176*4882a593Smuzhiyun 1177*4882a593Smuzhiyun log_test "Unknown unicast flood" 1178*4882a593Smuzhiyun} 1179*4882a593Smuzhiyun 1180*4882a593Smuzhiyunflood_multicast_test() 1181*4882a593Smuzhiyun{ 1182*4882a593Smuzhiyun local br_port=$1 1183*4882a593Smuzhiyun local host1_if=$2 1184*4882a593Smuzhiyun local host2_if=$3 1185*4882a593Smuzhiyun local mac=01:00:5e:00:00:01 1186*4882a593Smuzhiyun local ip=239.0.0.1 1187*4882a593Smuzhiyun 1188*4882a593Smuzhiyun RET=0 1189*4882a593Smuzhiyun 1190*4882a593Smuzhiyun bridge link set dev $br_port mcast_flood off 1191*4882a593Smuzhiyun 1192*4882a593Smuzhiyun flood_test_do false $mac $ip $host1_if $host2_if 1193*4882a593Smuzhiyun check_err $? "Packet flooded when should not" 1194*4882a593Smuzhiyun 1195*4882a593Smuzhiyun bridge link set dev $br_port mcast_flood on 1196*4882a593Smuzhiyun 1197*4882a593Smuzhiyun flood_test_do true $mac $ip $host1_if $host2_if 1198*4882a593Smuzhiyun check_err $? "Packet was not flooded when should" 1199*4882a593Smuzhiyun 1200*4882a593Smuzhiyun log_test "Unregistered multicast flood" 1201*4882a593Smuzhiyun} 1202*4882a593Smuzhiyun 1203*4882a593Smuzhiyunflood_test() 1204*4882a593Smuzhiyun{ 1205*4882a593Smuzhiyun # `br_port` is connected to `host2_if` 1206*4882a593Smuzhiyun local br_port=$1 1207*4882a593Smuzhiyun local host1_if=$2 1208*4882a593Smuzhiyun local host2_if=$3 1209*4882a593Smuzhiyun 1210*4882a593Smuzhiyun flood_unicast_test $br_port $host1_if $host2_if 1211*4882a593Smuzhiyun flood_multicast_test $br_port $host1_if $host2_if 1212*4882a593Smuzhiyun} 1213*4882a593Smuzhiyun 1214*4882a593Smuzhiyun__start_traffic() 1215*4882a593Smuzhiyun{ 1216*4882a593Smuzhiyun local proto=$1; shift 1217*4882a593Smuzhiyun local h_in=$1; shift # Where the traffic egresses the host 1218*4882a593Smuzhiyun local sip=$1; shift 1219*4882a593Smuzhiyun local dip=$1; shift 1220*4882a593Smuzhiyun local dmac=$1; shift 1221*4882a593Smuzhiyun 1222*4882a593Smuzhiyun $MZ $h_in -p 8000 -A $sip -B $dip -c 0 \ 1223*4882a593Smuzhiyun -a own -b $dmac -t "$proto" -q "$@" & 1224*4882a593Smuzhiyun sleep 1 1225*4882a593Smuzhiyun} 1226*4882a593Smuzhiyun 1227*4882a593Smuzhiyunstart_traffic() 1228*4882a593Smuzhiyun{ 1229*4882a593Smuzhiyun __start_traffic udp "$@" 1230*4882a593Smuzhiyun} 1231*4882a593Smuzhiyun 1232*4882a593Smuzhiyunstart_tcp_traffic() 1233*4882a593Smuzhiyun{ 1234*4882a593Smuzhiyun __start_traffic tcp "$@" 1235*4882a593Smuzhiyun} 1236*4882a593Smuzhiyun 1237*4882a593Smuzhiyunstop_traffic() 1238*4882a593Smuzhiyun{ 1239*4882a593Smuzhiyun # Suppress noise from killing mausezahn. 1240*4882a593Smuzhiyun { kill %% && wait %%; } 2>/dev/null 1241*4882a593Smuzhiyun} 1242*4882a593Smuzhiyun 1243*4882a593Smuzhiyuntcpdump_start() 1244*4882a593Smuzhiyun{ 1245*4882a593Smuzhiyun local if_name=$1; shift 1246*4882a593Smuzhiyun local ns=$1; shift 1247*4882a593Smuzhiyun 1248*4882a593Smuzhiyun capfile=$(mktemp) 1249*4882a593Smuzhiyun capout=$(mktemp) 1250*4882a593Smuzhiyun 1251*4882a593Smuzhiyun if [ -z $ns ]; then 1252*4882a593Smuzhiyun ns_cmd="" 1253*4882a593Smuzhiyun else 1254*4882a593Smuzhiyun ns_cmd="ip netns exec ${ns}" 1255*4882a593Smuzhiyun fi 1256*4882a593Smuzhiyun 1257*4882a593Smuzhiyun if [ -z $SUDO_USER ] ; then 1258*4882a593Smuzhiyun capuser="" 1259*4882a593Smuzhiyun else 1260*4882a593Smuzhiyun capuser="-Z $SUDO_USER" 1261*4882a593Smuzhiyun fi 1262*4882a593Smuzhiyun 1263*4882a593Smuzhiyun $ns_cmd tcpdump -e -n -Q in -i $if_name \ 1264*4882a593Smuzhiyun -s 65535 -B 32768 $capuser -w $capfile > "$capout" 2>&1 & 1265*4882a593Smuzhiyun cappid=$! 1266*4882a593Smuzhiyun 1267*4882a593Smuzhiyun sleep 1 1268*4882a593Smuzhiyun} 1269*4882a593Smuzhiyun 1270*4882a593Smuzhiyuntcpdump_stop() 1271*4882a593Smuzhiyun{ 1272*4882a593Smuzhiyun $ns_cmd kill $cappid 1273*4882a593Smuzhiyun sleep 1 1274*4882a593Smuzhiyun} 1275*4882a593Smuzhiyun 1276*4882a593Smuzhiyuntcpdump_cleanup() 1277*4882a593Smuzhiyun{ 1278*4882a593Smuzhiyun rm $capfile $capout 1279*4882a593Smuzhiyun} 1280*4882a593Smuzhiyun 1281*4882a593Smuzhiyuntcpdump_show() 1282*4882a593Smuzhiyun{ 1283*4882a593Smuzhiyun tcpdump -e -n -r $capfile 2>&1 1284*4882a593Smuzhiyun} 1285