xref: /linux/tools/testing/selftests/net/openvswitch/openvswitch.sh (revision 5c458073553f0ef74f5c8db1bd459c87c722a299)
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	icmpv6					icmpv6: ICMPv6 echo type match
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# psample test
615# - use psample to observe packets
616test_psample() {
617	sbx_add "test_psample" || return $?
618
619	# Add a datapath with per-vport dispatching.
620	ovs_add_dp "test_psample" psample -V 2:1 || return 1
621
622	info "create namespaces"
623	ovs_add_netns_and_veths "test_psample" "psample" \
624		client c0 c1 172.31.110.10/24 -u || return 1
625	ovs_add_netns_and_veths "test_psample" "psample" \
626		server s0 s1 172.31.110.20/24 -u || return 1
627
628	# Check if psample actions can be configured.
629	ovs_add_flow "test_psample" psample \
630	'in_port(1),eth(),eth_type(0x0806),arp()' 'psample(group=1)' &> /dev/null
631	if [ $? == 1 ]; then
632		info "no support for psample - skipping"
633		ovs_exit_sig
634		return $ksft_skip
635	fi
636
637	ovs_del_flows "test_psample" psample
638
639	# Test action verification.
640	OLDIFS=$IFS
641	IFS='*'
642	min_key='in_port(1),eth(),eth_type(0x0800),ipv4()'
643	for testcase in \
644		"cookie to large"*"psample(group=1,cookie=1615141312111009080706050403020100)" \
645		"no group with cookie"*"psample(cookie=abcd)" \
646		"no group"*"psample()";
647	do
648		set -- $testcase;
649		ovs_test_flow_fails "test_psample" psample $min_key $2
650		if [ $? == 1 ]; then
651			info "failed - $1"
652			return 1
653		fi
654	done
655	IFS=$OLDIFS
656
657	ovs_del_flows "test_psample" psample
658	# Allow ARP
659	ovs_add_flow "test_psample" psample \
660		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
661	ovs_add_flow "test_psample" psample \
662		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
663
664	# Sample first 14 bytes of all traffic.
665	ovs_add_flow "test_psample" psample \
666	    "in_port(1),eth(),eth_type(0x0800),ipv4()" \
667            "trunc(14),psample(group=1,cookie=c0ffee),2"
668
669	# Sample all traffic. In this case, use a sample() action with both
670	# psample and an upcall emulating simultaneous local sampling and
671	# sFlow / IPFIX.
672	nlpid=$(grep -E "listening on upcall packet handler" \
673            $ovs_dir/s0.out | cut -d ":" -f 2 | tr -d ' ')
674	[ -z "$nlpid" ] && \
675		{ info "failed to get upcall PID"; return 1; }
676
677	ovs_add_flow "test_psample" psample \
678            "in_port(2),eth(),eth_type(0x0800),ipv4()" \
679            "sample(sample=100%,actions(psample(group=2,cookie=eeff0c),userspace(pid=${nlpid},userdata=eeff0c))),1"
680
681	# Record psample data.
682	ovs_spawn_daemon "test_psample" python3 $ovs_base/ovs-dpctl.py psample-events
683	ovs_wait grep -q "listening for psample events" ${ovs_dir}/stdout
684
685	# Send a single ping.
686	ovs_sbx "test_psample" ip netns exec client ping -I c1 172.31.110.20 -c 1 || return 1
687
688	# We should have received one userspace action upcall and 2 psample packets.
689	ovs_wait grep -q "userspace action command" $ovs_dir/s0.out || return 1
690
691	# client -> server samples should only contain the first 14 bytes of the packet.
692	ovs_wait grep -qE "rate:4294967295,group:1,cookie:c0ffee data:[0-9a-f]{28}$" \
693		$ovs_dir/stdout || return 1
694
695	ovs_wait grep -q "rate:4294967295,group:2,cookie:eeff0c" $ovs_dir/stdout || return 1
696
697	return 0
698}
699
700# drop_reason test
701# - drop packets and verify the right drop reason is reported
702test_drop_reason() {
703	which perf >/dev/null 2>&1 || return $ksft_skip
704	which pahole >/dev/null 2>&1 || return $ksft_skip
705
706	ovs_drop_subsys=$(pahole -C skb_drop_reason_subsys |
707			      awk '/OPENVSWITCH/ { print $3; }' |
708			      tr -d ,)
709	if [ -z "$ovs_drop_subsys" ]; then
710		info "failed to get OVS drop subsys ID"
711		return $ksft_skip
712	fi
713
714	sbx_add "test_drop_reason" || return $?
715
716	ovs_add_dp "test_drop_reason" dropreason || return 1
717
718	info "create namespaces"
719	for ns in client server; do
720		ovs_add_netns_and_veths "test_drop_reason" "dropreason" "$ns" \
721			"${ns:0:1}0" "${ns:0:1}1" || return 1
722	done
723
724	# Setup client namespace
725	ip netns exec client ip addr add 172.31.110.10/24 dev c1
726	ip netns exec client ip link set c1 up
727
728	# Setup server namespace
729	ip netns exec server ip addr add 172.31.110.20/24 dev s1
730	ip netns exec server ip link set s1 up
731
732	# Check if drop reasons can be sent
733	ovs_add_flow "test_drop_reason" dropreason \
734		'in_port(1),eth(),eth_type(0x0806),arp()' 'drop(10)' 2>/dev/null
735	if [ $? == 1 ]; then
736		info "no support for drop reasons - skipping"
737		ovs_exit_sig
738		return $ksft_skip
739	fi
740
741	ovs_del_flows "test_drop_reason" dropreason
742
743	# Allow ARP
744	ovs_add_flow "test_drop_reason" dropreason \
745		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
746	ovs_add_flow "test_drop_reason" dropreason \
747		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
748
749	# Allow client ICMP traffic but drop return path
750	ovs_add_flow "test_drop_reason" dropreason \
751		"in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10,proto=1),icmp()" '2'
752	ovs_add_flow "test_drop_reason" dropreason \
753		"in_port(2),eth(),eth_type(0x0800),ipv4(src=172.31.110.20,proto=1),icmp()" 'drop'
754
755	ovs_drop_record_and_run "test_drop_reason" ip netns exec client ping -c 2 172.31.110.20
756	ovs_drop_reason_count 0x${ovs_drop_subsys}0001 # OVS_DROP_FLOW_ACTION
757	if [[ "$?" -ne "2" ]]; then
758		info "Did not detect expected drops: $?"
759		return 1
760	fi
761
762	# Drop UDP 6000 traffic with an explicit action and an error code.
763	ovs_add_flow "test_drop_reason" dropreason \
764		"in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10,proto=17),udp(dst=6000)" \
765                'drop(42)'
766	# Drop UDP 7000 traffic with an explicit action with no error code.
767	ovs_add_flow "test_drop_reason" dropreason \
768		"in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10,proto=17),udp(dst=7000)" \
769                'drop(0)'
770
771	ovs_drop_record_and_run \
772            "test_drop_reason" ip netns exec client nc -i 1 -zuv 172.31.110.20 6000
773	ovs_drop_reason_count 0x${ovs_drop_subsys}0004 # OVS_DROP_EXPLICIT_ACTION_ERROR
774	if [[ "$?" -ne "1" ]]; then
775		info "Did not detect expected explicit error drops: $?"
776		return 1
777	fi
778
779	ovs_drop_record_and_run \
780            "test_drop_reason" ip netns exec client nc -i 1 -zuv 172.31.110.20 7000
781	ovs_drop_reason_count 0x${ovs_drop_subsys}0003 # OVS_DROP_EXPLICIT_ACTION
782	if [[ "$?" -ne "1" ]]; then
783		info "Did not detect expected explicit drops: $?"
784		return 1
785	fi
786
787	return 0
788}
789
790# arp_ping test
791# - client has 1500 byte MTU
792# - server has 1500 byte MTU
793# - send ARP ping between two ns
794test_arp_ping () {
795
796	which arping >/dev/null 2>&1 || return $ksft_skip
797
798	sbx_add "test_arp_ping" || return $?
799
800	ovs_add_dp "test_arp_ping" arpping || return 1
801
802	info "create namespaces"
803	for ns in client server; do
804		ovs_add_netns_and_veths "test_arp_ping" "arpping" "$ns" \
805		    "${ns:0:1}0" "${ns:0:1}1" || return 1
806	done
807
808	# Setup client namespace
809	ip netns exec client ip addr add 172.31.110.10/24 dev c1
810	ip netns exec client ip link set c1 up
811	HW_CLIENT=$(ip netns exec client ip link show dev c1 \
812		| awk '/link\/ether/ {print $2}')
813	[ -z "$HW_CLIENT" ] && \
814		{ info "failed to get client hwaddr"; return 1; }
815	info "Client hwaddr: $HW_CLIENT"
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	HW_SERVER=$(ip netns exec server ip link show dev s1 \
821		| awk '/link\/ether/ {print $2}')
822	[ -z "$HW_SERVER" ] && \
823		{ info "failed to get server hwaddr"; return 1; }
824	info "Server hwaddr: $HW_SERVER"
825
826	ovs_add_flow "test_arp_ping" arpping \
827		"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
828	ovs_add_flow "test_arp_ping" arpping \
829		"in_port(2),eth(),eth_type(0x0806),arp()" '1' || return 1
830
831	ovs_sbx "test_arp_ping" ip netns exec client arping -I c1 172.31.110.20 -c 1 || return 1
832
833	return 0
834}
835
836# ct_connect_v4 test
837#  - client has 1500 byte MTU
838#  - server has 1500 byte MTU
839#  - use ICMP to ping in each direction
840#  - only allow CT state stuff to pass through new in c -> s
841test_ct_connect_v4 () {
842
843	which nc >/dev/null 2>/dev/null || return $ksft_skip
844
845	sbx_add "test_ct_connect_v4" || return $?
846
847	ovs_add_dp "test_ct_connect_v4" ct4 || return 1
848	info "create namespaces"
849	for ns in client server; do
850		ovs_add_netns_and_veths "test_ct_connect_v4" "ct4" "$ns" \
851		    "${ns:0:1}0" "${ns:0:1}1" || return 1
852	done
853
854	ip netns exec client ip addr add 172.31.110.10/24 dev c1
855	ip netns exec client ip link set c1 up
856	ip netns exec server ip addr add 172.31.110.20/24 dev s1
857	ip netns exec server ip link set s1 up
858
859	# Add forwarding for ARP and ip packets - completely wildcarded
860	ovs_add_flow "test_ct_connect_v4" ct4 \
861		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
862	ovs_add_flow "test_ct_connect_v4" ct4 \
863		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
864	ovs_add_flow "test_ct_connect_v4" ct4 \
865		     'ct_state(-trk),eth(),eth_type(0x0800),ipv4()' \
866		     'ct(commit),recirc(0x1)' || return 1
867	ovs_add_flow "test_ct_connect_v4" ct4 \
868		     'recirc_id(0x1),ct_state(+trk+new),in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10)' \
869		     '2' || return 1
870	ovs_add_flow "test_ct_connect_v4" ct4 \
871		     'recirc_id(0x1),ct_state(+trk+est),in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10)' \
872		     '2' || return 1
873	ovs_add_flow "test_ct_connect_v4" ct4 \
874		     'recirc_id(0x1),ct_state(+trk+est),in_port(2),eth(),eth_type(0x0800),ipv4(dst=172.31.110.10)' \
875		     '1' || return 1
876	ovs_add_flow "test_ct_connect_v4" ct4 \
877		     'recirc_id(0x1),ct_state(+trk+inv),eth(),eth_type(0x0800),ipv4()' 'drop' || \
878		     return 1
879
880	# do a ping
881	ovs_sbx "test_ct_connect_v4" ip netns exec client ping 172.31.110.20 -c 3 || return 1
882
883	# create an echo server in 'server'
884	echo "server" | \
885		ovs_netns_spawn_daemon "test_ct_connect_v4" "server" \
886				nc -lvnp 4443
887	ovs_sbx "test_ct_connect_v4" ip netns exec client nc -i 1 -zv 172.31.110.20 4443 || return 1
888
889	# Now test in the other direction (should fail)
890	echo "client" | \
891		ovs_netns_spawn_daemon "test_ct_connect_v4" "client" \
892				nc -lvnp 4443
893	ovs_sbx "test_ct_connect_v4" ip netns exec client nc -i 1 -zv 172.31.110.10 4443
894	if [ $? == 0 ]; then
895	   info "ct connect to client was successful"
896	   return 1
897	fi
898
899	info "done..."
900	return 0
901}
902
903# connect_v4 test
904#  - client has 1500 byte MTU
905#  - server has 1500 byte MTU
906#  - use ICMP to ping in each direction
907test_connect_v4 () {
908
909	sbx_add "test_connect_v4" || return $?
910
911	ovs_add_dp "test_connect_v4" cv4 || return 1
912
913	info "create namespaces"
914	for ns in client server; do
915		ovs_add_netns_and_veths "test_connect_v4" "cv4" "$ns" \
916		    "${ns:0:1}0" "${ns:0:1}1" || return 1
917	done
918
919
920	ip netns exec client ip addr add 172.31.110.10/24 dev c1
921	ip netns exec client ip link set c1 up
922	ip netns exec server ip addr add 172.31.110.20/24 dev s1
923	ip netns exec server ip link set s1 up
924
925	# Add forwarding for ARP and ip packets - completely wildcarded
926	ovs_add_flow "test_connect_v4" cv4 \
927		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
928	ovs_add_flow "test_connect_v4" cv4 \
929		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
930	ovs_add_flow "test_connect_v4" cv4 \
931		'in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10)' '2' || return 1
932	ovs_add_flow "test_connect_v4" cv4 \
933		'in_port(2),eth(),eth_type(0x0800),ipv4(src=172.31.110.20)' '1' || return 1
934
935	# do a ping
936	ovs_sbx "test_connect_v4" ip netns exec client ping 172.31.110.20 -c 3 || return 1
937
938	info "done..."
939	return 0
940}
941
942# nat_connect_v4 test
943#  - client has 1500 byte MTU
944#  - server has 1500 byte MTU
945#  - use ICMP to ping in each direction
946#  - only allow CT state stuff to pass through new in c -> s
947test_nat_connect_v4 () {
948	which nc >/dev/null 2>/dev/null || return $ksft_skip
949
950	sbx_add "test_nat_connect_v4" || return $?
951
952	ovs_add_dp "test_nat_connect_v4" nat4 || return 1
953	info "create namespaces"
954	for ns in client server; do
955		ovs_add_netns_and_veths "test_nat_connect_v4" "nat4" "$ns" \
956		    "${ns:0:1}0" "${ns:0:1}1" || return 1
957	done
958
959	ip netns exec client ip addr add 172.31.110.10/24 dev c1
960	ip netns exec client ip link set c1 up
961	ip netns exec server ip addr add 172.31.110.20/24 dev s1
962	ip netns exec server ip link set s1 up
963
964	ip netns exec client ip route add default via 172.31.110.20
965
966	ovs_add_flow "test_nat_connect_v4" nat4 \
967		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
968	ovs_add_flow "test_nat_connect_v4" nat4 \
969		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
970	ovs_add_flow "test_nat_connect_v4" nat4 \
971		"ct_state(-trk),in_port(1),eth(),eth_type(0x0800),ipv4(dst=192.168.0.20)" \
972		"ct(commit,nat(dst=172.31.110.20)),recirc(0x1)"
973	ovs_add_flow "test_nat_connect_v4" nat4 \
974		"ct_state(-trk),in_port(2),eth(),eth_type(0x0800),ipv4()" \
975		"ct(commit,nat),recirc(0x2)"
976
977	ovs_add_flow "test_nat_connect_v4" nat4 \
978		"recirc_id(0x1),ct_state(+trk-inv),in_port(1),eth(),eth_type(0x0800),ipv4()" "2"
979	ovs_add_flow "test_nat_connect_v4" nat4 \
980		"recirc_id(0x2),ct_state(+trk-inv),in_port(2),eth(),eth_type(0x0800),ipv4()" "1"
981
982	# do a ping
983	ovs_sbx "test_nat_connect_v4" ip netns exec client ping 192.168.0.20 -c 3 || return 1
984
985	# create an echo server in 'server'
986	echo "server" | \
987		ovs_netns_spawn_daemon "test_nat_connect_v4" "server" \
988				nc -lvnp 4443
989	ovs_sbx "test_nat_connect_v4" ip netns exec client nc -i 1 -zv 192.168.0.20 4443 || return 1
990
991	# Now test in the other direction (should fail)
992	echo "client" | \
993		ovs_netns_spawn_daemon "test_nat_connect_v4" "client" \
994				nc -lvnp 4443
995	ovs_sbx "test_nat_connect_v4" ip netns exec client nc -i 1 -zv 172.31.110.10 4443
996	if [ $? == 0 ]; then
997	   info "connect to client was successful"
998	   return 1
999	fi
1000
1001	info "done..."
1002	return 0
1003}
1004
1005# nat_related_v4 test
1006#  - client->server ip packets go via SNAT
1007#  - client solicits ICMP destination unreachable packet from server
1008#  - undo NAT for ICMP reply and test dst ip has been updated
1009test_nat_related_v4 () {
1010	which nc >/dev/null 2>/dev/null || return $ksft_skip
1011
1012	sbx_add "test_nat_related_v4" || return $?
1013
1014	ovs_add_dp "test_nat_related_v4" natrelated4 || return 1
1015	info "create namespaces"
1016	for ns in client server; do
1017		ovs_add_netns_and_veths "test_nat_related_v4" "natrelated4" "$ns" \
1018			"${ns:0:1}0" "${ns:0:1}1" || return 1
1019	done
1020
1021	ip netns exec client ip addr add 172.31.110.10/24 dev c1
1022	ip netns exec client ip link set c1 up
1023	ip netns exec server ip addr add 172.31.110.20/24 dev s1
1024	ip netns exec server ip link set s1 up
1025
1026	ip netns exec server ip route add 192.168.0.20/32 via 172.31.110.10
1027
1028	# Allow ARP
1029	ovs_add_flow "test_nat_related_v4" natrelated4 \
1030		"in_port(1),eth(),eth_type(0x0806),arp()" "2" || return 1
1031	ovs_add_flow "test_nat_related_v4" natrelated4 \
1032		"in_port(2),eth(),eth_type(0x0806),arp()" "1" || return 1
1033
1034	# Allow IP traffic from client->server, rewrite source IP with SNAT to 192.168.0.20
1035	ovs_add_flow "test_nat_related_v4" natrelated4 \
1036		"ct_state(-trk),in_port(1),eth(),eth_type(0x0800),ipv4(dst=172.31.110.20)" \
1037		"ct(commit,nat(src=192.168.0.20)),recirc(0x1)" || return 1
1038	ovs_add_flow "test_nat_related_v4" natrelated4 \
1039		"recirc_id(0x1),ct_state(+trk-inv),in_port(1),eth(),eth_type(0x0800),ipv4()" \
1040		"2" || return 1
1041
1042	# Allow related ICMP responses back from server and undo NAT to restore original IP
1043	# Drop any ICMP related packets where dst ip hasn't been restored back to original IP
1044	ovs_add_flow "test_nat_related_v4" natrelated4 \
1045		"ct_state(-trk),in_port(2),eth(),eth_type(0x0800),ipv4()" \
1046		"ct(commit,nat),recirc(0x2)" || return 1
1047	ovs_add_flow "test_nat_related_v4" natrelated4 \
1048		"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()" \
1049		"1" || return 1
1050	ovs_add_flow "test_nat_related_v4" natrelated4 \
1051		"recirc_id(0x2),ct_state(+rel+trk),in_port(2),eth(),eth_type(0x0800),ipv4(dst=192.168.0.20,proto=1),icmp()" \
1052		"drop" || return 1
1053
1054	# Solicit destination unreachable response from server
1055	ovs_sbx "test_nat_related_v4" ip netns exec client \
1056		bash -c "echo a | nc -u -w 1 172.31.110.20 10000"
1057
1058	# Check to make sure no packets matched the drop rule with incorrect dst ip
1059	python3 "$ovs_base/ovs-dpctl.py" dump-flows natrelated4 \
1060		| grep "drop" | grep "packets:0" >/dev/null || return 1
1061
1062	info "done..."
1063	return 0
1064}
1065
1066# netlink_validation
1067# - Create a dp
1068# - check no warning with "old version" simulation
1069test_netlink_checks () {
1070	sbx_add "test_netlink_checks" || return 1
1071
1072	info "setting up new DP"
1073	ovs_add_dp "test_netlink_checks" nv0 || return 1
1074	# now try again
1075	PRE_TEST=$(dmesg | grep -E "RIP: [0-9a-fA-Fx]+:ovs_dp_cmd_new\+")
1076	ovs_add_dp "test_netlink_checks" nv0 -V 0 || return 1
1077	POST_TEST=$(dmesg | grep -E "RIP: [0-9a-fA-Fx]+:ovs_dp_cmd_new\+")
1078	if [ "$PRE_TEST" != "$POST_TEST" ]; then
1079		info "failed - gen warning"
1080		return 1
1081	fi
1082
1083	ovs_add_netns_and_veths "test_netlink_checks" nv0 left left0 l0 || \
1084	    return 1
1085	ovs_add_netns_and_veths "test_netlink_checks" nv0 right right0 r0 || \
1086	    return 1
1087	[ $(python3 $ovs_base/ovs-dpctl.py show nv0 | grep port | \
1088	    wc -l) == 3 ] || \
1089	      return 1
1090	ovs_del_if "test_netlink_checks" nv0 right0 || return 1
1091	[ $(python3 $ovs_base/ovs-dpctl.py show nv0 | grep port | \
1092	    wc -l) == 2 ] || \
1093	      return 1
1094
1095	info "Checking clone depth"
1096	ERR_MSG="Flow actions may not be safe on all matching packets"
1097	PRE_TEST=$(dmesg | grep -c "${ERR_MSG}")
1098	ovs_add_flow "test_netlink_checks" nv0 \
1099		'in_port(1),eth(),eth_type(0x800),ipv4()' \
1100		'clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(drop)))))))))))))))))' \
1101		>/dev/null 2>&1 && return 1
1102	POST_TEST=$(dmesg | grep -c "${ERR_MSG}")
1103
1104	if [ "$PRE_TEST" == "$POST_TEST" ]; then
1105		info "failed - clone depth too large"
1106		return 1
1107	fi
1108
1109	PRE_TEST=$(dmesg | grep -c "${ERR_MSG}")
1110	ovs_add_flow "test_netlink_checks" nv0 \
1111		'in_port(1),eth(),eth_type(0x0806),arp()' 'drop(0),2' \
1112		&> /dev/null && return 1
1113	POST_TEST=$(dmesg | grep -c "${ERR_MSG}")
1114	if [ "$PRE_TEST" == "$POST_TEST" ]; then
1115		info "failed - error not generated"
1116		return 1
1117	fi
1118	return 0
1119}
1120
1121test_upcall_interfaces() {
1122	sbx_add "test_upcall_interfaces" || return 1
1123
1124	info "setting up new DP"
1125	ovs_add_dp "test_upcall_interfaces" ui0 -V 2:1 || return 1
1126
1127	ovs_add_netns_and_veths "test_upcall_interfaces" ui0 upc left0 l0 \
1128	    172.31.110.1/24 -u || return 1
1129
1130	ovs_wait grep -q "listening on upcall packet handler" ${ovs_dir}/left0.out
1131
1132	info "sending arping"
1133	ip netns exec upc arping -I l0 172.31.110.20 -c 1 \
1134	    >$ovs_dir/arping.stdout 2>$ovs_dir/arping.stderr
1135
1136	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
1137	return 0
1138}
1139
1140ovs_add_kernel_tunnel() {
1141	local sbxname=$1; shift
1142	local ns=$1; shift
1143	local tnl_type=$1; shift
1144	local name=$1; shift
1145	local addr=$1; shift
1146
1147	info "setting up kernel ${tnl_type} tunnel ${name}"
1148	ovs_sbx "${sbxname}" ip -netns ${ns} link add dev ${name} type ${tnl_type} $* || return 1
1149	on_exit "ovs_sbx ${sbxname} ip -netns ${ns} link del ${name} >/dev/null 2>&1"
1150	ovs_sbx "${sbxname}" ip -netns ${ns} addr add dev ${name} ${addr} || return 1
1151	ovs_sbx "${sbxname}" ip -netns ${ns} link set dev ${name} mtu 1450 up || return 1
1152}
1153
1154test_tunnel_metadata() {
1155	which arping >/dev/null 2>&1 || return $ksft_skip
1156
1157	sbxname="test_tunnel_metadata"
1158	sbx_add "${sbxname}" || return 1
1159
1160	info "setting up new DP"
1161	ovs_add_dp "${sbxname}" tdp0 -V 2:1 || return 1
1162
1163	ovs_add_netns_and_veths "${sbxname}" tdp0 tns left0 l0 \
1164		172.31.110.1/24 || return 1
1165
1166	info "removing veth interface from openvswitch and setting IP"
1167	ovs_del_if "${sbxname}" tdp0 left0 || return 1
1168	ovs_sbx "${sbxname}" ip addr add 172.31.110.2/24 dev left0 || return 1
1169	ovs_sbx "${sbxname}" ip link set left0 up || return 1
1170
1171	info "setting up tunnel port in openvswitch"
1172	ovs_add_if "${sbxname}" "vxlan" tdp0 ovs-vxlan0 -u || return 1
1173	on_exit "ovs_sbx ${sbxname} ip link del ovs-vxlan0"
1174	ovs_wait ip link show ovs-vxlan0 &>/dev/null || return 1
1175	ovs_sbx "${sbxname}" ip link set ovs-vxlan0 up || return 1
1176
1177	configs=$(echo '
1178	    1 172.31.221.1/24 1155332 32   set   udpcsum flags\(df\|csum\)
1179	    2 172.31.222.1/24 1234567 45   set noudpcsum flags\(df\)
1180	    3 172.31.223.1/24 1020304 23 unset   udpcsum flags\(csum\)
1181	    4 172.31.224.1/24 1357986 15 unset noudpcsum' | sed '/^$/d')
1182
1183	while read -r i addr id ttl df csum flags; do
1184		ovs_add_kernel_tunnel "${sbxname}" tns vxlan vxlan${i} ${addr} \
1185			remote 172.31.110.2 id ${id} dstport 4789 \
1186			ttl ${ttl} df ${df} ${csum} || return 1
1187	done <<< "${configs}"
1188
1189	ovs_wait grep -q 'listening on upcall packet handler' \
1190		${ovs_dir}/ovs-vxlan0.out || return 1
1191
1192	info "sending arping"
1193	for i in 1 2 3 4; do
1194		ovs_sbx "${sbxname}" ip netns exec tns \
1195			arping -I vxlan${i} 172.31.22${i}.2 -c 1 \
1196			>${ovs_dir}/arping.stdout 2>${ovs_dir}/arping.stderr
1197	done
1198
1199	info "checking that received decapsulated packets carry correct metadata"
1200	while read -r i addr id ttl df csum flags; do
1201		arp_hdr="arp\\(sip=172.31.22${i}.1,tip=172.31.22${i}.2,op=1,sha="
1202		addrs="src=172.31.110.1,dst=172.31.110.2"
1203		ports="tp_src=[0-9]*,tp_dst=4789"
1204		tnl_md="tunnel\\(tun_id=${id},${addrs},ttl=${ttl},${ports},${flags}\\)"
1205
1206		ovs_sbx "${sbxname}" grep -qE "MISS upcall.*${tnl_md}.*${arp_hdr}" \
1207			${ovs_dir}/ovs-vxlan0.out || return 1
1208	done <<< "${configs}"
1209
1210	return 0
1211}
1212
1213test_tunnel_refcount() {
1214	sbxname="test_tunnel_refcount"
1215	sbx_add "${sbxname}" || return 1
1216
1217	ovs_sbx "${sbxname}" ip netns add trefns || return 1
1218	on_exit "ovs_sbx ${sbxname} ip netns del trefns"
1219
1220	for tun_type in gre vxlan geneve; do
1221		info "testing ${tun_type} tunnel vport refcount"
1222
1223		ovs_sbx "${sbxname}" ip netns exec trefns \
1224			python3 $ovs_base/ovs-dpctl.py \
1225			add-dp dp-${tun_type} || return 1
1226
1227		ovs_sbx "${sbxname}" ip netns exec trefns \
1228			python3 $ovs_base/ovs-dpctl.py \
1229			add-if --no-lwt -t ${tun_type} \
1230			dp-${tun_type} ovs-${tun_type}0 || return 1
1231
1232		ovs_wait ip -netns trefns link show \
1233			ovs-${tun_type}0 >/dev/null 2>&1 || return 1
1234
1235		info "deleting dp - may hang if reference counting is broken"
1236		ovs_sbx "${sbxname}" ip netns exec trefns \
1237			python3 $ovs_base/ovs-dpctl.py \
1238			del-dp dp-${tun_type} &
1239
1240		dev_removed() {
1241			! ip -netns trefns link show "$1" >/dev/null 2>&1
1242		}
1243		ovs_wait dev_removed dp-${tun_type} || return 1
1244		ovs_wait dev_removed ovs-${tun_type}0 || return 1
1245	done
1246
1247	return 0
1248}
1249
1250test_pop_vlan() {
1251	local sbx="test_pop_vlan"
1252	sbx_add "$sbx" || return $?
1253	ovs_add_dp "$sbx" vlandp || return 1
1254
1255	ovs_add_netns_and_veths "$sbx" vlandp \
1256		ns1 veth1 ns1veth 192.0.2.1/24 || return 1
1257	ovs_add_netns_and_veths "$sbx" vlandp \
1258		ns2 veth2 ns2veth 192.0.2.2/24 || return 1
1259
1260	# Baseline: untagged bidirectional forwarding
1261	ovs_add_flow "$sbx" vlandp \
1262		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
1263	ovs_add_flow "$sbx" vlandp \
1264		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
1265	ovs_add_flow "$sbx" vlandp \
1266		'in_port(1),eth(),eth_type(0x0800),ipv4()' '2' || return 1
1267	ovs_add_flow "$sbx" vlandp \
1268		'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1
1269	ovs_sbx "$sbx" ip netns exec ns1 ping -c 3 -W 2 \
1270		192.0.2.2 || return 1
1271
1272	# VLAN topology: ns1 uses VLAN sub-interface, ns2 is plain
1273	ip -n ns1 link add link ns1veth name ns1veth.10 \
1274		type vlan id 10 || return 1
1275	on_exit "ip -n ns1 link del ns1veth.10 2>/dev/null"
1276	ip -n ns1 addr add 198.51.100.1/24 dev ns1veth.10 || return 1
1277	ip -n ns1 link set ns1veth.10 up || return 1
1278	ip -n ns2 addr add 198.51.100.2/24 dev ns2veth || return 1
1279
1280	ovs_del_flows "$sbx" vlandp
1281
1282	# Static ARP: avoids VLAN-tagged ARP complexity
1283	local ns1veth10mac ns2mac
1284	ns1veth10mac=$(ip -n ns1 link show ns1veth.10 \
1285		| awk '/link\/ether/ {print $2}')
1286	[ -z "$ns1veth10mac" ] && \
1287		{ info "failed to get ns1veth10mac"; return 1; }
1288	ns2mac=$(ip -n ns2 link show ns2veth \
1289		| awk '/link\/ether/ {print $2}')
1290	[ -z "$ns2mac" ] && \
1291		{ info "failed to get ns2mac"; return 1; }
1292	ip -n ns1 neigh replace 198.51.100.2 lladdr "$ns2mac" \
1293		dev ns1veth.10 nud permanent || return 1
1294	ip -n ns2 neigh replace 198.51.100.1 \
1295		lladdr "$ns1veth10mac" \
1296		dev ns2veth nud permanent || return 1
1297
1298	local vlan_match='in_port(1),eth(),eth_type(0x8100),'
1299	vlan_match+='vlan(vid=10),'
1300	vlan_match+='encap(eth_type(0x0800),'
1301	vlan_match+='ipv4(src=198.51.100.1,proto=1),icmp())'
1302
1303	# Negative: forward without pop_vlan -- tagged frame
1304	# is invisible to ns2 (no VLAN sub-interface), ping fails
1305	ovs_add_flow "$sbx" vlandp "$vlan_match" '2' || return 1
1306	ovs_sbx "$sbx" ip netns exec ns1 ping -I ns1veth.10 \
1307		-c 3 -W 1 198.51.100.2 >/dev/null 2>&1 \
1308		&& { info "FAIL: ping should fail without pop_vlan"
1309		     return 1; }
1310
1311	ovs_del_flows "$sbx" vlandp
1312
1313	# Positive: pop_vlan strips tag on forward path,
1314	# push_vlan restores tag on return path -- ping succeeds
1315	ovs_add_flow "$sbx" vlandp \
1316		"$vlan_match" 'pop_vlan,2' || return 1
1317	ovs_add_flow "$sbx" vlandp \
1318		'in_port(2),eth(),eth_type(0x0800),ipv4()' \
1319		'push_vlan(vid=10,pcp=0,tpid=0x8100),1' || return 1
1320	ovs_sbx "$sbx" ip netns exec ns1 ping -I ns1veth.10 \
1321		-c 3 -W 2 198.51.100.2 || return 1
1322
1323	return 0
1324}
1325
1326run_test() {
1327	(
1328	tname="$1"
1329	tdesc="$2"
1330
1331	if python3 ovs-dpctl.py -h 2>&1 | \
1332	     grep -E "Need to (install|upgrade) the python" >/dev/null 2>&1; then
1333		stdbuf -o0 printf "TEST: %-60s  [PYLIB]\n" "${tdesc}"
1334		return $ksft_skip
1335	fi
1336
1337	python3 ovs-dpctl.py show >/dev/null 2>&1 || \
1338		echo "[DPCTL] show exception."
1339
1340	if ! lsmod | grep openvswitch >/dev/null 2>&1; then
1341		stdbuf -o0 printf "TEST: %-60s  [NOMOD]\n" "${tdesc}"
1342		return $ksft_skip
1343	fi
1344
1345	printf "TEST: %-60s  [START]\n" "${tname}"
1346
1347	unset IFS
1348
1349	eval test_${tname}
1350	ret=$?
1351
1352	if [ $ret -eq 0 ]; then
1353		printf "TEST: %-60s  [ OK ]\n" "${tdesc}"
1354		ovs_exit_sig
1355		rm -rf "$ovs_dir"
1356	elif [ $ret -eq 1 ]; then
1357		printf "TEST: %-60s  [FAIL]\n" "${tdesc}"
1358		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
1359			echo
1360			echo "Pausing. Logs in $ovs_dir/. Hit enter to continue"
1361			read a
1362		fi
1363		ovs_exit_sig
1364		[ "${PAUSE_ON_FAIL}" = "yes" ] || rm -rf "$ovs_dir"
1365		exit 1
1366	elif [ $ret -eq $ksft_skip ]; then
1367		printf "TEST: %-60s  [SKIP]\n" "${tdesc}"
1368	elif [ $ret -eq 2 ]; then
1369		rm -rf test_${tname}
1370		run_test "$1" "$2"
1371	fi
1372
1373	return $ret
1374	)
1375	ret=$?
1376	case $ret in
1377		0)
1378			[ $all_skipped = true ] && [ $exitcode=$ksft_skip ] && exitcode=0
1379			all_skipped=false
1380		;;
1381		$ksft_skip)
1382			[ $all_skipped = true ] && exitcode=$ksft_skip
1383		;;
1384		*)
1385			all_skipped=false
1386			exitcode=1
1387		;;
1388	esac
1389
1390	return $ret
1391}
1392
1393
1394exitcode=0
1395desc=0
1396all_skipped=true
1397
1398while getopts :pvt o
1399do
1400	case $o in
1401	p) PAUSE_ON_FAIL=yes;;
1402	v) VERBOSE=1;;
1403	t) if which tcpdump > /dev/null 2>&1; then
1404		TRACING=1
1405	   else
1406		echo "=== tcpdump not available, tracing disabled"
1407	   fi
1408	   ;;
1409	*) usage;;
1410	esac
1411done
1412shift $(($OPTIND-1))
1413
1414IFS="
1415"
1416
1417for arg do
1418	# Check first that all requested tests are available before running any
1419	command -v > /dev/null "test_${arg}" || { echo "=== Test ${arg} not found"; usage; }
1420done
1421
1422name=""
1423desc=""
1424for t in ${tests}; do
1425	[ "${name}" = "" ]	&& name="${t}"	&& continue
1426	[ "${desc}" = "" ]	&& desc="${t}"
1427
1428	run_this=1
1429	for arg do
1430		[ "${arg}" != "${arg#--*}" ] && continue
1431		[ "${arg}" = "${name}" ] && run_this=1 && break
1432		run_this=0
1433	done
1434	if [ $run_this -eq 1 ]; then
1435		run_test "${name}" "${desc}"
1436	fi
1437	name=""
1438	desc=""
1439done
1440
1441exit ${exitcode}
1442