net: cls_bpf: limit hardware offload by software-only flag
authorJakub Kicinski <jakub.kicinski@netronome.com>
Wed, 21 Sep 2016 10:43:54 +0000 (11:43 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 21 Sep 2016 23:50:02 +0000 (19:50 -0400)
Add cls_bpf support for the TCA_CLS_FLAGS_SKIP_HW flag.
Unlike U32 and flower cls_bpf already has some netlink
flags defined.  Create a new attribute to be able to use
the same flag values as the above.

Unlike U32 and flower reject unknown flags.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/pkt_cls.h
include/uapi/linux/pkt_cls.h
net/sched/cls_bpf.c

index 41e8071dff87044adc1c24f15079e5f73296afae..57af9f3032ff76fb6ab94221b8b2ff8104e7b8cb 100644 (file)
@@ -498,6 +498,7 @@ struct tc_cls_bpf_offload {
        struct bpf_prog *prog;
        const char *name;
        bool exts_integrated;
+       u32 gen_flags;
 };
 
 #endif
index 8915b61bbf83d124d871392eb4e1760986dfeea7..8fd715f806a27f327051d48a8e6b4ab8656c9703 100644 (file)
@@ -396,6 +396,7 @@ enum {
        TCA_BPF_FD,
        TCA_BPF_NAME,
        TCA_BPF_FLAGS,
+       TCA_BPF_FLAGS_GEN,
        __TCA_BPF_MAX,
 };
 
index 6523c5b4c0a5d504de3b21d48eb50969796baa90..ebf01f7c1470f8ac27fd15f6f7a81a42b63e24e8 100644 (file)
@@ -27,6 +27,8 @@ MODULE_AUTHOR("Daniel Borkmann <dborkman@redhat.com>");
 MODULE_DESCRIPTION("TC BPF based classifier");
 
 #define CLS_BPF_NAME_LEN       256
+#define CLS_BPF_SUPPORTED_GEN_FLAGS            \
+       TCA_CLS_FLAGS_SKIP_HW
 
 struct cls_bpf_head {
        struct list_head plist;
@@ -40,6 +42,7 @@ struct cls_bpf_prog {
        struct tcf_result res;
        bool exts_integrated;
        bool offloaded;
+       u32 gen_flags;
        struct tcf_exts exts;
        u32 handle;
        union {
@@ -55,6 +58,7 @@ struct cls_bpf_prog {
 static const struct nla_policy bpf_policy[TCA_BPF_MAX + 1] = {
        [TCA_BPF_CLASSID]       = { .type = NLA_U32 },
        [TCA_BPF_FLAGS]         = { .type = NLA_U32 },
+       [TCA_BPF_FLAGS_GEN]     = { .type = NLA_U32 },
        [TCA_BPF_FD]            = { .type = NLA_U32 },
        [TCA_BPF_NAME]          = { .type = NLA_NUL_STRING,
                                    .len = CLS_BPF_NAME_LEN },
@@ -154,6 +158,7 @@ static int cls_bpf_offload_cmd(struct tcf_proto *tp, struct cls_bpf_prog *prog,
        bpf_offload.prog = prog->filter;
        bpf_offload.name = prog->bpf_name;
        bpf_offload.exts_integrated = prog->exts_integrated;
+       bpf_offload.gen_flags = prog->gen_flags;
 
        return dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle,
                                             tp->protocol, &offload);
@@ -167,14 +172,14 @@ static void cls_bpf_offload(struct tcf_proto *tp, struct cls_bpf_prog *prog,
        enum tc_clsbpf_command cmd;
 
        if (oldprog && oldprog->offloaded) {
-               if (tc_should_offload(dev, tp, 0)) {
+               if (tc_should_offload(dev, tp, prog->gen_flags)) {
                        cmd = TC_CLSBPF_REPLACE;
                } else {
                        obj = oldprog;
                        cmd = TC_CLSBPF_DESTROY;
                }
        } else {
-               if (!tc_should_offload(dev, tp, 0))
+               if (!tc_should_offload(dev, tp, prog->gen_flags))
                        return;
                cmd = TC_CLSBPF_ADD;
        }
@@ -370,6 +375,7 @@ static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp,
 {
        bool is_bpf, is_ebpf, have_exts = false;
        struct tcf_exts exts;
+       u32 gen_flags = 0;
        int ret;
 
        is_bpf = tb[TCA_BPF_OPS_LEN] && tb[TCA_BPF_OPS];
@@ -394,8 +400,17 @@ static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp,
 
                have_exts = bpf_flags & TCA_BPF_FLAG_ACT_DIRECT;
        }
+       if (tb[TCA_BPF_FLAGS_GEN]) {
+               gen_flags = nla_get_u32(tb[TCA_BPF_FLAGS_GEN]);
+               if (gen_flags & ~CLS_BPF_SUPPORTED_GEN_FLAGS ||
+                   !tc_flags_valid(gen_flags)) {
+                       ret = -EINVAL;
+                       goto errout;
+               }
+       }
 
        prog->exts_integrated = have_exts;
+       prog->gen_flags = gen_flags;
 
        ret = is_bpf ? cls_bpf_prog_from_ops(tb, prog) :
                       cls_bpf_prog_from_efd(tb, prog, tp);
@@ -568,6 +583,9 @@ static int cls_bpf_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
                bpf_flags |= TCA_BPF_FLAG_ACT_DIRECT;
        if (bpf_flags && nla_put_u32(skb, TCA_BPF_FLAGS, bpf_flags))
                goto nla_put_failure;
+       if (prog->gen_flags &&
+           nla_put_u32(skb, TCA_BPF_FLAGS_GEN, prog->gen_flags))
+               goto nla_put_failure;
 
        nla_nest_end(skb, nest);