162306a36Sopenharmony_ci#!/bin/sh
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
362306a36Sopenharmony_ci#
462306a36Sopenharmony_ci# OVS kernel module self tests
562306a36Sopenharmony_ci
662306a36Sopenharmony_citrap ovs_exit_sig EXIT TERM INT ERR
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci# Kselftest framework requirement - SKIP code is 4.
962306a36Sopenharmony_ciksft_skip=4
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ciPAUSE_ON_FAIL=no
1262306a36Sopenharmony_ciVERBOSE=0
1362306a36Sopenharmony_ciTRACING=0
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_citests="
1662306a36Sopenharmony_ci	arp_ping				eth-arp: Basic arp ping between two NS
1762306a36Sopenharmony_ci	ct_connect_v4				ip4-ct-xon: Basic ipv4 tcp connection using ct
1862306a36Sopenharmony_ci	connect_v4				ip4-xon: Basic ipv4 ping between two NS
1962306a36Sopenharmony_ci	nat_connect_v4				ip4-nat-xon: Basic ipv4 tcp connection via NAT
2062306a36Sopenharmony_ci	netlink_checks				ovsnl: validate netlink attrs and settings
2162306a36Sopenharmony_ci	upcall_interfaces			ovs: test the upcall interfaces
2262306a36Sopenharmony_ci	drop_reason				drop: test drop reasons are emitted"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ciinfo() {
2562306a36Sopenharmony_ci    [ $VERBOSE = 0 ] || echo $*
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ciovs_base=`pwd`
2962306a36Sopenharmony_cisbxs=
3062306a36Sopenharmony_cisbx_add () {
3162306a36Sopenharmony_ci	info "adding sandbox '$1'"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	sbxs="$sbxs $1"
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	NO_BIN=0
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	# Create sandbox.
3862306a36Sopenharmony_ci	local d="$ovs_base"/$1
3962306a36Sopenharmony_ci	if [ -e $d ]; then
4062306a36Sopenharmony_ci		info "removing $d"
4162306a36Sopenharmony_ci		rm -rf "$d"
4262306a36Sopenharmony_ci	fi
4362306a36Sopenharmony_ci	mkdir "$d" || return 1
4462306a36Sopenharmony_ci	ovs_setenv $1
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ciovs_exit_sig() {
4862306a36Sopenharmony_ci	[ -e ${ovs_dir}/cleanup ] && . "$ovs_dir/cleanup"
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cion_exit() {
5262306a36Sopenharmony_ci	echo "$1" > ${ovs_dir}/cleanup.tmp
5362306a36Sopenharmony_ci	cat ${ovs_dir}/cleanup >> ${ovs_dir}/cleanup.tmp
5462306a36Sopenharmony_ci	mv ${ovs_dir}/cleanup.tmp ${ovs_dir}/cleanup
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ciovs_setenv() {
5862306a36Sopenharmony_ci	sandbox=$1
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	ovs_dir=$ovs_base${1:+/$1}; export ovs_dir
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	test -e ${ovs_dir}/cleanup || : > ${ovs_dir}/cleanup
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ciovs_sbx() {
6662306a36Sopenharmony_ci	if test "X$2" != X; then
6762306a36Sopenharmony_ci		(ovs_setenv $1; shift; "$@" >> ${ovs_dir}/debug.log)
6862306a36Sopenharmony_ci	else
6962306a36Sopenharmony_ci		ovs_setenv $1
7062306a36Sopenharmony_ci	fi
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ciovs_add_dp () {
7462306a36Sopenharmony_ci	info "Adding DP/Bridge IF: sbx:$1 dp:$2 {$3, $4, $5}"
7562306a36Sopenharmony_ci	sbxname="$1"
7662306a36Sopenharmony_ci	shift
7762306a36Sopenharmony_ci	ovs_sbx "$sbxname" python3 $ovs_base/ovs-dpctl.py add-dp $*
7862306a36Sopenharmony_ci	on_exit "ovs_sbx $sbxname python3 $ovs_base/ovs-dpctl.py del-dp $1;"
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ciovs_add_if () {
8262306a36Sopenharmony_ci	info "Adding IF to DP: br:$2 if:$3"
8362306a36Sopenharmony_ci	if [ "$4" != "-u" ]; then
8462306a36Sopenharmony_ci		ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py add-if "$2" "$3" \
8562306a36Sopenharmony_ci		    || return 1
8662306a36Sopenharmony_ci	else
8762306a36Sopenharmony_ci		python3 $ovs_base/ovs-dpctl.py add-if \
8862306a36Sopenharmony_ci		    -u "$2" "$3" >$ovs_dir/$3.out 2>$ovs_dir/$3.err &
8962306a36Sopenharmony_ci		pid=$!
9062306a36Sopenharmony_ci		on_exit "ovs_sbx $1 kill -TERM $pid 2>/dev/null"
9162306a36Sopenharmony_ci	fi
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ciovs_del_if () {
9562306a36Sopenharmony_ci	info "Deleting IF from DP: br:$2 if:$3"
9662306a36Sopenharmony_ci	ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py del-if "$2" "$3" || return 1
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ciovs_netns_spawn_daemon() {
10062306a36Sopenharmony_ci	sbx=$1
10162306a36Sopenharmony_ci	shift
10262306a36Sopenharmony_ci	netns=$1
10362306a36Sopenharmony_ci	shift
10462306a36Sopenharmony_ci	info "spawning cmd: $*"
10562306a36Sopenharmony_ci	ip netns exec $netns $*  >> $ovs_dir/stdout  2>> $ovs_dir/stderr &
10662306a36Sopenharmony_ci	pid=$!
10762306a36Sopenharmony_ci	ovs_sbx "$sbx" on_exit "kill -TERM $pid 2>/dev/null"
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ciovs_add_netns_and_veths () {
11162306a36Sopenharmony_ci	info "Adding netns attached: sbx:$1 dp:$2 {$3, $4, $5}"
11262306a36Sopenharmony_ci	ovs_sbx "$1" ip netns add "$3" || return 1
11362306a36Sopenharmony_ci	on_exit "ovs_sbx $1 ip netns del $3"
11462306a36Sopenharmony_ci	ovs_sbx "$1" ip link add "$4" type veth peer name "$5" || return 1
11562306a36Sopenharmony_ci	on_exit "ovs_sbx $1 ip link del $4 >/dev/null 2>&1"
11662306a36Sopenharmony_ci	ovs_sbx "$1" ip link set "$4" up || return 1
11762306a36Sopenharmony_ci	ovs_sbx "$1" ip link set "$5" netns "$3" || return 1
11862306a36Sopenharmony_ci	ovs_sbx "$1" ip netns exec "$3" ip link set "$5" up || return 1
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	if [ "$6" != "" ]; then
12162306a36Sopenharmony_ci		ovs_sbx "$1" ip netns exec "$3" ip addr add "$6" dev "$5" \
12262306a36Sopenharmony_ci		    || return 1
12362306a36Sopenharmony_ci	fi
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	if [ "$7" != "-u" ]; then
12662306a36Sopenharmony_ci		ovs_add_if "$1" "$2" "$4" || return 1
12762306a36Sopenharmony_ci	else
12862306a36Sopenharmony_ci		ovs_add_if "$1" "$2" "$4" -u || return 1
12962306a36Sopenharmony_ci	fi
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	[ $TRACING -eq 1 ] && ovs_netns_spawn_daemon "$1" "$ns" \
13262306a36Sopenharmony_ci			tcpdump -i any -s 65535
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	return 0
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ciovs_add_flow () {
13862306a36Sopenharmony_ci	info "Adding flow to DP: sbx:$1 br:$2 flow:$3 act:$4"
13962306a36Sopenharmony_ci	ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py add-flow "$2" "$3" "$4"
14062306a36Sopenharmony_ci	if [ $? -ne 0 ]; then
14162306a36Sopenharmony_ci		echo "Flow [ $3 : $4 ] failed" >> ${ovs_dir}/debug.log
14262306a36Sopenharmony_ci		return 1
14362306a36Sopenharmony_ci	fi
14462306a36Sopenharmony_ci	return 0
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ciovs_del_flows () {
14862306a36Sopenharmony_ci	info "Deleting all flows from DP: sbx:$1 br:$2"
14962306a36Sopenharmony_ci	ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py del-flows "$2"
15062306a36Sopenharmony_ci	return 0
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ciovs_drop_record_and_run () {
15462306a36Sopenharmony_ci	local sbx=$1
15562306a36Sopenharmony_ci	shift
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	perf record -a -q -e skb:kfree_skb -o ${ovs_dir}/perf.data $* \
15862306a36Sopenharmony_ci		>> ${ovs_dir}/stdout 2>> ${ovs_dir}/stderr
15962306a36Sopenharmony_ci	return $?
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ciovs_drop_reason_count()
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	local reason=$1
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	local perf_output=`perf script -i ${ovs_dir}/perf.data -F trace:event,trace`
16762306a36Sopenharmony_ci	local pattern="skb:kfree_skb:.*reason: $reason"
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	return `echo "$perf_output" | grep "$pattern" | wc -l`
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ciusage() {
17362306a36Sopenharmony_ci	echo
17462306a36Sopenharmony_ci	echo "$0 [OPTIONS] [TEST]..."
17562306a36Sopenharmony_ci	echo "If no TEST argument is given, all tests will be run."
17662306a36Sopenharmony_ci	echo
17762306a36Sopenharmony_ci	echo "Options"
17862306a36Sopenharmony_ci	echo "  -t: capture traffic via tcpdump"
17962306a36Sopenharmony_ci	echo "  -v: verbose"
18062306a36Sopenharmony_ci	echo "  -p: pause on failure"
18162306a36Sopenharmony_ci	echo
18262306a36Sopenharmony_ci	echo "Available tests${tests}"
18362306a36Sopenharmony_ci	exit 1
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci# drop_reason test
18762306a36Sopenharmony_ci# - drop packets and verify the right drop reason is reported
18862306a36Sopenharmony_citest_drop_reason() {
18962306a36Sopenharmony_ci	which perf >/dev/null 2>&1 || return $ksft_skip
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	sbx_add "test_drop_reason" || return $?
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	ovs_add_dp "test_drop_reason" dropreason || return 1
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	info "create namespaces"
19662306a36Sopenharmony_ci	for ns in client server; do
19762306a36Sopenharmony_ci		ovs_add_netns_and_veths "test_drop_reason" "dropreason" "$ns" \
19862306a36Sopenharmony_ci			"${ns:0:1}0" "${ns:0:1}1" || return 1
19962306a36Sopenharmony_ci	done
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	# Setup client namespace
20262306a36Sopenharmony_ci	ip netns exec client ip addr add 172.31.110.10/24 dev c1
20362306a36Sopenharmony_ci	ip netns exec client ip link set c1 up
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	# Setup server namespace
20662306a36Sopenharmony_ci	ip netns exec server ip addr add 172.31.110.20/24 dev s1
20762306a36Sopenharmony_ci	ip netns exec server ip link set s1 up
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	# Check if drop reasons can be sent
21062306a36Sopenharmony_ci	ovs_add_flow "test_drop_reason" dropreason \
21162306a36Sopenharmony_ci		'in_port(1),eth(),eth_type(0x0806),arp()' 'drop(10)' 2>/dev/null
21262306a36Sopenharmony_ci	if [ $? == 1 ]; then
21362306a36Sopenharmony_ci		info "no support for drop reasons - skipping"
21462306a36Sopenharmony_ci		ovs_exit_sig
21562306a36Sopenharmony_ci		return $ksft_skip
21662306a36Sopenharmony_ci	fi
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	ovs_del_flows "test_drop_reason" dropreason
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	# Allow ARP
22162306a36Sopenharmony_ci	ovs_add_flow "test_drop_reason" dropreason \
22262306a36Sopenharmony_ci		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
22362306a36Sopenharmony_ci	ovs_add_flow "test_drop_reason" dropreason \
22462306a36Sopenharmony_ci		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	# Allow client ICMP traffic but drop return path
22762306a36Sopenharmony_ci	ovs_add_flow "test_drop_reason" dropreason \
22862306a36Sopenharmony_ci		"in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10,proto=1),icmp()" '2'
22962306a36Sopenharmony_ci	ovs_add_flow "test_drop_reason" dropreason \
23062306a36Sopenharmony_ci		"in_port(2),eth(),eth_type(0x0800),ipv4(src=172.31.110.20,proto=1),icmp()" 'drop'
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	ovs_drop_record_and_run "test_drop_reason" ip netns exec client ping -c 2 172.31.110.20
23362306a36Sopenharmony_ci	ovs_drop_reason_count 0x30001 # OVS_DROP_FLOW_ACTION
23462306a36Sopenharmony_ci	if [[ "$?" -ne "2" ]]; then
23562306a36Sopenharmony_ci		info "Did not detect expected drops: $?"
23662306a36Sopenharmony_ci		return 1
23762306a36Sopenharmony_ci	fi
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	# Drop UDP 6000 traffic with an explicit action and an error code.
24062306a36Sopenharmony_ci	ovs_add_flow "test_drop_reason" dropreason \
24162306a36Sopenharmony_ci		"in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10,proto=17),udp(dst=6000)" \
24262306a36Sopenharmony_ci                'drop(42)'
24362306a36Sopenharmony_ci	# Drop UDP 7000 traffic with an explicit action with no error code.
24462306a36Sopenharmony_ci	ovs_add_flow "test_drop_reason" dropreason \
24562306a36Sopenharmony_ci		"in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10,proto=17),udp(dst=7000)" \
24662306a36Sopenharmony_ci                'drop(0)'
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	ovs_drop_record_and_run \
24962306a36Sopenharmony_ci            "test_drop_reason" ip netns exec client nc -i 1 -zuv 172.31.110.20 6000
25062306a36Sopenharmony_ci	ovs_drop_reason_count 0x30004 # OVS_DROP_EXPLICIT_ACTION_ERROR
25162306a36Sopenharmony_ci	if [[ "$?" -ne "1" ]]; then
25262306a36Sopenharmony_ci		info "Did not detect expected explicit error drops: $?"
25362306a36Sopenharmony_ci		return 1
25462306a36Sopenharmony_ci	fi
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	ovs_drop_record_and_run \
25762306a36Sopenharmony_ci            "test_drop_reason" ip netns exec client nc -i 1 -zuv 172.31.110.20 7000
25862306a36Sopenharmony_ci	ovs_drop_reason_count 0x30003 # OVS_DROP_EXPLICIT_ACTION
25962306a36Sopenharmony_ci	if [[ "$?" -ne "1" ]]; then
26062306a36Sopenharmony_ci		info "Did not detect expected explicit drops: $?"
26162306a36Sopenharmony_ci		return 1
26262306a36Sopenharmony_ci	fi
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return 0
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci# arp_ping test
26862306a36Sopenharmony_ci# - client has 1500 byte MTU
26962306a36Sopenharmony_ci# - server has 1500 byte MTU
27062306a36Sopenharmony_ci# - send ARP ping between two ns
27162306a36Sopenharmony_citest_arp_ping () {
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	which arping >/dev/null 2>&1 || return $ksft_skip
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	sbx_add "test_arp_ping" || return $?
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	ovs_add_dp "test_arp_ping" arpping || return 1
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	info "create namespaces"
28062306a36Sopenharmony_ci	for ns in client server; do
28162306a36Sopenharmony_ci		ovs_add_netns_and_veths "test_arp_ping" "arpping" "$ns" \
28262306a36Sopenharmony_ci		    "${ns:0:1}0" "${ns:0:1}1" || return 1
28362306a36Sopenharmony_ci	done
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	# Setup client namespace
28662306a36Sopenharmony_ci	ip netns exec client ip addr add 172.31.110.10/24 dev c1
28762306a36Sopenharmony_ci	ip netns exec client ip link set c1 up
28862306a36Sopenharmony_ci	HW_CLIENT=`ip netns exec client ip link show dev c1 | grep -E 'link/ether [0-9a-f:]+' | awk '{print $2;}'`
28962306a36Sopenharmony_ci	info "Client hwaddr: $HW_CLIENT"
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	# Setup server namespace
29262306a36Sopenharmony_ci	ip netns exec server ip addr add 172.31.110.20/24 dev s1
29362306a36Sopenharmony_ci	ip netns exec server ip link set s1 up
29462306a36Sopenharmony_ci	HW_SERVER=`ip netns exec server ip link show dev s1 | grep -E 'link/ether [0-9a-f:]+' | awk '{print $2;}'`
29562306a36Sopenharmony_ci	info "Server hwaddr: $HW_SERVER"
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	ovs_add_flow "test_arp_ping" arpping \
29862306a36Sopenharmony_ci		"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
29962306a36Sopenharmony_ci	ovs_add_flow "test_arp_ping" arpping \
30062306a36Sopenharmony_ci		"in_port(2),eth(),eth_type(0x0806),arp()" '1' || return 1
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	ovs_sbx "test_arp_ping" ip netns exec client arping -I c1 172.31.110.20 -c 1 || return 1
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	return 0
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci# ct_connect_v4 test
30862306a36Sopenharmony_ci#  - client has 1500 byte MTU
30962306a36Sopenharmony_ci#  - server has 1500 byte MTU
31062306a36Sopenharmony_ci#  - use ICMP to ping in each direction
31162306a36Sopenharmony_ci#  - only allow CT state stuff to pass through new in c -> s
31262306a36Sopenharmony_citest_ct_connect_v4 () {
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	which nc >/dev/null 2>/dev/null || return $ksft_skip
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	sbx_add "test_ct_connect_v4" || return $?
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	ovs_add_dp "test_ct_connect_v4" ct4 || return 1
31962306a36Sopenharmony_ci	info "create namespaces"
32062306a36Sopenharmony_ci	for ns in client server; do
32162306a36Sopenharmony_ci		ovs_add_netns_and_veths "test_ct_connect_v4" "ct4" "$ns" \
32262306a36Sopenharmony_ci		    "${ns:0:1}0" "${ns:0:1}1" || return 1
32362306a36Sopenharmony_ci	done
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	ip netns exec client ip addr add 172.31.110.10/24 dev c1
32662306a36Sopenharmony_ci	ip netns exec client ip link set c1 up
32762306a36Sopenharmony_ci	ip netns exec server ip addr add 172.31.110.20/24 dev s1
32862306a36Sopenharmony_ci	ip netns exec server ip link set s1 up
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	# Add forwarding for ARP and ip packets - completely wildcarded
33162306a36Sopenharmony_ci	ovs_add_flow "test_ct_connect_v4" ct4 \
33262306a36Sopenharmony_ci		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
33362306a36Sopenharmony_ci	ovs_add_flow "test_ct_connect_v4" ct4 \
33462306a36Sopenharmony_ci		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
33562306a36Sopenharmony_ci	ovs_add_flow "test_ct_connect_v4" ct4 \
33662306a36Sopenharmony_ci		     'ct_state(-trk),eth(),eth_type(0x0800),ipv4()' \
33762306a36Sopenharmony_ci		     'ct(commit),recirc(0x1)' || return 1
33862306a36Sopenharmony_ci	ovs_add_flow "test_ct_connect_v4" ct4 \
33962306a36Sopenharmony_ci		     'recirc_id(0x1),ct_state(+trk+new),in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10)' \
34062306a36Sopenharmony_ci		     '2' || return 1
34162306a36Sopenharmony_ci	ovs_add_flow "test_ct_connect_v4" ct4 \
34262306a36Sopenharmony_ci		     'recirc_id(0x1),ct_state(+trk+est),in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10)' \
34362306a36Sopenharmony_ci		     '2' || return 1
34462306a36Sopenharmony_ci	ovs_add_flow "test_ct_connect_v4" ct4 \
34562306a36Sopenharmony_ci		     'recirc_id(0x1),ct_state(+trk+est),in_port(2),eth(),eth_type(0x0800),ipv4(dst=172.31.110.10)' \
34662306a36Sopenharmony_ci		     '1' || return 1
34762306a36Sopenharmony_ci	ovs_add_flow "test_ct_connect_v4" ct4 \
34862306a36Sopenharmony_ci		     'recirc_id(0x1),ct_state(+trk+inv),eth(),eth_type(0x0800),ipv4()' 'drop' || \
34962306a36Sopenharmony_ci		     return 1
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	# do a ping
35262306a36Sopenharmony_ci	ovs_sbx "test_ct_connect_v4" ip netns exec client ping 172.31.110.20 -c 3 || return 1
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	# create an echo server in 'server'
35562306a36Sopenharmony_ci	echo "server" | \
35662306a36Sopenharmony_ci		ovs_netns_spawn_daemon "test_ct_connect_v4" "server" \
35762306a36Sopenharmony_ci				nc -lvnp 4443
35862306a36Sopenharmony_ci	ovs_sbx "test_ct_connect_v4" ip netns exec client nc -i 1 -zv 172.31.110.20 4443 || return 1
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	# Now test in the other direction (should fail)
36162306a36Sopenharmony_ci	echo "client" | \
36262306a36Sopenharmony_ci		ovs_netns_spawn_daemon "test_ct_connect_v4" "client" \
36362306a36Sopenharmony_ci				nc -lvnp 4443
36462306a36Sopenharmony_ci	ovs_sbx "test_ct_connect_v4" ip netns exec client nc -i 1 -zv 172.31.110.10 4443
36562306a36Sopenharmony_ci	if [ $? == 0 ]; then
36662306a36Sopenharmony_ci	   info "ct connect to client was successful"
36762306a36Sopenharmony_ci	   return 1
36862306a36Sopenharmony_ci	fi
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	info "done..."
37162306a36Sopenharmony_ci	return 0
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci# connect_v4 test
37562306a36Sopenharmony_ci#  - client has 1500 byte MTU
37662306a36Sopenharmony_ci#  - server has 1500 byte MTU
37762306a36Sopenharmony_ci#  - use ICMP to ping in each direction
37862306a36Sopenharmony_citest_connect_v4 () {
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	sbx_add "test_connect_v4" || return $?
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	ovs_add_dp "test_connect_v4" cv4 || return 1
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	info "create namespaces"
38562306a36Sopenharmony_ci	for ns in client server; do
38662306a36Sopenharmony_ci		ovs_add_netns_and_veths "test_connect_v4" "cv4" "$ns" \
38762306a36Sopenharmony_ci		    "${ns:0:1}0" "${ns:0:1}1" || return 1
38862306a36Sopenharmony_ci	done
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	ip netns exec client ip addr add 172.31.110.10/24 dev c1
39262306a36Sopenharmony_ci	ip netns exec client ip link set c1 up
39362306a36Sopenharmony_ci	ip netns exec server ip addr add 172.31.110.20/24 dev s1
39462306a36Sopenharmony_ci	ip netns exec server ip link set s1 up
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	# Add forwarding for ARP and ip packets - completely wildcarded
39762306a36Sopenharmony_ci	ovs_add_flow "test_connect_v4" cv4 \
39862306a36Sopenharmony_ci		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
39962306a36Sopenharmony_ci	ovs_add_flow "test_connect_v4" cv4 \
40062306a36Sopenharmony_ci		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
40162306a36Sopenharmony_ci	ovs_add_flow "test_connect_v4" cv4 \
40262306a36Sopenharmony_ci		'in_port(1),eth(),eth_type(0x0800),ipv4(src=172.31.110.10)' '2' || return 1
40362306a36Sopenharmony_ci	ovs_add_flow "test_connect_v4" cv4 \
40462306a36Sopenharmony_ci		'in_port(2),eth(),eth_type(0x0800),ipv4(src=172.31.110.20)' '1' || return 1
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	# do a ping
40762306a36Sopenharmony_ci	ovs_sbx "test_connect_v4" ip netns exec client ping 172.31.110.20 -c 3 || return 1
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	info "done..."
41062306a36Sopenharmony_ci	return 0
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci# nat_connect_v4 test
41462306a36Sopenharmony_ci#  - client has 1500 byte MTU
41562306a36Sopenharmony_ci#  - server has 1500 byte MTU
41662306a36Sopenharmony_ci#  - use ICMP to ping in each direction
41762306a36Sopenharmony_ci#  - only allow CT state stuff to pass through new in c -> s
41862306a36Sopenharmony_citest_nat_connect_v4 () {
41962306a36Sopenharmony_ci	which nc >/dev/null 2>/dev/null || return $ksft_skip
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	sbx_add "test_nat_connect_v4" || return $?
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	ovs_add_dp "test_nat_connect_v4" nat4 || return 1
42462306a36Sopenharmony_ci	info "create namespaces"
42562306a36Sopenharmony_ci	for ns in client server; do
42662306a36Sopenharmony_ci		ovs_add_netns_and_veths "test_nat_connect_v4" "nat4" "$ns" \
42762306a36Sopenharmony_ci		    "${ns:0:1}0" "${ns:0:1}1" || return 1
42862306a36Sopenharmony_ci	done
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	ip netns exec client ip addr add 172.31.110.10/24 dev c1
43162306a36Sopenharmony_ci	ip netns exec client ip link set c1 up
43262306a36Sopenharmony_ci	ip netns exec server ip addr add 172.31.110.20/24 dev s1
43362306a36Sopenharmony_ci	ip netns exec server ip link set s1 up
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	ip netns exec client ip route add default via 172.31.110.20
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	ovs_add_flow "test_nat_connect_v4" nat4 \
43862306a36Sopenharmony_ci		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
43962306a36Sopenharmony_ci	ovs_add_flow "test_nat_connect_v4" nat4 \
44062306a36Sopenharmony_ci		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
44162306a36Sopenharmony_ci	ovs_add_flow "test_nat_connect_v4" nat4 \
44262306a36Sopenharmony_ci		"ct_state(-trk),in_port(1),eth(),eth_type(0x0800),ipv4(dst=192.168.0.20)" \
44362306a36Sopenharmony_ci		"ct(commit,nat(dst=172.31.110.20)),recirc(0x1)"
44462306a36Sopenharmony_ci	ovs_add_flow "test_nat_connect_v4" nat4 \
44562306a36Sopenharmony_ci		"ct_state(-trk),in_port(2),eth(),eth_type(0x0800),ipv4()" \
44662306a36Sopenharmony_ci		"ct(commit,nat),recirc(0x2)"
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	ovs_add_flow "test_nat_connect_v4" nat4 \
44962306a36Sopenharmony_ci		"recirc_id(0x1),ct_state(+trk-inv),in_port(1),eth(),eth_type(0x0800),ipv4()" "2"
45062306a36Sopenharmony_ci	ovs_add_flow "test_nat_connect_v4" nat4 \
45162306a36Sopenharmony_ci		"recirc_id(0x2),ct_state(+trk-inv),in_port(2),eth(),eth_type(0x0800),ipv4()" "1"
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	# do a ping
45462306a36Sopenharmony_ci	ovs_sbx "test_nat_connect_v4" ip netns exec client ping 192.168.0.20 -c 3 || return 1
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	# create an echo server in 'server'
45762306a36Sopenharmony_ci	echo "server" | \
45862306a36Sopenharmony_ci		ovs_netns_spawn_daemon "test_nat_connect_v4" "server" \
45962306a36Sopenharmony_ci				nc -lvnp 4443
46062306a36Sopenharmony_ci	ovs_sbx "test_nat_connect_v4" ip netns exec client nc -i 1 -zv 192.168.0.20 4443 || return 1
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	# Now test in the other direction (should fail)
46362306a36Sopenharmony_ci	echo "client" | \
46462306a36Sopenharmony_ci		ovs_netns_spawn_daemon "test_nat_connect_v4" "client" \
46562306a36Sopenharmony_ci				nc -lvnp 4443
46662306a36Sopenharmony_ci	ovs_sbx "test_nat_connect_v4" ip netns exec client nc -i 1 -zv 172.31.110.10 4443
46762306a36Sopenharmony_ci	if [ $? == 0 ]; then
46862306a36Sopenharmony_ci	   info "connect to client was successful"
46962306a36Sopenharmony_ci	   return 1
47062306a36Sopenharmony_ci	fi
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	info "done..."
47362306a36Sopenharmony_ci	return 0
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci# netlink_validation
47762306a36Sopenharmony_ci# - Create a dp
47862306a36Sopenharmony_ci# - check no warning with "old version" simulation
47962306a36Sopenharmony_citest_netlink_checks () {
48062306a36Sopenharmony_ci	sbx_add "test_netlink_checks" || return 1
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	info "setting up new DP"
48362306a36Sopenharmony_ci	ovs_add_dp "test_netlink_checks" nv0 || return 1
48462306a36Sopenharmony_ci	# now try again
48562306a36Sopenharmony_ci	PRE_TEST=$(dmesg | grep -E "RIP: [0-9a-fA-Fx]+:ovs_dp_cmd_new\+")
48662306a36Sopenharmony_ci	ovs_add_dp "test_netlink_checks" nv0 -V 0 || return 1
48762306a36Sopenharmony_ci	POST_TEST=$(dmesg | grep -E "RIP: [0-9a-fA-Fx]+:ovs_dp_cmd_new\+")
48862306a36Sopenharmony_ci	if [ "$PRE_TEST" != "$POST_TEST" ]; then
48962306a36Sopenharmony_ci		info "failed - gen warning"
49062306a36Sopenharmony_ci		return 1
49162306a36Sopenharmony_ci	fi
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	ovs_add_netns_and_veths "test_netlink_checks" nv0 left left0 l0 || \
49462306a36Sopenharmony_ci	    return 1
49562306a36Sopenharmony_ci	ovs_add_netns_and_veths "test_netlink_checks" nv0 right right0 r0 || \
49662306a36Sopenharmony_ci	    return 1
49762306a36Sopenharmony_ci	[ $(python3 $ovs_base/ovs-dpctl.py show nv0 | grep port | \
49862306a36Sopenharmony_ci	    wc -l) == 3 ] || \
49962306a36Sopenharmony_ci	      return 1
50062306a36Sopenharmony_ci	ovs_del_if "test_netlink_checks" nv0 right0 || return 1
50162306a36Sopenharmony_ci	[ $(python3 $ovs_base/ovs-dpctl.py show nv0 | grep port | \
50262306a36Sopenharmony_ci	    wc -l) == 2 ] || \
50362306a36Sopenharmony_ci	      return 1
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	info "Checking clone depth"
50662306a36Sopenharmony_ci	ERR_MSG="Flow actions may not be safe on all matching packets"
50762306a36Sopenharmony_ci	PRE_TEST=$(dmesg | grep -c "${ERR_MSG}")
50862306a36Sopenharmony_ci	ovs_add_flow "test_netlink_checks" nv0 \
50962306a36Sopenharmony_ci		'in_port(1),eth(),eth_type(0x800),ipv4()' \
51062306a36Sopenharmony_ci		'clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(drop)))))))))))))))))' \
51162306a36Sopenharmony_ci		>/dev/null 2>&1 && return 1
51262306a36Sopenharmony_ci	POST_TEST=$(dmesg | grep -c "${ERR_MSG}")
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	if [ "$PRE_TEST" == "$POST_TEST" ]; then
51562306a36Sopenharmony_ci		info "failed - clone depth too large"
51662306a36Sopenharmony_ci		return 1
51762306a36Sopenharmony_ci	fi
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	PRE_TEST=$(dmesg | grep -c "${ERR_MSG}")
52062306a36Sopenharmony_ci	ovs_add_flow "test_netlink_checks" nv0 \
52162306a36Sopenharmony_ci		'in_port(1),eth(),eth_type(0x0806),arp()' 'drop(0),2' \
52262306a36Sopenharmony_ci		&> /dev/null && return 1
52362306a36Sopenharmony_ci	POST_TEST=$(dmesg | grep -c "${ERR_MSG}")
52462306a36Sopenharmony_ci	if [ "$PRE_TEST" == "$POST_TEST" ]; then
52562306a36Sopenharmony_ci		info "failed - error not generated"
52662306a36Sopenharmony_ci		return 1
52762306a36Sopenharmony_ci	fi
52862306a36Sopenharmony_ci	return 0
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_citest_upcall_interfaces() {
53262306a36Sopenharmony_ci	sbx_add "test_upcall_interfaces" || return 1
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	info "setting up new DP"
53562306a36Sopenharmony_ci	ovs_add_dp "test_upcall_interfaces" ui0 -V 2:1 || return 1
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	ovs_add_netns_and_veths "test_upcall_interfaces" ui0 upc left0 l0 \
53862306a36Sopenharmony_ci	    172.31.110.1/24 -u || return 1
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	sleep 1
54162306a36Sopenharmony_ci	info "sending arping"
54262306a36Sopenharmony_ci	ip netns exec upc arping -I l0 172.31.110.20 -c 1 \
54362306a36Sopenharmony_ci	    >$ovs_dir/arping.stdout 2>$ovs_dir/arping.stderr
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	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
54662306a36Sopenharmony_ci	return 0
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_cirun_test() {
55062306a36Sopenharmony_ci	(
55162306a36Sopenharmony_ci	tname="$1"
55262306a36Sopenharmony_ci	tdesc="$2"
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	if ! lsmod | grep openvswitch >/dev/null 2>&1; then
55562306a36Sopenharmony_ci		stdbuf -o0 printf "TEST: %-60s  [NOMOD]\n" "${tdesc}"
55662306a36Sopenharmony_ci		return $ksft_skip
55762306a36Sopenharmony_ci	fi
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	if python3 ovs-dpctl.py -h 2>&1 | \
56062306a36Sopenharmony_ci	     grep -E "Need to (install|upgrade) the python" >/dev/null 2>&1; then
56162306a36Sopenharmony_ci		stdbuf -o0 printf "TEST: %-60s  [PYLIB]\n" "${tdesc}"
56262306a36Sopenharmony_ci		return $ksft_skip
56362306a36Sopenharmony_ci	fi
56462306a36Sopenharmony_ci	printf "TEST: %-60s  [START]\n" "${tname}"
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	unset IFS
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	eval test_${tname}
56962306a36Sopenharmony_ci	ret=$?
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	if [ $ret -eq 0 ]; then
57262306a36Sopenharmony_ci		printf "TEST: %-60s  [ OK ]\n" "${tdesc}"
57362306a36Sopenharmony_ci		ovs_exit_sig
57462306a36Sopenharmony_ci		rm -rf "$ovs_dir"
57562306a36Sopenharmony_ci	elif [ $ret -eq 1 ]; then
57662306a36Sopenharmony_ci		printf "TEST: %-60s  [FAIL]\n" "${tdesc}"
57762306a36Sopenharmony_ci		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
57862306a36Sopenharmony_ci			echo
57962306a36Sopenharmony_ci			echo "Pausing. Logs in $ovs_dir/. Hit enter to continue"
58062306a36Sopenharmony_ci			read a
58162306a36Sopenharmony_ci		fi
58262306a36Sopenharmony_ci		ovs_exit_sig
58362306a36Sopenharmony_ci		[ "${PAUSE_ON_FAIL}" = "yes" ] || rm -rf "$ovs_dir"
58462306a36Sopenharmony_ci		exit 1
58562306a36Sopenharmony_ci	elif [ $ret -eq $ksft_skip ]; then
58662306a36Sopenharmony_ci		printf "TEST: %-60s  [SKIP]\n" "${tdesc}"
58762306a36Sopenharmony_ci	elif [ $ret -eq 2 ]; then
58862306a36Sopenharmony_ci		rm -rf test_${tname}
58962306a36Sopenharmony_ci		run_test "$1" "$2"
59062306a36Sopenharmony_ci	fi
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	return $ret
59362306a36Sopenharmony_ci	)
59462306a36Sopenharmony_ci	ret=$?
59562306a36Sopenharmony_ci	case $ret in
59662306a36Sopenharmony_ci		0)
59762306a36Sopenharmony_ci			[ $all_skipped = true ] && [ $exitcode=$ksft_skip ] && exitcode=0
59862306a36Sopenharmony_ci			all_skipped=false
59962306a36Sopenharmony_ci		;;
60062306a36Sopenharmony_ci		$ksft_skip)
60162306a36Sopenharmony_ci			[ $all_skipped = true ] && exitcode=$ksft_skip
60262306a36Sopenharmony_ci		;;
60362306a36Sopenharmony_ci		*)
60462306a36Sopenharmony_ci			all_skipped=false
60562306a36Sopenharmony_ci			exitcode=1
60662306a36Sopenharmony_ci		;;
60762306a36Sopenharmony_ci	esac
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	return $ret
61062306a36Sopenharmony_ci}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ciexitcode=0
61462306a36Sopenharmony_cidesc=0
61562306a36Sopenharmony_ciall_skipped=true
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ciwhile getopts :pvt o
61862306a36Sopenharmony_cido
61962306a36Sopenharmony_ci	case $o in
62062306a36Sopenharmony_ci	p) PAUSE_ON_FAIL=yes;;
62162306a36Sopenharmony_ci	v) VERBOSE=1;;
62262306a36Sopenharmony_ci	t) if which tcpdump > /dev/null 2>&1; then
62362306a36Sopenharmony_ci		TRACING=1
62462306a36Sopenharmony_ci	   else
62562306a36Sopenharmony_ci		echo "=== tcpdump not available, tracing disabled"
62662306a36Sopenharmony_ci	   fi
62762306a36Sopenharmony_ci	   ;;
62862306a36Sopenharmony_ci	*) usage;;
62962306a36Sopenharmony_ci	esac
63062306a36Sopenharmony_cidone
63162306a36Sopenharmony_cishift $(($OPTIND-1))
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ciIFS="	
63462306a36Sopenharmony_ci"
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cifor arg do
63762306a36Sopenharmony_ci	# Check first that all requested tests are available before running any
63862306a36Sopenharmony_ci	command -v > /dev/null "test_${arg}" || { echo "=== Test ${arg} not found"; usage; }
63962306a36Sopenharmony_cidone
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ciname=""
64262306a36Sopenharmony_cidesc=""
64362306a36Sopenharmony_cifor t in ${tests}; do
64462306a36Sopenharmony_ci	[ "${name}" = "" ]	&& name="${t}"	&& continue
64562306a36Sopenharmony_ci	[ "${desc}" = "" ]	&& desc="${t}"
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	run_this=1
64862306a36Sopenharmony_ci	for arg do
64962306a36Sopenharmony_ci		[ "${arg}" != "${arg#--*}" ] && continue
65062306a36Sopenharmony_ci		[ "${arg}" = "${name}" ] && run_this=1 && break
65162306a36Sopenharmony_ci		run_this=0
65262306a36Sopenharmony_ci	done
65362306a36Sopenharmony_ci	if [ $run_this -eq 1 ]; then
65462306a36Sopenharmony_ci		run_test "${name}" "${desc}"
65562306a36Sopenharmony_ci	fi
65662306a36Sopenharmony_ci	name=""
65762306a36Sopenharmony_ci	desc=""
65862306a36Sopenharmony_cidone
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ciexit ${exitcode}
661