]>
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
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
31 #include "tc_common.h"
36 int resolve_hosts
= 0;
39 struct rtnl_handle rth
;
41 static void *BODY
; /* cached handle dlopen(NULL) */
42 static struct qdisc_util
* qdisc_list
;
43 static struct filter_util
* filter_list
;
45 static int print_noqopt(struct qdisc_util
*qu
, FILE *f
,
48 if (opt
&& RTA_PAYLOAD(opt
))
49 fprintf(f
, "[Unknown qdisc, optlen=%u] ",
50 (unsigned) RTA_PAYLOAD(opt
));
54 static int parse_noqopt(struct qdisc_util
*qu
, int argc
, char **argv
, struct nlmsghdr
*n
)
57 fprintf(stderr
, "Unknown qdisc \"%s\", hence option \"%s\" is unparsable\n", qu
->id
, *argv
);
63 static int print_nofopt(struct filter_util
*qu
, FILE *f
, struct rtattr
*opt
, __u32 fhandle
)
65 if (opt
&& RTA_PAYLOAD(opt
))
66 fprintf(f
, "fh %08x [Unknown filter, optlen=%u] ",
67 fhandle
, (unsigned) RTA_PAYLOAD(opt
));
69 fprintf(f
, "fh %08x ", fhandle
);
73 static int parse_nofopt(struct filter_util
*qu
, char *fhandle
, int argc
, char **argv
, struct nlmsghdr
*n
)
78 fprintf(stderr
, "Unknown filter \"%s\", hence option \"%s\" is unparsable\n", qu
->id
, *argv
);
82 struct tcmsg
*t
= NLMSG_DATA(n
);
83 if (get_u32(&handle
, fhandle
, 16)) {
84 fprintf(stderr
, "Unparsable filter ID \"%s\"\n", fhandle
);
87 t
->tcm_handle
= handle
;
92 struct qdisc_util
*get_qdisc_kind(const char *str
)
98 for (q
= qdisc_list
; q
; q
= q
->next
)
99 if (strcmp(q
->id
, str
) == 0)
102 snprintf(buf
, sizeof(buf
), "/usr/lib/tc/q_%s.so", str
);
103 dlh
= dlopen(buf
, RTLD_LAZY
);
105 /* look in current binary, only open once */
108 dlh
= BODY
= dlopen(NULL
, RTLD_LAZY
);
114 snprintf(buf
, sizeof(buf
), "%s_qdisc_util", str
);
120 q
->next
= qdisc_list
;
125 q
= malloc(sizeof(*q
));
128 memset(q
, 0, sizeof(*q
));
129 q
->id
= strcpy(malloc(strlen(str
)+1), str
);
130 q
->parse_qopt
= parse_noqopt
;
131 q
->print_qopt
= print_noqopt
;
138 struct filter_util
*get_filter_kind(const char *str
)
142 struct filter_util
*q
;
144 for (q
= filter_list
; q
; q
= q
->next
)
145 if (strcmp(q
->id
, str
) == 0)
148 snprintf(buf
, sizeof(buf
), "/usr/lib/tc/f_%s.so", str
);
149 dlh
= dlopen(buf
, RTLD_LAZY
);
153 dlh
= BODY
= dlopen(NULL
, RTLD_LAZY
);
159 snprintf(buf
, sizeof(buf
), "%s_filter_util", str
);
165 q
->next
= filter_list
;
169 q
= malloc(sizeof(*q
));
171 memset(q
, 0, sizeof(*q
));
172 strncpy(q
->id
, str
, 15);
173 q
->parse_fopt
= parse_nofopt
;
174 q
->print_fopt
= print_nofopt
;
180 static void usage(void)
182 fprintf(stderr
, "Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }\n"
183 "where OBJECT := { qdisc | class | filter | action }\n"
184 " OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -b[atch] [file] }\n");
187 static int do_cmd(int argc
, char **argv
)
189 if (matches(*argv
, "qdisc") == 0)
190 return do_qdisc(argc
-1, argv
+1);
192 if (matches(*argv
, "class") == 0)
193 return do_class(argc
-1, argv
+1);
195 if (matches(*argv
, "filter") == 0)
196 return do_filter(argc
-1, argv
+1);
198 if (matches(*argv
, "actions") == 0)
199 return do_action(argc
-1, argv
+1);
201 if (matches(*argv
, "help") == 0) {
206 fprintf(stderr
, "Object \"%s\" is unknown, try \"tc help\".\n",
211 /* split command line into argument vector */
212 static int makeargs(char *line
, char *argv
[], int maxargs
)
214 static const char ws
[] = " \t\r\n";
218 for (cp
= strtok(line
, ws
); cp
; cp
= strtok(NULL
, ws
)) {
219 if (argc
>= (maxargs
- 1)) {
220 fprintf(stderr
, "Too many arguments to command\n");
231 /* Like glibc getline but handle continuation lines and comments */
232 static size_t getcmdline(char **linep
, size_t *lenp
, FILE *in
)
237 if ((cc
= getline(linep
, lenp
, in
)) < 0)
238 return cc
; /* eof or error */
241 cp
= strchr(*linep
, '#');
245 while ((cp
= strstr(*linep
, "\\\n")) != NULL
) {
250 if ((cc1
= getline(&line1
, &len1
, in
)) < 0) {
251 fprintf(stderr
, "Missing continuation line\n");
258 cp
= strchr(line1
, '#');
262 *linep
= realloc(*linep
, strlen(*linep
) + strlen(line1
) + 1);
264 fprintf(stderr
, "Out of memory\n");
268 strcat(*linep
, line1
);
274 static int batch(const char *name
)
280 if (name
&& strcmp(name
, "-") != 0) {
281 if (freopen(name
, "r", stdin
) == NULL
) {
282 fprintf(stderr
, "Cannot open file \"%s\" for reading: %s=n",
283 name
, strerror(errno
));
290 if (rtnl_open(&rth
, 0) < 0) {
291 fprintf(stderr
, "Cannot open rtnetlink\n");
296 while (getcmdline(&line
, &len
, stdin
) != -1) {
300 largc
= makeargs(line
, largv
, 100);
302 continue; /* blank line */
304 if (do_cmd(largc
, largv
)) {
305 fprintf(stderr
, "Command failed %s:%d\n", name
, lineno
);
317 int main(int argc
, char **argv
)
321 char *batchfile
= NULL
;
324 if (argv
[1][0] != '-')
326 if (matches(argv
[1], "-stats") == 0 ||
327 matches(argv
[1], "-statistics") == 0) {
329 } else if (matches(argv
[1], "-details") == 0) {
331 } else if (matches(argv
[1], "-raw") == 0) {
333 } else if (matches(argv
[1], "-Version") == 0) {
334 printf("tc utility, iproute2-ss%s\n", SNAPSHOT
);
336 } else if (matches(argv
[1], "-iec") == 0) {
338 } else if (matches(argv
[1], "-help") == 0) {
341 } else if (matches(argv
[1], "-force") == 0) {
343 } else if (matches(argv
[1], "-batch") == 0) {
349 fprintf(stderr
, "Option \"%s\" is unknown, try \"tc -help\".\n", argv
[1]);
356 return batch(batchfile
);
364 if (rtnl_open(&rth
, 0) < 0) {
365 fprintf(stderr
, "Cannot open rtnetlink\n");
369 ret
= do_cmd(argc
-1, argv
+1);