blob: df98312e88d49b26ba695a2c861995fc0c2f1394 [file] [log] [blame]
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001/*
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>
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>
22
23#include "utils.h"
24#include "tc_util.h"
25#include "tc_cbq.h"
26
27static void explain_class(void)
28{
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}
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
48#define usage() return(-1)
49
50static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
51{
52 struct tc_ratespec r;
53 struct tc_cbq_lssopt lss;
54 __u32 rtab[256];
55 unsigned mpu=0, avpkt=0, allot=0;
Stephen Hemmingerae665a52006-12-05 10:10:22 -080056 int cell_log=-1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000057 int ewma_log=-1;
58 struct rtattr *tail;
59
60 memset(&lss, 0, sizeof(lss));
61 memset(&r, 0, sizeof(r));
62
63 while (argc > 0) {
64 if (strcmp(*argv, "bandwidth") == 0 ||
65 strcmp(*argv, "rate") == 0) {
66 NEXT_ARG();
67 if (get_rate(&r.rate, *argv)) {
68 explain1("bandwidth");
69 return -1;
70 }
71 } else if (strcmp(*argv, "ewma") == 0) {
72 NEXT_ARG();
shemmingerf332d162005-07-05 22:37:15 +000073 if (get_integer(&ewma_log, *argv, 0)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000074 explain1("ewma");
75 return -1;
76 }
77 if (ewma_log > 31) {
78 fprintf(stderr, "ewma_log must be < 32\n");
79 return -1;
80 }
81 } else if (strcmp(*argv, "cell") == 0) {
82 unsigned cell;
83 int i;
84 NEXT_ARG();
85 if (get_size(&cell, *argv)) {
86 explain1("cell");
87 return -1;
88 }
89 for (i=0; i<32; i++)
90 if ((1<<i) == cell)
91 break;
92 if (i>=32) {
93 fprintf(stderr, "cell must be 2^n\n");
94 return -1;
95 }
96 cell_log = i;
97 } else if (strcmp(*argv, "avpkt") == 0) {
98 NEXT_ARG();
99 if (get_size(&avpkt, *argv)) {
100 explain1("avpkt");
101 return -1;
102 }
103 } else if (strcmp(*argv, "mpu") == 0) {
104 NEXT_ARG();
105 if (get_size(&mpu, *argv)) {
106 explain1("mpu");
107 return -1;
108 }
109 } else if (strcmp(*argv, "allot") == 0) {
110 NEXT_ARG();
111 /* Accept and ignore "allot" for backward compatibility */
112 if (get_size(&allot, *argv)) {
113 explain1("allot");
114 return -1;
115 }
116 } else if (strcmp(*argv, "help") == 0) {
117 explain();
118 return -1;
119 } else {
120 fprintf(stderr, "What is \"%s\"?\n", *argv);
121 explain();
122 return -1;
123 }
124 argc--; argv++;
125 }
126
127 /* OK. All options are parsed. */
128
129 if (r.rate == 0) {
130 fprintf(stderr, "CBQ: bandwidth is required parameter.\n");
131 return -1;
132 }
133 if (avpkt == 0) {
134 fprintf(stderr, "CBQ: \"avpkt\" is required.\n");
135 return -1;
136 }
137 if (allot < (avpkt*3)/2)
138 allot = (avpkt*3)/2;
139
Jesper Dangaard Brouerd5f46f92007-09-05 10:47:47 +0200140 r.mpu = mpu;
141 if (tc_calc_rtable(&r, rtab, cell_log, allot) < 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000142 fprintf(stderr, "CBQ: failed to calculate rate table.\n");
143 return -1;
144 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000145
146 if (ewma_log < 0)
147 ewma_log = TC_CBQ_DEF_EWMA;
148 lss.ewma_log = ewma_log;
Patrick McHardy476daa72007-03-04 20:14:56 +0100149 lss.maxidle = tc_calc_xmittime(r.rate, avpkt);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000150 lss.change = TCF_CBQ_LSS_MAXIDLE|TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
151 lss.avpkt = avpkt;
152
5!tgraf034102f2005-01-18 01:24:18 +0000153 tail = NLMSG_TAIL(n);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000154 addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
155 addattr_l(n, 1024, TCA_CBQ_RATE, &r, sizeof(r));
156 addattr_l(n, 1024, TCA_CBQ_LSSOPT, &lss, sizeof(lss));
157 addattr_l(n, 3024, TCA_CBQ_RTAB, rtab, 1024);
158 if (show_raw) {
159 int i;
160 for (i=0; i<256; i++)
161 printf("%u ", rtab[i]);
162 printf("\n");
163 }
5!tgraf034102f2005-01-18 01:24:18 +0000164 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000165 return 0;
166}
167
168static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
169{
170 int wrr_ok=0, fopt_ok=0;
171 struct tc_ratespec r;
172 struct tc_cbq_lssopt lss;
173 struct tc_cbq_wrropt wrr;
174 struct tc_cbq_fopt fopt;
175 struct tc_cbq_ovl ovl;
176 __u32 rtab[256];
177 unsigned mpu=0;
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800178 int cell_log=-1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000179 int ewma_log=-1;
180 unsigned bndw = 0;
181 unsigned minburst=0, maxburst=0;
182 struct rtattr *tail;
183
184 memset(&r, 0, sizeof(r));
185 memset(&lss, 0, sizeof(lss));
186 memset(&wrr, 0, sizeof(wrr));
187 memset(&fopt, 0, sizeof(fopt));
188 memset(&ovl, 0, sizeof(ovl));
189
190 while (argc > 0) {
191 if (strcmp(*argv, "rate") == 0) {
192 NEXT_ARG();
193 if (get_rate(&r.rate, *argv)) {
194 explain1("rate");
195 return -1;
196 }
197 } else if (strcmp(*argv, "bandwidth") == 0) {
198 NEXT_ARG();
199 if (get_rate(&bndw, *argv)) {
200 explain1("bandwidth");
201 return -1;
202 }
203 } else if (strcmp(*argv, "minidle") == 0) {
204 NEXT_ARG();
205 if (get_u32(&lss.minidle, *argv, 0)) {
206 explain1("minidle");
207 return -1;
208 }
209 lss.change |= TCF_CBQ_LSS_MINIDLE;
210 } else if (strcmp(*argv, "minburst") == 0) {
211 NEXT_ARG();
212 if (get_u32(&minburst, *argv, 0)) {
213 explain1("minburst");
214 return -1;
215 }
216 lss.change |= TCF_CBQ_LSS_OFFTIME;
217 } else if (strcmp(*argv, "maxburst") == 0) {
218 NEXT_ARG();
219 if (get_u32(&maxburst, *argv, 0)) {
220 explain1("maxburst");
221 return -1;
222 }
223 lss.change |= TCF_CBQ_LSS_MAXIDLE;
224 } else if (strcmp(*argv, "bounded") == 0) {
225 lss.flags |= TCF_CBQ_LSS_BOUNDED;
226 lss.change |= TCF_CBQ_LSS_FLAGS;
227 } else if (strcmp(*argv, "borrow") == 0) {
228 lss.flags &= ~TCF_CBQ_LSS_BOUNDED;
229 lss.change |= TCF_CBQ_LSS_FLAGS;
230 } else if (strcmp(*argv, "isolated") == 0) {
231 lss.flags |= TCF_CBQ_LSS_ISOLATED;
232 lss.change |= TCF_CBQ_LSS_FLAGS;
233 } else if (strcmp(*argv, "sharing") == 0) {
234 lss.flags &= ~TCF_CBQ_LSS_ISOLATED;
235 lss.change |= TCF_CBQ_LSS_FLAGS;
236 } else if (strcmp(*argv, "ewma") == 0) {
237 NEXT_ARG();
shemmingerf332d162005-07-05 22:37:15 +0000238 if (get_integer(&ewma_log, *argv, 0)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000239 explain1("ewma");
240 return -1;
241 }
242 if (ewma_log > 31) {
243 fprintf(stderr, "ewma_log must be < 32\n");
244 return -1;
245 }
246 lss.change |= TCF_CBQ_LSS_EWMA;
247 } else if (strcmp(*argv, "cell") == 0) {
248 unsigned cell;
249 int i;
250 NEXT_ARG();
251 if (get_size(&cell, *argv)) {
252 explain1("cell");
253 return -1;
254 }
255 for (i=0; i<32; i++)
256 if ((1<<i) == cell)
257 break;
258 if (i>=32) {
259 fprintf(stderr, "cell must be 2^n\n");
260 return -1;
261 }
262 cell_log = i;
263 } else if (strcmp(*argv, "prio") == 0) {
264 unsigned prio;
265 NEXT_ARG();
266 if (get_u32(&prio, *argv, 0)) {
267 explain1("prio");
268 return -1;
269 }
270 if (prio > TC_CBQ_MAXPRIO) {
271 fprintf(stderr, "\"prio\" must be number in the range 1...%d\n", TC_CBQ_MAXPRIO);
272 return -1;
273 }
274 wrr.priority = prio;
275 wrr_ok++;
276 } else if (strcmp(*argv, "allot") == 0) {
277 NEXT_ARG();
278 if (get_size(&wrr.allot, *argv)) {
279 explain1("allot");
280 return -1;
281 }
282 } else if (strcmp(*argv, "avpkt") == 0) {
283 NEXT_ARG();
284 if (get_size(&lss.avpkt, *argv)) {
285 explain1("avpkt");
286 return -1;
287 }
288 lss.change |= TCF_CBQ_LSS_AVPKT;
289 } else if (strcmp(*argv, "mpu") == 0) {
290 NEXT_ARG();
291 if (get_size(&mpu, *argv)) {
292 explain1("mpu");
293 return -1;
294 }
295 } else if (strcmp(*argv, "weight") == 0) {
296 NEXT_ARG();
297 if (get_size(&wrr.weight, *argv)) {
298 explain1("weight");
299 return -1;
300 }
301 wrr_ok++;
302 } else if (strcmp(*argv, "split") == 0) {
303 NEXT_ARG();
304 if (get_tc_classid(&fopt.split, *argv)) {
305 fprintf(stderr, "Invalid split node ID.\n");
306 usage();
307 }
308 fopt_ok++;
309 } else if (strcmp(*argv, "defmap") == 0) {
310 int err;
311 NEXT_ARG();
312 err = sscanf(*argv, "%08x/%08x", &fopt.defmap, &fopt.defchange);
313 if (err < 1) {
314 fprintf(stderr, "Invalid defmap, should be MASK32[/MASK]\n");
315 return -1;
316 }
317 if (err == 1)
318 fopt.defchange = ~0;
319 fopt_ok++;
320 } else if (strcmp(*argv, "help") == 0) {
321 explain_class();
322 return -1;
323 } else {
324 fprintf(stderr, "What is \"%s\"?\n", *argv);
325 explain_class();
326 return -1;
327 }
328 argc--; argv++;
329 }
330
331 /* OK. All options are parsed. */
332
333 /* 1. Prepare link sharing scheduler parameters */
334 if (r.rate) {
335 unsigned pktsize = wrr.allot;
336 if (wrr.allot < (lss.avpkt*3)/2)
337 wrr.allot = (lss.avpkt*3)/2;
Jesper Dangaard Brouerd5f46f92007-09-05 10:47:47 +0200338 r.mpu = mpu;
339 if (tc_calc_rtable(&r, rtab, cell_log, pktsize) < 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000340 fprintf(stderr, "CBQ: failed to calculate rate table.\n");
341 return -1;
342 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000343 }
344 if (ewma_log < 0)
345 ewma_log = TC_CBQ_DEF_EWMA;
346 lss.ewma_log = ewma_log;
347 if (lss.change&(TCF_CBQ_LSS_OFFTIME|TCF_CBQ_LSS_MAXIDLE)) {
348 if (lss.avpkt == 0) {
349 fprintf(stderr, "CBQ: avpkt is required for max/minburst.\n");
350 return -1;
351 }
352 if (bndw==0 || r.rate == 0) {
353 fprintf(stderr, "CBQ: bandwidth&rate are required for max/minburst.\n");
354 return -1;
355 }
356 }
357 if (wrr.priority == 0 && (n->nlmsg_flags&NLM_F_EXCL)) {
358 wrr_ok = 1;
359 wrr.priority = TC_CBQ_MAXPRIO;
360 if (wrr.allot == 0)
361 wrr.allot = (lss.avpkt*3)/2;
362 }
363 if (wrr_ok) {
364 if (wrr.weight == 0)
365 wrr.weight = (wrr.priority == TC_CBQ_MAXPRIO) ? 1 : r.rate;
366 if (wrr.allot == 0) {
367 fprintf(stderr, "CBQ: \"allot\" is required to set WRR parameters.\n");
368 return -1;
369 }
370 }
371 if (lss.change&TCF_CBQ_LSS_MAXIDLE) {
372 lss.maxidle = tc_cbq_calc_maxidle(bndw, r.rate, lss.avpkt, ewma_log, maxburst);
373 lss.change |= TCF_CBQ_LSS_MAXIDLE;
374 lss.change |= TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
375 }
376 if (lss.change&TCF_CBQ_LSS_OFFTIME) {
377 lss.offtime = tc_cbq_calc_offtime(bndw, r.rate, lss.avpkt, ewma_log, minburst);
378 lss.change |= TCF_CBQ_LSS_OFFTIME;
379 lss.change |= TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
380 }
381 if (lss.change&TCF_CBQ_LSS_MINIDLE) {
382 lss.minidle <<= lss.ewma_log;
383 lss.change |= TCF_CBQ_LSS_EWMA;
384 }
385
5!tgraf034102f2005-01-18 01:24:18 +0000386 tail = NLMSG_TAIL(n);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000387 addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
388 if (lss.change) {
389 lss.change |= TCF_CBQ_LSS_FLAGS;
390 addattr_l(n, 1024, TCA_CBQ_LSSOPT, &lss, sizeof(lss));
391 }
392 if (wrr_ok)
393 addattr_l(n, 1024, TCA_CBQ_WRROPT, &wrr, sizeof(wrr));
394 if (fopt_ok)
395 addattr_l(n, 1024, TCA_CBQ_FOPT, &fopt, sizeof(fopt));
396 if (r.rate) {
397 addattr_l(n, 1024, TCA_CBQ_RATE, &r, sizeof(r));
398 addattr_l(n, 3024, TCA_CBQ_RTAB, rtab, 1024);
399 if (show_raw) {
400 int i;
401 for (i=0; i<256; i++)
402 printf("%u ", rtab[i]);
403 printf("\n");
404 }
405 }
5!tgraf034102f2005-01-18 01:24:18 +0000406 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000407 return 0;
408}
409
410
411static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
412{
413 struct rtattr *tb[TCA_CBQ_MAX+1];
414 struct tc_ratespec *r = NULL;
415 struct tc_cbq_lssopt *lss = NULL;
416 struct tc_cbq_wrropt *wrr = NULL;
417 struct tc_cbq_fopt *fopt = NULL;
418 struct tc_cbq_ovl *ovl = NULL;
Patrick McHardybd29e352007-03-04 20:15:01 +0100419 SPRINT_BUF(b1);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000420
421 if (opt == NULL)
422 return 0;
423
5!tgraf021ed132005-01-18 22:11:58 +0000424 parse_rtattr_nested(tb, TCA_CBQ_MAX, opt);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000425
426 if (tb[TCA_CBQ_RATE]) {
427 if (RTA_PAYLOAD(tb[TCA_CBQ_RATE]) < sizeof(*r))
428 fprintf(stderr, "CBQ: too short rate opt\n");
429 else
430 r = RTA_DATA(tb[TCA_CBQ_RATE]);
431 }
432 if (tb[TCA_CBQ_LSSOPT]) {
433 if (RTA_PAYLOAD(tb[TCA_CBQ_LSSOPT]) < sizeof(*lss))
434 fprintf(stderr, "CBQ: too short lss opt\n");
435 else
436 lss = RTA_DATA(tb[TCA_CBQ_LSSOPT]);
437 }
438 if (tb[TCA_CBQ_WRROPT]) {
439 if (RTA_PAYLOAD(tb[TCA_CBQ_WRROPT]) < sizeof(*wrr))
440 fprintf(stderr, "CBQ: too short wrr opt\n");
441 else
442 wrr = RTA_DATA(tb[TCA_CBQ_WRROPT]);
443 }
444 if (tb[TCA_CBQ_FOPT]) {
445 if (RTA_PAYLOAD(tb[TCA_CBQ_FOPT]) < sizeof(*fopt))
446 fprintf(stderr, "CBQ: too short fopt\n");
447 else
448 fopt = RTA_DATA(tb[TCA_CBQ_FOPT]);
449 }
450 if (tb[TCA_CBQ_OVL_STRATEGY]) {
451 if (RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]) < sizeof(*ovl))
452 fprintf(stderr, "CBQ: too short overlimit strategy %u/%u\n",
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800453 (unsigned) RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]),
osdl.net!shemmingerbb6a21a2004-10-06 23:17:10 +0000454 (unsigned) sizeof(*ovl));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000455 else
456 ovl = RTA_DATA(tb[TCA_CBQ_OVL_STRATEGY]);
457 }
458
459 if (r) {
460 char buf[64];
461 print_rate(buf, sizeof(buf), r->rate);
462 fprintf(f, "rate %s ", buf);
463 if (show_details) {
464 fprintf(f, "cell %ub ", 1<<r->cell_log);
465 if (r->mpu)
466 fprintf(f, "mpu %ub ", r->mpu);
467 }
468 }
469 if (lss && lss->flags) {
470 int comma=0;
471 fprintf(f, "(");
472 if (lss->flags&TCF_CBQ_LSS_BOUNDED) {
473 fprintf(f, "bounded");
474 comma=1;
475 }
476 if (lss->flags&TCF_CBQ_LSS_ISOLATED) {
477 if (comma)
478 fprintf(f, ",");
479 fprintf(f, "isolated");
480 }
481 fprintf(f, ") ");
482 }
483 if (wrr) {
484 if (wrr->priority != TC_CBQ_MAXPRIO)
485 fprintf(f, "prio %u", wrr->priority);
486 else
487 fprintf(f, "prio no-transmit");
488 if (show_details) {
489 char buf[64];
490 fprintf(f, "/%u ", wrr->cpriority);
491 if (wrr->weight != 1) {
492 print_rate(buf, sizeof(buf), wrr->weight);
493 fprintf(f, "weight %s ", buf);
494 }
495 if (wrr->allot)
496 fprintf(f, "allot %ub ", wrr->allot);
497 }
498 }
499 if (lss && show_details) {
500 fprintf(f, "\nlevel %u ewma %u avpkt %ub ", lss->level, lss->ewma_log, lss->avpkt);
501 if (lss->maxidle) {
Patrick McHardybd29e352007-03-04 20:15:01 +0100502 fprintf(f, "maxidle %s ", sprint_ticks(lss->maxidle>>lss->ewma_log, b1));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000503 if (show_raw)
504 fprintf(f, "[%08x] ", lss->maxidle);
505 }
506 if (lss->minidle!=0x7fffffff) {
Patrick McHardybd29e352007-03-04 20:15:01 +0100507 fprintf(f, "minidle %s ", sprint_ticks(lss->minidle>>lss->ewma_log, b1));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000508 if (show_raw)
509 fprintf(f, "[%08x] ", lss->minidle);
510 }
511 if (lss->offtime) {
Patrick McHardybd29e352007-03-04 20:15:01 +0100512 fprintf(f, "offtime %s ", sprint_ticks(lss->offtime, b1));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000513 if (show_raw)
514 fprintf(f, "[%08x] ", lss->offtime);
515 }
516 }
517 if (fopt && show_details) {
518 char buf[64];
519 print_tc_classid(buf, sizeof(buf), fopt->split);
520 fprintf(f, "\nsplit %s ", buf);
521 if (fopt->defmap) {
522 fprintf(f, "defmap %08x", fopt->defmap);
523 }
524 }
525 return 0;
526}
527
528static int cbq_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats)
529{
530 struct tc_cbq_xstats *st;
531
532 if (xstats == NULL)
533 return 0;
534
535 if (RTA_PAYLOAD(xstats) < sizeof(*st))
536 return -1;
537
538 st = RTA_DATA(xstats);
539 fprintf(f, " borrowed %u overactions %u avgidle %g undertime %g", st->borrows,
540 st->overactions, (double)st->avgidle, (double)st->undertime);
541 return 0;
542}
543
net[shemminger]!kaber95812b52004-09-28 18:35:49 +0000544struct qdisc_util cbq_qdisc_util = {
osdl.net!shemmingerf2f99e22004-08-31 17:45:21 +0000545 .id = "cbq",
546 .parse_qopt = cbq_parse_opt,
547 .print_qopt = cbq_print_opt,
548 .print_xstats = cbq_print_xstats,
549 .parse_copt = cbq_parse_class_opt,
550 .print_copt = cbq_print_opt,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000551};
552