aboutsummaryrefslogtreecommitdiffstats
path: root/tools/testing/selftests/drivers/net/mlxsw/fib_offload.sh
blob: e99ae500f38735e56e15737dd42c8687fb733f4b (plain) (blame)
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
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Test unicast FIB offload indication.

lib_dir=$(dirname $0)/../../../net/forwarding

ALL_TESTS="
	ipv6_route_add
	ipv6_route_replace
	ipv6_route_nexthop_group_share
	ipv6_route_rate
"
NUM_NETIFS=4
source $lib_dir/lib.sh
source $lib_dir/devlink_lib.sh

tor1_create()
{
	simple_if_init $tor1_p1 2001:db8:1::2/128 2001:db8:1::3/128
}

tor1_destroy()
{
	simple_if_fini $tor1_p1 2001:db8:1::2/128 2001:db8:1::3/128
}

tor2_create()
{
	simple_if_init $tor2_p1 2001:db8:2::2/128 2001:db8:2::3/128
}

tor2_destroy()
{
	simple_if_fini $tor2_p1 2001:db8:2::2/128 2001:db8:2::3/128
}

spine_create()
{
	ip link set dev $spine_p1 up
	ip link set dev $spine_p2 up

	__addr_add_del $spine_p1 add 2001:db8:1::1/64
	__addr_add_del $spine_p2 add 2001:db8:2::1/64
}

spine_destroy()
{
	__addr_add_del $spine_p2 del 2001:db8:2::1/64
	__addr_add_del $spine_p1 del 2001:db8:1::1/64

	ip link set dev $spine_p2 down
	ip link set dev $spine_p1 down
}

ipv6_offload_check()
{
	local pfx="$1"; shift
	local expected_num=$1; shift
	local num

	# Try to avoid races with route offload
	sleep .1

	num=$(ip -6 route show match ${pfx} | grep "offload" | wc -l)

	if [ $num -eq $expected_num ]; then
		return 0
	fi

	return 1
}

ipv6_route_add_prefix()
{
	RET=0

	# Add a prefix route and check that it is offloaded.
	ip -6 route add 2001:db8:3::/64 dev $spine_p1 metric 100
	ipv6_offload_check "2001:db8:3::/64 dev $spine_p1 metric 100" 1
	check_err $? "prefix route not offloaded"

	# Append an identical prefix route with an higher metric and check that
	# offload indication did not change.
	ip -6 route append 2001:db8:3::/64 dev $spine_p1 metric 200
	ipv6_offload_check "2001:db8:3::/64 dev $spine_p1 metric 100" 1
	check_err $? "lowest metric not offloaded after append"
	ipv6_offload_check "2001:db8:3::/64 dev $spine_p1 metric 200" 0
	check_err $? "highest metric offloaded when should not"

	# Prepend an identical prefix route with lower metric and check that
	# it is offloaded and the others are not.
	ip -6 route append 2001:db8:3::/64 dev $spine_p1 metric 10
	ipv6_offload_check "2001:db8:3::/64 dev $spine_p1 metric 10" 1
	check_err $? "lowest metric not offloaded after prepend"
	ipv6_offload_check "2001:db8:3::/64 dev $spine_p1 metric 100" 0
	check_err $? "mid metric offloaded when should not"
	ipv6_offload_check "2001:db8:3::/64 dev $spine_p1 metric 200" 0
	check_err $? "highest metric offloaded when should not"

	# Delete the routes and add the same route with a different nexthop
	# device. Check that it is offloaded.
	ip -6 route flush 2001:db8:3::/64 dev $spine_p1
	ip -6 route add 2001:db8:3::/64 dev $spine_p2
	ipv6_offload_check "2001:db8:3::/64 dev $spine_p2" 1

	log_test "IPv6 prefix route add"

	ip -6 route flush 2001:db8:3::/64
}

