xref: /linux/tools/testing/selftests/net/openvswitch/openvswitch.sh (revision b0e75977c6883283b55fbbdcd64d1c7111b134f2)
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	drop_reason				drop: test drop reasons are emitted
30	pop_vlan				vlan: POP_VLAN action strips tag
31	dec_ttl					ttl: dec_ttl decrements IP TTL
32	flow_set				flow-set: Flow modify
33	action_set				set: SET action rewrites fields
34	trunc					trunc: output truncation
35	icmpv6					icmpv6: ICMPv6 echo type match
36	sctp_connect_v4				sctp: SCTP flow key matching
37	sctp_connect_v6				sctp6: SCTP flow keys over IPv6
38	sctp_nat_connect_v4			sctpnat4: SCTP NAT translation
39	psample					psample: Sampling packets with psample"
40
41info() {
42	[ "${ovs_dir}" != "" ] &&
43		echo "`date +"[%m-%d %H:%M:%S]"` $*" >> ${ovs_dir}/debug.log
44	[ $VERBOSE = 0 ] || echo $*
45}
46
47ovs_wait() {
48	info "waiting $WAIT_TIMEOUT s for: $@"
49
50	if "$@" ; then
51		info "wait succeeded immediately"
52		return 0
53	fi
54
55	# A quick re-check helps speed up small races in fast systems.
56	# However, fractional sleeps might not necessarily work.
57	local start=0
58	sleep 0.1 || { sleep 1; start=1; }
59
60	for (( i=start; i<WAIT_TIMEOUT; i++ )); do
61		if "$@" ; then
62			info "wait succeeded after $i seconds"
63			return 0
64		fi
65		sleep 1
66	done
67	info "wait failed after $i seconds"
68	return 1
69}
70
71ovs_base=`pwd`
72sbxs=
73sbx_add () {
74	info "adding sandbox '$1'"
75
76	sbxs="$sbxs $1"
77
78	NO_BIN=0
79
80	# Create sandbox.
81	local d="$ovs_base"/$1
82	if [ -e $d ]; then
83		info "removing $d"
84		rm -rf "$d"
85	fi
86	mkdir "$d" || return 1
87	ovs_setenv $1
88}
89
90ovs_exit_sig() {
91	[ -e ${ovs_dir}/cleanup ] && . "$ovs_dir/cleanup"
92}
93
94on_exit() {
95	echo "$1" > ${ovs_dir}/cleanup.tmp
96	cat ${ovs_dir}/cleanup >> ${ovs_dir}/cleanup.tmp
97	mv ${ovs_dir}/cleanup.tmp ${ovs_dir}/cleanup
98}
99
100ovs_setenv() {
101	sandbox=$1
102
103	ovs_dir=$ovs_base${1:+/$1}; export ovs_dir
104
105	test -e ${ovs_dir}/cleanup || : > ${ovs_dir}/cleanup
106}
107
108ovs_sbx() {
109	if test "X$2" != X; then
110		(ovs_setenv $1; shift;
111		 info "run cmd: $@"; "$@" >> ${ovs_dir}/debug.log)
112	else
113		ovs_setenv $1
114	fi
115}
116
117ovs_add_dp () {
118	info "Adding DP/Bridge IF: sbx:$1 dp:$2 {$3, $4, $5}"
119	sbxname="$1"
120	shift
121	ovs_sbx "$sbxname" python3 $ovs_base/ovs-dpctl.py add-dp $*
122	on_exit "ovs_sbx $sbxname python3 $ovs_base/ovs-dpctl.py del-dp $1;"
123}
124
125ovs_add_if () {
126	info "Adding IF to DP: br:$3 if:$4 ($2)"
127	if [ "$5" != "-u" ]; then
128		ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py add-if \
129		    -t "$2" "$3" "$4" || return 1
130	else
131		python3 $ovs_base/ovs-dpctl.py add-if \
132		    -u -t "$2" "$3" "$4" >$ovs_dir/$4.out 2>$ovs_dir/$4.err &
133		pid=$!
134		on_exit "ovs_sbx $1 kill -TERM $pid 2>/dev/null"
135	fi
136}
137
138ovs_del_if () {
139	info "Deleting IF from DP: br:$2 if:$3"
140	ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py del-if "$2" "$3" || return 1
141}
142
143ovs_netns_spawn_daemon() {
144	sbx=$1
145	shift
146	netns=$1
147	shift
148	if [ "$netns" == "_default" ]; then
149		$*  >> $ovs_dir/stdout  2>> $ovs_dir/stderr &
150	else
151		ip netns exec $netns $*  >> $ovs_dir/stdout  2>> $ovs_dir/stderr &
152	fi
153	pid=$!
154	ovs_sbx "$sbx" on_exit "kill -TERM $pid 2>/dev/null"
155}
156
157ovs_spawn_daemon() {
158	sbx=$1
159	shift
160	ovs_netns_spawn_daemon $sbx "_default" $*
161}
162
163ovs_add_netns_and_veths () {
164	info "Adding netns attached: sbx:$1 dp:$2 {$3, $4, $5}"
165	ovs_sbx "$1" ip netns add "$3" || return 1
166	on_exit "ovs_sbx $1 ip netns del $3"
167	ovs_sbx "$1" ip link add "$4" type veth peer name "$5" || return 1
168	on_exit "ovs_sbx $1 ip link del $4 >/dev/null 2>&1"
169	ovs_sbx "$1" ip link set "$4" up || return 1
170	ovs_sbx "$1" ip link set "$5" netns "$3" || return 1
171	ovs_sbx "$1" ip netns exec "$3" ip link set "$5" up || return 1
172
173	if [ "$6" != "" ]; then
174		ovs_sbx "$1" ip netns exec "$3" ip addr add "$6" dev "$5" \
175		    || return 1
176	fi
177
178	if [ "$7" != "-u" ]; then
179		ovs_add_if "$1" "netdev" "$2" "$4" || return 1
180	else
181		ovs_add_if "$1" "netdev" "$2" "$4" -u || return 1
182	fi
183
184	if [ $TRACING -eq 1 ]; then
185		ovs_netns_spawn_daemon "$1" "$3" tcpdump -l -i any -s 6553
186		ovs_wait grep -q "listening on any" ${ovs_dir}/stderr
187	fi
188
189	return 0
190}
191
192ovs_add_flow () {
193	info "Adding flow to DP: sbx:$1 br:$2 flow:$3 act:$4"
194	ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py add-flow "$2" "$3" "$4"
195	if [ $? -ne 0 ]; then
196		info "Flow [ $3 : $4 ] failed"
197		return 1
198	fi
199	return 0
200}
201
202ovs_mod_flow () {
203	if [ -n "$4" ]; then
204		info "Modifying flow: sbx:$1 br:$2 flow:$3 act:$4"
205		ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py \
206			mod-flow "$2" "$3" "$4"
207	else
208		info "Modifying flow (no actions): sbx:$1 br:$2 flow:$3"
209		ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py \
210			mod-flow "$2" "$3"
211	fi
212	if [ $? -ne 0 ]; then
213		info "Flow modify [ $3 ] failed"
214		return 1
215	fi
216	return 0
217}
218
219ovs_del_flows () {
220	info "Deleting all flows from DP: sbx:$1 br:$2"
221	ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py del-flows "$2"
222	return 0
223}
224
225ovs_drop_record_and_run () {
226	local sbx=$1
227	shift
228
229	perf record -a -q -e skb:kfree_skb -o ${ovs_dir}/perf.data $* \
230		>> ${ovs_dir}/stdout 2>> ${ovs_dir}/stderr
231	return $?
232}
233
234ovs_drop_reason_count()
235{
236	local reason=$1
237
238	local perf_output=`perf script -i ${ovs_dir}/perf.data -F trace:event,trace`
239	local pattern="skb:kfree_skb:.*reason: $reason"
240
241	return `echo "$perf_output" | grep "$pattern" | wc -l`
242}
243
244ovs_test_flow_fails () {
245	ERR_MSG="Flow actions may not be safe on all matching packets"
246
247	PRE_TEST=$(dmesg | grep -c "${ERR_MSG}")
248	ovs_add_flow $@ &> /dev/null $@ && return 1
249	POST_TEST=$(dmesg | grep -c "${ERR_MSG}")
250
251	if [ "$PRE_TEST" == "$POST_TEST" ]; then
252		return 1
253	fi
254	return 0
255}
256
257usage() {
258	echo
259	echo "$0 [OPTIONS] [TEST]..."
260	echo "If no TEST argument is given, all tests will be run."
261	echo
262	echo "Options"
263	echo "  -t: capture traffic via tcpdump"
264	echo "  -v: verbose"
265	echo "  -p: pause on failure"
266	echo
267	echo "Available tests${tests}"
268	exit 1
269}
270
271
272test_dec_ttl() {
273	sbx_add "test_dec_ttl" || return $?
274	ovs_add_dp "test_dec_ttl" decttl || return 1
275
276	info "create namespaces"
277	for ns in client server; do
278		ovs_add_netns_and_veths "test_dec_ttl" "decttl" "$ns" \
279			"${ns:0:1}0" "${ns:0:1}1" || return 1
280	done
281
282	ip netns exec client ip addr add 10.0.0.1/24 dev c1
283	ip netns exec client ip link set c1 up
284	ip netns exec server ip addr add 10.0.0.2/24 dev s1
285	ip netns exec server ip link set s1 up
286
287	# Probe: check if kernel supports dec_ttl action.
288	ovs_add_flow "test_dec_ttl" decttl \
289		'in_port(1),eth(),eth_type(0x0800),ipv4()' \
290		'dec_ttl(le_1())' &>/dev/null
291	if [ $? -ne 0 ]; then
292		info "no support for dec_ttl - skipping"
293		ovs_exit_sig
294		return $ksft_skip
295	fi
296
297	ovs_del_flows "test_dec_ttl" decttl
298
299	# ARP flows (bidirectional)
300	ovs_add_flow "test_dec_ttl" decttl \
301		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
302	ovs_add_flow "test_dec_ttl" decttl \
303		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
304
305	# IP flows with dec_ttl action
306	ovs_add_flow "test_dec_ttl" decttl \
307		'in_port(1),eth(),eth_type(0x0800),ipv4()' \
308		'dec_ttl(le_1()),2' || return 1
309	ovs_add_flow "test_dec_ttl" decttl \
310		'in_port(2),eth(),eth_type(0x0800),ipv4()' \
311		'dec_ttl(le_1()),1' || return 1
312
313	info "verify connectivity with dec_ttl"
314	ovs_sbx "test_dec_ttl" ip netns exec client ping -c 1 -W 2 \
315		10.0.0.2 || return 1
316
317	info "verify TTL=1 is dropped by dec_ttl"
318	ovs_sbx "test_dec_ttl" ip netns exec client ping -c 1 -W 2 \
319		-t 1 10.0.0.2 >/dev/null 2>&1 \
320		&& { info "FAIL: ping should fail with TTL=1 and dec_ttl"
321		     return 1; }
322
323	return 0
324}
325
326test_flow_set() {
327	sbx_add "test_flow_set" || return $?
328	ovs_add_dp "test_flow_set" flowset || return 1
329
330	info "create namespaces"
331	for ns in client server; do
332		ovs_add_netns_and_veths "test_flow_set" "flowset" "$ns" \
333			"${ns:0:1}0" "${ns:0:1}1" || return 1
334	done
335
336	ip netns exec client ip addr add 10.0.0.1/24 dev c1
337	ip netns exec client ip link set c1 up
338	ip netns exec server ip addr add 10.0.0.2/24 dev s1
339	ip netns exec server ip link set s1 up
340
341	ovs_add_flow "test_flow_set" flowset \
342		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
343	ovs_add_flow "test_flow_set" flowset \
344		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
345
346	local fwd_flow="ufid:00000001-0002-0003-0004-000500060007"
347	fwd_flow="$fwd_flow,in_port(1),eth(),eth_type(0x0800),ipv4()"
348
349	ovs_add_flow "test_flow_set" flowset "$fwd_flow" '2' \
350		|| return 1
351	ovs_add_flow "test_flow_set" flowset \
352		'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1
353
354	info "verify initial forwarding"
355	ovs_sbx "test_flow_set" ip netns exec client ping -c 1 -W 2 \
356		10.0.0.2 || return 1
357
358	info "mod-flow with new actions (change to drop)"
359	ovs_mod_flow "test_flow_set" flowset "$fwd_flow" 'drop' \
360		|| return 1
361
362	info "verify traffic is now dropped"
363	ovs_sbx "test_flow_set" ip netns exec client ping -c 1 -W 2 \
364		10.0.0.2 >/dev/null 2>&1 \
365		&& { info "FAIL: ping should fail after mod-flow to drop"
366		     return 1; }
367
368	info "mod-flow without actions"
369	ovs_mod_flow "test_flow_set" flowset "$fwd_flow" || return 1
370
371	info "verify flow retained drop action via dump"
372	python3 "$ovs_base/ovs-dpctl.py" dump-flows flowset \
373		| grep -q "actions:drop" || \
374		{ info "FAIL: flow not showing drop action"; return 1; }
375
376	info "verify drop actions unchanged"
377	ovs_sbx "test_flow_set" ip netns exec client ping -c 1 -W 2 \
378		10.0.0.2 >/dev/null 2>&1 \
379		&& { info "FAIL: ping should still fail after no-actions set"
380		     return 1; }
381
382	return 0
383}
384
385test_action_set() {
386	sbx_add "test_action_set" || return $?
387	ovs_add_dp "test_action_set" settest || return 1
388
389	info "create namespaces"
390	for ns in client server; do
391		ovs_add_netns_and_veths "test_action_set" "settest" "$ns" \
392			"${ns:0:1}0" "${ns:0:1}1" || return 1
393	done
394
395	ip netns exec client ip addr add 10.0.0.1/24 dev c1
396	ip netns exec client ip link set c1 up
397	ip netns exec server ip addr add 10.0.0.2/24 dev s1
398	ip netns exec server ip link set s1 up
399
400	ovs_add_flow "test_action_set" settest \
401		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
402	ovs_add_flow "test_action_set" settest \
403		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
404
405	ovs_add_flow "test_action_set" settest \
406		'in_port(1),eth(),eth_type(0x0800),ipv4()' '2' || return 1
407	ovs_add_flow "test_action_set" settest \
408		'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1
409
410	info "verify connectivity without SET"
411	ovs_sbx "test_action_set" ip netns exec client ping -c 1 -W 2 \
412		10.0.0.2 || return 1
413
414	ovs_del_flows "test_action_set" settest
415	ovs_add_flow "test_action_set" settest \
416		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
417	ovs_add_flow "test_action_set" settest \
418		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
419
420	info "set ipv4 dst to unreachable address"
421	ovs_add_flow "test_action_set" settest \
422		'in_port(1),eth(),eth_type(0x0800),ipv4()' \
423		'set(ipv4(dst=10.0.0.99)),2' || return 1
424	ovs_add_flow "test_action_set" settest \
425		'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1
426
427	info "verify ping fails with rewritten dst"
428	ovs_sbx "test_action_set" ip netns exec client ping -c 1 -W 2 \
429		10.0.0.2 >/dev/null 2>&1 \
430		&& { info "FAIL: ping should fail with dst rewritten"
431		     return 1; }
432
433	ovs_del_flows "test_action_set" settest
434	ovs_add_flow "test_action_set" settest \
435		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
436	ovs_add_flow "test_action_set" settest \
437		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
438	ovs_add_flow "test_action_set" settest \
439		'in_port(1),eth(),eth_type(0x0800),ipv4()' '2' || return 1
440	ovs_add_flow "test_action_set" settest \
441		'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1
442
443	info "verify connectivity restored without SET"
444	ovs_sbx "test_action_set" ip netns exec client ping -c 1 -W 2 \
445		10.0.0.2 || return 1
446
447	return 0
448}
449
450# trunc test
451# - trunc(14): truncate to ETH_HLEN, strips IP payload, ping fails
452# - trunc(1) and trunc(13): kernel rejects below ETH_HLEN (EINVAL)
453# - restore normal forwarding and verify recovery
454test_trunc() {
455	sbx_add "test_trunc" || return $?
456	ovs_add_dp "test_trunc" trunctest || return 1
457
458	info "create namespaces"
459	for ns in client server; do
460		ovs_add_netns_and_veths "test_trunc" "trunctest" \
461		    "$ns" "${ns:0:1}0" "${ns:0:1}1" || return 1
462	done
463
464	ip netns exec client ip addr add 10.0.0.1/24 dev c1
465	ip netns exec client ip link set c1 up
466	ip netns exec server ip addr add 10.0.0.2/24 dev s1
467	ip netns exec server ip link set s1 up
468
469	ovs_add_flow "test_trunc" trunctest \
470	    'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
471	ovs_add_flow "test_trunc" trunctest \
472	    'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
473	ovs_add_flow "test_trunc" trunctest \
474	    'in_port(1),eth(),eth_type(0x0800),ipv4()' \
475	    '2' || return 1
476	ovs_add_flow "test_trunc" trunctest \
477	    'in_port(2),eth(),eth_type(0x0800),ipv4()' \
478	    '1' || return 1
479
480	info "verify connectivity without truncation"
481	ovs_sbx "test_trunc" ip netns exec client \
482	    ping -c 1 -W 2 10.0.0.2 || return 1
483
484	# trunc below ETH_HLEN must be rejected by the kernel
485	info "verify trunc(1) is rejected"
486	ovs_add_flow "test_trunc" trunctest \
487	    'in_port(1),eth(),eth_type(0x0800),ipv4()' \
488	    'trunc(1),2' &> /dev/null \
489	    && { info "trunc(1) should be rejected"; return 1; }
490
491	info "verify trunc(13) is rejected"
492	ovs_add_flow "test_trunc" trunctest \
493	    'in_port(1),eth(),eth_type(0x0800),ipv4()' \
494	    'trunc(13),2' &> /dev/null \
495	    && { info "trunc(13) should be rejected"; return 1; }
496
497	ovs_del_flows "test_trunc" trunctest
498	ovs_add_flow "test_trunc" trunctest \
499	    'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
500	ovs_add_flow "test_trunc" trunctest \
501	    'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
502
503	info "add trunc(14) forwarding flow"
504	ovs_add_flow "test_trunc" trunctest \
505	    'in_port(1),eth(),eth_type(0x0800),ipv4()' \
506	    'trunc(14),2' || return 1
507	ovs_add_flow "test_trunc" trunctest \
508	    'in_port(2),eth(),eth_type(0x0800),ipv4()' \
509	    '1' || return 1
510
511	info "verify ping fails with trunc(14)"
512	ovs_sbx "test_trunc" ip netns exec client \
513	    ping -c 1 -W 2 10.0.0.2 >/dev/null 2>&1 \
514	    && { info "ping should fail with trunc(14)"
515	         return 1; }
516
517	ovs_del_flows "test_trunc" trunctest
518	ovs_add_flow "test_trunc" trunctest \
519	    'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
520	ovs_add_flow "test_trunc" trunctest \
521	    'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
522	ovs_add_flow "test_trunc" trunctest \
523	    'in_port(1),eth(),eth_type(0x0800),ipv4()' \
524	    '2' || return 1
525	ovs_add_flow "test_trunc" trunctest \
526	    'in_port(2),eth(),eth_type(0x0800),ipv4()' \
527	    '1' || return 1
528
529	info "verify connectivity restored"
530	ovs_sbx "test_trunc" ip netns exec client \
531	    ping -c 1 -W 2 10.0.0.2 || return 1
532
533	return 0
534}
535
536# icmpv6 test
537# - static neighbours to bypass NDP (nud permanent)
538# - icmpv6(type=128) echo request, icmpv6(type=129) echo reply
539# - remove flows and verify ping fails, reinstall and recover
540test_icmpv6() {
541	local t="test_icmpv6"
542	local v6="eth_type(0x86dd),ipv6(proto=58)"
543
544	sbx_add "$t" || return $?
545	ovs_add_dp "$t" icmpv6 || return 1
546
547	info "create namespaces"
548	for ns in client server; do
549		ovs_add_netns_and_veths "$t" "icmpv6" \
550		    "$ns" "${ns:0:1}0" "${ns:0:1}1" || return 1
551	done
552
553	ip netns exec client ip addr add fd00::1/64 dev c1 nodad
554	ip netns exec client ip link set c1 up
555	ip netns exec server ip addr add fd00::2/64 dev s1 nodad
556	ip netns exec server ip link set s1 up
557
558	local cl_mac sl_mac
559	cl_mac=$(ip netns exec client ip link show c1 \
560	    | awk '/link\/ether/ {print $2}')
561	[ -z "$cl_mac" ] && \
562	    { info "failed to get c1 hwaddr"; return 1; }
563	sl_mac=$(ip netns exec server ip link show s1 \
564	    | awk '/link\/ether/ {print $2}')
565	[ -z "$sl_mac" ] && \
566	    { info "failed to get s1 hwaddr"; return 1; }
567	ip netns exec client ip -6 neigh add fd00::2 \
568	    lladdr "$sl_mac" nud permanent dev c1 || return 1
569	ip netns exec server ip -6 neigh add fd00::1 \
570	    lladdr "$cl_mac" nud permanent dev s1 || return 1
571
572	# Probe: check if kernel supports icmpv6 flow key.
573	ovs_add_flow "$t" icmpv6 \
574	    "in_port(1),eth(),$v6,icmpv6(type=128)" \
575	    '2' &>/dev/null
576	if [ $? -ne 0 ]; then
577		info "no support for icmpv6 key - skipping"
578		ovs_exit_sig
579		return $ksft_skip
580	fi
581	ovs_del_flows "$t" icmpv6
582
583	ovs_add_flow "$t" icmpv6 \
584	    "in_port(1),eth(),$v6,icmpv6(type=128)" \
585	    '2' || return 1
586	ovs_add_flow "$t" icmpv6 \
587	    "in_port(2),eth(),$v6,icmpv6(type=129)" \
588	    '1' || return 1
589
590	info "verify ICMPv6 echo with type-specific flows"
591	ovs_sbx "$t" ip netns exec client \
592	    ping -6 -c 1 -W 2 fd00::2 || return 1
593
594	ovs_del_flows "$t" icmpv6
595
596	info "verify ping fails without echo flows"
597	ovs_sbx "$t" ip netns exec client \
598	    ping -6 -c 1 -W 2 fd00::2 >/dev/null 2>&1 \
599	    && { info "ping should fail without flows"
600	         return 1; }
601
602	ovs_add_flow "$t" icmpv6 \
603	    "in_port(1),eth(),$v6,icmpv6(type=128)" \
604	    '2' || return 1
605	ovs_add_flow "$t" icmpv6 \
606	    "in_port(2),eth(),$v6,icmpv6(type=129)" \
607	    '1' || return 1
608
609	info "verify connectivity restored"
610	ovs_sbx "$t" ip netns exec client \
611	    ping -6 -c 1 -W 2 fd00::2 || return 1
612
613	return 0
614}
615
616# Check for an SCTP endpoint via /proc, which works without sctp_diag.
617sctp_eps_has() {
618	ip netns exec "$1" awk -v p="$2" '$6==p' /proc/net/sctp/eps | grep -q .
619}
620
621# sctp_connect_v4 test
622# - sctp(dst=4443) matches client-to-server INIT
623# - sctp(src=4443) matches server-to-client INIT-ACK
624# - remove flows and verify connection fails, reinstall and recover
625test_sctp_connect_v4() {
626	local t="test_sctp_connect_v4"
627	local srv_ip=172.31.110.20
628
629	modprobe -q sctp 2>/dev/null || return "$ksft_skip"
630	socat -V 2>&1 | grep -q "define WITH_SCTP" || return "$ksft_skip"
631
632	sbx_add "$t" || return $?
633	ovs_add_dp "$t" sctp4 || return 1
634
635	info "create namespaces"
636	for ns in client server; do
637		ovs_add_netns_and_veths "$t" "sctp4" "$ns" \
638		    "${ns:0:1}0" "${ns:0:1}1" || return 1
639	done
640
641	ip netns exec client ip addr add 172.31.110.10/24 dev c1
642	ip netns exec client ip link set c1 up
643	ip netns exec server ip addr add "${srv_ip}/24" dev s1
644	ip netns exec server ip link set s1 up
645
646	# ARP forwarding
647	ovs_add_flow "$t" sctp4 \
648	    'in_port(1),eth(),eth_type(0x0806),arp()' \
649	    '2' || return 1
650	ovs_add_flow "$t" sctp4 \
651	    'in_port(2),eth(),eth_type(0x0806),arp()' \
652	    '1' || return 1
653
654	# SCTP port matching: dst for request, src for reply
655	ovs_add_flow "$t" sctp4 \
656	    'in_port(1),eth(),eth_type(0x0800),ipv4(proto=132),sctp(dst=4443)' \
657	    '2' || return 1
658	ovs_add_flow "$t" sctp4 \
659	    'in_port(2),eth(),eth_type(0x0800),ipv4(proto=132),sctp(src=4443)' \
660	    '1' || return 1
661
662	# The listener forks a child per association, so one instance serves
663	# the whole test and the flows stay the only variable. -t 1 bounds
664	# how long a child lingers after its association closes.
665	ovs_netns_spawn_daemon "$t" "server" \
666	    socat -u -t 1 SCTP4-LISTEN:4443,fork STDOUT
667	ovs_wait sctp_eps_has server 4443 || return 1
668
669	info "verify SCTP association with port-keyed flows"
670	ovs_sbx "$t" ip netns exec client \
671	    timeout 3 socat -u STDIN "SCTP4-CONNECT:${srv_ip}:4443" </dev/null \
672	    || return 1
673
674	ovs_del_flows "$t" sctp4
675
676	info "verify connection fails without flows"
677	ovs_add_flow "$t" sctp4 \
678	    'in_port(1),eth(),eth_type(0x0806),arp()' \
679	    '2' || return 1
680	ovs_add_flow "$t" sctp4 \
681	    'in_port(2),eth(),eth_type(0x0806),arp()' \
682	    '1' || return 1
683
684	ovs_sbx "$t" ip netns exec client \
685	    timeout 3 socat -u STDIN "SCTP4-CONNECT:${srv_ip}:4443" </dev/null \
686	    >/dev/null 2>&1 \
687	    && { info "connection should fail without flows"
688	         return 1; }
689
690	info "reinstall flows and verify recovery"
691	ovs_add_flow "$t" sctp4 \
692	    'in_port(1),eth(),eth_type(0x0800),ipv4(proto=132),sctp(dst=4443)' \
693	    '2' || return 1
694	ovs_add_flow "$t" sctp4 \
695	    'in_port(2),eth(),eth_type(0x0800),ipv4(proto=132),sctp(src=4443)' \
696	    '1' || return 1
697
698	ovs_sbx "$t" ip netns exec client \
699	    timeout 3 socat -u STDIN "SCTP4-CONNECT:${srv_ip}:4443" </dev/null \
700	    || return 1
701
702	return 0
703}
704
705# sctp_connect_v6 test
706# - sctp(dst=4443) matches client-to-server INIT
707# - sctp(src=4443) matches server-to-client INIT-ACK
708# - icmpv6 NS/NA flows forward neighbour discovery
709# - remove flows and verify connection fails, reinstall and recover
710test_sctp_connect_v6() {
711	local t="test_sctp_connect_v6"
712	local v6="eth_type(0x86dd),ipv6(proto=132)"
713	local payload="SCTP6_DATA_OK"
714	local rxfile="${ovs_base}/${t}/sctp-rx.txt"
715
716	modprobe -q sctp 2>/dev/null || return "$ksft_skip"
717	socat -V 2>&1 | grep -q "define WITH_SCTP" || return "$ksft_skip"
718	socat -V 2>&1 | grep -q "define WITH_IP6" || return "$ksft_skip"
719	[ -e /proc/sys/net/ipv6 ] || return "$ksft_skip"
720
721	sbx_add "$t" || return $?
722	ovs_add_dp "$t" sctp6 || return 1
723
724	info "create namespaces"
725	for ns in client server; do
726		ovs_add_netns_and_veths "$t" "sctp6" "$ns" \
727		    "${ns:0:1}0" "${ns:0:1}1" || return 1
728	done
729
730	ip netns exec client ip addr add fd00::1/64 dev c1 nodad
731	ip netns exec client ip link set c1 up
732	ip netns exec server ip addr add fd00::2/64 dev s1 nodad
733	ip netns exec server ip link set s1 up
734
735	# NS/NA forwarding
736	ovs_add_flow "$t" sctp6 \
737	    'in_port(1),eth(),eth_type(0x86dd),ipv6(proto=58),icmpv6()' \
738	    '2' || return 1
739	ovs_add_flow "$t" sctp6 \
740	    'in_port(2),eth(),eth_type(0x86dd),ipv6(proto=58),icmpv6()' \
741	    '1' || return 1
742
743	# SCTP port matching: dst for request, src for reply
744	ovs_add_flow "$t" sctp6 \
745	    "in_port(1),eth(),$v6,sctp(dst=4443)" \
746	    '2' || return 1
747	ovs_add_flow "$t" sctp6 \
748	    "in_port(2),eth(),$v6,sctp(src=4443)" \
749	    '1' || return 1
750
751	# A keyless ipv6(proto=132) install must be refused (EINVAL):
752	# match_validate() requires the sctp() key. Pin the reject side
753	# of that rule; the keyed installs above cover the accept side.
754	# Verify the refusal is EINVAL (missing key), not a parse error.
755	err=$(ovs_sbx "$t" python3 $ovs_base/ovs-dpctl.py add-flow sctp6 \
756	    "in_port(1),eth(),$v6" '2' 2>&1 >/dev/null) \
757	    && { info "keyless SCTP flow should be refused"
758	         return 1; }
759	echo "$err" | grep -q "(22," || {
760		info "keyless SCTP flow refused for wrong reason: $err"
761		return 1
762	}
763
764	ovs_netns_spawn_daemon "$t" "server" \
765	    socat -u -t 1 SCTP6-LISTEN:4443,fork \
766	    OPEN:"$rxfile",creat,append
767	ovs_wait sctp_eps_has server 4443 || return 1
768
769	info "verify SCTP association with port-keyed flows"
770	ovs_sbx "$t" ip netns exec client \
771	    timeout 3 socat -u STDIN "SCTP6-CONNECT:[fd00::2]:4443" </dev/null \
772	    || return 1
773
774	info "verify SCTP DATA chunk crosses the datapath"
775	ovs_sbx "$t" ip netns exec client \
776	    timeout 3 socat -u STDIN "SCTP6-CONNECT:[fd00::2]:4443" \
777	    <<< "$payload" || return 1
778	ovs_wait grep -q "$payload" "$rxfile" \
779	    || { info "server did not receive SCTP DATA payload"
780	         return 1; }
781
782	ovs_del_flows "$t" sctp6
783
784	info "verify connection fails without flows"
785	ovs_add_flow "$t" sctp6 \
786	    'in_port(1),eth(),eth_type(0x86dd),ipv6(proto=58),icmpv6()' \
787	    '2' || return 1
788	ovs_add_flow "$t" sctp6 \
789	    'in_port(2),eth(),eth_type(0x86dd),ipv6(proto=58),icmpv6()' \
790	    '1' || return 1
791
792	ovs_sbx "$t" ip netns exec client \
793	    timeout 3 socat -u STDIN "SCTP6-CONNECT:[fd00::2]:4443" </dev/null \
794	    >/dev/null 2>&1 \
795	    && { info "connection should fail without flows"
796	         return 1; }
797
798	info "reinstall flows and verify recovery"
799	ovs_add_flow "$t" sctp6 \
800	    "in_port(1),eth(),$v6,sctp(dst=4443)" \
801	    '2' || return 1
802	ovs_add_flow "$t" sctp6 \
803	    "in_port(2),eth(),$v6,sctp(src=4443)" \
804	    '1' || return 1
805
806	ovs_sbx "$t" ip netns exec client \
807	    timeout 3 socat -u STDIN "SCTP6-CONNECT:[fd00::2]:4443" </dev/null \
808	    || return 1
809
810	return 0
811}
812
813# psample test
814# - use psample to observe packets
815test_psample() {
816	sbx_add "test_psample" || return $?
817
818	# Add a datapath with per-vport dispatching.
819	ovs_add_dp "test_psample" psample -V 2:1 || return 1
820
821	info "create namespaces"
822	ovs_add_netns_and_veths "test_psample" "psample" \
823		client c0 c1 172.31.110.10/24 -u || return 1
824	ovs_add_netns_and_veths "test_psample" "psample" \
825		server s0 s1 172.31.110.20/24 -u || return 1
826
827	# Check if psample actions can be configured.
828	ovs_add_flow "test_psample" psample \
829	'in_port(1),eth(),eth_type(0x0806),arp()' 'psample(group=1)' &> /dev/null
830	if [ $? == 1 ]; then
831		info "no support for psample - skipping"
832		ovs_exit_sig
833		return $ksft_skip
834	fi
835
836	ovs_del_flows "test_psample" psample
837
838	# Test action verification.
839	OLDIFS=$IFS
840	IFS='*'
841	min_key='in_port(1),eth(),eth_type(0x0800),ipv4()'
842	for testcase in \
843		"cookie to large"*"psample(group=1,cookie=1615141312111009080706050403020100)" \
844		"no group with cookie"*"psample(cookie=abcd)" \
845		"no group"*"psample()";
846	do
847		set -- $testcase;
848		ovs_test_flow_fails "test_psample" psample $min_key $2
849		if [ $? == 1 ]; then
850			info "failed - $1"
851			return 1
852		fi
853	done
854	IFS=$OLDIFS
855
856	ovs_del_flows "test_psample" psample
857	# Allow ARP
858	ovs_add_flow "test_psample" psample \
859		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
860	ovs_add_flow "test_psample" psample \
861		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
862
863	# Sample first 14 bytes of all traffic.
864	ovs_add_flow "test_psample" psample \
865	    "in_port(1),eth(),eth_type(0x0800),ipv4()" \
866            "trunc(14),psample(group=1,cookie=c0ffee),2"
867
868	# Sample all traffic. In this case, use a sample() action with both
869	# psample and an upcall emulating simultaneous local sampling and
870	# sFlow / IPFIX.
871	nlpid=$(grep -E "listening on upcall packet handler" \
872            $ovs_dir/s0.out | cut -d ":" -f 2 | tr -d ' ')
873	[ -z "$nlpid" ] && \
874		{ info "failed to get upcall PID"; return 1; }
875
876	ovs_add_flow "test_psample" psample \
877            "in_port(2),eth(),eth_type(0x0800),ipv4()" \
878            "sample(sample=100%,actions(psample(group=2,cookie=eeff0c),userspace(pid=${nlpid},userdata=eeff0c))),1"
879
880	# Record psample data.
881	ovs_spawn_daemon "test_psample" python3 $ovs_base/ovs-dpctl.py psample-events
882	ovs_wait grep -q "listening for psample events" ${ovs_dir}/stdout
883
884	# Send a single ping.
885	ovs_sbx "test_psample" ip netns exec client ping -I c1 172.31.110.20 -c 1 || return 1
886
887	# We should have received one userspace action upcall and 2 psample packets.
888	ovs_wait grep -q "userspace action command" $ovs_dir/s0.out || return 1
889
890	# client -> server samples should only contain the first 14 bytes of the packet.
891	ovs_wait grep -qE "rate:4294967295,group:1,cookie:c0ffee data:[0-9a-f]{28}$" \
892		$ovs_dir/stdout || return 1
893
894	ovs_wait grep -q "rate:4294967295,group:2,cookie:eeff0c" $ovs_dir/stdout || return 1
895
896	return 0
897}
898
899# drop_reason test
900# - drop packets and verify the right drop reason is reported
901test_drop_reason() {
902	which perf >/dev/null 2>&1 || return $ksft_skip
903	which pahole >/dev/null 2>&1 || return $ksft_skip
904
905	ovs_drop_subsys=$(pahole -C skb_drop_reason_subsys |
906			      awk '/OPENVSWITCH/ { print $3; }' |
907			      tr -d ,)
908	if [ -z "$ovs_drop_subsys" ]; then
909		info "failed to get OVS drop subsys ID"
910		return $ksft_skip
911	fi
912
913	sbx_add "test_drop_reason" || return $?
914
915	ovs_add_dp "test_drop_reason" dropreason || return 1
916
917	info "create namespaces"
918	for ns in client server; do
919		ovs_add_netns_and_veths "test_drop_reason" "dropreason" "$ns" \
920			"${ns:0:1}0" "${ns:0:1}1" || return 1
921	done
922
923	# Setup client namespace
924	ip netns exec client ip addr add 172.31.110.10/24 dev c1
925	ip netns exec client ip link set c1 up
926
927	# Setup server namespace
928	ip netns exec server ip addr add 172.31.110.20/24 dev s1
929	ip netns exec server ip link set s1 up
930
931	# Check if drop reasons can be sent
932	ovs_add_flow "test_drop_reason" dropreason \
933		'in_port(1),eth(),eth_type(0x0806),arp()' 'drop(10)' 2>/dev/null
934	if [ $? == 1 ]; then
935		info "no support for drop reasons - skipping"
936		ovs_exit_sig
937		return $ksft_skip
938	fi
939
940	ovs_del_flows "test_drop_reason" dropreason
941
942	# Allow ARP
943	ovs_add_flow "test_drop_reason" dropreason \
944		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
945	ovs_add_flow "test_drop_reason" dropreason \
946		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
947
948	# Allow client ICMP traffic but drop return path
949	ovs_add_flow "test_drop_reason" dropreason \
950		"in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10,proto=1),icmp()" '2'
951	ovs_add_flow "test_drop_reason" dropreason \
952		"in_port(2),eth(),eth_type(0x0800),ipv4(src=172.31.110.20,proto=1),icmp()" 'drop'
953
954	ovs_drop_record_and_run "test_drop_reason" ip netns exec client ping -c 2 172.31.110.20
955	ovs_drop_reason_count 0x${ovs_drop_subsys}0001 # OVS_DROP_FLOW_ACTION
956	if [[ "$?" -ne "2" ]]; then
957		info "Did not detect expected drops: $?"
958		return 1
959	fi
960
961	# Drop UDP 6000 traffic with an explicit action and an error code.
962	ovs_add_flow "test_drop_reason" dropreason \
963		"in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10,proto=17),udp(dst=6000)" \
964                'drop(42)'
965	# Drop UDP 7000 traffic with an explicit action with no error code.
966	ovs_add_flow "test_drop_reason" dropreason \
967		"in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10,proto=17),udp(dst=7000)" \
968                'drop(0)'
969
970	ovs_drop_record_and_run \
971            "test_drop_reason" ip netns exec client nc -i 1 -zuv 172.31.110.20 6000
972	ovs_drop_reason_count 0x${ovs_drop_subsys}0004 # OVS_DROP_EXPLICIT_ACTION_ERROR
973	if [[ "$?" -ne "1" ]]; then
974		info "Did not detect expected explicit error drops: $?"
975		return 1
976	fi
977
978	ovs_drop_record_and_run \
979            "test_drop_reason" ip netns exec client nc -i 1 -zuv 172.31.110.20 7000
980	ovs_drop_reason_count 0x${ovs_drop_subsys}0003 # OVS_DROP_EXPLICIT_ACTION
981	if [[ "$?" -ne "1" ]]; then
982		info "Did not detect expected explicit drops: $?"
983		return 1
984	fi
985
986	return 0
987}
988
989# arp_ping test
990# - client has 1500 byte MTU
991# - server has 1500 byte MTU
992# - send ARP ping between two ns
993test_arp_ping () {
994
995	which arping >/dev/null 2>&1 || return $ksft_skip
996
997	sbx_add "test_arp_ping" || return $?
998
999	ovs_add_dp "test_arp_ping" arpping || return 1
1000
1001	info "create namespaces"
1002	for ns in client server; do
1003		ovs_add_netns_and_veths "test_arp_ping" "arpping" "$ns" \
1004		    "${ns:0:1}0" "${ns:0:1}1" || return 1
1005	done
1006
1007	# Setup client namespace
1008	ip netns exec client ip addr add 172.31.110.10/24 dev c1
1009	ip netns exec client ip link set c1 up
1010	HW_CLIENT=$(ip netns exec client ip link show dev c1 \
1011		| awk '/link\/ether/ {print $2}')
1012	[ -z "$HW_CLIENT" ] && \
1013		{ info "failed to get client hwaddr"; return 1; }
1014	info "Client hwaddr: $HW_CLIENT"
1015
1016	# Setup server namespace
1017	ip netns exec server ip addr add 172.31.110.20/24 dev s1
1018	ip netns exec server ip link set s1 up
1019	HW_SERVER=$(ip netns exec server ip link show dev s1 \
1020		| awk '/link\/ether/ {print $2}')
1021	[ -z "$HW_SERVER" ] && \
1022		{ info "failed to get server hwaddr"; return 1; }
1023	info "Server hwaddr: $HW_SERVER"
1024
1025	ovs_add_flow "test_arp_ping" arpping \
1026		"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
1027	ovs_add_flow "test_arp_ping" arpping \
1028		"in_port(2),eth(),eth_type(0x0806),arp()" '1' || return 1
1029
1030	ovs_sbx "test_arp_ping" ip netns exec client arping -I c1 172.31.110.20 -c 1 || return 1
1031
1032	return 0
1033}
1034
1035# ct_connect_v4 test
1036#  - client has 1500 byte MTU
1037#  - server has 1500 byte MTU
1038#  - use ICMP to ping in each direction
1039#  - only allow CT state stuff to pass through new in c -> s
1040test_ct_connect_v4 () {
1041
1042	which nc >/dev/null 2>/dev/null || return $ksft_skip
1043
1044	sbx_add "test_ct_connect_v4" || return $?
1045
1046	ovs_add_dp "test_ct_connect_v4" ct4 || return 1
1047	info "create namespaces"
1048	for ns in client server; do
1049		ovs_add_netns_and_veths "test_ct_connect_v4" "ct4" "$ns" \
1050		    "${ns:0:1}0" "${ns:0:1}1" || return 1
1051	done
1052
1053	ip netns exec client ip addr add 172.31.110.10/24 dev c1
1054	ip netns exec client ip link set c1 up
1055	ip netns exec server ip addr add 172.31.110.20/24 dev s1
1056	ip netns exec server ip link set s1 up
1057
1058	# Add forwarding for ARP and ip packets - completely wildcarded
1059	ovs_add_flow "test_ct_connect_v4" ct4 \
1060		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
1061	ovs_add_flow "test_ct_connect_v4" ct4 \
1062		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
1063	ovs_add_flow "test_ct_connect_v4" ct4 \
1064		     'ct_state(-trk),eth(),eth_type(0x0800),ipv4()' \
1065		     'ct(commit),recirc(0x1)' || return 1
1066	ovs_add_flow "test_ct_connect_v4" ct4 \
1067		     'recirc_id(0x1),ct_state(+trk+new),in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10)' \
1068		     '2' || return 1
1069	ovs_add_flow "test_ct_connect_v4" ct4 \
1070		     'recirc_id(0x1),ct_state(+trk+est),in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10)' \
1071		     '2' || return 1
1072	ovs_add_flow "test_ct_connect_v4" ct4 \
1073		     'recirc_id(0x1),ct_state(+trk+est),in_port(2),eth(),eth_type(0x0800),ipv4(dst=172.31.110.10)' \
1074		     '1' || return 1
1075	ovs_add_flow "test_ct_connect_v4" ct4 \
1076		     'recirc_id(0x1),ct_state(+trk+inv),eth(),eth_type(0x0800),ipv4()' 'drop' || \
1077		     return 1
1078
1079	# do a ping
1080	ovs_sbx "test_ct_connect_v4" ip netns exec client ping 172.31.110.20 -c 3 || return 1
1081
1082	# create an echo server in 'server'
1083	echo "server" | \
1084		ovs_netns_spawn_daemon "test_ct_connect_v4" "server" \
1085				nc -lvnp 4443
1086	ovs_sbx "test_ct_connect_v4" ip netns exec client nc -i 1 -zv 172.31.110.20 4443 || return 1
1087
1088	# Now test in the other direction (should fail)
1089	echo "client" | \
1090		ovs_netns_spawn_daemon "test_ct_connect_v4" "client" \
1091				nc -lvnp 4443
1092	ovs_sbx "test_ct_connect_v4" ip netns exec client nc -i 1 -zv 172.31.110.10 4443
1093	if [ $? == 0 ]; then
1094	   info "ct connect to client was successful"
1095	   return 1
1096	fi
1097
1098	info "done..."
1099	return 0
1100}
1101
1102# connect_v4 test
1103#  - client has 1500 byte MTU
1104#  - server has 1500 byte MTU
1105#  - use ICMP to ping in each direction
1106test_connect_v4 () {
1107
1108	sbx_add "test_connect_v4" || return $?
1109
1110	ovs_add_dp "test_connect_v4" cv4 || return 1
1111
1112	info "create namespaces"
1113	for ns in client server; do
1114		ovs_add_netns_and_veths "test_connect_v4" "cv4" "$ns" \
1115		    "${ns:0:1}0" "${ns:0:1}1" || return 1
1116	done
1117
1118
1119	ip netns exec client ip addr add 172.31.110.10/24 dev c1
1120	ip netns exec client ip link set c1 up
1121	ip netns exec server ip addr add 172.31.110.20/24 dev s1
1122	ip netns exec server ip link set s1 up
1123
1124	# Add forwarding for ARP and ip packets - completely wildcarded
1125	ovs_add_flow "test_connect_v4" cv4 \
1126		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
1127	ovs_add_flow "test_connect_v4" cv4 \
1128		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
1129	ovs_add_flow "test_connect_v4" cv4 \
1130		'in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10)' '2' || return 1
1131	ovs_add_flow "test_connect_v4" cv4 \
1132		'in_port(2),eth(),eth_type(0x0800),ipv4(src=172.31.110.20)' '1' || return 1
1133
1134	# do a ping
1135	ovs_sbx "test_connect_v4" ip netns exec client ping 172.31.110.20 -c 3 || return 1
1136
1137	info "done..."
1138	return 0
1139}
1140
1141# nat_connect_v4 test
1142#  - client has 1500 byte MTU
1143#  - server has 1500 byte MTU
1144#  - use ICMP to ping in each direction
1145#  - only allow CT state stuff to pass through new in c -> s
1146test_nat_connect_v4 () {
1147	which nc >/dev/null 2>/dev/null || return $ksft_skip
1148
1149	sbx_add "test_nat_connect_v4" || return $?
1150
1151	ovs_add_dp "test_nat_connect_v4" nat4 || return 1
1152	info "create namespaces"
1153	for ns in client server; do
1154		ovs_add_netns_and_veths "test_nat_connect_v4" "nat4" "$ns" \
1155		    "${ns:0:1}0" "${ns:0:1}1" || return 1
1156	done
1157
1158	ip netns exec client ip addr add 172.31.110.10/24 dev c1
1159	ip netns exec client ip link set c1 up
1160	ip netns exec server ip addr add 172.31.110.20/24 dev s1
1161	ip netns exec server ip link set s1 up
1162
1163	ip netns exec client ip route add default via 172.31.110.20
1164
1165	ovs_add_flow "test_nat_connect_v4" nat4 \
1166		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
1167	ovs_add_flow "test_nat_connect_v4" nat4 \
1168		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
1169	ovs_add_flow "test_nat_connect_v4" nat4 \
1170		"ct_state(-trk),in_port(1),eth(),eth_type(0x0800),ipv4(dst=192.168.0.20)" \
1171		"ct(commit,nat(dst=172.31.110.20)),recirc(0x1)"
1172	ovs_add_flow "test_nat_connect_v4" nat4 \
1173		"ct_state(-trk),in_port(2),eth(),eth_type(0x0800),ipv4()" \
1174		"ct(commit,nat),recirc(0x2)"
1175
1176	ovs_add_flow "test_nat_connect_v4" nat4 \
1177		"recirc_id(0x1),ct_state(+trk-inv),in_port(1),eth(),eth_type(0x0800),ipv4()" "2"
1178	ovs_add_flow "test_nat_connect_v4" nat4 \
1179		"recirc_id(0x2),ct_state(+trk-inv),in_port(2),eth(),eth_type(0x0800),ipv4()" "1"
1180
1181	# do a ping
1182	ovs_sbx "test_nat_connect_v4" ip netns exec client ping 192.168.0.20 -c 3 || return 1
1183
1184	# create an echo server in 'server'
1185	echo "server" | \
1186		ovs_netns_spawn_daemon "test_nat_connect_v4" "server" \
1187				nc -lvnp 4443
1188	ovs_sbx "test_nat_connect_v4" ip netns exec client nc -i 1 -zv 192.168.0.20 4443 || return 1
1189
1190	# Now test in the other direction (should fail)
1191	echo "client" | \
1192		ovs_netns_spawn_daemon "test_nat_connect_v4" "client" \
1193				nc -lvnp 4443
1194	ovs_sbx "test_nat_connect_v4" ip netns exec client nc -i 1 -zv 172.31.110.10 4443
1195	if [ $? == 0 ]; then
1196	   info "connect to client was successful"
1197	   return 1
1198	fi
1199
1200	info "done..."
1201	return 0
1202}
1203
1204# sctp_nat_connect_v4 test
1205#  - SCTP association crosses a ct(commit,nat(dst=ip:port)) DNAT
1206#  - post-recirc flows match the translated address and port, so the
1207#    SCTP branch of the post-NAT flow key update is load-bearing
1208test_sctp_nat_connect_v4 () {
1209	local t="test_sctp_nat_connect_v4"
1210	local payload="SCTP_NAT_DATA_OK"
1211	local rxfile="${ovs_base}/${t}/sctp-rx.txt"
1212
1213	modprobe -q sctp 2>/dev/null || return "$ksft_skip"
1214	socat -V 2>&1 | grep -q "define WITH_SCTP" || return "$ksft_skip"
1215	# SCTP conntrack is compiled into nf_conntrack.ko, so check that
1216	# loading it actually exposed the SCTP conntrack sysctls.
1217	modprobe -q nf_conntrack 2>/dev/null || return "$ksft_skip"
1218	[ -e /proc/sys/net/netfilter/nf_conntrack_sctp_timeout_established ] \
1219	    || { info "no SCTP conntrack support - skipping"
1220	         return "$ksft_skip"; }
1221
1222	sbx_add "test_sctp_nat_connect_v4" || return $?
1223
1224	ovs_add_dp "test_sctp_nat_connect_v4" sctpnat4 || return 1
1225	info "create namespaces"
1226	for ns in client server; do
1227		ovs_add_netns_and_veths "test_sctp_nat_connect_v4" "sctpnat4" \
1228		    "$ns" "${ns:0:1}0" "${ns:0:1}1" || return 1
1229	done
1230
1231	ip netns exec client ip addr add 172.31.110.10/24 dev c1
1232	ip netns exec client ip link set c1 up
1233	ip netns exec server ip addr add 172.31.110.20/24 dev s1
1234	ip netns exec server ip link set s1 up
1235
1236	ip netns exec client ip route add default via 172.31.110.20
1237
1238	# Check if the ct and nat actions can be configured.
1239	ovs_add_flow "test_sctp_nat_connect_v4" sctpnat4 \
1240		'in_port(1),eth(),eth_type(0x0800),ipv4()' \
1241		'ct(commit,nat(dst=172.31.110.20:5555)),recirc(0x1)' \
1242		&> /dev/null
1243	if [ $? == 1 ]; then
1244		info "no support for ct/nat actions - skipping"
1245		ovs_exit_sig
1246		return $ksft_skip
1247	fi
1248
1249	ovs_del_flows "test_sctp_nat_connect_v4" sctpnat4
1250
1251	ovs_add_flow "test_sctp_nat_connect_v4" sctpnat4 \
1252		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
1253	ovs_add_flow "test_sctp_nat_connect_v4" sctpnat4 \
1254		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
1255	ovs_add_flow "test_sctp_nat_connect_v4" sctpnat4 \
1256		"ct_state(-trk),in_port(1),eth(),eth_type(0x0800),"\
1257"ipv4(dst=192.168.0.20)" \
1258		"ct(commit,nat(dst=172.31.110.20:5555)),recirc(0x1)" || return 1
1259	ovs_add_flow "test_sctp_nat_connect_v4" sctpnat4 \
1260		"ct_state(-trk),in_port(2),eth(),eth_type(0x0800),ipv4()" \
1261		"ct(commit,nat),recirc(0x2)" || return 1
1262
1263	ovs_add_flow "test_sctp_nat_connect_v4" sctpnat4 \
1264		"recirc_id(0x1),ct_state(+trk-inv),in_port(1),eth(),"\
1265"eth_type(0x0800),ipv4(dst=172.31.110.20,proto=132),"\
1266"sctp(dst=5555)" \
1267		"2" || return 1
1268	ovs_add_flow "test_sctp_nat_connect_v4" sctpnat4 \
1269		"recirc_id(0x2),ct_state(+trk-inv),in_port(2),eth(),"\
1270"eth_type(0x0800),ipv4(src=192.168.0.20,proto=132),"\
1271"sctp(src=4443)" \
1272		"1" || return 1
1273
1274	ovs_netns_spawn_daemon "test_sctp_nat_connect_v4" "server" \
1275		socat -u -t 1 SCTP4-LISTEN:5555,fork \
1276		OPEN:"$rxfile",creat,append
1277	ovs_wait sctp_eps_has server 5555 || return 1
1278
1279	info "verify SCTP association across NAT"
1280	ovs_sbx "test_sctp_nat_connect_v4" ip netns exec client \
1281	    timeout 3 socat -u STDIN "SCTP4-CONNECT:192.168.0.20:4443" \
1282	    </dev/null || return 1
1283
1284	info "verify SCTP DATA chunk crosses NAT"
1285	ovs_sbx "test_sctp_nat_connect_v4" ip netns exec client \
1286	    timeout 3 socat -u STDIN "SCTP4-CONNECT:192.168.0.20:4443" \
1287	    <<< "$payload" || return 1
1288	ovs_wait grep -q "$payload" "$rxfile" \
1289	    || { info "server did not receive SCTP DATA payload"
1290	         return 1; }
1291
1292	info "done..."
1293	return 0
1294}
1295
1296# nat_related_v4 test
1297#  - client->server ip packets go via SNAT
1298#  - client solicits ICMP destination unreachable packet from server
1299#  - undo NAT for ICMP reply and test dst ip has been updated
1300test_nat_related_v4 () {
1301	which nc >/dev/null 2>/dev/null || return $ksft_skip
1302
1303	sbx_add "test_nat_related_v4" || return $?
1304
1305	ovs_add_dp "test_nat_related_v4" natrelated4 || return 1
1306	info "create namespaces"
1307	for ns in client server; do
1308		ovs_add_netns_and_veths "test_nat_related_v4" "natrelated4" "$ns" \
1309			"${ns:0:1}0" "${ns:0:1}1" || return 1
1310	done
1311
1312	ip netns exec client ip addr add 172.31.110.10/24 dev c1
1313	ip netns exec client ip link set c1 up
1314	ip netns exec server ip addr add 172.31.110.20/24 dev s1
1315	ip netns exec server ip link set s1 up
1316
1317	ip netns exec server ip route add 192.168.0.20/32 via 172.31.110.10
1318
1319	# Allow ARP
1320	ovs_add_flow "test_nat_related_v4" natrelated4 \
1321		"in_port(1),eth(),eth_type(0x0806),arp()" "2" || return 1
1322	ovs_add_flow "test_nat_related_v4" natrelated4 \
1323		"in_port(2),eth(),eth_type(0x0806),arp()" "1" || return 1
1324
1325	# Allow IP traffic from client->server, rewrite source IP with SNAT to 192.168.0.20
1326	ovs_add_flow "test_nat_related_v4" natrelated4 \
1327		"ct_state(-trk),in_port(1),eth(),eth_type(0x0800),ipv4(dst=172.31.110.20)" \
1328		"ct(commit,nat(src=192.168.0.20)),recirc(0x1)" || return 1
1329	ovs_add_flow "test_nat_related_v4" natrelated4 \
1330		"recirc_id(0x1),ct_state(+trk-inv),in_port(1),eth(),eth_type(0x0800),ipv4()" \
1331		"2" || return 1
1332
1333	# Allow related ICMP responses back from server and undo NAT to restore original IP
1334	# Drop any ICMP related packets where dst ip hasn't been restored back to original IP
1335	ovs_add_flow "test_nat_related_v4" natrelated4 \
1336		"ct_state(-trk),in_port(2),eth(),eth_type(0x0800),ipv4()" \
1337		"ct(commit,nat),recirc(0x2)" || return 1
1338	ovs_add_flow "test_nat_related_v4" natrelated4 \
1339		"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()" \
1340		"1" || return 1
1341	ovs_add_flow "test_nat_related_v4" natrelated4 \
1342		"recirc_id(0x2),ct_state(+rel+trk),in_port(2),eth(),eth_type(0x0800),ipv4(dst=192.168.0.20,proto=1),icmp()" \
1343		"drop" || return 1
1344
1345	# Solicit destination unreachable response from server
1346	ovs_sbx "test_nat_related_v4" ip netns exec client \
1347		bash -c "echo a | nc -u -w 1 172.31.110.20 10000"
1348
1349	# Check to make sure no packets matched the drop rule with incorrect dst ip
1350	python3 "$ovs_base/ovs-dpctl.py" dump-flows natrelated4 \
1351		| grep "drop" | grep "packets:0" >/dev/null || return 1
1352
1353	info "done..."
1354	return 0
1355}
1356
1357# netlink_validation
1358# - Create a dp
1359# - check no warning with "old version" simulation
1360test_netlink_checks () {
1361	sbx_add "test_netlink_checks" || return 1
1362
1363	info "setting up new DP"
1364	ovs_add_dp "test_netlink_checks" nv0 || return 1
1365	# now try again
1366	PRE_TEST=$(dmesg | grep -E "RIP: [0-9a-fA-Fx]+:ovs_dp_cmd_new\+")
1367	ovs_add_dp "test_netlink_checks" nv0 -V 0 || return 1
1368	POST_TEST=$(dmesg | grep -E "RIP: [0-9a-fA-Fx]+:ovs_dp_cmd_new\+")
1369	if [ "$PRE_TEST" != "$POST_TEST" ]; then
1370		info "failed - gen warning"
1371		return 1
1372	fi
1373
1374	ovs_add_netns_and_veths "test_netlink_checks" nv0 left left0 l0 || \
1375	    return 1
1376	ovs_add_netns_and_veths "test_netlink_checks" nv0 right right0 r0 || \
1377	    return 1
1378	[ $(python3 $ovs_base/ovs-dpctl.py show nv0 | grep port | \
1379	    wc -l) == 3 ] || \
1380	      return 1
1381	ovs_del_if "test_netlink_checks" nv0 right0 || return 1
1382	[ $(python3 $ovs_base/ovs-dpctl.py show nv0 | grep port | \
1383	    wc -l) == 2 ] || \
1384	      return 1
1385
1386	info "Checking clone depth"
1387	ERR_MSG="Flow actions may not be safe on all matching packets"
1388	PRE_TEST=$(dmesg | grep -c "${ERR_MSG}")
1389	ovs_add_flow "test_netlink_checks" nv0 \
1390		'in_port(1),eth(),eth_type(0x800),ipv4()' \
1391		'clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(drop)))))))))))))))))' \
1392		>/dev/null 2>&1 && return 1
1393	POST_TEST=$(dmesg | grep -c "${ERR_MSG}")
1394
1395	if [ "$PRE_TEST" == "$POST_TEST" ]; then
1396		info "failed - clone depth too large"
1397		return 1
1398	fi
1399
1400	PRE_TEST=$(dmesg | grep -c "${ERR_MSG}")
1401	ovs_add_flow "test_netlink_checks" nv0 \
1402		'in_port(1),eth(),eth_type(0x0806),arp()' 'drop(0),2' \
1403		&> /dev/null && return 1
1404	POST_TEST=$(dmesg | grep -c "${ERR_MSG}")
1405	if [ "$PRE_TEST" == "$POST_TEST" ]; then
1406		info "failed - error not generated"
1407		return 1
1408	fi
1409	return 0
1410}
1411
1412test_upcall_interfaces() {
1413	sbx_add "test_upcall_interfaces" || return 1
1414
1415	info "setting up new DP"
1416	ovs_add_dp "test_upcall_interfaces" ui0 -V 2:1 || return 1
1417
1418	ovs_add_netns_and_veths "test_upcall_interfaces" ui0 upc left0 l0 \
1419	    172.31.110.1/24 -u || return 1
1420
1421	ovs_wait grep -q "listening on upcall packet handler" ${ovs_dir}/left0.out
1422
1423	info "sending arping"
1424	ip netns exec upc arping -I l0 172.31.110.20 -c 1 \
1425	    >$ovs_dir/arping.stdout 2>$ovs_dir/arping.stderr
1426
1427	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
1428	return 0
1429}
1430
1431ovs_add_kernel_tunnel() {
1432	local sbxname=$1; shift
1433	local ns=$1; shift
1434	local tnl_type=$1; shift
1435	local name=$1; shift
1436	local addr=$1; shift
1437
1438	info "setting up kernel ${tnl_type} tunnel ${name}"
1439	ovs_sbx "${sbxname}" ip -netns ${ns} link add dev ${name} type ${tnl_type} $* || return 1
1440	on_exit "ovs_sbx ${sbxname} ip -netns ${ns} link del ${name} >/dev/null 2>&1"
1441	ovs_sbx "${sbxname}" ip -netns ${ns} addr add dev ${name} ${addr} || return 1
1442	ovs_sbx "${sbxname}" ip -netns ${ns} link set dev ${name} mtu 1450 up || return 1
1443}
1444
1445test_tunnel_metadata() {
1446	which arping >/dev/null 2>&1 || return $ksft_skip
1447
1448	sbxname="test_tunnel_metadata"
1449	sbx_add "${sbxname}" || return 1
1450
1451	info "setting up new DP"
1452	ovs_add_dp "${sbxname}" tdp0 -V 2:1 || return 1
1453
1454	ovs_add_netns_and_veths "${sbxname}" tdp0 tns left0 l0 \
1455		172.31.110.1/24 || return 1
1456
1457	info "removing veth interface from openvswitch and setting IP"
1458	ovs_del_if "${sbxname}" tdp0 left0 || return 1
1459	ovs_sbx "${sbxname}" ip addr add 172.31.110.2/24 dev left0 || return 1
1460	ovs_sbx "${sbxname}" ip link set left0 up || return 1
1461
1462	info "setting up tunnel port in openvswitch"
1463	ovs_add_if "${sbxname}" "vxlan" tdp0 ovs-vxlan0 -u || return 1
1464	on_exit "ovs_sbx ${sbxname} ip link del ovs-vxlan0"
1465	ovs_wait ip link show ovs-vxlan0 &>/dev/null || return 1
1466	ovs_sbx "${sbxname}" ip link set ovs-vxlan0 up || return 1
1467
1468	configs=$(echo '
1469	    1 172.31.221.1/24 1155332 32   set   udpcsum flags\(df\|csum\)
1470	    2 172.31.222.1/24 1234567 45   set noudpcsum flags\(df\)
1471	    3 172.31.223.1/24 1020304 23 unset   udpcsum flags\(csum\)
1472	    4 172.31.224.1/24 1357986 15 unset noudpcsum' | sed '/^$/d')
1473
1474	while read -r i addr id ttl df csum flags; do
1475		ovs_add_kernel_tunnel "${sbxname}" tns vxlan vxlan${i} ${addr} \
1476			remote 172.31.110.2 id ${id} dstport 4789 \
1477			ttl ${ttl} df ${df} ${csum} || return 1
1478	done <<< "${configs}"
1479
1480	ovs_wait grep -q 'listening on upcall packet handler' \
1481		${ovs_dir}/ovs-vxlan0.out || return 1
1482
1483	info "sending arping"
1484	for i in 1 2 3 4; do
1485		ovs_sbx "${sbxname}" ip netns exec tns \
1486			arping -I vxlan${i} 172.31.22${i}.2 -c 1 \
1487			>${ovs_dir}/arping.stdout 2>${ovs_dir}/arping.stderr
1488	done
1489
1490	info "checking that received decapsulated packets carry correct metadata"
1491	while read -r i addr id ttl df csum flags; do
1492		arp_hdr="arp\\(sip=172.31.22${i}.1,tip=172.31.22${i}.2,op=1,sha="
1493		addrs="src=172.31.110.1,dst=172.31.110.2"
1494		ports="tp_src=[0-9]*,tp_dst=4789"
1495		tnl_md="tunnel\\(tun_id=${id},${addrs},ttl=${ttl},${ports},${flags}\\)"
1496
1497		ovs_sbx "${sbxname}" grep -qE "MISS upcall.*${tnl_md}.*${arp_hdr}" \
1498			${ovs_dir}/ovs-vxlan0.out || return 1
1499	done <<< "${configs}"
1500
1501	return 0
1502}
1503
1504test_pop_vlan() {
1505	local sbx="test_pop_vlan"
1506	sbx_add "$sbx" || return $?
1507	ovs_add_dp "$sbx" vlandp || return 1
1508
1509	ovs_add_netns_and_veths "$sbx" vlandp \
1510		ns1 veth1 ns1veth 192.0.2.1/24 || return 1
1511	ovs_add_netns_and_veths "$sbx" vlandp \
1512		ns2 veth2 ns2veth 192.0.2.2/24 || return 1
1513
1514	# Baseline: untagged bidirectional forwarding
1515	ovs_add_flow "$sbx" vlandp \
1516		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
1517	ovs_add_flow "$sbx" vlandp \
1518		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
1519	ovs_add_flow "$sbx" vlandp \
1520		'in_port(1),eth(),eth_type(0x0800),ipv4()' '2' || return 1
1521	ovs_add_flow "$sbx" vlandp \
1522		'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1
1523	ovs_sbx "$sbx" ip netns exec ns1 ping -c 3 -W 2 \
1524		192.0.2.2 || return 1
1525
1526	# VLAN topology: ns1 uses VLAN sub-interface, ns2 is plain
1527	ip -n ns1 link add link ns1veth name ns1veth.10 \
1528		type vlan id 10 || return 1
1529	on_exit "ip -n ns1 link del ns1veth.10 2>/dev/null"
1530	ip -n ns1 addr add 198.51.100.1/24 dev ns1veth.10 || return 1
1531	ip -n ns1 link set ns1veth.10 up || return 1
1532	ip -n ns2 addr add 198.51.100.2/24 dev ns2veth || return 1
1533
1534	ovs_del_flows "$sbx" vlandp
1535
1536	# Static ARP: avoids VLAN-tagged ARP complexity
1537	local ns1veth10mac ns2mac
1538	ns1veth10mac=$(ip -n ns1 link show ns1veth.10 \
1539		| awk '/link\/ether/ {print $2}')
1540	[ -z "$ns1veth10mac" ] && \
1541		{ info "failed to get ns1veth10mac"; return 1; }
1542	ns2mac=$(ip -n ns2 link show ns2veth \
1543		| awk '/link\/ether/ {print $2}')
1544	[ -z "$ns2mac" ] && \
1545		{ info "failed to get ns2mac"; return 1; }
1546	ip -n ns1 neigh replace 198.51.100.2 lladdr "$ns2mac" \
1547		dev ns1veth.10 nud permanent || return 1
1548	ip -n ns2 neigh replace 198.51.100.1 \
1549		lladdr "$ns1veth10mac" \
1550		dev ns2veth nud permanent || return 1
1551
1552	local vlan_match='in_port(1),eth(),eth_type(0x8100),'
1553	vlan_match+='vlan(vid=10),'
1554	vlan_match+='encap(eth_type(0x0800),'
1555	vlan_match+='ipv4(src=198.51.100.1,proto=1),icmp())'
1556
1557	# Negative: forward without pop_vlan -- tagged frame
1558	# is invisible to ns2 (no VLAN sub-interface), ping fails
1559	ovs_add_flow "$sbx" vlandp "$vlan_match" '2' || return 1
1560	ovs_sbx "$sbx" ip netns exec ns1 ping -I ns1veth.10 \
1561		-c 3 -W 1 198.51.100.2 >/dev/null 2>&1 \
1562		&& { info "FAIL: ping should fail without pop_vlan"
1563		     return 1; }
1564
1565	ovs_del_flows "$sbx" vlandp
1566
1567	# Positive: pop_vlan strips tag on forward path,
1568	# push_vlan restores tag on return path -- ping succeeds
1569	ovs_add_flow "$sbx" vlandp \
1570		"$vlan_match" 'pop_vlan,2' || return 1
1571	ovs_add_flow "$sbx" vlandp \
1572		'in_port(2),eth(),eth_type(0x0800),ipv4()' \
1573		'push_vlan(vid=10,pcp=0,tpid=0x8100),1' || return 1
1574	ovs_sbx "$sbx" ip netns exec ns1 ping -I ns1veth.10 \
1575		-c 3 -W 2 198.51.100.2 || return 1
1576
1577	return 0
1578}
1579
1580run_test() {
1581	(
1582	tname="$1"
1583	tdesc="$2"
1584
1585	if python3 ovs-dpctl.py -h 2>&1 | \
1586	     grep -E "Need to (install|upgrade) the python" >/dev/null 2>&1; then
1587		stdbuf -o0 printf "TEST: %-60s  [PYLIB]\n" "${tdesc}"
1588		return $ksft_skip
1589	fi
1590
1591	python3 ovs-dpctl.py show >/dev/null 2>&1 || \
1592		echo "[DPCTL] show exception."
1593
1594	if ! lsmod | grep openvswitch >/dev/null 2>&1; then
1595		stdbuf -o0 printf "TEST: %-60s  [NOMOD]\n" "${tdesc}"
1596		return $ksft_skip
1597	fi
1598
1599	printf "TEST: %-60s  [START]\n" "${tname}"
1600
1601	unset IFS
1602
1603	eval test_${tname}
1604	ret=$?
1605
1606	if [ $ret -eq 0 ]; then
1607		printf "TEST: %-60s  [ OK ]\n" "${tdesc}"
1608		ovs_exit_sig
1609		rm -rf "$ovs_dir"
1610	elif [ $ret -eq 1 ]; then
1611		printf "TEST: %-60s  [FAIL]\n" "${tdesc}"
1612		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
1613			echo
1614			echo "Pausing. Logs in $ovs_dir/. Hit enter to continue"
1615			read a
1616		fi
1617		ovs_exit_sig
1618		[ "${PAUSE_ON_FAIL}" = "yes" ] || rm -rf "$ovs_dir"
1619		exit 1
1620	elif [ $ret -eq $ksft_skip ]; then
1621		printf "TEST: %-60s  [SKIP]\n" "${tdesc}"
1622	elif [ $ret -eq 2 ]; then
1623		rm -rf test_${tname}
1624		run_test "$1" "$2"
1625	fi
1626
1627	return $ret
1628	)
1629	ret=$?
1630	case $ret in
1631		0)
1632			[ $all_skipped = true ] && [ $exitcode=$ksft_skip ] && exitcode=0
1633			all_skipped=false
1634		;;
1635		$ksft_skip)
1636			[ $all_skipped = true ] && exitcode=$ksft_skip
1637		;;
1638		*)
1639			all_skipped=false
1640			exitcode=1
1641		;;
1642	esac
1643
1644	return $ret
1645}
1646
1647
1648exitcode=0
1649desc=0
1650all_skipped=true
1651
1652while getopts :pvt o
1653do
1654	case $o in
1655	p) PAUSE_ON_FAIL=yes;;
1656	v) VERBOSE=1;;
1657	t) if which tcpdump > /dev/null 2>&1; then
1658		TRACING=1
1659	   else
1660		echo "=== tcpdump not available, tracing disabled"
1661	   fi
1662	   ;;
1663	*) usage;;
1664	esac
1665done
1666shift $(($OPTIND-1))
1667
1668IFS="
1669"
1670
1671for arg do
1672	# Check first that all requested tests are available before running any
1673	command -v > /dev/null "test_${arg}" || { echo "=== Test ${arg} not found"; usage; }
1674done
1675
1676name=""
1677desc=""
1678for t in ${tests}; do
1679	[ "${name}" = "" ]	&& name="${t}"	&& continue
1680	[ "${desc}" = "" ]	&& desc="${t}"
1681
1682	run_this=1
1683	for arg do
1684		[ "${arg}" != "${arg#--*}" ] && continue
1685		[ "${arg}" = "${name}" ] && run_this=1 && break
1686		run_this=0
1687	done
1688	if [ $run_this -eq 1 ]; then
1689		run_test "${name}" "${desc}"
1690	fi
1691	name=""
1692	desc=""
1693done
1694
1695exit ${exitcode}
1696