Skip to content

Commit 22c8852

Browse files
borkmanndavem330
authored andcommitted
bpf: improve selftests and add tests for meta pointer
Add various test_verifier selftests, and a simple xdp/tc functional test that is being attached to veths. Also let new versions of clang use the recently added -mcpu=probe support [1] for the BPF target, so that it can probe the underlying kernel for BPF insn set extensions. We could also just set this options always, where older versions just ignore it and give a note to the user that the -mcpu value is not supported, but given emitting the note cannot be turned off from clang side lets not confuse users running selftests with it, thus fallback to the default generic one when we see that clang doesn't support it. Also allow CPU option to be overridden in the Makefile from command line. [1] llvm-mirror/llvm@d7276a4 Signed-off-by: Daniel Borkmann <[email protected]> Acked-by: Alexei Starovoitov <[email protected]> Acked-by: John Fastabend <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ac29991 commit 22c8852

File tree

5 files changed

+370
-4
lines changed

5 files changed

+370
-4
lines changed

tools/testing/selftests/bpf/Makefile

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test
1515
test_align
1616

1717
TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \
18-
test_pkt_md_access.o test_xdp_redirect.o sockmap_parse_prog.o sockmap_verdict_prog.o
18+
test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \
19+
sockmap_verdict_prog.o
1920

20-
TEST_PROGS := test_kmod.sh test_xdp_redirect.sh
21+
TEST_PROGS := test_kmod.sh test_xdp_redirect.sh test_xdp_meta.sh
2122

2223
include ../lib.mk
2324

@@ -34,8 +35,20 @@ $(BPFOBJ): force
3435
$(MAKE) -C $(BPFDIR) OUTPUT=$(OUTPUT)/
3536

3637
CLANG ?= clang
38+
LLC ?= llc
39+
40+
PROBE := $(shell llc -march=bpf -mcpu=probe -filetype=null /dev/null 2>&1)
41+
42+
# Let newer LLVM versions transparently probe the kernel for availability
43+
# of full BPF instruction set.
44+
ifeq ($(PROBE),)
45+
CPU ?= probe
46+
else
47+
CPU ?= generic
48+
endif
3749

3850
%.o: %.c
3951
$(CLANG) -I. -I./include/uapi -I../../../include/uapi \
40-
-Wno-compare-distinct-pointer-types \
41-
-O2 -target bpf -c $< -o $@
52+
-Wno-compare-distinct-pointer-types \
53+
-O2 -target bpf -emit-llvm -c $< -o - | \
54+
$(LLC) -march=bpf -mcpu=$(CPU) -filetype=obj -o $@

tools/testing/selftests/bpf/bpf_helpers.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ static unsigned long long (*bpf_get_prandom_u32)(void) =
6262
(void *) BPF_FUNC_get_prandom_u32;
6363
static int (*bpf_xdp_adjust_head)(void *ctx, int offset) =
6464
(void *) BPF_FUNC_xdp_adjust_head;
65+
static int (*bpf_xdp_adjust_meta)(void *ctx, int offset) =
66+
(void *) BPF_FUNC_xdp_adjust_meta;
6567
static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval,
6668
int optlen) =
6769
(void *) BPF_FUNC_setsockopt;

