#include <string.h>
#include <errno.h>
-#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;
int show_details;
int show_raw;
-int show_pretty;
int show_graph;
int timestamp;
int force;
bool use_names;
int json;
+int color;
+int oneline;
+int brief;
static char *conf_file;
static void usage(void)
{
fprintf(stderr,
- "Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }\n"
- " tc [-force] -batch filename\n"
- "where OBJECT := { qdisc | class | filter | action | monitor | exec }\n"
+ "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"
- " -j[son] | -p[retty] |\n"
- " -b[atch] [filename] | -n[etns] name |\n"
- " -nm | -nam[es] | { -cf | -conf } path }\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"
+ " -br[ief] }\n");
}
-static int do_cmd(int argc, char **argv, void *buf, size_t buflen)
+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, buf, buflen);
+ 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, buf, buflen);
+ 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 -1;
}
-#define TC_MAX_SUBC 10
-static bool batchsize_enabled(int argc, char *argv[])
+static int tc_batch_cmd(int argc, char *argv[], void *data)
{
- struct {
- char *c;
- char *subc[TC_MAX_SUBC];
- } table[] = {
- { "filter", { "add", "delete", "change", "replace", NULL} },
- { "actions", { "add", "change", "replace", NULL} },
- { NULL },
- }, *iter;
- char *s;
- int i;
-
- if (argc < 2)
- return false;
-
- for (iter = table; iter->c; iter++) {
- if (matches(argv[0], iter->c))
- continue;
- for (i = 0; i < TC_MAX_SUBC; i++) {
- s = iter->subc[i];
- if (s && matches(argv[1], s) == 0)
- return true;
- }
- }
-
- return false;
-}
-
-struct batch_buf {
- struct batch_buf *next;
- char buf[16420]; /* sizeof (struct nlmsghdr) +
- max(sizeof (struct tcmsg) +
- sizeof (struct tcamsg)) +
- MAX_MSG */
-};
-
-static struct batch_buf *get_batch_buf(struct batch_buf **pool,
- struct batch_buf **head,
- struct batch_buf **tail)
-{
- struct batch_buf *buf;
-
- if (*pool == NULL)
- buf = calloc(1, sizeof(struct batch_buf));
- else {
- buf = *pool;
- *pool = (*pool)->next;
- memset(buf, 0, sizeof(struct batch_buf));
- }
-
- if (*head == NULL)
- *head = *tail = buf;
- else {
- (*tail)->next = buf;
- (*tail) = buf;
- }
-
- return buf;
-}
-
-static void put_batch_bufs(struct batch_buf **pool,
- struct batch_buf **head,
- struct batch_buf **tail)
-{
- if (*head == NULL || *tail == NULL)
- return;
-
- if (*pool == NULL)
- *pool = *head;
- else {
- (*tail)->next = *pool;
- *pool = *head;
- }
- *head = NULL;
- *tail = NULL;
-}
-
-static void free_batch_bufs(struct batch_buf **pool)
-{
- struct batch_buf *buf;
-
- for (buf = *pool; buf != NULL; buf = *pool) {
- *pool = buf->next;
- free(buf);
- }
- *pool = NULL;
+ return do_cmd(argc, argv);
}
static int batch(const char *name)
{
- struct batch_buf *head = NULL, *tail = NULL, *buf_pool = NULL;
- char *largv[100], *largv_next[100];
- char *line, *line_next = NULL;
- bool bs_enabled_next = false;
- bool bs_enabled = false;
- bool lastline = false;
- int largc, largc_next;
- bool bs_enabled_saved;
- int batchsize = 0;
- size_t len = 0;
- int ret = 0;
- bool send;
+ int ret;
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) {
return -1;
}
- cmdlineno = 0;
- if (getcmdline(&line, &len, stdin) == -1)
- goto Exit;
- largc = makeargs(line, largv, 100);
- bs_enabled = batchsize_enabled(largc, largv);
- bs_enabled_saved = bs_enabled;
- do {
- if (getcmdline(&line_next, &len, stdin) == -1)
- lastline = true;
-
- largc_next = makeargs(line_next, largv_next, 100);
- bs_enabled_next = batchsize_enabled(largc_next, largv_next);
- if (bs_enabled) {
- struct batch_buf *buf;
-
- buf = get_batch_buf(&buf_pool, &head, &tail);
- if (!buf) {
- fprintf(stderr,
- "failed to allocate batch_buf\n");
- return -1;
- }
- ++batchsize;
- }
-
- /*
- * In batch mode, if we haven't accumulated enough commands
- * and this is not the last command and this command & next
- * command both support the batchsize feature, don't send the
- * message immediately.
- */
- if (!lastline && bs_enabled && bs_enabled_next
- && batchsize != MSG_IOV_MAX)
- send = false;
- else
- send = true;
-
- line = line_next;
- line_next = NULL;
- len = 0;
- bs_enabled_saved = bs_enabled;
- bs_enabled = bs_enabled_next;
- bs_enabled_next = false;
-
- if (largc == 0) {
- largc = largc_next;
- memcpy(largv, largv_next, largc * sizeof(char *));
- continue; /* blank line */
- }
-
- ret = do_cmd(largc, largv, tail == NULL ? NULL : tail->buf,
- tail == NULL ? 0 : sizeof(tail->buf));
- if (ret != 0) {
- fprintf(stderr, "Command failed %s:%d\n", name,
- cmdlineno - 1);
- ret = 1;
- if (!force)
- break;
- }
- largc = largc_next;
- memcpy(largv, largv_next, largc * sizeof(char *));
-
- if (send && bs_enabled_saved) {
- struct iovec *iov, *iovs;
- struct batch_buf *buf;
- struct nlmsghdr *n;
-
- iov = iovs = malloc(batchsize * sizeof(struct iovec));
- for (buf = head; buf != NULL; buf = buf->next, ++iov) {
- n = (struct nlmsghdr *)&buf->buf;
- iov->iov_base = n;
- iov->iov_len = n->nlmsg_len;
- }
-
- ret = rtnl_talk_iov(&rth, iovs, batchsize, NULL);
- if (ret < 0) {
- fprintf(stderr, "Command failed %s:%d\n", name,
- cmdlineno - (batchsize + ret) - 1);
- return 2;
- }
- put_batch_bufs(&buf_pool, &head, &tail);
- batchsize = 0;
- free(iovs);
- }
- } while (!lastline);
+ ret = do_batch(name, force, tc_batch_cmd, NULL);
- free_batch_bufs(&buf_pool);
-Exit:
- free(line);
rtnl_close(&rth);
-
return ret;
}
} else if (matches(argv[1], "-raw") == 0) {
++show_raw;
} else if (matches(argv[1], "-pretty") == 0) {
- ++show_pretty;
+ ++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);
+ printf("tc utility, iproute2-%s\n", version);
return 0;
} else if (matches(argv[1], "-iec") == 0) {
++use_iec;
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;
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_short;
} else if (matches(argv[1], "-json") == 0) {
++json;
+ } else if (matches(argv[1], "-oneline") == 0) {
+ ++oneline;
+ }else if (matches(argv[1], "-brief") == 0) {
+ ++brief;
} else {
fprintf(stderr,
"Option \"%s\" is unknown, try \"tc -help\".\n",
argc--; argv++;
}
+ _SL_ = oneline ? "\\" : "\n";
+
+ check_enable_color(color, json);
+
if (batch_file)
return batch(batch_file);
goto Exit;
}
- ret = do_cmd(argc-1, argv+1, NULL, 0);
+ ret = do_cmd(argc-1, argv+1);
Exit:
rtnl_close(&rth);