Skip to content

Commit

Permalink
Merge branch 'ebpf_support_for_cls_bpf'
Browse files Browse the repository at this point in the history
Daniel Borkmann says:

====================
eBPF support for cls_bpf

This is the non-RFC version of my patchset posted before netdev01 [1]
conference. It contains a couple of eBPF cleanups and preparation
patches to get eBPF support into cls_bpf. The last patch adds the
actual support. I'll post the iproute2 parts after the kernel bits
are merged, an initial preview link to the code is mentioned in the
last patch.

Patch 4 and 5 were originally one patch, but I've split them into
two parts upon request as patch 4 only is also needed for Alexei's
tracing patches that go via tip tree.

Tested with tc and all in-kernel available BPF test suites.

I have configured and built LLVM with --enable-experimental-targets=BPF
but as Alexei put it, the plan is to get rid of the experimental
status in future [2].

Thanks a lot!

v1 -> v2:
 - Removed arch patches from this series
  - x86 is already queued in tip tree, under x86/mm
  - arm64 just reposted directly to arm folks
 - Rest is unchanged

  [1] http://thread.gmane.org/gmane.linux.network/350191
  [2] http://article.gmane.org/gmane.linux.kernel/1874969
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Mar 1, 2015
2 parents b656cc6 + e2e9b65 commit 68932f7
Show file tree
Hide file tree
Showing 15 changed files with 243 additions and 193 deletions.
38 changes: 24 additions & 14 deletions include/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ struct bpf_map {
u32 key_size;
u32 value_size;
u32 max_entries;
struct bpf_map_ops *ops;
const struct bpf_map_ops *ops;
struct work_struct work;
};

struct bpf_map_type_list {
struct list_head list_node;
struct bpf_map_ops *ops;
const struct bpf_map_ops *ops;
enum bpf_map_type type;
};

Expand Down Expand Up @@ -109,37 +109,47 @@ struct bpf_verifier_ops {

struct bpf_prog_type_list {
struct list_head list_node;
struct bpf_verifier_ops *ops;
const struct bpf_verifier_ops *ops;
enum bpf_prog_type type;
};

void bpf_register_prog_type(struct bpf_prog_type_list *tl);

struct bpf_prog;

struct bpf_prog_aux {
atomic_t refcnt;
bool is_gpl_compatible;
enum bpf_prog_type prog_type;
struct bpf_verifier_ops *ops;
struct bpf_map **used_maps;
u32 used_map_cnt;
const struct bpf_verifier_ops *ops;
struct bpf_map **used_maps;
struct bpf_prog *prog;
struct work_struct work;
};

#ifdef CONFIG_BPF_SYSCALL
void bpf_register_prog_type(struct bpf_prog_type_list *tl);

void bpf_prog_put(struct bpf_prog *prog);
struct bpf_prog *bpf_prog_get(u32 ufd);
#else
static inline void bpf_prog_put(struct bpf_prog *prog) {}
static inline void bpf_register_prog_type(struct bpf_prog_type_list *tl)
{
}

static inline struct bpf_prog *bpf_prog_get(u32 ufd)
{
return ERR_PTR(-EOPNOTSUPP);
}

static inline void bpf_prog_put(struct bpf_prog *prog)
{
}
#endif
struct bpf_prog *bpf_prog_get(u32 ufd);

/* verify correctness of eBPF program */
int bpf_check(struct bpf_prog *fp, union bpf_attr *attr);

/* verifier prototypes for helper functions called from eBPF programs */
extern struct bpf_func_proto bpf_map_lookup_elem_proto;
extern struct bpf_func_proto bpf_map_update_elem_proto;
extern struct bpf_func_proto bpf_map_delete_elem_proto;
extern const struct bpf_func_proto bpf_map_lookup_elem_proto;
extern const struct bpf_func_proto bpf_map_update_elem_proto;
extern const struct bpf_func_proto bpf_map_delete_elem_proto;

#endif /* _LINUX_BPF_H */
6 changes: 3 additions & 3 deletions include/linux/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,6 @@ struct bpf_prog_aux;
.off = 0, \
.imm = ((__u64) (IMM)) >> 32 })

#define BPF_PSEUDO_MAP_FD 1

