Mon, Jan 02, 2017 at 11:21:41PM CET, j...@mojatatu.com wrote: >On 17-01-02 01:23 PM, John Fastabend wrote: > >> >> Additionally I would like to point out this is an arbitrary length binary >> blob (for undefined use, without even a specified encoding) that gets pushed >> between user space and hardware ;) This seemed to get folks fairly excited in >> the past. >> > >The binary blob size is a little strange - but i think there is value >in storing some "cookie" field. The challenge is whether the kernel >gets to intepret it; in which case encoding must be specified. Or >whether we should leave it up to user space - in which something >like tc could standardize its own encodings.
This should never be interpreted by kernel. I think this would be good to make clear in the comment in the code. > >> Some questions, exactly what do you mean by "port mappings" above? In >> general the 'tc' API uses the netdev the netlink msg is processed on as >> the port mapping. If you mean OVS port to netdev port I think this is >> a OVS problem and nothing to do with 'tc'. For what its worth there is an >> existing problem with 'tc' where rules only apply to a single ingress or >> egress port which is limiting on hardware. >> > >In our case the desire is to be able to correlate for a system wide >mostly identity/key mapping. > >> The UFID in my ovs code base is defined as best I can tell here, >> >> [OVS_FLOW_ATTR_UFID] = { .type = NL_A_UNSPEC, .optional = true, >> .min_len = sizeof(ovs_u128) }, >> >> So you need 128 bits if you want a 1:1 mapping onto 'tc'. So rather >> than an arbitrary blob why not make the case that 'tc' ids need to be >> 128 bits long? Even if its just initially done in flower call it >> flower_flow_id and define it so its not opaque and at least at the code >> level it isn't an arbitrary blob of data. >> > >I dont know what this UFID is, but do note: >The idea is not new - the FIB for example has some such cookie >(albeit a tiny one) which will typically be populated to tell >you who/what installed the entry. >I could see f.e use for this cookie to simplify and pretty print in >a human language for the u32 classifier (i.e user space tc sets >some fields in the cookie when updating kernel and when user space >invokes get/dump it uses the cookie to intepret how to pretty print). > >I have attached a compile tested version of the cookies on actions >(flat 64 bit; now that we have experienced the use when we have a >large number of counters - I would not mind a 128 bit field). > > >cheers, >jamal > >> And what are the "next" uses of this besides OVS. It would be really >> valuable to see how this generalizes to other usage models. To avoid >> embedding OVS syntax into 'tc'. >> >> Finally if you want to see an example of binary data encodings look at >> how drivers/hardware/users are currently using the user defined bits in >> ethtools ntuple API. Also track down out of tree drivers to see other >> interesting uses. And that was capped at 64bits :/ >> >> Thanks, >> John >> >> >> >> >> > >diff --git a/include/net/act_api.h b/include/net/act_api.h >index 1d71644..f299ed3 100644 >--- a/include/net/act_api.h >+++ b/include/net/act_api.h >@@ -41,6 +41,7 @@ struct tc_action { > struct rcu_head tcfa_rcu; > struct gnet_stats_basic_cpu __percpu *cpu_bstats; > struct gnet_stats_queue __percpu *cpu_qstats; >+ u64 cookie; > }; > #define tcf_head common.tcfa_head > #define tcf_index common.tcfa_index >diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h >index cb4bcdc..2e968ee 100644 >--- a/include/uapi/linux/pkt_cls.h >+++ b/include/uapi/linux/pkt_cls.h >@@ -67,6 +67,7 @@ enum { > TCA_ACT_INDEX, > TCA_ACT_STATS, > TCA_ACT_PAD, >+ TCA_ACT_COOKIE, > __TCA_ACT_MAX > }; > >diff --git a/net/sched/act_api.c b/net/sched/act_api.c >index 2095c83..97eae6b 100644 >--- a/net/sched/act_api.c >+++ b/net/sched/act_api.c >@@ -26,6 +26,7 @@ > #include <net/sch_generic.h> > #include <net/act_api.h> > #include <net/netlink.h> >+#include <net/tc_act/tc_gact.h> > > static void free_tcf(struct rcu_head *head) > { >@@ -467,17 +468,21 @@ int tcf_action_destroy(struct list_head *actions, int >bind) > return a->ops->dump(skb, a, bind, ref); > } > >-int >-tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int bind, int ref) >+int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int bind, >+ int ref) > { > int err = -EINVAL; > unsigned char *b = skb_tail_pointer(skb); > struct nlattr *nest; >+ u64 cookie = a->cookie; > > if (nla_put_string(skb, TCA_KIND, a->ops->kind)) > goto nla_put_failure; > if (tcf_action_copy_stats(skb, a, 0)) > goto nla_put_failure; >+ if (nla_put_u64_64bit(skb, TCA_ACT_COOKIE, cookie, TCA_ACT_PAD)) >+ goto nla_put_failure; >+ > nest = nla_nest_start(skb, TCA_OPTIONS); > if (nest == NULL) > goto nla_put_failure; >@@ -578,6 +583,11 @@ struct tc_action *tcf_action_init_1(struct net *net, >struct nlattr *nla, > if (err < 0) > goto err_mod; > >+ if (tb[TCA_ACT_COOKIE]) >+ a->cookie = nla_get_u64(tb[TCA_ACT_COOKIE]); >+ else >+ a->cookie = 0; /* kernel uses 0 */ >+ > /* module count goes up only when brand new policy is created > * if it exists and is only bound to in a_o->init() then > * ACT_P_CREATED is not returned (a zero is). >commit 0a6fd6b024db77e3a460c22ab8a496a714bc71b7 >Author: Jamal Hadi Salim <h...@mojatatu.com> >Date: Fri Aug 12 06:10:46 2016 -0400 > > actions: add support for cookies > > Signed-off-by: Jamal Hadi Salim <j...@mojatatu.com> > >diff --git a/tc/m_action.c b/tc/m_action.c >index c416d98..75d1a5a 100644 >--- a/tc/m_action.c >+++ b/tc/m_action.c >@@ -137,8 +137,7 @@ noexist: > return a; > } > >-static int >-new_cmd(char **argv) >+static int new_cmd(char **argv) > { > if ((matches(*argv, "change") == 0) || > (matches(*argv, "replace") == 0) || >@@ -151,8 +150,7 @@ new_cmd(char **argv) > > } > >-int >-parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) >+int parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) > { > int argc = *argc_p; > char **argv = *argv_p; >@@ -160,6 +158,7 @@ parse_action(int *argc_p, char ***argv_p, int tca_id, >struct nlmsghdr *n) > char k[16]; > int ok = 0; > int eap = 0; /* expect action parameters */ >+ __u64 act_ck = 0; > > int ret = 0; > int prio = 0; >@@ -215,13 +214,28 @@ done0: > tail = NLMSG_TAIL(n); > addattr_l(n, MAX_MSG, ++prio, NULL, 0); > addattr_l(n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1); >- >- ret = a->parse_aopt(a, &argc, &argv, TCA_ACT_OPTIONS, >n); >+ ret = a->parse_aopt(a, &argc, &argv, TCA_ACT_OPTIONS, >+ n); > > if (ret < 0) { >- fprintf(stderr, "bad action parsing\n"); >+ fprintf(stderr, "bad action option parsing\n"); > goto bad_val; > } >+ >+ if (*argv && strcmp(*argv, "cookie") == 0) { >+ NEXT_ARG(); >+ ret = get_u64(&act_ck, *argv, 0); >+ if (ret) { >+ fprintf(stderr, "bad cookie <%s>\n", >+ *argv); >+ goto bad_val; >+ } >+ argc--; >+ argv++; >+ } >+ >+ if (act_ck) >+ addattr64(n, MAX_MSG, TCA_ACT_COOKIE, act_ck); > tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; > ok++; > } >@@ -246,8 +260,7 @@ bad_val: > return -1; > } > >-static int >-tc_print_one_action(FILE *f, struct rtattr *arg) >+static int tc_print_one_action(FILE *f, struct rtattr *arg) > { > > struct rtattr *tb[TCA_ACT_MAX + 1]; >@@ -277,6 +290,10 @@ tc_print_one_action(FILE *f, struct rtattr *arg) > if (show_stats && tb[TCA_ACT_STATS]) { > fprintf(f, "\tAction statistics:\n"); > print_tcstats2_attr(f, tb[TCA_ACT_STATS], "\t", NULL); >+ if (tb[TCA_ACT_COOKIE]) { >+ __u64 acookie = rta_getattr_u64(tb[TCA_ACT_COOKIE]); >+ fprintf(f, "cookie 0x%llx ", acookie); >+ } > fprintf(f, "\n"); > }