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