]> git.proxmox.com Git - mirror_iproute2.git/blame - tc/q_cbq.c
bridge: fdb: add support for src_vni option
[mirror_iproute2.git] / tc / q_cbq.c
CommitLineData
aba5acdf
SH
1/*
2 * q_cbq.c CBQ.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 *
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <unistd.h>
aba5acdf
SH
16#include <fcntl.h>
17#include <sys/socket.h>
18#include <netinet/in.h>
19#include <arpa/inet.h>
20#include <string.h>
21
22#include "utils.h"
23#include "tc_util.h"
24#include "tc_cbq.h"
25
26static void explain_class(void)
27{
28 fprintf(stderr, "Usage: ... cbq bandwidth BPS rate BPS maxburst PKTS [ avpkt BYTES ]\n");
29 fprintf(stderr, " [ minburst PKTS ] [ bounded ] [ isolated ]\n");
30 fprintf(stderr, " [ allot BYTES ] [ mpu BYTES ] [ weight RATE ]\n");
31 fprintf(stderr, " [ prio NUMBER ] [ cell BYTES ] [ ewma LOG ]\n");
32 fprintf(stderr, " [ estimator INTERVAL TIME_CONSTANT ]\n");
33 fprintf(stderr, " [ split CLASSID ] [ defmap MASK/CHANGE ]\n");
292f29b4 34 fprintf(stderr, " [ overhead BYTES ] [ linklayer TYPE ]\n");
aba5acdf
SH
35}
36
37static void explain(void)
38{
39 fprintf(stderr, "Usage: ... cbq bandwidth BPS avpkt BYTES [ mpu BYTES ]\n");
40 fprintf(stderr, " [ cell BYTES ] [ ewma LOG ]\n");
41}
42
43static void explain1(char *arg)
44{
45 fprintf(stderr, "Illegal \"%s\"\n", arg);
46}
47
aba5acdf 48
927e3cfb 49static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
aba5acdf 50{
d17b136f
PS
51 struct tc_ratespec r = {};
52 struct tc_cbq_lssopt lss = {};
aba5acdf 53 __u32 rtab[256];
32a121cb
SH
54 unsigned mpu = 0, avpkt = 0, allot = 0;
55 unsigned short overhead = 0;
292f29b4 56 unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
32a121cb
SH
57 int cell_log = -1;
58 int ewma_log = -1;
aba5acdf
SH
59 struct rtattr *tail;
60
aba5acdf 61 while (argc > 0) {
1db5e2ec
JDB
62 if (matches(*argv, "bandwidth") == 0 ||
63 matches(*argv, "rate") == 0) {
aba5acdf 64 NEXT_ARG();
927e3cfb
ND
65 if (strchr(*argv, '%')) {
66 if (get_percent_rate(&r.rate, *argv, dev)) {
67 explain1("bandwidth");
68 return -1;
69 }
70 } else if (get_rate(&r.rate, *argv)) {
aba5acdf
SH
71 explain1("bandwidth");
72 return -1;
73 }
1db5e2ec 74 } else if (matches(*argv, "ewma") == 0) {
aba5acdf 75 NEXT_ARG();
f332d169 76 if (get_integer(&ewma_log, *argv, 0)) {
aba5acdf
SH
77 explain1("ewma");
78 return -1;
79 }
80 if (ewma_log > 31) {
81 fprintf(stderr, "ewma_log must be < 32\n");
82 return -1;
83 }
1db5e2ec 84 } else if (matches(*argv, "cell") == 0) {
32a121cb 85 unsigned int cell;
aba5acdf 86 int i;
32a121cb 87
aba5acdf
SH
88 NEXT_ARG();
89 if (get_size(&cell, *argv)) {
90 explain1("cell");
91 return -1;
92 }
32a121cb 93 for (i = 0; i < 32; i++)
aba5acdf
SH
94 if ((1<<i) == cell)
95 break;
32a121cb 96 if (i >= 32) {
aba5acdf
SH
97 fprintf(stderr, "cell must be 2^n\n");
98 return -1;
99 }
100 cell_log = i;
1db5e2ec 101 } else if (matches(*argv, "avpkt") == 0) {
aba5acdf
SH
102 NEXT_ARG();
103 if (get_size(&avpkt, *argv)) {
104 explain1("avpkt");
105 return -1;
106 }
1db5e2ec 107 } else if (matches(*argv, "mpu") == 0) {
aba5acdf
SH
108 NEXT_ARG();
109 if (get_size(&mpu, *argv)) {
110 explain1("mpu");
111 return -1;
112 }
1db5e2ec 113 } else if (matches(*argv, "allot") == 0) {
aba5acdf
SH
114 NEXT_ARG();
115 /* Accept and ignore "allot" for backward compatibility */
116 if (get_size(&allot, *argv)) {
117 explain1("allot");
118 return -1;
119 }
08fd0184
JDB
120 } else if (matches(*argv, "overhead") == 0) {
121 NEXT_ARG();
122 if (get_u16(&overhead, *argv, 10)) {
123 explain1("overhead"); return -1;
124 }
292f29b4
JDB
125 } else if (matches(*argv, "linklayer") == 0) {
126 NEXT_ARG();
127 if (get_linklayer(&linklayer, *argv)) {
128 explain1("linklayer"); return -1;
129 }
1db5e2ec 130 } else if (matches(*argv, "help") == 0) {
aba5acdf
SH
131 explain();
132 return -1;
133 } else {
134 fprintf(stderr, "What is \"%s\"?\n", *argv);
135 explain();
136 return -1;
137 }
138 argc--; argv++;
139 }
140
141 /* OK. All options are parsed. */
142
143 if (r.rate == 0) {
144 fprintf(stderr, "CBQ: bandwidth is required parameter.\n");
145 return -1;
146 }
147 if (avpkt == 0) {
148 fprintf(stderr, "CBQ: \"avpkt\" is required.\n");
149 return -1;
150 }
151 if (allot < (avpkt*3)/2)
152 allot = (avpkt*3)/2;
153
d5f46f9c 154 r.mpu = mpu;
08fd0184 155 r.overhead = overhead;
292f29b4 156 if (tc_calc_rtable(&r, rtab, cell_log, allot, linklayer) < 0) {
aba5acdf
SH
157 fprintf(stderr, "CBQ: failed to calculate rate table.\n");
158 return -1;
159 }
aba5acdf
SH
160
161 if (ewma_log < 0)
162 ewma_log = TC_CBQ_DEF_EWMA;
163 lss.ewma_log = ewma_log;
476daa72 164 lss.maxidle = tc_calc_xmittime(r.rate, avpkt);
aba5acdf
SH
165 lss.change = TCF_CBQ_LSS_MAXIDLE|TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
166 lss.avpkt = avpkt;
167
c14f9d92 168 tail = addattr_nest(n, 1024, TCA_OPTIONS);
aba5acdf
SH
169 addattr_l(n, 1024, TCA_CBQ_RATE, &r, sizeof(r));
170 addattr_l(n, 1024, TCA_CBQ_LSSOPT, &lss, sizeof(lss));
171 addattr_l(n, 3024, TCA_CBQ_RTAB, rtab, 1024);
172 if (show_raw) {
173 int i;
32a121cb
SH
174
175 for (i = 0; i < 256; i++)
aba5acdf
SH
176 printf("%u ", rtab[i]);
177 printf("\n");
178 }
c14f9d92 179 addattr_nest_end(n, tail);
aba5acdf
SH
180 return 0;
181}
182
927e3cfb 183static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
aba5acdf 184{
32a121cb 185 int wrr_ok = 0, fopt_ok = 0;
d17b136f
PS
186 struct tc_ratespec r = {};
187 struct tc_cbq_lssopt lss = {};
188 struct tc_cbq_wrropt wrr = {};
189 struct tc_cbq_fopt fopt = {};
aba5acdf 190 __u32 rtab[256];
32a121cb
SH
191 unsigned mpu = 0;
192 int cell_log = -1;
193 int ewma_log = -1;
194 unsigned int bndw = 0;
195 unsigned minburst = 0, maxburst = 0;
196 unsigned short overhead = 0;
292f29b4 197 unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
aba5acdf
SH
198 struct rtattr *tail;
199
aba5acdf 200 while (argc > 0) {
1db5e2ec 201 if (matches(*argv, "rate") == 0) {
aba5acdf 202 NEXT_ARG();
927e3cfb
ND
203 if (strchr(*argv, '%')) {
204 if (get_percent_rate(&r.rate, *argv, dev)) {
205 explain1("rate");
206 return -1;
207 }
208 } else if (get_rate(&r.rate, *argv)) {
aba5acdf
SH
209 explain1("rate");
210 return -1;
211 }
1db5e2ec 212 } else if (matches(*argv, "bandwidth") == 0) {
aba5acdf 213 NEXT_ARG();
927e3cfb
ND
214 if (strchr(*argv, '%')) {
215 if (get_percent_rate(&bndw, *argv, dev)) {
216 explain1("bandwidth");
217 return -1;
218 }
219 } else if (get_rate(&bndw, *argv)) {
aba5acdf
SH
220 explain1("bandwidth");
221 return -1;
222 }
1db5e2ec 223 } else if (matches(*argv, "minidle") == 0) {
aba5acdf
SH
224 NEXT_ARG();
225 if (get_u32(&lss.minidle, *argv, 0)) {
226 explain1("minidle");
227 return -1;
228 }
229 lss.change |= TCF_CBQ_LSS_MINIDLE;
1db5e2ec 230 } else if (matches(*argv, "minburst") == 0) {
aba5acdf
SH
231 NEXT_ARG();
232 if (get_u32(&minburst, *argv, 0)) {
233 explain1("minburst");
234 return -1;
235 }
236 lss.change |= TCF_CBQ_LSS_OFFTIME;
1db5e2ec 237 } else if (matches(*argv, "maxburst") == 0) {
aba5acdf
SH
238 NEXT_ARG();
239 if (get_u32(&maxburst, *argv, 0)) {
240 explain1("maxburst");
241 return -1;
242 }
243 lss.change |= TCF_CBQ_LSS_MAXIDLE;
1db5e2ec 244 } else if (matches(*argv, "bounded") == 0) {
aba5acdf
SH
245 lss.flags |= TCF_CBQ_LSS_BOUNDED;
246 lss.change |= TCF_CBQ_LSS_FLAGS;
1db5e2ec 247 } else if (matches(*argv, "borrow") == 0) {
aba5acdf
SH
248 lss.flags &= ~TCF_CBQ_LSS_BOUNDED;
249 lss.change |= TCF_CBQ_LSS_FLAGS;
1db5e2ec 250 } else if (matches(*argv, "isolated") == 0) {
aba5acdf
SH
251 lss.flags |= TCF_CBQ_LSS_ISOLATED;
252 lss.change |= TCF_CBQ_LSS_FLAGS;
1db5e2ec 253 } else if (matches(*argv, "sharing") == 0) {
aba5acdf
SH
254 lss.flags &= ~TCF_CBQ_LSS_ISOLATED;
255 lss.change |= TCF_CBQ_LSS_FLAGS;
1db5e2ec 256 } else if (matches(*argv, "ewma") == 0) {
aba5acdf 257 NEXT_ARG();
f332d169 258 if (get_integer(&ewma_log, *argv, 0)) {
aba5acdf
SH
259 explain1("ewma");
260 return -1;
261 }
262 if (ewma_log > 31) {
263 fprintf(stderr, "ewma_log must be < 32\n");
264 return -1;
265 }
266 lss.change |= TCF_CBQ_LSS_EWMA;
1db5e2ec 267 } else if (matches(*argv, "cell") == 0) {
32a121cb 268 unsigned int cell;
aba5acdf 269 int i;
32a121cb 270
aba5acdf
SH
271 NEXT_ARG();
272 if (get_size(&cell, *argv)) {
273 explain1("cell");
274 return -1;
275 }
32a121cb 276 for (i = 0; i < 32; i++)
aba5acdf
SH
277 if ((1<<i) == cell)
278 break;
32a121cb 279 if (i >= 32) {
aba5acdf
SH
280 fprintf(stderr, "cell must be 2^n\n");
281 return -1;
282 }
283 cell_log = i;
1db5e2ec 284 } else if (matches(*argv, "prio") == 0) {
32a121cb
SH
285 unsigned int prio;
286
aba5acdf
SH
287 NEXT_ARG();
288 if (get_u32(&prio, *argv, 0)) {
289 explain1("prio");
290 return -1;
291 }
292 if (prio > TC_CBQ_MAXPRIO) {
293 fprintf(stderr, "\"prio\" must be number in the range 1...%d\n", TC_CBQ_MAXPRIO);
294 return -1;
295 }
296 wrr.priority = prio;
297 wrr_ok++;
1db5e2ec 298 } else if (matches(*argv, "allot") == 0) {
aba5acdf
SH
299 NEXT_ARG();
300 if (get_size(&wrr.allot, *argv)) {
301 explain1("allot");
302 return -1;
303 }
1db5e2ec 304 } else if (matches(*argv, "avpkt") == 0) {
aba5acdf
SH
305 NEXT_ARG();
306 if (get_size(&lss.avpkt, *argv)) {
307 explain1("avpkt");
308 return -1;
309 }
310 lss.change |= TCF_CBQ_LSS_AVPKT;
1db5e2ec 311 } else if (matches(*argv, "mpu") == 0) {
aba5acdf
SH
312 NEXT_ARG();
313 if (get_size(&mpu, *argv)) {
314 explain1("mpu");
315 return -1;
316 }
1db5e2ec 317 } else if (matches(*argv, "weight") == 0) {
aba5acdf
SH
318 NEXT_ARG();
319 if (get_size(&wrr.weight, *argv)) {
320 explain1("weight");
321 return -1;
322 }
323 wrr_ok++;
1db5e2ec 324 } else if (matches(*argv, "split") == 0) {
aba5acdf
SH
325 NEXT_ARG();
326 if (get_tc_classid(&fopt.split, *argv)) {
327 fprintf(stderr, "Invalid split node ID.\n");
8d8de113 328 return -1;
aba5acdf
SH
329 }
330 fopt_ok++;
1db5e2ec 331 } else if (matches(*argv, "defmap") == 0) {
aba5acdf 332 int err;
32a121cb 333
aba5acdf
SH
334 NEXT_ARG();
335 err = sscanf(*argv, "%08x/%08x", &fopt.defmap, &fopt.defchange);
336 if (err < 1) {
337 fprintf(stderr, "Invalid defmap, should be MASK32[/MASK]\n");
338 return -1;
339 }
340 if (err == 1)
341 fopt.defchange = ~0;
342 fopt_ok++;
08fd0184
JDB
343 } else if (matches(*argv, "overhead") == 0) {
344 NEXT_ARG();
345 if (get_u16(&overhead, *argv, 10)) {
346 explain1("overhead"); return -1;
347 }
292f29b4
JDB
348 } else if (matches(*argv, "linklayer") == 0) {
349 NEXT_ARG();
350 if (get_linklayer(&linklayer, *argv)) {
351 explain1("linklayer"); return -1;
352 }
1db5e2ec 353 } else if (matches(*argv, "help") == 0) {
aba5acdf
SH
354 explain_class();
355 return -1;
356 } else {
357 fprintf(stderr, "What is \"%s\"?\n", *argv);
358 explain_class();
359 return -1;
360 }
361 argc--; argv++;
362 }
363
364 /* OK. All options are parsed. */
365
366 /* 1. Prepare link sharing scheduler parameters */
367 if (r.rate) {
32a121cb
SH
368 unsigned int pktsize = wrr.allot;
369
aba5acdf
SH
370 if (wrr.allot < (lss.avpkt*3)/2)
371 wrr.allot = (lss.avpkt*3)/2;
d5f46f9c 372 r.mpu = mpu;
08fd0184 373 r.overhead = overhead;
292f29b4 374 if (tc_calc_rtable(&r, rtab, cell_log, pktsize, linklayer) < 0) {
aba5acdf
SH
375 fprintf(stderr, "CBQ: failed to calculate rate table.\n");
376 return -1;
377 }
aba5acdf
SH
378 }
379 if (ewma_log < 0)
380 ewma_log = TC_CBQ_DEF_EWMA;
381 lss.ewma_log = ewma_log;
382 if (lss.change&(TCF_CBQ_LSS_OFFTIME|TCF_CBQ_LSS_MAXIDLE)) {
383 if (lss.avpkt == 0) {
384 fprintf(stderr, "CBQ: avpkt is required for max/minburst.\n");
385 return -1;
386 }
32a121cb 387 if (bndw == 0 || r.rate == 0) {
aba5acdf
SH
388 fprintf(stderr, "CBQ: bandwidth&rate are required for max/minburst.\n");
389 return -1;
390 }
391 }
392 if (wrr.priority == 0 && (n->nlmsg_flags&NLM_F_EXCL)) {
393 wrr_ok = 1;
394 wrr.priority = TC_CBQ_MAXPRIO;
395 if (wrr.allot == 0)
396 wrr.allot = (lss.avpkt*3)/2;
397 }
398 if (wrr_ok) {
399 if (wrr.weight == 0)
400 wrr.weight = (wrr.priority == TC_CBQ_MAXPRIO) ? 1 : r.rate;
401 if (wrr.allot == 0) {
402 fprintf(stderr, "CBQ: \"allot\" is required to set WRR parameters.\n");
403 return -1;
404 }
405 }
406 if (lss.change&TCF_CBQ_LSS_MAXIDLE) {
407 lss.maxidle = tc_cbq_calc_maxidle(bndw, r.rate, lss.avpkt, ewma_log, maxburst);
408 lss.change |= TCF_CBQ_LSS_MAXIDLE;
409 lss.change |= TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
410 }
411 if (lss.change&TCF_CBQ_LSS_OFFTIME) {
412 lss.offtime = tc_cbq_calc_offtime(bndw, r.rate, lss.avpkt, ewma_log, minburst);
413 lss.change |= TCF_CBQ_LSS_OFFTIME;
414 lss.change |= TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
415 }
416 if (lss.change&TCF_CBQ_LSS_MINIDLE) {
417 lss.minidle <<= lss.ewma_log;
418 lss.change |= TCF_CBQ_LSS_EWMA;
419 }
420
c14f9d92 421 tail = addattr_nest(n, 1024, TCA_OPTIONS);
aba5acdf
SH
422 if (lss.change) {
423 lss.change |= TCF_CBQ_LSS_FLAGS;
424 addattr_l(n, 1024, TCA_CBQ_LSSOPT, &lss, sizeof(lss));
425 }
426 if (wrr_ok)
427 addattr_l(n, 1024, TCA_CBQ_WRROPT, &wrr, sizeof(wrr));
428 if (fopt_ok)
429 addattr_l(n, 1024, TCA_CBQ_FOPT, &fopt, sizeof(fopt));
430 if (r.rate) {
431 addattr_l(n, 1024, TCA_CBQ_RATE, &r, sizeof(r));
432 addattr_l(n, 3024, TCA_CBQ_RTAB, rtab, 1024);
433 if (show_raw) {
434 int i;
32a121cb
SH
435
436 for (i = 0; i < 256; i++)
aba5acdf
SH
437 printf("%u ", rtab[i]);
438 printf("\n");
439 }
440 }
c14f9d92 441 addattr_nest_end(n, tail);
aba5acdf
SH
442 return 0;
443}
444
445
446static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
447{
448 struct rtattr *tb[TCA_CBQ_MAX+1];
449 struct tc_ratespec *r = NULL;
450 struct tc_cbq_lssopt *lss = NULL;
451 struct tc_cbq_wrropt *wrr = NULL;
452 struct tc_cbq_fopt *fopt = NULL;
453 struct tc_cbq_ovl *ovl = NULL;
3e92ff52 454 unsigned int linklayer;
32a121cb 455
bd29e35d 456 SPRINT_BUF(b1);
3e92ff52 457 SPRINT_BUF(b2);
aba5acdf
SH
458
459 if (opt == NULL)
460 return 0;
461
021ed13f 462 parse_rtattr_nested(tb, TCA_CBQ_MAX, opt);
aba5acdf
SH
463
464 if (tb[TCA_CBQ_RATE]) {
465 if (RTA_PAYLOAD(tb[TCA_CBQ_RATE]) < sizeof(*r))
466 fprintf(stderr, "CBQ: too short rate opt\n");
467 else
468 r = RTA_DATA(tb[TCA_CBQ_RATE]);
469 }
470 if (tb[TCA_CBQ_LSSOPT]) {
471 if (RTA_PAYLOAD(tb[TCA_CBQ_LSSOPT]) < sizeof(*lss))
472 fprintf(stderr, "CBQ: too short lss opt\n");
473 else
474 lss = RTA_DATA(tb[TCA_CBQ_LSSOPT]);
475 }
476 if (tb[TCA_CBQ_WRROPT]) {
477 if (RTA_PAYLOAD(tb[TCA_CBQ_WRROPT]) < sizeof(*wrr))
478 fprintf(stderr, "CBQ: too short wrr opt\n");
479 else
480 wrr = RTA_DATA(tb[TCA_CBQ_WRROPT]);
481 }
482 if (tb[TCA_CBQ_FOPT]) {
483 if (RTA_PAYLOAD(tb[TCA_CBQ_FOPT]) < sizeof(*fopt))
484 fprintf(stderr, "CBQ: too short fopt\n");
485 else
486 fopt = RTA_DATA(tb[TCA_CBQ_FOPT]);
487 }
488 if (tb[TCA_CBQ_OVL_STRATEGY]) {
489 if (RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]) < sizeof(*ovl))
490 fprintf(stderr, "CBQ: too short overlimit strategy %u/%u\n",
32a121cb
SH
491 (unsigned int) RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]),
492 (unsigned int) sizeof(*ovl));
aba5acdf
SH
493 else
494 ovl = RTA_DATA(tb[TCA_CBQ_OVL_STRATEGY]);
495 }
496
497 if (r) {
498 char buf[64];
32a121cb 499
aba5acdf
SH
500 print_rate(buf, sizeof(buf), r->rate);
501 fprintf(f, "rate %s ", buf);
3e92ff52
JDB
502 linklayer = (r->linklayer & TC_LINKLAYER_MASK);
503 if (linklayer > TC_LINKLAYER_ETHERNET || show_details)
504 fprintf(f, "linklayer %s ", sprint_linklayer(linklayer, b2));
aba5acdf
SH
505 if (show_details) {
506 fprintf(f, "cell %ub ", 1<<r->cell_log);
507 if (r->mpu)
508 fprintf(f, "mpu %ub ", r->mpu);
08fd0184
JDB
509 if (r->overhead)
510 fprintf(f, "overhead %ub ", r->overhead);
aba5acdf
SH
511 }
512 }
513 if (lss && lss->flags) {
32a121cb
SH
514 int comma = 0;
515
aba5acdf
SH
516 fprintf(f, "(");
517 if (lss->flags&TCF_CBQ_LSS_BOUNDED) {
518 fprintf(f, "bounded");
32a121cb 519 comma = 1;
aba5acdf
SH
520 }
521 if (lss->flags&TCF_CBQ_LSS_ISOLATED) {
522 if (comma)
523 fprintf(f, ",");
524 fprintf(f, "isolated");
525 }
526 fprintf(f, ") ");
527 }
528 if (wrr) {
529 if (wrr->priority != TC_CBQ_MAXPRIO)
530 fprintf(f, "prio %u", wrr->priority);
531 else
532 fprintf(f, "prio no-transmit");
533 if (show_details) {
534 char buf[64];
32a121cb 535
aba5acdf
SH
536 fprintf(f, "/%u ", wrr->cpriority);
537 if (wrr->weight != 1) {
538 print_rate(buf, sizeof(buf), wrr->weight);
539 fprintf(f, "weight %s ", buf);
540 }
541 if (wrr->allot)
542 fprintf(f, "allot %ub ", wrr->allot);
543 }
544 }
545 if (lss && show_details) {
546 fprintf(f, "\nlevel %u ewma %u avpkt %ub ", lss->level, lss->ewma_log, lss->avpkt);
547 if (lss->maxidle) {
bd29e35d 548 fprintf(f, "maxidle %s ", sprint_ticks(lss->maxidle>>lss->ewma_log, b1));
aba5acdf
SH
549 if (show_raw)
550 fprintf(f, "[%08x] ", lss->maxidle);
551 }
32a121cb 552 if (lss->minidle != 0x7fffffff) {
bd29e35d 553 fprintf(f, "minidle %s ", sprint_ticks(lss->minidle>>lss->ewma_log, b1));
aba5acdf
SH
554 if (show_raw)
555 fprintf(f, "[%08x] ", lss->minidle);
556 }
557 if (lss->offtime) {
bd29e35d 558 fprintf(f, "offtime %s ", sprint_ticks(lss->offtime, b1));
aba5acdf
SH
559 if (show_raw)
560 fprintf(f, "[%08x] ", lss->offtime);
561 }
562 }
563 if (fopt && show_details) {
564 char buf[64];
32a121cb 565
aba5acdf
SH
566 print_tc_classid(buf, sizeof(buf), fopt->split);
567 fprintf(f, "\nsplit %s ", buf);
568 if (fopt->defmap) {
569 fprintf(f, "defmap %08x", fopt->defmap);
570 }
571 }
572 return 0;
573}
574
575static int cbq_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats)
576{
577 struct tc_cbq_xstats *st;
578
579 if (xstats == NULL)
580 return 0;
581
582 if (RTA_PAYLOAD(xstats) < sizeof(*st))
583 return -1;
584
585 st = RTA_DATA(xstats);
586 fprintf(f, " borrowed %u overactions %u avgidle %g undertime %g", st->borrows,
587 st->overactions, (double)st->avgidle, (double)st->undertime);
588 return 0;
589}
590
95812b56 591struct qdisc_util cbq_qdisc_util = {
f2f99e2e
SH
592 .id = "cbq",
593 .parse_qopt = cbq_parse_opt,
594 .print_qopt = cbq_print_opt,
595 .print_xstats = cbq_print_xstats,
596 .parse_copt = cbq_parse_class_opt,
597 .print_copt = cbq_print_opt,
aba5acdf 598};