]> git.baikalelectronics.ru Git - kernel.git/commitdiff
bpf: offload: move offload device validation out to the drivers
authorJakub Kicinski <jakub.kicinski@netronome.com>
Mon, 20 Nov 2017 23:21:54 +0000 (15:21 -0800)
committerDaniel Borkmann <daniel@iogearbox.net>
Mon, 20 Nov 2017 23:37:35 +0000 (00:37 +0100)
With TC shared block changes we can't depend on correct netdev
pointer being available in cls_bpf.  Move the device validation
to the driver.  Core will only make sure that offloaded programs
are always attached in the driver (or in HW by the driver).  We
trust that drivers which implement offload callbacks will perform
necessary checks.

Moving the checks to the driver is generally a useful thing,
in practice the check should be against a switchdev instance,
not a netdev, given that most ASICs will probably allow using
the same program on many ports.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
drivers/net/ethernet/netronome/nfp/bpf/offload.c
include/linux/bpf.h
kernel/bpf/syscall.c
net/core/dev.c
net/sched/cls_bpf.c

index b6cee71f49d3d4a0b68afeda4d879f2cd12de5f6..bc879aeb62d4ee95a42654a78ae9329145d22b3f 100644 (file)
@@ -214,8 +214,14 @@ int nfp_net_bpf_offload(struct nfp_net *nn, struct bpf_prog *prog,
 {
        int err;
 
-       if (prog && !prog->aux->offload)
-               return -EINVAL;
+       if (prog) {
+               struct bpf_dev_offload *offload = prog->aux->offload;
+
+               if (!offload)
+                       return -EINVAL;
+               if (offload->netdev != nn->dp.netdev)
+                       return -EINVAL;
+       }
 
        if (prog && old_prog) {
                u8 cap;
index c397934f91dd78acb9b051d13f4ee4e5cbe76569..f82be640731e0ca6aef95c66959fa633e20f6a98 100644 (file)
@@ -336,7 +336,7 @@ extern const struct bpf_verifier_ops xdp_analyzer_ops;
 struct bpf_prog *bpf_prog_get(u32 ufd);
 struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type);
 struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type,
-                                      struct net_device *netdev);
+                                      bool attach_drv);
 struct bpf_prog * __must_check bpf_prog_add(struct bpf_prog *prog, int i);
 void bpf_prog_sub(struct bpf_prog *prog, int i);
 struct bpf_prog * __must_check bpf_prog_inc(struct bpf_prog *prog);
@@ -433,7 +433,7 @@ static inline struct bpf_prog *bpf_prog_get_type(u32 ufd,
 
 static inline struct bpf_prog *bpf_prog_get_type_dev(u32 ufd,
                                                     enum bpf_prog_type type,
-                                                    struct net_device *netdev)
+                                                    bool attach_drv)
 {
        return ERR_PTR(-EOPNOTSUPP);
 }
index 8e9d065bb7cd44b4ed375c743571ff98c2925493..38da55905ab09f19496f21d97148d609561a8944 100644 (file)
@@ -1057,22 +1057,23 @@ struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog)
 }
 EXPORT_SYMBOL_GPL(bpf_prog_inc_not_zero);
 
-static bool bpf_prog_can_attach(struct bpf_prog *prog,
-                               enum bpf_prog_type *attach_type,
-                               struct net_device *netdev)
+static bool bpf_prog_get_ok(struct bpf_prog *prog,
+                           enum bpf_prog_type *attach_type, bool attach_drv)
 {
-       struct bpf_dev_offload *offload = prog->aux->offload;
+       /* not an attachment, just a refcount inc, always allow */
+       if (!attach_type)
+               return true;
 
        if (prog->type != *attach_type)
                return false;
-       if (offload && offload->netdev != netdev)
+       if (bpf_prog_is_dev_bound(prog->aux) && !attach_drv)
                return false;
 
        return true;
 }
 
 static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type,
-                                      struct net_device *netdev)
+                                      bool attach_drv)
 {
        struct fd f = fdget(ufd);
        struct bpf_prog *prog;
@@ -1080,7 +1081,7 @@ static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type,
        prog = ____bpf_prog_get(f);
        if (IS_ERR(prog))
                return prog;
-       if (attach_type && !bpf_prog_can_attach(prog, attach_type, netdev)) {
+       if (!bpf_prog_get_ok(prog, attach_type, attach_drv)) {
                prog = ERR_PTR(-EINVAL);
                goto out;
        }
@@ -1093,12 +1094,12 @@ out:
 
 struct bpf_prog *bpf_prog_get(u32 ufd)
 {
-       return __bpf_prog_get(ufd, NULL, NULL);
+       return __bpf_prog_get(ufd, NULL, false);
 }
 
 struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type)
 {
-       struct bpf_prog *prog = __bpf_prog_get(ufd, &type, NULL);
+       struct bpf_prog *prog = __bpf_prog_get(ufd, &type, false);
 
        if (!IS_ERR(prog))
                trace_bpf_prog_get_type(prog);
@@ -1107,9 +1108,9 @@ struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type)
 EXPORT_SYMBOL_GPL(bpf_prog_get_type);
 
 struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type,
-                                      struct net_device *netdev)
+                                      bool attach_drv)
 {
-       struct bpf_prog *prog = __bpf_prog_get(ufd, &type, netdev);
+       struct bpf_prog *prog = __bpf_prog_get(ufd, &type, attach_drv);
 
        if (!IS_ERR(prog))
                trace_bpf_prog_get_type(prog);
index 8ee29f4f5fa91894e63734cfee3ee6909fd21b26..09525a27319c7a619c091cd96cd1b0953de0e6c2 100644 (file)
@@ -7139,11 +7139,8 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
                    __dev_xdp_attached(dev, bpf_op, NULL))
                        return -EBUSY;
 
-               if (bpf_op == ops->ndo_bpf)
-                       prog = bpf_prog_get_type_dev(fd, BPF_PROG_TYPE_XDP,
-                                                    dev);
-               else
-                       prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_XDP);
+               prog = bpf_prog_get_type_dev(fd, BPF_PROG_TYPE_XDP,
+                                            bpf_op == ops->ndo_bpf);
                if (IS_ERR(prog))
                        return PTR_ERR(prog);
        }
index fb680dafac5a2e49515ab84ecc820c592bca4ae0..a9f3e317055c46bae55568627404e2bbc2dc31d9 100644 (file)
@@ -382,15 +382,13 @@ static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog,
 {
        struct bpf_prog *fp;
        char *name = NULL;
+       bool skip_sw;
        u32 bpf_fd;
 
        bpf_fd = nla_get_u32(tb[TCA_BPF_FD]);
+       skip_sw = gen_flags & TCA_CLS_FLAGS_SKIP_SW;
 
-       if (gen_flags & TCA_CLS_FLAGS_SKIP_SW)
-               fp = bpf_prog_get_type_dev(bpf_fd, BPF_PROG_TYPE_SCHED_CLS,
-                                          qdisc_dev(tp->q));
-       else
-               fp = bpf_prog_get_type(bpf_fd, BPF_PROG_TYPE_SCHED_CLS);
+       fp = bpf_prog_get_type_dev(bpf_fd, BPF_PROG_TYPE_SCHED_CLS, skip_sw);
        if (IS_ERR(fp))
                return PTR_ERR(fp);