Commit 6547f424 authored by Daniel Borkmann's avatar Daniel Borkmann

Merge branch 'bpf-offload-fixes'

Jakub Kicinski says:

====================
This series addresses some late comments and moves checking if program
has been loaded for the correct device to the drivers.  There are also
some problems with net namespaces which I didn't take into consideration.
On the kernel side we will now simply ignore namespace moves.  Since the
user space API is not reporting any namespace identification we have to
remove the ifindex until a correct way of reporting is agreed upon.

v2:
 - fix ext ack reporting for XDP (David A);
 - add Jiri's Ack.
====================
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
parents 32a72bbd 14380194
...@@ -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) {
return -EINVAL; struct bpf_dev_offload *offload = prog->aux->offload;
if (!offload)
return -EINVAL;
if (offload->netdev != nn->dp.netdev)
return -EINVAL;
}
if (prog && old_prog) { if (prog && old_prog) {
u8 cap; u8 cap;
......
...@@ -334,9 +334,8 @@ extern const struct bpf_verifier_ops tc_cls_act_analyzer_ops; ...@@ -334,9 +334,8 @@ extern const struct bpf_verifier_ops tc_cls_act_analyzer_ops;
extern const struct bpf_verifier_ops xdp_analyzer_ops; 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_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);
...@@ -425,15 +424,9 @@ static inline struct bpf_prog *bpf_prog_get(u32 ufd) ...@@ -425,15 +424,9 @@ static inline struct bpf_prog *bpf_prog_get(u32 ufd)
return ERR_PTR(-EOPNOTSUPP); return ERR_PTR(-EOPNOTSUPP);
} }
static inline struct bpf_prog *bpf_prog_get_type(u32 ufd,
enum bpf_prog_type type)
{
return ERR_PTR(-EOPNOTSUPP);
}
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);
} }
...@@ -514,9 +507,14 @@ static inline int cpu_map_enqueue(struct bpf_cpu_map_entry *rcpu, ...@@ -514,9 +507,14 @@ static inline int cpu_map_enqueue(struct bpf_cpu_map_entry *rcpu,
} }
#endif /* CONFIG_BPF_SYSCALL */ #endif /* CONFIG_BPF_SYSCALL */
static inline struct bpf_prog *bpf_prog_get_type(u32 ufd,
enum bpf_prog_type type)
{
return bpf_prog_get_type_dev(ufd, type, false);
}
int bpf_prog_offload_compile(struct bpf_prog *prog); int bpf_prog_offload_compile(struct bpf_prog *prog);
void bpf_prog_offload_destroy(struct bpf_prog *prog); void bpf_prog_offload_destroy(struct bpf_prog *prog);
u32 bpf_prog_offload_ifindex(struct bpf_prog *prog);
#if defined(CONFIG_NET) && defined(CONFIG_BPF_SYSCALL) #if defined(CONFIG_NET) && defined(CONFIG_BPF_SYSCALL)
int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr); int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr);
......
...@@ -171,7 +171,7 @@ static inline struct bpf_reg_state *cur_regs(struct bpf_verifier_env *env) ...@@ -171,7 +171,7 @@ static inline struct bpf_reg_state *cur_regs(struct bpf_verifier_env *env)
#if defined(CONFIG_NET) && defined(CONFIG_BPF_SYSCALL) #if defined(CONFIG_NET) && defined(CONFIG_BPF_SYSCALL)
int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env); int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env);
#else #else
int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env) static inline int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env)
{ {
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
......
...@@ -262,7 +262,7 @@ union bpf_attr { ...@@ -262,7 +262,7 @@ union bpf_attr {
__u32 kern_version; /* checked when prog_type=kprobe */ __u32 kern_version; /* checked when prog_type=kprobe */
__u32 prog_flags; __u32 prog_flags;
char prog_name[BPF_OBJ_NAME_LEN]; char prog_name[BPF_OBJ_NAME_LEN];
__u32 prog_target_ifindex; /* ifindex of netdev to prep for */ __u32 prog_ifindex; /* ifindex of netdev to prep for */
}; };
struct { /* anonymous struct used by BPF_OBJ_* commands */ struct { /* anonymous struct used by BPF_OBJ_* commands */
...@@ -897,10 +897,6 @@ enum sk_action { ...@@ -897,10 +897,6 @@ enum sk_action {
#define BPF_TAG_SIZE 8 #define BPF_TAG_SIZE 8
enum bpf_prog_status {
BPF_PROG_STATUS_DEV_BOUND = (1 << 0),
};
struct bpf_prog_info { struct bpf_prog_info {
__u32 type; __u32 type;
__u32 id; __u32 id;
...@@ -914,8 +910,6 @@ struct bpf_prog_info { ...@@ -914,8 +910,6 @@ struct bpf_prog_info {
__u32 nr_map_ids; __u32 nr_map_ids;
__aligned_u64 map_ids; __aligned_u64 map_ids;
char name[BPF_OBJ_NAME_LEN]; char name[BPF_OBJ_NAME_LEN];
__u32 ifindex;
__u32 status;
} __attribute__((aligned(8))); } __attribute__((aligned(8)));
struct bpf_map_info { struct bpf_map_info {
......
...@@ -14,8 +14,9 @@ int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr) ...@@ -14,8 +14,9 @@ int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr)
struct net *net = current->nsproxy->net_ns; struct net *net = current->nsproxy->net_ns;
struct bpf_dev_offload *offload; struct bpf_dev_offload *offload;
if (!capable(CAP_SYS_ADMIN)) if (attr->prog_type != BPF_PROG_TYPE_SCHED_CLS &&
return -EPERM; attr->prog_type != BPF_PROG_TYPE_XDP)
return -EINVAL;
if (attr->prog_flags) if (attr->prog_flags)
return -EINVAL; return -EINVAL;
...@@ -28,7 +29,7 @@ int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr) ...@@ -28,7 +29,7 @@ int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr)
init_waitqueue_head(&offload->verifier_done); init_waitqueue_head(&offload->verifier_done);
rtnl_lock(); rtnl_lock();
offload->netdev = __dev_get_by_index(net, attr->prog_target_ifindex); offload->netdev = __dev_get_by_index(net, attr->prog_ifindex);
if (!offload->netdev) { if (!offload->netdev) {
rtnl_unlock(); rtnl_unlock();
kfree(offload); kfree(offload);
...@@ -85,6 +86,10 @@ static void __bpf_prog_offload_destroy(struct bpf_prog *prog) ...@@ -85,6 +86,10 @@ static void __bpf_prog_offload_destroy(struct bpf_prog *prog)
struct bpf_dev_offload *offload = prog->aux->offload; struct bpf_dev_offload *offload = prog->aux->offload;
struct netdev_bpf data = {}; struct netdev_bpf data = {};
/* Caution - if netdev is destroyed before the program, this function
* will be called twice.
*/
data.offload.prog = prog; data.offload.prog = prog;
if (offload->verifier_running) if (offload->verifier_running)
...@@ -144,18 +149,6 @@ int bpf_prog_offload_compile(struct bpf_prog *prog) ...@@ -144,18 +149,6 @@ int bpf_prog_offload_compile(struct bpf_prog *prog)
return bpf_prog_offload_translate(prog); return bpf_prog_offload_translate(prog);
} }
u32 bpf_prog_offload_ifindex(struct bpf_prog *prog)
{
struct bpf_dev_offload *offload = prog->aux->offload;
u32 ifindex;
rtnl_lock();
ifindex = offload->netdev ? offload->netdev->ifindex : 0;
rtnl_unlock();
return ifindex;
}
const struct bpf_prog_ops bpf_offload_prog_ops = { const struct bpf_prog_ops bpf_offload_prog_ops = {
}; };
...@@ -169,6 +162,10 @@ static int bpf_offload_notification(struct notifier_block *notifier, ...@@ -169,6 +162,10 @@ static int bpf_offload_notification(struct notifier_block *notifier,
switch (event) { switch (event) {
case NETDEV_UNREGISTER: case NETDEV_UNREGISTER:
/* ignore namespace changes */
if (netdev->reg_state != NETREG_UNREGISTERING)
break;
list_for_each_entry_safe(offload, tmp, &bpf_prog_offload_devs, list_for_each_entry_safe(offload, tmp, &bpf_prog_offload_devs,
offloads) { offloads) {
if (offload->netdev == netdev) if (offload->netdev == netdev)
......
...@@ -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,23 +1094,13 @@ static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type, ...@@ -1093,23 +1094,13 @@ 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 *prog = __bpf_prog_get(ufd, &type, NULL);
if (!IS_ERR(prog))
trace_bpf_prog_get_type(prog);
return prog;
}
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);
...@@ -1118,7 +1109,7 @@ struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type, ...@@ -1118,7 +1109,7 @@ struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type,
EXPORT_SYMBOL_GPL(bpf_prog_get_type_dev); EXPORT_SYMBOL_GPL(bpf_prog_get_type_dev);
/* last field in 'union bpf_attr' used by this command */ /* last field in 'union bpf_attr' used by this command */
#define BPF_PROG_LOAD_LAST_FIELD prog_target_ifindex #define BPF_PROG_LOAD_LAST_FIELD prog_ifindex
static int bpf_prog_load(union bpf_attr *attr) static int bpf_prog_load(union bpf_attr *attr)
{ {
...@@ -1181,7 +1172,7 @@ static int bpf_prog_load(union bpf_attr *attr) ...@@ -1181,7 +1172,7 @@ static int bpf_prog_load(union bpf_attr *attr)
atomic_set(&prog->aux->refcnt, 1); atomic_set(&prog->aux->refcnt, 1);
prog->gpl_compatible = is_gpl ? 1 : 0; prog->gpl_compatible = is_gpl ? 1 : 0;
if (attr->prog_target_ifindex) { if (attr->prog_ifindex) {
err = bpf_prog_offload_init(prog, attr); err = bpf_prog_offload_init(prog, attr);
if (err) if (err)
goto free_prog; goto free_prog;
...@@ -1625,11 +1616,6 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, ...@@ -1625,11 +1616,6 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
return -EFAULT; return -EFAULT;
} }
if (bpf_prog_is_dev_bound(prog->aux)) {
info.status |= BPF_PROG_STATUS_DEV_BOUND;
info.ifindex = bpf_prog_offload_ifindex(prog);
}
done: done:
if (copy_to_user(uinfo, &info, info_len) || if (copy_to_user(uinfo, &info, info_len) ||
put_user(info_len, &uattr->info.info_len)) put_user(info_len, &uattr->info.info_len))
......
...@@ -7139,13 +7139,17 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack, ...@@ -7139,13 +7139,17 @@ 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, bpf_op == ops->ndo_bpf);
dev);
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);
if (!(flags & XDP_FLAGS_HW_MODE) &&
bpf_prog_is_dev_bound(prog->aux)) {
NL_SET_ERR_MSG(extack, "using device-bound program without HW_MODE flag is not supported");
bpf_prog_put(prog);
return -EINVAL;
}
} }
err = dev_xdp_install(dev, bpf_op, extack, flags, prog); err = dev_xdp_install(dev, bpf_op, extack, flags, 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);
......
...@@ -41,7 +41,6 @@ ...@@ -41,7 +41,6 @@
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include <net/if.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
...@@ -230,21 +229,6 @@ static void print_prog_json(struct bpf_prog_info *info, int fd) ...@@ -230,21 +229,6 @@ static void print_prog_json(struct bpf_prog_info *info, int fd)
info->tag[0], info->tag[1], info->tag[2], info->tag[3], info->tag[0], info->tag[1], info->tag[2], info->tag[3],
info->tag[4], info->tag[5], info->tag[6], info->tag[7]); info->tag[4], info->tag[5], info->tag[6], info->tag[7]);
if (info->status & BPF_PROG_STATUS_DEV_BOUND) {
jsonw_name(json_wtr, "dev");
if (info->ifindex) {
char name[IF_NAMESIZE];
if (!if_indextoname(info->ifindex, name))
jsonw_printf(json_wtr, "\"ifindex:%d\"",
info->ifindex);
else
jsonw_printf(json_wtr, "\"%s\"", name);
} else {
jsonw_printf(json_wtr, "\"unknown\"");
}
}
if (info->load_time) { if (info->load_time) {
char buf[32]; char buf[32];
...@@ -302,21 +286,6 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd) ...@@ -302,21 +286,6 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd)
printf("tag "); printf("tag ");
fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); fprint_hex(stdout, info->tag, BPF_TAG_SIZE, "");
printf(" ");
if (info->status & BPF_PROG_STATUS_DEV_BOUND) {
printf("dev ");
if (info->ifindex) {
char name[IF_NAMESIZE];
if (!if_indextoname(info->ifindex, name))
printf("ifindex:%d ", info->ifindex);
else
printf("%s ", name);
} else {
printf("unknown ");
}
}
printf("\n"); printf("\n");
if (info->load_time) { if (info->load_time) {
......
...@@ -262,7 +262,7 @@ union bpf_attr { ...@@ -262,7 +262,7 @@ union bpf_attr {
__u32 kern_version; /* checked when prog_type=kprobe */ __u32 kern_version; /* checked when prog_type=kprobe */
__u32 prog_flags; __u32 prog_flags;
char prog_name[BPF_OBJ_NAME_LEN]; char prog_name[BPF_OBJ_NAME_LEN];
__u32 prog_target_ifindex; /* ifindex of netdev to prep for */ __u32 prog_ifindex; /* ifindex of netdev to prep for */
}; };
struct { /* anonymous struct used by BPF_OBJ_* commands */ struct { /* anonymous struct used by BPF_OBJ_* commands */
...@@ -897,10 +897,6 @@ enum sk_action { ...@@ -897,10 +897,6 @@ enum sk_action {
#define BPF_TAG_SIZE 8 #define BPF_TAG_SIZE 8
enum bpf_prog_status {
BPF_PROG_STATUS_DEV_BOUND = (1 << 0),
};
struct bpf_prog_info { struct bpf_prog_info {
__u32 type; __u32 type;
__u32 id; __u32 id;
...@@ -914,8 +910,6 @@ struct bpf_prog_info { ...@@ -914,8 +910,6 @@ struct bpf_prog_info {
__u32 nr_map_ids; __u32 nr_map_ids;
__aligned_u64 map_ids; __aligned_u64 map_ids;
char name[BPF_OBJ_NAME_LEN]; char name[BPF_OBJ_NAME_LEN];
__u32 ifindex;
__u32 status;
} __attribute__((aligned(8))); } __attribute__((aligned(8)));
struct bpf_map_info { struct bpf_map_info {
......
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