Fix build break in 64bit architectures
[platform/upstream/iproute2.git] / tc / tc_filter.c
1 /*
2  * tc_filter.c          "tc filter".
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 <fcntl.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
20 #include <string.h>
21 #include <linux/if_ether.h>
22
23 #include "rt_names.h"
24 #include "utils.h"
25 #include "tc_util.h"
26 #include "tc_common.h"
27
28 static void usage(void)
29 {
30         fprintf(stderr,
31                 "Usage: tc filter [ add | del | change | replace | show ] [ dev STRING ]\n"
32                 "       tc filter [ add | del | change | replace | show ] [ block BLOCK_INDEX ]\n"
33                 "       tc filter get dev STRING parent CLASSID protocol PROTO handle FILTERID pref PRIO FILTER_TYPE\n"
34                 "       tc filter get block BLOCK_INDEX protocol PROTO handle FILTERID pref PRIO FILTER_TYPE\n"
35                 "       [ pref PRIO ] protocol PROTO [ chain CHAIN_INDEX ]\n"
36                 "       [ estimator INTERVAL TIME_CONSTANT ]\n"
37                 "       [ root | ingress | egress | parent CLASSID ]\n"
38                 "       [ handle FILTERID ] [ [ FILTER_TYPE ] [ help | OPTIONS ] ]\n"
39                 "\n"
40                 "       tc filter show [ dev STRING ] [ root | ingress | egress | parent CLASSID ]\n"
41                 "       tc filter show [ block BLOCK_INDEX ]\n"
42                 "Where:\n"
43                 "FILTER_TYPE := { rsvp | u32 | bpf | fw | route | etc. }\n"
44                 "FILTERID := ... format depends on classifier, see there\n"
45                 "OPTIONS := ... try tc filter add <desired FILTER_KIND> help\n");
46 }
47
48 static void chain_usage(void)
49 {
50         fprintf(stderr,
51                 "Usage: tc chain [ add | del | get | show ] [ dev STRING ]\n"
52                 "       tc chain [ add | del | get | show ] [ block BLOCK_INDEX ] ]\n");
53 }
54
55 struct tc_filter_req {
56         struct nlmsghdr         n;
57         struct tcmsg            t;
58         char                    buf[MAX_MSG];
59 };
60
61 static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
62 {
63         struct {
64                 struct nlmsghdr n;
65                 struct tcmsg            t;
66                 char                    buf[MAX_MSG];
67         } req = {
68                 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
69                 .n.nlmsg_flags = NLM_F_REQUEST | flags,
70                 .n.nlmsg_type = cmd,
71                 .t.tcm_family = AF_UNSPEC,
72         };
73         struct filter_util *q = NULL;
74         __u32 prio = 0;
75         __u32 protocol = 0;
76         int protocol_set = 0;
77         __u32 block_index = 0;
78         __u32 chain_index;
79         int chain_index_set = 0;
80         char *fhandle = NULL;
81         char  d[IFNAMSIZ] = {};
82         char  k[FILTER_NAMESZ] = {};
83         struct tc_estimator est = {};
84
85         if (cmd == RTM_NEWTFILTER && flags & NLM_F_CREATE)
86                 protocol = htons(ETH_P_ALL);
87
88         while (argc > 0) {
89                 if (strcmp(*argv, "dev") == 0) {
90                         NEXT_ARG();
91                         if (d[0])
92                                 duparg("dev", *argv);
93                         if (block_index) {
94                                 fprintf(stderr, "Error: \"dev\" and \"block\" are mutually exclusive\n");
95                                 return -1;
96                         }
97                         strncpy(d, *argv, sizeof(d)-1);
98                 } else if (matches(*argv, "block") == 0) {
99                         NEXT_ARG();
100                         if (block_index)
101                                 duparg("block", *argv);
102                         if (d[0]) {
103                                 fprintf(stderr, "Error: \"dev\" and \"block\" are mutually exclusive\n");
104                                 return -1;
105                         }
106                         if (get_u32(&block_index, *argv, 0) || !block_index)
107                                 invarg("invalid block index value", *argv);
108                 } else if (strcmp(*argv, "root") == 0) {
109                         if (req.t.tcm_parent) {
110                                 fprintf(stderr,
111                                         "Error: \"root\" is duplicate parent ID\n");
112                                 return -1;
113                         }
114                         req.t.tcm_parent = TC_H_ROOT;
115                 } else if (strcmp(*argv, "ingress") == 0) {
116                         if (req.t.tcm_parent) {
117                                 fprintf(stderr,
118                                         "Error: \"ingress\" is duplicate parent ID\n");
119                                 return -1;
120                         }
121                         req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
122                                                      TC_H_MIN_INGRESS);
123                 } else if (strcmp(*argv, "egress") == 0) {
124                         if (req.t.tcm_parent) {
125                                 fprintf(stderr,
126                                         "Error: \"egress\" is duplicate parent ID\n");
127                                 return -1;
128                         }
129                         req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
130                                                      TC_H_MIN_EGRESS);
131                 } else if (strcmp(*argv, "parent") == 0) {
132                         __u32 handle;
133
134                         NEXT_ARG();
135                         if (req.t.tcm_parent)
136                                 duparg("parent", *argv);
137                         if (get_tc_classid(&handle, *argv))
138                                 invarg("Invalid parent ID", *argv);
139                         req.t.tcm_parent = handle;
140                 } else if (strcmp(*argv, "handle") == 0) {
141                         NEXT_ARG();
142                         if (fhandle)
143                                 duparg("handle", *argv);
144                         fhandle = *argv;
145                 } else if (matches(*argv, "preference") == 0 ||
146                            matches(*argv, "priority") == 0) {
147                         NEXT_ARG();
148                         if (prio)
149                                 duparg("priority", *argv);
150                         if (get_u32(&prio, *argv, 0) || prio > 0xFFFF)
151                                 invarg("invalid priority value", *argv);
152                 } else if (matches(*argv, "protocol") == 0) {
153                         __u16 id;
154
155                         NEXT_ARG();
156                         if (protocol_set)
157                                 duparg("protocol", *argv);
158                         if (ll_proto_a2n(&id, *argv))
159                                 invarg("invalid protocol", *argv);
160                         protocol = id;
161                         protocol_set = 1;
162                 } else if (matches(*argv, "chain") == 0) {
163                         NEXT_ARG();
164                         if (chain_index_set)
165                                 duparg("chain", *argv);
166                         if (get_u32(&chain_index, *argv, 0))
167                                 invarg("invalid chain index value", *argv);
168                         chain_index_set = 1;
169                 } else if (matches(*argv, "estimator") == 0) {
170                         if (parse_estimator(&argc, &argv, &est) < 0)
171                                 return -1;
172                 } else if (matches(*argv, "help") == 0) {
173                         usage();
174                         return 0;
175                 } else {
176                         strncpy(k, *argv, sizeof(k)-1);
177
178                         q = get_filter_kind(k);
179                         argc--; argv++;
180                         break;
181                 }
182
183                 argc--; argv++;
184         }
185
186         req.t.tcm_info = TC_H_MAKE(prio<<16, protocol);
187
188         if (chain_index_set)
189                 addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index);
190
191         if (k[0])
192                 addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1);
193
194         if (d[0])  {
195                 ll_init_map(&rth);
196
197                 req.t.tcm_ifindex = ll_name_to_index(d);
198                 if (req.t.tcm_ifindex == 0) {
199                         fprintf(stderr, "Cannot find device \"%s\"\n", d);
200                         return 1;
201                 }
202         } else if (block_index) {
203                 req.t.tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK;
204                 req.t.tcm_block_index = block_index;
205         }
206
207         if (q) {
208                 if (q->parse_fopt(q, fhandle, argc, argv, &req.n))
209                         return 1;
210         } else {
211                 if (fhandle) {
212                         fprintf(stderr,
213                                 "Must specify filter type when using \"handle\"\n");
214                         return -1;
215                 }
216                 if (argc) {
217                         if (matches(*argv, "help") == 0)
218                                 usage();
219                         fprintf(stderr,
220                                 "Garbage instead of arguments \"%s ...\". Try \"tc filter help\".\n",
221                                 *argv);
222                         return -1;
223                 }
224         }
225
226         if (est.ewma_log)
227                 addattr_l(&req.n, sizeof(req), TCA_RATE, &est, sizeof(est));
228
229         if (rtnl_talk(&rth, &req.n, NULL) < 0) {
230                 fprintf(stderr, "We have an error talking to the kernel\n");
231                 return 2;
232         }
233
234         return 0;
235 }
236
237 static __u32 filter_parent;
238 static int filter_ifindex;
239 static __u32 filter_prio;
240 static __u32 filter_protocol;
241 static __u32 filter_chain_index;
242 static int filter_chain_index_set;
243 static __u32 filter_block_index;
244 __u16 f_proto;
245
246 int print_filter(struct nlmsghdr *n, void *arg)
247 {
248         FILE *fp = (FILE *)arg;
249         struct tcmsg *t = NLMSG_DATA(n);
250         int len = n->nlmsg_len;
251         struct rtattr *tb[TCA_MAX+1];
252         struct filter_util *q;
253         char abuf[256];
254
255         if (n->nlmsg_type != RTM_NEWTFILTER &&
256             n->nlmsg_type != RTM_GETTFILTER &&
257             n->nlmsg_type != RTM_DELTFILTER &&
258             n->nlmsg_type != RTM_NEWCHAIN &&
259             n->nlmsg_type != RTM_GETCHAIN &&
260             n->nlmsg_type != RTM_DELCHAIN) {
261                 fprintf(stderr, "Not a filter(cmd %d)\n", n->nlmsg_type);
262                 return 0;
263         }
264         len -= NLMSG_LENGTH(sizeof(*t));
265         if (len < 0) {
266                 fprintf(stderr, "Wrong len %d\n", len);
267                 return -1;
268         }
269
270         parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len);
271
272         if (tb[TCA_KIND] == NULL && (n->nlmsg_type == RTM_NEWTFILTER ||
273                                      n->nlmsg_type == RTM_GETTFILTER ||
274                                      n->nlmsg_type == RTM_DELTFILTER)) {
275                 fprintf(stderr, "print_filter: NULL kind\n");
276                 return -1;
277         }
278
279         open_json_object(NULL);
280
281         if (n->nlmsg_type == RTM_DELTFILTER || n->nlmsg_type == RTM_DELCHAIN)
282                 print_bool(PRINT_ANY, "deleted", "deleted ", true);
283
284         if ((n->nlmsg_type == RTM_NEWTFILTER ||
285              n->nlmsg_type == RTM_NEWCHAIN) &&
286                         (n->nlmsg_flags & NLM_F_CREATE) &&
287                         !(n->nlmsg_flags & NLM_F_EXCL))
288                 print_bool(PRINT_ANY, "replaced", "replaced ", true);
289
290         if ((n->nlmsg_type == RTM_NEWTFILTER ||
291              n->nlmsg_type == RTM_NEWCHAIN) &&
292                         (n->nlmsg_flags & NLM_F_CREATE) &&
293                         (n->nlmsg_flags & NLM_F_EXCL))
294                 print_bool(PRINT_ANY, "added", "added ", true);
295
296         if (n->nlmsg_type == RTM_NEWTFILTER ||
297             n->nlmsg_type == RTM_GETTFILTER ||
298             n->nlmsg_type == RTM_DELTFILTER)
299                 print_string(PRINT_FP, NULL, "filter ", NULL);
300         else
301                 print_string(PRINT_FP, NULL, "chain ", NULL);
302         if (t->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK) {
303                 if (!filter_block_index ||
304                     filter_block_index != t->tcm_block_index)
305                         print_uint(PRINT_ANY, "block", "block %u ",
306                                    t->tcm_block_index);
307         } else {
308                 if (!filter_ifindex || filter_ifindex != t->tcm_ifindex)
309                         print_devname(PRINT_ANY, t->tcm_ifindex);
310
311                 if (!filter_parent || filter_parent != t->tcm_parent) {
312                         if (t->tcm_parent == TC_H_ROOT)
313                                 print_bool(PRINT_ANY, "root", "root ", true);
314                         else if (t->tcm_parent == TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS))
315                                 print_bool(PRINT_ANY, "ingress", "ingress ", true);
316                         else if (t->tcm_parent == TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS))
317                                 print_bool(PRINT_ANY, "egress", "egress ", true);
318                         else {
319                                 print_tc_classid(abuf, sizeof(abuf), t->tcm_parent);
320                                 print_string(PRINT_ANY, "parent", "parent %s ", abuf);
321                         }
322                 }
323         }
324
325         if (t->tcm_info && (n->nlmsg_type == RTM_NEWTFILTER ||
326                             n->nlmsg_type == RTM_DELTFILTER ||
327                             n->nlmsg_type == RTM_GETTFILTER)) {
328                 f_proto = TC_H_MIN(t->tcm_info);
329                 __u32 prio = TC_H_MAJ(t->tcm_info)>>16;
330
331                 if (!filter_protocol || filter_protocol != f_proto) {
332                         if (f_proto) {
333                                 SPRINT_BUF(b1);
334                                 print_string(PRINT_ANY, "protocol",
335                                              "protocol %s ",
336                                              ll_proto_n2a(f_proto, b1, sizeof(b1)));
337                         }
338                 }
339                 if (!filter_prio || filter_prio != prio) {
340                         if (prio)
341                                 print_uint(PRINT_ANY, "pref", "pref %u ", prio);
342                 }
343         }
344         if (tb[TCA_KIND])
345                 print_string(PRINT_ANY, "kind", "%s ", rta_getattr_str(tb[TCA_KIND]));
346
347         if (tb[TCA_CHAIN]) {
348                 __u32 chain_index = rta_getattr_u32(tb[TCA_CHAIN]);
349
350                 if (!filter_chain_index_set ||
351                     filter_chain_index != chain_index)
352                         print_uint(PRINT_ANY, "chain", "chain %u ",
353                                    chain_index);
354         }
355
356         if (tb[TCA_KIND]) {
357                 q = get_filter_kind(RTA_DATA(tb[TCA_KIND]));
358                 if (tb[TCA_OPTIONS]) {
359                         open_json_object("options");
360                         if (q)
361                                 q->print_fopt(q, fp, tb[TCA_OPTIONS], t->tcm_handle);
362                         else
363                                 fprintf(stderr, "cannot parse option parameters\n");
364                         close_json_object();
365                 }
366         }
367         print_string(PRINT_FP, NULL, "\n", NULL);
368
369         if (show_stats && (tb[TCA_STATS] || tb[TCA_STATS2])) {
370                 print_tcstats_attr(fp, tb, " ", NULL);
371                 print_string(PRINT_FP, NULL, "\n", NULL);
372         }
373
374         close_json_object();
375         fflush(fp);
376         return 0;
377 }
378
379 static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv)
380 {
381         struct {
382                 struct nlmsghdr n;
383                 struct tcmsg            t;
384                 char                    buf[MAX_MSG];
385         } req = {
386                 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
387                 /* NLM_F_ECHO is for backward compatibility. old kernels never
388                  * respond without it and newer kernels will ignore it.
389                  * In old kernels there is a side effect:
390                  * In addition to a response to the GET you will receive an
391                  * event (if you do tc mon).
392                  */
393                 .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ECHO | flags,
394                 .n.nlmsg_type = cmd,
395                 .t.tcm_parent = TC_H_UNSPEC,
396                 .t.tcm_family = AF_UNSPEC,
397         };
398         struct nlmsghdr *answer;
399         struct filter_util *q = NULL;
400         __u32 prio = 0;
401         __u32 protocol = 0;
402         int protocol_set = 0;
403         __u32 chain_index;
404         int chain_index_set = 0;
405         __u32 block_index = 0;
406         __u32 parent_handle = 0;
407         char *fhandle = NULL;
408         char  d[IFNAMSIZ] = {};
409         char  k[FILTER_NAMESZ] = {};
410
411         while (argc > 0) {
412                 if (strcmp(*argv, "dev") == 0) {
413                         NEXT_ARG();
414                         if (d[0])
415                                 duparg("dev", *argv);
416                         if (block_index) {
417                                 fprintf(stderr, "Error: \"dev\" and \"block\" are mutually exclusive\n");
418                                 return -1;
419                         }
420                         strncpy(d, *argv, sizeof(d)-1);
421                 } else if (matches(*argv, "block") == 0) {
422                         NEXT_ARG();
423                         if (block_index)
424                                 duparg("block", *argv);
425                         if (d[0]) {
426                                 fprintf(stderr, "Error: \"dev\" and \"block\" are mutually exclusive\n");
427                                 return -1;
428                         }
429                         if (get_u32(&block_index, *argv, 0) || !block_index)
430                                 invarg("invalid block index value", *argv);
431                 } else if (strcmp(*argv, "root") == 0) {
432                         if (req.t.tcm_parent) {
433                                 fprintf(stderr,
434                                         "Error: \"root\" is duplicate parent ID\n");
435                                 return -1;
436                         }
437                         req.t.tcm_parent = TC_H_ROOT;
438                 } else if (strcmp(*argv, "ingress") == 0) {
439                         if (req.t.tcm_parent) {
440                                 fprintf(stderr,
441                                         "Error: \"ingress\" is duplicate parent ID\n");
442                                 return -1;
443                         }
444                         req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
445                                                      TC_H_MIN_INGRESS);
446                 } else if (strcmp(*argv, "egress") == 0) {
447                         if (req.t.tcm_parent) {
448                                 fprintf(stderr,
449                                         "Error: \"egress\" is duplicate parent ID\n");
450                                 return -1;
451                         }
452                         req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
453                                                      TC_H_MIN_EGRESS);
454                 } else if (strcmp(*argv, "parent") == 0) {
455
456                         NEXT_ARG();
457                         if (req.t.tcm_parent)
458                                 duparg("parent", *argv);
459                         if (get_tc_classid(&parent_handle, *argv))
460                                 invarg("Invalid parent ID", *argv);
461                         req.t.tcm_parent = parent_handle;
462                 } else if (strcmp(*argv, "handle") == 0) {
463                         NEXT_ARG();
464                         if (fhandle)
465                                 duparg("handle", *argv);
466                         fhandle = *argv;
467                 } else if (matches(*argv, "preference") == 0 ||
468                            matches(*argv, "priority") == 0) {
469                         NEXT_ARG();
470                         if (prio)
471                                 duparg("priority", *argv);
472                         if (get_u32(&prio, *argv, 0) || prio > 0xFFFF)
473                                 invarg("invalid priority value", *argv);
474                 } else if (matches(*argv, "protocol") == 0) {
475                         __u16 id;
476
477                         NEXT_ARG();
478                         if (protocol_set)
479                                 duparg("protocol", *argv);
480                         if (ll_proto_a2n(&id, *argv))
481                                 invarg("invalid protocol", *argv);
482                         protocol = id;
483                         protocol_set = 1;
484                 } else if (matches(*argv, "chain") == 0) {
485                         NEXT_ARG();
486                         if (chain_index_set)
487                                 duparg("chain", *argv);
488                         if (get_u32(&chain_index, *argv, 0))
489                                 invarg("invalid chain index value", *argv);
490                         chain_index_set = 1;
491                 } else if (matches(*argv, "help") == 0) {
492                         usage();
493                         return 0;
494                 } else {
495                         if (!**argv)
496                                 invarg("invalid filter name", *argv);
497
498                         strncpy(k, *argv, sizeof(k)-1);
499
500                         q = get_filter_kind(k);
501                         argc--; argv++;
502                         break;
503                 }
504
505                 argc--; argv++;
506         }
507
508         if (cmd == RTM_GETTFILTER) {
509                 if (!protocol_set) {
510                         fprintf(stderr, "Must specify filter protocol\n");
511                         return -1;
512                 }
513
514                 if (!prio) {
515                         fprintf(stderr, "Must specify filter priority\n");
516                         return -1;
517                 }
518
519                 req.t.tcm_info = TC_H_MAKE(prio<<16, protocol);
520         }
521
522         if (chain_index_set)
523                 addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index);
524
525         if (req.t.tcm_parent == TC_H_UNSPEC) {
526                 fprintf(stderr, "Must specify filter parent\n");
527                 return -1;
528         }
529
530         if (cmd == RTM_GETTFILTER) {
531                 if (k[0])
532                         addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1);
533                 else {
534                         fprintf(stderr, "Must specify filter type\n");
535                         return -1;
536                 }
537         }
538
539         if (d[0])  {
540                 ll_init_map(&rth);
541
542                 req.t.tcm_ifindex = ll_name_to_index(d);
543                 if (!req.t.tcm_ifindex)
544                         return -nodev(d);
545                 filter_ifindex = req.t.tcm_ifindex;
546         } else if (block_index) {
547                 req.t.tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK;
548                 req.t.tcm_block_index = block_index;
549                 filter_block_index = block_index;
550         } else {
551                 fprintf(stderr, "Must specify netdevice \"dev\" or block index \"block\"\n");
552                 return -1;
553         }
554
555         if (cmd == RTM_GETTFILTER &&
556             q->parse_fopt(q, fhandle, argc, argv, &req.n))
557                 return 1;
558
559         if (!fhandle && cmd == RTM_GETTFILTER) {
560                 fprintf(stderr, "Must specify filter \"handle\"\n");
561                 return -1;
562         }
563
564         if (argc) {
565                 if (matches(*argv, "help") == 0)
566                         usage();
567                 fprintf(stderr,
568                         "Garbage instead of arguments \"%s ...\". Try \"tc filter help\".\n",
569                         *argv);
570                 return -1;
571         }
572
573         if (rtnl_talk(&rth, &req.n, &answer) < 0) {
574                 fprintf(stderr, "We have an error talking to the kernel\n");
575                 return 2;
576         }
577
578         new_json_obj(json);
579         print_filter(answer, (void *)stdout);
580         delete_json_obj();
581
582         free(answer);
583         return 0;
584 }
585
586 static int tc_filter_list(int cmd, int argc, char **argv)
587 {
588         struct {
589                 struct nlmsghdr n;
590                 struct tcmsg t;
591                 char buf[MAX_MSG];
592         } req = {
593                 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
594                 .n.nlmsg_type = cmd,
595                 .t.tcm_parent = TC_H_UNSPEC,
596                 .t.tcm_family = AF_UNSPEC,
597         };
598         char d[IFNAMSIZ] = {};
599         __u32 prio = 0;
600         __u32 protocol = 0;
601         __u32 chain_index;
602         __u32 block_index = 0;
603         char *fhandle = NULL;
604
605         while (argc > 0) {
606                 if (strcmp(*argv, "dev") == 0) {
607                         NEXT_ARG();
608                         if (d[0])
609                                 duparg("dev", *argv);
610                         if (block_index) {
611                                 fprintf(stderr, "Error: \"dev\" cannot be used in the same time as \"block\"\n");
612                                 return -1;
613                         }
614                         strncpy(d, *argv, sizeof(d)-1);
615                 } else if (matches(*argv, "block") == 0) {
616                         NEXT_ARG();
617                         if (block_index)
618                                 duparg("block", *argv);
619                         if (d[0]) {
620                                 fprintf(stderr, "Error: \"block\" cannot be used in the same time as \"dev\"\n");
621                                 return -1;
622                         }
623                         if (get_u32(&block_index, *argv, 0) || !block_index)
624                                 invarg("invalid block index value", *argv);
625                 } else if (strcmp(*argv, "root") == 0) {
626                         if (req.t.tcm_parent) {
627                                 fprintf(stderr,
628                                         "Error: \"root\" is duplicate parent ID\n");
629                                 return -1;
630                         }
631                         filter_parent = req.t.tcm_parent = TC_H_ROOT;
632                 } else if (strcmp(*argv, "ingress") == 0) {
633                         if (req.t.tcm_parent) {
634                                 fprintf(stderr,
635                                         "Error: \"ingress\" is duplicate parent ID\n");
636                                 return -1;
637                         }
638                         filter_parent = TC_H_MAKE(TC_H_CLSACT,
639                                                   TC_H_MIN_INGRESS);
640                         req.t.tcm_parent = filter_parent;
641                 } else if (strcmp(*argv, "egress") == 0) {
642                         if (req.t.tcm_parent) {
643                                 fprintf(stderr,
644                                         "Error: \"egress\" is duplicate parent ID\n");
645                                 return -1;
646                         }
647                         filter_parent = TC_H_MAKE(TC_H_CLSACT,
648                                                   TC_H_MIN_EGRESS);
649                         req.t.tcm_parent = filter_parent;
650                 } else if (strcmp(*argv, "parent") == 0) {
651                         __u32 handle;
652
653                         NEXT_ARG();
654                         if (req.t.tcm_parent)
655                                 duparg("parent", *argv);
656                         if (get_tc_classid(&handle, *argv))
657                                 invarg("invalid parent ID", *argv);
658                         filter_parent = req.t.tcm_parent = handle;
659                 } else if (strcmp(*argv, "handle") == 0) {
660                         NEXT_ARG();
661                         if (fhandle)
662                                 duparg("handle", *argv);
663                         fhandle = *argv;
664                 } else if (matches(*argv, "preference") == 0 ||
665                            matches(*argv, "priority") == 0) {
666                         NEXT_ARG();
667                         if (prio)
668                                 duparg("priority", *argv);
669                         if (get_u32(&prio, *argv, 0))
670                                 invarg("invalid preference", *argv);
671                         filter_prio = prio;
672                 } else if (matches(*argv, "protocol") == 0) {
673                         __u16 res;
674
675                         NEXT_ARG();
676                         if (protocol)
677                                 duparg("protocol", *argv);
678                         if (ll_proto_a2n(&res, *argv))
679                                 invarg("invalid protocol", *argv);
680                         protocol = res;
681                         filter_protocol = protocol;
682                 } else if (matches(*argv, "chain") == 0) {
683                         NEXT_ARG();
684                         if (filter_chain_index_set)
685                                 duparg("chain", *argv);
686                         if (get_u32(&chain_index, *argv, 0))
687                                 invarg("invalid chain index value", *argv);
688                         filter_chain_index_set = 1;
689                         filter_chain_index = chain_index;
690                 } else if (matches(*argv, "help") == 0) {
691                         usage();
692                 } else {
693                         fprintf(stderr,
694                                 " What is \"%s\"? Try \"tc filter help\"\n",
695                                 *argv);
696                         return -1;
697                 }
698
699                 argc--; argv++;
700         }
701
702         req.t.tcm_info = TC_H_MAKE(prio<<16, protocol);
703
704         ll_init_map(&rth);
705
706         if (d[0]) {
707                 req.t.tcm_ifindex = ll_name_to_index(d);
708                 if (!req.t.tcm_ifindex)
709                         return -nodev(d);
710                 filter_ifindex = req.t.tcm_ifindex;
711         } else if (block_index) {
712                 if (!tc_qdisc_block_exists(block_index)) {
713                         fprintf(stderr, "Cannot find block \"%u\"\n", block_index);
714                         return 1;
715                 }
716                 req.t.tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK;
717                 req.t.tcm_block_index = block_index;
718                 filter_block_index = block_index;
719         }
720
721         if (filter_chain_index_set)
722                 addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index);
723
724         if (rtnl_dump_request_n(&rth, &req.n) < 0) {
725                 perror("Cannot send dump request");
726                 return 1;
727         }
728
729         new_json_obj(json);
730         if (rtnl_dump_filter(&rth, print_filter, stdout) < 0) {
731                 fprintf(stderr, "Dump terminated\n");
732                 return 1;
733         }
734         delete_json_obj();
735
736         return 0;
737 }
738
739 int do_filter(int argc, char **argv)
740 {
741         if (argc < 1)
742                 return tc_filter_list(RTM_GETTFILTER, 0, NULL);
743         if (matches(*argv, "add") == 0)
744                 return tc_filter_modify(RTM_NEWTFILTER, NLM_F_EXCL|NLM_F_CREATE,
745                                         argc-1, argv+1);
746         if (matches(*argv, "change") == 0)
747                 return tc_filter_modify(RTM_NEWTFILTER, 0, argc-1, argv+1);
748         if (matches(*argv, "replace") == 0)
749                 return tc_filter_modify(RTM_NEWTFILTER, NLM_F_CREATE, argc-1,
750                                         argv+1);
751         if (matches(*argv, "delete") == 0)
752                 return tc_filter_modify(RTM_DELTFILTER, 0,  argc-1, argv+1);
753         if (matches(*argv, "get") == 0)
754                 return tc_filter_get(RTM_GETTFILTER, 0,  argc-1, argv+1);
755         if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
756             || matches(*argv, "lst") == 0)
757                 return tc_filter_list(RTM_GETTFILTER, argc-1, argv+1);
758         if (matches(*argv, "help") == 0) {
759                 usage();
760                 return 0;
761         }
762         fprintf(stderr, "Command \"%s\" is unknown, try \"tc filter help\".\n",
763                 *argv);
764         return -1;
765 }
766
767 int do_chain(int argc, char **argv)
768 {
769         if (argc < 1)
770                 return tc_filter_list(RTM_GETCHAIN, 0, NULL);
771         if (matches(*argv, "add") == 0) {
772                 return tc_filter_modify(RTM_NEWCHAIN, NLM_F_EXCL | NLM_F_CREATE,
773                                         argc - 1, argv + 1);
774         } else if (matches(*argv, "delete") == 0) {
775                 return tc_filter_modify(RTM_DELCHAIN, 0,
776                                         argc - 1, argv + 1);
777         } else if (matches(*argv, "get") == 0) {
778                 return tc_filter_get(RTM_GETCHAIN, 0,
779                                      argc - 1, argv + 1);
780         } else if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0 ||
781                    matches(*argv, "lst") == 0) {
782                 return tc_filter_list(RTM_GETCHAIN, argc - 1, argv + 1);
783         } else if (matches(*argv, "help") == 0) {
784                 chain_usage();
785                 return 0;
786         }
787         fprintf(stderr, "Command \"%s\" is unknown, try \"tc chain help\".\n",
788                 *argv);
789         return -1;
790 }