1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4ALL_TESTS="
5	test_defaults
6	test_dcb_ets
7	test_mtu
8	test_pfc
9	test_int_buf
10	test_tc_priomap
11	test_tc_mtu
12	test_tc_sizes
13	test_tc_int_buf
14"
15
16lib_dir=$(dirname $0)/../../../net/forwarding
17
18NUM_NETIFS=0
19source $lib_dir/lib.sh
20source $lib_dir/devlink_lib.sh
21source qos_lib.sh
22
23swp=$NETIF_NO_CABLE
24
25cleanup()
26{
27	pre_cleanup
28}
29
30get_prio_pg()
31{
32	# Produces a string of numbers "<B0> <B1> ... <B7> ", where BX is number
33	# of buffer that priority X is mapped to.
34	dcb -j buffer show dev $swp |
35		jq -r '[.prio_buffer | .[] | tostring + " "] | add'
36}
37
38get_prio_pfc()
39{
40	# Produces a string of numbers "<P0> <P1> ... <P7> ", where PX denotes
41	# whether priority X has PFC enabled (the value is 1) or disabled (0).
42	dcb -j pfc show dev $swp |
43		jq -r '[.prio_pfc | .[] | if . then "1 " else "0 " end] | add'
44}
45
46get_prio_tc()
47{
48	# Produces a string of numbers "<T0> <T1> ... <T7> ", where TC is number
49	# of TC that priority X is mapped to.
50	dcb -j ets show dev $swp |
51		jq -r '[.prio_tc | .[] | tostring + " "] | add'
52}
53
54get_buf_size()
55{
56	local idx=$1; shift
57
58	dcb -j buffer show dev $swp | jq ".buffer_size[$idx]"
59}
60
61get_tot_size()
62{
63	dcb -j buffer show dev $swp | jq '.total_size'
64}
65
66check_prio_pg()
67{
68	local expect=$1; shift
69
70	local current=$(get_prio_pg)
71	test "$current" = "$expect"
72	check_err $? "prio2buffer is '$current', expected '$expect'"
73}
74
75check_prio_pfc()
76{
77	local expect=$1; shift
78
79	local current=$(get_prio_pfc)
80	test "$current" = "$expect"
81	check_err $? "prio PFC is '$current', expected '$expect'"
82}
83
84check_prio_tc()
85{
86	local expect=$1; shift
87
88	local current=$(get_prio_tc)
89	test "$current" = "$expect"
90	check_err $? "prio_tc is '$current', expected '$expect'"
91}
92
93__check_buf_size()
94{
95	local idx=$1; shift
96	local expr=$1; shift
97	local what=$1; shift
98
99	local current=$(get_buf_size $idx)
100	((current $expr))
101	check_err $? "${what}buffer $idx size is '$current', expected '$expr'"
102	echo $current
103}
104
105check_buf_size()
106{
107	__check_buf_size "$@" > /dev/null
108}
109
110test_defaults()
111{
112	RET=0
113
114	check_prio_pg "0 0 0 0 0 0 0 0 "
115	check_prio_tc "0 0 0 0 0 0 0 0 "
116	check_prio_pfc "0 0 0 0 0 0 0 0 "
117
118	log_test "Default headroom configuration"
119}
120
121test_dcb_ets()
122{
123	RET=0
124
125	dcb ets set dev $swp prio-tc 0:0 1:2 2:4 3:6 4:1 5:3 6:5 7:7
126
127	check_prio_pg "0 2 4 6 1 3 5 7 "
128	check_prio_tc "0 2 4 6 1 3 5 7 "
129	check_prio_pfc "0 0 0 0 0 0 0 0 "
130
131	dcb ets set dev $swp prio-tc all:0
132
133	check_prio_pg "0 0 0 0 0 0 0 0 "
134	check_prio_tc "0 0 0 0 0 0 0 0 "
135
136	dcb buffer set dev $swp prio-buffer 0:1 1:3 2:5 3:7 4:0 5:2 6:4 7:6 2>/dev/null
137	check_fail $? "prio2buffer accepted in DCB mode"
138
139	log_test "Configuring headroom through ETS"
140}
141
142test_mtu()
143{
144	local what=$1; shift
145	local buf0size_2
146	local buf0size
147
148	RET=0
149	buf0size=$(__check_buf_size 0 "> 0")
150
151	mtu_set $swp 3000
152	buf0size_2=$(__check_buf_size 0 "> $buf0size" "MTU 3000: ")
153	mtu_restore $swp
154
155	mtu_set $swp 6000
156	check_buf_size 0 "> $buf0size_2" "MTU 6000: "
157	mtu_restore $swp
158
159	check_buf_size 0 "== $buf0size"
160
161	log_test "${what}MTU impacts buffer size"
162}
163
164test_tc_mtu()
165{
166	# In TC mode, MTU still impacts the threshold below which a buffer is
167	# not permitted to go.
168
169	tc qdisc replace dev $swp root handle 1: bfifo limit 1.5M
170	test_mtu "TC: "
171	tc qdisc delete dev $swp root
172}
173
174test_pfc()
175{
176	RET=0
177
178	dcb ets set dev $swp prio-tc all:0 5:1 6:2 7:3
179
180	local buf0size=$(get_buf_size 0)
181	local buf1size=$(get_buf_size 1)
182	local buf2size=$(get_buf_size 2)
183	local buf3size=$(get_buf_size 3)
184	check_buf_size 0 "> 0"
185	check_buf_size 1 "> 0"
186	check_buf_size 2 "> 0"
187	check_buf_size 3 "> 0"
188	check_buf_size 4 "== 0"
189	check_buf_size 5 "== 0"
190	check_buf_size 6 "== 0"
191	check_buf_size 7 "== 0"
192
193	log_test "Buffer size sans PFC"
194
195	RET=0
196
197	dcb pfc set dev $swp prio-pfc all:off 5:on 6:on 7:on delay 0
198
199	check_prio_pg "0 0 0 0 0 1 2 3 "
200	check_prio_pfc "0 0 0 0 0 1 1 1 "
201	check_buf_size 0 "== $buf0size"
202	check_buf_size 1 "> $buf1size"
203	check_buf_size 2 "> $buf2size"
204	check_buf_size 3 "> $buf3size"
205
206	local buf1size=$(get_buf_size 1)
207	check_buf_size 2 "== $buf1size"
208	check_buf_size 3 "== $buf1size"
209
210	log_test "PFC: Cable length 0"
211
212	RET=0
213
214	dcb pfc set dev $swp delay 1000
215
216	check_buf_size 0 "== $buf0size"
217	check_buf_size 1 "> $buf1size"
218	check_buf_size 2 "> $buf1size"
219	check_buf_size 3 "> $buf1size"
220
221	log_test "PFC: Cable length 1000"
222
223	RET=0
224
225	dcb pfc set dev $swp prio-pfc all:off delay 0
226	dcb ets set dev $swp prio-tc all:0
227
228	check_prio_pg "0 0 0 0 0 0 0 0 "
229	check_prio_tc "0 0 0 0 0 0 0 0 "
230	check_buf_size 0 "> 0"
231	check_buf_size 1 "== 0"
232	check_buf_size 2 "== 0"
233	check_buf_size 3 "== 0"
234	check_buf_size 4 "== 0"
235	check_buf_size 5 "== 0"
236	check_buf_size 6 "== 0"
237	check_buf_size 7 "== 0"
238
239	log_test "PFC: Restore defaults"
240}
241
242test_tc_priomap()
243{
244	RET=0
245
246	dcb ets set dev $swp prio-tc 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7
247	check_prio_pg "0 1 2 3 4 5 6 7 "
248
249	tc qdisc replace dev $swp root handle 1: bfifo limit 1.5M
250	check_prio_pg "0 0 0 0 0 0 0 0 "
251
252	dcb buffer set dev $swp prio-buffer 0:1 1:3 2:5 3:7 4:0 5:2 6:4 7:6
253	check_prio_pg "1 3 5 7 0 2 4 6 "
254
255	tc qdisc delete dev $swp root
256	check_prio_pg "0 1 2 3 4 5 6 7 "
257
258	# Clean up.
259	tc qdisc replace dev $swp root handle 1: bfifo limit 1.5M
260	dcb buffer set dev $swp prio-buffer all:0
261	tc qdisc delete dev $swp root
262	dcb ets set dev $swp prio-tc all:0
263
264	log_test "TC: priomap"
265}
266
267test_tc_sizes()
268{
269	local cell_size=$(devlink_cell_size_get)
270	local size=$((cell_size * 1000))
271
272	RET=0
273
274	dcb buffer set dev $swp buffer-size all:0 0:$size 2>/dev/null
275	check_fail $? "buffer_size should fail before qdisc is added"
276
277	tc qdisc replace dev $swp root handle 1: bfifo limit 1.5M
278
279	dcb buffer set dev $swp buffer-size all:0 0:$size
280	check_err $? "buffer_size should pass after qdisc is added"
281	check_buf_size 0 "== $size" "set size: "
282
283	mtu_set $swp 6000
284	check_buf_size 0 "== $size" "set MTU: "
285	mtu_restore $swp
286
287	dcb buffer set dev $swp buffer-size all:0
288
289	# After replacing the qdisc for the same kind, buffer_size still has to
290	# work.
291	tc qdisc replace dev $swp root handle 1: bfifo limit 1M
292
293	dcb buffer set dev $swp buffer-size all:0 0:$size
294	check_buf_size 0 "== $size" "post replace, set size: "
295
296	dcb buffer set dev $swp buffer-size all:0
297
298	# Likewise after replacing for a different kind.
299	tc qdisc replace dev $swp root handle 2: prio bands 8
300
301	dcb buffer set dev $swp buffer-size all:0 0:$size
302	check_buf_size 0 "== $size" "post replace different kind, set size: "
303
304	tc qdisc delete dev $swp root
305
306	dcb buffer set dev $swp buffer-size all:0 0:$size 2>/dev/null
307	check_fail $? "buffer_size should fail after qdisc is deleted"
308
309	log_test "TC: buffer size"
310}
311
312test_int_buf()
313{
314	local what=$1; shift
315
316	RET=0
317
318	local buf0size=$(get_buf_size 0)
319	local tot_size=$(get_tot_size)
320
321	# Size of internal buffer and buffer 9.
322	local dsize=$((tot_size - buf0size))
323
324	tc qdisc add dev $swp clsact
325	tc filter add dev $swp egress matchall skip_sw action mirred egress mirror dev $swp
326
327	local buf0size_2=$(get_buf_size 0)
328	local tot_size_2=$(get_tot_size)
329	local dsize_2=$((tot_size_2 - buf0size_2))
330
331	# Egress SPAN should have added to the "invisible" buffer configuration.
332	((dsize_2 > dsize))
333	check_err $? "Invisible buffers account for '$dsize_2', expected '> $dsize'"
334
335	mtu_set $swp 3000
336
337	local buf0size_3=$(get_buf_size 0)
338	local tot_size_3=$(get_tot_size)
339	local dsize_3=$((tot_size_3 - buf0size_3))
340
341	# MTU change might change buffer 0, which will show at total, but the
342	# hidden buffers should stay the same size.
343	((dsize_3 == dsize_2))
344	check_err $? "MTU change: Invisible buffers account for '$dsize_3', expected '== $dsize_2'"
345
346	mtu_restore $swp
347	tc qdisc del dev $swp clsact
348
349	# After SPAN removal, hidden buffers should be back to the original sizes.
350	local buf0size_4=$(get_buf_size 0)
351	local tot_size_4=$(get_tot_size)
352	local dsize_4=$((tot_size_4 - buf0size_4))
353	((dsize_4 == dsize))
354	check_err $? "SPAN removed: Invisible buffers account for '$dsize_4', expected '== $dsize'"
355
356	log_test "${what}internal buffer size"
357}
358
359test_tc_int_buf()
360{
361	local cell_size=$(devlink_cell_size_get)
362	local size=$((cell_size * 1000))
363
364	tc qdisc replace dev $swp root handle 1: bfifo limit 1.5M
365	test_int_buf "TC: "
366
367	dcb buffer set dev $swp buffer-size all:0 0:$size
368	test_int_buf "TC+buffsize: "
369
370	dcb buffer set dev $swp buffer-size all:0
371	tc qdisc delete dev $swp root
372}
373
374trap cleanup EXIT
375
376bail_on_lldpad
377setup_wait
378tests_run
379
380exit $EXIT_STATUS
381