X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=tc%2Ftc.c;h=5d57054b45fbcabae538fb4ceab2ccdfa3139849;hb=fbef655568ee931a82ad463a6f46f01ce3fb27aa;hp=3a76caab6758de01934d48ef575e0e38dbddedfc;hpb=bb6a21a4fcaf400ca4766eea6064f2df30393d1e;p=mirror_iproute2.git diff --git a/tc/tc.c b/tc/tc.c index 3a76caab..5d57054b 100644 --- a/tc/tc.c +++ b/tc/tc.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -25,34 +24,51 @@ #include #include -#include "SNAPSHOT.h" +#include "version.h" #include "utils.h" #include "tc_util.h" #include "tc_common.h" +#include "namespace.h" +#include "rt_names.h" -int show_stats = 0; -int show_details = 0; -int show_raw = 0; -int resolve_hosts = 0; -int use_iec = 0; +int show_stats; +int show_details; +int show_raw; +int show_graph; +int timestamp; + +int batch_mode; +int use_iec; +int force; +bool use_names; +int json; +int color; +int oneline; + +static char *conf_file; + +struct rtnl_handle rth; static void *BODY; /* cached handle dlopen(NULL) */ -static struct qdisc_util * qdisc_list; -static struct filter_util * filter_list; +static struct qdisc_util *qdisc_list; +static struct filter_util *filter_list; -static int print_noqopt(struct qdisc_util *qu, FILE *f, +static int print_noqopt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) { if (opt && RTA_PAYLOAD(opt)) - fprintf(f, "[Unknown qdisc, optlen=%u] ", - (unsigned) RTA_PAYLOAD(opt)); + fprintf(f, "[Unknown qdisc, optlen=%u] ", + (unsigned int) RTA_PAYLOAD(opt)); return 0; } -static int parse_noqopt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) +static int parse_noqopt(struct qdisc_util *qu, int argc, char **argv, + struct nlmsghdr *n, const char *dev) { if (argc) { - fprintf(stderr, "Unknown qdisc \"%s\", hence option \"%s\" is unparsable\n", qu->id, *argv); + fprintf(stderr, + "Unknown qdisc \"%s\", hence option \"%s\" is unparsable\n", + qu->id, *argv); return -1; } return 0; @@ -61,23 +77,27 @@ static int parse_noqopt(struct qdisc_util *qu, int argc, char **argv, struct nlm static int print_nofopt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 fhandle) { if (opt && RTA_PAYLOAD(opt)) - fprintf(f, "fh %08x [Unknown filter, optlen=%u] ", - fhandle, (unsigned) RTA_PAYLOAD(opt)); + fprintf(f, "fh %08x [Unknown filter, optlen=%u] ", + fhandle, (unsigned int) RTA_PAYLOAD(opt)); else if (fhandle) fprintf(f, "fh %08x ", fhandle); return 0; } -static int parse_nofopt(struct filter_util *qu, char *fhandle, int argc, char **argv, struct nlmsghdr *n) +static int parse_nofopt(struct filter_util *qu, char *fhandle, + int argc, char **argv, struct nlmsghdr *n) { __u32 handle; if (argc) { - fprintf(stderr, "Unknown filter \"%s\", hence option \"%s\" is unparsable\n", qu->id, *argv); + fprintf(stderr, + "Unknown filter \"%s\", hence option \"%s\" is unparsable\n", + qu->id, *argv); return -1; } if (fhandle) { struct tcmsg *t = NLMSG_DATA(n); + if (get_u32(&handle, fhandle, 16)) { fprintf(stderr, "Unparsable filter ID \"%s\"\n", fhandle); return -1; @@ -97,7 +117,7 @@ struct qdisc_util *get_qdisc_kind(const char *str) if (strcmp(q->id, str) == 0) return q; - snprintf(buf, sizeof(buf), "/usr/lib/tc/q_%s.so", str); + snprintf(buf, sizeof(buf), "%s/q_%s.so", get_tc_lib(), str); dlh = dlopen(buf, RTLD_LAZY); if (!dlh) { /* look in current binary, only open once */ @@ -120,11 +140,9 @@ reg: return q; noexist: - q = malloc(sizeof(*q)); + q = calloc(1, sizeof(*q)); if (q) { - - memset(q, 0, sizeof(*q)); - q->id = strcpy(malloc(strlen(str)+1), str); + q->id = strdup(str); q->parse_qopt = parse_noqopt; q->print_qopt = print_noqopt; goto reg; @@ -143,7 +161,7 @@ struct filter_util *get_filter_kind(const char *str) if (strcmp(q->id, str) == 0) return q; - snprintf(buf, sizeof(buf), "/usr/lib/tc/f_%s.so", str); + snprintf(buf, sizeof(buf), "%s/f_%s.so", get_tc_lib(), str); dlh = dlopen(buf, RTLD_LAZY); if (dlh == NULL) { dlh = BODY; @@ -164,9 +182,8 @@ reg: filter_list = q; return q; noexist: - q = malloc(sizeof(*q)); + q = calloc(1, sizeof(*q)); if (q) { - memset(q, 0, sizeof(*q)); strncpy(q->id, str, 15); q->parse_fopt = parse_nofopt; q->print_fopt = print_nofopt; @@ -175,92 +192,98 @@ noexist: return q; } -static void usage(void) __attribute__((noreturn)); - static void usage(void) { - fprintf(stderr, "Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }\n" - "where OBJECT := { qdisc | class | filter | action }\n" - " OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -b[atch] file }\n"); - exit(-1); + fprintf(stderr, + "Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }\n" + " tc [-force] -batch filename\n" + "where OBJECT := { qdisc | class | filter | chain |\n" + " action | monitor | exec }\n" + " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[aw] |\n" + " -o[neline] | -j[son] | -p[retty] | -c[olor]\n" + " -b[atch] [filename] | -n[etns] name | -N[umeric] |\n" + " -nm | -nam[es] | { -cf | -conf } path }\n"); } +static int do_cmd(int argc, char **argv) +{ + if (matches(*argv, "qdisc") == 0) + return do_qdisc(argc-1, argv+1); + if (matches(*argv, "class") == 0) + return do_class(argc-1, argv+1); + if (matches(*argv, "filter") == 0) + return do_filter(argc-1, argv+1); + if (matches(*argv, "chain") == 0) + return do_chain(argc-1, argv+1); + if (matches(*argv, "actions") == 0) + return do_action(argc-1, argv+1); + if (matches(*argv, "monitor") == 0) + return do_tcmonitor(argc-1, argv+1); + if (matches(*argv, "exec") == 0) + return do_exec(argc-1, argv+1); + if (matches(*argv, "help") == 0) { + usage(); + return 0; + } + fprintf(stderr, "Object \"%s\" is unknown, try \"tc help\".\n", + *argv); + return -1; +} -int main(int argc, char **argv) +static int batch(const char *name) { - char *basename; - - basename = strrchr(argv[0], '/'); - if (basename == NULL) - basename = argv[0]; - else - basename++; - - - /* batch mode */ - if (argc > 1 && matches(argv[1], "-batch") == 0) { - FILE *batch; - char line[400]; - char *largv[100]; - int largc, ret=0; -#define BMAXARG (sizeof(largv)/sizeof(char *)-2) - - if (argc != 3) { - fprintf(stderr, "Wrong number of arguments in batch mode\n"); - exit(-1); - } - if (matches(argv[2], "-") != 0) { - if ((batch = fopen(argv[2], "r")) == NULL) { - fprintf(stderr, "Cannot open file \"%s\" for reading: %s=n", argv[2], strerror(errno)); - exit(-1); - } - } else { - if ((batch = fdopen(0, "r")) == NULL) { - fprintf(stderr, "Cannot open stdin for reading: %s=n", strerror(errno)); - exit(-1); - } + char *line = NULL; + size_t len = 0; + int ret = 0; + + batch_mode = 1; + if (name && strcmp(name, "-") != 0) { + if (freopen(name, "r", stdin) == NULL) { + fprintf(stderr, + "Cannot open file \"%s\" for reading: %s\n", + name, strerror(errno)); + return -1; } + } + + tc_core_init(); + + if (rtnl_open(&rth, 0) < 0) { + fprintf(stderr, "Cannot open rtnetlink\n"); + return -1; + } - tc_core_init(); - - while (fgets(line, sizeof(line)-1, batch)) { - if (line[strlen(line)-1]=='\n') { - line[strlen(line)-1] = '\0'; - } else { - fprintf(stderr, "No newline at the end of line, looks like to long (%d chars or more)\n", - (int) strlen(line)); - exit(-1); - } - largc = 0; - largv[largc]=strtok(line, " "); - while ((largv[++largc]=strtok(NULL, " ")) != NULL) { - if (largc > BMAXARG) { - fprintf(stderr, "Over %d arguments in batch mode, enough!\n", - (int) BMAXARG); - exit(-1); - } - } - - if (matches(largv[0], "qdisc") == 0) { - ret += do_qdisc(largc-1, largv+1); - } else if (matches(largv[0], "class") == 0) { - ret += do_class(largc-1, largv+1); - } else if (matches(largv[0], "filter") == 0) { - ret += do_filter(largc-1, largv+1); - } else if (matches(largv[0], "action") == 0) { - ret += do_action(largc-1, largv+1); - } else if (matches(largv[0], "help") == 0) { - usage(); /* note that usage() doesn't return */ - } else { - fprintf(stderr, "Object \"%s\" is unknown, try \"tc help\".\n", largv[1]); - exit(-1); - } + cmdlineno = 0; + while (getcmdline(&line, &len, stdin) != -1) { + char *largv[100]; + int largc; + + largc = makeargs(line, largv, 100); + if (largc == 0) + continue; /* blank line */ + + if (do_cmd(largc, largv)) { + fprintf(stderr, "Command failed %s:%d\n", + name, cmdlineno); + ret = 1; + if (!force) + break; } - fclose(batch); - exit(0); /* end of batch, that's all */ + fflush(stdout); } + free(line); + rtnl_close(&rth); + return ret; +} + + +int main(int argc, char **argv) +{ + int ret; + char *batch_file = NULL; + while (argc > 1) { if (argv[1][0] != '-') break; @@ -271,36 +294,86 @@ int main(int argc, char **argv) ++show_details; } else if (matches(argv[1], "-raw") == 0) { ++show_raw; + } else if (matches(argv[1], "-pretty") == 0) { + ++pretty; + } else if (matches(argv[1], "-graph") == 0) { + show_graph = 1; } else if (matches(argv[1], "-Version") == 0) { - printf("tc utility, iproute2-ss%s\n", SNAPSHOT); - exit(0); + printf("tc utility, iproute2-%s\n", version); + return 0; } else if (matches(argv[1], "-iec") == 0) { ++use_iec; } else if (matches(argv[1], "-help") == 0) { usage(); + return 0; + } else if (matches(argv[1], "-force") == 0) { + ++force; + } else if (matches(argv[1], "-batch") == 0) { + argc--; argv++; + if (argc <= 1) + usage(); + batch_file = argv[1]; + } else if (matches(argv[1], "-netns") == 0) { + NEXT_ARG(); + if (netns_switch(argv[1])) + return -1; + } else if (matches(argv[1], "-Numeric") == 0) { + ++numeric; + } else if (matches(argv[1], "-names") == 0 || + matches(argv[1], "-nm") == 0) { + use_names = true; + } else if (matches(argv[1], "-cf") == 0 || + matches(argv[1], "-conf") == 0) { + NEXT_ARG(); + conf_file = argv[1]; + } else if (matches_color(argv[1], &color)) { + } else if (matches(argv[1], "-timestamp") == 0) { + timestamp++; + } else if (matches(argv[1], "-tshort") == 0) { + ++timestamp; + ++timestamp_short; + } else if (matches(argv[1], "-json") == 0) { + ++json; + } else if (matches(argv[1], "-oneline") == 0) { + ++oneline; } else { - fprintf(stderr, "Option \"%s\" is unknown, try \"tc -help\".\n", argv[1]); - exit(-1); + fprintf(stderr, + "Option \"%s\" is unknown, try \"tc -help\".\n", + argv[1]); + return -1; } argc--; argv++; } + _SL_ = oneline ? "\\" : "\n"; + + check_enable_color(color, json); + + if (batch_file) + return batch(batch_file); + + if (argc <= 1) { + usage(); + return 0; + } + tc_core_init(); + if (rtnl_open(&rth, 0) < 0) { + fprintf(stderr, "Cannot open rtnetlink\n"); + exit(1); + } - if (argc > 1) { - if (matches(argv[1], "qdisc") == 0) - return do_qdisc(argc-2, argv+2); - if (matches(argv[1], "class") == 0) - return do_class(argc-2, argv+2); - if (matches(argv[1], "filter") == 0) - return do_filter(argc-2, argv+2); - if (matches(argv[1], "actions") == 0) - return do_action(argc-2, argv+2); - if (matches(argv[1], "help") == 0) - usage(); - fprintf(stderr, "Object \"%s\" is unknown, try \"tc help\".\n", argv[1]); - exit(-1); + if (use_names && cls_names_init(conf_file)) { + ret = -1; + goto Exit; } - usage(); + ret = do_cmd(argc-1, argv+1); +Exit: + rtnl_close(&rth); + + if (use_names) + cls_names_uninit(); + + return ret; }