Skip to content

Commit 6a773a1

Browse files
Brenden Blancodavem330
Brenden Blanco
authored andcommitted
bpf: add XDP prog type for early driver filter
Add a new bpf prog type that is intended to run in early stages of the packet rx path. Only minimal packet metadata will be available, hence a new context type, struct xdp_md, is exposed to userspace. So far only expose the packet start and end pointers, and only in read mode. An XDP program must return one of the well known enum values, all other return codes are reserved for future use. Unfortunately, this restriction is hard to enforce at verification time, so take the approach of warning at runtime when such programs are encountered. Out of bounds return codes should alias to XDP_ABORTED. Signed-off-by: Brenden Blanco <[email protected]> Acked-by: Alexei Starovoitov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 59d3656 commit 6a773a1

File tree

4 files changed

+118
-0
lines changed

4 files changed

+118
-0
lines changed

include/linux/filter.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,11 @@ struct bpf_skb_data_end {
368368
void *data_end;
369369
};
370370

371+
struct xdp_buff {
372+
void *data;
373+
void *data_end;
374+
};
375+
371376
/* compute the linear packet data range [data, data_end) which
372377
* will be accessed by cls_bpf and act_bpf programs
373378
*/
@@ -429,6 +434,18 @@ static inline u32 bpf_prog_run_clear_cb(const struct bpf_prog *prog,
429434
return BPF_PROG_RUN(prog, skb);
430435
}
431436

437+
static inline u32 bpf_prog_run_xdp(const struct bpf_prog *prog,
438+
struct xdp_buff *xdp)
439+
{
440+
u32 ret;
441+
442+
rcu_read_lock();
443+
ret = BPF_PROG_RUN(prog, (void *)xdp);
444+
rcu_read_unlock();
445+
446+
return ret;
447+
}
448+
432449
static inline unsigned int bpf_prog_size(unsigned int proglen)
433450
{
434451
return max(sizeof(struct bpf_prog),
@@ -509,6 +526,7 @@ bool bpf_helper_changes_skb_data(void *func);
509526

510527
struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
511528
const struct bpf_insn *patch, u32 len);
529+
void bpf_warn_invalid_xdp_action(u32 act);
512530

513531
#ifdef CONFIG_BPF_JIT
514532
extern int bpf_jit_enable;

include/uapi/linux/bpf.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ enum bpf_prog_type {
9494
BPF_PROG_TYPE_SCHED_CLS,
9595
BPF_PROG_TYPE_SCHED_ACT,
9696
BPF_PROG_TYPE_TRACEPOINT,
97+
BPF_PROG_TYPE_XDP,
9798
};
9899

99100
#define BPF_PSEUDO_MAP_FD 1
@@ -439,4 +440,23 @@ struct bpf_tunnel_key {
439440
__u32 tunnel_label;
440441
};
441442

443+
/* User return codes for XDP prog type.
444+
* A valid XDP program must return one of these defined values. All other
445+
* return codes are reserved for future use. Unknown return codes will result
446+
* in packet drop.
447+
*/
448+
enum xdp_action {
449+
XDP_ABORTED = 0,
450+
XDP_DROP,
451+
XDP_PASS,
452+
};
453+
454+
/* user accessible metadata for XDP packet hook
455+
* new fields must be added to the end of this structure
456+
*/
457+
struct xdp_md {
458+
__u32 data;
459+
__u32 data_end;
460+
};
461+
442462
#endif /* _UAPI__LINUX_BPF_H__ */

kernel/bpf/verifier.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,7 @@ static int check_ptr_alignment(struct verifier_env *env, struct reg_state *reg,
713713
switch (env->prog->type) {
714714
case BPF_PROG_TYPE_SCHED_CLS:
715715
case BPF_PROG_TYPE_SCHED_ACT:
716+
case BPF_PROG_TYPE_XDP:
716717
break;
717718
default:
718719
verbose("verifier is misconfigured\n");

net/core/filter.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2410,6 +2410,12 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)
24102410
}
24112411
}
24122412

