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