1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <unistd.h>
41#include <fcntl.h>
42#include <sys/socket.h>
43#include <netinet/in.h>
44#include <arpa/inet.h>
45#include <string.h>
46#include <stdbool.h>
47
48#include "utils.h"
49#include "tc_util.h"
50
51static void explain(void)
52{
53 fprintf(stderr,
54 "Usage: ... fq [ limit PACKETS ] [ flow_limit PACKETS ]\n"
55 " [ quantum BYTES ] [ initial_quantum BYTES ]\n"
56 " [ maxrate RATE ] [ buckets NUMBER ]\n"
57 " [ [no]pacing ] [ refill_delay TIME ]\n"
58 " [ low_rate_threshold RATE ]\n"
59 " [ orphan_mask MASK]\n"
60 " [ timer_slack TIME]\n"
61 " [ ce_threshold TIME ]\n"
62 " [ horizon TIME ]\n"
63 " [ horizon_{cap|drop} ]\n");
64}
65
66static unsigned int ilog2(unsigned int val)
67{
68 unsigned int res = 0;
69
70 val--;
71 while (val) {
72 res++;
73 val >>= 1;
74 }
75 return res;
76}
77
78static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
79 struct nlmsghdr *n, const char *dev)
80{
81 unsigned int plimit;
82 unsigned int flow_plimit;
83 unsigned int quantum;
84 unsigned int initial_quantum;
85 unsigned int buckets = 0;
86 unsigned int maxrate;
87 unsigned int low_rate_threshold;
88 unsigned int defrate;
89 unsigned int refill_delay;
90 unsigned int orphan_mask;
91 unsigned int ce_threshold;
92 unsigned int timer_slack;
93 unsigned int horizon;
94 __u8 horizon_drop = 255;
95 bool set_plimit = false;
96 bool set_flow_plimit = false;
97 bool set_quantum = false;
98 bool set_initial_quantum = false;
99 bool set_maxrate = false;
100 bool set_defrate = false;
101 bool set_refill_delay = false;
102 bool set_orphan_mask = false;
103 bool set_low_rate_threshold = false;
104 bool set_ce_threshold = false;
105 bool set_timer_slack = false;
106 bool set_horizon = false;
107 int pacing = -1;
108 struct rtattr *tail;
109
110 while (argc > 0) {
111 if (strcmp(*argv, "limit") == 0) {
112 NEXT_ARG();
113 if (get_unsigned(&plimit, *argv, 0)) {
114 fprintf(stderr, "Illegal \"limit\"\n");
115 return -1;
116 }
117 set_plimit = true;
118 } else if (strcmp(*argv, "flow_limit") == 0) {
119 NEXT_ARG();
120 if (get_unsigned(&flow_plimit, *argv, 0)) {
121 fprintf(stderr, "Illegal \"flow_limit\"\n");
122 return -1;
123 }
124 set_flow_plimit = true;
125 } else if (strcmp(*argv, "buckets") == 0) {
126 NEXT_ARG();
127 if (get_unsigned(&buckets, *argv, 0)) {
128 fprintf(stderr, "Illegal \"buckets\"\n");
129 return -1;
130 }
131 } else if (strcmp(*argv, "maxrate") == 0) {
132 NEXT_ARG();
133 if (strchr(*argv, '%')) {
134 if (get_percent_rate(&maxrate, *argv, dev)) {
135 fprintf(stderr, "Illegal \"maxrate\"\n");
136 return -1;
137 }
138 } else if (get_rate(&maxrate, *argv)) {
139 fprintf(stderr, "Illegal \"maxrate\"\n");
140 return -1;
141 }
142 set_maxrate = true;
143 } else if (strcmp(*argv, "low_rate_threshold") == 0) {
144 NEXT_ARG();
145 if (get_rate(&low_rate_threshold, *argv)) {
146 fprintf(stderr, "Illegal \"low_rate_threshold\"\n");
147 return -1;
148 }
149 set_low_rate_threshold = true;
150 } else if (strcmp(*argv, "ce_threshold") == 0) {
151 NEXT_ARG();
152 if (get_time(&ce_threshold, *argv)) {
153 fprintf(stderr, "Illegal \"ce_threshold\"\n");
154 return -1;
155 }
156 set_ce_threshold = true;
157 } else if (strcmp(*argv, "timer_slack") == 0) {
158 __s64 t64;
159
160 NEXT_ARG();
161 if (get_time64(&t64, *argv)) {
162 fprintf(stderr, "Illegal \"timer_slack\"\n");
163 return -1;
164 }
165 timer_slack = t64;
166 if (timer_slack != t64) {
167 fprintf(stderr, "Illegal (out of range) \"timer_slack\"\n");
168 return -1;
169 }
170 set_timer_slack = true;
171 } else if (strcmp(*argv, "horizon_drop") == 0) {
172 horizon_drop = 1;
173 } else if (strcmp(*argv, "horizon_cap") == 0) {
174 horizon_drop = 0;
175 } else if (strcmp(*argv, "horizon") == 0) {
176 NEXT_ARG();
177 if (get_time(&horizon, *argv)) {
178 fprintf(stderr, "Illegal \"horizon\"\n");
179 return -1;
180 }
181 set_horizon = true;
182 } else if (strcmp(*argv, "defrate") == 0) {
183 NEXT_ARG();
184 if (strchr(*argv, '%')) {
185 if (get_percent_rate(&defrate, *argv, dev)) {
186 fprintf(stderr, "Illegal \"defrate\"\n");
187 return -1;
188 }
189 } else if (get_rate(&defrate, *argv)) {
190 fprintf(stderr, "Illegal \"defrate\"\n");
191 return -1;
192 }
193 set_defrate = true;
194 } else if (strcmp(*argv, "quantum") == 0) {
195 NEXT_ARG();
196 if (get_unsigned(&quantum, *argv, 0)) {
197 fprintf(stderr, "Illegal \"quantum\"\n");
198 return -1;
199 }
200 set_quantum = true;
201 } else if (strcmp(*argv, "initial_quantum") == 0) {
202 NEXT_ARG();
203 if (get_unsigned(&initial_quantum, *argv, 0)) {
204 fprintf(stderr, "Illegal \"initial_quantum\"\n");
205 return -1;
206 }
207 set_initial_quantum = true;
208 } else if (strcmp(*argv, "orphan_mask") == 0) {
209 NEXT_ARG();
210 if (get_unsigned(&orphan_mask, *argv, 0)) {
211 fprintf(stderr, "Illegal \"initial_quantum\"\n");
212 return -1;
213 }
214 set_orphan_mask = true;
215 } else if (strcmp(*argv, "refill_delay") == 0) {
216 NEXT_ARG();
217 if (get_time(&refill_delay, *argv)) {
218 fprintf(stderr, "Illegal \"refill_delay\"\n");
219 return -1;
220 }
221 set_refill_delay = true;
222 } else if (strcmp(*argv, "pacing") == 0) {
223 pacing = 1;
224 } else if (strcmp(*argv, "nopacing") == 0) {
225 pacing = 0;
226 } else if (strcmp(*argv, "help") == 0) {
227 explain();
228 return -1;
229 } else {
230 fprintf(stderr, "What is \"%s\"?\n", *argv);
231 explain();
232 return -1;
233 }
234 argc--; argv++;
235 }
236
237 tail = addattr_nest(n, 1024, TCA_OPTIONS);
238 if (buckets) {
239 unsigned int log = ilog2(buckets);
240
241 addattr_l(n, 1024, TCA_FQ_BUCKETS_LOG,
242 &log, sizeof(log));
243 }
244 if (set_plimit)
245 addattr_l(n, 1024, TCA_FQ_PLIMIT,
246 &plimit, sizeof(plimit));
247 if (set_flow_plimit)
248 addattr_l(n, 1024, TCA_FQ_FLOW_PLIMIT,
249 &flow_plimit, sizeof(flow_plimit));
250 if (set_quantum)
251 addattr_l(n, 1024, TCA_FQ_QUANTUM, &quantum, sizeof(quantum));
252 if (set_initial_quantum)
253 addattr_l(n, 1024, TCA_FQ_INITIAL_QUANTUM,
254 &initial_quantum, sizeof(initial_quantum));
255 if (pacing != -1)
256 addattr_l(n, 1024, TCA_FQ_RATE_ENABLE,
257 &pacing, sizeof(pacing));
258 if (set_maxrate)
259 addattr_l(n, 1024, TCA_FQ_FLOW_MAX_RATE,
260 &maxrate, sizeof(maxrate));
261 if (set_low_rate_threshold)
262 addattr_l(n, 1024, TCA_FQ_LOW_RATE_THRESHOLD,
263 &low_rate_threshold, sizeof(low_rate_threshold));
264 if (set_defrate)
265 addattr_l(n, 1024, TCA_FQ_FLOW_DEFAULT_RATE,
266 &defrate, sizeof(defrate));
267 if (set_refill_delay)
268 addattr_l(n, 1024, TCA_FQ_FLOW_REFILL_DELAY,
269 &refill_delay, sizeof(refill_delay));
270 if (set_orphan_mask)
271 addattr_l(n, 1024, TCA_FQ_ORPHAN_MASK,
272 &orphan_mask, sizeof(orphan_mask));
273 if (set_ce_threshold)
274 addattr_l(n, 1024, TCA_FQ_CE_THRESHOLD,
275 &ce_threshold, sizeof(ce_threshold));
276 if (set_timer_slack)
277 addattr_l(n, 1024, TCA_FQ_TIMER_SLACK,
278 &timer_slack, sizeof(timer_slack));
279 if (set_horizon)
280 addattr_l(n, 1024, TCA_FQ_HORIZON,
281 &horizon, sizeof(horizon));
282 if (horizon_drop != 255)
283 addattr_l(n, 1024, TCA_FQ_HORIZON_DROP,
284 &horizon_drop, sizeof(horizon_drop));
285 addattr_nest_end(n, tail);
286 return 0;
287}
288
289static int fq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
290{
291 struct rtattr *tb[TCA_FQ_MAX + 1];
292 unsigned int plimit, flow_plimit;
293 unsigned int buckets_log;
294 int pacing;
295 unsigned int rate, quantum;
296 unsigned int refill_delay;
297 unsigned int orphan_mask;
298 unsigned int ce_threshold;
299 unsigned int timer_slack;
300 unsigned int horizon;
301 __u8 horizon_drop;
302
303 SPRINT_BUF(b1);
304
305 if (opt == NULL)
306 return 0;
307
308 parse_rtattr_nested(tb, TCA_FQ_MAX, opt);
309
310 if (tb[TCA_FQ_PLIMIT] &&
311 RTA_PAYLOAD(tb[TCA_FQ_PLIMIT]) >= sizeof(__u32)) {
312 plimit = rta_getattr_u32(tb[TCA_FQ_PLIMIT]);
313 print_uint(PRINT_ANY, "limit", "limit %up ", plimit);
314 }
315 if (tb[TCA_FQ_FLOW_PLIMIT] &&
316 RTA_PAYLOAD(tb[TCA_FQ_FLOW_PLIMIT]) >= sizeof(__u32)) {
317 flow_plimit = rta_getattr_u32(tb[TCA_FQ_FLOW_PLIMIT]);
318 print_uint(PRINT_ANY, "flow_limit", "flow_limit %up ",
319 flow_plimit);
320 }
321 if (tb[TCA_FQ_BUCKETS_LOG] &&
322 RTA_PAYLOAD(tb[TCA_FQ_BUCKETS_LOG]) >= sizeof(__u32)) {
323 buckets_log = rta_getattr_u32(tb[TCA_FQ_BUCKETS_LOG]);
324 print_uint(PRINT_ANY, "buckets", "buckets %u ",
325 1U << buckets_log);
326 }
327 if (tb[TCA_FQ_ORPHAN_MASK] &&
328 RTA_PAYLOAD(tb[TCA_FQ_ORPHAN_MASK]) >= sizeof(__u32)) {
329 orphan_mask = rta_getattr_u32(tb[TCA_FQ_ORPHAN_MASK]);
330 print_uint(PRINT_ANY, "orphan_mask", "orphan_mask %u ",
331 orphan_mask);
332 }
333 if (tb[TCA_FQ_RATE_ENABLE] &&
334 RTA_PAYLOAD(tb[TCA_FQ_RATE_ENABLE]) >= sizeof(int)) {
335 pacing = rta_getattr_u32(tb[TCA_FQ_RATE_ENABLE]);
336 if (pacing == 0)
337 print_bool(PRINT_ANY, "pacing", "nopacing ", false);
338 }
339 if (tb[TCA_FQ_QUANTUM] &&
340 RTA_PAYLOAD(tb[TCA_FQ_QUANTUM]) >= sizeof(__u32)) {
341 quantum = rta_getattr_u32(tb[TCA_FQ_QUANTUM]);
342 print_size(PRINT_ANY, "quantum", "quantum %s ", quantum);
343 }
344 if (tb[TCA_FQ_INITIAL_QUANTUM] &&
345 RTA_PAYLOAD(tb[TCA_FQ_INITIAL_QUANTUM]) >= sizeof(__u32)) {
346 quantum = rta_getattr_u32(tb[TCA_FQ_INITIAL_QUANTUM]);
347 print_size(PRINT_ANY, "initial_quantum", "initial_quantum %s ",
348 quantum);
349 }
350 if (tb[TCA_FQ_FLOW_MAX_RATE] &&
351 RTA_PAYLOAD(tb[TCA_FQ_FLOW_MAX_RATE]) >= sizeof(__u32)) {
352 rate = rta_getattr_u32(tb[TCA_FQ_FLOW_MAX_RATE]);
353
354 if (rate != ~0U)
355 tc_print_rate(PRINT_ANY,
356 "maxrate", "maxrate %s ", rate);
357 }
358 if (tb[TCA_FQ_FLOW_DEFAULT_RATE] &&
359 RTA_PAYLOAD(tb[TCA_FQ_FLOW_DEFAULT_RATE]) >= sizeof(__u32)) {
360 rate = rta_getattr_u32(tb[TCA_FQ_FLOW_DEFAULT_RATE]);
361
362 if (rate != 0)
363 tc_print_rate(PRINT_ANY,
364 "defrate", "defrate %s ", rate);
365 }
366 if (tb[TCA_FQ_LOW_RATE_THRESHOLD] &&
367 RTA_PAYLOAD(tb[TCA_FQ_LOW_RATE_THRESHOLD]) >= sizeof(__u32)) {
368 rate = rta_getattr_u32(tb[TCA_FQ_LOW_RATE_THRESHOLD]);
369
370 if (rate != 0)
371 tc_print_rate(PRINT_ANY, "low_rate_threshold",
372 "low_rate_threshold %s ", rate);
373 }
374 if (tb[TCA_FQ_FLOW_REFILL_DELAY] &&
375 RTA_PAYLOAD(tb[TCA_FQ_FLOW_REFILL_DELAY]) >= sizeof(__u32)) {
376 refill_delay = rta_getattr_u32(tb[TCA_FQ_FLOW_REFILL_DELAY]);
377 print_uint(PRINT_JSON, "refill_delay", NULL, refill_delay);
378 print_string(PRINT_FP, NULL, "refill_delay %s ",
379 sprint_time(refill_delay, b1));
380 }
381
382 if (tb[TCA_FQ_CE_THRESHOLD] &&
383 RTA_PAYLOAD(tb[TCA_FQ_CE_THRESHOLD]) >= sizeof(__u32)) {
384 ce_threshold = rta_getattr_u32(tb[TCA_FQ_CE_THRESHOLD]);
385 if (ce_threshold != ~0U) {
386 print_uint(PRINT_JSON, "ce_threshold", NULL,
387 ce_threshold);
388 print_string(PRINT_FP, NULL, "ce_threshold %s ",
389 sprint_time(ce_threshold, b1));
390 }
391 }
392
393 if (tb[TCA_FQ_TIMER_SLACK] &&
394 RTA_PAYLOAD(tb[TCA_FQ_TIMER_SLACK]) >= sizeof(__u32)) {
395 timer_slack = rta_getattr_u32(tb[TCA_FQ_TIMER_SLACK]);
396 print_uint(PRINT_JSON, "timer_slack", NULL, timer_slack);
397 print_string(PRINT_FP, NULL, "timer_slack %s ",
398 sprint_time64(timer_slack, b1));
399 }
400
401 if (tb[TCA_FQ_HORIZON] &&
402 RTA_PAYLOAD(tb[TCA_FQ_HORIZON]) >= sizeof(__u32)) {
403 horizon = rta_getattr_u32(tb[TCA_FQ_HORIZON]);
404 print_uint(PRINT_JSON, "horizon", NULL, horizon);
405 print_string(PRINT_FP, NULL, "horizon %s ",
406 sprint_time(horizon, b1));
407 }
408
409 if (tb[TCA_FQ_HORIZON_DROP] &&
410 RTA_PAYLOAD(tb[TCA_FQ_HORIZON_DROP]) >= sizeof(__u8)) {
411 horizon_drop = rta_getattr_u8(tb[TCA_FQ_HORIZON_DROP]);
412 if (!horizon_drop)
413 print_null(PRINT_ANY, "horizon_cap", "horizon_cap ", NULL);
414 else
415 print_null(PRINT_ANY, "horizon_drop", "horizon_drop ", NULL);
416 }
417
418 return 0;
419}
420
421static int fq_print_xstats(struct qdisc_util *qu, FILE *f,
422 struct rtattr *xstats)
423{
424 struct tc_fq_qd_stats *st, _st;
425
426 SPRINT_BUF(b1);
427
428 if (xstats == NULL)
429 return 0;
430
431 memset(&_st, 0, sizeof(_st));
432 memcpy(&_st, RTA_DATA(xstats), min(RTA_PAYLOAD(xstats), sizeof(*st)));
433
434 st = &_st;
435
436 print_uint(PRINT_ANY, "flows", " flows %u", st->flows);
437 print_uint(PRINT_ANY, "inactive", " (inactive %u", st->inactive_flows);
438 print_uint(PRINT_ANY, "throttled", " throttled %u)",
439 st->throttled_flows);
440
441 if (st->time_next_delayed_flow > 0) {
442 print_lluint(PRINT_JSON, "next_packet_delay", NULL,
443 st->time_next_delayed_flow);
444 print_string(PRINT_FP, NULL, " next_packet_delay %s",
445 sprint_time64(st->time_next_delayed_flow, b1));
446 }
447
448 print_nl();
449 print_lluint(PRINT_ANY, "gc", " gc %llu", st->gc_flows);
450 print_lluint(PRINT_ANY, "highprio", " highprio %llu",
451 st->highprio_packets);
452
453 if (st->tcp_retrans)
454 print_lluint(PRINT_ANY, "retrans", " retrans %llu",
455 st->tcp_retrans);
456
457 print_lluint(PRINT_ANY, "throttled", " throttled %llu", st->throttled);
458
459 if (st->unthrottle_latency_ns) {
460 print_uint(PRINT_JSON, "latency", NULL,
461 st->unthrottle_latency_ns);
462 print_string(PRINT_FP, NULL, " latency %s",
463 sprint_time64(st->unthrottle_latency_ns, b1));
464 }
465
466 if (st->ce_mark)
467 print_lluint(PRINT_ANY, "ce_mark", " ce_mark %llu",
468 st->ce_mark);
469
470 if (st->flows_plimit)
471 print_lluint(PRINT_ANY, "flows_plimit", " flows_plimit %llu",
472 st->flows_plimit);
473
474 if (st->pkts_too_long || st->allocation_errors ||
475 st->horizon_drops || st->horizon_caps) {
476 print_nl();
477 if (st->pkts_too_long)
478 print_lluint(PRINT_ANY, "pkts_too_long",
479 " pkts_too_long %llu",
480 st->pkts_too_long);
481 if (st->allocation_errors)
482 print_lluint(PRINT_ANY, "alloc_errors",
483 " alloc_errors %llu",
484 st->allocation_errors);
485 if (st->horizon_drops)
486 print_lluint(PRINT_ANY, "horizon_drops",
487 " horizon_drops %llu",
488 st->horizon_drops);
489 if (st->horizon_caps)
490 print_lluint(PRINT_ANY, "horizon_caps",
491 " horizon_caps %llu",
492 st->horizon_caps);
493 }
494
495 return 0;
496}
497
498struct qdisc_util fq_qdisc_util = {
499 .id = "fq",
500 .parse_qopt = fq_parse_opt,
501 .print_qopt = fq_print_opt,
502 .print_xstats = fq_print_xstats,
503};
504