/* pseudo BPF_LD_IMM64 insn used to refer to process-local map_fd */
#define BPF_LD_MAP_FD(DST, MAP_FD) \
BPF_LD_IMM64_RAW(DST, BPF_PSEUDO_MAP_FD, MAP_FD)
Expand Down Expand Up @@ -310,9 +308,11 @@ struct bpf_binary_header {
struct bpf_prog {
u16 pages; /* Number of allocated pages */
bool jited; /* Is our filter JIT'ed? */
bool gpl_compatible; /* Is our filter GPL compatible? */
u32 len; /* Number of filter blocks */
struct sock_fprog_kern *orig_prog; /* Original BPF program */
enum bpf_prog_type type; /* Type of BPF program */
struct bpf_prog_aux *aux; /* Auxiliary fields */
struct sock_fprog_kern *orig_prog; /* Original BPF program */
unsigned int (*bpf_func)(const struct sk_buff *skb,
const struct bpf_insn *filter);
/* Instructions for interpreter */
Expand Down
3 changes: 3 additions & 0 deletions include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,11 @@ enum bpf_map_type {
enum bpf_prog_type {
BPF_PROG_TYPE_UNSPEC,
BPF_PROG_TYPE_SOCKET_FILTER,
BPF_PROG_TYPE_SCHED_CLS,
};

#define BPF_PSEUDO_MAP_FD 1

/* flags for BPF_MAP_UPDATE_ELEM command */
#define BPF_ANY 0 /* create new element or update existing */
#define BPF_NOEXIST 1 /* create new element if it didn't exist */
Expand Down
2 changes: 2 additions & 0 deletions include/uapi/linux/pkt_cls.h
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,8 @@ enum {
TCA_BPF_CLASSID,
TCA_BPF_OPS_LEN,
TCA_BPF_OPS,
TCA_BPF_FD,
TCA_BPF_NAME,
__TCA_BPF_MAX,
};

Expand Down
3 changes: 0 additions & 3 deletions kernel/bpf/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
obj-y := core.o
obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o hashtab.o arraymap.o helpers.o
ifdef CONFIG_TEST_BPF
obj-$(CONFIG_BPF_SYSCALL) += test_stub.o
endif
6 changes: 3 additions & 3 deletions kernel/bpf/arraymap.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ static void array_map_free(struct bpf_map *map)
kvfree(array);
}

static struct bpf_map_ops array_ops = {
static const struct bpf_map_ops array_ops = {
.map_alloc = array_map_alloc,
.map_free = array_map_free,
.map_get_next_key = array_map_get_next_key,
Expand All @@ -143,14 +143,14 @@ static struct bpf_map_ops array_ops = {
.map_delete_elem = array_map_delete_elem,
};

static struct bpf_map_type_list tl = {
static struct bpf_map_type_list array_type __read_mostly = {
.ops = &array_ops,
.type = BPF_MAP_TYPE_ARRAY,
};

static int __init register_array_map(void)
{
bpf_register_map_type(&tl);
bpf_register_map_type(&array_type);
return 0;
}
late_initcall(register_array_map);
6 changes: 3 additions & 3 deletions kernel/bpf/hashtab.c
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ static void htab_map_free(struct bpf_map *map)
kfree(htab);
}

static struct bpf_map_ops htab_ops = {
static const struct bpf_map_ops htab_ops = {
.map_alloc = htab_map_alloc,
.map_free = htab_map_free,
.map_get_next_key = htab_map_get_next_key,
Expand All @@ -354,14 +354,14 @@ static struct bpf_map_ops htab_ops = {
.map_delete_elem = htab_map_delete_elem,
};

static struct bpf_map_type_list tl = {
static struct bpf_map_type_list htab_type __read_mostly = {
.ops = &htab_ops,
.type = BPF_MAP_TYPE_HASH,
};

static int __init register_htab_map(void)
{
bpf_register_map_type(&tl);
bpf_register_map_type(&htab_type);
return 0;
}
late_initcall(register_htab_map);
6 changes: 3 additions & 3 deletions kernel/bpf/helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ static u64 bpf_map_lookup_elem(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
return (unsigned long) value;
}

struct bpf_func_proto bpf_map_lookup_elem_proto = {
const struct bpf_func_proto bpf_map_lookup_elem_proto = {
.func = bpf_map_lookup_elem,
.gpl_only = false,
.ret_type = RET_PTR_TO_MAP_VALUE_OR_NULL,
Expand All @@ -60,7 +60,7 @@ static u64 bpf_map_update_elem(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
return map->ops->map_update_elem(map, key, value, r4);
}

struct bpf_func_proto bpf_map_update_elem_proto = {
const struct bpf_func_proto bpf_map_update_elem_proto = {
.func = bpf_map_update_elem,
.gpl_only = false,
.ret_type = RET_INTEGER,
Expand All @@ -80,7 +80,7 @@ static u64 bpf_map_delete_elem(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
return map->ops->map_delete_elem(map, key);
}

struct bpf_func_proto bpf_map_delete_elem_proto = {
const struct bpf_func_proto bpf_map_delete_elem_proto = {
.func = bpf_map_delete_elem,
.gpl_only = false,
.ret_type = RET_INTEGER,
Expand Down
9 changes: 5 additions & 4 deletions kernel/bpf/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -354,10 +354,11 @@ static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog)
list_for_each_entry(tl, &bpf_prog_types, list_node) {
if (tl->type == type) {
prog->aux->ops = tl->ops;
prog->aux->prog_type = type;
prog->type = type;
return 0;
}
}

return -EINVAL;
}

Expand Down Expand Up @@ -418,6 +419,7 @@ void bpf_prog_put(struct bpf_prog *prog)
bpf_prog_free(prog);
}
}
EXPORT_SYMBOL_GPL(bpf_prog_put);

static int bpf_prog_release(struct inode *inode, struct file *filp)
{
Expand Down Expand Up @@ -465,6 +467,7 @@ struct bpf_prog *bpf_prog_get(u32 ufd)
fdput(f);
return prog;
}
EXPORT_SYMBOL_GPL(bpf_prog_get);

/* last field in 'union bpf_attr' used by this command */
#define BPF_PROG_LOAD_LAST_FIELD log_buf
Expand Down Expand Up @@ -508,7 +511,7 @@ static int bpf_prog_load(union bpf_attr *attr)
prog->jited = false;

atomic_set(&prog->aux->refcnt, 1);
prog->aux->is_gpl_compatible = is_gpl;
prog->gpl_compatible = is_gpl;

/* find program type: socket_filter vs tracing_filter */
err = find_prog_type(type, prog);
Expand All @@ -517,7 +520,6 @@ static int bpf_prog_load(union bpf_attr *attr)

/* run eBPF verifier */
err = bpf_check(prog, attr);

if (err < 0)
goto free_used_maps;

Expand All @@ -528,7 +530,6 @@ static int bpf_prog_load(union bpf_attr *attr)
bpf_prog_select_runtime(prog);

err = anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog, O_RDWR | O_CLOEXEC);

if (err < 0)
/* failed to allocate fd */
goto free_used_maps;
Expand Down
78 changes: 0 additions & 78 deletions kernel/bpf/test_stub.c

This file was deleted.

17 changes: 14 additions & 3 deletions kernel/bpf/verifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,7 @@ static int check_call(struct verifier_env *env, int func_id)
}

/* eBPF programs must be GPL compatible to use GPL-ed functions */
if (!env->prog->aux->is_gpl_compatible && fn->gpl_only) {
if (!env->prog->gpl_compatible && fn->gpl_only) {
verbose("cannot call GPL only function from proprietary program\n");
return -EINVAL;
}
Expand Down Expand Up @@ -1172,6 +1172,17 @@ static int check_ld_imm(struct verifier_env *env, struct bpf_insn *insn)
return 0;
}

static bool may_access_skb(enum bpf_prog_type type)
{
switch (type) {
case BPF_PROG_TYPE_SOCKET_FILTER:
case BPF_PROG_TYPE_SCHED_CLS:
return true;
default:
return false;
}
}

/* verify safety of LD_ABS|LD_IND instructions:
* - they can only appear in the programs where ctx == skb
* - since they are wrappers of function calls, they scratch R1-R5 registers,
Expand All @@ -1194,8 +1205,8 @@ static int check_ld_abs(struct verifier_env *env, struct bpf_insn *insn)
struct reg_state *reg;
int i, err;

if (env->prog->aux->prog_type != BPF_PROG_TYPE_SOCKET_FILTER) {
verbose("BPF_LD_ABS|IND instructions are only allowed in socket filters\n");
if (!may_access_skb(env->prog->type)) {
verbose("BPF_LD_ABS|IND instructions not allowed for this program type\n");
return -EINVAL;
}

Expand Down
Loading

0 comments on commit 68932f7

Please sign in to comment.