From: Jiri Pirko <j...@mellanox.com> Signed-off-by: Jiri Pirko <j...@mellanox.com> --- v1->v2: - moved the template handling from "tc filter template" to "tc chaintemplate" --- include/uapi/linux/rtnetlink.h | 7 +++ man/man8/tc.8 | 26 ++++++++++ tc/tc.c | 5 +- tc/tc_common.h | 1 + tc/tc_filter.c | 106 ++++++++++++++++++++++++++++++----------- tc/tc_monitor.c | 5 +- 6 files changed, 121 insertions(+), 29 deletions(-)
diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index c3a7d8ecc7b9..dddb05e5cca8 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -150,6 +150,13 @@ enum { RTM_NEWCACHEREPORT = 96, #define RTM_NEWCACHEREPORT RTM_NEWCACHEREPORT + RTM_NEWCHAINTMPLT = 100, +#define RTM_NEWCHAINTMPLT RTM_NEWCHAINTMPLT + RTM_DELCHAINTMPLT, +#define RTM_DELCHAINTMPLT RTM_DELCHAINTMPLT + RTM_GETCHAINTMPLT, +#define RTM_GETCHAINTMPLT RTM_GETCHAINTMPLT + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) }; diff --git a/man/man8/tc.8 b/man/man8/tc.8 index 840880fbdba6..3eee1aceaae4 100644 --- a/man/man8/tc.8 +++ b/man/man8/tc.8 @@ -58,6 +58,22 @@ tc \- show / manipulate traffic control settings .B flowid \fIflow-id\fR +.B tc +.RI "[ " OPTIONS " ]" +.B chaintemplate [ add | delete | get ] dev +\fIDEV\fR +.B [ parent +\fIqdisc-id\fR +.B | root ]\fR filtertype +[ filtertype specific parameters ] + +.B tc +.RI "[ " OPTIONS " ]" +.B chaintemplate [ add | delete | get ] block +\fIBLOCK_INDEX\fR filtertype +[ filtertype specific parameters ] + + .B tc .RI "[ " OPTIONS " ]" .RI "[ " FORMAT " ]" @@ -80,6 +96,16 @@ tc \- show / manipulate traffic control settings .RI "[ " OPTIONS " ]" .B filter show block \fIBLOCK_INDEX\fR +.P +.B tc +.RI "[ " OPTIONS " ]" +.B chaintemplate show dev +\fIDEV\fR +.P +.B tc +.RI "[ " OPTIONS " ]" +.B chaintemplate show block +\fIBLOCK_INDEX\fR .P .B tc diff --git a/tc/tc.c b/tc/tc.c index 0d223281ba25..8a0592c45800 100644 --- a/tc/tc.c +++ b/tc/tc.c @@ -197,7 +197,8 @@ 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" + "where OBJECT := { qdisc | class | filter | chaintemplate |\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" @@ -212,6 +213,8 @@ static int do_cmd(int argc, char **argv, void *buf, size_t buflen) return do_class(argc-1, argv+1); if (matches(*argv, "filter") == 0) return do_filter(argc-1, argv+1, buf, buflen); + if (matches(*argv, "chaintemplate") == 0) + return do_chaintmplt(argc-1, argv+1, buf, buflen); if (matches(*argv, "actions") == 0) return do_action(argc-1, argv+1, buf, buflen); if (matches(*argv, "monitor") == 0) diff --git a/tc/tc_common.h b/tc/tc_common.h index 49c24616c2c3..16cefe896109 100644 --- a/tc/tc_common.h +++ b/tc/tc_common.h @@ -8,6 +8,7 @@ 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, void *buf, size_t buflen); +extern int do_chaintmplt(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); diff --git a/tc/tc_filter.c b/tc/tc_filter.c index c5bb0bffe19b..df0ce853fbcc 100644 --- a/tc/tc_filter.c +++ b/tc/tc_filter.c @@ -39,12 +39,21 @@ static void usage(void) "\n" " tc filter show [ dev STRING ] [ root | ingress | egress | parent CLASSID ]\n" " tc filter show [ block BLOCK_INDEX ]\n" + " tc chaintemplate [ add | del | get | show ] [ dev STRING ]\n" + " tc chaintemplate [ add | del | get | show ] [ block BLOCK_INDEX ] ]\n" "Where:\n" "FILTER_TYPE := { rsvp | u32 | bpf | fw | route | etc. }\n" "FILTERID := ... format depends on classifier, see there\n" "OPTIONS := ... try tc filter add <desired FILTER_KIND> help\n"); } +static void chaintmplt_usage(void) +{ + fprintf(stderr, + "Usage: tc chaintemplate [ add | del | get | show ] [ dev STRING ]\n" + " tc chaintemplate [ add | del | get | show ] [ block BLOCK_INDEX ] ]\n"); +} + struct tc_filter_req { struct nlmsghdr n; struct tcmsg t; @@ -85,7 +94,8 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv, req->n.nlmsg_type = cmd; req->t.tcm_family = AF_UNSPEC; - if (cmd == RTM_NEWTFILTER && flags & NLM_F_CREATE) + if ((cmd == RTM_NEWTFILTER || cmd == RTM_NEWCHAINTMPLT) && + flags & NLM_F_CREATE) protocol = htons(ETH_P_ALL); while (argc > 0) { @@ -261,7 +271,10 @@ int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (n->nlmsg_type != RTM_NEWTFILTER && n->nlmsg_type != RTM_GETTFILTER && - n->nlmsg_type != RTM_DELTFILTER) { + n->nlmsg_type != RTM_DELTFILTER && + n->nlmsg_type != RTM_NEWCHAINTMPLT && + n->nlmsg_type != RTM_GETCHAINTMPLT && + n->nlmsg_type != RTM_DELCHAINTMPLT) { fprintf(stderr, "Not a filter(cmd %d)\n", n->nlmsg_type); return 0; } @@ -280,20 +293,26 @@ int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) open_json_object(NULL); - if (n->nlmsg_type == RTM_DELTFILTER) + if (n->nlmsg_type == RTM_DELTFILTER || n->nlmsg_type == RTM_DELCHAINTMPLT) print_bool(PRINT_ANY, "deleted", "deleted ", true); - if (n->nlmsg_type == RTM_NEWTFILTER && + if ((n->nlmsg_type == RTM_NEWTFILTER || + n->nlmsg_type == RTM_NEWCHAINTMPLT) && (n->nlmsg_flags & NLM_F_CREATE) && !(n->nlmsg_flags & NLM_F_EXCL)) print_bool(PRINT_ANY, "replaced", "replaced ", true); - if (n->nlmsg_type == RTM_NEWTFILTER && + if ((n->nlmsg_type == RTM_NEWTFILTER || + n->nlmsg_type == RTM_NEWCHAINTMPLT) && (n->nlmsg_flags & NLM_F_CREATE) && (n->nlmsg_flags & NLM_F_EXCL)) print_bool(PRINT_ANY, "added", "added ", true); - print_string(PRINT_FP, NULL, "filter ", NULL); + if (n->nlmsg_type == RTM_NEWTFILTER || + n->nlmsg_type == RTM_DELTFILTER) + print_string(PRINT_FP, NULL, "filter ", NULL); + else + print_string(PRINT_FP, NULL, "chaintemplate ", NULL); if (t->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK) { if (!filter_block_index || filter_block_index != t->tcm_block_index) @@ -317,7 +336,9 @@ int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) } } - if (t->tcm_info) { + if (t->tcm_info && (n->nlmsg_type == RTM_NEWTFILTER || + n->nlmsg_type == RTM_DELTFILTER || + n->nlmsg_type == RTM_GETTFILTER)) { f_proto = TC_H_MIN(t->tcm_info); __u32 prio = TC_H_MAJ(t->tcm_info)>>16; @@ -496,17 +517,19 @@ static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv) argc--; argv++; } - if (!protocol_set) { - fprintf(stderr, "Must specify filter protocol\n"); - return -1; - } + if (cmd == RTM_GETTFILTER) { + if (!protocol_set) { + fprintf(stderr, "Must specify filter protocol\n"); + return -1; + } - if (!prio) { - fprintf(stderr, "Must specify filter priority\n"); - return -1; - } + if (!prio) { + fprintf(stderr, "Must specify filter priority\n"); + return -1; + } - 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); @@ -516,11 +539,13 @@ static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv) return -1; } - if (k[0]) - addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1); - else { - fprintf(stderr, "Must specify filter type\n"); - return -1; + if (cmd == RTM_GETTFILTER) { + if (k[0]) + addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1); + else { + fprintf(stderr, "Must specify filter type\n"); + return -1; + } } if (d[0]) { @@ -539,10 +564,11 @@ static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv) return -1; } - if (q->parse_fopt(q, fhandle, argc, argv, &req.n)) + if (cmd == RTM_GETTFILTER && + q->parse_fopt(q, fhandle, argc, argv, &req.n)) return 1; - if (!fhandle) { + if (!fhandle && cmd == RTM_GETTFILTER) { fprintf(stderr, "Must specify filter \"handle\"\n"); return -1; } @@ -569,7 +595,7 @@ static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv) return 0; } -static int tc_filter_list(int argc, char **argv) +static int tc_filter_list(int cmd, int argc, char **argv) { struct { struct nlmsghdr n; @@ -577,7 +603,7 @@ static int tc_filter_list(int argc, char **argv) char buf[MAX_MSG]; } req = { .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), - .n.nlmsg_type = RTM_GETTFILTER, + .n.nlmsg_type = cmd, .t.tcm_parent = TC_H_UNSPEC, .t.tcm_family = AF_UNSPEC, }; @@ -725,7 +751,7 @@ static int tc_filter_list(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); + return tc_filter_list(RTM_GETTFILTER, 0, NULL); if (matches(*argv, "add") == 0) return tc_filter_modify(RTM_NEWTFILTER, NLM_F_EXCL|NLM_F_CREATE, argc-1, argv+1, buf, buflen); @@ -742,7 +768,7 @@ int do_filter(int argc, char **argv, void *buf, size_t buflen) return tc_filter_get(RTM_GETTFILTER, 0, argc-1, argv+1); if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0 || matches(*argv, "lst") == 0) - return tc_filter_list(argc-1, argv+1); + return tc_filter_list(RTM_GETTFILTER, argc-1, argv+1); if (matches(*argv, "help") == 0) { usage(); return 0; @@ -751,3 +777,29 @@ int do_filter(int argc, char **argv, void *buf, size_t buflen) *argv); return -1; } + +int do_chaintmplt(int argc, char **argv, void *buf, size_t buflen) +{ + if (argc < 1) + return tc_filter_list(RTM_GETCHAINTMPLT, 0, NULL); + if (matches(*argv, "add") == 0) { + return tc_filter_modify(RTM_NEWCHAINTMPLT, NLM_F_EXCL | NLM_F_CREATE, + argc - 1, argv + 1, buf, buflen); + } else if (matches(*argv, "delete") == 0) { + return tc_filter_modify(RTM_DELCHAINTMPLT, 0, + argc - 1, argv + 1, buf, buflen); + } else if (matches(*argv, "get") == 0) { + return tc_filter_get(RTM_GETCHAINTMPLT, 0, + argc - 1, argv + 1); + } else if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0 || + matches(*argv, "lst") == 0) { + return tc_filter_list(RTM_GETCHAINTMPLT, argc - 1, argv + 1); + } else if (matches(*argv, "help") == 0) { + chaintmplt_usage(); + return 0; + } + fprintf(stderr, "Command \"%s\" is unknown, try \"tc chaintemplate help\".\n", + *argv); + return -1; +} + diff --git a/tc/tc_monitor.c b/tc/tc_monitor.c index 077b138d1ec5..33633837432c 100644 --- a/tc/tc_monitor.c +++ b/tc/tc_monitor.c @@ -43,7 +43,10 @@ static int accept_tcmsg(const struct sockaddr_nl *who, if (timestamp) print_timestamp(fp); - if (n->nlmsg_type == RTM_NEWTFILTER || n->nlmsg_type == RTM_DELTFILTER) { + if (n->nlmsg_type == RTM_NEWTFILTER || + n->nlmsg_type == RTM_DELTFILTER || + n->nlmsg_type == RTM_NEWCHAINTMPLT || + n->nlmsg_type == RTM_DELCHAINTMPLT) { print_filter(who, n, arg); return 0; } -- 2.14.4