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