Commit c4154cff authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'selftests-Add-ethtool-and-scale-tests'

Ido Schimmel says:

====================
selftests: Add ethtool and scale tests

This patch set adds generic ethtool tests and a mlxsw-specific router
scale test for Spectrum-2.

Patches #1-#2 from Danielle add the router scale test for Spectrum-2. It
re-uses the same test as Spectrum-1, but it is invoked with a different
scale, according to what it is queried from devlink-resource.

Patches #3-#5 from Amit are a re-work of the ethtool tests that were
posted in the past [1]. Patches #3-#4 add the necessary library
routines, whereas patch #5 adds the test itself. The test checks both
good and bad flows with autoneg on and off. The test plan it detailed in
the commit message.

Last time Andrew and Florian (copied) provided very useful feedback that
is incorporated in this set. Namely:

* Parse the value of the different link modes from
  /usr/include/linux/ethtool.h
* Differentiate between supported and advertised speeds and use the
  latter in autoneg tests
* Make the test generic and move it to net/forwarding/ instead of being
  mlxsw-specific

[1] https://patchwork.ozlabs.org/cover/1112903/


====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 6960f7e3 64916b57
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -8,6 +8,11 @@ source $lib_dir/lib.sh
source $lib_dir/tc_common.sh
source $lib_dir/devlink_lib.sh

if [ "$DEVLINK_VIDDID" != "15b3:cf6c" ]; then
	echo "SKIP: test is tailored for Mellanox Spectrum-2"
	exit 1
fi

current_test=""

cleanup()
@@ -16,11 +21,13 @@ cleanup()
	if [ ! -z $current_test ]; then
		${current_test}_cleanup
	fi
	# Need to reload in order to avoid router abort.
	devlink_reload
}

trap cleanup EXIT

ALL_TESTS="tc_flower mirror_gre"
ALL_TESTS="router tc_flower mirror_gre"
for current_test in ${TESTS:-$ALL_TESTS}; do
	source ${current_test}_scale.sh

@@ -34,6 +41,7 @@ for current_test in ${TESTS:-$ALL_TESTS}; do
		setup_wait $num_netifs
		${current_test}_test "$target" "$should_fail"
		${current_test}_cleanup
		devlink_reload
		if [[ "$should_fail" -eq 0 ]]; then
			log_test "'$current_test' $target"
		else
+18 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0
source ../router_scale.sh

router_get_target()
{
	local should_fail=$1
	local target

	target=$(devlink_resource_size_get kvd)

	if [[ $should_fail -eq 0 ]]; then
		target=$((target * 85 / 100))
	else
		target=$((target + 1))
	fi

	echo $target
}
+318 −0
Original line number Diff line number Diff line
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0

ALL_TESTS="
	same_speeds_autoneg_off
	different_speeds_autoneg_off
	combination_of_neg_on_and_off
	advertise_subset_of_speeds
	check_highest_speed_is_chosen
	different_speeds_autoneg_on
"
NUM_NETIFS=2
source lib.sh
source ethtool_lib.sh

h1_create()
{
	simple_if_init $h1 192.0.2.1/24
}

h1_destroy()
{
	simple_if_fini $h1 192.0.2.1/24
}

h2_create()
{
	simple_if_init $h2 192.0.2.2/24
}

h2_destroy()
{
	simple_if_fini $h2 192.0.2.2/24
}

setup_prepare()
{
	h1=${NETIFS[p1]}
	h2=${NETIFS[p2]}

	h1_create
	h2_create
}

cleanup()
{
	pre_cleanup

	h2_destroy
	h1_destroy
}

