Skip to content

Commit a0bc96c

Browse files
wdebruijkuba-moo
authored andcommitted
selftests: net: verify fq per-band packet limit
Commit 29f834a ("net_sched: sch_fq: add 3 bands and WRR scheduling") introduces multiple traffic bands, and per-band maximum packet count. Per-band limits ensures that packets in one class cannot fill the entire qdisc and so cause DoS to the traffic in the other classes. Verify this behavior: 1. set the limit to 10 per band 2. send 20 pkts on band A: verify that 10 are queued, 10 dropped 3. send 20 pkts on band A: verify that 0 are queued, 20 dropped 4. send 20 pkts on band B: verify that 10 are queued, 10 dropped Packets must remain queued for a period to trigger this behavior. Use SO_TXTIME to store packets for 100 msec. The test reuses existing upstream test infra. The script is a fork of cmsg_time.sh. The scripts call cmsg_sender. The test extends cmsg_sender with two arguments: * '-P' SO_PRIORITY There is a subtle difference between IPv4 and IPv6 stack behavior: PF_INET/IP_TOS sets IP header bits and sk_priority PF_INET6/IPV6_TCLASS sets IP header bits BUT NOT sk_priority * '-n' num pkts Send multiple packets in quick succession. I first attempted a for loop in the script, but this is too slow in virtualized environments, causing flakiness as the 100ms timeout is reached and packets are dequeued. Also do not wait for timestamps to be queued unless timestamps are requested. Signed-off-by: Willem de Bruijn <willemb@google.com> Reviewed-by: Simon Horman <horms@kernel.org> Reviewed-by: Eric Dumazet <edumazet@google.com> Link: https://lore.kernel.org/r/20231116203449.2627525-1-willemdebruijn.kernel@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 45933b2 commit a0bc96c

File tree

3 files changed

+91
-17
lines changed

3 files changed

+91
-17
lines changed

tools/testing/selftests/net/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ TEST_PROGS += test_bridge_neigh_suppress.sh
9191
TEST_PROGS += test_vxlan_nolocalbypass.sh
9292
TEST_PROGS += test_bridge_backup_port.sh
9393
TEST_PROGS += fdb_flush.sh
94+
TEST_PROGS += fq_band_pktlimit.sh
9495

9596
TEST_FILES := settings
9697

