]>
Commit | Line | Data |
---|---|---|
c3524efc ED |
1 | /* |
2 | * Fair Queue Codel | |
3 | * | |
df1c7d91 | 4 | * Copyright (C) 2012,2015 Eric Dumazet <edumazet@google.com> |
c3524efc ED |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions, and the following disclaimer, | |
11 | * without modification. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. The names of the authors may not be used to endorse or promote products | |
16 | * derived from this software without specific prior written permission. | |
17 | * | |
18 | * Alternatively, provided that this notice is retained in full, this | |
19 | * software may be distributed under the terms of the GNU General | |
20 | * Public License ("GPL") version 2, in which case the provisions of the | |
21 | * GPL apply INSTEAD OF those given above. | |
22 | * | |
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
26 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
27 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
29 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
30 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
31 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
32 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
33 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | |
34 | * DAMAGE. | |
35 | * | |
36 | */ | |
37 | ||
38 | #include <stdio.h> | |
39 | #include <stdlib.h> | |
40 | #include <unistd.h> | |
c3524efc ED |
41 | #include <fcntl.h> |
42 | #include <sys/socket.h> | |
43 | #include <netinet/in.h> | |
44 | #include <arpa/inet.h> | |
45 | #include <string.h> | |
46 | ||
47 | #include "utils.h" | |
48 | #include "tc_util.h" | |
49 | ||
50 | static void explain(void) | |
51 | { | |
8589eb4e MC |
52 | fprintf(stderr, |
53 | "Usage: ... fq_codel [ limit PACKETS ] [ flows NUMBER ]\n" | |
54 | "[ memory_limit BYTES ]\n" | |
55 | "[ target TIME ] [ interval TIME ]\n" | |
56 | "[ quantum BYTES ] [ [no]ecn ]\n" | |
7868f802 ED |
57 | "[ ce_threshold TIME ]\n" |
58 | "[ drop_batch SIZE ]\n"); | |
c3524efc ED |
59 | } |
60 | ||
61 | static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, | |
927e3cfb | 62 | struct nlmsghdr *n, const char *dev) |
c3524efc | 63 | { |
7868f802 | 64 | unsigned int drop_batch = 0; |
32a121cb SH |
65 | unsigned int limit = 0; |
66 | unsigned int flows = 0; | |
67 | unsigned int target = 0; | |
68 | unsigned int interval = 0; | |
69 | unsigned int quantum = 0; | |
70 | unsigned int ce_threshold = ~0U; | |
4de4b5ca | 71 | unsigned int memory = ~0U; |
c3524efc ED |
72 | int ecn = -1; |
73 | struct rtattr *tail; | |
74 | ||
75 | while (argc > 0) { | |
76 | if (strcmp(*argv, "limit") == 0) { | |
77 | NEXT_ARG(); | |
78 | if (get_unsigned(&limit, *argv, 0)) { | |
79 | fprintf(stderr, "Illegal \"limit\"\n"); | |
80 | return -1; | |
81 | } | |
82 | } else if (strcmp(*argv, "flows") == 0) { | |
83 | NEXT_ARG(); | |
84 | if (get_unsigned(&flows, *argv, 0)) { | |
85 | fprintf(stderr, "Illegal \"flows\"\n"); | |
86 | return -1; | |
87 | } | |
88 | } else if (strcmp(*argv, "quantum") == 0) { | |
89 | NEXT_ARG(); | |
90 | if (get_unsigned(&quantum, *argv, 0)) { | |
91 | fprintf(stderr, "Illegal \"quantum\"\n"); | |
92 | return -1; | |
93 | } | |
7868f802 ED |
94 | } else if (strcmp(*argv, "drop_batch") == 0) { |
95 | NEXT_ARG(); | |
96 | if (get_unsigned(&drop_batch, *argv, 0)) { | |
97 | fprintf(stderr, "Illegal \"drop_batch\"\n"); | |
98 | return -1; | |
99 | } | |
c3524efc ED |
100 | } else if (strcmp(*argv, "target") == 0) { |
101 | NEXT_ARG(); | |
102 | if (get_time(&target, *argv)) { | |
103 | fprintf(stderr, "Illegal \"target\"\n"); | |
104 | return -1; | |
105 | } | |
df1c7d91 ED |
106 | } else if (strcmp(*argv, "ce_threshold") == 0) { |
107 | NEXT_ARG(); | |
108 | if (get_time(&ce_threshold, *argv)) { | |
109 | fprintf(stderr, "Illegal \"ce_threshold\"\n"); | |
110 | return -1; | |
111 | } | |
4de4b5ca ED |
112 | } else if (strcmp(*argv, "memory_limit") == 0) { |
113 | NEXT_ARG(); | |
114 | if (get_size(&memory, *argv)) { | |
115 | fprintf(stderr, "Illegal \"memory_limit\"\n"); | |
116 | return -1; | |
117 | } | |
c3524efc ED |
118 | } else if (strcmp(*argv, "interval") == 0) { |
119 | NEXT_ARG(); | |
120 | if (get_time(&interval, *argv)) { | |
121 | fprintf(stderr, "Illegal \"interval\"\n"); | |
122 | return -1; | |
123 | } | |
124 | } else if (strcmp(*argv, "ecn") == 0) { | |
125 | ecn = 1; | |
126 | } else if (strcmp(*argv, "noecn") == 0) { | |
127 | ecn = 0; | |
128 | } else if (strcmp(*argv, "help") == 0) { | |
129 | explain(); | |
130 | return -1; | |
131 | } else { | |
132 | fprintf(stderr, "What is \"%s\"?\n", *argv); | |
133 | explain(); | |
134 | return -1; | |
135 | } | |
136 | argc--; argv++; | |
137 | } | |
138 | ||
c14f9d92 | 139 | tail = addattr_nest(n, 1024, TCA_OPTIONS); |
c3524efc ED |
140 | if (limit) |
141 | addattr_l(n, 1024, TCA_FQ_CODEL_LIMIT, &limit, sizeof(limit)); | |
142 | if (flows) | |
143 | addattr_l(n, 1024, TCA_FQ_CODEL_FLOWS, &flows, sizeof(flows)); | |
144 | if (quantum) | |
145 | addattr_l(n, 1024, TCA_FQ_CODEL_QUANTUM, &quantum, sizeof(quantum)); | |
146 | if (interval) | |
147 | addattr_l(n, 1024, TCA_FQ_CODEL_INTERVAL, &interval, sizeof(interval)); | |
148 | if (target) | |
149 | addattr_l(n, 1024, TCA_FQ_CODEL_TARGET, &target, sizeof(target)); | |
150 | if (ecn != -1) | |
151 | addattr_l(n, 1024, TCA_FQ_CODEL_ECN, &ecn, sizeof(ecn)); | |
df1c7d91 ED |
152 | if (ce_threshold != ~0U) |
153 | addattr_l(n, 1024, TCA_FQ_CODEL_CE_THRESHOLD, | |
154 | &ce_threshold, sizeof(ce_threshold)); | |
4de4b5ca ED |
155 | if (memory != ~0U) |
156 | addattr_l(n, 1024, TCA_FQ_CODEL_MEMORY_LIMIT, | |
157 | &memory, sizeof(memory)); | |
7868f802 ED |
158 | if (drop_batch) |
159 | addattr_l(n, 1024, TCA_FQ_CODEL_DROP_BATCH_SIZE, &drop_batch, sizeof(drop_batch)); | |
4de4b5ca | 160 | |
c14f9d92 | 161 | addattr_nest_end(n, tail); |
c3524efc ED |
162 | return 0; |
163 | } | |
164 | ||
165 | static int fq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) | |
166 | { | |
167 | struct rtattr *tb[TCA_FQ_CODEL_MAX + 1]; | |
32a121cb SH |
168 | unsigned int limit; |
169 | unsigned int flows; | |
170 | unsigned int interval; | |
171 | unsigned int target; | |
172 | unsigned int ecn; | |
173 | unsigned int quantum; | |
174 | unsigned int ce_threshold; | |
4de4b5ca | 175 | unsigned int memory_limit; |
7868f802 | 176 | unsigned int drop_batch; |
32a121cb | 177 | |
c3524efc ED |
178 | SPRINT_BUF(b1); |
179 | ||
180 | if (opt == NULL) | |
181 | return 0; | |
182 | ||
183 | parse_rtattr_nested(tb, TCA_FQ_CODEL_MAX, opt); | |
184 | ||
185 | if (tb[TCA_FQ_CODEL_LIMIT] && | |
186 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_LIMIT]) >= sizeof(__u32)) { | |
187 | limit = rta_getattr_u32(tb[TCA_FQ_CODEL_LIMIT]); | |
378ac491 | 188 | print_uint(PRINT_ANY, "limit", "limit %up ", limit); |
c3524efc ED |
189 | } |
190 | if (tb[TCA_FQ_CODEL_FLOWS] && | |
191 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_FLOWS]) >= sizeof(__u32)) { | |
192 | flows = rta_getattr_u32(tb[TCA_FQ_CODEL_FLOWS]); | |
378ac491 | 193 | print_uint(PRINT_ANY, "flows", "flows %u ", flows); |
c3524efc ED |
194 | } |
195 | if (tb[TCA_FQ_CODEL_QUANTUM] && | |
196 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_QUANTUM]) >= sizeof(__u32)) { | |
197 | quantum = rta_getattr_u32(tb[TCA_FQ_CODEL_QUANTUM]); | |
378ac491 | 198 | print_uint(PRINT_ANY, "quantum", "quantum %u ", quantum); |
c3524efc ED |
199 | } |
200 | if (tb[TCA_FQ_CODEL_TARGET] && | |
201 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_TARGET]) >= sizeof(__u32)) { | |
202 | target = rta_getattr_u32(tb[TCA_FQ_CODEL_TARGET]); | |
378ac491 JP |
203 | print_uint(PRINT_JSON, "target", NULL, target); |
204 | print_string(PRINT_FP, NULL, "target %s ", | |
205 | sprint_time(target, b1)); | |
c3524efc | 206 | } |
df1c7d91 ED |
207 | if (tb[TCA_FQ_CODEL_CE_THRESHOLD] && |
208 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_CE_THRESHOLD]) >= sizeof(__u32)) { | |
209 | ce_threshold = rta_getattr_u32(tb[TCA_FQ_CODEL_CE_THRESHOLD]); | |
378ac491 JP |
210 | print_uint(PRINT_JSON, "ce_threshold", NULL, ce_threshold); |
211 | print_string(PRINT_FP, NULL, "ce_threshold %s ", | |
212 | sprint_time(ce_threshold, b1)); | |
df1c7d91 | 213 | } |
c3524efc ED |
214 | if (tb[TCA_FQ_CODEL_INTERVAL] && |
215 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_INTERVAL]) >= sizeof(__u32)) { | |
216 | interval = rta_getattr_u32(tb[TCA_FQ_CODEL_INTERVAL]); | |
378ac491 JP |
217 | print_uint(PRINT_JSON, "interval", NULL, interval); |
218 | print_string(PRINT_FP, NULL, "interval %s ", | |
219 | sprint_time(interval, b1)); | |
c3524efc | 220 | } |
4de4b5ca ED |
221 | if (tb[TCA_FQ_CODEL_MEMORY_LIMIT] && |
222 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_MEMORY_LIMIT]) >= sizeof(__u32)) { | |
223 | memory_limit = rta_getattr_u32(tb[TCA_FQ_CODEL_MEMORY_LIMIT]); | |
adbe5de9 PM |
224 | print_size(PRINT_ANY, "memory_limit", "memory_limit %s ", |
225 | memory_limit); | |
4de4b5ca | 226 | } |
c3524efc ED |
227 | if (tb[TCA_FQ_CODEL_ECN] && |
228 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_ECN]) >= sizeof(__u32)) { | |
229 | ecn = rta_getattr_u32(tb[TCA_FQ_CODEL_ECN]); | |
230 | if (ecn) | |
378ac491 | 231 | print_bool(PRINT_ANY, "ecn", "ecn ", true); |
c3524efc | 232 | } |
7868f802 ED |
233 | if (tb[TCA_FQ_CODEL_DROP_BATCH_SIZE] && |
234 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_DROP_BATCH_SIZE]) >= sizeof(__u32)) { | |
235 | drop_batch = rta_getattr_u32(tb[TCA_FQ_CODEL_DROP_BATCH_SIZE]); | |
236 | if (drop_batch) | |
237 | print_uint(PRINT_ANY, "drop_batch", "drop_batch %u ", drop_batch); | |
238 | } | |
c3524efc ED |
239 | |
240 | return 0; | |
241 | } | |
242 | ||
243 | static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f, | |
244 | struct rtattr *xstats) | |
245 | { | |
d17b136f | 246 | struct tc_fq_codel_xstats _st = {}, *st; |
32a121cb | 247 | |
c3524efc ED |
248 | SPRINT_BUF(b1); |
249 | ||
250 | if (xstats == NULL) | |
251 | return 0; | |
252 | ||
c3524efc | 253 | st = RTA_DATA(xstats); |
df1c7d91 | 254 | if (RTA_PAYLOAD(xstats) < sizeof(*st)) { |
df1c7d91 ED |
255 | memcpy(&_st, st, RTA_PAYLOAD(xstats)); |
256 | st = &_st; | |
257 | } | |
c3524efc | 258 | if (st->type == TCA_FQ_CODEL_XSTATS_QDISC) { |
997f2dc1 THJ |
259 | print_uint(PRINT_ANY, "maxpacket", " maxpacket %u", |
260 | st->qdisc_stats.maxpacket); | |
261 | print_uint(PRINT_ANY, "drop_overlimit", " drop_overlimit %u", | |
262 | st->qdisc_stats.drop_overlimit); | |
263 | print_uint(PRINT_ANY, "new_flow_count", " new_flow_count %u", | |
264 | st->qdisc_stats.new_flow_count); | |
265 | print_uint(PRINT_ANY, "ecn_mark", " ecn_mark %u", | |
c3524efc | 266 | st->qdisc_stats.ecn_mark); |
df1c7d91 | 267 | if (st->qdisc_stats.ce_mark) |
997f2dc1 THJ |
268 | print_uint(PRINT_ANY, "ce_mark", " ce_mark %u", |
269 | st->qdisc_stats.ce_mark); | |
4de4b5ca | 270 | if (st->qdisc_stats.memory_usage) |
997f2dc1 THJ |
271 | print_uint(PRINT_ANY, "memory_used", " memory_used %u", |
272 | st->qdisc_stats.memory_usage); | |
4de4b5ca | 273 | if (st->qdisc_stats.drop_overmemory) |
997f2dc1 THJ |
274 | print_uint(PRINT_ANY, "drop_overmemory", " drop_overmemory %u", |
275 | st->qdisc_stats.drop_overmemory); | |
7b0d424a SH |
276 | print_nl(); |
277 | print_uint(PRINT_ANY, "new_flows_len", " new_flows_len %u", | |
997f2dc1 THJ |
278 | st->qdisc_stats.new_flows_len); |
279 | print_uint(PRINT_ANY, "old_flows_len", " old_flows_len %u", | |
c3524efc ED |
280 | st->qdisc_stats.old_flows_len); |
281 | } | |
282 | if (st->type == TCA_FQ_CODEL_XSTATS_CLASS) { | |
f03ad792 | 283 | print_int(PRINT_ANY, "deficit", " deficit %d", |
997f2dc1 THJ |
284 | st->class_stats.deficit); |
285 | print_uint(PRINT_ANY, "count", " count %u", | |
286 | st->class_stats.count); | |
287 | print_uint(PRINT_ANY, "lastcount", " lastcount %u", | |
288 | st->class_stats.lastcount); | |
289 | print_uint(PRINT_JSON, "ldelay", NULL, | |
290 | st->class_stats.ldelay); | |
291 | print_string(PRINT_FP, NULL, " ldelay %s", | |
c3524efc ED |
292 | sprint_time(st->class_stats.ldelay, b1)); |
293 | if (st->class_stats.dropping) { | |
997f2dc1 | 294 | print_bool(PRINT_ANY, "dropping", " dropping", true); |
e819d3a0 LM |
295 | print_int(PRINT_JSON, "drop_next", NULL, |
296 | st->class_stats.drop_next); | |
c3524efc | 297 | if (st->class_stats.drop_next < 0) |
997f2dc1 | 298 | print_string(PRINT_FP, NULL, " drop_next -%s", |
c3524efc | 299 | sprint_time(-st->class_stats.drop_next, b1)); |
997f2dc1 | 300 | else { |
997f2dc1 | 301 | print_string(PRINT_FP, NULL, " drop_next %s", |
c3524efc | 302 | sprint_time(st->class_stats.drop_next, b1)); |
997f2dc1 | 303 | } |
c3524efc ED |
304 | } |
305 | } | |
306 | return 0; | |
307 | ||
308 | } | |
309 | ||
310 | struct qdisc_util fq_codel_qdisc_util = { | |
311 | .id = "fq_codel", | |
312 | .parse_qopt = fq_codel_parse_opt, | |
313 | .print_qopt = fq_codel_print_opt, | |
314 | .print_xstats = fq_codel_print_xstats, | |
315 | }; |