xref: /OK3568_Linux_fs/kernel/tools/testing/selftests/net/forwarding/lib.sh (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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