different_speeds_get()
{
	local dev1=$1; shift
	local dev2=$1; shift
	local with_mode=$1; shift
	local adver=$1; shift

	local -a speeds_arr

	speeds_arr=($(common_speeds_get $dev1 $dev2 $with_mode $adver))
	if [[ ${#speeds_arr[@]} < 2 ]]; then
		check_err 1 "cannot check different speeds. There are not enough speeds"
	fi

	echo ${speeds_arr[0]} ${speeds_arr[1]}
}

same_speeds_autoneg_off()
{
	# Check that when each of the reported speeds is forced, the links come
	# up and are operational.
	local -a speeds_arr=($(common_speeds_get $h1 $h2 0 0))

	for speed in "${speeds_arr[@]}"; do
		RET=0
		ethtool_set $h1 speed $speed autoneg off
		ethtool_set $h2 speed $speed autoneg off

		setup_wait_dev_with_timeout $h1
		setup_wait_dev_with_timeout $h2
		ping_do $h1 192.0.2.2
		check_err $? "speed $speed autoneg off"
		log_test "force of same speed autoneg off"
		log_info "speed = $speed"
	done

	ethtool -s $h2 autoneg on
	ethtool -s $h1 autoneg on
}

different_speeds_autoneg_off()
{
	# Test that when we force different speeds, links are not up and ping
	# fails.
	RET=0

	local -a speeds_arr=($(different_speeds_get $h1 $h2 0 0))
	local speed1=${speeds_arr[0]}
	local speed2=${speeds_arr[1]}

	ethtool_set $h1 speed $speed1 autoneg off
	ethtool_set $h2 speed $speed2 autoneg off

	setup_wait_dev_with_timeout $h1
	setup_wait_dev_with_timeout $h2
	ping_do $h1 192.0.2.2
	check_fail $? "ping with different speeds"

	log_test "force of different speeds autoneg off"

	ethtool -s $h2 autoneg on
	ethtool -s $h1 autoneg on
}

combination_of_neg_on_and_off()
{
	# Test that when one device is forced to a speed supported by both
	# endpoints and the other device is configured to autoneg on, the links
	# are up and ping passes.
	local -a speeds_arr=($(common_speeds_get $h1 $h2 0 1))

	for speed in "${speeds_arr[@]}"; do
		RET=0
		ethtool_set $h1 speed $speed autoneg off

		setup_wait_dev_with_timeout $h1
		setup_wait_dev_with_timeout $h2
		ping_do $h1 192.0.2.2
		check_err $? "h1-speed=$speed autoneg off, h2 autoneg on"
		log_test "one side with autoneg off and another with autoneg on"
		log_info "force speed = $speed"
	done

	ethtool -s $h1 autoneg on
}

hex_speed_value_get()
{
	local speed=$1; shift

	local shift_size=${speed_values[$speed]}
	speed=$((0x1 << $"shift_size"))
	printf "%#x" "$speed"
}

subset_of_common_speeds_get()
{
	local dev1=$1; shift
	local dev2=$1; shift
	local adver=$1; shift

	local -a speeds_arr=($(common_speeds_get $dev1 $dev2 0 $adver))
	local speed_to_advertise=0
	local speed_to_remove=${speeds_arr[0]}
	speed_to_remove+='base'

	local -a speeds_mode_arr=($(common_speeds_get $dev1 $dev2 1 $adver))

	for speed in ${speeds_mode_arr[@]}; do
		if [[ $speed != $speed_to_remove* ]]; then
			speed=$(hex_speed_value_get $speed)
			speed_to_advertise=$(($speed_to_advertise | \
						$speed))
		fi

	done

	# Convert to hex.
	printf "%#x" "$speed_to_advertise"
}

speed_to_advertise_get()
{
	# The function returns the hex number that is composed by OR-ing all
	# the modes corresponding to the provided speed.
	local speed_without_mode=$1; shift
	local supported_speeds=("$@"); shift
	local speed_to_advertise=0

	speed_without_mode+='base'

	for speed in ${supported_speeds[@]}; do
		if [[ $speed == $speed_without_mode* ]]; then
			speed=$(hex_speed_value_get $speed)
			speed_to_advertise=$(($speed_to_advertise | \
						$speed))
		fi

	done

	# Convert to hex.
	printf "%#x" "$speed_to_advertise"
}

advertise_subset_of_speeds()
{
	# Test that when one device advertises a subset of speeds and another
	# advertises a specific speed (but all modes of this speed), the links
	# are up and ping passes.
	RET=0

	local speed_1_to_advertise=$(subset_of_common_speeds_get $h1 $h2 1)
	ethtool_set $h1 advertise $speed_1_to_advertise

	if [ $RET != 0 ]; then
		log_test "advertise subset of speeds"
		return
	fi

	local -a speeds_arr_without_mode=($(common_speeds_get $h1 $h2 0 1))
	# Check only speeds that h1 advertised. Remove the first speed.
	unset speeds_arr_without_mode[0]
	local -a speeds_arr_with_mode=($(common_speeds_get $h1 $h2 1 1))

	for speed_value in ${speeds_arr_without_mode[@]}; do
		RET=0
		local speed_2_to_advertise=$(speed_to_advertise_get $speed_value \
			"${speeds_arr_with_mode[@]}")
		ethtool_set $h2 advertise $speed_2_to_advertise

		setup_wait_dev_with_timeout $h1
		setup_wait_dev_with_timeout $h2
		ping_do $h1 192.0.2.2
		check_err $? "h1=$speed_1_to_advertise, h2=$speed_2_to_advertise ($speed_value)"

		log_test "advertise subset of speeds"
		log_info "h1=$speed_1_to_advertise, h2=$speed_2_to_advertise"
	done

	ethtool -s $h2 autoneg on
	ethtool -s $h1 autoneg on
}

check_highest_speed_is_chosen()
{
	# Test that when one device advertises a subset of speeds, the other
	# chooses the highest speed. This test checks configuration without
	# traffic.
	RET=0

	local max_speed
	local chosen_speed
	local speed_to_advertise=$(subset_of_common_speeds_get $h1 $h2 1)

	ethtool_set $h1 advertise $speed_to_advertise

	if [ $RET != 0 ]; then
		log_test "check highest speed"
		return
	fi

	local -a speeds_arr=($(common_speeds_get $h1 $h2 0 1))
	# Remove the first speed, h1 does not advertise this speed.
	unset speeds_arr[0]

	max_speed=${speeds_arr[0]}
	for current in ${speeds_arr[@]}; do
		if [[ $current -gt $max_speed ]]; then
			max_speed=$current
		fi
	done

	setup_wait_dev_with_timeout $h1
	setup_wait_dev_with_timeout $h2
	chosen_speed=$(ethtool $h1 | grep 'Speed:')
	chosen_speed=${chosen_speed%"Mb/s"*}
	chosen_speed=${chosen_speed#*"Speed: "}
	((chosen_speed == max_speed))
	check_err $? "h1 advertise $speed_to_advertise, h2 sync to speed $chosen_speed"

	log_test "check highest speed"

	ethtool -s $h2 autoneg on
	ethtool -s $h1 autoneg on
}

different_speeds_autoneg_on()
{
	# Test that when we configure links to advertise different speeds,
	# links are not up and ping fails.
	RET=0

	local -a speeds=($(different_speeds_get $h1 $h2 1 1))
	local speed1=${speeds[0]}
	local speed2=${speeds[1]}

	speed1=$(hex_speed_value_get $speed1)
	speed2=$(hex_speed_value_get $speed2)

	ethtool_set $h1 advertise $speed1
	ethtool_set $h2 advertise $speed2

	if (($RET)); then
		setup_wait_dev_with_timeout $h1
		setup_wait_dev_with_timeout $h2
		ping_do $h1 192.0.2.2
		check_fail $? "ping with different speeds autoneg on"
	fi

	log_test "advertise different speeds autoneg on"

	ethtool -s $h2 autoneg on
	ethtool -s $h1 autoneg on
}

trap cleanup EXIT

setup_prepare
setup_wait

declare -gA speed_values
eval "speed_values=($(speeds_arr_get))"

tests_run

exit $EXIT_STATUS
+69 −0
Original line number Diff line number Diff line
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0

speeds_arr_get()
{
	cmd='/ETHTOOL_LINK_MODE_[^[:space:]]*_BIT[[:space:]]+=[[:space:]]+/ \
		{sub(/,$/, "") \
		sub(/ETHTOOL_LINK_MODE_/,"") \
		sub(/_BIT/,"") \
		sub(/_Full/,"/Full") \
		sub(/_Half/,"/Half");\
		print "["$1"]="$3}'

	awk "${cmd}" /usr/include/linux/ethtool.h
}

ethtool_set()
{
	local cmd="$@"
	local out=$(ethtool -s $cmd 2>&1 | wc -l)

	check_err $out "error in configuration. $cmd"
}

dev_speeds_get()
{
	local dev=$1; shift
	local with_mode=$1; shift
	local adver=$1; shift
	local speeds_str

	if (($adver)); then
		mode="Advertised link modes"
	else
		mode="Supported link modes"
	fi

	speeds_str=$(ethtool "$dev" | \
		# Snip everything before the link modes section.
		sed -n '/'"$mode"':/,$p' | \
		# Quit processing the rest at the start of the next section.
		# When checking, skip the header of this section (hence the 2,).
		sed -n '2,${/^[\t][^ \t]/q};p' | \
		# Drop the section header of the current section.
		cut -d':' -f2)

	local -a speeds_arr=($speeds_str)
	if [[ $with_mode -eq 0 ]]; then
		for ((i=0; i<${#speeds_arr[@]}; i++)); do
			speeds_arr[$i]=${speeds_arr[$i]%base*}
		done
	fi
	echo ${speeds_arr[@]}
}

common_speeds_get()
{
	dev1=$1; shift
	dev2=$1; shift
	with_mode=$1; shift
	adver=$1; shift

	local -a dev1_speeds=($(dev_speeds_get $dev1 $with_mode $adver))
	local -a dev2_speeds=($(dev_speeds_get $dev2 $with_mode $adver))

	comm -12 \
		<(printf '%s\n' "${dev1_speeds[@]}" | sort -u) \
		<(printf '%s\n' "${dev2_speeds[@]}" | sort -u)
}
+26 −3
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ NETIF_CREATE=${NETIF_CREATE:=yes}
MCD=${MCD:=smcrouted}
MC_CLI=${MC_CLI:=smcroutectl}
PING_TIMEOUT=${PING_TIMEOUT:=5}
WAIT_TIMEOUT=${WAIT_TIMEOUT:=20}
INTERFACE_TIMEOUT=${INTERFACE_TIMEOUT:=600}

relative_path="${BASH_SOURCE%/*}"
if [[ "$relative_path" == "${BASH_SOURCE}" ]]; then
@@ -226,24 +228,45 @@ log_info()
setup_wait_dev()
{
	local dev=$1; shift
	local wait_time=${1:-$WAIT_TIME}; shift

	while true; do
	setup_wait_dev_with_timeout "$dev" $INTERFACE_TIMEOUT $wait_time

	if (($?)); then
		check_err 1
		log_test setup_wait_dev ": Interface $dev does not come up."
		exit 1
	fi
}

setup_wait_dev_with_timeout()
{
	local dev=$1; shift
	local max_iterations=${1:-$WAIT_TIMEOUT}; shift
	local wait_time=${1:-$WAIT_TIME}; shift
	local i

	for ((i = 1; i <= $max_iterations; ++i)); do
		ip link show dev $dev up \
			| grep 'state UP' &> /dev/null
		if [[ $? -ne 0 ]]; then
			sleep 1
		else
			break
			sleep $wait_time
			return 0
		fi
	done

	return 1
}

setup_wait()
{
	local num_netifs=${1:-$NUM_NETIFS}
	local i

	for ((i = 1; i <= num_netifs; ++i)); do
		setup_wait_dev ${NETIFS[p$i]}
		setup_wait_dev ${NETIFS[p$i]} 0
	done

	# Make sure links are ready.