1493 lines · 45.2 KB · Shell
RawDownload
#!/bin/bash# SPDX-License-Identifier: GPL-2.0## OVS kernel module self tests trap ovs_exit_sig EXIT TERM INT ERR # Kselftest framework requirement - SKIP code is 4.ksft_skip=4 PAUSE_ON_FAIL=noVERBOSE=0TRACING=0WAIT_TIMEOUT=5 if test "X$KSFT_MACHINE_SLOW" == "Xyes"; then	WAIT_TIMEOUT=10fi tests="	arp_ping				eth-arp: Basic arp ping between two NS	ct_connect_v4				ip4-ct-xon: Basic ipv4 tcp connection using ct	connect_v4				ip4-xon: Basic ipv4 ping between two NS	nat_connect_v4				ip4-nat-xon: Basic ipv4 tcp connection via NAT	nat_related_v4				ip4-nat-related: ICMP related matches work with SNAT	netlink_checks				ovsnl: validate netlink attrs and settings	upcall_interfaces			ovs: test the upcall interfaces	tunnel_metadata				ovs: test extraction of tunnel metadata	drop_reason				drop: test drop reasons are emitted	pop_vlan				vlan: POP_VLAN action strips tag	dec_ttl					ttl: dec_ttl decrements IP TTL	flow_set				flow-set: Flow modify	action_set				set: SET action rewrites fields	trunc					trunc: output truncation	icmpv6					icmpv6: ICMPv6 echo type match	sctp_connect_v4				sctp: SCTP flow key matching	psample					psample: Sampling packets with psample" info() {	[ "${ovs_dir}" != "" ] &&		echo "`date +"[%m-%d %H:%M:%S]"` $*" >> ${ovs_dir}/debug.log	[ $VERBOSE = 0 ] || echo $*} ovs_wait() {	info "waiting $WAIT_TIMEOUT s for: $@" 	if "$@" ; then		info "wait succeeded immediately"		return 0	fi 	# A quick re-check helps speed up small races in fast systems.	# However, fractional sleeps might not necessarily work.	local start=0	sleep 0.1 || { sleep 1; start=1; } 	for (( i=start; i<WAIT_TIMEOUT; i++ )); do		if "$@" ; then			info "wait succeeded after $i seconds"			return 0		fi		sleep 1	done	info "wait failed after $i seconds"	return 1} ovs_base=`pwd`sbxs=sbx_add () {	info "adding sandbox '$1'" 	sbxs="$sbxs $1" 	NO_BIN=0 	# Create sandbox.	local d="$ovs_base"/$1	if [ -e $d ]; then		info "removing $d"		rm -rf "$d"	fi	mkdir "$d" || return 1	ovs_setenv $1} ovs_exit_sig() {	[ -e ${ovs_dir}/cleanup ] && . "$ovs_dir/cleanup"} on_exit() {	echo "$1" > ${ovs_dir}/cleanup.tmp	cat ${ovs_dir}/cleanup >> ${ovs_dir}/cleanup.tmp	mv ${ovs_dir}/cleanup.tmp ${ovs_dir}/cleanup} ovs_setenv() {	sandbox=$1 	ovs_dir=$ovs_base${1:+/$1}; export ovs_dir 	test -e ${ovs_dir}/cleanup || : > ${ovs_dir}/cleanup} ovs_sbx() {	if test "X$2" != X; then		(ovs_setenv $1; shift;		 info "run cmd: $@"; "$@" >> ${ovs_dir}/debug.log)	else		ovs_setenv $1	fi} ovs_add_dp () {	info "Adding DP/Bridge IF: sbx:$1 dp:$2 {$3, $4, $5}"	sbxname="$1"	shift	ovs_sbx "$sbxname" python3 $ovs_base/ovs-dpctl.py add-dp $*	on_exit "ovs_sbx $sbxname python3 $ovs_base/ovs-dpctl.py del-dp $1;"} ovs_add_if () {	info "Adding IF to DP: br:$3 if:$4 ($2)"	if [ "$5" != "-u" ]; then		ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py add-if \		    -t "$2" "$3" "$4" || return 1	else		python3 $ovs_base/ovs-dpctl.py add-if \		    -u -t "$2" "$3" "$4" >$ovs_dir/$4.out 2>$ovs_dir/$4.err &		pid=$!		on_exit "ovs_sbx $1 kill -TERM $pid 2>/dev/null"	fi} ovs_del_if () {	info "Deleting IF from DP: br:$2 if:$3"	ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py del-if "$2" "$3" || return 1} ovs_netns_spawn_daemon() {	sbx=$1	shift	netns=$1	shift	if [ "$netns" == "_default" ]; then		$*  >> $ovs_dir/stdout  2>> $ovs_dir/stderr &	else		ip netns exec $netns $*  >> $ovs_dir/stdout  2>> $ovs_dir/stderr &	fi	pid=$!	ovs_sbx "$sbx" on_exit "kill -TERM $pid 2>/dev/null"} ovs_spawn_daemon() {	sbx=$1	shift	ovs_netns_spawn_daemon $sbx "_default" $*} ovs_add_netns_and_veths () {	info "Adding netns attached: sbx:$1 dp:$2 {$3, $4, $5}"	ovs_sbx "$1" ip netns add "$3" || return 1	on_exit "ovs_sbx $1 ip netns del $3"	ovs_sbx "$1" ip link add "$4" type veth peer name "$5" || return 1	on_exit "ovs_sbx $1 ip link del $4 >/dev/null 2>&1"	ovs_sbx "$1" ip link set "$4" up || return 1	ovs_sbx "$1" ip link set "$5" netns "$3" || return 1	ovs_sbx "$1" ip netns exec "$3" ip link set "$5" up || return 1 	if [ "$6" != "" ]; then		ovs_sbx "$1" ip netns exec "$3" ip addr add "$6" dev "$5" \		    || return 1	fi 	if [ "$7" != "-u" ]; then		ovs_add_if "$1" "netdev" "$2" "$4" || return 1	else		ovs_add_if "$1" "netdev" "$2" "$4" -u || return 1	fi 	if [ $TRACING -eq 1 ]; then		ovs_netns_spawn_daemon "$1" "$3" tcpdump -l -i any -s 6553		ovs_wait grep -q "listening on any" ${ovs_dir}/stderr	fi 	return 0} ovs_add_flow () {	info "Adding flow to DP: sbx:$1 br:$2 flow:$3 act:$4"	ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py add-flow "$2" "$3" "$4"	if [ $? -ne 0 ]; then		info "Flow [ $3 : $4 ] failed"		return 1	fi	return 0} ovs_mod_flow () {	if [ -n "$4" ]; then		info "Modifying flow: sbx:$1 br:$2 flow:$3 act:$4"		ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py \			mod-flow "$2" "$3" "$4"	else		info "Modifying flow (no actions): sbx:$1 br:$2 flow:$3"		ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py \			mod-flow "$2" "$3"	fi	if [ $? -ne 0 ]; then		info "Flow modify [ $3 ] failed"		return 1	fi	return 0} ovs_del_flows () {	info "Deleting all flows from DP: sbx:$1 br:$2"	ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py del-flows "$2"	return 0} ovs_drop_record_and_run () {	local sbx=$1	shift 	perf record -a -q -e skb:kfree_skb -o ${ovs_dir}/perf.data $* \		>> ${ovs_dir}/stdout 2>> ${ovs_dir}/stderr	return $?} ovs_drop_reason_count(){	local reason=$1 	local perf_output=`perf script -i ${ovs_dir}/perf.data -F trace:event,trace`	local pattern="skb:kfree_skb:.*reason: $reason" 	return `echo "$perf_output" | grep "$pattern" | wc -l`} ovs_test_flow_fails () {	ERR_MSG="Flow actions may not be safe on all matching packets" 	PRE_TEST=$(dmesg | grep -c "${ERR_MSG}")	ovs_add_flow $@ &> /dev/null $@ && return 1	POST_TEST=$(dmesg | grep -c "${ERR_MSG}") 	if [ "$PRE_TEST" == "$POST_TEST" ]; then		return 1	fi	return 0} usage() {	echo	echo "$0 [OPTIONS] [TEST]..."	echo "If no TEST argument is given, all tests will be run."	echo	echo "Options"	echo "  -t: capture traffic via tcpdump"	echo "  -v: verbose"	echo "  -p: pause on failure"	echo	echo "Available tests${tests}"	exit 1}  test_dec_ttl() {	sbx_add "test_dec_ttl" || return $?	ovs_add_dp "test_dec_ttl" decttl || return 1 	info "create namespaces"	for ns in client server; do		ovs_add_netns_and_veths "test_dec_ttl" "decttl" "$ns" \			"${ns:0:1}0" "${ns:0:1}1" || return 1	done 	ip netns exec client ip addr add 10.0.0.1/24 dev c1	ip netns exec client ip link set c1 up	ip netns exec server ip addr add 10.0.0.2/24 dev s1	ip netns exec server ip link set s1 up 	# Probe: check if kernel supports dec_ttl action.	ovs_add_flow "test_dec_ttl" decttl \		'in_port(1),eth(),eth_type(0x0800),ipv4()' \		'dec_ttl(le_1())' &>/dev/null	if [ $? -ne 0 ]; then		info "no support for dec_ttl - skipping"		ovs_exit_sig		return $ksft_skip	fi 	ovs_del_flows "test_dec_ttl" decttl 	# ARP flows (bidirectional)	ovs_add_flow "test_dec_ttl" decttl \		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1	ovs_add_flow "test_dec_ttl" decttl \		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1 	# IP flows with dec_ttl action	ovs_add_flow "test_dec_ttl" decttl \		'in_port(1),eth(),eth_type(0x0800),ipv4()' \		'dec_ttl(le_1()),2' || return 1	ovs_add_flow "test_dec_ttl" decttl \		'in_port(2),eth(),eth_type(0x0800),ipv4()' \		'dec_ttl(le_1()),1' || return 1 	info "verify connectivity with dec_ttl"	ovs_sbx "test_dec_ttl" ip netns exec client ping -c 1 -W 2 \		10.0.0.2 || return 1 	info "verify TTL=1 is dropped by dec_ttl"	ovs_sbx "test_dec_ttl" ip netns exec client ping -c 1 -W 2 \		-t 1 10.0.0.2 >/dev/null 2>&1 \		&& { info "FAIL: ping should fail with TTL=1 and dec_ttl"		     return 1; } 	return 0} test_flow_set() {	sbx_add "test_flow_set" || return $?	ovs_add_dp "test_flow_set" flowset || return 1 	info "create namespaces"	for ns in client server; do		ovs_add_netns_and_veths "test_flow_set" "flowset" "$ns" \			"${ns:0:1}0" "${ns:0:1}1" || return 1	done 	ip netns exec client ip addr add 10.0.0.1/24 dev c1	ip netns exec client ip link set c1 up	ip netns exec server ip addr add 10.0.0.2/24 dev s1	ip netns exec server ip link set s1 up 	ovs_add_flow "test_flow_set" flowset \		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1	ovs_add_flow "test_flow_set" flowset \		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1 	local fwd_flow="ufid:00000001-0002-0003-0004-000500060007"	fwd_flow="$fwd_flow,in_port(1),eth(),eth_type(0x0800),ipv4()" 	ovs_add_flow "test_flow_set" flowset "$fwd_flow" '2' \		|| return 1	ovs_add_flow "test_flow_set" flowset \		'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1 	info "verify initial forwarding"	ovs_sbx "test_flow_set" ip netns exec client ping -c 1 -W 2 \		10.0.0.2 || return 1 	info "mod-flow with new actions (change to drop)"	ovs_mod_flow "test_flow_set" flowset "$fwd_flow" 'drop' \		|| return 1 	info "verify traffic is now dropped"	ovs_sbx "test_flow_set" ip netns exec client ping -c 1 -W 2 \		10.0.0.2 >/dev/null 2>&1 \		&& { info "FAIL: ping should fail after mod-flow to drop"		     return 1; } 	info "mod-flow without actions"	ovs_mod_flow "test_flow_set" flowset "$fwd_flow" || return 1 	info "verify flow retained drop action via dump"	python3 "$ovs_base/ovs-dpctl.py" dump-flows flowset \		| grep -q "actions:drop" || \		{ info "FAIL: flow not showing drop action"; return 1; } 	info "verify drop actions unchanged"	ovs_sbx "test_flow_set" ip netns exec client ping -c 1 -W 2 \		10.0.0.2 >/dev/null 2>&1 \		&& { info "FAIL: ping should still fail after no-actions set"		     return 1; } 	return 0} test_action_set() {	sbx_add "test_action_set" || return $?	ovs_add_dp "test_action_set" settest || return 1 	info "create namespaces"	for ns in client server; do		ovs_add_netns_and_veths "test_action_set" "settest" "$ns" \			"${ns:0:1}0" "${ns:0:1}1" || return 1	done 	ip netns exec client ip addr add 10.0.0.1/24 dev c1	ip netns exec client ip link set c1 up	ip netns exec server ip addr add 10.0.0.2/24 dev s1	ip netns exec server ip link set s1 up 	ovs_add_flow "test_action_set" settest \		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1	ovs_add_flow "test_action_set" settest \		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1 	ovs_add_flow "test_action_set" settest \		'in_port(1),eth(),eth_type(0x0800),ipv4()' '2' || return 1	ovs_add_flow "test_action_set" settest \		'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1 	info "verify connectivity without SET"	ovs_sbx "test_action_set" ip netns exec client ping -c 1 -W 2 \		10.0.0.2 || return 1 	ovs_del_flows "test_action_set" settest	ovs_add_flow "test_action_set" settest \		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1	ovs_add_flow "test_action_set" settest \		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1 	info "set ipv4 dst to unreachable address"	ovs_add_flow "test_action_set" settest \		'in_port(1),eth(),eth_type(0x0800),ipv4()' \		'set(ipv4(dst=10.0.0.99)),2' || return 1	ovs_add_flow "test_action_set" settest \		'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1 	info "verify ping fails with rewritten dst"	ovs_sbx "test_action_set" ip netns exec client ping -c 1 -W 2 \		10.0.0.2 >/dev/null 2>&1 \		&& { info "FAIL: ping should fail with dst rewritten"		     return 1; } 	ovs_del_flows "test_action_set" settest	ovs_add_flow "test_action_set" settest \		'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1	ovs_add_flow "test_action_set" settest \		'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1	ovs_add_flow "test_action_set" settest \		'in_port(1),eth(),eth_type(0x0800),ipv4()' '2' || return 1	ovs_add_flow "test_action_set" settest \		'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1 	info "verify connectivity restored without SET"	ovs_sbx "test_action_set" ip netns exec client ping -c 1 -W 2 \		10.0.0.2 || return 1 	return 0} # trunc test# - trunc(14): truncate to ETH_HLEN, strips IP payload, ping fails# - trunc(1) and trunc(13): kernel rejects below ETH_HLEN (EINVAL)# - restore normal forwarding and verify recoverytest_trunc() {	sbx_add "test_trunc" || return $?	ovs_add_dp "test_trunc" trunctest || return 1 	info "create namespaces"	for ns in client server; do		ovs_add_netns_and_veths "test_trunc" "trunctest" \		    "$ns" "${ns:0:1}0" "${ns:0:1}1" || return 1	done 	ip netns exec client ip addr add 10.0.0.1/24 dev c1	ip netns exec client ip link set c1 up	ip netns exec server ip addr add 10.0.0.2/24 dev s1	ip netns exec server ip link set s1 up 	ovs_add_flow "test_trunc" trunctest \	    'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1	ovs_add_flow "test_trunc" trunctest \	    'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1	ovs_add_flow "test_trunc" trunctest \	    'in_port(1),eth(),eth_type(0x0800),ipv4()' \	    '2' || return 1	ovs_add_flow "test_trunc" trunctest \	    'in_port(2),eth(),eth_type(0x0800),ipv4()' \	    '1' || return 1 	info "verify connectivity without truncation"	ovs_sbx "test_trunc" ip netns exec client \	    ping -c 1 -W 2 10.0.0.2 || return 1 	# trunc below ETH_HLEN must be rejected by the kernel	info "verify trunc(1) is rejected"	ovs_add_flow "test_trunc" trunctest \	    'in_port(1),eth(),eth_type(0x0800),ipv4()' \	    'trunc(1),2' &> /dev/null \	    && { info "trunc(1) should be rejected"; return 1; } 	info "verify trunc(13) is rejected"	ovs_add_flow "test_trunc" trunctest \	    'in_port(1),eth(),eth_type(0x0800),ipv4()' \	    'trunc(13),2' &> /dev/null \	    && { info "trunc(13) should be rejected"; return 1; } 	ovs_del_flows "test_trunc" trunctest	ovs_add_flow "test_trunc" trunctest \	    'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1	ovs_add_flow "test_trunc" trunctest \	    'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1 

Lines 1–500 of 1493.