]>
git.proxmox.com Git - mirror_iproute2.git/blob - tc/tc.c
2 * tc.c "tc" utility frontend.
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.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
13 * Petri Mattila <petri@prihateam.fi> 990308: wrong memset's resulted in faults
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
30 #include "tc_common.h"
31 #include "namespace.h"
47 static char *conf_file
;
49 struct rtnl_handle rth
;
51 static void *BODY
; /* cached handle dlopen(NULL) */
52 static struct qdisc_util
*qdisc_list
;
53 static struct filter_util
*filter_list
;
55 static int print_noqopt(struct qdisc_util
*qu
, FILE *f
,
58 if (opt
&& RTA_PAYLOAD(opt
))
59 fprintf(f
, "[Unknown qdisc, optlen=%u] ",
60 (unsigned int) RTA_PAYLOAD(opt
));
64 static int parse_noqopt(struct qdisc_util
*qu
, int argc
, char **argv
,
65 struct nlmsghdr
*n
, const char *dev
)
69 "Unknown qdisc \"%s\", hence option \"%s\" is unparsable\n",
76 static int print_nofopt(struct filter_util
*qu
, FILE *f
, struct rtattr
*opt
, __u32 fhandle
)
78 if (opt
&& RTA_PAYLOAD(opt
))
79 fprintf(f
, "fh %08x [Unknown filter, optlen=%u] ",
80 fhandle
, (unsigned int) RTA_PAYLOAD(opt
));
82 fprintf(f
, "fh %08x ", fhandle
);
86 static int parse_nofopt(struct filter_util
*qu
, char *fhandle
,
87 int argc
, char **argv
, struct nlmsghdr
*n
)
93 "Unknown filter \"%s\", hence option \"%s\" is unparsable\n",
98 struct tcmsg
*t
= NLMSG_DATA(n
);
100 if (get_u32(&handle
, fhandle
, 16)) {
101 fprintf(stderr
, "Unparsable filter ID \"%s\"\n", fhandle
);
104 t
->tcm_handle
= handle
;
109 struct qdisc_util
*get_qdisc_kind(const char *str
)
113 struct qdisc_util
*q
;
115 for (q
= qdisc_list
; q
; q
= q
->next
)
116 if (strcmp(q
->id
, str
) == 0)
119 snprintf(buf
, sizeof(buf
), "%s/q_%s.so", get_tc_lib(), str
);
120 dlh
= dlopen(buf
, RTLD_LAZY
);
122 /* look in current binary, only open once */
125 dlh
= BODY
= dlopen(NULL
, RTLD_LAZY
);
131 snprintf(buf
, sizeof(buf
), "%s_qdisc_util", str
);
137 q
->next
= qdisc_list
;
142 q
= calloc(1, sizeof(*q
));
145 q
->parse_qopt
= parse_noqopt
;
146 q
->print_qopt
= print_noqopt
;
153 struct filter_util
*get_filter_kind(const char *str
)
157 struct filter_util
*q
;
159 for (q
= filter_list
; q
; q
= q
->next
)
160 if (strcmp(q
->id
, str
) == 0)
163 snprintf(buf
, sizeof(buf
), "%s/f_%s.so", get_tc_lib(), str
);
164 dlh
= dlopen(buf
, RTLD_LAZY
);
168 dlh
= BODY
= dlopen(NULL
, RTLD_LAZY
);
174 snprintf(buf
, sizeof(buf
), "%s_filter_util", str
);
180 q
->next
= filter_list
;
184 q
= calloc(1, sizeof(*q
));
186 strncpy(q
->id
, str
, 15);
187 q
->parse_fopt
= parse_nofopt
;
188 q
->print_fopt
= print_nofopt
;
194 static void usage(void)
197 "Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }\n"
198 " tc [-force] -batch filename\n"
199 "where OBJECT := { qdisc | class | filter | chain |\n"
200 " action | monitor | exec }\n"
201 " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[aw] |\n"
202 " -o[neline] | -j[son] | -p[retty] | -c[olor]\n"
203 " -b[atch] [filename] | -n[etns] name |\n"
204 " -nm | -nam[es] | { -cf | -conf } path }\n");
207 static int do_cmd(int argc
, char **argv
, void *buf
, size_t buflen
)
209 if (matches(*argv
, "qdisc") == 0)
210 return do_qdisc(argc
-1, argv
+1);
211 if (matches(*argv
, "class") == 0)
212 return do_class(argc
-1, argv
+1);
213 if (matches(*argv
, "filter") == 0)
214 return do_filter(argc
-1, argv
+1, buf
, buflen
);
215 if (matches(*argv
, "chain") == 0)
216 return do_chain(argc
-1, argv
+1, buf
, buflen
);
217 if (matches(*argv
, "actions") == 0)
218 return do_action(argc
-1, argv
+1, buf
, buflen
);
219 if (matches(*argv
, "monitor") == 0)
220 return do_tcmonitor(argc
-1, argv
+1);
221 if (matches(*argv
, "exec") == 0)
222 return do_exec(argc
-1, argv
+1);
223 if (matches(*argv
, "help") == 0) {
228 fprintf(stderr
, "Object \"%s\" is unknown, try \"tc help\".\n",
233 #define TC_MAX_SUBC 10
234 static bool batchsize_enabled(int argc
, char *argv
[])
238 char *subc
[TC_MAX_SUBC
];
240 { "filter", { "add", "delete", "change", "replace", NULL
} },
241 { "actions", { "add", "change", "replace", NULL
} },
250 for (iter
= table
; iter
->c
; iter
++) {
251 if (matches(argv
[0], iter
->c
))
253 for (i
= 0; i
< TC_MAX_SUBC
; i
++) {
255 if (s
&& matches(argv
[1], s
) == 0)
264 struct batch_buf
*next
;
265 char buf
[16420]; /* sizeof (struct nlmsghdr) +
266 max(sizeof (struct tcmsg) +
267 sizeof (struct tcamsg)) +
271 static struct batch_buf
*get_batch_buf(struct batch_buf
**pool
,
272 struct batch_buf
**head
,
273 struct batch_buf
**tail
)
275 struct batch_buf
*buf
;
278 buf
= calloc(1, sizeof(struct batch_buf
));
281 *pool
= (*pool
)->next
;
282 memset(buf
, 0, sizeof(struct batch_buf
));
295 static void put_batch_bufs(struct batch_buf
**pool
,
296 struct batch_buf
**head
,
297 struct batch_buf
**tail
)
299 if (*head
== NULL
|| *tail
== NULL
)
305 (*tail
)->next
= *pool
;
312 static void free_batch_bufs(struct batch_buf
**pool
)
314 struct batch_buf
*buf
;
316 for (buf
= *pool
; buf
!= NULL
; buf
= *pool
) {
323 static int batch(const char *name
)
325 struct batch_buf
*head
= NULL
, *tail
= NULL
, *buf_pool
= NULL
;
326 char *largv
[100], *largv_next
[100];
327 char *line
, *line_next
= NULL
;
328 bool bs_enabled
= false;
329 bool lastline
= false;
330 int largc
, largc_next
;
331 bool bs_enabled_saved
;
332 bool bs_enabled_next
;
340 if (name
&& strcmp(name
, "-") != 0) {
341 if (freopen(name
, "r", stdin
) == NULL
) {
343 "Cannot open file \"%s\" for reading: %s\n",
344 name
, strerror(errno
));
351 if (rtnl_open(&rth
, 0) < 0) {
352 fprintf(stderr
, "Cannot open rtnetlink\n");
357 if (getcmdline(&line
, &len
, stdin
) == -1)
359 largc
= makeargs(line
, largv
, 100);
360 bs_enabled
= batchsize_enabled(largc
, largv
);
362 if (getcmdline(&line_next
, &len
, stdin
) == -1)
365 largc_next
= makeargs(line_next
, largv_next
, 100);
366 bs_enabled_next
= batchsize_enabled(largc_next
, largv_next
);
368 struct batch_buf
*buf
;
370 buf
= get_batch_buf(&buf_pool
, &head
, &tail
);
373 "failed to allocate batch_buf\n");
380 * In batch mode, if we haven't accumulated enough commands
381 * and this is not the last command and this command & next
382 * command both support the batchsize feature, don't send the
383 * message immediately.
385 if (!lastline
&& bs_enabled
&& bs_enabled_next
386 && batchsize
!= MSG_IOV_MAX
)
394 bs_enabled_saved
= bs_enabled
;
395 bs_enabled
= bs_enabled_next
;
399 memcpy(largv
, largv_next
, largc
* sizeof(char *));
400 continue; /* blank line */
403 err
= do_cmd(largc
, largv
, tail
== NULL
? NULL
: tail
->buf
,
404 tail
== NULL
? 0 : sizeof(tail
->buf
));
407 fprintf(stderr
, "Command failed %s:%d\n", name
,
414 memcpy(largv
, largv_next
, largc
* sizeof(char *));
416 if (send
&& bs_enabled_saved
) {
417 struct iovec
*iov
, *iovs
;
418 struct batch_buf
*buf
;
421 iov
= iovs
= malloc(batchsize
* sizeof(struct iovec
));
422 for (buf
= head
; buf
!= NULL
; buf
= buf
->next
, ++iov
) {
423 n
= (struct nlmsghdr
*)&buf
->buf
;
425 iov
->iov_len
= n
->nlmsg_len
;
428 err
= rtnl_talk_iov(&rth
, iovs
, batchsize
, NULL
);
429 put_batch_bufs(&buf_pool
, &head
, &tail
);
432 fprintf(stderr
, "Command failed %s:%d\n", name
,
433 cmdlineno
- (batchsize
+ err
) - 1);
442 free_batch_bufs(&buf_pool
);
451 int main(int argc
, char **argv
)
454 char *batch_file
= NULL
;
457 if (argv
[1][0] != '-')
459 if (matches(argv
[1], "-stats") == 0 ||
460 matches(argv
[1], "-statistics") == 0) {
462 } else if (matches(argv
[1], "-details") == 0) {
464 } else if (matches(argv
[1], "-raw") == 0) {
466 } else if (matches(argv
[1], "-pretty") == 0) {
468 } else if (matches(argv
[1], "-graph") == 0) {
470 } else if (matches(argv
[1], "-Version") == 0) {
471 printf("tc utility, iproute2-ss%s\n", SNAPSHOT
);
473 } else if (matches(argv
[1], "-iec") == 0) {
475 } else if (matches(argv
[1], "-help") == 0) {
478 } else if (matches(argv
[1], "-force") == 0) {
480 } else if (matches(argv
[1], "-batch") == 0) {
484 batch_file
= argv
[1];
485 } else if (matches(argv
[1], "-netns") == 0) {
487 if (netns_switch(argv
[1]))
489 } else if (matches(argv
[1], "-names") == 0 ||
490 matches(argv
[1], "-nm") == 0) {
492 } else if (matches(argv
[1], "-cf") == 0 ||
493 matches(argv
[1], "-conf") == 0) {
496 } else if (matches_color(argv
[1], &color
)) {
497 } else if (matches(argv
[1], "-timestamp") == 0) {
499 } else if (matches(argv
[1], "-tshort") == 0) {
502 } else if (matches(argv
[1], "-json") == 0) {
504 } else if (matches(argv
[1], "-oneline") == 0) {
508 "Option \"%s\" is unknown, try \"tc -help\".\n",
515 _SL_
= oneline
? "\\" : "\n";
517 check_enable_color(color
, json
);
520 return batch(batch_file
);
528 if (rtnl_open(&rth
, 0) < 0) {
529 fprintf(stderr
, "Cannot open rtnetlink\n");
533 if (use_names
&& cls_names_init(conf_file
)) {
538 ret
= do_cmd(argc
-1, argv
+1, NULL
, 0);