blob: c84c18a67516016e5c1de701006705ed16595db0 [file] [log] [blame]
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +00001/* vi: set sw=4 ts=4: */
2/*
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02003 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +00004 *
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02005 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +00006 *
Bernhard Reutner-Fischer6c4dade2008-09-25 12:13:34 +00007 * Bernhard Reutner-Fischer adjusted for busybox
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +00008 */
9
Pere Orga5bc8c002011-04-11 03:29:49 +020010//usage:#define tc_trivial_usage
11/* //usage: "[OPTIONS] OBJECT CMD [dev STRING]" */
12//usage: "OBJECT CMD [dev STRING]"
13//usage:#define tc_full_usage "\n\n"
14//usage: "OBJECT: {qdisc|class|filter}\n"
15//usage: "CMD: {add|del|change|replace|show}\n"
16//usage: "\n"
17//usage: "qdisc [ handle QHANDLE ] [ root |"IF_FEATURE_TC_INGRESS(" ingress |")" parent CLASSID ]\n"
18/* //usage: "[ estimator INTERVAL TIME_CONSTANT ]\n" */
19//usage: " [ [ QDISC_KIND ] [ help | OPTIONS ] ]\n"
20//usage: " QDISC_KIND := { [p|b]fifo | tbf | prio | cbq | red | etc. }\n"
21//usage: "qdisc show [ dev STRING ]"IF_FEATURE_TC_INGRESS(" [ingress]")"\n"
22//usage: "class [ classid CLASSID ] [ root | parent CLASSID ]\n"
23//usage: " [ [ QDISC_KIND ] [ help | OPTIONS ] ]\n"
24//usage: "class show [ dev STRING ] [ root | parent CLASSID ]\n"
25//usage: "filter [ pref PRIO ] [ protocol PROTO ]\n"
26/* //usage: "\t[ estimator INTERVAL TIME_CONSTANT ]\n" */
27//usage: " [ root | classid CLASSID ] [ handle FILTERID ]\n"
28//usage: " [ [ FILTER_TYPE ] [ help | OPTIONS ] ]\n"
29//usage: "filter show [ dev STRING ] [ root | parent CLASSID ]"
30
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +000031#include "libbb.h"
32
33#include "libiproute/utils.h"
34#include "libiproute/ip_common.h"
35#include "libiproute/rt_names.h"
36#include <linux/pkt_sched.h> /* for the TC_H_* macros */
37
38#define parse_rtattr_nested(tb, max, rta) \
39 (parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta)))
40
41/* nullifies tb on error */
42#define __parse_rtattr_nested_compat(tb, max, rta, len) \
43 ({if ((RTA_PAYLOAD(rta) >= len) && \
44 (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr))) { \
45 rta = RTA_DATA(rta) + RTA_ALIGN(len); \
46 parse_rtattr_nested(tb, max, rta); \
47 } else \
48 memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); \
49 })
50
51#define parse_rtattr_nested_compat(tb, max, rta, data, len) \
52 ({data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \
53 __parse_rtattr_nested_compat(tb, max, rta, len); })
54
55#define show_details (0) /* not implemented. Does anyone need it? */
56#define use_iec (0) /* not currently documented in the upstream manpage */
57
58
59struct globals {
60 int filter_ifindex;
Daniel Fandrich6295d272011-06-09 15:44:44 -070061 uint32_t filter_qdisc;
62 uint32_t filter_parent;
63 uint32_t filter_prio;
64 uint32_t filter_proto;
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +010065} FIX_ALIASING;
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +000066#define G (*(struct globals*)&bb_common_bufsiz1)
67#define filter_ifindex (G.filter_ifindex)
68#define filter_qdisc (G.filter_qdisc)
69#define filter_parent (G.filter_parent)
70#define filter_prio (G.filter_prio)
71#define filter_proto (G.filter_proto)
Denys Vlasenkoab3964d2015-10-13 14:50:20 +020072#define INIT_G() do { \
73 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
74} while (0)
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +000075
76/* Allocates a buffer containing the name of a class id.
77 * The caller must free the returned memory. */
78static char* print_tc_classid(uint32_t cid)
79{
80#if 0 /* IMPOSSIBLE */
81 if (cid == TC_H_ROOT)
82 return xasprintf("root");
83 else
84#endif
85 if (cid == TC_H_UNSPEC)
86 return xasprintf("none");
87 else if (TC_H_MAJ(cid) == 0)
88 return xasprintf(":%x", TC_H_MIN(cid));
89 else if (TC_H_MIN(cid) == 0)
90 return xasprintf("%x:", TC_H_MAJ(cid)>>16);
91 else
92 return xasprintf("%x:%x", TC_H_MAJ(cid)>>16, TC_H_MIN(cid));
93}
94
95/* Get a qdisc handle. Return 0 on success, !0 otherwise. */
Daniel Fandrich6295d272011-06-09 15:44:44 -070096static int get_qdisc_handle(uint32_t *h, const char *str) {
97 uint32_t maj;
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +000098 char *p;
99
100 maj = TC_H_UNSPEC;
101 if (!strcmp(str, "none"))
102 goto ok;
103 maj = strtoul(str, &p, 16);
104 if (p == str)
105 return 1;
106 maj <<= 16;
Denys Vlasenko1f27ab02009-09-23 17:17:53 +0200107 if (*p != ':' && *p != '\0')
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000108 return 1;
109 ok:
110 *h = maj;
111 return 0;
112}
113
114/* Get class ID. Return 0 on success, !0 otherwise. */
Daniel Fandrich6295d272011-06-09 15:44:44 -0700115static int get_tc_classid(uint32_t *h, const char *str) {
116 uint32_t maj, min;
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000117 char *p;
118
119 maj = TC_H_ROOT;
120 if (!strcmp(str, "root"))
121 goto ok;
122 maj = TC_H_UNSPEC;
123 if (!strcmp(str, "none"))
124 goto ok;
125 maj = strtoul(str, &p, 16);
126 if (p == str) {
127 if (*p != ':')
128 return 1;
129 maj = 0;
130 }
131 if (*p == ':') {
132 if (maj >= (1<<16))
133 return 1;
134 maj <<= 16;
135 str = p + 1;
136 min = strtoul(str, &p, 16);
Denys Vlasenko1f27ab02009-09-23 17:17:53 +0200137//FIXME: check for "" too?
138 if (*p != '\0' || min >= (1<<16))
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000139 return 1;
140 maj |= min;
141 } else if (*p != 0)
142 return 1;
143 ok:
144 *h = maj;
145 return 0;
146}
147
148static void print_rate(char *buf, int len, uint32_t rate)
149{
150 double tmp = (double)rate*8;
151
152 if (use_iec) {
Denys Vlasenkob8781212015-05-24 18:01:53 +0200153 if (tmp >= 1000*1024*1024)
154 snprintf(buf, len, "%.0fMibit", tmp/(1024*1024));
155 else if (tmp >= 1000*1024)
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000156 snprintf(buf, len, "%.0fKibit", tmp/1024);
157 else
158 snprintf(buf, len, "%.0fbit", tmp);
159 } else {
Denys Vlasenkob8781212015-05-24 18:01:53 +0200160 if (tmp >= 1000*1000000)
161 snprintf(buf, len, "%.0fMbit", tmp/1000000);
162 else if (tmp >= 1000*1000)
163 snprintf(buf, len, "%.0fKbit", tmp/1000);
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000164 else
165 snprintf(buf, len, "%.0fbit", tmp);
166 }
167}
168
169/* This is "pfifo_fast". */
170static int prio_parse_opt(int argc, char **argv, struct nlmsghdr *n)
171{
172 return 0;
173}
174static int prio_print_opt(struct rtattr *opt)
175{
176 int i;
177 struct tc_prio_qopt *qopt;
178 struct rtattr *tb[TCA_PRIO_MAX+1];
179
180 if (opt == NULL)
181 return 0;
182 parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt, sizeof(*qopt));
183 if (tb == NULL)
184 return 0;
185 printf("bands %u priomap ", qopt->bands);
186 for (i=0; i<=TC_PRIO_MAX; i++)
187 printf(" %d", qopt->priomap[i]);
188
189 if (tb[TCA_PRIO_MQ])
190 printf(" multiqueue: o%s ",
191 *(unsigned char *)RTA_DATA(tb[TCA_PRIO_MQ]) ? "n" : "ff");
192
193 return 0;
194}
195
196/* Class Based Queue */
197static int cbq_parse_opt(int argc, char **argv, struct nlmsghdr *n)
198{
199 return 0;
200}
201static int cbq_print_opt(struct rtattr *opt)
202{
203 struct rtattr *tb[TCA_CBQ_MAX+1];
204 struct tc_ratespec *r = NULL;
205 struct tc_cbq_lssopt *lss = NULL;
206 struct tc_cbq_wrropt *wrr = NULL;
207 struct tc_cbq_fopt *fopt = NULL;
208 struct tc_cbq_ovl *ovl = NULL;
Denys Vlasenko695fa512010-01-06 18:16:39 +0100209 const char *const error = "CBQ: too short %s opt";
210 char buf[64];
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000211
212 if (opt == NULL)
213 goto done;
214 parse_rtattr_nested(tb, TCA_CBQ_MAX, opt);
215
216 if (tb[TCA_CBQ_RATE]) {
217 if (RTA_PAYLOAD(tb[TCA_CBQ_RATE]) < sizeof(*r))
218 bb_error_msg(error, "rate");
219 else
220 r = RTA_DATA(tb[TCA_CBQ_RATE]);
221 }
222 if (tb[TCA_CBQ_LSSOPT]) {
223 if (RTA_PAYLOAD(tb[TCA_CBQ_LSSOPT]) < sizeof(*lss))
224 bb_error_msg(error, "lss");
225 else
226 lss = RTA_DATA(tb[TCA_CBQ_LSSOPT]);
227 }
228 if (tb[TCA_CBQ_WRROPT]) {
229 if (RTA_PAYLOAD(tb[TCA_CBQ_WRROPT]) < sizeof(*wrr))
230 bb_error_msg(error, "wrr");
231 else
232 wrr = RTA_DATA(tb[TCA_CBQ_WRROPT]);
233 }
234 if (tb[TCA_CBQ_FOPT]) {
235 if (RTA_PAYLOAD(tb[TCA_CBQ_FOPT]) < sizeof(*fopt))
236 bb_error_msg(error, "fopt");
237 else
238 fopt = RTA_DATA(tb[TCA_CBQ_FOPT]);
239 }
240 if (tb[TCA_CBQ_OVL_STRATEGY]) {
241 if (RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]) < sizeof(*ovl))
242 bb_error_msg("CBQ: too short overlimit strategy %u/%u",
243 (unsigned) RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]),
244 (unsigned) sizeof(*ovl));
245 else
246 ovl = RTA_DATA(tb[TCA_CBQ_OVL_STRATEGY]);
247 }
248
249 if (r) {
250 print_rate(buf, sizeof(buf), r->rate);
251 printf("rate %s ", buf);
252 if (show_details) {
253 printf("cell %ub ", 1<<r->cell_log);
254 if (r->mpu)
255 printf("mpu %ub ", r->mpu);
256 if (r->overhead)
257 printf("overhead %ub ", r->overhead);
258 }
259 }
260 if (lss && lss->flags) {
261 bool comma = false;
262 bb_putchar('(');
263 if (lss->flags&TCF_CBQ_LSS_BOUNDED) {
264 printf("bounded");
265 comma = true;
266 }
267 if (lss->flags&TCF_CBQ_LSS_ISOLATED) {
268 if (comma)
269 bb_putchar(',');
270 printf("isolated");
271 }
272 printf(") ");
273 }
274 if (wrr) {
275 if (wrr->priority != TC_CBQ_MAXPRIO)
276 printf("prio %u", wrr->priority);
277 else
278 printf("prio no-transmit");
279 if (show_details) {
280 printf("/%u ", wrr->cpriority);
281 if (wrr->weight != 1) {
282 print_rate(buf, sizeof(buf), wrr->weight);
283 printf("weight %s ", buf);
284 }
285 if (wrr->allot)
286 printf("allot %ub ", wrr->allot);
287 }
288 }
289 done:
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000290 return 0;
291}
292
293static int print_qdisc(const struct sockaddr_nl *who UNUSED_PARAM,
294 struct nlmsghdr *hdr, void *arg UNUSED_PARAM)
295{
296 struct tcmsg *msg = NLMSG_DATA(hdr);
297 int len = hdr->nlmsg_len;
298 struct rtattr * tb[TCA_MAX+1];
299 char *name;
300
301 if (hdr->nlmsg_type != RTM_NEWQDISC && hdr->nlmsg_type != RTM_DELQDISC) {
Denis Vlasenko1fd3b382009-04-29 12:02:57 +0000302 /* bb_error_msg("not a qdisc"); */
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000303 return 0; /* ??? mimic upstream; should perhaps return -1 */
304 }
305 len -= NLMSG_LENGTH(sizeof(*msg));
306 if (len < 0) {
Denis Vlasenko1fd3b382009-04-29 12:02:57 +0000307 /* bb_error_msg("wrong len %d", len); */
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000308 return -1;
309 }
310 /* not the desired interface? */
311 if (filter_ifindex && filter_ifindex != msg->tcm_ifindex)
312 return 0;
313 memset (tb, 0, sizeof(tb));
314 parse_rtattr(tb, TCA_MAX, TCA_RTA(msg), len);
315 if (tb[TCA_KIND] == NULL) {
316 /* bb_error_msg("%s: NULL kind", "qdisc"); */
317 return -1;
318 }
319 if (hdr->nlmsg_type == RTM_DELQDISC)
320 printf("deleted ");
321 name = (char*)RTA_DATA(tb[TCA_KIND]);
322 printf("qdisc %s %x: ", name, msg->tcm_handle>>16);
323 if (filter_ifindex == 0)
324 printf("dev %s ", ll_index_to_name(msg->tcm_ifindex));
325 if (msg->tcm_parent == TC_H_ROOT)
326 printf("root ");
327 else if (msg->tcm_parent) {
328 char *classid = print_tc_classid(msg->tcm_parent);
329 printf("parent %s ", classid);
330 if (ENABLE_FEATURE_CLEAN_UP)
331 free(classid);
332 }
333 if (msg->tcm_info != 1)
334 printf("refcnt %d ", msg->tcm_info);
335 if (tb[TCA_OPTIONS]) {
336 static const char _q_[] ALIGN1 = "pfifo_fast\0""cbq\0";
337 int qqq = index_in_strings(_q_, name);
338 if (qqq == 0) { /* pfifo_fast aka prio */
339 prio_print_opt(tb[TCA_OPTIONS]);
Denys Vlasenkobf2af9a2009-05-25 04:15:37 +0200340 } else if (qqq == 1) { /* class based queuing */
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000341 cbq_print_opt(tb[TCA_OPTIONS]);
342 } else
343 bb_error_msg("unknown %s", name);
344 }
345 bb_putchar('\n');
346 return 0;
347}
348
349static int print_class(const struct sockaddr_nl *who UNUSED_PARAM,
350 struct nlmsghdr *hdr, void *arg UNUSED_PARAM)
351{
352 struct tcmsg *msg = NLMSG_DATA(hdr);
353 int len = hdr->nlmsg_len;
354 struct rtattr * tb[TCA_MAX+1];
355 char *name, *classid;
356
357 /*XXX Eventually factor out common code */
358
359 if (hdr->nlmsg_type != RTM_NEWTCLASS && hdr->nlmsg_type != RTM_DELTCLASS) {
Denis Vlasenko1fd3b382009-04-29 12:02:57 +0000360 /* bb_error_msg("not a class"); */
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000361 return 0; /* ??? mimic upstream; should perhaps return -1 */
362 }
363 len -= NLMSG_LENGTH(sizeof(*msg));
364 if (len < 0) {
Denis Vlasenko1fd3b382009-04-29 12:02:57 +0000365 /* bb_error_msg("wrong len %d", len); */
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000366 return -1;
367 }
368 /* not the desired interface? */
369 if (filter_qdisc && TC_H_MAJ(msg->tcm_handle^filter_qdisc))
370 return 0;
371 memset (tb, 0, sizeof(tb));
372 parse_rtattr(tb, TCA_MAX, TCA_RTA(msg), len);
373 if (tb[TCA_KIND] == NULL) {
374 /* bb_error_msg("%s: NULL kind", "class"); */
375 return -1;
376 }
377 if (hdr->nlmsg_type == RTM_DELTCLASS)
378 printf("deleted ");
379
380 name = (char*)RTA_DATA(tb[TCA_KIND]);
381 classid = !msg->tcm_handle ? NULL : print_tc_classid(
382 filter_qdisc ? TC_H_MIN(msg->tcm_parent) : msg->tcm_parent);
383 printf ("class %s %s", name, classid);
384 if (ENABLE_FEATURE_CLEAN_UP)
385 free(classid);
386
387 if (filter_ifindex == 0)
388 printf("dev %s ", ll_index_to_name(msg->tcm_ifindex));
389 if (msg->tcm_parent == TC_H_ROOT)
390 printf("root ");
391 else if (msg->tcm_parent) {
392 classid = print_tc_classid(filter_qdisc ?
Denys Vlasenko60cb48c2013-01-14 15:57:44 +0100393 TC_H_MIN(msg->tcm_parent) : msg->tcm_parent);
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000394 printf("parent %s ", classid);
395 if (ENABLE_FEATURE_CLEAN_UP)
396 free(classid);
397 }
398 if (msg->tcm_info)
399 printf("leaf %x ", msg->tcm_info >> 16);
400 /* Do that get_qdisc_kind(RTA_DATA(tb[TCA_KIND])). */
401 if (tb[TCA_OPTIONS]) {
402 static const char _q_[] ALIGN1 = "pfifo_fast\0""cbq\0";
403 int qqq = index_in_strings(_q_, name);
404 if (qqq == 0) { /* pfifo_fast aka prio */
405 /* nothing. */ /*prio_print_opt(tb[TCA_OPTIONS]);*/
Denys Vlasenkobf2af9a2009-05-25 04:15:37 +0200406 } else if (qqq == 1) { /* class based queuing */
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000407 /* cbq_print_copt() is identical to cbq_print_opt(). */
408 cbq_print_opt(tb[TCA_OPTIONS]);
409 } else
410 bb_error_msg("unknown %s", name);
411 }
412 bb_putchar('\n');
413
414 return 0;
415}
416
417static int print_filter(const struct sockaddr_nl *who UNUSED_PARAM,
418 struct nlmsghdr *hdr, void *arg UNUSED_PARAM)
419{
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000420 return 0;
421}
422
423int tc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
424int tc_main(int argc UNUSED_PARAM, char **argv)
425{
426 static const char objects[] ALIGN1 =
427 "qdisc\0""class\0""filter\0"
428 ;
429 enum { OBJ_qdisc = 0, OBJ_class, OBJ_filter };
430 static const char commands[] ALIGN1 =
431 "add\0""delete\0""change\0"
432 "link\0" /* only qdisc */
433 "replace\0"
434 "show\0""list\0"
435 ;
436 static const char args[] ALIGN1 =
437 "dev\0" /* qdisc, class, filter */
438 "root\0" /* class, filter */
439 "parent\0" /* class, filter */
440 "qdisc\0" /* class */
441 "handle\0" /* change: qdisc, class(classid) list: filter */
442 "classid\0" /* change: for class use "handle" */
443 "preference\0""priority\0""protocol\0" /* filter */
444 ;
445 enum { CMD_add = 0, CMD_del, CMD_change, CMD_link, CMD_replace, CMD_show };
446 enum { ARG_dev = 0, ARG_root, ARG_parent, ARG_qdisc,
447 ARG_handle, ARG_classid, ARG_pref, ARG_prio, ARG_proto};
448 struct rtnl_handle rth;
449 struct tcmsg msg;
450 int ret, obj, cmd, arg;
451 char *dev = NULL;
452
453 INIT_G();
454
455 if (!*++argv)
456 bb_show_usage();
457 xrtnl_open(&rth);
458 ret = EXIT_SUCCESS;
459
460 obj = index_in_substrings(objects, *argv++);
461
Denys Vlasenko0f296a32015-10-14 13:21:01 +0200462 if (obj < 0)
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000463 bb_show_usage();
464 if (!*argv)
465 cmd = CMD_show; /* list is the default */
466 else {
467 cmd = index_in_substrings(commands, *argv);
468 if (cmd < 0)
Denys Vlasenko0f296a32015-10-14 13:21:01 +0200469 invarg_1_to_2(*argv, argv[-1]);
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000470 argv++;
471 }
472 memset(&msg, 0, sizeof(msg));
473 msg.tcm_family = AF_UNSPEC;
474 ll_init_map(&rth);
475 while (*argv) {
476 arg = index_in_substrings(args, *argv);
477 if (arg == ARG_dev) {
478 NEXT_ARG();
479 if (dev)
480 duparg2("dev", *argv);
481 dev = *argv++;
482 msg.tcm_ifindex = xll_name_to_index(dev);
483 if (cmd >= CMD_show)
484 filter_ifindex = msg.tcm_ifindex;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100485 } else
486 if ((arg == ARG_qdisc && obj == OBJ_class && cmd >= CMD_show)
487 || (arg == ARG_handle && obj == OBJ_qdisc && cmd == CMD_change)
488 ) {
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000489 NEXT_ARG();
490 /* We don't care about duparg2("qdisc handle",*argv) for now */
491 if (get_qdisc_handle(&filter_qdisc, *argv))
Denys Vlasenko0f296a32015-10-14 13:21:01 +0200492 invarg_1_to_2(*argv, "qdisc");
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100493 } else
494 if (obj != OBJ_qdisc
495 && (arg == ARG_root
496 || arg == ARG_parent
497 || (obj == OBJ_filter && arg >= ARG_pref)
498 )
499 ) {
500 /* nothing */
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000501 } else {
Denys Vlasenko0f296a32015-10-14 13:21:01 +0200502 invarg_1_to_2(*argv, "command");
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000503 }
504 NEXT_ARG();
505 if (arg == ARG_root) {
506 if (msg.tcm_parent)
507 duparg("parent", *argv);
508 msg.tcm_parent = TC_H_ROOT;
509 if (obj == OBJ_filter)
510 filter_parent = TC_H_ROOT;
511 } else if (arg == ARG_parent) {
Daniel Fandrich6295d272011-06-09 15:44:44 -0700512 uint32_t handle;
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000513 if (msg.tcm_parent)
514 duparg(*argv, "parent");
515 if (get_tc_classid(&handle, *argv))
Denys Vlasenko0f296a32015-10-14 13:21:01 +0200516 invarg_1_to_2(*argv, "parent");
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000517 msg.tcm_parent = handle;
518 if (obj == OBJ_filter)
519 filter_parent = handle;
520 } else if (arg == ARG_handle) { /* filter::list */
521 if (msg.tcm_handle)
522 duparg(*argv, "handle");
523 /* reject LONG_MIN || LONG_MAX */
524 /* TODO: for fw
Denys Vlasenko60cb48c2013-01-14 15:57:44 +0100525 slash = strchr(handle, '/');
526 if (slash != NULL)
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000527 *slash = '\0';
528 */
Denis Vlasenko76140a72009-03-05 09:21:57 +0000529 msg.tcm_handle = get_u32(*argv, "handle");
Daniel Fandrich6295d272011-06-09 15:44:44 -0700530 /* if (slash) {if (get_u32(uint32_t &mask, slash+1, NULL)) inv mask; addattr32(n, MAX_MSG, TCA_FW_MASK, mask); */
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000531 } else if (arg == ARG_classid && obj == OBJ_class && cmd == CMD_change){
532 } else if (arg == ARG_pref || arg == ARG_prio) { /* filter::list */
533 if (filter_prio)
534 duparg(*argv, "priority");
Denis Vlasenko76140a72009-03-05 09:21:57 +0000535 filter_prio = get_u32(*argv, "priority");
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000536 } else if (arg == ARG_proto) { /* filter::list */
Denys Vlasenko0568b6e2009-08-08 03:20:12 +0200537 uint16_t tmp;
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000538 if (filter_proto)
539 duparg(*argv, "protocol");
540 if (ll_proto_a2n(&tmp, *argv))
Denys Vlasenko0f296a32015-10-14 13:21:01 +0200541 invarg_1_to_2(*argv, "protocol");
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000542 filter_proto = tmp;
543 }
544 }
545 if (cmd >= CMD_show) { /* show or list */
546 if (obj == OBJ_filter)
547 msg.tcm_info = TC_H_MAKE(filter_prio<<16, filter_proto);
548 if (rtnl_dump_request(&rth, obj == OBJ_qdisc ? RTM_GETQDISC :
549 obj == OBJ_class ? RTM_GETTCLASS : RTM_GETTFILTER,
550 &msg, sizeof(msg)) < 0)
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100551 bb_simple_perror_msg_and_die("can't send dump request");
Bernhard Reutner-Fischer0901c512008-09-04 13:22:58 +0000552
553 xrtnl_dump_filter(&rth, obj == OBJ_qdisc ? print_qdisc :
554 obj == OBJ_class ? print_class : print_filter,
555 NULL);
556 }
557 if (ENABLE_FEATURE_CLEAN_UP) {
558 rtnl_close(&rth);
559 }
560 return ret;
561}