Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
Daniel Borkmann says: ==================== pull-request: bpf-next 2018-04-27 The following pull-request contains BPF updates for your *net-next* tree. The main changes are: 1) Add extensive BPF helper description into include/uapi/linux/bpf.h and a new script bpf_helpers_doc.py which allows for generating a man page out of it. Thus, every helper in BPF now comes with proper function signature, detailed description and return code explanation, from Quentin. 2) Migrate the BPF collect metadata tunnel tests from BPF samples over to the BPF selftests and further extend them with v6 vxlan, geneve and ipip tests, simplify the ipip tests, improve documentation and convert to bpf_ntoh*() / bpf_hton*() api, from William. 3) Currently, helpers that expect ARG_PTR_TO_MAP_{KEY,VALUE} can only access stack and packet memory. Extend this to allow such helpers to also use map values, which enabled use cases where value from a first lookup can be directly used as a key for a second lookup, from Paul. 4) Add a new helper bpf_skb_get_xfrm_state() for tc BPF programs in order to retrieve XFRM state information containing SPI, peer address and reqid values, from Eyal. 5) Various optimizations in nfp driver's BPF JIT in order to turn ADD and SUB instructions with negative immediate into the opposite operation with a positive immediate such that nfp can better fit small immediates into instructions. Savings in instruction count up to 4% have been observed, from Jakub. 6) Add the BPF prog's gpl_compatible flag to struct bpf_prog_info and add support for dumping this through bpftool, from Jiri. 7) Move the BPF sockmap samples over into BPF selftests instead since sockmap was rather a series of tests than sample anyway and this way this can be run from automated bots, from John. 8) Follow-up fix for bpf_adjust_tail() helper in order to make it work with generic XDP, from Nikita. 9) Some follow-up cleanups to BTF, namely, removing unused defines from BTF uapi header and renaming 'name' struct btf_* members into name_off to make it more clear they are offsets into string section, from Martin. 10) Remove test_sock_addr from TEST_GEN_PROGS in BPF selftests since not run directly but invoked from test_sock_addr.sh, from Yonghong. 11) Remove redundant ret assignment in sample BPF loader, from Wang. 12) Add couple of missing files to BPF selftest's gitignore, from Anders. There are two trivial merge conflicts while pulling: 1) Remove samples/sockmap/Makefile since all sockmap tests have been moved to selftests. 2) Add both hunks from tools/testing/selftests/bpf/.gitignore to the file since git should ignore all of them. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
79741a38b4
|
@ -1214,45 +1214,83 @@ wrp_test_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
wrp_cmp_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
|
||||
enum br_mask br_mask, bool swap)
|
||||
static const struct jmp_code_map {
|
||||
enum br_mask br_mask;
|
||||
bool swap;
|
||||
} jmp_code_map[] = {
|
||||
[BPF_JGT >> 4] = { BR_BLO, true },
|
||||
[BPF_JGE >> 4] = { BR_BHS, false },
|
||||
[BPF_JLT >> 4] = { BR_BLO, false },
|
||||
[BPF_JLE >> 4] = { BR_BHS, true },
|
||||
[BPF_JSGT >> 4] = { BR_BLT, true },
|
||||
[BPF_JSGE >> 4] = { BR_BGE, false },
|
||||
[BPF_JSLT >> 4] = { BR_BLT, false },
|
||||
[BPF_JSLE >> 4] = { BR_BGE, true },
|
||||
};
|
||||
|
||||
static const struct jmp_code_map *nfp_jmp_code_get(struct nfp_insn_meta *meta)
|
||||
{
|
||||
unsigned int op;
|
||||
|
||||
op = BPF_OP(meta->insn.code) >> 4;
|
||||
/* br_mask of 0 is BR_BEQ which we don't use in jump code table */
|
||||
if (WARN_ONCE(op >= ARRAY_SIZE(jmp_code_map) ||
|
||||
!jmp_code_map[op].br_mask,
|
||||
"no code found for jump instruction"))
|
||||
return NULL;
|
||||
|
||||
return &jmp_code_map[op];
|
||||
}
|
||||
|
||||
static int cmp_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
const struct bpf_insn *insn = &meta->insn;
|
||||
u64 imm = insn->imm; /* sign extend */
|
||||
const struct jmp_code_map *code;
|
||||
enum alu_op alu_op, carry_op;
|
||||
u8 reg = insn->dst_reg * 2;
|
||||
swreg tmp_reg;
|
||||
|
||||
code = nfp_jmp_code_get(meta);
|
||||
if (!code)
|
||||
return -EINVAL;
|
||||
|
||||
alu_op = meta->jump_neg_op ? ALU_OP_ADD : ALU_OP_SUB;
|
||||
carry_op = meta->jump_neg_op ? ALU_OP_ADD_C : ALU_OP_SUB_C;
|
||||
|
||||
tmp_reg = ur_load_imm_any(nfp_prog, imm & ~0U, imm_b(nfp_prog));
|
||||
if (!swap)
|
||||
emit_alu(nfp_prog, reg_none(), reg_a(reg), ALU_OP_SUB, tmp_reg);
|
||||
if (!code->swap)
|
||||
emit_alu(nfp_prog, reg_none(), reg_a(reg), alu_op, tmp_reg);
|
||||
else
|
||||
emit_alu(nfp_prog, reg_none(), tmp_reg, ALU_OP_SUB, reg_a(reg));
|
||||
emit_alu(nfp_prog, reg_none(), tmp_reg, alu_op, reg_a(reg));
|
||||
|
||||
tmp_reg = ur_load_imm_any(nfp_prog, imm >> 32, imm_b(nfp_prog));
|
||||
if (!swap)
|
||||
if (!code->swap)
|
||||
emit_alu(nfp_prog, reg_none(),
|
||||
reg_a(reg + 1), ALU_OP_SUB_C, tmp_reg);
|
||||
reg_a(reg + 1), carry_op, tmp_reg);
|
||||
else
|
||||
emit_alu(nfp_prog, reg_none(),
|
||||
tmp_reg, ALU_OP_SUB_C, reg_a(reg + 1));
|
||||
tmp_reg, carry_op, reg_a(reg + 1));
|
||||
|
||||
emit_br(nfp_prog, br_mask, insn->off, 0);
|
||||
emit_br(nfp_prog, code->br_mask, insn->off, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
wrp_cmp_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
|
||||
enum br_mask br_mask, bool swap)
|
||||
static int cmp_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
const struct bpf_insn *insn = &meta->insn;
|
||||
const struct jmp_code_map *code;
|
||||
u8 areg, breg;
|
||||
|
||||
code = nfp_jmp_code_get(meta);
|
||||
if (!code)
|
||||
return -EINVAL;
|
||||
|
||||
areg = insn->dst_reg * 2;
|
||||
breg = insn->src_reg * 2;
|
||||
|
||||
if (swap) {
|
||||
if (code->swap) {
|
||||
areg ^= breg;
|
||||
breg ^= areg;
|
||||
areg ^= breg;
|
||||
|
@ -1261,7 +1299,7 @@ wrp_cmp_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
|
|||
emit_alu(nfp_prog, reg_none(), reg_a(areg), ALU_OP_SUB, reg_b(breg));
|
||||
emit_alu(nfp_prog, reg_none(),
|
||||
reg_a(areg + 1), ALU_OP_SUB_C, reg_b(breg + 1));
|
||||
emit_br(nfp_prog, br_mask, insn->off, 0);
|
||||
emit_br(nfp_prog, code->br_mask, insn->off, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1400,7 +1438,7 @@ map_call_stack_common(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
|||
if (!load_lm_ptr)
|
||||
return 0;
|
||||
|
||||
emit_csr_wr(nfp_prog, stack_reg(nfp_prog), NFP_CSR_ACT_LM_ADDR0);
|
||||
emit_csr_wr(nfp_prog, stack_reg(nfp_prog), NFP_CSR_ACT_LM_ADDR0);
|
||||
wrp_nops(nfp_prog, 3);
|
||||
|
||||
return 0;
|
||||
|
@ -2283,46 +2321,6 @@ static int jeq_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int jgt_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
return wrp_cmp_imm(nfp_prog, meta, BR_BLO, true);
|
||||
}
|
||||
|
||||
static int jge_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
return wrp_cmp_imm(nfp_prog, meta, BR_BHS, false);
|
||||
}
|
||||
|
||||
static int jlt_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
return wrp_cmp_imm(nfp_prog, meta, BR_BLO, false);
|
||||
}
|
||||
|
||||
static int jle_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
return wrp_cmp_imm(nfp_prog, meta, BR_BHS, true);
|
||||
}
|
||||
|
||||
static int jsgt_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
return wrp_cmp_imm(nfp_prog, meta, BR_BLT, true);
|
||||
}
|
||||
|
||||
static int jsge_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
return wrp_cmp_imm(nfp_prog, meta, BR_BGE, false);
|
||||
}
|
||||
|
||||
static int jslt_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
return wrp_cmp_imm(nfp_prog, meta, BR_BLT, false);
|
||||
}
|
||||
|
||||
static int jsle_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
return wrp_cmp_imm(nfp_prog, meta, BR_BGE, true);
|
||||
}
|
||||
|
||||
static int jset_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
const struct bpf_insn *insn = &meta->insn;
|
||||
|
@ -2392,46 +2390,6 @@ static int jeq_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int jgt_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
return wrp_cmp_reg(nfp_prog, meta, BR_BLO, true);
|
||||
}
|
||||
|
||||
static int jge_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
return wrp_cmp_reg(nfp_prog, meta, BR_BHS, false);
|
||||
}
|
||||
|
||||
static int jlt_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
return wrp_cmp_reg(nfp_prog, meta, BR_BLO, false);
|
||||
}
|
||||
|
||||
static int jle_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
return wrp_cmp_reg(nfp_prog, meta, BR_BHS, true);
|
||||
}
|
||||
|
||||
static int jsgt_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
return wrp_cmp_reg(nfp_prog, meta, BR_BLT, true);
|
||||
}
|
||||
|
||||
static int jsge_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
return wrp_cmp_reg(nfp_prog, meta, BR_BGE, false);
|
||||
}
|
||||
|
||||
static int jslt_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
return wrp_cmp_reg(nfp_prog, meta, BR_BLT, false);
|
||||
}
|
||||
|
||||
static int jsle_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
return wrp_cmp_reg(nfp_prog, meta, BR_BGE, true);
|
||||
}
|
||||
|
||||
static int jset_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
return wrp_test_reg(nfp_prog, meta, ALU_OP_AND, BR_BNE);
|
||||
|
@ -2520,25 +2478,25 @@ static const instr_cb_t instr_cb[256] = {
|
|||
[BPF_ST | BPF_MEM | BPF_DW] = mem_st8,
|
||||
[BPF_JMP | BPF_JA | BPF_K] = jump,
|
||||
[BPF_JMP | BPF_JEQ | BPF_K] = jeq_imm,
|
||||
[BPF_JMP | BPF_JGT | BPF_K] = jgt_imm,
|
||||
[BPF_JMP | BPF_JGE | BPF_K] = jge_imm,
|
||||
[BPF_JMP | BPF_JLT | BPF_K] = jlt_imm,
|
||||
[BPF_JMP | BPF_JLE | BPF_K] = jle_imm,
|
||||
[BPF_JMP | BPF_JSGT | BPF_K] = jsgt_imm,
|
||||
[BPF_JMP | BPF_JSGE | BPF_K] = jsge_imm,
|
||||
[BPF_JMP | BPF_JSLT | BPF_K] = jslt_imm,
|
||||
[BPF_JMP | BPF_JSLE | BPF_K] = jsle_imm,
|
||||
[BPF_JMP | BPF_JGT | BPF_K] = cmp_imm,
|
||||
[BPF_JMP | BPF_JGE | BPF_K] = cmp_imm,
|
||||
[BPF_JMP | BPF_JLT | BPF_K] = cmp_imm,
|
||||
[BPF_JMP | BPF_JLE | BPF_K] = cmp_imm,
|
||||
[BPF_JMP | BPF_JSGT | BPF_K] = cmp_imm,
|
||||
[BPF_JMP | BPF_JSGE | BPF_K] = cmp_imm,
|
||||
[BPF_JMP | BPF_JSLT | BPF_K] = cmp_imm,
|
||||
[BPF_JMP | BPF_JSLE | BPF_K] = cmp_imm,
|
||||
[BPF_JMP | BPF_JSET | BPF_K] = jset_imm,
|
||||
[BPF_JMP | BPF_JNE | BPF_K] = jne_imm,
|
||||
[BPF_JMP | BPF_JEQ | BPF_X] = jeq_reg,
|
||||
[BPF_JMP | BPF_JGT | BPF_X] = jgt_reg,
|
||||
[BPF_JMP | BPF_JGE | BPF_X] = jge_reg,
|
||||
[BPF_JMP | BPF_JLT | BPF_X] = jlt_reg,
|
||||
[BPF_JMP | BPF_JLE | BPF_X] = jle_reg,
|
||||
[BPF_JMP | BPF_JSGT | BPF_X] = jsgt_reg,
|
||||
[BPF_JMP | BPF_JSGE | BPF_X] = jsge_reg,
|
||||
[BPF_JMP | BPF_JSLT | BPF_X] = jslt_reg,
|
||||
[BPF_JMP | BPF_JSLE | BPF_X] = jsle_reg,
|
||||
[BPF_JMP | BPF_JGT | BPF_X] = cmp_reg,
|
||||
[BPF_JMP | BPF_JGE | BPF_X] = cmp_reg,
|
||||
[BPF_JMP | BPF_JLT | BPF_X] = cmp_reg,
|
||||
[BPF_JMP | BPF_JLE | BPF_X] = cmp_reg,
|
||||
[BPF_JMP | BPF_JSGT | BPF_X] = cmp_reg,
|
||||
[BPF_JMP | BPF_JSGE | BPF_X] = cmp_reg,
|
||||
[BPF_JMP | BPF_JSLT | BPF_X] = cmp_reg,
|
||||
[BPF_JMP | BPF_JSLE | BPF_X] = cmp_reg,
|
||||
[BPF_JMP | BPF_JSET | BPF_X] = jset_reg,
|
||||
[BPF_JMP | BPF_JNE | BPF_X] = jne_reg,
|
||||
[BPF_JMP | BPF_CALL] = call,
|
||||
|
@ -2777,6 +2735,54 @@ static void nfp_bpf_opt_reg_init(struct nfp_prog *nfp_prog)
|
|||
}
|
||||
}
|
||||
|
||||
/* abs(insn.imm) will fit better into unrestricted reg immediate -
|
||||
* convert add/sub of a negative number into a sub/add of a positive one.
|
||||
*/
|
||||
static void nfp_bpf_opt_neg_add_sub(struct nfp_prog *nfp_prog)
|
||||
{
|
||||
struct nfp_insn_meta *meta;
|
||||
|
||||
list_for_each_entry(meta, &nfp_prog->insns, l) {
|
||||
struct bpf_insn insn = meta->insn;
|
||||
|
||||
if (meta->skip)
|
||||
continue;
|
||||
|
||||
if (BPF_CLASS(insn.code) != BPF_ALU &&
|
||||
BPF_CLASS(insn.code) != BPF_ALU64 &&
|
||||
BPF_CLASS(insn.code) != BPF_JMP)
|
||||
continue;
|
||||
if (BPF_SRC(insn.code) != BPF_K)
|
||||
continue;
|
||||
if (insn.imm >= 0)
|
||||
continue;
|
||||
|
||||
if (BPF_CLASS(insn.code) == BPF_JMP) {
|
||||
switch (BPF_OP(insn.code)) {
|
||||
case BPF_JGE:
|
||||
case BPF_JSGE:
|
||||
case BPF_JLT:
|
||||
case BPF_JSLT:
|
||||
meta->jump_neg_op = true;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (BPF_OP(insn.code) == BPF_ADD)
|
||||
insn.code = BPF_CLASS(insn.code) | BPF_SUB;
|
||||
else if (BPF_OP(insn.code) == BPF_SUB)
|
||||
insn.code = BPF_CLASS(insn.code) | BPF_ADD;
|
||||
else
|
||||
continue;
|
||||
|
||||
meta->insn.code = insn.code | BPF_K;
|
||||
}
|
||||
|
||||
meta->insn.imm = -insn.imm;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove masking after load since our load guarantees this is not needed */
|
||||
static void nfp_bpf_opt_ld_mask(struct nfp_prog *nfp_prog)
|
||||
{
|
||||
|
@ -3212,6 +3218,7 @@ static int nfp_bpf_optimize(struct nfp_prog *nfp_prog)
|
|||
{
|
||||
nfp_bpf_opt_reg_init(nfp_prog);
|
||||
|
||||
nfp_bpf_opt_neg_add_sub(nfp_prog);
|
||||
nfp_bpf_opt_ld_mask(nfp_prog);
|
||||
nfp_bpf_opt_ld_shift(nfp_prog);
|
||||
nfp_bpf_opt_ldst_gather(nfp_prog);
|
||||
|
|
|
@ -236,6 +236,7 @@ struct nfp_bpf_reg_state {
|
|||
* @xadd_over_16bit: 16bit immediate is not guaranteed
|
||||
* @xadd_maybe_16bit: 16bit immediate is possible
|
||||
* @jmp_dst: destination info for jump instructions
|
||||
* @jump_neg_op: jump instruction has inverted immediate, use ADD instead of SUB
|
||||
* @func_id: function id for call instructions
|
||||
* @arg1: arg1 for call instructions
|
||||
* @arg2: arg2 for call instructions
|
||||
|
@ -264,7 +265,10 @@ struct nfp_insn_meta {
|
|||
bool xadd_maybe_16bit;
|
||||
};
|
||||
/* jump */
|
||||
struct nfp_insn_meta *jmp_dst;
|
||||
struct {
|
||||
struct nfp_insn_meta *jmp_dst;
|
||||
bool jump_neg_op;
|
||||
};
|
||||
/* function calls */
|
||||
struct {
|
||||
u32 func_id;
|
||||
|
|
|
@ -765,7 +765,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
|
|||
/* recalculate len if xdp.data or xdp.data_end were
|
||||
* adjusted
|
||||
*/
|
||||
len = xdp.data_end - xdp.data;
|
||||
len = xdp.data_end - xdp.data + vi->hdr_len;
|
||||
/* We can only create skb based on xdp_page. */
|
||||
if (unlikely(xdp_page != page)) {
|
||||
rcu_read_unlock();
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -6,9 +6,7 @@
|
|||
#include <linux/types.h>
|
||||
|
||||
#define BTF_MAGIC 0xeB9F
|
||||
#define BTF_MAGIC_SWAP 0x9FeB
|
||||
#define BTF_VERSION 1
|
||||
#define BTF_FLAGS_COMPR 0x01
|
||||
|
||||
struct btf_header {
|
||||
__u16 magic;
|
||||
|
@ -43,7 +41,7 @@ struct btf_header {
|
|||
#define BTF_STR_OFFSET(ref) ((ref) & BTF_MAX_NAME_OFFSET)
|
||||
|
||||
struct btf_type {
|
||||
__u32 name;
|
||||
__u32 name_off;
|
||||
/* "info" bits arrangement
|
||||
* bits 0-15: vlen (e.g. # of struct's members)
|
||||
* bits 16-23: unused
|
||||
|
@ -105,7 +103,7 @@ struct btf_type {
|
|||
* info in "struct btf_type").
|
||||
*/
|
||||
struct btf_enum {
|
||||
__u32 name;
|
||||
__u32 name_off;
|
||||
__s32 val;
|
||||
};
|
||||
|
||||
|
@ -122,7 +120,7 @@ struct btf_array {
|
|||
* "struct btf_type").
|
||||
*/
|
||||
struct btf_member {
|
||||
__u32 name;
|
||||
__u32 name_off;
|
||||
__u32 type;
|
||||
__u32 offset; /* offset in bits */
|
||||
};
|
||||
|
|
|
@ -473,7 +473,7 @@ __printf(4, 5) static void __btf_verifier_log_type(struct btf_verifier_env *env,
|
|||
__btf_verifier_log(log, "[%u] %s %s%s",
|
||||
env->log_type_id,
|
||||
btf_kind_str[kind],
|
||||
btf_name_by_offset(btf, t->name),
|
||||
btf_name_by_offset(btf, t->name_off),
|
||||
log_details ? " " : "");
|
||||
|
||||
if (log_details)
|
||||
|
@ -517,7 +517,7 @@ static void btf_verifier_log_member(struct btf_verifier_env *env,
|
|||
btf_verifier_log_type(env, struct_type, NULL);
|
||||
|
||||
__btf_verifier_log(log, "\t%s type_id=%u bits_offset=%u",
|
||||
btf_name_by_offset(btf, member->name),
|
||||
btf_name_by_offset(btf, member->name_off),
|
||||
member->type, member->offset);
|
||||
|
||||
if (fmt && *fmt) {
|
||||
|
@ -1419,10 +1419,10 @@ static s32 btf_struct_check_meta(struct btf_verifier_env *env,
|
|||
btf_verifier_log_type(env, t, NULL);
|
||||
|
||||
for_each_member(i, t, member) {
|
||||
if (!btf_name_offset_valid(btf, member->name)) {
|
||||
if (!btf_name_offset_valid(btf, member->name_off)) {
|
||||
btf_verifier_log_member(env, t, member,
|
||||
"Invalid member name_offset:%u",
|
||||
member->name);
|
||||
member->name_off);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -1605,14 +1605,14 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env,
|
|||
btf_verifier_log_type(env, t, NULL);
|
||||
|
||||
for (i = 0; i < nr_enums; i++) {
|
||||
if (!btf_name_offset_valid(btf, enums[i].name)) {
|
||||
if (!btf_name_offset_valid(btf, enums[i].name_off)) {
|
||||
btf_verifier_log(env, "\tInvalid name_offset:%u",
|
||||
enums[i].name);
|
||||
enums[i].name_off);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
btf_verifier_log(env, "\t%s val=%d\n",
|
||||
btf_name_by_offset(btf, enums[i].name),
|
||||
btf_name_by_offset(btf, enums[i].name_off),
|
||||
enums[i].val);
|
||||
}
|
||||
|
||||
|
@ -1636,7 +1636,7 @@ static void btf_enum_seq_show(const struct btf *btf, const struct btf_type *t,
|
|||
for (i = 0; i < nr_enums; i++) {
|
||||
if (v == enums[i].val) {
|
||||
seq_printf(m, "%s",
|
||||
btf_name_by_offset(btf, enums[i].name));
|
||||
btf_name_by_offset(btf, enums[i].name_off));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1687,9 +1687,9 @@ static s32 btf_check_meta(struct btf_verifier_env *env,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!btf_name_offset_valid(env->btf, t->name)) {
|
||||
if (!btf_name_offset_valid(env->btf, t->name_off)) {
|
||||
btf_verifier_log(env, "[%u] Invalid name_offset:%u",
|
||||
env->log_type_id, t->name);
|
||||
env->log_type_id, t->name_off);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
@ -1914,6 +1914,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
|
|||
info.load_time = prog->aux->load_time;
|
||||
info.created_by_uid = from_kuid_munged(current_user_ns(),
|
||||
prog->aux->user->uid);
|
||||
info.gpl_compatible = prog->gpl_compatible;
|
||||
|
||||
memcpy(info.tag, prog->tag, sizeof(prog->tag));
|
||||
memcpy(info.name, prog->aux->name, sizeof(prog->aux->name));
|
||||
|
|
|
@ -1914,7 +1914,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
|
|||
if (arg_type == ARG_PTR_TO_MAP_KEY ||
|
||||
arg_type == ARG_PTR_TO_MAP_VALUE) {
|
||||
expected_type = PTR_TO_STACK;
|
||||
if (!type_is_pkt_pointer(type) &&
|
||||
if (!type_is_pkt_pointer(type) && type != PTR_TO_MAP_VALUE &&
|
||||
type != expected_type)
|
||||
goto err_type;
|
||||
} else if (arg_type == ARG_CONST_SIZE ||
|
||||
|
@ -1966,14 +1966,9 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
|
|||
verbose(env, "invalid map_ptr to access map->key\n");
|
||||
return -EACCES;
|
||||
}
|
||||
if (type_is_pkt_pointer(type))
|
||||
err = check_packet_access(env, regno, reg->off,
|
||||
meta->map_ptr->key_size,
|
||||
false);
|
||||
else
|
||||
err = check_stack_boundary(env, regno,
|
||||
meta->map_ptr->key_size,
|
||||
false, NULL);
|
||||
err = check_helper_mem_access(env, regno,
|
||||
meta->map_ptr->key_size, false,
|
||||
NULL);
|
||||
} else if (arg_type == ARG_PTR_TO_MAP_VALUE) {
|
||||
/* bpf_map_xxx(..., map_ptr, ..., value) call:
|
||||
* check [value, value + map->value_size) validity
|
||||
|
@ -1983,14 +1978,9 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
|
|||
verbose(env, "invalid map_ptr to access map->value\n");
|
||||
return -EACCES;
|
||||
}
|
||||
if (type_is_pkt_pointer(type))
|
||||
err = check_packet_access(env, regno, reg->off,
|
||||
meta->map_ptr->value_size,
|
||||
false);
|
||||
else
|
||||
err = check_stack_boundary(env, regno,
|
||||
meta->map_ptr->value_size,
|
||||
false, NULL);
|
||||
err = check_helper_mem_access(env, regno,
|
||||
meta->map_ptr->value_size, false,
|
||||
NULL);
|
||||
} else if (arg_type_is_mem_size(arg_type)) {
|
||||
bool zero_size_allowed = (arg_type == ARG_CONST_SIZE_OR_ZERO);
|
||||
|
||||
|
|
|
@ -4057,8 +4057,10 @@ static u32 netif_receive_generic_xdp(struct sk_buff *skb,
|
|||
* pckt.
|
||||
*/
|
||||
off = orig_data_end - xdp.data_end;
|
||||
if (off != 0)
|
||||
if (off != 0) {
|
||||
skb_set_tail_pointer(skb, xdp.data_end - xdp.data);
|
||||
skb->len -= off;
|
||||
}
|
||||
|
||||
switch (act) {
|
||||
case XDP_REDIRECT:
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
#include <net/sock_reuseport.h>
|
||||
#include <net/busy_poll.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/xfrm.h>
|
||||
#include <linux/bpf_trace.h>
|
||||
|
||||
/**
|
||||
|
@ -3744,6 +3745,49 @@ static const struct bpf_func_proto bpf_bind_proto = {
|
|||
.arg3_type = ARG_CONST_SIZE,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_XFRM
|
||||
BPF_CALL_5(bpf_skb_get_xfrm_state, struct sk_buff *, skb, u32, index,
|
||||
struct bpf_xfrm_state *, to, u32, size, u64, flags)
|
||||
{
|
||||
const struct sec_path *sp = skb_sec_path(skb);
|
||||
const struct xfrm_state *x;
|
||||
|
||||
if (!sp || unlikely(index >= sp->len || flags))
|
||||
goto err_clear;
|
||||
|
||||
x = sp->xvec[index];
|
||||
|
||||
if (unlikely(size != sizeof(struct bpf_xfrm_state)))
|
||||
goto err_clear;
|
||||
|
||||
to->reqid = x->props.reqid;
|
||||
to->spi = x->id.spi;
|
||||
to->family = x->props.family;
|
||||
if (to->family == AF_INET6) {
|
||||
memcpy(to->remote_ipv6, x->props.saddr.a6,
|
||||
sizeof(to->remote_ipv6));
|
||||
} else {
|
||||
to->remote_ipv4 = x->props.saddr.a4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_clear:
|
||||
memset(to, 0, size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct bpf_func_proto bpf_skb_get_xfrm_state_proto = {
|
||||
.func = bpf_skb_get_xfrm_state,
|
||||
.gpl_only = false,
|
||||
.ret_type = RET_INTEGER,
|
||||
.arg1_type = ARG_PTR_TO_CTX,
|
||||
.arg2_type = ARG_ANYTHING,
|
||||
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
|
||||
.arg4_type = ARG_CONST_SIZE,
|
||||
.arg5_type = ARG_ANYTHING,
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct bpf_func_proto *
|
||||
bpf_base_func_proto(enum bpf_func_id func_id)
|
||||
{
|
||||
|
@ -3885,6 +3929,10 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||
return &bpf_get_socket_cookie_proto;
|
||||
case BPF_FUNC_get_socket_uid:
|
||||
return &bpf_get_socket_uid_proto;
|
||||
#ifdef CONFIG_XFRM
|
||||
case BPF_FUNC_skb_get_xfrm_state:
|
||||
return &bpf_skb_get_xfrm_state_proto;
|
||||
#endif
|
||||
default:
|
||||
return bpf_base_func_proto(func_id);
|
||||
}
|
||||
|
|
|
@ -114,7 +114,6 @@ always += sock_flags_kern.o
|
|||
always += test_probe_write_user_kern.o
|
||||
always += trace_output_kern.o
|
||||
always += tcbpf1_kern.o
|
||||
always += tcbpf2_kern.o
|
||||
always += tc_l2_redirect_kern.o
|
||||
always += lathist_kern.o
|
||||
always += offwaketime_kern.o
|
||||
|
|
|
@ -549,7 +549,6 @@ static int do_load_bpf_file(const char *path, fixup_map_cb fixup_map)
|
|||
if (nr_maps < 0) {
|
||||
printf("Error: Failed loading ELF maps (errno:%d):%s\n",
|
||||
nr_maps, strerror(-nr_maps));
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
if (load_maps(map_data, nr_maps, fixup_map))
|
||||
|
@ -615,7 +614,6 @@ static int do_load_bpf_file(const char *path, fixup_map_cb fixup_map)
|
|||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
done:
|
||||
close(fd);
|
||||
return ret;
|
||||
|
|
|
@ -1,319 +0,0 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# In Namespace 0 (at_ns0) using native tunnel
|
||||
# Overlay IP: 10.1.1.100
|
||||
# local 192.16.1.100 remote 192.16.1.200
|
||||
# veth0 IP: 172.16.1.100, tunnel dev <type>00
|
||||
|
||||
# Out of Namespace using BPF set/get on lwtunnel
|
||||
# Overlay IP: 10.1.1.200
|
||||
# local 172.16.1.200 remote 172.16.1.100
|
||||
# veth1 IP: 172.16.1.200, tunnel dev <type>11
|
||||
|
||||
function config_device {
|
||||
ip netns add at_ns0
|
||||
ip link add veth0 type veth peer name veth1
|
||||
ip link set veth0 netns at_ns0
|
||||
ip netns exec at_ns0 ip addr add 172.16.1.100/24 dev veth0
|
||||
ip netns exec at_ns0 ip link set dev veth0 up
|
||||
ip link set dev veth1 up mtu 1500
|
||||
ip addr add dev veth1 172.16.1.200/24
|
||||
}
|
||||
|
||||
function add_gre_tunnel {
|
||||
# in namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE seq key 2 \
|
||||
local 172.16.1.100 remote 172.16.1.200
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
|
||||
# out of namespace
|
||||
ip link add dev $DEV type $TYPE key 2 external
|
||||
ip link set dev $DEV up
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
}
|
||||
|
||||
function add_ip6gretap_tunnel {
|
||||
|
||||
# assign ipv6 address
|
||||
ip netns exec at_ns0 ip addr add ::11/96 dev veth0
|
||||
ip netns exec at_ns0 ip link set dev veth0 up
|
||||
ip addr add dev veth1 ::22/96
|
||||
ip link set dev veth1 up
|
||||
|
||||
# in namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE seq flowlabel 0xbcdef key 2 \
|
||||
local ::11 remote ::22
|
||||
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS fc80::100/96
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
|
||||
# out of namespace
|
||||
ip link add dev $DEV type $TYPE external
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
ip addr add dev $DEV fc80::200/24
|
||||
ip link set dev $DEV up
|
||||
}
|
||||
|
||||
function add_erspan_tunnel {
|
||||
# in namespace
|
||||
if [ "$1" == "v1" ]; then
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE seq key 2 \
|
||||
local 172.16.1.100 remote 172.16.1.200 \
|
||||
erspan_ver 1 erspan 123
|
||||
else
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE seq key 2 \
|
||||
local 172.16.1.100 remote 172.16.1.200 \
|
||||
erspan_ver 2 erspan_dir egress erspan_hwid 3
|
||||
fi
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
|
||||
# out of namespace
|
||||
ip link add dev $DEV type $TYPE external
|
||||
ip link set dev $DEV up
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
}
|
||||
|
||||
function add_ip6erspan_tunnel {
|
||||
|
||||
# assign ipv6 address
|
||||
ip netns exec at_ns0 ip addr add ::11/96 dev veth0
|
||||
ip netns exec at_ns0 ip link set dev veth0 up
|
||||
ip addr add dev veth1 ::22/96
|
||||
ip link set dev veth1 up
|
||||
|
||||
# in namespace
|
||||
if [ "$1" == "v1" ]; then
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE seq key 2 \
|
||||
local ::11 remote ::22 \
|
||||
erspan_ver 1 erspan 123
|
||||
else
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE seq key 2 \
|
||||
local ::11 remote ::22 \
|
||||
erspan_ver 2 erspan_dir egress erspan_hwid 7
|
||||
fi
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
|
||||
# out of namespace
|
||||
ip link add dev $DEV type $TYPE external
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
ip link set dev $DEV up
|
||||
}
|
||||
|
||||
function add_vxlan_tunnel {
|
||||
# Set static ARP entry here because iptables set-mark works
|
||||
# on L3 packet, as a result not applying to ARP packets,
|
||||
# causing errors at get_tunnel_{key/opt}.
|
||||
|
||||
# in namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE id 2 dstport 4789 gbp remote 172.16.1.200
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS address 52:54:00:d9:01:00 up
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
ip netns exec at_ns0 arp -s 10.1.1.200 52:54:00:d9:02:00
|
||||
ip netns exec at_ns0 iptables -A OUTPUT -j MARK --set-mark 0x800FF
|
||||
|
||||
# out of namespace
|
||||
ip link add dev $DEV type $TYPE external gbp dstport 4789
|
||||
ip link set dev $DEV address 52:54:00:d9:02:00 up
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
arp -s 10.1.1.100 52:54:00:d9:01:00
|
||||
}
|
||||
|
||||
function add_geneve_tunnel {
|
||||
# in namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE id 2 dstport 6081 remote 172.16.1.200
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
|
||||
# out of namespace
|
||||
ip link add dev $DEV type $TYPE dstport 6081 external
|
||||
ip link set dev $DEV up
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
}
|
||||
|
||||
function add_ipip_tunnel {
|
||||
# in namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE local 172.16.1.100 remote 172.16.1.200
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
|
||||
# out of namespace
|
||||
ip link add dev $DEV type $TYPE external
|
||||
ip link set dev $DEV up
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
}
|
||||
|
||||
function attach_bpf {
|
||||
DEV=$1
|
||||
SET_TUNNEL=$2
|
||||
GET_TUNNEL=$3
|
||||
tc qdisc add dev $DEV clsact
|
||||
tc filter add dev $DEV egress bpf da obj tcbpf2_kern.o sec $SET_TUNNEL
|
||||
tc filter add dev $DEV ingress bpf da obj tcbpf2_kern.o sec $GET_TUNNEL
|
||||
}
|
||||
|
||||
function test_gre {
|
||||
TYPE=gretap
|
||||
DEV_NS=gretap00
|
||||
DEV=gretap11
|
||||
config_device
|
||||
add_gre_tunnel
|
||||
attach_bpf $DEV gre_set_tunnel gre_get_tunnel
|
||||
ping -c 1 10.1.1.100
|
||||
ip netns exec at_ns0 ping -c 1 10.1.1.200
|
||||
cleanup
|
||||
}
|
||||
|
||||
function test_ip6gre {
|
||||
TYPE=ip6gre
|
||||
DEV_NS=ip6gre00
|
||||
DEV=ip6gre11
|
||||
config_device
|
||||
# reuse the ip6gretap function
|
||||
add_ip6gretap_tunnel
|
||||
attach_bpf $DEV ip6gretap_set_tunnel ip6gretap_get_tunnel
|
||||
# underlay
|
||||
ping6 -c 4 ::11
|
||||
# overlay: ipv4 over ipv6
|
||||
ip netns exec at_ns0 ping -c 1 10.1.1.200
|
||||
ping -c 1 10.1.1.100
|
||||
# overlay: ipv6 over ipv6
|
||||
ip netns exec at_ns0 ping6 -c 1 fc80::200
|
||||
cleanup
|
||||
}
|
||||
|
||||
function test_ip6gretap {
|
||||
TYPE=ip6gretap
|
||||
DEV_NS=ip6gretap00
|
||||
DEV=ip6gretap11
|
||||
config_device
|
||||
add_ip6gretap_tunnel
|
||||
attach_bpf $DEV ip6gretap_set_tunnel ip6gretap_get_tunnel
|
||||
# underlay
|
||||
ping6 -c 4 ::11
|
||||
# overlay: ipv4 over ipv6
|
||||
ip netns exec at_ns0 ping -i .2 -c 1 10.1.1.200
|
||||
ping -c 1 10.1.1.100
|
||||
# overlay: ipv6 over ipv6
|
||||
ip netns exec at_ns0 ping6 -c 1 fc80::200
|
||||
cleanup
|
||||
}
|
||||
|
||||
function test_erspan {
|
||||
TYPE=erspan
|
||||
DEV_NS=erspan00
|
||||
DEV=erspan11
|
||||
config_device
|
||||
add_erspan_tunnel $1
|
||||
attach_bpf $DEV erspan_set_tunnel erspan_get_tunnel
|
||||
ping -c 1 10.1.1.100
|
||||
ip netns exec at_ns0 ping -c 1 10.1.1.200
|
||||
cleanup
|
||||
}
|
||||
|
||||
function test_ip6erspan {
|
||||
TYPE=ip6erspan
|
||||
DEV_NS=ip6erspan00
|
||||
DEV=ip6erspan11
|
||||
config_device
|
||||
add_ip6erspan_tunnel $1
|
||||
attach_bpf $DEV ip4ip6erspan_set_tunnel ip4ip6erspan_get_tunnel
|
||||
ping6 -c 3 ::11
|
||||
ip netns exec at_ns0 ping -c 1 10.1.1.200
|
||||
cleanup
|
||||
}
|
||||
|
||||
function test_vxlan {
|
||||
TYPE=vxlan
|
||||
DEV_NS=vxlan00
|
||||
DEV=vxlan11
|
||||
config_device
|
||||
add_vxlan_tunnel
|
||||
attach_bpf $DEV vxlan_set_tunnel vxlan_get_tunnel
|
||||
ping -c 1 10.1.1.100
|
||||
ip netns exec at_ns0 ping -c 1 10.1.1.200
|
||||
cleanup
|
||||
}
|
||||
|
||||
function test_geneve {
|
||||
TYPE=geneve
|
||||
DEV_NS=geneve00
|
||||
DEV=geneve11
|
||||
config_device
|
||||
add_geneve_tunnel
|
||||
attach_bpf $DEV geneve_set_tunnel geneve_get_tunnel
|
||||
ping -c 1 10.1.1.100
|
||||
ip netns exec at_ns0 ping -c 1 10.1.1.200
|
||||
cleanup
|
||||
}
|
||||
|
||||
function test_ipip {
|
||||
TYPE=ipip
|
||||
DEV_NS=ipip00
|
||||
DEV=ipip11
|
||||
config_device
|
||||
tcpdump -nei veth1 &
|
||||
cat /sys/kernel/debug/tracing/trace_pipe &
|
||||
add_ipip_tunnel
|
||||
ethtool -K veth1 gso off gro off rx off tx off
|
||||
ip link set dev veth1 mtu 1500
|
||||
attach_bpf $DEV ipip_set_tunnel ipip_get_tunnel
|
||||
ping -c 1 10.1.1.100
|
||||
ip netns exec at_ns0 ping -c 1 10.1.1.200
|
||||
ip netns exec at_ns0 iperf -sD -p 5200 > /dev/null
|
||||
sleep 0.2
|
||||
iperf -c 10.1.1.100 -n 5k -p 5200
|
||||
cleanup
|
||||
}
|
||||
|
||||
function cleanup {
|
||||
set +ex
|
||||
pkill iperf
|
||||
ip netns delete at_ns0
|
||||
ip link del veth1
|
||||
ip link del ipip11
|
||||
ip link del gretap11
|
||||
ip link del ip6gre11
|
||||
ip link del ip6gretap11
|
||||
ip link del vxlan11
|
||||
ip link del geneve11
|
||||
ip link del erspan11
|
||||
ip link del ip6erspan11
|
||||
pkill tcpdump
|
||||
pkill cat
|
||||
set -ex
|
||||
}
|
||||
|
||||
trap cleanup 0 2 3 6 9
|
||||
cleanup
|
||||
echo "Testing GRE tunnel..."
|
||||
test_gre
|
||||
echo "Testing IP6GRE tunnel..."
|
||||
test_ip6gre
|
||||
echo "Testing IP6GRETAP tunnel..."
|
||||
test_ip6gretap
|
||||
echo "Testing ERSPAN tunnel..."
|
||||
test_erspan v1
|
||||
test_erspan v2
|
||||
echo "Testing IP6ERSPAN tunnel..."
|
||||
test_ip6erspan v1
|
||||
test_ip6erspan v2
|
||||
echo "Testing VXLAN tunnel..."
|
||||
test_vxlan
|
||||
echo "Testing GENEVE tunnel..."
|
||||
test_geneve
|
||||
echo "Testing IPIP tunnel..."
|
||||
test_ipip
|
||||
echo "*** PASS ***"
|
|
@ -1,78 +0,0 @@
|
|||
# List of programs to build
|
||||
hostprogs-y := sockmap
|
||||
|
||||
# Libbpf dependencies
|
||||
LIBBPF := ../../tools/lib/bpf/bpf.o ../../tools/lib/bpf/nlattr.o
|
||||
|
||||
HOSTCFLAGS += -I$(objtree)/usr/include
|
||||
HOSTCFLAGS += -I$(srctree)/tools/lib/
|
||||
HOSTCFLAGS += -I$(srctree)/tools/testing/selftests/bpf/
|
||||
HOSTCFLAGS += -I$(srctree)/tools/lib/ -I$(srctree)/tools/include
|
||||
HOSTCFLAGS += -I$(srctree)/tools/perf
|
||||
|
||||
sockmap-objs := ../bpf/bpf_load.o $(LIBBPF) sockmap_user.o
|
||||
|
||||
# Tell kbuild to always build the programs
|
||||
always := $(hostprogs-y)
|
||||
always += sockmap_kern.o
|
||||
|
||||
HOSTLOADLIBES_sockmap += -lelf -lpthread
|
||||
|
||||
# Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline:
|
||||
# make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang
|
||||
LLC ?= llc
|
||||
CLANG ?= clang
|
||||
|
||||
# Trick to allow make to be run from this directory
|
||||
all:
|
||||
$(MAKE) -C ../../ $(CURDIR)/
|
||||
|
||||
clean:
|
||||
$(MAKE) -C ../../ M=$(CURDIR) clean
|
||||
@rm -f *~
|
||||
|
||||
$(obj)/syscall_nrs.s: $(src)/syscall_nrs.c
|
||||
$(call if_changed_dep,cc_s_c)
|
||||
|
||||
$(obj)/syscall_nrs.h: $(obj)/syscall_nrs.s FORCE
|
||||
$(call filechk,offsets,__SYSCALL_NRS_H__)
|
||||
|
||||
clean-files += syscall_nrs.h
|
||||
|
||||
FORCE:
|
||||
|
||||
|
||||
# Verify LLVM compiler tools are available and bpf target is supported by llc
|
||||
.PHONY: verify_cmds verify_target_bpf $(CLANG) $(LLC)
|
||||
|
||||
verify_cmds: $(CLANG) $(LLC)
|
||||
@for TOOL in $^ ; do \
|
||||
if ! (which -- "$${TOOL}" > /dev/null 2>&1); then \
|
||||
echo "*** ERROR: Cannot find LLVM tool $${TOOL}" ;\
|
||||
exit 1; \
|
||||
else true; fi; \
|
||||
done
|
||||
|
||||
verify_target_bpf: verify_cmds
|
||||
@if ! (${LLC} -march=bpf -mattr=help > /dev/null 2>&1); then \
|
||||
echo "*** ERROR: LLVM (${LLC}) does not support 'bpf' target" ;\
|
||||
echo " NOTICE: LLVM version >= 3.7.1 required" ;\
|
||||
exit 2; \
|
||||
else true; fi
|
||||
|
||||
$(src)/*.c: verify_target_bpf
|
||||
|
||||
# asm/sysreg.h - inline assembly used by it is incompatible with llvm.
|
||||
# But, there is no easy way to fix it, so just exclude it since it is
|
||||
# useless for BPF samples.
|
||||
#
|
||||
# -target bpf option required with SK_MSG programs, this is to ensure
|
||||
# reading 'void *' data types for data and data_end are __u64 reads.
|
||||
$(obj)/%.o: $(src)/%.c
|
||||
$(CLANG) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(EXTRA_CFLAGS) -I$(obj) \
|
||||
-D__KERNEL__ -D__ASM_SYSREG_H -Wno-unused-value -Wno-pointer-sign \
|
||||
-Wno-compare-distinct-pointer-types \
|
||||
-Wno-gnu-variable-sized-type-not-at-end \
|
||||
-Wno-address-of-packed-member -Wno-tautological-compare \
|
||||
-Wno-unknown-warning-option -O2 -target bpf \
|
||||
-emit-llvm -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $@
|
|
@ -1,488 +0,0 @@
|
|||
#Test a bunch of positive cases to verify basic functionality
|
||||
for prog in "--txmsg_redir --txmsg_skb" "--txmsg_redir --txmsg_ingress" "--txmsg" "--txmsg_redir" "--txmsg_redir --txmsg_ingress" "--txmsg_drop"; do
|
||||
for t in "sendmsg" "sendpage"; do
|
||||
for r in 1 10 100; do
|
||||
for i in 1 10 100; do
|
||||
for l in 1 10 100; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
done
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
#Test max iov
|
||||
t="sendmsg"
|
||||
r=1
|
||||
i=1024
|
||||
l=1
|
||||
prog="--txmsg"
|
||||
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
prog="--txmsg_redir"
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
|
||||
# Test max iov with 1k send
|
||||
|
||||
t="sendmsg"
|
||||
r=1
|
||||
i=1024
|
||||
l=1024
|
||||
prog="--txmsg"
|
||||
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
prog="--txmsg_redir"
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
|
||||
# Test apply with 1B
|
||||
r=1
|
||||
i=1024
|
||||
l=1024
|
||||
prog="--txmsg_apply 1"
|
||||
|
||||
for t in "sendmsg" "sendpage"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Test apply with larger value than send
|
||||
r=1
|
||||
i=8
|
||||
l=1024
|
||||
prog="--txmsg_apply 2048"
|
||||
|
||||
for t in "sendmsg" "sendpage"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Test apply with apply that never reaches limit
|
||||
r=1024
|
||||
i=1
|
||||
l=1
|
||||
prog="--txmsg_apply 2048"
|
||||
|
||||
for t in "sendmsg" "sendpage"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Test apply and redirect with 1B
|
||||
r=1
|
||||
i=1024
|
||||
l=1024
|
||||
prog="--txmsg_redir --txmsg_apply 1"
|
||||
|
||||
for t in "sendmsg" "sendpage"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
prog="--txmsg_redir --txmsg_apply 1 --txmsg_ingress"
|
||||
|
||||
for t in "sendmsg" "sendpage"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
prog="--txmsg_redir --txmsg_apply 1 --txmsg_skb"
|
||||
|
||||
for t in "sendmsg" "sendpage"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
|
||||
# Test apply and redirect with larger value than send
|
||||
r=1
|
||||
i=8
|
||||
l=1024
|
||||
prog="--txmsg_redir --txmsg_apply 2048"
|
||||
|
||||
for t in "sendmsg" "sendpage"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
prog="--txmsg_redir --txmsg_apply 2048 --txmsg_ingress"
|
||||
|
||||
for t in "sendmsg" "sendpage"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
prog="--txmsg_redir --txmsg_apply 2048 --txmsg_skb"
|
||||
|
||||
for t in "sendmsg" "sendpage"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
|
||||
# Test apply and redirect with apply that never reaches limit
|
||||
r=1024
|
||||
i=1
|
||||
l=1
|
||||
prog="--txmsg_apply 2048"
|
||||
|
||||
for t in "sendmsg" "sendpage"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Test cork with 1B not really useful but test it anyways
|
||||
r=1
|
||||
i=1024
|
||||
l=1024
|
||||
prog="--txmsg_cork 1"
|
||||
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Test cork with a more reasonable 100B
|
||||
r=1
|
||||
i=1000
|
||||
l=1000
|
||||
prog="--txmsg_cork 100"
|
||||
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Test cork with larger value than send
|
||||
r=1
|
||||
i=8
|
||||
l=1024
|
||||
prog="--txmsg_cork 2048"
|
||||
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Test cork with cork that never reaches limit
|
||||
r=1024
|
||||
i=1
|
||||
l=1
|
||||
prog="--txmsg_cork 2048"
|
||||
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
r=1
|
||||
i=1024
|
||||
l=1024
|
||||
prog="--txmsg_redir --txmsg_cork 1"
|
||||
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Test cork with a more reasonable 100B
|
||||
r=1
|
||||
i=1000
|
||||
l=1000
|
||||
prog="--txmsg_redir --txmsg_cork 100"
|
||||
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Test cork with larger value than send
|
||||
r=1
|
||||
i=8
|
||||
l=1024
|
||||
prog="--txmsg_redir --txmsg_cork 2048"
|
||||
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Test cork with cork that never reaches limit
|
||||
r=1024
|
||||
i=1
|
||||
l=1
|
||||
prog="--txmsg_cork 2048"
|
||||
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
|
||||
# mix and match cork and apply not really useful but valid programs
|
||||
|
||||
# Test apply < cork
|
||||
r=100
|
||||
i=1
|
||||
l=5
|
||||
prog="--txmsg_apply 10 --txmsg_cork 100"
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Try again with larger sizes so we hit overflow case
|
||||
r=100
|
||||
i=1000
|
||||
l=2048
|
||||
prog="--txmsg_apply 4096 --txmsg_cork 8096"
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Test apply > cork
|
||||
r=100
|
||||
i=1
|
||||
l=5
|
||||
prog="--txmsg_apply 100 --txmsg_cork 10"
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Again with larger sizes so we hit overflow cases
|
||||
r=100
|
||||
i=1000
|
||||
l=2048
|
||||
prog="--txmsg_apply 8096 --txmsg_cork 4096"
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
|
||||
# Test apply = cork
|
||||
r=100
|
||||
i=1
|
||||
l=5
|
||||
prog="--txmsg_apply 10 --txmsg_cork 10"
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
r=100
|
||||
i=1000
|
||||
l=2048
|
||||
prog="--txmsg_apply 4096 --txmsg_cork 4096"
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Test apply < cork
|
||||
r=100
|
||||
i=1
|
||||
l=5
|
||||
prog="--txmsg_redir --txmsg_apply 10 --txmsg_cork 100"
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Try again with larger sizes so we hit overflow case
|
||||
r=100
|
||||
i=1000
|
||||
l=2048
|
||||
prog="--txmsg_redir --txmsg_apply 4096 --txmsg_cork 8096"
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Test apply > cork
|
||||
r=100
|
||||
i=1
|
||||
l=5
|
||||
prog="--txmsg_redir --txmsg_apply 100 --txmsg_cork 10"
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Again with larger sizes so we hit overflow cases
|
||||
r=100
|
||||
i=1000
|
||||
l=2048
|
||||
prog="--txmsg_redir --txmsg_apply 8096 --txmsg_cork 4096"
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
|
||||
# Test apply = cork
|
||||
r=100
|
||||
i=1
|
||||
l=5
|
||||
prog="--txmsg_redir --txmsg_apply 10 --txmsg_cork 10"
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
r=100
|
||||
i=1000
|
||||
l=2048
|
||||
prog="--txmsg_redir --txmsg_apply 4096 --txmsg_cork 4096"
|
||||
for t in "sendpage" "sendmsg"; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Tests for bpf_msg_pull_data()
|
||||
for i in `seq 99 100 1600`; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t sendpage -r 16 -i 1 -l 100 \
|
||||
--txmsg --txmsg_start 0 --txmsg_end $i --txmsg_cork 1600"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
for i in `seq 199 100 1600`; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t sendpage -r 16 -i 1 -l 100 \
|
||||
--txmsg --txmsg_start 100 --txmsg_end $i --txmsg_cork 1600"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t sendpage -r 16 -i 1 -l 100 \
|
||||
--txmsg --txmsg_start 1500 --txmsg_end 1600 --txmsg_cork 1600"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t sendpage -r 16 -i 1 -l 100 \
|
||||
--txmsg --txmsg_start 1111 --txmsg_end 1112 --txmsg_cork 1600"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t sendpage -r 16 -i 1 -l 100 \
|
||||
--txmsg --txmsg_start 1111 --txmsg_end 0 --txmsg_cork 1600"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t sendpage -r 16 -i 1 -l 100 \
|
||||
--txmsg --txmsg_start 0 --txmsg_end 1601 --txmsg_cork 1600"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t sendpage -r 16 -i 1 -l 100 \
|
||||
--txmsg --txmsg_start 0 --txmsg_end 1601 --txmsg_cork 1602"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
|
||||
# Run through gamut again with start and end
|
||||
for prog in "--txmsg" "--txmsg_redir" "--txmsg_drop"; do
|
||||
for t in "sendmsg" "sendpage"; do
|
||||
for r in 1 10 100; do
|
||||
for i in 1 10 100; do
|
||||
for l in 1 10 100; do
|
||||
TEST="./sockmap --cgroup /mnt/cgroup2/ -t $t -r $r -i $i -l $l $prog --txmsg_start 1 --txmsg_end 2"
|
||||
echo $TEST
|
||||
$TEST
|
||||
sleep 2
|
||||
done
|
||||
done
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
# Some specific tests to cover specific code paths
|
||||
./sockmap --cgroup /mnt/cgroup2/ -t sendpage \
|
||||
-r 5 -i 1 -l 1 --txmsg_redir --txmsg_cork 5 --txmsg_apply 3
|
||||
./sockmap --cgroup /mnt/cgroup2/ -t sendmsg \
|
||||
-r 5 -i 1 -l 1 --txmsg_redir --txmsg_cork 5 --txmsg_apply 3
|
||||
./sockmap --cgroup /mnt/cgroup2/ -t sendpage \
|
||||
-r 5 -i 1 -l 1 --txmsg_redir --txmsg_cork 5 --txmsg_apply 5
|
||||
./sockmap --cgroup /mnt/cgroup2/ -t sendmsg \
|
||||
-r 5 -i 1 -l 1 --txmsg_redir --txmsg_cork 5 --txmsg_apply 5
|
|
@ -0,0 +1,421 @@
|
|||
#!/usr/bin/python3
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Copyright (C) 2018 Netronome Systems, Inc.
|
||||
|
||||
# In case user attempts to run with Python 2.
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import sys, os
|
||||
|
||||
class NoHelperFound(BaseException):
|
||||
pass
|
||||
|
||||
class ParsingError(BaseException):
|
||||
def __init__(self, line='<line not provided>', reader=None):
|
||||
if reader:
|
||||
BaseException.__init__(self,
|
||||
'Error at file offset %d, parsing line: %s' %
|
||||
(reader.tell(), line))
|
||||
else:
|
||||
BaseException.__init__(self, 'Error parsing line: %s' % line)
|
||||
|
||||
class Helper(object):
|
||||
"""
|
||||
An object representing the description of an eBPF helper function.
|
||||
@proto: function prototype of the helper function
|
||||
@desc: textual description of the helper function
|
||||
@ret: description of the return value of the helper function
|
||||
"""
|
||||
def __init__(self, proto='', desc='', ret=''):
|
||||
self.proto = proto
|
||||
self.desc = desc
|
||||
self.ret = ret
|
||||
|
||||
def proto_break_down(self):
|
||||
"""
|
||||
Break down helper function protocol into smaller chunks: return type,
|
||||
name, distincts arguments.
|
||||
"""
|
||||
arg_re = re.compile('^((const )?(struct )?(\w+|...))( (\**)(\w+))?$')
|
||||
res = {}
|
||||
proto_re = re.compile('^(.+) (\**)(\w+)\(((([^,]+)(, )?){1,5})\)$')
|
||||
|
||||
capture = proto_re.match(self.proto)
|
||||
res['ret_type'] = capture.group(1)
|
||||
res['ret_star'] = capture.group(2)
|
||||
res['name'] = capture.group(3)
|
||||
res['args'] = []
|
||||
|
||||
args = capture.group(4).split(', ')
|
||||
for a in args:
|
||||
capture = arg_re.match(a)
|
||||
res['args'].append({
|
||||
'type' : capture.group(1),
|
||||
'star' : capture.group(6),
|
||||
'name' : capture.group(7)
|
||||
})
|
||||
|
||||
return res
|
||||
|
||||
class HeaderParser(object):
|
||||
"""
|
||||
An object used to parse a file in order to extract the documentation of a
|
||||
list of eBPF helper functions. All the helpers that can be retrieved are
|
||||
stored as Helper object, in the self.helpers() array.
|
||||
@filename: name of file to parse, usually include/uapi/linux/bpf.h in the
|
||||
kernel tree
|
||||
"""
|
||||
def __init__(self, filename):
|
||||
self.reader = open(filename, 'r')
|
||||
self.line = ''
|
||||
self.helpers = []
|
||||
|
||||
def parse_helper(self):
|
||||
proto = self.parse_proto()
|
||||
desc = self.parse_desc()
|
||||
ret = self.parse_ret()
|
||||
return Helper(proto=proto, desc=desc, ret=ret)
|
||||
|
||||
def parse_proto(self):
|
||||
# Argument can be of shape:
|
||||
# - "void"
|
||||
# - "type name"
|
||||
# - "type *name"
|
||||
# - Same as above, with "const" and/or "struct" in front of type
|
||||
# - "..." (undefined number of arguments, for bpf_trace_printk())
|
||||
# There is at least one term ("void"), and at most five arguments.
|
||||
p = re.compile('^ \* ((.+) \**\w+\((((const )?(struct )?(\w+|\.\.\.)( \**\w+)?)(, )?){1,5}\))$')
|
||||
capture = p.match(self.line)
|
||||
if not capture:
|
||||
raise NoHelperFound
|
||||
self.line = self.reader.readline()
|
||||
return capture.group(1)
|
||||
|
||||
def parse_desc(self):
|
||||
p = re.compile('^ \* \tDescription$')
|
||||
capture = p.match(self.line)
|
||||
if not capture:
|
||||
# Helper can have empty description and we might be parsing another
|
||||
# attribute: return but do not consume.
|
||||
return ''
|
||||
# Description can be several lines, some of them possibly empty, and it
|
||||
# stops when another subsection title is met.
|
||||
desc = ''
|
||||
while True:
|
||||
self.line = self.reader.readline()
|
||||
if self.line == ' *\n':
|
||||
desc += '\n'
|
||||
else:
|
||||
p = re.compile('^ \* \t\t(.*)')
|
||||
capture = p.match(self.line)
|
||||
if capture:
|
||||
desc += capture.group(1) + '\n'
|
||||
else:
|
||||
break
|
||||
return desc
|
||||
|
||||
def parse_ret(self):
|
||||
p = re.compile('^ \* \tReturn$')
|
||||
capture = p.match(self.line)
|
||||
if not capture:
|
||||
# Helper can have empty retval and we might be parsing another
|
||||
# attribute: return but do not consume.
|
||||
return ''
|
||||
# Return value description can be several lines, some of them possibly
|
||||
# empty, and it stops when another subsection title is met.
|
||||
ret = ''
|
||||
while True:
|
||||
self.line = self.reader.readline()
|
||||
if self.line == ' *\n':
|
||||
ret += '\n'
|
||||
else:
|
||||
p = re.compile('^ \* \t\t(.*)')
|
||||
capture = p.match(self.line)
|
||||
if capture:
|
||||
ret += capture.group(1) + '\n'
|
||||
else:
|
||||
break
|
||||
return ret
|
||||
|
||||
def run(self):
|
||||
# Advance to start of helper function descriptions.
|
||||
offset = self.reader.read().find('* Start of BPF helper function descriptions:')
|
||||
if offset == -1:
|
||||
raise Exception('Could not find start of eBPF helper descriptions list')
|
||||
self.reader.seek(offset)
|
||||
self.reader.readline()
|
||||
self.reader.readline()
|
||||
self.line = self.reader.readline()
|
||||
|
||||
while True:
|
||||
try:
|
||||
helper = self.parse_helper()
|
||||
self.helpers.append(helper)
|
||||
except NoHelperFound:
|
||||
break
|
||||
|
||||
self.reader.close()
|
||||
print('Parsed description of %d helper function(s)' % len(self.helpers),
|
||||
file=sys.stderr)
|
||||
|
||||
###############################################################################
|
||||
|
||||
class Printer(object):
|
||||
"""
|
||||
A generic class for printers. Printers should be created with an array of
|
||||
Helper objects, and implement a way to print them in the desired fashion.
|
||||
@helpers: array of Helper objects to print to standard output
|
||||
"""
|
||||
def __init__(self, helpers):
|
||||
self.helpers = helpers
|
||||
|
||||
def print_header(self):
|
||||
pass
|
||||
|
||||
def print_footer(self):
|
||||
pass
|
||||
|
||||
def print_one(self, helper):
|
||||
pass
|
||||
|
||||
def print_all(self):
|
||||
self.print_header()
|
||||
for helper in self.helpers:
|
||||
self.print_one(helper)
|
||||
self.print_footer()
|
||||
|
||||
class PrinterRST(Printer):
|
||||
"""
|
||||
A printer for dumping collected information about helpers as a ReStructured
|
||||
Text page compatible with the rst2man program, which can be used to
|
||||
generate a manual page for the helpers.
|
||||
@helpers: array of Helper objects to print to standard output
|
||||
"""
|
||||
def print_header(self):
|
||||
header = '''\
|
||||
.. Copyright (C) All BPF authors and contributors from 2014 to present.
|
||||
.. See git log include/uapi/linux/bpf.h in kernel tree for details.
|
||||
..
|
||||
.. %%%LICENSE_START(VERBATIM)
|
||||
.. Permission is granted to make and distribute verbatim copies of this
|
||||
.. manual provided the copyright notice and this permission notice are
|
||||
.. preserved on all copies.
|
||||
..
|
||||
.. Permission is granted to copy and distribute modified versions of this
|
||||
.. manual under the conditions for verbatim copying, provided that the
|
||||
.. entire resulting derived work is distributed under the terms of a
|
||||
.. permission notice identical to this one.
|
||||
..
|
||||
.. Since the Linux kernel and libraries are constantly changing, this
|
||||
.. manual page may be incorrect or out-of-date. The author(s) assume no
|
||||
.. responsibility for errors or omissions, or for damages resulting from
|
||||
.. the use of the information contained herein. The author(s) may not
|
||||
.. have taken the same level of care in the production of this manual,
|
||||
.. which is licensed free of charge, as they might when working
|
||||
.. professionally.
|
||||
..
|
||||
.. Formatted or processed versions of this manual, if unaccompanied by
|
||||
.. the source, must acknowledge the copyright and authors of this work.
|
||||
.. %%%LICENSE_END
|
||||
..
|
||||
.. Please do not edit this file. It was generated from the documentation
|
||||
.. located in file include/uapi/linux/bpf.h of the Linux kernel sources
|
||||
.. (helpers description), and from scripts/bpf_helpers_doc.py in the same
|
||||
.. repository (header and footer).
|
||||
|
||||
===========
|
||||
BPF-HELPERS
|
||||
===========
|
||||
-------------------------------------------------------------------------------
|
||||
list of eBPF helper functions
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
:Manual section: 7
|
||||
|
||||
DESCRIPTION
|
||||
===========
|
||||
|
||||
The extended Berkeley Packet Filter (eBPF) subsystem consists in programs
|
||||
written in a pseudo-assembly language, then attached to one of the several
|
||||
kernel hooks and run in reaction of specific events. This framework differs
|
||||
from the older, "classic" BPF (or "cBPF") in several aspects, one of them being
|
||||
the ability to call special functions (or "helpers") from within a program.
|
||||
These functions are restricted to a white-list of helpers defined in the
|
||||
kernel.
|
||||
|
||||
These helpers are used by eBPF programs to interact with the system, or with
|
||||
the context in which they work. For instance, they can be used to print
|
||||
debugging messages, to get the time since the system was booted, to interact
|
||||
with eBPF maps, or to manipulate network packets. Since there are several eBPF
|
||||
program types, and that they do not run in the same context, each program type
|
||||
can only call a subset of those helpers.
|
||||
|
||||
Due to eBPF conventions, a helper can not have more than five arguments.
|
||||
|
||||
Internally, eBPF programs call directly into the compiled helper functions
|
||||
without requiring any foreign-function interface. As a result, calling helpers
|
||||
introduces no overhead, thus offering excellent performance.
|
||||
|
||||
This document is an attempt to list and document the helpers available to eBPF
|
||||
developers. They are sorted by chronological order (the oldest helpers in the
|
||||
kernel at the top).
|
||||
|
||||
HELPERS
|
||||
=======
|
||||
'''
|
||||
print(header)
|
||||
|
||||
def print_footer(self):
|
||||
footer = '''
|
||||
EXAMPLES
|
||||
========
|
||||
|
||||
Example usage for most of the eBPF helpers listed in this manual page are
|
||||
available within the Linux kernel sources, at the following locations:
|
||||
|
||||
* *samples/bpf/*
|
||||
* *tools/testing/selftests/bpf/*
|
||||
|
||||
LICENSE
|
||||
=======
|
||||
|
||||
eBPF programs can have an associated license, passed along with the bytecode
|
||||
instructions to the kernel when the programs are loaded. The format for that
|
||||
string is identical to the one in use for kernel modules (Dual licenses, such
|
||||
as "Dual BSD/GPL", may be used). Some helper functions are only accessible to
|
||||
programs that are compatible with the GNU Privacy License (GPL).
|
||||
|
||||
In order to use such helpers, the eBPF program must be loaded with the correct
|
||||
license string passed (via **attr**) to the **bpf**\ () system call, and this
|
||||
generally translates into the C source code of the program containing a line
|
||||
similar to the following:
|
||||
|
||||
::
|
||||
|
||||
char ____license[] __attribute__((section("license"), used)) = "GPL";
|
||||
|
||||
IMPLEMENTATION
|
||||
==============
|
||||
|
||||
This manual page is an effort to document the existing eBPF helper functions.
|
||||
But as of this writing, the BPF sub-system is under heavy development. New eBPF
|
||||
program or map types are added, along with new helper functions. Some helpers
|
||||
are occasionally made available for additional program types. So in spite of
|
||||
the efforts of the community, this page might not be up-to-date. If you want to
|
||||
check by yourself what helper functions exist in your kernel, or what types of
|
||||
programs they can support, here are some files among the kernel tree that you
|
||||
may be interested in:
|
||||
|
||||
* *include/uapi/linux/bpf.h* is the main BPF header. It contains the full list
|
||||
of all helper functions, as well as many other BPF definitions including most
|
||||
of the flags, structs or constants used by the helpers.
|
||||
* *net/core/filter.c* contains the definition of most network-related helper
|
||||
functions, and the list of program types from which they can be used.
|
||||
* *kernel/trace/bpf_trace.c* is the equivalent for most tracing program-related
|
||||
helpers.
|
||||
* *kernel/bpf/verifier.c* contains the functions used to check that valid types
|
||||
of eBPF maps are used with a given helper function.
|
||||
* *kernel/bpf/* directory contains other files in which additional helpers are
|
||||
defined (for cgroups, sockmaps, etc.).
|
||||
|
||||
Compatibility between helper functions and program types can generally be found
|
||||
in the files where helper functions are defined. Look for the **struct
|
||||
bpf_func_proto** objects and for functions returning them: these functions
|
||||
contain a list of helpers that a given program type can call. Note that the
|
||||
**default:** label of the **switch ... case** used to filter helpers can call
|
||||
other functions, themselves allowing access to additional helpers. The
|
||||
requirement for GPL license is also in those **struct bpf_func_proto**.
|
||||
|
||||
Compatibility between helper functions and map types can be found in the
|
||||
**check_map_func_compatibility**\ () function in file *kernel/bpf/verifier.c*.
|
||||
|
||||
Helper functions that invalidate the checks on **data** and **data_end**
|
||||
pointers for network processing are listed in function
|
||||
**bpf_helper_changes_pkt_data**\ () in file *net/core/filter.c*.
|
||||
|
||||
SEE ALSO
|
||||
========
|
||||
|
||||
**bpf**\ (2),
|
||||
**cgroups**\ (7),
|
||||
**ip**\ (8),
|
||||
**perf_event_open**\ (2),
|
||||
**sendmsg**\ (2),
|
||||
**socket**\ (7),
|
||||
**tc-bpf**\ (8)'''
|
||||
print(footer)
|
||||
|
||||
def print_proto(self, helper):
|
||||
"""
|
||||
Format function protocol with bold and italics markers. This makes RST
|
||||
file less readable, but gives nice results in the manual page.
|
||||
"""
|
||||
proto = helper.proto_break_down()
|
||||
|
||||
print('**%s %s%s(' % (proto['ret_type'],
|
||||
proto['ret_star'].replace('*', '\\*'),
|
||||
proto['name']),
|
||||
end='')
|
||||
|
||||
comma = ''
|
||||
for a in proto['args']:
|
||||
one_arg = '{}{}'.format(comma, a['type'])
|
||||
if a['name']:
|
||||
if a['star']:
|
||||
one_arg += ' {}**\ '.format(a['star'].replace('*', '\\*'))
|
||||
else:
|
||||
one_arg += '** '
|
||||
one_arg += '*{}*\\ **'.format(a['name'])
|
||||
comma = ', '
|
||||
print(one_arg, end='')
|
||||
|
||||
print(')**')
|
||||
|
||||
def print_one(self, helper):
|
||||
self.print_proto(helper)
|
||||
|
||||
if (helper.desc):
|
||||
print('\tDescription')
|
||||
# Do not strip all newline characters: formatted code at the end of
|
||||
# a section must be followed by a blank line.
|
||||
for line in re.sub('\n$', '', helper.desc, count=1).split('\n'):
|
||||
print('{}{}'.format('\t\t' if line else '', line))
|
||||
|
||||
if (helper.ret):
|
||||
print('\tReturn')
|
||||
for line in helper.ret.rstrip().split('\n'):
|
||||
print('{}{}'.format('\t\t' if line else '', line))
|
||||
|
||||
print('')
|
||||
|
||||
###############################################################################
|
||||
|
||||
# If script is launched from scripts/ from kernel tree and can access
|
||||
# ../include/uapi/linux/bpf.h, use it as a default name for the file to parse,
|
||||
# otherwise the --filename argument will be required from the command line.
|
||||
script = os.path.abspath(sys.argv[0])
|
||||
linuxRoot = os.path.dirname(os.path.dirname(script))
|
||||
bpfh = os.path.join(linuxRoot, 'include/uapi/linux/bpf.h')
|
||||
|
||||
argParser = argparse.ArgumentParser(description="""
|
||||
Parse eBPF header file and generate documentation for eBPF helper functions.
|
||||
The RST-formatted output produced can be turned into a manual page with the
|
||||
rst2man utility.
|
||||
""")
|
||||
if (os.path.isfile(bpfh)):
|
||||
argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h',
|
||||
default=bpfh)
|
||||
else:
|
||||
argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h')
|
||||
args = argParser.parse_args()
|
||||
|
||||
# Parse file.
|
||||
headerParser = HeaderParser(args.filename)
|
||||
headerParser.run()
|
||||
|
||||
# Print formatted output to standard output.
|
||||
printer = PrinterRST(headerParser.helpers)
|
||||
printer.print_all()
|
|
@ -95,7 +95,7 @@ EXAMPLES
|
|||
**# bpftool prog show**
|
||||
::
|
||||
|
||||
10: xdp name some_prog tag 005a3d2123620c8b
|
||||
10: xdp name some_prog tag 005a3d2123620c8b gpl
|
||||
loaded_at Sep 29/20:11 uid 0
|
||||
xlated 528B jited 370B memlock 4096B map_ids 10
|
||||
|
||||
|
@ -108,6 +108,7 @@ EXAMPLES
|
|||
"id": 10,
|
||||
"type": "xdp",
|
||||
"tag": "005a3d2123620c8b",
|
||||
"gpl_compatible": true,
|
||||
"loaded_at": "Sep 29/20:11",
|
||||
"uid": 0,
|
||||
"bytes_xlated": 528,
|
||||
|
|
|
@ -235,6 +235,8 @@ 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]);
|
||||
|
||||
jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible);
|
||||
|
||||
print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
|
||||
|
||||
if (info->load_time) {
|
||||
|
@ -295,6 +297,7 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd)
|
|||
printf("tag ");
|
||||
fprint_hex(stdout, info->tag, BPF_TAG_SIZE, "");
|
||||
print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
|
||||
printf("%s", info->gpl_compatible ? " gpl" : "");
|
||||
printf("\n");
|
||||
|
||||
if (info->load_time) {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -6,9 +6,7 @@
|
|||
#include <linux/types.h>
|
||||
|
||||
#define BTF_MAGIC 0xeB9F
|
||||
#define BTF_MAGIC_SWAP 0x9FeB
|
||||
#define BTF_VERSION 1
|
||||
#define BTF_FLAGS_COMPR 0x01
|
||||
|
||||
struct btf_header {
|
||||
__u16 magic;
|
||||
|
@ -43,7 +41,7 @@ struct btf_header {
|
|||
#define BTF_STR_OFFSET(ref) ((ref) & BTF_MAX_NAME_OFFSET)
|
||||
|
||||
struct btf_type {
|
||||
__u32 name;
|
||||
__u32 name_off;
|
||||
/* "info" bits arrangement
|
||||
* bits 0-15: vlen (e.g. # of struct's members)
|
||||
* bits 16-23: unused
|
||||
|
@ -105,7 +103,7 @@ struct btf_type {
|
|||
* info in "struct btf_type").
|
||||
*/
|
||||
struct btf_enum {
|
||||
__u32 name;
|
||||
__u32 name_off;
|
||||
__s32 val;
|
||||
};
|
||||
|
||||
|
@ -122,7 +120,7 @@ struct btf_array {
|
|||
* "struct btf_type").
|
||||
*/
|
||||
struct btf_member {
|
||||
__u32 name;
|
||||
__u32 name_off;
|
||||
__u32 type;
|
||||
__u32 offset; /* offset in bits */
|
||||
};
|
||||
|
|
|
@ -281,7 +281,7 @@ int32_t btf__find_by_name(const struct btf *btf, const char *type_name)
|
|||
|
||||
for (i = 1; i <= btf->nr_types; i++) {
|
||||
const struct btf_type *t = btf->types[i];
|
||||
const char *name = btf_name_by_offset(btf, t->name);
|
||||
const char *name = btf_name_by_offset(btf, t->name_off);
|
||||
|
||||
if (name && !strcmp(type_name, name))
|
||||
return i;
|
||||
|
|
|
@ -1961,8 +1961,8 @@ BPF_PROG_TYPE_FNS(raw_tracepoint, BPF_PROG_TYPE_RAW_TRACEPOINT);
|
|||
BPF_PROG_TYPE_FNS(xdp, BPF_PROG_TYPE_XDP);
|
||||
BPF_PROG_TYPE_FNS(perf_event, BPF_PROG_TYPE_PERF_EVENT);
|
||||
|
||||
static void bpf_program__set_expected_attach_type(struct bpf_program *prog,
|
||||
enum bpf_attach_type type)
|
||||
void bpf_program__set_expected_attach_type(struct bpf_program *prog,
|
||||
enum bpf_attach_type type)
|
||||
{
|
||||
prog->expected_attach_type = type;
|
||||
}
|
||||
|
|
|
@ -193,6 +193,8 @@ int bpf_program__set_sched_act(struct bpf_program *prog);
|
|||
int bpf_program__set_xdp(struct bpf_program *prog);
|
||||
int bpf_program__set_perf_event(struct bpf_program *prog);
|
||||
void bpf_program__set_type(struct bpf_program *prog, enum bpf_prog_type type);
|
||||
void bpf_program__set_expected_attach_type(struct bpf_program *prog,
|
||||
enum bpf_attach_type type);
|
||||
|
||||
bool bpf_program__is_socket_filter(struct bpf_program *prog);
|
||||
bool bpf_program__is_tracepoint(struct bpf_program *prog);
|
||||
|
|
|
@ -15,3 +15,4 @@ test_libbpf_open
|
|||
test_sock
|
||||
test_sock_addr
|
||||
urandom_read
|
||||
test_btf
|
||||
|
|
|
@ -24,7 +24,7 @@ urandom_read: urandom_read.c
|
|||
# Order correspond to 'make run_tests' order
|
||||
TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \
|
||||
test_align test_verifier_log test_dev_cgroup test_tcpbpf_user \
|
||||
test_sock test_sock_addr test_btf
|
||||
test_sock test_btf test_sockmap
|
||||
|
||||
TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \
|
||||
test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \
|
||||
|
@ -32,7 +32,7 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test
|
|||
test_l4lb_noinline.o test_xdp_noinline.o test_stacktrace_map.o \
|
||||
sample_map_ret0.o test_tcpbpf_kern.o test_stacktrace_build_id.o \
|
||||
sockmap_tcp_msg_prog.o connect4_prog.o connect6_prog.o test_adjust_tail.o \
|
||||
test_btf_haskv.o test_btf_nokv.o
|
||||
test_btf_haskv.o test_btf_nokv.o test_sockmap_kern.o test_tunnel_kern.o
|
||||
|
||||
# Order correspond to 'make run_tests' order
|
||||
TEST_PROGS := test_kmod.sh \
|
||||
|
@ -40,10 +40,11 @@ TEST_PROGS := test_kmod.sh \
|
|||
test_xdp_redirect.sh \
|
||||
test_xdp_meta.sh \
|
||||
test_offload.py \
|
||||
test_sock_addr.sh
|
||||
test_sock_addr.sh \
|
||||
test_tunnel.sh
|
||||
|
||||
# Compile but not part of 'make run_tests'
|
||||
TEST_GEN_PROGS_EXTENDED = test_libbpf_open
|
||||
TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr
|
||||
|
||||
include ../lib.mk
|
||||
|
||||
|
@ -56,6 +57,7 @@ $(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/libbpf.a
|
|||
$(OUTPUT)/test_dev_cgroup: cgroup_helpers.c
|
||||
$(OUTPUT)/test_sock: cgroup_helpers.c
|
||||
$(OUTPUT)/test_sock_addr: cgroup_helpers.c
|
||||
$(OUTPUT)/test_sockmap: cgroup_helpers.c
|
||||
|
||||
.PHONY: force
|
||||
|
||||
|
|
|
@ -98,7 +98,9 @@ static int (*bpf_bind)(void *ctx, void *addr, int addr_len) =
|
|||
(void *) BPF_FUNC_bind;
|
||||
static int (*bpf_xdp_adjust_tail)(void *ctx, int offset) =
|
||||
(void *) BPF_FUNC_xdp_adjust_tail;
|
||||
|
||||
static int (*bpf_skb_get_xfrm_state)(void *ctx, int index, void *state,
|
||||
int size, int flags) =
|
||||
(void *) BPF_FUNC_skb_get_xfrm_state;
|
||||
|
||||
/* llvm builtin functions that eBPF C program may use to
|
||||
* emit BPF_LD_ABS and BPF_LD_IND instructions
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,20 +1,19 @@
|
|||
/* Copyright (c) 2017 Covalent IO, Inc. http://covalent.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*/
|
||||
#include <uapi/linux/bpf.h>
|
||||
#include <uapi/linux/if_ether.h>
|
||||
#include <uapi/linux/if_packet.h>
|
||||
#include <uapi/linux/ip.h>
|
||||
#include "../../tools/testing/selftests/bpf/bpf_helpers.h"
|
||||
#include "../../tools/testing/selftests/bpf/bpf_endian.h"
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2017-2018 Covalent IO, Inc. http://covalent.io
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/pkt_cls.h>
|
||||
#include <sys/socket.h>
|
||||
#include "bpf_helpers.h"
|
||||
#include "bpf_endian.h"
|
||||
|
||||
/* Sockmap sample program connects a client and a backend together
|
||||
* using cgroups.
|
||||
|
@ -337,5 +336,5 @@ int bpf_prog10(struct sk_msg_md *msg)
|
|||
return SK_DROP;
|
||||
}
|
||||
|
||||
|
||||
int _version SEC("version") = 1;
|
||||
char _license[] SEC("license") = "GPL";
|
|
@ -0,0 +1,729 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# End-to-end eBPF tunnel test suite
|
||||
# The script tests BPF network tunnel implementation.
|
||||
#
|
||||
# Topology:
|
||||
# ---------
|
||||
# root namespace | at_ns0 namespace
|
||||
# |
|
||||
# ----------- | -----------
|
||||
# | tnl dev | | | tnl dev | (overlay network)
|
||||
# ----------- | -----------
|
||||
# metadata-mode | native-mode
|
||||
# with bpf |
|
||||
# |
|
||||
# ---------- | ----------
|
||||
# | veth1 | --------- | veth0 | (underlay network)
|
||||
# ---------- peer ----------
|
||||
#
|
||||
#
|
||||
# Device Configuration
|
||||
# --------------------
|
||||
# Root namespace with metadata-mode tunnel + BPF
|
||||
# Device names and addresses:
|
||||
# veth1 IP: 172.16.1.200, IPv6: 00::22 (underlay)
|
||||
# tunnel dev <type>11, ex: gre11, IPv4: 10.1.1.200 (overlay)
|
||||
#
|
||||
# Namespace at_ns0 with native tunnel
|
||||
# Device names and addresses:
|
||||
# veth0 IPv4: 172.16.1.100, IPv6: 00::11 (underlay)
|
||||
# tunnel dev <type>00, ex: gre00, IPv4: 10.1.1.100 (overlay)
|
||||
#
|
||||
#
|
||||
# End-to-end ping packet flow
|
||||
# ---------------------------
|
||||
# Most of the tests start by namespace creation, device configuration,
|
||||
# then ping the underlay and overlay network. When doing 'ping 10.1.1.100'
|
||||
# from root namespace, the following operations happen:
|
||||
# 1) Route lookup shows 10.1.1.100/24 belongs to tnl dev, fwd to tnl dev.
|
||||
# 2) Tnl device's egress BPF program is triggered and set the tunnel metadata,
|
||||
# with remote_ip=172.16.1.200 and others.
|
||||
# 3) Outer tunnel header is prepended and route the packet to veth1's egress
|
||||
# 4) veth0's ingress queue receive the tunneled packet at namespace at_ns0
|
||||
# 5) Tunnel protocol handler, ex: vxlan_rcv, decap the packet
|
||||
# 6) Forward the packet to the overlay tnl dev
|
||||
|
||||
PING_ARG="-c 3 -w 10 -q"
|
||||
ret=0
|
||||
GREEN='\033[0;92m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
config_device()
|
||||
{
|
||||
ip netns add at_ns0
|
||||
ip link add veth0 type veth peer name veth1
|
||||
ip link set veth0 netns at_ns0
|
||||
ip netns exec at_ns0 ip addr add 172.16.1.100/24 dev veth0
|
||||
ip netns exec at_ns0 ip link set dev veth0 up
|
||||
ip link set dev veth1 up mtu 1500
|
||||
ip addr add dev veth1 172.16.1.200/24
|
||||
}
|
||||
|
||||
add_gre_tunnel()
|
||||
{
|
||||
# at_ns0 namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE seq key 2 \
|
||||
local 172.16.1.100 remote 172.16.1.200
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE key 2 external
|
||||
ip link set dev $DEV up
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
}
|
||||
|
||||
add_ip6gretap_tunnel()
|
||||
{
|
||||
|
||||
# assign ipv6 address
|
||||
ip netns exec at_ns0 ip addr add ::11/96 dev veth0
|
||||
ip netns exec at_ns0 ip link set dev veth0 up
|
||||
ip addr add dev veth1 ::22/96
|
||||
ip link set dev veth1 up
|
||||
|
||||
# at_ns0 namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE seq flowlabel 0xbcdef key 2 \
|
||||
local ::11 remote ::22
|
||||
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS fc80::100/96
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE external
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
ip addr add dev $DEV fc80::200/24
|
||||
ip link set dev $DEV up
|
||||
}
|
||||
|
||||
add_erspan_tunnel()
|
||||
{
|
||||
# at_ns0 namespace
|
||||
if [ "$1" == "v1" ]; then
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE seq key 2 \
|
||||
local 172.16.1.100 remote 172.16.1.200 \
|
||||
erspan_ver 1 erspan 123
|
||||
else
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE seq key 2 \
|
||||
local 172.16.1.100 remote 172.16.1.200 \
|
||||
erspan_ver 2 erspan_dir egress erspan_hwid 3
|
||||
fi
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE external
|
||||
ip link set dev $DEV up
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
}
|
||||
|
||||
add_ip6erspan_tunnel()
|
||||
{
|
||||
|
||||
# assign ipv6 address
|
||||
ip netns exec at_ns0 ip addr add ::11/96 dev veth0
|
||||
ip netns exec at_ns0 ip link set dev veth0 up
|
||||
ip addr add dev veth1 ::22/96
|
||||
ip link set dev veth1 up
|
||||
|
||||
# at_ns0 namespace
|
||||
if [ "$1" == "v1" ]; then
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE seq key 2 \
|
||||
local ::11 remote ::22 \
|
||||
erspan_ver 1 erspan 123
|
||||
else
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE seq key 2 \
|
||||
local ::11 remote ::22 \
|
||||
erspan_ver 2 erspan_dir egress erspan_hwid 7
|
||||
fi
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE external
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
ip link set dev $DEV up
|
||||
}
|
||||
|
||||
add_vxlan_tunnel()
|
||||
{
|
||||
# Set static ARP entry here because iptables set-mark works
|
||||
# on L3 packet, as a result not applying to ARP packets,
|
||||
# causing errors at get_tunnel_{key/opt}.
|
||||
|
||||
# at_ns0 namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE \
|
||||
id 2 dstport 4789 gbp remote 172.16.1.200
|
||||
ip netns exec at_ns0 \
|
||||
ip link set dev $DEV_NS address 52:54:00:d9:01:00 up
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
ip netns exec at_ns0 arp -s 10.1.1.200 52:54:00:d9:02:00
|
||||
ip netns exec at_ns0 iptables -A OUTPUT -j MARK --set-mark 0x800FF
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE external gbp dstport 4789
|
||||
ip link set dev $DEV address 52:54:00:d9:02:00 up
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
arp -s 10.1.1.100 52:54:00:d9:01:00
|
||||
}
|
||||
|
||||
add_ip6vxlan_tunnel()
|
||||
{
|
||||
#ip netns exec at_ns0 ip -4 addr del 172.16.1.100 dev veth0
|
||||
ip netns exec at_ns0 ip -6 addr add ::11/96 dev veth0
|
||||
ip netns exec at_ns0 ip link set dev veth0 up
|
||||
#ip -4 addr del 172.16.1.200 dev veth1
|
||||
ip -6 addr add dev veth1 ::22/96
|
||||
ip link set dev veth1 up
|
||||
|
||||
# at_ns0 namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE id 22 dstport 4789 \
|
||||
local ::11 remote ::22
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE external dstport 4789
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
ip link set dev $DEV up
|
||||
}
|
||||
|
||||
add_geneve_tunnel()
|
||||
{
|
||||
# at_ns0 namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE \
|
||||
id 2 dstport 6081 remote 172.16.1.200
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE dstport 6081 external
|
||||
ip link set dev $DEV up
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
}
|
||||
|
||||
add_ip6geneve_tunnel()
|
||||
{
|
||||
ip netns exec at_ns0 ip addr add ::11/96 dev veth0
|
||||
ip netns exec at_ns0 ip link set dev veth0 up
|
||||
ip addr add dev veth1 ::22/96
|
||||
ip link set dev veth1 up
|
||||
|
||||
# at_ns0 namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE id 22 \
|
||||
remote ::22 # geneve has no local option
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE external
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
ip link set dev $DEV up
|
||||
}
|
||||
|
||||
add_ipip_tunnel()
|
||||
{
|
||||
# at_ns0 namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE \
|
||||
local 172.16.1.100 remote 172.16.1.200
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE external
|
||||
ip link set dev $DEV up
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
}
|
||||
|
||||
add_ipip6tnl_tunnel()
|
||||
{
|
||||
ip netns exec at_ns0 ip addr add ::11/96 dev veth0
|
||||
ip netns exec at_ns0 ip link set dev veth0 up
|
||||
ip addr add dev veth1 ::22/96
|
||||
ip link set dev veth1 up
|
||||
|
||||
# at_ns0 namespace
|
||||
ip netns exec at_ns0 \
|
||||
ip link add dev $DEV_NS type $TYPE \
|
||||
local ::11 remote ::22
|
||||
ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
|
||||
ip netns exec at_ns0 ip link set dev $DEV_NS up
|
||||
|
||||
# root namespace
|
||||
ip link add dev $DEV type $TYPE external
|
||||
ip addr add dev $DEV 10.1.1.200/24
|
||||
ip link set dev $DEV up
|
||||
}
|
||||
|
||||
test_gre()
|
||||
{
|
||||
TYPE=gretap
|
||||
DEV_NS=gretap00
|
||||
DEV=gretap11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_gre_tunnel
|
||||
attach_bpf $DEV gre_set_tunnel gre_get_tunnel
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: $TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: $TYPE"${NC}
|
||||
}
|
||||
|
||||
test_ip6gre()
|
||||
{
|
||||
TYPE=ip6gre
|
||||
DEV_NS=ip6gre00
|
||||
DEV=ip6gre11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
# reuse the ip6gretap function
|
||||
add_ip6gretap_tunnel
|
||||
attach_bpf $DEV ip6gretap_set_tunnel ip6gretap_get_tunnel
|
||||
# underlay
|
||||
ping6 $PING_ARG ::11
|
||||
# overlay: ipv4 over ipv6
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
# overlay: ipv6 over ipv6
|
||||
ip netns exec at_ns0 ping6 $PING_ARG fc80::200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: $TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: $TYPE"${NC}
|
||||
}
|
||||
|
||||
test_ip6gretap()
|
||||
{
|
||||
TYPE=ip6gretap
|
||||
DEV_NS=ip6gretap00
|
||||
DEV=ip6gretap11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_ip6gretap_tunnel
|
||||
attach_bpf $DEV ip6gretap_set_tunnel ip6gretap_get_tunnel
|
||||
# underlay
|
||||
ping6 $PING_ARG ::11
|
||||
# overlay: ipv4 over ipv6
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
# overlay: ipv6 over ipv6
|
||||
ip netns exec at_ns0 ping6 $PING_ARG fc80::200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: $TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: $TYPE"${NC}
|
||||
}
|
||||
|
||||
test_erspan()
|
||||
{
|
||||
TYPE=erspan
|
||||
DEV_NS=erspan00
|
||||
DEV=erspan11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_erspan_tunnel $1
|
||||
attach_bpf $DEV erspan_set_tunnel erspan_get_tunnel
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: $TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: $TYPE"${NC}
|
||||
}
|
||||
|
||||
test_ip6erspan()
|
||||
{
|
||||
TYPE=ip6erspan
|
||||
DEV_NS=ip6erspan00
|
||||
DEV=ip6erspan11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_ip6erspan_tunnel $1
|
||||
attach_bpf $DEV ip4ip6erspan_set_tunnel ip4ip6erspan_get_tunnel
|
||||
ping6 $PING_ARG ::11
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: $TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: $TYPE"${NC}
|
||||
}
|
||||
|
||||
test_vxlan()
|
||||
{
|
||||
TYPE=vxlan
|
||||
DEV_NS=vxlan00
|
||||
DEV=vxlan11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_vxlan_tunnel
|
||||
attach_bpf $DEV vxlan_set_tunnel vxlan_get_tunnel
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: $TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: $TYPE"${NC}
|
||||
}
|
||||
|
||||
test_ip6vxlan()
|
||||
{
|
||||
TYPE=vxlan
|
||||
DEV_NS=ip6vxlan00
|
||||
DEV=ip6vxlan11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_ip6vxlan_tunnel
|
||||
ip link set dev veth1 mtu 1500
|
||||
attach_bpf $DEV ip6vxlan_set_tunnel ip6vxlan_get_tunnel
|
||||
# underlay
|
||||
ping6 $PING_ARG ::11
|
||||
# ip4 over ip6
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: ip6$TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: ip6$TYPE"${NC}
|
||||
}
|
||||
|
||||
test_geneve()
|
||||
{
|
||||
TYPE=geneve
|
||||
DEV_NS=geneve00
|
||||
DEV=geneve11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_geneve_tunnel
|
||||
attach_bpf $DEV geneve_set_tunnel geneve_get_tunnel
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: $TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: $TYPE"${NC}
|
||||
}
|
||||
|
||||
test_ip6geneve()
|
||||
{
|
||||
TYPE=geneve
|
||||
DEV_NS=ip6geneve00
|
||||
DEV=ip6geneve11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_ip6geneve_tunnel
|
||||
attach_bpf $DEV ip6geneve_set_tunnel ip6geneve_get_tunnel
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: ip6$TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: ip6$TYPE"${NC}
|
||||
}
|
||||
|
||||
test_ipip()
|
||||
{
|
||||
TYPE=ipip
|
||||
DEV_NS=ipip00
|
||||
DEV=ipip11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_ipip_tunnel
|
||||
ip link set dev veth1 mtu 1500
|
||||
attach_bpf $DEV ipip_set_tunnel ipip_get_tunnel
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: $TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: $TYPE"${NC}
|
||||
}
|
||||
|
||||
test_ipip6()
|
||||
{
|
||||
TYPE=ip6tnl
|
||||
DEV_NS=ipip6tnl00
|
||||
DEV=ipip6tnl11
|
||||
ret=0
|
||||
|
||||
check $TYPE
|
||||
config_device
|
||||
add_ipip6tnl_tunnel
|
||||
ip link set dev veth1 mtu 1500
|
||||
attach_bpf $DEV ipip6_set_tunnel ipip6_get_tunnel
|
||||
# underlay
|
||||
ping6 $PING_ARG ::11
|
||||
# ip4 over ip6
|
||||
ping $PING_ARG 10.1.1.100
|
||||
check_err $?
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: $TYPE"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: $TYPE"${NC}
|
||||
}
|
||||
|
||||
setup_xfrm_tunnel()
|
||||
{
|
||||
auth=0x$(printf '1%.0s' {1..40})
|
||||
enc=0x$(printf '2%.0s' {1..32})
|
||||
spi_in_to_out=0x1
|
||||
spi_out_to_in=0x2
|
||||
# at_ns0 namespace
|
||||
# at_ns0 -> root
|
||||
ip netns exec at_ns0 \
|
||||
ip xfrm state add src 172.16.1.100 dst 172.16.1.200 proto esp \
|
||||
spi $spi_in_to_out reqid 1 mode tunnel \
|
||||
auth-trunc 'hmac(sha1)' $auth 96 enc 'cbc(aes)' $enc
|
||||
ip netns exec at_ns0 \
|
||||
ip xfrm policy add src 10.1.1.100/32 dst 10.1.1.200/32 dir out \
|
||||
tmpl src 172.16.1.100 dst 172.16.1.200 proto esp reqid 1 \
|
||||
mode tunnel
|
||||
# root -> at_ns0
|
||||
ip netns exec at_ns0 \
|
||||
ip xfrm state add src 172.16.1.200 dst 172.16.1.100 proto esp \
|
||||
spi $spi_out_to_in reqid 2 mode tunnel \
|
||||
auth-trunc 'hmac(sha1)' $auth 96 enc 'cbc(aes)' $enc
|
||||
ip netns exec at_ns0 \
|
||||
ip xfrm policy add src 10.1.1.200/32 dst 10.1.1.100/32 dir in \
|
||||
tmpl src 172.16.1.200 dst 172.16.1.100 proto esp reqid 2 \
|
||||
mode tunnel
|
||||
# address & route
|
||||
ip netns exec at_ns0 \
|
||||
ip addr add dev veth0 10.1.1.100/32
|
||||
ip netns exec at_ns0 \
|
||||
ip route add 10.1.1.200 dev veth0 via 172.16.1.200 \
|
||||
src 10.1.1.100
|
||||
|
||||
# root namespace
|
||||
# at_ns0 -> root
|
||||
ip xfrm state add src 172.16.1.100 dst 172.16.1.200 proto esp \
|
||||
spi $spi_in_to_out reqid 1 mode tunnel \
|
||||
auth-trunc 'hmac(sha1)' $auth 96 enc 'cbc(aes)' $enc
|
||||
ip xfrm policy add src 10.1.1.100/32 dst 10.1.1.200/32 dir in \
|
||||
tmpl src 172.16.1.100 dst 172.16.1.200 proto esp reqid 1 \
|
||||
mode tunnel
|
||||
# root -> at_ns0
|
||||
ip xfrm state add src 172.16.1.200 dst 172.16.1.100 proto esp \
|
||||
spi $spi_out_to_in reqid 2 mode tunnel \
|
||||
auth-trunc 'hmac(sha1)' $auth 96 enc 'cbc(aes)' $enc
|
||||
ip xfrm policy add src 10.1.1.200/32 dst 10.1.1.100/32 dir out \
|
||||
tmpl src 172.16.1.200 dst 172.16.1.100 proto esp reqid 2 \
|
||||
mode tunnel
|
||||
# address & route
|
||||
ip addr add dev veth1 10.1.1.200/32
|
||||
ip route add 10.1.1.100 dev veth1 via 172.16.1.100 src 10.1.1.200
|
||||
}
|
||||
|
||||
test_xfrm_tunnel()
|
||||
{
|
||||
config_device
|
||||
#tcpdump -nei veth1 ip &
|
||||
output=$(mktemp)
|
||||
cat /sys/kernel/debug/tracing/trace_pipe | tee $output &
|
||||
setup_xfrm_tunnel
|
||||
tc qdisc add dev veth1 clsact
|
||||
tc filter add dev veth1 proto ip ingress bpf da obj test_tunnel_kern.o \
|
||||
sec xfrm_get_state
|
||||
ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
|
||||
sleep 1
|
||||
grep "reqid 1" $output
|
||||
check_err $?
|
||||
grep "spi 0x1" $output
|
||||
check_err $?
|
||||
grep "remote ip 0xac100164" $output
|
||||
check_err $?
|
||||
cleanup
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo -e ${RED}"FAIL: xfrm tunnel"${NC}
|
||||
return 1
|
||||
fi
|
||||
echo -e ${GREEN}"PASS: xfrm tunnel"${NC}
|
||||
}
|
||||
|
||||
attach_bpf()
|
||||
{
|
||||
DEV=$1
|
||||
SET=$2
|
||||
GET=$3
|
||||
tc qdisc add dev $DEV clsact
|
||||
tc filter add dev $DEV egress bpf da obj test_tunnel_kern.o sec $SET
|
||||
tc filter add dev $DEV ingress bpf da obj test_tunnel_kern.o sec $GET
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
ip netns delete at_ns0 2> /dev/null
|
||||
ip link del veth1 2> /dev/null
|
||||
ip link del ipip11 2> /dev/null
|
||||
ip link del ipip6tnl11 2> /dev/null
|
||||
ip link del gretap11 2> /dev/null
|
||||
ip link del ip6gre11 2> /dev/null
|
||||
ip link del ip6gretap11 2> /dev/null
|
||||
ip link del vxlan11 2> /dev/null
|
||||
ip link del ip6vxlan11 2> /dev/null
|
||||
ip link del geneve11 2> /dev/null
|
||||
ip link del ip6geneve11 2> /dev/null
|
||||
ip link del erspan11 2> /dev/null
|
||||
ip link del ip6erspan11 2> /dev/null
|
||||
}
|
||||
|
||||
cleanup_exit()
|
||||
{
|
||||
echo "CATCH SIGKILL or SIGINT, cleanup and exit"
|
||||
cleanup
|
||||
exit 0
|
||||
}
|
||||
|
||||
check()
|
||||
{
|
||||
ip link help $1 2>&1 | grep -q "^Usage:"
|
||||
if [ $? -ne 0 ];then
|
||||
echo "SKIP $1: iproute2 not support"
|
||||
cleanup
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
enable_debug()
|
||||
{
|
||||
echo 'file ip_gre.c +p' > /sys/kernel/debug/dynamic_debug/control
|
||||
echo 'file ip6_gre.c +p' > /sys/kernel/debug/dynamic_debug/control
|
||||
echo 'file vxlan.c +p' > /sys/kernel/debug/dynamic_debug/control
|
||||
echo 'file geneve.c +p' > /sys/kernel/debug/dynamic_debug/control
|
||||
echo 'file ipip.c +p' > /sys/kernel/debug/dynamic_debug/control
|
||||
}
|
||||
|
||||
check_err()
|
||||
{
|
||||
if [ $ret -eq 0 ]; then
|
||||
ret=$1
|
||||
fi
|
||||
}
|
||||
|
||||
bpf_tunnel_test()
|
||||
{
|
||||
echo "Testing GRE tunnel..."
|
||||
test_gre
|
||||
echo "Testing IP6GRE tunnel..."
|
||||
test_ip6gre
|
||||
echo "Testing IP6GRETAP tunnel..."
|
||||
test_ip6gretap
|
||||
echo "Testing ERSPAN tunnel..."
|
||||
test_erspan v2
|
||||
echo "Testing IP6ERSPAN tunnel..."
|
||||
test_ip6erspan v2
|
||||
echo "Testing VXLAN tunnel..."
|
||||
test_vxlan
|
||||
echo "Testing IP6VXLAN tunnel..."
|
||||
test_ip6vxlan
|
||||
echo "Testing GENEVE tunnel..."
|
||||
test_geneve
|
||||
echo "Testing IP6GENEVE tunnel..."
|
||||
test_ip6geneve
|
||||
echo "Testing IPIP tunnel..."
|
||||
test_ipip
|
||||
echo "Testing IPIP6 tunnel..."
|
||||
test_ipip6
|
||||
echo "Testing IPSec tunnel..."
|
||||
test_xfrm_tunnel
|
||||
}
|
||||
|
||||
trap cleanup 0 3 6
|
||||
trap cleanup_exit 2 9
|
||||
|
||||
cleanup
|
||||
bpf_tunnel_test
|
||||
|
||||
exit 0
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2016 VMware
|
||||
* Copyright (c) 2016 Facebook
|
||||
*
|
||||
|
@ -5,39 +6,41 @@
|
|||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation.
|
||||
*/
|
||||
#define KBUILD_MODNAME "foo"
|
||||
#include <uapi/linux/bpf.h>
|
||||
#include <uapi/linux/if_ether.h>
|
||||
#include <uapi/linux/if_packet.h>
|
||||
#include <uapi/linux/ip.h>
|
||||
#include <uapi/linux/ipv6.h>
|
||||
#include <uapi/linux/in.h>
|
||||
#include <uapi/linux/tcp.h>
|
||||
#include <uapi/linux/filter.h>
|
||||
#include <uapi/linux/pkt_cls.h>
|
||||
#include <uapi/linux/erspan.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/pkt_cls.h>
|
||||
#include <linux/erspan.h>
|
||||
#include "bpf_helpers.h"
|
||||
#include "bpf_endian.h"
|
||||
|
||||
#define _htonl __builtin_bswap32
|
||||
#define ERROR(ret) do {\
|
||||
char fmt[] = "ERROR line:%d ret:%d\n";\
|
||||
bpf_trace_printk(fmt, sizeof(fmt), __LINE__, ret); \
|
||||
} while(0)
|
||||
} while (0)
|
||||
|
||||
int _version SEC("version") = 1;
|
||||
|
||||
struct geneve_opt {
|
||||
__be16 opt_class;
|
||||
u8 type;
|
||||
u8 length:5;
|
||||
u8 r3:1;
|
||||
u8 r2:1;
|
||||
u8 r1:1;
|
||||
u8 opt_data[8]; /* hard-coded to 8 byte */
|
||||
__u8 type;
|
||||
__u8 length:5;
|
||||
__u8 r3:1;
|
||||
__u8 r2:1;
|
||||
__u8 r1:1;
|
||||
__u8 opt_data[8]; /* hard-coded to 8 byte */
|
||||
};
|
||||
|
||||
struct vxlan_metadata {
|
||||
u32 gbp;
|
||||
__u32 gbp;
|
||||
};
|
||||
|
||||
SEC("gre_set_tunnel")
|
||||
|
@ -86,7 +89,7 @@ int _ip6gretap_set_tunnel(struct __sk_buff *skb)
|
|||
int ret;
|
||||
|
||||
__builtin_memset(&key, 0x0, sizeof(key));
|
||||
key.remote_ipv6[3] = _htonl(0x11); /* ::11 */
|
||||
key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */
|
||||
key.tunnel_id = 2;
|
||||
key.tunnel_tos = 0;
|
||||
key.tunnel_ttl = 64;
|
||||
|
@ -136,7 +139,8 @@ int _erspan_set_tunnel(struct __sk_buff *skb)
|
|||
key.tunnel_tos = 0;
|
||||
key.tunnel_ttl = 64;
|
||||
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), BPF_F_ZERO_CSUM_TX);
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_ZERO_CSUM_TX);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
|
@ -147,8 +151,8 @@ int _erspan_set_tunnel(struct __sk_buff *skb)
|
|||
md.version = 1;
|
||||
md.u.index = bpf_htonl(123);
|
||||
#else
|
||||
u8 direction = 1;
|
||||
u8 hwid = 7;
|
||||
__u8 direction = 1;
|
||||
__u8 hwid = 7;
|
||||
|
||||
md.version = 2;
|
||||
md.u.md2.dir = direction;
|
||||
|
@ -171,7 +175,7 @@ int _erspan_get_tunnel(struct __sk_buff *skb)
|
|||
char fmt[] = "key %d remote ip 0x%x erspan version %d\n";
|
||||
struct bpf_tunnel_key key;
|
||||
struct erspan_metadata md;
|
||||
u32 index;
|
||||
__u32 index;
|
||||
int ret;
|
||||
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);
|
||||
|
@ -214,7 +218,7 @@ int _ip4ip6erspan_set_tunnel(struct __sk_buff *skb)
|
|||
int ret;
|
||||
|
||||
__builtin_memset(&key, 0x0, sizeof(key));
|
||||
key.remote_ipv6[3] = _htonl(0x11);
|
||||
key.remote_ipv6[3] = bpf_htonl(0x11);
|
||||
key.tunnel_id = 2;
|
||||
key.tunnel_tos = 0;
|
||||
key.tunnel_ttl = 64;
|
||||
|
@ -229,11 +233,11 @@ int _ip4ip6erspan_set_tunnel(struct __sk_buff *skb)
|
|||
__builtin_memset(&md, 0, sizeof(md));
|
||||
|
||||
#ifdef ERSPAN_V1
|
||||
md.u.index = htonl(123);
|
||||
md.u.index = bpf_htonl(123);
|
||||
md.version = 1;
|
||||
#else
|
||||
u8 direction = 0;
|
||||
u8 hwid = 17;
|
||||
__u8 direction = 0;
|
||||
__u8 hwid = 17;
|
||||
|
||||
md.version = 2;
|
||||
md.u.md2.dir = direction;
|
||||
|
@ -256,10 +260,11 @@ int _ip4ip6erspan_get_tunnel(struct __sk_buff *skb)
|
|||
char fmt[] = "ip6erspan get key %d remote ip6 ::%x erspan version %d\n";
|
||||
struct bpf_tunnel_key key;
|
||||
struct erspan_metadata md;
|
||||
u32 index;
|
||||
__u32 index;
|
||||
int ret;
|
||||
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), BPF_F_TUNINFO_IPV6);
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
|
@ -304,7 +309,8 @@ int _vxlan_set_tunnel(struct __sk_buff *skb)
|
|||
key.tunnel_tos = 0;
|
||||
key.tunnel_ttl = 64;
|
||||
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), BPF_F_ZERO_CSUM_TX);
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_ZERO_CSUM_TX);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
|
@ -346,6 +352,48 @@ int _vxlan_get_tunnel(struct __sk_buff *skb)
|
|||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("ip6vxlan_set_tunnel")
|
||||
int _ip6vxlan_set_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_tunnel_key key;
|
||||
int ret;
|
||||
|
||||
__builtin_memset(&key, 0x0, sizeof(key));
|
||||
key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */
|
||||
key.tunnel_id = 22;
|
||||
key.tunnel_tos = 0;
|
||||
key.tunnel_ttl = 64;
|
||||
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("ip6vxlan_get_tunnel")
|
||||
int _ip6vxlan_get_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
char fmt[] = "key %d remote ip6 ::%x label %x\n";
|
||||
struct bpf_tunnel_key key;
|
||||
int ret;
|
||||
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
bpf_trace_printk(fmt, sizeof(fmt),
|
||||
key.tunnel_id, key.remote_ipv6[3], key.tunnel_label);
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("geneve_set_tunnel")
|
||||
int _geneve_set_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
|
@ -360,15 +408,16 @@ int _geneve_set_tunnel(struct __sk_buff *skb)
|
|||
key.tunnel_ttl = 64;
|
||||
|
||||
__builtin_memset(&gopt, 0x0, sizeof(gopt));
|
||||
gopt.opt_class = 0x102; /* Open Virtual Networking (OVN) */
|
||||
gopt.opt_class = bpf_htons(0x102); /* Open Virtual Networking (OVN) */
|
||||
gopt.type = 0x08;
|
||||
gopt.r1 = 0;
|
||||
gopt.r2 = 0;
|
||||
gopt.r3 = 0;
|
||||
gopt.length = 2; /* 4-byte multiple */
|
||||
*(int *) &gopt.opt_data = 0xdeadbeef;
|
||||
*(int *) &gopt.opt_data = bpf_htonl(0xdeadbeef);
|
||||
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), BPF_F_ZERO_CSUM_TX);
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_ZERO_CSUM_TX);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
|
@ -408,6 +457,71 @@ int _geneve_get_tunnel(struct __sk_buff *skb)
|
|||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("ip6geneve_set_tunnel")
|
||||
int _ip6geneve_set_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_tunnel_key key;
|
||||
struct geneve_opt gopt;
|
||||
int ret;
|
||||
|
||||
__builtin_memset(&key, 0x0, sizeof(key));
|
||||
key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */
|
||||
key.tunnel_id = 22;
|
||||
key.tunnel_tos = 0;
|
||||
key.tunnel_ttl = 64;
|
||||
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
__builtin_memset(&gopt, 0x0, sizeof(gopt));
|
||||
gopt.opt_class = bpf_htons(0x102); /* Open Virtual Networking (OVN) */
|
||||
gopt.type = 0x08;
|
||||
gopt.r1 = 0;
|
||||
gopt.r2 = 0;
|
||||
gopt.r3 = 0;
|
||||
gopt.length = 2; /* 4-byte multiple */
|
||||
*(int *) &gopt.opt_data = bpf_htonl(0xfeedbeef);
|
||||
|
||||
ret = bpf_skb_set_tunnel_opt(skb, &gopt, sizeof(gopt));
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("ip6geneve_get_tunnel")
|
||||
int _ip6geneve_get_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
char fmt[] = "key %d remote ip 0x%x geneve class 0x%x\n";
|
||||
struct bpf_tunnel_key key;
|
||||
struct geneve_opt gopt;
|
||||
int ret;
|
||||
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
ret = bpf_skb_get_tunnel_opt(skb, &gopt, sizeof(gopt));
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
bpf_trace_printk(fmt, sizeof(fmt),
|
||||
key.tunnel_id, key.remote_ipv4, gopt.opt_class);
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("ipip_set_tunnel")
|
||||
int _ipip_set_tunnel(struct __sk_buff *skb)
|
||||
{
|
||||
|
@ -431,9 +545,9 @@ int _ipip_set_tunnel(struct __sk_buff *skb)
|
|||
if (iph->protocol != IPPROTO_TCP || iph->ihl != 5)
|
||||
return TC_ACT_SHOT;
|
||||
|
||||
if (tcp->dest == htons(5200))
|
||||
if (tcp->dest == bpf_htons(5200))
|
||||
key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
|
||||
else if (tcp->dest == htons(5201))
|
||||
else if (tcp->dest == bpf_htons(5201))
|
||||
key.remote_ipv4 = 0xac100165; /* 172.16.1.101 */
|
||||
else
|
||||
return TC_ACT_SHOT;
|
||||
|
@ -481,28 +595,12 @@ int _ipip6_set_tunnel(struct __sk_buff *skb)
|
|||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
key.remote_ipv6[0] = _htonl(0x2401db00);
|
||||
__builtin_memset(&key, 0x0, sizeof(key));
|
||||
key.remote_ipv6[3] = bpf_htonl(0x11); /* ::11 */
|
||||
key.tunnel_ttl = 64;
|
||||
|
||||
if (iph->protocol == IPPROTO_ICMP) {
|
||||
key.remote_ipv6[3] = _htonl(1);
|
||||
} else {
|
||||
if (iph->protocol != IPPROTO_TCP || iph->ihl != 5) {
|
||||
ERROR(iph->protocol);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
if (tcp->dest == htons(5200)) {
|
||||
key.remote_ipv6[3] = _htonl(1);
|
||||
} else if (tcp->dest == htons(5201)) {
|
||||
key.remote_ipv6[3] = _htonl(2);
|
||||
} else {
|
||||
ERROR(tcp->dest);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
}
|
||||
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), BPF_F_TUNINFO_IPV6);
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
|
@ -518,14 +616,15 @@ int _ipip6_get_tunnel(struct __sk_buff *skb)
|
|||
struct bpf_tunnel_key key;
|
||||
char fmt[] = "remote ip6 %x::%x\n";
|
||||
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), BPF_F_TUNINFO_IPV6);
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
bpf_trace_printk(fmt, sizeof(fmt), _htonl(key.remote_ipv6[0]),
|
||||
_htonl(key.remote_ipv6[3]));
|
||||
bpf_trace_printk(fmt, sizeof(fmt), bpf_htonl(key.remote_ipv6[0]),
|
||||
bpf_htonl(key.remote_ipv6[3]));
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
|
@ -545,28 +644,29 @@ int _ip6ip6_set_tunnel(struct __sk_buff *skb)
|
|||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
key.remote_ipv6[0] = _htonl(0x2401db00);
|
||||
key.remote_ipv6[0] = bpf_htonl(0x2401db00);
|
||||
key.tunnel_ttl = 64;
|
||||
|
||||
if (iph->nexthdr == NEXTHDR_ICMP) {
|
||||
key.remote_ipv6[3] = _htonl(1);
|
||||
if (iph->nexthdr == 58 /* NEXTHDR_ICMP */) {
|
||||
key.remote_ipv6[3] = bpf_htonl(1);
|
||||
} else {
|
||||
if (iph->nexthdr != NEXTHDR_TCP) {
|
||||
if (iph->nexthdr != 6 /* NEXTHDR_TCP */) {
|
||||
ERROR(iph->nexthdr);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
if (tcp->dest == htons(5200)) {
|
||||
key.remote_ipv6[3] = _htonl(1);
|
||||
} else if (tcp->dest == htons(5201)) {
|
||||
key.remote_ipv6[3] = _htonl(2);
|
||||
if (tcp->dest == bpf_htons(5200)) {
|
||||
key.remote_ipv6[3] = bpf_htonl(1);
|
||||
} else if (tcp->dest == bpf_htons(5201)) {
|
||||
key.remote_ipv6[3] = bpf_htonl(2);
|
||||
} else {
|
||||
ERROR(tcp->dest);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
}
|
||||
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), BPF_F_TUNINFO_IPV6);
|
||||
ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
|
@ -582,14 +682,31 @@ int _ip6ip6_get_tunnel(struct __sk_buff *skb)
|
|||
struct bpf_tunnel_key key;
|
||||
char fmt[] = "remote ip6 %x::%x\n";
|
||||
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), BPF_F_TUNINFO_IPV6);
|
||||
ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
|
||||
BPF_F_TUNINFO_IPV6);
|
||||
if (ret < 0) {
|
||||
ERROR(ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
bpf_trace_printk(fmt, sizeof(fmt), _htonl(key.remote_ipv6[0]),
|
||||
_htonl(key.remote_ipv6[3]));
|
||||
bpf_trace_printk(fmt, sizeof(fmt), bpf_htonl(key.remote_ipv6[0]),
|
||||
bpf_htonl(key.remote_ipv6[3]));
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
SEC("xfrm_get_state")
|
||||
int _xfrm_get_state(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_xfrm_state x;
|
||||
char fmt[] = "reqid %d spi 0x%x remote ip 0x%x\n";
|
||||
int ret;
|
||||
|
||||
ret = bpf_skb_get_xfrm_state(skb, 0, &x, sizeof(x), 0);
|
||||
if (ret < 0)
|
||||
return TC_ACT_OK;
|
||||
|
||||
bpf_trace_printk(fmt, sizeof(fmt), x.reqid, bpf_ntohl(x.spi),
|
||||
bpf_ntohl(x.remote_ipv4));
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
|
@ -64,6 +64,7 @@ struct bpf_test {
|
|||
struct bpf_insn insns[MAX_INSNS];
|
||||
int fixup_map1[MAX_FIXUPS];
|
||||
int fixup_map2[MAX_FIXUPS];
|
||||
int fixup_map3[MAX_FIXUPS];
|
||||
int fixup_prog[MAX_FIXUPS];
|
||||
int fixup_map_in_map[MAX_FIXUPS];
|
||||
const char *errstr;
|
||||
|
@ -88,6 +89,11 @@ struct test_val {
|
|||
int foo[MAX_ENTRIES];
|
||||
};
|
||||
|
||||
struct other_val {
|
||||
long long foo;
|
||||
long long bar;
|
||||
};
|
||||
|
||||
static struct bpf_test tests[] = {
|
||||
{
|
||||
"add+sub+mul",
|
||||
|
@ -5593,6 +5599,257 @@ static struct bpf_test tests[] = {
|
|||
.errstr = "R1 min value is negative",
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map lookup helper access to map",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 8 },
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map update helper access to map",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
|
||||
BPF_MOV64_IMM(BPF_REG_4, 0),
|
||||
BPF_MOV64_REG(BPF_REG_3, BPF_REG_0),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_update_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 10 },
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map update helper access to map: wrong size",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
|
||||
BPF_MOV64_IMM(BPF_REG_4, 0),
|
||||
BPF_MOV64_REG(BPF_REG_3, BPF_REG_0),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_update_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map1 = { 3 },
|
||||
.fixup_map3 = { 10 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value, value_size=8 off=0 size=16",
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map helper access to adjusted map (via const imm)",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2,
|
||||
offsetof(struct other_val, bar)),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 9 },
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map helper access to adjusted map (via const imm): out-of-bound 1",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2,
|
||||
sizeof(struct other_val) - 4),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 9 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value, value_size=16 off=12 size=8",
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map helper access to adjusted map (via const imm): out-of-bound 2",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 9 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value, value_size=16 off=-4 size=8",
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map helper access to adjusted map (via const reg)",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_MOV64_IMM(BPF_REG_3,
|
||||
offsetof(struct other_val, bar)),
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_3),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 10 },
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map helper access to adjusted map (via const reg): out-of-bound 1",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_MOV64_IMM(BPF_REG_3,
|
||||
sizeof(struct other_val) - 4),
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_3),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 10 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value, value_size=16 off=12 size=8",
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map helper access to adjusted map (via const reg): out-of-bound 2",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_MOV64_IMM(BPF_REG_3, -4),
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_3),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 10 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value, value_size=16 off=-4 size=8",
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map helper access to adjusted map (via variable)",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0),
|
||||
BPF_JMP_IMM(BPF_JGT, BPF_REG_3,
|
||||
offsetof(struct other_val, bar), 4),
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_3),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 11 },
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map helper access to adjusted map (via variable): no max check",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0),
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_3),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 10 },
|
||||
.result = REJECT,
|
||||
.errstr = "R2 unbounded memory access, make sure to bounds check any array access into a map",
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map helper access to adjusted map (via variable): wrong max check",
|
||||
.insns = {
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0),
|
||||
BPF_JMP_IMM(BPF_JGT, BPF_REG_3,
|
||||
offsetof(struct other_val, bar) + 1, 4),
|
||||
BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_3),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.fixup_map3 = { 3, 11 },
|
||||
.result = REJECT,
|
||||
.errstr = "invalid access to map value, value_size=16 off=9 size=8",
|
||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||
},
|
||||
{
|
||||
"map element value is preserved across register spilling",
|
||||
.insns = {
|
||||
|
@ -11533,6 +11790,7 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog,
|
|||
{
|
||||
int *fixup_map1 = test->fixup_map1;
|
||||
int *fixup_map2 = test->fixup_map2;
|
||||
int *fixup_map3 = test->fixup_map3;
|
||||
int *fixup_prog = test->fixup_prog;
|
||||
int *fixup_map_in_map = test->fixup_map_in_map;
|
||||
|
||||
|
@ -11556,6 +11814,14 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog,
|
|||
} while (*fixup_map2);
|
||||
}
|
||||
|
||||
if (*fixup_map3) {
|
||||
map_fds[1] = create_map(sizeof(struct other_val), 1);
|
||||
do {
|
||||
prog[*fixup_map3].imm = map_fds[1];
|
||||
fixup_map3++;
|
||||
} while (*fixup_map3);
|
||||
}
|
||||
|
||||
if (*fixup_prog) {
|
||||
map_fds[2] = create_prog_array();
|
||||
do {
|
||||
|
|
Loading…
Reference in New Issue