xref: /linux/tools/testing/selftests/net/openvswitch/openvswitch.sh (revision 30d772a03582bd10447af1bcdd1c731c89b54174)
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
14
15tests="
16	arp_ping				eth-arp: Basic arp ping between two NS
17	ct_connect_v4				ip4-ct-xon: Basic ipv4 tcp connection using ct
18	connect_v4				ip4-xon: Basic ipv4 ping between two NS
19	nat_connect_v4				ip4-nat-xon: Basic ipv4 tcp connection via NAT
20	nat_related_v4				ip4-nat-related: ICMP related matches work with SNAT
21	netlink_checks				ovsnl: validate netlink attrs and settings
22	upcall_interfaces			ovs: test the upcall interfaces
23	drop_reason				drop: test drop reasons are emitted
24	psample					psample: Sampling packets with psample"
25
26info() {
27	[ "${ovs_dir}" != "" ] &&
28		echo "`date +"[%m-%d %H:%M:%S]"` $*" >> ${ovs_dir}/debug.log
29	[ $VERBOSE = 0 ] || echo $*
30}
31
32ovs_base=`pwd`
33sbxs=
34sbx_add () {
35	info "adding sandbox '$1'"
36
37	sbxs="$sbxs $1"
38
39	NO_BIN=0
40
41	# Create sandbox.
42	local d="$ovs_base"/$1
43	if [ -e $d ]; then
44		info "removing $d"
45		rm -rf "$d"
46	fi
47	mkdir "$d" || return 1
48	ovs_setenv $1
49}
50
51ovs_exit_sig() {
52	[ -e ${ovs_dir}/cleanup ] && . "$ovs_dir/cleanup"
53}
54
55on_exit() {
56	echo "$1" > ${ovs_dir}/cleanup.tmp
57	cat ${ovs_dir}/cleanup >> ${ovs_dir}/cleanup.tmp
58	mv ${ovs_dir}/cleanup.tmp ${ovs_dir}/cleanup
59}
60
61ovs_setenv() {
62	sandbox=$1
63
64	ovs_dir=$ovs_base${1:+/$1}; export ovs_dir
65
66	test -e ${ovs_dir}/cleanup || : > ${ovs_dir}/cleanup
67}
68
69ovs_sbx() {
70	if test "X$2" != X; then
71		(ovs_setenv $1; shift;
72		 info "run cmd: $@"; "$@" >> ${ovs_dir}/debug.log)
73	else
74		ovs_setenv $1
75	fi
76}
77
78ovs_add_dp () {
79	info "Adding DP/Bridge IF: sbx:$1 dp:$2 {$3, $4, $5}"
80	sbxname="$1"
81	shift
82	ovs_sbx "$sbxname" python3 $ovs_base/ovs-dpctl.py add-dp $*
83	on_exit "ovs_sbx $sbxname python3 $ovs_base/ovs-dpctl.py del-dp $1;"
84}
85
86ovs_add_if () {
87	info "Adding IF to DP: br:$2 if:$3"
88	if [ "$4" != "-u" ]; then
89		ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py add-if "$2" "$3" \
90		    || return 1
91	else
92		python3 $ovs_base/ovs-dpctl.py add-if \
93		    -u "$2" "$3" >$ovs_dir/$3.out 2>$ovs_dir/$3.err &
94		pid=$!
95		on_exit "ovs_sbx $1 kill -TERM $pid 2>/dev/null"
96	fi
97}
98
99ovs_del_if () {
100	info "Deleting IF from DP: br:$2 if:$3"
101	ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py del-if "$2" "$3" || return 1
102}
103
104ovs_netns_spawn_daemon() {
105	sbx=$1
106	shift
107	netns=$1
108	shift
109	if [ "$netns" == "_default" ]; then
110		$*  >> $ovs_dir/stdout  2>> $ovs_dir/stderr &
111	else
112		ip netns exec $netns $*  >> $ovs_dir/stdout  2>> $ovs_dir/stderr &
113	fi
114	pid=$!
115	ovs_sbx "$sbx" on_exit "kill -TERM $pid 2>/dev/null"
116}
117
118ovs_spawn_daemon() {
119	sbx=$1
120	shift
121	ovs_netns_spawn_daemon $sbx "_default" $*
122}
123
124ovs_add_netns_and_veths () {
125	info "Adding netns attached: sbx:$1 dp:$2 {$3, $4, $5}"
126	ovs_sbx "$1" ip netns add "$3" || return 1
127	on_exit "ovs_sbx $1 ip netns del $3"
128	ovs_sbx "$1" ip link add "$4" type veth peer name "$5" || return 1
129	on_exit "ovs_sbx $1 ip link del $4 >/dev/null 2>&1"
130	ovs_sbx "$1" ip link set "$4" up || return 1
131	ovs_sbx "$1" ip link set "$5" netns "$3" || return 1
132	ovs_sbx "$1" ip netns exec "$3" ip link set "$5" up || return 1
133
134	if [ "$6" != "" ]; then
135		ovs_sbx "$1" ip netns exec "$3" ip addr add "$6" dev "$5" \
136		    || return 1
137	fi
138
139	if [ "$7" != "-u" ]; then
140		ovs_add_if "$1" "$2" "$4" || return 1
141	else
142		ovs_add_if "$1" "$2" "$4" -u || return 1
143	fi
144
145	[ $TRACING -eq 1 ] && ovs_netns_spawn_daemon "$1" "$ns" \
146			tcpdump -i any -s 65535
147
148	return 0
149}
150
151ovs_add_flow () {
152	info "Adding flow to DP: sbx:$1 br:$2 flow:$3 act:$4"
153	ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py add-flow "$2" "$3" "$4"
154	if [ $? -ne 0 ]; then
155		info "Flow [ $3 : $4 ] failed"
156		return 1
157	fi
158	return 0
159}
160
161ovs_del_flows () {
162	info "Deleting all flows from DP: sbx:$1 br:$2"
163	ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py del-flows "$2"
164	return 0
165}
166
167ovs_drop_record_and_run () {
168	local sbx=$1
169	shift
170
171	perf record -a -q -e skb:kfree_skb -o ${ovs_dir}/perf.data $* \
172		>> ${ovs_dir}/stdout 2>> ${ovs_dir}/stderr
173	return $?
174}
175
176ovs_drop_reason_count()
177{
178	local reason=$1
179
180	local perf_output=`perf script -i ${ovs_dir}/perf.data -F trace:event,trace`
181	local pattern="skb:kfree_skb:.*reason: $reason"
182
183	return `echo "$perf_output" | grep "$pattern" | wc -l`
184}
185
186ovs_test_flow_fails () {
187	ERR_MSG="Flow actions may not be safe on all matching packets"
188
189	PRE_TEST=$(dmesg | grep -c "${ERR_MSG}")
190	ovs_add_flow $@ &> /dev/null $@ && return 1
191	POST_TEST=$(dmesg | grep -c "${ERR_MSG}")
192
193	if [ "$PRE_TEST" == "$POST_TEST" ]; then
194		return 1
195	fi
196	return 0
197}
198
199usage() {
200	echo
201	echo "$0 [OPTIONS] [TEST]..."
202	echo "If no TEST argument is given, all tests will be run."
203	echo
204	echo "Options"
205	echo "  -t: capture traffic via tcpdump"
206	echo "  -v: verbose"
207	echo "  -p: pause on failure"
208	echo
209	echo "Available tests${tests}"
210	exit 1
211}
212
213
214# psample test
215# - use psample to observe packets
216test_psample() {
217	sbx_add "test_psample" || return $?
218
219	# Add a datapath with per-vport dispatching.
220	ovs_add_dp "test_psample" psample -V 2:1 || return 1
221
222	info "create namespaces"
223	ovs_add_netns_and_veths "test_psample" "psample" \
224		client c0 c1 172.31.110.10/24 -u || return 1
225	ovs_add_netns_and_veths "test_psample" "psample" \
226		server s0 s1 172.31.110.20/24 -u || return 1
227
228	# Check if psample actions can be configured.
229	ovs_add_flow "test_psample" psample \
230	'in_port(1),eth(),eth_type(0x0806),arp()' 'psample(group=1)' &> /dev/null
231	if [ $? == 1 ]; then
232		info "no support for psample - skipping"
233		ovs_exit_sig
234		return $ksft_skip
235	fi
236
237	ovs_del_flows "test_psample" psample
238
239	# Test action verification.
240	OLDIFS=$IFS
241	IFS='*'
242	min_key='in_port(1),eth(),eth_type(0x0800),ipv4()'
243	for testcase in \
244		"cookie to large"*"psample(group=1,cookie=1615141312111009080706050403020100)" \
245		"no group with cookie"*"psample(cookie=abcd)" \
246		"no group"*"psample()";
247	do
248		set -- $testcase;
249		ovs_test_flow_fails "test_psample" psample $min_key $2
250		if [ $? == 1 ]; then
251			info "failed - $1"
252			return 1
253		fi
254	done
255	IFS=$OLDIFS
256
257	ovs_del_flows "test_psample" psample
258	# Allow ARP
259	ovs_add_flow "test_psample" psample \
260		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
261	ovs_add_flow "test_psample" psample \
262		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
263
264	# Sample first 14 bytes of all traffic.
265	ovs_add_flow "test_psample" psample \
266	    "in_port(1),eth(),eth_type(0x0800),ipv4()" \
267            "trunc(14),psample(group=1,cookie=c0ffee),2"
268
269	# Sample all traffic. In this case, use a sample() action with both
270	# psample and an upcall emulating simultaneous local sampling and
271	# sFlow / IPFIX.
272	nlpid=$(grep -E "listening on upcall packet handler" \
273            $ovs_dir/s0.out | cut -d ":" -f 2 | tr -d ' ')
274
275	ovs_add_flow "test_psample" psample \
276            "in_port(2),eth(),eth_type(0x0800),ipv4()" \
277            "sample(sample=100%,actions(psample(group=2,cookie=eeff0c),userspace(pid=${nlpid},userdata=eeff0c))),1"
278
279	# Record psample data.
280	ovs_spawn_daemon "test_psample" python3 $ovs_base/ovs-dpctl.py psample-events
281
282	# Send a single ping.
283	sleep 1
284	ovs_sbx "test_psample" ip netns exec client ping -I c1 172.31.110.20 -c 1 || return 1
285	sleep 1
286
287	# We should have received one userspace action upcall and 2 psample packets.
288	grep -E "userspace action command" $ovs_dir/s0.out >/dev/null 2>&1 || return 1
289
290	# client -> server samples should only contain the first 14 bytes of the packet.
291	grep -E "rate:4294967295,group:1,cookie:c0ffee data:[0-9a-f]{28}$" \
292			 $ovs_dir/stdout >/dev/null 2>&1 || return 1
293	grep -E "rate:4294967295,group:2,cookie:eeff0c" \
294			 $ovs_dir/stdout >/dev/null 2>&1 || return 1
295
296	return 0
297}
298
299# drop_reason test
300# - drop packets and verify the right drop reason is reported
301test_drop_reason() {
302	which perf >/dev/null 2>&1 || return $ksft_skip
303
304	sbx_add "test_drop_reason" || return $?
305
306	ovs_add_dp "test_drop_reason" dropreason || return 1
307
308	info "create namespaces"
309	for ns in client server; do
310		ovs_add_netns_and_veths "test_drop_reason" "dropreason" "$ns" \
311			"${ns:0:1}0" "${ns:0:1}1" || return 1
312	done
313
314	# Setup client namespace
315	ip netns exec client ip addr add 172.31.110.10/24 dev c1
316	ip netns exec client ip link set c1 up
317
318	# Setup server namespace
319	ip netns exec server ip addr add 172.31.110.20/24 dev s1
320	ip netns exec server ip link set s1 up
321
322	# Check if drop reasons can be sent
323	ovs_add_flow "test_drop_reason" dropreason \
324		'in_port(1),eth(),eth_type(0x0806),arp()' 'drop(10)' 2>/dev/null
325	if [ $? == 1 ]; then
326		info "no support for drop reasons - skipping"
327		ovs_exit_sig
328		return $ksft_skip
329	fi
330
331	ovs_del_flows "test_drop_reason" dropreason
332
333	# Allow ARP
334	ovs_add_flow "test_drop_reason" dropreason \
335		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
336	ovs_add_flow "test_drop_reason" dropreason \
337		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
338
339	# Allow client ICMP traffic but drop return path
340	ovs_add_flow "test_drop_reason" dropreason \
341		"in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10,proto=1),icmp()" '2'
342	ovs_add_flow "test_drop_reason" dropreason \
343		"in_port(2),eth(),eth_type(0x0800),ipv4(src=172.31.110.20,proto=1),icmp()" 'drop'
344
345	ovs_drop_record_and_run "test_drop_reason" ip netns exec client ping -c 2 172.31.110.20
346	ovs_drop_reason_count 0x30001 # OVS_DROP_FLOW_ACTION
347	if [[ "$?" -ne "2" ]]; then
348		info "Did not detect expected drops: $?"
349		return 1
350	fi
351
352	# Drop UDP 6000 traffic with an explicit action and an error code.
353	ovs_add_flow "test_drop_reason" dropreason \
354		"in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10,proto=17),udp(dst=6000)" \
355                'drop(42)'
356	# Drop UDP 7000 traffic with an explicit action with no error code.
357	ovs_add_flow "test_drop_reason" dropreason \
358		"in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10,proto=17),udp(dst=7000)" \
359                'drop(0)'
360
361	ovs_drop_record_and_run \
362            "test_drop_reason" ip netns exec client nc -i 1 -zuv 172.31.110.20 6000
363	ovs_drop_reason_count 0x30004 # OVS_DROP_EXPLICIT_ACTION_ERROR
364	if [[ "$?" -ne "1" ]]; then
365		info "Did not detect expected explicit error drops: $?"
366		return 1
367	fi
368
369	ovs_drop_record_and_run \
370            "test_drop_reason" ip netns exec client nc -i 1 -zuv 172.31.110.20 7000
371	ovs_drop_reason_count 0x30003 # OVS_DROP_EXPLICIT_ACTION
372	if [[ "$?" -ne "1" ]]; then
373		info "Did not detect expected explicit drops: $?"
374		return 1
375	fi
376
377	return 0
378}
379
380# arp_ping test
381# - client has 1500 byte MTU
382# - server has 1500 byte MTU
383# - send ARP ping between two ns
384test_arp_ping () {
385
386	which arping >/dev/null 2>&1 || return $ksft_skip
387
388	sbx_add "test_arp_ping" || return $?
389
390	ovs_add_dp "test_arp_ping" arpping || return 1
391
392	info "create namespaces"
393	for ns in client server; do
394		ovs_add_netns_and_veths "test_arp_ping" "arpping" "$ns" \
395		    "${ns:0:1}0" "${ns:0:1}1" || return 1
396	done
397
398	# Setup client namespace
399	ip netns exec client ip addr add 172.31.110.10/24 dev c1
400	ip netns exec client ip link set c1 up
401	HW_CLIENT=`ip netns exec client ip link show dev c1 | grep -E 'link/ether [0-9a-f:]+' | awk '{print $2;}'`
402	info "Client hwaddr: $HW_CLIENT"
403
404	# Setup server namespace
405	ip netns exec server ip addr add 172.31.110.20/24 dev s1
406	ip netns exec server ip link set s1 up
407	HW_SERVER=`ip netns exec server ip link show dev s1 | grep -E 'link/ether [0-9a-f:]+' | awk '{print $2;}'`
408	info "Server hwaddr: $HW_SERVER"
409
410	ovs_add_flow "test_arp_ping" arpping \
411		"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
412	ovs_add_flow "test_arp_ping" arpping \
413		"in_port(2),eth(),eth_type(0x0806),arp()" '1' || return 1
414
415	ovs_sbx "test_arp_ping" ip netns exec client arping -I c1 172.31.110.20 -c 1 || return 1
416
417	return 0
418}
419
420# ct_connect_v4 test
421#  - client has 1500 byte MTU
422#  - server has 1500 byte MTU
423#  - use ICMP to ping in each direction
424#  - only allow CT state stuff to pass through new in c -> s
425test_ct_connect_v4 () {
426
427	which nc >/dev/null 2>/dev/null || return $ksft_skip
428
429	sbx_add "test_ct_connect_v4" || return $?
430
431	ovs_add_dp "test_ct_connect_v4" ct4 || return 1
432	info "create namespaces"
433	for ns in client server; do
434		ovs_add_netns_and_veths "test_ct_connect_v4" "ct4" "$ns" \
435		    "${ns:0:1}0" "${ns:0:1}1" || return 1
436	done
437
438	ip netns exec client ip addr add 172.31.110.10/24 dev c1
439	ip netns exec client ip link set c1 up
440	ip netns exec server ip addr add 172.31.110.20/24 dev s1
441	ip netns exec server ip link set s1 up
442
443	# Add forwarding for ARP and ip packets - completely wildcarded
444	ovs_add_flow "test_ct_connect_v4" ct4 \
445		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
446	ovs_add_flow "test_ct_connect_v4" ct4 \
447		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
448	ovs_add_flow "test_ct_connect_v4" ct4 \
449		     'ct_state(-trk),eth(),eth_type(0x0800),ipv4()' \
450		     'ct(commit),recirc(0x1)' || return 1
451	ovs_add_flow "test_ct_connect_v4" ct4 \
452		     'recirc_id(0x1),ct_state(+trk+new),in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10)' \
453		     '2' || return 1
454	ovs_add_flow "test_ct_connect_v4" ct4 \
455		     'recirc_id(0x1),ct_state(+trk+est),in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10)' \
456		     '2' || return 1
457	ovs_add_flow "test_ct_connect_v4" ct4 \
458		     'recirc_id(0x1),ct_state(+trk+est),in_port(2),eth(),eth_type(0x0800),ipv4(dst=172.31.110.10)' \
459		     '1' || return 1
460	ovs_add_flow "test_ct_connect_v4" ct4 \
461		     'recirc_id(0x1),ct_state(+trk+inv),eth(),eth_type(0x0800),ipv4()' 'drop' || \
462		     return 1
463
464	# do a ping
465	ovs_sbx "test_ct_connect_v4" ip netns exec client ping 172.31.110.20 -c 3 || return 1
466
467	# create an echo server in 'server'
468	echo "server" | \
469		ovs_netns_spawn_daemon "test_ct_connect_v4" "server" \
470				nc -lvnp 4443
471	ovs_sbx "test_ct_connect_v4" ip netns exec client nc -i 1 -zv 172.31.110.20 4443 || return 1
472
473	# Now test in the other direction (should fail)
474	echo "client" | \
475		ovs_netns_spawn_daemon "test_ct_connect_v4" "client" \
476				nc -lvnp 4443
477	ovs_sbx "test_ct_connect_v4" ip netns exec client nc -i 1 -zv 172.31.110.10 4443
478	if [ $? == 0 ]; then
479	   info "ct connect to client was successful"
480	   return 1
481	fi
482
483	info "done..."
484	return 0
485}
486
487# connect_v4 test
488#  - client has 1500 byte MTU
489#  - server has 1500 byte MTU
490#  - use ICMP to ping in each direction
491test_connect_v4 () {
492
493	sbx_add "test_connect_v4" || return $?
494
495	ovs_add_dp "test_connect_v4" cv4 || return 1
496
497	info "create namespaces"
498	for ns in client server; do
499		ovs_add_netns_and_veths "test_connect_v4" "cv4" "$ns" \
500		    "${ns:0:1}0" "${ns:0:1}1" || return 1
501	done
502
503
504	ip netns exec client ip addr add 172.31.110.10/24 dev c1
505	ip netns exec client ip link set c1 up
506	ip netns exec server ip addr add 172.31.110.20/24 dev s1
507	ip netns exec server ip link set s1 up
508
509	# Add forwarding for ARP and ip packets - completely wildcarded
510	ovs_add_flow "test_connect_v4" cv4 \
511		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
512	ovs_add_flow "test_connect_v4" cv4 \
513		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
514	ovs_add_flow "test_connect_v4" cv4 \
515		'in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10)' '2' || return 1
516	ovs_add_flow "test_connect_v4" cv4 \
517		'in_port(2),eth(),eth_type(0x0800),ipv4(src=172.31.110.20)' '1' || return 1
518
519	# do a ping
520	ovs_sbx "test_connect_v4" ip netns exec client ping 172.31.110.20 -c 3 || return 1
521
522	info "done..."
523	return 0
524}
525
526# nat_connect_v4 test
527#  - client has 1500 byte MTU
528#  - server has 1500 byte MTU
529#  - use ICMP to ping in each direction
530#  - only allow CT state stuff to pass through new in c -> s
531test_nat_connect_v4 () {
532	which nc >/dev/null 2>/dev/null || return $ksft_skip
533
534	sbx_add "test_nat_connect_v4" || return $?
535
536	ovs_add_dp "test_nat_connect_v4" nat4 || return 1
537	info "create namespaces"
538	for ns in client server; do
539		ovs_add_netns_and_veths "test_nat_connect_v4" "nat4" "$ns" \
540		    "${ns:0:1}0" "${ns:0:1}1" || return 1
541	done
542
543	ip netns exec client ip addr add 172.31.110.10/24 dev c1
544	ip netns exec client ip link set c1 up
545	ip netns exec server ip addr add 172.31.110.20/24 dev s1
546	ip netns exec server ip link set s1 up
547
548	ip netns exec client ip route add default via 172.31.110.20
549
550	ovs_add_flow "test_nat_connect_v4" nat4 \
551		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
552	ovs_add_flow "test_nat_connect_v4" nat4 \
553		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
554	ovs_add_flow "test_nat_connect_v4" nat4 \
555		"ct_state(-trk),in_port(1),eth(),eth_type(0x0800),ipv4(dst=192.168.0.20)" \
556		"ct(commit,nat(dst=172.31.110.20)),recirc(0x1)"
557	ovs_add_flow "test_nat_connect_v4" nat4 \
558		"ct_state(-trk),in_port(2),eth(),eth_type(0x0800),ipv4()" \
559		"ct(commit,nat),recirc(0x2)"
560
561	ovs_add_flow "test_nat_connect_v4" nat4 \
562		"recirc_id(0x1),ct_state(+trk-inv),in_port(1),eth(),eth_type(0x0800),ipv4()" "2"
563	ovs_add_flow "test_nat_connect_v4" nat4 \
564		"recirc_id(0x2),ct_state(+trk-inv),in_port(2),eth(),eth_type(0x0800),ipv4()" "1"
565
566	# do a ping
567	ovs_sbx "test_nat_connect_v4" ip netns exec client ping 192.168.0.20 -c 3 || return 1
568
569	# create an echo server in 'server'
570	echo "server" | \
571		ovs_netns_spawn_daemon "test_nat_connect_v4" "server" \
572				nc -lvnp 4443
573	ovs_sbx "test_nat_connect_v4" ip netns exec client nc -i 1 -zv 192.168.0.20 4443 || return 1
574
575	# Now test in the other direction (should fail)
576	echo "client" | \
577		ovs_netns_spawn_daemon "test_nat_connect_v4" "client" \
578				nc -lvnp 4443
579	ovs_sbx "test_nat_connect_v4" ip netns exec client nc -i 1 -zv 172.31.110.10 4443
580	if [ $? == 0 ]; then
581	   info "connect to client was successful"
582	   return 1
583	fi
584
585	info "done..."
586	return 0
587}
588
589# nat_related_v4 test
590#  - client->server ip packets go via SNAT
591#  - client solicits ICMP destination unreachable packet from server
592#  - undo NAT for ICMP reply and test dst ip has been updated
593test_nat_related_v4 () {
594	which nc >/dev/null 2>/dev/null || return $ksft_skip
595
596	sbx_add "test_nat_related_v4" || return $?
597
598	ovs_add_dp "test_nat_related_v4" natrelated4 || return 1
599	info "create namespaces"
600	for ns in client server; do
601		ovs_add_netns_and_veths "test_nat_related_v4" "natrelated4" "$ns" \
602			"${ns:0:1}0" "${ns:0:1}1" || return 1
603	done
604
605	ip netns exec client ip addr add 172.31.110.10/24 dev c1
606	ip netns exec client ip link set c1 up
607	ip netns exec server ip addr add 172.31.110.20/24 dev s1
608	ip netns exec server ip link set s1 up
609
610	ip netns exec server ip route add 192.168.0.20/32 via 172.31.110.10
611
612	# Allow ARP
613	ovs_add_flow "test_nat_related_v4" natrelated4 \
614		"in_port(1),eth(),eth_type(0x0806),arp()" "2" || return 1
615	ovs_add_flow "test_nat_related_v4" natrelated4 \
616		"in_port(2),eth(),eth_type(0x0806),arp()" "1" || return 1
617
618	# Allow IP traffic from client->server, rewrite source IP with SNAT to 192.168.0.20
619	ovs_add_flow "test_nat_related_v4" natrelated4 \
620		"ct_state(-trk),in_port(1),eth(),eth_type(0x0800),ipv4(dst=172.31.110.20)" \
621		"ct(commit,nat(src=192.168.0.20)),recirc(0x1)" || return 1
622	ovs_add_flow "test_nat_related_v4" natrelated4 \
623		"recirc_id(0x1),ct_state(+trk-inv),in_port(1),eth(),eth_type(0x0800),ipv4()" \
624		"2" || return 1
625
626	# Allow related ICMP responses back from server and undo NAT to restore original IP
627	# Drop any ICMP related packets where dst ip hasn't been restored back to original IP
628	ovs_add_flow "test_nat_related_v4" natrelated4 \
629		"ct_state(-trk),in_port(2),eth(),eth_type(0x0800),ipv4()" \
630		"ct(commit,nat),recirc(0x2)" || return 1
631	ovs_add_flow "test_nat_related_v4" natrelated4 \
632		"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()" \
633		"1" || return 1
634	ovs_add_flow "test_nat_related_v4" natrelated4 \
635		"recirc_id(0x2),ct_state(+rel+trk),in_port(2),eth(),eth_type(0x0800),ipv4(dst=192.168.0.20,proto=1),icmp()" \
636		"drop" || return 1
637
638	# Solicit destination unreachable response from server
639	ovs_sbx "test_nat_related_v4" ip netns exec client \
640		bash -c "echo a | nc -u -w 1 172.31.110.20 10000"
641
642	# Check to make sure no packets matched the drop rule with incorrect dst ip
643	python3 "$ovs_base/ovs-dpctl.py" dump-flows natrelated4 \
644		| grep "drop" | grep "packets:0" >/dev/null || return 1
645
646	info "done..."
647	return 0
648}
649
650# netlink_validation
651# - Create a dp
652# - check no warning with "old version" simulation
653test_netlink_checks () {
654	sbx_add "test_netlink_checks" || return 1
655
656	info "setting up new DP"
657	ovs_add_dp "test_netlink_checks" nv0 || return 1
658	# now try again
659	PRE_TEST=$(dmesg | grep -E "RIP: [0-9a-fA-Fx]+:ovs_dp_cmd_new\+")
660	ovs_add_dp "test_netlink_checks" nv0 -V 0 || return 1
661	POST_TEST=$(dmesg | grep -E "RIP: [0-9a-fA-Fx]+:ovs_dp_cmd_new\+")
662	if [ "$PRE_TEST" != "$POST_TEST" ]; then
663		info "failed - gen warning"
664		return 1
665	fi
666
667	ovs_add_netns_and_veths "test_netlink_checks" nv0 left left0 l0 || \
668	    return 1
669	ovs_add_netns_and_veths "test_netlink_checks" nv0 right right0 r0 || \
670	    return 1
671	[ $(python3 $ovs_base/ovs-dpctl.py show nv0 | grep port | \
672	    wc -l) == 3 ] || \
673	      return 1
674	ovs_del_if "test_netlink_checks" nv0 right0 || return 1
675	[ $(python3 $ovs_base/ovs-dpctl.py show nv0 | grep port | \
676	    wc -l) == 2 ] || \
677	      return 1
678
679	info "Checking clone depth"
680	ERR_MSG="Flow actions may not be safe on all matching packets"
681	PRE_TEST=$(dmesg | grep -c "${ERR_MSG}")
682	ovs_add_flow "test_netlink_checks" nv0 \
683		'in_port(1),eth(),eth_type(0x800),ipv4()' \
684		'clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(drop)))))))))))))))))' \
685		>/dev/null 2>&1 && return 1
686	POST_TEST=$(dmesg | grep -c "${ERR_MSG}")
687
688	if [ "$PRE_TEST" == "$POST_TEST" ]; then
689		info "failed - clone depth too large"
690		return 1
691	fi
692
693	PRE_TEST=$(dmesg | grep -c "${ERR_MSG}")
694	ovs_add_flow "test_netlink_checks" nv0 \
695		'in_port(1),eth(),eth_type(0x0806),arp()' 'drop(0),2' \
696		&> /dev/null && return 1
697	POST_TEST=$(dmesg | grep -c "${ERR_MSG}")
698	if [ "$PRE_TEST" == "$POST_TEST" ]; then
699		info "failed - error not generated"
700		return 1
701	fi
702	return 0
703}
704
705test_upcall_interfaces() {
706	sbx_add "test_upcall_interfaces" || return 1
707
708	info "setting up new DP"
709	ovs_add_dp "test_upcall_interfaces" ui0 -V 2:1 || return 1
710
711	ovs_add_netns_and_veths "test_upcall_interfaces" ui0 upc left0 l0 \
712	    172.31.110.1/24 -u || return 1
713
714	sleep 1
715	info "sending arping"
716	ip netns exec upc arping -I l0 172.31.110.20 -c 1 \
717	    >$ovs_dir/arping.stdout 2>$ovs_dir/arping.stderr
718
719	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
720	return 0
721}
722
723run_test() {
724	(
725	tname="$1"
726	tdesc="$2"
727
728	if python3 ovs-dpctl.py -h 2>&1 | \
729	     grep -E "Need to (install|upgrade) the python" >/dev/null 2>&1; then
730		stdbuf -o0 printf "TEST: %-60s  [PYLIB]\n" "${tdesc}"
731		return $ksft_skip
732	fi
733
734	python3 ovs-dpctl.py show >/dev/null 2>&1 || \
735		echo "[DPCTL] show exception."
736
737	if ! lsmod | grep openvswitch >/dev/null 2>&1; then
738		stdbuf -o0 printf "TEST: %-60s  [NOMOD]\n" "${tdesc}"
739		return $ksft_skip
740	fi
741
742	printf "TEST: %-60s  [START]\n" "${tname}"
743
744	unset IFS
745
746	eval test_${tname}
747	ret=$?
748
749	if [ $ret -eq 0 ]; then
750		printf "TEST: %-60s  [ OK ]\n" "${tdesc}"
751		ovs_exit_sig
752		rm -rf "$ovs_dir"
753	elif [ $ret -eq 1 ]; then
754		printf "TEST: %-60s  [FAIL]\n" "${tdesc}"
755		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
756			echo
757			echo "Pausing. Logs in $ovs_dir/. Hit enter to continue"
758			read a
759		fi
760		ovs_exit_sig
761		[ "${PAUSE_ON_FAIL}" = "yes" ] || rm -rf "$ovs_dir"
762		exit 1
763	elif [ $ret -eq $ksft_skip ]; then
764		printf "TEST: %-60s  [SKIP]\n" "${tdesc}"
765	elif [ $ret -eq 2 ]; then
766		rm -rf test_${tname}
767		run_test "$1" "$2"
768	fi
769
770	return $ret
771	)
772	ret=$?
773	case $ret in
774		0)
775			[ $all_skipped = true ] && [ $exitcode=$ksft_skip ] && exitcode=0
776			all_skipped=false
777		;;
778		$ksft_skip)
779			[ $all_skipped = true ] && exitcode=$ksft_skip
780		;;
781		*)
782			all_skipped=false
783			exitcode=1
784		;;
785	esac
786
787	return $ret
788}
789
790
791exitcode=0
792desc=0
793all_skipped=true
794
795while getopts :pvt o
796do
797	case $o in
798	p) PAUSE_ON_FAIL=yes;;
799	v) VERBOSE=1;;
800	t) if which tcpdump > /dev/null 2>&1; then
801		TRACING=1
802	   else
803		echo "=== tcpdump not available, tracing disabled"
804	   fi
805	   ;;
806	*) usage;;
807	esac
808done
809shift $(($OPTIND-1))
810
811IFS="
812"
813
814for arg do
815	# Check first that all requested tests are available before running any
816	command -v > /dev/null "test_${arg}" || { echo "=== Test ${arg} not found"; usage; }
817done
818
819name=""
820desc=""
821for t in ${tests}; do
822	[ "${name}" = "" ]	&& name="${t}"	&& continue
823	[ "${desc}" = "" ]	&& desc="${t}"
824
825	run_this=1
826	for arg do
827		[ "${arg}" != "${arg#--*}" ] && continue
828		[ "${arg}" = "${name}" ] && run_this=1 && break
829		run_this=0
830	done
831	if [ $run_this -eq 1 ]; then
832		run_test "${name}" "${desc}"
833	fi
834	name=""
835	desc=""
836done
837
838exit ${exitcode}
839