blob: 17078676f631942a22484fab7d6da0eb8f6780d1 [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
34int show_stats = 0;
35int show_details = 0;
36int show_raw = 0;
Stephen Hemminger44dcfe82008-05-09 15:42:34 -070037int show_pretty = 0;
Vadim Kochand954b342014-12-26 02:10:06 +020038int show_graph = 0;
Eric Dumazet32a6fbe2015-09-23 16:40:04 -070039int timestamp;
Stephen Hemminger44dcfe82008-05-09 15:42:34 -070040
Vadim Kochand954b342014-12-26 02:10:06 +020041int batch_mode = 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000042int resolve_hosts = 0;
osdl.net!shemminger3ea2bf42004-06-28 20:42:59 +000043int use_iec = 0;
osdl.net!shemminger08856f02005-03-18 19:40:55 +000044int force = 0;
Vadim Kochan4612d042015-03-03 18:41:18 +020045bool use_names = false;
46
47static char *conf_file;
48
osdl.net!shemminger79016602005-03-14 19:34:12 +000049struct rtnl_handle rth;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000050
shemmingerf453a0d2005-10-07 16:33:21 +000051static void *BODY = NULL; /* cached handle dlopen(NULL) */
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000052static struct qdisc_util * qdisc_list;
53static struct filter_util * filter_list;
54
Stephen Hemmingerae665a52006-12-05 10:10:22 -080055static int print_noqopt(struct qdisc_util *qu, FILE *f,
osdl.net!shemminger1798c9d2004-08-31 17:45:21 +000056 struct rtattr *opt)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000057{
58 if (opt && RTA_PAYLOAD(opt))
Stephen Hemmingerae665a52006-12-05 10:10:22 -080059 fprintf(f, "[Unknown qdisc, optlen=%u] ",
osdl.net!shemmingerbb6a21a2004-10-06 23:17:10 +000060 (unsigned) RTA_PAYLOAD(opt));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000061 return 0;
62}
63
64static int parse_noqopt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
65{
66 if (argc) {
67 fprintf(stderr, "Unknown qdisc \"%s\", hence option \"%s\" is unparsable\n", qu->id, *argv);
68 return -1;
69 }
70 return 0;
71}
72
73static int print_nofopt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 fhandle)
74{
75 if (opt && RTA_PAYLOAD(opt))
Stephen Hemmingerae665a52006-12-05 10:10:22 -080076 fprintf(f, "fh %08x [Unknown filter, optlen=%u] ",
osdl.net!shemmingerbb6a21a2004-10-06 23:17:10 +000077 fhandle, (unsigned) RTA_PAYLOAD(opt));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000078 else if (fhandle)
79 fprintf(f, "fh %08x ", fhandle);
80 return 0;
81}
82
83static int parse_nofopt(struct filter_util *qu, char *fhandle, int argc, char **argv, struct nlmsghdr *n)
84{
85 __u32 handle;
86
87 if (argc) {
88 fprintf(stderr, "Unknown filter \"%s\", hence option \"%s\" is unparsable\n", qu->id, *argv);
89 return -1;
90 }
91 if (fhandle) {
92 struct tcmsg *t = NLMSG_DATA(n);
93 if (get_u32(&handle, fhandle, 16)) {
94 fprintf(stderr, "Unparsable filter ID \"%s\"\n", fhandle);
95 return -1;
96 }
97 t->tcm_handle = handle;
98 }
99 return 0;
100}
101
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000102struct qdisc_util *get_qdisc_kind(const char *str)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000103{
104 void *dlh;
105 char buf[256];
106 struct qdisc_util *q;
107
108 for (q = qdisc_list; q; q = q->next)
109 if (strcmp(q->id, str) == 0)
110 return q;
111
Stephen Hemmingeraa27f882007-06-20 15:27:22 -0700112 snprintf(buf, sizeof(buf), "%s/q_%s.so", get_tc_lib(), str);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000113 dlh = dlopen(buf, RTLD_LAZY);
osdl.net!shemmingerb7a45152004-07-02 17:47:53 +0000114 if (!dlh) {
115 /* look in current binary, only open once */
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000116 dlh = BODY;
117 if (dlh == NULL) {
118 dlh = BODY = dlopen(NULL, RTLD_LAZY);
119 if (dlh == NULL)
120 goto noexist;
121 }
122 }
123
net[shemminger]!kaber95812b52004-09-28 18:35:49 +0000124 snprintf(buf, sizeof(buf), "%s_qdisc_util", str);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000125 q = dlsym(dlh, buf);
126 if (q == NULL)
127 goto noexist;
128
129reg:
130 q->next = qdisc_list;
131 qdisc_list = q;
132 return q;
133
134noexist:
135 q = malloc(sizeof(*q));
136 if (q) {
osdl.net!shemminger1798c9d2004-08-31 17:45:21 +0000137
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000138 memset(q, 0, sizeof(*q));
osdl.net!shemminger1798c9d2004-08-31 17:45:21 +0000139 q->id = strcpy(malloc(strlen(str)+1), str);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000140 q->parse_qopt = parse_noqopt;
141 q->print_qopt = print_noqopt;
142 goto reg;
143 }
144 return q;
145}
146
147
osdl.org!shemminger4094db72004-06-02 20:22:08 +0000148struct filter_util *get_filter_kind(const char *str)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000149{
150 void *dlh;
151 char buf[256];
152 struct filter_util *q;
153
154 for (q = filter_list; q; q = q->next)
155 if (strcmp(q->id, str) == 0)
156 return q;
157
Stephen Hemmingeraa27f882007-06-20 15:27:22 -0700158 snprintf(buf, sizeof(buf), "%s/f_%s.so", get_tc_lib(), str);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000159 dlh = dlopen(buf, RTLD_LAZY);
160 if (dlh == NULL) {
161 dlh = BODY;
162 if (dlh == NULL) {
163 dlh = BODY = dlopen(NULL, RTLD_LAZY);
164 if (dlh == NULL)
165 goto noexist;
166 }
167 }
168
net[shemminger]!kaber95812b52004-09-28 18:35:49 +0000169 snprintf(buf, sizeof(buf), "%s_filter_util", str);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000170 q = dlsym(dlh, buf);
171 if (q == NULL)
172 goto noexist;
173
174reg:
175 q->next = filter_list;
176 filter_list = q;
177 return q;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000178noexist:
179 q = malloc(sizeof(*q));
180 if (q) {
181 memset(q, 0, sizeof(*q));
182 strncpy(q->id, str, 15);
183 q->parse_fopt = parse_nofopt;
184 q->print_fopt = print_nofopt;
185 goto reg;
186 }
187 return q;
188}
189
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000190static void usage(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000191{
192 fprintf(stderr, "Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }\n"
Petr Jediný10494d22008-08-07 16:45:33 +0200193 " tc [-force] -batch filename\n"
Daniel Borkmann4bd62442015-04-16 21:20:06 +0200194 "where OBJECT := { qdisc | class | filter | action | monitor | exec }\n"
Vadim Kochan67e1d732014-12-24 23:04:11 +0200195 " OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -p[retty] | -b[atch] [filename] | "
Vadim Kochan4612d042015-03-03 18:41:18 +0200196 "-n[etns] name |\n"
197 " -nm | -nam[es] | { -cf | -conf } path }\n");
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000198}
199
200static int do_cmd(int argc, char **argv)
201{
202 if (matches(*argv, "qdisc") == 0)
203 return do_qdisc(argc-1, argv+1);
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000204 if (matches(*argv, "class") == 0)
205 return do_class(argc-1, argv+1);
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000206 if (matches(*argv, "filter") == 0)
207 return do_filter(argc-1, argv+1);
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000208 if (matches(*argv, "actions") == 0)
209 return do_action(argc-1, argv+1);
Jamal Hadi Salim5bec3482006-08-08 11:55:15 -0700210 if (matches(*argv, "monitor") == 0)
211 return do_tcmonitor(argc-1, argv+1);
Daniel Borkmann4bd62442015-04-16 21:20:06 +0200212 if (matches(*argv, "exec") == 0)
213 return do_exec(argc-1, argv+1);
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000214 if (matches(*argv, "help") == 0) {
215 usage();
216 return 0;
217 }
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800218
219 fprintf(stderr, "Object \"%s\" is unknown, try \"tc help\".\n",
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000220 *argv);
osdl.net!shemminger044ebf32005-03-14 19:02:41 +0000221 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000222}
223
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000224static int batch(const char *name)
225{
226 char *line = NULL;
227 size_t len = 0;
osdl.net!shemminger08856f02005-03-18 19:40:55 +0000228 int ret = 0;
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000229
Stephen Hemmingera3aa47a2013-07-16 10:04:05 -0700230 batch_mode = 1;
shemmingerdd3e9082005-06-23 17:32:22 +0000231 if (name && strcmp(name, "-") != 0) {
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000232 if (freopen(name, "r", stdin) == NULL) {
Stephen Hemminger84d66882008-02-07 22:10:14 -0800233 fprintf(stderr, "Cannot open file \"%s\" for reading: %s\n",
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000234 name, strerror(errno));
235 return -1;
236 }
237 }
238
239 tc_core_init();
240
241 if (rtnl_open(&rth, 0) < 0) {
242 fprintf(stderr, "Cannot open rtnetlink\n");
243 return -1;
244 }
245
shemminger351efcd2005-09-01 19:21:50 +0000246 cmdlineno = 0;
osdl.net!shemminger08856f02005-03-18 19:40:55 +0000247 while (getcmdline(&line, &len, stdin) != -1) {
248 char *largv[100];
249 int largc;
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000250
251 largc = makeargs(line, largv, 100);
osdl.net!shemminger08856f02005-03-18 19:40:55 +0000252 if (largc == 0)
253 continue; /* blank line */
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000254
osdl.net!shemminger08856f02005-03-18 19:40:55 +0000255 if (do_cmd(largc, largv)) {
shemminger351efcd2005-09-01 19:21:50 +0000256 fprintf(stderr, "Command failed %s:%d\n", name, cmdlineno);
osdl.net!shemminger08856f02005-03-18 19:40:55 +0000257 ret = 1;
258 if (!force)
259 break;
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000260 }
261 }
shemminger8ed63ab2005-09-21 19:33:17 +0000262 if (line)
263 free(line);
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000264
265 rtnl_close(&rth);
266 return ret;
267}
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000268
269
270int main(int argc, char **argv)
271{
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000272 int ret;
Stephen Hemmingera3aa47a2013-07-16 10:04:05 -0700273 char *batch_file = NULL;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000274
275 while (argc > 1) {
276 if (argv[1][0] != '-')
277 break;
278 if (matches(argv[1], "-stats") == 0 ||
osdl.net!shemminger3ea2bf42004-06-28 20:42:59 +0000279 matches(argv[1], "-statistics") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000280 ++show_stats;
281 } else if (matches(argv[1], "-details") == 0) {
282 ++show_details;
283 } else if (matches(argv[1], "-raw") == 0) {
284 ++show_raw;
Stephen Hemminger44dcfe82008-05-09 15:42:34 -0700285 } else if (matches(argv[1], "-pretty") == 0) {
286 ++show_pretty;
Vadim Kochand954b342014-12-26 02:10:06 +0200287 } else if (matches(argv[1], "-graph") == 0) {
288 show_graph = 1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000289 } else if (matches(argv[1], "-Version") == 0) {
290 printf("tc utility, iproute2-ss%s\n", SNAPSHOT);
osdl.net!shemminger044ebf32005-03-14 19:02:41 +0000291 return 0;
osdl.net!shemminger3ea2bf42004-06-28 20:42:59 +0000292 } else if (matches(argv[1], "-iec") == 0) {
293 ++use_iec;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000294 } else if (matches(argv[1], "-help") == 0) {
295 usage();
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000296 return 0;
osdl.net!shemminger08856f02005-03-18 19:40:55 +0000297 } else if (matches(argv[1], "-force") == 0) {
298 ++force;
Vadim Kochan4612d042015-03-03 18:41:18 +0200299 } else if (matches(argv[1], "-batch") == 0) {
osdl.net!shemminger08856f02005-03-18 19:40:55 +0000300 argc--; argv++;
Stephen Hemmingera3aa47a2013-07-16 10:04:05 -0700301 if (argc <= 1)
302 usage();
303 batch_file = argv[1];
Vadim Kochan67e1d732014-12-24 23:04:11 +0200304 } else if (matches(argv[1], "-netns") == 0) {
305 NEXT_ARG();
306 if (netns_switch(argv[1]))
307 return -1;
Vadim Kochan4612d042015-03-03 18:41:18 +0200308 } else if (matches(argv[1], "-names") == 0 ||
309 matches(argv[1], "-nm") == 0) {
310 use_names = true;
311 } else if (matches(argv[1], "-cf") == 0 ||
312 matches(argv[1], "-conf") == 0) {
313 NEXT_ARG();
314 conf_file = argv[1];
Eric Dumazet32a6fbe2015-09-23 16:40:04 -0700315 } else if (matches(argv[1], "-timestamp") == 0) {
316 timestamp++;
317 } else if (matches(argv[1], "-tshort") == 0) {
318 ++timestamp;
319 ++timestamp_short;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000320 } else {
321 fprintf(stderr, "Option \"%s\" is unknown, try \"tc -help\".\n", argv[1]);
osdl.net!shemminger044ebf32005-03-14 19:02:41 +0000322 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000323 }
324 argc--; argv++;
325 }
326
Stephen Hemmingera3aa47a2013-07-16 10:04:05 -0700327 if (batch_file)
328 return batch(batch_file);
osdl.net!shemminger08856f02005-03-18 19:40:55 +0000329
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000330 if (argc <= 1) {
331 usage();
332 return 0;
333 }
334
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000335 tc_core_init();
osdl.net!shemminger79016602005-03-14 19:34:12 +0000336 if (rtnl_open(&rth, 0) < 0) {
337 fprintf(stderr, "Cannot open rtnetlink\n");
338 exit(1);
339 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000340
Vadim Kochan4612d042015-03-03 18:41:18 +0200341 if (use_names && cls_names_init(conf_file)) {
342 ret = -1;
343 goto Exit;
344 }
345
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000346 ret = do_cmd(argc-1, argv+1);
Vadim Kochan4612d042015-03-03 18:41:18 +0200347Exit:
osdl.net!shemminger79016602005-03-14 19:34:12 +0000348 rtnl_close(&rth);
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000349
Vadim Kochan4612d042015-03-03 18:41:18 +0200350 if (use_names)
351 cls_names_uninit();
352
site!shemmingerc2f3a0f2005-03-14 22:19:16 +0000353 return ret;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000354}