Commit 4d0dac49 authored by Willem de Bruijn's avatar Willem de Bruijn Committed by Paolo Abeni
Browse files

selftests/net: test tcp connection load balancing



Verify that TCP connections use both routes when connecting multiple
times to a remote service over a two nexthop multipath route.

Use socat to create the connections. Use tc prio + tc filter to
count routes taken, counting SYN packets across the two egress
devices. Also verify that the saddr matches that of the device.

To avoid flaky tests when testing inherently randomized behavior,
set a low bar and pass if even a single SYN is observed on each
device.

Signed-off-by: default avatarWillem de Bruijn <willemb@google.com>
Reviewed-by: default avatarIdo Schimmel <idosch@nvidia.com>
Tested-by: default avatarIdo Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20250424143549.669426-4-willemdebruijn.kernel@gmail.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 65e90246
Loading
Loading
Loading
Loading
+119 −1
Original line number Diff line number Diff line
@@ -11,7 +11,7 @@ TESTS="unregister down carrier nexthop suppress ipv6_notify ipv4_notify \
       ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric ipv6_route_metrics \
       ipv4_route_metrics ipv4_route_v6_gw rp_filter ipv4_del_addr \
       ipv6_del_addr ipv4_mangle ipv6_mangle ipv4_bcast_neigh fib6_gc_test \
       ipv4_mpath_list ipv6_mpath_list"
       ipv4_mpath_list ipv6_mpath_list ipv4_mpath_balance ipv6_mpath_balance"

VERBOSE=0
PAUSE_ON_FAIL=no
@@ -1085,6 +1085,35 @@ route_setup()
	set +e
}

forwarding_cleanup()
{
	cleanup_ns $ns3

	route_cleanup
}

# extend route_setup with an ns3 reachable through ns2 over both devices
forwarding_setup()
{
	forwarding_cleanup

	route_setup

	setup_ns ns3

	ip link add veth5 netns $ns3 type veth peer name veth6 netns $ns2
	ip -netns $ns3 link set veth5 up
	ip -netns $ns2 link set veth6 up

	ip -netns $ns3 -4 addr add dev veth5 172.16.105.1/24
	ip -netns $ns2 -4 addr add dev veth6 172.16.105.2/24
	ip -netns $ns3 -4 route add 172.16.100.0/22 via 172.16.105.2

	ip -netns $ns3 -6 addr add dev veth5 2001:db8:105::1/64 nodad
	ip -netns $ns2 -6 addr add dev veth6 2001:db8:105::2/64 nodad
	ip -netns $ns3 -6 route add 2001:db8:101::/33 via 2001:db8:105::2
}

# assumption is that basic add of a single path route works
# otherwise just adding an address on an interface is broken
ipv6_rt_add()
@@ -2600,6 +2629,93 @@ ipv6_mpath_list_test()
	route_cleanup
}

tc_set_flower_counter__saddr_syn() {
	tc_set_flower_counter $1 $2 $3 "src_ip $4 ip_proto tcp tcp_flags 0x2"
}

ip_mpath_balance_dep_check()
{
	if [ ! -x "$(command -v socat)" ]; then
		echo "socat command not found. Skipping test"
		return 1
	fi

	if [ ! -x "$(command -v jq)" ]; then
		echo "jq command not found. Skipping test"
		return 1
	fi
}

ip_mpath_balance() {
	local -r ipver=$1
	local -r daddr=$2
	local -r num_conn=20

	for i in $(seq 1 $num_conn); do
		ip netns exec $ns3 socat $ipver TCP-LISTEN:8000 STDIO >/dev/null &
		sleep 0.02
		echo -n a | ip netns exec $ns1 socat $ipver STDIO TCP:$daddr:8000
	done

	local -r syn0="$(tc_get_flower_counter $ns1 veth1)"
	local -r syn1="$(tc_get_flower_counter $ns1 veth3)"
	local -r syns=$((syn0+syn1))

	[ "$VERBOSE" = "1" ] && echo "multipath: syns seen: ($syn0,$syn1)"

	[[ $syns -ge $num_conn ]] && [[ $syn0 -gt 0 ]] && [[ $syn1 -gt 0 ]]
}

ipv4_mpath_balance_test()
{
	echo
	echo "IPv4 multipath load balance test"

	ip_mpath_balance_dep_check || return 1
	forwarding_setup

	$IP route add 172.16.105.1 \
		nexthop via 172.16.101.2 \
		nexthop via 172.16.103.2

	ip netns exec $ns1 \
		sysctl -q -w net.ipv4.fib_multipath_hash_policy=1

	tc_set_flower_counter__saddr_syn $ns1 4 veth1 172.16.101.1
	tc_set_flower_counter__saddr_syn $ns1 4 veth3 172.16.103.1

	ip_mpath_balance -4 172.16.105.1

	log_test $? 0 "IPv4 multipath loadbalance"

	forwarding_cleanup
}

ipv6_mpath_balance_test()
{
	echo
	echo "IPv6 multipath load balance test"

	ip_mpath_balance_dep_check || return 1
	forwarding_setup

	$IP route add 2001:db8:105::1\
		nexthop via 2001:db8:101::2 \
		nexthop via 2001:db8:103::2

	ip netns exec $ns1 \
		sysctl -q -w net.ipv6.fib_multipath_hash_policy=1

	tc_set_flower_counter__saddr_syn $ns1 6 veth1 2001:db8:101::1
	tc_set_flower_counter__saddr_syn $ns1 6 veth3 2001:db8:103::1

	ip_mpath_balance -6 "[2001:db8:105::1]"

	log_test $? 0 "IPv6 multipath loadbalance"

	forwarding_cleanup
}

################################################################################
# usage

@@ -2683,6 +2799,8 @@ do
	fib6_gc_test|ipv6_gc)		fib6_gc_test;;
	ipv4_mpath_list)		ipv4_mpath_list_test;;
	ipv6_mpath_list)		ipv6_mpath_list_test;;
	ipv4_mpath_balance)		ipv4_mpath_balance_test;;
	ipv6_mpath_balance)		ipv6_mpath_balance_test;;

	help) echo "Test names: $TESTS"; exit 0;;
	esac
+24 −0
Original line number Diff line number Diff line
@@ -270,6 +270,30 @@ tc_rule_handle_stats_get()
		  .options.actions[0].stats$selector"
}

# attach a qdisc with two children match/no-match and a flower filter to match
tc_set_flower_counter() {
	local -r ns=$1
	local -r ipver=$2
	local -r dev=$3
	local -r flower_expr=$4

	tc -n $ns qdisc add dev $dev root handle 1: prio bands 2 \
			priomap 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

	tc -n $ns qdisc add dev $dev parent 1:1 handle 11: pfifo
	tc -n $ns qdisc add dev $dev parent 1:2 handle 12: pfifo

	tc -n $ns filter add dev $dev parent 1: protocol ipv$ipver \
			flower $flower_expr classid 1:2
}

tc_get_flower_counter() {
	local -r ns=$1
	local -r dev=$2

	tc -n $ns -j -s qdisc show dev $dev handle 12: | jq .[0].packets
}

ret_set_ksft_status()
{
	local ksft_status=$1; shift