]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/blob - tc/tc_filter.c
iproute2: Support IFF_LOWER_UP and IFF_DORMANT
[lisovros/iproute2_canprio.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 <syslog.h>
17 #include <fcntl.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 #include <string.h>
22 #include <linux/if_ether.h>
23
24 #include "rt_names.h"
25 #include "utils.h"
26 #include "tc_util.h"
27 #include "tc_common.h"
28
29 static void usage(void);
30
31 static void usage(void)
32 {
33         fprintf(stderr, "Usage: tc filter [ add | del | change | replace | show ] dev STRING\n");
34         fprintf(stderr, "       [ pref PRIO ] [ protocol PROTO ]\n");
35         fprintf(stderr, "       [ estimator INTERVAL TIME_CONSTANT ]\n");
36         fprintf(stderr, "       [ root | classid CLASSID ] [ handle FILTERID ]\n");
37         fprintf(stderr, "       [ [ FILTER_TYPE ] [ help | OPTIONS ] ]\n");
38         fprintf(stderr, "\n");
39         fprintf(stderr, "       tc filter show [ dev STRING ] [ root | parent CLASSID ]\n");
40         fprintf(stderr, "Where:\n");
41         fprintf(stderr, "FILTER_TYPE := { rsvp | u32 | fw | route | etc. }\n");
42         fprintf(stderr, "FILTERID := ... format depends on classifier, see there\n");
43         fprintf(stderr, "OPTIONS := ... try tc filter add <desired FILTER_KIND> help\n");
44         return;
45 }
46
47
48 int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv)
49 {
50         struct {
51                 struct nlmsghdr         n;
52                 struct tcmsg            t;
53                 char                    buf[MAX_MSG];
54         } req;
55         struct filter_util *q = NULL;
56         __u32 prio = 0;
57         __u32 protocol = 0;
58         char *fhandle = NULL;
59         char  d[16];
60         char  k[16];
61         struct tc_estimator est;
62
63         memset(&req, 0, sizeof(req));
64         memset(&est, 0, sizeof(est));
65         memset(d, 0, sizeof(d));
66         memset(k, 0, sizeof(k));
67         memset(&req, 0, sizeof(req));
68
69         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
70         req.n.nlmsg_flags = NLM_F_REQUEST|flags;
71         req.n.nlmsg_type = cmd;
72         req.t.tcm_family = AF_UNSPEC;
73
74         while (argc > 0) {
75                 if (strcmp(*argv, "dev") == 0) {
76                         NEXT_ARG();
77                         if (d[0])
78                                 duparg("dev", *argv);
79                         strncpy(d, *argv, sizeof(d)-1);
80                 } else if (strcmp(*argv, "root") == 0) {
81                         if (req.t.tcm_parent) {
82                                 fprintf(stderr, "Error: \"root\" is duplicate parent ID\n");
83                                 return -1;
84                         }
85                         req.t.tcm_parent = TC_H_ROOT;
86                 } else if (strcmp(*argv, "parent") == 0) {
87                         __u32 handle;
88                         NEXT_ARG();
89                         if (req.t.tcm_parent)
90                                 duparg("parent", *argv);
91                         if (get_tc_classid(&handle, *argv))
92                                 invarg(*argv, "Invalid parent ID");
93                         req.t.tcm_parent = handle;
94                 } else if (strcmp(*argv, "handle") == 0) {
95                         NEXT_ARG();
96                         if (fhandle)
97                                 duparg("handle", *argv);
98                         fhandle = *argv;
99                 } else if (matches(*argv, "preference") == 0 ||
100                            matches(*argv, "priority") == 0) {
101                         NEXT_ARG();
102                         if (prio)
103                                 duparg("priority", *argv);
104                         if (get_u32(&prio, *argv, 0))
105                                 invarg(*argv, "invalid prpriority value");
106                 } else if (matches(*argv, "protocol") == 0) {
107                         __u16 id;
108                         NEXT_ARG();
109                         if (protocol)
110                                 duparg("protocol", *argv);
111                         if (ll_proto_a2n(&id, *argv))
112                                 invarg(*argv, "invalid protocol");
113                         protocol = id;
114                 } else if (matches(*argv, "estimator") == 0) {
115                         if (parse_estimator(&argc, &argv, &est) < 0)
116                                 return -1;
117                 } else if (matches(*argv, "help") == 0) {
118                         usage();
119                 } else {
120                         strncpy(k, *argv, sizeof(k)-1);
121
122                         q = get_filter_kind(k);
123                         argc--; argv++;
124                         break;
125                 }
126
127                 argc--; argv++;
128         }
129
130         req.t.tcm_info = TC_H_MAKE(prio<<16, protocol);
131
132         if (k[0])
133                 addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1);
134
135         if (q) {
136                 if (q->parse_fopt(q, fhandle, argc, argv, &req.n))
137                         return 1;
138         } else {
139                 if (fhandle) {
140                         fprintf(stderr, "Must specify filter type when using "
141                                 "\"handle\"\n");
142                         return -1;
143                 }
144                 if (argc) {
145                         if (matches(*argv, "help") == 0)
146                                 usage();
147                         fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"tc filter help\".\n", *argv);
148                         return -1;
149                 }
150         }
151         if (est.ewma_log)
152                 addattr_l(&req.n, sizeof(req), TCA_RATE, &est, sizeof(est));
153
154
155         if (d[0])  {
156                 ll_init_map(&rth);
157
158                 if ((req.t.tcm_ifindex = ll_name_to_index(d)) == 0) {
159                         fprintf(stderr, "Cannot find device \"%s\"\n", d);
160                         return 1;
161                 }
162         }
163
164         if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) {
165                 fprintf(stderr, "We have an error talking to the kernel\n");
166                 return 2;
167         }
168
169         return 0;
170 }
171
172 static __u32 filter_parent;
173 static int filter_ifindex;
174 static __u32 filter_prio;
175 static __u32 filter_protocol;
176
177 int print_filter(const struct sockaddr_nl *who,
178                         struct nlmsghdr *n,
179                         void *arg)
180 {
181         FILE *fp = (FILE*)arg;
182         struct tcmsg *t = NLMSG_DATA(n);
183         int len = n->nlmsg_len;
184         struct rtattr * tb[TCA_MAX+1];
185         struct filter_util *q;
186         char abuf[256];
187
188         if (n->nlmsg_type != RTM_NEWTFILTER && n->nlmsg_type != RTM_DELTFILTER) {
189                 fprintf(stderr, "Not a filter\n");
190                 return 0;
191         }
192         len -= NLMSG_LENGTH(sizeof(*t));
193         if (len < 0) {
194                 fprintf(stderr, "Wrong len %d\n", len);
195                 return -1;
196         }
197
198         memset(tb, 0, sizeof(tb));
199         parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len);
200
201         if (tb[TCA_KIND] == NULL) {
202                 fprintf(stderr, "print_filter: NULL kind\n");
203                 return -1;
204         }
205
206         if (n->nlmsg_type == RTM_DELTFILTER)
207                 fprintf(fp, "deleted ");
208
209         fprintf(fp, "filter ");
210         if (!filter_ifindex || filter_ifindex != t->tcm_ifindex)
211                 fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex));
212
213         if (!filter_parent || filter_parent != t->tcm_parent) {
214                 if (t->tcm_parent == TC_H_ROOT)
215                         fprintf(fp, "root ");
216                 else {
217                         print_tc_classid(abuf, sizeof(abuf), t->tcm_parent);
218                         fprintf(fp, "parent %s ", abuf);
219                 }
220         }
221         if (t->tcm_info) {
222                 __u32 protocol = TC_H_MIN(t->tcm_info);
223                 __u32 prio = TC_H_MAJ(t->tcm_info)>>16;
224                 if (!filter_protocol || filter_protocol != protocol) {
225                         if (protocol) {
226                                 SPRINT_BUF(b1);
227                                 fprintf(fp, "protocol %s ",
228                                         ll_proto_n2a(protocol, b1, sizeof(b1)));
229                         }
230                 }
231                 if (!filter_prio || filter_prio != prio) {
232                         if (prio)
233                                 fprintf(fp, "pref %u ", prio);
234                 }
235         }
236         fprintf(fp, "%s ", (char*)RTA_DATA(tb[TCA_KIND]));
237         q = get_filter_kind(RTA_DATA(tb[TCA_KIND]));
238         if (tb[TCA_OPTIONS]) {
239                 if (q)
240                         q->print_fopt(q, fp, tb[TCA_OPTIONS], t->tcm_handle);
241                 else
242                         fprintf(fp, "[cannot parse parameters]");
243         }
244         fprintf(fp, "\n");
245
246         if (show_stats && (tb[TCA_STATS] || tb[TCA_STATS2])) {
247                 print_tcstats_attr(fp, tb, " ", NULL);
248                 fprintf(fp, "\n");
249         }
250
251         fflush(fp);
252         return 0;
253 }
254
255
256 int tc_filter_list(int argc, char **argv)
257 {
258         struct tcmsg t;
259         char d[16];
260         __u32 prio = 0;
261         __u32 protocol = 0;
262         char *fhandle = NULL;
263
264         memset(&t, 0, sizeof(t));
265         t.tcm_family = AF_UNSPEC;
266         memset(d, 0, sizeof(d));
267
268         while (argc > 0) {
269                 if (strcmp(*argv, "dev") == 0) {
270                         NEXT_ARG();
271                         if (d[0])
272                                 duparg("dev", *argv);
273                         strncpy(d, *argv, sizeof(d)-1);
274                 } else if (strcmp(*argv, "root") == 0) {
275                         if (t.tcm_parent) {
276                                 fprintf(stderr, "Error: \"root\" is duplicate parent ID\n");
277                                 return -1;
278                         }
279                         filter_parent = t.tcm_parent = TC_H_ROOT;
280                 } else if (strcmp(*argv, "parent") == 0) {
281                         __u32 handle;
282                         NEXT_ARG();
283                         if (t.tcm_parent)
284                                 duparg("parent", *argv);
285                         if (get_tc_classid(&handle, *argv))
286                                 invarg(*argv, "invalid parent ID");
287                         filter_parent = t.tcm_parent = handle;
288                 } else if (strcmp(*argv, "handle") == 0) {
289                         NEXT_ARG();
290                         if (fhandle)
291                                 duparg("handle", *argv);
292                         fhandle = *argv;
293                 } else if (matches(*argv, "preference") == 0 ||
294                            matches(*argv, "priority") == 0) {
295                         NEXT_ARG();
296                         if (prio)
297                                 duparg("priority", *argv);
298                         if (get_u32(&prio, *argv, 0))
299                                 invarg(*argv, "invalid preference");
300                         filter_prio = prio;
301                 } else if (matches(*argv, "protocol") == 0) {
302                         __u16 res;
303                         NEXT_ARG();
304                         if (protocol)
305                                 duparg("protocol", *argv);
306                         if (ll_proto_a2n(&res, *argv))
307                                 invarg(*argv, "invalid protocol");
308                         protocol = res;
309                         filter_protocol = protocol;
310                 } else if (matches(*argv, "help") == 0) {
311                         usage();
312                 } else {
313                         fprintf(stderr, " What is \"%s\"? Try \"tc filter help\"\n", *argv);
314                         return -1;
315                 }
316
317                 argc--; argv++;
318         }
319
320         t.tcm_info = TC_H_MAKE(prio<<16, protocol);
321
322         ll_init_map(&rth);
323
324         if (d[0]) {
325                 if ((t.tcm_ifindex = ll_name_to_index(d)) == 0) {
326                         fprintf(stderr, "Cannot find device \"%s\"\n", d);
327                         return 1;
328                 }
329                 filter_ifindex = t.tcm_ifindex;
330         }
331
332         if (rtnl_dump_request(&rth, RTM_GETTFILTER, &t, sizeof(t)) < 0) {
333                 perror("Cannot send dump request");
334                 return 1;
335         }
336
337         if (rtnl_dump_filter(&rth, print_filter, stdout, NULL, NULL) < 0) {
338                 fprintf(stderr, "Dump terminated\n");
339                 return 1;
340         }
341
342         return 0;
343 }
344
345 int do_filter(int argc, char **argv)
346 {
347         if (argc < 1)
348                 return tc_filter_list(0, NULL);
349         if (matches(*argv, "add") == 0)
350                 return tc_filter_modify(RTM_NEWTFILTER, NLM_F_EXCL|NLM_F_CREATE, argc-1, argv+1);
351         if (matches(*argv, "change") == 0)
352                 return tc_filter_modify(RTM_NEWTFILTER, 0, argc-1, argv+1);
353         if (matches(*argv, "replace") == 0)
354                 return tc_filter_modify(RTM_NEWTFILTER, NLM_F_CREATE, argc-1, argv+1);
355         if (matches(*argv, "delete") == 0)
356                 return tc_filter_modify(RTM_DELTFILTER, 0,  argc-1, argv+1);
357 #if 0
358         if (matches(*argv, "get") == 0)
359                 return tc_filter_get(RTM_GETTFILTER, 0,  argc-1, argv+1);
360 #endif
361         if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
362             || matches(*argv, "lst") == 0)
363                 return tc_filter_list(argc-1, argv+1);
364         if (matches(*argv, "help") == 0) {
365                 usage();
366                 return 0;
367         }
368         fprintf(stderr, "Command \"%s\" is unknown, try \"tc filter help\".\n", *argv);
369         return -1;
370 }
371