blob: 82a30042950fdc9e1151128a7e7557518c751f2d [file] [log] [blame]
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001/*
2 * tc.c "tc" utility frontend.
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 * Fixes:
12 *
13 * Petri Mattila <petri@prihateam.fi> 990308: wrong memset's resulted in faults
14 */
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <unistd.h>
19#include <syslog.h>
20#include <fcntl.h>
21#include <dlfcn.h>
22#include <sys/socket.h>
23#include <netinet/in.h>
24#include <arpa/inet.h>
25#include <string.h>
26#include <errno.h>
27
28#include "SNAPSHOT.h"
29#include "utils.h"
30#include "tc_util.h"
31#include "tc_common.h"
Vadim Kochan67e1d732014-12-24 23:04:11 +020032#include "namespace.h"
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000033
Stephen Hemminger32a121c2016-03-21 11:48:36 -070034int show_stats;
35int show_details;
36int show_raw;
37int show_pretty;
38int show_graph;
Eric Dumazet32a6fbe2015-09-23 16:40:04 -070039int timestamp;
Stephen Hemminger44dcfe82008-05-09 15:42:34 -070040
Stephen Hemminger32a121c2016-03-21 11:48:36 -070041int batch_mode;
Stephen Hemminger32a121c2016-03-21 11:48:36 -070042int use_iec;
43int force;
44bool use_names;
Vadim Kochan4612d042015-03-03 18:41:18 +020045
46static char *conf_file;
47
osdl.net!shemminger79016602005-03-14 19:34:12 +000048struct rtnl_handle rth;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000049
Stephen Hemminger32a121c2016-03-21 11:48:36 -070050static void *BODY; /* cached handle dlopen(NULL) */
51static struct qdisc_util *qdisc_list;
52static struct filter_util *filter_list;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000053
San Mehat8e86eb92010-04-07 13:46:14 -070054#ifdef ANDROID
55extern struct qdisc_util cbq_qdisc_util;
San Mehat926d4a22010-04-29 14:11:17 -070056extern struct qdisc_util htb_qdisc_util;
San Mehatec731b72010-04-21 14:22:13 -070057extern struct qdisc_util ingress_qdisc_util;
San Mehat8e86eb92010-04-07 13:46:14 -070058extern struct filter_util u32_filter_util;
59#endif
60
Stephen Hemmingerae665a52006-12-05 10:10:22 -080061static int print_noqopt(struct qdisc_util *qu, FILE *f,
osdl.net!shemminger1798c9d2004-08-31 17:45:21 +000062 struct rtattr *opt)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000063{
64 if (opt && RTA_PAYLOAD(opt))
Stephen Hemmingerae665a52006-12-05 10:10:22 -080065 fprintf(f, "[Unknown qdisc, optlen=%u] ",
Stephen Hemminger32a121c2016-03-21 11:48:36 -070066 (unsigned int) RTA_PAYLOAD(opt));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000067 return 0;
68}
69
70static int parse_noqopt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
71{
72 if (argc) {
73 fprintf(stderr, "Unknown qdisc \"%s\", hence option \"%s\" is unparsable\n", qu->id, *argv);
74 return -1;
75 }
76 return 0;
77}
78
79static int print_nofopt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 fhandle)
80{
81 if (opt && RTA_PAYLOAD(opt))
Stephen Hemmingerae665a52006-12-05 10:10:22 -080082 fprintf(f, "fh %08x [Unknown filter, optlen=%u] ",
Stephen Hemminger32a121c2016-03-21 11:48:36 -070083 fhandle, (unsigned int) RTA_PAYLOAD(opt));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000084 else if (fhandle)
85 fprintf(f, "fh %08x ", fhandle);
86 return 0;
87}
88
89static int parse_nofopt(struct filter_util *qu, char *fhandle, int argc, char **argv, struct nlmsghdr *n)
90{
91 __u32 handle;
92
93 if (argc) {
94 fprintf(stderr, "Unknown filter \"%s\", hence option \"%s\" is unparsable\n", qu->id, *argv);
95 return -1;
96 }
97 if (fhandle) {
98 struct tcmsg *t = NLMSG_DATA(n);
Stephen Hemminger32a121c2016-03-21 11:48:36 -070099
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000100 if (get_u32(&handle, fhandle, 16)) {
101 fprintf(stderr, "Unparsable filter ID \"%s\"\n", fhandle);
102 return -1;
103 }
104 t->tcm_handle = handle;
105 }
106 return 0;
107}
108
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000109struct qdisc_util *get_qdisc_kind(const char *str)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000110{
111 void *dlh;
112 char buf[256];
113 struct qdisc_util *q;
114
San Mehat8e86eb92010-04-07 13:46:14 -0700115#ifdef ANDROID
116 if (!strcmp(str, "cbq"))
117 return &cbq_qdisc_util;
San Mehat926d4a22010-04-29 14:11:17 -0700118 else if (!strcmp(str, "htb"))
119 return &htb_qdisc_util;
San Mehatec731b72010-04-21 14:22:13 -0700120 else if (!strcmp(str, "ingress"))
121 return &ingress_qdisc_util;
San Mehat8e86eb92010-04-07 13:46:14 -0700122 else {
San Mehat926d4a22010-04-29 14:11:17 -0700123 fprintf(stderr, "Android does not support qdisc '%s'\n", str);
San Mehat8e86eb92010-04-07 13:46:14 -0700124 return NULL;
125 }
126#endif
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000127 for (q = qdisc_list; q; q = q->next)
128 if (strcmp(q->id, str) == 0)
129 return q;
130
Stephen Hemmingeraa27f882007-06-20 15:27:22 -0700131 snprintf(buf, sizeof(buf), "%s/q_%s.so", get_tc_lib(), str);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000132 dlh = dlopen(buf, RTLD_LAZY);
osdl.net!shemmingerb7a45152004-07-02 17:47:53 +0000133 if (!dlh) {
134 /* look in current binary, only open once */
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000135 dlh = BODY;
136 if (dlh == NULL) {
137 dlh = BODY = dlopen(NULL, RTLD_LAZY);
138 if (dlh == NULL)
139 goto noexist;
140 }
141 }
142
net[shemminger]!kaber95812b52004-09-28 18:35:49 +0000143 snprintf(buf, sizeof(buf), "%s_qdisc_util", str);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000144 q = dlsym(dlh, buf);
145 if (q == NULL)
146 goto noexist;
147
148reg:
149 q->next = qdisc_list;
150 qdisc_list = q;
151 return q;
152
153noexist:
Phil Sutterf89bb022016-07-18 16:48:43 +0200154 q = calloc(1, sizeof(*q));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000155 if (q) {
Phil Sutterf89bb022016-07-18 16:48:43 +0200156 q->id = strdup(str);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000157 q->parse_qopt = parse_noqopt;
158 q->print_qopt = print_noqopt;
159 goto reg;
160 }
161 return q;
162}
163
164
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000165struct filter_util *get_filter_kind(const char *str)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000166{
167 void *dlh;
168 char buf[256];
169 struct filter_util *q;
San Mehat8e86eb92010-04-07 13:46:14 -0700170#ifdef ANDROID
171 if (!strcmp(str, "u32"))
172 return &u32_filter_util;
173 else {
San Mehat926d4a22010-04-29 14:11:17 -0700174 fprintf(stderr, "Android does not support filter '%s'\n", str);
San Mehat8e86eb92010-04-07 13:46:14 -0700175 return NULL;
176 }
177#endif
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000178
179 for (q = filter_list; q; q = q->next)
180 if (strcmp(q->id, str) == 0)
181 return q;
182
Stephen Hemmingeraa27f882007-06-20 15:27:22 -0700183 snprintf(buf, sizeof(buf), "%s/f_%s.so", get_tc_lib(), str);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000184 dlh = dlopen(buf, RTLD_LAZY);
185 if (dlh == NULL) {
186 dlh = BODY;
187 if (dlh == NULL) {
188 dlh = BODY = dlopen(NULL, RTLD_LAZY);
189 if (dlh == NULL)
190 goto noexist;
191 }
192 }
193
net[shemminger]!kaber95812b52004-09-28 18:35:49 +0000194 snprintf(buf, sizeof(buf), "%s_filter_util", str);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000195 q = dlsym(dlh, buf);
196 if (q == NULL)
197 goto noexist;
198
199reg:
200 q->next = filter_list;
201 filter_list = q;
202 return q;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000203noexist:
Phil Sutterf89bb022016-07-18 16:48:43 +0200204 q = calloc(1, sizeof(*q));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000205 if (q) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000206 strncpy(q->id, str, 15);
207 q->parse_fopt = parse_nofopt;
208 q->print_fopt = print_nofopt;
209 goto reg;
210 }
211 return q;
212}
213
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000214static void usage(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000215{
216 fprintf(stderr, "Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }\n"
San Mehat66449002010-04-07 09:44:54 -0700217#ifdef ANDROID
218 " tc [-force]\n"
219#else
Petr Jediný10494d22008-08-07 16:45:33 +0200220 " tc [-force] -batch filename\n"
San Mehat66449002010-04-07 09:44:54 -0700221#endif
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700222 "where OBJECT := { qdisc | class | filter | action | monitor | exec }\n"
223 " OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -p[retty] | -b[atch] [filename] | -n[etns] name |\n"
Vadim Kochan4612d042015-03-03 18:41:18 +0200224 " -nm | -nam[es] | { -cf | -conf } path }\n");
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000225}
226
227static int do_cmd(int argc, char **argv)
228{
229 if (matches(*argv, "qdisc") == 0)
230 return do_qdisc(argc-1, argv+1);
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000231 if (matches(*argv, "class") == 0)
232 return do_class(argc-1, argv+1);
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000233 if (matches(*argv, "filter") == 0)
234 return do_filter(argc-1, argv+1);
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000235 if (matches(*argv, "actions") == 0)
236 return do_action(argc-1, argv+1);
Jamal Hadi Salim5bec3482006-08-08 11:55:15 -0700237 if (matches(*argv, "monitor") == 0)
238 return do_tcmonitor(argc-1, argv+1);
Daniel Borkmann4bd62442015-04-16 21:20:06 +0200239 if (matches(*argv, "exec") == 0)
240 return do_exec(argc-1, argv+1);
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000241 if (matches(*argv, "help") == 0) {
242 usage();
243 return 0;
244 }
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800245
246 fprintf(stderr, "Object \"%s\" is unknown, try \"tc help\".\n",
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000247 *argv);
osdl.net!shemminger044ebf32005-03-14 19:02:41 +0000248 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000249}
250
San Mehat66449002010-04-07 09:44:54 -0700251#ifndef ANDROID
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000252static int batch(const char *name)
253{
254 char *line = NULL;
255 size_t len = 0;
osdl.net!shemminger08856f02005-03-18 19:40:55 +0000256 int ret = 0;
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000257
Stephen Hemmingera3aa47a2013-07-16 10:04:05 -0700258 batch_mode = 1;
shemmingerdd3e9082005-06-23 17:32:22 +0000259 if (name && strcmp(name, "-") != 0) {
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000260 if (freopen(name, "r", stdin) == NULL) {
Stephen Hemminger84d66882008-02-07 22:10:14 -0800261 fprintf(stderr, "Cannot open file \"%s\" for reading: %s\n",
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000262 name, strerror(errno));
263 return -1;
264 }
265 }
266
267 tc_core_init();
268
269 if (rtnl_open(&rth, 0) < 0) {
270 fprintf(stderr, "Cannot open rtnetlink\n");
271 return -1;
272 }
273
shemminger351efcd2005-09-01 19:21:50 +0000274 cmdlineno = 0;
osdl.net!shemminger08856f02005-03-18 19:40:55 +0000275 while (getcmdline(&line, &len, stdin) != -1) {
276 char *largv[100];
277 int largc;
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000278
279 largc = makeargs(line, largv, 100);
osdl.net!shemminger08856f02005-03-18 19:40:55 +0000280 if (largc == 0)
281 continue; /* blank line */
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000282
osdl.net!shemminger08856f02005-03-18 19:40:55 +0000283 if (do_cmd(largc, largv)) {
shemminger351efcd2005-09-01 19:21:50 +0000284 fprintf(stderr, "Command failed %s:%d\n", name, cmdlineno);
osdl.net!shemminger08856f02005-03-18 19:40:55 +0000285 ret = 1;
286 if (!force)
287 break;
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000288 }
289 }
shemminger8ed63ab2005-09-21 19:33:17 +0000290 if (line)
291 free(line);
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000292
293 rtnl_close(&rth);
294 return ret;
295}
San Mehat66449002010-04-07 09:44:54 -0700296#endif
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000297
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000298
299int main(int argc, char **argv)
300{
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000301 int ret;
San Mehat66449002010-04-07 09:44:54 -0700302#ifndef ANDROID
Stephen Hemmingera3aa47a2013-07-16 10:04:05 -0700303 char *batch_file = NULL;
San Mehat66449002010-04-07 09:44:54 -0700304#endif
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000305
306 while (argc > 1) {
307 if (argv[1][0] != '-')
308 break;
309 if (matches(argv[1], "-stats") == 0 ||
osdl.net!shemminger3ea2bf42004-06-28 20:42:59 +0000310 matches(argv[1], "-statistics") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000311 ++show_stats;
312 } else if (matches(argv[1], "-details") == 0) {
313 ++show_details;
314 } else if (matches(argv[1], "-raw") == 0) {
315 ++show_raw;
Stephen Hemminger44dcfe82008-05-09 15:42:34 -0700316 } else if (matches(argv[1], "-pretty") == 0) {
317 ++show_pretty;
Vadim Kochand954b342014-12-26 02:10:06 +0200318 } else if (matches(argv[1], "-graph") == 0) {
319 show_graph = 1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000320 } else if (matches(argv[1], "-Version") == 0) {
321 printf("tc utility, iproute2-ss%s\n", SNAPSHOT);
osdl.net!shemminger044ebf32005-03-14 19:02:41 +0000322 return 0;
osdl.net!shemminger3ea2bf42004-06-28 20:42:59 +0000323 } else if (matches(argv[1], "-iec") == 0) {
324 ++use_iec;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000325 } else if (matches(argv[1], "-help") == 0) {
326 usage();
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000327 return 0;
osdl.net!shemminger08856f02005-03-18 19:40:55 +0000328 } else if (matches(argv[1], "-force") == 0) {
329 ++force;
San Mehat66449002010-04-07 09:44:54 -0700330#ifndef ANDROID
Vadim Kochan4612d042015-03-03 18:41:18 +0200331 } else if (matches(argv[1], "-batch") == 0) {
osdl.net!shemminger08856f02005-03-18 19:40:55 +0000332 argc--; argv++;
Stephen Hemmingera3aa47a2013-07-16 10:04:05 -0700333 if (argc <= 1)
334 usage();
335 batch_file = argv[1];
San Mehat66449002010-04-07 09:44:54 -0700336#endif
Vadim Kochan67e1d732014-12-24 23:04:11 +0200337 } else if (matches(argv[1], "-netns") == 0) {
338 NEXT_ARG();
339 if (netns_switch(argv[1]))
340 return -1;
Vadim Kochan4612d042015-03-03 18:41:18 +0200341 } else if (matches(argv[1], "-names") == 0 ||
342 matches(argv[1], "-nm") == 0) {
343 use_names = true;
344 } else if (matches(argv[1], "-cf") == 0 ||
345 matches(argv[1], "-conf") == 0) {
346 NEXT_ARG();
347 conf_file = argv[1];
Eric Dumazet32a6fbe2015-09-23 16:40:04 -0700348 } else if (matches(argv[1], "-timestamp") == 0) {
349 timestamp++;
350 } else if (matches(argv[1], "-tshort") == 0) {
351 ++timestamp;
352 ++timestamp_short;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000353 } else {
354 fprintf(stderr, "Option \"%s\" is unknown, try \"tc -help\".\n", argv[1]);
osdl.net!shemminger044ebf32005-03-14 19:02:41 +0000355 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000356 }
357 argc--; argv++;
358 }
359
San Mehat66449002010-04-07 09:44:54 -0700360#ifndef ANDROID
Stephen Hemmingera3aa47a2013-07-16 10:04:05 -0700361 if (batch_file)
362 return batch(batch_file);
San Mehat66449002010-04-07 09:44:54 -0700363#endif
osdl.net!shemminger08856f02005-03-18 19:40:55 +0000364
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000365 if (argc <= 1) {
366 usage();
367 return 0;
368 }
369
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000370 tc_core_init();
osdl.net!shemminger79016602005-03-14 19:34:12 +0000371 if (rtnl_open(&rth, 0) < 0) {
372 fprintf(stderr, "Cannot open rtnetlink\n");
373 exit(1);
374 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000375
Vadim Kochan4612d042015-03-03 18:41:18 +0200376 if (use_names && cls_names_init(conf_file)) {
377 ret = -1;
378 goto Exit;
379 }
380
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000381 ret = do_cmd(argc-1, argv+1);
Vadim Kochan4612d042015-03-03 18:41:18 +0200382Exit:
osdl.net!shemminger79016602005-03-14 19:34:12 +0000383 rtnl_close(&rth);
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000384
Vadim Kochan4612d042015-03-03 18:41:18 +0200385 if (use_names)
386 cls_names_uninit();
387
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000388 return ret;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000389}