ipv6_route_add_mpath()
{
	RET=0

	# Add a multipath route and check that it is offloaded.
	ip -6 route add 2001:db8:3::/64 metric 100 \
		nexthop via 2001:db8:1::2 dev $spine_p1 \
		nexthop via 2001:db8:2::2 dev $spine_p2
	ipv6_offload_check "2001:db8:3::/64 metric 100" 2
	check_err $? "multipath route not offloaded when should"

	# Append another nexthop and check that it is offloaded as well.
	ip -6 route append 2001:db8:3::/64 metric 100 \
		nexthop via 2001:db8:1::3 dev $spine_p1
	ipv6_offload_check "2001:db8:3::/64 metric 100" 3
	check_err $? "appended nexthop not offloaded when should"

	# Mimic route replace by removing the route and adding it back with
	# only two nexthops.
	ip -6 route del 2001:db8:3::/64
	ip -6 route add 2001:db8:3::/64 metric 100 \
		nexthop via 2001:db8:1::2 dev $spine_p1 \
		nexthop via 2001:db8:2::2 dev $spine_p2
	ipv6_offload_check "2001:db8:3::/64 metric 100" 2
	check_err $? "multipath route not offloaded after delete & add"

	# Append a nexthop with an higher metric and check that the offload
	# indication did not change.
	ip -6 route append 2001:db8:3::/64 metric 200 \
		nexthop via 2001:db8:1::3 dev $spine_p1
	ipv6_offload_check "2001:db8:3::/64 metric 100" 2
	check_err $? "lowest metric not offloaded after append"
	ipv6_offload_check "2001:db8:3::/64 metric 200" 0
	check_err $? "highest metric offloaded when should not"

	# Prepend a nexthop with a lower metric and check that it is offloaded
	# and the others are not.
	ip -6 route append 2001:db8:3::/64 metric 10 \
		nexthop via 2001:db8:1::3 dev $spine_p1
	ipv6_offload_check "2001:db8:3::/64 metric 10" 1
	check_err $? "lowest metric not offloaded after prepend"
	ipv6_offload_check "2001:db8:3::/64 metric 100" 0
	check_err $? "mid metric offloaded when should not"
	ipv6_offload_check "2001:db8:3::/64 metric 200" 0
	check_err $? "highest metric offloaded when should not"

	log_test "IPv6 multipath route add"

	ip -6 route flush 2001:db8:3::/64
}

ipv6_route_add()
{
	ipv6_route_add_prefix
	ipv6_route_add_mpath
}

ipv6_route_replace()
{
	RET=0

	# Replace prefix route with prefix route.
	ip -6 route add 2001:db8:3::/64 metric 100 dev $spine_p1
	ipv6_offload_check "2001:db8:3::/64 metric 100" 1
	check_err $? "prefix route not offloaded when should"
	ip -6 route replace 2001:db8:3::/64 metric 100 dev $spine_p2
	ipv6_offload_check "2001:db8:3::/64 metric 100" 1
	check_err $? "prefix route not offloaded after replace"

	# Replace prefix route with multipath route.
	ip -6 route replace 2001:db8:3::/64 metric 100 \
		nexthop via 2001:db8:1::2 dev $spine_p1 \
		nexthop via 2001:db8:2::2 dev $spine_p2
	ipv6_offload_check "2001:db8:3::/64 metric 100" 2
	check_err $? "multipath route not offloaded after replace"

	# Replace multipath route with prefix route. A prefix route cannot
	# replace a multipath route, so it is appended.
	ip -6 route replace 2001:db8:3::/64 metric 100 dev $spine_p1
	ipv6_offload_check "2001:db8:3::/64 metric 100 dev $spine_p1" 0
	check_err $? "prefix route offloaded after 'replacing' multipath route"
	ipv6_offload_check "2001:db8:3::/64 metric 100" 2
	check_err $? "multipath route not offloaded after being 'replaced' by prefix route"

	# Replace multipath route with multipath route.
	ip -6 route replace 2001:db8:3::/64 metric 100 \
		nexthop via 2001:db8:1::3 dev $spine_p1 \
		nexthop via 2001:db8:2::3 dev $spine_p2
	ipv6_offload_check "2001:db8:3::/64 metric 100" 2
	check_err $? "multipath route not offloaded after replacing multipath route"

	# Replace a non-existing multipath route with a multipath route and
	# check that it is appended and not offloaded.
	ip -6 route replace 2001:db8:3::/64 metric 200 \
		nexthop via 2001:db8:1::3 dev $spine_p1 \
		nexthop via 2001:db8:2::3 dev $spine_p2
	ipv6_offload_check "2001:db8:3::/64 metric 100" 2
	check_err $? "multipath route not offloaded after non-existing route was 'replaced'"
	ipv6_offload_check "2001:db8:3::/64 metric 200" 0
	check_err $? "multipath route offloaded after 'replacing' non-existing route"

	log_test "IPv6 route replace"

	ip -6 route flush 2001:db8:3::/64
}