tools/testing/selftests/bpf/test_verifier.c

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6645,6 +6645,253 @@ static struct bpf_test tests[] = {
66456645
.errstr = "BPF_END uses reserved fields",
66466646
.result = REJECT,
66476647
},
6648+
{
6649+
"meta access, test1",
6650+
.insns = {
6651+
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
6652+
offsetof(struct xdp_md, data_meta)),
6653+
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
6654+
offsetof(struct xdp_md, data)),
6655+
BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
6656+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
6657+
BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1),
6658+
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0),
6659+
BPF_MOV64_IMM(BPF_REG_0, 0),
6660+
BPF_EXIT_INSN(),
6661+
},
6662+
.result = ACCEPT,
6663+
.prog_type = BPF_PROG_TYPE_XDP,
6664+
},
6665+
{
6666+
"meta access, test2",
6667+
.insns = {
6668+
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
6669+
offsetof(struct xdp_md, data_meta)),
6670+
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
6671+
offsetof(struct xdp_md, data)),
6672+
BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
6673+
BPF_ALU64_IMM(BPF_SUB, BPF_REG_0, 8),
6674+
BPF_MOV64_REG(BPF_REG_4, BPF_REG_2),
6675+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 8),
6676+
BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_3, 1),
6677+
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
6678+
BPF_MOV64_IMM(BPF_REG_0, 0),
6679+
BPF_EXIT_INSN(),
6680+
},
6681+
.result = REJECT,
6682+
.errstr = "invalid access to packet, off=-8",
6683+
.prog_type = BPF_PROG_TYPE_XDP,
6684+
},
6685+
{
6686+
"meta access, test3",
6687+
.insns = {
6688+
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
6689+
offsetof(struct xdp_md, data_meta)),
6690+
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
6691+
offsetof(struct xdp_md, data_end)),
6692+
BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
6693+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
6694+
BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1),
6695+
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0),
6696+
BPF_MOV64_IMM(BPF_REG_0, 0),
6697+
BPF_EXIT_INSN(),
6698+
},
6699+
.result = REJECT,
6700+
.errstr = "invalid access to packet",
6701+
.prog_type = BPF_PROG_TYPE_XDP,
6702+
},
6703+
{
6704+
"meta access, test4",
6705+
.insns = {
6706+
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
6707+
offsetof(struct xdp_md, data_meta)),
6708+
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
6709+
offsetof(struct xdp_md, data_end)),
6710+
BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1,
6711+
offsetof(struct xdp_md, data)),
6712+
BPF_MOV64_REG(BPF_REG_0, BPF_REG_4),
6713+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
6714+
BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1),
6715+
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0),
6716+
BPF_MOV64_IMM(BPF_REG_0, 0),
6717+
BPF_EXIT_INSN(),
6718+
},
6719+
.result = REJECT,
6720+
.errstr = "invalid access to packet",
6721+
.prog_type = BPF_PROG_TYPE_XDP,
6722+
},
6723+
{
6724+
"meta access, test5",
6725+
.insns = {
6726+
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
6727+
offsetof(struct xdp_md, data_meta)),
6728+
BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1,
6729+
offsetof(struct xdp_md, data)),
6730+
BPF_MOV64_REG(BPF_REG_0, BPF_REG_3),
6731+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
6732+
BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_4, 3),
6733+
BPF_MOV64_IMM(BPF_REG_2, -8),
6734+
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
6735+
BPF_FUNC_xdp_adjust_meta),
6736+
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_3, 0),
6737+
BPF_MOV64_IMM(BPF_REG_0, 0),
6738+
BPF_EXIT_INSN(),
6739+
},
6740+
.result = REJECT,
6741+
.errstr = "R3 !read_ok",
6742+
.prog_type = BPF_PROG_TYPE_XDP,
6743+
},
6744+
{
6745+
"meta access, test6",
6746+
.insns = {
6747+
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
6748+
offsetof(struct xdp_md, data_meta)),
6749+
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
6750+
offsetof(struct xdp_md, data)),
6751+
BPF_MOV64_REG(BPF_REG_0, BPF_REG_3),
6752+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
6753+
BPF_MOV64_REG(BPF_REG_4, BPF_REG_2),
6754+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 8),
6755+
BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_0, 1),
6756+
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0),
6757+
BPF_MOV64_IMM(BPF_REG_0, 0),
6758+
BPF_EXIT_INSN(),
6759+
},
6760+
.result = REJECT,
6761+
.errstr = "invalid access to packet",
6762+
.prog_type = BPF_PROG_TYPE_XDP,
6763+
},
6764+
{
6765+
"meta access, test7",
6766+
.insns = {
6767+
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
6768+
offsetof(struct xdp_md, data_meta)),
6769+
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
6770+
offsetof(struct xdp_md, data)),
6771+
BPF_MOV64_REG(BPF_REG_0, BPF_REG_3),
6772+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
6773+
BPF_MOV64_REG(BPF_REG_4, BPF_REG_2),
6774+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 8),
6775+
BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_3, 1),
6776+
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0),
6777+
BPF_MOV64_IMM(BPF_REG_0, 0),
6778+
BPF_EXIT_INSN(),
6779+
},
6780+
.result = ACCEPT,
6781+
.prog_type = BPF_PROG_TYPE_XDP,
6782+
},
6783+
{
6784+
"meta access, test8",
6785+
.insns = {
6786+
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
6787+
offsetof(struct xdp_md, data_meta)),
6788+
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
6789+
offsetof(struct xdp_md, data)),
6790+
BPF_MOV64_REG(BPF_REG_4, BPF_REG_2),
6791+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 0xFFFF),
6792+
BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_3, 1),
6793+
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0),
6794+
BPF_MOV64_IMM(BPF_REG_0, 0),
6795+
BPF_EXIT_INSN(),
6796+
},
6797+
.result = ACCEPT,
6798+
.prog_type = BPF_PROG_TYPE_XDP,
6799+
},
6800+
{
6801+
"meta access, test9",
6802+
.insns = {
6803+
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
6804+
offsetof(struct xdp_md, data_meta)),
6805+
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
6806+
offsetof(struct xdp_md, data)),
6807+
BPF_MOV64_REG(BPF_REG_4, BPF_REG_2),
6808+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 0xFFFF),
6809+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 1),
6810+
BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_3, 1),
6811+
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0),
6812+
BPF_MOV64_IMM(BPF_REG_0, 0),
6813+
BPF_EXIT_INSN(),
6814+
},
6815+
.result = REJECT,
6816+
.errstr = "invalid access to packet",
6817+
.prog_type = BPF_PROG_TYPE_XDP,
6818+
},
6819+
{
6820+
"meta access, test10",
6821+
.insns = {
6822+
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
6823+
offsetof(struct xdp_md, data_meta)),
6824+
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
6825+
offsetof(struct xdp_md, data)),
6826+
BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1,
6827+
offsetof(struct xdp_md, data_end)),
6828+
BPF_MOV64_IMM(BPF_REG_5, 42),
6829+
BPF_MOV64_IMM(BPF_REG_6, 24),
6830+
BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_5, -8),
6831+
BPF_STX_XADD(BPF_DW, BPF_REG_10, BPF_REG_6, -8),
6832+
BPF_LDX_MEM(BPF_DW, BPF_REG_5, BPF_REG_10, -8),
6833+
BPF_JMP_IMM(BPF_JGT, BPF_REG_5, 100, 6),
6834+
BPF_ALU64_REG(BPF_ADD, BPF_REG_3, BPF_REG_5),
6835+
BPF_MOV64_REG(BPF_REG_5, BPF_REG_3),
6836+
BPF_MOV64_REG(BPF_REG_6, BPF_REG_2),
6837+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 8),
6838+
BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_5, 1),
6839+
BPF_LDX_MEM(BPF_B, BPF_REG_2, BPF_REG_2, 0),
6840+
BPF_MOV64_IMM(BPF_REG_0, 0),
6841+
BPF_EXIT_INSN(),
6842+
},
6843+
.result = REJECT,
6844+
.errstr = "invalid access to packet",
6845+
.prog_type = BPF_PROG_TYPE_XDP,
6846+
},
6847+
{
6848+
"meta access, test11",
6849+
.insns = {
6850+
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
6851+
offsetof(struct xdp_md, data_meta)),
6852+
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
6853+
offsetof(struct xdp_md, data)),
6854+
BPF_MOV64_IMM(BPF_REG_5, 42),
6855+
BPF_MOV64_IMM(BPF_REG_6, 24),
6856+
BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_5, -8),
6857+
BPF_STX_XADD(BPF_DW, BPF_REG_10, BPF_REG_6, -8),
6858+
BPF_LDX_MEM(BPF_DW, BPF_REG_5, BPF_REG_10, -8),
6859+
BPF_JMP_IMM(BPF_JGT, BPF_REG_5, 100, 6),
6860+
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_5),
6861+
BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
6862+
BPF_MOV64_REG(BPF_REG_6, BPF_REG_2),
6863+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 8),
6864+
BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_3, 1),
6865+
BPF_LDX_MEM(BPF_B, BPF_REG_5, BPF_REG_5, 0),
6866+
BPF_MOV64_IMM(BPF_REG_0, 0),
6867+
BPF_EXIT_INSN(),
6868+
},
6869+
.result = ACCEPT,
6870+
.prog_type = BPF_PROG_TYPE_XDP,
6871+
},
6872+
{
6873+
"meta access, test12",
6874+
.insns = {
6875+
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
6876+
offsetof(struct xdp_md, data_meta)),
6877+
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
6878+
offsetof(struct xdp_md, data)),
6879+
BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1,
6880+
offsetof(struct xdp_md, data_end)),
6881+
BPF_MOV64_REG(BPF_REG_5, BPF_REG_3),
6882+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 16),
6883+
BPF_JMP_REG(BPF_JGT, BPF_REG_5, BPF_REG_4, 5),
6884+
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_3, 0),
6885+
BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
6886+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 16),
6887+
BPF_JMP_REG(BPF_JGT, BPF_REG_5, BPF_REG_3, 1),
6888+
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0),
6889+
BPF_MOV64_IMM(BPF_REG_0, 0),
6890+
BPF_EXIT_INSN(),
6891+
},
6892+
.result = ACCEPT,
6893+
.prog_type = BPF_PROG_TYPE_XDP,
6894+
},
66486895
};
66496896

