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