Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
Alexei Starovoitov says: ==================== pull-request: bpf-next 2018-05-24 The following pull-request contains BPF updates for your *net-next* tree. The main changes are: 1) Björn Töpel cleans up AF_XDP (removes rebind, explicit cache alignment from uapi, etc). 2) David Ahern adds mtu checks to bpf_ipv{4,6}_fib_lookup() helpers. 3) Jesper Dangaard Brouer adds bulking support to ndo_xdp_xmit. 4) Jiong Wang adds support for indirect and arithmetic shifts to NFP 5) Martin KaFai Lau cleans up BTF uapi and makes the btf_header extensible. 6) Mathieu Xhonneux adds an End.BPF action to seg6local with BPF helpers allowing to edit/grow/shrink a SRH and apply on a packet generic SRv6 actions. 7) Sandipan Das adds support for bpf2bpf function calls in ppc64 JIT. 8) Yonghong Song adds BPF_TASK_FD_QUERY command for introspection of tracing events. 9) other misc fixes from Gustavo A. R. Silva, Sirio Balmelli, John Fastabend, and Magnus Karlsson ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
此提交包含在:
@@ -33,7 +33,8 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test
|
||||
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_sockmap_kern.o test_tunnel_kern.o \
|
||||
test_get_stack_rawtp.o test_sockmap_kern.o test_sockhash_kern.o
|
||||
test_get_stack_rawtp.o test_sockmap_kern.o test_sockhash_kern.o \
|
||||
test_lwt_seg6local.o
|
||||
|
||||
# Order correspond to 'make run_tests' order
|
||||
TEST_PROGS := test_kmod.sh \
|
||||
@@ -42,7 +43,8 @@ TEST_PROGS := test_kmod.sh \
|
||||
test_xdp_meta.sh \
|
||||
test_offload.py \
|
||||
test_sock_addr.sh \
|
||||
test_tunnel.sh
|
||||
test_tunnel.sh \
|
||||
test_lwt_seg6local.sh
|
||||
|
||||
# Compile but not part of 'make run_tests'
|
||||
TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr
|
||||
@@ -84,7 +86,17 @@ else
|
||||
CPU ?= generic
|
||||
endif
|
||||
|
||||
# Get Clang's default includes on this system, as opposed to those seen by
|
||||
# '-target bpf'. This fixes "missing" files on some architectures/distros,
|
||||
# such as asm/byteorder.h, asm/socket.h, asm/sockios.h, sys/cdefs.h etc.
|
||||
#
|
||||
# Use '-idirafter': Don't interfere with include mechanics except where the
|
||||
# build would have failed anyways.
|
||||
CLANG_SYS_INCLUDES := $(shell $(CLANG) -v -E - </dev/null 2>&1 \
|
||||
| sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }')
|
||||
|
||||
CLANG_FLAGS = -I. -I./include/uapi -I../../../include/uapi \
|
||||
$(CLANG_SYS_INCLUDES) \
|
||||
-Wno-compare-distinct-pointer-types
|
||||
|
||||
$(OUTPUT)/test_l4lb_noinline.o: CLANG_FLAGS += -fno-inline
|
||||
|
@@ -114,6 +114,18 @@ static int (*bpf_get_stack)(void *ctx, void *buf, int size, int flags) =
|
||||
static int (*bpf_fib_lookup)(void *ctx, struct bpf_fib_lookup *params,
|
||||
int plen, __u32 flags) =
|
||||
(void *) BPF_FUNC_fib_lookup;
|
||||
static int (*bpf_lwt_push_encap)(void *ctx, unsigned int type, void *hdr,
|
||||
unsigned int len) =
|
||||
(void *) BPF_FUNC_lwt_push_encap;
|
||||
static int (*bpf_lwt_seg6_store_bytes)(void *ctx, unsigned int offset,
|
||||
void *from, unsigned int len) =
|
||||
(void *) BPF_FUNC_lwt_seg6_store_bytes;
|
||||
static int (*bpf_lwt_seg6_action)(void *ctx, unsigned int action, void *param,
|
||||
unsigned int param_len) =
|
||||
(void *) BPF_FUNC_lwt_seg6_action;
|
||||
static int (*bpf_lwt_seg6_adjust_srh)(void *ctx, unsigned int offset,
|
||||
unsigned int len) =
|
||||
(void *) BPF_FUNC_lwt_seg6_adjust_srh;
|
||||
|
||||
/* llvm builtin functions that eBPF C program may use to
|
||||
* emit BPF_LD_ABS and BPF_LD_IND instructions
|
||||
|
@@ -113,22 +113,25 @@ static char btf_log_buf[BTF_LOG_BUF_SIZE];
|
||||
static struct btf_header hdr_tmpl = {
|
||||
.magic = BTF_MAGIC,
|
||||
.version = BTF_VERSION,
|
||||
.hdr_len = sizeof(struct btf_header),
|
||||
};
|
||||
|
||||
struct btf_raw_test {
|
||||
const char *descr;
|
||||
const char *str_sec;
|
||||
const char *map_name;
|
||||
const char *err_str;
|
||||
__u32 raw_types[MAX_NR_RAW_TYPES];
|
||||
__u32 str_sec_size;
|
||||
enum bpf_map_type map_type;
|
||||
__u32 key_size;
|
||||
__u32 value_size;
|
||||
__u32 key_id;
|
||||
__u32 value_id;
|
||||
__u32 key_type_id;
|
||||
__u32 value_type_id;
|
||||
__u32 max_entries;
|
||||
bool btf_load_err;
|
||||
bool map_create_err;
|
||||
int hdr_len_delta;
|
||||
int type_off_delta;
|
||||
int str_off_delta;
|
||||
int str_len_delta;
|
||||
@@ -141,8 +144,8 @@ static struct btf_raw_test raw_tests[] = {
|
||||
* };
|
||||
*
|
||||
* struct A {
|
||||
* int m;
|
||||
* unsigned long long n;
|
||||
* unsigned long long m;
|
||||
* int n;
|
||||
* char o;
|
||||
* [3 bytes hole]
|
||||
* int p[8];
|
||||
@@ -163,8 +166,8 @@ static struct btf_raw_test raw_tests[] = {
|
||||
BTF_TYPE_ARRAY_ENC(1, 1, 8), /* [4] */
|
||||
/* struct A { */ /* [5] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 6), 180),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, 0), /* int m; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, 32),/* unsigned long long n;*/
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, 0), /* unsigned long long m;*/
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, 64),/* int n; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 3, 96),/* char o; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 4, 128),/* int p[8] */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 6, 384),/* int q[4][8] */
|
||||
@@ -172,6 +175,7 @@ static struct btf_raw_test raw_tests[] = {
|
||||
/* } */
|
||||
/* int[4][8] */
|
||||
BTF_TYPE_ARRAY_ENC(4, 1, 4), /* [6] */
|
||||
/* enum E */ /* [7] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 2), sizeof(int)),
|
||||
BTF_ENUM_ENC(NAME_TBD, 0),
|
||||
BTF_ENUM_ENC(NAME_TBD, 1),
|
||||
@@ -183,8 +187,8 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "struct_test1_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 180,
|
||||
.key_id = 1,
|
||||
.value_id = 5,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 5,
|
||||
.max_entries = 4,
|
||||
},
|
||||
|
||||
@@ -238,8 +242,8 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "struct_test2_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 68,
|
||||
.key_id = 1,
|
||||
.value_id = 3,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 3,
|
||||
.max_entries = 4,
|
||||
},
|
||||
|
||||
@@ -258,7 +262,7 @@ static struct btf_raw_test raw_tests[] = {
|
||||
/* struct A { */ /* [2] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), sizeof(int) * 2 - 1),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, 0), /* int m; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, 32),/* int n; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, 32),/* int n; */
|
||||
/* } */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
@@ -268,10 +272,11 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "size_check1_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 1,
|
||||
.key_id = 1,
|
||||
.value_id = 2,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 2,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Member exceeds struct_size",
|
||||
},
|
||||
|
||||
/* Test member exeeds the size of struct
|
||||
@@ -301,11 +306,11 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "size_check2_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 1,
|
||||
.key_id = 1,
|
||||
.value_id = 3,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 3,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
|
||||
.err_str = "Member exceeds struct_size",
|
||||
},
|
||||
|
||||
/* Test member exeeds the size of struct
|
||||
@@ -335,10 +340,11 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "size_check3_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 1,
|
||||
.key_id = 1,
|
||||
.value_id = 3,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 3,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Member exceeds struct_size",
|
||||
},
|
||||
|
||||
/* Test member exceeds the size of struct
|
||||
@@ -376,10 +382,11 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "size_check4_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 1,
|
||||
.key_id = 1,
|
||||
.value_id = 3,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 3,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Member exceeds struct_size",
|
||||
},
|
||||
|
||||
/* typedef const void * const_void_ptr;
|
||||
@@ -411,8 +418,8 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "void_test1_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(void *),
|
||||
.key_id = 1,
|
||||
.value_id = 4,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 4,
|
||||
.max_entries = 4,
|
||||
},
|
||||
|
||||
@@ -440,10 +447,11 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "void_test2_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(void *),
|
||||
.key_id = 1,
|
||||
.value_id = 3,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 3,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid member",
|
||||
},
|
||||
|
||||
/* typedef const void * const_void_ptr;
|
||||
@@ -458,9 +466,9 @@ static struct btf_raw_test raw_tests[] = {
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 0),
|
||||
/* const void* */ /* [3] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 2),
|
||||
/* typedef const void * const_void_ptr */
|
||||
/* typedef const void * const_void_ptr */ /* [4] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 3),
|
||||
/* const_void_ptr[4] */ /* [4] */
|
||||
/* const_void_ptr[4] */ /* [5] */
|
||||
BTF_TYPE_ARRAY_ENC(3, 1, 4),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
@@ -470,8 +478,8 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "void_test3_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(void *) * 4,
|
||||
.key_id = 1,
|
||||
.value_id = 4,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 4,
|
||||
.max_entries = 4,
|
||||
},
|
||||
|
||||
@@ -493,10 +501,11 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "void_test4_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(void *) * 4,
|
||||
.key_id = 1,
|
||||
.value_id = 3,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 3,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid elem",
|
||||
},
|
||||
|
||||
/* Array_A <------------------+
|
||||
@@ -523,10 +532,11 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "loop_test1_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(sizeof(int) * 8),
|
||||
.key_id = 1,
|
||||
.value_id = 2,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 2,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Loop detected",
|
||||
},
|
||||
|
||||
/* typedef is _before_ the BTF type of Array_A and Array_B
|
||||
@@ -551,7 +561,6 @@ static struct btf_raw_test raw_tests[] = {
|
||||
BTF_TYPE_ARRAY_ENC(2, 1, 8), /* [3] */
|
||||
/* Array_B */
|
||||
BTF_TYPE_ARRAY_ENC(3, 1, 8), /* [4] */
|
||||
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0int_array\0",
|
||||
@@ -560,10 +569,11 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "loop_test2_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(sizeof(int) * 8),
|
||||
.key_id = 1,
|
||||
.value_id = 2,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 2,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Loop detected",
|
||||
},
|
||||
|
||||
/* Array_A <------------------+
|
||||
@@ -582,7 +592,6 @@ static struct btf_raw_test raw_tests[] = {
|
||||
BTF_TYPE_ARRAY_ENC(3, 1, 8),
|
||||
/* Array_B */ /* [3] */
|
||||
BTF_TYPE_ARRAY_ENC(2, 1, 8),
|
||||
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "",
|
||||
@@ -591,10 +600,11 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "loop_test3_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(sizeof(int) * 8),
|
||||
.key_id = 1,
|
||||
.value_id = 2,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 2,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Loop detected",
|
||||
},
|
||||
|
||||
/* typedef is _between_ the BTF type of Array_A and Array_B
|
||||
@@ -627,10 +637,11 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "loop_test4_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(sizeof(int) * 8),
|
||||
.key_id = 1,
|
||||
.value_id = 2,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 2,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Loop detected",
|
||||
},
|
||||
|
||||
/* typedef struct B Struct_B
|
||||
@@ -668,10 +679,11 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "loop_test5_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 8,
|
||||
.key_id = 1,
|
||||
.value_id = 2,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 2,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Loop detected",
|
||||
},
|
||||
|
||||
/* struct A {
|
||||
@@ -697,10 +709,11 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "loop_test6_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = 8,
|
||||
.key_id = 1,
|
||||
.value_id = 2,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 2,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Loop detected",
|
||||
},
|
||||
|
||||
{
|
||||
@@ -724,10 +737,11 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "loop_test7_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(void *),
|
||||
.key_id = 1,
|
||||
.value_id = 2,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 2,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Loop detected",
|
||||
},
|
||||
|
||||
{
|
||||
@@ -759,14 +773,73 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "loop_test8_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(void *),
|
||||
.key_id = 1,
|
||||
.value_id = 2,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 2,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Loop detected",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "type_off == str_off",
|
||||
.descr = "string section does not end with null",
|
||||
.raw_types = {
|
||||
/* int */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0int",
|
||||
.str_sec_size = sizeof("\0int") - 1,
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "hdr_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid string section",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "empty string section",
|
||||
.raw_types = {
|
||||
/* int */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "",
|
||||
.str_sec_size = 0,
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "hdr_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid string section",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "empty type section",
|
||||
.raw_types = {
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0int",
|
||||
.str_sec_size = sizeof("\0int"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "hdr_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "No type found",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "btf_header test. Longer hdr_len",
|
||||
.raw_types = {
|
||||
/* int */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
|
||||
@@ -778,15 +851,16 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "hdr_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_id = 1,
|
||||
.value_id = 1,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.type_off_delta = sizeof(struct btf_type) + sizeof(int) + sizeof("\0int"),
|
||||
.hdr_len_delta = 4,
|
||||
.err_str = "Unsupported btf_header",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "Unaligned type_off",
|
||||
.descr = "btf_header test. Gap between hdr and type",
|
||||
.raw_types = {
|
||||
/* int */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
|
||||
@@ -798,15 +872,16 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "hdr_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_id = 1,
|
||||
.value_id = 1,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.type_off_delta = 1,
|
||||
.type_off_delta = 4,
|
||||
.err_str = "Unsupported section found",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "str_off beyonds btf size",
|
||||
.descr = "btf_header test. Gap between type and str",
|
||||
.raw_types = {
|
||||
/* int */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
|
||||
@@ -818,15 +893,16 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "hdr_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_id = 1,
|
||||
.value_id = 1,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.str_off_delta = sizeof("\0int") + 1,
|
||||
.str_off_delta = 4,
|
||||
.err_str = "Unsupported section found",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "str_len beyonds btf size",
|
||||
.descr = "btf_header test. Overlap between type and str",
|
||||
.raw_types = {
|
||||
/* int */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
|
||||
@@ -838,15 +914,16 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "hdr_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_id = 1,
|
||||
.value_id = 1,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.str_len_delta = 1,
|
||||
.str_off_delta = -4,
|
||||
.err_str = "Section overlap found",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "String section does not end with null",
|
||||
.descr = "btf_header test. Larger BTF size",
|
||||
.raw_types = {
|
||||
/* int */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
|
||||
@@ -858,15 +935,16 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "hdr_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_id = 1,
|
||||
.value_id = 1,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.str_len_delta = -1,
|
||||
.str_len_delta = -4,
|
||||
.err_str = "Unsupported section found",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "Empty string section",
|
||||
.descr = "btf_header test. Smaller BTF size",
|
||||
.raw_types = {
|
||||
/* int */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
|
||||
@@ -878,11 +956,267 @@ static struct btf_raw_test raw_tests[] = {
|
||||
.map_name = "hdr_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_id = 1,
|
||||
.value_id = 1,
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.str_len_delta = 0 - (int)sizeof("\0int"),
|
||||
.str_len_delta = 4,
|
||||
.err_str = "Total section length too long",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "array test. index_type/elem_type \"int\"",
|
||||
.raw_types = {
|
||||
/* int */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
|
||||
/* int[16] */ /* [2] */
|
||||
BTF_TYPE_ARRAY_ENC(1, 1, 16),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "",
|
||||
.str_sec_size = sizeof(""),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "array_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "array test. index_type/elem_type \"const int\"",
|
||||
.raw_types = {
|
||||
/* int */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
|
||||
/* int[16] */ /* [2] */
|
||||
BTF_TYPE_ARRAY_ENC(3, 3, 16),
|
||||
/* CONST type_id=1 */ /* [3] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 1),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "",
|
||||
.str_sec_size = sizeof(""),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "array_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "array test. index_type \"const int:31\"",
|
||||
.raw_types = {
|
||||
/* int */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
|
||||
/* int:31 */ /* [2] */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 31, 4),
|
||||
/* int[16] */ /* [3] */
|
||||
BTF_TYPE_ARRAY_ENC(1, 4, 16),
|
||||
/* CONST type_id=2 */ /* [4] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 2),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "",
|
||||
.str_sec_size = sizeof(""),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "array_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid index",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "array test. elem_type \"const int:31\"",
|
||||
.raw_types = {
|
||||
/* int */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
|
||||
/* int:31 */ /* [2] */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 31, 4),
|
||||
/* int[16] */ /* [3] */
|
||||
BTF_TYPE_ARRAY_ENC(4, 1, 16),
|
||||
/* CONST type_id=2 */ /* [4] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 2),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "",
|
||||
.str_sec_size = sizeof(""),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "array_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid array of int",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "array test. index_type \"void\"",
|
||||
.raw_types = {
|
||||
/* int */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
|
||||
/* int[16] */ /* [2] */
|
||||
BTF_TYPE_ARRAY_ENC(1, 0, 16),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "",
|
||||
.str_sec_size = sizeof(""),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "array_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid index",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "array test. index_type \"const void\"",
|
||||
.raw_types = {
|
||||
/* int */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
|
||||
/* int[16] */ /* [2] */
|
||||
BTF_TYPE_ARRAY_ENC(1, 3, 16),
|
||||
/* CONST type_id=0 (void) */ /* [3] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 0),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "",
|
||||
.str_sec_size = sizeof(""),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "array_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid index",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "array test. elem_type \"const void\"",
|
||||
.raw_types = {
|
||||
/* int */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
|
||||
/* int[16] */ /* [2] */
|
||||
BTF_TYPE_ARRAY_ENC(3, 1, 16),
|
||||
/* CONST type_id=0 (void) */ /* [3] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 0),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "",
|
||||
.str_sec_size = sizeof(""),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "array_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid elem",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "array test. elem_type \"const void *\"",
|
||||
.raw_types = {
|
||||
/* int */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
|
||||
/* const void *[16] */ /* [2] */
|
||||
BTF_TYPE_ARRAY_ENC(3, 1, 16),
|
||||
/* CONST type_id=4 */ /* [3] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 4),
|
||||
/* void* */ /* [4] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 0),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "",
|
||||
.str_sec_size = sizeof(""),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "array_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "array test. index_type \"const void *\"",
|
||||
.raw_types = {
|
||||
/* int */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
|
||||
/* const void *[16] */ /* [2] */
|
||||
BTF_TYPE_ARRAY_ENC(3, 3, 16),
|
||||
/* CONST type_id=4 */ /* [3] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 4),
|
||||
/* void* */ /* [4] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 0),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "",
|
||||
.str_sec_size = sizeof(""),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "array_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid index",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "int test. invalid int_data",
|
||||
.raw_types = {
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_INT, 0, 0), 4),
|
||||
0x10000000,
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "",
|
||||
.str_sec_size = sizeof(""),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "array_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid int_data",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "invalid BTF_INFO",
|
||||
.raw_types = {
|
||||
/* int */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
|
||||
BTF_TYPE_ENC(0, 0x10000000, 4),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "",
|
||||
.str_sec_size = sizeof(""),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "array_test_map",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid btf_info",
|
||||
},
|
||||
|
||||
}; /* struct btf_raw_test raw_tests[] */
|
||||
@@ -951,6 +1285,7 @@ static void *btf_raw_create(const struct btf_header *hdr,
|
||||
memcpy(raw_btf + offset, str, str_sec_size);
|
||||
|
||||
ret_hdr = (struct btf_header *)raw_btf;
|
||||
ret_hdr->type_len = type_sec_size;
|
||||
ret_hdr->str_off = type_sec_size;
|
||||
ret_hdr->str_len = str_sec_size;
|
||||
|
||||
@@ -981,6 +1316,7 @@ static int do_test_raw(unsigned int test_num)
|
||||
|
||||
hdr = raw_btf;
|
||||
|
||||
hdr->hdr_len = (int)hdr->hdr_len + test->hdr_len_delta;
|
||||
hdr->type_off = (int)hdr->type_off + test->type_off_delta;
|
||||
hdr->str_off = (int)hdr->str_off + test->str_off_delta;
|
||||
hdr->str_len = (int)hdr->str_len + test->str_len_delta;
|
||||
@@ -992,8 +1328,13 @@ static int do_test_raw(unsigned int test_num)
|
||||
free(raw_btf);
|
||||
|
||||
err = ((btf_fd == -1) != test->btf_load_err);
|
||||
CHECK(err, "btf_fd:%d test->btf_load_err:%u",
|
||||
btf_fd, test->btf_load_err);
|
||||
if (CHECK(err, "btf_fd:%d test->btf_load_err:%u",
|
||||
btf_fd, test->btf_load_err) ||
|
||||
CHECK(test->err_str && !strstr(btf_log_buf, test->err_str),
|
||||
"expected err_str:%s", test->err_str)) {
|
||||
err = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (err || btf_fd == -1)
|
||||
goto done;
|
||||
@@ -1004,8 +1345,8 @@ static int do_test_raw(unsigned int test_num)
|
||||
create_attr.value_size = test->value_size;
|
||||
create_attr.max_entries = test->max_entries;
|
||||
create_attr.btf_fd = btf_fd;
|
||||
create_attr.btf_key_id = test->key_id;
|
||||
create_attr.btf_value_id = test->value_id;
|
||||
create_attr.btf_key_type_id = test->key_type_id;
|
||||
create_attr.btf_value_type_id = test->value_type_id;
|
||||
|
||||
map_fd = bpf_create_map_xattr(&create_attr);
|
||||
|
||||
@@ -1267,8 +1608,8 @@ static int test_btf_id(unsigned int test_num)
|
||||
create_attr.value_size = sizeof(unsigned int);
|
||||
create_attr.max_entries = 4;
|
||||
create_attr.btf_fd = btf_fd[0];
|
||||
create_attr.btf_key_id = 1;
|
||||
create_attr.btf_value_id = 2;
|
||||
create_attr.btf_key_type_id = 1;
|
||||
create_attr.btf_value_type_id = 2;
|
||||
|
||||
map_fd = bpf_create_map_xattr(&create_attr);
|
||||
if (CHECK(map_fd == -1, "errno:%d", errno)) {
|
||||
@@ -1279,10 +1620,10 @@ static int test_btf_id(unsigned int test_num)
|
||||
info_len = sizeof(map_info);
|
||||
err = bpf_obj_get_info_by_fd(map_fd, &map_info, &info_len);
|
||||
if (CHECK(err || map_info.btf_id != info[0].id ||
|
||||
map_info.btf_key_id != 1 || map_info.btf_value_id != 2,
|
||||
"err:%d errno:%d info.id:%u btf_id:%u btf_key_id:%u btf_value_id:%u",
|
||||
err, errno, info[0].id, map_info.btf_id, map_info.btf_key_id,
|
||||
map_info.btf_value_id)) {
|
||||
map_info.btf_key_type_id != 1 || map_info.btf_value_type_id != 2,
|
||||
"err:%d errno:%d info.id:%u btf_id:%u btf_key_type_id:%u btf_value_type_id:%u",
|
||||
err, errno, info[0].id, map_info.btf_id, map_info.btf_key_type_id,
|
||||
map_info.btf_value_type_id)) {
|
||||
err = -1;
|
||||
goto done;
|
||||
}
|
||||
@@ -1542,10 +1883,10 @@ static int do_test_file(unsigned int test_num)
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = (bpf_map__btf_key_id(map) == 0 || bpf_map__btf_value_id(map) == 0)
|
||||
err = (bpf_map__btf_key_type_id(map) == 0 || bpf_map__btf_value_type_id(map) == 0)
|
||||
!= test->btf_kv_notfound;
|
||||
if (CHECK(err, "btf_key_id:%u btf_value_id:%u test->btf_kv_notfound:%u",
|
||||
bpf_map__btf_key_id(map), bpf_map__btf_value_id(map),
|
||||
if (CHECK(err, "btf_key_type_id:%u btf_value_type_id:%u test->btf_kv_notfound:%u",
|
||||
bpf_map__btf_key_type_id(map), bpf_map__btf_value_type_id(map),
|
||||
test->btf_kv_notfound))
|
||||
goto done;
|
||||
|
||||
@@ -1615,7 +1956,7 @@ static struct btf_raw_test pprint_test = {
|
||||
/* 28 bits */ /* [7] */
|
||||
BTF_TYPE_INT_ENC(0, 0, 0, 28, 4),
|
||||
/* uint8_t[8] */ /* [8] */
|
||||
BTF_TYPE_ARRAY_ENC(9, 3, 8),
|
||||
BTF_TYPE_ARRAY_ENC(9, 1, 8),
|
||||
/* typedef unsigned char uint8_t */ /* [9] */
|
||||
BTF_TYPEDEF_ENC(NAME_TBD, 1),
|
||||
/* typedef unsigned short uint16_t */ /* [10] */
|
||||
@@ -1654,8 +1995,8 @@ static struct btf_raw_test pprint_test = {
|
||||
.map_name = "pprint_test",
|
||||
.key_size = sizeof(unsigned int),
|
||||
.value_size = sizeof(struct pprint_mapv),
|
||||
.key_id = 3, /* unsigned int */
|
||||
.value_id = 16, /* struct pprint_mapv */
|
||||
.key_type_id = 3, /* unsigned int */
|
||||
.value_type_id = 16, /* struct pprint_mapv */
|
||||
.max_entries = 128 * 1024,
|
||||
};
|
||||
|
||||
@@ -1712,8 +2053,8 @@ static int test_pprint(void)
|
||||
create_attr.value_size = test->value_size;
|
||||
create_attr.max_entries = test->max_entries;
|
||||
create_attr.btf_fd = btf_fd;
|
||||
create_attr.btf_key_id = test->key_id;
|
||||
create_attr.btf_value_id = test->value_id;
|
||||
create_attr.btf_key_type_id = test->key_type_id;
|
||||
create_attr.btf_value_type_id = test->value_type_id;
|
||||
|
||||
map_fd = bpf_create_map_xattr(&create_attr);
|
||||
if (CHECK(map_fd == -1, "errno:%d", errno)) {
|
||||
|
@@ -0,0 +1,437 @@
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
#include <errno.h>
|
||||
#include <linux/seg6_local.h>
|
||||
#include <linux/bpf.h>
|
||||
#include "bpf_helpers.h"
|
||||
#include "bpf_endian.h"
|
||||
|
||||
#define bpf_printk(fmt, ...) \
|
||||
({ \
|
||||
char ____fmt[] = fmt; \
|
||||
bpf_trace_printk(____fmt, sizeof(____fmt), \
|
||||
##__VA_ARGS__); \
|
||||
})
|
||||
|
||||
/* Packet parsing state machine helpers. */
|
||||
#define cursor_advance(_cursor, _len) \
|
||||
({ void *_tmp = _cursor; _cursor += _len; _tmp; })
|
||||
|
||||
#define SR6_FLAG_ALERT (1 << 4)
|
||||
|
||||
#define htonll(x) ((bpf_htonl(1)) == 1 ? (x) : ((uint64_t)bpf_htonl((x) & \
|
||||
0xFFFFFFFF) << 32) | bpf_htonl((x) >> 32))
|
||||
#define ntohll(x) ((bpf_ntohl(1)) == 1 ? (x) : ((uint64_t)bpf_ntohl((x) & \
|
||||
0xFFFFFFFF) << 32) | bpf_ntohl((x) >> 32))
|
||||
#define BPF_PACKET_HEADER __attribute__((packed))
|
||||
|
||||
struct ip6_t {
|
||||
unsigned int ver:4;
|
||||
unsigned int priority:8;
|
||||
unsigned int flow_label:20;
|
||||
unsigned short payload_len;
|
||||
unsigned char next_header;
|
||||
unsigned char hop_limit;
|
||||
unsigned long long src_hi;
|
||||
unsigned long long src_lo;
|
||||
unsigned long long dst_hi;
|
||||
unsigned long long dst_lo;
|
||||
} BPF_PACKET_HEADER;
|
||||
|
||||
struct ip6_addr_t {
|
||||
unsigned long long hi;
|
||||
unsigned long long lo;
|
||||
} BPF_PACKET_HEADER;
|
||||
|
||||
struct ip6_srh_t {
|
||||
unsigned char nexthdr;
|
||||
unsigned char hdrlen;
|
||||
unsigned char type;
|
||||
unsigned char segments_left;
|
||||
unsigned char first_segment;
|
||||
unsigned char flags;
|
||||
unsigned short tag;
|
||||
|
||||
struct ip6_addr_t segments[0];
|
||||
} BPF_PACKET_HEADER;
|
||||
|
||||
struct sr6_tlv_t {
|
||||
unsigned char type;
|
||||
unsigned char len;
|
||||
unsigned char value[0];
|
||||
} BPF_PACKET_HEADER;
|
||||
|
||||
__attribute__((always_inline)) struct ip6_srh_t *get_srh(struct __sk_buff *skb)
|
||||
{
|
||||
void *cursor, *data_end;
|
||||
struct ip6_srh_t *srh;
|
||||
struct ip6_t *ip;
|
||||
uint8_t *ipver;
|
||||
|
||||
data_end = (void *)(long)skb->data_end;
|
||||
cursor = (void *)(long)skb->data;
|
||||
ipver = (uint8_t *)cursor;
|
||||
|
||||
if ((void *)ipver + sizeof(*ipver) > data_end)
|
||||
return NULL;
|
||||
|
||||
if ((*ipver >> 4) != 6)
|
||||
return NULL;
|
||||
|
||||
ip = cursor_advance(cursor, sizeof(*ip));
|
||||
if ((void *)ip + sizeof(*ip) > data_end)
|
||||
return NULL;
|
||||
|
||||
if (ip->next_header != 43)
|
||||
return NULL;
|
||||
|
||||
srh = cursor_advance(cursor, sizeof(*srh));
|
||||
if ((void *)srh + sizeof(*srh) > data_end)
|
||||
return NULL;
|
||||
|
||||
if (srh->type != 4)
|
||||
return NULL;
|
||||
|
||||
return srh;
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
int update_tlv_pad(struct __sk_buff *skb, uint32_t new_pad,
|
||||
uint32_t old_pad, uint32_t pad_off)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (new_pad != old_pad) {
|
||||
err = bpf_lwt_seg6_adjust_srh(skb, pad_off,
|
||||
(int) new_pad - (int) old_pad);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (new_pad > 0) {
|
||||
char pad_tlv_buf[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0};
|
||||
struct sr6_tlv_t *pad_tlv = (struct sr6_tlv_t *) pad_tlv_buf;
|
||||
|
||||
pad_tlv->type = SR6_TLV_PADDING;
|
||||
pad_tlv->len = new_pad - 2;
|
||||
|
||||
err = bpf_lwt_seg6_store_bytes(skb, pad_off,
|
||||
(void *)pad_tlv_buf, new_pad);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
int is_valid_tlv_boundary(struct __sk_buff *skb, struct ip6_srh_t *srh,
|
||||
uint32_t *tlv_off, uint32_t *pad_size,
|
||||
uint32_t *pad_off)
|
||||
{
|
||||
uint32_t srh_off, cur_off;
|
||||
int offset_valid = 0;
|
||||
int err;
|
||||
|
||||
srh_off = (char *)srh - (char *)(long)skb->data;
|
||||
// cur_off = end of segments, start of possible TLVs
|
||||
cur_off = srh_off + sizeof(*srh) +
|
||||
sizeof(struct ip6_addr_t) * (srh->first_segment + 1);
|
||||
|
||||
*pad_off = 0;
|
||||
|
||||
// we can only go as far as ~10 TLVs due to the BPF max stack size
|
||||
#pragma clang loop unroll(full)
|
||||
for (int i = 0; i < 10; i++) {
|
||||
struct sr6_tlv_t tlv;
|
||||
|
||||
if (cur_off == *tlv_off)
|
||||
offset_valid = 1;
|
||||
|
||||
if (cur_off >= srh_off + ((srh->hdrlen + 1) << 3))
|
||||
break;
|
||||
|
||||
err = bpf_skb_load_bytes(skb, cur_off, &tlv, sizeof(tlv));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (tlv.type == SR6_TLV_PADDING) {
|
||||
*pad_size = tlv.len + sizeof(tlv);
|
||||
*pad_off = cur_off;
|
||||
|
||||
if (*tlv_off == srh_off) {
|
||||
*tlv_off = cur_off;
|
||||
offset_valid = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
} else if (tlv.type == SR6_TLV_HMAC) {
|
||||
break;
|
||||
}
|
||||
|
||||
cur_off += sizeof(tlv) + tlv.len;
|
||||
} // we reached the padding or HMAC TLVs, or the end of the SRH
|
||||
|
||||
if (*pad_off == 0)
|
||||
*pad_off = cur_off;
|
||||
|
||||
if (*tlv_off == -1)
|
||||
*tlv_off = cur_off;
|
||||
else if (!offset_valid)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
int add_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, uint32_t tlv_off,
|
||||
struct sr6_tlv_t *itlv, uint8_t tlv_size)
|
||||
{
|
||||
uint32_t srh_off = (char *)srh - (char *)(long)skb->data;
|
||||
uint8_t len_remaining, new_pad;
|
||||
uint32_t pad_off = 0;
|
||||
uint32_t pad_size = 0;
|
||||
uint32_t partial_srh_len;
|
||||
int err;
|
||||
|
||||
if (tlv_off != -1)
|
||||
tlv_off += srh_off;
|
||||
|
||||
if (itlv->type == SR6_TLV_PADDING || itlv->type == SR6_TLV_HMAC)
|
||||
return -EINVAL;
|
||||
|
||||
err = is_valid_tlv_boundary(skb, srh, &tlv_off, &pad_size, &pad_off);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = bpf_lwt_seg6_adjust_srh(skb, tlv_off, sizeof(*itlv) + itlv->len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = bpf_lwt_seg6_store_bytes(skb, tlv_off, (void *)itlv, tlv_size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
// the following can't be moved inside update_tlv_pad because the
|
||||
// bpf verifier has some issues with it
|
||||
pad_off += sizeof(*itlv) + itlv->len;
|
||||
partial_srh_len = pad_off - srh_off;
|
||||
len_remaining = partial_srh_len % 8;
|
||||
new_pad = 8 - len_remaining;
|
||||
|
||||
if (new_pad == 1) // cannot pad for 1 byte only
|
||||
new_pad = 9;
|
||||
else if (new_pad == 8)
|
||||
new_pad = 0;
|
||||
|
||||
return update_tlv_pad(skb, new_pad, pad_size, pad_off);
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
int delete_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh,
|
||||
uint32_t tlv_off)
|
||||
{
|
||||
uint32_t srh_off = (char *)srh - (char *)(long)skb->data;
|
||||
uint8_t len_remaining, new_pad;
|
||||
uint32_t partial_srh_len;
|
||||
uint32_t pad_off = 0;
|
||||
uint32_t pad_size = 0;
|
||||
struct sr6_tlv_t tlv;
|
||||
int err;
|
||||
|
||||
tlv_off += srh_off;
|
||||
|
||||
err = is_valid_tlv_boundary(skb, srh, &tlv_off, &pad_size, &pad_off);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = bpf_skb_load_bytes(skb, tlv_off, &tlv, sizeof(tlv));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = bpf_lwt_seg6_adjust_srh(skb, tlv_off, -(sizeof(tlv) + tlv.len));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
pad_off -= sizeof(tlv) + tlv.len;
|
||||
partial_srh_len = pad_off - srh_off;
|
||||
len_remaining = partial_srh_len % 8;
|
||||
new_pad = 8 - len_remaining;
|
||||
if (new_pad == 1) // cannot pad for 1 byte only
|
||||
new_pad = 9;
|
||||
else if (new_pad == 8)
|
||||
new_pad = 0;
|
||||
|
||||
return update_tlv_pad(skb, new_pad, pad_size, pad_off);
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
int has_egr_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh)
|
||||
{
|
||||
int tlv_offset = sizeof(struct ip6_t) + sizeof(struct ip6_srh_t) +
|
||||
((srh->first_segment + 1) << 4);
|
||||
struct sr6_tlv_t tlv;
|
||||
|
||||
if (bpf_skb_load_bytes(skb, tlv_offset, &tlv, sizeof(struct sr6_tlv_t)))
|
||||
return 0;
|
||||
|
||||
if (tlv.type == SR6_TLV_EGRESS && tlv.len == 18) {
|
||||
struct ip6_addr_t egr_addr;
|
||||
|
||||
if (bpf_skb_load_bytes(skb, tlv_offset + 4, &egr_addr, 16))
|
||||
return 0;
|
||||
|
||||
// check if egress TLV value is correct
|
||||
if (ntohll(egr_addr.hi) == 0xfd00000000000000 &&
|
||||
ntohll(egr_addr.lo) == 0x4)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This function will push a SRH with segments fd00::1, fd00::2, fd00::3,
|
||||
// fd00::4
|
||||
SEC("encap_srh")
|
||||
int __encap_srh(struct __sk_buff *skb)
|
||||
{
|
||||
unsigned long long hi = 0xfd00000000000000;
|
||||
struct ip6_addr_t *seg;
|
||||
struct ip6_srh_t *srh;
|
||||
char srh_buf[72]; // room for 4 segments
|
||||
int err;
|
||||
|
||||
srh = (struct ip6_srh_t *)srh_buf;
|
||||
srh->nexthdr = 0;
|
||||
srh->hdrlen = 8;
|
||||
srh->type = 4;
|
||||
srh->segments_left = 3;
|
||||
srh->first_segment = 3;
|
||||
srh->flags = 0;
|
||||
srh->tag = 0;
|
||||
|
||||
seg = (struct ip6_addr_t *)((char *)srh + sizeof(*srh));
|
||||
|
||||
#pragma clang loop unroll(full)
|
||||
for (unsigned long long lo = 0; lo < 4; lo++) {
|
||||
seg->lo = htonll(4 - lo);
|
||||
seg->hi = htonll(hi);
|
||||
seg = (struct ip6_addr_t *)((char *)seg + sizeof(*seg));
|
||||
}
|
||||
|
||||
err = bpf_lwt_push_encap(skb, 0, (void *)srh, sizeof(srh_buf));
|
||||
if (err)
|
||||
return BPF_DROP;
|
||||
|
||||
return BPF_REDIRECT;
|
||||
}
|
||||
|
||||
// Add an Egress TLV fc00::4, add the flag A,
|
||||
// and apply End.X action to fc42::1
|
||||
SEC("add_egr_x")
|
||||
int __add_egr_x(struct __sk_buff *skb)
|
||||
{
|
||||
unsigned long long hi = 0xfc42000000000000;
|
||||
unsigned long long lo = 0x1;
|
||||
struct ip6_srh_t *srh = get_srh(skb);
|
||||
uint8_t new_flags = SR6_FLAG_ALERT;
|
||||
struct ip6_addr_t addr;
|
||||
int err, offset;
|
||||
|
||||
if (srh == NULL)
|
||||
return BPF_DROP;
|
||||
|
||||
uint8_t tlv[20] = {2, 18, 0, 0, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4};
|
||||
|
||||
err = add_tlv(skb, srh, (srh->hdrlen+1) << 3,
|
||||
(struct sr6_tlv_t *)&tlv, 20);
|
||||
if (err)
|
||||
return BPF_DROP;
|
||||
|
||||
offset = sizeof(struct ip6_t) + offsetof(struct ip6_srh_t, flags);
|
||||
err = bpf_lwt_seg6_store_bytes(skb, offset,
|
||||
(void *)&new_flags, sizeof(new_flags));
|
||||
if (err)
|
||||
return BPF_DROP;
|
||||
|
||||
addr.lo = htonll(lo);
|
||||
addr.hi = htonll(hi);
|
||||
err = bpf_lwt_seg6_action(skb, SEG6_LOCAL_ACTION_END_X,
|
||||
(void *)&addr, sizeof(addr));
|
||||
if (err)
|
||||
return BPF_DROP;
|
||||
return BPF_REDIRECT;
|
||||
}
|
||||
|
||||
// Pop the Egress TLV, reset the flags, change the tag 2442 and finally do a
|
||||
// simple End action
|
||||
SEC("pop_egr")
|
||||
int __pop_egr(struct __sk_buff *skb)
|
||||
{
|
||||
struct ip6_srh_t *srh = get_srh(skb);
|
||||
uint16_t new_tag = bpf_htons(2442);
|
||||
uint8_t new_flags = 0;
|
||||
int err, offset;
|
||||
|
||||
if (srh == NULL)
|
||||
return BPF_DROP;
|
||||
|
||||
if (srh->flags != SR6_FLAG_ALERT)
|
||||
return BPF_DROP;
|
||||
|
||||
if (srh->hdrlen != 11) // 4 segments + Egress TLV + Padding TLV
|
||||
return BPF_DROP;
|
||||
|
||||
if (!has_egr_tlv(skb, srh))
|
||||
return BPF_DROP;
|
||||
|
||||
err = delete_tlv(skb, srh, 8 + (srh->first_segment + 1) * 16);
|
||||
if (err)
|
||||
return BPF_DROP;
|
||||
|
||||
offset = sizeof(struct ip6_t) + offsetof(struct ip6_srh_t, flags);
|
||||
if (bpf_lwt_seg6_store_bytes(skb, offset, (void *)&new_flags,
|
||||
sizeof(new_flags)))
|
||||
return BPF_DROP;
|
||||
|
||||
offset = sizeof(struct ip6_t) + offsetof(struct ip6_srh_t, tag);
|
||||
if (bpf_lwt_seg6_store_bytes(skb, offset, (void *)&new_tag,
|
||||
sizeof(new_tag)))
|
||||
return BPF_DROP;
|
||||
|
||||
return BPF_OK;
|
||||
}
|
||||
|
||||
// Inspect if the Egress TLV and flag have been removed, if the tag is correct,
|
||||
// then apply a End.T action to reach the last segment
|
||||
SEC("inspect_t")
|
||||
int __inspect_t(struct __sk_buff *skb)
|
||||
{
|
||||
struct ip6_srh_t *srh = get_srh(skb);
|
||||
int table = 117;
|
||||
int err;
|
||||
|
||||
if (srh == NULL)
|
||||
return BPF_DROP;
|
||||
|
||||
if (srh->flags != 0)
|
||||
return BPF_DROP;
|
||||
|
||||
if (srh->tag != bpf_htons(2442))
|
||||
return BPF_DROP;
|
||||
|
||||
if (srh->hdrlen != 8) // 4 segments
|
||||
return BPF_DROP;
|
||||
|
||||
err = bpf_lwt_seg6_action(skb, SEG6_LOCAL_ACTION_END_T,
|
||||
(void *)&table, sizeof(table));
|
||||
|
||||
if (err)
|
||||
return BPF_DROP;
|
||||
|
||||
return BPF_REDIRECT;
|
||||
}
|
||||
|
||||
char __license[] SEC("license") = "GPL";
|
@@ -0,0 +1,140 @@
|
||||
#!/bin/bash
|
||||
# Connects 6 network namespaces through veths.
|
||||
# Each NS may have different IPv6 global scope addresses :
|
||||
# NS1 ---- NS2 ---- NS3 ---- NS4 ---- NS5 ---- NS6
|
||||
# fb00::1 fd00::1 fd00::2 fd00::3 fb00::6
|
||||
# fc42::1 fd00::4
|
||||
#
|
||||
# All IPv6 packets going to fb00::/16 through NS2 will be encapsulated in a
|
||||
# IPv6 header with a Segment Routing Header, with segments :
|
||||
# fd00::1 -> fd00::2 -> fd00::3 -> fd00::4
|
||||
#
|
||||
# 3 fd00::/16 IPv6 addresses are binded to seg6local End.BPF actions :
|
||||
# - fd00::1 : add a TLV, change the flags and apply a End.X action to fc42::1
|
||||
# - fd00::2 : remove the TLV, change the flags, add a tag
|
||||
# - fd00::3 : apply an End.T action to fd00::4, through routing table 117
|
||||
#
|
||||
# fd00::4 is a simple Segment Routing node decapsulating the inner IPv6 packet.
|
||||
# Each End.BPF action will validate the operations applied on the SRH by the
|
||||
# previous BPF program in the chain, otherwise the packet is dropped.
|
||||
#
|
||||
# An UDP datagram is sent from fb00::1 to fb00::6. The test succeeds if this
|
||||
# datagram can be read on NS6 when binding to fb00::6.
|
||||
|
||||
TMP_FILE="/tmp/selftest_lwt_seg6local.txt"
|
||||
|
||||
cleanup()
|
||||
{
|
||||
if [ "$?" = "0" ]; then
|
||||
echo "selftests: test_lwt_seg6local [PASS]";
|
||||
else
|
||||
echo "selftests: test_lwt_seg6local [FAILED]";
|
||||
fi
|
||||
|
||||
set +e
|
||||
ip netns del ns1 2> /dev/null
|
||||
ip netns del ns2 2> /dev/null
|
||||
ip netns del ns3 2> /dev/null
|
||||
ip netns del ns4 2> /dev/null
|
||||
ip netns del ns5 2> /dev/null
|
||||
ip netns del ns6 2> /dev/null
|
||||
rm -f $TMP_FILE
|
||||
}
|
||||
|
||||
set -e
|
||||
|
||||
ip netns add ns1
|
||||
ip netns add ns2
|
||||
ip netns add ns3
|
||||
ip netns add ns4
|
||||
ip netns add ns5
|
||||
ip netns add ns6
|
||||
|
||||
trap cleanup 0 2 3 6 9
|
||||
|
||||
ip link add veth1 type veth peer name veth2
|
||||
ip link add veth3 type veth peer name veth4
|
||||
ip link add veth5 type veth peer name veth6
|
||||
ip link add veth7 type veth peer name veth8
|
||||
ip link add veth9 type veth peer name veth10
|
||||
|
||||
ip link set veth1 netns ns1
|
||||
ip link set veth2 netns ns2
|
||||
ip link set veth3 netns ns2
|
||||
ip link set veth4 netns ns3
|
||||
ip link set veth5 netns ns3
|
||||
ip link set veth6 netns ns4
|
||||
ip link set veth7 netns ns4
|
||||
ip link set veth8 netns ns5
|
||||
ip link set veth9 netns ns5
|
||||
ip link set veth10 netns ns6
|
||||
|
||||
ip netns exec ns1 ip link set dev veth1 up
|
||||
ip netns exec ns2 ip link set dev veth2 up
|
||||
ip netns exec ns2 ip link set dev veth3 up
|
||||
ip netns exec ns3 ip link set dev veth4 up
|
||||
ip netns exec ns3 ip link set dev veth5 up
|
||||
ip netns exec ns4 ip link set dev veth6 up
|
||||
ip netns exec ns4 ip link set dev veth7 up
|
||||
ip netns exec ns5 ip link set dev veth8 up
|
||||
ip netns exec ns5 ip link set dev veth9 up
|
||||
ip netns exec ns6 ip link set dev veth10 up
|
||||
ip netns exec ns6 ip link set dev lo up
|
||||
|
||||
# All link scope addresses and routes required between veths
|
||||
ip netns exec ns1 ip -6 addr add fb00::12/16 dev veth1 scope link
|
||||
ip netns exec ns1 ip -6 route add fb00::21 dev veth1 scope link
|
||||
ip netns exec ns2 ip -6 addr add fb00::21/16 dev veth2 scope link
|
||||
ip netns exec ns2 ip -6 addr add fb00::34/16 dev veth3 scope link
|
||||
ip netns exec ns2 ip -6 route add fb00::43 dev veth3 scope link
|
||||
ip netns exec ns3 ip -6 route add fb00::65 dev veth5 scope link
|
||||
ip netns exec ns3 ip -6 addr add fb00::43/16 dev veth4 scope link
|
||||
ip netns exec ns3 ip -6 addr add fb00::56/16 dev veth5 scope link
|
||||
ip netns exec ns4 ip -6 addr add fb00::65/16 dev veth6 scope link
|
||||
ip netns exec ns4 ip -6 addr add fb00::78/16 dev veth7 scope link
|
||||
ip netns exec ns4 ip -6 route add fb00::87 dev veth7 scope link
|
||||
ip netns exec ns5 ip -6 addr add fb00::87/16 dev veth8 scope link
|
||||
ip netns exec ns5 ip -6 addr add fb00::910/16 dev veth9 scope link
|
||||
ip netns exec ns5 ip -6 route add fb00::109 dev veth9 scope link
|
||||
ip netns exec ns5 ip -6 route add fb00::109 table 117 dev veth9 scope link
|
||||
ip netns exec ns6 ip -6 addr add fb00::109/16 dev veth10 scope link
|
||||
|
||||
ip netns exec ns1 ip -6 addr add fb00::1/16 dev lo
|
||||
ip netns exec ns1 ip -6 route add fb00::6 dev veth1 via fb00::21
|
||||
|
||||
ip netns exec ns2 ip -6 route add fb00::6 encap bpf in obj test_lwt_seg6local.o sec encap_srh dev veth2
|
||||
ip netns exec ns2 ip -6 route add fd00::1 dev veth3 via fb00::43 scope link
|
||||
|
||||
ip netns exec ns3 ip -6 route add fc42::1 dev veth5 via fb00::65
|
||||
ip netns exec ns3 ip -6 route add fd00::1 encap seg6local action End.BPF obj test_lwt_seg6local.o sec add_egr_x dev veth4
|
||||
|
||||
ip netns exec ns4 ip -6 route add fd00::2 encap seg6local action End.BPF obj test_lwt_seg6local.o sec pop_egr dev veth6
|
||||
ip netns exec ns4 ip -6 addr add fc42::1 dev lo
|
||||
ip netns exec ns4 ip -6 route add fd00::3 dev veth7 via fb00::87
|
||||
|
||||
ip netns exec ns5 ip -6 route add fd00::4 table 117 dev veth9 via fb00::109
|
||||
ip netns exec ns5 ip -6 route add fd00::3 encap seg6local action End.BPF obj test_lwt_seg6local.o sec inspect_t dev veth8
|
||||
|
||||
ip netns exec ns6 ip -6 addr add fb00::6/16 dev lo
|
||||
ip netns exec ns6 ip -6 addr add fd00::4/16 dev lo
|
||||
|
||||
ip netns exec ns1 sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
|
||||
ip netns exec ns2 sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
|
||||
ip netns exec ns3 sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
|
||||
ip netns exec ns4 sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
|
||||
ip netns exec ns5 sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
|
||||
|
||||
ip netns exec ns6 sysctl net.ipv6.conf.all.seg6_enabled=1 > /dev/null
|
||||
ip netns exec ns6 sysctl net.ipv6.conf.lo.seg6_enabled=1 > /dev/null
|
||||
ip netns exec ns6 sysctl net.ipv6.conf.veth10.seg6_enabled=1 > /dev/null
|
||||
|
||||
ip netns exec ns6 nc -l -6 -u -d 7330 > $TMP_FILE &
|
||||
ip netns exec ns1 bash -c "echo 'foobar' | nc -w0 -6 -u -p 2121 -s fb00::1 fb00::6 7330"
|
||||
sleep 5 # wait enough time to ensure the UDP datagram arrived to the last segment
|
||||
kill -INT $!
|
||||
|
||||
if [[ $(< $TMP_FILE) != "foobar" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
@@ -1542,6 +1542,162 @@ close_prog_noerr:
|
||||
bpf_object__close(obj);
|
||||
}
|
||||
|
||||
static void test_task_fd_query_rawtp(void)
|
||||
{
|
||||
const char *file = "./test_get_stack_rawtp.o";
|
||||
__u64 probe_offset, probe_addr;
|
||||
__u32 len, prog_id, fd_type;
|
||||
struct bpf_object *obj;
|
||||
int efd, err, prog_fd;
|
||||
__u32 duration = 0;
|
||||
char buf[256];
|
||||
|
||||
err = bpf_prog_load(file, BPF_PROG_TYPE_RAW_TRACEPOINT, &obj, &prog_fd);
|
||||
if (CHECK(err, "prog_load raw tp", "err %d errno %d\n", err, errno))
|
||||
return;
|
||||
|
||||
efd = bpf_raw_tracepoint_open("sys_enter", prog_fd);
|
||||
if (CHECK(efd < 0, "raw_tp_open", "err %d errno %d\n", efd, errno))
|
||||
goto close_prog;
|
||||
|
||||
/* query (getpid(), efd) */
|
||||
len = sizeof(buf);
|
||||
err = bpf_task_fd_query(getpid(), efd, 0, buf, &len, &prog_id,
|
||||
&fd_type, &probe_offset, &probe_addr);
|
||||
if (CHECK(err < 0, "bpf_task_fd_query", "err %d errno %d\n", err,
|
||||
errno))
|
||||
goto close_prog;
|
||||
|
||||
err = fd_type == BPF_FD_TYPE_RAW_TRACEPOINT &&
|
||||
strcmp(buf, "sys_enter") == 0;
|
||||
if (CHECK(!err, "check_results", "fd_type %d tp_name %s\n",
|
||||
fd_type, buf))
|
||||
goto close_prog;
|
||||
|
||||
/* test zero len */
|
||||
len = 0;
|
||||
err = bpf_task_fd_query(getpid(), efd, 0, buf, &len, &prog_id,
|
||||
&fd_type, &probe_offset, &probe_addr);
|
||||
if (CHECK(err < 0, "bpf_task_fd_query (len = 0)", "err %d errno %d\n",
|
||||
err, errno))
|
||||
goto close_prog;
|
||||
err = fd_type == BPF_FD_TYPE_RAW_TRACEPOINT &&
|
||||
len == strlen("sys_enter");
|
||||
if (CHECK(!err, "check_results", "fd_type %d len %u\n", fd_type, len))
|
||||
goto close_prog;
|
||||
|
||||
/* test empty buffer */
|
||||
len = sizeof(buf);
|
||||
err = bpf_task_fd_query(getpid(), efd, 0, 0, &len, &prog_id,
|
||||
&fd_type, &probe_offset, &probe_addr);
|
||||
if (CHECK(err < 0, "bpf_task_fd_query (buf = 0)", "err %d errno %d\n",
|
||||
err, errno))
|
||||
goto close_prog;
|
||||
err = fd_type == BPF_FD_TYPE_RAW_TRACEPOINT &&
|
||||
len == strlen("sys_enter");
|
||||
if (CHECK(!err, "check_results", "fd_type %d len %u\n", fd_type, len))
|
||||
goto close_prog;
|
||||
|
||||
/* test smaller buffer */
|
||||
len = 3;
|
||||
err = bpf_task_fd_query(getpid(), efd, 0, buf, &len, &prog_id,
|
||||
&fd_type, &probe_offset, &probe_addr);
|
||||
if (CHECK(err >= 0 || errno != ENOSPC, "bpf_task_fd_query (len = 3)",
|
||||
"err %d errno %d\n", err, errno))
|
||||
goto close_prog;
|
||||
err = fd_type == BPF_FD_TYPE_RAW_TRACEPOINT &&
|
||||
len == strlen("sys_enter") &&
|
||||
strcmp(buf, "sy") == 0;
|
||||
if (CHECK(!err, "check_results", "fd_type %d len %u\n", fd_type, len))
|
||||
goto close_prog;
|
||||
|
||||
goto close_prog_noerr;
|
||||
close_prog:
|
||||
error_cnt++;
|
||||
close_prog_noerr:
|
||||
bpf_object__close(obj);
|
||||
}
|
||||
|
||||
static void test_task_fd_query_tp_core(const char *probe_name,
|
||||
const char *tp_name)
|
||||
{
|
||||
const char *file = "./test_tracepoint.o";
|
||||
int err, bytes, efd, prog_fd, pmu_fd;
|
||||
struct perf_event_attr attr = {};
|
||||
__u64 probe_offset, probe_addr;
|
||||
__u32 len, prog_id, fd_type;
|
||||
struct bpf_object *obj;
|
||||
__u32 duration = 0;
|
||||
char buf[256];
|
||||
|
||||
err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd);
|
||||
if (CHECK(err, "bpf_prog_load", "err %d errno %d\n", err, errno))
|
||||
goto close_prog;
|
||||
|
||||
snprintf(buf, sizeof(buf),
|
||||
"/sys/kernel/debug/tracing/events/%s/id", probe_name);
|
||||
efd = open(buf, O_RDONLY, 0);
|
||||
if (CHECK(efd < 0, "open", "err %d errno %d\n", efd, errno))
|
||||
goto close_prog;
|
||||
bytes = read(efd, buf, sizeof(buf));
|
||||
close(efd);
|
||||
if (CHECK(bytes <= 0 || bytes >= sizeof(buf), "read",
|
||||
"bytes %d errno %d\n", bytes, errno))
|
||||
goto close_prog;
|
||||
|
||||
attr.config = strtol(buf, NULL, 0);
|
||||
attr.type = PERF_TYPE_TRACEPOINT;
|
||||
attr.sample_type = PERF_SAMPLE_RAW;
|
||||
attr.sample_period = 1;
|
||||
attr.wakeup_events = 1;
|
||||
pmu_fd = syscall(__NR_perf_event_open, &attr, -1 /* pid */,
|
||||
0 /* cpu 0 */, -1 /* group id */,
|
||||
0 /* flags */);
|
||||
if (CHECK(err, "perf_event_open", "err %d errno %d\n", err, errno))
|
||||
goto close_pmu;
|
||||
|
||||
err = ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0);
|
||||
if (CHECK(err, "perf_event_ioc_enable", "err %d errno %d\n", err,
|
||||
errno))
|
||||
goto close_pmu;
|
||||
|
||||
err = ioctl(pmu_fd, PERF_EVENT_IOC_SET_BPF, prog_fd);
|
||||
if (CHECK(err, "perf_event_ioc_set_bpf", "err %d errno %d\n", err,
|
||||
errno))
|
||||
goto close_pmu;
|
||||
|
||||
/* query (getpid(), pmu_fd) */
|
||||
len = sizeof(buf);
|
||||
err = bpf_task_fd_query(getpid(), pmu_fd, 0, buf, &len, &prog_id,
|
||||
&fd_type, &probe_offset, &probe_addr);
|
||||
if (CHECK(err < 0, "bpf_task_fd_query", "err %d errno %d\n", err,
|
||||
errno))
|
||||
goto close_pmu;
|
||||
|
||||
err = (fd_type == BPF_FD_TYPE_TRACEPOINT) && !strcmp(buf, tp_name);
|
||||
if (CHECK(!err, "check_results", "fd_type %d tp_name %s\n",
|
||||
fd_type, buf))
|
||||
goto close_pmu;
|
||||
|
||||
close(pmu_fd);
|
||||
goto close_prog_noerr;
|
||||
|
||||
close_pmu:
|
||||
close(pmu_fd);
|
||||
close_prog:
|
||||
error_cnt++;
|
||||
close_prog_noerr:
|
||||
bpf_object__close(obj);
|
||||
}
|
||||
|
||||
static void test_task_fd_query_tp(void)
|
||||
{
|
||||
test_task_fd_query_tp_core("sched/sched_switch",
|
||||
"sched_switch");
|
||||
test_task_fd_query_tp_core("syscalls/sys_enter_read",
|
||||
"sys_enter_read");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
jit_enabled = is_jit_enabled();
|
||||
@@ -1561,6 +1717,8 @@ int main(void)
|
||||
test_stacktrace_build_id_nmi();
|
||||
test_stacktrace_map_raw_tp();
|
||||
test_get_stack_raw_tp();
|
||||
test_task_fd_query_rawtp();
|
||||
test_task_fd_query_tp();
|
||||
|
||||
printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt);
|
||||
return error_cnt ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
|
@@ -1685,6 +1685,121 @@ static struct bpf_test tests[] = {
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_SK_SKB,
|
||||
},
|
||||
{
|
||||
"valid access family in SK_MSG",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
|
||||
offsetof(struct sk_msg_md, family)),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_SK_MSG,
|
||||
},
|
||||
{
|
||||
"valid access remote_ip4 in SK_MSG",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
|
||||
offsetof(struct sk_msg_md, remote_ip4)),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_SK_MSG,
|
||||
},
|
||||
{
|
||||
"valid access local_ip4 in SK_MSG",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
|
||||
offsetof(struct sk_msg_md, local_ip4)),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_SK_MSG,
|
||||
},
|
||||
{
|
||||
"valid access remote_port in SK_MSG",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
|
||||
offsetof(struct sk_msg_md, remote_port)),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_SK_MSG,
|
||||
},
|
||||
{
|
||||
"valid access local_port in SK_MSG",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
|
||||
offsetof(struct sk_msg_md, local_port)),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_SK_MSG,
|
||||
},
|
||||
{
|
||||
"valid access remote_ip6 in SK_MSG",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
|
||||
offsetof(struct sk_msg_md, remote_ip6[0])),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
|
||||
offsetof(struct sk_msg_md, remote_ip6[1])),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
|
||||
offsetof(struct sk_msg_md, remote_ip6[2])),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
|
||||
offsetof(struct sk_msg_md, remote_ip6[3])),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_SK_SKB,
|
||||
},
|
||||
{
|
||||
"valid access local_ip6 in SK_MSG",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
|
||||
offsetof(struct sk_msg_md, local_ip6[0])),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
|
||||
offsetof(struct sk_msg_md, local_ip6[1])),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
|
||||
offsetof(struct sk_msg_md, local_ip6[2])),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
|
||||
offsetof(struct sk_msg_md, local_ip6[3])),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_SK_SKB,
|
||||
},
|
||||
{
|
||||
"invalid 64B read of family in SK_MSG",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1,
|
||||
offsetof(struct sk_msg_md, family)),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "invalid bpf_context access",
|
||||
.result = REJECT,
|
||||
.prog_type = BPF_PROG_TYPE_SK_MSG,
|
||||
},
|
||||
{
|
||||
"invalid read past end of SK_MSG",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
|
||||
offsetof(struct sk_msg_md, local_port) + 4),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "R0 !read_ok",
|
||||
.result = REJECT,
|
||||
.prog_type = BPF_PROG_TYPE_SK_MSG,
|
||||
},
|
||||
{
|
||||
"invalid read offset in SK_MSG",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
|
||||
offsetof(struct sk_msg_md, family) + 1),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr = "invalid bpf_context access",
|
||||
.result = REJECT,
|
||||
.prog_type = BPF_PROG_TYPE_SK_MSG,
|
||||
},
|
||||
{
|
||||
"direct packet read for SK_MSG",
|
||||
.insns = {
|
||||
|
@@ -72,6 +72,18 @@ struct ksym *ksym_search(long key)
|
||||
return &syms[0];
|
||||
}
|
||||
|
||||
long ksym_get_addr(const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sym_cnt; i++) {
|
||||
if (strcmp(syms[i].name, name) == 0)
|
||||
return syms[i].addr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int page_size;
|
||||
static int page_cnt = 8;
|
||||
static struct perf_event_mmap_page *header;
|
||||
|
@@ -11,6 +11,7 @@ struct ksym {
|
||||
|
||||
int load_kallsyms(void);
|
||||
struct ksym *ksym_search(long key);
|
||||
long ksym_get_addr(const char *name);
|
||||
|
||||
typedef enum bpf_perf_event_ret (*perf_event_print_fn)(void *data, int size);
|
||||
|
||||
|
新增問題並參考
封鎖使用者