66506897
static int probe_filter_length(const struct bpf_insn *fp)
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#include <linux/bpf.h>
2+
#include <linux/if_ether.h>
3+
#include <linux/pkt_cls.h>
4+
5+
#include "bpf_helpers.h"
6+
7+
#define __round_mask(x, y) ((__typeof__(x))((y) - 1))
8+
#define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1)
9+
#define ctx_ptr(ctx, mem) (void *)(unsigned long)ctx->mem
10+
11+
SEC("t")
12+
int ing_cls(struct __sk_buff *ctx)
13+
{
14+
__u8 *data, *data_meta, *data_end;
15+
__u32 diff = 0;
16+
17+
data_meta = ctx_ptr(ctx, data_meta);
18+
data_end = ctx_ptr(ctx, data_end);
19+
data = ctx_ptr(ctx, data);
20+
21+
if (data + ETH_ALEN > data_end ||
22+
data_meta + round_up(ETH_ALEN, 4) > data)
23+
return TC_ACT_SHOT;
24+
25+
diff |= ((__u32 *)data_meta)[0] ^ ((__u32 *)data)[0];
26+
diff |= ((__u16 *)data_meta)[2] ^ ((__u16 *)data)[2];
27+
28+
return diff ? TC_ACT_SHOT : TC_ACT_OK;
29+
}
30+
31+
SEC("x")
32+
int ing_xdp(struct xdp_md *ctx)
33+
{
34+
__u8 *data, *data_meta, *data_end;
35+
int ret;
36+
37+
ret = bpf_xdp_adjust_meta(ctx, -round_up(ETH_ALEN, 4));
38+
if (ret < 0)
39+
return XDP_DROP;
40+
41+
data_meta = ctx_ptr(ctx, data_meta);
42+
data_end = ctx_ptr(ctx, data_end);
43+
data = ctx_ptr(ctx, data);
44+
45+
if (data + ETH_ALEN > data_end ||
46+
data_meta + round_up(ETH_ALEN, 4) > data)
47+
return XDP_DROP;
48+
49+
__builtin_memcpy(data_meta, data, ETH_ALEN);
50+
return XDP_PASS;
51+
}
52+
53+
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)