summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/net/forwarding/ethtool.sh
blob: aa2eafb7b2437652e1e73745887a4794a7b596f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
#!/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
}

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))

	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
}

skip_on_veth

trap cleanup EXIT

setup_prepare
setup_wait

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

tests_run

exit $EXIT_STATUS