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