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