Changes to update Tomato RAF.
[tomato.git] / release / src / router / iproute2 / tc / q_cbq.c
blob1264cc6749848b3abfd6c3a3b5e8904cd4bcbb5d
1 /*
2 * q_cbq.c CBQ.
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.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <syslog.h>
17 #include <fcntl.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 #include <string.h>
23 #include "utils.h"
24 #include "tc_util.h"
25 #include "tc_cbq.h"
27 static void explain_class(void)
29 fprintf(stderr, "Usage: ... cbq bandwidth BPS rate BPS maxburst PKTS [ avpkt BYTES ]\n");
30 fprintf(stderr, " [ minburst PKTS ] [ bounded ] [ isolated ]\n");
31 fprintf(stderr, " [ allot BYTES ] [ mpu BYTES ] [ weight RATE ]\n");
32 fprintf(stderr, " [ prio NUMBER ] [ cell BYTES ] [ ewma LOG ]\n");
33 fprintf(stderr, " [ estimator INTERVAL TIME_CONSTANT ]\n");
34 fprintf(stderr, " [ split CLASSID ] [ defmap MASK/CHANGE ]\n");
35 fprintf(stderr, " [ overhead BYTES ] [ atm ]\n");
38 static void explain(void)
40 fprintf(stderr, "Usage: ... cbq bandwidth BPS avpkt BYTES [ mpu BYTES ]\n");
41 fprintf(stderr, " [ cell BYTES ] [ ewma LOG ]\n");
44 static void explain1(char *arg)
46 fprintf(stderr, "Illegal \"%s\"\n", arg);
49 #define usage() return(-1)
51 static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
53 struct tc_ratespec r;
54 struct tc_cbq_lssopt lss;
55 __u32 rtab[256];
56 unsigned avpkt=0, allot=0;
57 __u8 mpu=0;
58 __s8 overhead=0;
59 int atm=0;
60 int cell_log=-1;
61 int ewma_log=-1;
62 struct rtattr *tail;
64 memset(&lss, 0, sizeof(lss));
65 memset(&r, 0, sizeof(r));
67 while (argc > 0) {
68 if (strcmp(*argv, "bandwidth") == 0 ||
69 strcmp(*argv, "rate") == 0) {
70 NEXT_ARG();
71 if (get_rate(&r.rate, *argv)) {
72 explain1("bandwidth");
73 return -1;
75 } else if (strcmp(*argv, "ewma") == 0) {
76 NEXT_ARG();
77 if (get_integer(&ewma_log, *argv, 0)) {
78 explain1("ewma");
79 return -1;
81 if (ewma_log > 31) {
82 fprintf(stderr, "ewma_log must be < 32\n");
83 return -1;
85 } else if (strcmp(*argv, "cell") == 0) {
86 unsigned cell;
87 int i;
88 NEXT_ARG();
89 if (get_size(&cell, *argv)) {
90 explain1("cell");
91 return -1;
93 for (i=0; i<32; i++)
94 if ((1<<i) == cell)
95 break;
96 if (i>=32) {
97 fprintf(stderr, "cell must be 2^n\n");
98 return -1;
100 cell_log = i;
101 } else if (strcmp(*argv, "avpkt") == 0) {
102 NEXT_ARG();
103 if (get_size(&avpkt, *argv)) {
104 explain1("avpkt");
105 return -1;
107 } else if (strcmp(*argv, "mpu") == 0) {
108 NEXT_ARG();
109 if (get_u8(&mpu, *argv, 10)) {
110 explain1("mpu");
111 return -1;
113 } else if (strcmp(*argv, "allot") == 0) {
114 NEXT_ARG();
115 /* Accept and ignore "allot" for backward compatibility */
116 if (get_size(&allot, *argv)) {
117 explain1("allot");
118 return -1;
120 } else if (strcmp(*argv, "overhead") == 0) {
121 NEXT_ARG();
122 if (get_s8(&overhead, *argv, 10)) {
123 explain1("overhead");
124 return -1;
126 } else if (strcmp(*argv, "atm") == 0) {
127 atm = 1;
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;
136 argc--; argv++;
139 /* OK. All options are parsed. */
141 if (r.rate == 0) {
142 fprintf(stderr, "CBQ: bandwidth is required parameter.\n");
143 return -1;
145 if (avpkt == 0) {
146 fprintf(stderr, "CBQ: \"avpkt\" is required.\n");
147 return -1;
149 if (allot < (avpkt*3)/2)
150 allot = (avpkt*3)/2;
152 tc_calc_ratespec(&r, rtab, r.rate, cell_log, allot, mpu, atm, overhead);
154 if (ewma_log < 0)
155 ewma_log = TC_CBQ_DEF_EWMA;
156 lss.ewma_log = ewma_log;
157 lss.maxidle = tc_cbq_calc_maxidle(r.rate, r.rate, avpkt, lss.ewma_log, 0);
158 lss.change = TCF_CBQ_LSS_MAXIDLE|TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
159 lss.avpkt = avpkt;
161 tail = NLMSG_TAIL(n);
162 addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
163 addattr_l(n, 1024, TCA_CBQ_RATE, &r, sizeof(r));
164 addattr_l(n, 1024, TCA_CBQ_LSSOPT, &lss, sizeof(lss));
165 addattr_l(n, 3024, TCA_CBQ_RTAB, rtab, 1024);
166 if (show_raw) {
167 int i;
168 for (i=0; i<256; i++)
169 printf("%u ", rtab[i]);
170 printf("\n");
172 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
173 return 0;
176 static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
178 int wrr_ok=0, fopt_ok=0;
179 struct tc_ratespec r;
180 struct tc_cbq_lssopt lss;
181 struct tc_cbq_wrropt wrr;
182 struct tc_cbq_fopt fopt;
183 struct tc_cbq_ovl ovl;
184 __u32 rtab[256];
185 __u8 mpu=0;
186 __s8 overhead = 0;
187 int atm = 0;
188 int cell_log=-1;
189 int ewma_log=-1;
190 unsigned bndw = 0;
191 unsigned minburst=0, maxburst=0;
192 struct rtattr *tail;
194 memset(&r, 0, sizeof(r));
195 memset(&lss, 0, sizeof(lss));
196 memset(&wrr, 0, sizeof(wrr));
197 memset(&fopt, 0, sizeof(fopt));
198 memset(&ovl, 0, sizeof(ovl));
200 while (argc > 0) {
201 if (strcmp(*argv, "rate") == 0) {
202 NEXT_ARG();
203 if (get_rate(&r.rate, *argv)) {
204 explain1("rate");
205 return -1;
207 } else if (strcmp(*argv, "bandwidth") == 0) {
208 NEXT_ARG();
209 if (get_rate(&bndw, *argv)) {
210 explain1("bandwidth");
211 return -1;
213 } else if (strcmp(*argv, "minidle") == 0) {
214 NEXT_ARG();
215 if (get_u32(&lss.minidle, *argv, 0)) {
216 explain1("minidle");
217 return -1;
219 lss.change |= TCF_CBQ_LSS_MINIDLE;
220 } else if (strcmp(*argv, "minburst") == 0) {
221 NEXT_ARG();
222 if (get_u32(&minburst, *argv, 0)) {
223 explain1("minburst");
224 return -1;
226 lss.change |= TCF_CBQ_LSS_OFFTIME;
227 } else if (strcmp(*argv, "maxburst") == 0) {
228 NEXT_ARG();
229 if (get_u32(&maxburst, *argv, 0)) {
230 explain1("maxburst");
231 return -1;
233 lss.change |= TCF_CBQ_LSS_MAXIDLE;
234 } else if (strcmp(*argv, "bounded") == 0) {
235 lss.flags |= TCF_CBQ_LSS_BOUNDED;
236 lss.change |= TCF_CBQ_LSS_FLAGS;
237 } else if (strcmp(*argv, "borrow") == 0) {
238 lss.flags &= ~TCF_CBQ_LSS_BOUNDED;
239 lss.change |= TCF_CBQ_LSS_FLAGS;
240 } else if (strcmp(*argv, "isolated") == 0) {
241 lss.flags |= TCF_CBQ_LSS_ISOLATED;
242 lss.change |= TCF_CBQ_LSS_FLAGS;
243 } else if (strcmp(*argv, "sharing") == 0) {
244 lss.flags &= ~TCF_CBQ_LSS_ISOLATED;
245 lss.change |= TCF_CBQ_LSS_FLAGS;
246 } else if (strcmp(*argv, "ewma") == 0) {
247 NEXT_ARG();
248 if (get_integer(&ewma_log, *argv, 0)) {
249 explain1("ewma");
250 return -1;
252 if (ewma_log > 31) {
253 fprintf(stderr, "ewma_log must be < 32\n");
254 return -1;
256 lss.change |= TCF_CBQ_LSS_EWMA;
257 } else if (strcmp(*argv, "cell") == 0) {
258 unsigned cell;
259 int i;
260 NEXT_ARG();
261 if (get_size(&cell, *argv)) {
262 explain1("cell");
263 return -1;
265 for (i=0; i<32; i++)
266 if ((1<<i) == cell)
267 break;
268 if (i>=32) {
269 fprintf(stderr, "cell must be 2^n\n");
270 return -1;
272 cell_log = i;
273 } else if (strcmp(*argv, "prio") == 0) {
274 unsigned prio;
275 NEXT_ARG();
276 if (get_u32(&prio, *argv, 0)) {
277 explain1("prio");
278 return -1;
280 if (prio > TC_CBQ_MAXPRIO) {
281 fprintf(stderr, "\"prio\" must be number in the range 1...%d\n", TC_CBQ_MAXPRIO);
282 return -1;
284 wrr.priority = prio;
285 wrr_ok++;
286 } else if (strcmp(*argv, "allot") == 0) {
287 NEXT_ARG();
288 if (get_size(&wrr.allot, *argv)) {
289 explain1("allot");
290 return -1;
292 } else if (strcmp(*argv, "avpkt") == 0) {
293 NEXT_ARG();
294 if (get_size(&lss.avpkt, *argv)) {
295 explain1("avpkt");
296 return -1;
298 lss.change |= TCF_CBQ_LSS_AVPKT;
299 } else if (strcmp(*argv, "mpu") == 0) {
300 NEXT_ARG();
301 if (get_u8(&mpu, *argv, 10)) {
302 explain1("mpu");
303 return -1;
305 } else if (strcmp(*argv, "overhead") == 0) {
306 NEXT_ARG();
307 if (get_s8(&overhead, *argv, 10)) {
308 explain1("overhead");
309 return -1;
311 } else if (strcmp(*argv, "atm") == 0) {
312 atm = 1;
313 } else if (strcmp(*argv, "weight") == 0) {
314 NEXT_ARG();
315 if (get_size(&wrr.weight, *argv)) {
316 explain1("weight");
317 return -1;
319 wrr_ok++;
320 } else if (strcmp(*argv, "split") == 0) {
321 NEXT_ARG();
322 if (get_tc_classid(&fopt.split, *argv)) {
323 fprintf(stderr, "Invalid split node ID.\n");
324 usage();
326 fopt_ok++;
327 } else if (strcmp(*argv, "defmap") == 0) {
328 int err;
329 NEXT_ARG();
330 err = sscanf(*argv, "%08x/%08x", &fopt.defmap, &fopt.defchange);
331 if (err < 1) {
332 fprintf(stderr, "Invalid defmap, should be MASK32[/MASK]\n");
333 return -1;
335 if (err == 1)
336 fopt.defchange = ~0;
337 fopt_ok++;
338 } else if (strcmp(*argv, "help") == 0) {
339 explain_class();
340 return -1;
341 } else {
342 fprintf(stderr, "What is \"%s\"?\n", *argv);
343 explain_class();
344 return -1;
346 argc--; argv++;
349 /* OK. All options are parsed. */
351 /* 1. Prepare link sharing scheduler parameters */
352 if (r.rate) {
353 unsigned pktsize = wrr.allot;
354 if (wrr.allot < (lss.avpkt*3)/2)
355 wrr.allot = (lss.avpkt*3)/2;
357 tc_calc_ratespec(&r, rtab, r.rate, cell_log, pktsize, mpu, atm, overhead);
359 if (ewma_log < 0)
360 ewma_log = TC_CBQ_DEF_EWMA;
361 lss.ewma_log = ewma_log;
362 if (lss.change&(TCF_CBQ_LSS_OFFTIME|TCF_CBQ_LSS_MAXIDLE)) {
363 if (lss.avpkt == 0) {
364 fprintf(stderr, "CBQ: avpkt is required for max/minburst.\n");
365 return -1;
367 if (bndw==0 || r.rate == 0) {
368 fprintf(stderr, "CBQ: bandwidth&rate are required for max/minburst.\n");
369 return -1;
372 if (wrr.priority == 0 && (n->nlmsg_flags&NLM_F_EXCL)) {
373 wrr_ok = 1;
374 wrr.priority = TC_CBQ_MAXPRIO;
375 if (wrr.allot == 0)
376 wrr.allot = (lss.avpkt*3)/2;
378 if (wrr_ok) {
379 if (wrr.weight == 0)
380 wrr.weight = (wrr.priority == TC_CBQ_MAXPRIO) ? 1 : r.rate;
381 if (wrr.allot == 0) {
382 fprintf(stderr, "CBQ: \"allot\" is required to set WRR parameters.\n");
383 return -1;
386 if (lss.change&TCF_CBQ_LSS_MAXIDLE) {
387 lss.maxidle = tc_cbq_calc_maxidle(bndw, r.rate, lss.avpkt, ewma_log, maxburst);
388 lss.change |= TCF_CBQ_LSS_MAXIDLE;
389 lss.change |= TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
391 if (lss.change&TCF_CBQ_LSS_OFFTIME) {
392 lss.offtime = tc_cbq_calc_offtime(bndw, r.rate, lss.avpkt, ewma_log, minburst);
393 lss.change |= TCF_CBQ_LSS_OFFTIME;
394 lss.change |= TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
396 if (lss.change&TCF_CBQ_LSS_MINIDLE) {
397 lss.minidle <<= lss.ewma_log;
398 lss.change |= TCF_CBQ_LSS_EWMA;
401 tail = NLMSG_TAIL(n);
402 addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
403 if (lss.change) {
404 lss.change |= TCF_CBQ_LSS_FLAGS;
405 addattr_l(n, 1024, TCA_CBQ_LSSOPT, &lss, sizeof(lss));
407 if (wrr_ok)
408 addattr_l(n, 1024, TCA_CBQ_WRROPT, &wrr, sizeof(wrr));
409 if (fopt_ok)
410 addattr_l(n, 1024, TCA_CBQ_FOPT, &fopt, sizeof(fopt));
411 if (r.rate) {
412 addattr_l(n, 1024, TCA_CBQ_RATE, &r, sizeof(r));
413 addattr_l(n, 3024, TCA_CBQ_RTAB, rtab, 1024);
414 if (show_raw) {
415 int i;
416 for (i=0; i<256; i++)
417 printf("%u ", rtab[i]);
418 printf("\n");
421 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
422 return 0;
426 static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
428 struct rtattr *tb[TCA_CBQ_MAX+1];
429 struct tc_ratespec *r = NULL;
430 struct tc_cbq_lssopt *lss = NULL;
431 struct tc_cbq_wrropt *wrr = NULL;
432 struct tc_cbq_fopt *fopt = NULL;
433 struct tc_cbq_ovl *ovl = NULL;
435 if (opt == NULL)
436 return 0;
438 parse_rtattr_nested(tb, TCA_CBQ_MAX, opt);
440 if (tb[TCA_CBQ_RATE]) {
441 if (RTA_PAYLOAD(tb[TCA_CBQ_RATE]) < sizeof(*r))
442 fprintf(stderr, "CBQ: too short rate opt\n");
443 else
444 r = RTA_DATA(tb[TCA_CBQ_RATE]);
446 if (tb[TCA_CBQ_LSSOPT]) {
447 if (RTA_PAYLOAD(tb[TCA_CBQ_LSSOPT]) < sizeof(*lss))
448 fprintf(stderr, "CBQ: too short lss opt\n");
449 else
450 lss = RTA_DATA(tb[TCA_CBQ_LSSOPT]);
452 if (tb[TCA_CBQ_WRROPT]) {
453 if (RTA_PAYLOAD(tb[TCA_CBQ_WRROPT]) < sizeof(*wrr))
454 fprintf(stderr, "CBQ: too short wrr opt\n");
455 else
456 wrr = RTA_DATA(tb[TCA_CBQ_WRROPT]);
458 if (tb[TCA_CBQ_FOPT]) {
459 if (RTA_PAYLOAD(tb[TCA_CBQ_FOPT]) < sizeof(*fopt))
460 fprintf(stderr, "CBQ: too short fopt\n");
461 else
462 fopt = RTA_DATA(tb[TCA_CBQ_FOPT]);
464 if (tb[TCA_CBQ_OVL_STRATEGY]) {
465 if (RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]) < sizeof(*ovl))
466 fprintf(stderr, "CBQ: too short overlimit strategy %u/%u\n",
467 (unsigned) RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]),
468 (unsigned) sizeof(*ovl));
469 else
470 ovl = RTA_DATA(tb[TCA_CBQ_OVL_STRATEGY]);
473 if (r) {
474 char buf[64];
475 print_rate(buf, sizeof(buf), r->rate);
476 fprintf(f, "rate %s ", buf);
477 if (show_details) {
478 fprintf(f, "cell %ub ", 1<<r->cell_log);
479 if (r->mpu & 0xff)
480 fprintf(f, "mpu %ub ", (__u8)r->mpu);
481 if ((r->mpu >> 8))
482 fprintf(f, "overhead %db ", (__s8)(r->mpu >> 8));
483 if (r->feature & 0x0001)
484 fprintf(f, "atm ");
487 if (lss && lss->flags) {
488 int comma=0;
489 fprintf(f, "(");
490 if (lss->flags&TCF_CBQ_LSS_BOUNDED) {
491 fprintf(f, "bounded");
492 comma=1;
494 if (lss->flags&TCF_CBQ_LSS_ISOLATED) {
495 if (comma)
496 fprintf(f, ",");
497 fprintf(f, "isolated");
499 fprintf(f, ") ");
501 if (wrr) {
502 if (wrr->priority != TC_CBQ_MAXPRIO)
503 fprintf(f, "prio %u", wrr->priority);
504 else
505 fprintf(f, "prio no-transmit");
506 if (show_details) {
507 char buf[64];
508 fprintf(f, "/%u ", wrr->cpriority);
509 if (wrr->weight != 1) {
510 print_rate(buf, sizeof(buf), wrr->weight);
511 fprintf(f, "weight %s ", buf);
513 if (wrr->allot)
514 fprintf(f, "allot %ub ", wrr->allot);
517 if (lss && show_details) {
518 fprintf(f, "\nlevel %u ewma %u avpkt %ub ", lss->level, lss->ewma_log, lss->avpkt);
519 if (lss->maxidle) {
520 fprintf(f, "maxidle %luus ", tc_core_tick2usec(lss->maxidle>>lss->ewma_log));
521 if (show_raw)
522 fprintf(f, "[%08x] ", lss->maxidle);
524 if (lss->minidle!=0x7fffffff) {
525 fprintf(f, "minidle %luus ", tc_core_tick2usec(lss->minidle>>lss->ewma_log));
526 if (show_raw)
527 fprintf(f, "[%08x] ", lss->minidle);
529 if (lss->offtime) {
530 fprintf(f, "offtime %luus ", tc_core_tick2usec(lss->offtime));
531 if (show_raw)
532 fprintf(f, "[%08x] ", lss->offtime);
535 if (fopt && show_details) {
536 char buf[64];
537 print_tc_classid(buf, sizeof(buf), fopt->split);
538 fprintf(f, "\nsplit %s ", buf);
539 if (fopt->defmap) {
540 fprintf(f, "defmap %08x", fopt->defmap);
543 return 0;
546 static int cbq_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats)
548 struct tc_cbq_xstats *st;
550 if (xstats == NULL)
551 return 0;
553 if (RTA_PAYLOAD(xstats) < sizeof(*st))
554 return -1;
556 st = RTA_DATA(xstats);
557 fprintf(f, " borrowed %u overactions %u avgidle %g undertime %g", st->borrows,
558 st->overactions, (double)st->avgidle, (double)st->undertime);
559 return 0;
562 struct qdisc_util cbq_qdisc_util = {
563 .id = "cbq",
564 .parse_qopt = cbq_parse_opt,
565 .print_qopt = cbq_print_opt,
566 .print_xstats = cbq_print_xstats,
567 .parse_copt = cbq_parse_class_opt,
568 .print_copt = cbq_print_opt,