]> git.itanic.dy.fi Git - linux-stable/blob - tools/testing/selftests/net/forwarding/sch_red.sh
e714bae473fb4b424a900f8a94141c6c62eb2c3d
[linux-stable] / tools / testing / selftests / net / forwarding / sch_red.sh
1 # SPDX-License-Identifier: GPL-2.0
2
3 # This test sends one stream of traffic from H1 through a TBF shaper, to a RED
4 # within TBF shaper on $swp3. The two shapers have the same configuration, and
5 # thus the resulting stream should fill all available bandwidth on the latter
6 # shaper. A second stream is sent from H2 also via $swp3, and used to inject
7 # additional traffic. Since all available bandwidth is taken, this traffic has
8 # to go to backlog.
9 #
10 # +--------------------------+                     +--------------------------+
11 # | H1                       |                     | H2                       |
12 # |     + $h1                |                     |     + $h2                |
13 # |     | 192.0.2.1/28       |                     |     | 192.0.2.2/28       |
14 # |     | TBF 10Mbps         |                     |     |                    |
15 # +-----|--------------------+                     +-----|--------------------+
16 #       |                                                |
17 # +-----|------------------------------------------------|--------------------+
18 # | SW  |                                                |                    |
19 # |  +--|------------------------------------------------|----------------+   |
20 # |  |  + $swp1                                          + $swp2          |   |
21 # |  |                               BR                                   |   |
22 # |  |                                                                    |   |
23 # |  |                                + $swp3                             |   |
24 # |  |                                | TBF 10Mbps / RED                  |   |
25 # |  +--------------------------------|-----------------------------------+   |
26 # |                                   |                                       |
27 # +-----------------------------------|---------------------------------------+
28 #                                     |
29 #                               +-----|--------------------+
30 #                               | H3  |                    |
31 #                               |     + $h1                |
32 #                               |       192.0.2.3/28       |
33 #                               |                          |
34 #                               +--------------------------+
35
36 ALL_TESTS="
37         ping_ipv4
38         ecn_test
39         ecn_nodrop_test
40         red_test
41         red_qevent_test
42         ecn_qevent_test
43 "
44
45 NUM_NETIFS=6
46 CHECK_TC="yes"
47 source lib.sh
48
49 BACKLOG=30000
50 PKTSZ=1400
51
52 h1_create()
53 {
54         simple_if_init $h1 192.0.2.1/28
55         mtu_set $h1 10000
56         tc qdisc replace dev $h1 root handle 1: tbf \
57            rate 10Mbit burst 10K limit 1M
58 }
59
60 h1_destroy()
61 {
62         tc qdisc del dev $h1 root
63         mtu_restore $h1
64         simple_if_fini $h1 192.0.2.1/28
65 }
66
67 h2_create()
68 {
69         simple_if_init $h2 192.0.2.2/28
70         mtu_set $h2 10000
71 }
72
73 h2_destroy()
74 {
75         mtu_restore $h2
76         simple_if_fini $h2 192.0.2.2/28
77 }
78
79 h3_create()
80 {
81         simple_if_init $h3 192.0.2.3/28
82         mtu_set $h3 10000
83 }
84
85 h3_destroy()
86 {
87         mtu_restore $h3
88         simple_if_fini $h3 192.0.2.3/28
89 }
90
91 switch_create()
92 {
93         ip link add dev br up type bridge
94         ip link set dev $swp1 up master br
95         ip link set dev $swp2 up master br
96         ip link set dev $swp3 up master br
97
98         mtu_set $swp1 10000
99         mtu_set $swp2 10000
100         mtu_set $swp3 10000
101
102         tc qdisc replace dev $swp3 root handle 1: tbf \
103            rate 10Mbit burst 10K limit 1M
104         ip link add name _drop_test up type dummy
105 }
106
107 switch_destroy()
108 {
109         ip link del dev _drop_test
110         tc qdisc del dev $swp3 root
111
112         mtu_restore $h3
113         mtu_restore $h2
114         mtu_restore $h1
115
116         ip link set dev $swp3 down nomaster
117         ip link set dev $swp2 down nomaster
118         ip link set dev $swp1 down nomaster
119         ip link del dev br
120 }
121
122 setup_prepare()
123 {
124         h1=${NETIFS[p1]}
125         swp1=${NETIFS[p2]}
126
127         h2=${NETIFS[p3]}
128         swp2=${NETIFS[p4]}
129
130         swp3=${NETIFS[p5]}
131         h3=${NETIFS[p6]}
132
133         h3_mac=$(mac_get $h3)
134
135         vrf_prepare
136
137         h1_create
138         h2_create
139         h3_create
140         switch_create
141 }
142
143 cleanup()
144 {
145         pre_cleanup
146
147         switch_destroy
148         h3_destroy
149         h2_destroy
150         h1_destroy
151
152         vrf_cleanup
153 }
154
155 ping_ipv4()
156 {
157         ping_test $h1 192.0.2.3 " from host 1"
158         ping_test $h2 192.0.2.3 " from host 2"
159 }
160
161 get_qdisc_backlog()
162 {
163         qdisc_stats_get $swp3 11: .backlog
164 }
165
166 get_nmarked()
167 {
168         qdisc_stats_get $swp3 11: .marked
169 }
170
171 get_qdisc_npackets()
172 {
173         qdisc_stats_get $swp3 11: .packets
174 }
175
176 get_nmirrored()
177 {
178         link_stats_get _drop_test tx packets
179 }
180
181 send_packets()
182 {
183         local proto=$1; shift
184         local pkts=$1; shift
185
186         $MZ $h2 -p $PKTSZ -a own -b $h3_mac -A 192.0.2.2 -B 192.0.2.3 -t $proto -q -c $pkts "$@"
187 }
188
189 # This sends traffic in an attempt to build a backlog of $size. Returns 0 on
190 # success. After 10 failed attempts it bails out and returns 1. It dumps the
191 # backlog size to stdout.
192 build_backlog()
193 {
194         local size=$1; shift
195         local proto=$1; shift
196
197         local i=0
198
199         while :; do
200                 local cur=$(get_qdisc_backlog)
201                 local diff=$((size - cur))
202                 local pkts=$(((diff + PKTSZ - 1) / PKTSZ))
203
204                 if ((cur >= size)); then
205                         echo $cur
206                         return 0
207                 elif ((i++ > 10)); then
208                         echo $cur
209                         return 1
210                 fi
211
212                 send_packets $proto $pkts "$@"
213                 sleep 1
214         done
215 }
216
217 check_marking()
218 {
219         local cond=$1; shift
220
221         local npackets_0=$(get_qdisc_npackets)
222         local nmarked_0=$(get_nmarked)
223         sleep 5
224         local npackets_1=$(get_qdisc_npackets)
225         local nmarked_1=$(get_nmarked)
226
227         local nmarked_d=$((nmarked_1 - nmarked_0))
228         local npackets_d=$((npackets_1 - npackets_0))
229         local pct=$((100 * nmarked_d / npackets_d))
230
231         echo $pct
232         ((pct $cond))
233 }
234
235 check_mirroring()
236 {
237         local cond=$1; shift
238
239         local npackets_0=$(get_qdisc_npackets)
240         local nmirrored_0=$(get_nmirrored)
241         sleep 5
242         local npackets_1=$(get_qdisc_npackets)
243         local nmirrored_1=$(get_nmirrored)
244
245         local nmirrored_d=$((nmirrored_1 - nmirrored_0))
246         local npackets_d=$((npackets_1 - npackets_0))
247         local pct=$((100 * nmirrored_d / npackets_d))
248
249         echo $pct
250         ((pct $cond))
251 }
252
253 ecn_test_common()
254 {
255         local name=$1; shift
256         local limit=$1; shift
257         local backlog
258         local pct
259
260         # Build the below-the-limit backlog using UDP. We could use TCP just
261         # fine, but this way we get a proof that UDP is accepted when queue
262         # length is below the limit. The main stream is using TCP, and if the
263         # limit is misconfigured, we would see this traffic being ECN marked.
264         RET=0
265         backlog=$(build_backlog $((2 * limit / 3)) udp)
266         check_err $? "Could not build the requested backlog"
267         pct=$(check_marking "== 0")
268         check_err $? "backlog $backlog / $limit Got $pct% marked packets, expected == 0."
269         log_test "$name backlog < limit"
270
271         # Now push TCP, because non-TCP traffic would be early-dropped after the
272         # backlog crosses the limit, and we want to make sure that the backlog
273         # is above the limit.
274         RET=0
275         backlog=$(build_backlog $((3 * limit / 2)) tcp tos=0x01)
276         check_err $? "Could not build the requested backlog"
277         pct=$(check_marking ">= 95")
278         check_err $? "backlog $backlog / $limit Got $pct% marked packets, expected >= 95."
279         log_test "$name backlog > limit"
280 }
281
282 do_ecn_test()
283 {
284         local limit=$1; shift
285         local name=ECN
286
287         $MZ $h1 -p $PKTSZ -A 192.0.2.1 -B 192.0.2.3 -c 0 \
288                 -a own -b $h3_mac -t tcp -q tos=0x01 &
289         sleep 1
290
291         ecn_test_common "$name" $limit
292
293         # Up there we saw that UDP gets accepted when backlog is below the
294         # limit. Now that it is above, it should all get dropped, and backlog
295         # building should fail.
296         RET=0
297         build_backlog $((2 * limit)) udp >/dev/null
298         check_fail $? "UDP traffic went into backlog instead of being early-dropped"
299         log_test "$name backlog > limit: UDP early-dropped"
300
301         stop_traffic
302         sleep 1
303 }
304
305 do_ecn_nodrop_test()
306 {
307         local limit=$1; shift
308         local name="ECN nodrop"
309
310         $MZ $h1 -p $PKTSZ -A 192.0.2.1 -B 192.0.2.3 -c 0 \
311                 -a own -b $h3_mac -t tcp -q tos=0x01 &
312         sleep 1
313
314         ecn_test_common "$name" $limit
315
316         # Up there we saw that UDP gets accepted when backlog is below the
317         # limit. Now that it is above, in nodrop mode, make sure it goes to
318         # backlog as well.
319         RET=0
320         build_backlog $((2 * limit)) udp >/dev/null
321         check_err $? "UDP traffic was early-dropped instead of getting into backlog"
322         log_test "$name backlog > limit: UDP not dropped"
323
324         stop_traffic
325         sleep 1
326 }
327
328 do_red_test()
329 {
330         local limit=$1; shift
331         local backlog
332         local pct
333
334         # Use ECN-capable TCP to verify there's no marking even though the queue
335         # is above limit.
336         $MZ $h1 -p $PKTSZ -A 192.0.2.1 -B 192.0.2.3 -c 0 \
337                 -a own -b $h3_mac -t tcp -q tos=0x01 &
338
339         # Pushing below the queue limit should work.
340         RET=0
341         backlog=$(build_backlog $((2 * limit / 3)) tcp tos=0x01)
342         check_err $? "Could not build the requested backlog"
343         pct=$(check_marking "== 0")
344         check_err $? "backlog $backlog / $limit Got $pct% marked packets, expected == 0."
345         log_test "RED backlog < limit"
346
347         # Pushing above should not.
348         RET=0
349         backlog=$(build_backlog $((3 * limit / 2)) tcp tos=0x01)
350         check_fail $? "Traffic went into backlog instead of being early-dropped"
351         pct=$(check_marking "== 0")
352         check_err $? "backlog $backlog / $limit Got $pct% marked packets, expected == 0."
353         log_test "RED backlog > limit"
354
355         stop_traffic
356         sleep 1
357 }
358
359 do_red_qevent_test()
360 {
361         local limit=$1; shift
362         local backlog
363         local base
364         local now
365         local pct
366
367         RET=0
368
369         $MZ $h1 -p $PKTSZ -A 192.0.2.1 -B 192.0.2.3 -c 0 \
370                 -a own -b $h3_mac -t udp -q &
371         sleep 1
372
373         tc filter add block 10 pref 1234 handle 102 matchall skip_hw \
374            action mirred egress mirror dev _drop_test
375
376         # Push to the queue until it's at the limit. The configured limit is
377         # rounded by the qdisc, so this is the best we can do to get to the real
378         # limit.
379         build_backlog $((3 * limit / 2)) udp >/dev/null
380
381         base=$(get_nmirrored)
382         send_packets udp 100
383         sleep 1
384         now=$(get_nmirrored)
385         ((now >= base + 100))
386         check_err $? "Dropped packets not observed: 100 expected, $((now - base)) seen"
387
388         tc filter del block 10 pref 1234 handle 102 matchall
389
390         base=$(get_nmirrored)
391         send_packets udp 100
392         sleep 1
393         now=$(get_nmirrored)
394         ((now == base))
395         check_err $? "Dropped packets still observed: 0 expected, $((now - base)) seen"
396
397         log_test "RED early_dropped packets mirrored"
398
399         stop_traffic
400         sleep 1
401 }
402
403 do_ecn_qevent_test()
404 {
405         local limit=$1; shift
406         local name=ECN
407
408         RET=0
409
410         $MZ $h1 -p $PKTSZ -A 192.0.2.1 -B 192.0.2.3 -c 0 \
411                 -a own -b $h3_mac -t tcp -q tos=0x01 &
412         sleep 1
413
414         tc filter add block 10 pref 1234 handle 102 matchall skip_hw \
415            action mirred egress mirror dev _drop_test
416
417         backlog=$(build_backlog $((2 * limit / 3)) tcp tos=0x01)
418         check_err $? "Could not build the requested backlog"
419         pct=$(check_mirroring "== 0")
420         check_err $? "backlog $backlog / $limit Got $pct% mirrored packets, expected == 0."
421
422         backlog=$(build_backlog $((3 * limit / 2)) tcp tos=0x01)
423         check_err $? "Could not build the requested backlog"
424         pct=$(check_mirroring ">= 95")
425         check_err $? "backlog $backlog / $limit Got $pct% mirrored packets, expected >= 95."
426
427         tc filter del block 10 pref 1234 handle 102 matchall
428
429         log_test "ECN marked packets mirrored"
430
431         stop_traffic
432         sleep 1
433 }
434
435 install_qdisc()
436 {
437         local -a args=("$@")
438
439         tc qdisc replace dev $swp3 parent 1:1 handle 11: red \
440            limit 1M avpkt $PKTSZ probability 1 \
441            min $BACKLOG max $((BACKLOG + 1)) burst 38 "${args[@]}"
442         sleep 1
443 }
444
445 uninstall_qdisc()
446 {
447         tc qdisc del dev $swp3 parent 1:1
448 }
449
450 ecn_test()
451 {
452         install_qdisc ecn
453         do_ecn_test $BACKLOG
454         uninstall_qdisc
455 }
456
457 ecn_nodrop_test()
458 {
459         install_qdisc ecn nodrop
460         do_ecn_nodrop_test $BACKLOG
461         uninstall_qdisc
462 }
463
464 red_test()
465 {
466         install_qdisc
467         do_red_test $BACKLOG
468         uninstall_qdisc
469 }
470
471 red_qevent_test()
472 {
473         install_qdisc qevent early_drop block 10
474         do_red_qevent_test $BACKLOG
475         uninstall_qdisc
476 }
477
478 ecn_qevent_test()
479 {
480         install_qdisc ecn qevent mark block 10
481         do_ecn_qevent_test $BACKLOG
482         uninstall_qdisc
483 }
484
485 trap cleanup EXIT
486
487 setup_prepare
488 setup_wait
489
490 tests_run
491
492 exit $EXIT_STATUS