ipv6_route_nexthop_group_share()
{
	RET=0

	# The driver consolidates identical nexthop groups in order to reduce
	# the resource usage in its adjacency table. Check that the deletion
	# of one multipath route using the group does not affect the other.
	ip -6 route add 2001:db8:3::/64 \
		nexthop via 2001:db8:1::2 dev $spine_p1 \
		nexthop via 2001:db8:2::2 dev $spine_p2
	ip -6 route add 2001:db8:4::/64 \
		nexthop via 2001:db8:1::2 dev $spine_p1 \
		nexthop via 2001:db8:2::2 dev $spine_p2
	ipv6_offload_check "2001:db8:3::/64" 2
	check_err $? "multipath route not offloaded when should"
	ipv6_offload_check "2001:db8:4::/64" 2
	check_err $? "multipath route not offloaded when should"
	ip -6 route del 2001:db8:3::/64
	ipv6_offload_check "2001:db8:4::/64" 2
	check_err $? "multipath route not offloaded after deletion of route sharing the nexthop group"

	# Check that after unsharing a nexthop group the routes are still
	# marked as offloaded.
	ip -6 route add 2001:db8:3::/64 \
		nexthop via 2001:db8:1::2 dev $spine_p1 \
		nexthop via 2001:db8:2::2 dev $spine_p2
	ip -6 route del 2001:db8:4::/64 \
		nexthop via 2001:db8:1::2 dev $spine_p1
	ipv6_offload_check "2001:db8:4::/64" 1
	check_err $? "singlepath route not offloaded after unsharing the nexthop group"
	ipv6_offload_check "2001:db8:3::/64" 2
	check_err $? "multipath route not offloaded after unsharing the nexthop group"

	log_test "IPv6 nexthop group sharing"

	ip -6 route flush 2001:db8:3::/64
	ip -6 route flush 2001:db8:4::/64
}

ipv6_route_rate()
{
	local batch_dir=$(mktemp -d)
	local num_rts=$((40 * 1024))
	local num_nhs=16
	local total
	local start
	local diff
	local end
	local nhs
	local i

	RET=0

	# Prepare 40K /64 multipath routes with 16 nexthops each and check how
	# long it takes to add them. A limit of 60 seconds is set. It is much
	# higher than insertion should take and meant to flag a serious
	# regression.
	total=$((nums_nhs * num_rts))

	for i in $(seq 1 $num_nhs); do
		ip -6 address add 2001:db8:1::10:$i/128 dev $tor1_p1
		nexthops+=" nexthop via 2001:db8:1::10:$i dev $spine_p1"
	done

	for i in $(seq 1 $num_rts); do
		echo "route add 2001:db8:8:$(printf "%x" $i)::/64$nexthops" \
			>> $batch_dir/add.batch
		echo "route del 2001:db8:8:$(printf "%x" $i)::/64$nexthops" \
			>> $batch_dir/del.batch
	done

	start=$(date +%s.%N)

	ip -batch $batch_dir/add.batch
	count=$(ip -6 route show | grep offload | wc -l)
	while [ $count -lt $total ]; do
		sleep .01
		count=$(ip -6 route show | grep offload | wc -l)
	done

	end=$(date +%s.%N)

	diff=$(echo "$end - $start" | bc -l)
	test "$(echo "$diff > 60" | bc -l)" -eq 0
	check_err $? "route insertion took too long"
	log_info "inserted $num_rts routes in $diff seconds"

	log_test "IPv6 routes insertion rate"

	ip -batch $batch_dir/del.batch
	for i in $(seq 1 $num_nhs); do
		ip -6 address del 2001:db8:1::10:$i/128 dev $tor1_p1
	done
	rm -rf $batch_dir
}

setup_prepare()
{
	spine_p1=${NETIFS[p1]}
	tor1_p1=${NETIFS[p2]}

	spine_p2=${NETIFS[p3]}
	tor2_p1=${NETIFS[p4]}

	vrf_prepare
	forwarding_enable

	tor1_create
	tor2_create
	spine_create
}

cleanup()
{
	pre_cleanup

	spine_destroy
	tor2_destroy
	tor1_destroy

	forwarding_restore
	vrf_cleanup
}

trap cleanup EXIT

setup_prepare
setup_wait

tests_run

exit $EXIT_STATUS