Commit 288b3de5 authored by Jakub Kicinski's avatar Jakub Kicinski Committed by Daniel Borkmann

bpf: offload: move offload device validation out to the drivers

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: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: default avatarQuentin Monnet <quentin.monnet@netronome.com>
Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
Acked-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
parent 1f6f4cb7
...@@ -214,8 +214,14 @@ int nfp_net_bpf_offload(struct nfp_net *nn, struct bpf_prog *prog, ...@@ -214,8 +214,14 @@ int nfp_net_bpf_offload(struct nfp_net *nn, struct bpf_prog *prog,
{ {
int err; int err;
if (prog && !prog->aux->offload) if (prog) {
struct bpf_dev_offload *offload = prog->aux->offload;
if (!offload)
return -EINVAL;
if (offload->netdev != nn->dp.netdev)
return -EINVAL; return -EINVAL;
}
if (prog && old_prog) { if (prog && old_prog) {
u8 cap; u8 cap;
......
...@@ -336,7 +336,7 @@ extern const struct bpf_verifier_ops xdp_analyzer_ops; ...@@ -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(u32 ufd);
struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type); 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 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); struct bpf_prog * __must_check bpf_prog_add(struct bpf_prog *prog, int i);
void bpf_prog_sub(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); 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, ...@@ -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, static inline struct bpf_prog *bpf_prog_get_type_dev(u32 ufd,
enum bpf_prog_type type, enum bpf_prog_type type,
struct net_device *netdev) bool attach_drv)
{ {
return ERR_PTR(-EOPNOTSUPP); return ERR_PTR(-EOPNOTSUPP);
} }
......
...@@ -1057,22 +1057,23 @@ struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog) ...@@ -1057,22 +1057,23 @@ struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog)
} }
EXPORT_SYMBOL_GPL(bpf_prog_inc_not_zero); EXPORT_SYMBOL_GPL(bpf_prog_inc_not_zero);
static bool bpf_prog_can_attach(struct bpf_prog *prog, static bool bpf_prog_get_ok(struct bpf_prog *prog,
enum bpf_prog_type *attach_type, enum bpf_prog_type *attach_type, bool attach_drv)
struct net_device *netdev)
{ {
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) if (prog->type != *attach_type)
return false; return false;
if (offload && offload->netdev != netdev) if (bpf_prog_is_dev_bound(prog->aux) && !attach_drv)
return false; return false;
return true; return true;
} }
static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type, 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 fd f = fdget(ufd);
struct bpf_prog *prog; struct bpf_prog *prog;
...@@ -1080,7 +1081,7 @@ static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type, ...@@ -1080,7 +1081,7 @@ static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type,
prog = ____bpf_prog_get(f); prog = ____bpf_prog_get(f);
if (IS_ERR(prog)) if (IS_ERR(prog))
return 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); prog = ERR_PTR(-EINVAL);
goto out; goto out;
} }
...@@ -1093,12 +1094,12 @@ static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type, ...@@ -1093,12 +1094,12 @@ static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type,
struct bpf_prog *bpf_prog_get(u32 ufd) 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 *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)) if (!IS_ERR(prog))
trace_bpf_prog_get_type(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) ...@@ -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); EXPORT_SYMBOL_GPL(bpf_prog_get_type);
struct bpf_prog *bpf_prog_get_type_dev(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 *prog = __bpf_prog_get(ufd, &type, netdev); struct bpf_prog *prog = __bpf_prog_get(ufd, &type, attach_drv);
if (!IS_ERR(prog)) if (!IS_ERR(prog))
trace_bpf_prog_get_type(prog); trace_bpf_prog_get_type(prog);
......
...@@ -7139,11 +7139,8 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack, ...@@ -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)) __dev_xdp_attached(dev, bpf_op, NULL))
return -EBUSY; return -EBUSY;
if (bpf_op == ops->ndo_bpf)
prog = bpf_prog_get_type_dev(fd, BPF_PROG_TYPE_XDP, prog = bpf_prog_get_type_dev(fd, BPF_PROG_TYPE_XDP,
dev); bpf_op == ops->ndo_bpf);
else
prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_XDP);
if (IS_ERR(prog)) if (IS_ERR(prog))
return PTR_ERR(prog); return PTR_ERR(prog);
} }
......
...@@ -382,15 +382,13 @@ static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog, ...@@ -382,15 +382,13 @@ static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog,
{ {
struct bpf_prog *fp; struct bpf_prog *fp;
char *name = NULL; char *name = NULL;
bool skip_sw;
u32 bpf_fd; u32 bpf_fd;
bpf_fd = nla_get_u32(tb[TCA_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, 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);
if (IS_ERR(fp)) if (IS_ERR(fp))
return PTR_ERR(fp); return PTR_ERR(fp);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment