Merge branch 'tc-batch' into net-next
Chris Mi says: ==================== Currently in tc batch mode, only one command is read from the batch file and sent to kernel to process. With this patchset, at most 128 commands can be accumulated before sending to kernel. We introduced a new function in patch 1 to support for sending multiple messages. In patch 2, we add this support for filter add/delete/change/replace and actions add/change/replace commands. But please note that kernel still processes the requests one by one. To process the requests in parallel in kernel is another effort. The time we're saving in this patchset is the user mode and kernel mode context switch. So this patchset works on top of the current kernel. Using the following script in kernel, we can generate 1,000,000 rules. tools/testing/selftests/tc-testing/tdc_batch.py Without this patchset, 'tc -b $file' exection time is: real 0m15.555s user 0m7.211s sys 0m8.284s With this patchset, 'tc -b $file' exection time is: real 0m12.360s user 0m6.082s sys 0m6.213s The insertion rate is improved more than 10%. ==================== Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
commit
e209d4c83d
|
|
@ -96,6 +96,9 @@ int rtnl_dump_filter_nc(struct rtnl_handle *rth,
|
|||
int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
|
||||
struct nlmsghdr **answer)
|
||||
__attribute__((warn_unused_result));
|
||||
int rtnl_talk_iov(struct rtnl_handle *rtnl, struct iovec *iovec, size_t iovlen,
|
||||
struct nlmsghdr **answer)
|
||||
__attribute__((warn_unused_result));
|
||||
int rtnl_talk_extack(struct rtnl_handle *rtnl, struct nlmsghdr *n,
|
||||
struct nlmsghdr **answer, nl_ext_ack_fn_t errfn)
|
||||
__attribute__((warn_unused_result));
|
||||
|
|
|
|||
|
|
@ -581,30 +581,30 @@ static void rtnl_talk_error(struct nlmsghdr *h, struct nlmsgerr *err,
|
|||
strerror(-err->error));
|
||||
}
|
||||
|
||||
static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
|
||||
struct nlmsghdr **answer,
|
||||
bool show_rtnl_err, nl_ext_ack_fn_t errfn)
|
||||
|
||||
static int __rtnl_talk_iov(struct rtnl_handle *rtnl, struct iovec *iov,
|
||||
size_t iovlen, struct nlmsghdr **answer,
|
||||
bool show_rtnl_err, nl_ext_ack_fn_t errfn)
|
||||
{
|
||||
int status;
|
||||
unsigned int seq;
|
||||
struct nlmsghdr *h;
|
||||
struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
|
||||
struct iovec iov = {
|
||||
.iov_base = n,
|
||||
.iov_len = n->nlmsg_len
|
||||
};
|
||||
struct iovec riov;
|
||||
struct msghdr msg = {
|
||||
.msg_name = &nladdr,
|
||||
.msg_namelen = sizeof(nladdr),
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_iov = iov,
|
||||
.msg_iovlen = iovlen,
|
||||
};
|
||||
unsigned int seq = 0;
|
||||
struct nlmsghdr *h;
|
||||
int i, status;
|
||||
char *buf;
|
||||
|
||||
n->nlmsg_seq = seq = ++rtnl->seq;
|
||||
|
||||
if (answer == NULL)
|
||||
n->nlmsg_flags |= NLM_F_ACK;
|
||||
for (i = 0; i < iovlen; i++) {
|
||||
h = iov[i].iov_base;
|
||||
h->nlmsg_seq = seq = ++rtnl->seq;
|
||||
if (answer == NULL)
|
||||
h->nlmsg_flags |= NLM_F_ACK;
|
||||
}
|
||||
|
||||
status = sendmsg(rtnl->fd, &msg, 0);
|
||||
if (status < 0) {
|
||||
|
|
@ -612,8 +612,14 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* change msg to use the response iov */
|
||||
msg.msg_iov = &riov;
|
||||
msg.msg_iovlen = 1;
|
||||
i = 0;
|
||||
while (1) {
|
||||
next:
|
||||
status = rtnl_recvmsg(rtnl->fd, &msg, &buf);
|
||||
++i;
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
|
@ -642,7 +648,7 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
|
|||
|
||||
if (nladdr.nl_pid != 0 ||
|
||||
h->nlmsg_pid != rtnl->local.nl_pid ||
|
||||
h->nlmsg_seq != seq) {
|
||||
h->nlmsg_seq > seq || h->nlmsg_seq < seq - iovlen) {
|
||||
/* Don't forget to skip that message. */
|
||||
status -= NLMSG_ALIGN(len);
|
||||
h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
|
||||
|
|
@ -662,7 +668,10 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
|
|||
*answer = (struct nlmsghdr *)buf;
|
||||
else
|
||||
free(buf);
|
||||
return 0;
|
||||
if (h->nlmsg_seq == seq)
|
||||
return 0;
|
||||
else
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (rtnl->proto != NETLINK_SOCK_DIAG &&
|
||||
|
|
@ -671,7 +680,7 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
|
|||
|
||||
errno = -err->error;
|
||||
free(buf);
|
||||
return -1;
|
||||
return -i;
|
||||
}
|
||||
|
||||
if (answer) {
|
||||
|
|
@ -698,12 +707,30 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
|
|||
}
|
||||
}
|
||||
|
||||
static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
|
||||
struct nlmsghdr **answer,
|
||||
bool show_rtnl_err, nl_ext_ack_fn_t errfn)
|
||||
{
|
||||
struct iovec iov = {
|
||||
.iov_base = n,
|
||||
.iov_len = n->nlmsg_len
|
||||
};
|
||||
|
||||
return __rtnl_talk_iov(rtnl, &iov, 1, answer, show_rtnl_err, errfn);
|
||||
}
|
||||
|
||||
int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
|
||||
struct nlmsghdr **answer)
|
||||
{
|
||||
return __rtnl_talk(rtnl, n, answer, true, NULL);
|
||||
}
|
||||
|
||||
int rtnl_talk_iov(struct rtnl_handle *rtnl, struct iovec *iovec, size_t iovlen,
|
||||
struct nlmsghdr **answer)
|
||||
{
|
||||
return __rtnl_talk_iov(rtnl, iovec, iovlen, answer, true, NULL);
|
||||
}
|
||||
|
||||
int rtnl_talk_extack(struct rtnl_handle *rtnl, struct nlmsghdr *n,
|
||||
struct nlmsghdr **answer,
|
||||
nl_ext_ack_fn_t errfn)
|
||||
|
|
|
|||
|
|
@ -546,40 +546,61 @@ bad_val:
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct tc_action_req {
|
||||
struct nlmsghdr n;
|
||||
struct tcamsg t;
|
||||
char buf[MAX_MSG];
|
||||
};
|
||||
|
||||
static int tc_action_modify(int cmd, unsigned int flags,
|
||||
int *argc_p, char ***argv_p)
|
||||
int *argc_p, char ***argv_p,
|
||||
void *buf, size_t buflen)
|
||||
{
|
||||
int argc = *argc_p;
|
||||
struct tc_action_req *req, action_req;
|
||||
char **argv = *argv_p;
|
||||
struct rtattr *tail;
|
||||
int argc = *argc_p;
|
||||
struct iovec iov;
|
||||
int ret = 0;
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct tcamsg t;
|
||||
char buf[MAX_MSG];
|
||||
} req = {
|
||||
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)),
|
||||
.n.nlmsg_flags = NLM_F_REQUEST | flags,
|
||||
.n.nlmsg_type = cmd,
|
||||
.t.tca_family = AF_UNSPEC,
|
||||
};
|
||||
struct rtattr *tail = NLMSG_TAIL(&req.n);
|
||||
|
||||
if (buf) {
|
||||
req = buf;
|
||||
if (buflen < sizeof (struct tc_action_req)) {
|
||||
fprintf(stderr, "buffer is too small: %zu\n", buflen);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
memset(&action_req, 0, sizeof (struct tc_action_req));
|
||||
req = &action_req;
|
||||
}
|
||||
|
||||
req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg));
|
||||
req->n.nlmsg_flags = NLM_F_REQUEST | flags;
|
||||
req->n.nlmsg_type = cmd;
|
||||
req->t.tca_family = AF_UNSPEC;
|
||||
tail = NLMSG_TAIL(&req->n);
|
||||
|
||||
argc -= 1;
|
||||
argv += 1;
|
||||
if (parse_action(&argc, &argv, TCA_ACT_TAB, &req.n)) {
|
||||
if (parse_action(&argc, &argv, TCA_ACT_TAB, &req->n)) {
|
||||
fprintf(stderr, "Illegal \"action\"\n");
|
||||
return -1;
|
||||
}
|
||||
tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail;
|
||||
|
||||
if (rtnl_talk(&rth, &req.n, NULL) < 0) {
|
||||
fprintf(stderr, "We have an error talking to the kernel\n");
|
||||
ret = -1;
|
||||
}
|
||||
tail->rta_len = (void *) NLMSG_TAIL(&req->n) - (void *) tail;
|
||||
|
||||
*argc_p = argc;
|
||||
*argv_p = argv;
|
||||
|
||||
if (buf)
|
||||
return 0;
|
||||
|
||||
iov.iov_base = &req->n;
|
||||
iov.iov_len = req->n.nlmsg_len;
|
||||
if (rtnl_talk_iov(&rth, &iov, 1, NULL) < 0) {
|
||||
fprintf(stderr, "We have an error talking to the kernel\n");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -679,7 +700,7 @@ bad_val:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int do_action(int argc, char **argv)
|
||||
int do_action(int argc, char **argv, void *buf, size_t buflen)
|
||||
{
|
||||
|
||||
int ret = 0;
|
||||
|
|
@ -689,12 +710,12 @@ int do_action(int argc, char **argv)
|
|||
if (matches(*argv, "add") == 0) {
|
||||
ret = tc_action_modify(RTM_NEWACTION,
|
||||
NLM_F_EXCL | NLM_F_CREATE,
|
||||
&argc, &argv);
|
||||
&argc, &argv, buf, buflen);
|
||||
} else if (matches(*argv, "change") == 0 ||
|
||||
matches(*argv, "replace") == 0) {
|
||||
ret = tc_action_modify(RTM_NEWACTION,
|
||||
NLM_F_CREATE | NLM_F_REPLACE,
|
||||
&argc, &argv);
|
||||
&argc, &argv, buf, buflen);
|
||||
} else if (matches(*argv, "delete") == 0) {
|
||||
argc -= 1;
|
||||
argv += 1;
|
||||
|
|
|
|||
199
tc/tc.c
199
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 = makeargs(line, largv, 100);
|
||||
if (largc == 0)
|
||||
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 */
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#define TCA_BUF_MAX (64*1024)
|
||||
#define MSG_IOV_MAX 128
|
||||
|
||||
extern struct rtnl_handle rth;
|
||||
|
||||
extern int do_qdisc(int argc, char **argv);
|
||||
extern int do_class(int argc, char **argv);
|
||||
extern int do_filter(int argc, char **argv);
|
||||
extern int do_action(int argc, char **argv);
|
||||
extern int do_filter(int argc, char **argv, void *buf, size_t buflen);
|
||||
extern int do_action(int argc, char **argv, void *buf, size_t buflen);
|
||||
extern int do_tcmonitor(int argc, char **argv);
|
||||
extern int do_exec(int argc, char **argv);
|
||||
|
||||
|
|
|
|||
106
tc/tc_filter.c
106
tc/tc_filter.c
|
|
@ -42,28 +42,44 @@ static void usage(void)
|
|||
"OPTIONS := ... try tc filter add <desired FILTER_KIND> help\n");
|
||||
}
|
||||
|
||||
static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
|
||||
struct tc_filter_req {
|
||||
struct nlmsghdr n;
|
||||
struct tcmsg t;
|
||||
char buf[MAX_MSG];
|
||||
};
|
||||
|
||||
static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv,
|
||||
void *buf, size_t buflen)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct tcmsg t;
|
||||
char buf[MAX_MSG];
|
||||
} req = {
|
||||
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
|
||||
.n.nlmsg_flags = NLM_F_REQUEST | flags,
|
||||
.n.nlmsg_type = cmd,
|
||||
.t.tcm_family = AF_UNSPEC,
|
||||
};
|
||||
struct tc_filter_req *req, filter_req;
|
||||
struct filter_util *q = NULL;
|
||||
__u32 prio = 0;
|
||||
__u32 protocol = 0;
|
||||
int protocol_set = 0;
|
||||
__u32 chain_index;
|
||||
int chain_index_set = 0;
|
||||
char *fhandle = NULL;
|
||||
char d[IFNAMSIZ] = {};
|
||||
char k[FILTER_NAMESZ] = {};
|
||||
struct tc_estimator est = {};
|
||||
char k[FILTER_NAMESZ] = {};
|
||||
int chain_index_set = 0;
|
||||
char d[IFNAMSIZ] = {};
|
||||
int protocol_set = 0;
|
||||
char *fhandle = NULL;
|
||||
__u32 protocol = 0;
|
||||
__u32 chain_index;
|
||||
struct iovec iov;
|
||||
__u32 prio = 0;
|
||||
int ret;
|
||||
|
||||
if (buf) {
|
||||
req = buf;
|
||||
if (buflen < sizeof (struct tc_filter_req)) {
|
||||
fprintf(stderr, "buffer is too small: %zu\n", buflen);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
memset(&filter_req, 0, sizeof (struct tc_filter_req));
|
||||
req = &filter_req;
|
||||
}
|
||||
|
||||
req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
|
||||
req->n.nlmsg_flags = NLM_F_REQUEST | flags;
|
||||
req->n.nlmsg_type = cmd;
|
||||
req->t.tcm_family = AF_UNSPEC;
|
||||
|
||||
if (cmd == RTM_NEWTFILTER && flags & NLM_F_CREATE)
|
||||
protocol = htons(ETH_P_ALL);
|
||||
|
|
@ -75,37 +91,37 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
|
|||
duparg("dev", *argv);
|
||||
strncpy(d, *argv, sizeof(d)-1);
|
||||
} else if (strcmp(*argv, "root") == 0) {
|
||||
if (req.t.tcm_parent) {
|
||||
if (req->t.tcm_parent) {
|
||||
fprintf(stderr,
|
||||
"Error: \"root\" is duplicate parent ID\n");
|
||||
return -1;
|
||||
}
|
||||
req.t.tcm_parent = TC_H_ROOT;
|
||||
req->t.tcm_parent = TC_H_ROOT;
|
||||
} else if (strcmp(*argv, "ingress") == 0) {
|
||||
if (req.t.tcm_parent) {
|
||||
if (req->t.tcm_parent) {
|
||||
fprintf(stderr,
|
||||
"Error: \"ingress\" is duplicate parent ID\n");
|
||||
return -1;
|
||||
}
|
||||
req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
|
||||
req->t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
|
||||
TC_H_MIN_INGRESS);
|
||||
} else if (strcmp(*argv, "egress") == 0) {
|
||||
if (req.t.tcm_parent) {
|
||||
if (req->t.tcm_parent) {
|
||||
fprintf(stderr,
|
||||
"Error: \"egress\" is duplicate parent ID\n");
|
||||
return -1;
|
||||
}
|
||||
req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
|
||||
req->t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
|
||||
TC_H_MIN_EGRESS);
|
||||
} else if (strcmp(*argv, "parent") == 0) {
|
||||
__u32 handle;
|
||||
|
||||
NEXT_ARG();
|
||||
if (req.t.tcm_parent)
|
||||
if (req->t.tcm_parent)
|
||||
duparg("parent", *argv);
|
||||
if (get_tc_classid(&handle, *argv))
|
||||
invarg("Invalid parent ID", *argv);
|
||||
req.t.tcm_parent = handle;
|
||||
req->t.tcm_parent = handle;
|
||||
} else if (strcmp(*argv, "handle") == 0) {
|
||||
NEXT_ARG();
|
||||
if (fhandle)
|
||||
|
|
@ -152,26 +168,26 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
|
|||
argc--; argv++;
|
||||
}
|
||||
|
||||
req.t.tcm_info = TC_H_MAKE(prio<<16, protocol);
|
||||
req->t.tcm_info = TC_H_MAKE(prio<<16, protocol);
|
||||
|
||||
if (chain_index_set)
|
||||
addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index);
|
||||
addattr32(&req->n, sizeof(*req), TCA_CHAIN, chain_index);
|
||||
|
||||
if (k[0])
|
||||
addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1);
|
||||
addattr_l(&req->n, sizeof(*req), TCA_KIND, k, strlen(k)+1);
|
||||
|
||||
if (d[0]) {
|
||||
ll_init_map(&rth);
|
||||
|
||||
req.t.tcm_ifindex = ll_name_to_index(d);
|
||||
if (req.t.tcm_ifindex == 0) {
|
||||
req->t.tcm_ifindex = ll_name_to_index(d);
|
||||
if (req->t.tcm_ifindex == 0) {
|
||||
fprintf(stderr, "Cannot find device \"%s\"\n", d);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (q) {
|
||||
if (q->parse_fopt(q, fhandle, argc, argv, &req.n))
|
||||
if (q->parse_fopt(q, fhandle, argc, argv, &req->n))
|
||||
return 1;
|
||||
} else {
|
||||
if (fhandle) {
|
||||
|
|
@ -190,10 +206,16 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
|
|||
}
|
||||
|
||||
if (est.ewma_log)
|
||||
addattr_l(&req.n, sizeof(req), TCA_RATE, &est, sizeof(est));
|
||||
addattr_l(&req->n, sizeof(*req), TCA_RATE, &est, sizeof(est));
|
||||
|
||||
if (rtnl_talk(&rth, &req.n, NULL) < 0) {
|
||||
fprintf(stderr, "We have an error talking to the kernel\n");
|
||||
if (buf)
|
||||
return 0;
|
||||
|
||||
iov.iov_base = &req->n;
|
||||
iov.iov_len = req->n.nlmsg_len;
|
||||
ret = rtnl_talk_iov(&rth, &iov, 1, NULL);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "We have an error talking to the kernel, %d\n", ret);
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
|
@ -636,20 +658,22 @@ static int tc_filter_list(int argc, char **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int do_filter(int argc, char **argv)
|
||||
int do_filter(int argc, char **argv, void *buf, size_t buflen)
|
||||
{
|
||||
if (argc < 1)
|
||||
return tc_filter_list(0, NULL);
|
||||
if (matches(*argv, "add") == 0)
|
||||
return tc_filter_modify(RTM_NEWTFILTER, NLM_F_EXCL|NLM_F_CREATE,
|
||||
argc-1, argv+1);
|
||||
argc-1, argv+1, buf, buflen);
|
||||
if (matches(*argv, "change") == 0)
|
||||
return tc_filter_modify(RTM_NEWTFILTER, 0, argc-1, argv+1);
|
||||
return tc_filter_modify(RTM_NEWTFILTER, 0, argc-1, argv+1,
|
||||
buf, buflen);
|
||||
if (matches(*argv, "replace") == 0)
|
||||
return tc_filter_modify(RTM_NEWTFILTER, NLM_F_CREATE, argc-1,
|
||||
argv+1);
|
||||
argv+1, buf, buflen);
|
||||
if (matches(*argv, "delete") == 0)
|
||||
return tc_filter_modify(RTM_DELTFILTER, 0, argc-1, argv+1);
|
||||
return tc_filter_modify(RTM_DELTFILTER, 0, argc-1, argv+1,
|
||||
buf, buflen);
|
||||
if (matches(*argv, "get") == 0)
|
||||
return tc_filter_get(RTM_GETTFILTER, 0, argc-1, argv+1);
|
||||
if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
|
||||
|
|
|
|||
Loading…
Reference in New Issue