tools/testing/selftests/net/cmsg_sender.c

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,13 @@ struct options {
4545
const char *host;
4646
const char *service;
4747
unsigned int size;
48+
unsigned int num_pkt;
4849
struct {
4950
unsigned int mark;
5051
unsigned int dontfrag;
5152
unsigned int tclass;
5253
unsigned int hlimit;
54+
unsigned int priority;
5355
} sockopt;
5456
struct {
5557
unsigned int family;
@@ -72,6 +74,7 @@ struct options {
7274
} v6;
7375
} opt = {
7476
.size = 13,
77+
.num_pkt = 1,
7578
.sock = {
7679
.family = AF_UNSPEC,
7780
.type = SOCK_DGRAM,
@@ -112,7 +115,7 @@ static void cs_parse_args(int argc, char *argv[])
112115
{
113116
int o;
114117

115-
while ((o = getopt(argc, argv, "46sS:p:m:M:d:tf:F:c:C:l:L:H:")) != -1) {
118+
while ((o = getopt(argc, argv, "46sS:p:P:m:M:n:d:tf:F:c:C:l:L:H:")) != -1) {
116119
switch (o) {
117120
case 's':
118121
opt.silent_send = true;
@@ -138,14 +141,19 @@ static void cs_parse_args(int argc, char *argv[])
138141
cs_usage(argv[0]);
139142
}
140143
break;
141-
144+
case 'P':
145+
opt.sockopt.priority = atoi(optarg);
146+
break;
142147
case 'm':
143148
opt.mark.ena = true;
144149
opt.mark.val = atoi(optarg);
145150
break;
146151
case 'M':
147152
opt.sockopt.mark = atoi(optarg);
148153
break;
154+
case 'n':
155+
opt.num_pkt = atoi(optarg);
156+
break;
149157
case 'd':
150158
opt.txtime.ena = true;
151159
opt.txtime.delay = atoi(optarg);
@@ -410,6 +418,10 @@ static void ca_set_sockopts(int fd)
410418
setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS,
411419
&opt.sockopt.hlimit, sizeof(opt.sockopt.hlimit)))
412420
error(ERN_SOCKOPT, errno, "setsockopt IPV6_HOPLIMIT");
421+
if (opt.sockopt.priority &&
422+
setsockopt(fd, SOL_SOCKET, SO_PRIORITY,
423+
&opt.sockopt.priority, sizeof(opt.sockopt.priority)))
424+
error(ERN_SOCKOPT, errno, "setsockopt SO_PRIORITY");
413425
}
414426

415427
int main(int argc, char *argv[])
@@ -421,6 +433,7 @@ int main(int argc, char *argv[])
421433
char *buf;
422434
int err;
423435
int fd;
436+
int i;
424437

425438
cs_parse_args(argc, argv);
426439

@@ -480,24 +493,27 @@ int main(int argc, char *argv[])
480493

481494
cs_write_cmsg(fd, &msg, cbuf, sizeof(cbuf));
482495

483-
err = sendmsg(fd, &msg, 0);
484-
if (err < 0) {
485-
if (!opt.silent_send)
486-
fprintf(stderr, "send failed: %s\n", strerror(errno));
487-
err = ERN_SEND;
488-
goto err_out;
489-
} else if (err != (int)opt.size) {
490-
fprintf(stderr, "short send\n");
491-
err = ERN_SEND_SHORT;
492-
goto err_out;
493-
} else {
494-
err = ERN_SUCCESS;
496+
for (i = 0; i < opt.num_pkt; i++) {
497+
err = sendmsg(fd, &msg, 0);
498+
if (err < 0) {
499+
if (!opt.silent_send)
500+
fprintf(stderr, "send failed: %s\n", strerror(errno));
501+
err = ERN_SEND;
502+
goto err_out;
503+
} else if (err != (int)opt.size) {
504+
fprintf(stderr, "short send\n");
505+
err = ERN_SEND_SHORT;
506+
goto err_out;
507+
}
495508
}
509+
err = ERN_SUCCESS;
496510

497-
/* Make sure all timestamps have time to loop back */
498-
usleep(opt.txtime.delay);
511+
if (opt.ts.ena) {
512+
/* Make sure all timestamps have time to loop back */
513+
usleep(opt.txtime.delay);
499514

500-
cs_read_cmsg(fd, &msg, cbuf, sizeof(cbuf));
515+
cs_read_cmsg(fd, &msg, cbuf, sizeof(cbuf));
516+
}
501517

502518
err_out:
503519
close(fd);
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/bin/bash
2+
# SPDX-License-Identifier: GPL-2.0
3+
#
4+
# Verify that FQ has a packet limit per band:
5+
#
6+
# 1. set the limit to 10 per band
7+
# 2. send 20 pkts on band A: verify that 10 are queued, 10 dropped
8+
# 3. send 20 pkts on band A: verify that 0 are queued, 20 dropped
9+
# 4. send 20 pkts on band B: verify that 10 are queued, 10 dropped
10+
#
11+
# Send packets with a 100ms delay to ensure that previously sent
12+
# packets are still queued when later ones are sent.
13+
# Use SO_TXTIME for this.
14+
15+
die() {
16+
echo "$1"
17+
exit 1
18+
}
19+
20+
# run inside private netns
21+
if [[ $# -eq 0 ]]; then
22+
./in_netns.sh "$0" __subprocess
23+
exit
24+
fi
25+
26+
ip link add type dummy
27+
ip link set dev dummy0 up
28+
ip -6 addr add fdaa::1/128 dev dummy0
29+
ip -6 route add fdaa::/64 dev dummy0
30+
tc qdisc replace dev dummy0 root handle 1: fq quantum 1514 initial_quantum 1514 limit 10
31+
32+
./cmsg_sender -6 -p u -d 100000 -n 20 fdaa::2 8000
33+
OUT1="$(tc -s qdisc show dev dummy0 | grep '^\ Sent')"
34+
35+
./cmsg_sender -6 -p u -d 100000 -n 20 fdaa::2 8000
36+
OUT2="$(tc -s qdisc show dev dummy0 | grep '^\ Sent')"
37+
38+
./cmsg_sender -6 -p u -d 100000 -n 20 -P 7 fdaa::2 8000
39+
OUT3="$(tc -s qdisc show dev dummy0 | grep '^\ Sent')"
40+
41+
# Initial stats will report zero sent, as all packets are still
42+
# queued in FQ. Sleep for the delay period (100ms) and see that
43+
# twenty are now sent.
44+
sleep 0.1
45+
OUT4="$(tc -s qdisc show dev dummy0 | grep '^\ Sent')"
46+
47+
# Log the output after the test
48+
echo "${OUT1}"
49+
echo "${OUT2}"
50+
echo "${OUT3}"
51+
echo "${OUT4}"
52+
53+
# Test the output for expected values
54+
echo "${OUT1}" | grep -q '0\ pkt\ (dropped\ 10' || die "unexpected drop count at 1"
55+
echo "${OUT2}" | grep -q '0\ pkt\ (dropped\ 30' || die "unexpected drop count at 2"
56+
echo "${OUT3}" | grep -q '0\ pkt\ (dropped\ 40' || die "unexpected drop count at 3"
57+
echo "${OUT4}" | grep -q '20\ pkt\ (dropped\ 40' || die "unexpected accept count at 4"

0 commit comments

Comments
 (0)