summaryrefslogtreecommitdiff
path: root/tc/tc.c
diff options
context:
space:
mode:
authorChris Mi <chrism@mellanox.com>2018-01-12 14:13:16 +0900
committerDavid Ahern <dsahern@gmail.com>2018-01-14 09:03:35 -0800
commit485d0c6001c4aa134b99c86913d6a7089b7b2ab0 (patch)
tree7cd9d79433fdabb3ac207f42862497d406c43435 /tc/tc.c
parent72a2ff3916e59d2132a7d613d9e8f5eb372ba43e (diff)
tc: Add batchsize feature for filter and actions
Currently in tc batch mode, only one command is read from the batch file and sent to kernel to process. With this support, at most 128 commands can be accumulated before sending to kernel. Now it only works for the following successive commands: 1. filter add/delete/change/replace 2. actions add/change/replace Signed-off-by: Chris Mi <chrism@mellanox.com> Signed-off-by: David Ahern <dsahern@gmail.com>
Diffstat (limited to 'tc/tc.c')
-rw-r--r--tc/tc.c199
1 files changed, 184 insertions, 15 deletions
diff --git a/tc/tc.c b/tc/tc.c
index ad9f07e9..63e64fec 100644
--- a/tc/tc.c
+++ b/tc/tc.c
@@ -193,16 +193,16 @@ static void usage(void)
" -nm | -nam[es] | { -cf | -conf } path } | -j[son]\n");
}
-static int do_cmd(int argc, char **argv)
+static int do_cmd(int argc, char **argv, void *buf, size_t buflen)
{
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);
+ return do_filter(argc-1, argv+1, buf, buflen);
if (matches(*argv, "actions") == 0)
- return do_action(argc-1, argv+1);
+ return do_action(argc-1, argv+1, buf, buflen);
if (matches(*argv, "monitor") == 0)
return do_tcmonitor(argc-1, argv+1);
if (matches(*argv, "exec") == 0)
@@ -217,11 +217,110 @@ static int do_cmd(int argc, char **argv)
return -1;
}
+#define TC_MAX_SUBC 10
+static bool batchsize_enabled(int argc, char *argv[])
+{
+ 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;
+}
+
static int batch(const char *name)
{
- char *line = NULL;
+ 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;
batch_mode = 1;
if (name && strcmp(name, "-") != 0) {
@@ -240,25 +339,95 @@ static int batch(const char *name)
}
cmdlineno = 0;
- while (getcmdline(&line, &len, stdin) != -1) {
- char *largv[100];
- int largc;
+ 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;
+ }
- largc = makeargs(line, largv, 100);
- if (largc == 0)
+ /*
+ * 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 */
+ }
- if (do_cmd(largc, largv)) {
- fprintf(stderr, "Command failed %s:%d\n", name, cmdlineno);
+ 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;
}
- }
- if (line)
- free(line);
+ 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);
+ free_batch_bufs(&buf_pool);
+Exit:
+ free(line);
rtnl_close(&rth);
+
return ret;
}
@@ -341,7 +510,7 @@ int main(int argc, char **argv)
goto Exit;
}
- ret = do_cmd(argc-1, argv+1);
+ ret = do_cmd(argc-1, argv+1, NULL, 0);
Exit:
rtnl_close(&rth);