xref: /linux/tools/testing/selftests/net/openvswitch/openvswitch.sh (revision 3e9201e4fe8bd78f4601a51212562505bbb60e3a)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# OVS kernel module self tests
5
6trap ovs_exit_sig EXIT TERM INT ERR
7
8# Kselftest framework requirement - SKIP code is 4.
9ksft_skip=4
10
11PAUSE_ON_FAIL=no
12VERBOSE=0
13TRACING=0
14WAIT_TIMEOUT=5
15
16if test "X$KSFT_MACHINE_SLOW" == "Xyes"; then
17	WAIT_TIMEOUT=10
18fi
19
20tests="
21	arp_ping				eth-arp: Basic arp ping between two NS
22	ct_connect_v4				ip4-ct-xon: Basic ipv4 tcp connection using ct
23	connect_v4				ip4-xon: Basic ipv4 ping between two NS
24	nat_connect_v4				ip4-nat-xon: Basic ipv4 tcp connection via NAT
25	nat_related_v4				ip4-nat-related: ICMP related matches work with SNAT
26	netlink_checks				ovsnl: validate netlink attrs and settings
27	upcall_interfaces			ovs: test the upcall interfaces
28	tunnel_metadata				ovs: test extraction of tunnel metadata
29	tunnel_refcount				ovs: test tunnel vport reference cleanup
30	drop_reason				drop: test drop reasons are emitted
31	pop_vlan				vlan: POP_VLAN action strips tag
32	dec_ttl					ttl: dec_ttl decrements IP TTL
33	flow_set				flow-set: Flow modify
34	psample					psample: Sampling packets with psample"
35
36info() {
37	[ "${ovs_dir}" != "" ] &&
38		echo "`date +"[%m-%d %H:%M:%S]"` $*" >> ${ovs_dir}/debug.log
39	[ $VERBOSE = 0 ] || echo $*
40}
41
42ovs_wait() {
43	info "waiting $WAIT_TIMEOUT s for: $@"
44
45	if "$@" ; then
46		info "wait succeeded immediately"
47		return 0
48	fi
49
50	# A quick re-check helps speed up small races in fast systems.
51	# However, fractional sleeps might not necessarily work.
52	local start=0
53	sleep 0.1 || { sleep 1; start=1; }
54
55	for (( i=start; i<WAIT_TIMEOUT; i++ )); do
56		if "$@" ; then
57			info "wait succeeded after $i seconds"
58			return 0
59		fi
60		sleep 1
61	done
62	info "wait failed after $i seconds"
63	return 1
64}
65
66ovs_base=`pwd`
67sbxs=
68sbx_add () {
69	info "adding sandbox '$1'"
70
71	sbxs="$sbxs $1"
72
73	NO_BIN=0
74
75	# Create sandbox.
76	local d="$ovs_base"/$1
77	if [ -e $d ]; then
78		info "removing $d"
79		rm -rf "$d"
80	fi
81	mkdir "$d" || return 1
82	ovs_setenv $1
83}
84
85ovs_exit_sig() {
86	[ -e ${ovs_dir}/cleanup ] && . "$ovs_dir/cleanup"
87}
88
89on_exit() {
90	echo "$1" > ${ovs_dir}/cleanup.tmp
91	cat ${ovs_dir}/cleanup >> ${ovs_dir}/cleanup.tmp
92	mv ${ovs_dir}/cleanup.tmp ${ovs_dir}/cleanup
93}
94
95ovs_setenv() {
96	sandbox=$1
97
98	ovs_dir=$ovs_base${1:+/$1}; export ovs_dir
99
100	test -e ${ovs_dir}/cleanup || : > ${ovs_dir}/cleanup
101}
102
103ovs_sbx() {
104	if test "X$2" != X; then
105		(ovs_setenv $1; shift;
106		 info "run cmd: $@"; "$@" >> ${ovs_dir}/debug.log)
107	else
108		ovs_setenv $1
109	fi
110}
111
112ovs_add_dp () {
113	info "Adding DP/Bridge IF: sbx:$1 dp:$2 {$3, $4, $5}"
114	sbxname="$1"
115	shift
116	ovs_sbx "$sbxname" python3 $ovs_base/ovs-dpctl.py add-dp $*
117	on_exit "ovs_sbx $sbxname python3 $ovs_base/ovs-dpctl.py del-dp $1;"
118}
119
120ovs_add_if () {
121	info "Adding IF to DP: br:$3 if:$4 ($2)"
122	if [ "$5" != "-u" ]; then
123		ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py add-if \
124		    -t "$2" "$3" "$4" || return 1
125	else
126		python3 $ovs_base/ovs-dpctl.py add-if \
127		    -u -t "$2" "$3" "$4" >$ovs_dir/$4.out 2>$ovs_dir/$4.err &
128		pid=$!
129		on_exit "ovs_sbx $1 kill -TERM $pid 2>/dev/null"
130	fi
131}
132
133ovs_del_if () {
134	info "Deleting IF from DP: br:$2 if:$3"
135	ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py del-if "$2" "$3" || return 1
136}
137
138ovs_netns_spawn_daemon() {
139	sbx=$1
140	shift
141	netns=$1
142	shift
143	if [ "$netns" == "_default" ]; then
144		$*  >> $ovs_dir/stdout  2>> $ovs_dir/stderr &
145	else
146		ip netns exec $netns $*  >> $ovs_dir/stdout  2>> $ovs_dir/stderr &
147	fi
148	pid=$!
149	ovs_sbx "$sbx" on_exit "kill -TERM $pid 2>/dev/null"
150}
151
152ovs_spawn_daemon() {
153	sbx=$1
154	shift
155	ovs_netns_spawn_daemon $sbx "_default" $*
156}
157
158ovs_add_netns_and_veths () {
159	info "Adding netns attached: sbx:$1 dp:$2 {$3, $4, $5}"
160	ovs_sbx "$1" ip netns add "$3" || return 1
161	on_exit "ovs_sbx $1 ip netns del $3"
162	ovs_sbx "$1" ip link add "$4" type veth peer name "$5" || return 1
163	on_exit "ovs_sbx $1 ip link del $4 >/dev/null 2>&1"
164	ovs_sbx "$1" ip link set "$4" up || return 1
165	ovs_sbx "$1" ip link set "$5" netns "$3" || return 1
166	ovs_sbx "$1" ip netns exec "$3" ip link set "$5" up || return 1
167
168	if [ "$6" != "" ]; then
169		ovs_sbx "$1" ip netns exec "$3" ip addr add "$6" dev "$5" \
170		    || return 1
171	fi
172
173	if [ "$7" != "-u" ]; then
174		ovs_add_if "$1" "netdev" "$2" "$4" || return 1
175	else
176		ovs_add_if "$1" "netdev" "$2" "$4" -u || return 1
177	fi
178
179	if [ $TRACING -eq 1 ]; then
180		ovs_netns_spawn_daemon "$1" "$3" tcpdump -l -i any -s 6553
181		ovs_wait grep -q "listening on any" ${ovs_dir}/stderr
182	fi
183
184	return 0
185}
186
187ovs_add_flow () {
188	info "Adding flow to DP: sbx:$1 br:$2 flow:$3 act:$4"
189	ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py add-flow "$2" "$3" "$4"
190	if [ $? -ne 0 ]; then
191		info "Flow [ $3 : $4 ] failed"
192		return 1
193	fi
194	return 0
195}
196
197ovs_mod_flow () {
198	if [ -n "$4" ]; then
199		info "Modifying flow: sbx:$1 br:$2 flow:$3 act:$4"
200		ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py \
201			mod-flow "$2" "$3" "$4"
202	else
203		info "Modifying flow (no actions): sbx:$1 br:$2 flow:$3"
204		ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py \
205			mod-flow "$2" "$3"
206	fi
207	if [ $? -ne 0 ]; then
208		info "Flow modify [ $3 ] failed"
209		return 1
210	fi
211	return 0
212}
213
214ovs_del_flows () {
215	info "Deleting all flows from DP: sbx:$1 br:$2"
216	ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py del-flows "$2"
217	return 0
218}
219
220ovs_drop_record_and_run () {
221	local sbx=$1
222	shift
223
224	perf record -a -q -e skb:kfree_skb -o ${ovs_dir}/perf.data $* \
225		>> ${ovs_dir}/stdout 2>> ${ovs_dir}/stderr
226	return $?
227}
228
229ovs_drop_reason_count()
230{
231	local reason=$1
232
233	local perf_output=`perf script -i ${ovs_dir}/perf.data -F trace:event,trace`
234	local pattern="skb:kfree_skb:.*reason: $reason"
235
236	return `echo "$perf_output" | grep "$pattern" | wc -l`
237}
238
239ovs_test_flow_fails () {
240	ERR_MSG="Flow actions may not be safe on all matching packets"
241
242	PRE_TEST=$(dmesg | grep -c "${ERR_MSG}")
243	ovs_add_flow $@ &> /dev/null $@ && return 1
244	POST_TEST=$(dmesg | grep -c "${ERR_MSG}")
245
246	if [ "$PRE_TEST" == "$POST_TEST" ]; then
247		return 1
248	fi
249	return 0
250}
251
252usage() {
253	echo
254	echo "$0 [OPTIONS] [TEST]..."
255	echo "If no TEST argument is given, all tests will be run."
256	echo
257	echo "Options"
258	echo "  -t: capture traffic via tcpdump"
259	echo "  -v: verbose"
260	echo "  -p: pause on failure"
261	echo
262	echo "Available tests${tests}"
263	exit 1
264}
265
266
267test_dec_ttl() {
268	sbx_add "test_dec_ttl" || return $?
269	ovs_add_dp "test_dec_ttl" decttl || return 1
270
271	info "create namespaces"
272	for ns in client server; do
273		ovs_add_netns_and_veths "test_dec_ttl" "decttl" "$ns" \
274			"${ns:0:1}0" "${ns:0:1}1" || return 1
275	done
276
277	ip netns exec client ip addr add 10.0.0.1/24 dev c1
278	ip netns exec client ip link set c1 up
279	ip netns exec server ip addr add 10.0.0.2/24 dev s1
280	ip netns exec server ip link set s1 up
281
282	# Probe: check if kernel supports dec_ttl action.
283	ovs_add_flow "test_dec_ttl" decttl \
284		'in_port(1),eth(),eth_type(0x0800),ipv4()' \
285		'dec_ttl(le_1())' &>/dev/null
286	if [ $? -ne 0 ]; then
287		info "no support for dec_ttl - skipping"
288		ovs_exit_sig
289		return $ksft_skip
290	fi
291
292	ovs_del_flows "test_dec_ttl" decttl
293
294	# ARP flows (bidirectional)
295	ovs_add_flow "test_dec_ttl" decttl \
296		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
297	ovs_add_flow "test_dec_ttl" decttl \
298		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
299
300	# IP flows with dec_ttl action
301	ovs_add_flow "test_dec_ttl" decttl \
302		'in_port(1),eth(),eth_type(0x0800),ipv4()' \
303		'dec_ttl(le_1()),2' || return 1
304	ovs_add_flow "test_dec_ttl" decttl \
305		'in_port(2),eth(),eth_type(0x0800),ipv4()' \
306		'dec_ttl(le_1()),1' || return 1
307
308	info "verify connectivity with dec_ttl"
309	ovs_sbx "test_dec_ttl" ip netns exec client ping -c 1 -W 2 \
310		10.0.0.2 || return 1
311
312	info "verify TTL=1 is dropped by dec_ttl"
313	ovs_sbx "test_dec_ttl" ip netns exec client ping -c 1 -W 2 \
314		-t 1 10.0.0.2 >/dev/null 2>&1 \
315		&& { info "FAIL: ping should fail with TTL=1 and dec_ttl"
316		     return 1; }
317
318	return 0
319}
320
321test_flow_set() {
322	sbx_add "test_flow_set" || return $?
323	ovs_add_dp "test_flow_set" flowset || return 1
324
325	info "create namespaces"
326	for ns in client server; do
327		ovs_add_netns_and_veths "test_flow_set" "flowset" "$ns" \
328			"${ns:0:1}0" "${ns:0:1}1" || return 1
329	done
330
331	ip netns exec client ip addr add 10.0.0.1/24 dev c1
332	ip netns exec client ip link set c1 up
333	ip netns exec server ip addr add 10.0.0.2/24 dev s1
334	ip netns exec server ip link set s1 up
335
336	ovs_add_flow "test_flow_set" flowset \
337		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
338	ovs_add_flow "test_flow_set" flowset \
339		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
340
341	local fwd_flow="ufid:00000001-0002-0003-0004-000500060007"
342	fwd_flow="$fwd_flow,in_port(1),eth(),eth_type(0x0800),ipv4()"
343
344	ovs_add_flow "test_flow_set" flowset "$fwd_flow" '2' \
345		|| return 1
346	ovs_add_flow "test_flow_set" flowset \
347		'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1
348
349	info "verify initial forwarding"
350	ovs_sbx "test_flow_set" ip netns exec client ping -c 1 -W 2 \
351		10.0.0.2 || return 1
352
353	info "mod-flow with new actions (change to drop)"
354	ovs_mod_flow "test_flow_set" flowset "$fwd_flow" 'drop' \
355		|| return 1
356
357	info "verify traffic is now dropped"
358	ovs_sbx "test_flow_set" ip netns exec client ping -c 1 -W 2 \
359		10.0.0.2 >/dev/null 2>&1 \
360		&& { info "FAIL: ping should fail after mod-flow to drop"
361		     return 1; }
362
363	info "mod-flow without actions"
364	ovs_mod_flow "test_flow_set" flowset "$fwd_flow" || return 1
365
366	info "verify flow retained drop action via dump"
367	python3 "$ovs_base/ovs-dpctl.py" dump-flows flowset \
368		| grep -q "actions:drop" || \
369		{ info "FAIL: flow not showing drop action"; return 1; }
370
371	info "verify drop actions unchanged"
372	ovs_sbx "test_flow_set" ip netns exec client ping -c 1 -W 2 \
373		10.0.0.2 >/dev/null 2>&1 \
374		&& { info "FAIL: ping should still fail after no-actions set"
375		     return 1; }
376
377	return 0
378}
379
380# psample test
381# - use psample to observe packets
382test_psample() {
383	sbx_add "test_psample" || return $?
384
385	# Add a datapath with per-vport dispatching.
386	ovs_add_dp "test_psample" psample -V 2:1 || return 1
387
388	info "create namespaces"
389	ovs_add_netns_and_veths "test_psample" "psample" \
390		client c0 c1 172.31.110.10/24 -u || return 1
391	ovs_add_netns_and_veths "test_psample" "psample" \
392		server s0 s1 172.31.110.20/24 -u || return 1
393
394	# Check if psample actions can be configured.
395	ovs_add_flow "test_psample" psample \
396	'in_port(1),eth(),eth_type(0x0806),arp()' 'psample(group=1)' &> /dev/null
397	if [ $? == 1 ]; then
398		info "no support for psample - skipping"
399		ovs_exit_sig
400		return $ksft_skip
401	fi
402
403	ovs_del_flows "test_psample" psample
404
405	# Test action verification.
406	OLDIFS=$IFS
407	IFS='*'
408	min_key='in_port(1),eth(),eth_type(0x0800),ipv4()'
409	for testcase in \
410		"cookie to large"*"psample(group=1,cookie=1615141312111009080706050403020100)" \
411		"no group with cookie"*"psample(cookie=abcd)" \
412		"no group"*"psample()";
413	do
414		set -- $testcase;
415		ovs_test_flow_fails "test_psample" psample $min_key $2
416		if [ $? == 1 ]; then
417			info "failed - $1"
418			return 1
419		fi
420	done
421	IFS=$OLDIFS
422
423	ovs_del_flows "test_psample" psample
424	# Allow ARP
425	ovs_add_flow "test_psample" psample \
426		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
427	ovs_add_flow "test_psample" psample \
428		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
429
430	# Sample first 14 bytes of all traffic.
431	ovs_add_flow "test_psample" psample \
432	    "in_port(1),eth(),eth_type(0x0800),ipv4()" \
433            "trunc(14),psample(group=1,cookie=c0ffee),2"
434
435	# Sample all traffic. In this case, use a sample() action with both
436	# psample and an upcall emulating simultaneous local sampling and
437	# sFlow / IPFIX.
438	nlpid=$(grep -E "listening on upcall packet handler" \
439            $ovs_dir/s0.out | cut -d ":" -f 2 | tr -d ' ')
440	[ -z "$nlpid" ] && \
441		{ info "failed to get upcall PID"; return 1; }
442
443	ovs_add_flow "test_psample" psample \
444            "in_port(2),eth(),eth_type(0x0800),ipv4()" \
445            "sample(sample=100%,actions(psample(group=2,cookie=eeff0c),userspace(pid=${nlpid},userdata=eeff0c))),1"
446
447	# Record psample data.
448	ovs_spawn_daemon "test_psample" python3 $ovs_base/ovs-dpctl.py psample-events
449	ovs_wait grep -q "listening for psample events" ${ovs_dir}/stdout
450
451	# Send a single ping.
452	ovs_sbx "test_psample" ip netns exec client ping -I c1 172.31.110.20 -c 1 || return 1
453
454	# We should have received one userspace action upcall and 2 psample packets.
455	ovs_wait grep -q "userspace action command" $ovs_dir/s0.out || return 1
456
457	# client -> server samples should only contain the first 14 bytes of the packet.
458	ovs_wait grep -qE "rate:4294967295,group:1,cookie:c0ffee data:[0-9a-f]{28}$" \
459		$ovs_dir/stdout || return 1
460
461	ovs_wait grep -q "rate:4294967295,group:2,cookie:eeff0c" $ovs_dir/stdout || return 1
462
463	return 0
464}
465
466# drop_reason test
467# - drop packets and verify the right drop reason is reported
468test_drop_reason() {
469	which perf >/dev/null 2>&1 || return $ksft_skip
470	which pahole >/dev/null 2>&1 || return $ksft_skip
471
472	ovs_drop_subsys=$(pahole -C skb_drop_reason_subsys |
473			      awk '/OPENVSWITCH/ { print $3; }' |
474			      tr -d ,)
475	if [ -z "$ovs_drop_subsys" ]; then
476		info "failed to get OVS drop subsys ID"
477		return $ksft_skip
478	fi
479
480	sbx_add "test_drop_reason" || return $?
481
482	ovs_add_dp "test_drop_reason" dropreason || return 1
483
484	info "create namespaces"
485	for ns in client server; do
486		ovs_add_netns_and_veths "test_drop_reason" "dropreason" "$ns" \
487			"${ns:0:1}0" "${ns:0:1}1" || return 1
488	done
489
490	# Setup client namespace
491	ip netns exec client ip addr add 172.31.110.10/24 dev c1
492	ip netns exec client ip link set c1 up
493
494	# Setup server namespace
495	ip netns exec server ip addr add 172.31.110.20/24 dev s1
496	ip netns exec server ip link set s1 up
497
498	# Check if drop reasons can be sent
499	ovs_add_flow "test_drop_reason" dropreason \
500		'in_port(1),eth(),eth_type(0x0806),arp()' 'drop(10)' 2>/dev/null
501	if [ $? == 1 ]; then
502		info "no support for drop reasons - skipping"
503		ovs_exit_sig
504		return $ksft_skip
505	fi
506
507	ovs_del_flows "test_drop_reason" dropreason
508
509	# Allow ARP
510	ovs_add_flow "test_drop_reason" dropreason \
511		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
512	ovs_add_flow "test_drop_reason" dropreason \
513		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
514
515	# Allow client ICMP traffic but drop return path
516	ovs_add_flow "test_drop_reason" dropreason \
517		"in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10,proto=1),icmp()" '2'
518	ovs_add_flow "test_drop_reason" dropreason \
519		"in_port(2),eth(),eth_type(0x0800),ipv4(src=172.31.110.20,proto=1),icmp()" 'drop'
520
521	ovs_drop_record_and_run "test_drop_reason" ip netns exec client ping -c 2 172.31.110.20
522	ovs_drop_reason_count 0x${ovs_drop_subsys}0001 # OVS_DROP_FLOW_ACTION
523	if [[ "$?" -ne "2" ]]; then
524		info "Did not detect expected drops: $?"
525		return 1
526	fi
527
528	# Drop UDP 6000 traffic with an explicit action and an error code.
529	ovs_add_flow "test_drop_reason" dropreason \
530		"in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10,proto=17),udp(dst=6000)" \
531                'drop(42)'
532	# Drop UDP 7000 traffic with an explicit action with no error code.
533	ovs_add_flow "test_drop_reason" dropreason \
534		"in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10,proto=17),udp(dst=7000)" \
535                'drop(0)'
536
537	ovs_drop_record_and_run \
538            "test_drop_reason" ip netns exec client nc -i 1 -zuv 172.31.110.20 6000
539	ovs_drop_reason_count 0x${ovs_drop_subsys}0004 # OVS_DROP_EXPLICIT_ACTION_ERROR
540	if [[ "$?" -ne "1" ]]; then
541		info "Did not detect expected explicit error drops: $?"
542		return 1
543	fi
544
545	ovs_drop_record_and_run \
546            "test_drop_reason" ip netns exec client nc -i 1 -zuv 172.31.110.20 7000
547	ovs_drop_reason_count 0x${ovs_drop_subsys}0003 # OVS_DROP_EXPLICIT_ACTION
548	if [[ "$?" -ne "1" ]]; then
549		info "Did not detect expected explicit drops: $?"
550		return 1
551	fi
552
553	return 0
554}
555
556# arp_ping test
557# - client has 1500 byte MTU
558# - server has 1500 byte MTU
559# - send ARP ping between two ns
560test_arp_ping () {
561
562	which arping >/dev/null 2>&1 || return $ksft_skip
563
564	sbx_add "test_arp_ping" || return $?
565
566	ovs_add_dp "test_arp_ping" arpping || return 1
567
568	info "create namespaces"
569	for ns in client server; do
570		ovs_add_netns_and_veths "test_arp_ping" "arpping" "$ns" \
571		    "${ns:0:1}0" "${ns:0:1}1" || return 1
572	done
573
574	# Setup client namespace
575	ip netns exec client ip addr add 172.31.110.10/24 dev c1
576	ip netns exec client ip link set c1 up
577	HW_CLIENT=$(ip netns exec client ip link show dev c1 \
578		| awk '/link\/ether/ {print $2}')
579	[ -z "$HW_CLIENT" ] && \
580		{ info "failed to get client hwaddr"; return 1; }
581	info "Client hwaddr: $HW_CLIENT"
582
583	# Setup server namespace
584	ip netns exec server ip addr add 172.31.110.20/24 dev s1
585	ip netns exec server ip link set s1 up
586	HW_SERVER=$(ip netns exec server ip link show dev s1 \
587		| awk '/link\/ether/ {print $2}')
588	[ -z "$HW_SERVER" ] && \
589		{ info "failed to get server hwaddr"; return 1; }
590	info "Server hwaddr: $HW_SERVER"
591
592	ovs_add_flow "test_arp_ping" arpping \
593		"in_port(1),eth(),eth_type(0x0806),arp(sip=172.31.110.10,tip=172.31.110.20,sha=$HW_CLIENT,tha=ff:ff:ff:ff:ff:ff)" '2' || return 1
594	ovs_add_flow "test_arp_ping" arpping \
595		"in_port(2),eth(),eth_type(0x0806),arp()" '1' || return 1
596
597	ovs_sbx "test_arp_ping" ip netns exec client arping -I c1 172.31.110.20 -c 1 || return 1
598
599	return 0
600}
601
602# ct_connect_v4 test
603#  - client has 1500 byte MTU
604#  - server has 1500 byte MTU
605#  - use ICMP to ping in each direction
606#  - only allow CT state stuff to pass through new in c -> s
607test_ct_connect_v4 () {
608
609	which nc >/dev/null 2>/dev/null || return $ksft_skip
610
611	sbx_add "test_ct_connect_v4" || return $?
612
613	ovs_add_dp "test_ct_connect_v4" ct4 || return 1
614	info "create namespaces"
615	for ns in client server; do
616		ovs_add_netns_and_veths "test_ct_connect_v4" "ct4" "$ns" \
617		    "${ns:0:1}0" "${ns:0:1}1" || return 1
618	done
619
620	ip netns exec client ip addr add 172.31.110.10/24 dev c1
621	ip netns exec client ip link set c1 up
622	ip netns exec server ip addr add 172.31.110.20/24 dev s1
623	ip netns exec server ip link set s1 up
624
625	# Add forwarding for ARP and ip packets - completely wildcarded
626	ovs_add_flow "test_ct_connect_v4" ct4 \
627		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
628	ovs_add_flow "test_ct_connect_v4" ct4 \
629		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
630	ovs_add_flow "test_ct_connect_v4" ct4 \
631		     'ct_state(-trk),eth(),eth_type(0x0800),ipv4()' \
632		     'ct(commit),recirc(0x1)' || return 1
633	ovs_add_flow "test_ct_connect_v4" ct4 \
634		     'recirc_id(0x1),ct_state(+trk+new),in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10)' \
635		     '2' || return 1
636	ovs_add_flow "test_ct_connect_v4" ct4 \
637		     'recirc_id(0x1),ct_state(+trk+est),in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10)' \
638		     '2' || return 1
639	ovs_add_flow "test_ct_connect_v4" ct4 \
640		     'recirc_id(0x1),ct_state(+trk+est),in_port(2),eth(),eth_type(0x0800),ipv4(dst=172.31.110.10)' \
641		     '1' || return 1
642	ovs_add_flow "test_ct_connect_v4" ct4 \
643		     'recirc_id(0x1),ct_state(+trk+inv),eth(),eth_type(0x0800),ipv4()' 'drop' || \
644		     return 1
645
646	# do a ping
647	ovs_sbx "test_ct_connect_v4" ip netns exec client ping 172.31.110.20 -c 3 || return 1
648
649	# create an echo server in 'server'
650	echo "server" | \
651		ovs_netns_spawn_daemon "test_ct_connect_v4" "server" \
652				nc -lvnp 4443
653	ovs_sbx "test_ct_connect_v4" ip netns exec client nc -i 1 -zv 172.31.110.20 4443 || return 1
654
655	# Now test in the other direction (should fail)
656	echo "client" | \
657		ovs_netns_spawn_daemon "test_ct_connect_v4" "client" \
658				nc -lvnp 4443
659	ovs_sbx "test_ct_connect_v4" ip netns exec client nc -i 1 -zv 172.31.110.10 4443
660	if [ $? == 0 ]; then
661	   info "ct connect to client was successful"
662	   return 1
663	fi
664
665	info "done..."
666	return 0
667}
668
669# connect_v4 test
670#  - client has 1500 byte MTU
671#  - server has 1500 byte MTU
672#  - use ICMP to ping in each direction
673test_connect_v4 () {
674
675	sbx_add "test_connect_v4" || return $?
676
677	ovs_add_dp "test_connect_v4" cv4 || return 1
678
679	info "create namespaces"
680	for ns in client server; do
681		ovs_add_netns_and_veths "test_connect_v4" "cv4" "$ns" \
682		    "${ns:0:1}0" "${ns:0:1}1" || return 1
683	done
684
685
686	ip netns exec client ip addr add 172.31.110.10/24 dev c1
687	ip netns exec client ip link set c1 up
688	ip netns exec server ip addr add 172.31.110.20/24 dev s1
689	ip netns exec server ip link set s1 up
690
691	# Add forwarding for ARP and ip packets - completely wildcarded
692	ovs_add_flow "test_connect_v4" cv4 \
693		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
694	ovs_add_flow "test_connect_v4" cv4 \
695		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
696	ovs_add_flow "test_connect_v4" cv4 \
697		'in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10)' '2' || return 1
698	ovs_add_flow "test_connect_v4" cv4 \
699		'in_port(2),eth(),eth_type(0x0800),ipv4(src=172.31.110.20)' '1' || return 1
700
701	# do a ping
702	ovs_sbx "test_connect_v4" ip netns exec client ping 172.31.110.20 -c 3 || return 1
703
704	info "done..."
705	return 0
706}
707
708# nat_connect_v4 test
709#  - client has 1500 byte MTU
710#  - server has 1500 byte MTU
711#  - use ICMP to ping in each direction
712#  - only allow CT state stuff to pass through new in c -> s
713test_nat_connect_v4 () {
714	which nc >/dev/null 2>/dev/null || return $ksft_skip
715
716	sbx_add "test_nat_connect_v4" || return $?
717
718	ovs_add_dp "test_nat_connect_v4" nat4 || return 1
719	info "create namespaces"
720	for ns in client server; do
721		ovs_add_netns_and_veths "test_nat_connect_v4" "nat4" "$ns" \
722		    "${ns:0:1}0" "${ns:0:1}1" || return 1
723	done
724
725	ip netns exec client ip addr add 172.31.110.10/24 dev c1
726	ip netns exec client ip link set c1 up
727	ip netns exec server ip addr add 172.31.110.20/24 dev s1
728	ip netns exec server ip link set s1 up
729
730	ip netns exec client ip route add default via 172.31.110.20
731
732	ovs_add_flow "test_nat_connect_v4" nat4 \
733		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
734	ovs_add_flow "test_nat_connect_v4" nat4 \
735		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
736	ovs_add_flow "test_nat_connect_v4" nat4 \
737		"ct_state(-trk),in_port(1),eth(),eth_type(0x0800),ipv4(dst=192.168.0.20)" \
738		"ct(commit,nat(dst=172.31.110.20)),recirc(0x1)"
739	ovs_add_flow "test_nat_connect_v4" nat4 \
740		"ct_state(-trk),in_port(2),eth(),eth_type(0x0800),ipv4()" \
741		"ct(commit,nat),recirc(0x2)"
742
743	ovs_add_flow "test_nat_connect_v4" nat4 \
744		"recirc_id(0x1),ct_state(+trk-inv),in_port(1),eth(),eth_type(0x0800),ipv4()" "2"
745	ovs_add_flow "test_nat_connect_v4" nat4 \
746		"recirc_id(0x2),ct_state(+trk-inv),in_port(2),eth(),eth_type(0x0800),ipv4()" "1"
747
748	# do a ping
749	ovs_sbx "test_nat_connect_v4" ip netns exec client ping 192.168.0.20 -c 3 || return 1
750
751	# create an echo server in 'server'
752	echo "server" | \
753		ovs_netns_spawn_daemon "test_nat_connect_v4" "server" \
754				nc -lvnp 4443
755	ovs_sbx "test_nat_connect_v4" ip netns exec client nc -i 1 -zv 192.168.0.20 4443 || return 1
756
757	# Now test in the other direction (should fail)
758	echo "client" | \
759		ovs_netns_spawn_daemon "test_nat_connect_v4" "client" \
760				nc -lvnp 4443
761	ovs_sbx "test_nat_connect_v4" ip netns exec client nc -i 1 -zv 172.31.110.10 4443
762	if [ $? == 0 ]; then
763	   info "connect to client was successful"
764	   return 1
765	fi
766
767	info "done..."
768	return 0
769}
770
771# nat_related_v4 test
772#  - client->server ip packets go via SNAT
773#  - client solicits ICMP destination unreachable packet from server
774#  - undo NAT for ICMP reply and test dst ip has been updated
775test_nat_related_v4 () {
776	which nc >/dev/null 2>/dev/null || return $ksft_skip
777
778	sbx_add "test_nat_related_v4" || return $?
779
780	ovs_add_dp "test_nat_related_v4" natrelated4 || return 1
781	info "create namespaces"
782	for ns in client server; do
783		ovs_add_netns_and_veths "test_nat_related_v4" "natrelated4" "$ns" \
784			"${ns:0:1}0" "${ns:0:1}1" || return 1
785	done
786
787	ip netns exec client ip addr add 172.31.110.10/24 dev c1
788	ip netns exec client ip link set c1 up
789	ip netns exec server ip addr add 172.31.110.20/24 dev s1
790	ip netns exec server ip link set s1 up
791
792	ip netns exec server ip route add 192.168.0.20/32 via 172.31.110.10
793
794	# Allow ARP
795	ovs_add_flow "test_nat_related_v4" natrelated4 \
796		"in_port(1),eth(),eth_type(0x0806),arp()" "2" || return 1
797	ovs_add_flow "test_nat_related_v4" natrelated4 \
798		"in_port(2),eth(),eth_type(0x0806),arp()" "1" || return 1
799
800	# Allow IP traffic from client->server, rewrite source IP with SNAT to 192.168.0.20
801	ovs_add_flow "test_nat_related_v4" natrelated4 \
802		"ct_state(-trk),in_port(1),eth(),eth_type(0x0800),ipv4(dst=172.31.110.20)" \
803		"ct(commit,nat(src=192.168.0.20)),recirc(0x1)" || return 1
804	ovs_add_flow "test_nat_related_v4" natrelated4 \
805		"recirc_id(0x1),ct_state(+trk-inv),in_port(1),eth(),eth_type(0x0800),ipv4()" \
806		"2" || return 1
807
808	# Allow related ICMP responses back from server and undo NAT to restore original IP
809	# Drop any ICMP related packets where dst ip hasn't been restored back to original IP
810	ovs_add_flow "test_nat_related_v4" natrelated4 \
811		"ct_state(-trk),in_port(2),eth(),eth_type(0x0800),ipv4()" \
812		"ct(commit,nat),recirc(0x2)" || return 1
813	ovs_add_flow "test_nat_related_v4" natrelated4 \
814		"recirc_id(0x2),ct_state(+rel+trk),in_port(2),eth(),eth_type(0x0800),ipv4(src=172.31.110.20,dst=172.31.110.10,proto=1),icmp()" \
815		"1" || return 1
816	ovs_add_flow "test_nat_related_v4" natrelated4 \
817		"recirc_id(0x2),ct_state(+rel+trk),in_port(2),eth(),eth_type(0x0800),ipv4(dst=192.168.0.20,proto=1),icmp()" \
818		"drop" || return 1
819
820	# Solicit destination unreachable response from server
821	ovs_sbx "test_nat_related_v4" ip netns exec client \
822		bash -c "echo a | nc -u -w 1 172.31.110.20 10000"
823
824	# Check to make sure no packets matched the drop rule with incorrect dst ip
825	python3 "$ovs_base/ovs-dpctl.py" dump-flows natrelated4 \
826		| grep "drop" | grep "packets:0" >/dev/null || return 1
827
828	info "done..."
829	return 0
830}
831
832# netlink_validation
833# - Create a dp
834# - check no warning with "old version" simulation
835test_netlink_checks () {
836	sbx_add "test_netlink_checks" || return 1
837
838	info "setting up new DP"
839	ovs_add_dp "test_netlink_checks" nv0 || return 1
840	# now try again
841	PRE_TEST=$(dmesg | grep -E "RIP: [0-9a-fA-Fx]+:ovs_dp_cmd_new\+")
842	ovs_add_dp "test_netlink_checks" nv0 -V 0 || return 1
843	POST_TEST=$(dmesg | grep -E "RIP: [0-9a-fA-Fx]+:ovs_dp_cmd_new\+")
844	if [ "$PRE_TEST" != "$POST_TEST" ]; then
845		info "failed - gen warning"
846		return 1
847	fi
848
849	ovs_add_netns_and_veths "test_netlink_checks" nv0 left left0 l0 || \
850	    return 1
851	ovs_add_netns_and_veths "test_netlink_checks" nv0 right right0 r0 || \
852	    return 1
853	[ $(python3 $ovs_base/ovs-dpctl.py show nv0 | grep port | \
854	    wc -l) == 3 ] || \
855	      return 1
856	ovs_del_if "test_netlink_checks" nv0 right0 || return 1
857	[ $(python3 $ovs_base/ovs-dpctl.py show nv0 | grep port | \
858	    wc -l) == 2 ] || \
859	      return 1
860
861	info "Checking clone depth"
862	ERR_MSG="Flow actions may not be safe on all matching packets"
863	PRE_TEST=$(dmesg | grep -c "${ERR_MSG}")
864	ovs_add_flow "test_netlink_checks" nv0 \
865		'in_port(1),eth(),eth_type(0x800),ipv4()' \
866		'clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(drop)))))))))))))))))' \
867		>/dev/null 2>&1 && return 1
868	POST_TEST=$(dmesg | grep -c "${ERR_MSG}")
869
870	if [ "$PRE_TEST" == "$POST_TEST" ]; then
871		info "failed - clone depth too large"
872		return 1
873	fi
874
875	PRE_TEST=$(dmesg | grep -c "${ERR_MSG}")
876	ovs_add_flow "test_netlink_checks" nv0 \
877		'in_port(1),eth(),eth_type(0x0806),arp()' 'drop(0),2' \
878		&> /dev/null && return 1
879	POST_TEST=$(dmesg | grep -c "${ERR_MSG}")
880	if [ "$PRE_TEST" == "$POST_TEST" ]; then
881		info "failed - error not generated"
882		return 1
883	fi
884	return 0
885}
886
887test_upcall_interfaces() {
888	sbx_add "test_upcall_interfaces" || return 1
889
890	info "setting up new DP"
891	ovs_add_dp "test_upcall_interfaces" ui0 -V 2:1 || return 1
892
893	ovs_add_netns_and_veths "test_upcall_interfaces" ui0 upc left0 l0 \
894	    172.31.110.1/24 -u || return 1
895
896	ovs_wait grep -q "listening on upcall packet handler" ${ovs_dir}/left0.out
897
898	info "sending arping"
899	ip netns exec upc arping -I l0 172.31.110.20 -c 1 \
900	    >$ovs_dir/arping.stdout 2>$ovs_dir/arping.stderr
901
902	grep -E "MISS upcall\[0/yes\]: .*arp\(sip=172.31.110.1,tip=172.31.110.20,op=1,sha=" $ovs_dir/left0.out >/dev/null 2>&1 || return 1
903	return 0
904}
905
906ovs_add_kernel_tunnel() {
907	local sbxname=$1; shift
908	local ns=$1; shift
909	local tnl_type=$1; shift
910	local name=$1; shift
911	local addr=$1; shift
912
913	info "setting up kernel ${tnl_type} tunnel ${name}"
914	ovs_sbx "${sbxname}" ip -netns ${ns} link add dev ${name} type ${tnl_type} $* || return 1
915	on_exit "ovs_sbx ${sbxname} ip -netns ${ns} link del ${name} >/dev/null 2>&1"
916	ovs_sbx "${sbxname}" ip -netns ${ns} addr add dev ${name} ${addr} || return 1
917	ovs_sbx "${sbxname}" ip -netns ${ns} link set dev ${name} mtu 1450 up || return 1
918}
919
920test_tunnel_metadata() {
921	which arping >/dev/null 2>&1 || return $ksft_skip
922
923	sbxname="test_tunnel_metadata"
924	sbx_add "${sbxname}" || return 1
925
926	info "setting up new DP"
927	ovs_add_dp "${sbxname}" tdp0 -V 2:1 || return 1
928
929	ovs_add_netns_and_veths "${sbxname}" tdp0 tns left0 l0 \
930		172.31.110.1/24 || return 1
931
932	info "removing veth interface from openvswitch and setting IP"
933	ovs_del_if "${sbxname}" tdp0 left0 || return 1
934	ovs_sbx "${sbxname}" ip addr add 172.31.110.2/24 dev left0 || return 1
935	ovs_sbx "${sbxname}" ip link set left0 up || return 1
936
937	info "setting up tunnel port in openvswitch"
938	ovs_add_if "${sbxname}" "vxlan" tdp0 ovs-vxlan0 -u || return 1
939	on_exit "ovs_sbx ${sbxname} ip link del ovs-vxlan0"
940	ovs_wait ip link show ovs-vxlan0 &>/dev/null || return 1
941	ovs_sbx "${sbxname}" ip link set ovs-vxlan0 up || return 1
942
943	configs=$(echo '
944	    1 172.31.221.1/24 1155332 32   set   udpcsum flags\(df\|csum\)
945	    2 172.31.222.1/24 1234567 45   set noudpcsum flags\(df\)
946	    3 172.31.223.1/24 1020304 23 unset   udpcsum flags\(csum\)
947	    4 172.31.224.1/24 1357986 15 unset noudpcsum' | sed '/^$/d')
948
949	while read -r i addr id ttl df csum flags; do
950		ovs_add_kernel_tunnel "${sbxname}" tns vxlan vxlan${i} ${addr} \
951			remote 172.31.110.2 id ${id} dstport 4789 \
952			ttl ${ttl} df ${df} ${csum} || return 1
953	done <<< "${configs}"
954
955	ovs_wait grep -q 'listening on upcall packet handler' \
956		${ovs_dir}/ovs-vxlan0.out || return 1
957
958	info "sending arping"
959	for i in 1 2 3 4; do
960		ovs_sbx "${sbxname}" ip netns exec tns \
961			arping -I vxlan${i} 172.31.22${i}.2 -c 1 \
962			>${ovs_dir}/arping.stdout 2>${ovs_dir}/arping.stderr
963	done
964
965	info "checking that received decapsulated packets carry correct metadata"
966	while read -r i addr id ttl df csum flags; do
967		arp_hdr="arp\\(sip=172.31.22${i}.1,tip=172.31.22${i}.2,op=1,sha="
968		addrs="src=172.31.110.1,dst=172.31.110.2"
969		ports="tp_src=[0-9]*,tp_dst=4789"
970		tnl_md="tunnel\\(tun_id=${id},${addrs},ttl=${ttl},${ports},${flags}\\)"
971
972		ovs_sbx "${sbxname}" grep -qE "MISS upcall.*${tnl_md}.*${arp_hdr}" \
973			${ovs_dir}/ovs-vxlan0.out || return 1
974	done <<< "${configs}"
975
976	return 0
977}
978
979test_tunnel_refcount() {
980	sbxname="test_tunnel_refcount"
981	sbx_add "${sbxname}" || return 1
982
983	ovs_sbx "${sbxname}" ip netns add trefns || return 1
984	on_exit "ovs_sbx ${sbxname} ip netns del trefns"
985
986	for tun_type in gre vxlan geneve; do
987		info "testing ${tun_type} tunnel vport refcount"
988
989		ovs_sbx "${sbxname}" ip netns exec trefns \
990			python3 $ovs_base/ovs-dpctl.py \
991			add-dp dp-${tun_type} || return 1
992
993		ovs_sbx "${sbxname}" ip netns exec trefns \
994			python3 $ovs_base/ovs-dpctl.py \
995			add-if --no-lwt -t ${tun_type} \
996			dp-${tun_type} ovs-${tun_type}0 || return 1
997
998		ovs_wait ip -netns trefns link show \
999			ovs-${tun_type}0 >/dev/null 2>&1 || return 1
1000
1001		info "deleting dp - may hang if reference counting is broken"
1002		ovs_sbx "${sbxname}" ip netns exec trefns \
1003			python3 $ovs_base/ovs-dpctl.py \
1004			del-dp dp-${tun_type} &
1005
1006		dev_removed() {
1007			! ip -netns trefns link show "$1" >/dev/null 2>&1
1008		}
1009		ovs_wait dev_removed dp-${tun_type} || return 1
1010		ovs_wait dev_removed ovs-${tun_type}0 || return 1
1011	done
1012
1013	return 0
1014}
1015
1016test_pop_vlan() {
1017	local sbx="test_pop_vlan"
1018	sbx_add "$sbx" || return $?
1019	ovs_add_dp "$sbx" vlandp || return 1
1020
1021	ovs_add_netns_and_veths "$sbx" vlandp \
1022		ns1 veth1 ns1veth 192.0.2.1/24 || return 1
1023	ovs_add_netns_and_veths "$sbx" vlandp \
1024		ns2 veth2 ns2veth 192.0.2.2/24 || return 1
1025
1026	# Baseline: untagged bidirectional forwarding
1027	ovs_add_flow "$sbx" vlandp \
1028		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
1029	ovs_add_flow "$sbx" vlandp \
1030		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
1031	ovs_add_flow "$sbx" vlandp \
1032		'in_port(1),eth(),eth_type(0x0800),ipv4()' '2' || return 1
1033	ovs_add_flow "$sbx" vlandp \
1034		'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1
1035	ovs_sbx "$sbx" ip netns exec ns1 ping -c 3 -W 2 \
1036		192.0.2.2 || return 1
1037
1038	# VLAN topology: ns1 uses VLAN sub-interface, ns2 is plain
1039	ip -n ns1 link add link ns1veth name ns1veth.10 \
1040		type vlan id 10 || return 1
1041	on_exit "ip -n ns1 link del ns1veth.10 2>/dev/null"
1042	ip -n ns1 addr add 198.51.100.1/24 dev ns1veth.10 || return 1
1043	ip -n ns1 link set ns1veth.10 up || return 1
1044	ip -n ns2 addr add 198.51.100.2/24 dev ns2veth || return 1
1045
1046	ovs_del_flows "$sbx" vlandp
1047
1048	# Static ARP: avoids VLAN-tagged ARP complexity
1049	local ns1veth10mac ns2mac
1050	ns1veth10mac=$(ip -n ns1 link show ns1veth.10 \
1051		| awk '/link\/ether/ {print $2}')
1052	[ -z "$ns1veth10mac" ] && \
1053		{ info "failed to get ns1veth10mac"; return 1; }
1054	ns2mac=$(ip -n ns2 link show ns2veth \
1055		| awk '/link\/ether/ {print $2}')
1056	[ -z "$ns2mac" ] && \
1057		{ info "failed to get ns2mac"; return 1; }
1058	ip -n ns1 neigh replace 198.51.100.2 lladdr "$ns2mac" \
1059		dev ns1veth.10 nud permanent || return 1
1060	ip -n ns2 neigh replace 198.51.100.1 \
1061		lladdr "$ns1veth10mac" \
1062		dev ns2veth nud permanent || return 1
1063
1064	local vlan_match='in_port(1),eth(),eth_type(0x8100),'
1065	vlan_match+='vlan(vid=10),'
1066	vlan_match+='encap(eth_type(0x0800),'
1067	vlan_match+='ipv4(src=198.51.100.1,proto=1),icmp())'
1068
1069	# Negative: forward without pop_vlan -- tagged frame
1070	# is invisible to ns2 (no VLAN sub-interface), ping fails
1071	ovs_add_flow "$sbx" vlandp "$vlan_match" '2' || return 1
1072	ovs_sbx "$sbx" ip netns exec ns1 ping -I ns1veth.10 \
1073		-c 3 -W 1 198.51.100.2 >/dev/null 2>&1 \
1074		&& { info "FAIL: ping should fail without pop_vlan"
1075		     return 1; }
1076
1077	ovs_del_flows "$sbx" vlandp
1078
1079	# Positive: pop_vlan strips tag on forward path,
1080	# push_vlan restores tag on return path -- ping succeeds
1081	ovs_add_flow "$sbx" vlandp \
1082		"$vlan_match" 'pop_vlan,2' || return 1
1083	ovs_add_flow "$sbx" vlandp \
1084		'in_port(2),eth(),eth_type(0x0800),ipv4()' \
1085		'push_vlan(vid=10,pcp=0,tpid=0x8100),1' || return 1
1086	ovs_sbx "$sbx" ip netns exec ns1 ping -I ns1veth.10 \
1087		-c 3 -W 2 198.51.100.2 || return 1
1088
1089	return 0
1090}
1091
1092run_test() {
1093	(
1094	tname="$1"
1095	tdesc="$2"
1096
1097	if python3 ovs-dpctl.py -h 2>&1 | \
1098	     grep -E "Need to (install|upgrade) the python" >/dev/null 2>&1; then
1099		stdbuf -o0 printf "TEST: %-60s  [PYLIB]\n" "${tdesc}"
1100		return $ksft_skip
1101	fi
1102
1103	python3 ovs-dpctl.py show >/dev/null 2>&1 || \
1104		echo "[DPCTL] show exception."
1105
1106	if ! lsmod | grep openvswitch >/dev/null 2>&1; then
1107		stdbuf -o0 printf "TEST: %-60s  [NOMOD]\n" "${tdesc}"
1108		return $ksft_skip
1109	fi
1110
1111	printf "TEST: %-60s  [START]\n" "${tname}"
1112
1113	unset IFS
1114
1115	eval test_${tname}
1116	ret=$?
1117
1118	if [ $ret -eq 0 ]; then
1119		printf "TEST: %-60s  [ OK ]\n" "${tdesc}"
1120		ovs_exit_sig
1121		rm -rf "$ovs_dir"
1122	elif [ $ret -eq 1 ]; then
1123		printf "TEST: %-60s  [FAIL]\n" "${tdesc}"
1124		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
1125			echo
1126			echo "Pausing. Logs in $ovs_dir/. Hit enter to continue"
1127			read a
1128		fi
1129		ovs_exit_sig
1130		[ "${PAUSE_ON_FAIL}" = "yes" ] || rm -rf "$ovs_dir"
1131		exit 1
1132	elif [ $ret -eq $ksft_skip ]; then
1133		printf "TEST: %-60s  [SKIP]\n" "${tdesc}"
1134	elif [ $ret -eq 2 ]; then
1135		rm -rf test_${tname}
1136		run_test "$1" "$2"
1137	fi
1138
1139	return $ret
1140	)
1141	ret=$?
1142	case $ret in
1143		0)
1144			[ $all_skipped = true ] && [ $exitcode=$ksft_skip ] && exitcode=0
1145			all_skipped=false
1146		;;
1147		$ksft_skip)
1148			[ $all_skipped = true ] && exitcode=$ksft_skip
1149		;;
1150		*)
1151			all_skipped=false
1152			exitcode=1
1153		;;
1154	esac
1155
1156	return $ret
1157}
1158
1159
1160exitcode=0
1161desc=0
1162all_skipped=true
1163
1164while getopts :pvt o
1165do
1166	case $o in
1167	p) PAUSE_ON_FAIL=yes;;
1168	v) VERBOSE=1;;
1169	t) if which tcpdump > /dev/null 2>&1; then
1170		TRACING=1
1171	   else
1172		echo "=== tcpdump not available, tracing disabled"
1173	   fi
1174	   ;;
1175	*) usage;;
1176	esac
1177done
1178shift $(($OPTIND-1))
1179
1180IFS="
1181"
1182
1183for arg do
1184	# Check first that all requested tests are available before running any
1185	command -v > /dev/null "test_${arg}" || { echo "=== Test ${arg} not found"; usage; }
1186done
1187
1188name=""
1189desc=""
1190for t in ${tests}; do
1191	[ "${name}" = "" ]	&& name="${t}"	&& continue
1192	[ "${desc}" = "" ]	&& desc="${t}"
1193
1194	run_this=1
1195	for arg do
1196		[ "${arg}" != "${arg#--*}" ] && continue
1197		[ "${arg}" = "${name}" ] && run_this=1 && break
1198		run_this=0
1199	done
1200	if [ $run_this -eq 1 ]; then
1201		run_test "${name}" "${desc}"
1202	fi
1203	name=""
1204	desc=""
1205done
1206
1207exit ${exitcode}
1208