2413+
static const struct bpf_func_proto *
2414+
xdp_func_proto(enum bpf_func_id func_id)
2415+
{
2416+
return sk_filter_func_proto(func_id);
2417+
}
2418+
24132419
static bool __is_valid_access(int off, int size, enum bpf_access_type type)
24142420
{
24152421
if (off < 0 || off >= sizeof(struct __sk_buff))
@@ -2477,6 +2483,44 @@ static bool tc_cls_act_is_valid_access(int off, int size,
24772483
return __is_valid_access(off, size, type);
24782484
}
24792485

2486+
static bool __is_valid_xdp_access(int off, int size,
2487+
enum bpf_access_type type)
2488+
{
2489+
if (off < 0 || off >= sizeof(struct xdp_md))
2490+
return false;
2491+
if (off % size != 0)
2492+
return false;
2493+
if (size != 4)
2494+
return false;
2495+
2496+
return true;
2497+
}
2498+
2499+
static bool xdp_is_valid_access(int off, int size,
2500+
enum bpf_access_type type,
2501+
enum bpf_reg_type *reg_type)
2502+
{
2503+
if (type == BPF_WRITE)
2504+
return false;
2505+
2506+
switch (off) {
2507+
case offsetof(struct xdp_md, data):
2508+
*reg_type = PTR_TO_PACKET;
2509+
break;
2510+
case offsetof(struct xdp_md, data_end):
2511+
*reg_type = PTR_TO_PACKET_END;
2512+
break;
2513+
}
2514+
2515+
return __is_valid_xdp_access(off, size, type);
2516+
}
2517+
2518+
void bpf_warn_invalid_xdp_action(u32 act)
2519+
{
2520+
WARN_ONCE(1, "Illegal XDP return value %u, expect packet loss\n", act);
2521+
}
2522+
EXPORT_SYMBOL_GPL(bpf_warn_invalid_xdp_action);
2523+
24802524
static u32 bpf_net_convert_ctx_access(enum bpf_access_type type, int dst_reg,
24812525
int src_reg, int ctx_off,
24822526
struct bpf_insn *insn_buf,
@@ -2628,6 +2672,29 @@ static u32 bpf_net_convert_ctx_access(enum bpf_access_type type, int dst_reg,
26282672
return insn - insn_buf;
26292673
}
26302674

2675+
static u32 xdp_convert_ctx_access(enum bpf_access_type type, int dst_reg,
2676+
int src_reg, int ctx_off,
2677+
struct bpf_insn *insn_buf,
2678+
struct bpf_prog *prog)
2679+
{
2680+
struct bpf_insn *insn = insn_buf;
2681+
2682+
switch (ctx_off) {
2683+
case offsetof(struct xdp_md, data):
2684+
*insn++ = BPF_LDX_MEM(bytes_to_bpf_size(FIELD_SIZEOF(struct xdp_buff, data)),
2685+
dst_reg, src_reg,
2686+
offsetof(struct xdp_buff, data));
2687+
break;
2688+
case offsetof(struct xdp_md, data_end):
2689+
*insn++ = BPF_LDX_MEM(bytes_to_bpf_size(FIELD_SIZEOF(struct xdp_buff, data_end)),
2690+
dst_reg, src_reg,
2691+
offsetof(struct xdp_buff, data_end));
2692+
break;
2693+
}
2694+
2695+
return insn - insn_buf;
2696+
}
2697+
26312698
static const struct bpf_verifier_ops sk_filter_ops = {
26322699
.get_func_proto = sk_filter_func_proto,
26332700
.is_valid_access = sk_filter_is_valid_access,
@@ -2640,6 +2707,12 @@ static const struct bpf_verifier_ops tc_cls_act_ops = {
26402707
.convert_ctx_access = bpf_net_convert_ctx_access,
26412708
};
26422709

2710+
static const struct bpf_verifier_ops xdp_ops = {
2711+
.get_func_proto = xdp_func_proto,
2712+
.is_valid_access = xdp_is_valid_access,
2713+
.convert_ctx_access = xdp_convert_ctx_access,
2714+
};
2715+
26432716
static struct bpf_prog_type_list sk_filter_type __read_mostly = {
26442717
.ops = &sk_filter_ops,
26452718
.type = BPF_PROG_TYPE_SOCKET_FILTER,
@@ -2655,11 +2728,17 @@ static struct bpf_prog_type_list sched_act_type __read_mostly = {
26552728
.type = BPF_PROG_TYPE_SCHED_ACT,
26562729
};
26572730

2731+
static struct bpf_prog_type_list xdp_type __read_mostly = {
2732+
.ops = &xdp_ops,
2733+
.type = BPF_PROG_TYPE_XDP,
2734+
};
2735+
26582736
static int __init register_sk_filter_ops(void)
26592737
{
26602738
bpf_register_prog_type(&sk_filter_type);
26612739
bpf_register_prog_type(&sched_cls_type);
26622740
bpf_register_prog_type(&sched_act_type);
2741+
bpf_register_prog_type(&xdp_type);
26632742

26642743
return 0;
26652744
}

0 commit comments

Comments
 (0)