Skip to content

Commit

Permalink
Merge branch 'bpf-offload-fixes'
Browse files Browse the repository at this point in the history
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: Daniel Borkmann <daniel@iogearbox.net>
  • Loading branch information
Daniel Borkmann committed Nov 20, 2017
2 parents 32a72bb + 1438019 commit 6547f42
Show file tree
Hide file tree
Showing 10 changed files with 56 additions and 110 deletions.
10 changes: 8 additions & 2 deletions drivers/net/ethernet/netronome/nfp/bpf/offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
18 changes: 8 additions & 10 deletions include/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -334,9 +334,8 @@ extern const struct bpf_verifier_ops tc_cls_act_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_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);
Expand Down Expand Up @@ -425,15 +424,9 @@ static inline struct bpf_prog *bpf_prog_get(u32 ufd)
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,
enum bpf_prog_type type,
struct net_device *netdev)
bool attach_drv)
{
return ERR_PTR(-EOPNOTSUPP);
}
Expand Down Expand Up @@ -514,9 +507,14 @@ static inline int cpu_map_enqueue(struct bpf_cpu_map_entry *rcpu,
}
#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);
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)
int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr);
Expand Down
2 changes: 1 addition & 1 deletion include/linux/bpf_verifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env);
#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;
}
Expand Down
8 changes: 1 addition & 7 deletions include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ union bpf_attr {
__u32 kern_version; /* checked when prog_type=kprobe */
__u32 prog_flags;
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 */
Expand Down Expand Up @@ -897,10 +897,6 @@ enum sk_action {

#define BPF_TAG_SIZE 8

enum bpf_prog_status {
BPF_PROG_STATUS_DEV_BOUND = (1 << 0),
};

struct bpf_prog_info {
__u32 type;
__u32 id;
Expand All @@ -914,8 +910,6 @@ struct bpf_prog_info {
__u32 nr_map_ids;
__aligned_u64 map_ids;
char name[BPF_OBJ_NAME_LEN];
__u32 ifindex;
__u32 status;
} __attribute__((aligned(8)));

struct bpf_map_info {
Expand Down
27 changes: 12 additions & 15 deletions kernel/bpf/offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 bpf_dev_offload *offload;

if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (attr->prog_type != BPF_PROG_TYPE_SCHED_CLS &&
attr->prog_type != BPF_PROG_TYPE_XDP)
return -EINVAL;

if (attr->prog_flags)
return -EINVAL;
Expand All @@ -28,7 +29,7 @@ int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr)
init_waitqueue_head(&offload->verifier_done);

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) {
rtnl_unlock();
kfree(offload);
Expand Down Expand Up @@ -85,6 +86,10 @@ static void __bpf_prog_offload_destroy(struct bpf_prog *prog)
struct bpf_dev_offload *offload = prog->aux->offload;
struct netdev_bpf data = {};

/* Caution - if netdev is destroyed before the program, this function
* will be called twice.
*/

data.offload.prog = prog;

if (offload->verifier_running)
Expand Down Expand Up @@ -144,18 +149,6 @@ int bpf_prog_offload_compile(struct bpf_prog *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 = {
};

Expand All @@ -169,6 +162,10 @@ static int bpf_offload_notification(struct notifier_block *notifier,

switch (event) {
case NETDEV_UNREGISTER:
/* ignore namespace changes */
if (netdev->reg_state != NETREG_UNREGISTERING)
break;

list_for_each_entry_safe(offload, tmp, &bpf_prog_offload_devs,
offloads) {
if (offload->netdev == netdev)
Expand Down
40 changes: 13 additions & 27 deletions kernel/bpf/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -1057,30 +1057,31 @@ 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;

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;
}
Expand All @@ -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)
{
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 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);
Expand All @@ -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);

/* 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)
{
Expand Down Expand Up @@ -1181,7 +1172,7 @@ static int bpf_prog_load(union bpf_attr *attr)
atomic_set(&prog->aux->refcnt, 1);
prog->gpl_compatible = is_gpl ? 1 : 0;

if (attr->prog_target_ifindex) {
if (attr->prog_ifindex) {
err = bpf_prog_offload_init(prog, attr);
if (err)
goto free_prog;
Expand Down Expand Up @@ -1625,11 +1616,6 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
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:
if (copy_to_user(uinfo, &info, info_len) ||
put_user(info_len, &uattr->info.info_len))
Expand Down
14 changes: 9 additions & 5 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
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);

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);
Expand Down
8 changes: 3 additions & 5 deletions net/sched/cls_bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
31 changes: 0 additions & 31 deletions tools/bpf/bpftool/prog.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/stat.h>

Expand Down Expand Up @@ -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[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) {
char buf[32];

Expand Down Expand Up @@ -302,21 +286,6 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd)

printf("tag ");
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");

if (info->load_time) {
Expand Down
8 changes: 1 addition & 7 deletions tools/include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ union bpf_attr {
__u32 kern_version; /* checked when prog_type=kprobe */
__u32 prog_flags;
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 */
Expand Down Expand Up @@ -897,10 +897,6 @@ enum sk_action {

#define BPF_TAG_SIZE 8

enum bpf_prog_status {
BPF_PROG_STATUS_DEV_BOUND = (1 << 0),
};

struct bpf_prog_info {
__u32 type;
__u32 id;
Expand All @@ -914,8 +910,6 @@ struct bpf_prog_info {
__u32 nr_map_ids;
__aligned_u64 map_ids;
char name[BPF_OBJ_NAME_LEN];
__u32 ifindex;
__u32 status;
} __attribute__((aligned(8)));

struct bpf_map_info {
Expand Down

0 comments on commit 6547f42

Please sign in to comment.