From d911ba7ceafd29606df4018bbd87a1642f9e6d88 Mon Sep 17 00:00:00 2001 From: Joanne Koong Date: Thu, 20 Apr 2023 00:14:14 -0700 Subject: selftests/bpf: Add tests for dynptr convenience helpers Add various tests for the added dynptr convenience helpers. Signed-off-by: Joanne Koong Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230420071414.570108-6-joannelkoong@gmail.com --- tools/testing/selftests/bpf/bpf_kfuncs.h | 6 + tools/testing/selftests/bpf/prog_tests/dynptr.c | 6 + tools/testing/selftests/bpf/progs/dynptr_fail.c | 287 ++++++++++++++++++++ tools/testing/selftests/bpf/progs/dynptr_success.c | 298 +++++++++++++++++++++ 4 files changed, 597 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/bpf_kfuncs.h b/tools/testing/selftests/bpf/bpf_kfuncs.h index 8c993ec8ceea..f3c41f8902a0 100644 --- a/tools/testing/selftests/bpf/bpf_kfuncs.h +++ b/tools/testing/selftests/bpf/bpf_kfuncs.h @@ -35,4 +35,10 @@ extern void *bpf_dynptr_slice(const struct bpf_dynptr *ptr, __u32 offset, extern void *bpf_dynptr_slice_rdwr(const struct bpf_dynptr *ptr, __u32 offset, void *buffer, __u32 buffer__szk) __ksym; +extern int bpf_dynptr_adjust(const struct bpf_dynptr *ptr, __u32 start, __u32 end) __ksym; +extern int bpf_dynptr_is_null(const struct bpf_dynptr *ptr) __ksym; +extern int bpf_dynptr_is_rdonly(const struct bpf_dynptr *ptr) __ksym; +extern __u32 bpf_dynptr_size(const struct bpf_dynptr *ptr) __ksym; +extern int bpf_dynptr_clone(const struct bpf_dynptr *ptr, struct bpf_dynptr *clone__init) __ksym; + #endif diff --git a/tools/testing/selftests/bpf/prog_tests/dynptr.c b/tools/testing/selftests/bpf/prog_tests/dynptr.c index d176c34a7d2e..0478916aff37 100644 --- a/tools/testing/selftests/bpf/prog_tests/dynptr.c +++ b/tools/testing/selftests/bpf/prog_tests/dynptr.c @@ -20,6 +20,12 @@ static struct { {"test_ringbuf", SETUP_SYSCALL_SLEEP}, {"test_skb_readonly", SETUP_SKB_PROG}, {"test_dynptr_skb_data", SETUP_SKB_PROG}, + {"test_adjust", SETUP_SYSCALL_SLEEP}, + {"test_adjust_err", SETUP_SYSCALL_SLEEP}, + {"test_zero_size_dynptr", SETUP_SYSCALL_SLEEP}, + {"test_dynptr_is_null", SETUP_SYSCALL_SLEEP}, + {"test_dynptr_is_rdonly", SETUP_SKB_PROG}, + {"test_dynptr_clone", SETUP_SKB_PROG}, }; static void verify_success(const char *prog_name, enum test_setup_type setup_type) diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c index 759eb5c245cd..efe4ce72d00e 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c @@ -1378,3 +1378,290 @@ int invalid_slice_rdwr_rdonly(struct __sk_buff *skb) return 0; } + +/* bpf_dynptr_adjust can only be called on initialized dynptrs */ +SEC("?raw_tp") +__failure __msg("Expected an initialized dynptr as arg #1") +int dynptr_adjust_invalid(void *ctx) +{ + struct bpf_dynptr ptr; + + /* this should fail */ + bpf_dynptr_adjust(&ptr, 1, 2); + + return 0; +} + +/* bpf_dynptr_is_null can only be called on initialized dynptrs */ +SEC("?raw_tp") +__failure __msg("Expected an initialized dynptr as arg #1") +int dynptr_is_null_invalid(void *ctx) +{ + struct bpf_dynptr ptr; + + /* this should fail */ + bpf_dynptr_is_null(&ptr); + + return 0; +} + +/* bpf_dynptr_is_rdonly can only be called on initialized dynptrs */ +SEC("?raw_tp") +__failure __msg("Expected an initialized dynptr as arg #1") +int dynptr_is_rdonly_invalid(void *ctx) +{ + struct bpf_dynptr ptr; + + /* this should fail */ + bpf_dynptr_is_rdonly(&ptr); + + return 0; +} + +/* bpf_dynptr_size can only be called on initialized dynptrs */ +SEC("?raw_tp") +__failure __msg("Expected an initialized dynptr as arg #1") +int dynptr_size_invalid(void *ctx) +{ + struct bpf_dynptr ptr; + + /* this should fail */ + bpf_dynptr_size(&ptr); + + return 0; +} + +/* Only initialized dynptrs can be cloned */ +SEC("?raw_tp") +__failure __msg("Expected an initialized dynptr as arg #1") +int clone_invalid1(void *ctx) +{ + struct bpf_dynptr ptr1; + struct bpf_dynptr ptr2; + + /* this should fail */ + bpf_dynptr_clone(&ptr1, &ptr2); + + return 0; +} + +/* Can't overwrite an existing dynptr when cloning */ +SEC("?xdp") +__failure __msg("cannot overwrite referenced dynptr") +int clone_invalid2(struct xdp_md *xdp) +{ + struct bpf_dynptr ptr1; + struct bpf_dynptr clone; + + bpf_dynptr_from_xdp(xdp, 0, &ptr1); + + bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &clone); + + /* this should fail */ + bpf_dynptr_clone(&ptr1, &clone); + + bpf_ringbuf_submit_dynptr(&clone, 0); + + return 0; +} + +/* Invalidating a dynptr should invalidate its clones */ +SEC("?raw_tp") +__failure __msg("Expected an initialized dynptr as arg #3") +int clone_invalidate1(void *ctx) +{ + struct bpf_dynptr clone; + struct bpf_dynptr ptr; + char read_data[64]; + + bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); + + bpf_dynptr_clone(&ptr, &clone); + + bpf_ringbuf_submit_dynptr(&ptr, 0); + + /* this should fail */ + bpf_dynptr_read(read_data, sizeof(read_data), &clone, 0, 0); + + return 0; +} + +/* Invalidating a dynptr should invalidate its parent */ +SEC("?raw_tp") +__failure __msg("Expected an initialized dynptr as arg #3") +int clone_invalidate2(void *ctx) +{ + struct bpf_dynptr ptr; + struct bpf_dynptr clone; + char read_data[64]; + + bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); + + bpf_dynptr_clone(&ptr, &clone); + + bpf_ringbuf_submit_dynptr(&clone, 0); + + /* this should fail */ + bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0); + + return 0; +} + +/* Invalidating a dynptr should invalidate its siblings */ +SEC("?raw_tp") +__failure __msg("Expected an initialized dynptr as arg #3") +int clone_invalidate3(void *ctx) +{ + struct bpf_dynptr ptr; + struct bpf_dynptr clone1; + struct bpf_dynptr clone2; + char read_data[64]; + + bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); + + bpf_dynptr_clone(&ptr, &clone1); + + bpf_dynptr_clone(&ptr, &clone2); + + bpf_ringbuf_submit_dynptr(&clone2, 0); + + /* this should fail */ + bpf_dynptr_read(read_data, sizeof(read_data), &clone1, 0, 0); + + return 0; +} + +/* Invalidating a dynptr should invalidate any data slices + * of its clones + */ +SEC("?raw_tp") +__failure __msg("invalid mem access 'scalar'") +int clone_invalidate4(void *ctx) +{ + struct bpf_dynptr ptr; + struct bpf_dynptr clone; + int *data; + + bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); + + bpf_dynptr_clone(&ptr, &clone); + data = bpf_dynptr_data(&clone, 0, sizeof(val)); + if (!data) + return 0; + + bpf_ringbuf_submit_dynptr(&ptr, 0); + + /* this should fail */ + *data = 123; + + return 0; +} + +/* Invalidating a dynptr should invalidate any data slices + * of its parent + */ +SEC("?raw_tp") +__failure __msg("invalid mem access 'scalar'") +int clone_invalidate5(void *ctx) +{ + struct bpf_dynptr ptr; + struct bpf_dynptr clone; + int *data; + + bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); + data = bpf_dynptr_data(&ptr, 0, sizeof(val)); + if (!data) + return 0; + + bpf_dynptr_clone(&ptr, &clone); + + bpf_ringbuf_submit_dynptr(&clone, 0); + + /* this should fail */ + *data = 123; + + return 0; +} + +/* Invalidating a dynptr should invalidate any data slices + * of its sibling + */ +SEC("?raw_tp") +__failure __msg("invalid mem access 'scalar'") +int clone_invalidate6(void *ctx) +{ + struct bpf_dynptr ptr; + struct bpf_dynptr clone1; + struct bpf_dynptr clone2; + int *data; + + bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); + + bpf_dynptr_clone(&ptr, &clone1); + + bpf_dynptr_clone(&ptr, &clone2); + + data = bpf_dynptr_data(&clone1, 0, sizeof(val)); + if (!data) + return 0; + + bpf_ringbuf_submit_dynptr(&clone2, 0); + + /* this should fail */ + *data = 123; + + return 0; +} + +/* A skb clone's data slices should be invalid anytime packet data changes */ +SEC("?tc") +__failure __msg("invalid mem access 'scalar'") +int clone_skb_packet_data(struct __sk_buff *skb) +{ + char buffer[sizeof(__u32)] = {}; + struct bpf_dynptr clone; + struct bpf_dynptr ptr; + __u32 *data; + + bpf_dynptr_from_skb(skb, 0, &ptr); + + bpf_dynptr_clone(&ptr, &clone); + data = bpf_dynptr_slice_rdwr(&clone, 0, buffer, sizeof(buffer)); + if (!data) + return XDP_DROP; + + if (bpf_skb_pull_data(skb, skb->len)) + return SK_DROP; + + /* this should fail */ + *data = 123; + + return 0; +} + +/* A xdp clone's data slices should be invalid anytime packet data changes */ +SEC("?xdp") +__failure __msg("invalid mem access 'scalar'") +int clone_xdp_packet_data(struct xdp_md *xdp) +{ + char buffer[sizeof(__u32)] = {}; + struct bpf_dynptr clone; + struct bpf_dynptr ptr; + struct ethhdr *hdr; + __u32 *data; + + bpf_dynptr_from_xdp(xdp, 0, &ptr); + + bpf_dynptr_clone(&ptr, &clone); + data = bpf_dynptr_slice_rdwr(&clone, 0, buffer, sizeof(buffer)); + if (!data) + return XDP_DROP; + + if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(*hdr))) + return XDP_DROP; + + /* this should fail */ + *data = 123; + + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/dynptr_success.c b/tools/testing/selftests/bpf/progs/dynptr_success.c index b2fa6c47ecc0..be7de62de045 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_success.c +++ b/tools/testing/selftests/bpf/progs/dynptr_success.c @@ -207,3 +207,301 @@ int test_dynptr_skb_data(struct __sk_buff *skb) return 1; } + +SEC("tp/syscalls/sys_enter_nanosleep") +int test_adjust(void *ctx) +{ + struct bpf_dynptr ptr; + __u32 bytes = 64; + __u32 off = 10; + __u32 trim = 15; + + if (bpf_get_current_pid_tgid() >> 32 != pid) + return 0; + + err = bpf_ringbuf_reserve_dynptr(&ringbuf, bytes, 0, &ptr); + if (err) { + err = 1; + goto done; + } + + if (bpf_dynptr_size(&ptr) != bytes) { + err = 2; + goto done; + } + + /* Advance the dynptr by off */ + err = bpf_dynptr_adjust(&ptr, off, bpf_dynptr_size(&ptr)); + if (err) { + err = 3; + goto done; + } + + if (bpf_dynptr_size(&ptr) != bytes - off) { + err = 4; + goto done; + } + + /* Trim the dynptr */ + err = bpf_dynptr_adjust(&ptr, off, 15); + if (err) { + err = 5; + goto done; + } + + /* Check that the size was adjusted correctly */ + if (bpf_dynptr_size(&ptr) != trim - off) { + err = 6; + goto done; + } + +done: + bpf_ringbuf_discard_dynptr(&ptr, 0); + return 0; +} + +SEC("tp/syscalls/sys_enter_nanosleep") +int test_adjust_err(void *ctx) +{ + char write_data[45] = "hello there, world!!"; + struct bpf_dynptr ptr; + __u32 size = 64; + __u32 off = 20; + + if (bpf_get_current_pid_tgid() >> 32 != pid) + return 0; + + if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 0, &ptr)) { + err = 1; + goto done; + } + + /* Check that start can't be greater than end */ + if (bpf_dynptr_adjust(&ptr, 5, 1) != -EINVAL) { + err = 2; + goto done; + } + + /* Check that start can't be greater than size */ + if (bpf_dynptr_adjust(&ptr, size + 1, size + 1) != -ERANGE) { + err = 3; + goto done; + } + + /* Check that end can't be greater than size */ + if (bpf_dynptr_adjust(&ptr, 0, size + 1) != -ERANGE) { + err = 4; + goto done; + } + + if (bpf_dynptr_adjust(&ptr, off, size)) { + err = 5; + goto done; + } + + /* Check that you can't write more bytes than available into the dynptr + * after you've adjusted it + */ + if (bpf_dynptr_write(&ptr, 0, &write_data, sizeof(write_data), 0) != -E2BIG) { + err = 6; + goto done; + } + + /* Check that even after adjusting, submitting/discarding + * a ringbuf dynptr works + */ + bpf_ringbuf_submit_dynptr(&ptr, 0); + return 0; + +done: + bpf_ringbuf_discard_dynptr(&ptr, 0); + return 0; +} + +SEC("tp/syscalls/sys_enter_nanosleep") +int test_zero_size_dynptr(void *ctx) +{ + char write_data = 'x', read_data; + struct bpf_dynptr ptr; + __u32 size = 64; + + if (bpf_get_current_pid_tgid() >> 32 != pid) + return 0; + + if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 0, &ptr)) { + err = 1; + goto done; + } + + /* After this, the dynptr has a size of 0 */ + if (bpf_dynptr_adjust(&ptr, size, size)) { + err = 2; + goto done; + } + + /* Test that reading + writing non-zero bytes is not ok */ + if (bpf_dynptr_read(&read_data, sizeof(read_data), &ptr, 0, 0) != -E2BIG) { + err = 3; + goto done; + } + + if (bpf_dynptr_write(&ptr, 0, &write_data, sizeof(write_data), 0) != -E2BIG) { + err = 4; + goto done; + } + + /* Test that reading + writing 0 bytes from a 0-size dynptr is ok */ + if (bpf_dynptr_read(&read_data, 0, &ptr, 0, 0)) { + err = 5; + goto done; + } + + if (bpf_dynptr_write(&ptr, 0, &write_data, 0, 0)) { + err = 6; + goto done; + } + + err = 0; + +done: + bpf_ringbuf_discard_dynptr(&ptr, 0); + return 0; +} + +SEC("tp/syscalls/sys_enter_nanosleep") +int test_dynptr_is_null(void *ctx) +{ + struct bpf_dynptr ptr1; + struct bpf_dynptr ptr2; + __u64 size = 4; + + if (bpf_get_current_pid_tgid() >> 32 != pid) + return 0; + + /* Pass in invalid flags, get back an invalid dynptr */ + if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 123, &ptr1) != -EINVAL) { + err = 1; + goto exit_early; + } + + /* Test that the invalid dynptr is null */ + if (!bpf_dynptr_is_null(&ptr1)) { + err = 2; + goto exit_early; + } + + /* Get a valid dynptr */ + if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 0, &ptr2)) { + err = 3; + goto exit; + } + + /* Test that the valid dynptr is not null */ + if (bpf_dynptr_is_null(&ptr2)) { + err = 4; + goto exit; + } + +exit: + bpf_ringbuf_discard_dynptr(&ptr2, 0); +exit_early: + bpf_ringbuf_discard_dynptr(&ptr1, 0); + return 0; +} + +SEC("cgroup_skb/egress") +int test_dynptr_is_rdonly(struct __sk_buff *skb) +{ + struct bpf_dynptr ptr1; + struct bpf_dynptr ptr2; + struct bpf_dynptr ptr3; + + /* Pass in invalid flags, get back an invalid dynptr */ + if (bpf_dynptr_from_skb(skb, 123, &ptr1) != -EINVAL) { + err = 1; + return 0; + } + + /* Test that an invalid dynptr is_rdonly returns false */ + if (bpf_dynptr_is_rdonly(&ptr1)) { + err = 2; + return 0; + } + + /* Get a read-only dynptr */ + if (bpf_dynptr_from_skb(skb, 0, &ptr2)) { + err = 3; + return 0; + } + + /* Test that the dynptr is read-only */ + if (!bpf_dynptr_is_rdonly(&ptr2)) { + err = 4; + return 0; + } + + /* Get a read-writeable dynptr */ + if (bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr3)) { + err = 5; + goto done; + } + + /* Test that the dynptr is read-only */ + if (bpf_dynptr_is_rdonly(&ptr3)) { + err = 6; + goto done; + } + +done: + bpf_ringbuf_discard_dynptr(&ptr3, 0); + return 0; +} + +SEC("cgroup_skb/egress") +int test_dynptr_clone(struct __sk_buff *skb) +{ + struct bpf_dynptr ptr1; + struct bpf_dynptr ptr2; + __u32 off = 2, size; + + /* Get a dynptr */ + if (bpf_dynptr_from_skb(skb, 0, &ptr1)) { + err = 1; + return 0; + } + + if (bpf_dynptr_adjust(&ptr1, off, bpf_dynptr_size(&ptr1))) { + err = 2; + return 0; + } + + /* Clone the dynptr */ + if (bpf_dynptr_clone(&ptr1, &ptr2)) { + err = 3; + return 0; + } + + size = bpf_dynptr_size(&ptr1); + + /* Check that the clone has the same size and rd-only */ + if (bpf_dynptr_size(&ptr2) != size) { + err = 4; + return 0; + } + + if (bpf_dynptr_is_rdonly(&ptr2) != bpf_dynptr_is_rdonly(&ptr1)) { + err = 5; + return 0; + } + + /* Advance and trim the original dynptr */ + bpf_dynptr_adjust(&ptr1, 5, 5); + + /* Check that only original dynptr was affected, and the clone wasn't */ + if (bpf_dynptr_size(&ptr2) != size) { + err = 6; + return 0; + } + + return 0; +} -- cgit v1.2.3 From b3e8701dd1fa25fc59cffa68240326efccff0336 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 4 Apr 2023 14:05:58 +0000 Subject: selftests/bpf: Add test case to assert precise scalar path pruning Add a test case to check for precision marking of safe paths. Ensure that the verifier will not prematurely prune scalars contributing to registers needing precision. Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/verifier/precise.c | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/verifier/precise.c b/tools/testing/selftests/bpf/verifier/precise.c index 6c03a7d805f9..8f0340eed696 100644 --- a/tools/testing/selftests/bpf/verifier/precise.c +++ b/tools/testing/selftests/bpf/verifier/precise.c @@ -217,3 +217,39 @@ .errstr = "invalid access to memory, mem_size=1 off=42 size=8", .result = REJECT, }, +{ + "precise: program doesn't prematurely prune branches", + .insns = { + BPF_ALU64_IMM(BPF_MOV, BPF_REG_6, 0x400), + BPF_ALU64_IMM(BPF_MOV, BPF_REG_7, 0), + BPF_ALU64_IMM(BPF_MOV, BPF_REG_8, 0), + BPF_ALU64_IMM(BPF_MOV, BPF_REG_9, 0x80000000), + BPF_ALU64_IMM(BPF_MOD, BPF_REG_6, 0x401), + BPF_JMP_IMM(BPF_JA, 0, 0, 0), + BPF_JMP_REG(BPF_JLE, BPF_REG_6, BPF_REG_9, 2), + BPF_ALU64_IMM(BPF_MOD, BPF_REG_6, 1), + BPF_ALU64_IMM(BPF_MOV, BPF_REG_9, 0), + BPF_JMP_REG(BPF_JLE, BPF_REG_6, BPF_REG_9, 1), + BPF_ALU64_IMM(BPF_MOV, BPF_REG_6, 0), + BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 0), + BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), + BPF_LD_MAP_FD(BPF_REG_4, 0), + BPF_ALU64_REG(BPF_MOV, BPF_REG_1, BPF_REG_4), + BPF_ALU64_REG(BPF_MOV, BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), + BPF_EXIT_INSN(), + BPF_ALU64_IMM(BPF_RSH, BPF_REG_6, 10), + BPF_ALU64_IMM(BPF_MUL, BPF_REG_6, 8192), + BPF_ALU64_REG(BPF_MOV, BPF_REG_1, BPF_REG_0), + BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_6), + BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, 0), + BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_3, 0), + BPF_EXIT_INSN(), + }, + .fixup_map_array_48b = { 13 }, + .prog_type = BPF_PROG_TYPE_XDP, + .result = REJECT, + .errstr = "register with unbounded min value is not allowed", +}, -- cgit v1.2.3 From bb323478767d4b4d78380bc9e2c0971ca33442af Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 18 Apr 2023 15:31:03 +0200 Subject: selftests/bpf: xdp_hw_metadata track more timestamps To correlate the hardware RX timestamp with something, add tracking of two software timestamps both clock source CLOCK_TAI (see description in man clock_gettime(2)). XDP metadata is extended with xdp_timestamp for capturing when XDP received the packet. Populated with BPF helper bpf_ktime_get_tai_ns(). I could not find a BPF helper for getting CLOCK_REALTIME, which would have been preferred. In userspace when AF_XDP sees the packet another software timestamp is recorded via clock_gettime() also clock source CLOCK_TAI. Example output shortly after loading igc driver: poll: 1 (0) skip=1 fail=0 redir=2 xsk_ring_cons__peek: 1 0x12557a8: rx_desc[1]->addr=100000000009000 addr=9100 comp_addr=9000 rx_hash: 0x82A96531 with RSS type:0x1 rx_timestamp: 1681740540304898909 (sec:1681740540.3049) XDP RX-time: 1681740577304958316 (sec:1681740577.3050) delta sec:37.0001 (37000059.407 usec) AF_XDP time: 1681740577305051315 (sec:1681740577.3051) delta sec:0.0001 (92.999 usec) 0x12557a8: complete idx=9 addr=9000 The first observation is that the 37 sec difference between RX HW vs XDP timestamps, which indicate hardware is likely clock source CLOCK_REALTIME, because (as of this writing) CLOCK_TAI is initialised with a 37 sec offset. The 93 usec (microsec) difference between XDP vs AF_XDP userspace is the userspace wakeup time. On this hardware it was caused by CPU idle sleep states, which can be reduced by tuning /dev/cpu_dma_latency. View current requested/allowed latency bound via: hexdump --format '"%d\n"' /dev/cpu_dma_latency More explanation of the output and how this can be used to identify clock drift for the HW clock can be seen here[1]: [1] https://github.com/xdp-project/xdp-project/blob/master/areas/hints/xdp_hints_kfuncs02_driver_igc.org Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Daniel Borkmann Acked-by: Stanislav Fomichev Acked-by: Song Yoong Siang Link: https://lore.kernel.org/bpf/168182466298.616355.2544377890818617459.stgit@firesoul --- .../testing/selftests/bpf/progs/xdp_hw_metadata.c | 4 +- tools/testing/selftests/bpf/xdp_hw_metadata.c | 47 +++++++++++++++++++--- tools/testing/selftests/bpf/xdp_metadata.h | 1 + 3 files changed, 46 insertions(+), 6 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/progs/xdp_hw_metadata.c b/tools/testing/selftests/bpf/progs/xdp_hw_metadata.c index e1c787815e44..b2dfd7066c6e 100644 --- a/tools/testing/selftests/bpf/progs/xdp_hw_metadata.c +++ b/tools/testing/selftests/bpf/progs/xdp_hw_metadata.c @@ -77,7 +77,9 @@ int rx(struct xdp_md *ctx) } err = bpf_xdp_metadata_rx_timestamp(ctx, &meta->rx_timestamp); - if (err) + if (!err) + meta->xdp_timestamp = bpf_ktime_get_tai_ns(); + else meta->rx_timestamp = 0; /* Used by AF_XDP as not avail signal */ err = bpf_xdp_metadata_rx_hash(ctx, &meta->rx_hash, &meta->rx_hash_type); diff --git a/tools/testing/selftests/bpf/xdp_hw_metadata.c b/tools/testing/selftests/bpf/xdp_hw_metadata.c index 987cf0db5ebc..613321eb84c1 100644 --- a/tools/testing/selftests/bpf/xdp_hw_metadata.c +++ b/tools/testing/selftests/bpf/xdp_hw_metadata.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "xdp_metadata.h" @@ -134,18 +135,52 @@ static void refill_rx(struct xsk *xsk, __u64 addr) } } -static void verify_xdp_metadata(void *data) +#define NANOSEC_PER_SEC 1000000000 /* 10^9 */ +static __u64 gettime(clockid_t clock_id) +{ + struct timespec t; + int res; + + /* See man clock_gettime(2) for type of clock_id's */ + res = clock_gettime(clock_id, &t); + + if (res < 0) + error(res, errno, "Error with clock_gettime()"); + + return (__u64) t.tv_sec * NANOSEC_PER_SEC + t.tv_nsec; +} + +static void verify_xdp_metadata(void *data, clockid_t clock_id) { struct xdp_meta *meta; meta = data - sizeof(*meta); - printf("rx_timestamp: %llu\n", meta->rx_timestamp); if (meta->rx_hash_err < 0) printf("No rx_hash err=%d\n", meta->rx_hash_err); else printf("rx_hash: 0x%X with RSS type:0x%X\n", meta->rx_hash, meta->rx_hash_type); + + printf("rx_timestamp: %llu (sec:%0.4f)\n", meta->rx_timestamp, + (double)meta->rx_timestamp / NANOSEC_PER_SEC); + if (meta->rx_timestamp) { + __u64 usr_clock = gettime(clock_id); + __u64 xdp_clock = meta->xdp_timestamp; + __s64 delta_X = xdp_clock - meta->rx_timestamp; + __s64 delta_X2U = usr_clock - xdp_clock; + + printf("XDP RX-time: %llu (sec:%0.4f) delta sec:%0.4f (%0.3f usec)\n", + xdp_clock, (double)xdp_clock / NANOSEC_PER_SEC, + (double)delta_X / NANOSEC_PER_SEC, + (double)delta_X / 1000); + + printf("AF_XDP time: %llu (sec:%0.4f) delta sec:%0.4f (%0.3f usec)\n", + usr_clock, (double)usr_clock / NANOSEC_PER_SEC, + (double)delta_X2U / NANOSEC_PER_SEC, + (double)delta_X2U / 1000); + } + } static void verify_skb_metadata(int fd) @@ -193,7 +228,7 @@ static void verify_skb_metadata(int fd) printf("skb hwtstamp is not found!\n"); } -static int verify_metadata(struct xsk *rx_xsk, int rxq, int server_fd) +static int verify_metadata(struct xsk *rx_xsk, int rxq, int server_fd, clockid_t clock_id) { const struct xdp_desc *rx_desc; struct pollfd fds[rxq + 1]; @@ -243,7 +278,8 @@ static int verify_metadata(struct xsk *rx_xsk, int rxq, int server_fd) addr = xsk_umem__add_offset_to_addr(rx_desc->addr); printf("%p: rx_desc[%u]->addr=%llx addr=%llx comp_addr=%llx\n", xsk, idx, rx_desc->addr, addr, comp_addr); - verify_xdp_metadata(xsk_umem__get_data(xsk->umem_area, addr)); + verify_xdp_metadata(xsk_umem__get_data(xsk->umem_area, addr), + clock_id); xsk_ring_cons__release(&xsk->rx, 1); refill_rx(xsk, comp_addr); } @@ -370,6 +406,7 @@ static void timestamping_enable(int fd, int val) int main(int argc, char *argv[]) { + clockid_t clock_id = CLOCK_TAI; int server_fd = -1; int ret; int i; @@ -443,7 +480,7 @@ int main(int argc, char *argv[]) error(1, -ret, "bpf_xdp_attach"); signal(SIGINT, handle_signal); - ret = verify_metadata(rx_xsk, rxq, server_fd); + ret = verify_metadata(rx_xsk, rxq, server_fd, clock_id); close(server_fd); cleanup(); if (ret) diff --git a/tools/testing/selftests/bpf/xdp_metadata.h b/tools/testing/selftests/bpf/xdp_metadata.h index 0c4624dc6f2f..938a729bd307 100644 --- a/tools/testing/selftests/bpf/xdp_metadata.h +++ b/tools/testing/selftests/bpf/xdp_metadata.h @@ -11,6 +11,7 @@ struct xdp_meta { __u64 rx_timestamp; + __u64 xdp_timestamp; __u32 rx_hash; union { __u32 rx_hash_type; -- cgit v1.2.3 From a4644119208444f84d9ffcd4d0af630046c2de98 Mon Sep 17 00:00:00 2001 From: Florent Revest Date: Thu, 27 Apr 2023 16:32:07 +0200 Subject: selftests/bpf: Update the aarch64 tests deny list Now that ftrace supports direct call on arm64, BPF tracing programs work on that architecture. This fixes the vast majority of BPF selftests except for: - multi_kprobe programs which require fprobe, not available on arm64 yet - tracing_struct which requires trampoline support to access struct args This patch updates the list of BPF selftests which are known to fail so the BPF CI can validate the tests which pass now. Signed-off-by: Florent Revest Signed-off-by: Daniel Borkmann Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20230427143207.635263-1-revest@chromium.org --- tools/testing/selftests/bpf/DENYLIST.aarch64 | 81 ++-------------------------- 1 file changed, 4 insertions(+), 77 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/DENYLIST.aarch64 b/tools/testing/selftests/bpf/DENYLIST.aarch64 index 0a6837f97c32..4b6b18424140 100644 --- a/tools/testing/selftests/bpf/DENYLIST.aarch64 +++ b/tools/testing/selftests/bpf/DENYLIST.aarch64 @@ -1,33 +1,5 @@ -bloom_filter_map # libbpf: prog 'check_bloom': failed to attach: ERROR: strerror_r(-524)=22 -bpf_cookie/lsm -bpf_cookie/multi_kprobe_attach_api -bpf_cookie/multi_kprobe_link_api -bpf_cookie/trampoline -bpf_loop/check_callback_fn_stop # link unexpected error: -524 -bpf_loop/check_invalid_flags -bpf_loop/check_nested_calls -bpf_loop/check_non_constant_callback -bpf_loop/check_nr_loops -bpf_loop/check_null_callback_ctx -bpf_loop/check_stack -bpf_mod_race # bpf_mod_kfunc_race__attach unexpected error: -524 (errno 524) -bpf_tcp_ca/dctcp_fallback -btf_dump/btf_dump: var_data # find type id unexpected find type id: actual -2 < expected 0 -cgroup_hierarchical_stats # attach unexpected error: -524 (errno 524) -d_path/basic # setup attach failed: -524 -deny_namespace # attach unexpected error: -524 (errno 524) -fentry_fexit # fentry_attach unexpected error: -1 (errno 524) -fentry_test # fentry_attach unexpected error: -1 (errno 524) -fexit_sleep # fexit_attach fexit attach failed: -1 -fexit_stress # fexit attach unexpected fexit attach: actual -524 < expected 0 -fexit_test # fexit_attach unexpected error: -1 (errno 524) -get_func_args_test # get_func_args_test__attach unexpected error: -524 (errno 524) (trampoline) -get_func_ip_test # get_func_ip_test__attach unexpected error: -524 (errno 524) (trampoline) -htab_update/reenter_update -kfree_skb # attach fentry unexpected error: -524 (trampoline) -kfunc_call/subprog # extern (var ksym) 'bpf_prog_active': not found in kernel BTF -kfunc_call/subprog_lskel # skel unexpected error: -2 -kfunc_dynptr_param/dynptr_data_null # libbpf: prog 'dynptr_data_null': failed to attach: ERROR: strerror_r(-524)=22 +bpf_cookie/multi_kprobe_attach_api # kprobe_multi_link_api_subtest:FAIL:fentry_raw_skel_load unexpected error: -3 +bpf_cookie/multi_kprobe_link_api # kprobe_multi_link_api_subtest:FAIL:fentry_raw_skel_load unexpected error: -3 kprobe_multi_bench_attach # bpf_program__attach_kprobe_multi_opts unexpected error: -95 kprobe_multi_test/attach_api_addrs # bpf_program__attach_kprobe_multi_opts unexpected error: -95 kprobe_multi_test/attach_api_pattern # bpf_program__attach_kprobe_multi_opts unexpected error: -95 @@ -35,51 +7,6 @@ kprobe_multi_test/attach_api_syms # bpf_program__attach_kprobe_mu kprobe_multi_test/bench_attach # bpf_program__attach_kprobe_multi_opts unexpected error: -95 kprobe_multi_test/link_api_addrs # link_fd unexpected link_fd: actual -95 < expected 0 kprobe_multi_test/link_api_syms # link_fd unexpected link_fd: actual -95 < expected 0 -kprobe_multi_test/skel_api # kprobe_multi__attach unexpected error: -524 (errno 524) -ksyms_module/libbpf # 'bpf_testmod_ksym_percpu': not found in kernel BTF -ksyms_module/lskel # test_ksyms_module_lskel__open_and_load unexpected error: -2 -libbpf_get_fd_by_id_opts # test_libbpf_get_fd_by_id_opts__attach unexpected error: -524 (errno 524) -linked_list -lookup_key # test_lookup_key__attach unexpected error: -524 (errno 524) -lru_bug # lru_bug__attach unexpected error: -524 (errno 524) -modify_return # modify_return__attach failed unexpected error: -524 (errno 524) -module_attach # skel_attach skeleton attach failed: -524 -module_fentry_shadow # bpf_link_create unexpected bpf_link_create: actual -524 < expected 0 -mptcp/base # run_test mptcp unexpected error: -524 (errno 524) -netcnt # packets unexpected packets: actual 10001 != expected 10000 -rcu_read_lock # failed to attach: ERROR: strerror_r(-524)=22 -recursion # skel_attach unexpected error: -524 (errno 524) -ringbuf # skel_attach skeleton attachment failed: -1 -setget_sockopt # attach_cgroup unexpected error: -524 -sk_storage_tracing # test_sk_storage_tracing__attach unexpected error: -524 (errno 524) -skc_to_unix_sock # could not attach BPF object unexpected error: -524 (errno 524) -socket_cookie # prog_attach unexpected error: -524 -stacktrace_build_id # compare_stack_ips stackmap vs. stack_amap err -1 errno 2 -task_local_storage/exit_creds # skel_attach unexpected error: -524 (errno 524) -task_local_storage/recursion # skel_attach unexpected error: -524 (errno 524) -test_bprm_opts # attach attach failed: -524 -test_ima # attach attach failed: -524 -test_local_storage # attach lsm attach failed: -524 -test_lsm # test_lsm_first_attach unexpected error: -524 (errno 524) -test_overhead # attach_fentry unexpected error: -524 -timer # timer unexpected error: -524 (errno 524) -timer_crash # timer_crash__attach unexpected error: -524 (errno 524) -timer_mim # timer_mim unexpected error: -524 (errno 524) -trace_printk # trace_printk__attach unexpected error: -1 (errno 524) -trace_vprintk # trace_vprintk__attach unexpected error: -1 (errno 524) +kprobe_multi_test/skel_api # libbpf: failed to load BPF skeleton 'kprobe_multi': -3 +module_attach # prog 'kprobe_multi': failed to auto-attach: -95 tracing_struct # tracing_struct__attach unexpected error: -524 (errno 524) -trampoline_count # attach_prog unexpected error: -524 -unpriv_bpf_disabled # skel_attach unexpected error: -524 (errno 524) -user_ringbuf/test_user_ringbuf_post_misaligned # misaligned_skel unexpected error: -524 (errno 524) -user_ringbuf/test_user_ringbuf_post_producer_wrong_offset -user_ringbuf/test_user_ringbuf_post_larger_than_ringbuf_sz -user_ringbuf/test_user_ringbuf_basic # ringbuf_basic_skel unexpected error: -524 (errno 524) -user_ringbuf/test_user_ringbuf_sample_full_ring_buffer -user_ringbuf/test_user_ringbuf_post_alignment_autoadjust -user_ringbuf/test_user_ringbuf_overfill -user_ringbuf/test_user_ringbuf_discards_properly_ignored -user_ringbuf/test_user_ringbuf_loop -user_ringbuf/test_user_ringbuf_msg_protocol -user_ringbuf/test_user_ringbuf_blocking_reserve -verify_pkcs7_sig # test_verify_pkcs7_sig__attach unexpected error: -524 (errno 524) -vmlinux # skel_attach skeleton attach failed: -524 -- cgit v1.2.3 From f1f5553d91a11663a5761b78e61f70c1db0bbd2f Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 25 Apr 2023 10:47:44 -0700 Subject: selftests/bpf: Fix selftest test_global_funcs/global_func1 failure with latest clang The selftest test_global_funcs/global_func1 failed with the latest clang17. The reason is due to upstream ArgumentPromotionPass ([1]), which may manipulate static function parameters and cause inlining although the funciton is marked as noinline. The original code: static __attribute__ ((noinline)) int f0(int var, struct __sk_buff *skb) { return skb->len; } __attribute__ ((noinline)) int f1(struct __sk_buff *skb) { ... return f0(0, skb) + skb->len; } ... SEC("tc") __failure __msg("combined stack size of 4 calls is 544") int global_func1(struct __sk_buff *skb) { return f0(1, skb) + f1(skb) + f2(2, skb) + f3(3, skb, 4); } After ArgumentPromotionPass, the code is translated to static __attribute__ ((noinline)) int f0(int var, int skb_len) { return skb_len; } __attribute__ ((noinline)) int f1(struct __sk_buff *skb) { ... return f0(0, skb->len) + skb->len; } ... SEC("tc") __failure __msg("combined stack size of 4 calls is 544") int global_func1(struct __sk_buff *skb) { return f0(1, skb->len) + f1(skb) + f2(2, skb) + f3(3, skb, 4); } And later llvm InstCombine phase recognized that f0() simplify returns the value of the second argument and removed f0() completely and the final code looks like: __attribute__ ((noinline)) int f1(struct __sk_buff *skb) { ... return skb->len + skb->len; } ... SEC("tc") __failure __msg("combined stack size of 4 calls is 544") int global_func1(struct __sk_buff *skb) { return skb->len + f1(skb) + f2(2, skb) + f3(3, skb, 4); } If f0() is not inlined, the verification will fail with stack size 544 for a particular callchain. With f0() inlined, the maximum stack size is 512 which is in the limit. Let us add a `asm volatile ("")` in f0() to prevent ArgumentPromotionPass from hoisting the code to its caller, and this fixed the test failure. [1] https://reviews.llvm.org/D148269 Signed-off-by: Yonghong Song Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20230425174744.1758515-1-yhs@fb.com --- tools/testing/selftests/bpf/progs/test_global_func1.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/progs/test_global_func1.c b/tools/testing/selftests/bpf/progs/test_global_func1.c index b85fc8c423ba..17a9f59bf5f3 100644 --- a/tools/testing/selftests/bpf/progs/test_global_func1.c +++ b/tools/testing/selftests/bpf/progs/test_global_func1.c @@ -10,6 +10,8 @@ static __attribute__ ((noinline)) int f0(int var, struct __sk_buff *skb) { + asm volatile (""); + return skb->len; } -- cgit v1.2.3 From 31f4f810d533e7ed9a835c5f946eceaec015ce10 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Thu, 27 Apr 2023 20:37:44 -0700 Subject: selftests/bpf: Add fexit_sleep to DENYLIST.aarch64 It is reported that the fexit_sleep never returns in aarch64. The remaining tests cannot start. Put this test into DENYLIST.aarch64 for now so that other tests can continue to run in the CI. Acked-by: Manu Bretelle Reported-by: Manu Bretelle Signed-off-by: Martin KaFai Lau --- tools/testing/selftests/bpf/DENYLIST.aarch64 | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/DENYLIST.aarch64 b/tools/testing/selftests/bpf/DENYLIST.aarch64 index 4b6b18424140..cd42e2825bd2 100644 --- a/tools/testing/selftests/bpf/DENYLIST.aarch64 +++ b/tools/testing/selftests/bpf/DENYLIST.aarch64 @@ -1,5 +1,6 @@ bpf_cookie/multi_kprobe_attach_api # kprobe_multi_link_api_subtest:FAIL:fentry_raw_skel_load unexpected error: -3 bpf_cookie/multi_kprobe_link_api # kprobe_multi_link_api_subtest:FAIL:fentry_raw_skel_load unexpected error: -3 +fexit_sleep # The test never returns. The remaining tests cannot start. kprobe_multi_bench_attach # bpf_program__attach_kprobe_multi_opts unexpected error: -95 kprobe_multi_test/attach_api_addrs # bpf_program__attach_kprobe_multi_opts unexpected error: -95 kprobe_multi_test/attach_api_pattern # bpf_program__attach_kprobe_multi_opts unexpected error: -95 -- cgit v1.2.3 From 0a5c0de8b66f9789422f04de7304e374a2ea8df5 Mon Sep 17 00:00:00 2001 From: Stephen Veiss Date: Thu, 27 Apr 2023 15:53:32 -0700 Subject: selftests/bpf: Extract insert_test from parse_test_list Split the logic to insert new tests into test filter sets out from parse_test_list. Fix the subtest insertion logic to reuse an existing top-level test filter, which prevents the creation of duplicate top-level test filters each with a single subtest. Signed-off-by: Stephen Veiss Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20230427225333.3506052-2-sveiss@meta.com --- .../testing/selftests/bpf/prog_tests/arg_parsing.c | 13 ++ tools/testing/selftests/bpf/testing_helpers.c | 160 ++++++++++++--------- 2 files changed, 108 insertions(+), 65 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/arg_parsing.c b/tools/testing/selftests/bpf/prog_tests/arg_parsing.c index b17bfa0e0aac..3754cd5f8c0a 100644 --- a/tools/testing/selftests/bpf/prog_tests/arg_parsing.c +++ b/tools/testing/selftests/bpf/prog_tests/arg_parsing.c @@ -96,6 +96,19 @@ static void test_parse_test_list(void) goto error; ASSERT_OK(strcmp("*bpf_cookie*", set.tests[0].name), "test name"); ASSERT_OK(strcmp("*trace*", set.tests[0].subtests[0]), "subtest name"); + free_test_filter_set(&set); + + ASSERT_OK(parse_test_list("t/subtest1,t/subtest2", &set, true), + "parsing"); + if (!ASSERT_EQ(set.cnt, 1, "count of test filters")) + goto error; + if (!ASSERT_OK_PTR(set.tests, "test filters initialized")) + goto error; + if (!ASSERT_EQ(set.tests[0].subtest_cnt, 2, "subtest filters count")) + goto error; + ASSERT_OK(strcmp("t", set.tests[0].name), "test name"); + ASSERT_OK(strcmp("subtest1", set.tests[0].subtests[0]), "subtest name"); + ASSERT_OK(strcmp("subtest2", set.tests[0].subtests[1]), "subtest name"); error: free_test_filter_set(&set); } diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c index 0b5e0829e5be..fca617e87710 100644 --- a/tools/testing/selftests/bpf/testing_helpers.c +++ b/tools/testing/selftests/bpf/testing_helpers.c @@ -70,92 +70,122 @@ int parse_num_list(const char *s, bool **num_set, int *num_set_len) return 0; } -int parse_test_list(const char *s, - struct test_filter_set *set, - bool is_glob_pattern) +static int do_insert_test(struct test_filter_set *set, + char *test_str, + char *subtest_str) { - char *input, *state = NULL, *next; - struct test_filter *tmp, *tests = NULL; - int i, j, cnt = 0; + struct test_filter *tmp, *test; + char **ctmp; + int i; - input = strdup(s); - if (!input) + for (i = 0; i < set->cnt; i++) { + test = &set->tests[i]; + + if (strcmp(test_str, test->name) == 0) { + free(test_str); + goto subtest; + } + } + + tmp = realloc(set->tests, sizeof(*test) * (set->cnt + 1)); + if (!tmp) return -ENOMEM; - while ((next = strtok_r(state ? NULL : input, ",", &state))) { - char *subtest_str = strchr(next, '/'); - char *pattern = NULL; - int glob_chars = 0; + set->tests = tmp; + test = &set->tests[set->cnt]; - tmp = realloc(tests, sizeof(*tests) * (cnt + 1)); - if (!tmp) - goto err; - tests = tmp; + test->name = test_str; + test->subtests = NULL; + test->subtest_cnt = 0; - tests[cnt].subtest_cnt = 0; - tests[cnt].subtests = NULL; + set->cnt++; - if (is_glob_pattern) { - pattern = "%s"; - } else { - pattern = "*%s*"; - glob_chars = 2; - } +subtest: + if (!subtest_str) + return 0; - if (subtest_str) { - char **tmp_subtests = NULL; - int subtest_cnt = tests[cnt].subtest_cnt; - - *subtest_str = '\0'; - subtest_str += 1; - tmp_subtests = realloc(tests[cnt].subtests, - sizeof(*tmp_subtests) * - (subtest_cnt + 1)); - if (!tmp_subtests) - goto err; - tests[cnt].subtests = tmp_subtests; - - tests[cnt].subtests[subtest_cnt] = - malloc(strlen(subtest_str) + glob_chars + 1); - if (!tests[cnt].subtests[subtest_cnt]) - goto err; - sprintf(tests[cnt].subtests[subtest_cnt], - pattern, - subtest_str); - - tests[cnt].subtest_cnt++; + for (i = 0; i < test->subtest_cnt; i++) { + if (strcmp(subtest_str, test->subtests[i]) == 0) { + free(subtest_str); + return 0; } + } - tests[cnt].name = malloc(strlen(next) + glob_chars + 1); - if (!tests[cnt].name) - goto err; - sprintf(tests[cnt].name, pattern, next); + ctmp = realloc(test->subtests, + sizeof(*test->subtests) * (test->subtest_cnt + 1)); + if (!ctmp) + return -ENOMEM; + + test->subtests = ctmp; + test->subtests[test->subtest_cnt] = subtest_str; - cnt++; + test->subtest_cnt++; + + return 0; +} + +static int insert_test(struct test_filter_set *set, + char *test_spec, + bool is_glob_pattern) +{ + char *pattern, *subtest_str, *ext_test_str, *ext_subtest_str = NULL; + int glob_chars = 0; + + if (is_glob_pattern) { + pattern = "%s"; + } else { + pattern = "*%s*"; + glob_chars = 2; } - tmp = realloc(set->tests, sizeof(*tests) * (cnt + set->cnt)); - if (!tmp) + subtest_str = strchr(test_spec, '/'); + if (subtest_str) { + *subtest_str = '\0'; + subtest_str += 1; + } + + ext_test_str = malloc(strlen(test_spec) + glob_chars + 1); + if (!ext_test_str) goto err; - memcpy(tmp + set->cnt, tests, sizeof(*tests) * cnt); - set->tests = tmp; - set->cnt += cnt; + sprintf(ext_test_str, pattern, test_spec); - free(tests); - free(input); - return 0; + if (subtest_str) { + ext_subtest_str = malloc(strlen(subtest_str) + glob_chars + 1); + if (!ext_subtest_str) + goto err; + + sprintf(ext_subtest_str, pattern, subtest_str); + } + + return do_insert_test(set, ext_test_str, ext_subtest_str); err: - for (i = 0; i < cnt; i++) { - for (j = 0; j < tests[i].subtest_cnt; j++) - free(tests[i].subtests[j]); + free(ext_test_str); + free(ext_subtest_str); + + return -ENOMEM; +} - free(tests[i].name); +int parse_test_list(const char *s, + struct test_filter_set *set, + bool is_glob_pattern) +{ + char *input, *state = NULL, *test_spec; + int err = 0; + + input = strdup(s); + if (!input) + return -ENOMEM; + + while ((test_spec = strtok_r(state ? NULL : input, ",", &state))) { + err = insert_test(set, test_spec, is_glob_pattern); + if (err) + break; } - free(tests); + free(input); - return -ENOMEM; + return err; } __u32 link_info_prog_id(const struct bpf_link *link, struct bpf_link_info *info) -- cgit v1.2.3 From 64276f01dce85f72853617e513622b5645497d81 Mon Sep 17 00:00:00 2001 From: Stephen Veiss Date: Thu, 27 Apr 2023 15:53:33 -0700 Subject: selftests/bpf: Test_progs can read test lists from file Improve test selection logic when using -a/-b/-d/-t options. The list of tests to include or exclude can now be read from a file, specified as @. The file contains one name (or wildcard pattern) per line, and comments beginning with # are ignored. These options can be passed multiple times to read more than one file. Signed-off-by: Stephen Veiss Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20230427225333.3506052-3-sveiss@meta.com --- .../testing/selftests/bpf/prog_tests/arg_parsing.c | 55 ++++++++++++++++++++++ tools/testing/selftests/bpf/test_progs.c | 37 +++++++++++---- tools/testing/selftests/bpf/testing_helpers.c | 47 ++++++++++++++++++ tools/testing/selftests/bpf/testing_helpers.h | 3 ++ 4 files changed, 132 insertions(+), 10 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/arg_parsing.c b/tools/testing/selftests/bpf/prog_tests/arg_parsing.c index 3754cd5f8c0a..bb143de68875 100644 --- a/tools/testing/selftests/bpf/prog_tests/arg_parsing.c +++ b/tools/testing/selftests/bpf/prog_tests/arg_parsing.c @@ -113,8 +113,63 @@ error: free_test_filter_set(&set); } +static void test_parse_test_list_file(void) +{ + struct test_filter_set set; + char tmpfile[80]; + FILE *fp; + int fd; + + snprintf(tmpfile, sizeof(tmpfile), "/tmp/bpf_arg_parsing_test.XXXXXX"); + fd = mkstemp(tmpfile); + if (!ASSERT_GE(fd, 0, "create tmp")) + return; + + fp = fdopen(fd, "w"); + if (!ASSERT_NEQ(fp, NULL, "fdopen tmp")) { + close(fd); + goto out_remove; + } + + fprintf(fp, "# comment\n"); + fprintf(fp, " test_with_spaces \n"); + fprintf(fp, "testA/subtest # comment\n"); + fprintf(fp, "testB#comment with no space\n"); + fprintf(fp, "testB # duplicate\n"); + fprintf(fp, "testA/subtest # subtest duplicate\n"); + fprintf(fp, "testA/subtest2\n"); + fprintf(fp, "testC_no_eof_newline"); + fflush(fp); + + if (!ASSERT_OK(ferror(fp), "prepare tmp")) + goto out_fclose; + + init_test_filter_set(&set); + + ASSERT_OK(parse_test_list_file(tmpfile, &set, true), "parse file"); + + ASSERT_EQ(set.cnt, 4, "test count"); + ASSERT_OK(strcmp("test_with_spaces", set.tests[0].name), "test 0 name"); + ASSERT_EQ(set.tests[0].subtest_cnt, 0, "test 0 subtest count"); + ASSERT_OK(strcmp("testA", set.tests[1].name), "test 1 name"); + ASSERT_EQ(set.tests[1].subtest_cnt, 2, "test 1 subtest count"); + ASSERT_OK(strcmp("subtest", set.tests[1].subtests[0]), "test 1 subtest 0"); + ASSERT_OK(strcmp("subtest2", set.tests[1].subtests[1]), "test 1 subtest 1"); + ASSERT_OK(strcmp("testB", set.tests[2].name), "test 2 name"); + ASSERT_OK(strcmp("testC_no_eof_newline", set.tests[3].name), "test 3 name"); + + free_test_filter_set(&set); + +out_fclose: + fclose(fp); +out_remove: + remove(tmpfile); +} + void test_arg_parsing(void) { if (test__start_subtest("test_parse_test_list")) test_parse_test_list(); + if (test__start_subtest("test_parse_test_list_file")) + test_parse_test_list_file(); } diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index ea82921110da..793689dcc170 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -714,7 +714,13 @@ static struct test_state test_states[ARRAY_SIZE(prog_test_defs)]; const char *argp_program_version = "test_progs 0.1"; const char *argp_program_bug_address = ""; -static const char argp_program_doc[] = "BPF selftests test runner"; +static const char argp_program_doc[] = +"BPF selftests test runner\v" +"Options accepting the NAMES parameter take either a comma-separated list\n" +"of test names, or a filename prefixed with @. The file contains one name\n" +"(or wildcard pattern) per line, and comments beginning with # are ignored.\n" +"\n" +"These options can be passed repeatedly to read multiple files.\n"; enum ARG_KEYS { ARG_TEST_NUM = 'n', @@ -797,6 +803,7 @@ extern int extra_prog_load_log_flags; static error_t parse_arg(int key, char *arg, struct argp_state *state) { struct test_env *env = state->input; + int err = 0; switch (key) { case ARG_TEST_NUM: { @@ -821,18 +828,28 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) } case ARG_TEST_NAME_GLOB_ALLOWLIST: case ARG_TEST_NAME: { - if (parse_test_list(arg, - &env->test_selector.whitelist, - key == ARG_TEST_NAME_GLOB_ALLOWLIST)) - return -ENOMEM; + if (arg[0] == '@') + err = parse_test_list_file(arg + 1, + &env->test_selector.whitelist, + key == ARG_TEST_NAME_GLOB_ALLOWLIST); + else + err = parse_test_list(arg, + &env->test_selector.whitelist, + key == ARG_TEST_NAME_GLOB_ALLOWLIST); + break; } case ARG_TEST_NAME_GLOB_DENYLIST: case ARG_TEST_NAME_BLACKLIST: { - if (parse_test_list(arg, - &env->test_selector.blacklist, - key == ARG_TEST_NAME_GLOB_DENYLIST)) - return -ENOMEM; + if (arg[0] == '@') + err = parse_test_list_file(arg + 1, + &env->test_selector.blacklist, + key == ARG_TEST_NAME_GLOB_DENYLIST); + else + err = parse_test_list(arg, + &env->test_selector.blacklist, + key == ARG_TEST_NAME_GLOB_DENYLIST); + break; } case ARG_VERIFIER_STATS: @@ -900,7 +917,7 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) default: return ARGP_ERR_UNKNOWN; } - return 0; + return err; } /* diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c index fca617e87710..dc9595ade8de 100644 --- a/tools/testing/selftests/bpf/testing_helpers.c +++ b/tools/testing/selftests/bpf/testing_helpers.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) /* Copyright (C) 2019 Netronome Systems, Inc. */ /* Copyright (C) 2020 Facebook, Inc. */ +#include #include #include #include @@ -167,6 +168,52 @@ err: return -ENOMEM; } +int parse_test_list_file(const char *path, + struct test_filter_set *set, + bool is_glob_pattern) +{ + char *buf = NULL, *capture_start, *capture_end, *scan_end; + size_t buflen = 0; + int err = 0; + FILE *f; + + f = fopen(path, "r"); + if (!f) { + err = -errno; + fprintf(stderr, "Failed to open '%s': %d\n", path, err); + return err; + } + + while (getline(&buf, &buflen, f) != -1) { + capture_start = buf; + + while (isspace(*capture_start)) + ++capture_start; + + capture_end = capture_start; + scan_end = capture_start; + + while (*scan_end && *scan_end != '#') { + if (!isspace(*scan_end)) + capture_end = scan_end; + + ++scan_end; + } + + if (capture_end == capture_start) + continue; + + *(++capture_end) = '\0'; + + err = insert_test(set, capture_start, is_glob_pattern); + if (err) + break; + } + + fclose(f); + return err; +} + int parse_test_list(const char *s, struct test_filter_set *set, bool is_glob_pattern) diff --git a/tools/testing/selftests/bpf/testing_helpers.h b/tools/testing/selftests/bpf/testing_helpers.h index eb8790f928e4..98f09bbae86f 100644 --- a/tools/testing/selftests/bpf/testing_helpers.h +++ b/tools/testing/selftests/bpf/testing_helpers.h @@ -20,5 +20,8 @@ struct test_filter_set; int parse_test_list(const char *s, struct test_filter_set *test_set, bool is_glob_pattern); +int parse_test_list_file(const char *path, + struct test_filter_set *test_set, + bool is_glob_pattern); __u64 read_perf_max_sample_freq(void); -- cgit v1.2.3 From 5956f3011604f03be073cba0fbe5f399b4d779ec Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 May 2023 21:33:08 -0700 Subject: veristat: add -t flag for adding BPF_F_TEST_STATE_FREQ program flag Sometimes during debugging it's important that BPF program is loaded with BPF_F_TEST_STATE_FREQ flag set to force verifier to do frequent state checkpointing. Teach veristat to do this when -t ("test state") flag is specified. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20230505043317.3629845-2-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/veristat.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/veristat.c b/tools/testing/selftests/bpf/veristat.c index 1db7185181da..655095810d4a 100644 --- a/tools/testing/selftests/bpf/veristat.c +++ b/tools/testing/selftests/bpf/veristat.c @@ -141,6 +141,7 @@ static struct env { bool verbose; bool debug; bool quiet; + bool force_checkpoints; enum resfmt out_fmt; bool show_version; bool comparison_mode; @@ -209,6 +210,8 @@ static const struct argp_option opts[] = { { "log-level", 'l', "LEVEL", 0, "Verifier log level (default 0 for normal mode, 1 for verbose mode)" }, { "log-fixed", OPT_LOG_FIXED, NULL, 0, "Disable verifier log rotation" }, { "log-size", OPT_LOG_SIZE, "BYTES", 0, "Customize verifier log size (default to 16MB)" }, + { "test-states", 't', NULL, 0, + "Force frequent BPF verifier state checkpointing (set BPF_F_TEST_STATE_FREQ program flag)" }, { "quiet", 'q', NULL, 0, "Quiet mode" }, { "emit", 'e', "SPEC", 0, "Specify stats to be emitted" }, { "sort", 's', "SPEC", 0, "Specify sort order" }, @@ -284,6 +287,9 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) argp_usage(state); } break; + case 't': + env.force_checkpoints = true; + break; case 'C': env.comparison_mode = true; break; @@ -989,6 +995,9 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf /* increase chances of successful BPF object loading */ fixup_obj(obj, prog, base_filename); + if (env.force_checkpoints) + bpf_program__set_flags(prog, bpf_program__flags(prog) | BPF_F_TEST_STATE_FREQ); + err = bpf_object__load(obj); env.progs_processed++; -- cgit v1.2.3 From d9439c21a9e4769bfd83a03ab39056164d44ac31 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 May 2023 21:33:11 -0700 Subject: bpf: improve precision backtrack logging Add helper to format register and stack masks in more human-readable format. Adjust logging a bit during backtrack propagation and especially during forcing precision fallback logic to make it clearer what's going on (with log_level=2, of course), and also start reporting affected frame depth. This is in preparation for having more than one active frame later when precision propagation between subprog calls is added. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20230505043317.3629845-5-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf_verifier.h | 13 ++- kernel/bpf/verifier.c | 72 +++++++++++++++-- tools/testing/selftests/bpf/verifier/precise.c | 106 +++++++++++++------------ 3 files changed, 128 insertions(+), 63 deletions(-) (limited to 'tools/testing') diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 33f541366f4e..5b11a3b0fec0 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -18,8 +18,11 @@ * that converting umax_value to int cannot overflow. */ #define BPF_MAX_VAR_SIZ (1 << 29) -/* size of type_str_buf in bpf_verifier. */ -#define TYPE_STR_BUF_LEN 128 +/* size of tmp_str_buf in bpf_verifier. + * we need at least 306 bytes to fit full stack mask representation + * (in the "-8,-16,...,-512" form) + */ +#define TMP_STR_BUF_LEN 320 /* Liveness marks, used for registers and spilled-regs (in stack slots). * Read marks propagate upwards until they find a write mark; they record that @@ -620,8 +623,10 @@ struct bpf_verifier_env { /* Same as scratched_regs but for stack slots */ u64 scratched_stack_slots; u64 prev_log_pos, prev_insn_print_pos; - /* buffer used in reg_type_str() to generate reg_type string */ - char type_str_buf[TYPE_STR_BUF_LEN]; + /* buffer used to generate temporary string representations, + * e.g., in reg_type_str() to generate reg_type string + */ + char tmp_str_buf[TMP_STR_BUF_LEN]; }; __printf(2, 0) void bpf_verifier_vlog(struct bpf_verifier_log *log, diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 9b2e571250e1..5412c8c8511d 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -605,9 +605,9 @@ static const char *reg_type_str(struct bpf_verifier_env *env, type & PTR_TRUSTED ? "trusted_" : "" ); - snprintf(env->type_str_buf, TYPE_STR_BUF_LEN, "%s%s%s", + snprintf(env->tmp_str_buf, TMP_STR_BUF_LEN, "%s%s%s", prefix, str[base_type(type)], postfix); - return env->type_str_buf; + return env->tmp_str_buf; } static char slot_type_char[] = { @@ -3308,6 +3308,45 @@ static inline bool bt_is_slot_set(struct backtrack_state *bt, u32 slot) return bt->stack_masks[bt->frame] & (1ull << slot); } +/* format registers bitmask, e.g., "r0,r2,r4" for 0x15 mask */ +static void fmt_reg_mask(char *buf, ssize_t buf_sz, u32 reg_mask) +{ + DECLARE_BITMAP(mask, 64); + bool first = true; + int i, n; + + buf[0] = '\0'; + + bitmap_from_u64(mask, reg_mask); + for_each_set_bit(i, mask, 32) { + n = snprintf(buf, buf_sz, "%sr%d", first ? "" : ",", i); + first = false; + buf += n; + buf_sz -= n; + if (buf_sz < 0) + break; + } +} +/* format stack slots bitmask, e.g., "-8,-24,-40" for 0x15 mask */ +static void fmt_stack_mask(char *buf, ssize_t buf_sz, u64 stack_mask) +{ + DECLARE_BITMAP(mask, 64); + bool first = true; + int i, n; + + buf[0] = '\0'; + + bitmap_from_u64(mask, stack_mask); + for_each_set_bit(i, mask, 64) { + n = snprintf(buf, buf_sz, "%s%d", first ? "" : ",", -(i + 1) * 8); + first = false; + buf += n; + buf_sz -= n; + if (buf_sz < 0) + break; + } +} + /* For given verifier state backtrack_insn() is called from the last insn to * the first insn. Its purpose is to compute a bitmask of registers and * stack slots that needs precision in the parent verifier state. @@ -3331,7 +3370,11 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, if (insn->code == 0) return 0; if (env->log.level & BPF_LOG_LEVEL2) { - verbose(env, "regs=%x stack=%llx before ", bt_reg_mask(bt), bt_stack_mask(bt)); + fmt_reg_mask(env->tmp_str_buf, TMP_STR_BUF_LEN, bt_reg_mask(bt)); + verbose(env, "mark_precise: frame%d: regs=%s ", + bt->frame, env->tmp_str_buf); + fmt_stack_mask(env->tmp_str_buf, TMP_STR_BUF_LEN, bt_stack_mask(bt)); + verbose(env, "stack=%s before ", env->tmp_str_buf); verbose(env, "%d: ", idx); print_bpf_insn(&cbs, insn, env->allow_ptr_leaks); } @@ -3531,6 +3574,11 @@ static void mark_all_scalars_precise(struct bpf_verifier_env *env, struct bpf_reg_state *reg; int i, j; + if (env->log.level & BPF_LOG_LEVEL2) { + verbose(env, "mark_precise: frame%d: falling back to forcing all scalars precise\n", + st->curframe); + } + /* big hammer: mark all scalars precise in this path. * pop_stack may still get !precise scalars. * We also skip current state and go straight to first parent state, @@ -3542,17 +3590,25 @@ static void mark_all_scalars_precise(struct bpf_verifier_env *env, func = st->frame[i]; for (j = 0; j < BPF_REG_FP; j++) { reg = &func->regs[j]; - if (reg->type != SCALAR_VALUE) + if (reg->type != SCALAR_VALUE || reg->precise) continue; reg->precise = true; + if (env->log.level & BPF_LOG_LEVEL2) { + verbose(env, "force_precise: frame%d: forcing r%d to be precise\n", + i, j); + } } for (j = 0; j < func->allocated_stack / BPF_REG_SIZE; j++) { if (!is_spilled_reg(&func->stack[j])) continue; reg = &func->stack[j].spilled_ptr; - if (reg->type != SCALAR_VALUE) + if (reg->type != SCALAR_VALUE || reg->precise) continue; reg->precise = true; + if (env->log.level & BPF_LOG_LEVEL2) { + verbose(env, "force_precise: frame%d: forcing fp%d to be precise\n", + i, -(j + 1) * 8); + } } } } @@ -3716,8 +3772,10 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int frame, int r DECLARE_BITMAP(mask, 64); u32 history = st->jmp_history_cnt; - if (env->log.level & BPF_LOG_LEVEL2) - verbose(env, "last_idx %d first_idx %d\n", last_idx, first_idx); + if (env->log.level & BPF_LOG_LEVEL2) { + verbose(env, "mark_precise: frame%d: last_idx %d first_idx %d\n", + bt->frame, last_idx, first_idx); + } if (last_idx < 0) { /* we are at the entry into subprog, which diff --git a/tools/testing/selftests/bpf/verifier/precise.c b/tools/testing/selftests/bpf/verifier/precise.c index 8f0340eed696..a22fabd404ed 100644 --- a/tools/testing/selftests/bpf/verifier/precise.c +++ b/tools/testing/selftests/bpf/verifier/precise.c @@ -38,25 +38,24 @@ .fixup_map_array_48b = { 1 }, .result = VERBOSE_ACCEPT, .errstr = - "26: (85) call bpf_probe_read_kernel#113\ - last_idx 26 first_idx 20\ - regs=4 stack=0 before 25\ - regs=4 stack=0 before 24\ - regs=4 stack=0 before 23\ - regs=4 stack=0 before 22\ - regs=4 stack=0 before 20\ - parent didn't have regs=4 stack=0 marks\ - last_idx 19 first_idx 10\ - regs=4 stack=0 before 19\ - regs=200 stack=0 before 18\ - regs=300 stack=0 before 17\ - regs=201 stack=0 before 15\ - regs=201 stack=0 before 14\ - regs=200 stack=0 before 13\ - regs=200 stack=0 before 12\ - regs=200 stack=0 before 11\ - regs=200 stack=0 before 10\ - parent already had regs=0 stack=0 marks", + "mark_precise: frame0: last_idx 26 first_idx 20\ + mark_precise: frame0: regs=r2 stack= before 25\ + mark_precise: frame0: regs=r2 stack= before 24\ + mark_precise: frame0: regs=r2 stack= before 23\ + mark_precise: frame0: regs=r2 stack= before 22\ + mark_precise: frame0: regs=r2 stack= before 20\ + parent didn't have regs=4 stack=0 marks:\ + mark_precise: frame0: last_idx 19 first_idx 10\ + mark_precise: frame0: regs=r2 stack= before 19\ + mark_precise: frame0: regs=r9 stack= before 18\ + mark_precise: frame0: regs=r8,r9 stack= before 17\ + mark_precise: frame0: regs=r0,r9 stack= before 15\ + mark_precise: frame0: regs=r0,r9 stack= before 14\ + mark_precise: frame0: regs=r9 stack= before 13\ + mark_precise: frame0: regs=r9 stack= before 12\ + mark_precise: frame0: regs=r9 stack= before 11\ + mark_precise: frame0: regs=r9 stack= before 10\ + parent already had regs=0 stack=0 marks:", }, { "precise: test 2", @@ -100,20 +99,20 @@ .flags = BPF_F_TEST_STATE_FREQ, .errstr = "26: (85) call bpf_probe_read_kernel#113\ - last_idx 26 first_idx 22\ - regs=4 stack=0 before 25\ - regs=4 stack=0 before 24\ - regs=4 stack=0 before 23\ - regs=4 stack=0 before 22\ - parent didn't have regs=4 stack=0 marks\ - last_idx 20 first_idx 20\ - regs=4 stack=0 before 20\ - parent didn't have regs=4 stack=0 marks\ - last_idx 19 first_idx 17\ - regs=4 stack=0 before 19\ - regs=200 stack=0 before 18\ - regs=300 stack=0 before 17\ - parent already had regs=0 stack=0 marks", + mark_precise: frame0: last_idx 26 first_idx 22\ + mark_precise: frame0: regs=r2 stack= before 25\ + mark_precise: frame0: regs=r2 stack= before 24\ + mark_precise: frame0: regs=r2 stack= before 23\ + mark_precise: frame0: regs=r2 stack= before 22\ + parent didn't have regs=4 stack=0 marks:\ + mark_precise: frame0: last_idx 20 first_idx 20\ + mark_precise: frame0: regs=r2 stack= before 20\ + parent didn't have regs=4 stack=0 marks:\ + mark_precise: frame0: last_idx 19 first_idx 17\ + mark_precise: frame0: regs=r2 stack= before 19\ + mark_precise: frame0: regs=r9 stack= before 18\ + mark_precise: frame0: regs=r8,r9 stack= before 17\ + parent already had regs=0 stack=0 marks:", }, { "precise: cross frame pruning", @@ -153,15 +152,15 @@ }, .prog_type = BPF_PROG_TYPE_XDP, .flags = BPF_F_TEST_STATE_FREQ, - .errstr = "5: (2d) if r4 > r0 goto pc+0\ - last_idx 5 first_idx 5\ - parent didn't have regs=10 stack=0 marks\ - last_idx 4 first_idx 2\ - regs=10 stack=0 before 4\ - regs=10 stack=0 before 3\ - regs=0 stack=1 before 2\ - last_idx 5 first_idx 5\ - parent didn't have regs=1 stack=0 marks", + .errstr = "mark_precise: frame0: last_idx 5 first_idx 5\ + parent didn't have regs=10 stack=0 marks:\ + mark_precise: frame0: last_idx 4 first_idx 2\ + mark_precise: frame0: regs=r4 stack= before 4\ + mark_precise: frame0: regs=r4 stack= before 3\ + mark_precise: frame0: regs= stack=-8 before 2\ + mark_precise: frame0: falling back to forcing all scalars precise\ + mark_precise: frame0: last_idx 5 first_idx 5\ + parent didn't have regs=1 stack=0 marks:", .result = VERBOSE_ACCEPT, .retval = -1, }, @@ -179,16 +178,19 @@ }, .prog_type = BPF_PROG_TYPE_XDP, .flags = BPF_F_TEST_STATE_FREQ, - .errstr = "last_idx 6 first_idx 6\ - parent didn't have regs=10 stack=0 marks\ - last_idx 5 first_idx 3\ - regs=10 stack=0 before 5\ - regs=10 stack=0 before 4\ - regs=0 stack=1 before 3\ - last_idx 6 first_idx 6\ - parent didn't have regs=1 stack=0 marks\ - last_idx 5 first_idx 3\ - regs=1 stack=0 before 5", + .errstr = "mark_precise: frame0: last_idx 6 first_idx 6\ + parent didn't have regs=10 stack=0 marks:\ + mark_precise: frame0: last_idx 5 first_idx 3\ + mark_precise: frame0: regs=r4 stack= before 5\ + mark_precise: frame0: regs=r4 stack= before 4\ + mark_precise: frame0: regs= stack=-8 before 3\ + mark_precise: frame0: falling back to forcing all scalars precise\ + force_precise: frame0: forcing r0 to be precise\ + force_precise: frame0: forcing r0 to be precise\ + mark_precise: frame0: last_idx 6 first_idx 6\ + parent didn't have regs=1 stack=0 marks:\ + mark_precise: frame0: last_idx 5 first_idx 3\ + mark_precise: frame0: regs=r0 stack= before 5", .result = VERBOSE_ACCEPT, .retval = -1, }, -- cgit v1.2.3 From 1ef22b6865a73a8aed36d43375fe8c7b30869326 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 May 2023 21:33:12 -0700 Subject: bpf: maintain bitmasks across all active frames in __mark_chain_precision Teach __mark_chain_precision logic to maintain register/stack masks across all active frames when going from child state to parent state. Currently this should be mostly no-op, as precision backtracking usually bails out when encountering subprog entry/exit. It's not very apparent from the diff due to increased indentation, but the logic remains the same, except everything is done on specific `fr` frame index. Calls to bt_clear_reg() and bt_clear_slot() are replaced with frame-specific bt_clear_frame_reg() and bt_clear_frame_slot(), where frame index is passed explicitly, instead of using current frame number. We also adjust logging to emit affected frame number. And we also add better logging of human-readable register and stack slot masks, similar to previous patch. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20230505043317.3629845-6-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 100 +++++++++++++------------ tools/testing/selftests/bpf/verifier/precise.c | 18 ++--- 2 files changed, 62 insertions(+), 56 deletions(-) (limited to 'tools/testing') diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 5412c8c8511d..5a7997bc96f5 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -3736,7 +3736,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int frame, int r struct bpf_func_state *func; struct bpf_reg_state *reg; bool skip_first = true; - int i, err; + int i, fr, err; if (!env->bpf_capable) return 0; @@ -3845,56 +3845,62 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int frame, int r if (!st) break; - func = st->frame[frame]; - bitmap_from_u64(mask, bt_reg_mask(bt)); - for_each_set_bit(i, mask, 32) { - reg = &func->regs[i]; - if (reg->type != SCALAR_VALUE) { - bt_clear_reg(bt, i); - continue; + for (fr = bt->frame; fr >= 0; fr--) { + func = st->frame[fr]; + bitmap_from_u64(mask, bt_frame_reg_mask(bt, fr)); + for_each_set_bit(i, mask, 32) { + reg = &func->regs[i]; + if (reg->type != SCALAR_VALUE) { + bt_clear_frame_reg(bt, fr, i); + continue; + } + if (reg->precise) + bt_clear_frame_reg(bt, fr, i); + else + reg->precise = true; } - if (reg->precise) - bt_clear_reg(bt, i); - else - reg->precise = true; - } - bitmap_from_u64(mask, bt_stack_mask(bt)); - for_each_set_bit(i, mask, 64) { - if (i >= func->allocated_stack / BPF_REG_SIZE) { - /* the sequence of instructions: - * 2: (bf) r3 = r10 - * 3: (7b) *(u64 *)(r3 -8) = r0 - * 4: (79) r4 = *(u64 *)(r10 -8) - * doesn't contain jmps. It's backtracked - * as a single block. - * During backtracking insn 3 is not recognized as - * stack access, so at the end of backtracking - * stack slot fp-8 is still marked in stack_mask. - * However the parent state may not have accessed - * fp-8 and it's "unallocated" stack space. - * In such case fallback to conservative. - */ - mark_all_scalars_precise(env, st); - bt_reset(bt); - return 0; - } + bitmap_from_u64(mask, bt_frame_stack_mask(bt, fr)); + for_each_set_bit(i, mask, 64) { + if (i >= func->allocated_stack / BPF_REG_SIZE) { + /* the sequence of instructions: + * 2: (bf) r3 = r10 + * 3: (7b) *(u64 *)(r3 -8) = r0 + * 4: (79) r4 = *(u64 *)(r10 -8) + * doesn't contain jmps. It's backtracked + * as a single block. + * During backtracking insn 3 is not recognized as + * stack access, so at the end of backtracking + * stack slot fp-8 is still marked in stack_mask. + * However the parent state may not have accessed + * fp-8 and it's "unallocated" stack space. + * In such case fallback to conservative. + */ + mark_all_scalars_precise(env, st); + bt_reset(bt); + return 0; + } - if (!is_spilled_scalar_reg(&func->stack[i])) { - bt_clear_slot(bt, i); - continue; + if (!is_spilled_scalar_reg(&func->stack[i])) { + bt_clear_frame_slot(bt, fr, i); + continue; + } + reg = &func->stack[i].spilled_ptr; + if (reg->precise) + bt_clear_frame_slot(bt, fr, i); + else + reg->precise = true; + } + if (env->log.level & BPF_LOG_LEVEL2) { + fmt_reg_mask(env->tmp_str_buf, TMP_STR_BUF_LEN, + bt_frame_reg_mask(bt, fr)); + verbose(env, "mark_precise: frame%d: parent state regs=%s ", + fr, env->tmp_str_buf); + fmt_stack_mask(env->tmp_str_buf, TMP_STR_BUF_LEN, + bt_frame_stack_mask(bt, fr)); + verbose(env, "stack=%s: ", env->tmp_str_buf); + print_verifier_state(env, func, true); } - reg = &func->stack[i].spilled_ptr; - if (reg->precise) - bt_clear_slot(bt, i); - else - reg->precise = true; - } - if (env->log.level & BPF_LOG_LEVEL2) { - verbose(env, "parent %s regs=%x stack=%llx marks:", - !bt_empty(bt) ? "didn't have" : "already had", - bt_reg_mask(bt), bt_stack_mask(bt)); - print_verifier_state(env, func, true); } if (bt_empty(bt)) diff --git a/tools/testing/selftests/bpf/verifier/precise.c b/tools/testing/selftests/bpf/verifier/precise.c index a22fabd404ed..77ea018582c5 100644 --- a/tools/testing/selftests/bpf/verifier/precise.c +++ b/tools/testing/selftests/bpf/verifier/precise.c @@ -44,7 +44,7 @@ mark_precise: frame0: regs=r2 stack= before 23\ mark_precise: frame0: regs=r2 stack= before 22\ mark_precise: frame0: regs=r2 stack= before 20\ - parent didn't have regs=4 stack=0 marks:\ + mark_precise: frame0: parent state regs=r2 stack=:\ mark_precise: frame0: last_idx 19 first_idx 10\ mark_precise: frame0: regs=r2 stack= before 19\ mark_precise: frame0: regs=r9 stack= before 18\ @@ -55,7 +55,7 @@ mark_precise: frame0: regs=r9 stack= before 12\ mark_precise: frame0: regs=r9 stack= before 11\ mark_precise: frame0: regs=r9 stack= before 10\ - parent already had regs=0 stack=0 marks:", + mark_precise: frame0: parent state regs= stack=:", }, { "precise: test 2", @@ -104,15 +104,15 @@ mark_precise: frame0: regs=r2 stack= before 24\ mark_precise: frame0: regs=r2 stack= before 23\ mark_precise: frame0: regs=r2 stack= before 22\ - parent didn't have regs=4 stack=0 marks:\ + mark_precise: frame0: parent state regs=r2 stack=:\ mark_precise: frame0: last_idx 20 first_idx 20\ mark_precise: frame0: regs=r2 stack= before 20\ - parent didn't have regs=4 stack=0 marks:\ + mark_precise: frame0: parent state regs=r2 stack=:\ mark_precise: frame0: last_idx 19 first_idx 17\ mark_precise: frame0: regs=r2 stack= before 19\ mark_precise: frame0: regs=r9 stack= before 18\ mark_precise: frame0: regs=r8,r9 stack= before 17\ - parent already had regs=0 stack=0 marks:", + mark_precise: frame0: parent state regs= stack=:", }, { "precise: cross frame pruning", @@ -153,14 +153,14 @@ .prog_type = BPF_PROG_TYPE_XDP, .flags = BPF_F_TEST_STATE_FREQ, .errstr = "mark_precise: frame0: last_idx 5 first_idx 5\ - parent didn't have regs=10 stack=0 marks:\ + mark_precise: frame0: parent state regs=r4 stack=:\ mark_precise: frame0: last_idx 4 first_idx 2\ mark_precise: frame0: regs=r4 stack= before 4\ mark_precise: frame0: regs=r4 stack= before 3\ mark_precise: frame0: regs= stack=-8 before 2\ mark_precise: frame0: falling back to forcing all scalars precise\ mark_precise: frame0: last_idx 5 first_idx 5\ - parent didn't have regs=1 stack=0 marks:", + mark_precise: frame0: parent state regs=r0 stack=:", .result = VERBOSE_ACCEPT, .retval = -1, }, @@ -179,7 +179,7 @@ .prog_type = BPF_PROG_TYPE_XDP, .flags = BPF_F_TEST_STATE_FREQ, .errstr = "mark_precise: frame0: last_idx 6 first_idx 6\ - parent didn't have regs=10 stack=0 marks:\ + mark_precise: frame0: parent state regs=r4 stack=:\ mark_precise: frame0: last_idx 5 first_idx 3\ mark_precise: frame0: regs=r4 stack= before 5\ mark_precise: frame0: regs=r4 stack= before 4\ @@ -188,7 +188,7 @@ force_precise: frame0: forcing r0 to be precise\ force_precise: frame0: forcing r0 to be precise\ mark_precise: frame0: last_idx 6 first_idx 6\ - parent didn't have regs=1 stack=0 marks:\ + mark_precise: frame0: parent state regs=r0 stack=:\ mark_precise: frame0: last_idx 5 first_idx 3\ mark_precise: frame0: regs=r0 stack= before 5", .result = VERBOSE_ACCEPT, -- cgit v1.2.3 From c50c0b57a515826b5d2e1ce85cd85f24f0da10c2 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 May 2023 21:33:14 -0700 Subject: bpf: fix mark_all_scalars_precise use in mark_chain_precision When precision backtracking bails out due to some unsupported sequence of instructions (e.g., stack access through register other than r10), we need to mark all SCALAR registers as precise to be safe. Currently, though, we mark SCALARs precise only starting from the state we detected unsupported condition, which could be one of the parent states of the actual current state. This will leave some registers potentially not marked as precise, even though they should. So make sure we start marking scalars as precise from current state (env->cur_state). Further, we don't currently detect a situation when we end up with some stack slots marked as needing precision, but we ran out of available states to find the instructions that populate those stack slots. This is akin the `i >= func->allocated_stack / BPF_REG_SIZE` check and should be handled similarly by falling back to marking all SCALARs precise. Add this check when we run out of states. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20230505043317.3629845-8-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 16 +++++++++++++--- tools/testing/selftests/bpf/verifier/precise.c | 9 +++++---- 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'tools/testing') diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 13bbaa2485fc..899122832d8e 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -3806,7 +3806,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) err = backtrack_insn(env, i, bt); } if (err == -ENOTSUPP) { - mark_all_scalars_precise(env, st); + mark_all_scalars_precise(env, env->cur_state); bt_reset(bt); return 0; } else if (err) { @@ -3868,7 +3868,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) * fp-8 and it's "unallocated" stack space. * In such case fallback to conservative. */ - mark_all_scalars_precise(env, st); + mark_all_scalars_precise(env, env->cur_state); bt_reset(bt); return 0; } @@ -3896,11 +3896,21 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) } if (bt_empty(bt)) - break; + return 0; last_idx = st->last_insn_idx; first_idx = st->first_insn_idx; } + + /* if we still have requested precise regs or slots, we missed + * something (e.g., stack access through non-r10 register), so + * fallback to marking all precise + */ + if (!bt_empty(bt)) { + mark_all_scalars_precise(env, env->cur_state); + bt_reset(bt); + } + return 0; } diff --git a/tools/testing/selftests/bpf/verifier/precise.c b/tools/testing/selftests/bpf/verifier/precise.c index 77ea018582c5..b8c0aae8e7ec 100644 --- a/tools/testing/selftests/bpf/verifier/precise.c +++ b/tools/testing/selftests/bpf/verifier/precise.c @@ -159,8 +159,9 @@ mark_precise: frame0: regs=r4 stack= before 3\ mark_precise: frame0: regs= stack=-8 before 2\ mark_precise: frame0: falling back to forcing all scalars precise\ + force_precise: frame0: forcing r0 to be precise\ mark_precise: frame0: last_idx 5 first_idx 5\ - mark_precise: frame0: parent state regs=r0 stack=:", + mark_precise: frame0: parent state regs= stack=:", .result = VERBOSE_ACCEPT, .retval = -1, }, @@ -187,10 +188,10 @@ mark_precise: frame0: falling back to forcing all scalars precise\ force_precise: frame0: forcing r0 to be precise\ force_precise: frame0: forcing r0 to be precise\ + force_precise: frame0: forcing r0 to be precise\ + force_precise: frame0: forcing r0 to be precise\ mark_precise: frame0: last_idx 6 first_idx 6\ - mark_precise: frame0: parent state regs=r0 stack=:\ - mark_precise: frame0: last_idx 5 first_idx 3\ - mark_precise: frame0: regs=r0 stack= before 5", + mark_precise: frame0: parent state regs= stack=:", .result = VERBOSE_ACCEPT, .retval = -1, }, -- cgit v1.2.3 From 3ef3d2177b1a5484908c53d19269b964c488c20f Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 May 2023 21:33:16 -0700 Subject: selftests/bpf: add precision propagation tests in the presence of subprogs Add a bunch of tests validating verifier's precision backpropagation logic in the presence of subprog calls and/or callback-calling helpers/kfuncs. We validate the following conditions: - subprog_result_precise: static subprog r0 result precision handling; - global_subprog_result_precise: global subprog r0 precision shortcutting, similar to BPF helper handling; - callback_result_precise: similarly r0 marking precise for callback-calling helpers; - parent_callee_saved_reg_precise, parent_callee_saved_reg_precise_global: propagation of precision for callee-saved registers bypassing static/global subprogs; - parent_callee_saved_reg_precise_with_callback: same as above, but in the presence of callback-calling helper; - parent_stack_slot_precise, parent_stack_slot_precise_global: similar to above, but instead propagating precision of stack slot (spilled SCALAR reg); - parent_stack_slot_precise_with_callback: same as above, but in the presence of callback-calling helper; - subprog_arg_precise: propagation of precision of static subprog's input argument back to caller; - subprog_spill_into_parent_stack_slot_precise: negative test validating that verifier currently can't support backtracking of stack access with non-r10 register, we validate that we fallback to forcing precision for all SCALARs. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20230505043317.3629845-10-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/prog_tests/verifier.c | 2 + tools/testing/selftests/bpf/progs/bpf_misc.h | 4 + .../bpf/progs/verifier_subprog_precision.c | 536 +++++++++++++++++++++ 3 files changed, 542 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/verifier_subprog_precision.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c index 2497716ee379..531621adef42 100644 --- a/tools/testing/selftests/bpf/prog_tests/verifier.c +++ b/tools/testing/selftests/bpf/prog_tests/verifier.c @@ -55,6 +55,7 @@ #include "verifier_spill_fill.skel.h" #include "verifier_spin_lock.skel.h" #include "verifier_stack_ptr.skel.h" +#include "verifier_subprog_precision.skel.h" #include "verifier_subreg.skel.h" #include "verifier_uninit.skel.h" #include "verifier_unpriv.skel.h" @@ -154,6 +155,7 @@ void test_verifier_sock(void) { RUN(verifier_sock); } void test_verifier_spill_fill(void) { RUN(verifier_spill_fill); } void test_verifier_spin_lock(void) { RUN(verifier_spin_lock); } void test_verifier_stack_ptr(void) { RUN(verifier_stack_ptr); } +void test_verifier_subprog_precision(void) { RUN(verifier_subprog_precision); } void test_verifier_subreg(void) { RUN(verifier_subreg); } void test_verifier_uninit(void) { RUN(verifier_uninit); } void test_verifier_unpriv(void) { RUN(verifier_unpriv); } diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h index d3c1217ba79a..38a57a2e70db 100644 --- a/tools/testing/selftests/bpf/progs/bpf_misc.h +++ b/tools/testing/selftests/bpf/progs/bpf_misc.h @@ -86,6 +86,10 @@ #define POINTER_VALUE 0xcafe4all #define TEST_DATA_LEN 64 +#ifndef __used +#define __used __attribute__((used)) +#endif + #if defined(__TARGET_ARCH_x86) #define SYSCALL_WRAPPER 1 #define SYS_PREFIX "__x64_" diff --git a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c new file mode 100644 index 000000000000..db6b3143338b --- /dev/null +++ b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c @@ -0,0 +1,536 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include +#include +#include +#include +#include "bpf_misc.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +int vals[] SEC(".data.vals") = {1, 2, 3, 4}; + +__naked __noinline __used +static unsigned long identity_subprog() +{ + /* the simplest *static* 64-bit identity function */ + asm volatile ( + "r0 = r1;" + "exit;" + ); +} + +__noinline __used +unsigned long global_identity_subprog(__u64 x) +{ + /* the simplest *global* 64-bit identity function */ + return x; +} + +__naked __noinline __used +static unsigned long callback_subprog() +{ + /* the simplest callback function */ + asm volatile ( + "r0 = 0;" + "exit;" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("7: (0f) r1 += r0") +__msg("mark_precise: frame0: regs=r0 stack= before 6: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r0 stack= before 5: (27) r0 *= 4") +__msg("mark_precise: frame0: regs=r0 stack= before 11: (95) exit") +__msg("mark_precise: frame1: regs=r0 stack= before 10: (bf) r0 = r1") +__msg("mark_precise: frame1: regs=r1 stack= before 4: (85) call pc+5") +__msg("mark_precise: frame0: regs=r1 stack= before 3: (bf) r1 = r6") +__msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3") +__naked int subprog_result_precise(void) +{ + asm volatile ( + "r6 = 3;" + /* pass r6 through r1 into subprog to get it back as r0; + * this whole chain will have to be marked as precise later + */ + "r1 = r6;" + "call identity_subprog;" + /* now use subprog's returned value (which is a + * r6 -> r1 -> r0 chain), as index into vals array, forcing + * all of that to be known precisely + */ + "r0 *= 4;" + "r1 = %[vals];" + /* here r0->r1->r6 chain is forced to be precise and has to be + * propagated back to the beginning, including through the + * subprog call + */ + "r1 += r0;" + "r0 = *(u32 *)(r1 + 0);" + "exit;" + : + : __imm_ptr(vals) + : __clobber_common, "r6" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("9: (0f) r1 += r0") +__msg("mark_precise: frame0: last_idx 9 first_idx 0") +__msg("mark_precise: frame0: regs=r0 stack= before 8: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r0 stack= before 7: (27) r0 *= 4") +__msg("mark_precise: frame0: regs=r0 stack= before 5: (a5) if r0 < 0x4 goto pc+1") +__msg("mark_precise: frame0: regs=r0 stack= before 4: (85) call pc+7") +__naked int global_subprog_result_precise(void) +{ + asm volatile ( + "r6 = 3;" + /* pass r6 through r1 into subprog to get it back as r0; + * given global_identity_subprog is global, precision won't + * propagate all the way back to r6 + */ + "r1 = r6;" + "call global_identity_subprog;" + /* now use subprog's returned value (which is unknown now, so + * we need to clamp it), as index into vals array, forcing r0 + * to be marked precise (with no effect on r6, though) + */ + "if r0 < %[vals_arr_sz] goto 1f;" + "r0 = %[vals_arr_sz] - 1;" + "1:" + "r0 *= 4;" + "r1 = %[vals];" + /* here r0 is forced to be precise and has to be + * propagated back to the global subprog call, but it + * shouldn't go all the way to mark r6 as precise + */ + "r1 += r0;" + "r0 = *(u32 *)(r1 + 0);" + "exit;" + : + : __imm_ptr(vals), + __imm_const(vals_arr_sz, ARRAY_SIZE(vals)) + : __clobber_common, "r6" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("14: (0f) r1 += r6") +__msg("mark_precise: frame0: last_idx 14 first_idx 10") +__msg("mark_precise: frame0: regs=r6 stack= before 13: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r6 stack= before 12: (27) r6 *= 4") +__msg("mark_precise: frame0: regs=r6 stack= before 11: (25) if r6 > 0x3 goto pc+4") +__msg("mark_precise: frame0: regs=r6 stack= before 10: (bf) r6 = r0") +__msg("mark_precise: frame0: parent state regs=r0 stack=:") +__msg("mark_precise: frame0: last_idx 18 first_idx 0") +__msg("mark_precise: frame0: regs=r0 stack= before 18: (95) exit") +__naked int callback_result_precise(void) +{ + asm volatile ( + "r6 = 3;" + + /* call subprog and use result; r0 shouldn't propagate back to + * callback_subprog + */ + "r1 = r6;" /* nr_loops */ + "r2 = %[callback_subprog];" /* callback_fn */ + "r3 = 0;" /* callback_ctx */ + "r4 = 0;" /* flags */ + "call %[bpf_loop];" + + "r6 = r0;" + "if r6 > 3 goto 1f;" + "r6 *= 4;" + "r1 = %[vals];" + /* here r6 is forced to be precise and has to be propagated + * back to the bpf_loop() call, but not beyond + */ + "r1 += r6;" + "r0 = *(u32 *)(r1 + 0);" + "1:" + "exit;" + : + : __imm_ptr(vals), + __imm_ptr(callback_subprog), + __imm(bpf_loop) + : __clobber_common, "r6" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("7: (0f) r1 += r6") +__msg("mark_precise: frame0: last_idx 7 first_idx 0") +__msg("mark_precise: frame0: regs=r6 stack= before 6: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r6 stack= before 5: (27) r6 *= 4") +__msg("mark_precise: frame0: regs=r6 stack= before 11: (95) exit") +__msg("mark_precise: frame1: regs= stack= before 10: (bf) r0 = r1") +__msg("mark_precise: frame1: regs= stack= before 4: (85) call pc+5") +__msg("mark_precise: frame0: regs=r6 stack= before 3: (b7) r1 = 0") +__msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3") +__naked int parent_callee_saved_reg_precise(void) +{ + asm volatile ( + "r6 = 3;" + + /* call subprog and ignore result; we need this call only to + * complicate jump history + */ + "r1 = 0;" + "call identity_subprog;" + + "r6 *= 4;" + "r1 = %[vals];" + /* here r6 is forced to be precise and has to be propagated + * back to the beginning, handling (and ignoring) subprog call + */ + "r1 += r6;" + "r0 = *(u32 *)(r1 + 0);" + "exit;" + : + : __imm_ptr(vals) + : __clobber_common, "r6" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("7: (0f) r1 += r6") +__msg("mark_precise: frame0: last_idx 7 first_idx 0") +__msg("mark_precise: frame0: regs=r6 stack= before 6: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r6 stack= before 5: (27) r6 *= 4") +__msg("mark_precise: frame0: regs=r6 stack= before 4: (85) call pc+5") +__msg("mark_precise: frame0: regs=r6 stack= before 3: (b7) r1 = 0") +__msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3") +__naked int parent_callee_saved_reg_precise_global(void) +{ + asm volatile ( + "r6 = 3;" + + /* call subprog and ignore result; we need this call only to + * complicate jump history + */ + "r1 = 0;" + "call global_identity_subprog;" + + "r6 *= 4;" + "r1 = %[vals];" + /* here r6 is forced to be precise and has to be propagated + * back to the beginning, handling (and ignoring) subprog call + */ + "r1 += r6;" + "r0 = *(u32 *)(r1 + 0);" + "exit;" + : + : __imm_ptr(vals) + : __clobber_common, "r6" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("12: (0f) r1 += r6") +__msg("mark_precise: frame0: last_idx 12 first_idx 10") +__msg("mark_precise: frame0: regs=r6 stack= before 11: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r6 stack= before 10: (27) r6 *= 4") +__msg("mark_precise: frame0: parent state regs=r6 stack=:") +__msg("mark_precise: frame0: last_idx 16 first_idx 0") +__msg("mark_precise: frame0: regs=r6 stack= before 16: (95) exit") +__msg("mark_precise: frame1: regs= stack= before 15: (b7) r0 = 0") +__msg("mark_precise: frame1: regs= stack= before 9: (85) call bpf_loop#181") +__msg("mark_precise: frame0: regs=r6 stack= before 8: (b7) r4 = 0") +__msg("mark_precise: frame0: regs=r6 stack= before 7: (b7) r3 = 0") +__msg("mark_precise: frame0: regs=r6 stack= before 6: (bf) r2 = r8") +__msg("mark_precise: frame0: regs=r6 stack= before 5: (b7) r1 = 1") +__msg("mark_precise: frame0: regs=r6 stack= before 4: (b7) r6 = 3") +__naked int parent_callee_saved_reg_precise_with_callback(void) +{ + asm volatile ( + "r6 = 3;" + + /* call subprog and ignore result; we need this call only to + * complicate jump history + */ + "r1 = 1;" /* nr_loops */ + "r2 = %[callback_subprog];" /* callback_fn */ + "r3 = 0;" /* callback_ctx */ + "r4 = 0;" /* flags */ + "call %[bpf_loop];" + + "r6 *= 4;" + "r1 = %[vals];" + /* here r6 is forced to be precise and has to be propagated + * back to the beginning, handling (and ignoring) callback call + */ + "r1 += r6;" + "r0 = *(u32 *)(r1 + 0);" + "exit;" + : + : __imm_ptr(vals), + __imm_ptr(callback_subprog), + __imm(bpf_loop) + : __clobber_common, "r6" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("9: (0f) r1 += r6") +__msg("mark_precise: frame0: last_idx 9 first_idx 6") +__msg("mark_precise: frame0: regs=r6 stack= before 8: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r6 stack= before 7: (27) r6 *= 4") +__msg("mark_precise: frame0: regs=r6 stack= before 6: (79) r6 = *(u64 *)(r10 -8)") +__msg("mark_precise: frame0: parent state regs= stack=-8:") +__msg("mark_precise: frame0: last_idx 13 first_idx 0") +__msg("mark_precise: frame0: regs= stack=-8 before 13: (95) exit") +__msg("mark_precise: frame1: regs= stack= before 12: (bf) r0 = r1") +__msg("mark_precise: frame1: regs= stack= before 5: (85) call pc+6") +__msg("mark_precise: frame0: regs= stack=-8 before 4: (b7) r1 = 0") +__msg("mark_precise: frame0: regs= stack=-8 before 3: (7b) *(u64 *)(r10 -8) = r6") +__msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3") +__naked int parent_stack_slot_precise(void) +{ + asm volatile ( + /* spill reg */ + "r6 = 3;" + "*(u64 *)(r10 - 8) = r6;" + + /* call subprog and ignore result; we need this call only to + * complicate jump history + */ + "r1 = 0;" + "call identity_subprog;" + + /* restore reg from stack; in this case we'll be carrying + * stack mask when going back into subprog through jump + * history + */ + "r6 = *(u64 *)(r10 - 8);" + + "r6 *= 4;" + "r1 = %[vals];" + /* here r6 is forced to be precise and has to be propagated + * back to the beginning, handling (and ignoring) subprog call + */ + "r1 += r6;" + "r0 = *(u32 *)(r1 + 0);" + "exit;" + : + : __imm_ptr(vals) + : __clobber_common, "r6" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("9: (0f) r1 += r6") +__msg("mark_precise: frame0: last_idx 9 first_idx 6") +__msg("mark_precise: frame0: regs=r6 stack= before 8: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r6 stack= before 7: (27) r6 *= 4") +__msg("mark_precise: frame0: regs=r6 stack= before 6: (79) r6 = *(u64 *)(r10 -8)") +__msg("mark_precise: frame0: parent state regs= stack=-8:") +__msg("mark_precise: frame0: last_idx 5 first_idx 0") +__msg("mark_precise: frame0: regs= stack=-8 before 5: (85) call pc+6") +__msg("mark_precise: frame0: regs= stack=-8 before 4: (b7) r1 = 0") +__msg("mark_precise: frame0: regs= stack=-8 before 3: (7b) *(u64 *)(r10 -8) = r6") +__msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3") +__naked int parent_stack_slot_precise_global(void) +{ + asm volatile ( + /* spill reg */ + "r6 = 3;" + "*(u64 *)(r10 - 8) = r6;" + + /* call subprog and ignore result; we need this call only to + * complicate jump history + */ + "r1 = 0;" + "call global_identity_subprog;" + + /* restore reg from stack; in this case we'll be carrying + * stack mask when going back into subprog through jump + * history + */ + "r6 = *(u64 *)(r10 - 8);" + + "r6 *= 4;" + "r1 = %[vals];" + /* here r6 is forced to be precise and has to be propagated + * back to the beginning, handling (and ignoring) subprog call + */ + "r1 += r6;" + "r0 = *(u32 *)(r1 + 0);" + "exit;" + : + : __imm_ptr(vals) + : __clobber_common, "r6" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("14: (0f) r1 += r6") +__msg("mark_precise: frame0: last_idx 14 first_idx 11") +__msg("mark_precise: frame0: regs=r6 stack= before 13: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r6 stack= before 12: (27) r6 *= 4") +__msg("mark_precise: frame0: regs=r6 stack= before 11: (79) r6 = *(u64 *)(r10 -8)") +__msg("mark_precise: frame0: parent state regs= stack=-8:") +__msg("mark_precise: frame0: last_idx 18 first_idx 0") +__msg("mark_precise: frame0: regs= stack=-8 before 18: (95) exit") +__msg("mark_precise: frame1: regs= stack= before 17: (b7) r0 = 0") +__msg("mark_precise: frame1: regs= stack= before 10: (85) call bpf_loop#181") +__msg("mark_precise: frame0: regs= stack=-8 before 9: (b7) r4 = 0") +__msg("mark_precise: frame0: regs= stack=-8 before 8: (b7) r3 = 0") +__msg("mark_precise: frame0: regs= stack=-8 before 7: (bf) r2 = r8") +__msg("mark_precise: frame0: regs= stack=-8 before 6: (bf) r1 = r6") +__msg("mark_precise: frame0: regs= stack=-8 before 5: (7b) *(u64 *)(r10 -8) = r6") +__msg("mark_precise: frame0: regs=r6 stack= before 4: (b7) r6 = 3") +__naked int parent_stack_slot_precise_with_callback(void) +{ + asm volatile ( + /* spill reg */ + "r6 = 3;" + "*(u64 *)(r10 - 8) = r6;" + + /* ensure we have callback frame in jump history */ + "r1 = r6;" /* nr_loops */ + "r2 = %[callback_subprog];" /* callback_fn */ + "r3 = 0;" /* callback_ctx */ + "r4 = 0;" /* flags */ + "call %[bpf_loop];" + + /* restore reg from stack; in this case we'll be carrying + * stack mask when going back into subprog through jump + * history + */ + "r6 = *(u64 *)(r10 - 8);" + + "r6 *= 4;" + "r1 = %[vals];" + /* here r6 is forced to be precise and has to be propagated + * back to the beginning, handling (and ignoring) subprog call + */ + "r1 += r6;" + "r0 = *(u32 *)(r1 + 0);" + "exit;" + : + : __imm_ptr(vals), + __imm_ptr(callback_subprog), + __imm(bpf_loop) + : __clobber_common, "r6" + ); +} + +__noinline __used +static __u64 subprog_with_precise_arg(__u64 x) +{ + return vals[x]; /* x is forced to be precise */ +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("8: (0f) r2 += r1") +__msg("mark_precise: frame1: last_idx 8 first_idx 0") +__msg("mark_precise: frame1: regs=r1 stack= before 6: (18) r2 = ") +__msg("mark_precise: frame1: regs=r1 stack= before 5: (67) r1 <<= 2") +__msg("mark_precise: frame1: regs=r1 stack= before 2: (85) call pc+2") +__msg("mark_precise: frame0: regs=r1 stack= before 1: (bf) r1 = r6") +__msg("mark_precise: frame0: regs=r6 stack= before 0: (b7) r6 = 3") +__naked int subprog_arg_precise(void) +{ + asm volatile ( + "r6 = 3;" + "r1 = r6;" + /* subprog_with_precise_arg expects its argument to be + * precise, so r1->r6 will be marked precise from inside the + * subprog + */ + "call subprog_with_precise_arg;" + "r0 += r6;" + "exit;" + : + : + : __clobber_common, "r6" + ); +} + +/* r1 is pointer to stack slot; + * r2 is a register to spill into that slot + * subprog also spills r2 into its own stack slot + */ +__naked __noinline __used +static __u64 subprog_spill_reg_precise(void) +{ + asm volatile ( + /* spill to parent stack */ + "*(u64 *)(r1 + 0) = r2;" + /* spill to subprog stack (we use -16 offset to avoid + * accidental confusion with parent's -8 stack slot in + * verifier log output) + */ + "*(u64 *)(r10 - 16) = r2;" + /* use both spills as return result to propagete precision everywhere */ + "r0 = *(u64 *)(r10 - 16);" + "r2 = *(u64 *)(r1 + 0);" + "r0 += r2;" + "exit;" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +/* precision backtracking can't currently handle stack access not through r10, + * so we won't be able to mark stack slot fp-8 as precise, and so will + * fallback to forcing all as precise + */ +__msg("mark_precise: frame0: falling back to forcing all scalars precise") +__naked int subprog_spill_into_parent_stack_slot_precise(void) +{ + asm volatile ( + "r6 = 1;" + + /* pass pointer to stack slot and r6 to subprog; + * r6 will be marked precise and spilled into fp-8 slot, which + * also should be marked precise + */ + "r1 = r10;" + "r1 += -8;" + "r2 = r6;" + "call subprog_spill_reg_precise;" + + /* restore reg from stack; in this case we'll be carrying + * stack mask when going back into subprog through jump + * history + */ + "r7 = *(u64 *)(r10 - 8);" + + "r7 *= 4;" + "r1 = %[vals];" + /* here r7 is forced to be precise and has to be propagated + * back to the beginning, handling subprog call and logic + */ + "r1 += r7;" + "r0 = *(u32 *)(r1 + 0);" + "exit;" + : + : __imm_ptr(vals) + : __clobber_common, "r6", "r7" + ); +} + +__naked __noinline __used +static __u64 subprog_with_checkpoint(void) +{ + asm volatile ( + "r0 = 0;" + /* guaranteed checkpoint if BPF_F_TEST_STATE_FREQ is used */ + "goto +0;" + "exit;" + ); +} + +char _license[] SEC("license") = "GPL"; -- cgit v1.2.3 From c91ab90cea7ae61334c7026daf310f5875dfdee7 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 May 2023 21:33:17 -0700 Subject: selftests/bpf: revert iter test subprog precision workaround Now that precision propagation is supported fully in the presence of subprogs, there is no need to work around iter test. Revert original workaround. This reverts be7dbd275dc6 ("selftests/bpf: avoid mark_all_scalars_precise() trigger in one of iter tests"). Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20230505043317.3629845-11-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/progs/iters.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/progs/iters.c b/tools/testing/selftests/bpf/progs/iters.c index be16143ae292..6b9b3c56f009 100644 --- a/tools/testing/selftests/bpf/progs/iters.c +++ b/tools/testing/selftests/bpf/progs/iters.c @@ -651,29 +651,25 @@ int iter_stack_array_loop(const void *ctx) return sum; } -#define ARR_SZ 16 - -static __noinline void fill(struct bpf_iter_num *it, int *arr, int mul) +static __noinline void fill(struct bpf_iter_num *it, int *arr, __u32 n, int mul) { - int *t; - __u64 i; + int *t, i; while ((t = bpf_iter_num_next(it))) { i = *t; - if (i >= ARR_SZ) + if (i >= n) break; arr[i] = i * mul; } } -static __noinline int sum(struct bpf_iter_num *it, int *arr) +static __noinline int sum(struct bpf_iter_num *it, int *arr, __u32 n) { - int *t, sum = 0;; - __u64 i; + int *t, i, sum = 0;; while ((t = bpf_iter_num_next(it))) { i = *t; - if (i >= ARR_SZ) + if (i >= n) break; sum += arr[i]; } @@ -685,7 +681,7 @@ SEC("raw_tp") __success int iter_pass_iter_ptr_to_subprog(const void *ctx) { - int arr1[ARR_SZ], arr2[ARR_SZ]; + int arr1[16], arr2[32]; struct bpf_iter_num it; int n, sum1, sum2; @@ -694,25 +690,25 @@ int iter_pass_iter_ptr_to_subprog(const void *ctx) /* fill arr1 */ n = ARRAY_SIZE(arr1); bpf_iter_num_new(&it, 0, n); - fill(&it, arr1, 2); + fill(&it, arr1, n, 2); bpf_iter_num_destroy(&it); /* fill arr2 */ n = ARRAY_SIZE(arr2); bpf_iter_num_new(&it, 0, n); - fill(&it, arr2, 10); + fill(&it, arr2, n, 10); bpf_iter_num_destroy(&it); /* sum arr1 */ n = ARRAY_SIZE(arr1); bpf_iter_num_new(&it, 0, n); - sum1 = sum(&it, arr1); + sum1 = sum(&it, arr1, n); bpf_iter_num_destroy(&it); /* sum arr2 */ n = ARRAY_SIZE(arr2); bpf_iter_num_new(&it, 0, n); - sum2 = sum(&it, arr2); + sum2 = sum(&it, arr2, n); bpf_iter_num_destroy(&it); bpf_printk("sum1=%d, sum2=%d", sum1, sum2); -- cgit v1.2.3 From 49e0263ab40f15a11cefa397bb17a0204505cead Mon Sep 17 00:00:00 2001 From: Feng Zhou Date: Sat, 6 May 2023 11:15:45 +0800 Subject: selftests/bpf: Add testcase for bpf_task_under_cgroup test_progs: Tests new kfunc bpf_task_under_cgroup(). The bpf program saves the new task's pid within a given cgroup to the remote_pid, which is convenient for the user-mode program to verify the test correctness. The user-mode program creates its own mount namespace, and mounts the cgroupsv2 hierarchy in there, call the fork syscall, then check if remote_pid and local_pid are unequal. Signed-off-by: Feng Zhou Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20230506031545.35991-3-zhoufeng.zf@bytedance.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/DENYLIST.s390x | 1 + .../selftests/bpf/prog_tests/task_under_cgroup.c | 53 ++++++++++++++++++++++ .../selftests/bpf/progs/test_task_under_cgroup.c | 51 +++++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/task_under_cgroup.c create mode 100644 tools/testing/selftests/bpf/progs/test_task_under_cgroup.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/DENYLIST.s390x b/tools/testing/selftests/bpf/DENYLIST.s390x index c7463f3ec3c0..5061d9e24c16 100644 --- a/tools/testing/selftests/bpf/DENYLIST.s390x +++ b/tools/testing/selftests/bpf/DENYLIST.s390x @@ -26,3 +26,4 @@ user_ringbuf # failed to find kernel BTF type ID of verif_stats # trace_vprintk__open_and_load unexpected error: -9 (?) xdp_bonding # failed to auto-attach program 'trace_on_entry': -524 (trampoline) xdp_metadata # JIT does not support calling kernel function (kfunc) +test_task_under_cgroup # JIT does not support calling kernel function (kfunc) diff --git a/tools/testing/selftests/bpf/prog_tests/task_under_cgroup.c b/tools/testing/selftests/bpf/prog_tests/task_under_cgroup.c new file mode 100644 index 000000000000..4224727fb364 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/task_under_cgroup.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Bytedance */ + +#include +#include +#include +#include "test_task_under_cgroup.skel.h" + +#define FOO "/foo" + +void test_task_under_cgroup(void) +{ + struct test_task_under_cgroup *skel; + int ret, foo; + pid_t pid; + + foo = test__join_cgroup(FOO); + if (!ASSERT_OK(foo < 0, "cgroup_join_foo")) + return; + + skel = test_task_under_cgroup__open(); + if (!ASSERT_OK_PTR(skel, "test_task_under_cgroup__open")) + goto cleanup; + + skel->rodata->local_pid = getpid(); + skel->bss->remote_pid = getpid(); + skel->rodata->cgid = get_cgroup_id(FOO); + + ret = test_task_under_cgroup__load(skel); + if (!ASSERT_OK(ret, "test_task_under_cgroup__load")) + goto cleanup; + + ret = test_task_under_cgroup__attach(skel); + if (!ASSERT_OK(ret, "test_task_under_cgroup__attach")) + goto cleanup; + + pid = fork(); + if (pid == 0) + exit(0); + + ret = (pid == -1); + if (ASSERT_OK(ret, "fork process")) + wait(NULL); + + test_task_under_cgroup__detach(skel); + + ASSERT_NEQ(skel->bss->remote_pid, skel->rodata->local_pid, + "test task_under_cgroup"); + +cleanup: + test_task_under_cgroup__destroy(skel); + close(foo); +} diff --git a/tools/testing/selftests/bpf/progs/test_task_under_cgroup.c b/tools/testing/selftests/bpf/progs/test_task_under_cgroup.c new file mode 100644 index 000000000000..56cdc0a553f0 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_task_under_cgroup.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Bytedance */ + +#include +#include +#include + +#include "bpf_misc.h" + +struct cgroup *bpf_cgroup_from_id(u64 cgid) __ksym; +long bpf_task_under_cgroup(struct task_struct *task, struct cgroup *ancestor) __ksym; +void bpf_cgroup_release(struct cgroup *p) __ksym; +struct task_struct *bpf_task_acquire(struct task_struct *p) __ksym; +void bpf_task_release(struct task_struct *p) __ksym; + +const volatile int local_pid; +const volatile __u64 cgid; +int remote_pid; + +SEC("tp_btf/task_newtask") +int BPF_PROG(handle__task_newtask, struct task_struct *task, u64 clone_flags) +{ + struct cgroup *cgrp = NULL; + struct task_struct *acquired; + + if (local_pid != (bpf_get_current_pid_tgid() >> 32)) + return 0; + + acquired = bpf_task_acquire(task); + if (!acquired) + return 0; + + if (local_pid == acquired->tgid) + goto out; + + cgrp = bpf_cgroup_from_id(cgid); + if (!cgrp) + goto out; + + if (bpf_task_under_cgroup(acquired, cgrp)) + remote_pid = acquired->tgid; + +out: + if (cgrp) + bpf_cgroup_release(cgrp); + bpf_task_release(acquired); + + return 0; +} + +char _license[] SEC("license") = "GPL"; -- cgit v1.2.3 From 1ce33b6c846fbe0439eeee477b767de4bc3ad35f Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 5 May 2023 18:31:31 -0700 Subject: selftests/bpf: Test allowing NULL buffer in dynptr slice bpf_dynptr_slice(_rw) no longer requires a buffer for verification. If the buffer is needed, but not present, the function will return NULL. Signed-off-by: Daniel Rosenberg Link: https://lore.kernel.org/r/20230506013134.2492210-3-drosen@google.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/prog_tests/dynptr.c | 1 + tools/testing/selftests/bpf/progs/dynptr_success.c | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/dynptr.c b/tools/testing/selftests/bpf/prog_tests/dynptr.c index 0478916aff37..13d4b9ab16e7 100644 --- a/tools/testing/selftests/bpf/prog_tests/dynptr.c +++ b/tools/testing/selftests/bpf/prog_tests/dynptr.c @@ -26,6 +26,7 @@ static struct { {"test_dynptr_is_null", SETUP_SYSCALL_SLEEP}, {"test_dynptr_is_rdonly", SETUP_SKB_PROG}, {"test_dynptr_clone", SETUP_SKB_PROG}, + {"test_dynptr_skb_no_buff", SETUP_SKB_PROG}, }; static void verify_success(const char *prog_name, enum test_setup_type setup_type) diff --git a/tools/testing/selftests/bpf/progs/dynptr_success.c b/tools/testing/selftests/bpf/progs/dynptr_success.c index be7de62de045..d299ef3b4d1f 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_success.c +++ b/tools/testing/selftests/bpf/progs/dynptr_success.c @@ -505,3 +505,20 @@ int test_dynptr_clone(struct __sk_buff *skb) return 0; } + +SEC("?cgroup_skb/egress") +int test_dynptr_skb_no_buff(struct __sk_buff *skb) +{ + struct bpf_dynptr ptr; + __u64 *data; + + if (bpf_dynptr_from_skb(skb, 0, &ptr)) { + err = 1; + return 1; + } + + /* This may return NULL. SKB may require a buffer */ + data = bpf_dynptr_slice(&ptr, 0, NULL, 1); + + return !!data; +} -- cgit v1.2.3 From 3881fdfed21ff129a23979c0a92df6d3c5f49aa9 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 5 May 2023 18:31:32 -0700 Subject: selftests/bpf: Check overflow in optional buffer This ensures we still reject invalid memory accesses in buffers that are marked optional. Signed-off-by: Daniel Rosenberg Link: https://lore.kernel.org/r/20230506013134.2492210-4-drosen@google.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/progs/dynptr_fail.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c index efe4ce72d00e..c2f0e18af951 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c @@ -1665,3 +1665,23 @@ int clone_xdp_packet_data(struct xdp_md *xdp) return 0; } + +/* Buffers that are provided must be sufficiently long */ +SEC("?cgroup_skb/egress") +__failure __msg("memory, len pair leads to invalid memory access") +int test_dynptr_skb_small_buff(struct __sk_buff *skb) +{ + struct bpf_dynptr ptr; + char buffer[8] = {}; + __u64 *data; + + if (bpf_dynptr_from_skb(skb, 0, &ptr)) { + err = 1; + return 1; + } + + /* This may return NULL. SKB may require a buffer */ + data = bpf_dynptr_slice(&ptr, 0, buffer, 9); + + return !!data; +} -- cgit v1.2.3 From 798e48fc28fa64aa4eca6e8a404fa20ac8f7c09e Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 5 May 2023 18:31:34 -0700 Subject: selftests/bpf: Accept mem from dynptr in helper funcs This ensures that buffers retrieved from dynptr_data are allowed to be passed in to helpers that take mem, like bpf_strncmp Signed-off-by: Daniel Rosenberg Link: https://lore.kernel.org/r/20230506013134.2492210-6-drosen@google.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/prog_tests/dynptr.c | 1 + tools/testing/selftests/bpf/progs/dynptr_success.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/dynptr.c b/tools/testing/selftests/bpf/prog_tests/dynptr.c index 13d4b9ab16e7..7cfac53c0d58 100644 --- a/tools/testing/selftests/bpf/prog_tests/dynptr.c +++ b/tools/testing/selftests/bpf/prog_tests/dynptr.c @@ -27,6 +27,7 @@ static struct { {"test_dynptr_is_rdonly", SETUP_SKB_PROG}, {"test_dynptr_clone", SETUP_SKB_PROG}, {"test_dynptr_skb_no_buff", SETUP_SKB_PROG}, + {"test_dynptr_skb_strcmp", SETUP_SKB_PROG}, }; static void verify_success(const char *prog_name, enum test_setup_type setup_type) diff --git a/tools/testing/selftests/bpf/progs/dynptr_success.c b/tools/testing/selftests/bpf/progs/dynptr_success.c index d299ef3b4d1f..0c053976f8f9 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_success.c +++ b/tools/testing/selftests/bpf/progs/dynptr_success.c @@ -522,3 +522,24 @@ int test_dynptr_skb_no_buff(struct __sk_buff *skb) return !!data; } + +SEC("?cgroup_skb/egress") +int test_dynptr_skb_strcmp(struct __sk_buff *skb) +{ + struct bpf_dynptr ptr; + char *data; + + if (bpf_dynptr_from_skb(skb, 0, &ptr)) { + err = 1; + return 1; + } + + /* This may return NULL. SKB may require a buffer */ + data = bpf_dynptr_slice(&ptr, 0, NULL, 10); + if (data) { + bpf_strncmp(data, 10, "foo"); + return 1; + } + + return 1; +} -- cgit v1.2.3 From e30f65c4b3d671115bf2a9d9ef142285387f2aff Mon Sep 17 00:00:00 2001 From: Daniel Latypov Date: Mon, 1 May 2023 11:16:10 -0700 Subject: kunit: tool: undo type subscripts for subprocess.Popen Writing `subprocess.Popen[str]` requires python 3.9+. kunit.py has an assertion that the python version is 3.7+, so we should try to stay backwards compatible. This conflicts a bit with commit 1da2e6220e11 ("kunit: tool: fix pre-existing `mypy --strict` errors and update run_checks.py"), since mypy complains like so > kunit_kernel.py:95: error: Missing type parameters for generic type "Popen" [type-arg] Note: `mypy --strict --python-version 3.7` does not work. We could annotate each file with comments like `# mypy: disable-error-code="type-arg" but then we might still get nudged to break back-compat in other files. This patch adds a `mypy.ini` file since it seems like the only way to disable specific error codes for all our files. Note: run_checks.py doesn't need to specify `--config_file mypy.ini`, but I think being explicit is better, particularly since most kernel devs won't be familiar with how mypy works. Fixes: 695e26030858 ("kunit: tool: add subscripts for type annotations where appropriate") Reported-by: SeongJae Park Link: https://lore.kernel.org/linux-kselftest/20230501171520.138753-1-sj@kernel.org Signed-off-by: Daniel Latypov Tested-by: SeongJae Park Reviewed-by: David Gow Signed-off-by: Shuah Khan --- tools/testing/kunit/kunit_kernel.py | 6 +++--- tools/testing/kunit/mypy.ini | 6 ++++++ tools/testing/kunit/run_checks.py | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 tools/testing/kunit/mypy.ini (limited to 'tools/testing') diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kunit_kernel.py index f01f94106129..7f648802caf6 100644 --- a/tools/testing/kunit/kunit_kernel.py +++ b/tools/testing/kunit/kunit_kernel.py @@ -92,7 +92,7 @@ class LinuxSourceTreeOperations: if stderr: # likely only due to build warnings print(stderr.decode()) - def start(self, params: List[str], build_dir: str) -> subprocess.Popen[str]: + def start(self, params: List[str], build_dir: str) -> subprocess.Popen: raise RuntimeError('not implemented!') @@ -113,7 +113,7 @@ class LinuxSourceTreeOperationsQemu(LinuxSourceTreeOperations): kconfig.merge_in_entries(base_kunitconfig) return kconfig - def start(self, params: List[str], build_dir: str) -> subprocess.Popen[str]: + def start(self, params: List[str], build_dir: str) -> subprocess.Popen: kernel_path = os.path.join(build_dir, self._kernel_path) qemu_command = ['qemu-system-' + self._qemu_arch, '-nodefaults', @@ -142,7 +142,7 @@ class LinuxSourceTreeOperationsUml(LinuxSourceTreeOperations): kconfig.merge_in_entries(base_kunitconfig) return kconfig - def start(self, params: List[str], build_dir: str) -> subprocess.Popen[str]: + def start(self, params: List[str], build_dir: str) -> subprocess.Popen: """Runs the Linux UML binary. Must be named 'linux'.""" linux_bin = os.path.join(build_dir, 'linux') params.extend(['mem=1G', 'console=tty', 'kunit_shutdown=halt']) diff --git a/tools/testing/kunit/mypy.ini b/tools/testing/kunit/mypy.ini new file mode 100644 index 000000000000..ddd288309efa --- /dev/null +++ b/tools/testing/kunit/mypy.ini @@ -0,0 +1,6 @@ +[mypy] +strict = True + +# E.g. we can't write subprocess.Popen[str] until Python 3.9+. +# But kunit.py tries to support Python 3.7+, so let's disable it. +disable_error_code = type-arg diff --git a/tools/testing/kunit/run_checks.py b/tools/testing/kunit/run_checks.py index 8208c3b3135e..c6d494ea3373 100755 --- a/tools/testing/kunit/run_checks.py +++ b/tools/testing/kunit/run_checks.py @@ -23,7 +23,7 @@ commands: Dict[str, Sequence[str]] = { 'kunit_tool_test.py': ['./kunit_tool_test.py'], 'kunit smoke test': ['./kunit.py', 'run', '--kunitconfig=lib/kunit', '--build_dir=kunit_run_checks'], 'pytype': ['/bin/sh', '-c', 'pytype *.py'], - 'mypy': ['mypy', '--strict', '--exclude', '_test.py$', '--exclude', 'qemu_configs/', '.'], + 'mypy': ['mypy', '--config-file', 'mypy.ini', '--exclude', '_test.py$', '--exclude', 'qemu_configs/', '.'], } # The user might not have mypy or pytype installed, skip them if so. -- cgit v1.2.3 From 2f0f556713f08515f3017fd35309b1f00fbc8932 Mon Sep 17 00:00:00 2001 From: Liang Li Date: Tue, 9 May 2023 09:09:19 +0000 Subject: selftests: bonding: delete unnecessary line "ip link set dev "$devbond1" nomaster" This line code in bond-eth-type-change.sh is unnecessary. Because $devbond1 was not added to any master device. Signed-off-by: Liang Li Acked-by: Hangbin Liu Reviewed-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- tools/testing/selftests/drivers/net/bonding/bond-eth-type-change.sh | 1 - 1 file changed, 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/drivers/net/bonding/bond-eth-type-change.sh b/tools/testing/selftests/drivers/net/bonding/bond-eth-type-change.sh index 5cdd22048ba7..862e947e17c7 100755 --- a/tools/testing/selftests/drivers/net/bonding/bond-eth-type-change.sh +++ b/tools/testing/selftests/drivers/net/bonding/bond-eth-type-change.sh @@ -53,7 +53,6 @@ bond_test_enslave_type_change() # restore ARPHRD_ETHER type by enslaving such device ip link set dev "$devbond2" master "$devbond0" check_err $? "could not enslave $devbond2 to $devbond0" - ip link set dev "$devbond1" nomaster bond_check_flags "$devbond0" -- cgit v1.2.3 From b409afe0268faeb77267f028ea85f2d93438fced Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 21 Mar 2023 16:40:08 -0700 Subject: rcutorture: Correct name of use_softirq module parameter The BUSTED-BOOST and TREE03 scenarios specify a mythical tree.use_softirq module parameter, which means a failure to get full test coverage. This commit therefore corrects the name to rcutree.use_softirq. Fixes: e2b949d54392 ("rcutorture: Make TREE03 use real-time tree.use_softirq setting") Signed-off-by: Paul E. McKenney Reviewed-by: Joel Fernandes (Google) --- tools/testing/selftests/rcutorture/configs/rcu/BUSTED-BOOST.boot | 2 +- tools/testing/selftests/rcutorture/configs/rcu/TREE03.boot | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/rcutorture/configs/rcu/BUSTED-BOOST.boot b/tools/testing/selftests/rcutorture/configs/rcu/BUSTED-BOOST.boot index f57720c52c0f..84f6bb98ce99 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/BUSTED-BOOST.boot +++ b/tools/testing/selftests/rcutorture/configs/rcu/BUSTED-BOOST.boot @@ -5,4 +5,4 @@ rcutree.gp_init_delay=3 rcutree.gp_cleanup_delay=3 rcutree.kthread_prio=2 threadirqs -tree.use_softirq=0 +rcutree.use_softirq=0 diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE03.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE03.boot index 64f864f1f361..8e50bfd4b710 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE03.boot +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE03.boot @@ -4,4 +4,4 @@ rcutree.gp_init_delay=3 rcutree.gp_cleanup_delay=3 rcutree.kthread_prio=2 threadirqs -tree.use_softirq=0 +rcutree.use_softirq=0 -- cgit v1.2.3 From aeefbb574c38025fd65a1b053c41595ba13b2408 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Thu, 11 May 2023 16:39:25 +0200 Subject: selftests: Add SO_DONTROUTE option to nettest. Add --client-dontroute and --server-dontroute options to nettest. They allow to set the SO_DONTROUTE option to the client and server sockets respectively. This will be used by the following patches to test the SO_DONTROUTE kernel behaviour with TCP and UDP. Signed-off-by: Guillaume Nault Reviewed-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/nettest.c | 46 ++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/nettest.c b/tools/testing/selftests/net/nettest.c index ee9a72982705..39a0e01f8554 100644 --- a/tools/testing/selftests/net/nettest.c +++ b/tools/testing/selftests/net/nettest.c @@ -76,7 +76,9 @@ struct sock_args { has_grp:1, has_expected_laddr:1, has_expected_raddr:1, - bind_test_only:1; + bind_test_only:1, + client_dontroute:1, + server_dontroute:1; unsigned short port; @@ -611,6 +613,18 @@ static int set_dsfield(int sd, int version, int dsfield) return 0; } +static int set_dontroute(int sd) +{ + unsigned int one = 1; + + if (setsockopt(sd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0) { + log_err_errno("setsockopt(SO_DONTROUTE)"); + return -1; + } + + return 0; +} + static int str_to_uint(const char *str, int min, int max, unsigned int *value) { int number; @@ -1351,6 +1365,14 @@ static int msock_init(struct sock_args *args, int server) if (set_dsfield(sd, AF_INET, args->dsfield) != 0) goto out_err; + if (server) { + if (args->server_dontroute && set_dontroute(sd) != 0) + goto out_err; + } else { + if (args->client_dontroute && set_dontroute(sd) != 0) + goto out_err; + } + if (args->dev && bind_to_device(sd, args->dev) != 0) goto out_err; else if (args->use_setsockopt && @@ -1482,6 +1504,9 @@ static int lsock_init(struct sock_args *args) if (set_dsfield(sd, args->version, args->dsfield) != 0) goto err; + if (args->server_dontroute && set_dontroute(sd) != 0) + goto err; + if (args->dev && bind_to_device(sd, args->dev) != 0) goto err; else if (args->use_setsockopt && @@ -1698,6 +1723,9 @@ static int connectsock(void *addr, socklen_t alen, struct sock_args *args) if (set_dsfield(sd, args->version, args->dsfield) != 0) goto err; + if (args->client_dontroute && set_dontroute(sd) != 0) + goto err; + if (args->dev && bind_to_device(sd, args->dev) != 0) goto err; else if (args->use_setsockopt && @@ -1905,10 +1933,14 @@ static int ipc_parent(int cpid, int fd, struct sock_args *args) #define GETOPT_STR "sr:l:c:Q:p:t:g:P:DRn:M:X:m:d:I:BN:O:SUCi6xL:0:1:2:3:Fbqf" #define OPT_FORCE_BIND_KEY_IFINDEX 1001 #define OPT_NO_BIND_KEY_IFINDEX 1002 +#define OPT_CLIENT_DONTROUTE 1003 +#define OPT_SERVER_DONTROUTE 1004 static struct option long_opts[] = { {"force-bind-key-ifindex", 0, 0, OPT_FORCE_BIND_KEY_IFINDEX}, {"no-bind-key-ifindex", 0, 0, OPT_NO_BIND_KEY_IFINDEX}, + {"client-dontroute", 0, 0, OPT_CLIENT_DONTROUTE}, + {"server-dontroute", 0, 0, OPT_SERVER_DONTROUTE}, {0, 0, 0, 0} }; @@ -1954,6 +1986,12 @@ static void print_usage(char *prog) " --no-bind-key-ifindex: Force TCP_MD5SIG_FLAG_IFINDEX off\n" " --force-bind-key-ifindex: Force TCP_MD5SIG_FLAG_IFINDEX on\n" " (default: only if -I is passed)\n" + " --client-dontroute: don't use gateways for client socket: send\n" + " packets only if destination is on link (see\n" + " SO_DONTROUTE in socket(7))\n" + " --server-dontroute: don't use gateways for server socket: send\n" + " packets only if destination is on link (see\n" + " SO_DONTROUTE in socket(7))\n" "\n" " -g grp multicast group (e.g., 239.1.1.1)\n" " -i interactive mode (default is echo and terminate)\n" @@ -2076,6 +2114,12 @@ int main(int argc, char *argv[]) case OPT_NO_BIND_KEY_IFINDEX: args.bind_key_ifindex = -1; break; + case OPT_CLIENT_DONTROUTE: + args.client_dontroute = 1; + break; + case OPT_SERVER_DONTROUTE: + args.server_dontroute = 1; + break; case 'X': args.client_pw = optarg; break; -- cgit v1.2.3 From dd017c72dde677cef5a5a965ca71ac4736b53452 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Thu, 11 May 2023 16:39:32 +0200 Subject: selftests: fcnal: Test SO_DONTROUTE on TCP sockets. Use nettest --{client,server}-dontroute to test the kernel behaviour with TCP sockets having the SO_DONTROUTE option. Sending packets to a neighbour (on link) host, should work. When the host is behind a router, sending should fail. Client and server sockets are tested independently, so that we can cover different TCP kernel paths. SO_DONTROUTE also affects the syncookies path. So ipv4_tcp_dontroute() is made to work with or without syncookies, to cover both paths. Signed-off-by: Guillaume Nault Reviewed-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fcnal-test.sh | 56 +++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh index 21ca91473c09..3a1f3051321f 100755 --- a/tools/testing/selftests/net/fcnal-test.sh +++ b/tools/testing/selftests/net/fcnal-test.sh @@ -1098,6 +1098,59 @@ test_ipv4_md5_vrf__global_server__bind_ifindex0() set_sysctl net.ipv4.tcp_l3mdev_accept="$old_tcp_l3mdev_accept" } +ipv4_tcp_dontroute() +{ + local syncookies=$1 + local nsa_syncookies + local nsb_syncookies + local a + + # + # Link local connection tests (SO_DONTROUTE). + # Connections should succeed only when the remote IP address is + # on link (doesn't need to be routed through a gateway). + # + + nsa_syncookies=$(ip netns exec "${NSA}" sysctl -n net.ipv4.tcp_syncookies) + nsb_syncookies=$(ip netns exec "${NSB}" sysctl -n net.ipv4.tcp_syncookies) + ip netns exec "${NSA}" sysctl -wq net.ipv4.tcp_syncookies=${syncookies} + ip netns exec "${NSB}" sysctl -wq net.ipv4.tcp_syncookies=${syncookies} + + # Test with eth1 address (on link). + + a=${NSB_IP} + log_start + do_run_cmd nettest -B -N "${NSA}" -O "${NSB}" -r ${a} --client-dontroute + log_test_addr ${a} $? 0 "SO_DONTROUTE client, syncookies=${syncookies}" + + a=${NSB_IP} + log_start + do_run_cmd nettest -B -N "${NSA}" -O "${NSB}" -r ${a} --server-dontroute + log_test_addr ${a} $? 0 "SO_DONTROUTE server, syncookies=${syncookies}" + + # Test with loopback address (routed). + # + # The client would use the eth1 address as source IP by default. + # Therefore, we need to use the -c option here, to force the use of the + # routed (loopback) address as source IP (so that the server will try + # to respond to a routed address and not a link local one). + + a=${NSB_LO_IP} + log_start + show_hint "Should fail 'Network is unreachable' since server is not on link" + do_run_cmd nettest -B -N "${NSA}" -O "${NSB}" -c "${NSA_LO_IP}" -r ${a} --client-dontroute + log_test_addr ${a} $? 1 "SO_DONTROUTE client, syncookies=${syncookies}" + + a=${NSB_LO_IP} + log_start + show_hint "Should timeout since server cannot respond (client is not on link)" + do_run_cmd nettest -B -N "${NSA}" -O "${NSB}" -c "${NSA_LO_IP}" -r ${a} --server-dontroute + log_test_addr ${a} $? 2 "SO_DONTROUTE server, syncookies=${syncookies}" + + ip netns exec "${NSB}" sysctl -wq net.ipv4.tcp_syncookies=${nsb_syncookies} + ip netns exec "${NSA}" sysctl -wq net.ipv4.tcp_syncookies=${nsa_syncookies} +} + ipv4_tcp_novrf() { local a @@ -1217,6 +1270,9 @@ ipv4_tcp_novrf() log_test_addr ${a} $? 1 "No server, device client, local conn" ipv4_tcp_md5_novrf + + ipv4_tcp_dontroute 0 + ipv4_tcp_dontroute 2 } ipv4_tcp_vrf() -- cgit v1.2.3 From a431327c4faacf978defa94dd0da1710d0c69801 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Thu, 11 May 2023 16:39:39 +0200 Subject: selftests: fcnal: Test SO_DONTROUTE on UDP sockets. Use nettest --client-dontroute to test the kernel behaviour with UDP sockets having the SO_DONTROUTE option. Sending packets to a neighbour (on link) host, should work. When the host is behind a router, sending should fail. Signed-off-by: Guillaume Nault Reviewed-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fcnal-test.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh index 3a1f3051321f..08b4b96cbd63 100755 --- a/tools/testing/selftests/net/fcnal-test.sh +++ b/tools/testing/selftests/net/fcnal-test.sh @@ -1641,6 +1641,23 @@ ipv4_udp_novrf() log_start run_cmd nettest -D -d ${NSA_DEV} -r ${a} log_test_addr ${a} $? 2 "No server, device client, local conn" + + # + # Link local connection tests (SO_DONTROUTE). + # Connections should succeed only when the remote IP address is + # on link (doesn't need to be routed through a gateway). + # + + a=${NSB_IP} + log_start + do_run_cmd nettest -B -D -N "${NSA}" -O "${NSB}" -r ${a} --client-dontroute + log_test_addr ${a} $? 0 "SO_DONTROUTE client" + + a=${NSB_LO_IP} + log_start + show_hint "Should fail 'Network is unreachable' since server is not on link" + do_run_cmd nettest -B -D -N "${NSA}" -O "${NSB}" -r ${a} --client-dontroute + log_test_addr ${a} $? 1 "SO_DONTROUTE client" } ipv4_udp_vrf() -- cgit v1.2.3 From ceec9f272432b03168376d6487e7e7817d215f07 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Thu, 11 May 2023 16:39:46 +0200 Subject: selftests: fcnal: Test SO_DONTROUTE on raw and ping sockets. Use ping -r to test the kernel behaviour with raw and ping sockets having the SO_DONTROUTE option. Since ipv4_ping_novrf() is called with different values of net.ipv4.ping_group_range, then it tests both raw and ping sockets (ping uses ping sockets if its user ID belongs to ping_group_range and raw sockets otherwise). With both socket types, sending packets to a neighbour (on link) host, should work. When the host is behind a router, sending should fail. Signed-off-by: Guillaume Nault Reviewed-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fcnal-test.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh index 08b4b96cbd63..05b5c4af7a08 100755 --- a/tools/testing/selftests/net/fcnal-test.sh +++ b/tools/testing/selftests/net/fcnal-test.sh @@ -584,6 +584,20 @@ ipv4_ping_novrf() log_test_addr ${a} $? 0 "ping out, address bind" done + # + # out, but don't use gateway if peer is not on link + # + a=${NSB_IP} + log_start + run_cmd ping -c 1 -w 1 -r ${a} + log_test_addr ${a} $? 0 "ping out (don't route), peer on link" + + a=${NSB_LO_IP} + log_start + show_hint "Fails since peer is not on link" + run_cmd ping -c 1 -w 1 -r ${a} + log_test_addr ${a} $? 1 "ping out (don't route), peer not on link" + # # in # -- cgit v1.2.3 From 305c041899971ff210ad5f9c50249d179c95ada4 Mon Sep 17 00:00:00 2001 From: Vladimir Nikishkin Date: Fri, 12 May 2023 11:40:34 +0800 Subject: selftests: net: vxlan: Add tests for vxlan nolocalbypass option. Add test to make sure that the localbypass option is on by default. Add test to change vxlan localbypass to nolocalbypass and check that packets are delivered to userspace. Signed-off-by: Vladimir Nikishkin Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/Makefile | 1 + .../selftests/net/test_vxlan_nolocalbypass.sh | 240 +++++++++++++++++++++ 2 files changed, 241 insertions(+) create mode 100755 tools/testing/selftests/net/test_vxlan_nolocalbypass.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index c12df57d5539..7f3ab2a93ed6 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -84,6 +84,7 @@ TEST_GEN_FILES += ip_local_port_range TEST_GEN_FILES += bind_wildcard TEST_PROGS += test_vxlan_mdb.sh TEST_PROGS += test_bridge_neigh_suppress.sh +TEST_PROGS += test_vxlan_nolocalbypass.sh TEST_FILES := settings diff --git a/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh b/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh new file mode 100755 index 000000000000..46067db53068 --- /dev/null +++ b/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh @@ -0,0 +1,240 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# This test is for checking the [no]localbypass VXLAN device option. The test +# configures two VXLAN devices in the same network namespace and a tc filter on +# the loopback device that drops encapsulated packets. The test sends packets +# from the first VXLAN device and verifies that by default these packets are +# received by the second VXLAN device. The test then enables the nolocalbypass +# option and verifies that packets are no longer received by the second VXLAN +# device. + +ret=0 +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + +TESTS=" + nolocalbypass +" +VERBOSE=0 +PAUSE_ON_FAIL=no +PAUSE=no + +################################################################################ +# Utilities + +log_test() +{ + local rc=$1 + local expected=$2 + local msg="$3" + + if [ ${rc} -eq ${expected} ]; then + printf "TEST: %-60s [ OK ]\n" "${msg}" + nsuccess=$((nsuccess+1)) + else + ret=1 + nfail=$((nfail+1)) + printf "TEST: %-60s [FAIL]\n" "${msg}" + if [ "$VERBOSE" = "1" ]; then + echo " rc=$rc, expected $expected" + fi + + if [ "${PAUSE_ON_FAIL}" = "yes" ]; then + echo + echo "hit enter to continue, 'q' to quit" + read a + [ "$a" = "q" ] && exit 1 + fi + fi + + if [ "${PAUSE}" = "yes" ]; then + echo + echo "hit enter to continue, 'q' to quit" + read a + [ "$a" = "q" ] && exit 1 + fi + + [ "$VERBOSE" = "1" ] && echo +} + +run_cmd() +{ + local cmd="$1" + local out + local stderr="2>/dev/null" + + if [ "$VERBOSE" = "1" ]; then + printf "COMMAND: $cmd\n" + stderr= + fi + + out=$(eval $cmd $stderr) + rc=$? + if [ "$VERBOSE" = "1" -a -n "$out" ]; then + echo " $out" + fi + + return $rc +} + +tc_check_packets() +{ + local ns=$1; shift + local id=$1; shift + local handle=$1; shift + local count=$1; shift + local pkts + + sleep 0.1 + pkts=$(tc -n $ns -j -s filter show $id \ + | jq ".[] | select(.options.handle == $handle) | \ + .options.actions[0].stats.packets") + [[ $pkts == $count ]] +} + +################################################################################ +# Setup + +setup() +{ + ip netns add ns1 + + ip -n ns1 link set dev lo up + ip -n ns1 address add 192.0.2.1/32 dev lo + ip -n ns1 address add 198.51.100.1/32 dev lo + + ip -n ns1 link add name vx0 up type vxlan id 100 local 198.51.100.1 \ + dstport 4789 nolearning + ip -n ns1 link add name vx1 up type vxlan id 100 dstport 4790 +} + +cleanup() +{ + ip netns del ns1 &> /dev/null +} + +################################################################################ +# Tests + +nolocalbypass() +{ + local smac=00:01:02:03:04:05 + local dmac=00:0a:0b:0c:0d:0e + + run_cmd "bridge -n ns1 fdb add $dmac dev vx0 self static dst 192.0.2.1 port 4790" + + run_cmd "tc -n ns1 qdisc add dev vx1 clsact" + run_cmd "tc -n ns1 filter add dev vx1 ingress pref 1 handle 101 proto all flower src_mac $smac dst_mac $dmac action pass" + + run_cmd "tc -n ns1 qdisc add dev lo clsact" + run_cmd "tc -n ns1 filter add dev lo ingress pref 1 handle 101 proto ip flower ip_proto udp dst_port 4790 action drop" + + run_cmd "ip -n ns1 -d link show dev vx0 | grep ' localbypass'" + log_test $? 0 "localbypass enabled" + + run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q" + + tc_check_packets "ns1" "dev vx1 ingress" 101 1 + log_test $? 0 "Packet received by local VXLAN device - localbypass" + + run_cmd "ip -n ns1 link set dev vx0 type vxlan nolocalbypass" + + run_cmd "ip -n ns1 -d link show dev vx0 | grep 'nolocalbypass'" + log_test $? 0 "localbypass disabled" + + run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q" + + tc_check_packets "ns1" "dev vx1 ingress" 101 1 + log_test $? 0 "Packet not received by local VXLAN device - nolocalbypass" + + run_cmd "ip -n ns1 link set dev vx0 type vxlan localbypass" + + run_cmd "ip -n ns1 -d link show dev vx0 | grep ' localbypass'" + log_test $? 0 "localbypass enabled" + + run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q" + + tc_check_packets "ns1" "dev vx1 ingress" 101 2 + log_test $? 0 "Packet received by local VXLAN device - localbypass" +} + +################################################################################ +# Usage + +usage() +{ + cat < Test(s) to run (default: all) + (options: $TESTS) + -p Pause on fail + -P Pause after each test before cleanup + -v Verbose mode (show commands and output) +EOF +} + +################################################################################ +# Main + +trap cleanup EXIT + +while getopts ":t:pPvh" opt; do + case $opt in + t) TESTS=$OPTARG ;; + p) PAUSE_ON_FAIL=yes;; + P) PAUSE=yes;; + v) VERBOSE=$(($VERBOSE + 1));; + h) usage; exit 0;; + *) usage; exit 1;; + esac +done + +# Make sure we don't pause twice. +[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no + +if [ "$(id -u)" -ne 0 ];then + echo "SKIP: Need root privileges" + exit $ksft_skip; +fi + +if [ ! -x "$(command -v ip)" ]; then + echo "SKIP: Could not run test without ip tool" + exit $ksft_skip +fi + +if [ ! -x "$(command -v bridge)" ]; then + echo "SKIP: Could not run test without bridge tool" + exit $ksft_skip +fi + +if [ ! -x "$(command -v mausezahn)" ]; then + echo "SKIP: Could not run test without mausezahn tool" + exit $ksft_skip +fi + +if [ ! -x "$(command -v jq)" ]; then + echo "SKIP: Could not run test without jq tool" + exit $ksft_skip +fi + +ip link help vxlan 2>&1 | grep -q "localbypass" +if [ $? -ne 0 ]; then + echo "SKIP: iproute2 ip too old, missing VXLAN nolocalbypass support" + exit $ksft_skip +fi + +cleanup + +for t in $TESTS +do + setup; $t; cleanup; +done + +if [ "$TESTS" != "none" ]; then + printf "\nTests passed: %3d\n" ${nsuccess} + printf "Tests failed: %3d\n" ${nfail} +fi + +exit $ret -- cgit v1.2.3 From 989a4a7dbff21399da42e808a4ae134023546f41 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Thu, 11 May 2023 10:04:54 -0700 Subject: selftests/bpf: Update EFAULT {g,s}etsockopt selftests Instead of assuming EFAULT, let's assume the BPF program's output is ignored. Remove "getsockopt: deny arbitrary ctx->retval" because it was actually testing optlen. We have separate set of tests for retval. Signed-off-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20230511170456.1759459-3-sdf@google.com Signed-off-by: Martin KaFai Lau --- tools/testing/selftests/bpf/prog_tests/sockopt.c | 96 ++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 6 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/sockopt.c b/tools/testing/selftests/bpf/prog_tests/sockopt.c index aa4debf62fc6..33dd4532e642 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockopt.c +++ b/tools/testing/selftests/bpf/prog_tests/sockopt.c @@ -5,10 +5,15 @@ static char bpf_log_buf[4096]; static bool verbose; +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + enum sockopt_test_error { OK = 0, DENY_LOAD, DENY_ATTACH, + EOPNOTSUPP_GETSOCKOPT, EPERM_GETSOCKOPT, EFAULT_GETSOCKOPT, EPERM_SETSOCKOPT, @@ -273,10 +278,31 @@ static struct sockopt_test { .error = EFAULT_GETSOCKOPT, }, { - .descr = "getsockopt: deny arbitrary ctx->retval", + .descr = "getsockopt: ignore >PAGE_SIZE optlen", .insns = { - /* ctx->retval = 123 */ - BPF_MOV64_IMM(BPF_REG_0, 123), + /* write 0xFF to the first optval byte */ + + /* r6 = ctx->optval */ + BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, + offsetof(struct bpf_sockopt, optval)), + /* r2 = ctx->optval */ + BPF_MOV64_REG(BPF_REG_2, BPF_REG_6), + /* r6 = ctx->optval + 1 */ + BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1), + + /* r7 = ctx->optval_end */ + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1, + offsetof(struct bpf_sockopt, optval_end)), + + /* if (ctx->optval + 1 <= ctx->optval_end) { */ + BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1), + /* ctx->optval[0] = 0xF0 */ + BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 0xFF), + /* } */ + + /* retval changes are ignored */ + /* ctx->retval = 5 */ + BPF_MOV64_IMM(BPF_REG_0, 5), BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, offsetof(struct bpf_sockopt, retval)), @@ -287,9 +313,11 @@ static struct sockopt_test { .attach_type = BPF_CGROUP_GETSOCKOPT, .expected_attach_type = BPF_CGROUP_GETSOCKOPT, - .get_optlen = 64, - - .error = EFAULT_GETSOCKOPT, + .get_level = 1234, + .get_optname = 5678, + .get_optval = {}, /* the changes are ignored */ + .get_optlen = PAGE_SIZE + 1, + .error = EOPNOTSUPP_GETSOCKOPT, }, { .descr = "getsockopt: support smaller ctx->optlen", @@ -648,6 +676,45 @@ static struct sockopt_test { .error = EFAULT_SETSOCKOPT, }, + { + .descr = "setsockopt: ignore >PAGE_SIZE optlen", + .insns = { + /* write 0xFF to the first optval byte */ + + /* r6 = ctx->optval */ + BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, + offsetof(struct bpf_sockopt, optval)), + /* r2 = ctx->optval */ + BPF_MOV64_REG(BPF_REG_2, BPF_REG_6), + /* r6 = ctx->optval + 1 */ + BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1), + + /* r7 = ctx->optval_end */ + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1, + offsetof(struct bpf_sockopt, optval_end)), + + /* if (ctx->optval + 1 <= ctx->optval_end) { */ + BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1), + /* ctx->optval[0] = 0xF0 */ + BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 0xF0), + /* } */ + + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + + .set_level = SOL_IP, + .set_optname = IP_TOS, + .set_optval = {}, + .set_optlen = PAGE_SIZE + 1, + + .get_level = SOL_IP, + .get_optname = IP_TOS, + .get_optval = {}, /* the changes are ignored */ + .get_optlen = 4, + }, { .descr = "setsockopt: allow changing ctx->optlen within bounds", .insns = { @@ -906,6 +973,13 @@ static int run_test(int cgroup_fd, struct sockopt_test *test) } if (test->set_optlen) { + if (test->set_optlen >= PAGE_SIZE) { + int num_pages = test->set_optlen / PAGE_SIZE; + int remainder = test->set_optlen % PAGE_SIZE; + + test->set_optlen = num_pages * sysconf(_SC_PAGESIZE) + remainder; + } + err = setsockopt(sock_fd, test->set_level, test->set_optname, test->set_optval, test->set_optlen); if (err) { @@ -921,7 +995,15 @@ static int run_test(int cgroup_fd, struct sockopt_test *test) } if (test->get_optlen) { + if (test->get_optlen >= PAGE_SIZE) { + int num_pages = test->get_optlen / PAGE_SIZE; + int remainder = test->get_optlen % PAGE_SIZE; + + test->get_optlen = num_pages * sysconf(_SC_PAGESIZE) + remainder; + } + optval = malloc(test->get_optlen); + memset(optval, 0, test->get_optlen); socklen_t optlen = test->get_optlen; socklen_t expected_get_optlen = test->get_optlen_ret ?: test->get_optlen; @@ -929,6 +1011,8 @@ static int run_test(int cgroup_fd, struct sockopt_test *test) err = getsockopt(sock_fd, test->get_level, test->get_optname, optval, &optlen); if (err) { + if (errno == EOPNOTSUPP && test->error == EOPNOTSUPP_GETSOCKOPT) + goto free_optval; if (errno == EPERM && test->error == EPERM_GETSOCKOPT) goto free_optval; if (errno == EFAULT && test->error == EFAULT_GETSOCKOPT) -- cgit v1.2.3 From e01b4a72f132c1ca63e3ed851bef9b3c62ae6149 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Thu, 11 May 2023 10:04:55 -0700 Subject: selftests/bpf: Correctly handle optlen > 4096 Even though it's not relevant in selftests, the people might still copy-paste from them. So let's take care of optlen > 4096 cases explicitly. Signed-off-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20230511170456.1759459-4-sdf@google.com Signed-off-by: Martin KaFai Lau --- .../bpf/prog_tests/cgroup_getset_retval.c | 20 ++++ .../selftests/bpf/prog_tests/sockopt_inherit.c | 59 ++++------- .../selftests/bpf/prog_tests/sockopt_multi.c | 108 ++++++--------------- .../selftests/bpf/prog_tests/sockopt_qos_to_cc.c | 2 + .../bpf/progs/cgroup_getset_retval_getsockopt.c | 13 +++ .../bpf/progs/cgroup_getset_retval_setsockopt.c | 17 ++++ .../testing/selftests/bpf/progs/sockopt_inherit.c | 18 +++- tools/testing/selftests/bpf/progs/sockopt_multi.c | 26 ++++- .../selftests/bpf/progs/sockopt_qos_to_cc.c | 10 +- tools/testing/selftests/bpf/progs/sockopt_sk.c | 25 +++-- 10 files changed, 166 insertions(+), 132 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/cgroup_getset_retval.c b/tools/testing/selftests/bpf/prog_tests/cgroup_getset_retval.c index 4d2fa99273d8..2bb5773d6f99 100644 --- a/tools/testing/selftests/bpf/prog_tests/cgroup_getset_retval.c +++ b/tools/testing/selftests/bpf/prog_tests/cgroup_getset_retval.c @@ -25,6 +25,8 @@ static void test_setsockopt_set(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach setsockopt that sets EUNATCH, assert that * we actually get that error when we run setsockopt() */ @@ -59,6 +61,8 @@ static void test_setsockopt_set_and_get(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach setsockopt that sets EUNATCH, and one that gets the * previously set errno. Assert that we get the same errno back. */ @@ -100,6 +104,8 @@ static void test_setsockopt_default_zero(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach setsockopt that gets the previously set errno. * Assert that, without anything setting one, we get 0. */ @@ -134,6 +140,8 @@ static void test_setsockopt_default_zero_and_set(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach setsockopt that gets the previously set errno, and then * one that sets the errno to EUNATCH. Assert that the get does not * see EUNATCH set later, and does not prevent EUNATCH from being set. @@ -177,6 +185,8 @@ static void test_setsockopt_override(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach setsockopt that sets EUNATCH, then one that sets EISCONN, * and then one that gets the exported errno. Assert both the syscall * and the helper sees the last set errno. @@ -224,6 +234,8 @@ static void test_setsockopt_legacy_eperm(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach setsockopt that return a reject without setting errno * (legacy reject), and one that gets the errno. Assert that for * backward compatibility the syscall result in EPERM, and this @@ -268,6 +280,8 @@ static void test_setsockopt_legacy_no_override(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach setsockopt that sets EUNATCH, then one that return a reject * without setting errno, and then one that gets the exported errno. * Assert both the syscall and the helper's errno are unaffected by @@ -319,6 +333,8 @@ static void test_getsockopt_get(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach getsockopt that gets previously set errno. Assert that the * error from kernel is in both ctx_retval_value and retval_value. */ @@ -359,6 +375,8 @@ static void test_getsockopt_override(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach getsockopt that sets retval to -EISCONN. Assert that this * overrides the value from kernel. */ @@ -396,6 +414,8 @@ static void test_getsockopt_retval_sync(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach getsockopt that sets retval to -EISCONN, and one that clears * ctx retval. Assert that the clearing ctx retval is synced to helper * and clears any errors both from kernel and BPF.. diff --git a/tools/testing/selftests/bpf/prog_tests/sockopt_inherit.c b/tools/testing/selftests/bpf/prog_tests/sockopt_inherit.c index 60c17a8e2789..917f486db826 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockopt_inherit.c +++ b/tools/testing/selftests/bpf/prog_tests/sockopt_inherit.c @@ -2,6 +2,8 @@ #include #include "cgroup_helpers.h" +#include "sockopt_inherit.skel.h" + #define SOL_CUSTOM 0xdeadbeef #define CUSTOM_INHERIT1 0 #define CUSTOM_INHERIT2 1 @@ -132,58 +134,30 @@ static int start_server(void) return fd; } -static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title, - const char *prog_name) -{ - enum bpf_attach_type attach_type; - enum bpf_prog_type prog_type; - struct bpf_program *prog; - int err; - - err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); - if (err) { - log_err("Failed to deduct types for %s BPF program", prog_name); - return -1; - } - - prog = bpf_object__find_program_by_name(obj, prog_name); - if (!prog) { - log_err("Failed to find %s BPF program", prog_name); - return -1; - } - - err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, - attach_type, 0); - if (err) { - log_err("Failed to attach %s BPF program", prog_name); - return -1; - } - - return 0; -} - static void run_test(int cgroup_fd) { + struct bpf_link *link_getsockopt = NULL; + struct bpf_link *link_setsockopt = NULL; int server_fd = -1, client_fd; - struct bpf_object *obj; + struct sockopt_inherit *obj; void *server_err; pthread_t tid; int err; - obj = bpf_object__open_file("sockopt_inherit.bpf.o", NULL); - if (!ASSERT_OK_PTR(obj, "obj_open")) + obj = sockopt_inherit__open_and_load(); + if (!ASSERT_OK_PTR(obj, "skel-load")) return; - err = bpf_object__load(obj); - if (!ASSERT_OK(err, "obj_load")) - goto close_bpf_object; + obj->bss->page_size = sysconf(_SC_PAGESIZE); - err = prog_attach(obj, cgroup_fd, "cgroup/getsockopt", "_getsockopt"); - if (!ASSERT_OK(err, "prog_attach _getsockopt")) + link_getsockopt = bpf_program__attach_cgroup(obj->progs._getsockopt, + cgroup_fd); + if (!ASSERT_OK_PTR(link_getsockopt, "cg-attach-getsockopt")) goto close_bpf_object; - err = prog_attach(obj, cgroup_fd, "cgroup/setsockopt", "_setsockopt"); - if (!ASSERT_OK(err, "prog_attach _setsockopt")) + link_setsockopt = bpf_program__attach_cgroup(obj->progs._setsockopt, + cgroup_fd); + if (!ASSERT_OK_PTR(link_setsockopt, "cg-attach-setsockopt")) goto close_bpf_object; server_fd = start_server(); @@ -217,7 +191,10 @@ static void run_test(int cgroup_fd) close_server_fd: close(server_fd); close_bpf_object: - bpf_object__close(obj); + bpf_link__destroy(link_getsockopt); + bpf_link__destroy(link_setsockopt); + + sockopt_inherit__destroy(obj); } void test_sockopt_inherit(void) diff --git a/tools/testing/selftests/bpf/prog_tests/sockopt_multi.c b/tools/testing/selftests/bpf/prog_tests/sockopt_multi.c index 7f5659349011..759bbb6f8c5f 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockopt_multi.c +++ b/tools/testing/selftests/bpf/prog_tests/sockopt_multi.c @@ -2,61 +2,13 @@ #include #include "cgroup_helpers.h" -static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title, const char *name) -{ - enum bpf_attach_type attach_type; - enum bpf_prog_type prog_type; - struct bpf_program *prog; - int err; - - err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); - if (err) { - log_err("Failed to deduct types for %s BPF program", title); - return -1; - } - - prog = bpf_object__find_program_by_name(obj, name); - if (!prog) { - log_err("Failed to find %s BPF program", name); - return -1; - } - - err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, - attach_type, BPF_F_ALLOW_MULTI); - if (err) { - log_err("Failed to attach %s BPF program", name); - return -1; - } - - return 0; -} +#include "sockopt_multi.skel.h" -static int prog_detach(struct bpf_object *obj, int cgroup_fd, const char *title, const char *name) -{ - enum bpf_attach_type attach_type; - enum bpf_prog_type prog_type; - struct bpf_program *prog; - int err; - - err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); - if (err) - return -1; - - prog = bpf_object__find_program_by_name(obj, name); - if (!prog) - return -1; - - err = bpf_prog_detach2(bpf_program__fd(prog), cgroup_fd, - attach_type); - if (err) - return -1; - - return 0; -} - -static int run_getsockopt_test(struct bpf_object *obj, int cg_parent, +static int run_getsockopt_test(struct sockopt_multi *obj, int cg_parent, int cg_child, int sock_fd) { + struct bpf_link *link_parent = NULL; + struct bpf_link *link_child = NULL; socklen_t optlen; __u8 buf; int err; @@ -89,8 +41,9 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent, * - child: 0x80 -> 0x90 */ - err = prog_attach(obj, cg_child, "cgroup/getsockopt", "_getsockopt_child"); - if (err) + link_child = bpf_program__attach_cgroup(obj->progs._getsockopt_child, + cg_child); + if (!ASSERT_OK_PTR(link_child, "cg-attach-getsockopt_child")) goto detach; buf = 0x00; @@ -113,8 +66,9 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent, * - parent: 0x90 -> 0xA0 */ - err = prog_attach(obj, cg_parent, "cgroup/getsockopt", "_getsockopt_parent"); - if (err) + link_parent = bpf_program__attach_cgroup(obj->progs._getsockopt_parent, + cg_parent); + if (!ASSERT_OK_PTR(link_parent, "cg-attach-getsockopt_parent")) goto detach; buf = 0x00; @@ -157,11 +111,8 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent, * - parent: unexpected 0x40, EPERM */ - err = prog_detach(obj, cg_child, "cgroup/getsockopt", "_getsockopt_child"); - if (err) { - log_err("Failed to detach child program"); - goto detach; - } + bpf_link__destroy(link_child); + link_child = NULL; buf = 0x00; optlen = 1; @@ -198,15 +149,17 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent, } detach: - prog_detach(obj, cg_child, "cgroup/getsockopt", "_getsockopt_child"); - prog_detach(obj, cg_parent, "cgroup/getsockopt", "_getsockopt_parent"); + bpf_link__destroy(link_child); + bpf_link__destroy(link_parent); return err; } -static int run_setsockopt_test(struct bpf_object *obj, int cg_parent, +static int run_setsockopt_test(struct sockopt_multi *obj, int cg_parent, int cg_child, int sock_fd) { + struct bpf_link *link_parent = NULL; + struct bpf_link *link_child = NULL; socklen_t optlen; __u8 buf; int err; @@ -236,8 +189,9 @@ static int run_setsockopt_test(struct bpf_object *obj, int cg_parent, /* Attach child program and make sure it adds 0x10. */ - err = prog_attach(obj, cg_child, "cgroup/setsockopt", "_setsockopt"); - if (err) + link_child = bpf_program__attach_cgroup(obj->progs._setsockopt, + cg_child); + if (!ASSERT_OK_PTR(link_child, "cg-attach-setsockopt_child")) goto detach; buf = 0x80; @@ -263,8 +217,9 @@ static int run_setsockopt_test(struct bpf_object *obj, int cg_parent, /* Attach parent program and make sure it adds another 0x10. */ - err = prog_attach(obj, cg_parent, "cgroup/setsockopt", "_setsockopt"); - if (err) + link_parent = bpf_program__attach_cgroup(obj->progs._setsockopt, + cg_parent); + if (!ASSERT_OK_PTR(link_parent, "cg-attach-setsockopt_parent")) goto detach; buf = 0x80; @@ -289,8 +244,8 @@ static int run_setsockopt_test(struct bpf_object *obj, int cg_parent, } detach: - prog_detach(obj, cg_child, "cgroup/setsockopt", "_setsockopt"); - prog_detach(obj, cg_parent, "cgroup/setsockopt", "_setsockopt"); + bpf_link__destroy(link_child); + bpf_link__destroy(link_parent); return err; } @@ -298,9 +253,8 @@ detach: void test_sockopt_multi(void) { int cg_parent = -1, cg_child = -1; - struct bpf_object *obj = NULL; + struct sockopt_multi *obj = NULL; int sock_fd = -1; - int err = -1; cg_parent = test__join_cgroup("/parent"); if (!ASSERT_GE(cg_parent, 0, "join_cgroup /parent")) @@ -310,13 +264,11 @@ void test_sockopt_multi(void) if (!ASSERT_GE(cg_child, 0, "join_cgroup /parent/child")) goto out; - obj = bpf_object__open_file("sockopt_multi.bpf.o", NULL); - if (!ASSERT_OK_PTR(obj, "obj_load")) + obj = sockopt_multi__open_and_load(); + if (!ASSERT_OK_PTR(obj, "skel-load")) goto out; - err = bpf_object__load(obj); - if (!ASSERT_OK(err, "obj_load")) - goto out; + obj->bss->page_size = sysconf(_SC_PAGESIZE); sock_fd = socket(AF_INET, SOCK_STREAM, 0); if (!ASSERT_GE(sock_fd, 0, "socket")) @@ -327,7 +279,7 @@ void test_sockopt_multi(void) out: close(sock_fd); - bpf_object__close(obj); + sockopt_multi__destroy(obj); close(cg_child); close(cg_parent); } diff --git a/tools/testing/selftests/bpf/prog_tests/sockopt_qos_to_cc.c b/tools/testing/selftests/bpf/prog_tests/sockopt_qos_to_cc.c index 6b53b3cb8dad..6b2d300e9fd4 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockopt_qos_to_cc.c +++ b/tools/testing/selftests/bpf/prog_tests/sockopt_qos_to_cc.c @@ -42,6 +42,8 @@ void test_sockopt_qos_to_cc(void) if (!ASSERT_OK_PTR(skel, "skel")) goto done; + skel->bss->page_size = sysconf(_SC_PAGESIZE); + sock_fd = socket(AF_INET6, SOCK_STREAM, 0); if (!ASSERT_GE(sock_fd, 0, "v6 socket open")) goto done; diff --git a/tools/testing/selftests/bpf/progs/cgroup_getset_retval_getsockopt.c b/tools/testing/selftests/bpf/progs/cgroup_getset_retval_getsockopt.c index b2a409e6382a..932b8ecd4ae3 100644 --- a/tools/testing/selftests/bpf/progs/cgroup_getset_retval_getsockopt.c +++ b/tools/testing/selftests/bpf/progs/cgroup_getset_retval_getsockopt.c @@ -12,6 +12,7 @@ __u32 invocations = 0; __u32 assertion_error = 0; __u32 retval_value = 0; __u32 ctx_retval_value = 0; +__u32 page_size = 0; SEC("cgroup/getsockopt") int get_retval(struct bpf_sockopt *ctx) @@ -20,6 +21,10 @@ int get_retval(struct bpf_sockopt *ctx) ctx_retval_value = ctx->retval; __sync_fetch_and_add(&invocations, 1); + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } @@ -31,6 +36,10 @@ int set_eisconn(struct bpf_sockopt *ctx) if (bpf_set_retval(-EISCONN)) assertion_error = 1; + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } @@ -41,5 +50,9 @@ int clear_retval(struct bpf_sockopt *ctx) ctx->retval = 0; + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } diff --git a/tools/testing/selftests/bpf/progs/cgroup_getset_retval_setsockopt.c b/tools/testing/selftests/bpf/progs/cgroup_getset_retval_setsockopt.c index d6e5903e06ba..b7fa8804e19d 100644 --- a/tools/testing/selftests/bpf/progs/cgroup_getset_retval_setsockopt.c +++ b/tools/testing/selftests/bpf/progs/cgroup_getset_retval_setsockopt.c @@ -11,6 +11,7 @@ __u32 invocations = 0; __u32 assertion_error = 0; __u32 retval_value = 0; +__u32 page_size = 0; SEC("cgroup/setsockopt") int get_retval(struct bpf_sockopt *ctx) @@ -18,6 +19,10 @@ int get_retval(struct bpf_sockopt *ctx) retval_value = bpf_get_retval(); __sync_fetch_and_add(&invocations, 1); + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } @@ -29,6 +34,10 @@ int set_eunatch(struct bpf_sockopt *ctx) if (bpf_set_retval(-EUNATCH)) assertion_error = 1; + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 0; } @@ -40,6 +49,10 @@ int set_eisconn(struct bpf_sockopt *ctx) if (bpf_set_retval(-EISCONN)) assertion_error = 1; + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 0; } @@ -48,5 +61,9 @@ int legacy_eperm(struct bpf_sockopt *ctx) { __sync_fetch_and_add(&invocations, 1); + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 0; } diff --git a/tools/testing/selftests/bpf/progs/sockopt_inherit.c b/tools/testing/selftests/bpf/progs/sockopt_inherit.c index 9fb241b97291..c8f59caa4639 100644 --- a/tools/testing/selftests/bpf/progs/sockopt_inherit.c +++ b/tools/testing/selftests/bpf/progs/sockopt_inherit.c @@ -9,6 +9,8 @@ char _license[] SEC("license") = "GPL"; #define CUSTOM_INHERIT2 1 #define CUSTOM_LISTENER 2 +__u32 page_size = 0; + struct sockopt_inherit { __u8 val; }; @@ -55,7 +57,7 @@ int _getsockopt(struct bpf_sockopt *ctx) __u8 *optval = ctx->optval; if (ctx->level != SOL_CUSTOM) - return 1; /* only interested in SOL_CUSTOM */ + goto out; /* only interested in SOL_CUSTOM */ if (optval + 1 > optval_end) return 0; /* EPERM, bounds check */ @@ -70,6 +72,12 @@ int _getsockopt(struct bpf_sockopt *ctx) ctx->optlen = 1; return 1; + +out: + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } SEC("cgroup/setsockopt") @@ -80,7 +88,7 @@ int _setsockopt(struct bpf_sockopt *ctx) __u8 *optval = ctx->optval; if (ctx->level != SOL_CUSTOM) - return 1; /* only interested in SOL_CUSTOM */ + goto out; /* only interested in SOL_CUSTOM */ if (optval + 1 > optval_end) return 0; /* EPERM, bounds check */ @@ -93,4 +101,10 @@ int _setsockopt(struct bpf_sockopt *ctx) ctx->optlen = -1; return 1; + +out: + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } diff --git a/tools/testing/selftests/bpf/progs/sockopt_multi.c b/tools/testing/selftests/bpf/progs/sockopt_multi.c index 177a59069dae..96f29fce050b 100644 --- a/tools/testing/selftests/bpf/progs/sockopt_multi.c +++ b/tools/testing/selftests/bpf/progs/sockopt_multi.c @@ -5,6 +5,8 @@ char _license[] SEC("license") = "GPL"; +__u32 page_size = 0; + SEC("cgroup/getsockopt") int _getsockopt_child(struct bpf_sockopt *ctx) { @@ -12,7 +14,7 @@ int _getsockopt_child(struct bpf_sockopt *ctx) __u8 *optval = ctx->optval; if (ctx->level != SOL_IP || ctx->optname != IP_TOS) - return 1; + goto out; if (optval + 1 > optval_end) return 0; /* EPERM, bounds check */ @@ -26,6 +28,12 @@ int _getsockopt_child(struct bpf_sockopt *ctx) ctx->optlen = 1; return 1; + +out: + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } SEC("cgroup/getsockopt") @@ -35,7 +43,7 @@ int _getsockopt_parent(struct bpf_sockopt *ctx) __u8 *optval = ctx->optval; if (ctx->level != SOL_IP || ctx->optname != IP_TOS) - return 1; + goto out; if (optval + 1 > optval_end) return 0; /* EPERM, bounds check */ @@ -49,6 +57,12 @@ int _getsockopt_parent(struct bpf_sockopt *ctx) ctx->optlen = 1; return 1; + +out: + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } SEC("cgroup/setsockopt") @@ -58,7 +72,7 @@ int _setsockopt(struct bpf_sockopt *ctx) __u8 *optval = ctx->optval; if (ctx->level != SOL_IP || ctx->optname != IP_TOS) - return 1; + goto out; if (optval + 1 > optval_end) return 0; /* EPERM, bounds check */ @@ -67,4 +81,10 @@ int _setsockopt(struct bpf_sockopt *ctx) ctx->optlen = 1; return 1; + +out: + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } diff --git a/tools/testing/selftests/bpf/progs/sockopt_qos_to_cc.c b/tools/testing/selftests/bpf/progs/sockopt_qos_to_cc.c index 1bce83b6e3a7..dbe235ede7f3 100644 --- a/tools/testing/selftests/bpf/progs/sockopt_qos_to_cc.c +++ b/tools/testing/selftests/bpf/progs/sockopt_qos_to_cc.c @@ -9,6 +9,8 @@ char _license[] SEC("license") = "GPL"; +__u32 page_size = 0; + SEC("cgroup/setsockopt") int sockopt_qos_to_cc(struct bpf_sockopt *ctx) { @@ -19,7 +21,7 @@ int sockopt_qos_to_cc(struct bpf_sockopt *ctx) char cc_cubic[TCP_CA_NAME_MAX] = "cubic"; if (ctx->level != SOL_IPV6 || ctx->optname != IPV6_TCLASS) - return 1; + goto out; if (optval + 1 > optval_end) return 0; /* EPERM, bounds check */ @@ -36,4 +38,10 @@ int sockopt_qos_to_cc(struct bpf_sockopt *ctx) return 0; } return 1; + +out: + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } diff --git a/tools/testing/selftests/bpf/progs/sockopt_sk.c b/tools/testing/selftests/bpf/progs/sockopt_sk.c index fe1df4cd206e..cb990a7d3d45 100644 --- a/tools/testing/selftests/bpf/progs/sockopt_sk.c +++ b/tools/testing/selftests/bpf/progs/sockopt_sk.c @@ -37,7 +37,7 @@ int _getsockopt(struct bpf_sockopt *ctx) /* Bypass AF_NETLINK. */ sk = ctx->sk; if (sk && sk->family == AF_NETLINK) - return 1; + goto out; /* Make sure bpf_get_netns_cookie is callable. */ @@ -52,8 +52,7 @@ int _getsockopt(struct bpf_sockopt *ctx) * let next BPF program in the cgroup chain or kernel * handle it. */ - ctx->optlen = 0; /* bypass optval>PAGE_SIZE */ - return 1; + goto out; } if (ctx->level == SOL_SOCKET && ctx->optname == SO_SNDBUF) { @@ -61,7 +60,7 @@ int _getsockopt(struct bpf_sockopt *ctx) * let next BPF program in the cgroup chain or kernel * handle it. */ - return 1; + goto out; } if (ctx->level == SOL_TCP && ctx->optname == TCP_CONGESTION) { @@ -69,7 +68,7 @@ int _getsockopt(struct bpf_sockopt *ctx) * let next BPF program in the cgroup chain or kernel * handle it. */ - return 1; + goto out; } if (ctx->level == SOL_TCP && ctx->optname == TCP_ZEROCOPY_RECEIVE) { @@ -85,7 +84,7 @@ int _getsockopt(struct bpf_sockopt *ctx) if (((struct tcp_zerocopy_receive *)optval)->address != 0) return 0; /* unexpected data */ - return 1; + goto out; } if (ctx->level == SOL_IP && ctx->optname == IP_FREEBIND) { @@ -129,6 +128,12 @@ int _getsockopt(struct bpf_sockopt *ctx) ctx->optlen = 1; return 1; + +out: + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } SEC("cgroup/setsockopt") @@ -142,7 +147,7 @@ int _setsockopt(struct bpf_sockopt *ctx) /* Bypass AF_NETLINK. */ sk = ctx->sk; if (sk && sk->family == AF_NETLINK) - return 1; + goto out; /* Make sure bpf_get_netns_cookie is callable. */ @@ -224,4 +229,10 @@ int _setsockopt(struct bpf_sockopt *ctx) */ return 1; + +out: + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } -- cgit v1.2.3 From 90564f1e3dd66052af29e2c29cba3dc98b6604d0 Mon Sep 17 00:00:00 2001 From: Florent Revest Date: Thu, 11 May 2023 16:05:07 +0200 Subject: bpf, arm64: Support struct arguments in the BPF trampoline This extends the BPF trampoline JIT to support attachment to functions that take small structures (up to 128bit) as argument. This is trivially achieved by saving/restoring a number of "argument registers" rather than a number of arguments. The AAPCS64 section 6.8.2 describes the parameter passing ABI. "Composite types" (like C structs) below 16 bytes (as enforced by the BPF verifier) are provided as part of the 8 argument registers as explained in the section C.12. Signed-off-by: Florent Revest Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Acked-by: Xu Kuohai Link: https://lore.kernel.org/bpf/20230511140507.514888-1-revest@chromium.org --- arch/arm64/net/bpf_jit_comp.c | 55 ++++++++++++++-------------- tools/testing/selftests/bpf/DENYLIST.aarch64 | 1 - 2 files changed, 28 insertions(+), 28 deletions(-) (limited to 'tools/testing') diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index b26da8efa616..145b540ec34f 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -1731,21 +1731,21 @@ static void invoke_bpf_mod_ret(struct jit_ctx *ctx, struct bpf_tramp_links *tl, } } -static void save_args(struct jit_ctx *ctx, int args_off, int nargs) +static void save_args(struct jit_ctx *ctx, int args_off, int nregs) { int i; - for (i = 0; i < nargs; i++) { + for (i = 0; i < nregs; i++) { emit(A64_STR64I(i, A64_SP, args_off), ctx); args_off += 8; } } -static void restore_args(struct jit_ctx *ctx, int args_off, int nargs) +static void restore_args(struct jit_ctx *ctx, int args_off, int nregs) { int i; - for (i = 0; i < nargs; i++) { + for (i = 0; i < nregs; i++) { emit(A64_LDR64I(i, A64_SP, args_off), ctx); args_off += 8; } @@ -1764,7 +1764,7 @@ static void restore_args(struct jit_ctx *ctx, int args_off, int nargs) */ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, struct bpf_tramp_links *tlinks, void *orig_call, - int nargs, u32 flags) + int nregs, u32 flags) { int i; int stack_size; @@ -1772,7 +1772,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, int regs_off; int retval_off; int args_off; - int nargs_off; + int nregs_off; int ip_off; int run_ctx_off; struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY]; @@ -1795,11 +1795,11 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, * SP + retval_off [ return value ] BPF_TRAMP_F_CALL_ORIG or * BPF_TRAMP_F_RET_FENTRY_RET * - * [ argN ] + * [ arg reg N ] * [ ... ] - * SP + args_off [ arg1 ] + * SP + args_off [ arg reg 1 ] * - * SP + nargs_off [ args count ] + * SP + nregs_off [ arg regs count ] * * SP + ip_off [ traced function ] BPF_TRAMP_F_IP_ARG flag * @@ -1816,13 +1816,13 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, if (flags & BPF_TRAMP_F_IP_ARG) stack_size += 8; - nargs_off = stack_size; + nregs_off = stack_size; /* room for args count */ stack_size += 8; args_off = stack_size; /* room for args */ - stack_size += nargs * 8; + stack_size += nregs * 8; /* room for return value */ retval_off = stack_size; @@ -1865,12 +1865,12 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, emit(A64_STR64I(A64_R(10), A64_SP, ip_off), ctx); } - /* save args count*/ - emit(A64_MOVZ(1, A64_R(10), nargs, 0), ctx); - emit(A64_STR64I(A64_R(10), A64_SP, nargs_off), ctx); + /* save arg regs count*/ + emit(A64_MOVZ(1, A64_R(10), nregs, 0), ctx); + emit(A64_STR64I(A64_R(10), A64_SP, nregs_off), ctx); - /* save args */ - save_args(ctx, args_off, nargs); + /* save arg regs */ + save_args(ctx, args_off, nregs); /* save callee saved registers */ emit(A64_STR64I(A64_R(19), A64_SP, regs_off), ctx); @@ -1897,7 +1897,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, } if (flags & BPF_TRAMP_F_CALL_ORIG) { - restore_args(ctx, args_off, nargs); + restore_args(ctx, args_off, nregs); /* call original func */ emit(A64_LDR64I(A64_R(10), A64_SP, retaddr_off), ctx); emit(A64_ADR(A64_LR, AARCH64_INSN_SIZE * 2), ctx); @@ -1926,7 +1926,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, } if (flags & BPF_TRAMP_F_RESTORE_REGS) - restore_args(ctx, args_off, nargs); + restore_args(ctx, args_off, nregs); /* restore callee saved register x19 and x20 */ emit(A64_LDR64I(A64_R(19), A64_SP, regs_off), ctx); @@ -1967,24 +1967,25 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *orig_call) { int i, ret; - int nargs = m->nr_args; + int nregs = m->nr_args; int max_insns = ((long)image_end - (long)image) / AARCH64_INSN_SIZE; struct jit_ctx ctx = { .image = NULL, .idx = 0, }; - /* the first 8 arguments are passed by registers */ - if (nargs > 8) - return -ENOTSUPP; - - /* don't support struct argument */ + /* extra registers needed for struct argument */ for (i = 0; i < MAX_BPF_FUNC_ARGS; i++) { + /* The arg_size is at most 16 bytes, enforced by the verifier. */ if (m->arg_flags[i] & BTF_FMODEL_STRUCT_ARG) - return -ENOTSUPP; + nregs += (m->arg_size[i] + 7) / 8 - 1; } - ret = prepare_trampoline(&ctx, im, tlinks, orig_call, nargs, flags); + /* the first 8 registers are used for arguments */ + if (nregs > 8) + return -ENOTSUPP; + + ret = prepare_trampoline(&ctx, im, tlinks, orig_call, nregs, flags); if (ret < 0) return ret; @@ -1995,7 +1996,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, ctx.idx = 0; jit_fill_hole(image, (unsigned int)(image_end - image)); - ret = prepare_trampoline(&ctx, im, tlinks, orig_call, nargs, flags); + ret = prepare_trampoline(&ctx, im, tlinks, orig_call, nregs, flags); if (ret > 0 && validate_code(&ctx) < 0) ret = -EINVAL; diff --git a/tools/testing/selftests/bpf/DENYLIST.aarch64 b/tools/testing/selftests/bpf/DENYLIST.aarch64 index cd42e2825bd2..08adc805878b 100644 --- a/tools/testing/selftests/bpf/DENYLIST.aarch64 +++ b/tools/testing/selftests/bpf/DENYLIST.aarch64 @@ -10,4 +10,3 @@ kprobe_multi_test/link_api_addrs # link_fd unexpected link_fd: a kprobe_multi_test/link_api_syms # link_fd unexpected link_fd: actual -95 < expected 0 kprobe_multi_test/skel_api # libbpf: failed to load BPF skeleton 'kprobe_multi': -3 module_attach # prog 'kprobe_multi': failed to auto-attach: -95 -tracing_struct # tracing_struct__attach unexpected error: -524 (errno 524) -- cgit v1.2.3 From ce2544b2d05ee84cb9be1e05bf3e1a98c72b15dc Mon Sep 17 00:00:00 2001 From: Zhouyi Zhou Date: Sun, 26 Mar 2023 08:24:34 +0800 Subject: torture: Remove duplicated argument -enable-kvm for ppc64 The qemu argument -enable-kvm is duplicated because the qemu_args bash variable in kvm-test-1-run.sh already provides it. This commit therefore removes the ppc64-specific copy in functions.sh. Signed-off-by: Zhouyi Zhou Signed-off-by: Paul E. McKenney Reviewed-by: Joel Fernandes (Google) --- tools/testing/selftests/rcutorture/bin/functions.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh b/tools/testing/selftests/rcutorture/bin/functions.sh index b52d5069563c..48b9147e8c91 100644 --- a/tools/testing/selftests/rcutorture/bin/functions.sh +++ b/tools/testing/selftests/rcutorture/bin/functions.sh @@ -250,7 +250,7 @@ identify_qemu_args () { echo -machine virt,gic-version=host -cpu host ;; qemu-system-ppc64) - echo -enable-kvm -M pseries -nodefaults + echo -M pseries -nodefaults echo -device spapr-vscsi if test -n "$TORTURE_QEMU_INTERACTIVE" -a -n "$TORTURE_QEMU_MAC" then -- cgit v1.2.3 From 4d9060981f886ba881aa3e8de688433c1f1ed11f Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sun, 2 Apr 2023 19:56:34 -0700 Subject: kunit: tool: Enable CONFIG_FORTIFY_SOURCE under UML Since commit ba38961a069b ("um: Enable FORTIFY_SOURCE"), it's possible to run the FORTIFY tests under UML. Enable CONFIG_FORTIFY_SOURCE when running with --alltests to gain additional coverage, and by default under UML. Signed-off-by: Kees Cook --- tools/testing/kunit/configs/all_tests.config | 2 ++ tools/testing/kunit/configs/arch_uml.config | 3 +++ 2 files changed, 5 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/kunit/configs/all_tests.config b/tools/testing/kunit/configs/all_tests.config index f990cbb73250..0393940c706a 100644 --- a/tools/testing/kunit/configs/all_tests.config +++ b/tools/testing/kunit/configs/all_tests.config @@ -9,6 +9,8 @@ CONFIG_KUNIT=y CONFIG_KUNIT_EXAMPLE_TEST=y CONFIG_KUNIT_ALL_TESTS=y +CONFIG_FORTIFY_SOURCE=y + CONFIG_IIO=y CONFIG_EXT4_FS=y diff --git a/tools/testing/kunit/configs/arch_uml.config b/tools/testing/kunit/configs/arch_uml.config index e824ce43b05a..54ad8972681a 100644 --- a/tools/testing/kunit/configs/arch_uml.config +++ b/tools/testing/kunit/configs/arch_uml.config @@ -3,3 +3,6 @@ # Enable virtio/pci, as a lot of tests require it. CONFIG_VIRTIO_UML=y CONFIG_UML_PCI_OVER_VIRTIO=y + +# Enable FORTIFY_SOURCE for wider checking. +CONFIG_FORTIFY_SOURCE=y -- cgit v1.2.3 From 24a86d833bc5509ad34343dd6c649ea11ed1cad3 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 15 May 2023 13:48:33 -0700 Subject: selftests/bpf: improve netcnt test robustness Change netcnt to demand at least 10K packets, as we frequently see some stray packet arriving during the test in BPF CI. It seems more important to make sure we haven't lost any packet than enforcing exact number of packets. Cc: Stanislav Fomichev Signed-off-by: Andrii Nakryiko Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20230515204833.2832000-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/prog_tests/netcnt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/netcnt.c b/tools/testing/selftests/bpf/prog_tests/netcnt.c index d3915c58d0e1..c3333edd029f 100644 --- a/tools/testing/selftests/bpf/prog_tests/netcnt.c +++ b/tools/testing/selftests/bpf/prog_tests/netcnt.c @@ -67,12 +67,12 @@ void serial_test_netcnt(void) } /* No packets should be lost */ - ASSERT_EQ(packets, 10000, "packets"); + ASSERT_GE(packets, 10000, "packets"); /* Let's check that bytes counter matches the number of packets * multiplied by the size of ipv6 ICMP packet. */ - ASSERT_EQ(bytes, packets * 104, "bytes"); + ASSERT_GE(bytes, packets * 104, "bytes"); err: if (cg_fd != -1) -- cgit v1.2.3 From de58ef414d8d7a0a635cd331b3b013d8216c4e60 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 16 May 2023 14:49:45 -0700 Subject: selftests/bpf: Fix s390 sock_field test failure llvm patch [1] enabled cross-function optimization for func arguments (ArgumentPromotion) at -O2 level. And this caused s390 sock_fields test failure ([2]). The failure is gone right now as patch [1] was reverted in [3]. But it is possible that patch [3] will be reverted again and then the test failure in [2] will show up again. So it is desirable to fix the failure regardless. The following is an analysis why sock_field test fails with llvm patch [1]. The main problem is in static __noinline bool sk_dst_port__load_word(struct bpf_sock *sk) { __u32 *word = (__u32 *)&sk->dst_port; return word[0] == bpf_htons(0xcafe); } static __noinline bool sk_dst_port__load_half(struct bpf_sock *sk) { __u16 *half = (__u16 *)&sk->dst_port; return half[0] == bpf_htons(0xcafe); } ... int read_sk_dst_port(struct __sk_buff *skb) { ... sk = skb->sk; ... if (!sk_dst_port__load_word(sk)) RET_LOG(); if (!sk_dst_port__load_half(sk)) RET_LOG(); ... } Through some cross-function optimization by ArgumentPromotion optimization, the compiler does: static __noinline bool sk_dst_port__load_word(__u32 word_val) { return word_val == bpf_htons(0xcafe); } static __noinline bool sk_dst_port__load_half(__u16 half_val) { return half_val == bpf_htons(0xcafe); } ... int read_sk_dst_port(struct __sk_buff *skb) { ... sk = skb->sk; ... __u32 *word = (__u32 *)&sk->dst_port; __u32 word_val = word[0]; ... if (!sk_dst_port__load_word(word_val)) RET_LOG(); __u16 half_val = word_val >> 16; if (!sk_dst_port__load_half(half_val)) RET_LOG(); ... } In current uapi bpf.h, we have struct bpf_sock { ... __be16 dst_port; /* network byte order */ __u16 :16; /* zero padding */ ... }; But the old kernel (e.g., 5.6) we have struct bpf_sock { ... __u32 dst_port; /* network byte order */ ... }; So for backward compatability reason, 4-byte load of dst_port is converted to 2-byte load internally. Specifically, 'word_val = word[0]' is replaced by 2-byte load by the verifier and this caused the trouble for later sk_dst_port__load_half() where half_val becomes 0. Typical usr program won't have such a code pattern tiggering the above bug, so let us fix the test failure with source code change. Adding an empty asm volatile statement seems enough to prevent undesired transformation. [1] https://reviews.llvm.org/D148269 [2] https://lore.kernel.org/bpf/e7f2c5e8-a50c-198d-8f95-388165f1e4fd@meta.com/ [3] https://reviews.llvm.org/rG141be5c062ecf22bd287afffd310e8ac4711444a Tested-by: Ilya Leoshkevich Signed-off-by: Yonghong Song Link: https://lore.kernel.org/r/20230516214945.1013578-1-yhs@fb.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/progs/test_sock_fields.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/progs/test_sock_fields.c b/tools/testing/selftests/bpf/progs/test_sock_fields.c index bbad3c2d9aa5..f75e531bf36f 100644 --- a/tools/testing/selftests/bpf/progs/test_sock_fields.c +++ b/tools/testing/selftests/bpf/progs/test_sock_fields.c @@ -265,7 +265,10 @@ static __noinline bool sk_dst_port__load_word(struct bpf_sock *sk) static __noinline bool sk_dst_port__load_half(struct bpf_sock *sk) { - __u16 *half = (__u16 *)&sk->dst_port; + __u16 *half; + + asm volatile (""); + half = (__u16 *)&sk->dst_port; return half[0] == bpf_htons(0xcafe); } -- cgit v1.2.3 From 8e9af82171247e2a8d2c08a3dea709d03884a815 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 15 May 2023 15:37:48 +0200 Subject: selftests/bpf: Move kfunc exports to bpf_testmod/bpf_testmod_kfunc.h Move all kfunc exports into separate bpf_testmod_kfunc.h header file and include it in tests that need it. We will move all test kfuncs into bpf_testmod in following change, so it's convenient to have declarations in single place. The bpf_testmod_kfunc.h is included by both bpf_testmod and bpf programs that use test kfuncs. As suggested by David, the bpf_testmod_kfunc.h includes vmlinux.h and bpf/bpf_helpers.h for bpf programs build, so the declarations have proper __ksym attribute and we can resolve all the structs. Note in kfunc_call_test_subprog.c we can no longer use the sk_state define from bpf_tcp_helpers.h (because it clashed with vmlinux.h) and we need to address __sk_common.skc_state field directly. Acked-by: David Vernet Signed-off-by: Jiri Olsa Link: https://lore.kernel.org/r/20230515133756.1658301-3-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h | 40 ++++++++++++++++++++++ tools/testing/selftests/bpf/progs/cb_refs.c | 4 +-- tools/testing/selftests/bpf/progs/jit_probe_mem.c | 4 +-- .../selftests/bpf/progs/kfunc_call_destructive.c | 3 +- .../testing/selftests/bpf/progs/kfunc_call_fail.c | 9 +---- .../testing/selftests/bpf/progs/kfunc_call_race.c | 3 +- .../testing/selftests/bpf/progs/kfunc_call_test.c | 17 +-------- .../selftests/bpf/progs/kfunc_call_test_subprog.c | 9 ++--- .../testing/selftests/bpf/progs/local_kptr_stash.c | 5 ++- tools/testing/selftests/bpf/progs/map_kptr.c | 5 +-- tools/testing/selftests/bpf/progs/map_kptr_fail.c | 4 +-- 11 files changed, 52 insertions(+), 51 deletions(-) create mode 100644 tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h new file mode 100644 index 000000000000..f0755135061d --- /dev/null +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _BPF_TESTMOD_KFUNC_H +#define _BPF_TESTMOD_KFUNC_H + +#ifndef __KERNEL__ +#include +#include +#else +#define __ksym +#endif + +extern struct prog_test_ref_kfunc * +bpf_kfunc_call_test_acquire(unsigned long *scalar_ptr) __ksym; +extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; +void bpf_kfunc_call_test_ref(struct prog_test_ref_kfunc *p) __ksym; + +extern void bpf_kfunc_call_test_mem_len_pass1(void *mem, int len) __ksym; +extern int *bpf_kfunc_call_test_get_rdwr_mem(struct prog_test_ref_kfunc *p, const int rdwr_buf_size) __ksym; +extern int *bpf_kfunc_call_test_get_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; +extern int *bpf_kfunc_call_test_acq_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; +extern void bpf_kfunc_call_int_mem_release(int *p) __ksym; +extern u32 bpf_kfunc_call_test_static_unused_arg(u32 arg, u32 unused) __ksym; + +extern void bpf_testmod_test_mod_kfunc(int i) __ksym; + +extern __u64 bpf_kfunc_call_test1(struct sock *sk, __u32 a, __u64 b, + __u32 c, __u64 d) __ksym; +extern int bpf_kfunc_call_test2(struct sock *sk, __u32 a, __u32 b) __ksym; +extern struct sock *bpf_kfunc_call_test3(struct sock *sk) __ksym; +extern long bpf_kfunc_call_test4(signed char a, short b, int c, long d) __ksym; + +extern void bpf_kfunc_call_test_pass_ctx(struct __sk_buff *skb) __ksym; +extern void bpf_kfunc_call_test_pass1(struct prog_test_pass1 *p) __ksym; +extern void bpf_kfunc_call_test_pass2(struct prog_test_pass2 *p) __ksym; +extern void bpf_kfunc_call_test_mem_len_fail2(__u64 *mem, int len) __ksym; + +extern void bpf_kfunc_call_test_destructive(void) __ksym; + +#endif /* _BPF_TESTMOD_KFUNC_H */ diff --git a/tools/testing/selftests/bpf/progs/cb_refs.c b/tools/testing/selftests/bpf/progs/cb_refs.c index 50f95ec61165..76d661b20e87 100644 --- a/tools/testing/selftests/bpf/progs/cb_refs.c +++ b/tools/testing/selftests/bpf/progs/cb_refs.c @@ -2,6 +2,7 @@ #include #include #include +#include "../bpf_testmod/bpf_testmod_kfunc.h" struct map_value { struct prog_test_ref_kfunc __kptr *ptr; @@ -14,9 +15,6 @@ struct { __uint(max_entries, 16); } array_map SEC(".maps"); -extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym; -extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; - static __noinline int cb1(void *map, void *key, void *value, void *ctx) { void *p = *(void **)ctx; diff --git a/tools/testing/selftests/bpf/progs/jit_probe_mem.c b/tools/testing/selftests/bpf/progs/jit_probe_mem.c index 13f00ca2ed0a..f9789e668297 100644 --- a/tools/testing/selftests/bpf/progs/jit_probe_mem.c +++ b/tools/testing/selftests/bpf/progs/jit_probe_mem.c @@ -3,13 +3,11 @@ #include #include #include +#include "../bpf_testmod/bpf_testmod_kfunc.h" static struct prog_test_ref_kfunc __kptr *v; long total_sum = -1; -extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym; -extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; - SEC("tc") int test_jit_probe_mem(struct __sk_buff *ctx) { diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_destructive.c b/tools/testing/selftests/bpf/progs/kfunc_call_destructive.c index 767472bc5a97..7632d9ecb253 100644 --- a/tools/testing/selftests/bpf/progs/kfunc_call_destructive.c +++ b/tools/testing/selftests/bpf/progs/kfunc_call_destructive.c @@ -1,8 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include #include - -extern void bpf_kfunc_call_test_destructive(void) __ksym; +#include "../bpf_testmod/bpf_testmod_kfunc.h" SEC("tc") int kfunc_destructive_test(void) diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_fail.c b/tools/testing/selftests/bpf/progs/kfunc_call_fail.c index b98313d391c6..4b0b7b79cdfb 100644 --- a/tools/testing/selftests/bpf/progs/kfunc_call_fail.c +++ b/tools/testing/selftests/bpf/progs/kfunc_call_fail.c @@ -2,14 +2,7 @@ /* Copyright (c) 2021 Facebook */ #include #include - -extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym; -extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; -extern void bpf_kfunc_call_test_mem_len_pass1(void *mem, int len) __ksym; -extern int *bpf_kfunc_call_test_get_rdwr_mem(struct prog_test_ref_kfunc *p, const int rdwr_buf_size) __ksym; -extern int *bpf_kfunc_call_test_get_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; -extern int *bpf_kfunc_call_test_acq_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; -extern void bpf_kfunc_call_int_mem_release(int *p) __ksym; +#include "../bpf_testmod/bpf_testmod_kfunc.h" struct syscall_test_args { __u8 data[16]; diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_race.c b/tools/testing/selftests/bpf/progs/kfunc_call_race.c index 4e8fed75a4e0..d532af07decf 100644 --- a/tools/testing/selftests/bpf/progs/kfunc_call_race.c +++ b/tools/testing/selftests/bpf/progs/kfunc_call_race.c @@ -1,8 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include #include - -extern void bpf_testmod_test_mod_kfunc(int i) __ksym; +#include "../bpf_testmod/bpf_testmod_kfunc.h" SEC("tc") int kfunc_call_fail(struct __sk_buff *ctx) diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_test.c b/tools/testing/selftests/bpf/progs/kfunc_call_test.c index 7daa8f5720b9..cf68d1e48a0f 100644 --- a/tools/testing/selftests/bpf/progs/kfunc_call_test.c +++ b/tools/testing/selftests/bpf/progs/kfunc_call_test.c @@ -2,22 +2,7 @@ /* Copyright (c) 2021 Facebook */ #include #include - -extern long bpf_kfunc_call_test4(signed char a, short b, int c, long d) __ksym; -extern int bpf_kfunc_call_test2(struct sock *sk, __u32 a, __u32 b) __ksym; -extern __u64 bpf_kfunc_call_test1(struct sock *sk, __u32 a, __u64 b, - __u32 c, __u64 d) __ksym; - -extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym; -extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; -extern void bpf_kfunc_call_test_pass_ctx(struct __sk_buff *skb) __ksym; -extern void bpf_kfunc_call_test_pass1(struct prog_test_pass1 *p) __ksym; -extern void bpf_kfunc_call_test_pass2(struct prog_test_pass2 *p) __ksym; -extern void bpf_kfunc_call_test_mem_len_pass1(void *mem, int len) __ksym; -extern void bpf_kfunc_call_test_mem_len_fail2(__u64 *mem, int len) __ksym; -extern int *bpf_kfunc_call_test_get_rdwr_mem(struct prog_test_ref_kfunc *p, const int rdwr_buf_size) __ksym; -extern int *bpf_kfunc_call_test_get_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; -extern u32 bpf_kfunc_call_test_static_unused_arg(u32 arg, u32 unused) __ksym; +#include "../bpf_testmod/bpf_testmod_kfunc.h" SEC("tc") int kfunc_call_test4(struct __sk_buff *skb) diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_test_subprog.c b/tools/testing/selftests/bpf/progs/kfunc_call_test_subprog.c index c1fdecabeabf..2380c75e74ce 100644 --- a/tools/testing/selftests/bpf/progs/kfunc_call_test_subprog.c +++ b/tools/testing/selftests/bpf/progs/kfunc_call_test_subprog.c @@ -1,13 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2021 Facebook */ -#include -#include -#include "bpf_tcp_helpers.h" +#include "../bpf_testmod/bpf_testmod_kfunc.h" extern const int bpf_prog_active __ksym; -extern __u64 bpf_kfunc_call_test1(struct sock *sk, __u32 a, __u64 b, - __u32 c, __u64 d) __ksym; -extern struct sock *bpf_kfunc_call_test3(struct sock *sk) __ksym; int active_res = -1; int sk_state_res = -1; @@ -28,7 +23,7 @@ int __noinline f1(struct __sk_buff *skb) if (active) active_res = *active; - sk_state_res = bpf_kfunc_call_test3((struct sock *)sk)->sk_state; + sk_state_res = bpf_kfunc_call_test3((struct sock *)sk)->__sk_common.skc_state; return (__u32)bpf_kfunc_call_test1((struct sock *)sk, 1, 2, 3, 4); } diff --git a/tools/testing/selftests/bpf/progs/local_kptr_stash.c b/tools/testing/selftests/bpf/progs/local_kptr_stash.c index 0ef286da092b..06838083079c 100644 --- a/tools/testing/selftests/bpf/progs/local_kptr_stash.c +++ b/tools/testing/selftests/bpf/progs/local_kptr_stash.c @@ -5,7 +5,8 @@ #include #include #include -#include "bpf_experimental.h" +#include "../bpf_experimental.h" +#include "../bpf_testmod/bpf_testmod_kfunc.h" struct node_data { long key; @@ -32,8 +33,6 @@ struct map_value { */ struct node_data *just_here_because_btf_bug; -extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; - struct { __uint(type, BPF_MAP_TYPE_ARRAY); __type(key, int); diff --git a/tools/testing/selftests/bpf/progs/map_kptr.c b/tools/testing/selftests/bpf/progs/map_kptr.c index d7150041e5d1..da30f0d59364 100644 --- a/tools/testing/selftests/bpf/progs/map_kptr.c +++ b/tools/testing/selftests/bpf/progs/map_kptr.c @@ -2,6 +2,7 @@ #include #include #include +#include "../bpf_testmod/bpf_testmod_kfunc.h" struct map_value { struct prog_test_ref_kfunc __kptr_untrusted *unref_ptr; @@ -114,10 +115,6 @@ DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_HASH_OF_MAPS, hash_map, hash_of_hash_maps); DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_HASH_OF_MAPS, hash_malloc_map, hash_of_hash_malloc_maps); DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_HASH_OF_MAPS, lru_hash_map, hash_of_lru_hash_maps); -extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym; -extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; -void bpf_kfunc_call_test_ref(struct prog_test_ref_kfunc *p) __ksym; - #define WRITE_ONCE(x, val) ((*(volatile typeof(x) *) &(x)) = (val)) static void test_kptr_unref(struct map_value *v) diff --git a/tools/testing/selftests/bpf/progs/map_kptr_fail.c b/tools/testing/selftests/bpf/progs/map_kptr_fail.c index da8c724f839b..450bb373b179 100644 --- a/tools/testing/selftests/bpf/progs/map_kptr_fail.c +++ b/tools/testing/selftests/bpf/progs/map_kptr_fail.c @@ -4,6 +4,7 @@ #include #include #include "bpf_misc.h" +#include "../bpf_testmod/bpf_testmod_kfunc.h" struct map_value { char buf[8]; @@ -19,9 +20,6 @@ struct array_map { __uint(max_entries, 1); } array_map SEC(".maps"); -extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym; -extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; - SEC("?tc") __failure __msg("kptr access size must be BPF_DW") int size_not_bpf_dw(struct __sk_buff *ctx) -- cgit v1.2.3 From 45db310984bfea977177fb5fc0ea23ab430129bd Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 15 May 2023 15:37:49 +0200 Subject: selftests/bpf: Move test_progs helpers to testing_helpers object Moving test_progs helpers to testing_helpers object so they can be used from test_verifier in following changes. Also adding missing ifndef header guard to testing_helpers.h header. Using stderr instead of env.stderr because un/load_bpf_testmod helpers will be used outside test_progs. Also at the point of calling them in test_progs the std files are not hijacked yet and stderr is the same as env.stderr. Acked-by: David Vernet Signed-off-by: Jiri Olsa Link: https://lore.kernel.org/r/20230515133756.1658301-4-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_progs.c | 67 +-------------------------- tools/testing/selftests/bpf/test_progs.h | 1 - tools/testing/selftests/bpf/testing_helpers.c | 63 +++++++++++++++++++++++++ tools/testing/selftests/bpf/testing_helpers.h | 9 ++++ 4 files changed, 74 insertions(+), 66 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index 793689dcc170..cebe62d29f8d 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -11,7 +11,6 @@ #include #include #include /* backtrace */ -#include #include /* get_nprocs */ #include #include @@ -629,68 +628,6 @@ out: return err; } -static int finit_module(int fd, const char *param_values, int flags) -{ - return syscall(__NR_finit_module, fd, param_values, flags); -} - -static int delete_module(const char *name, int flags) -{ - return syscall(__NR_delete_module, name, flags); -} - -/* - * Trigger synchronize_rcu() in kernel. - */ -int kern_sync_rcu(void) -{ - return syscall(__NR_membarrier, MEMBARRIER_CMD_SHARED, 0, 0); -} - -static void unload_bpf_testmod(void) -{ - if (kern_sync_rcu()) - fprintf(env.stderr, "Failed to trigger kernel-side RCU sync!\n"); - if (delete_module("bpf_testmod", 0)) { - if (errno == ENOENT) { - if (verbose()) - fprintf(stdout, "bpf_testmod.ko is already unloaded.\n"); - return; - } - fprintf(env.stderr, "Failed to unload bpf_testmod.ko from kernel: %d\n", -errno); - return; - } - if (verbose()) - fprintf(stdout, "Successfully unloaded bpf_testmod.ko.\n"); -} - -static int load_bpf_testmod(void) -{ - int fd; - - /* ensure previous instance of the module is unloaded */ - unload_bpf_testmod(); - - if (verbose()) - fprintf(stdout, "Loading bpf_testmod.ko...\n"); - - fd = open("bpf_testmod.ko", O_RDONLY); - if (fd < 0) { - fprintf(env.stderr, "Can't find bpf_testmod.ko kernel module: %d\n", -errno); - return -ENOENT; - } - if (finit_module(fd, "", 0)) { - fprintf(env.stderr, "Failed to load bpf_testmod.ko into the kernel: %d\n", -errno); - close(fd); - return -EINVAL; - } - close(fd); - - if (verbose()) - fprintf(stdout, "Successfully loaded bpf_testmod.ko.\n"); - return 0; -} - /* extern declarations for test funcs */ #define DEFINE_TEST(name) \ extern void test_##name(void) __weak; \ @@ -1720,7 +1657,7 @@ int main(int argc, char **argv) env.stderr = stderr; env.has_testmod = true; - if (!env.list_test_names && load_bpf_testmod()) { + if (!env.list_test_names && load_bpf_testmod(verbose())) { fprintf(env.stderr, "WARNING! Selftests relying on bpf_testmod.ko will be skipped.\n"); env.has_testmod = false; } @@ -1819,7 +1756,7 @@ int main(int argc, char **argv) close(env.saved_netns_fd); out: if (!env.list_test_names && env.has_testmod) - unload_bpf_testmod(); + unload_bpf_testmod(verbose()); free_test_selector(&env.test_selector); free_test_selector(&env.subtest_selector); diff --git a/tools/testing/selftests/bpf/test_progs.h b/tools/testing/selftests/bpf/test_progs.h index 0ed3134333d4..77bd492c6024 100644 --- a/tools/testing/selftests/bpf/test_progs.h +++ b/tools/testing/selftests/bpf/test_progs.h @@ -405,7 +405,6 @@ static inline void *u64_to_ptr(__u64 ptr) int bpf_find_map(const char *test, struct bpf_object *obj, const char *name); int compare_map_keys(int map1_fd, int map2_fd); int compare_stack_ips(int smap_fd, int amap_fd, int stack_trace_len); -int kern_sync_rcu(void); int trigger_module_test_read(int read_sz); int trigger_module_test_write(int write_sz); int write_sysctl(const char *sysctl, const char *value); diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c index dc9595ade8de..648c7d3eb319 100644 --- a/tools/testing/selftests/bpf/testing_helpers.c +++ b/tools/testing/selftests/bpf/testing_helpers.c @@ -9,6 +9,7 @@ #include #include "test_progs.h" #include "testing_helpers.h" +#include int parse_num_list(const char *s, bool **num_set, int *num_set_len) { @@ -326,3 +327,65 @@ __u64 read_perf_max_sample_freq(void) fclose(f); return sample_freq; } + +static int finit_module(int fd, const char *param_values, int flags) +{ + return syscall(__NR_finit_module, fd, param_values, flags); +} + +static int delete_module(const char *name, int flags) +{ + return syscall(__NR_delete_module, name, flags); +} + +void unload_bpf_testmod(bool verbose) +{ + if (kern_sync_rcu()) + fprintf(stderr, "Failed to trigger kernel-side RCU sync!\n"); + if (delete_module("bpf_testmod", 0)) { + if (errno == ENOENT) { + if (verbose) + fprintf(stdout, "bpf_testmod.ko is already unloaded.\n"); + return; + } + fprintf(stderr, "Failed to unload bpf_testmod.ko from kernel: %d\n", -errno); + return; + } + if (verbose) + fprintf(stdout, "Successfully unloaded bpf_testmod.ko.\n"); +} + +int load_bpf_testmod(bool verbose) +{ + int fd; + + /* ensure previous instance of the module is unloaded */ + unload_bpf_testmod(verbose); + + if (verbose) + fprintf(stdout, "Loading bpf_testmod.ko...\n"); + + fd = open("bpf_testmod.ko", O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Can't find bpf_testmod.ko kernel module: %d\n", -errno); + return -ENOENT; + } + if (finit_module(fd, "", 0)) { + fprintf(stderr, "Failed to load bpf_testmod.ko into the kernel: %d\n", -errno); + close(fd); + return -EINVAL; + } + close(fd); + + if (verbose) + fprintf(stdout, "Successfully loaded bpf_testmod.ko.\n"); + return 0; +} + +/* + * Trigger synchronize_rcu() in kernel. + */ +int kern_sync_rcu(void) +{ + return syscall(__NR_membarrier, MEMBARRIER_CMD_SHARED, 0, 0); +} diff --git a/tools/testing/selftests/bpf/testing_helpers.h b/tools/testing/selftests/bpf/testing_helpers.h index 98f09bbae86f..02e8c4efd028 100644 --- a/tools/testing/selftests/bpf/testing_helpers.h +++ b/tools/testing/selftests/bpf/testing_helpers.h @@ -1,5 +1,9 @@ /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ /* Copyright (C) 2020 Facebook, Inc. */ + +#ifndef __TESTING_HELPERS_H +#define __TESTING_HELPERS_H + #include #include #include @@ -25,3 +29,8 @@ int parse_test_list_file(const char *path, bool is_glob_pattern); __u64 read_perf_max_sample_freq(void); +int load_bpf_testmod(bool verbose); +void unload_bpf_testmod(bool verbose); +int kern_sync_rcu(void); + +#endif /* __TESTING_HELPERS_H */ -- cgit v1.2.3 From d18decca69e36480247a73086336f4a44a08e36f Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 15 May 2023 15:37:50 +0200 Subject: selftests/bpf: Use only stdout in un/load_bpf_testmod functions We are about to use un/load_bpf_testmod functions in couple tests and it's better to print output to stdout, so it's aligned with tests ASSERT macros output, which use stdout as well. Acked-by: David Vernet Signed-off-by: Jiri Olsa Link: https://lore.kernel.org/r/20230515133756.1658301-5-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/testing_helpers.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c index 648c7d3eb319..f73bc88f3eb6 100644 --- a/tools/testing/selftests/bpf/testing_helpers.c +++ b/tools/testing/selftests/bpf/testing_helpers.c @@ -341,14 +341,14 @@ static int delete_module(const char *name, int flags) void unload_bpf_testmod(bool verbose) { if (kern_sync_rcu()) - fprintf(stderr, "Failed to trigger kernel-side RCU sync!\n"); + fprintf(stdout, "Failed to trigger kernel-side RCU sync!\n"); if (delete_module("bpf_testmod", 0)) { if (errno == ENOENT) { if (verbose) fprintf(stdout, "bpf_testmod.ko is already unloaded.\n"); return; } - fprintf(stderr, "Failed to unload bpf_testmod.ko from kernel: %d\n", -errno); + fprintf(stdout, "Failed to unload bpf_testmod.ko from kernel: %d\n", -errno); return; } if (verbose) @@ -367,11 +367,11 @@ int load_bpf_testmod(bool verbose) fd = open("bpf_testmod.ko", O_RDONLY); if (fd < 0) { - fprintf(stderr, "Can't find bpf_testmod.ko kernel module: %d\n", -errno); + fprintf(stdout, "Can't find bpf_testmod.ko kernel module: %d\n", -errno); return -ENOENT; } if (finit_module(fd, "", 0)) { - fprintf(stderr, "Failed to load bpf_testmod.ko into the kernel: %d\n", -errno); + fprintf(stdout, "Failed to load bpf_testmod.ko into the kernel: %d\n", -errno); close(fd); return -EINVAL; } -- cgit v1.2.3 From b58f3f0e6f3cbea56be39d8fb190b37f049505bb Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 15 May 2023 15:37:51 +0200 Subject: selftests/bpf: Do not unload bpf_testmod in load_bpf_testmod Do not unload bpf_testmod in load_bpf_testmod, instead call unload_bpf_testmod separatelly. This way we will be able use un/load_bpf_testmod functions in other tests that un/load bpf_testmod module. Acked-by: David Vernet Signed-off-by: Jiri Olsa Link: https://lore.kernel.org/r/20230515133756.1658301-6-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_progs.c | 11 ++++++++--- tools/testing/selftests/bpf/testing_helpers.c | 3 --- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index cebe62d29f8d..4d582cac2c09 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -1657,9 +1657,14 @@ int main(int argc, char **argv) env.stderr = stderr; env.has_testmod = true; - if (!env.list_test_names && load_bpf_testmod(verbose())) { - fprintf(env.stderr, "WARNING! Selftests relying on bpf_testmod.ko will be skipped.\n"); - env.has_testmod = false; + if (!env.list_test_names) { + /* ensure previous instance of the module is unloaded */ + unload_bpf_testmod(verbose()); + + if (load_bpf_testmod(verbose())) { + fprintf(env.stderr, "WARNING! Selftests relying on bpf_testmod.ko will be skipped.\n"); + env.has_testmod = false; + } } /* initializing tests */ diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c index f73bc88f3eb6..e01d7a62306c 100644 --- a/tools/testing/selftests/bpf/testing_helpers.c +++ b/tools/testing/selftests/bpf/testing_helpers.c @@ -359,9 +359,6 @@ int load_bpf_testmod(bool verbose) { int fd; - /* ensure previous instance of the module is unloaded */ - unload_bpf_testmod(verbose); - if (verbose) fprintf(stdout, "Loading bpf_testmod.ko...\n"); -- cgit v1.2.3 From 11642eb92b3bc67171b23abff0d062758c5a4730 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 15 May 2023 15:37:52 +0200 Subject: selftests/bpf: Use un/load_bpf_testmod functions in tests Now that we have un/load_bpf_testmod helpers in testing_helpers.h, we can use it in other tests and save some lines. Acked-by: David Vernet Signed-off-by: Jiri Olsa Link: https://lore.kernel.org/r/20230515133756.1658301-7-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/bpf_mod_race.c | 34 ++++------------------ .../selftests/bpf/prog_tests/module_attach.c | 12 +++----- tools/testing/selftests/bpf/testing_helpers.c | 7 +++-- tools/testing/selftests/bpf/testing_helpers.h | 2 +- 4 files changed, 14 insertions(+), 41 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_mod_race.c b/tools/testing/selftests/bpf/prog_tests/bpf_mod_race.c index a4d0cc9d3367..fe2c502e5089 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_mod_race.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_mod_race.c @@ -11,6 +11,7 @@ #include "ksym_race.skel.h" #include "bpf_mod_race.skel.h" #include "kfunc_call_race.skel.h" +#include "testing_helpers.h" /* This test crafts a race between btf_try_get_module and do_init_module, and * checks whether btf_try_get_module handles the invocation for a well-formed @@ -44,35 +45,10 @@ enum bpf_test_state { static _Atomic enum bpf_test_state state = _TS_INVALID; -static int sys_finit_module(int fd, const char *param_values, int flags) -{ - return syscall(__NR_finit_module, fd, param_values, flags); -} - -static int sys_delete_module(const char *name, unsigned int flags) -{ - return syscall(__NR_delete_module, name, flags); -} - -static int load_module(const char *mod) -{ - int ret, fd; - - fd = open("bpf_testmod.ko", O_RDONLY); - if (fd < 0) - return fd; - - ret = sys_finit_module(fd, "", 0); - close(fd); - if (ret < 0) - return ret; - return 0; -} - static void *load_module_thread(void *p) { - if (!ASSERT_NEQ(load_module("bpf_testmod.ko"), 0, "load_module_thread must fail")) + if (!ASSERT_NEQ(load_bpf_testmod(false), 0, "load_module_thread must fail")) atomic_store(&state, TS_MODULE_LOAD); else atomic_store(&state, TS_MODULE_LOAD_FAIL); @@ -124,7 +100,7 @@ static void test_bpf_mod_race_config(const struct test_config *config) if (!ASSERT_NEQ(fault_addr, MAP_FAILED, "mmap for uffd registration")) return; - if (!ASSERT_OK(sys_delete_module("bpf_testmod", 0), "unload bpf_testmod")) + if (!ASSERT_OK(unload_bpf_testmod(false), "unload bpf_testmod")) goto end_mmap; skel = bpf_mod_race__open(); @@ -202,8 +178,8 @@ end_destroy: bpf_mod_race__destroy(skel); ASSERT_OK(kern_sync_rcu(), "kern_sync_rcu"); end_module: - sys_delete_module("bpf_testmod", 0); - ASSERT_OK(load_module("bpf_testmod.ko"), "restore bpf_testmod"); + unload_bpf_testmod(false); + ASSERT_OK(load_bpf_testmod(false), "restore bpf_testmod"); end_mmap: munmap(fault_addr, 4096); atomic_store(&state, _TS_INVALID); diff --git a/tools/testing/selftests/bpf/prog_tests/module_attach.c b/tools/testing/selftests/bpf/prog_tests/module_attach.c index 7fc01ff490db..f53d658ed080 100644 --- a/tools/testing/selftests/bpf/prog_tests/module_attach.c +++ b/tools/testing/selftests/bpf/prog_tests/module_attach.c @@ -4,6 +4,7 @@ #include #include #include "test_module_attach.skel.h" +#include "testing_helpers.h" static int duration; @@ -32,11 +33,6 @@ static int trigger_module_test_writable(int *val) return 0; } -static int delete_module(const char *name, int flags) -{ - return syscall(__NR_delete_module, name, flags); -} - void test_module_attach(void) { const int READ_SZ = 456; @@ -93,21 +89,21 @@ void test_module_attach(void) if (!ASSERT_OK_PTR(link, "attach_fentry")) goto cleanup; - ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); + ASSERT_ERR(unload_bpf_testmod(false), "unload_bpf_testmod"); bpf_link__destroy(link); link = bpf_program__attach(skel->progs.handle_fexit); if (!ASSERT_OK_PTR(link, "attach_fexit")) goto cleanup; - ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); + ASSERT_ERR(unload_bpf_testmod(false), "unload_bpf_testmod"); bpf_link__destroy(link); link = bpf_program__attach(skel->progs.kprobe_multi); if (!ASSERT_OK_PTR(link, "attach_kprobe_multi")) goto cleanup; - ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); + ASSERT_ERR(unload_bpf_testmod(false), "unload_bpf_testmod"); bpf_link__destroy(link); cleanup: diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c index e01d7a62306c..8d994884c7b4 100644 --- a/tools/testing/selftests/bpf/testing_helpers.c +++ b/tools/testing/selftests/bpf/testing_helpers.c @@ -338,7 +338,7 @@ static int delete_module(const char *name, int flags) return syscall(__NR_delete_module, name, flags); } -void unload_bpf_testmod(bool verbose) +int unload_bpf_testmod(bool verbose) { if (kern_sync_rcu()) fprintf(stdout, "Failed to trigger kernel-side RCU sync!\n"); @@ -346,13 +346,14 @@ void unload_bpf_testmod(bool verbose) if (errno == ENOENT) { if (verbose) fprintf(stdout, "bpf_testmod.ko is already unloaded.\n"); - return; + return -1; } fprintf(stdout, "Failed to unload bpf_testmod.ko from kernel: %d\n", -errno); - return; + return -1; } if (verbose) fprintf(stdout, "Successfully unloaded bpf_testmod.ko.\n"); + return 0; } int load_bpf_testmod(bool verbose) diff --git a/tools/testing/selftests/bpf/testing_helpers.h b/tools/testing/selftests/bpf/testing_helpers.h index 02e8c4efd028..5312323881b6 100644 --- a/tools/testing/selftests/bpf/testing_helpers.h +++ b/tools/testing/selftests/bpf/testing_helpers.h @@ -30,7 +30,7 @@ int parse_test_list_file(const char *path, __u64 read_perf_max_sample_freq(void); int load_bpf_testmod(bool verbose); -void unload_bpf_testmod(bool verbose); +int unload_bpf_testmod(bool verbose); int kern_sync_rcu(void); #endif /* __TESTING_HELPERS_H */ -- cgit v1.2.3 From b23b385fa18f2196872bc3337c98ddd221c2827b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 15 May 2023 15:37:53 +0200 Subject: selftests/bpf: Load bpf_testmod for verifier test Loading bpf_testmod kernel module for verifier test. We will move all the tests kfuncs into bpf_testmod in following change. Acked-by: David Vernet Signed-off-by: Jiri Olsa Link: https://lore.kernel.org/r/20230515133756.1658301-8-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_verifier.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index e4657c5bc3f1..285ea4aba194 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -40,6 +40,7 @@ #include "bpf_util.h" #include "test_btf.h" #include "../../../include/linux/filter.h" +#include "testing_helpers.h" #ifndef ENOTSUPP #define ENOTSUPP 524 @@ -1684,6 +1685,12 @@ static int do_test(bool unpriv, unsigned int from, unsigned int to) { int i, passes = 0, errors = 0; + /* ensure previous instance of the module is unloaded */ + unload_bpf_testmod(verbose); + + if (load_bpf_testmod(verbose)) + return EXIT_FAILURE; + for (i = from; i < to; i++) { struct bpf_test *test = &tests[i]; @@ -1711,6 +1718,8 @@ static int do_test(bool unpriv, unsigned int from, unsigned int to) } } + unload_bpf_testmod(verbose); + printf("Summary: %d PASSED, %d SKIPPED, %d FAILED\n", passes, skips, errors); return errors ? EXIT_FAILURE : EXIT_SUCCESS; -- cgit v1.2.3 From f26ebdd3e4e4e1f5f08522b087ab9ec7216e9a3b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 15 May 2023 15:37:54 +0200 Subject: selftests/bpf: Allow to use kfunc from testmod.ko in test_verifier Currently the test_verifier allows test to specify kfunc symbol and search for it in the kernel BTF. Adding the possibility to search for kfunc also in bpf_testmod module when it's not found in kernel BTF. To find bpf_testmod btf we need to get back SYS_ADMIN cap. Acked-by: David Vernet Signed-off-by: Jiri Olsa Link: https://lore.kernel.org/r/20230515133756.1658301-9-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_verifier.c | 161 ++++++++++++++++++++++++---- 1 file changed, 139 insertions(+), 22 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 285ea4aba194..71704a38cac3 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -874,8 +874,140 @@ static int create_map_kptr(void) return fd; } +static void set_root(bool set) +{ + __u64 caps; + + if (set) { + if (cap_enable_effective(1ULL << CAP_SYS_ADMIN, &caps)) + perror("cap_disable_effective(CAP_SYS_ADMIN)"); + } else { + if (cap_disable_effective(1ULL << CAP_SYS_ADMIN, &caps)) + perror("cap_disable_effective(CAP_SYS_ADMIN)"); + } +} + +static __u64 ptr_to_u64(const void *ptr) +{ + return (uintptr_t) ptr; +} + +static struct btf *btf__load_testmod_btf(struct btf *vmlinux) +{ + struct bpf_btf_info info; + __u32 len = sizeof(info); + struct btf *btf = NULL; + char name[64]; + __u32 id = 0; + int err, fd; + + /* Iterate all loaded BTF objects and find bpf_testmod, + * we need SYS_ADMIN cap for that. + */ + set_root(true); + + while (true) { + err = bpf_btf_get_next_id(id, &id); + if (err) { + if (errno == ENOENT) + break; + perror("bpf_btf_get_next_id failed"); + break; + } + + fd = bpf_btf_get_fd_by_id(id); + if (fd < 0) { + if (errno == ENOENT) + continue; + perror("bpf_btf_get_fd_by_id failed"); + break; + } + + memset(&info, 0, sizeof(info)); + info.name_len = sizeof(name); + info.name = ptr_to_u64(name); + len = sizeof(info); + + err = bpf_obj_get_info_by_fd(fd, &info, &len); + if (err) { + close(fd); + perror("bpf_obj_get_info_by_fd failed"); + break; + } + + if (strcmp("bpf_testmod", name)) { + close(fd); + continue; + } + + btf = btf__load_from_kernel_by_id_split(id, vmlinux); + if (!btf) { + close(fd); + break; + } + + /* We need the fd to stay open so it can be used in fd_array. + * The final cleanup call to btf__free will free btf object + * and close the file descriptor. + */ + btf__set_fd(btf, fd); + break; + } + + set_root(false); + return btf; +} + +static struct btf *testmod_btf; +static struct btf *vmlinux_btf; + +static void kfuncs_cleanup(void) +{ + btf__free(testmod_btf); + btf__free(vmlinux_btf); +} + +static void fixup_prog_kfuncs(struct bpf_insn *prog, int *fd_array, + struct kfunc_btf_id_pair *fixup_kfunc_btf_id) +{ + /* Patch in kfunc BTF IDs */ + while (fixup_kfunc_btf_id->kfunc) { + int btf_id = 0; + + /* try to find kfunc in kernel BTF */ + vmlinux_btf = vmlinux_btf ?: btf__load_vmlinux_btf(); + if (vmlinux_btf) { + btf_id = btf__find_by_name_kind(vmlinux_btf, + fixup_kfunc_btf_id->kfunc, + BTF_KIND_FUNC); + btf_id = btf_id < 0 ? 0 : btf_id; + } + + /* kfunc not found in kernel BTF, try bpf_testmod BTF */ + if (!btf_id) { + testmod_btf = testmod_btf ?: btf__load_testmod_btf(vmlinux_btf); + if (testmod_btf) { + btf_id = btf__find_by_name_kind(testmod_btf, + fixup_kfunc_btf_id->kfunc, + BTF_KIND_FUNC); + btf_id = btf_id < 0 ? 0 : btf_id; + if (btf_id) { + /* We put bpf_testmod module fd into fd_array + * and its index 1 into instruction 'off'. + */ + *fd_array = btf__fd(testmod_btf); + prog[fixup_kfunc_btf_id->insn_idx].off = 1; + } + } + } + + prog[fixup_kfunc_btf_id->insn_idx].imm = btf_id; + fixup_kfunc_btf_id++; + } +} + static void do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type, - struct bpf_insn *prog, int *map_fds) + struct bpf_insn *prog, int *map_fds, int *fd_array) { int *fixup_map_hash_8b = test->fixup_map_hash_8b; int *fixup_map_hash_48b = test->fixup_map_hash_48b; @@ -900,7 +1032,6 @@ static void do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type, int *fixup_map_ringbuf = test->fixup_map_ringbuf; int *fixup_map_timer = test->fixup_map_timer; int *fixup_map_kptr = test->fixup_map_kptr; - struct kfunc_btf_id_pair *fixup_kfunc_btf_id = test->fixup_kfunc_btf_id; if (test->fill_helper) { test->fill_insns = calloc(MAX_TEST_INSNS, sizeof(struct bpf_insn)); @@ -1101,25 +1232,7 @@ static void do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type, } while (*fixup_map_kptr); } - /* Patch in kfunc BTF IDs */ - if (fixup_kfunc_btf_id->kfunc) { - struct btf *btf; - int btf_id; - - do { - btf_id = 0; - btf = btf__load_vmlinux_btf(); - if (btf) { - btf_id = btf__find_by_name_kind(btf, - fixup_kfunc_btf_id->kfunc, - BTF_KIND_FUNC); - btf_id = btf_id < 0 ? 0 : btf_id; - } - btf__free(btf); - prog[fixup_kfunc_btf_id->insn_idx].imm = btf_id; - fixup_kfunc_btf_id++; - } while (fixup_kfunc_btf_id->kfunc); - } + fixup_prog_kfuncs(prog, fd_array, test->fixup_kfunc_btf_id); } struct libcap { @@ -1446,6 +1559,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv, int run_errs, run_successes; int map_fds[MAX_NR_MAPS]; const char *expected_err; + int fd_array[2] = { -1, -1 }; int saved_errno; int fixup_skips; __u32 pflags; @@ -1459,7 +1573,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv, if (!prog_type) prog_type = BPF_PROG_TYPE_SOCKET_FILTER; fixup_skips = skips; - do_test_fixup(test, prog_type, prog, map_fds); + do_test_fixup(test, prog_type, prog, map_fds, &fd_array[1]); if (test->fill_insns) { prog = test->fill_insns; prog_len = test->prog_len; @@ -1493,6 +1607,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv, else opts.log_level = DEFAULT_LIBBPF_LOG_LEVEL; opts.prog_flags = pflags; + if (fd_array[1] != -1) + opts.fd_array = &fd_array[0]; if ((prog_type == BPF_PROG_TYPE_TRACING || prog_type == BPF_PROG_TYPE_LSM) && test->kfunc) { @@ -1719,6 +1835,7 @@ static int do_test(bool unpriv, unsigned int from, unsigned int to) } unload_bpf_testmod(verbose); + kfuncs_cleanup(); printf("Summary: %d PASSED, %d SKIPPED, %d FAILED\n", passes, skips, errors); -- cgit v1.2.3 From 6e2b50fa818bea4fc9a2d33f31a9633803a406ff Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 15 May 2023 15:37:55 +0200 Subject: selftests/bpf: Remove extern from kfuncs declarations There's no need to keep the extern in kfuncs declarations. Suggested-by: David Vernet Acked-by: David Vernet Signed-off-by: Jiri Olsa Link: https://lore.kernel.org/r/20230515133756.1658301-10-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h index f0755135061d..57f6166911f8 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h @@ -10,31 +10,31 @@ #define __ksym #endif -extern struct prog_test_ref_kfunc * +struct prog_test_ref_kfunc * bpf_kfunc_call_test_acquire(unsigned long *scalar_ptr) __ksym; -extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; +void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; void bpf_kfunc_call_test_ref(struct prog_test_ref_kfunc *p) __ksym; -extern void bpf_kfunc_call_test_mem_len_pass1(void *mem, int len) __ksym; -extern int *bpf_kfunc_call_test_get_rdwr_mem(struct prog_test_ref_kfunc *p, const int rdwr_buf_size) __ksym; -extern int *bpf_kfunc_call_test_get_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; -extern int *bpf_kfunc_call_test_acq_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; -extern void bpf_kfunc_call_int_mem_release(int *p) __ksym; -extern u32 bpf_kfunc_call_test_static_unused_arg(u32 arg, u32 unused) __ksym; +void bpf_kfunc_call_test_mem_len_pass1(void *mem, int len) __ksym; +int *bpf_kfunc_call_test_get_rdwr_mem(struct prog_test_ref_kfunc *p, const int rdwr_buf_size) __ksym; +int *bpf_kfunc_call_test_get_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; +int *bpf_kfunc_call_test_acq_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; +void bpf_kfunc_call_int_mem_release(int *p) __ksym; +u32 bpf_kfunc_call_test_static_unused_arg(u32 arg, u32 unused) __ksym; -extern void bpf_testmod_test_mod_kfunc(int i) __ksym; +void bpf_testmod_test_mod_kfunc(int i) __ksym; -extern __u64 bpf_kfunc_call_test1(struct sock *sk, __u32 a, __u64 b, +__u64 bpf_kfunc_call_test1(struct sock *sk, __u32 a, __u64 b, __u32 c, __u64 d) __ksym; -extern int bpf_kfunc_call_test2(struct sock *sk, __u32 a, __u32 b) __ksym; -extern struct sock *bpf_kfunc_call_test3(struct sock *sk) __ksym; -extern long bpf_kfunc_call_test4(signed char a, short b, int c, long d) __ksym; +int bpf_kfunc_call_test2(struct sock *sk, __u32 a, __u32 b) __ksym; +struct sock *bpf_kfunc_call_test3(struct sock *sk) __ksym; +long bpf_kfunc_call_test4(signed char a, short b, int c, long d) __ksym; -extern void bpf_kfunc_call_test_pass_ctx(struct __sk_buff *skb) __ksym; -extern void bpf_kfunc_call_test_pass1(struct prog_test_pass1 *p) __ksym; -extern void bpf_kfunc_call_test_pass2(struct prog_test_pass2 *p) __ksym; -extern void bpf_kfunc_call_test_mem_len_fail2(__u64 *mem, int len) __ksym; +void bpf_kfunc_call_test_pass_ctx(struct __sk_buff *skb) __ksym; +void bpf_kfunc_call_test_pass1(struct prog_test_pass1 *p) __ksym; +void bpf_kfunc_call_test_pass2(struct prog_test_pass2 *p) __ksym; +void bpf_kfunc_call_test_mem_len_fail2(__u64 *mem, int len) __ksym; -extern void bpf_kfunc_call_test_destructive(void) __ksym; +void bpf_kfunc_call_test_destructive(void) __ksym; #endif /* _BPF_TESTMOD_KFUNC_H */ -- cgit v1.2.3 From 65eb006d85a2ac0b23464808099726bd826e9877 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 15 May 2023 15:37:56 +0200 Subject: bpf: Move kernel test kfuncs to bpf_testmod Moving kernel test kfuncs into bpf_testmod kernel module, and adding necessary init calls and BTF IDs records. We need to keep following structs in kernel: struct prog_test_ref_kfunc struct prog_test_member (embedded in prog_test_ref_kfunc) The reason is because they need to be marked as rcu safe (check test prog mark_ref_as_untrusted_or_null) and such objects are being required to be defined only in kernel at the moment (see rcu_safe_kptr check in kernel). We need to keep also dtor functions for both objects in kernel: bpf_kfunc_call_test_release bpf_kfunc_call_memb_release We also keep the copy of these struct in bpf_testmod_kfunc.h, because other test functions use them. This is unfortunate, but this is just temporary solution until we are able to these structs them to bpf_testmod completely. As suggested by David adding bpf_testmod.ko make dependency for bpf programs, so they are rebuilt if we change the bpf_testmod.ko module. Also adding missing __bpf_kfunc to bpf_kfunc_call_test4 functions. Signed-off-by: Jiri Olsa Acked-by: David Vernet Link: https://lore.kernel.org/r/20230515133756.1658301-11-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- net/bpf/test_run.c | 201 --------------------- .../selftests/bpf/bpf_testmod/bpf_testmod.c | 166 +++++++++++++++++ .../selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h | 60 ++++++ 3 files changed, 226 insertions(+), 201 deletions(-) (limited to 'tools/testing') diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index 98143b86a9dd..2321bd2f9964 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -561,29 +561,6 @@ __bpf_kfunc int bpf_modify_return_test(int a, int *b) return a + *b; } -__bpf_kfunc u64 bpf_kfunc_call_test1(struct sock *sk, u32 a, u64 b, u32 c, u64 d) -{ - return a + b + c + d; -} - -__bpf_kfunc int bpf_kfunc_call_test2(struct sock *sk, u32 a, u32 b) -{ - return a + b; -} - -__bpf_kfunc struct sock *bpf_kfunc_call_test3(struct sock *sk) -{ - return sk; -} - -long noinline bpf_kfunc_call_test4(signed char a, short b, int c, long d) -{ - /* Provoke the compiler to assume that the caller has sign-extended a, - * b and c on platforms where this is required (e.g. s390x). - */ - return (long)a + (long)b + (long)c + d; -} - int noinline bpf_fentry_shadow_test(int a) { return a + 1; @@ -606,32 +583,6 @@ struct prog_test_ref_kfunc { refcount_t cnt; }; -static struct prog_test_ref_kfunc prog_test_struct = { - .a = 42, - .b = 108, - .next = &prog_test_struct, - .cnt = REFCOUNT_INIT(1), -}; - -__bpf_kfunc struct prog_test_ref_kfunc * -bpf_kfunc_call_test_acquire(unsigned long *scalar_ptr) -{ - refcount_inc(&prog_test_struct.cnt); - return &prog_test_struct; -} - -__bpf_kfunc void bpf_kfunc_call_test_offset(struct prog_test_ref_kfunc *p) -{ - WARN_ON_ONCE(1); -} - -__bpf_kfunc struct prog_test_member * -bpf_kfunc_call_memb_acquire(void) -{ - WARN_ON_ONCE(1); - return NULL; -} - __bpf_kfunc void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) { refcount_dec(&p->cnt); @@ -641,134 +592,6 @@ __bpf_kfunc void bpf_kfunc_call_memb_release(struct prog_test_member *p) { } -__bpf_kfunc void bpf_kfunc_call_memb1_release(struct prog_test_member1 *p) -{ - WARN_ON_ONCE(1); -} - -static int *__bpf_kfunc_call_test_get_mem(struct prog_test_ref_kfunc *p, const int size) -{ - if (size > 2 * sizeof(int)) - return NULL; - - return (int *)p; -} - -__bpf_kfunc int *bpf_kfunc_call_test_get_rdwr_mem(struct prog_test_ref_kfunc *p, - const int rdwr_buf_size) -{ - return __bpf_kfunc_call_test_get_mem(p, rdwr_buf_size); -} - -__bpf_kfunc int *bpf_kfunc_call_test_get_rdonly_mem(struct prog_test_ref_kfunc *p, - const int rdonly_buf_size) -{ - return __bpf_kfunc_call_test_get_mem(p, rdonly_buf_size); -} - -/* the next 2 ones can't be really used for testing expect to ensure - * that the verifier rejects the call. - * Acquire functions must return struct pointers, so these ones are - * failing. - */ -__bpf_kfunc int *bpf_kfunc_call_test_acq_rdonly_mem(struct prog_test_ref_kfunc *p, - const int rdonly_buf_size) -{ - return __bpf_kfunc_call_test_get_mem(p, rdonly_buf_size); -} - -__bpf_kfunc void bpf_kfunc_call_int_mem_release(int *p) -{ -} - -struct prog_test_pass1 { - int x0; - struct { - int x1; - struct { - int x2; - struct { - int x3; - }; - }; - }; -}; - -struct prog_test_pass2 { - int len; - short arr1[4]; - struct { - char arr2[4]; - unsigned long arr3[8]; - } x; -}; - -struct prog_test_fail1 { - void *p; - int x; -}; - -struct prog_test_fail2 { - int x8; - struct prog_test_pass1 x; -}; - -struct prog_test_fail3 { - int len; - char arr1[2]; - char arr2[]; -}; - -__bpf_kfunc void bpf_kfunc_call_test_pass_ctx(struct __sk_buff *skb) -{ -} - -__bpf_kfunc void bpf_kfunc_call_test_pass1(struct prog_test_pass1 *p) -{ -} - -__bpf_kfunc void bpf_kfunc_call_test_pass2(struct prog_test_pass2 *p) -{ -} - -__bpf_kfunc void bpf_kfunc_call_test_fail1(struct prog_test_fail1 *p) -{ -} - -__bpf_kfunc void bpf_kfunc_call_test_fail2(struct prog_test_fail2 *p) -{ -} - -__bpf_kfunc void bpf_kfunc_call_test_fail3(struct prog_test_fail3 *p) -{ -} - -__bpf_kfunc void bpf_kfunc_call_test_mem_len_pass1(void *mem, int mem__sz) -{ -} - -__bpf_kfunc void bpf_kfunc_call_test_mem_len_fail1(void *mem, int len) -{ -} - -__bpf_kfunc void bpf_kfunc_call_test_mem_len_fail2(u64 *mem, int len) -{ -} - -__bpf_kfunc void bpf_kfunc_call_test_ref(struct prog_test_ref_kfunc *p) -{ - /* p != NULL, but p->cnt could be 0 */ -} - -__bpf_kfunc void bpf_kfunc_call_test_destructive(void) -{ -} - -__bpf_kfunc static u32 bpf_kfunc_call_test_static_unused_arg(u32 arg, u32 unused) -{ - return arg; -} - __diag_pop(); BTF_SET8_START(bpf_test_modify_return_ids) @@ -782,32 +605,8 @@ static const struct btf_kfunc_id_set bpf_test_modify_return_set = { }; BTF_SET8_START(test_sk_check_kfunc_ids) -BTF_ID_FLAGS(func, bpf_kfunc_call_test1) -BTF_ID_FLAGS(func, bpf_kfunc_call_test2) -BTF_ID_FLAGS(func, bpf_kfunc_call_test3) -BTF_ID_FLAGS(func, bpf_kfunc_call_test4) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_acquire, KF_ACQUIRE | KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_kfunc_call_memb_acquire, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_kfunc_call_test_release, KF_RELEASE) BTF_ID_FLAGS(func, bpf_kfunc_call_memb_release, KF_RELEASE) -BTF_ID_FLAGS(func, bpf_kfunc_call_memb1_release, KF_RELEASE) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_get_rdwr_mem, KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_get_rdonly_mem, KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_acq_rdonly_mem, KF_ACQUIRE | KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_kfunc_call_int_mem_release, KF_RELEASE) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_pass_ctx) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_pass1) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_pass2) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_fail1) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_fail2) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_fail3) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_mem_len_pass1) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_mem_len_fail1) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_mem_len_fail2) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_ref, KF_TRUSTED_ARGS | KF_RCU) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_destructive, KF_DESTRUCTIVE) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_static_unused_arg) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_offset) BTF_SET8_END(test_sk_check_kfunc_ids) static void *bpf_test_init(const union bpf_attr *kattr, u32 user_size, diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c index 52785ba671e6..cf216041876c 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c @@ -9,6 +9,7 @@ #include #include #include "bpf_testmod.h" +#include "bpf_testmod_kfunc.h" #define CREATE_TRACE_POINTS #include "bpf_testmod-events.h" @@ -289,8 +290,171 @@ static const struct btf_kfunc_id_set bpf_testmod_common_kfunc_set = { .set = &bpf_testmod_common_kfunc_ids, }; +__bpf_kfunc u64 bpf_kfunc_call_test1(struct sock *sk, u32 a, u64 b, u32 c, u64 d) +{ + return a + b + c + d; +} + +__bpf_kfunc int bpf_kfunc_call_test2(struct sock *sk, u32 a, u32 b) +{ + return a + b; +} + +__bpf_kfunc struct sock *bpf_kfunc_call_test3(struct sock *sk) +{ + return sk; +} + +__bpf_kfunc long noinline bpf_kfunc_call_test4(signed char a, short b, int c, long d) +{ + /* Provoke the compiler to assume that the caller has sign-extended a, + * b and c on platforms where this is required (e.g. s390x). + */ + return (long)a + (long)b + (long)c + d; +} + +static struct prog_test_ref_kfunc prog_test_struct = { + .a = 42, + .b = 108, + .next = &prog_test_struct, + .cnt = REFCOUNT_INIT(1), +}; + +__bpf_kfunc struct prog_test_ref_kfunc * +bpf_kfunc_call_test_acquire(unsigned long *scalar_ptr) +{ + refcount_inc(&prog_test_struct.cnt); + return &prog_test_struct; +} + +__bpf_kfunc void bpf_kfunc_call_test_offset(struct prog_test_ref_kfunc *p) +{ + WARN_ON_ONCE(1); +} + +__bpf_kfunc struct prog_test_member * +bpf_kfunc_call_memb_acquire(void) +{ + WARN_ON_ONCE(1); + return NULL; +} + +__bpf_kfunc void bpf_kfunc_call_memb1_release(struct prog_test_member1 *p) +{ + WARN_ON_ONCE(1); +} + +static int *__bpf_kfunc_call_test_get_mem(struct prog_test_ref_kfunc *p, const int size) +{ + if (size > 2 * sizeof(int)) + return NULL; + + return (int *)p; +} + +__bpf_kfunc int *bpf_kfunc_call_test_get_rdwr_mem(struct prog_test_ref_kfunc *p, + const int rdwr_buf_size) +{ + return __bpf_kfunc_call_test_get_mem(p, rdwr_buf_size); +} + +__bpf_kfunc int *bpf_kfunc_call_test_get_rdonly_mem(struct prog_test_ref_kfunc *p, + const int rdonly_buf_size) +{ + return __bpf_kfunc_call_test_get_mem(p, rdonly_buf_size); +} + +/* the next 2 ones can't be really used for testing expect to ensure + * that the verifier rejects the call. + * Acquire functions must return struct pointers, so these ones are + * failing. + */ +__bpf_kfunc int *bpf_kfunc_call_test_acq_rdonly_mem(struct prog_test_ref_kfunc *p, + const int rdonly_buf_size) +{ + return __bpf_kfunc_call_test_get_mem(p, rdonly_buf_size); +} + +__bpf_kfunc void bpf_kfunc_call_int_mem_release(int *p) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_pass_ctx(struct __sk_buff *skb) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_pass1(struct prog_test_pass1 *p) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_pass2(struct prog_test_pass2 *p) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_fail1(struct prog_test_fail1 *p) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_fail2(struct prog_test_fail2 *p) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_fail3(struct prog_test_fail3 *p) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_mem_len_pass1(void *mem, int mem__sz) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_mem_len_fail1(void *mem, int len) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_mem_len_fail2(u64 *mem, int len) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_ref(struct prog_test_ref_kfunc *p) +{ + /* p != NULL, but p->cnt could be 0 */ +} + +__bpf_kfunc void bpf_kfunc_call_test_destructive(void) +{ +} + +__bpf_kfunc static u32 bpf_kfunc_call_test_static_unused_arg(u32 arg, u32 unused) +{ + return arg; +} + BTF_SET8_START(bpf_testmod_check_kfunc_ids) BTF_ID_FLAGS(func, bpf_testmod_test_mod_kfunc) +BTF_ID_FLAGS(func, bpf_kfunc_call_test1) +BTF_ID_FLAGS(func, bpf_kfunc_call_test2) +BTF_ID_FLAGS(func, bpf_kfunc_call_test3) +BTF_ID_FLAGS(func, bpf_kfunc_call_test4) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_mem_len_pass1) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_mem_len_fail1) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_mem_len_fail2) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_acquire, KF_ACQUIRE | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_kfunc_call_memb_acquire, KF_ACQUIRE | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_kfunc_call_memb1_release, KF_RELEASE) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_get_rdwr_mem, KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_get_rdonly_mem, KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_acq_rdonly_mem, KF_ACQUIRE | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_kfunc_call_int_mem_release, KF_RELEASE) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_pass_ctx) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_pass1) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_pass2) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_fail1) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_fail2) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_fail3) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_ref, KF_TRUSTED_ARGS | KF_RCU) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_destructive, KF_DESTRUCTIVE) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_static_unused_arg) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_offset) BTF_SET8_END(bpf_testmod_check_kfunc_ids) static const struct btf_kfunc_id_set bpf_testmod_kfunc_set = { @@ -312,6 +476,8 @@ static int bpf_testmod_init(void) ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_UNSPEC, &bpf_testmod_common_kfunc_set); ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, &bpf_testmod_kfunc_set); + ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &bpf_testmod_kfunc_set); + ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &bpf_testmod_kfunc_set); if (ret < 0) return ret; if (bpf_fentry_test1(0) < 0) diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h index 57f6166911f8..9693c626646b 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h @@ -8,8 +8,62 @@ #include #else #define __ksym +struct prog_test_member1 { + int a; +}; + +struct prog_test_member { + struct prog_test_member1 m; + int c; +}; + +struct prog_test_ref_kfunc { + int a; + int b; + struct prog_test_member memb; + struct prog_test_ref_kfunc *next; + refcount_t cnt; +}; #endif +struct prog_test_pass1 { + int x0; + struct { + int x1; + struct { + int x2; + struct { + int x3; + }; + }; + }; +}; + +struct prog_test_pass2 { + int len; + short arr1[4]; + struct { + char arr2[4]; + unsigned long arr3[8]; + } x; +}; + +struct prog_test_fail1 { + void *p; + int x; +}; + +struct prog_test_fail2 { + int x8; + struct prog_test_pass1 x; +}; + +struct prog_test_fail3 { + int len; + char arr1[2]; + char arr2[]; +}; + struct prog_test_ref_kfunc * bpf_kfunc_call_test_acquire(unsigned long *scalar_ptr) __ksym; void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; @@ -20,7 +74,13 @@ int *bpf_kfunc_call_test_get_rdwr_mem(struct prog_test_ref_kfunc *p, const int r int *bpf_kfunc_call_test_get_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; int *bpf_kfunc_call_test_acq_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; void bpf_kfunc_call_int_mem_release(int *p) __ksym; + +/* The bpf_kfunc_call_test_static_unused_arg is defined as static, + * but bpf program compilation needs to see it as global symbol. + */ +#ifndef __KERNEL__ u32 bpf_kfunc_call_test_static_unused_arg(u32 arg, u32 unused) __ksym; +#endif void bpf_testmod_test_mod_kfunc(int i) __ksym; -- cgit v1.2.3 From d2e541494935a659b67e51aa3d1945bb3b799c4e Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:00 +0200 Subject: selftests/xsk: do not change XDP program when not necessary Do not change the XDP program for the Tx thread when not needed. It was erroneously compared to the XDP program for the Rx thread, which is always going to be different, which meant that the code made unnecessary switches to the same program it had before. This did not affect functionality, just performance. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-2-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xskxceiver.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index f144d0604ddf..f7950af576e1 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -1402,11 +1402,20 @@ static void handler(int signum) pthread_exit(NULL); } -static bool xdp_prog_changed(struct test_spec *test, struct ifobject *ifobj) +static bool xdp_prog_changed_rx(struct test_spec *test) { + struct ifobject *ifobj = test->ifobj_rx; + return ifobj->xdp_prog != test->xdp_prog_rx || ifobj->mode != test->mode; } +static bool xdp_prog_changed_tx(struct test_spec *test) +{ + struct ifobject *ifobj = test->ifobj_tx; + + return ifobj->xdp_prog != test->xdp_prog_tx || ifobj->mode != test->mode; +} + static void xsk_reattach_xdp(struct ifobject *ifobj, struct bpf_program *xdp_prog, struct bpf_map *xskmap, enum test_mode mode) { @@ -1433,13 +1442,13 @@ static void xsk_reattach_xdp(struct ifobject *ifobj, struct bpf_program *xdp_pro static void xsk_attach_xdp_progs(struct test_spec *test, struct ifobject *ifobj_rx, struct ifobject *ifobj_tx) { - if (xdp_prog_changed(test, ifobj_rx)) + if (xdp_prog_changed_rx(test)) xsk_reattach_xdp(ifobj_rx, test->xdp_prog_rx, test->xskmap_rx, test->mode); if (!ifobj_tx || ifobj_tx->shared_umem) return; - if (xdp_prog_changed(test, ifobj_tx)) + if (xdp_prog_changed_tx(test)) xsk_reattach_xdp(ifobj_tx, test->xdp_prog_tx, test->xskmap_tx, test->mode); } -- cgit v1.2.3 From df82d2e89c41d1dc6f02a881f0cddac8252bb441 Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:01 +0200 Subject: selftests/xsk: generate simpler packets with variable length Implement support for generating pkts with variable length. Before this patch, they were all 64 bytes, exception for some packets of zero length and some that were too large. This feature will be used to test multi-buffer support for which large packets are needed. The packets are also made simpler, just a valid Ethernet header followed by a sequence number. This so that it will become easier to implement packet generation when each packet consists of multiple fragments. There is also a maintenance burden associated with carrying all this code for generating proper UDP/IP packets, especially since they are not needed. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-3-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xskxceiver.c | 221 +++++-------------------------- tools/testing/selftests/bpf/xskxceiver.h | 17 +-- 2 files changed, 38 insertions(+), 200 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index f7950af576e1..c13478875fb1 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -76,16 +76,13 @@ #include #include #include -#include #include -#include #include #include #include #include #include #include -#include #include #include #include @@ -94,10 +91,8 @@ #include #include #include -#include #include #include -#include #include "xsk_xdp_progs.skel.h" #include "xsk.h" @@ -109,10 +104,6 @@ static const char *MAC1 = "\x00\x0A\x56\x9E\xEE\x62"; static const char *MAC2 = "\x00\x0A\x56\x9E\xEE\x61"; -static const char *IP1 = "192.168.100.162"; -static const char *IP2 = "192.168.100.161"; -static const u16 UDP_PORT1 = 2020; -static const u16 UDP_PORT2 = 2121; static void __exit_with_error(int error, const char *file, const char *func, int line) { @@ -158,101 +149,11 @@ static void memset32_htonl(void *dest, u32 val, u32 size) ptr[i >> 2] = val; } -/* - * Fold a partial checksum - * This function code has been taken from - * Linux kernel include/asm-generic/checksum.h - */ -static __u16 csum_fold(__u32 csum) -{ - u32 sum = (__force u32)csum; - - sum = (sum & 0xffff) + (sum >> 16); - sum = (sum & 0xffff) + (sum >> 16); - return (__force __u16)~sum; -} - -/* - * This function code has been taken from - * Linux kernel lib/checksum.c - */ -static u32 from64to32(u64 x) -{ - /* add up 32-bit and 32-bit for 32+c bit */ - x = (x & 0xffffffff) + (x >> 32); - /* add up carry.. */ - x = (x & 0xffffffff) + (x >> 32); - return (u32)x; -} - -/* - * This function code has been taken from - * Linux kernel lib/checksum.c - */ -static __u32 csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len, __u8 proto, __u32 sum) -{ - unsigned long long s = (__force u32)sum; - - s += (__force u32)saddr; - s += (__force u32)daddr; -#ifdef __BIG_ENDIAN__ - s += proto + len; -#else - s += (proto + len) << 8; -#endif - return (__force __u32)from64to32(s); -} - -/* - * This function has been taken from - * Linux kernel include/asm-generic/checksum.h - */ -static __u16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len, __u8 proto, __u32 sum) -{ - return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum)); -} - -static u16 udp_csum(u32 saddr, u32 daddr, u32 len, u8 proto, u16 *udp_pkt) -{ - u32 csum = 0; - u32 cnt = 0; - - /* udp hdr and data */ - for (; cnt < len; cnt += 2) - csum += udp_pkt[cnt >> 1]; - - return csum_tcpudp_magic(saddr, daddr, len, proto, csum); -} - static void gen_eth_hdr(struct ifobject *ifobject, struct ethhdr *eth_hdr) { memcpy(eth_hdr->h_dest, ifobject->dst_mac, ETH_ALEN); memcpy(eth_hdr->h_source, ifobject->src_mac, ETH_ALEN); - eth_hdr->h_proto = htons(ETH_P_IP); -} - -static void gen_ip_hdr(struct ifobject *ifobject, struct iphdr *ip_hdr) -{ - ip_hdr->version = IP_PKT_VER; - ip_hdr->ihl = 0x5; - ip_hdr->tos = IP_PKT_TOS; - ip_hdr->tot_len = htons(IP_PKT_SIZE); - ip_hdr->id = 0; - ip_hdr->frag_off = 0; - ip_hdr->ttl = IPDEFTTL; - ip_hdr->protocol = IPPROTO_UDP; - ip_hdr->saddr = ifobject->src_ip; - ip_hdr->daddr = ifobject->dst_ip; - ip_hdr->check = 0; -} - -static void gen_udp_hdr(u32 payload, void *pkt, struct ifobject *ifobject, - struct udphdr *udp_hdr) -{ - udp_hdr->source = htons(ifobject->src_port); - udp_hdr->dest = htons(ifobject->dst_port); - udp_hdr->len = htons(UDP_PKT_SIZE); - memset32_htonl(pkt + PKT_HDR_SIZE, payload, UDP_PKT_DATA_SIZE); + eth_hdr->h_proto = htons(ETH_P_LOOPBACK); } static bool is_umem_valid(struct ifobject *ifobj) @@ -260,13 +161,6 @@ static bool is_umem_valid(struct ifobject *ifobj) return !!ifobj->umem->umem; } -static void gen_udp_csum(struct udphdr *udp_hdr, struct iphdr *ip_hdr) -{ - udp_hdr->check = 0; - udp_hdr->check = - udp_csum(ip_hdr->saddr, ip_hdr->daddr, UDP_PKT_SIZE, IPPROTO_UDP, (u16 *)udp_hdr); -} - static u32 mode_to_xdp_flags(enum test_mode mode) { return (mode == TEST_MODE_SKB) ? XDP_FLAGS_SKB_MODE : XDP_FLAGS_DRV_MODE; @@ -697,9 +591,7 @@ static void pkt_stream_receive_half(struct test_spec *test) static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb) { struct pkt *pkt = pkt_stream_get_pkt(ifobject->pkt_stream, pkt_nb); - struct udphdr *udp_hdr; struct ethhdr *eth_hdr; - struct iphdr *ip_hdr; void *data; if (!pkt) @@ -708,14 +600,10 @@ static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb) return pkt; data = xsk_umem__get_data(ifobject->umem->buffer, pkt->addr); - udp_hdr = (struct udphdr *)(data + sizeof(struct ethhdr) + sizeof(struct iphdr)); - ip_hdr = (struct iphdr *)(data + sizeof(struct ethhdr)); - eth_hdr = (struct ethhdr *)data; + eth_hdr = data; - gen_udp_hdr(pkt_nb, data, ifobject, udp_hdr); - gen_ip_hdr(ifobject, ip_hdr); - gen_udp_csum(udp_hdr, ip_hdr); gen_eth_hdr(ifobject, eth_hdr); + memset32_htonl(data + PKT_HDR_SIZE, pkt_nb, pkt->len - PKT_HDR_SIZE); return pkt; } @@ -746,18 +634,11 @@ static void pkt_stream_generate_custom(struct test_spec *test, struct pkt *pkts, __pkt_stream_generate_custom(test->ifobj_rx, pkts, nb_pkts); } -static void pkt_dump(void *pkt, u32 len) +static void pkt_dump(void *pkt) { - char s[INET_ADDRSTRLEN]; - struct ethhdr *ethhdr; - struct udphdr *udphdr; - struct iphdr *iphdr; + struct ethhdr *ethhdr = pkt; u32 payload, i; - ethhdr = pkt; - iphdr = pkt + sizeof(*ethhdr); - udphdr = pkt + sizeof(*ethhdr) + sizeof(*iphdr); - /*extract L2 frame */ fprintf(stdout, "DEBUG>> L2: dst mac: "); for (i = 0; i < ETH_ALEN; i++) @@ -767,19 +648,10 @@ static void pkt_dump(void *pkt, u32 len) for (i = 0; i < ETH_ALEN; i++) fprintf(stdout, "%02X", ethhdr->h_source[i]); - /*extract L3 frame */ - fprintf(stdout, "\nDEBUG>> L3: ip_hdr->ihl: %02X\n", iphdr->ihl); - fprintf(stdout, "DEBUG>> L3: ip_hdr->saddr: %s\n", - inet_ntop(AF_INET, &iphdr->saddr, s, sizeof(s))); - fprintf(stdout, "DEBUG>> L3: ip_hdr->daddr: %s\n", - inet_ntop(AF_INET, &iphdr->daddr, s, sizeof(s))); - /*extract L4 frame */ - fprintf(stdout, "DEBUG>> L4: udp_hdr->src: %d\n", ntohs(udphdr->source)); - fprintf(stdout, "DEBUG>> L4: udp_hdr->dst: %d\n", ntohs(udphdr->dest)); /*extract L5 frame */ payload = ntohl(*((u32 *)(pkt + PKT_HDR_SIZE))); - fprintf(stdout, "DEBUG>> L5: payload: %d\n", payload); + fprintf(stdout, "\nDEBUG>> L5: payload: %d\n", payload); fprintf(stdout, "---------------------------------------\n"); } @@ -818,7 +690,7 @@ static bool is_metadata_correct(struct pkt *pkt, void *buffer, u64 addr) static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len) { void *data = xsk_umem__get_data(buffer, addr); - struct iphdr *iphdr = (struct iphdr *)(data + sizeof(struct ethhdr)); + u32 seqnum; if (!pkt) { ksft_print_msg("[%s] too many packets received\n", __func__); @@ -836,21 +708,13 @@ static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len) return false; } - if (iphdr->version == IP_PKT_VER && iphdr->tos == IP_PKT_TOS) { - u32 seqnum = ntohl(*((u32 *)(data + PKT_HDR_SIZE))); - - if (opt_pkt_dump) - pkt_dump(data, PKT_SIZE); + seqnum = ntohl(*((u32 *)(data + PKT_HDR_SIZE))); + if (opt_pkt_dump) + pkt_dump(data); - if (pkt->payload != seqnum) { - ksft_print_msg("[%s] expected seqnum [%d], got seqnum [%d]\n", - __func__, pkt->payload, seqnum); - return false; - } - } else { - ksft_print_msg("Invalid frame received: "); - ksft_print_msg("[IP_PKT_VER: %02X], [IP_PKT_TOS: %02X]\n", iphdr->version, - iphdr->tos); + if (pkt->payload != seqnum) { + ksft_print_msg("[%s] expected seqnum [%d], got seqnum [%d]\n", + __func__, pkt->payload, seqnum); return false; } @@ -1606,9 +1470,9 @@ static void testapp_stats_tx_invalid_descs(struct test_spec *test) static void testapp_stats_rx_full(struct test_spec *test) { test_spec_set_name(test, "STAT_RX_FULL"); - pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, PKT_SIZE); + pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE); test->ifobj_rx->pkt_stream = pkt_stream_generate(test->ifobj_rx->umem, - DEFAULT_UMEM_BUFFERS, PKT_SIZE); + DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE); if (!test->ifobj_rx->pkt_stream) exit_with_error(ENOMEM); @@ -1621,9 +1485,9 @@ static void testapp_stats_rx_full(struct test_spec *test) static void testapp_stats_fill_empty(struct test_spec *test) { test_spec_set_name(test, "STAT_RX_FILL_EMPTY"); - pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, PKT_SIZE); + pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE); test->ifobj_rx->pkt_stream = pkt_stream_generate(test->ifobj_rx->umem, - DEFAULT_UMEM_BUFFERS, PKT_SIZE); + DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE); if (!test->ifobj_rx->pkt_stream) exit_with_error(ENOMEM); @@ -1659,7 +1523,7 @@ static bool testapp_unaligned(struct test_spec *test) test->ifobj_tx->umem->unaligned_mode = true; test->ifobj_rx->umem->unaligned_mode = true; /* Let half of the packets straddle a buffer boundrary */ - pkt_stream_replace_half(test, PKT_SIZE, -PKT_SIZE / 2); + pkt_stream_replace_half(test, MIN_PKT_SIZE, -MIN_PKT_SIZE / 2); test->ifobj_rx->pkt_stream->use_addr_for_fill = true; testapp_validate_traffic(test); @@ -1668,7 +1532,7 @@ static bool testapp_unaligned(struct test_spec *test) static void testapp_single_pkt(struct test_spec *test) { - struct pkt pkts[] = {{0x1000, PKT_SIZE, 0, true}}; + struct pkt pkts[] = {{0x1000, MIN_PKT_SIZE, 0, true}}; pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts)); testapp_validate_traffic(test); @@ -1679,25 +1543,25 @@ static void testapp_invalid_desc(struct test_spec *test) u64 umem_size = test->ifobj_tx->umem->num_frames * test->ifobj_tx->umem->frame_size; struct pkt pkts[] = { /* Zero packet address allowed */ - {0, PKT_SIZE, 0, true}, + {0, MIN_PKT_SIZE, 0, true}, /* Allowed packet */ - {0x1000, PKT_SIZE, 0, true}, + {0x1000, MIN_PKT_SIZE, 0, true}, /* Straddling the start of umem */ - {-2, PKT_SIZE, 0, false}, + {-2, MIN_PKT_SIZE, 0, false}, /* Packet too large */ {0x2000, XSK_UMEM__INVALID_FRAME_SIZE, 0, false}, /* Up to end of umem allowed */ - {umem_size - PKT_SIZE, PKT_SIZE, 0, true}, + {umem_size - MIN_PKT_SIZE, MIN_PKT_SIZE, 0, true}, /* After umem ends */ - {umem_size, PKT_SIZE, 0, false}, + {umem_size, MIN_PKT_SIZE, 0, false}, /* Straddle the end of umem */ - {umem_size - PKT_SIZE / 2, PKT_SIZE, 0, false}, + {umem_size - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, false}, /* Straddle a page boundrary */ - {0x3000 - PKT_SIZE / 2, PKT_SIZE, 0, false}, + {0x3000 - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, false}, /* Straddle a 2K boundrary */ - {0x3800 - PKT_SIZE / 2, PKT_SIZE, 0, true}, + {0x3800 - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, true}, /* Valid packet for synch so that something is received */ - {0x4000, PKT_SIZE, 0, true}}; + {0x4000, MIN_PKT_SIZE, 0, true}}; if (test->ifobj_tx->umem->unaligned_mode) { /* Crossing a page boundrary allowed */ @@ -1788,24 +1652,13 @@ static void xsk_unload_xdp_programs(struct ifobject *ifobj) } static void init_iface(struct ifobject *ifobj, const char *dst_mac, const char *src_mac, - const char *dst_ip, const char *src_ip, const u16 dst_port, - const u16 src_port, thread_func_t func_ptr) + thread_func_t func_ptr) { - struct in_addr ip; int err; memcpy(ifobj->dst_mac, dst_mac, ETH_ALEN); memcpy(ifobj->src_mac, src_mac, ETH_ALEN); - inet_aton(dst_ip, &ip); - ifobj->dst_ip = ip.s_addr; - - inet_aton(src_ip, &ip); - ifobj->src_ip = ip.s_addr; - - ifobj->dst_port = dst_port; - ifobj->src_port = src_port; - ifobj->func_ptr = func_ptr; err = xsk_load_xdp_programs(ifobj); @@ -1855,7 +1708,7 @@ static void run_pkt_test(struct test_spec *test, enum test_mode mode, enum test_ test_spec_set_name(test, "RUN_TO_COMPLETION_2K_FRAME_SIZE"); test->ifobj_tx->umem->frame_size = 2048; test->ifobj_rx->umem->frame_size = 2048; - pkt_stream_replace(test, DEFAULT_PKT_CNT, PKT_SIZE); + pkt_stream_replace(test, DEFAULT_PKT_CNT, MIN_PKT_SIZE); testapp_validate_traffic(test); break; case TEST_TYPE_RX_POLL: @@ -1912,8 +1765,8 @@ static void run_pkt_test(struct test_spec *test, enum test_mode mode, enum test_ */ page_size = sysconf(_SC_PAGESIZE); umem_size = test->ifobj_tx->umem->num_frames * test->ifobj_tx->umem->frame_size; - assert(umem_size % page_size > PKT_SIZE); - assert(umem_size % page_size < page_size - PKT_SIZE); + assert(umem_size % page_size > MIN_PKT_SIZE); + assert(umem_size % page_size < page_size - MIN_PKT_SIZE); testapp_invalid_desc(test); break; } @@ -2039,14 +1892,12 @@ int main(int argc, char **argv) modes++; } - init_iface(ifobj_rx, MAC1, MAC2, IP1, IP2, UDP_PORT1, UDP_PORT2, - worker_testapp_validate_rx); - init_iface(ifobj_tx, MAC2, MAC1, IP2, IP1, UDP_PORT2, UDP_PORT1, - worker_testapp_validate_tx); + init_iface(ifobj_rx, MAC1, MAC2, worker_testapp_validate_rx); + init_iface(ifobj_tx, MAC2, MAC1, worker_testapp_validate_tx); test_spec_init(&test, ifobj_tx, ifobj_rx, 0); - tx_pkt_stream_default = pkt_stream_generate(ifobj_tx->umem, DEFAULT_PKT_CNT, PKT_SIZE); - rx_pkt_stream_default = pkt_stream_generate(ifobj_rx->umem, DEFAULT_PKT_CNT, PKT_SIZE); + tx_pkt_stream_default = pkt_stream_generate(ifobj_tx->umem, DEFAULT_PKT_CNT, MIN_PKT_SIZE); + rx_pkt_stream_default = pkt_stream_generate(ifobj_rx->umem, DEFAULT_PKT_CNT, MIN_PKT_SIZE); if (!tx_pkt_stream_default || !rx_pkt_stream_default) exit_with_error(ENOMEM); test.tx_pkt_stream_default = tx_pkt_stream_default; diff --git a/tools/testing/selftests/bpf/xskxceiver.h b/tools/testing/selftests/bpf/xskxceiver.h index c535aeab2ca3..8b094718629d 100644 --- a/tools/testing/selftests/bpf/xskxceiver.h +++ b/tools/testing/selftests/bpf/xskxceiver.h @@ -35,17 +35,8 @@ #define MAX_SOCKETS 2 #define MAX_TEST_NAME_SIZE 32 #define MAX_TEARDOWN_ITER 10 -#define PKT_HDR_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) + \ - sizeof(struct udphdr)) -#define MIN_ETH_PKT_SIZE 64 -#define ETH_FCS_SIZE 4 -#define MIN_PKT_SIZE (MIN_ETH_PKT_SIZE - ETH_FCS_SIZE) -#define PKT_SIZE (MIN_PKT_SIZE) -#define IP_PKT_SIZE (PKT_SIZE - sizeof(struct ethhdr)) -#define IP_PKT_VER 0x4 -#define IP_PKT_TOS 0x9 -#define UDP_PKT_SIZE (IP_PKT_SIZE - sizeof(struct iphdr)) -#define UDP_PKT_DATA_SIZE (UDP_PKT_SIZE - sizeof(struct udphdr)) +#define PKT_HDR_SIZE (sizeof(struct ethhdr) + 2) /* Just to align the data in the packet */ +#define MIN_PKT_SIZE 64 #define USLEEP_MAX 10000 #define SOCK_RECONF_CTR 10 #define BATCH_SIZE 64 @@ -148,11 +139,7 @@ struct ifobject { struct bpf_program *xdp_prog; enum test_mode mode; int ifindex; - u32 dst_ip; - u32 src_ip; u32 bind_flags; - u16 src_port; - u16 dst_port; bool tx_on; bool rx_on; bool use_poll; -- cgit v1.2.3 From feb973a9094ff92fb8c141be5d2e762f9ab36a7a Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:02 +0200 Subject: selftests/xsk: add varying payload pattern within packet Add a varying payload pattern within the packet. Instead of having just a packet number that is the same for all words in a packet, make each word different in the packet. The upper 16-bits are set to the packet number and the lower 16-bits are the sequence number of the words in this packet. So the 3rd packet's 5th 32-bit word of data will contain the number (2<<32) | 4 as they are numbered from 0. This will make it easier to detect fragments that are out of order when starting to test multi-buffer support. The member payload in the packet is renamed pkt_nb to reflect that it is now only a pkt_nb, not the real payload as seen above. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-4-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xskxceiver.c | 68 +++++++++++++++++++++----------- tools/testing/selftests/bpf/xskxceiver.h | 3 +- 2 files changed, 47 insertions(+), 24 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index c13478875fb1..818b7130f932 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -138,15 +138,16 @@ static void report_failure(struct test_spec *test) test->fail = true; } -static void memset32_htonl(void *dest, u32 val, u32 size) +/* The payload is a word consisting of a packet sequence number in the upper + * 16-bits and a intra packet data sequence number in the lower 16 bits. So the 3rd packet's + * 5th word of data will contain the number (2<<16) | 4 as they are numbered from 0. + */ +static void write_payload(void *dest, u32 val, u32 size) { - u32 *ptr = (u32 *)dest; - int i; + u32 *ptr = (u32 *)dest, i; - val = htonl(val); - - for (i = 0; i < (size & (~0x3)); i += 4) - ptr[i >> 2] = val; + for (i = 0; i < size / sizeof(*ptr); i++) + ptr[i] = htonl(val << 16 | i); } static void gen_eth_hdr(struct ifobject *ifobject, struct ethhdr *eth_hdr) @@ -532,7 +533,7 @@ static struct pkt_stream *pkt_stream_generate(struct xsk_umem_info *umem, u32 nb for (i = 0; i < nb_pkts; i++) { pkt_set(umem, &pkt_stream->pkts[i], (i % umem->num_frames) * umem->frame_size, pkt_len); - pkt_stream->pkts[i].payload = i; + pkt_stream->pkts[i].pkt_nb = i; } return pkt_stream; @@ -603,7 +604,7 @@ static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb) eth_hdr = data; gen_eth_hdr(ifobject, eth_hdr); - memset32_htonl(data + PKT_HDR_SIZE, pkt_nb, pkt->len - PKT_HDR_SIZE); + write_payload(data + PKT_HDR_SIZE, pkt_nb, pkt->len - PKT_HDR_SIZE); return pkt; } @@ -621,7 +622,7 @@ static void __pkt_stream_generate_custom(struct ifobject *ifobj, for (i = 0; i < nb_pkts; i++) { pkt_stream->pkts[i].addr = pkts[i].addr + ifobj->umem->base_addr; pkt_stream->pkts[i].len = pkts[i].len; - pkt_stream->pkts[i].payload = i; + pkt_stream->pkts[i].pkt_nb = i; pkt_stream->pkts[i].valid = pkts[i].valid; } @@ -634,10 +635,24 @@ static void pkt_stream_generate_custom(struct test_spec *test, struct pkt *pkts, __pkt_stream_generate_custom(test->ifobj_rx, pkts, nb_pkts); } -static void pkt_dump(void *pkt) +static void pkt_print_data(u32 *data, u32 cnt) +{ + u32 i; + + for (i = 0; i < cnt; i++) { + u32 seqnum, pkt_nb; + + seqnum = ntohl(*data) & 0xffff; + pkt_nb = ntohl(*data) >> 16; + fprintf(stdout, "%u:%u ", pkt_nb, seqnum); + data++; + } +} + +static void pkt_dump(void *pkt, u32 len) { struct ethhdr *ethhdr = pkt; - u32 payload, i; + u32 i; /*extract L2 frame */ fprintf(stdout, "DEBUG>> L2: dst mac: "); @@ -649,10 +664,15 @@ static void pkt_dump(void *pkt) fprintf(stdout, "%02X", ethhdr->h_source[i]); /*extract L5 frame */ - payload = ntohl(*((u32 *)(pkt + PKT_HDR_SIZE))); - - fprintf(stdout, "\nDEBUG>> L5: payload: %d\n", payload); - fprintf(stdout, "---------------------------------------\n"); + fprintf(stdout, "\nDEBUG>> L5: seqnum: "); + pkt_print_data(pkt + PKT_HDR_SIZE, PKT_DUMP_NB_TO_PRINT); + fprintf(stdout, "...."); + if (len > PKT_DUMP_NB_TO_PRINT * sizeof(u32)) { + fprintf(stdout, "\n.... "); + pkt_print_data(pkt + PKT_HDR_SIZE + len - PKT_DUMP_NB_TO_PRINT * sizeof(u32), + PKT_DUMP_NB_TO_PRINT); + } + fprintf(stdout, "\n---------------------------------------\n"); } static bool is_offset_correct(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream, u64 addr, @@ -678,9 +698,9 @@ static bool is_metadata_correct(struct pkt *pkt, void *buffer, u64 addr) void *data = xsk_umem__get_data(buffer, addr); struct xdp_info *meta = data - sizeof(struct xdp_info); - if (meta->count != pkt->payload) { + if (meta->count != pkt->pkt_nb) { ksft_print_msg("[%s] expected meta_count [%d], got meta_count [%d]\n", - __func__, pkt->payload, meta->count); + __func__, pkt->pkt_nb, meta->count); return false; } @@ -690,7 +710,7 @@ static bool is_metadata_correct(struct pkt *pkt, void *buffer, u64 addr) static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len) { void *data = xsk_umem__get_data(buffer, addr); - u32 seqnum; + u32 seqnum, pkt_data; if (!pkt) { ksft_print_msg("[%s] too many packets received\n", __func__); @@ -708,13 +728,15 @@ static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len) return false; } - seqnum = ntohl(*((u32 *)(data + PKT_HDR_SIZE))); + pkt_data = ntohl(*((u32 *)(data + PKT_HDR_SIZE))); + seqnum = pkt_data >> 16; + if (opt_pkt_dump) - pkt_dump(data); + pkt_dump(data, len); - if (pkt->payload != seqnum) { + if (pkt->pkt_nb != seqnum) { ksft_print_msg("[%s] expected seqnum [%d], got seqnum [%d]\n", - __func__, pkt->payload, seqnum); + __func__, pkt->pkt_nb, seqnum); return false; } diff --git a/tools/testing/selftests/bpf/xskxceiver.h b/tools/testing/selftests/bpf/xskxceiver.h index 8b094718629d..91022c4876eb 100644 --- a/tools/testing/selftests/bpf/xskxceiver.h +++ b/tools/testing/selftests/bpf/xskxceiver.h @@ -48,6 +48,7 @@ #define UMEM_HEADROOM_TEST_SIZE 128 #define XSK_UMEM__INVALID_FRAME_SIZE (XSK_UMEM__DEFAULT_FRAME_SIZE + 1) #define HUGEPAGE_SIZE (2 * 1024 * 1024) +#define PKT_DUMP_NB_TO_PRINT 16 #define print_verbose(x...) do { if (opt_verbose) ksft_print_msg(x); } while (0) @@ -111,7 +112,7 @@ struct xsk_socket_info { struct pkt { u64 addr; u32 len; - u32 payload; + u32 pkt_nb; bool valid; }; -- cgit v1.2.3 From 7a8a6762822a1f5249eec356e7ea31f98161fba0 Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:03 +0200 Subject: selftests/xsk: dump packet at error Dump the content of the packet when a test finds that packets are received out of order, the length is wrong, or some other packet error. Use the already existing pkt_dump function for this and call it when the above errors are detected. Get rid of the command line option for dumping packets as it is not useful to print out thousands of good packets followed by the faulty one you would like to see. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-5-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_xsk.sh | 10 +--------- tools/testing/selftests/bpf/xskxceiver.c | 20 ++++++++------------ tools/testing/selftests/bpf/xskxceiver.h | 1 - 3 files changed, 9 insertions(+), 22 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_xsk.sh b/tools/testing/selftests/bpf/test_xsk.sh index 377fb157a57c..c2ad50f26b63 100755 --- a/tools/testing/selftests/bpf/test_xsk.sh +++ b/tools/testing/selftests/bpf/test_xsk.sh @@ -68,9 +68,6 @@ # Run with verbose output: # sudo ./test_xsk.sh -v # -# Run and dump packet contents: -# sudo ./test_xsk.sh -D -# # Set up veth interfaces and leave them up so xskxceiver can be launched in a debugger: # sudo ./test_xsk.sh -d # @@ -81,11 +78,10 @@ ETH="" -while getopts "vDi:d" flag +while getopts "vi:d" flag do case "${flag}" in v) verbose=1;; - D) dump_pkts=1;; d) debug=1;; i) ETH=${OPTARG};; esac @@ -157,10 +153,6 @@ if [[ $verbose -eq 1 ]]; then ARGS+="-v " fi -if [[ $dump_pkts -eq 1 ]]; then - ARGS="-D " -fi - retval=$? test_status $retval "${TEST_NAME}" diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index 818b7130f932..0a8231ed6626 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -275,7 +275,6 @@ out: static struct option long_options[] = { {"interface", required_argument, 0, 'i'}, {"busy-poll", no_argument, 0, 'b'}, - {"dump-pkts", no_argument, 0, 'D'}, {"verbose", no_argument, 0, 'v'}, {0, 0, 0, 0} }; @@ -286,7 +285,6 @@ static void usage(const char *prog) " Usage: %s [OPTIONS]\n" " Options:\n" " -i, --interface Use interface\n" - " -D, --dump-pkts Dump packets L2 - L5\n" " -v, --verbose Verbose output\n" " -b, --busy-poll Enable busy poll\n"; @@ -310,7 +308,7 @@ static void parse_command_line(struct ifobject *ifobj_tx, struct ifobject *ifobj opterr = 0; for (;;) { - c = getopt_long(argc, argv, "i:Dvb", long_options, &option_index); + c = getopt_long(argc, argv, "i:vb", long_options, &option_index); if (c == -1) break; @@ -332,9 +330,6 @@ static void parse_command_line(struct ifobject *ifobj_tx, struct ifobject *ifobj interface_nb++; break; - case 'D': - opt_pkt_dump = true; - break; case 'v': opt_verbose = true; break; @@ -714,7 +709,7 @@ static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len) if (!pkt) { ksft_print_msg("[%s] too many packets received\n", __func__); - return false; + goto error; } if (len < MIN_PKT_SIZE || pkt->len < MIN_PKT_SIZE) { @@ -725,22 +720,23 @@ static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len) if (pkt->len != len) { ksft_print_msg("[%s] expected length [%d], got length [%d]\n", __func__, pkt->len, len); - return false; + goto error; } pkt_data = ntohl(*((u32 *)(data + PKT_HDR_SIZE))); seqnum = pkt_data >> 16; - if (opt_pkt_dump) - pkt_dump(data, len); - if (pkt->pkt_nb != seqnum) { ksft_print_msg("[%s] expected seqnum [%d], got seqnum [%d]\n", __func__, pkt->pkt_nb, seqnum); - return false; + goto error; } return true; + +error: + pkt_dump(data, len); + return false; } static void kick_tx(struct xsk_socket_info *xsk) diff --git a/tools/testing/selftests/bpf/xskxceiver.h b/tools/testing/selftests/bpf/xskxceiver.h index 91022c4876eb..5e0be9685557 100644 --- a/tools/testing/selftests/bpf/xskxceiver.h +++ b/tools/testing/selftests/bpf/xskxceiver.h @@ -85,7 +85,6 @@ enum test_type { TEST_TYPE_MAX }; -static bool opt_pkt_dump; static bool opt_verbose; struct xsk_umem_info { -- cgit v1.2.3 From 69fc03d220a318a4df2c6f0612b17225e71a6069 Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:04 +0200 Subject: selftests/xsk: add packet iterator for tx to packet stream Convert the current variable rx_pkt_nb to an iterator that can be used for both Rx and Tx. This to simplify the code and making Tx more like Rx that already has this feature. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-6-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xskxceiver.c | 43 +++++++++++++++++--------------- tools/testing/selftests/bpf/xskxceiver.h | 2 +- 2 files changed, 24 insertions(+), 21 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index 0a8231ed6626..0823890c0709 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -444,24 +444,24 @@ static void test_spec_set_xdp_prog(struct test_spec *test, struct bpf_program *x static void pkt_stream_reset(struct pkt_stream *pkt_stream) { if (pkt_stream) - pkt_stream->rx_pkt_nb = 0; + pkt_stream->current_pkt_nb = 0; } -static struct pkt *pkt_stream_get_pkt(struct pkt_stream *pkt_stream, u32 pkt_nb) +static struct pkt *pkt_stream_get_next_tx_pkt(struct pkt_stream *pkt_stream) { - if (pkt_nb >= pkt_stream->nb_pkts) + if (pkt_stream->current_pkt_nb >= pkt_stream->nb_pkts) return NULL; - return &pkt_stream->pkts[pkt_nb]; + return &pkt_stream->pkts[pkt_stream->current_pkt_nb++]; } static struct pkt *pkt_stream_get_next_rx_pkt(struct pkt_stream *pkt_stream, u32 *pkts_sent) { - while (pkt_stream->rx_pkt_nb < pkt_stream->nb_pkts) { + while (pkt_stream->current_pkt_nb < pkt_stream->nb_pkts) { (*pkts_sent)++; - if (pkt_stream->pkts[pkt_stream->rx_pkt_nb].valid) - return &pkt_stream->pkts[pkt_stream->rx_pkt_nb++]; - pkt_stream->rx_pkt_nb++; + if (pkt_stream->pkts[pkt_stream->current_pkt_nb].valid) + return &pkt_stream->pkts[pkt_stream->current_pkt_nb++]; + pkt_stream->current_pkt_nb++; } return NULL; } @@ -584,9 +584,9 @@ static void pkt_stream_receive_half(struct test_spec *test) pkt_stream->pkts[i].valid = false; } -static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb) +static struct pkt *pkt_generate(struct ifobject *ifobject) { - struct pkt *pkt = pkt_stream_get_pkt(ifobject->pkt_stream, pkt_nb); + struct pkt *pkt = pkt_stream_get_next_tx_pkt(ifobject->pkt_stream); struct ethhdr *eth_hdr; void *data; @@ -599,7 +599,7 @@ static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb) eth_hdr = data; gen_eth_hdr(ifobject, eth_hdr); - write_payload(data + PKT_HDR_SIZE, pkt_nb, pkt->len - PKT_HDR_SIZE); + write_payload(data + PKT_HDR_SIZE, pkt->pkt_nb, pkt->len - PKT_HDR_SIZE); return pkt; } @@ -883,8 +883,7 @@ static int receive_pkts(struct test_spec *test, struct pollfd *fds) return TEST_PASS; } -static int __send_pkts(struct ifobject *ifobject, u32 *pkt_nb, struct pollfd *fds, - bool timeout) +static int __send_pkts(struct ifobject *ifobject, struct pollfd *fds, bool timeout) { struct xsk_socket_info *xsk = ifobject->xsk; bool use_poll = ifobject->use_poll; @@ -916,14 +915,13 @@ static int __send_pkts(struct ifobject *ifobject, u32 *pkt_nb, struct pollfd *fd for (i = 0; i < BATCH_SIZE; i++) { struct xdp_desc *tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx + i); - struct pkt *pkt = pkt_generate(ifobject, *pkt_nb); + struct pkt *pkt = pkt_generate(ifobject); if (!pkt) break; tx_desc->addr = pkt->addr; tx_desc->len = pkt->len; - (*pkt_nb)++; if (pkt->valid) valid_pkts++; } @@ -970,15 +968,16 @@ static void wait_for_tx_completion(struct xsk_socket_info *xsk) static int send_pkts(struct test_spec *test, struct ifobject *ifobject) { + struct pkt_stream *pkt_stream = ifobject->pkt_stream; bool timeout = !is_umem_valid(test->ifobj_rx); struct pollfd fds = { }; - u32 pkt_cnt = 0, ret; + u32 ret; fds.fd = xsk_socket__fd(ifobject->xsk->xsk); fds.events = POLLOUT; - while (pkt_cnt < ifobject->pkt_stream->nb_pkts) { - ret = __send_pkts(ifobject, &pkt_cnt, &fds, timeout); + while (pkt_stream->current_pkt_nb < pkt_stream->nb_pkts) { + ret = __send_pkts(ifobject, &fds, timeout); if ((ret || test->fail) && !timeout) return TEST_FAILURE; else if (ret == TEST_PASS && timeout) @@ -1150,7 +1149,7 @@ static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream u64 addr; if (pkt_stream->use_addr_for_fill) { - struct pkt *pkt = pkt_stream_get_pkt(pkt_stream, i); + struct pkt *pkt = pkt_stream_get_next_tx_pkt(pkt_stream); if (!pkt) break; @@ -1162,6 +1161,8 @@ static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream *xsk_ring_prod__fill_addr(&umem->fq, idx++) = addr; } xsk_ring_prod__submit(&umem->fq, i); + + pkt_stream_reset(pkt_stream); } static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject) @@ -1339,9 +1340,11 @@ static int __testapp_validate_traffic(struct test_spec *test, struct ifobject *i { pthread_t t0, t1; - if (ifobj2) + if (ifobj2) { if (pthread_barrier_init(&barr, NULL, 2)) exit_with_error(errno); + pkt_stream_reset(ifobj2->pkt_stream); + } test->current_step++; pkt_stream_reset(ifobj1->pkt_stream); diff --git a/tools/testing/selftests/bpf/xskxceiver.h b/tools/testing/selftests/bpf/xskxceiver.h index 5e0be9685557..7ea28d844007 100644 --- a/tools/testing/selftests/bpf/xskxceiver.h +++ b/tools/testing/selftests/bpf/xskxceiver.h @@ -117,7 +117,7 @@ struct pkt { struct pkt_stream { u32 nb_pkts; - u32 rx_pkt_nb; + u32 current_pkt_nb; struct pkt *pkts; bool use_addr_for_fill; }; -- cgit v1.2.3 From d9f6d9709f87236f9a33de0d42dae8402b812e19 Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:05 +0200 Subject: selftests/xsk: store offset in pkt instead of addr Store the offset in struct pkt instead of the address. This is important since address is only meaningful in the context of a packet that is stored in a single umem buffer and thus a single Tx descriptor. If the packet, in contrast need to be represented by multiple buffers in the umem, storing the address makes no sense since the packet will consist of multiple buffers in the umem at various addresses. This change is in preparation for the upcoming multi-buffer support in AF_XDP and the corresponding tests. So instead of indicating the address, we instead indicate the offset of the packet in the first buffer. The actual address of the buffer is allocated from the umem with a new function called umem_alloc_buffer(). This also means we can get rid of the use_fill_for_addr flag as the addresses fed into the fill ring will always be the offset from the pkt specification in the packet stream plus the address of the allocated buffer from the umem. No special casing needed. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-7-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xskxceiver.c | 150 ++++++++++++++++++------------- tools/testing/selftests/bpf/xskxceiver.h | 4 +- 2 files changed, 90 insertions(+), 64 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index 0823890c0709..d488d859d3a2 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -167,7 +167,13 @@ static u32 mode_to_xdp_flags(enum test_mode mode) return (mode == TEST_MODE_SKB) ? XDP_FLAGS_SKB_MODE : XDP_FLAGS_DRV_MODE; } -static int xsk_configure_umem(struct xsk_umem_info *umem, void *buffer, u64 size) +static u64 umem_size(struct xsk_umem_info *umem) +{ + return umem->num_frames * umem->frame_size; +} + +static int xsk_configure_umem(struct ifobject *ifobj, struct xsk_umem_info *umem, void *buffer, + u64 size) { struct xsk_umem_config cfg = { .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS, @@ -187,9 +193,31 @@ static int xsk_configure_umem(struct xsk_umem_info *umem, void *buffer, u64 size return ret; umem->buffer = buffer; + if (ifobj->shared_umem && ifobj->rx_on) { + umem->base_addr = umem_size(umem); + umem->next_buffer = umem_size(umem); + } + return 0; } +static u64 umem_alloc_buffer(struct xsk_umem_info *umem) +{ + u64 addr; + + addr = umem->next_buffer; + umem->next_buffer += umem->frame_size; + if (umem->next_buffer >= umem->base_addr + umem_size(umem)) + umem->next_buffer = umem->base_addr; + + return addr; +} + +static void umem_reset_alloc(struct xsk_umem_info *umem) +{ + umem->next_buffer = 0; +} + static void enable_busy_poll(struct xsk_socket_info *xsk) { int sock_opt; @@ -249,7 +277,7 @@ static bool ifobj_zc_avail(struct ifobject *ifobject) exit_with_error(ENOMEM); } umem->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE; - ret = xsk_configure_umem(umem, bufs, umem_sz); + ret = xsk_configure_umem(ifobject, umem, bufs, umem_sz); if (ret) exit_with_error(-ret); @@ -372,9 +400,6 @@ static void __test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx, memset(ifobj->umem, 0, sizeof(*ifobj->umem)); ifobj->umem->num_frames = DEFAULT_UMEM_BUFFERS; ifobj->umem->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE; - if (ifobj->shared_umem && ifobj->rx_on) - ifobj->umem->base_addr = DEFAULT_UMEM_BUFFERS * - XSK_UMEM__DEFAULT_FRAME_SIZE; for (j = 0; j < MAX_SOCKETS; j++) { memset(&ifobj->xsk_arr[j], 0, sizeof(ifobj->xsk_arr[j])); @@ -506,9 +531,9 @@ static struct pkt_stream *__pkt_stream_alloc(u32 nb_pkts) return pkt_stream; } -static void pkt_set(struct xsk_umem_info *umem, struct pkt *pkt, u64 addr, u32 len) +static void pkt_set(struct xsk_umem_info *umem, struct pkt *pkt, int offset, u32 len) { - pkt->addr = addr + umem->base_addr; + pkt->offset = offset; pkt->len = len; if (len > umem->frame_size - XDP_PACKET_HEADROOM - MIN_PKT_SIZE * 2 - umem->frame_headroom) pkt->valid = false; @@ -526,8 +551,7 @@ static struct pkt_stream *pkt_stream_generate(struct xsk_umem_info *umem, u32 nb exit_with_error(ENOMEM); for (i = 0; i < nb_pkts; i++) { - pkt_set(umem, &pkt_stream->pkts[i], (i % umem->num_frames) * umem->frame_size, - pkt_len); + pkt_set(umem, &pkt_stream->pkts[i], 0, pkt_len); pkt_stream->pkts[i].pkt_nb = i; } @@ -559,8 +583,7 @@ static void __pkt_stream_replace_half(struct ifobject *ifobj, u32 pkt_len, pkt_stream = pkt_stream_clone(umem, ifobj->pkt_stream); for (i = 1; i < ifobj->pkt_stream->nb_pkts; i += 2) - pkt_set(umem, &pkt_stream->pkts[i], - (i % umem->num_frames) * umem->frame_size + offset, pkt_len); + pkt_set(umem, &pkt_stream->pkts[i], offset, pkt_len); ifobj->pkt_stream = pkt_stream; } @@ -584,24 +607,26 @@ static void pkt_stream_receive_half(struct test_spec *test) pkt_stream->pkts[i].valid = false; } -static struct pkt *pkt_generate(struct ifobject *ifobject) +static u64 pkt_get_addr(struct pkt *pkt, struct xsk_umem_info *umem) +{ + if (!pkt->valid) + return pkt->offset; + return pkt->offset + umem_alloc_buffer(umem); +} + +static void pkt_generate(struct ifobject *ifobject, struct pkt *pkt, u64 addr) { - struct pkt *pkt = pkt_stream_get_next_tx_pkt(ifobject->pkt_stream); struct ethhdr *eth_hdr; void *data; - if (!pkt) - return NULL; if (!pkt->valid || pkt->len < MIN_PKT_SIZE) - return pkt; + return; - data = xsk_umem__get_data(ifobject->umem->buffer, pkt->addr); + data = xsk_umem__get_data(ifobject->umem->buffer, addr); eth_hdr = data; gen_eth_hdr(ifobject, eth_hdr); write_payload(data + PKT_HDR_SIZE, pkt->pkt_nb, pkt->len - PKT_HDR_SIZE); - - return pkt; } static void __pkt_stream_generate_custom(struct ifobject *ifobj, @@ -615,7 +640,7 @@ static void __pkt_stream_generate_custom(struct ifobject *ifobj, exit_with_error(ENOMEM); for (i = 0; i < nb_pkts; i++) { - pkt_stream->pkts[i].addr = pkts[i].addr + ifobj->umem->base_addr; + pkt_stream->pkts[i].offset = pkts[i].offset; pkt_stream->pkts[i].len = pkts[i].len; pkt_stream->pkts[i].pkt_nb = i; pkt_stream->pkts[i].valid = pkts[i].valid; @@ -670,16 +695,16 @@ static void pkt_dump(void *pkt, u32 len) fprintf(stdout, "\n---------------------------------------\n"); } -static bool is_offset_correct(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream, u64 addr, - u64 pkt_stream_addr) +static bool is_offset_correct(struct xsk_umem_info *umem, struct pkt *pkt, u64 addr) { u32 headroom = umem->unaligned_mode ? 0 : umem->frame_headroom; - u32 offset = addr % umem->frame_size, expected_offset = 0; + u32 offset = addr % umem->frame_size, expected_offset; + int pkt_offset = pkt->valid ? pkt->offset : 0; - if (!pkt_stream->use_addr_for_fill) - pkt_stream_addr = 0; + if (!umem->unaligned_mode) + pkt_offset = 0; - expected_offset += (pkt_stream_addr + headroom + XDP_PACKET_HEADROOM) % umem->frame_size; + expected_offset = (pkt_offset + headroom + XDP_PACKET_HEADROOM) % umem->frame_size; if (offset == expected_offset) return true; @@ -858,7 +883,7 @@ static int receive_pkts(struct test_spec *test, struct pollfd *fds) addr = xsk_umem__add_offset_to_addr(addr); if (!is_pkt_valid(pkt, umem->buffer, addr, desc->len) || - !is_offset_correct(umem, pkt_stream, addr, pkt->addr) || + !is_offset_correct(umem, pkt, addr) || (ifobj->use_metadata && !is_metadata_correct(pkt, umem->buffer, addr))) return TEST_FAILURE; @@ -915,15 +940,16 @@ static int __send_pkts(struct ifobject *ifobject, struct pollfd *fds, bool timeo for (i = 0; i < BATCH_SIZE; i++) { struct xdp_desc *tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx + i); - struct pkt *pkt = pkt_generate(ifobject); + struct pkt *pkt = pkt_stream_get_next_tx_pkt(ifobject->pkt_stream); if (!pkt) break; - tx_desc->addr = pkt->addr; + tx_desc->addr = pkt_get_addr(pkt, ifobject->umem); tx_desc->len = pkt->len; if (pkt->valid) valid_pkts++; + pkt_generate(ifobject, pkt, tx_desc->addr); } pthread_mutex_lock(&pacing_mutex); @@ -1130,11 +1156,12 @@ static void thread_common_ops_tx(struct test_spec *test, struct ifobject *ifobje ifobject->xsk = &ifobject->xsk_arr[0]; ifobject->xskmap = test->ifobj_rx->xskmap; memcpy(ifobject->umem, test->ifobj_rx->umem, sizeof(struct xsk_umem_info)); + ifobject->umem->base_addr = 0; } static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream) { - u32 idx = 0, i, buffers_to_fill; + u32 idx = 0, i, buffers_to_fill, nb_pkts; int ret; if (umem->num_frames < XSK_RING_PROD__DEFAULT_NUM_DESCS) @@ -1145,24 +1172,23 @@ static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream ret = xsk_ring_prod__reserve(&umem->fq, buffers_to_fill, &idx); if (ret != buffers_to_fill) exit_with_error(ENOSPC); + for (i = 0; i < buffers_to_fill; i++) { + struct pkt *pkt = pkt_stream_get_next_rx_pkt(pkt_stream, &nb_pkts); u64 addr; - if (pkt_stream->use_addr_for_fill) { - struct pkt *pkt = pkt_stream_get_next_tx_pkt(pkt_stream); - - if (!pkt) - break; - addr = pkt->addr; - } else { - addr = i * umem->frame_size; - } - + if (!pkt) + addr = i * umem->frame_size + umem->base_addr; + else if (pkt->offset >= 0) + addr = pkt->offset % umem->frame_size + umem_alloc_buffer(umem); + else + addr = pkt->offset + umem_alloc_buffer(umem); *xsk_ring_prod__fill_addr(&umem->fq, idx++) = addr; } xsk_ring_prod__submit(&umem->fq, i); pkt_stream_reset(pkt_stream); + umem_reset_alloc(umem); } static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject) @@ -1183,12 +1209,10 @@ static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject) if (bufs == MAP_FAILED) exit_with_error(errno); - ret = xsk_configure_umem(ifobject->umem, bufs, umem_sz); + ret = xsk_configure_umem(ifobject, ifobject->umem, bufs, umem_sz); if (ret) exit_with_error(-ret); - xsk_populate_fill_ring(ifobject->umem, ifobject->pkt_stream); - xsk_configure_socket(test, ifobject, ifobject->umem, false); ifobject->xsk = &ifobject->xsk_arr[0]; @@ -1196,6 +1220,8 @@ static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject) if (!ifobject->rx_on) return; + xsk_populate_fill_ring(ifobject->umem, ifobject->pkt_stream); + ret = xsk_update_xskmap(ifobject->xskmap, ifobject->xsk->xsk); if (ret) exit_with_error(errno); @@ -1543,9 +1569,8 @@ static bool testapp_unaligned(struct test_spec *test) test_spec_set_name(test, "UNALIGNED_MODE"); test->ifobj_tx->umem->unaligned_mode = true; test->ifobj_rx->umem->unaligned_mode = true; - /* Let half of the packets straddle a buffer boundrary */ + /* Let half of the packets straddle a 4K buffer boundary */ pkt_stream_replace_half(test, MIN_PKT_SIZE, -MIN_PKT_SIZE / 2); - test->ifobj_rx->pkt_stream->use_addr_for_fill = true; testapp_validate_traffic(test); return true; @@ -1553,7 +1578,7 @@ static bool testapp_unaligned(struct test_spec *test) static void testapp_single_pkt(struct test_spec *test) { - struct pkt pkts[] = {{0x1000, MIN_PKT_SIZE, 0, true}}; + struct pkt pkts[] = {{0, MIN_PKT_SIZE, 0, true}}; pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts)); testapp_validate_traffic(test); @@ -1561,42 +1586,43 @@ static void testapp_single_pkt(struct test_spec *test) static void testapp_invalid_desc(struct test_spec *test) { - u64 umem_size = test->ifobj_tx->umem->num_frames * test->ifobj_tx->umem->frame_size; + struct xsk_umem_info *umem = test->ifobj_tx->umem; + u64 umem_size = umem->num_frames * umem->frame_size; struct pkt pkts[] = { /* Zero packet address allowed */ {0, MIN_PKT_SIZE, 0, true}, /* Allowed packet */ - {0x1000, MIN_PKT_SIZE, 0, true}, + {0, MIN_PKT_SIZE, 0, true}, /* Straddling the start of umem */ {-2, MIN_PKT_SIZE, 0, false}, /* Packet too large */ - {0x2000, XSK_UMEM__INVALID_FRAME_SIZE, 0, false}, + {0, XSK_UMEM__INVALID_FRAME_SIZE, 0, false}, /* Up to end of umem allowed */ - {umem_size - MIN_PKT_SIZE, MIN_PKT_SIZE, 0, true}, + {umem_size - MIN_PKT_SIZE - 2 * umem->frame_size, MIN_PKT_SIZE, 0, true}, /* After umem ends */ {umem_size, MIN_PKT_SIZE, 0, false}, /* Straddle the end of umem */ {umem_size - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, false}, - /* Straddle a page boundrary */ - {0x3000 - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, false}, - /* Straddle a 2K boundrary */ - {0x3800 - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, true}, + /* Straddle a 4K boundary */ + {0x1000 - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, false}, + /* Straddle a 2K boundary */ + {0x800 - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, true}, /* Valid packet for synch so that something is received */ - {0x4000, MIN_PKT_SIZE, 0, true}}; + {0, MIN_PKT_SIZE, 0, true}}; - if (test->ifobj_tx->umem->unaligned_mode) { - /* Crossing a page boundrary allowed */ + if (umem->unaligned_mode) { + /* Crossing a page boundary allowed */ pkts[7].valid = true; } - if (test->ifobj_tx->umem->frame_size == XSK_UMEM__DEFAULT_FRAME_SIZE / 2) { - /* Crossing a 2K frame size boundrary not allowed */ + if (umem->frame_size == XSK_UMEM__DEFAULT_FRAME_SIZE / 2) { + /* Crossing a 2K frame size boundary not allowed */ pkts[8].valid = false; } if (test->ifobj_tx->shared_umem) { - pkts[4].addr += umem_size; - pkts[5].addr += umem_size; - pkts[6].addr += umem_size; + pkts[4].offset += umem_size; + pkts[5].offset += umem_size; + pkts[6].offset += umem_size; } pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts)); diff --git a/tools/testing/selftests/bpf/xskxceiver.h b/tools/testing/selftests/bpf/xskxceiver.h index 7ea28d844007..be4664a38d74 100644 --- a/tools/testing/selftests/bpf/xskxceiver.h +++ b/tools/testing/selftests/bpf/xskxceiver.h @@ -91,6 +91,7 @@ struct xsk_umem_info { struct xsk_ring_prod fq; struct xsk_ring_cons cq; struct xsk_umem *umem; + u64 next_buffer; u32 num_frames; u32 frame_headroom; void *buffer; @@ -109,7 +110,7 @@ struct xsk_socket_info { }; struct pkt { - u64 addr; + int offset; u32 len; u32 pkt_nb; bool valid; @@ -119,7 +120,6 @@ struct pkt_stream { u32 nb_pkts; u32 current_pkt_nb; struct pkt *pkts; - bool use_addr_for_fill; }; struct ifobject; -- cgit v1.2.3 From 041b68f688a38865434d7b8fbfe64beb03e54ff2 Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:06 +0200 Subject: selftests/xsx: test for huge pages only once Test for hugepages only once at the beginning of the execution of the whole test suite, instead of before each test that needs huge pages. These are the tests that use unaligned mode. As more unaligned tests will be added, so the current system just does not scale. With this change, there are now three possible outcomes of a test run: fail, pass, or skip. To simplify the handling of this, the function testapp_validate_traffic() now returns this value to the main loop. As this function is used by nearly all tests, it meant a small change to most of them. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-8-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xskxceiver.c | 186 +++++++++++++++---------------- tools/testing/selftests/bpf/xskxceiver.h | 2 + 2 files changed, 94 insertions(+), 94 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index d488d859d3a2..f0d929cb730a 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -1413,6 +1413,12 @@ static int testapp_validate_traffic(struct test_spec *test) struct ifobject *ifobj_rx = test->ifobj_rx; struct ifobject *ifobj_tx = test->ifobj_tx; + if ((ifobj_rx->umem->unaligned_mode && !ifobj_rx->unaligned_supp) || + (ifobj_tx->umem->unaligned_mode && !ifobj_tx->unaligned_supp)) { + ksft_test_result_skip("No huge pages present.\n"); + return TEST_SKIP; + } + xsk_attach_xdp_progs(test, ifobj_rx, ifobj_tx); return __testapp_validate_traffic(test, ifobj_rx, ifobj_tx); } @@ -1422,16 +1428,18 @@ static int testapp_validate_traffic_single_thread(struct test_spec *test, struct return __testapp_validate_traffic(test, ifobj, NULL); } -static void testapp_teardown(struct test_spec *test) +static int testapp_teardown(struct test_spec *test) { int i; test_spec_set_name(test, "TEARDOWN"); for (i = 0; i < MAX_TEARDOWN_ITER; i++) { if (testapp_validate_traffic(test)) - return; + return TEST_FAILURE; test_spec_reset(test); } + + return TEST_PASS; } static void swap_directions(struct ifobject **ifobj1, struct ifobject **ifobj2) @@ -1446,20 +1454,23 @@ static void swap_directions(struct ifobject **ifobj1, struct ifobject **ifobj2) *ifobj2 = tmp_ifobj; } -static void testapp_bidi(struct test_spec *test) +static int testapp_bidi(struct test_spec *test) { + int res; + test_spec_set_name(test, "BIDIRECTIONAL"); test->ifobj_tx->rx_on = true; test->ifobj_rx->tx_on = true; test->total_steps = 2; if (testapp_validate_traffic(test)) - return; + return TEST_FAILURE; print_verbose("Switching Tx/Rx vectors\n"); swap_directions(&test->ifobj_rx, &test->ifobj_tx); - __testapp_validate_traffic(test, test->ifobj_rx, test->ifobj_tx); + res = __testapp_validate_traffic(test, test->ifobj_rx, test->ifobj_tx); swap_directions(&test->ifobj_rx, &test->ifobj_tx); + return res; } static void swap_xsk_resources(struct ifobject *ifobj_tx, struct ifobject *ifobj_rx) @@ -1476,115 +1487,94 @@ static void swap_xsk_resources(struct ifobject *ifobj_tx, struct ifobject *ifobj exit_with_error(errno); } -static void testapp_bpf_res(struct test_spec *test) +static int testapp_bpf_res(struct test_spec *test) { test_spec_set_name(test, "BPF_RES"); test->total_steps = 2; test->nb_sockets = 2; if (testapp_validate_traffic(test)) - return; + return TEST_FAILURE; swap_xsk_resources(test->ifobj_tx, test->ifobj_rx); - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -static void testapp_headroom(struct test_spec *test) +static int testapp_headroom(struct test_spec *test) { test_spec_set_name(test, "UMEM_HEADROOM"); test->ifobj_rx->umem->frame_headroom = UMEM_HEADROOM_TEST_SIZE; - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -static void testapp_stats_rx_dropped(struct test_spec *test) +static int testapp_stats_rx_dropped(struct test_spec *test) { test_spec_set_name(test, "STAT_RX_DROPPED"); + if (test->mode == TEST_MODE_ZC) { + ksft_test_result_skip("Can not run RX_DROPPED test for ZC mode\n"); + return TEST_SKIP; + } + pkt_stream_replace_half(test, MIN_PKT_SIZE * 4, 0); test->ifobj_rx->umem->frame_headroom = test->ifobj_rx->umem->frame_size - XDP_PACKET_HEADROOM - MIN_PKT_SIZE * 3; pkt_stream_receive_half(test); test->ifobj_rx->validation_func = validate_rx_dropped; - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -static void testapp_stats_tx_invalid_descs(struct test_spec *test) +static int testapp_stats_tx_invalid_descs(struct test_spec *test) { test_spec_set_name(test, "STAT_TX_INVALID"); pkt_stream_replace_half(test, XSK_UMEM__INVALID_FRAME_SIZE, 0); test->ifobj_tx->validation_func = validate_tx_invalid_descs; - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -static void testapp_stats_rx_full(struct test_spec *test) +static int testapp_stats_rx_full(struct test_spec *test) { test_spec_set_name(test, "STAT_RX_FULL"); pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE); test->ifobj_rx->pkt_stream = pkt_stream_generate(test->ifobj_rx->umem, DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE); - if (!test->ifobj_rx->pkt_stream) - exit_with_error(ENOMEM); test->ifobj_rx->xsk->rxqsize = DEFAULT_UMEM_BUFFERS; test->ifobj_rx->release_rx = false; test->ifobj_rx->validation_func = validate_rx_full; - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -static void testapp_stats_fill_empty(struct test_spec *test) +static int testapp_stats_fill_empty(struct test_spec *test) { test_spec_set_name(test, "STAT_RX_FILL_EMPTY"); pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE); test->ifobj_rx->pkt_stream = pkt_stream_generate(test->ifobj_rx->umem, DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE); - if (!test->ifobj_rx->pkt_stream) - exit_with_error(ENOMEM); test->ifobj_rx->use_fill_ring = false; test->ifobj_rx->validation_func = validate_fill_empty; - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -/* Simple test */ -static bool hugepages_present(struct ifobject *ifobject) +static int testapp_unaligned(struct test_spec *test) { - size_t mmap_sz = 2 * ifobject->umem->num_frames * ifobject->umem->frame_size; - void *bufs; - - bufs = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_HUGE_2MB, -1, 0); - if (bufs == MAP_FAILED) - return false; - - mmap_sz = ceil_u64(mmap_sz, HUGEPAGE_SIZE) * HUGEPAGE_SIZE; - munmap(bufs, mmap_sz); - return true; -} - -static bool testapp_unaligned(struct test_spec *test) -{ - if (!hugepages_present(test->ifobj_tx)) { - ksft_test_result_skip("No 2M huge pages present.\n"); - return false; - } - test_spec_set_name(test, "UNALIGNED_MODE"); test->ifobj_tx->umem->unaligned_mode = true; test->ifobj_rx->umem->unaligned_mode = true; /* Let half of the packets straddle a 4K buffer boundary */ pkt_stream_replace_half(test, MIN_PKT_SIZE, -MIN_PKT_SIZE / 2); - testapp_validate_traffic(test); - return true; + return testapp_validate_traffic(test); } -static void testapp_single_pkt(struct test_spec *test) +static int testapp_single_pkt(struct test_spec *test) { struct pkt pkts[] = {{0, MIN_PKT_SIZE, 0, true}}; pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts)); - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -static void testapp_invalid_desc(struct test_spec *test) +static int testapp_invalid_desc(struct test_spec *test) { struct xsk_umem_info *umem = test->ifobj_tx->umem; u64 umem_size = umem->num_frames * umem->frame_size; @@ -1626,10 +1616,10 @@ static void testapp_invalid_desc(struct test_spec *test) } pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts)); - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -static void testapp_xdp_drop(struct test_spec *test) +static int testapp_xdp_drop(struct test_spec *test) { struct xsk_xdp_progs *skel_rx = test->ifobj_rx->xdp_progs; struct xsk_xdp_progs *skel_tx = test->ifobj_tx->xdp_progs; @@ -1639,10 +1629,10 @@ static void testapp_xdp_drop(struct test_spec *test) skel_rx->maps.xsk, skel_tx->maps.xsk); pkt_stream_receive_half(test); - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -static void testapp_xdp_metadata_count(struct test_spec *test) +static int testapp_xdp_metadata_count(struct test_spec *test) { struct xsk_xdp_progs *skel_rx = test->ifobj_rx->xdp_progs; struct xsk_xdp_progs *skel_tx = test->ifobj_tx->xdp_progs; @@ -1663,10 +1653,10 @@ static void testapp_xdp_metadata_count(struct test_spec *test) if (bpf_map_update_elem(bpf_map__fd(data_map), &key, &count, BPF_ANY)) exit_with_error(errno); - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -static void testapp_poll_txq_tmout(struct test_spec *test) +static int testapp_poll_txq_tmout(struct test_spec *test) { test_spec_set_name(test, "POLL_TXQ_FULL"); @@ -1674,14 +1664,14 @@ static void testapp_poll_txq_tmout(struct test_spec *test) /* create invalid frame by set umem frame_size and pkt length equal to 2048 */ test->ifobj_tx->umem->frame_size = 2048; pkt_stream_replace(test, 2 * DEFAULT_PKT_CNT, 2048); - testapp_validate_traffic_single_thread(test, test->ifobj_tx); + return testapp_validate_traffic_single_thread(test, test->ifobj_tx); } -static void testapp_poll_rxq_tmout(struct test_spec *test) +static int testapp_poll_rxq_tmout(struct test_spec *test) { test_spec_set_name(test, "POLL_RXQ_EMPTY"); test->ifobj_rx->use_poll = true; - testapp_validate_traffic_single_thread(test, test->ifobj_rx); + return testapp_validate_traffic_single_thread(test, test->ifobj_rx); } static int xsk_load_xdp_programs(struct ifobject *ifobj) @@ -1698,6 +1688,22 @@ static void xsk_unload_xdp_programs(struct ifobject *ifobj) xsk_xdp_progs__destroy(ifobj->xdp_progs); } +/* Simple test */ +static bool hugepages_present(void) +{ + size_t mmap_sz = 2 * DEFAULT_UMEM_BUFFERS * XSK_UMEM__DEFAULT_FRAME_SIZE; + void *bufs; + + bufs = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, MAP_HUGE_2MB); + if (bufs == MAP_FAILED) + return false; + + mmap_sz = ceil_u64(mmap_sz, HUGEPAGE_SIZE) * HUGEPAGE_SIZE; + munmap(bufs, mmap_sz); + return true; +} + static void init_iface(struct ifobject *ifobj, const char *dst_mac, const char *src_mac, thread_func_t func_ptr) { @@ -1713,94 +1719,87 @@ static void init_iface(struct ifobject *ifobj, const char *dst_mac, const char * printf("Error loading XDP program\n"); exit_with_error(err); } + + if (hugepages_present()) + ifobj->unaligned_supp = true; } static void run_pkt_test(struct test_spec *test, enum test_mode mode, enum test_type type) { + int ret = TEST_SKIP; + switch (type) { case TEST_TYPE_STATS_RX_DROPPED: - if (mode == TEST_MODE_ZC) { - ksft_test_result_skip("Can not run RX_DROPPED test for ZC mode\n"); - return; - } - testapp_stats_rx_dropped(test); + ret = testapp_stats_rx_dropped(test); break; case TEST_TYPE_STATS_TX_INVALID_DESCS: - testapp_stats_tx_invalid_descs(test); + ret = testapp_stats_tx_invalid_descs(test); break; case TEST_TYPE_STATS_RX_FULL: - testapp_stats_rx_full(test); + ret = testapp_stats_rx_full(test); break; case TEST_TYPE_STATS_FILL_EMPTY: - testapp_stats_fill_empty(test); + ret = testapp_stats_fill_empty(test); break; case TEST_TYPE_TEARDOWN: - testapp_teardown(test); + ret = testapp_teardown(test); break; case TEST_TYPE_BIDI: - testapp_bidi(test); + ret = testapp_bidi(test); break; case TEST_TYPE_BPF_RES: - testapp_bpf_res(test); + ret = testapp_bpf_res(test); break; case TEST_TYPE_RUN_TO_COMPLETION: test_spec_set_name(test, "RUN_TO_COMPLETION"); - testapp_validate_traffic(test); + ret = testapp_validate_traffic(test); break; case TEST_TYPE_RUN_TO_COMPLETION_SINGLE_PKT: test_spec_set_name(test, "RUN_TO_COMPLETION_SINGLE_PKT"); - testapp_single_pkt(test); + ret = testapp_single_pkt(test); break; case TEST_TYPE_RUN_TO_COMPLETION_2K_FRAME: test_spec_set_name(test, "RUN_TO_COMPLETION_2K_FRAME_SIZE"); test->ifobj_tx->umem->frame_size = 2048; test->ifobj_rx->umem->frame_size = 2048; pkt_stream_replace(test, DEFAULT_PKT_CNT, MIN_PKT_SIZE); - testapp_validate_traffic(test); + ret = testapp_validate_traffic(test); break; case TEST_TYPE_RX_POLL: test->ifobj_rx->use_poll = true; test_spec_set_name(test, "POLL_RX"); - testapp_validate_traffic(test); + ret = testapp_validate_traffic(test); break; case TEST_TYPE_TX_POLL: test->ifobj_tx->use_poll = true; test_spec_set_name(test, "POLL_TX"); - testapp_validate_traffic(test); + ret = testapp_validate_traffic(test); break; case TEST_TYPE_POLL_TXQ_TMOUT: - testapp_poll_txq_tmout(test); + ret = testapp_poll_txq_tmout(test); break; case TEST_TYPE_POLL_RXQ_TMOUT: - testapp_poll_rxq_tmout(test); + ret = testapp_poll_rxq_tmout(test); break; case TEST_TYPE_ALIGNED_INV_DESC: test_spec_set_name(test, "ALIGNED_INV_DESC"); - testapp_invalid_desc(test); + ret = testapp_invalid_desc(test); break; case TEST_TYPE_ALIGNED_INV_DESC_2K_FRAME: test_spec_set_name(test, "ALIGNED_INV_DESC_2K_FRAME_SIZE"); test->ifobj_tx->umem->frame_size = 2048; test->ifobj_rx->umem->frame_size = 2048; - testapp_invalid_desc(test); + ret = testapp_invalid_desc(test); break; case TEST_TYPE_UNALIGNED_INV_DESC: - if (!hugepages_present(test->ifobj_tx)) { - ksft_test_result_skip("No 2M huge pages present.\n"); - return; - } test_spec_set_name(test, "UNALIGNED_INV_DESC"); test->ifobj_tx->umem->unaligned_mode = true; test->ifobj_rx->umem->unaligned_mode = true; - testapp_invalid_desc(test); + ret = testapp_invalid_desc(test); break; case TEST_TYPE_UNALIGNED_INV_DESC_4K1_FRAME: { u64 page_size, umem_size; - if (!hugepages_present(test->ifobj_tx)) { - ksft_test_result_skip("No 2M huge pages present.\n"); - return; - } test_spec_set_name(test, "UNALIGNED_INV_DESC_4K1_FRAME_SIZE"); /* Odd frame size so the UMEM doesn't end near a page boundary. */ test->ifobj_tx->umem->frame_size = 4001; @@ -1814,27 +1813,26 @@ static void run_pkt_test(struct test_spec *test, enum test_mode mode, enum test_ umem_size = test->ifobj_tx->umem->num_frames * test->ifobj_tx->umem->frame_size; assert(umem_size % page_size > MIN_PKT_SIZE); assert(umem_size % page_size < page_size - MIN_PKT_SIZE); - testapp_invalid_desc(test); + ret = testapp_invalid_desc(test); break; } case TEST_TYPE_UNALIGNED: - if (!testapp_unaligned(test)) - return; + ret = testapp_unaligned(test); break; case TEST_TYPE_HEADROOM: - testapp_headroom(test); + ret = testapp_headroom(test); break; case TEST_TYPE_XDP_DROP_HALF: - testapp_xdp_drop(test); + ret = testapp_xdp_drop(test); break; case TEST_TYPE_XDP_METADATA_COUNT: - testapp_xdp_metadata_count(test); + ret = testapp_xdp_metadata_count(test); break; default: break; } - if (!test->fail) + if (ret == TEST_PASS) ksft_test_result_pass("PASS: %s %s%s\n", mode_string(test), busy_poll_string(test), test->name); pkt_stream_restore_default(test); diff --git a/tools/testing/selftests/bpf/xskxceiver.h b/tools/testing/selftests/bpf/xskxceiver.h index be4664a38d74..00862732e751 100644 --- a/tools/testing/selftests/bpf/xskxceiver.h +++ b/tools/testing/selftests/bpf/xskxceiver.h @@ -30,6 +30,7 @@ #define TEST_PASS 0 #define TEST_FAILURE -1 #define TEST_CONTINUE 1 +#define TEST_SKIP 2 #define MAX_INTERFACES 2 #define MAX_INTERFACE_NAME_CHARS 16 #define MAX_SOCKETS 2 @@ -148,6 +149,7 @@ struct ifobject { bool release_rx; bool shared_umem; bool use_metadata; + bool unaligned_supp; u8 dst_mac[ETH_ALEN]; u8 src_mac[ETH_ALEN]; }; -- cgit v1.2.3 From 86e41755b43227858ef04b452c25b9dbcf667622 Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:07 +0200 Subject: selftests/xsk: populate fill ring based on frags needed Populate the fill ring based on the number of frags a packet needs. With multi-buffer support, a packet might require more than a single fragment/buffer, so the function xsk_populate_fill_ring() needs to consider how many buffers a packet will consume, and put that many buffers on the fill ring for each packet it should receive. As we are still not sending any multi-buffer packets, the function will only produce one buffer per packet at the moment. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-9-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xsk.h | 5 ++++ tools/testing/selftests/bpf/xskxceiver.c | 48 ++++++++++++++++++++++++-------- 2 files changed, 41 insertions(+), 12 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/xsk.h b/tools/testing/selftests/bpf/xsk.h index 04ed8b544712..8da8d557768b 100644 --- a/tools/testing/selftests/bpf/xsk.h +++ b/tools/testing/selftests/bpf/xsk.h @@ -134,6 +134,11 @@ static inline void xsk_ring_prod__submit(struct xsk_ring_prod *prod, __u32 nb) __atomic_store_n(prod->producer, *prod->producer + nb, __ATOMIC_RELEASE); } +static inline void xsk_ring_prod__cancel(struct xsk_ring_prod *prod, __u32 nb) +{ + prod->cached_prod -= nb; +} + static inline __u32 xsk_ring_cons__peek(struct xsk_ring_cons *cons, __u32 nb, __u32 *idx) { __u32 entries = xsk_cons_nb_avail(cons, nb); diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index f0d929cb730a..c54f25dcf134 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -531,6 +531,18 @@ static struct pkt_stream *__pkt_stream_alloc(u32 nb_pkts) return pkt_stream; } +static u32 ceil_u32(u32 a, u32 b) +{ + return (a + b - 1) / b; +} + +static u32 pkt_nb_frags(u32 frame_size, struct pkt *pkt) +{ + if (!pkt || !pkt->valid) + return 1; + return ceil_u32(pkt->len, frame_size); +} + static void pkt_set(struct xsk_umem_info *umem, struct pkt *pkt, int offset, u32 len) { pkt->offset = offset; @@ -1159,9 +1171,11 @@ static void thread_common_ops_tx(struct test_spec *test, struct ifobject *ifobje ifobject->umem->base_addr = 0; } -static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream) +static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream, + bool fill_up) { - u32 idx = 0, i, buffers_to_fill, nb_pkts; + u32 rx_frame_size = umem->frame_size - XDP_PACKET_HEADROOM; + u32 idx = 0, filled = 0, buffers_to_fill, nb_pkts; int ret; if (umem->num_frames < XSK_RING_PROD__DEFAULT_NUM_DESCS) @@ -1173,19 +1187,29 @@ static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream if (ret != buffers_to_fill) exit_with_error(ENOSPC); - for (i = 0; i < buffers_to_fill; i++) { + while (filled < buffers_to_fill) { struct pkt *pkt = pkt_stream_get_next_rx_pkt(pkt_stream, &nb_pkts); u64 addr; + u32 i; + + for (i = 0; i < pkt_nb_frags(rx_frame_size, pkt); i++) { + if (!pkt) { + if (!fill_up) + break; + addr = filled * umem->frame_size + umem->base_addr; + } else if (pkt->offset >= 0) { + addr = pkt->offset % umem->frame_size + umem_alloc_buffer(umem); + } else { + addr = pkt->offset + umem_alloc_buffer(umem); + } - if (!pkt) - addr = i * umem->frame_size + umem->base_addr; - else if (pkt->offset >= 0) - addr = pkt->offset % umem->frame_size + umem_alloc_buffer(umem); - else - addr = pkt->offset + umem_alloc_buffer(umem); - *xsk_ring_prod__fill_addr(&umem->fq, idx++) = addr; + *xsk_ring_prod__fill_addr(&umem->fq, idx++) = addr; + if (++filled >= buffers_to_fill) + break; + } } - xsk_ring_prod__submit(&umem->fq, i); + xsk_ring_prod__submit(&umem->fq, filled); + xsk_ring_prod__cancel(&umem->fq, buffers_to_fill - filled); pkt_stream_reset(pkt_stream); umem_reset_alloc(umem); @@ -1220,7 +1244,7 @@ static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject) if (!ifobject->rx_on) return; - xsk_populate_fill_ring(ifobject->umem, ifobject->pkt_stream); + xsk_populate_fill_ring(ifobject->umem, ifobject->pkt_stream, ifobject->use_fill_ring); ret = xsk_update_xskmap(ifobject->xskmap, ifobject->xsk->xsk); if (ret) -- cgit v1.2.3 From 2f6eae0df1a80bb636f43f1b954678da0a10fa49 Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:08 +0200 Subject: selftests/xsk: generate data for multi-buffer packets Add the ability to generate data in the packets that are correct for multi-buffer packets. The ethernet header should only go into the first fragment followed by data and the others should only have data. We also need to modify the pkt_dump function so that it knows what fragment has an ethernet header so it can print this. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-10-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xskxceiver.c | 70 ++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 27 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index c54f25dcf134..b48017611499 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -142,12 +142,14 @@ static void report_failure(struct test_spec *test) * 16-bits and a intra packet data sequence number in the lower 16 bits. So the 3rd packet's * 5th word of data will contain the number (2<<16) | 4 as they are numbered from 0. */ -static void write_payload(void *dest, u32 val, u32 size) +static void write_payload(void *dest, u32 pkt_nb, u32 start, u32 size) { u32 *ptr = (u32 *)dest, i; - for (i = 0; i < size / sizeof(*ptr); i++) - ptr[i] = htonl(val << 16 | i); + start /= sizeof(*ptr); + size /= sizeof(*ptr); + for (i = 0; i < size; i++) + ptr[i] = htonl(pkt_nb << 16 | (i + start)); } static void gen_eth_hdr(struct ifobject *ifobject, struct ethhdr *eth_hdr) @@ -563,8 +565,10 @@ static struct pkt_stream *pkt_stream_generate(struct xsk_umem_info *umem, u32 nb exit_with_error(ENOMEM); for (i = 0; i < nb_pkts; i++) { - pkt_set(umem, &pkt_stream->pkts[i], 0, pkt_len); - pkt_stream->pkts[i].pkt_nb = i; + struct pkt *pkt = &pkt_stream->pkts[i]; + + pkt_set(umem, pkt, 0, pkt_len); + pkt->pkt_nb = i; } return pkt_stream; @@ -626,19 +630,24 @@ static u64 pkt_get_addr(struct pkt *pkt, struct xsk_umem_info *umem) return pkt->offset + umem_alloc_buffer(umem); } -static void pkt_generate(struct ifobject *ifobject, struct pkt *pkt, u64 addr) +static void pkt_generate(struct ifobject *ifobject, u64 addr, u32 len, u32 pkt_nb, + u32 bytes_written) { - struct ethhdr *eth_hdr; - void *data; + void *data = xsk_umem__get_data(ifobject->umem->buffer, addr); - if (!pkt->valid || pkt->len < MIN_PKT_SIZE) + if (len < MIN_PKT_SIZE) return; - data = xsk_umem__get_data(ifobject->umem->buffer, addr); - eth_hdr = data; + if (!bytes_written) { + gen_eth_hdr(ifobject, data); + + len -= PKT_HDR_SIZE; + data += PKT_HDR_SIZE; + } else { + bytes_written -= PKT_HDR_SIZE; + } - gen_eth_hdr(ifobject, eth_hdr); - write_payload(data + PKT_HDR_SIZE, pkt->pkt_nb, pkt->len - PKT_HDR_SIZE); + write_payload(data, pkt_nb, bytes_written, len); } static void __pkt_stream_generate_custom(struct ifobject *ifobj, @@ -681,27 +690,33 @@ static void pkt_print_data(u32 *data, u32 cnt) } } -static void pkt_dump(void *pkt, u32 len) +static void pkt_dump(void *pkt, u32 len, bool eth_header) { struct ethhdr *ethhdr = pkt; - u32 i; + u32 i, *data; - /*extract L2 frame */ - fprintf(stdout, "DEBUG>> L2: dst mac: "); - for (i = 0; i < ETH_ALEN; i++) - fprintf(stdout, "%02X", ethhdr->h_dest[i]); + if (eth_header) { + /*extract L2 frame */ + fprintf(stdout, "DEBUG>> L2: dst mac: "); + for (i = 0; i < ETH_ALEN; i++) + fprintf(stdout, "%02X", ethhdr->h_dest[i]); - fprintf(stdout, "\nDEBUG>> L2: src mac: "); - for (i = 0; i < ETH_ALEN; i++) - fprintf(stdout, "%02X", ethhdr->h_source[i]); + fprintf(stdout, "\nDEBUG>> L2: src mac: "); + for (i = 0; i < ETH_ALEN; i++) + fprintf(stdout, "%02X", ethhdr->h_source[i]); + + data = pkt + PKT_HDR_SIZE; + } else { + data = pkt; + } /*extract L5 frame */ fprintf(stdout, "\nDEBUG>> L5: seqnum: "); - pkt_print_data(pkt + PKT_HDR_SIZE, PKT_DUMP_NB_TO_PRINT); + pkt_print_data(data, PKT_DUMP_NB_TO_PRINT); fprintf(stdout, "...."); if (len > PKT_DUMP_NB_TO_PRINT * sizeof(u32)) { fprintf(stdout, "\n.... "); - pkt_print_data(pkt + PKT_HDR_SIZE + len - PKT_DUMP_NB_TO_PRINT * sizeof(u32), + pkt_print_data(data + len / sizeof(u32) - PKT_DUMP_NB_TO_PRINT, PKT_DUMP_NB_TO_PRINT); } fprintf(stdout, "\n---------------------------------------\n"); @@ -772,7 +787,7 @@ static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len) return true; error: - pkt_dump(data, len); + pkt_dump(data, len, true); return false; } @@ -959,9 +974,10 @@ static int __send_pkts(struct ifobject *ifobject, struct pollfd *fds, bool timeo tx_desc->addr = pkt_get_addr(pkt, ifobject->umem); tx_desc->len = pkt->len; - if (pkt->valid) + if (pkt->valid) { valid_pkts++; - pkt_generate(ifobject, pkt, tx_desc->addr); + pkt_generate(ifobject, tx_desc->addr, tx_desc->len, pkt->pkt_nb, 0); + } } pthread_mutex_lock(&pacing_mutex); -- cgit v1.2.3 From 7cd6df4f5ec278888b4c3ab12b291c2124b46c1c Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:09 +0200 Subject: selftests/xsk: adjust packet pacing for multi-buffer support Modify the packet pacing algorithm so that it works with multi-buffer packets. This algorithm makes sure we do not send too many buffers to the receiving thread so that packets have to be dropped. The previous algorithm made the assumption that each packet only consumes one buffer, but that is not true anymore when multi-buffer support gets added. Instead, we find out what the largest packet size is in the packet stream and assume that each packet will consume this many buffers. This is conservative and overly cautious as there might be smaller packets in the stream that need fewer buffers per packet. But it keeps the algorithm simple. Also simplify it by removing the pthread conditional and just test if there is enough space in the Rx thread before trying to send one more batch. Also makes the tests run faster. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-11-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xskxceiver.c | 48 +++++++++++++++++++------------- tools/testing/selftests/bpf/xskxceiver.h | 2 +- 2 files changed, 30 insertions(+), 20 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index b48017611499..218d7f694e5c 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -555,6 +555,11 @@ static void pkt_set(struct xsk_umem_info *umem, struct pkt *pkt, int offset, u32 pkt->valid = true; } +static u32 pkt_get_buffer_len(struct xsk_umem_info *umem, u32 len) +{ + return ceil_u32(len, umem->frame_size) * umem->frame_size; +} + static struct pkt_stream *pkt_stream_generate(struct xsk_umem_info *umem, u32 nb_pkts, u32 pkt_len) { struct pkt_stream *pkt_stream; @@ -564,6 +569,8 @@ static struct pkt_stream *pkt_stream_generate(struct xsk_umem_info *umem, u32 nb if (!pkt_stream) exit_with_error(ENOMEM); + pkt_stream->nb_pkts = nb_pkts; + pkt_stream->max_pkt_len = pkt_len; for (i = 0; i < nb_pkts; i++) { struct pkt *pkt = &pkt_stream->pkts[i]; @@ -661,10 +668,14 @@ static void __pkt_stream_generate_custom(struct ifobject *ifobj, exit_with_error(ENOMEM); for (i = 0; i < nb_pkts; i++) { - pkt_stream->pkts[i].offset = pkts[i].offset; - pkt_stream->pkts[i].len = pkts[i].len; - pkt_stream->pkts[i].pkt_nb = i; - pkt_stream->pkts[i].valid = pkts[i].valid; + struct pkt *pkt = &pkt_stream->pkts[i]; + + pkt->offset = pkts[i].offset; + pkt->len = pkts[i].len; + pkt->pkt_nb = i; + pkt->valid = pkts[i].valid; + if (pkt->len > pkt_stream->max_pkt_len) + pkt_stream->max_pkt_len = pkt->len; } ifobj->pkt_stream = pkt_stream; @@ -926,8 +937,6 @@ static int receive_pkts(struct test_spec *test, struct pollfd *fds) pthread_mutex_lock(&pacing_mutex); pkts_in_flight -= pkts_sent; - if (pkts_in_flight < umem->num_frames) - pthread_cond_signal(&pacing_cond); pthread_mutex_unlock(&pacing_mutex); pkts_sent = 0; } @@ -938,10 +947,18 @@ static int receive_pkts(struct test_spec *test, struct pollfd *fds) static int __send_pkts(struct ifobject *ifobject, struct pollfd *fds, bool timeout) { struct xsk_socket_info *xsk = ifobject->xsk; + struct xsk_umem_info *umem = ifobject->umem; + u32 i, idx = 0, valid_pkts = 0, buffer_len; bool use_poll = ifobject->use_poll; - u32 i, idx = 0, valid_pkts = 0; int ret; + buffer_len = pkt_get_buffer_len(umem, ifobject->pkt_stream->max_pkt_len); + /* pkts_in_flight might be negative if many invalid packets are sent */ + if (pkts_in_flight >= (int)((umem_size(umem) - BATCH_SIZE * buffer_len) / buffer_len)) { + kick_tx(xsk); + return TEST_CONTINUE; + } + while (xsk_ring_prod__reserve(&xsk->tx, BATCH_SIZE, &idx) < BATCH_SIZE) { if (use_poll) { ret = poll(fds, 1, POLL_TMOUT); @@ -972,7 +989,7 @@ static int __send_pkts(struct ifobject *ifobject, struct pollfd *fds, bool timeo if (!pkt) break; - tx_desc->addr = pkt_get_addr(pkt, ifobject->umem); + tx_desc->addr = pkt_get_addr(pkt, umem); tx_desc->len = pkt->len; if (pkt->valid) { valid_pkts++; @@ -982,11 +999,6 @@ static int __send_pkts(struct ifobject *ifobject, struct pollfd *fds, bool timeo pthread_mutex_lock(&pacing_mutex); pkts_in_flight += valid_pkts; - /* pkts_in_flight might be negative if many invalid packets are sent */ - if (pkts_in_flight >= (int)(ifobject->umem->num_frames - BATCH_SIZE)) { - kick_tx(xsk); - pthread_cond_wait(&pacing_cond, &pacing_mutex); - } pthread_mutex_unlock(&pacing_mutex); xsk_ring_prod__submit(&xsk->tx, i); @@ -1032,9 +1044,11 @@ static int send_pkts(struct test_spec *test, struct ifobject *ifobject) while (pkt_stream->current_pkt_nb < pkt_stream->nb_pkts) { ret = __send_pkts(ifobject, &fds, timeout); + if (ret == TEST_CONTINUE && !test->fail) + continue; if ((ret || test->fail) && !timeout) return TEST_FAILURE; - else if (ret == TEST_PASS && timeout) + if (ret == TEST_PASS && timeout) return ret; } @@ -1319,12 +1333,8 @@ static void *worker_testapp_validate_rx(void *arg) if (!err && ifobject->validation_func) err = ifobject->validation_func(ifobject); - if (err) { + if (err) report_failure(test); - pthread_mutex_lock(&pacing_mutex); - pthread_cond_signal(&pacing_cond); - pthread_mutex_unlock(&pacing_mutex); - } pthread_exit(NULL); } diff --git a/tools/testing/selftests/bpf/xskxceiver.h b/tools/testing/selftests/bpf/xskxceiver.h index 00862732e751..aaf27e067640 100644 --- a/tools/testing/selftests/bpf/xskxceiver.h +++ b/tools/testing/selftests/bpf/xskxceiver.h @@ -121,6 +121,7 @@ struct pkt_stream { u32 nb_pkts; u32 current_pkt_nb; struct pkt *pkts; + u32 max_pkt_len; }; struct ifobject; @@ -173,7 +174,6 @@ struct test_spec { pthread_barrier_t barr; pthread_mutex_t pacing_mutex = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t pacing_cond = PTHREAD_COND_INITIALIZER; int pkts_in_flight; -- cgit v1.2.3 From f04a32b2c5b539e3c097cb5c7c1df12a8f4a0cf0 Mon Sep 17 00:00:00 2001 From: Alexey Gladkov Date: Wed, 17 May 2023 11:49:46 +0200 Subject: selftests/bpf: Do not use sign-file as testcase The sign-file utility (from scripts/) is used in prog_tests/verify_pkcs7_sig.c, but the utility should not be called as a test. Executing this utility produces the following error: selftests: /linux/tools/testing/selftests/bpf: urandom_read ok 16 selftests: /linux/tools/testing/selftests/bpf: urandom_read selftests: /linux/tools/testing/selftests/bpf: sign-file not ok 17 selftests: /linux/tools/testing/selftests/bpf: sign-file # exit=2 Also, urandom_read is mistakenly used as a test. It does not lead to an error, but should be moved over to TEST_GEN_FILES as well. The empty TEST_CUSTOM_PROGS can then be removed. Fixes: fc97590668ae ("selftests/bpf: Add test for bpf_verify_pkcs7_signature() kfunc") Signed-off-by: Alexey Gladkov Signed-off-by: Daniel Borkmann Reviewed-by: Roberto Sassu Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/ZEuWFk3QyML9y5QQ@example.org Link: https://lore.kernel.org/bpf/88e3ab23029d726a2703adcf6af8356f7a2d3483.1684316821.git.legion@kernel.org --- tools/testing/selftests/bpf/Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index c49e5403ad0e..cd2426cca3d0 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -88,8 +88,7 @@ TEST_GEN_PROGS_EXTENDED = test_sock_addr test_skb_cgroup_id_user \ xskxceiver xdp_redirect_multi xdp_synproxy veristat xdp_hw_metadata \ xdp_features -TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read $(OUTPUT)/sign-file -TEST_GEN_FILES += liburandom_read.so +TEST_GEN_FILES += liburandom_read.so urandom_read sign-file # Emit succinct information message describing current building step # $1 - generic step name (e.g., CC, LINK, etc); -- cgit v1.2.3 From 12852f8e0f70d9a5263e2834c5483268b08b5e9c Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 16 May 2023 21:04:04 -0700 Subject: selftests/bpf: Fix dynptr/test_dynptr_is_null With latest llvm17, dynptr/test_dynptr_is_null subtest failed in my testing VM. The failure log looks like below: All error logs: tester_init:PASS:tester_log_buf 0 nsec process_subtest:PASS:obj_open_mem 0 nsec process_subtest:PASS:Can't alloc specs array 0 nsec verify_success:PASS:dynptr_success__open 0 nsec verify_success:PASS:bpf_object__find_program_by_name 0 nsec verify_success:PASS:dynptr_success__load 0 nsec verify_success:PASS:bpf_program__attach 0 nsec verify_success:FAIL:err unexpected err: actual 4 != expected 0 #65/9 dynptr/test_dynptr_is_null:FAIL The error happens for bpf prog test_dynptr_is_null in dynptr_success.c: if (bpf_dynptr_is_null(&ptr2)) { err = 4; goto exit; } The bpf_dynptr_is_null(&ptr) unexpectedly returned a non-zero value and the control went to the error path. Digging further, I found the root cause is due to function signature difference between kernel and user space. In kernel, we have ... __bpf_kfunc bool bpf_dynptr_is_null(struct bpf_dynptr_kern *ptr) ... while in bpf_kfuncs.h we have: extern int bpf_dynptr_is_null(const struct bpf_dynptr *ptr) __ksym; The kernel bpf_dynptr_is_null disasm code: ffffffff812f1a90 : ffffffff812f1a90: f3 0f 1e fa endbr64 ffffffff812f1a94: 0f 1f 44 00 00 nopl (%rax,%rax) ffffffff812f1a99: 53 pushq %rbx ffffffff812f1a9a: 48 89 fb movq %rdi, %rbx ffffffff812f1a9d: e8 ae 29 17 00 callq 0xffffffff81464450 <__asan_load8_noabort> ffffffff812f1aa2: 48 83 3b 00 cmpq $0x0, (%rbx) ffffffff812f1aa6: 0f 94 c0 sete %al ffffffff812f1aa9: 5b popq %rbx ffffffff812f1aaa: c3 retq Note that only 1-byte register %al is set and the other 7-bytes are not touched. In bpf program, the asm code for the above bpf_dynptr_is_null(&ptr2): 266: 85 10 00 00 ff ff ff ff call -0x1 267: b4 01 00 00 04 00 00 00 w1 = 0x4 268: 16 00 03 00 00 00 00 00 if w0 == 0x0 goto +0x3 Basically, 4-byte subregister is tested. This might cause error as the value other than the lowest byte might not be 0. This patch fixed the issue by using the identical func prototype across kernel and selftest user space. The fixed bpf asm code: 267: 85 10 00 00 ff ff ff ff call -0x1 268: 54 00 00 00 01 00 00 00 w0 &= 0x1 269: b4 01 00 00 04 00 00 00 w1 = 0x4 270: 16 00 03 00 00 00 00 00 if w0 == 0x0 goto +0x3 Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230517040404.4023912-1-yhs@fb.com --- tools/testing/selftests/bpf/bpf_kfuncs.h | 2 +- tools/testing/selftests/bpf/progs/dynptr_fail.c | 1 + tools/testing/selftests/bpf/progs/dynptr_success.c | 1 + tools/testing/selftests/bpf/progs/test_xdp_dynptr.c | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/bpf_kfuncs.h b/tools/testing/selftests/bpf/bpf_kfuncs.h index f3c41f8902a0..821c25b7d0df 100644 --- a/tools/testing/selftests/bpf/bpf_kfuncs.h +++ b/tools/testing/selftests/bpf/bpf_kfuncs.h @@ -36,7 +36,7 @@ extern void *bpf_dynptr_slice_rdwr(const struct bpf_dynptr *ptr, __u32 offset, void *buffer, __u32 buffer__szk) __ksym; extern int bpf_dynptr_adjust(const struct bpf_dynptr *ptr, __u32 start, __u32 end) __ksym; -extern int bpf_dynptr_is_null(const struct bpf_dynptr *ptr) __ksym; +extern bool bpf_dynptr_is_null(const struct bpf_dynptr *ptr) __ksym; extern int bpf_dynptr_is_rdonly(const struct bpf_dynptr *ptr) __ksym; extern __u32 bpf_dynptr_size(const struct bpf_dynptr *ptr) __ksym; extern int bpf_dynptr_clone(const struct bpf_dynptr *ptr, struct bpf_dynptr *clone__init) __ksym; diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c index c2f0e18af951..7ce7e827d5f0 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c @@ -3,6 +3,7 @@ #include #include +#include #include #include #include diff --git a/tools/testing/selftests/bpf/progs/dynptr_success.c b/tools/testing/selftests/bpf/progs/dynptr_success.c index 0c053976f8f9..5985920d162e 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_success.c +++ b/tools/testing/selftests/bpf/progs/dynptr_success.c @@ -2,6 +2,7 @@ /* Copyright (c) 2022 Facebook */ #include +#include #include #include #include "bpf_misc.h" diff --git a/tools/testing/selftests/bpf/progs/test_xdp_dynptr.c b/tools/testing/selftests/bpf/progs/test_xdp_dynptr.c index 25ee4a22e48d..78c368e71797 100644 --- a/tools/testing/selftests/bpf/progs/test_xdp_dynptr.c +++ b/tools/testing/selftests/bpf/progs/test_xdp_dynptr.c @@ -2,6 +2,7 @@ /* Copyright (c) 2022 Meta */ #include #include +#include #include #include #include -- cgit v1.2.3 From effcf62416240e5ec0eded0ea2644c48d2c7c9f1 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 16 May 2023 21:04:09 -0700 Subject: selftests/bpf: Make bpf_dynptr_is_rdonly() prototyype consistent with kernel Currently kernel kfunc bpf_dynptr_is_rdonly() has prototype ... __bpf_kfunc bool bpf_dynptr_is_rdonly(struct bpf_dynptr_kern *ptr) ... while selftests bpf_kfuncs.h has: extern int bpf_dynptr_is_rdonly(const struct bpf_dynptr *ptr) __ksym; Such a mismatch might cause problems although currently it is okay in selftests. Fix it to prevent future potential surprise. Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230517040409.4024618-1-yhs@fb.com --- tools/testing/selftests/bpf/bpf_kfuncs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/bpf_kfuncs.h b/tools/testing/selftests/bpf/bpf_kfuncs.h index 821c25b7d0df..642dda0e758a 100644 --- a/tools/testing/selftests/bpf/bpf_kfuncs.h +++ b/tools/testing/selftests/bpf/bpf_kfuncs.h @@ -37,7 +37,7 @@ extern void *bpf_dynptr_slice_rdwr(const struct bpf_dynptr *ptr, __u32 offset, extern int bpf_dynptr_adjust(const struct bpf_dynptr *ptr, __u32 start, __u32 end) __ksym; extern bool bpf_dynptr_is_null(const struct bpf_dynptr *ptr) __ksym; -extern int bpf_dynptr_is_rdonly(const struct bpf_dynptr *ptr) __ksym; +extern bool bpf_dynptr_is_rdonly(const struct bpf_dynptr *ptr) __ksym; extern __u32 bpf_dynptr_size(const struct bpf_dynptr *ptr) __ksym; extern int bpf_dynptr_clone(const struct bpf_dynptr *ptr, struct bpf_dynptr *clone__init) __ksym; -- cgit v1.2.3 From 45b1a1227a7aaa99254551c513406c7aa904e968 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Wed, 17 May 2023 12:16:16 -0700 Subject: mptcp: introduces more address related mibs Currently we don't track explicitly a few events related to address management suboption handling; this patch adds new mibs for ADD_ADDR and RM_ADDR options tx and for missed tx events due to internal storage exhaustion. The self-tests must be updated to properly handle different mibs with the same/shared prefix. Additionally removes a couple of warning tracking the loss event. Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/378 Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts Signed-off-by: Mat Martineau Signed-off-by: Jakub Kicinski --- net/mptcp/mib.c | 6 ++++++ net/mptcp/mib.h | 18 ++++++++++++++++++ net/mptcp/options.c | 5 ++++- net/mptcp/pm.c | 6 ++++-- tools/testing/selftests/net/mptcp/mptcp_join.sh | 4 ++-- 5 files changed, 34 insertions(+), 5 deletions(-) (limited to 'tools/testing') diff --git a/net/mptcp/mib.c b/net/mptcp/mib.c index 0dac2863c6e1..a0990c365a2e 100644 --- a/net/mptcp/mib.c +++ b/net/mptcp/mib.c @@ -34,7 +34,11 @@ static const struct snmp_mib mptcp_snmp_list[] = { SNMP_MIB_ITEM("NoDSSInWindow", MPTCP_MIB_NODSSWINDOW), SNMP_MIB_ITEM("DuplicateData", MPTCP_MIB_DUPDATA), SNMP_MIB_ITEM("AddAddr", MPTCP_MIB_ADDADDR), + SNMP_MIB_ITEM("AddAddrTx", MPTCP_MIB_ADDADDRTX), + SNMP_MIB_ITEM("AddAddrTxDrop", MPTCP_MIB_ADDADDRTXDROP), SNMP_MIB_ITEM("EchoAdd", MPTCP_MIB_ECHOADD), + SNMP_MIB_ITEM("EchoAddTx", MPTCP_MIB_ECHOADDTX), + SNMP_MIB_ITEM("EchoAddTxDrop", MPTCP_MIB_ECHOADDTXDROP), SNMP_MIB_ITEM("PortAdd", MPTCP_MIB_PORTADD), SNMP_MIB_ITEM("AddAddrDrop", MPTCP_MIB_ADDADDRDROP), SNMP_MIB_ITEM("MPJoinPortSynRx", MPTCP_MIB_JOINPORTSYNRX), @@ -44,6 +48,8 @@ static const struct snmp_mib mptcp_snmp_list[] = { SNMP_MIB_ITEM("MismatchPortAckRx", MPTCP_MIB_MISMATCHPORTACKRX), SNMP_MIB_ITEM("RmAddr", MPTCP_MIB_RMADDR), SNMP_MIB_ITEM("RmAddrDrop", MPTCP_MIB_RMADDRDROP), + SNMP_MIB_ITEM("RmAddrTx", MPTCP_MIB_RMADDRTX), + SNMP_MIB_ITEM("RmAddrTxDrop", MPTCP_MIB_RMADDRTXDROP), SNMP_MIB_ITEM("RmSubflow", MPTCP_MIB_RMSUBFLOW), SNMP_MIB_ITEM("MPPrioTx", MPTCP_MIB_MPPRIOTX), SNMP_MIB_ITEM("MPPrioRx", MPTCP_MIB_MPPRIORX), diff --git a/net/mptcp/mib.h b/net/mptcp/mib.h index 2be3596374f4..cae71d947252 100644 --- a/net/mptcp/mib.h +++ b/net/mptcp/mib.h @@ -27,7 +27,15 @@ enum linux_mptcp_mib_field { MPTCP_MIB_NODSSWINDOW, /* Segments not in MPTCP windows */ MPTCP_MIB_DUPDATA, /* Segments discarded due to duplicate DSS */ MPTCP_MIB_ADDADDR, /* Received ADD_ADDR with echo-flag=0 */ + MPTCP_MIB_ADDADDRTX, /* Sent ADD_ADDR with echo-flag=0 */ + MPTCP_MIB_ADDADDRTXDROP, /* ADD_ADDR with echo-flag=0 not send due to + * resource exhaustion + */ MPTCP_MIB_ECHOADD, /* Received ADD_ADDR with echo-flag=1 */ + MPTCP_MIB_ECHOADDTX, /* Send ADD_ADDR with echo-flag=1 */ + MPTCP_MIB_ECHOADDTXDROP, /* ADD_ADDR with echo-flag=1 not send due + * to resource exhaustion + */ MPTCP_MIB_PORTADD, /* Received ADD_ADDR with a port-number */ MPTCP_MIB_ADDADDRDROP, /* Dropped incoming ADD_ADDR */ MPTCP_MIB_JOINPORTSYNRX, /* Received a SYN MP_JOIN with a different port-number */ @@ -37,6 +45,8 @@ enum linux_mptcp_mib_field { MPTCP_MIB_MISMATCHPORTACKRX, /* Received an ACK MP_JOIN with a mismatched port-number */ MPTCP_MIB_RMADDR, /* Received RM_ADDR */ MPTCP_MIB_RMADDRDROP, /* Dropped incoming RM_ADDR */ + MPTCP_MIB_RMADDRTX, /* Sent RM_ADDR */ + MPTCP_MIB_RMADDRTXDROP, /* RM_ADDR not sent due to resource exhaustion */ MPTCP_MIB_RMSUBFLOW, /* Remove a subflow */ MPTCP_MIB_MPPRIOTX, /* Transmit a MP_PRIO */ MPTCP_MIB_MPPRIORX, /* Received a MP_PRIO */ @@ -63,6 +73,14 @@ struct mptcp_mib { unsigned long mibs[LINUX_MIB_MPTCP_MAX]; }; +static inline void MPTCP_ADD_STATS(struct net *net, + enum linux_mptcp_mib_field field, + int val) +{ + if (likely(net->mib.mptcp_statistics)) + SNMP_ADD_STATS(net->mib.mptcp_statistics, field, val); +} + static inline void MPTCP_INC_STATS(struct net *net, enum linux_mptcp_mib_field field) { diff --git a/net/mptcp/options.c b/net/mptcp/options.c index 19a01b6566f1..8a8083207be4 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -687,9 +687,12 @@ static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff * } opts->suboptions |= OPTION_MPTCP_ADD_ADDR; if (!echo) { + MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDRTX); opts->ahmac = add_addr_generate_hmac(msk->local_key, msk->remote_key, &opts->addr); + } else { + MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ECHOADDTX); } pr_debug("addr_id=%d, ahmac=%llu, echo=%d, port=%d", opts->addr.id, opts->ahmac, echo, ntohs(opts->addr.port)); @@ -723,7 +726,7 @@ static bool mptcp_established_options_rm_addr(struct sock *sk, for (i = 0; i < opts->rm_list.nr; i++) pr_debug("rm_list_ids[%d]=%d", i, opts->rm_list.ids[i]); - + MPTCP_ADD_STATS(sock_net(sk), MPTCP_MIB_RMADDRTX, opts->rm_list.nr); return true; } diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index 78c924506e83..7d03b5fd8200 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -26,7 +26,8 @@ int mptcp_pm_announce_addr(struct mptcp_sock *msk, if (add_addr & (echo ? BIT(MPTCP_ADD_ADDR_ECHO) : BIT(MPTCP_ADD_ADDR_SIGNAL))) { - pr_warn("addr_signal error, add_addr=%d, echo=%d", add_addr, echo); + MPTCP_INC_STATS(sock_net((struct sock *)msk), + echo ? MPTCP_MIB_ECHOADDTXDROP : MPTCP_MIB_ADDADDRTXDROP); return -EINVAL; } @@ -48,7 +49,8 @@ int mptcp_pm_remove_addr(struct mptcp_sock *msk, const struct mptcp_rm_list *rm_ pr_debug("msk=%p, rm_list_nr=%d", msk, rm_list->nr); if (rm_addr) { - pr_warn("addr_signal error, rm_addr=%d", rm_addr); + MPTCP_ADD_STATS(sock_net((struct sock *)msk), + MPTCP_MIB_RMADDRTXDROP, rm_list->nr); return -EINVAL; } diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 26310c17b4c6..0886ed2c59ea 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -1492,7 +1492,7 @@ chk_add_nr() fi echo -n " - echo " - count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtEchoAdd | awk '{print $2}') + count=$(ip netns exec $ns1 nstat -as MPTcpExtEchoAdd | grep MPTcpExtEchoAdd | awk '{print $2}') [ -z "$count" ] && count=0 if [ "$count" != "$echo_nr" ]; then echo "[fail] got $count ADD_ADDR echo[s] expected $echo_nr" @@ -1614,7 +1614,7 @@ chk_rm_nr() fi printf "%-${nr_blank}s %s" " " "rm " - count=$(ip netns exec $addr_ns nstat -as | grep MPTcpExtRmAddr | awk '{print $2}') + count=$(ip netns exec $addr_ns nstat -as MPTcpExtRmAddr | grep MPTcpExtRmAddr | awk '{print $2}') [ -z "$count" ] && count=0 if [ "$count" != "$rm_addr_nr" ]; then echo "[fail] got $count RM_ADDR[s] expected $rm_addr_nr" -- cgit v1.2.3 From 0639fa230a21062567222bd99f2996e9da6c232c Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Wed, 17 May 2023 12:16:17 -0700 Subject: selftests: mptcp: add explicit check for new mibs Instead of duplicating the all existing TX check with the TX side, add the new ones on selected test cases. Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts Signed-off-by: Mat Martineau Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 62 +++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 0886ed2c59ea..ca5bd2c3434a 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -1585,6 +1585,44 @@ chk_add_nr() [ "${dump_stats}" = 1 ] && dump_stats } +chk_add_tx_nr() +{ + local add_tx_nr=$1 + local echo_tx_nr=$2 + local dump_stats + local timeout + local count + + timeout=$(ip netns exec $ns1 sysctl -n net.mptcp.add_addr_timeout) + + printf "%-${nr_blank}s %s" " " "add TX" + count=$(ip netns exec $ns1 nstat -as MPTcpExtAddAddrTx | grep MPTcpExtAddAddrTx | awk '{print $2}') + [ -z "$count" ] && count=0 + + # if the test configured a short timeout tolerate greater then expected + # add addrs options, due to retransmissions + if [ "$count" != "$add_tx_nr" ] && { [ "$timeout" -gt 1 ] || [ "$count" -lt "$add_tx_nr" ]; }; then + echo "[fail] got $count ADD_ADDR[s] TX, expected $add_tx_nr" + fail_test + dump_stats=1 + else + echo -n "[ ok ]" + fi + + echo -n " - echo TX " + count=$(ip netns exec $ns2 nstat -as MPTcpExtEchoAddTx | grep MPTcpExtEchoAddTx | awk '{print $2}') + [ -z "$count" ] && count=0 + if [ "$count" != "$echo_tx_nr" ]; then + echo "[fail] got $count ADD_ADDR echo[s] TX, expected $echo_tx_nr" + fail_test + dump_stats=1 + else + echo "[ ok ]" + fi + + [ "${dump_stats}" = 1 ] && dump_stats +} + chk_rm_nr() { local rm_addr_nr=$1 @@ -1660,6 +1698,26 @@ chk_rm_nr() echo "$extra_msg" } +chk_rm_tx_nr() +{ + local rm_addr_tx_nr=$1 + + printf "%-${nr_blank}s %s" " " "rm TX " + count=$(ip netns exec $ns2 nstat -as MPTcpExtRmAddrTx | grep MPTcpExtRmAddrTx | awk '{print $2}') + [ -z "$count" ] && count=0 + if [ "$count" != "$rm_addr_tx_nr" ]; then + echo "[fail] got $count RM_ADDR[s] expected $rm_addr_tx_nr" + fail_test + dump_stats=1 + else + echo -n "[ ok ]" + fi + + [ "${dump_stats}" = 1 ] && dump_stats + + echo "$extra_msg" +} + chk_prio_nr() { local mp_prio_nr_tx=$1 @@ -1939,6 +1997,7 @@ signal_address_tests() pm_nl_add_endpoint $ns1 10.0.2.1 flags signal run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 0 0 0 + chk_add_tx_nr 1 1 chk_add_nr 1 1 fi @@ -2120,6 +2179,7 @@ add_addr_timeout_tests() pm_nl_add_endpoint $ns1 10.0.2.1 flags signal run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow chk_join_nr 1 1 1 + chk_add_tx_nr 4 4 chk_add_nr 4 0 fi @@ -2165,6 +2225,7 @@ remove_tests() pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow run_tests $ns1 $ns2 10.0.1.1 0 0 -1 slow chk_join_nr 1 1 1 + chk_rm_tx_nr 1 chk_rm_nr 1 1 fi @@ -2263,6 +2324,7 @@ remove_tests() pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow run_tests $ns1 $ns2 10.0.1.1 0 -8 -8 slow chk_join_nr 3 3 3 + chk_rm_tx_nr 0 chk_rm_nr 0 3 simult fi -- cgit v1.2.3 From 985de45923e29087a2dcf34bb71f24641d6cc55f Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Wed, 17 May 2023 12:16:18 -0700 Subject: selftests: mptcp: centralize stats dumping If a test case fails, the mptcp_join.sh script can dump the netns MIBs multiple times, leading to confusing output. Let's dump such info only once per test-case, when needed. This additionally allow removing some code duplication. Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts Signed-off-by: Mat Martineau Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 66 ++----------------------- 1 file changed, 5 insertions(+), 61 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index ca5bd2c3434a..e74d3074ef90 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -34,6 +34,7 @@ evts_ns1="" evts_ns2="" evts_ns1_pid=0 evts_ns2_pid=0 +stats_dumped=0 declare -A all_tests declare -a only_tests_ids @@ -87,6 +88,7 @@ init_partial() fi done + stats_dumped=0 check_invert=0 validate_checksum=$checksum FAILING_LINKS="" @@ -347,6 +349,9 @@ fail_test() { ret=1 failed_tests[${TEST_COUNT}]="${TEST_NAME}" + + [ "${stats_dumped}" = 0 ] && dump_stats + stats_dumped=1 } get_failed_tests_ids() @@ -1120,7 +1125,6 @@ chk_csum_nr() local csum_ns1=${1:-0} local csum_ns2=${2:-0} local count - local dump_stats local extra_msg="" local allow_multi_errors_ns1=0 local allow_multi_errors_ns2=0 @@ -1144,7 +1148,6 @@ chk_csum_nr() { [ "$count" -lt $csum_ns1 ] && [ $allow_multi_errors_ns1 -eq 1 ]; }; then echo "[fail] got $count data checksum error[s] expected $csum_ns1" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1158,11 +1161,9 @@ chk_csum_nr() { [ "$count" -lt $csum_ns2 ] && [ $allow_multi_errors_ns2 -eq 1 ]; }; then echo "[fail] got $count data checksum error[s] expected $csum_ns2" fail_test - dump_stats=1 else echo -n "[ ok ]" fi - [ "${dump_stats}" = 1 ] && dump_stats echo "$extra_msg" } @@ -1173,7 +1174,6 @@ chk_fail_nr() local fail_rx=$2 local ns_invert=${3:-""} local count - local dump_stats local ns_tx=$ns1 local ns_rx=$ns2 local extra_msg="" @@ -1205,7 +1205,6 @@ chk_fail_nr() { [ "$count" -gt "$fail_tx" ] && [ $allow_tx_lost -eq 1 ]; }; then echo "[fail] got $count MP_FAIL[s] TX expected $fail_tx" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1220,13 +1219,10 @@ chk_fail_nr() { [ "$count" -gt "$fail_rx" ] && [ $allow_rx_lost -eq 1 ]; }; then echo "[fail] got $count MP_FAIL[s] RX expected $fail_rx" fail_test - dump_stats=1 else echo -n "[ ok ]" fi - [ "${dump_stats}" = 1 ] && dump_stats - echo "$extra_msg" } @@ -1236,7 +1232,6 @@ chk_fclose_nr() local fclose_rx=$2 local ns_invert=$3 local count - local dump_stats local ns_tx=$ns2 local ns_rx=$ns1 local extra_msg=" " @@ -1254,7 +1249,6 @@ chk_fclose_nr() if [ "$count" != "$fclose_tx" ]; then echo "[fail] got $count MP_FASTCLOSE[s] TX expected $fclose_tx" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1266,13 +1260,10 @@ chk_fclose_nr() if [ "$count" != "$fclose_rx" ]; then echo "[fail] got $count MP_FASTCLOSE[s] RX expected $fclose_rx" fail_test - dump_stats=1 else echo -n "[ ok ]" fi - [ "${dump_stats}" = 1 ] && dump_stats - echo "$extra_msg" } @@ -1282,7 +1273,6 @@ chk_rst_nr() local rst_rx=$2 local ns_invert=${3:-""} local count - local dump_stats local ns_tx=$ns1 local ns_rx=$ns2 local extra_msg="" @@ -1299,7 +1289,6 @@ chk_rst_nr() if [ $count -lt $rst_tx ]; then echo "[fail] got $count MP_RST[s] TX expected $rst_tx" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1310,13 +1299,10 @@ chk_rst_nr() if [ "$count" -lt "$rst_rx" ]; then echo "[fail] got $count MP_RST[s] RX expected $rst_rx" fail_test - dump_stats=1 else echo -n "[ ok ]" fi - [ "${dump_stats}" = 1 ] && dump_stats - echo "$extra_msg" } @@ -1325,7 +1311,6 @@ chk_infi_nr() local infi_tx=$1 local infi_rx=$2 local count - local dump_stats printf "%-${nr_blank}s %s" " " "itx" count=$(ip netns exec $ns2 nstat -as | grep InfiniteMapTx | awk '{print $2}') @@ -1333,7 +1318,6 @@ chk_infi_nr() if [ "$count" != "$infi_tx" ]; then echo "[fail] got $count infinite map[s] TX expected $infi_tx" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1344,12 +1328,9 @@ chk_infi_nr() if [ "$count" != "$infi_rx" ]; then echo "[fail] got $count infinite map[s] RX expected $infi_rx" fail_test - dump_stats=1 else echo "[ ok ]" fi - - [ "${dump_stats}" = 1 ] && dump_stats } chk_join_nr() @@ -1364,7 +1345,6 @@ chk_join_nr() local infi_nr=${8:-0} local corrupted_pkts=${9:-0} local count - local dump_stats local with_cookie local title="${TEST_NAME}" @@ -1378,7 +1358,6 @@ chk_join_nr() if [ "$count" != "$syn_nr" ]; then echo "[fail] got $count JOIN[s] syn expected $syn_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1396,7 +1375,6 @@ chk_join_nr() else echo "[fail] got $count JOIN[s] synack expected $syn_ack_nr" fail_test - dump_stats=1 fi else echo -n "[ ok ]" @@ -1408,11 +1386,9 @@ chk_join_nr() if [ "$count" != "$ack_nr" ]; then echo "[fail] got $count JOIN[s] ack expected $ack_nr" fail_test - dump_stats=1 else echo "[ ok ]" fi - [ "${dump_stats}" = 1 ] && dump_stats if [ $validate_checksum -eq 1 ]; then chk_csum_nr $csum_ns1 $csum_ns2 chk_fail_nr $fail_nr $fail_nr @@ -1472,7 +1448,6 @@ chk_add_nr() local mis_syn_nr=${7:-0} local mis_ack_nr=${8:-0} local count - local dump_stats local timeout timeout=$(ip netns exec $ns1 sysctl -n net.mptcp.add_addr_timeout) @@ -1486,7 +1461,6 @@ chk_add_nr() if [ "$count" != "$add_nr" ] && { [ "$timeout" -gt 1 ] || [ "$count" -lt "$add_nr" ]; }; then echo "[fail] got $count ADD_ADDR[s] expected $add_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1497,7 +1471,6 @@ chk_add_nr() if [ "$count" != "$echo_nr" ]; then echo "[fail] got $count ADD_ADDR echo[s] expected $echo_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1509,7 +1482,6 @@ chk_add_nr() if [ "$count" != "$port_nr" ]; then echo "[fail] got $count ADD_ADDR[s] with a port-number expected $port_nr" fail_test - dump_stats=1 else echo "[ ok ]" fi @@ -1522,7 +1494,6 @@ chk_add_nr() echo "[fail] got $count JOIN[s] syn with a different \ port-number expected $syn_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1535,7 +1506,6 @@ chk_add_nr() echo "[fail] got $count JOIN[s] synack with a different \ port-number expected $syn_ack_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1548,7 +1518,6 @@ chk_add_nr() echo "[fail] got $count JOIN[s] ack with a different \ port-number expected $ack_nr" fail_test - dump_stats=1 else echo "[ ok ]" fi @@ -1561,7 +1530,6 @@ chk_add_nr() echo "[fail] got $count JOIN[s] syn with a mismatched \ port-number expected $mis_syn_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1574,22 +1542,18 @@ chk_add_nr() echo "[fail] got $count JOIN[s] ack with a mismatched \ port-number expected $mis_ack_nr" fail_test - dump_stats=1 else echo "[ ok ]" fi else echo "" fi - - [ "${dump_stats}" = 1 ] && dump_stats } chk_add_tx_nr() { local add_tx_nr=$1 local echo_tx_nr=$2 - local dump_stats local timeout local count @@ -1604,7 +1568,6 @@ chk_add_tx_nr() if [ "$count" != "$add_tx_nr" ] && { [ "$timeout" -gt 1 ] || [ "$count" -lt "$add_tx_nr" ]; }; then echo "[fail] got $count ADD_ADDR[s] TX, expected $add_tx_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1615,12 +1578,9 @@ chk_add_tx_nr() if [ "$count" != "$echo_tx_nr" ]; then echo "[fail] got $count ADD_ADDR echo[s] TX, expected $echo_tx_nr" fail_test - dump_stats=1 else echo "[ ok ]" fi - - [ "${dump_stats}" = 1 ] && dump_stats } chk_rm_nr() @@ -1630,7 +1590,6 @@ chk_rm_nr() local invert local simult local count - local dump_stats local addr_ns=$ns1 local subflow_ns=$ns2 local extra_msg="" @@ -1657,7 +1616,6 @@ chk_rm_nr() if [ "$count" != "$rm_addr_nr" ]; then echo "[fail] got $count RM_ADDR[s] expected $rm_addr_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1681,20 +1639,16 @@ chk_rm_nr() else echo "[fail] got $count RM_SUBFLOW[s] expected in range [$rm_subflow_nr:$((rm_subflow_nr*2))]" fail_test - dump_stats=1 fi return fi if [ "$count" != "$rm_subflow_nr" ]; then echo "[fail] got $count RM_SUBFLOW[s] expected $rm_subflow_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi - [ "${dump_stats}" = 1 ] && dump_stats - echo "$extra_msg" } @@ -1708,13 +1662,10 @@ chk_rm_tx_nr() if [ "$count" != "$rm_addr_tx_nr" ]; then echo "[fail] got $count RM_ADDR[s] expected $rm_addr_tx_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi - [ "${dump_stats}" = 1 ] && dump_stats - echo "$extra_msg" } @@ -1723,7 +1674,6 @@ chk_prio_nr() local mp_prio_nr_tx=$1 local mp_prio_nr_rx=$2 local count - local dump_stats printf "%-${nr_blank}s %s" " " "ptx" count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtMPPrioTx | awk '{print $2}') @@ -1731,7 +1681,6 @@ chk_prio_nr() if [ "$count" != "$mp_prio_nr_tx" ]; then echo "[fail] got $count MP_PRIO[s] TX expected $mp_prio_nr_tx" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1742,12 +1691,9 @@ chk_prio_nr() if [ "$count" != "$mp_prio_nr_rx" ]; then echo "[fail] got $count MP_PRIO[s] RX expected $mp_prio_nr_rx" fail_test - dump_stats=1 else echo "[ ok ]" fi - - [ "${dump_stats}" = 1 ] && dump_stats } chk_subflow_nr() @@ -1779,7 +1725,6 @@ chk_subflow_nr() ss -N $ns1 -tOni ss -N $ns1 -tOni | grep token ip -n $ns1 mptcp endpoint - dump_stats fi } @@ -1819,7 +1764,6 @@ chk_mptcp_info() if [ "$dump_stats" = 1 ]; then ss -N $ns1 -inmHM ss -N $ns2 -inmHM - dump_stats fi } -- cgit v1.2.3 From 176ba657e6aaa61df637558a57acd8b7bf043cb4 Mon Sep 17 00:00:00 2001 From: Aditi Ghag Date: Fri, 19 May 2023 22:51:56 +0000 Subject: selftests/bpf: Add helper to get port using getsockname The helper will be used to programmatically retrieve and pass ports in userspace and kernel selftest programs. Suggested-by: Stanislav Fomichev Signed-off-by: Aditi Ghag Link: https://lore.kernel.org/r/20230519225157.760788-9-aditi.ghag@isovalent.com Signed-off-by: Martin KaFai Lau --- tools/testing/selftests/bpf/network_helpers.c | 23 +++++++++++++++++++++++ tools/testing/selftests/bpf/network_helpers.h | 1 + 2 files changed, 24 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/network_helpers.c b/tools/testing/selftests/bpf/network_helpers.c index 596caa176582..a105c0cd008a 100644 --- a/tools/testing/selftests/bpf/network_helpers.c +++ b/tools/testing/selftests/bpf/network_helpers.c @@ -427,3 +427,26 @@ void close_netns(struct nstoken *token) close(token->orig_netns_fd); free(token); } + +int get_socket_local_port(int sock_fd) +{ + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + int err; + + err = getsockname(sock_fd, (struct sockaddr *)&addr, &addrlen); + if (err < 0) + return err; + + if (addr.ss_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *)&addr; + + return sin->sin_port; + } else if (addr.ss_family == AF_INET6) { + struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&addr; + + return sin->sin6_port; + } + + return -1; +} diff --git a/tools/testing/selftests/bpf/network_helpers.h b/tools/testing/selftests/bpf/network_helpers.h index f882c691b790..694185644da6 100644 --- a/tools/testing/selftests/bpf/network_helpers.h +++ b/tools/testing/selftests/bpf/network_helpers.h @@ -56,6 +56,7 @@ int fastopen_connect(int server_fd, const char *data, unsigned int data_len, int make_sockaddr(int family, const char *addr_str, __u16 port, struct sockaddr_storage *addr, socklen_t *len); char *ping_command(int family); +int get_socket_local_port(int sock_fd); struct nstoken; /** -- cgit v1.2.3 From 1a8bc2299f4028e9bac36020ffaaec27a0dfb9c1 Mon Sep 17 00:00:00 2001 From: Aditi Ghag Date: Fri, 19 May 2023 22:51:57 +0000 Subject: selftests/bpf: Test bpf_sock_destroy The test cases for destroying sockets mirror the intended usages of the bpf_sock_destroy kfunc using iterators. The destroy helpers set `ECONNABORTED` error code that we can validate in the test code with client sockets. But UDP sockets have an overriding error code from `disconnect()` called during abort, so the error code validation is only done for TCP sockets. The failure test cases validate that the `bpf_sock_destroy` kfunc is not allowed from program attach types other than BPF trace iterator, and such programs fail to load. Signed-off-by: Aditi Ghag Link: https://lore.kernel.org/r/20230519225157.760788-10-aditi.ghag@isovalent.com Signed-off-by: Martin KaFai Lau --- .../selftests/bpf/prog_tests/sock_destroy.c | 221 +++++++++++++++++++++ .../selftests/bpf/progs/sock_destroy_prog.c | 145 ++++++++++++++ .../selftests/bpf/progs/sock_destroy_prog_fail.c | 22 ++ 3 files changed, 388 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/sock_destroy.c create mode 100644 tools/testing/selftests/bpf/progs/sock_destroy_prog.c create mode 100644 tools/testing/selftests/bpf/progs/sock_destroy_prog_fail.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/sock_destroy.c b/tools/testing/selftests/bpf/prog_tests/sock_destroy.c new file mode 100644 index 000000000000..b0583309a94e --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/sock_destroy.c @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +#include "sock_destroy_prog.skel.h" +#include "sock_destroy_prog_fail.skel.h" +#include "network_helpers.h" + +#define TEST_NS "sock_destroy_netns" + +static void start_iter_sockets(struct bpf_program *prog) +{ + struct bpf_link *link; + char buf[50] = {}; + int iter_fd, len; + + link = bpf_program__attach_iter(prog, NULL); + if (!ASSERT_OK_PTR(link, "attach_iter")) + return; + + iter_fd = bpf_iter_create(bpf_link__fd(link)); + if (!ASSERT_GE(iter_fd, 0, "create_iter")) + goto free_link; + + while ((len = read(iter_fd, buf, sizeof(buf))) > 0) + ; + ASSERT_GE(len, 0, "read"); + + close(iter_fd); + +free_link: + bpf_link__destroy(link); +} + +static void test_tcp_client(struct sock_destroy_prog *skel) +{ + int serv = -1, clien = -1, accept_serv = -1, n; + + serv = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0); + if (!ASSERT_GE(serv, 0, "start_server")) + goto cleanup; + + clien = connect_to_fd(serv, 0); + if (!ASSERT_GE(clien, 0, "connect_to_fd")) + goto cleanup; + + accept_serv = accept(serv, NULL, NULL); + if (!ASSERT_GE(accept_serv, 0, "serv accept")) + goto cleanup; + + n = send(clien, "t", 1, 0); + if (!ASSERT_EQ(n, 1, "client send")) + goto cleanup; + + /* Run iterator program that destroys connected client sockets. */ + start_iter_sockets(skel->progs.iter_tcp6_client); + + n = send(clien, "t", 1, 0); + if (!ASSERT_LT(n, 0, "client_send on destroyed socket")) + goto cleanup; + ASSERT_EQ(errno, ECONNABORTED, "error code on destroyed socket"); + +cleanup: + if (clien != -1) + close(clien); + if (accept_serv != -1) + close(accept_serv); + if (serv != -1) + close(serv); +} + +static void test_tcp_server(struct sock_destroy_prog *skel) +{ + int serv = -1, clien = -1, accept_serv = -1, n, serv_port; + + serv = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0); + if (!ASSERT_GE(serv, 0, "start_server")) + goto cleanup; + serv_port = get_socket_local_port(serv); + if (!ASSERT_GE(serv_port, 0, "get_sock_local_port")) + goto cleanup; + skel->bss->serv_port = (__be16) serv_port; + + clien = connect_to_fd(serv, 0); + if (!ASSERT_GE(clien, 0, "connect_to_fd")) + goto cleanup; + + accept_serv = accept(serv, NULL, NULL); + if (!ASSERT_GE(accept_serv, 0, "serv accept")) + goto cleanup; + + n = send(clien, "t", 1, 0); + if (!ASSERT_EQ(n, 1, "client send")) + goto cleanup; + + /* Run iterator program that destroys server sockets. */ + start_iter_sockets(skel->progs.iter_tcp6_server); + + n = send(clien, "t", 1, 0); + if (!ASSERT_LT(n, 0, "client_send on destroyed socket")) + goto cleanup; + ASSERT_EQ(errno, ECONNRESET, "error code on destroyed socket"); + +cleanup: + if (clien != -1) + close(clien); + if (accept_serv != -1) + close(accept_serv); + if (serv != -1) + close(serv); +} + +static void test_udp_client(struct sock_destroy_prog *skel) +{ + int serv = -1, clien = -1, n = 0; + + serv = start_server(AF_INET6, SOCK_DGRAM, NULL, 0, 0); + if (!ASSERT_GE(serv, 0, "start_server")) + goto cleanup; + + clien = connect_to_fd(serv, 0); + if (!ASSERT_GE(clien, 0, "connect_to_fd")) + goto cleanup; + + n = send(clien, "t", 1, 0); + if (!ASSERT_EQ(n, 1, "client send")) + goto cleanup; + + /* Run iterator program that destroys sockets. */ + start_iter_sockets(skel->progs.iter_udp6_client); + + n = send(clien, "t", 1, 0); + if (!ASSERT_LT(n, 0, "client_send on destroyed socket")) + goto cleanup; + /* UDP sockets have an overriding error code after they are disconnected, + * so we don't check for ECONNABORTED error code. + */ + +cleanup: + if (clien != -1) + close(clien); + if (serv != -1) + close(serv); +} + +static void test_udp_server(struct sock_destroy_prog *skel) +{ + int *listen_fds = NULL, n, i, serv_port; + unsigned int num_listens = 5; + char buf[1]; + + /* Start reuseport servers. */ + listen_fds = start_reuseport_server(AF_INET6, SOCK_DGRAM, + "::1", 0, 0, num_listens); + if (!ASSERT_OK_PTR(listen_fds, "start_reuseport_server")) + goto cleanup; + serv_port = get_socket_local_port(listen_fds[0]); + if (!ASSERT_GE(serv_port, 0, "get_sock_local_port")) + goto cleanup; + skel->bss->serv_port = (__be16) serv_port; + + /* Run iterator program that destroys server sockets. */ + start_iter_sockets(skel->progs.iter_udp6_server); + + for (i = 0; i < num_listens; ++i) { + n = read(listen_fds[i], buf, sizeof(buf)); + if (!ASSERT_EQ(n, -1, "read") || + !ASSERT_EQ(errno, ECONNABORTED, "error code on destroyed socket")) + break; + } + ASSERT_EQ(i, num_listens, "server socket"); + +cleanup: + free_fds(listen_fds, num_listens); +} + +void test_sock_destroy(void) +{ + struct sock_destroy_prog *skel; + struct nstoken *nstoken = NULL; + int cgroup_fd; + + skel = sock_destroy_prog__open_and_load(); + if (!ASSERT_OK_PTR(skel, "skel_open")) + return; + + cgroup_fd = test__join_cgroup("/sock_destroy"); + if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup")) + goto cleanup; + + skel->links.sock_connect = bpf_program__attach_cgroup( + skel->progs.sock_connect, cgroup_fd); + if (!ASSERT_OK_PTR(skel->links.sock_connect, "prog_attach")) + goto cleanup; + + SYS(cleanup, "ip netns add %s", TEST_NS); + SYS(cleanup, "ip -net %s link set dev lo up", TEST_NS); + + nstoken = open_netns(TEST_NS); + if (!ASSERT_OK_PTR(nstoken, "open_netns")) + goto cleanup; + + if (test__start_subtest("tcp_client")) + test_tcp_client(skel); + if (test__start_subtest("tcp_server")) + test_tcp_server(skel); + if (test__start_subtest("udp_client")) + test_udp_client(skel); + if (test__start_subtest("udp_server")) + test_udp_server(skel); + + RUN_TESTS(sock_destroy_prog_fail); + +cleanup: + if (nstoken) + close_netns(nstoken); + SYS_NOFAIL("ip netns del " TEST_NS " &> /dev/null"); + if (cgroup_fd >= 0) + close(cgroup_fd); + sock_destroy_prog__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/progs/sock_destroy_prog.c b/tools/testing/selftests/bpf/progs/sock_destroy_prog.c new file mode 100644 index 000000000000..9e0bf7a54cec --- /dev/null +++ b/tools/testing/selftests/bpf/progs/sock_destroy_prog.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" +#include +#include + +#include "bpf_tracing_net.h" + +__be16 serv_port = 0; + +int bpf_sock_destroy(struct sock_common *sk) __ksym; + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, __u32); + __type(value, __u64); +} tcp_conn_sockets SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, __u32); + __type(value, __u64); +} udp_conn_sockets SEC(".maps"); + +SEC("cgroup/connect6") +int sock_connect(struct bpf_sock_addr *ctx) +{ + __u64 sock_cookie = 0; + int key = 0; + __u32 keyc = 0; + + if (ctx->family != AF_INET6 || ctx->user_family != AF_INET6) + return 1; + + sock_cookie = bpf_get_socket_cookie(ctx); + if (ctx->protocol == IPPROTO_TCP) + bpf_map_update_elem(&tcp_conn_sockets, &key, &sock_cookie, 0); + else if (ctx->protocol == IPPROTO_UDP) + bpf_map_update_elem(&udp_conn_sockets, &keyc, &sock_cookie, 0); + else + return 1; + + return 1; +} + +SEC("iter/tcp") +int iter_tcp6_client(struct bpf_iter__tcp *ctx) +{ + struct sock_common *sk_common = ctx->sk_common; + __u64 sock_cookie = 0; + __u64 *val; + int key = 0; + + if (!sk_common) + return 0; + + if (sk_common->skc_family != AF_INET6) + return 0; + + sock_cookie = bpf_get_socket_cookie(sk_common); + val = bpf_map_lookup_elem(&tcp_conn_sockets, &key); + if (!val) + return 0; + /* Destroy connected client sockets. */ + if (sock_cookie == *val) + bpf_sock_destroy(sk_common); + + return 0; +} + +SEC("iter/tcp") +int iter_tcp6_server(struct bpf_iter__tcp *ctx) +{ + struct sock_common *sk_common = ctx->sk_common; + const struct inet_connection_sock *icsk; + const struct inet_sock *inet; + struct tcp6_sock *tcp_sk; + __be16 srcp; + + if (!sk_common) + return 0; + + if (sk_common->skc_family != AF_INET6) + return 0; + + tcp_sk = bpf_skc_to_tcp6_sock(sk_common); + if (!tcp_sk) + return 0; + + icsk = &tcp_sk->tcp.inet_conn; + inet = &icsk->icsk_inet; + srcp = inet->inet_sport; + + /* Destroy server sockets. */ + if (srcp == serv_port) + bpf_sock_destroy(sk_common); + + return 0; +} + + +SEC("iter/udp") +int iter_udp6_client(struct bpf_iter__udp *ctx) +{ + struct udp_sock *udp_sk = ctx->udp_sk; + struct sock *sk = (struct sock *) udp_sk; + __u64 sock_cookie = 0, *val; + int key = 0; + + if (!sk) + return 0; + + sock_cookie = bpf_get_socket_cookie(sk); + val = bpf_map_lookup_elem(&udp_conn_sockets, &key); + if (!val) + return 0; + /* Destroy connected client sockets. */ + if (sock_cookie == *val) + bpf_sock_destroy((struct sock_common *)sk); + + return 0; +} + +SEC("iter/udp") +int iter_udp6_server(struct bpf_iter__udp *ctx) +{ + struct udp_sock *udp_sk = ctx->udp_sk; + struct sock *sk = (struct sock *) udp_sk; + struct inet_sock *inet; + __be16 srcp; + + if (!sk) + return 0; + + inet = &udp_sk->inet; + srcp = inet->inet_sport; + if (srcp == serv_port) + bpf_sock_destroy((struct sock_common *)sk); + + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/sock_destroy_prog_fail.c b/tools/testing/selftests/bpf/progs/sock_destroy_prog_fail.c new file mode 100644 index 000000000000..dd6850b58e25 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/sock_destroy_prog_fail.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" +#include +#include + +#include "bpf_misc.h" + +char _license[] SEC("license") = "GPL"; + +int bpf_sock_destroy(struct sock_common *sk) __ksym; + +SEC("tp_btf/tcp_destroy_sock") +__failure __msg("calling kernel function bpf_sock_destroy is not allowed") +int BPF_PROG(trace_tcp_destroy_sock, struct sock *sk) +{ + /* should not load */ + bpf_sock_destroy((struct sock_common *)sk); + + return 0; +} + -- cgit v1.2.3 From 6cc385d2cdb410fd7a774100bf865ae2da9c709b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 17 May 2023 15:41:33 +0200 Subject: selftests/bpf: Add xdp_feature selftest for bond device Introduce selftests to check xdp_feature support for bond driver. Signed-off-by: Lorenzo Bianconi Signed-off-by: Daniel Borkmann Reviewed-by: Jussi Maki Link: https://lore.kernel.org/bpf/64cb8f20e6491f5b971f8d3129335093c359aad7.1684329998.git.lorenzo@kernel.org --- .../testing/selftests/bpf/prog_tests/xdp_bonding.c | 121 +++++++++++++++++++++ 1 file changed, 121 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_bonding.c b/tools/testing/selftests/bpf/prog_tests/xdp_bonding.c index d19f79048ff6..c3b45745cbcc 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_bonding.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_bonding.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "xdp_dummy.skel.h" #include "xdp_redirect_multi_kern.skel.h" @@ -492,6 +493,123 @@ out: system("ip link del bond_nest2"); } +static void test_xdp_bonding_features(struct skeletons *skeletons) +{ + LIBBPF_OPTS(bpf_xdp_query_opts, query_opts); + int bond_idx, veth1_idx, err; + struct bpf_link *link = NULL; + + if (!ASSERT_OK(system("ip link add bond type bond"), "add bond")) + goto out; + + bond_idx = if_nametoindex("bond"); + if (!ASSERT_GE(bond_idx, 0, "if_nametoindex bond")) + goto out; + + /* query default xdp-feature for bond device */ + err = bpf_xdp_query(bond_idx, XDP_FLAGS_DRV_MODE, &query_opts); + if (!ASSERT_OK(err, "bond bpf_xdp_query")) + goto out; + + if (!ASSERT_EQ(query_opts.feature_flags, NETDEV_XDP_ACT_MASK, + "bond query_opts.feature_flags")) + goto out; + + if (!ASSERT_OK(system("ip link add veth0 type veth peer name veth1"), + "add veth{0,1} pair")) + goto out; + + if (!ASSERT_OK(system("ip link add veth2 type veth peer name veth3"), + "add veth{2,3} pair")) + goto out; + + if (!ASSERT_OK(system("ip link set veth0 master bond"), + "add veth0 to master bond")) + goto out; + + /* xdp-feature for bond device should be obtained from the single slave + * device (veth0) + */ + err = bpf_xdp_query(bond_idx, XDP_FLAGS_DRV_MODE, &query_opts); + if (!ASSERT_OK(err, "bond bpf_xdp_query")) + goto out; + + if (!ASSERT_EQ(query_opts.feature_flags, + NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | + NETDEV_XDP_ACT_RX_SG, + "bond query_opts.feature_flags")) + goto out; + + veth1_idx = if_nametoindex("veth1"); + if (!ASSERT_GE(veth1_idx, 0, "if_nametoindex veth1")) + goto out; + + link = bpf_program__attach_xdp(skeletons->xdp_dummy->progs.xdp_dummy_prog, + veth1_idx); + if (!ASSERT_OK_PTR(link, "attach program to veth1")) + goto out; + + /* xdp-feature for veth0 are changed */ + err = bpf_xdp_query(bond_idx, XDP_FLAGS_DRV_MODE, &query_opts); + if (!ASSERT_OK(err, "bond bpf_xdp_query")) + goto out; + + if (!ASSERT_EQ(query_opts.feature_flags, + NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | + NETDEV_XDP_ACT_RX_SG | NETDEV_XDP_ACT_NDO_XMIT | + NETDEV_XDP_ACT_NDO_XMIT_SG, + "bond query_opts.feature_flags")) + goto out; + + if (!ASSERT_OK(system("ip link set veth2 master bond"), + "add veth2 to master bond")) + goto out; + + err = bpf_xdp_query(bond_idx, XDP_FLAGS_DRV_MODE, &query_opts); + if (!ASSERT_OK(err, "bond bpf_xdp_query")) + goto out; + + /* xdp-feature for bond device should be set to the most restrict + * value obtained from attached slave devices (veth0 and veth2) + */ + if (!ASSERT_EQ(query_opts.feature_flags, + NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | + NETDEV_XDP_ACT_RX_SG, + "bond query_opts.feature_flags")) + goto out; + + if (!ASSERT_OK(system("ip link set veth2 nomaster"), + "del veth2 to master bond")) + goto out; + + err = bpf_xdp_query(bond_idx, XDP_FLAGS_DRV_MODE, &query_opts); + if (!ASSERT_OK(err, "bond bpf_xdp_query")) + goto out; + + if (!ASSERT_EQ(query_opts.feature_flags, + NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | + NETDEV_XDP_ACT_RX_SG | NETDEV_XDP_ACT_NDO_XMIT | + NETDEV_XDP_ACT_NDO_XMIT_SG, + "bond query_opts.feature_flags")) + goto out; + + if (!ASSERT_OK(system("ip link set veth0 nomaster"), + "del veth0 to master bond")) + goto out; + + err = bpf_xdp_query(bond_idx, XDP_FLAGS_DRV_MODE, &query_opts); + if (!ASSERT_OK(err, "bond bpf_xdp_query")) + goto out; + + ASSERT_EQ(query_opts.feature_flags, NETDEV_XDP_ACT_MASK, + "bond query_opts.feature_flags"); +out: + bpf_link__destroy(link); + system("ip link del veth0"); + system("ip link del veth2"); + system("ip link del bond"); +} + static int libbpf_debug_print(enum libbpf_print_level level, const char *format, va_list args) { @@ -546,6 +664,9 @@ void serial_test_xdp_bonding(void) if (test__start_subtest("xdp_bonding_nested")) test_xdp_bonding_nested(&skeletons); + if (test__start_subtest("xdp_bonding_features")) + test_xdp_bonding_features(&skeletons); + for (i = 0; i < ARRAY_SIZE(bond_test_cases); i++) { struct bond_test_case *test_case = &bond_test_cases[i]; -- cgit v1.2.3 From 3b22f98e5a05feee20699df0870dc5d47c9b61dd Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 May 2023 10:00:13 -0700 Subject: selftests/bpf: Add path_fd-based BPF_OBJ_PIN and BPF_OBJ_GET tests Add a selftest demonstrating using detach-mounted BPF FS using new mount APIs, and pinning and getting BPF map using such mount. This demonstrates how something like container manager could setup BPF FS, pin and adjust all the necessary objects in it, all before exposing BPF FS to a particular mount namespace. Also add a few subtests validating all meaningful combinations of path_fd and pathname. We use mounted /sys/fs/bpf location for these. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230523170013.728457-5-andrii@kernel.org --- .../selftests/bpf/prog_tests/bpf_obj_pinning.c | 268 +++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/bpf_obj_pinning.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_obj_pinning.c b/tools/testing/selftests/bpf/prog_tests/bpf_obj_pinning.c new file mode 100644 index 000000000000..31f1e815f671 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/bpf_obj_pinning.c @@ -0,0 +1,268 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +static inline int sys_fsopen(const char *fsname, unsigned flags) +{ + return syscall(__NR_fsopen, fsname, flags); +} + +static inline int sys_fsconfig(int fs_fd, unsigned cmd, const char *key, const void *val, int aux) +{ + return syscall(__NR_fsconfig, fs_fd, cmd, key, val, aux); +} + +static inline int sys_fsmount(int fs_fd, unsigned flags, unsigned ms_flags) +{ + return syscall(__NR_fsmount, fs_fd, flags, ms_flags); +} + +__attribute__((unused)) +static inline int sys_move_mount(int from_dfd, const char *from_path, + int to_dfd, const char *to_path, + unsigned int ms_flags) +{ + return syscall(__NR_move_mount, from_dfd, from_path, to_dfd, to_path, ms_flags); +} + +static void bpf_obj_pinning_detached(void) +{ + LIBBPF_OPTS(bpf_obj_pin_opts, pin_opts); + LIBBPF_OPTS(bpf_obj_get_opts, get_opts); + int fs_fd = -1, mnt_fd = -1; + int map_fd = -1, map_fd2 = -1; + int zero = 0, src_value, dst_value, err; + const char *map_name = "fsmount_map"; + + /* A bunch of below UAPI calls are constructed based on reading: + * https://brauner.io/2023/02/28/mounting-into-mount-namespaces.html + */ + + /* create VFS context */ + fs_fd = sys_fsopen("bpf", 0); + if (!ASSERT_GE(fs_fd, 0, "fs_fd")) + goto cleanup; + + /* instantiate FS object */ + err = sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0); + if (!ASSERT_OK(err, "fs_create")) + goto cleanup; + + /* create O_PATH fd for detached mount */ + mnt_fd = sys_fsmount(fs_fd, 0, 0); + if (!ASSERT_GE(mnt_fd, 0, "mnt_fd")) + goto cleanup; + + /* If we wanted to expose detached mount in the file system, we'd do + * something like below. But the whole point is that we actually don't + * even have to expose BPF FS in the file system to be able to work + * (pin/get objects) with it. + * + * err = sys_move_mount(mnt_fd, "", -EBADF, mnt_path, MOVE_MOUNT_F_EMPTY_PATH); + * if (!ASSERT_OK(err, "move_mount")) + * goto cleanup; + */ + + /* create BPF map to pin */ + map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, map_name, 4, 4, 1, NULL); + if (!ASSERT_GE(map_fd, 0, "map_fd")) + goto cleanup; + + /* pin BPF map into detached BPF FS through mnt_fd */ + pin_opts.file_flags = BPF_F_PATH_FD; + pin_opts.path_fd = mnt_fd; + err = bpf_obj_pin_opts(map_fd, map_name, &pin_opts); + if (!ASSERT_OK(err, "map_pin")) + goto cleanup; + + /* get BPF map from detached BPF FS through mnt_fd */ + get_opts.file_flags = BPF_F_PATH_FD; + get_opts.path_fd = mnt_fd; + map_fd2 = bpf_obj_get_opts(map_name, &get_opts); + if (!ASSERT_GE(map_fd2, 0, "map_get")) + goto cleanup; + + /* update map through one FD */ + src_value = 0xcafebeef; + err = bpf_map_update_elem(map_fd, &zero, &src_value, 0); + ASSERT_OK(err, "map_update"); + + /* check values written/read through different FDs do match */ + dst_value = 0; + err = bpf_map_lookup_elem(map_fd2, &zero, &dst_value); + ASSERT_OK(err, "map_lookup"); + ASSERT_EQ(dst_value, src_value, "map_value_eq1"); + ASSERT_EQ(dst_value, 0xcafebeef, "map_value_eq2"); + +cleanup: + if (map_fd >= 0) + ASSERT_OK(close(map_fd), "close_map_fd"); + if (map_fd2 >= 0) + ASSERT_OK(close(map_fd2), "close_map_fd2"); + if (fs_fd >= 0) + ASSERT_OK(close(fs_fd), "close_fs_fd"); + if (mnt_fd >= 0) + ASSERT_OK(close(mnt_fd), "close_mnt_fd"); +} + +enum path_kind +{ + PATH_STR_ABS, + PATH_STR_REL, + PATH_FD_REL, +}; + +static void validate_pin(int map_fd, const char *map_name, int src_value, + enum path_kind path_kind) +{ + LIBBPF_OPTS(bpf_obj_pin_opts, pin_opts); + char abs_path[PATH_MAX], old_cwd[PATH_MAX]; + const char *pin_path = NULL; + int zero = 0, dst_value, map_fd2, err; + + snprintf(abs_path, sizeof(abs_path), "/sys/fs/bpf/%s", map_name); + old_cwd[0] = '\0'; + + switch (path_kind) { + case PATH_STR_ABS: + /* absolute path */ + pin_path = abs_path; + break; + case PATH_STR_REL: + /* cwd + relative path */ + ASSERT_OK_PTR(getcwd(old_cwd, sizeof(old_cwd)), "getcwd"); + ASSERT_OK(chdir("/sys/fs/bpf"), "chdir"); + pin_path = map_name; + break; + case PATH_FD_REL: + /* dir fd + relative path */ + pin_opts.file_flags = BPF_F_PATH_FD; + pin_opts.path_fd = open("/sys/fs/bpf", O_PATH); + ASSERT_GE(pin_opts.path_fd, 0, "path_fd"); + pin_path = map_name; + break; + } + + /* pin BPF map using specified path definition */ + err = bpf_obj_pin_opts(map_fd, pin_path, &pin_opts); + ASSERT_OK(err, "obj_pin"); + + /* cleanup */ + if (pin_opts.path_fd >= 0) + close(pin_opts.path_fd); + if (old_cwd[0]) + ASSERT_OK(chdir(old_cwd), "restore_cwd"); + + map_fd2 = bpf_obj_get(abs_path); + if (!ASSERT_GE(map_fd2, 0, "map_get")) + goto cleanup; + + /* update map through one FD */ + err = bpf_map_update_elem(map_fd, &zero, &src_value, 0); + ASSERT_OK(err, "map_update"); + + /* check values written/read through different FDs do match */ + dst_value = 0; + err = bpf_map_lookup_elem(map_fd2, &zero, &dst_value); + ASSERT_OK(err, "map_lookup"); + ASSERT_EQ(dst_value, src_value, "map_value_eq"); +cleanup: + if (map_fd2 >= 0) + ASSERT_OK(close(map_fd2), "close_map_fd2"); + unlink(abs_path); +} + +static void validate_get(int map_fd, const char *map_name, int src_value, + enum path_kind path_kind) +{ + LIBBPF_OPTS(bpf_obj_get_opts, get_opts); + char abs_path[PATH_MAX], old_cwd[PATH_MAX]; + const char *pin_path = NULL; + int zero = 0, dst_value, map_fd2, err; + + snprintf(abs_path, sizeof(abs_path), "/sys/fs/bpf/%s", map_name); + /* pin BPF map using specified path definition */ + err = bpf_obj_pin(map_fd, abs_path); + if (!ASSERT_OK(err, "pin_map")) + return; + + old_cwd[0] = '\0'; + + switch (path_kind) { + case PATH_STR_ABS: + /* absolute path */ + pin_path = abs_path; + break; + case PATH_STR_REL: + /* cwd + relative path */ + ASSERT_OK_PTR(getcwd(old_cwd, sizeof(old_cwd)), "getcwd"); + ASSERT_OK(chdir("/sys/fs/bpf"), "chdir"); + pin_path = map_name; + break; + case PATH_FD_REL: + /* dir fd + relative path */ + get_opts.file_flags = BPF_F_PATH_FD; + get_opts.path_fd = open("/sys/fs/bpf", O_PATH); + ASSERT_GE(get_opts.path_fd, 0, "path_fd"); + pin_path = map_name; + break; + } + + map_fd2 = bpf_obj_get_opts(pin_path, &get_opts); + if (!ASSERT_GE(map_fd2, 0, "map_get")) + goto cleanup; + + /* cleanup */ + if (get_opts.path_fd >= 0) + close(get_opts.path_fd); + if (old_cwd[0]) + ASSERT_OK(chdir(old_cwd), "restore_cwd"); + + /* update map through one FD */ + err = bpf_map_update_elem(map_fd, &zero, &src_value, 0); + ASSERT_OK(err, "map_update"); + + /* check values written/read through different FDs do match */ + dst_value = 0; + err = bpf_map_lookup_elem(map_fd2, &zero, &dst_value); + ASSERT_OK(err, "map_lookup"); + ASSERT_EQ(dst_value, src_value, "map_value_eq"); +cleanup: + if (map_fd2 >= 0) + ASSERT_OK(close(map_fd2), "close_map_fd2"); + unlink(abs_path); +} + +static void bpf_obj_pinning_mounted(enum path_kind path_kind) +{ + const char *map_name = "mounted_map"; + int map_fd; + + /* create BPF map to pin */ + map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, map_name, 4, 4, 1, NULL); + if (!ASSERT_GE(map_fd, 0, "map_fd")) + return; + + validate_pin(map_fd, map_name, 100 + (int)path_kind, path_kind); + validate_get(map_fd, map_name, 200 + (int)path_kind, path_kind); + ASSERT_OK(close(map_fd), "close_map_fd"); +} + +void test_bpf_obj_pinning() +{ + if (test__start_subtest("detached")) + bpf_obj_pinning_detached(); + if (test__start_subtest("mounted-str-abs")) + bpf_obj_pinning_mounted(PATH_STR_ABS); + if (test__start_subtest("mounted-str-rel")) + bpf_obj_pinning_mounted(PATH_STR_REL); + if (test__start_subtest("mounted-fd-rel")) + bpf_obj_pinning_mounted(PATH_FD_REL); +} -- cgit v1.2.3 From b842f4f55810b5d94dbbdda00f38dce38ec1bbb6 Mon Sep 17 00:00:00 2001 From: Claudio Migliorelli Date: Sat, 25 Feb 2023 19:07:11 +0100 Subject: Add tests for memblock_alloc_node() This test is aimed at verifying the memblock_alloc_node() to work as expected, so setting the correct NUMA node for the new allocated region. The memblock_alloc_node() is called directly without using any stub. The core check is between the requested NUMA node and the `nid` field inside the memblock_region structure. These two are supposed to be equal for the test to succeed. Signed-off-by: Claudio Migliorelli Link: https://lore.kernel.org/r/ea5e938e-6b74-b188-af59-4b94b18bc0@mail.polimi.it Signed-off-by: Mike Rapoport (IBM) --- tools/testing/memblock/tests/alloc_nid_api.c | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/memblock/tests/alloc_nid_api.c b/tools/testing/memblock/tests/alloc_nid_api.c index 49ef68cccd6f..49bb416d34ff 100644 --- a/tools/testing/memblock/tests/alloc_nid_api.c +++ b/tools/testing/memblock/tests/alloc_nid_api.c @@ -2494,6 +2494,35 @@ static int alloc_nid_numa_split_all_reserved_generic_check(void) return 0; } +/* + * A simple test that tries to allocate a memory region through the + * memblock_alloc_node() on a NUMA node with id `nid`. Expected to have the + * correct NUMA node set for the new region. + */ +static int alloc_node_on_correct_nid(void) +{ + int nid_req = 2; + void *allocated_ptr = NULL; +#ifdef CONFIG_NUMA + struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +#endif + phys_addr_t size = SZ_512; + + PREFIX_PUSH(); + setup_numa_memblock(node_fractions); + + allocated_ptr = memblock_alloc_node(size, SMP_CACHE_BYTES, nid_req); + + ASSERT_NE(allocated_ptr, NULL); +#ifdef CONFIG_NUMA + ASSERT_EQ(nid_req, req_node->nid); +#endif + + test_pass_pop(); + + return 0; +} + /* Test case wrappers for NUMA tests */ static int alloc_nid_numa_simple_check(void) { @@ -2632,6 +2661,15 @@ static int alloc_nid_numa_split_all_reserved_check(void) return 0; } +static int alloc_node_numa_on_correct_nid(void) +{ + test_print("\tRunning %s...\n", __func__); + run_top_down(alloc_node_on_correct_nid); + run_bottom_up(alloc_node_on_correct_nid); + + return 0; +} + int __memblock_alloc_nid_numa_checks(void) { test_print("Running %s NUMA tests...\n", @@ -2652,6 +2690,8 @@ int __memblock_alloc_nid_numa_checks(void) alloc_nid_numa_reserved_full_merge_check(); alloc_nid_numa_split_all_reserved_check(); + alloc_node_numa_on_correct_nid(); + return 0; } -- cgit v1.2.3 From 08b0895675736c49f7b172eac7d5c042fc71c3ec Mon Sep 17 00:00:00 2001 From: JP Kobryn Date: Tue, 23 May 2023 17:45:37 -0700 Subject: libbpf: Selftests for resizing datasec maps This patch adds test coverage for resizing datasec maps. The first two subtests resize the bss and custom data sections. In both cases, an initial array (of length one) has its element set to one. After resizing the rest of the array is filled with ones as well. A BPF program is then run to sum the respective arrays and back on the userspace side the sum is checked to be equal to the number of elements. The third subtest attempts to perform resizing under conditions that will result in either the resize failing or the BTF info being cleared. Signed-off-by: JP Kobryn Signed-off-by: Andrii Nakryiko Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20230524004537.18614-3-inwardvessel@gmail.com --- .../selftests/bpf/prog_tests/global_map_resize.c | 227 +++++++++++++++++++++ .../selftests/bpf/progs/test_global_map_resize.c | 58 ++++++ 2 files changed, 285 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/global_map_resize.c create mode 100644 tools/testing/selftests/bpf/progs/test_global_map_resize.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/global_map_resize.c b/tools/testing/selftests/bpf/prog_tests/global_map_resize.c new file mode 100644 index 000000000000..fd41425d2e5c --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/global_map_resize.c @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ +#include +#include +#include +#include "test_global_map_resize.skel.h" +#include "test_progs.h" + +static void run_prog_bss_array_sum(void) +{ + (void)syscall(__NR_getpid); +} + +static void run_prog_data_array_sum(void) +{ + (void)syscall(__NR_getuid); +} + +static void global_map_resize_bss_subtest(void) +{ + int err; + struct test_global_map_resize *skel; + struct bpf_map *map; + const __u32 desired_sz = sizeof(skel->bss->sum) + sysconf(_SC_PAGE_SIZE) * 2; + size_t array_len, actual_sz; + + skel = test_global_map_resize__open(); + if (!ASSERT_OK_PTR(skel, "test_global_map_resize__open")) + goto teardown; + + /* set some initial value before resizing. + * it is expected this non-zero value will be preserved + * while resizing. + */ + skel->bss->array[0] = 1; + + /* resize map value and verify the new size */ + map = skel->maps.bss; + err = bpf_map__set_value_size(map, desired_sz); + if (!ASSERT_OK(err, "bpf_map__set_value_size")) + goto teardown; + if (!ASSERT_EQ(bpf_map__value_size(map), desired_sz, "resize")) + goto teardown; + + /* set the expected number of elements based on the resized array */ + array_len = (desired_sz - sizeof(skel->bss->sum)) / sizeof(skel->bss->array[0]); + if (!ASSERT_GT(array_len, 1, "array_len")) + goto teardown; + + skel->bss = bpf_map__initial_value(skel->maps.bss, &actual_sz); + if (!ASSERT_OK_PTR(skel->bss, "bpf_map__initial_value (ptr)")) + goto teardown; + if (!ASSERT_EQ(actual_sz, desired_sz, "bpf_map__initial_value (size)")) + goto teardown; + + /* fill the newly resized array with ones, + * skipping the first element which was previously set + */ + for (int i = 1; i < array_len; i++) + skel->bss->array[i] = 1; + + /* set global const values before loading */ + skel->rodata->pid = getpid(); + skel->rodata->bss_array_len = array_len; + skel->rodata->data_array_len = 1; + + err = test_global_map_resize__load(skel); + if (!ASSERT_OK(err, "test_global_map_resize__load")) + goto teardown; + err = test_global_map_resize__attach(skel); + if (!ASSERT_OK(err, "test_global_map_resize__attach")) + goto teardown; + + /* run the bpf program which will sum the contents of the array. + * since the array was filled with ones,verify the sum equals array_len + */ + run_prog_bss_array_sum(); + if (!ASSERT_EQ(skel->bss->sum, array_len, "sum")) + goto teardown; + +teardown: + test_global_map_resize__destroy(skel); +} + +static void global_map_resize_data_subtest(void) +{ + int err; + struct test_global_map_resize *skel; + struct bpf_map *map; + const __u32 desired_sz = sysconf(_SC_PAGE_SIZE) * 2; + size_t array_len, actual_sz; + + skel = test_global_map_resize__open(); + if (!ASSERT_OK_PTR(skel, "test_global_map_resize__open")) + goto teardown; + + /* set some initial value before resizing. + * it is expected this non-zero value will be preserved + * while resizing. + */ + skel->data_custom->my_array[0] = 1; + + /* resize map value and verify the new size */ + map = skel->maps.data_custom; + err = bpf_map__set_value_size(map, desired_sz); + if (!ASSERT_OK(err, "bpf_map__set_value_size")) + goto teardown; + if (!ASSERT_EQ(bpf_map__value_size(map), desired_sz, "resize")) + goto teardown; + + /* set the expected number of elements based on the resized array */ + array_len = (desired_sz - sizeof(skel->bss->sum)) / sizeof(skel->data_custom->my_array[0]); + if (!ASSERT_GT(array_len, 1, "array_len")) + goto teardown; + + skel->data_custom = bpf_map__initial_value(skel->maps.data_custom, &actual_sz); + if (!ASSERT_OK_PTR(skel->data_custom, "bpf_map__initial_value (ptr)")) + goto teardown; + if (!ASSERT_EQ(actual_sz, desired_sz, "bpf_map__initial_value (size)")) + goto teardown; + + /* fill the newly resized array with ones, + * skipping the first element which was previously set + */ + for (int i = 1; i < array_len; i++) + skel->data_custom->my_array[i] = 1; + + /* set global const values before loading */ + skel->rodata->pid = getpid(); + skel->rodata->bss_array_len = 1; + skel->rodata->data_array_len = array_len; + + err = test_global_map_resize__load(skel); + if (!ASSERT_OK(err, "test_global_map_resize__load")) + goto teardown; + err = test_global_map_resize__attach(skel); + if (!ASSERT_OK(err, "test_global_map_resize__attach")) + goto teardown; + + /* run the bpf program which will sum the contents of the array. + * since the array was filled with ones,verify the sum equals array_len + */ + run_prog_data_array_sum(); + if (!ASSERT_EQ(skel->bss->sum, array_len, "sum")) + goto teardown; + +teardown: + test_global_map_resize__destroy(skel); +} + +static void global_map_resize_invalid_subtest(void) +{ + int err; + struct test_global_map_resize *skel; + struct bpf_map *map; + __u32 element_sz, desired_sz; + + skel = test_global_map_resize__open(); + if (!ASSERT_OK_PTR(skel, "test_global_map_resize__open")) + return; + + /* attempt to resize a global datasec map to size + * which does NOT align with array + */ + map = skel->maps.data_custom; + if (!ASSERT_NEQ(bpf_map__btf_value_type_id(map), 0, ".data.custom initial btf")) + goto teardown; + /* set desired size a fraction of element size beyond an aligned size */ + element_sz = sizeof(skel->data_custom->my_array[0]); + desired_sz = element_sz + element_sz / 2; + /* confirm desired size does NOT align with array */ + if (!ASSERT_NEQ(desired_sz % element_sz, 0, "my_array alignment")) + goto teardown; + err = bpf_map__set_value_size(map, desired_sz); + /* confirm resize is OK but BTF info is cleared */ + if (!ASSERT_OK(err, ".data.custom bpf_map__set_value_size") || + !ASSERT_EQ(bpf_map__btf_key_type_id(map), 0, ".data.custom clear btf key") || + !ASSERT_EQ(bpf_map__btf_value_type_id(map), 0, ".data.custom clear btf val")) + goto teardown; + + /* attempt to resize a global datasec map whose only var is NOT an array */ + map = skel->maps.data_non_array; + if (!ASSERT_NEQ(bpf_map__btf_value_type_id(map), 0, ".data.non_array initial btf")) + goto teardown; + /* set desired size to arbitrary value */ + desired_sz = 1024; + err = bpf_map__set_value_size(map, desired_sz); + /* confirm resize is OK but BTF info is cleared */ + if (!ASSERT_OK(err, ".data.non_array bpf_map__set_value_size") || + !ASSERT_EQ(bpf_map__btf_key_type_id(map), 0, ".data.non_array clear btf key") || + !ASSERT_EQ(bpf_map__btf_value_type_id(map), 0, ".data.non_array clear btf val")) + goto teardown; + + /* attempt to resize a global datasec map + * whose last var is NOT an array + */ + map = skel->maps.data_array_not_last; + if (!ASSERT_NEQ(bpf_map__btf_value_type_id(map), 0, ".data.array_not_last initial btf")) + goto teardown; + /* set desired size to a multiple of element size */ + element_sz = sizeof(skel->data_array_not_last->my_array_first[0]); + desired_sz = element_sz * 8; + /* confirm desired size aligns with array */ + if (!ASSERT_EQ(desired_sz % element_sz, 0, "my_array_first alignment")) + goto teardown; + err = bpf_map__set_value_size(map, desired_sz); + /* confirm resize is OK but BTF info is cleared */ + if (!ASSERT_OK(err, ".data.array_not_last bpf_map__set_value_size") || + !ASSERT_EQ(bpf_map__btf_key_type_id(map), 0, ".data.array_not_last clear btf key") || + !ASSERT_EQ(bpf_map__btf_value_type_id(map), 0, ".data.array_not_last clear btf val")) + goto teardown; + +teardown: + test_global_map_resize__destroy(skel); +} + +void test_global_map_resize(void) +{ + if (test__start_subtest("global_map_resize_bss")) + global_map_resize_bss_subtest(); + + if (test__start_subtest("global_map_resize_data")) + global_map_resize_data_subtest(); + + if (test__start_subtest("global_map_resize_invalid")) + global_map_resize_invalid_subtest(); +} diff --git a/tools/testing/selftests/bpf/progs/test_global_map_resize.c b/tools/testing/selftests/bpf/progs/test_global_map_resize.c new file mode 100644 index 000000000000..2588f2384246 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_global_map_resize.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include "vmlinux.h" +#include + +char _license[] SEC("license") = "GPL"; + +/* rodata section */ +const volatile pid_t pid; +const volatile size_t bss_array_len; +const volatile size_t data_array_len; + +/* bss section */ +int sum = 0; +int array[1]; + +/* custom data secton */ +int my_array[1] SEC(".data.custom"); + +/* custom data section which should NOT be resizable, + * since it contains a single var which is not an array + */ +int my_int SEC(".data.non_array"); + +/* custom data section which should NOT be resizable, + * since its last var is not an array + */ +int my_array_first[1] SEC(".data.array_not_last"); +int my_int_last SEC(".data.array_not_last"); + +SEC("tp/syscalls/sys_enter_getpid") +int bss_array_sum(void *ctx) +{ + if (pid != (bpf_get_current_pid_tgid() >> 32)) + return 0; + + sum = 0; + + for (size_t i = 0; i < bss_array_len; ++i) + sum += array[i]; + + return 0; +} + +SEC("tp/syscalls/sys_enter_getuid") +int data_array_sum(void *ctx) +{ + if (pid != (bpf_get_current_pid_tgid() >> 32)) + return 0; + + sum = 0; + + for (size_t i = 0; i < data_array_len; ++i) + sum += my_array[i]; + + return 0; +} -- cgit v1.2.3 From 321a64b328156fd43d3be589c24905a641c7995b Mon Sep 17 00:00:00 2001 From: Daniel Müller Date: Thu, 25 May 2023 23:22:48 +0000 Subject: selftests/bpf: Check whether to run selftest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sockopt test invokes test__start_subtest and then unconditionally asserts the success. That means that even if deny-listed, any test will still run and potentially fail. Evaluate the return value of test__start_subtest() to achieve the desired behavior, as other tests do. Signed-off-by: Daniel Müller Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20230525232248.640465-1-deso@posteo.net --- tools/testing/selftests/bpf/prog_tests/sockopt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/sockopt.c b/tools/testing/selftests/bpf/prog_tests/sockopt.c index 33dd4532e642..9e6a5e3ed4de 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockopt.c +++ b/tools/testing/selftests/bpf/prog_tests/sockopt.c @@ -1060,7 +1060,9 @@ void test_sockopt(void) return; for (i = 0; i < ARRAY_SIZE(tests); i++) { - test__start_subtest(tests[i].descr); + if (!test__start_subtest(tests[i].descr)) + continue; + ASSERT_OK(run_test(cgroup_fd, &tests[i]), tests[i].descr); } -- cgit v1.2.3 From cb5aa637943857f7f937a51d1e621dbe925f9f67 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 22 May 2023 15:28:00 +0100 Subject: kselftest/arm64: Add a smoke test for ptracing hardware break/watch points There was a report that the hardware breakpoints and watch points weren't reporting the debug architecture version as expected, they were reporting a version of 0 which is not defined in the architecture. This happens when running in a KVM guest if the host has a debug architecture version not supported by KVM, it in turn confuses GDB which rejects any debug architecture version it does not know about. Add a test that covers that situation and while we're at it reports the debug architecture version and number of slots available to aid with figuring out problems that may arise. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230414-arm64-test-hw-breakpoint-v2-1-90a19e3b1059@kernel.org Signed-off-by: Catalin Marinas --- tools/testing/selftests/arm64/abi/ptrace.c | 32 +++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/arm64/abi/ptrace.c b/tools/testing/selftests/arm64/abi/ptrace.c index be952511af22..abe4d58d731d 100644 --- a/tools/testing/selftests/arm64/abi/ptrace.c +++ b/tools/testing/selftests/arm64/abi/ptrace.c @@ -20,7 +20,7 @@ #include "../../kselftest.h" -#define EXPECTED_TESTS 7 +#define EXPECTED_TESTS 11 #define MAX_TPIDRS 2 @@ -132,6 +132,34 @@ static void test_tpidr(pid_t child) } } +static void test_hw_debug(pid_t child, int type, const char *type_name) +{ + struct user_hwdebug_state state; + struct iovec iov; + int slots, arch, ret; + + iov.iov_len = sizeof(state); + iov.iov_base = &state; + + /* Should be able to read the values */ + ret = ptrace(PTRACE_GETREGSET, child, type, &iov); + ksft_test_result(ret == 0, "read_%s\n", type_name); + + if (ret == 0) { + /* Low 8 bits is the number of slots, next 4 bits the arch */ + slots = state.dbg_info & 0xff; + arch = (state.dbg_info >> 8) & 0xf; + + ksft_print_msg("%s version %d with %d slots\n", type_name, + arch, slots); + + /* Zero is not currently architecturally valid */ + ksft_test_result(arch, "%s_arch_set\n", type_name); + } else { + ksft_test_result_skip("%s_arch_set\n"); + } +} + static int do_child(void) { if (ptrace(PTRACE_TRACEME, -1, NULL, NULL)) @@ -207,6 +235,8 @@ static int do_parent(pid_t child) ksft_print_msg("Parent is %d, child is %d\n", getpid(), child); test_tpidr(child); + test_hw_debug(child, NT_ARM_HW_WATCH, "NT_ARM_HW_WATCH"); + test_hw_debug(child, NT_ARM_HW_BREAK, "NT_ARM_HW_BREAK"); ret = EXIT_SUCCESS; -- cgit v1.2.3 From 15d5daa0a7006b9bd4dcc49f90e7ac8ddbe102f2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 17 May 2023 15:18:07 +0200 Subject: kallsyms: remove unused arch_get_kallsym() helper The arch_get_kallsym() function was introduced so that x86 could override it, but that override was removed in bf904d2762ee ("x86/pti/64: Remove the SYSCALL64 entry trampoline"), so now this does nothing except causing a warning about a missing prototype: kernel/kallsyms.c:662:12: error: no previous prototype for 'arch_get_kallsym' [-Werror=missing-prototypes] 662 | int __weak arch_get_kallsym(unsigned int symnum, unsigned long *value, Restore the old behavior before d83212d5dd67 ("kallsyms, x86: Export addresses of PTI entry trampolines") to simplify the code and avoid the warning. Signed-off-by: Arnd Bergmann Tested-by: Alan Maguire [mcgrof: fold in bpf selftest fix] Signed-off-by: Luis Chamberlain --- kernel/kallsyms.c | 28 +---------------------- tools/testing/selftests/bpf/progs/bpf_iter_ksym.c | 4 +--- 2 files changed, 2 insertions(+), 30 deletions(-) (limited to 'tools/testing') diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 77747391f49b..290d8cc1943a 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -646,7 +646,6 @@ int sprint_backtrace_build_id(char *buffer, unsigned long address) /* To avoid using get_symbol_offset for every symbol, we carry prefix along. */ struct kallsym_iter { loff_t pos; - loff_t pos_arch_end; loff_t pos_mod_end; loff_t pos_ftrace_mod_end; loff_t pos_bpf_end; @@ -659,29 +658,9 @@ struct kallsym_iter { int show_value; }; -int __weak arch_get_kallsym(unsigned int symnum, unsigned long *value, - char *type, char *name) -{ - return -EINVAL; -} - -static int get_ksymbol_arch(struct kallsym_iter *iter) -{ - int ret = arch_get_kallsym(iter->pos - kallsyms_num_syms, - &iter->value, &iter->type, - iter->name); - - if (ret < 0) { - iter->pos_arch_end = iter->pos; - return 0; - } - - return 1; -} - static int get_ksymbol_mod(struct kallsym_iter *iter) { - int ret = module_get_kallsym(iter->pos - iter->pos_arch_end, + int ret = module_get_kallsym(iter->pos - kallsyms_num_syms, &iter->value, &iter->type, iter->name, iter->module_name, &iter->exported); @@ -764,7 +743,6 @@ static void reset_iter(struct kallsym_iter *iter, loff_t new_pos) iter->nameoff = get_symbol_offset(new_pos); iter->pos = new_pos; if (new_pos == 0) { - iter->pos_arch_end = 0; iter->pos_mod_end = 0; iter->pos_ftrace_mod_end = 0; iter->pos_bpf_end = 0; @@ -780,10 +758,6 @@ static int update_iter_mod(struct kallsym_iter *iter, loff_t pos) { iter->pos = pos; - if ((!iter->pos_arch_end || iter->pos_arch_end > pos) && - get_ksymbol_arch(iter)) - return 1; - if ((!iter->pos_mod_end || iter->pos_mod_end > pos) && get_ksymbol_mod(iter)) return 1; diff --git a/tools/testing/selftests/bpf/progs/bpf_iter_ksym.c b/tools/testing/selftests/bpf/progs/bpf_iter_ksym.c index 5ddcc46fd886..521267818f4d 100644 --- a/tools/testing/selftests/bpf/progs/bpf_iter_ksym.c +++ b/tools/testing/selftests/bpf/progs/bpf_iter_ksym.c @@ -59,9 +59,7 @@ int dump_ksym(struct bpf_iter__ksym *ctx) } else { BPF_SEQ_PRINTF(seq, "0x%llx %c %s ", value, type, iter->name); } - if (!iter->pos_arch_end || iter->pos_arch_end > iter->pos) - BPF_SEQ_PRINTF(seq, "CORE "); - else if (!iter->pos_mod_end || iter->pos_mod_end > iter->pos) + if (!iter->pos_mod_end || iter->pos_mod_end > iter->pos) BPF_SEQ_PRINTF(seq, "MOD "); else if (!iter->pos_ftrace_mod_end || iter->pos_ftrace_mod_end > iter->pos) BPF_SEQ_PRINTF(seq, "FTRACE_MOD "); -- cgit v1.2.3 From e38096d95f4d7e8cc15280b4a3515eee31925561 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 30 May 2023 13:50:34 -0700 Subject: selftests/bpf: Add a test where map key_type_id with decl_tag type Add two selftests where map creation key/value type_id's are decl_tags. Without previous patch, kernel warnings will appear similar to the one in the previous patch. With the previous patch, both kernel warnings are silenced. Signed-off-by: Yonghong Song Link: https://lore.kernel.org/r/20230530205034.266643-1-yhs@fb.com Signed-off-by: Martin KaFai Lau --- tools/testing/selftests/bpf/prog_tests/btf.c | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/btf.c b/tools/testing/selftests/bpf/prog_tests/btf.c index 210d643fda6c..4e0cdb593318 100644 --- a/tools/testing/selftests/bpf/prog_tests/btf.c +++ b/tools/testing/selftests/bpf/prog_tests/btf.c @@ -3990,6 +3990,46 @@ static struct btf_raw_test raw_tests[] = { .btf_load_err = true, .err_str = "Invalid arg#1", }, +{ + .descr = "decl_tag test #18, decl_tag as the map key type", + .raw_types = { + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + BTF_STRUCT_ENC(0, 2, 8), /* [2] */ + BTF_MEMBER_ENC(NAME_TBD, 1, 0), + BTF_MEMBER_ENC(NAME_TBD, 1, 32), + BTF_DECL_TAG_ENC(NAME_TBD, 2, -1), /* [3] */ + BTF_END_RAW, + }, + BTF_STR_SEC("\0m1\0m2\0tag"), + .map_type = BPF_MAP_TYPE_HASH, + .map_name = "tag_type_check_btf", + .key_size = 8, + .value_size = 4, + .key_type_id = 3, + .value_type_id = 1, + .max_entries = 1, + .map_create_err = true, +}, +{ + .descr = "decl_tag test #19, decl_tag as the map value type", + .raw_types = { + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + BTF_STRUCT_ENC(0, 2, 8), /* [2] */ + BTF_MEMBER_ENC(NAME_TBD, 1, 0), + BTF_MEMBER_ENC(NAME_TBD, 1, 32), + BTF_DECL_TAG_ENC(NAME_TBD, 2, -1), /* [3] */ + BTF_END_RAW, + }, + BTF_STR_SEC("\0m1\0m2\0tag"), + .map_type = BPF_MAP_TYPE_HASH, + .map_name = "tag_type_check_btf", + .key_size = 4, + .value_size = 8, + .key_type_id = 1, + .value_type_id = 3, + .max_entries = 1, + .map_create_err = true, +}, { .descr = "type_tag test #1", .raw_types = { -- cgit v1.2.3 From 8c33266ae26aa462409f8959624a95aea7831763 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 29 May 2023 14:48:35 +0300 Subject: selftests: forwarding: Add layer 2 miss test cases Add test cases to verify that the bridge driver correctly marks layer 2 misses only when it should and that the flower classifier can match on this metadata. Example output: # ./tc_flower_l2_miss.sh TEST: L2 miss - Unicast [ OK ] TEST: L2 miss - Multicast (IPv4) [ OK ] TEST: L2 miss - Multicast (IPv6) [ OK ] TEST: L2 miss - Link-local multicast (IPv4) [ OK ] TEST: L2 miss - Link-local multicast (IPv6) [ OK ] TEST: L2 miss - Broadcast [ OK ] Signed-off-by: Ido Schimmel Reviewed-by: Nikolay Aleksandrov Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/Makefile | 1 + .../selftests/net/forwarding/tc_flower_l2_miss.sh | 350 +++++++++++++++++++++ 2 files changed, 351 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/Makefile b/tools/testing/selftests/net/forwarding/Makefile index a474c60fe348..9d0062b542e5 100644 --- a/tools/testing/selftests/net/forwarding/Makefile +++ b/tools/testing/selftests/net/forwarding/Makefile @@ -83,6 +83,7 @@ TEST_PROGS = bridge_igmp.sh \ tc_chains.sh \ tc_flower_router.sh \ tc_flower.sh \ + tc_flower_l2_miss.sh \ tc_mpls_l2vpn.sh \ tc_police.sh \ tc_shblocks.sh \ diff --git a/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh b/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh new file mode 100755 index 000000000000..37b0369b5246 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh @@ -0,0 +1,350 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# +-----------------------+ +----------------------+ +# | H1 (vrf) | | H2 (vrf) | +# | + $h1 | | $h2 + | +# | | 192.0.2.1/28 | | 192.0.2.2/28 | | +# | | 2001:db8:1::1/64 | | 2001:db8:1::2/64 | | +# +----|------------------+ +------------------|---+ +# | | +# +----|-------------------------------------------------------------------|---+ +# | SW | | | +# | +-|-------------------------------------------------------------------|-+ | +# | | + $swp1 BR $swp2 + | | +# | +-----------------------------------------------------------------------+ | +# +----------------------------------------------------------------------------+ + +ALL_TESTS=" + test_l2_miss_unicast + test_l2_miss_multicast + test_l2_miss_ll_multicast + test_l2_miss_broadcast +" + +NUM_NETIFS=4 +source lib.sh +source tc_common.sh + +h1_create() +{ + simple_if_init $h1 192.0.2.1/28 2001:db8:1::1/64 +} + +h1_destroy() +{ + simple_if_fini $h1 192.0.2.1/28 2001:db8:1::1/64 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.2/28 2001:db8:1::2/64 +} + +h2_destroy() +{ + simple_if_fini $h2 192.0.2.2/28 2001:db8:1::2/64 +} + +switch_create() +{ + ip link add name br1 up type bridge + ip link set dev $swp1 master br1 + ip link set dev $swp1 up + ip link set dev $swp2 master br1 + ip link set dev $swp2 up + + tc qdisc add dev $swp2 clsact +} + +switch_destroy() +{ + tc qdisc del dev $swp2 clsact + + ip link set dev $swp2 down + ip link set dev $swp2 nomaster + ip link set dev $swp1 down + ip link set dev $swp1 nomaster + ip link del dev br1 +} + +test_l2_miss_unicast() +{ + local dmac=00:01:02:03:04:05 + local dip=192.0.2.2 + local sip=192.0.2.1 + + RET=0 + + # Unknown unicast. + tc filter add dev $swp2 egress protocol ipv4 handle 101 pref 1 \ + flower indev $swp1 l2_miss true dst_mac $dmac src_ip $sip \ + dst_ip $dip action pass + # Known unicast. + tc filter add dev $swp2 egress protocol ipv4 handle 102 pref 1 \ + flower indev $swp1 l2_miss false dst_mac $dmac src_ip $sip \ + dst_ip $dip action pass + + # Before adding FDB entry. + $MZ $h1 -a own -b $dmac -t ip -A $sip -B $dip -c 1 -p 100 -q + + tc_check_packets "dev $swp2 egress" 101 1 + check_err $? "Unknown unicast filter was not hit before adding FDB entry" + + tc_check_packets "dev $swp2 egress" 102 0 + check_err $? "Known unicast filter was hit before adding FDB entry" + + # Adding FDB entry. + bridge fdb replace $dmac dev $swp2 master static + + $MZ $h1 -a own -b $dmac -t ip -A $sip -B $dip -c 1 -p 100 -q + + tc_check_packets "dev $swp2 egress" 101 1 + check_err $? "Unknown unicast filter was hit after adding FDB entry" + + tc_check_packets "dev $swp2 egress" 102 1 + check_err $? "Known unicast filter was not hit after adding FDB entry" + + # Deleting FDB entry. + bridge fdb del $dmac dev $swp2 master static + + $MZ $h1 -a own -b $dmac -t ip -A $sip -B $dip -c 1 -p 100 -q + + tc_check_packets "dev $swp2 egress" 101 2 + check_err $? "Unknown unicast filter was not hit after deleting FDB entry" + + tc_check_packets "dev $swp2 egress" 102 1 + check_err $? "Known unicast filter was hit after deleting FDB entry" + + tc filter del dev $swp2 egress protocol ipv4 pref 1 handle 102 flower + tc filter del dev $swp2 egress protocol ipv4 pref 1 handle 101 flower + + log_test "L2 miss - Unicast" +} + +test_l2_miss_multicast_common() +{ + local proto=$1; shift + local sip=$1; shift + local dip=$1; shift + local mode=$1; shift + local name=$1; shift + + RET=0 + + # Unregistered multicast. + tc filter add dev $swp2 egress protocol $proto handle 101 pref 1 \ + flower indev $swp1 l2_miss true src_ip $sip dst_ip $dip \ + action pass + # Registered multicast. + tc filter add dev $swp2 egress protocol $proto handle 102 pref 1 \ + flower indev $swp1 l2_miss false src_ip $sip dst_ip $dip \ + action pass + + # Before adding MDB entry. + $MZ $mode $h1 -t ip -A $sip -B $dip -c 1 -p 100 -q + + tc_check_packets "dev $swp2 egress" 101 1 + check_err $? "Unregistered multicast filter was not hit before adding MDB entry" + + tc_check_packets "dev $swp2 egress" 102 0 + check_err $? "Registered multicast filter was hit before adding MDB entry" + + # Adding MDB entry. + bridge mdb replace dev br1 port $swp2 grp $dip permanent + + $MZ $mode $h1 -t ip -A $sip -B $dip -c 1 -p 100 -q + + tc_check_packets "dev $swp2 egress" 101 1 + check_err $? "Unregistered multicast filter was hit after adding MDB entry" + + tc_check_packets "dev $swp2 egress" 102 1 + check_err $? "Registered multicast filter was not hit after adding MDB entry" + + # Deleting MDB entry. + bridge mdb del dev br1 port $swp2 grp $dip + + $MZ $mode $h1 -t ip -A $sip -B $dip -c 1 -p 100 -q + + tc_check_packets "dev $swp2 egress" 101 2 + check_err $? "Unregistered multicast filter was not hit after deleting MDB entry" + + tc_check_packets "dev $swp2 egress" 102 1 + check_err $? "Registered multicast filter was hit after deleting MDB entry" + + tc filter del dev $swp2 egress protocol $proto pref 1 handle 102 flower + tc filter del dev $swp2 egress protocol $proto pref 1 handle 101 flower + + log_test "L2 miss - Multicast ($name)" +} + +test_l2_miss_multicast_ipv4() +{ + local proto="ipv4" + local sip=192.0.2.1 + local dip=239.1.1.1 + local mode="-4" + local name="IPv4" + + test_l2_miss_multicast_common $proto $sip $dip $mode $name +} + +test_l2_miss_multicast_ipv6() +{ + local proto="ipv6" + local sip=2001:db8:1::1 + local dip=ff0e::1 + local mode="-6" + local name="IPv6" + + test_l2_miss_multicast_common $proto $sip $dip $mode $name +} + +test_l2_miss_multicast() +{ + # Configure $swp2 as a multicast router port so that it will forward + # both registered and unregistered multicast traffic. + bridge link set dev $swp2 mcast_router 2 + + # Forwarding according to MDB entries only takes place when the bridge + # detects that there is a valid querier in the network. Set the bridge + # as the querier and assign it a valid IPv6 link-local address to be + # used as the source address for MLD queries. + ip link set dev br1 type bridge mcast_querier 1 + ip -6 address add fe80::1/64 nodad dev br1 + # Wait the default Query Response Interval (10 seconds) for the bridge + # to determine that there are no other queriers in the network. + sleep 10 + + test_l2_miss_multicast_ipv4 + test_l2_miss_multicast_ipv6 + + ip -6 address del fe80::1/64 dev br1 + ip link set dev br1 type bridge mcast_querier 0 + bridge link set dev $swp2 mcast_router 1 +} + +test_l2_miss_multicast_common2() +{ + local name=$1; shift + local dmac=$1; shift + local dip=224.0.0.1 + local sip=192.0.2.1 + +} + +test_l2_miss_ll_multicast_common() +{ + local proto=$1; shift + local dmac=$1; shift + local sip=$1; shift + local dip=$1; shift + local mode=$1; shift + local name=$1; shift + + RET=0 + + tc filter add dev $swp2 egress protocol $proto handle 101 pref 1 \ + flower indev $swp1 l2_miss true dst_mac $dmac src_ip $sip \ + dst_ip $dip action pass + + $MZ $mode $h1 -a own -b $dmac -t ip -A $sip -B $dip -c 1 -p 100 -q + + tc_check_packets "dev $swp2 egress" 101 1 + check_err $? "Filter was not hit" + + tc filter del dev $swp2 egress protocol $proto pref 1 handle 101 flower + + log_test "L2 miss - Link-local multicast ($name)" +} + +test_l2_miss_ll_multicast_ipv4() +{ + local proto=ipv4 + local dmac=01:00:5e:00:00:01 + local sip=192.0.2.1 + local dip=224.0.0.1 + local mode="-4" + local name="IPv4" + + test_l2_miss_ll_multicast_common $proto $dmac $sip $dip $mode $name +} + +test_l2_miss_ll_multicast_ipv6() +{ + local proto=ipv6 + local dmac=33:33:00:00:00:01 + local sip=2001:db8:1::1 + local dip=ff02::1 + local mode="-6" + local name="IPv6" + + test_l2_miss_ll_multicast_common $proto $dmac $sip $dip $mode $name +} + +test_l2_miss_ll_multicast() +{ + test_l2_miss_ll_multicast_ipv4 + test_l2_miss_ll_multicast_ipv6 +} + +test_l2_miss_broadcast() +{ + local dmac=ff:ff:ff:ff:ff:ff + local smac=00:01:02:03:04:05 + + RET=0 + + tc filter add dev $swp2 egress protocol all handle 101 pref 1 \ + flower l2_miss true dst_mac $dmac src_mac $smac \ + action pass + tc filter add dev $swp2 egress protocol all handle 102 pref 1 \ + flower l2_miss false dst_mac $dmac src_mac $smac \ + action pass + + $MZ $h1 -a $smac -b $dmac -c 1 -p 100 -q + + tc_check_packets "dev $swp2 egress" 101 0 + check_err $? "L2 miss filter was hit when should not" + + tc_check_packets "dev $swp2 egress" 102 1 + check_err $? "L2 no miss filter was not hit when should" + + tc filter del dev $swp2 egress protocol all pref 1 handle 102 flower + tc filter del dev $swp2 egress protocol all pref 1 handle 101 flower + + log_test "L2 miss - Broadcast" +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + vrf_prepare + h1_create + h2_create + switch_create +} + +cleanup() +{ + pre_cleanup + + switch_destroy + h2_destroy + h1_destroy + vrf_cleanup +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +tests_run + +exit $EXIT_STATUS -- cgit v1.2.3 From d4ae3e587eced73c9b6f82fd8f88606a09ff710c Mon Sep 17 00:00:00 2001 From: Louis DeLosSantos Date: Wed, 31 May 2023 15:38:49 -0400 Subject: selftests/bpf: Test table ID fib lookup BPF helper Add additional test cases to `fib_lookup.c` prog_test. These test cases add a new /24 network to the previously unused veth2 device, removes the directly connected route from the main routing table and moves it to table 100. The first test case then confirms a fib lookup for a remote address in this directly connected network, using the main routing table fails. The second test case ensures the same fib lookup using table 100 succeeds. An additional pair of tests which function in the same manner are added for IPv6. Signed-off-by: Louis DeLosSantos Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230505-bpf-add-tbid-fib-lookup-v2-2-0a31c22c748c@gmail.com --- .../testing/selftests/bpf/prog_tests/fib_lookup.c | 61 +++++++++++++++++++--- 1 file changed, 53 insertions(+), 8 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/fib_lookup.c b/tools/testing/selftests/bpf/prog_tests/fib_lookup.c index a1e712105811..2fd05649bad1 100644 --- a/tools/testing/selftests/bpf/prog_tests/fib_lookup.c +++ b/tools/testing/selftests/bpf/prog_tests/fib_lookup.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ +#include #include #include @@ -15,14 +16,23 @@ #define IPV4_IFACE_ADDR "10.0.0.254" #define IPV4_NUD_FAILED_ADDR "10.0.0.1" #define IPV4_NUD_STALE_ADDR "10.0.0.2" +#define IPV4_TBID_ADDR "172.0.0.254" +#define IPV4_TBID_NET "172.0.0.0" +#define IPV4_TBID_DST "172.0.0.2" +#define IPV6_TBID_ADDR "fd00::FFFF" +#define IPV6_TBID_NET "fd00::" +#define IPV6_TBID_DST "fd00::2" #define DMAC "11:11:11:11:11:11" #define DMAC_INIT { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, } +#define DMAC2 "01:01:01:01:01:01" +#define DMAC_INIT2 { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, } struct fib_lookup_test { const char *desc; const char *daddr; int expected_ret; int lookup_flags; + __u32 tbid; __u8 dmac[6]; }; @@ -43,6 +53,22 @@ static const struct fib_lookup_test tests[] = { { .desc = "IPv4 skip neigh", .daddr = IPV4_NUD_FAILED_ADDR, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS, .lookup_flags = BPF_FIB_LOOKUP_SKIP_NEIGH, }, + { .desc = "IPv4 TBID lookup failure", + .daddr = IPV4_TBID_DST, .expected_ret = BPF_FIB_LKUP_RET_NOT_FWDED, + .lookup_flags = BPF_FIB_LOOKUP_DIRECT | BPF_FIB_LOOKUP_TBID, + .tbid = RT_TABLE_MAIN, }, + { .desc = "IPv4 TBID lookup success", + .daddr = IPV4_TBID_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS, + .lookup_flags = BPF_FIB_LOOKUP_DIRECT | BPF_FIB_LOOKUP_TBID, .tbid = 100, + .dmac = DMAC_INIT2, }, + { .desc = "IPv6 TBID lookup failure", + .daddr = IPV6_TBID_DST, .expected_ret = BPF_FIB_LKUP_RET_NOT_FWDED, + .lookup_flags = BPF_FIB_LOOKUP_DIRECT | BPF_FIB_LOOKUP_TBID, + .tbid = RT_TABLE_MAIN, }, + { .desc = "IPv6 TBID lookup success", + .daddr = IPV6_TBID_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS, + .lookup_flags = BPF_FIB_LOOKUP_DIRECT | BPF_FIB_LOOKUP_TBID, .tbid = 100, + .dmac = DMAC_INIT2, }, }; static int ifindex; @@ -53,6 +79,7 @@ static int setup_netns(void) SYS(fail, "ip link add veth1 type veth peer name veth2"); SYS(fail, "ip link set dev veth1 up"); + SYS(fail, "ip link set dev veth2 up"); err = write_sysctl("/proc/sys/net/ipv4/neigh/veth1/gc_stale_time", "900"); if (!ASSERT_OK(err, "write_sysctl(net.ipv4.neigh.veth1.gc_stale_time)")) @@ -70,6 +97,17 @@ static int setup_netns(void) SYS(fail, "ip neigh add %s dev veth1 nud failed", IPV4_NUD_FAILED_ADDR); SYS(fail, "ip neigh add %s dev veth1 lladdr %s nud stale", IPV4_NUD_STALE_ADDR, DMAC); + /* Setup for tbid lookup tests */ + SYS(fail, "ip addr add %s/24 dev veth2", IPV4_TBID_ADDR); + SYS(fail, "ip route del %s/24 dev veth2", IPV4_TBID_NET); + SYS(fail, "ip route add table 100 %s/24 dev veth2", IPV4_TBID_NET); + SYS(fail, "ip neigh add %s dev veth2 lladdr %s nud stale", IPV4_TBID_DST, DMAC2); + + SYS(fail, "ip addr add %s/64 dev veth2", IPV6_TBID_ADDR); + SYS(fail, "ip -6 route del %s/64 dev veth2", IPV6_TBID_NET); + SYS(fail, "ip -6 route add table 100 %s/64 dev veth2", IPV6_TBID_NET); + SYS(fail, "ip neigh add %s dev veth2 lladdr %s nud stale", IPV6_TBID_DST, DMAC2); + err = write_sysctl("/proc/sys/net/ipv4/conf/veth1/forwarding", "1"); if (!ASSERT_OK(err, "write_sysctl(net.ipv4.conf.veth1.forwarding)")) goto fail; @@ -83,7 +121,7 @@ fail: return -1; } -static int set_lookup_params(struct bpf_fib_lookup *params, const char *daddr) +static int set_lookup_params(struct bpf_fib_lookup *params, const struct fib_lookup_test *test) { int ret; @@ -91,8 +129,9 @@ static int set_lookup_params(struct bpf_fib_lookup *params, const char *daddr) params->l4_protocol = IPPROTO_TCP; params->ifindex = ifindex; + params->tbid = test->tbid; - if (inet_pton(AF_INET6, daddr, params->ipv6_dst) == 1) { + if (inet_pton(AF_INET6, test->daddr, params->ipv6_dst) == 1) { params->family = AF_INET6; ret = inet_pton(AF_INET6, IPV6_IFACE_ADDR, params->ipv6_src); if (!ASSERT_EQ(ret, 1, "inet_pton(IPV6_IFACE_ADDR)")) @@ -100,7 +139,7 @@ static int set_lookup_params(struct bpf_fib_lookup *params, const char *daddr) return 0; } - ret = inet_pton(AF_INET, daddr, ¶ms->ipv4_dst); + ret = inet_pton(AF_INET, test->daddr, ¶ms->ipv4_dst); if (!ASSERT_EQ(ret, 1, "convert IP[46] address")) return -1; params->family = AF_INET; @@ -154,13 +193,12 @@ void test_fib_lookup(void) fib_params = &skel->bss->fib_params; for (i = 0; i < ARRAY_SIZE(tests); i++) { - printf("Testing %s\n", tests[i].desc); + printf("Testing %s ", tests[i].desc); - if (set_lookup_params(fib_params, tests[i].daddr)) + if (set_lookup_params(fib_params, &tests[i])) continue; skel->bss->fib_lookup_ret = -1; - skel->bss->lookup_flags = BPF_FIB_LOOKUP_OUTPUT | - tests[i].lookup_flags; + skel->bss->lookup_flags = tests[i].lookup_flags; err = bpf_prog_test_run_opts(prog_fd, &run_opts); if (!ASSERT_OK(err, "bpf_prog_test_run_opts")) @@ -175,7 +213,14 @@ void test_fib_lookup(void) mac_str(expected, tests[i].dmac); mac_str(actual, fib_params->dmac); - printf("dmac expected %s actual %s\n", expected, actual); + printf("dmac expected %s actual %s ", expected, actual); + } + + // ensure tbid is zero'd out after fib lookup. + if (tests[i].lookup_flags & BPF_FIB_LOOKUP_DIRECT) { + if (!ASSERT_EQ(skel->bss->fib_params.tbid, 0, + "expected fib_params.tbid to be zero")) + goto fail; } } -- cgit v1.2.3 From a395b8d1c7c3a074bfa83b9759a4a11901a295c5 Mon Sep 17 00:00:00 2001 From: Zhengchao Shao Date: Thu, 1 Jun 2023 09:22:50 +0800 Subject: selftests/tc-testing: replace mq with invalid parent ID The test case shown in [1] triggers the kernel to access the null pointer. Therefore, add related test cases to mq. The test results are as follows: ./tdc.py -e 0531 1..1 ok 1 0531 - Replace mq with invalid parent ID ./tdc.py -c mq 1..8 ok 1 ce7d - Add mq Qdisc to multi-queue device (4 queues) ok 2 2f82 - Add mq Qdisc to multi-queue device (256 queues) ok 3 c525 - Add duplicate mq Qdisc ok 4 128a - Delete nonexistent mq Qdisc ok 5 03a9 - Delete mq Qdisc twice ok 6 be0f - Add mq Qdisc to single-queue device ok 7 1023 - Show mq class ok 8 0531 - Replace mq with invalid parent ID [1] https://lore.kernel.org/all/20230527093747.3583502-1-shaozhengchao@huawei.com/ Signed-off-by: Zhengchao Shao Reviewed-by: Pedro Tammela Link: https://lore.kernel.org/r/20230601012250.52738-1-shaozhengchao@huawei.com Signed-off-by: Jakub Kicinski --- .../selftests/tc-testing/tc-tests/qdiscs/mq.json | 25 +++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/mq.json b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/mq.json index 44fbfc6caec7..e3d2de5c184f 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/mq.json +++ b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/mq.json @@ -155,5 +155,28 @@ "teardown": [ "echo \"1\" > /sys/bus/netdevsim/del_device" ] - } + }, + { + "id": "0531", + "name": "Replace mq with invalid parent ID", + "category": [ + "qdisc", + "mq" + ], + "plugins": { + "requires": "nsPlugin" + }, + "setup": [ + "echo \"1 1 16\" > /sys/bus/netdevsim/new_device", + "$TC qdisc add dev $ETH root handle ffff: mq" + ], + "cmdUnderTest": "$TC qdisc replace dev $ETH parent ffff:fff1 handle ffff: mq", + "expExitCode": "2", + "verifyCmd": "$TC qdisc show dev $ETH", + "matchPattern": "qdisc [a-zA-Z0-9_]+ 0: parent ffff", + "matchCount": "16", + "teardown": [ + "echo \"1\" > /sys/bus/netdevsim/del_device" + ] + } ] -- cgit v1.2.3 From 23fcb62bc19c37adb72a585d5dc702ac55b74fb1 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 31 May 2023 08:35:51 -0700 Subject: selftests: tls: add tests for poll behavior Make sure we don't generate premature POLLIN events. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/testing/selftests/net/tls.c | 131 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index e699548d4247..eccea9845c65 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -1637,6 +1638,136 @@ TEST_F(tls_err, timeo) } } +TEST_F(tls_err, poll_partial_rec) +{ + struct pollfd pfd = { }; + ssize_t rec_len; + char rec[256]; + char buf[128]; + + if (self->notls) + SKIP(return, "no TLS support"); + + pfd.fd = self->cfd2; + pfd.events = POLLIN; + EXPECT_EQ(poll(&pfd, 1, 1), 0); + + memrnd(buf, sizeof(buf)); + EXPECT_EQ(send(self->fd, buf, sizeof(buf), 0), sizeof(buf)); + rec_len = recv(self->cfd, rec, sizeof(rec), 0); + EXPECT_GT(rec_len, sizeof(buf)); + + /* Write 100B, not the full record ... */ + EXPECT_EQ(send(self->fd2, rec, 100, 0), 100); + /* ... no full record should mean no POLLIN */ + pfd.fd = self->cfd2; + pfd.events = POLLIN; + EXPECT_EQ(poll(&pfd, 1, 1), 0); + /* Now write the rest, and it should all pop out of the other end. */ + EXPECT_EQ(send(self->fd2, rec + 100, rec_len - 100, 0), rec_len - 100); + pfd.fd = self->cfd2; + pfd.events = POLLIN; + EXPECT_EQ(poll(&pfd, 1, 1), 1); + EXPECT_EQ(recv(self->cfd2, rec, sizeof(rec), 0), sizeof(buf)); + EXPECT_EQ(memcmp(buf, rec, sizeof(buf)), 0); +} + +TEST_F(tls_err, epoll_partial_rec) +{ + struct epoll_event ev, events[10]; + ssize_t rec_len; + char rec[256]; + char buf[128]; + int epollfd; + + if (self->notls) + SKIP(return, "no TLS support"); + + epollfd = epoll_create1(0); + ASSERT_GE(epollfd, 0); + + memset(&ev, 0, sizeof(ev)); + ev.events = EPOLLIN; + ev.data.fd = self->cfd2; + ASSERT_GE(epoll_ctl(epollfd, EPOLL_CTL_ADD, self->cfd2, &ev), 0); + + EXPECT_EQ(epoll_wait(epollfd, events, 10, 0), 0); + + memrnd(buf, sizeof(buf)); + EXPECT_EQ(send(self->fd, buf, sizeof(buf), 0), sizeof(buf)); + rec_len = recv(self->cfd, rec, sizeof(rec), 0); + EXPECT_GT(rec_len, sizeof(buf)); + + /* Write 100B, not the full record ... */ + EXPECT_EQ(send(self->fd2, rec, 100, 0), 100); + /* ... no full record should mean no POLLIN */ + EXPECT_EQ(epoll_wait(epollfd, events, 10, 0), 0); + /* Now write the rest, and it should all pop out of the other end. */ + EXPECT_EQ(send(self->fd2, rec + 100, rec_len - 100, 0), rec_len - 100); + EXPECT_EQ(epoll_wait(epollfd, events, 10, 0), 1); + EXPECT_EQ(recv(self->cfd2, rec, sizeof(rec), 0), sizeof(buf)); + EXPECT_EQ(memcmp(buf, rec, sizeof(buf)), 0); + + close(epollfd); +} + +TEST_F(tls_err, poll_partial_rec_async) +{ + struct pollfd pfd = { }; + ssize_t rec_len; + char rec[256]; + char buf[128]; + char token; + int p[2]; + int ret; + + if (self->notls) + SKIP(return, "no TLS support"); + + ASSERT_GE(pipe(p), 0); + + memrnd(buf, sizeof(buf)); + EXPECT_EQ(send(self->fd, buf, sizeof(buf), 0), sizeof(buf)); + rec_len = recv(self->cfd, rec, sizeof(rec), 0); + EXPECT_GT(rec_len, sizeof(buf)); + + ret = fork(); + ASSERT_GE(ret, 0); + + if (ret) { + int status, pid2; + + close(p[1]); + usleep(1000); /* Give child a head start */ + + EXPECT_EQ(send(self->fd2, rec, 100, 0), 100); + + EXPECT_EQ(read(p[0], &token, 1), 1); /* Barrier #1 */ + + EXPECT_EQ(send(self->fd2, rec + 100, rec_len - 100, 0), + rec_len - 100); + + pid2 = wait(&status); + EXPECT_EQ(pid2, ret); + EXPECT_EQ(status, 0); + } else { + close(p[0]); + + /* Child should sleep in poll(), never get a wake */ + pfd.fd = self->cfd2; + pfd.events = POLLIN; + EXPECT_EQ(poll(&pfd, 1, 5), 0); + + EXPECT_EQ(write(p[1], &token, 1), 1); /* Barrier #1 */ + + pfd.fd = self->cfd2; + pfd.events = POLLIN; + EXPECT_EQ(poll(&pfd, 1, 5), 1); + + exit(!_metadata->passed); + } +} + TEST(non_established) { struct tls12_crypto_info_aes_gcm_256 tls12; struct sockaddr_in addr; -- cgit v1.2.3 From 204cc3d04fe26c1794e50211393a050c7635cccc Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 2 Jun 2023 18:20:09 +0200 Subject: selftests: mlxsw: ingress_rif_conf_1d: Fix the diagram The topology diagram implies that $swp1 and $swp2 are members of the bridge br0, when in fact only their uppers, $swp1.10 and $swp2.10 are. Adjust the diagram. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: David S. Miller --- tools/testing/selftests/drivers/net/mlxsw/ingress_rif_conf_1d.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/drivers/net/mlxsw/ingress_rif_conf_1d.sh b/tools/testing/selftests/drivers/net/mlxsw/ingress_rif_conf_1d.sh index df2b09966886..7d7f862c809c 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/ingress_rif_conf_1d.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/ingress_rif_conf_1d.sh @@ -15,10 +15,9 @@ # +----------------|--+ +--|-----------------+ # | | # +----------------|-------------------------|-----------------+ -# | SW | | | +# | SW $swp1 + + $swp2 | +# | | | | # | +--------------|-------------------------|---------------+ | -# | | $swp1 + + $swp2 | | -# | | | | | | # | | $swp1.10 + + $swp2.10 | | # | | | | # | | br0 | | -- cgit v1.2.3 From 34ad708d1b4346ec4b0ee9c7aa1204c2d9734698 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 2 Jun 2023 18:20:10 +0200 Subject: selftests: mlxsw: egress_vid_classification: Fix the diagram The topology diagram implies that $swp1 and $swp2 are members of the bridge br0, when in fact only their uppers, $swp1.10 and $swp2.10 are. Adjust the diagram. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: David S. Miller --- .../testing/selftests/drivers/net/mlxsw/egress_vid_classification.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/drivers/net/mlxsw/egress_vid_classification.sh b/tools/testing/selftests/drivers/net/mlxsw/egress_vid_classification.sh index 0cf9e47e3209..a5c2aec52898 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/egress_vid_classification.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/egress_vid_classification.sh @@ -16,10 +16,9 @@ # +----------------|--+ +--|-----------------+ # | | # +----------------|-------------------------|-----------------+ -# | SW | | | +# | SW $swp1 + + $swp2 | +# | | | | # | +--------------|-------------------------|---------------+ | -# | | $swp1 + + $swp2 | | -# | | | | | | # | | $swp1.10 + + $swp2.10 | | # | | | | # | | br0 | | -- cgit v1.2.3 From 812de4dfab98640ebf0fd443b326c04724bf7eb0 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 2 Jun 2023 18:20:11 +0200 Subject: selftests: router_bridge_vlan: Add a diagram Add a topology diagram to this selftest to make the configuration easier to understand. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: David S. Miller --- .../selftests/net/forwarding/router_bridge_vlan.sh | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh b/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh index fa6a88c50750..695ef1f12e56 100755 --- a/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh +++ b/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh @@ -1,6 +1,28 @@ #!/bin/bash # SPDX-License-Identifier: GPL-2.0 +# +------------------------+ +----------------------+ +# | H1 (vrf) | | H2 (vrf) | +# | + $h1.555 | | + $h2 | +# | | 192.0.2.1/28 | | | 192.0.2.130/28 | +# | | 2001:db8:1::1/64 | | | 2001:db8:2::2/64 | +# | | | | | | +# | + $h1 | | | | +# +----|-------------------+ +--|-------------------+ +# | | +# +----|--------------------------------------------------|-------------------+ +# | SW | | | +# | +--|-------------------------------+ + $swp2 | +# | | + $swp1 | 192.0.2.129/28 | +# | | vid 555 | 2001:db8:2::1/64 | +# | | | | +# | | + BR1 (802.1q) | | +# | | vid 555 pvid untagged | | +# | | 192.0.2.2/28 | | +# | | 2001:db8:1::2/64 | | +# | +----------------------------------+ | +# +---------------------------------------------------------------------------+ + ALL_TESTS=" ping_ipv4 ping_ipv6 -- cgit v1.2.3 From f5136877f421f298423e595fdf6a00e4e4c52706 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 2 Jun 2023 18:20:12 +0200 Subject: selftests: router_bridge_vlan: Set vlan_default_pvid 0 on the bridge When everything is configured, VLAN membership on the bridge in this selftest are as follows: # bridge vlan show port vlan-id swp2 1 PVID Egress Untagged 555 br1 1 Egress Untagged 555 PVID Egress Untagged Note that it is possible for untagged traffic to just flow through as VLAN 1, instead of using VLAN 555 as intended by the test. This configuration seems too close to "works by accident", and it would be better to just shut out VLAN 1 altogether. To that end, configure vlan_default_pvid of 0: # bridge vlan show port vlan-id swp2 555 br1 555 PVID Egress Untagged Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/router_bridge_vlan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh b/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh index 695ef1f12e56..de2b2d5480dd 100755 --- a/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh +++ b/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh @@ -63,7 +63,7 @@ h2_destroy() router_create() { - ip link add name br1 type bridge vlan_filtering 1 + ip link add name br1 type bridge vlan_filtering 1 vlan_default_pvid 0 ip link set dev br1 up ip link set dev $swp1 master br1 -- cgit v1.2.3 From d8a324f102cc894fa0df6849504a9023f3ea5da6 Mon Sep 17 00:00:00 2001 From: Kristina Martsenko Date: Tue, 9 May 2023 15:22:35 +0100 Subject: kselftest/arm64: add MOPS to hwcap test Add the MOPS hwcap to the hwcap kselftest and check that a SIGILL is not generated when the feature is detected. A SIGILL is reliable when the feature is not detected as SCTLR_EL1.MSCEn won't have been set. Signed-off-by: Kristina Martsenko Reviewed-by: Mark Brown Link: https://lore.kernel.org/r/20230509142235.3284028-12-kristina.martsenko@arm.com Signed-off-by: Catalin Marinas --- tools/testing/selftests/arm64/abi/hwcap.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/arm64/abi/hwcap.c b/tools/testing/selftests/arm64/abi/hwcap.c index 93333a90bf3a..d4ad813fed10 100644 --- a/tools/testing/selftests/arm64/abi/hwcap.c +++ b/tools/testing/selftests/arm64/abi/hwcap.c @@ -39,6 +39,20 @@ static void cssc_sigill(void) asm volatile(".inst 0xdac01c00" : : : "x0"); } +static void mops_sigill(void) +{ + char dst[1], src[1]; + register char *dstp asm ("x0") = dst; + register char *srcp asm ("x1") = src; + register long size asm ("x2") = 1; + + /* CPYP [x0]!, [x1]!, x2! */ + asm volatile(".inst 0x1d010440" + : "+r" (dstp), "+r" (srcp), "+r" (size) + : + : "cc", "memory"); +} + static void rng_sigill(void) { asm volatile("mrs x0, S3_3_C2_C4_0" : : : "x0"); @@ -209,6 +223,14 @@ static const struct hwcap_data { .cpuinfo = "cssc", .sigill_fn = cssc_sigill, }, + { + .name = "MOPS", + .at_hwcap = AT_HWCAP2, + .hwcap_bit = HWCAP2_MOPS, + .cpuinfo = "mops", + .sigill_fn = mops_sigill, + .sigill_reliable = true, + }, { .name = "RNG", .at_hwcap = AT_HWCAP2, -- cgit v1.2.3 From 7793fc3babe9fea908e57f7c187ea819f9fd7e95 Mon Sep 17 00:00:00 2001 From: Dave Marchevsky Date: Thu, 1 Jun 2023 19:26:42 -0700 Subject: bpf: Make bpf_refcount_acquire fallible for non-owning refs This patch fixes an incorrect assumption made in the original bpf_refcount series [0], specifically that the BPF program calling bpf_refcount_acquire on some node can always guarantee that the node is alive. In that series, the patch adding failure behavior to rbtree_add and list_push_{front, back} breaks this assumption for non-owning references. Consider the following program: n = bpf_kptr_xchg(&mapval, NULL); /* skip error checking */ bpf_spin_lock(&l); if(bpf_rbtree_add(&t, &n->rb, less)) { bpf_refcount_acquire(n); /* Failed to add, do something else with the node */ } bpf_spin_unlock(&l); It's incorrect to assume that bpf_refcount_acquire will always succeed in this scenario. bpf_refcount_acquire is being called in a critical section here, but the lock being held is associated with rbtree t, which isn't necessarily the lock associated with the tree that the node is already in. So after bpf_rbtree_add fails to add the node and calls bpf_obj_drop in it, the program has no ownership of the node's lifetime. Therefore the node's refcount can be decr'd to 0 at any time after the failing rbtree_add. If this happens before the refcount_acquire above, the node might be free'd, and regardless refcount_acquire will be incrementing a 0 refcount. Later patches in the series exercise this scenario, resulting in the expected complaint from the kernel (without this patch's changes): refcount_t: addition on 0; use-after-free. WARNING: CPU: 1 PID: 207 at lib/refcount.c:25 refcount_warn_saturate+0xbc/0x110 Modules linked in: bpf_testmod(O) CPU: 1 PID: 207 Comm: test_progs Tainted: G O 6.3.0-rc7-02231-g723de1a718a2-dirty #371 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.15.0-0-g2dd4b9b3f840-prebuilt.qemu.org 04/01/2014 RIP: 0010:refcount_warn_saturate+0xbc/0x110 Code: 6f 64 f6 02 01 e8 84 a3 5c ff 0f 0b eb 9d 80 3d 5e 64 f6 02 00 75 94 48 c7 c7 e0 13 d2 82 c6 05 4e 64 f6 02 01 e8 64 a3 5c ff <0f> 0b e9 7a ff ff ff 80 3d 38 64 f6 02 00 0f 85 6d ff ff ff 48 c7 RSP: 0018:ffff88810b9179b0 EFLAGS: 00010082 RAX: 0000000000000000 RBX: 0000000000000002 RCX: 0000000000000000 RDX: 0000000000000202 RSI: 0000000000000008 RDI: ffffffff857c3680 RBP: ffff88810027d3c0 R08: ffffffff8125f2a4 R09: ffff88810b9176e7 R10: ffffed1021722edc R11: 746e756f63666572 R12: ffff88810027d388 R13: ffff88810027d3c0 R14: ffffc900005fe030 R15: ffffc900005fe048 FS: 00007fee0584a700(0000) GS:ffff88811b280000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00005634a96f6c58 CR3: 0000000108ce9002 CR4: 0000000000770ee0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 PKRU: 55555554 Call Trace: bpf_refcount_acquire_impl+0xb5/0xc0 (rest of output snipped) The patch addresses this by changing bpf_refcount_acquire_impl to use refcount_inc_not_zero instead of refcount_inc and marking bpf_refcount_acquire KF_RET_NULL. For owning references, though, we know the above scenario is not possible and thus that bpf_refcount_acquire will always succeed. Some verifier bookkeeping is added to track "is input owning ref?" for bpf_refcount_acquire calls and return false from is_kfunc_ret_null for bpf_refcount_acquire on owning refs despite it being marked KF_RET_NULL. Existing selftests using bpf_refcount_acquire are modified where necessary to NULL-check its return value. [0]: https://lore.kernel.org/bpf/20230415201811.343116-1-davemarchevsky@fb.com/ Fixes: d2dcc67df910 ("bpf: Migrate bpf_rbtree_add and bpf_list_push_{front,back} to possibly fail") Reported-by: Kumar Kartikeya Dwivedi Signed-off-by: Dave Marchevsky Link: https://lore.kernel.org/r/20230602022647.1571784-5-davemarchevsky@fb.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/helpers.c | 8 +++++-- kernel/bpf/verifier.c | 26 +++++++++++++++------- .../testing/selftests/bpf/progs/refcounted_kptr.c | 2 ++ .../selftests/bpf/progs/refcounted_kptr_fail.c | 4 +++- 4 files changed, 29 insertions(+), 11 deletions(-) (limited to 'tools/testing') diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index a4e437eabcb4..9e80efa59a5d 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1933,8 +1933,12 @@ __bpf_kfunc void *bpf_refcount_acquire_impl(void *p__refcounted_kptr, void *meta * bpf_refcount type so that it is emitted in vmlinux BTF */ ref = (struct bpf_refcount *)(p__refcounted_kptr + meta->record->refcount_off); + if (!refcount_inc_not_zero((refcount_t *)ref)) + return NULL; - refcount_inc((refcount_t *)ref); + /* Verifier strips KF_RET_NULL if input is owned ref, see is_kfunc_ret_null + * in verifier.c + */ return (void *)p__refcounted_kptr; } @@ -2406,7 +2410,7 @@ BTF_ID_FLAGS(func, crash_kexec, KF_DESTRUCTIVE) #endif BTF_ID_FLAGS(func, bpf_obj_new_impl, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_obj_drop_impl, KF_RELEASE) -BTF_ID_FLAGS(func, bpf_refcount_acquire_impl, KF_ACQUIRE) +BTF_ID_FLAGS(func, bpf_refcount_acquire_impl, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_list_push_front_impl) BTF_ID_FLAGS(func, bpf_list_push_back_impl) BTF_ID_FLAGS(func, bpf_list_pop_front, KF_ACQUIRE | KF_RET_NULL) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 34e56af5b0bc..27b54266b4c7 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -298,16 +298,19 @@ struct bpf_kfunc_call_arg_meta { bool found; } arg_constant; - /* arg_btf and arg_btf_id are used by kfunc-specific handling, + /* arg_{btf,btf_id,owning_ref} are used by kfunc-specific handling, * generally to pass info about user-defined local kptr types to later * verification logic * bpf_obj_drop * Record the local kptr type to be drop'd * bpf_refcount_acquire (via KF_ARG_PTR_TO_REFCOUNTED_KPTR arg type) - * Record the local kptr type to be refcount_incr'd + * Record the local kptr type to be refcount_incr'd and use + * arg_owning_ref to determine whether refcount_acquire should be + * fallible */ struct btf *arg_btf; u32 arg_btf_id; + bool arg_owning_ref; struct { struct btf_field *field; @@ -9678,11 +9681,6 @@ static bool is_kfunc_acquire(struct bpf_kfunc_call_arg_meta *meta) return meta->kfunc_flags & KF_ACQUIRE; } -static bool is_kfunc_ret_null(struct bpf_kfunc_call_arg_meta *meta) -{ - return meta->kfunc_flags & KF_RET_NULL; -} - static bool is_kfunc_release(struct bpf_kfunc_call_arg_meta *meta) { return meta->kfunc_flags & KF_RELEASE; @@ -9998,6 +9996,16 @@ BTF_ID(func, bpf_dynptr_slice) BTF_ID(func, bpf_dynptr_slice_rdwr) BTF_ID(func, bpf_dynptr_clone) +static bool is_kfunc_ret_null(struct bpf_kfunc_call_arg_meta *meta) +{ + if (meta->func_id == special_kfunc_list[KF_bpf_refcount_acquire_impl] && + meta->arg_owning_ref) { + return false; + } + + return meta->kfunc_flags & KF_RET_NULL; +} + static bool is_kfunc_bpf_rcu_read_lock(struct bpf_kfunc_call_arg_meta *meta) { return meta->func_id == special_kfunc_list[KF_bpf_rcu_read_lock]; @@ -10880,10 +10888,12 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ meta->subprogno = reg->subprogno; break; case KF_ARG_PTR_TO_REFCOUNTED_KPTR: - if (!type_is_ptr_alloc_obj(reg->type) && !type_is_non_owning_ref(reg->type)) { + if (!type_is_ptr_alloc_obj(reg->type)) { verbose(env, "arg#%d is neither owning or non-owning ref\n", i); return -EINVAL; } + if (!type_is_non_owning_ref(reg->type)) + meta->arg_owning_ref = true; rec = reg_btf_record(reg); if (!rec) { diff --git a/tools/testing/selftests/bpf/progs/refcounted_kptr.c b/tools/testing/selftests/bpf/progs/refcounted_kptr.c index 1d348a225140..a3da610b1e6b 100644 --- a/tools/testing/selftests/bpf/progs/refcounted_kptr.c +++ b/tools/testing/selftests/bpf/progs/refcounted_kptr.c @@ -375,6 +375,8 @@ long rbtree_refcounted_node_ref_escapes(void *ctx) bpf_rbtree_add(&aroot, &n->node, less_a); m = bpf_refcount_acquire(n); bpf_spin_unlock(&alock); + if (!m) + return 2; m->key = 2; bpf_obj_drop(m); diff --git a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c index efcb308f80ad..0b09e5c915b1 100644 --- a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c +++ b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c @@ -29,7 +29,7 @@ static bool less(struct bpf_rb_node *a, const struct bpf_rb_node *b) } SEC("?tc") -__failure __msg("Unreleased reference id=3 alloc_insn=21") +__failure __msg("Unreleased reference id=4 alloc_insn=21") long rbtree_refcounted_node_ref_escapes(void *ctx) { struct node_acquire *n, *m; @@ -43,6 +43,8 @@ long rbtree_refcounted_node_ref_escapes(void *ctx) /* m becomes an owning ref but is never drop'd or added to a tree */ m = bpf_refcount_acquire(n); bpf_spin_unlock(&glock); + if (!m) + return 2; m->key = 2; return 0; -- cgit v1.2.3 From f904c67876c42c14a108d7f80459ef59d900b8fc Mon Sep 17 00:00:00 2001 From: David Vernet Date: Fri, 2 Jun 2023 10:01:12 -0500 Subject: selftests/bpf: Add test for non-NULLable PTR_TO_BTF_IDs In a recent patch, we taught the verifier that trusted PTR_TO_BTF_ID can never be NULL. This prevents the verifier from incorrectly failing to load certain programs where it gets confused and thinks a reference isn't dropped because it incorrectly assumes that a branch exists in which a NULL PTR_TO_BTF_ID pointer is never released. This patch adds a testcase that verifies this cannot happen. Signed-off-by: David Vernet Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20230602150112.1494194-2-void@manifault.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/prog_tests/cpumask.c | 1 + .../testing/selftests/bpf/progs/cpumask_success.c | 24 ++++++++++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/cpumask.c b/tools/testing/selftests/bpf/prog_tests/cpumask.c index cdf4acc18e4c..d89191440fb1 100644 --- a/tools/testing/selftests/bpf/prog_tests/cpumask.c +++ b/tools/testing/selftests/bpf/prog_tests/cpumask.c @@ -70,5 +70,6 @@ void test_cpumask(void) verify_success(cpumask_success_testcases[i]); } + RUN_TESTS(cpumask_success); RUN_TESTS(cpumask_failure); } diff --git a/tools/testing/selftests/bpf/progs/cpumask_success.c b/tools/testing/selftests/bpf/progs/cpumask_success.c index 2fcdd7f68ac7..602a88b03dbc 100644 --- a/tools/testing/selftests/bpf/progs/cpumask_success.c +++ b/tools/testing/selftests/bpf/progs/cpumask_success.c @@ -5,6 +5,7 @@ #include #include +#include "bpf_misc.h" #include "cpumask_common.h" char _license[] SEC("license") = "GPL"; @@ -426,3 +427,26 @@ int BPF_PROG(test_global_mask_rcu, struct task_struct *task, u64 clone_flags) return 0; } + +SEC("tp_btf/task_newtask") +__success +int BPF_PROG(test_refcount_null_tracking, struct task_struct *task, u64 clone_flags) +{ + struct bpf_cpumask *mask1, *mask2; + + mask1 = bpf_cpumask_create(); + mask2 = bpf_cpumask_create(); + + if (!mask1 || !mask2) + goto free_masks_return; + + bpf_cpumask_test_cpu(0, (const struct cpumask *)mask1); + bpf_cpumask_test_cpu(0, (const struct cpumask *)mask2); + +free_masks_return: + if (mask1) + bpf_cpumask_release(mask1); + if (mask2) + bpf_cpumask_release(mask2); + return 0; +} -- cgit v1.2.3 From 3d272c2fa8045f31879a3beee230c1711367b697 Mon Sep 17 00:00:00 2001 From: David Vernet Date: Fri, 2 Jun 2023 09:01:08 -0500 Subject: selftests/bpf: Add missing selftests kconfig options Our selftests of course rely on the kernel being built with CONFIG_DEBUG_INFO_BTF=y, though this (nor its dependencies of CONFIG_DEBUG_INFO=y and CONFIG_DEBUG_INFO_DWARF4=y) are not specified. This causes the wrong kernel to be built, and selftests to similarly fail to build. Additionally, in the BPF selftests kconfig file, CONFIG_NF_CONNTRACK_MARK=y is specified, so that the 'u_int32_t mark' field will be present in the definition of struct nf_conn. While a dependency of CONFIG_NF_CONNTRACK_MARK=y, CONFIG_NETFILTER_ADVANCED=y, should be enabled by default, I've run into instances of CONFIG_NF_CONNTRACK_MARK not being set because CONFIG_NETFILTER_ADVANCED isn't set, and have to manually enable them with make menuconfig. Let's add these missing kconfig options to the file so that the necessary dependencies are in place to build vmlinux. Otherwise, we'll get errors like this when we try to compile selftests and generate vmlinux.h: $ cd /path/to/bpf-next $ make mrproper; make defconfig $ cat tools/testing/selftests/config >> .config $ make -j ... $ cd tools/testing/selftests/bpf $ make clean $ make -j ... LD [M] tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.ko tools/testing/selftests/bpf/tools/build/bpftool/bootstrap/bpftool btf dump file vmlinux format c > tools/testing/selftests/bpf/tools/build/bpftool/vmlinux.h libbpf: failed to find '.BTF' ELF section in vmlinux Error: failed to load BTF from bpf-next/vmlinux: No data available make[1]: *** [Makefile:208: tools/testing/selftests/bpf/tools/build/bpftool/vmlinux.h] Error 195 make[1]: *** Deleting file 'tools/testing/selftests/bpf/tools/build/bpftool/vmlinux.h' make: *** [Makefile:261: tools/testing/selftests/bpf/tools/sbin/bpftool] Error 2 Signed-off-by: David Vernet Signed-off-by: Andrii Nakryiko Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20230602140108.1177900-1-void@manifault.com --- tools/testing/selftests/bpf/config | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config index 63cd4ab70171..3b350bc31343 100644 --- a/tools/testing/selftests/bpf/config +++ b/tools/testing/selftests/bpf/config @@ -13,6 +13,9 @@ CONFIG_CGROUP_BPF=y CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_USER_API_HASH=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_INFO_BTF=y +CONFIG_DEBUG_INFO_DWARF4=y CONFIG_DYNAMIC_FTRACE=y CONFIG_FPROBE=y CONFIG_FTRACE_SYSCALLS=y @@ -60,6 +63,7 @@ CONFIG_NET_SCH_INGRESS=y CONFIG_NET_SCHED=y CONFIG_NETDEVSIM=y CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y CONFIG_NETFILTER_SYNPROXY=y CONFIG_NETFILTER_XT_CONNMARK=y CONFIG_NETFILTER_XT_MATCH_STATE=y -- cgit v1.2.3 From 095641817e1bf6aa2560e025e47575188ee3edaf Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 6 Jun 2023 13:30:47 +0200 Subject: selftests/bpf: Fix check_mtu using wrong variable type Dan Carpenter found via Smatch static checker, that unsigned 'mtu_lo' is never less than zero. Variable mtu_lo should have been an 'int', because read_mtu_device_lo() uses minus as error indications. Fixes: b62eba563229 ("selftests/bpf: Tests using bpf_check_mtu BPF-helper") Reported-by: Dan Carpenter Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Daniel Borkmann Reviewed-by: Simon Horman Link: https://lore.kernel.org/bpf/168605104733.3636467.17945947801753092590.stgit@firesoul --- tools/testing/selftests/bpf/prog_tests/check_mtu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/check_mtu.c b/tools/testing/selftests/bpf/prog_tests/check_mtu.c index 5338d2ea0460..2a9a30650350 100644 --- a/tools/testing/selftests/bpf/prog_tests/check_mtu.c +++ b/tools/testing/selftests/bpf/prog_tests/check_mtu.c @@ -183,7 +183,7 @@ cleanup: void serial_test_check_mtu(void) { - __u32 mtu_lo; + int mtu_lo; if (test__start_subtest("bpf_check_mtu XDP-attach")) test_check_mtu_xdp_attach(); -- cgit v1.2.3 From ee053e03b08e1b287d9a43152e4623a04cb24fe6 Mon Sep 17 00:00:00 2001 From: Joey Gouly Date: Tue, 6 Jun 2023 15:58:58 +0100 Subject: KVM: selftests: get-reg-list: support ID register features This stops the test complaining about missing registers, when running on an older kernel that does not support newer features. Signed-off-by: Joey Gouly Cc: Marc Zyngier Cc: Oliver Upton Cc: Mark Brown Cc: Shuah Khan Link: https://lore.kernel.org/r/20230606145859.697944-20-joey.gouly@arm.com Signed-off-by: Catalin Marinas --- tools/testing/selftests/kvm/aarch64/get-reg-list.c | 32 +++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index d4e1f4af29d6..3ab236ceb6fc 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -48,6 +48,16 @@ struct reg_sublist { __u64 rejects_set_n; }; +struct feature_id_reg { + __u64 reg; + __u64 id_reg; + __u64 feat_shift; + __u64 feat_min; +}; + +static struct feature_id_reg feat_id_regs[] = { +}; + struct vcpu_config { char *name; struct reg_sublist sublists[]; @@ -68,7 +78,8 @@ static int vcpu_configs_n; #define for_each_missing_reg(i) \ for ((i) = 0; (i) < blessed_n; ++(i)) \ - if (!find_reg(reg_list->reg, reg_list->n, blessed_reg[i])) + if (!find_reg(reg_list->reg, reg_list->n, blessed_reg[i])) \ + if (check_supported_feat_reg(vcpu, blessed_reg[i])) #define for_each_new_reg(i) \ for_each_reg_filtered(i) \ @@ -132,6 +143,25 @@ static bool find_reg(__u64 regs[], __u64 nr_regs, __u64 reg) return false; } +static bool check_supported_feat_reg(struct kvm_vcpu *vcpu, __u64 reg) +{ + int i, ret; + __u64 data, feat_val; + + for (i = 0; i < ARRAY_SIZE(feat_id_regs); i++) { + if (feat_id_regs[i].reg == reg) { + ret = __vcpu_get_reg(vcpu, feat_id_regs[i].id_reg, &data); + if (ret < 0) + return false; + + feat_val = ((data >> feat_id_regs[i].feat_shift) & 0xf); + return feat_val >= feat_id_regs[i].feat_min; + } + } + + return true; +} + static const char *str_with_index(const char *template, __u64 index) { char *str, *p; -- cgit v1.2.3 From 5f0419a0083b304566fa32c27a0f009634a7f703 Mon Sep 17 00:00:00 2001 From: Joey Gouly Date: Tue, 6 Jun 2023 15:58:59 +0100 Subject: KVM: selftests: get-reg-list: add Permission Indirection registers Add new system registers: - ID_AA64MMFR3_EL1 - TCR2_EL1 - PIRE0_EL1 - PIR_EL1 Signed-off-by: Joey Gouly Cc: Marc Zyngier Cc: Oliver Upton Cc: Mark Brown Cc: Shuah Khan Acked-by: Catalin Marinas Link: https://lore.kernel.org/r/20230606145859.697944-21-joey.gouly@arm.com Signed-off-by: Catalin Marinas --- tools/testing/selftests/kvm/aarch64/get-reg-list.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index 3ab236ceb6fc..4f10055af2aa 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -56,6 +56,24 @@ struct feature_id_reg { }; static struct feature_id_reg feat_id_regs[] = { + { + ARM64_SYS_REG(3, 0, 2, 0, 3), /* TCR2_EL1 */ + ARM64_SYS_REG(3, 0, 0, 7, 3), /* ID_AA64MMFR3_EL1 */ + 0, + 1 + }, + { + ARM64_SYS_REG(3, 0, 10, 2, 2), /* PIRE0_EL1 */ + ARM64_SYS_REG(3, 0, 0, 7, 3), /* ID_AA64MMFR3_EL1 */ + 4, + 1 + }, + { + ARM64_SYS_REG(3, 0, 10, 2, 3), /* PIR_EL1 */ + ARM64_SYS_REG(3, 0, 0, 7, 3), /* ID_AA64MMFR3_EL1 */ + 4, + 1 + } }; struct vcpu_config { @@ -873,12 +891,15 @@ static __u64 base_regs[] = { ARM64_SYS_REG(3, 0, 2, 0, 0), /* TTBR0_EL1 */ ARM64_SYS_REG(3, 0, 2, 0, 1), /* TTBR1_EL1 */ ARM64_SYS_REG(3, 0, 2, 0, 2), /* TCR_EL1 */ + ARM64_SYS_REG(3, 0, 2, 0, 3), /* TCR2_EL1 */ ARM64_SYS_REG(3, 0, 5, 1, 0), /* AFSR0_EL1 */ ARM64_SYS_REG(3, 0, 5, 1, 1), /* AFSR1_EL1 */ ARM64_SYS_REG(3, 0, 5, 2, 0), /* ESR_EL1 */ ARM64_SYS_REG(3, 0, 6, 0, 0), /* FAR_EL1 */ ARM64_SYS_REG(3, 0, 7, 4, 0), /* PAR_EL1 */ ARM64_SYS_REG(3, 0, 10, 2, 0), /* MAIR_EL1 */ + ARM64_SYS_REG(3, 0, 10, 2, 2), /* PIRE0_EL1 */ + ARM64_SYS_REG(3, 0, 10, 2, 3), /* PIR_EL1 */ ARM64_SYS_REG(3, 0, 10, 3, 0), /* AMAIR_EL1 */ ARM64_SYS_REG(3, 0, 12, 0, 0), /* VBAR_EL1 */ ARM64_SYS_REG(3, 0, 12, 1, 1), /* DISR_EL1 */ -- cgit v1.2.3 From 10b98a4db11a289b260928f2c81799642dcd2cb0 Mon Sep 17 00:00:00 2001 From: Ivan Orlov Date: Tue, 6 Jun 2023 23:32:54 +0400 Subject: selftests: ALSA: Add test for the 'pcmtest' driver This test covers the new Virtual PCM Test Driver, including the capturing, playback and ioctl redefinition functionalities for both interleaved and non-interleaved access modes. This test is also helpful as an usage example of the 'pcmtest' driver. We have a lot of different virtual media drivers, which can be used for testing of the userspace applications and media subsystem middle layer. However, all of them are aimed at testing the video functionality and simulating the video devices. For audio devices we have only snd-dummy module, which is good in simulating the correct behavior of an ALSA device. I decided to write a tool, which would help to test the userspace ALSA programs (and the PCM middle layer as well) under unusual circumstances to figure out how they would behave. So I came up with this Virtual PCM Test Driver. This new Virtual PCM Test Driver has several features which can be useful during the userspace ALSA applications testing/fuzzing, or testing/fuzzing of the PCM middle layer. Not all of them can be implemented using the existing virtual drivers (like dummy or loopback). Here is what can this driver do: - Simulate both capture and playback processes - Generate random or pattern-based capture data - Check the playback stream for containing the looped pattern - Inject delays into the playback and capturing processes - Inject errors during the PCM callbacks Also, this driver can check the playback stream for containing the predefined pattern, which is used in the corresponding selftest to check the PCM middle layer data transferring functionality. Additionally, this driver redefines the default RESET ioctl, and the selftest covers this PCM API functionality as well. The driver supports both interleaved and non-interleaved access modes, and have separate pattern buffers for each channel. The driver supports up to 4 channels and up to 8 substreams. Signed-off-by: Ivan Orlov Acked-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20230606193254.20791-3-ivan.orlov0322@gmail.com Signed-off-by: Takashi Iwai --- tools/testing/selftests/alsa/Makefile | 2 +- tools/testing/selftests/alsa/test-pcmtest-driver.c | 333 +++++++++++++++++++++ 2 files changed, 334 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/alsa/test-pcmtest-driver.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/alsa/Makefile b/tools/testing/selftests/alsa/Makefile index 901949db80ad..5af9ba8a4645 100644 --- a/tools/testing/selftests/alsa/Makefile +++ b/tools/testing/selftests/alsa/Makefile @@ -12,7 +12,7 @@ LDLIBS+=-lpthread OVERRIDE_TARGETS = 1 -TEST_GEN_PROGS := mixer-test pcm-test +TEST_GEN_PROGS := mixer-test pcm-test test-pcmtest-driver TEST_GEN_PROGS_EXTENDED := libatest.so diff --git a/tools/testing/selftests/alsa/test-pcmtest-driver.c b/tools/testing/selftests/alsa/test-pcmtest-driver.c new file mode 100644 index 000000000000..71931b240a83 --- /dev/null +++ b/tools/testing/selftests/alsa/test-pcmtest-driver.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This is the test which covers PCM middle layer data transferring using + * the virtual pcm test driver (snd-pcmtest). + * + * Copyright 2023 Ivan Orlov + */ +#include +#include +#include "../kselftest_harness.h" + +#define CH_NUM 4 + +struct pattern_buf { + char buf[1024]; + int len; +}; + +struct pattern_buf patterns[CH_NUM]; + +struct pcmtest_test_params { + unsigned long buffer_size; + unsigned long period_size; + unsigned long channels; + unsigned int rate; + snd_pcm_access_t access; + size_t sec_buf_len; + size_t sample_size; + int time; + snd_pcm_format_t format; +}; + +static int read_patterns(void) +{ + FILE *fp, *fpl; + int i; + char pf[64]; + char plf[64]; + + for (i = 0; i < CH_NUM; i++) { + sprintf(plf, "/sys/kernel/debug/pcmtest/fill_pattern%d_len", i); + fpl = fopen(plf, "r"); + if (!fpl) + return -1; + fscanf(fpl, "%u", &patterns[i].len); + fclose(fpl); + + sprintf(pf, "/sys/kernel/debug/pcmtest/fill_pattern%d", i); + fp = fopen(pf, "r"); + if (!fp) { + fclose(fpl); + return -1; + } + fread(patterns[i].buf, 1, patterns[i].len, fp); + fclose(fp); + } + + return 0; +} + +static int get_test_results(char *debug_name) +{ + int result; + FILE *f; + char fname[128]; + + sprintf(fname, "/sys/kernel/debug/pcmtest/%s", debug_name); + + f = fopen(fname, "r"); + if (!f) { + printf("Failed to open file\n"); + return -1; + } + fscanf(f, "%d", &result); + fclose(f); + + return result; +} + +static size_t get_sec_buf_len(unsigned int rate, unsigned long channels, snd_pcm_format_t format) +{ + return rate * channels * snd_pcm_format_physical_width(format) / 8; +} + +static int setup_handle(snd_pcm_t **handle, snd_pcm_sw_params_t *swparams, + snd_pcm_hw_params_t *hwparams, struct pcmtest_test_params *params, + int card, snd_pcm_stream_t stream) +{ + char pcm_name[32]; + int err; + + sprintf(pcm_name, "hw:%d,0,0", card); + err = snd_pcm_open(handle, pcm_name, stream, 0); + if (err < 0) + return err; + snd_pcm_hw_params_any(*handle, hwparams); + snd_pcm_hw_params_set_rate_resample(*handle, hwparams, 0); + snd_pcm_hw_params_set_access(*handle, hwparams, params->access); + snd_pcm_hw_params_set_format(*handle, hwparams, params->format); + snd_pcm_hw_params_set_channels(*handle, hwparams, params->channels); + snd_pcm_hw_params_set_rate_near(*handle, hwparams, ¶ms->rate, 0); + snd_pcm_hw_params_set_period_size_near(*handle, hwparams, ¶ms->period_size, 0); + snd_pcm_hw_params_set_buffer_size_near(*handle, hwparams, ¶ms->buffer_size); + snd_pcm_hw_params(*handle, hwparams); + snd_pcm_sw_params_current(*handle, swparams); + + snd_pcm_hw_params_set_rate_resample(*handle, hwparams, 0); + snd_pcm_sw_params_set_avail_min(*handle, swparams, params->period_size); + snd_pcm_hw_params_set_buffer_size_near(*handle, hwparams, ¶ms->buffer_size); + snd_pcm_hw_params_set_period_size_near(*handle, hwparams, ¶ms->period_size, 0); + snd_pcm_sw_params(*handle, swparams); + snd_pcm_hw_params(*handle, hwparams); + + return 0; +} + +FIXTURE(pcmtest) { + int card; + snd_pcm_sw_params_t *swparams; + snd_pcm_hw_params_t *hwparams; + struct pcmtest_test_params params; +}; + +FIXTURE_TEARDOWN(pcmtest) { +} + +FIXTURE_SETUP(pcmtest) { + char *card_name; + int err; + + if (geteuid()) + SKIP(exit(-1), "This test needs root to run!"); + + err = read_patterns(); + if (err) + SKIP(exit(-1), "Can't read patterns. Probably, module isn't loaded"); + + card_name = malloc(127); + ASSERT_NE(card_name, NULL); + self->params.buffer_size = 16384; + self->params.period_size = 4096; + self->params.channels = CH_NUM; + self->params.rate = 8000; + self->params.access = SND_PCM_ACCESS_RW_INTERLEAVED; + self->params.format = SND_PCM_FORMAT_S16_LE; + self->card = -1; + self->params.sample_size = snd_pcm_format_physical_width(self->params.format) / 8; + + self->params.sec_buf_len = get_sec_buf_len(self->params.rate, self->params.channels, + self->params.format); + self->params.time = 4; + + while (snd_card_next(&self->card) >= 0) { + if (self->card == -1) + break; + snd_card_get_name(self->card, &card_name); + if (!strcmp(card_name, "PCM-Test")) + break; + } + free(card_name); + ASSERT_NE(self->card, -1); +} + +/* + * Here we are trying to send the looped monotonically increasing sequence of bytes to the driver. + * If our data isn't corrupted, the driver will set the content of 'pc_test' debugfs file to '1' + */ +TEST_F(pcmtest, playback) { + snd_pcm_t *handle; + unsigned char *it; + size_t write_res; + int test_results; + int i, cur_ch, pos_in_ch; + void *samples; + struct pcmtest_test_params *params = &self->params; + + samples = calloc(self->params.sec_buf_len * self->params.time, 1); + ASSERT_NE(samples, NULL); + + snd_pcm_sw_params_alloca(&self->swparams); + snd_pcm_hw_params_alloca(&self->hwparams); + + ASSERT_EQ(setup_handle(&handle, self->swparams, self->hwparams, params, + self->card, SND_PCM_STREAM_PLAYBACK), 0); + snd_pcm_format_set_silence(params->format, samples, + params->rate * params->channels * params->time); + it = samples; + for (i = 0; i < self->params.sec_buf_len * params->time; i++) { + cur_ch = (i / params->sample_size) % CH_NUM; + pos_in_ch = i / params->sample_size / CH_NUM * params->sample_size + + (i % params->sample_size); + it[i] = patterns[cur_ch].buf[pos_in_ch % patterns[cur_ch].len]; + } + write_res = snd_pcm_writei(handle, samples, params->rate * params->time); + ASSERT_GE(write_res, 0); + + snd_pcm_close(handle); + free(samples); + test_results = get_test_results("pc_test"); + ASSERT_EQ(test_results, 1); +} + +/* + * Here we test that the virtual alsa driver returns looped and monotonically increasing sequence + * of bytes. In the interleaved mode the buffer will contain samples in the following order: + * C0, C1, C2, C3, C0, C1, ... + */ +TEST_F(pcmtest, capture) { + snd_pcm_t *handle; + unsigned char *it; + size_t read_res; + int i, cur_ch, pos_in_ch; + void *samples; + struct pcmtest_test_params *params = &self->params; + + samples = calloc(self->params.sec_buf_len * self->params.time, 1); + ASSERT_NE(samples, NULL); + + snd_pcm_sw_params_alloca(&self->swparams); + snd_pcm_hw_params_alloca(&self->hwparams); + + ASSERT_EQ(setup_handle(&handle, self->swparams, self->hwparams, + params, self->card, SND_PCM_STREAM_CAPTURE), 0); + snd_pcm_format_set_silence(params->format, samples, + params->rate * params->channels * params->time); + read_res = snd_pcm_readi(handle, samples, params->rate * params->time); + ASSERT_GE(read_res, 0); + snd_pcm_close(handle); + it = (unsigned char *)samples; + for (i = 0; i < self->params.sec_buf_len * self->params.time; i++) { + cur_ch = (i / params->sample_size) % CH_NUM; + pos_in_ch = i / params->sample_size / CH_NUM * params->sample_size + + (i % params->sample_size); + ASSERT_EQ(it[i], patterns[cur_ch].buf[pos_in_ch % patterns[cur_ch].len]); + } + free(samples); +} + +// Test capture in the non-interleaved access mode. The are buffers for each recorded channel +TEST_F(pcmtest, ni_capture) { + snd_pcm_t *handle; + struct pcmtest_test_params params = self->params; + char **chan_samples; + size_t i, j, read_res; + + chan_samples = calloc(CH_NUM, sizeof(*chan_samples)); + ASSERT_NE(chan_samples, NULL); + + snd_pcm_sw_params_alloca(&self->swparams); + snd_pcm_hw_params_alloca(&self->hwparams); + + params.access = SND_PCM_ACCESS_RW_NONINTERLEAVED; + + ASSERT_EQ(setup_handle(&handle, self->swparams, self->hwparams, + ¶ms, self->card, SND_PCM_STREAM_CAPTURE), 0); + + for (i = 0; i < CH_NUM; i++) + chan_samples[i] = calloc(params.sec_buf_len * params.time, 1); + + for (i = 0; i < 1; i++) { + read_res = snd_pcm_readn(handle, (void **)chan_samples, params.rate * params.time); + ASSERT_GE(read_res, 0); + } + snd_pcm_close(handle); + + for (i = 0; i < CH_NUM; i++) { + for (j = 0; j < params.rate * params.time; j++) + ASSERT_EQ(chan_samples[i][j], patterns[i].buf[j % patterns[i].len]); + free(chan_samples[i]); + } + free(chan_samples); +} + +TEST_F(pcmtest, ni_playback) { + snd_pcm_t *handle; + struct pcmtest_test_params params = self->params; + char **chan_samples; + size_t i, j, read_res; + int test_res; + + chan_samples = calloc(CH_NUM, sizeof(*chan_samples)); + ASSERT_NE(chan_samples, NULL); + + snd_pcm_sw_params_alloca(&self->swparams); + snd_pcm_hw_params_alloca(&self->hwparams); + + params.access = SND_PCM_ACCESS_RW_NONINTERLEAVED; + + ASSERT_EQ(setup_handle(&handle, self->swparams, self->hwparams, + ¶ms, self->card, SND_PCM_STREAM_PLAYBACK), 0); + + for (i = 0; i < CH_NUM; i++) { + chan_samples[i] = calloc(params.sec_buf_len * params.time, 1); + for (j = 0; j < params.sec_buf_len * params.time; j++) + chan_samples[i][j] = patterns[i].buf[j % patterns[i].len]; + } + + for (i = 0; i < 1; i++) { + read_res = snd_pcm_writen(handle, (void **)chan_samples, params.rate * params.time); + ASSERT_GE(read_res, 0); + } + + snd_pcm_close(handle); + test_res = get_test_results("pc_test"); + ASSERT_EQ(test_res, 1); + + for (i = 0; i < CH_NUM; i++) + free(chan_samples[i]); + free(chan_samples); +} + +/* + * Here we are testing the custom ioctl definition inside the virtual driver. If it triggers + * successfully, the driver sets the content of 'ioctl_test' debugfs file to '1'. + */ +TEST_F(pcmtest, reset_ioctl) { + snd_pcm_t *handle; + unsigned char *it; + int test_res; + struct pcmtest_test_params *params = &self->params; + + snd_pcm_sw_params_alloca(&self->swparams); + snd_pcm_hw_params_alloca(&self->hwparams); + + ASSERT_EQ(setup_handle(&handle, self->swparams, self->hwparams, params, + self->card, SND_PCM_STREAM_CAPTURE), 0); + snd_pcm_reset(handle); + test_res = get_test_results("ioctl_test"); + ASSERT_EQ(test_res, 1); + snd_pcm_close(handle); +} + +TEST_HARNESS_MAIN -- cgit v1.2.3 From 67faabbde36b7dc006cb0a71811098e7277976d0 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 7 Jun 2023 15:40:46 -0700 Subject: selftests/bpf: Add missing prototypes for several test kfuncs Adding missing prototypes for several kfuncs that are used by test_verifier tests. We don't really need kfunc prototypes for these tests, but adding them to silence 'make W=1' build and to have all test kfuncs declarations in bpf_testmod_kfunc.h. Also moving __diag_pop for -Wmissing-prototypes to cover also bpf_testmod_test_write and bpf_testmod_test_read and adding bpf_fentry_shadow_test in there as well. All of them need to be exported, but there's no need for declarations. Fixes: 65eb006d85a2 ("bpf: Move kernel test kfuncs to bpf_testmod") Reported-by: kernel test robot Signed-off-by: Jiri Olsa Signed-off-by: Daniel Borkmann Closes: https://lore.kernel.org/oe-kbuild-all/202306051319.EihCQZPs-lkp@intel.com Link: https://lore.kernel.org/bpf/20230607224046.236510-1-jolsa@kernel.org --- tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c | 16 ++++++++-------- .../selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h | 7 +++++++ 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c index cf216041876c..aaf6ef1201c7 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c @@ -191,8 +191,6 @@ noinline int bpf_testmod_fentry_test3(char a, int b, u64 c) return a + b + c; } -__diag_pop(); - int bpf_testmod_fentry_ok; noinline ssize_t @@ -273,6 +271,14 @@ bpf_testmod_test_write(struct file *file, struct kobject *kobj, EXPORT_SYMBOL(bpf_testmod_test_write); ALLOW_ERROR_INJECTION(bpf_testmod_test_write, ERRNO); +noinline int bpf_fentry_shadow_test(int a) +{ + return a + 2; +} +EXPORT_SYMBOL_GPL(bpf_fentry_shadow_test); + +__diag_pop(); + static struct bin_attribute bin_attr_bpf_testmod_file __ro_after_init = { .attr = { .name = "bpf_testmod", .mode = 0666, }, .read = bpf_testmod_test_read, @@ -462,12 +468,6 @@ static const struct btf_kfunc_id_set bpf_testmod_kfunc_set = { .set = &bpf_testmod_check_kfunc_ids, }; -noinline int bpf_fentry_shadow_test(int a) -{ - return a + 2; -} -EXPORT_SYMBOL_GPL(bpf_fentry_shadow_test); - extern int bpf_fentry_test1(int a); static int bpf_testmod_init(void) diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h index 9693c626646b..f5c5b1375c24 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h @@ -97,4 +97,11 @@ void bpf_kfunc_call_test_mem_len_fail2(__u64 *mem, int len) __ksym; void bpf_kfunc_call_test_destructive(void) __ksym; +void bpf_kfunc_call_test_offset(struct prog_test_ref_kfunc *p); +struct prog_test_member *bpf_kfunc_call_memb_acquire(void); +void bpf_kfunc_call_memb1_release(struct prog_test_member1 *p); +void bpf_kfunc_call_test_fail1(struct prog_test_fail1 *p); +void bpf_kfunc_call_test_fail2(struct prog_test_fail2 *p); +void bpf_kfunc_call_test_fail3(struct prog_test_fail3 *p); +void bpf_kfunc_call_test_mem_len_fail1(void *mem, int len); #endif /* _BPF_TESTMOD_KFUNC_H */ -- cgit v1.2.3 From 4c2216728f688da3c4478fec23be9bd820824664 Mon Sep 17 00:00:00 2001 From: Joshua Dickens Date: Thu, 11 May 2023 12:47:54 -0700 Subject: selftests: hid: Add touch tests for Wacom devices Adding a wacom touch device to use the test_multitouch tests. Adding a 2 additional tests. - A test to check if a touch event is sent when the contact_id of the event is 0. - A test to check if a touch event is not sent when confidence is set to 0. Signed-off-by: Joshua Dickens Reviewed-by: Jason Gerecke Signed-off-by: Jiri Kosina --- .../selftests/hid/tests/test_wacom_generic.py | 84 +++++++++++++++++++++- 1 file changed, 81 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/hid/tests/test_wacom_generic.py b/tools/testing/selftests/hid/tests/test_wacom_generic.py index b1eb2bc787fc..f92fe8e02c1b 100644 --- a/tools/testing/selftests/hid/tests/test_wacom_generic.py +++ b/tools/testing/selftests/hid/tests/test_wacom_generic.py @@ -31,6 +31,7 @@ from enum import Enum from hidtools.hut import HUT from hidtools.hid import HidUnit from . import base +from . import test_multitouch import libevdev import pytest @@ -517,7 +518,7 @@ class BaseTest: for usage in get_report_usages(report): yield usage - def assertName(self, uhdev): + def assertName(self, uhdev, type): """ Assert that the name is as we expect. @@ -526,7 +527,7 @@ class BaseTest: this assertion from the base class to work properly. """ evdev = uhdev.get_evdev() - expected_name = uhdev.name + " Pen" + expected_name = uhdev.name + type if "wacom" not in expected_name.lower(): expected_name = "Wacom " + expected_name assert evdev.name == expected_name @@ -549,6 +550,12 @@ class BaseTest: usage_id("Generic Desktop", "Y"): PhysRange( PhysRange.CENTIMETER, 5, 150 ), + usage_id("Digitizers", "Width"): PhysRange( + PhysRange.CENTIMETER, 5, 150 + ), + usage_id("Digitizers", "Height"): PhysRange( + PhysRange.CENTIMETER, 5, 150 + ), usage_id("Digitizers", "X Tilt"): PhysRange(PhysRange.DEGREE, 90, 180), usage_id("Digitizers", "Y Tilt"): PhysRange(PhysRange.DEGREE, 90, 180), usage_id("Digitizers", "Twist"): PhysRange(PhysRange.DEGREE, 358, 360), @@ -603,7 +610,17 @@ class BaseTest: pass -class TestOpaqueTablet(BaseTest.TestTablet): +class PenTabletTest(BaseTest.TestTablet): + def assertName(self, uhdev): + super().assertName(uhdev, " Pen") + + +class TouchTabletTest(BaseTest.TestTablet): + def assertName(self, uhdev): + super().assertName(uhdev, " Finger") + + +class TestOpaqueTablet(PenTabletTest): def create_device(self): return OpaqueTablet() @@ -842,3 +859,64 @@ class TestPTHX60_Pen(TestOpaqueCTLTablet): libevdev.InputEvent(libevdev.EV_KEY.BTN_0, 0), ], ) + + +class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest): + def create_device(self): + return test_multitouch.Digitizer( + "DTH 2452", + rdesc="05 0d 09 04 a1 01 85 0c 95 01 75 08 15 00 26 ff 00 81 03 09 54 81 02 09 22 a1 02 05 0d 95 01 75 01 25 01 09 42 81 02 81 03 09 47 81 02 95 05 81 03 09 51 26 ff 00 75 10 95 01 81 02 35 00 65 11 55 0e 05 01 09 30 26 a0 44 46 96 14 81 42 09 31 26 9a 26 46 95 0b 81 42 05 0d 75 08 95 01 15 00 09 48 26 5f 00 46 7c 14 81 02 09 49 25 35 46 7d 0b 81 02 45 00 65 00 55 00 c0 05 0d 09 22 a1 02 05 0d 95 01 75 01 25 01 09 42 81 02 81 03 09 47 81 02 95 05 81 03 09 51 26 ff 00 75 10 95 01 81 02 35 00 65 11 55 0e 05 01 09 30 26 a0 44 46 96 14 81 42 09 31 26 9a 26 46 95 0b 81 42 05 0d 75 08 95 01 15 00 09 48 26 5f 00 46 7c 14 81 02 09 49 25 35 46 7d 0b 81 02 45 00 65 00 55 00 c0 05 0d 09 22 a1 02 05 0d 95 01 75 01 25 01 09 42 81 02 81 03 09 47 81 02 95 05 81 03 09 51 26 ff 00 75 10 95 01 81 02 35 00 65 11 55 0e 05 01 09 30 26 a0 44 46 96 14 81 42 09 31 26 9a 26 46 95 0b 81 42 05 0d 75 08 95 01 15 00 09 48 26 5f 00 46 7c 14 81 02 09 49 25 35 46 7d 0b 81 02 45 00 65 00 55 00 c0 05 0d 09 22 a1 02 05 0d 95 01 75 01 25 01 09 42 81 02 81 03 09 47 81 02 95 05 81 03 09 51 26 ff 00 75 10 95 01 81 02 35 00 65 11 55 0e 05 01 09 30 26 a0 44 46 96 14 81 42 09 31 26 9a 26 46 95 0b 81 42 05 0d 75 08 95 01 15 00 09 48 26 5f 00 46 7c 14 81 02 09 49 25 35 46 7d 0b 81 02 45 00 65 00 55 00 c0 05 0d 09 22 a1 02 05 0d 95 01 75 01 25 01 09 42 81 02 81 03 09 47 81 02 95 05 81 03 09 51 26 ff 00 75 10 95 01 81 02 35 00 65 11 55 0e 05 01 09 30 26 a0 44 46 96 14 81 42 09 31 26 9a 26 46 95 0b 81 42 05 0d 75 08 95 01 15 00 09 48 26 5f 00 46 7c 14 81 02 09 49 25 35 46 7d 0b 81 02 45 00 65 00 55 00 c0 05 0d 27 ff ff 00 00 75 10 95 01 09 56 81 02 75 08 95 0e 81 03 09 55 26 ff 00 75 08 b1 02 85 0a 06 00 ff 09 c5 96 00 01 b1 02 c0 06 00 ff 09 01 a1 01 09 01 85 13 15 00 26 ff 00 75 08 95 3f 81 02 06 00 ff 09 01 15 00 26 ff 00 75 08 95 3f 91 02 c0", + input_info=(0x3, 0x056A, 0x0383), + ) + + def test_contact_id_0(self): + """ + Bring a finger in contact with the tablet, then hold it down and remove it. + + Ensure that even with contact ID = 0 which is usually given as an invalid + touch event by most tablets with the exception of a few, that given the + confidence bit is set to 1 it should process it as a valid touch to cover + the few tablets using contact ID = 0 as a valid touch value. + """ + uhdev = self.uhdev + evdev = uhdev.get_evdev() + + t0 = test_multitouch.Touch(0, 50, 100) + r = uhdev.event([t0]) + events = uhdev.next_sync_events() + self.debug_reports(r, uhdev, events) + + slot = self.get_slot(uhdev, t0, 0) + + assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events + assert evdev.slots[slot][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 0 + assert evdev.slots[slot][libevdev.EV_ABS.ABS_MT_POSITION_X] == 50 + assert evdev.slots[slot][libevdev.EV_ABS.ABS_MT_POSITION_Y] == 100 + + t0.tipswitch = False + if uhdev.quirks is None or "VALID_IS_INRANGE" not in uhdev.quirks: + t0.inrange = False + r = uhdev.event([t0]) + events = uhdev.next_sync_events() + self.debug_reports(r, uhdev, events) + assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 0) in events + assert evdev.slots[slot][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1 + + def test_confidence_false(self): + """ + Bring a finger in contact with the tablet with confidence set to false. + + Ensure that the confidence bit being set to false should not result in a touch event. + """ + uhdev = self.uhdev + evdev = uhdev.get_evdev() + + t0 = test_multitouch.Touch(1, 50, 100) + t0.confidence = False + r = uhdev.event([t0]) + events = uhdev.next_sync_events() + self.debug_reports(r, uhdev, events) + + slot = self.get_slot(uhdev, t0, 0) + + assert not events \ No newline at end of file -- cgit v1.2.3 From e7654c3fbdb348a0c54244015d97f0a0b8773b8c Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Tue, 28 Mar 2023 18:18:45 +0200 Subject: tools/nolibc: tests: use volatile to force stack smashing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a volatile pointer to write outside the buffer so the compiler can't optimize it away. Reported-by: Alexey Dobriyan Link: https://lore.kernel.org/lkml/c0584807-511c-4496-b062-1263ea38f349@p183/ Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/nolibc-test.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 21bacc928bf7..47013b78972e 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -667,17 +667,13 @@ int run_stdlib(int min, int max) return ret; } -#if defined(__clang__) -__attribute__((optnone)) -#elif defined(__GNUC__) -__attribute__((optimize("O0"))) -#endif static int smash_stack(void) { char buf[100]; + volatile char *ptr = buf; for (size_t i = 0; i < 200; i++) - buf[i] = 'P'; + ptr[i] = 'P'; return 1; } -- cgit v1.2.3 From aa662d127e651df6e51d710014d7eb4c2a3049f5 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 2 Apr 2023 10:13:56 +0200 Subject: tools/nolibc: tests: fix build on non-c99 compliant compilers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 9735716830f2 ("tools/nolibc: tests: add test for -fstack-protector") brought a declaration inside the initialization statement of a for loop, which breaks the build on compilers that do not default to c99 compatibility, making it more difficult to validate that the lib still builds on such compilers. The fix is trivial, so let's move the declaration to the variables block of the function instead. No backport is needed. Cc: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/nolibc-test.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 47013b78972e..6f2f109569a3 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -671,8 +671,9 @@ static int smash_stack(void) { char buf[100]; volatile char *ptr = buf; + size_t i; - for (size_t i = 0; i < 200; i++) + for (i = 0; i < 200; i++) ptr[i] = 'P'; return 1; -- cgit v1.2.3 From 2df07fc55d5cf377308fad02a022cf0f0401daf4 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 2 Apr 2023 10:13:57 +0200 Subject: tools/nolibc: fix build of the test case using glibc Some extra tests for various integer types and limits were added by commit d1209597ff00 ("tools/nolibc: add tests for the integer limits in stdint.h"), but we forgot to retest with glibc. Stddef and stdint are now needed for the program to build there. Cc: Vincent Dagonneau Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/nolibc-test.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 6f2f109569a3..1bafbd8da6af 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include #endif #endif -- cgit v1.2.3 From fc82d7dbca3b789897bfb7fb5098439959c8f296 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Sun, 2 Apr 2023 20:48:03 +0200 Subject: tools/nolibc: add libc-test binary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This can be used to easily compare the behavior of nolibc to the system libc. Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/.gitignore | 1 + tools/testing/selftests/nolibc/Makefile | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/.gitignore b/tools/testing/selftests/nolibc/.gitignore index 4696df589d68..52f613cdad54 100644 --- a/tools/testing/selftests/nolibc/.gitignore +++ b/tools/testing/selftests/nolibc/.gitignore @@ -1,4 +1,5 @@ /initramfs/ +/libc-test /nolibc-test /run.out /sysroot/ diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index bbce57420465..0cbe13809b37 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -94,6 +94,7 @@ help: @echo " help this help" @echo " sysroot create the nolibc sysroot here (uses \$$ARCH)" @echo " nolibc-test build the executable (uses \$$CC and \$$CROSS_COMPILE)" + @echo " libc-test build an executable using the compiler's default libc instead" @echo " run-user runs the executable under QEMU (uses \$$ARCH, \$$TEST)" @echo " initramfs prepare the initramfs with nolibc-test" @echo " defconfig create a fresh new default config (uses \$$ARCH)" @@ -128,6 +129,9 @@ nolibc-test: nolibc-test.c sysroot/$(ARCH)/include $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \ -nostdlib -static -Isysroot/$(ARCH)/include $< -lgcc +libc-test: nolibc-test.c + $(QUIET_CC)$(CC) -o $@ $< + # qemu user-land test run-user: nolibc-test $(Q)qemu-$(QEMU_ARCH) ./nolibc-test > "$(CURDIR)/run.out" || : @@ -159,6 +163,8 @@ clean: $(Q)rm -rf sysroot $(call QUIET_CLEAN, nolibc-test) $(Q)rm -f nolibc-test + $(call QUIET_CLEAN, libc-test) + $(Q)rm -f libc-test $(call QUIET_CLEAN, initramfs) $(Q)rm -rf initramfs $(call QUIET_CLEAN, run.out) -- cgit v1.2.3 From 69f2cd9fea01a21259d361e839efd02cba7fe945 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Sun, 2 Apr 2023 20:48:06 +0200 Subject: tools/nolibc: add testcases for vfprintf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vfprintf() is complex and so far did not have proper tests. Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/nolibc-test.c | 86 ++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 1bafbd8da6af..888da60eb5ba 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -669,6 +670,90 @@ int run_stdlib(int min, int max) return ret; } +#define EXPECT_VFPRINTF(c, expected, fmt, ...) \ + ret += expect_vfprintf(llen, c, expected, fmt, ##__VA_ARGS__) + +static int expect_vfprintf(int llen, size_t c, const char *expected, const char *fmt, ...) +{ + int ret, fd, w, r; + char buf[100]; + FILE *memfile; + va_list args; + + fd = memfd_create("vfprintf", 0); + if (fd == -1) { + pad_spc(llen, 64, "[FAIL]\n"); + return 1; + } + + memfile = fdopen(fd, "w+"); + if (!memfile) { + pad_spc(llen, 64, "[FAIL]\n"); + return 1; + } + + va_start(args, fmt); + w = vfprintf(memfile, fmt, args); + va_end(args); + + if (w != c) { + llen += printf(" written(%d) != %d", w, (int) c); + pad_spc(llen, 64, "[FAIL]\n"); + return 1; + } + + fflush(memfile); + lseek(fd, 0, SEEK_SET); + + r = read(fd, buf, sizeof(buf) - 1); + buf[r] = '\0'; + + fclose(memfile); + + if (r != w) { + llen += printf(" written(%d) != read(%d)", w, r); + pad_spc(llen, 64, "[FAIL]\n"); + return 1; + } + + llen += printf(" \"%s\" = \"%s\"", expected, buf); + ret = strncmp(expected, buf, c); + + pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); + return ret; +} + +static int run_vfprintf(int min, int max) +{ + int test; + int tmp; + int ret = 0; + void *p1, *p2; + + for (test = min; test >= 0 && test <= max; test++) { + int llen = 0; // line length + + /* avoid leaving empty lines below, this will insert holes into + * test numbers. + */ + switch (test + __LINE__ + 1) { + CASE_TEST(empty); EXPECT_VFPRINTF(0, "", ""); break; + CASE_TEST(simple); EXPECT_VFPRINTF(3, "foo", "foo"); break; + CASE_TEST(string); EXPECT_VFPRINTF(3, "foo", "%s", "foo"); break; + CASE_TEST(number); EXPECT_VFPRINTF(4, "1234", "%d", 1234); break; + CASE_TEST(negnumber); EXPECT_VFPRINTF(5, "-1234", "%d", -1234); break; + CASE_TEST(unsigned); EXPECT_VFPRINTF(5, "12345", "%u", 12345); break; + CASE_TEST(char); EXPECT_VFPRINTF(1, "c", "%c", 'c'); break; + CASE_TEST(hex); EXPECT_VFPRINTF(1, "f", "%x", 0xf); break; + CASE_TEST(pointer); EXPECT_VFPRINTF(3, "0x1", "%p", (void *) 0x1); break; + case __LINE__: + return ret; /* must be last */ + /* note: do not set any defaults so as to permit holes above */ + } + } + return ret; +} + static int smash_stack(void) { char buf[100]; @@ -777,6 +862,7 @@ static const struct test test_names[] = { /* add new tests here */ { .name = "syscall", .func = run_syscall }, { .name = "stdlib", .func = run_stdlib }, + { .name = "vfprintf", .func = run_vfprintf }, { .name = "protection", .func = run_protection }, { 0 } }; -- cgit v1.2.3 From 7f291cfa90d7f95da11fe9aa7062344ddfce603a Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Thu, 6 Apr 2023 21:54:47 +0000 Subject: tools/nolibc: use standard __asm__ statements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most of the code was migrated to C99-conformant __asm__ statements before. It seems string.h was missed. Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/string.h | 4 ++-- tools/testing/selftests/nolibc/nolibc-test.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/include/nolibc/string.h b/tools/include/nolibc/string.h index fffdaf6ff467..0c2e06c7c477 100644 --- a/tools/include/nolibc/string.h +++ b/tools/include/nolibc/string.h @@ -90,7 +90,7 @@ void *memset(void *dst, int b, size_t len) while (len--) { /* prevent gcc from recognizing memset() here */ - asm volatile(""); + __asm__ volatile(""); *(p++) = b; } return dst; @@ -139,7 +139,7 @@ size_t strlen(const char *str) size_t len; for (len = 0; str[len]; len++) - asm(""); + __asm__(""); return len; } diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 888da60eb5ba..e692be98973a 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -984,7 +984,7 @@ int main(int argc, char **argv, char **envp) #else else if (ioperm(0x501, 1, 1) == 0) #endif - asm volatile ("outb %%al, %%dx" :: "d"(0x501), "a"(0)); + __asm__ volatile ("outb %%al, %%dx" :: "d"(0x501), "a"(0)); /* if it does nothing, fall back to the regular panic */ #endif } -- cgit v1.2.3 From fddc8f81f1cccb081b69b66b1e0f5cfba58c7b43 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Thu, 6 Apr 2023 21:54:49 +0000 Subject: tools/nolibc: use C89 comment syntax MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most of nolibc is already using C89 comments. Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/arch-aarch64.h | 32 ++++++++-------- tools/include/nolibc/arch-arm.h | 44 +++++++++++----------- tools/include/nolibc/arch-i386.h | 40 ++++++++++---------- tools/include/nolibc/arch-loongarch.h | 38 +++++++++---------- tools/include/nolibc/arch-mips.h | 56 ++++++++++++++-------------- tools/include/nolibc/arch-riscv.h | 40 ++++++++++---------- tools/include/nolibc/arch-s390.h | 2 +- tools/include/nolibc/arch-x86_64.h | 34 ++++++++--------- tools/include/nolibc/stackprotector.h | 4 +- tools/include/nolibc/sys.h | 8 ++-- tools/testing/selftests/nolibc/nolibc-test.c | 12 +++--- 11 files changed, 155 insertions(+), 155 deletions(-) (limited to 'tools/testing') diff --git a/tools/include/nolibc/arch-aarch64.h b/tools/include/nolibc/arch-aarch64.h index 383baddef701..76ef26520c85 100644 --- a/tools/include/nolibc/arch-aarch64.h +++ b/tools/include/nolibc/arch-aarch64.h @@ -176,24 +176,24 @@ const unsigned long *_auxv __attribute__((weak)); void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void) { __asm__ volatile ( - "ldr x0, [sp]\n" // argc (x0) was in the stack - "add x1, sp, 8\n" // argv (x1) = sp - "lsl x2, x0, 3\n" // envp (x2) = 8*argc ... - "add x2, x2, 8\n" // + 8 (skip null) - "add x2, x2, x1\n" // + argv - "adrp x3, environ\n" // x3 = &environ (high bits) - "str x2, [x3, #:lo12:environ]\n" // store envp into environ - "mov x4, x2\n" // search for auxv (follows NULL after last env) + "ldr x0, [sp]\n" /* argc (x0) was in the stack */ + "add x1, sp, 8\n" /* argv (x1) = sp */ + "lsl x2, x0, 3\n" /* envp (x2) = 8*argc ... */ + "add x2, x2, 8\n" /* + 8 (skip null) */ + "add x2, x2, x1\n" /* + argv */ + "adrp x3, environ\n" /* x3 = &environ (high bits) */ + "str x2, [x3, #:lo12:environ]\n" /* store envp into environ */ + "mov x4, x2\n" /* search for auxv (follows NULL after last env) */ "0:\n" - "ldr x5, [x4], 8\n" // x5 = *x4; x4 += 8 - "cbnz x5, 0b\n" // and stop at NULL after last env - "adrp x3, _auxv\n" // x3 = &_auxv (high bits) - "str x4, [x3, #:lo12:_auxv]\n" // store x4 into _auxv - "and sp, x1, -16\n" // sp must be 16-byte aligned in the callee - "bl main\n" // main() returns the status code, we'll exit with it. - "mov x8, 93\n" // NR_exit == 93 + "ldr x5, [x4], 8\n" /* x5 = *x4; x4 += 8 */ + "cbnz x5, 0b\n" /* and stop at NULL after last env */ + "adrp x3, _auxv\n" /* x3 = &_auxv (high bits) */ + "str x4, [x3, #:lo12:_auxv]\n" /* store x4 into _auxv */ + "and sp, x1, -16\n" /* sp must be 16-byte aligned in the callee */ + "bl main\n" /* main() returns the status code, we'll exit with it. */ + "mov x8, 93\n" /* NR_exit == 93 */ "svc #0\n" ); __builtin_unreachable(); } -#endif // _NOLIBC_ARCH_AARCH64_H +#endif /* _NOLIBC_ARCH_AARCH64_H */ diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h index 42499f23e73c..2eab1aef321b 100644 --- a/tools/include/nolibc/arch-arm.h +++ b/tools/include/nolibc/arch-arm.h @@ -203,34 +203,34 @@ const unsigned long *_auxv __attribute__((weak)); void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void) { __asm__ volatile ( - "pop {%r0}\n" // argc was in the stack - "mov %r1, %sp\n" // argv = sp + "pop {%r0}\n" /* argc was in the stack */ + "mov %r1, %sp\n" /* argv = sp */ - "add %r2, %r0, $1\n" // envp = (argc + 1) ... - "lsl %r2, %r2, $2\n" // * 4 ... - "add %r2, %r2, %r1\n" // + argv - "ldr %r3, 1f\n" // r3 = &environ (see below) - "str %r2, [r3]\n" // store envp into environ + "add %r2, %r0, $1\n" /* envp = (argc + 1) ... */ + "lsl %r2, %r2, $2\n" /* * 4 ... */ + "add %r2, %r2, %r1\n" /* + argv */ + "ldr %r3, 1f\n" /* r3 = &environ (see below) */ + "str %r2, [r3]\n" /* store envp into environ */ - "mov r4, r2\n" // search for auxv (follows NULL after last env) + "mov r4, r2\n" /* search for auxv (follows NULL after last env) */ "0:\n" - "mov r5, r4\n" // r5 = r4 - "add r4, r4, #4\n" // r4 += 4 - "ldr r5,[r5]\n" // r5 = *r5 = *(r4-4) - "cmp r5, #0\n" // and stop at NULL after last env + "mov r5, r4\n" /* r5 = r4 */ + "add r4, r4, #4\n" /* r4 += 4 */ + "ldr r5,[r5]\n" /* r5 = *r5 = *(r4-4) */ + "cmp r5, #0\n" /* and stop at NULL after last env */ "bne 0b\n" - "ldr %r3, 2f\n" // r3 = &_auxv (low bits) - "str r4, [r3]\n" // store r4 into _auxv + "ldr %r3, 2f\n" /* r3 = &_auxv (low bits) */ + "str r4, [r3]\n" /* store r4 into _auxv */ - "mov %r3, $8\n" // AAPCS : sp must be 8-byte aligned in the - "neg %r3, %r3\n" // callee, and bl doesn't push (lr=pc) - "and %r3, %r3, %r1\n" // so we do sp = r1(=sp) & r3(=-8); - "mov %sp, %r3\n" // + "mov %r3, $8\n" /* AAPCS : sp must be 8-byte aligned in the */ + "neg %r3, %r3\n" /* callee, and bl doesn't push (lr=pc) */ + "and %r3, %r3, %r1\n" /* so we do sp = r1(=sp) & r3(=-8); */ + "mov %sp, %r3\n" - "bl main\n" // main() returns the status code, we'll exit with it. - "movs r7, $1\n" // NR_exit == 1 + "bl main\n" /* main() returns the status code, we'll exit with it. */ + "movs r7, $1\n" /* NR_exit == 1 */ "svc $0x00\n" - ".align 2\n" // below are the pointers to a few variables + ".align 2\n" /* below are the pointers to a few variables */ "1:\n" ".word environ\n" "2:\n" @@ -239,4 +239,4 @@ void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void) __builtin_unreachable(); } -#endif // _NOLIBC_ARCH_ARM_H +#endif /* _NOLIBC_ARCH_ARM_H */ diff --git a/tools/include/nolibc/arch-i386.h b/tools/include/nolibc/arch-i386.h index 2d98d78fd3f3..7c41897a08ce 100644 --- a/tools/include/nolibc/arch-i386.h +++ b/tools/include/nolibc/arch-i386.h @@ -194,31 +194,31 @@ void __attribute__((weak,noreturn,optimize("omit-frame-pointer"),no_stack_protec { __asm__ volatile ( #ifdef NOLIBC_STACKPROTECTOR - "call __stack_chk_init\n" // initialize stack protector + "call __stack_chk_init\n" /* initialize stack protector */ #endif - "pop %eax\n" // argc (first arg, %eax) - "mov %esp, %ebx\n" // argv[] (second arg, %ebx) - "lea 4(%ebx,%eax,4),%ecx\n" // then a NULL then envp (third arg, %ecx) - "mov %ecx, environ\n" // save environ - "xor %ebp, %ebp\n" // zero the stack frame - "mov %ecx, %edx\n" // search for auxv (follows NULL after last env) + "pop %eax\n" /* argc (first arg, %eax) */ + "mov %esp, %ebx\n" /* argv[] (second arg, %ebx) */ + "lea 4(%ebx,%eax,4),%ecx\n" /* then a NULL then envp (third arg, %ecx) */ + "mov %ecx, environ\n" /* save environ */ + "xor %ebp, %ebp\n" /* zero the stack frame */ + "mov %ecx, %edx\n" /* search for auxv (follows NULL after last env) */ "0:\n" - "add $4, %edx\n" // search for auxv using edx, it follows the - "cmp -4(%edx), %ebp\n" // ... NULL after last env (ebp is zero here) + "add $4, %edx\n" /* search for auxv using edx, it follows the */ + "cmp -4(%edx), %ebp\n" /* ... NULL after last env (ebp is zero here) */ "jnz 0b\n" - "mov %edx, _auxv\n" // save it into _auxv - "and $-16, %esp\n" // x86 ABI : esp must be 16-byte aligned before - "sub $4, %esp\n" // the call instruction (args are aligned) - "push %ecx\n" // push all registers on the stack so that we - "push %ebx\n" // support both regparm and plain stack modes + "mov %edx, _auxv\n" /* save it into _auxv */ + "and $-16, %esp\n" /* x86 ABI : esp must be 16-byte aligned before */ + "sub $4, %esp\n" /* the call instruction (args are aligned) */ + "push %ecx\n" /* push all registers on the stack so that we */ + "push %ebx\n" /* support both regparm and plain stack modes */ "push %eax\n" - "call main\n" // main() returns the status code in %eax - "mov %eax, %ebx\n" // retrieve exit code (32-bit int) - "movl $1, %eax\n" // NR_exit == 1 - "int $0x80\n" // exit now - "hlt\n" // ensure it does not + "call main\n" /* main() returns the status code in %eax */ + "mov %eax, %ebx\n" /* retrieve exit code (32-bit int) */ + "movl $1, %eax\n" /* NR_exit == 1 */ + "int $0x80\n" /* exit now */ + "hlt\n" /* ensure it does not */ ); __builtin_unreachable(); } -#endif // _NOLIBC_ARCH_I386_H +#endif /* _NOLIBC_ARCH_I386_H */ diff --git a/tools/include/nolibc/arch-loongarch.h b/tools/include/nolibc/arch-loongarch.h index 029ee3cd6baf..ec3b46a991a9 100644 --- a/tools/include/nolibc/arch-loongarch.h +++ b/tools/include/nolibc/arch-loongarch.h @@ -158,7 +158,7 @@ const unsigned long *_auxv __attribute__((weak)); #define LONG_ADDI "addi.w" #define LONG_SLL "slli.w" #define LONG_BSTRINS "bstrins.w" -#else // __loongarch_grlen == 64 +#else /* __loongarch_grlen == 64 */ #define LONGLOG "3" #define SZREG "8" #define REG_L "ld.d" @@ -173,28 +173,28 @@ const unsigned long *_auxv __attribute__((weak)); void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void) { __asm__ volatile ( - REG_L " $a0, $sp, 0\n" // argc (a0) was in the stack - LONG_ADDI " $a1, $sp, "SZREG"\n" // argv (a1) = sp + SZREG - LONG_SLL " $a2, $a0, "LONGLOG"\n" // envp (a2) = SZREG*argc ... - LONG_ADDI " $a2, $a2, "SZREG"\n" // + SZREG (skip null) - LONG_ADD " $a2, $a2, $a1\n" // + argv + REG_L " $a0, $sp, 0\n" /* argc (a0) was in the stack */ + LONG_ADDI " $a1, $sp, "SZREG"\n" /* argv (a1) = sp + SZREG */ + LONG_SLL " $a2, $a0, "LONGLOG"\n" /* envp (a2) = SZREG*argc ... */ + LONG_ADDI " $a2, $a2, "SZREG"\n" /* + SZREG (skip null) */ + LONG_ADD " $a2, $a2, $a1\n" /* + argv */ - "move $a3, $a2\n" // iterate a3 over envp to find auxv (after NULL) - "0:\n" // do { - REG_L " $a4, $a3, 0\n" // a4 = *a3; - LONG_ADDI " $a3, $a3, "SZREG"\n" // a3 += sizeof(void*); - "bne $a4, $zero, 0b\n" // } while (a4); - "la.pcrel $a4, _auxv\n" // a4 = &_auxv - LONG_S " $a3, $a4, 0\n" // store a3 into _auxv + "move $a3, $a2\n" /* iterate a3 over envp to find auxv (after NULL) */ + "0:\n" /* do { */ + REG_L " $a4, $a3, 0\n" /* a4 = *a3; */ + LONG_ADDI " $a3, $a3, "SZREG"\n" /* a3 += sizeof(void*); */ + "bne $a4, $zero, 0b\n" /* } while (a4); */ + "la.pcrel $a4, _auxv\n" /* a4 = &_auxv */ + LONG_S " $a3, $a4, 0\n" /* store a3 into _auxv */ - "la.pcrel $a3, environ\n" // a3 = &environ - LONG_S " $a2, $a3, 0\n" // store envp(a2) into environ - LONG_BSTRINS " $sp, $zero, 3, 0\n" // sp must be 16-byte aligned - "bl main\n" // main() returns the status code, we'll exit with it. - "li.w $a7, 93\n" // NR_exit == 93 + "la.pcrel $a3, environ\n" /* a3 = &environ */ + LONG_S " $a2, $a3, 0\n" /* store envp(a2) into environ */ + LONG_BSTRINS " $sp, $zero, 3, 0\n" /* sp must be 16-byte aligned */ + "bl main\n" /* main() returns the status code, we'll exit with it. */ + "li.w $a7, 93\n" /* NR_exit == 93 */ "syscall 0\n" ); __builtin_unreachable(); } -#endif // _NOLIBC_ARCH_LOONGARCH_H +#endif /* _NOLIBC_ARCH_LOONGARCH_H */ diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h index bf83432d23ed..8822f150e72f 100644 --- a/tools/include/nolibc/arch-mips.h +++ b/tools/include/nolibc/arch-mips.h @@ -183,42 +183,42 @@ const unsigned long *_auxv __attribute__((weak)); void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __start(void) { __asm__ volatile ( - //".set nomips16\n" + /*".set nomips16\n"*/ ".set push\n" ".set noreorder\n" ".option pic0\n" - //".ent __start\n" - //"__start:\n" - "lw $a0,($sp)\n" // argc was in the stack - "addiu $a1, $sp, 4\n" // argv = sp + 4 - "sll $a2, $a0, 2\n" // a2 = argc * 4 - "add $a2, $a2, $a1\n" // envp = argv + 4*argc ... - "addiu $a2, $a2, 4\n" // ... + 4 - "lui $a3, %hi(environ)\n" // load environ into a3 (hi) - "addiu $a3, %lo(environ)\n" // load environ into a3 (lo) - "sw $a2,($a3)\n" // store envp(a2) into environ - - "move $t0, $a2\n" // iterate t0 over envp, look for NULL - "0:" // do { - "lw $a3, ($t0)\n" // a3=*(t0); - "bne $a3, $0, 0b\n" // } while (a3); - "addiu $t0, $t0, 4\n" // delayed slot: t0+=4; - "lui $a3, %hi(_auxv)\n" // load _auxv into a3 (hi) - "addiu $a3, %lo(_auxv)\n" // load _auxv into a3 (lo) - "sw $t0, ($a3)\n" // store t0 into _auxv + /*".ent __start\n"*/ + /*"__start:\n"*/ + "lw $a0,($sp)\n" /* argc was in the stack */ + "addiu $a1, $sp, 4\n" /* argv = sp + 4 */ + "sll $a2, $a0, 2\n" /* a2 = argc * 4 */ + "add $a2, $a2, $a1\n" /* envp = argv + 4*argc ... */ + "addiu $a2, $a2, 4\n" /* ... + 4 */ + "lui $a3, %hi(environ)\n" /* load environ into a3 (hi) */ + "addiu $a3, %lo(environ)\n" /* load environ into a3 (lo) */ + "sw $a2,($a3)\n" /* store envp(a2) into environ */ + + "move $t0, $a2\n" /* iterate t0 over envp, look for NULL */ + "0:" /* do { */ + "lw $a3, ($t0)\n" /* a3=*(t0); */ + "bne $a3, $0, 0b\n" /* } while (a3); */ + "addiu $t0, $t0, 4\n" /* delayed slot: t0+=4; */ + "lui $a3, %hi(_auxv)\n" /* load _auxv into a3 (hi) */ + "addiu $a3, %lo(_auxv)\n" /* load _auxv into a3 (lo) */ + "sw $t0, ($a3)\n" /* store t0 into _auxv */ "li $t0, -8\n" - "and $sp, $sp, $t0\n" // sp must be 8-byte aligned - "addiu $sp,$sp,-16\n" // the callee expects to save a0..a3 there! - "jal main\n" // main() returns the status code, we'll exit with it. - "nop\n" // delayed slot - "move $a0, $v0\n" // retrieve 32-bit exit code from v0 - "li $v0, 4001\n" // NR_exit == 4001 + "and $sp, $sp, $t0\n" /* sp must be 8-byte aligned */ + "addiu $sp,$sp,-16\n" /* the callee expects to save a0..a3 there! */ + "jal main\n" /* main() returns the status code, we'll exit with it. */ + "nop\n" /* delayed slot */ + "move $a0, $v0\n" /* retrieve 32-bit exit code from v0 */ + "li $v0, 4001\n" /* NR_exit == 4001 */ "syscall\n" - //".end __start\n" + /*".end __start\n"*/ ".set pop\n" ); __builtin_unreachable(); } -#endif // _NOLIBC_ARCH_MIPS_H +#endif /* _NOLIBC_ARCH_MIPS_H */ diff --git a/tools/include/nolibc/arch-riscv.h b/tools/include/nolibc/arch-riscv.h index e197fcb10ac0..0d5f15fdedc4 100644 --- a/tools/include/nolibc/arch-riscv.h +++ b/tools/include/nolibc/arch-riscv.h @@ -181,28 +181,28 @@ void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void) ".option norelax\n" "lla gp, __global_pointer$\n" ".option pop\n" - "lw a0, 0(sp)\n" // argc (a0) was in the stack - "add a1, sp, "SZREG"\n" // argv (a1) = sp - "slli a2, a0, "PTRLOG"\n" // envp (a2) = SZREG*argc ... - "add a2, a2, "SZREG"\n" // + SZREG (skip null) - "add a2,a2,a1\n" // + argv - - "add a3, a2, zero\n" // iterate a3 over envp to find auxv (after NULL) - "0:\n" // do { - "ld a4, 0(a3)\n" // a4 = *a3; - "add a3, a3, "SZREG"\n" // a3 += sizeof(void*); - "bne a4, zero, 0b\n" // } while (a4); - "lui a4, %hi(_auxv)\n" // a4 = &_auxv (high bits) - "sd a3, %lo(_auxv)(a4)\n" // store a3 into _auxv - - "lui a3, %hi(environ)\n" // a3 = &environ (high bits) - "sd a2,%lo(environ)(a3)\n" // store envp(a2) into environ - "andi sp,a1,-16\n" // sp must be 16-byte aligned - "call main\n" // main() returns the status code, we'll exit with it. - "li a7, 93\n" // NR_exit == 93 + "lw a0, 0(sp)\n" /* argc (a0) was in the stack */ + "add a1, sp, "SZREG"\n" /* argv (a1) = sp */ + "slli a2, a0, "PTRLOG"\n" /* envp (a2) = SZREG*argc ... */ + "add a2, a2, "SZREG"\n" /* + SZREG (skip null) */ + "add a2,a2,a1\n" /* + argv */ + + "add a3, a2, zero\n" /* iterate a3 over envp to find auxv (after NULL) */ + "0:\n" /* do { */ + "ld a4, 0(a3)\n" /* a4 = *a3; */ + "add a3, a3, "SZREG"\n" /* a3 += sizeof(void*); */ + "bne a4, zero, 0b\n" /* } while (a4); */ + "lui a4, %hi(_auxv)\n" /* a4 = &_auxv (high bits) */ + "sd a3, %lo(_auxv)(a4)\n" /* store a3 into _auxv */ + + "lui a3, %hi(environ)\n" /* a3 = &environ (high bits) */ + "sd a2,%lo(environ)(a3)\n" /* store envp(a2) into environ */ + "andi sp,a1,-16\n" /* sp must be 16-byte aligned */ + "call main\n" /* main() returns the status code, we'll exit with it. */ + "li a7, 93\n" /* NR_exit == 93 */ "ecall\n" ); __builtin_unreachable(); } -#endif // _NOLIBC_ARCH_RISCV_H +#endif /* _NOLIBC_ARCH_RISCV_H */ diff --git a/tools/include/nolibc/arch-s390.h b/tools/include/nolibc/arch-s390.h index 6b0e54ed543d..c62ee2472407 100644 --- a/tools/include/nolibc/arch-s390.h +++ b/tools/include/nolibc/arch-s390.h @@ -223,4 +223,4 @@ void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, return (void *)my_syscall1(__NR_mmap, &args); } #define sys_mmap sys_mmap -#endif // _NOLIBC_ARCH_S390_H +#endif /* _NOLIBC_ARCH_S390_H */ diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h index f7f2a11d4c3b..d98f6c89d143 100644 --- a/tools/include/nolibc/arch-x86_64.h +++ b/tools/include/nolibc/arch-x86_64.h @@ -194,27 +194,27 @@ void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void) { __asm__ volatile ( #ifdef NOLIBC_STACKPROTECTOR - "call __stack_chk_init\n" // initialize stack protector + "call __stack_chk_init\n" /* initialize stack protector */ #endif - "pop %rdi\n" // argc (first arg, %rdi) - "mov %rsp, %rsi\n" // argv[] (second arg, %rsi) - "lea 8(%rsi,%rdi,8),%rdx\n" // then a NULL then envp (third arg, %rdx) - "mov %rdx, environ\n" // save environ - "xor %ebp, %ebp\n" // zero the stack frame - "mov %rdx, %rax\n" // search for auxv (follows NULL after last env) + "pop %rdi\n" /* argc (first arg, %rdi) */ + "mov %rsp, %rsi\n" /* argv[] (second arg, %rsi) */ + "lea 8(%rsi,%rdi,8),%rdx\n" /* then a NULL then envp (third arg, %rdx) */ + "mov %rdx, environ\n" /* save environ */ + "xor %ebp, %ebp\n" /* zero the stack frame */ + "mov %rdx, %rax\n" /* search for auxv (follows NULL after last env) */ "0:\n" - "add $8, %rax\n" // search for auxv using rax, it follows the - "cmp -8(%rax), %rbp\n" // ... NULL after last env (rbp is zero here) + "add $8, %rax\n" /* search for auxv using rax, it follows the */ + "cmp -8(%rax), %rbp\n" /* ... NULL after last env (rbp is zero here) */ "jnz 0b\n" - "mov %rax, _auxv\n" // save it into _auxv - "and $-16, %rsp\n" // x86 ABI : esp must be 16-byte aligned before call - "call main\n" // main() returns the status code, we'll exit with it. - "mov %eax, %edi\n" // retrieve exit code (32 bit) - "mov $60, %eax\n" // NR_exit == 60 - "syscall\n" // really exit - "hlt\n" // ensure it does not return + "mov %rax, _auxv\n" /* save it into _auxv */ + "and $-16, %rsp\n" /* x86 ABI : esp must be 16-byte aligned before call */ + "call main\n" /* main() returns the status code, we'll exit with it. */ + "mov %eax, %edi\n" /* retrieve exit code (32 bit) */ + "mov $60, %eax\n" /* NR_exit == 60 */ + "syscall\n" /* really exit */ + "hlt\n" /* ensure it does not return */ ); __builtin_unreachable(); } -#endif // _NOLIBC_ARCH_X86_64_H +#endif /* _NOLIBC_ARCH_X86_64_H */ diff --git a/tools/include/nolibc/stackprotector.h b/tools/include/nolibc/stackprotector.h index d119cbbbc256..77e5251c4490 100644 --- a/tools/include/nolibc/stackprotector.h +++ b/tools/include/nolibc/stackprotector.h @@ -48,6 +48,6 @@ void __stack_chk_init(void) /* a bit more randomness in case getrandom() fails */ __stack_chk_guard ^= (uintptr_t) &__stack_chk_guard; } -#endif // defined(NOLIBC_STACKPROTECTOR) +#endif /* defined(NOLIBC_STACKPROTECTOR) */ -#endif // _NOLIBC_STACKPROTECTOR_H +#endif /* _NOLIBC_STACKPROTECTOR_H */ diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index bea9760dbd16..1b9b91cd8b57 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -12,15 +12,15 @@ /* system includes */ #include -#include // for SIGCHLD +#include /* for SIGCHLD */ #include #include #include #include #include #include -#include // for O_* and AT_* -#include // for statx() +#include /* for O_* and AT_* */ +#include /* for statx() */ #include "arch.h" #include "errno.h" @@ -322,7 +322,7 @@ static __attribute__((noreturn,unused)) void sys_exit(int status) { my_syscall1(__NR_exit, status & 255); - while(1); // shut the "noreturn" warnings. + while(1); /* shut the "noreturn" warnings. */ } static __attribute__((noreturn,unused)) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index e692be98973a..f06b38cfe38a 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ #define _GNU_SOURCE @@ -46,8 +46,8 @@ char **environ; /* definition of a series of tests */ struct test { - const char *name; // test name - int (*func)(int min, int max); // handler + const char *name; /* test name */ + int (*func)(int min, int max); /* handler */ }; #ifndef _NOLIBC_STDLIB_H @@ -494,7 +494,7 @@ int run_syscall(int min, int max) euid0 = geteuid() == 0; for (test = min; test >= 0 && test <= max; test++) { - int llen = 0; // line length + int llen = 0; /* line length */ /* avoid leaving empty lines below, this will insert holes into * test numbers. @@ -584,7 +584,7 @@ int run_stdlib(int min, int max) void *p1, *p2; for (test = min; test >= 0 && test <= max; test++) { - int llen = 0; // line length + int llen = 0; /* line length */ /* avoid leaving empty lines below, this will insert holes into * test numbers. @@ -731,7 +731,7 @@ static int run_vfprintf(int min, int max) void *p1, *p2; for (test = min; test >= 0 && test <= max; test++) { - int llen = 0; // line length + int llen = 0; /* line length */ /* avoid leaving empty lines below, this will insert holes into * test numbers. -- cgit v1.2.3 From f2fa6b384c67feebd367fa2cb45254a79fd37312 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Thu, 6 Apr 2023 21:54:57 +0000 Subject: tools/nolibc: validate C89 compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To make sure no non-compatible changes are introduced accidentally validate the language standard when building the tests. Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index 0cbe13809b37..423d22f353a0 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -83,7 +83,7 @@ CFLAGS_STKP_i386 = $(CFLAGS_STACKPROTECTOR) CFLAGS_STKP_x86_64 = $(CFLAGS_STACKPROTECTOR) CFLAGS_STKP_x86 = $(CFLAGS_STACKPROTECTOR) CFLAGS_s390 = -m64 -CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables \ +CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 \ $(call cc-option,-fno-stack-protector) \ $(CFLAGS_STKP_$(ARCH)) $(CFLAGS_$(ARCH)) LDFLAGS := -s -- cgit v1.2.3 From 3ad09d72e4d2232374f0dadf94641011b5772bb2 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Sat, 15 Apr 2023 23:28:48 +0200 Subject: tools/nolibc: add testcase for fork()/waitpid() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On s390 the arguments to clone() which is used by fork() are different than other archs. Make sure everything works correctly. Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/nolibc-test.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index f06b38cfe38a..f042a6436b6b 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -474,6 +474,25 @@ static int test_getpagesize(void) return !c; } +static int test_fork(void) +{ + int status; + pid_t pid = fork(); + + switch (pid) { + case -1: + return 1; + + case 0: + exit(123); + + default: + pid = waitpid(pid, &status, 0); + + return pid == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 123; + } +} + /* Run syscall tests between IDs and . * Return 0 on success, non-zero on failure. */ @@ -530,6 +549,7 @@ int run_syscall(int min, int max) CASE_TEST(dup3_0); tmp = dup3(0, 100, 0); EXPECT_SYSNE(1, tmp, -1); close(tmp); break; CASE_TEST(dup3_m1); tmp = dup3(-1, 100, 0); EXPECT_SYSER(1, tmp, -1, EBADF); if (tmp != -1) close(tmp); break; CASE_TEST(execve_root); EXPECT_SYSER(1, execve("/", (char*[]){ [0] = "/", [1] = NULL }, NULL), -1, EACCES); break; + CASE_TEST(fork); EXPECT_SYSZR(1, test_fork()); break; CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break; CASE_TEST(getdents64_null); EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break; CASE_TEST(gettimeofday_null); EXPECT_SYSZR(1, gettimeofday(NULL, NULL)); break; -- cgit v1.2.3 From 53fcfafa8c5c848d4ef1712053f6ea23b263a0de Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Sat, 20 May 2023 09:58:57 +0200 Subject: tools/nolibc/unistd: add syscall() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit syscall() is used by "normal" libcs to allow users to directly call syscalls. By having the same syntax inside nolibc users can more easily write code that works with different libcs. The macro logic is adapted from systemtaps STAP_PROBEV() macro that is released in the public domain / CC0. Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/unistd.h | 15 +++++++++++++++ tools/testing/selftests/nolibc/nolibc-test.c | 2 ++ 2 files changed, 17 insertions(+) (limited to 'tools/testing') diff --git a/tools/include/nolibc/unistd.h b/tools/include/nolibc/unistd.h index ac7d53d986cd..0e832e10a0b2 100644 --- a/tools/include/nolibc/unistd.h +++ b/tools/include/nolibc/unistd.h @@ -56,6 +56,21 @@ int tcsetpgrp(int fd, pid_t pid) return ioctl(fd, TIOCSPGRP, &pid); } +#define _syscall(N, ...) \ +({ \ + long _ret = my_syscall##N(__VA_ARGS__); \ + if (_ret < 0) { \ + SET_ERRNO(-_ret); \ + _ret = -1; \ + } \ + _ret; \ +}) + +#define _syscall_narg(...) __syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) +#define __syscall_narg(_0, _1, _2, _3, _4, _5, _6, N, ...) N +#define _syscall_n(N, ...) _syscall(N, __VA_ARGS__) +#define syscall(...) _syscall_n(_syscall_narg(__VA_ARGS__), ##__VA_ARGS__) + /* make sure to include all global symbols */ #include "nolibc.h" diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index f042a6436b6b..54bf91847af3 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -588,6 +588,8 @@ int run_syscall(int min, int max) CASE_TEST(waitpid_child); EXPECT_SYSER(1, waitpid(getpid(), &tmp, WNOHANG), -1, ECHILD); break; CASE_TEST(write_badf); EXPECT_SYSER(1, write(-1, &tmp, 1), -1, EBADF); break; CASE_TEST(write_zero); EXPECT_SYSZR(1, write(1, &tmp, 0)); break; + CASE_TEST(syscall_noargs); EXPECT_SYSEQ(1, syscall(__NR_getpid), getpid()); break; + CASE_TEST(syscall_args); EXPECT_SYSER(1, syscall(__NR_fstat, 0, NULL), -1, EFAULT); break; case __LINE__: return ret; /* must be last */ /* note: do not set any defaults so as to permit holes above */ -- cgit v1.2.3 From ec8e1b73d58863d1600ca292c9d18de4ec258ba7 Mon Sep 17 00:00:00 2001 From: Zhangjin Wu Date: Sat, 3 Jun 2023 16:00:46 +0800 Subject: selftests/nolibc: syscall_args: use generic __NR_statx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compiling nolibc-test.c for rv32 got such error: tools/testing/selftests/nolibc/nolibc-test.c:599:57: error: ‘__NR_fstat’ undeclared (first use in this function) 599 | CASE_TEST(syscall_args); EXPECT_SYSER(1, syscall(__NR_fstat, 0, NULL), -1, EFAULT); break; The generic include/uapi/asm-generic/unistd.h used by rv32 doesn't support __NR_fstat, use the more generic __NR_statx instead: Running test 'syscall' 69 syscall_noargs = 1 [OK] 70 syscall_args = -1 EFAULT [OK] __NR_statx has been added from v4.10: commit a528d35e8bfc ("statx: Add a system call to make enhanced file info available") It has been supported by all of the platforms since at least from v4.20. Suggested-by: Arnd Bergmann Link: https://lore.kernel.org/linux-riscv/ee8b1f02-ded1-488b-a3a5-68774f0349b5@app.fastmail.com/ Signed-off-by: Zhangjin Wu Reviewed-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/nolibc-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 54bf91847af3..0e2ee513b273 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -589,7 +589,7 @@ int run_syscall(int min, int max) CASE_TEST(write_badf); EXPECT_SYSER(1, write(-1, &tmp, 1), -1, EBADF); break; CASE_TEST(write_zero); EXPECT_SYSZR(1, write(1, &tmp, 0)); break; CASE_TEST(syscall_noargs); EXPECT_SYSEQ(1, syscall(__NR_getpid), getpid()); break; - CASE_TEST(syscall_args); EXPECT_SYSER(1, syscall(__NR_fstat, 0, NULL), -1, EFAULT); break; + CASE_TEST(syscall_args); EXPECT_SYSER(1, syscall(__NR_statx, 0, NULL, 0, 0, NULL), -1, EFAULT); break; case __LINE__: return ret; /* must be last */ /* note: do not set any defaults so as to permit holes above */ -- cgit v1.2.3 From 443de903146e83c13ce43d4ad7ed470129aa348a Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 17 Apr 2023 18:01:31 +0200 Subject: selftests/nolibc: reduce syscalls during space padding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously each space character used for alignment during test execution was written in a single write() call. This would make the output from strace fairly unreadable. Coalesce all spaces into a single call to write(). Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/nolibc-test.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 0e2ee513b273..d5d4dea63cd6 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -111,19 +111,26 @@ const char *errorname(int err) } } +static void putcharn(char c, size_t n) +{ + char buf[64]; + + memset(buf, c, n); + buf[n] = '\0'; + fputs(buf, stdout); +} + static int pad_spc(int llen, int cnt, const char *fmt, ...) { va_list args; - int len; int ret; - for (len = 0; len < cnt - llen; len++) - putchar(' '); + putcharn(' ', cnt - llen); va_start(args, fmt); ret = vfprintf(stdout, fmt, args); va_end(args); - return ret < 0 ? ret : ret + len; + return ret < 0 ? ret : ret + cnt - llen; } /* The tests below are intended to be used by the macroes, which evaluate -- cgit v1.2.3 From c1e30f7d38fd64add1fff08b59c21cf3129e4f7f Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 17 Apr 2023 18:01:33 +0200 Subject: tools/nolibc: aarch64: add stackprotector support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/arch-aarch64.h | 7 ++++++- tools/testing/selftests/nolibc/Makefile | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/include/nolibc/arch-aarch64.h b/tools/include/nolibc/arch-aarch64.h index 76ef26520c85..6a859131c530 100644 --- a/tools/include/nolibc/arch-aarch64.h +++ b/tools/include/nolibc/arch-aarch64.h @@ -172,10 +172,15 @@ struct sys_stat_struct { char **environ __attribute__((weak)); const unsigned long *_auxv __attribute__((weak)); +#define __ARCH_SUPPORTS_STACK_PROTECTOR + /* startup code */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void) +void __attribute__((weak,noreturn,optimize("omit-frame-pointer"),no_stack_protector)) _start(void) { __asm__ volatile ( +#ifdef NOLIBC_STACKPROTECTOR + "bl __stack_chk_init\n" /* initialize stack protector */ +#endif "ldr x0, [sp]\n" /* argc (x0) was in the stack */ "add x1, sp, 8\n" /* argv (x1) = sp */ "lsl x2, x0, 3\n" /* envp (x2) = 8*argc ... */ diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index 423d22f353a0..fa0075479a26 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -82,6 +82,7 @@ CFLAGS_STACKPROTECTOR = -DNOLIBC_STACKPROTECTOR \ CFLAGS_STKP_i386 = $(CFLAGS_STACKPROTECTOR) CFLAGS_STKP_x86_64 = $(CFLAGS_STACKPROTECTOR) CFLAGS_STKP_x86 = $(CFLAGS_STACKPROTECTOR) +CFLAGS_STKP_arm64 = $(CFLAGS_STACKPROTECTOR) CFLAGS_s390 = -m64 CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 \ $(call cc-option,-fno-stack-protector) \ -- cgit v1.2.3 From ed6c0d89bb391c736850e79dbc82aea5e078a941 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 17 Apr 2023 18:01:34 +0200 Subject: tools/nolibc: arm: add stackprotector support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/arch-arm.h | 7 ++++++- tools/testing/selftests/nolibc/Makefile | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h index 2eab1aef321b..202e64f537dc 100644 --- a/tools/include/nolibc/arch-arm.h +++ b/tools/include/nolibc/arch-arm.h @@ -199,10 +199,15 @@ struct sys_stat_struct { char **environ __attribute__((weak)); const unsigned long *_auxv __attribute__((weak)); +#define __ARCH_SUPPORTS_STACK_PROTECTOR + /* startup code */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void) +void __attribute__((weak,noreturn,optimize("omit-frame-pointer"),no_stack_protector)) _start(void) { __asm__ volatile ( +#ifdef NOLIBC_STACKPROTECTOR + "bl __stack_chk_init\n" /* initialize stack protector */ +#endif "pop {%r0}\n" /* argc was in the stack */ "mov %r1, %sp\n" /* argv = sp */ diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index fa0075479a26..7585035cbb0d 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -83,6 +83,7 @@ CFLAGS_STKP_i386 = $(CFLAGS_STACKPROTECTOR) CFLAGS_STKP_x86_64 = $(CFLAGS_STACKPROTECTOR) CFLAGS_STKP_x86 = $(CFLAGS_STACKPROTECTOR) CFLAGS_STKP_arm64 = $(CFLAGS_STACKPROTECTOR) +CFLAGS_STKP_arm = $(CFLAGS_STACKPROTECTOR) CFLAGS_s390 = -m64 CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 \ $(call cc-option,-fno-stack-protector) \ -- cgit v1.2.3 From ca2d0437141681cf3d446e7002692c3617a5bd28 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 17 Apr 2023 18:01:35 +0200 Subject: tools/nolibc: loongarch: add stackprotector support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/arch-loongarch.h | 7 ++++++- tools/testing/selftests/nolibc/Makefile | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/include/nolibc/arch-loongarch.h b/tools/include/nolibc/arch-loongarch.h index ec3b46a991a9..07e3b1fd7262 100644 --- a/tools/include/nolibc/arch-loongarch.h +++ b/tools/include/nolibc/arch-loongarch.h @@ -149,6 +149,8 @@ char **environ __attribute__((weak)); const unsigned long *_auxv __attribute__((weak)); +#define __ARCH_SUPPORTS_STACK_PROTECTOR + #if __loongarch_grlen == 32 #define LONGLOG "2" #define SZREG "4" @@ -170,9 +172,12 @@ const unsigned long *_auxv __attribute__((weak)); #endif /* startup code */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void) +void __attribute__((weak,noreturn,optimize("omit-frame-pointer"),no_stack_protector)) _start(void) { __asm__ volatile ( +#ifdef NOLIBC_STACKPROTECTOR + "bl __stack_chk_init\n" /* initialize stack protector */ +#endif REG_L " $a0, $sp, 0\n" /* argc (a0) was in the stack */ LONG_ADDI " $a1, $sp, "SZREG"\n" /* argv (a1) = sp + SZREG */ LONG_SLL " $a2, $a0, "LONGLOG"\n" /* envp (a2) = SZREG*argc ... */ diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index 7585035cbb0d..ab6e7c0c2494 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -84,6 +84,7 @@ CFLAGS_STKP_x86_64 = $(CFLAGS_STACKPROTECTOR) CFLAGS_STKP_x86 = $(CFLAGS_STACKPROTECTOR) CFLAGS_STKP_arm64 = $(CFLAGS_STACKPROTECTOR) CFLAGS_STKP_arm = $(CFLAGS_STACKPROTECTOR) +CFLAGS_STKP_loongarch = $(CFLAGS_STACKPROTECTOR) CFLAGS_s390 = -m64 CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 \ $(call cc-option,-fno-stack-protector) \ -- cgit v1.2.3 From 3da0de377b5c93518e894f63766d3555ed883f93 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 17 Apr 2023 18:01:36 +0200 Subject: tools/nolibc: mips: add stackprotector support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/arch-mips.h | 8 +++++++- tools/testing/selftests/nolibc/Makefile | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h index 8822f150e72f..65c19ccc7f9d 100644 --- a/tools/include/nolibc/arch-mips.h +++ b/tools/include/nolibc/arch-mips.h @@ -179,14 +179,20 @@ struct sys_stat_struct { char **environ __attribute__((weak)); const unsigned long *_auxv __attribute__((weak)); +#define __ARCH_SUPPORTS_STACK_PROTECTOR + /* startup code, note that it's called __start on MIPS */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __start(void) +void __attribute__((weak,noreturn,optimize("omit-frame-pointer"),no_stack_protector)) __start(void) { __asm__ volatile ( /*".set nomips16\n"*/ ".set push\n" ".set noreorder\n" ".option pic0\n" +#ifdef NOLIBC_STACKPROTECTOR + "jal __stack_chk_init\n" /* initialize stack protector */ + "nop\n" /* delayed slot */ +#endif /*".ent __start\n"*/ /*"__start:\n"*/ "lw $a0,($sp)\n" /* argc was in the stack */ diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index ab6e7c0c2494..6d660d922240 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -84,6 +84,7 @@ CFLAGS_STKP_x86_64 = $(CFLAGS_STACKPROTECTOR) CFLAGS_STKP_x86 = $(CFLAGS_STACKPROTECTOR) CFLAGS_STKP_arm64 = $(CFLAGS_STACKPROTECTOR) CFLAGS_STKP_arm = $(CFLAGS_STACKPROTECTOR) +CFLAGS_STKP_mips = $(CFLAGS_STACKPROTECTOR) CFLAGS_STKP_loongarch = $(CFLAGS_STACKPROTECTOR) CFLAGS_s390 = -m64 CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 \ -- cgit v1.2.3 From 56d294a50cf34990dec8886bef3f1a1386d56ac6 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Sat, 20 May 2023 11:53:35 +0200 Subject: tools/nolibc: riscv: add stackprotector support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Weißschuh Acked-by: Palmer Dabbelt Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/arch-riscv.h | 7 ++++++- tools/testing/selftests/nolibc/Makefile | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/include/nolibc/arch-riscv.h b/tools/include/nolibc/arch-riscv.h index 992a1739dd9c..d0439249c9c9 100644 --- a/tools/include/nolibc/arch-riscv.h +++ b/tools/include/nolibc/arch-riscv.h @@ -177,14 +177,19 @@ struct sys_stat_struct { char **environ __attribute__((weak)); const unsigned long *_auxv __attribute__((weak)); +#define __ARCH_SUPPORTS_STACK_PROTECTOR + /* startup code */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void) +void __attribute__((weak,noreturn,optimize("omit-frame-pointer"),no_stack_protector)) _start(void) { __asm__ volatile ( ".option push\n" ".option norelax\n" "lla gp, __global_pointer$\n" ".option pop\n" +#ifdef NOLIBC_STACKPROTECTOR + "call __stack_chk_init\n" /* initialize stack protector */ +#endif REG_L" a0, 0(sp)\n" /* argc (a0) was in the stack */ "add a1, sp, "SZREG"\n" /* argv (a1) = sp */ "slli a2, a0, "PTRLOG"\n" /* envp (a2) = SZREG*argc ... */ diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index 6d660d922240..bd41102ea299 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -85,6 +85,7 @@ CFLAGS_STKP_x86 = $(CFLAGS_STACKPROTECTOR) CFLAGS_STKP_arm64 = $(CFLAGS_STACKPROTECTOR) CFLAGS_STKP_arm = $(CFLAGS_STACKPROTECTOR) CFLAGS_STKP_mips = $(CFLAGS_STACKPROTECTOR) +CFLAGS_STKP_riscv = $(CFLAGS_STACKPROTECTOR) CFLAGS_STKP_loongarch = $(CFLAGS_STACKPROTECTOR) CFLAGS_s390 = -m64 CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 \ -- cgit v1.2.3 From 8525092104ca97d5131fe594081dc176bcce34b5 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Sun, 21 May 2023 11:36:32 +0200 Subject: tools/nolibc: add test for __stack_chk_guard initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/nolibc-test.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index d5d4dea63cd6..861b9a74b71f 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -808,6 +808,14 @@ static int run_protection(int min, int max) return 0; #endif +#if defined(NOLIBC_STACKPROTECTOR) + if (!__stack_chk_guard) { + llen += printf("__stack_chk_guard not initialized"); + pad_spc(llen, 64, "[FAIL]\n"); + return 1; + } +#endif + pid = -1; pid = fork(); -- cgit v1.2.3 From 818924d1295ea16db267ea6defe08b21243583b6 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Sun, 21 May 2023 11:36:34 +0200 Subject: tools/nolibc: add autodetection for stackprotector support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The stackprotector support in nolibc should be enabled iff it is also enabled in the compiler. Use the preprocessor defines added by gcc and clang if stackprotector support is enable to automatically do so in nolibc. This completely removes the need for any user-visible API. To avoid inlining the lengthy preprocessor check into every user introduce a new header compiler.h that abstracts the logic away. As the define NOLIBC_STACKPROTECTOR is now not user-relevant anymore prefix it with an underscore. Suggested-by: Willy Tarreau Link: https://lore.kernel.org/lkml/20230520133237.GA27501@1wt.eu/ Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/Makefile | 1 + tools/include/nolibc/arch-aarch64.h | 6 +++--- tools/include/nolibc/arch-arm.h | 6 +++--- tools/include/nolibc/arch-i386.h | 6 +++--- tools/include/nolibc/arch-loongarch.h | 6 +++--- tools/include/nolibc/arch-mips.h | 6 +++--- tools/include/nolibc/arch-riscv.h | 6 +++--- tools/include/nolibc/arch-x86_64.h | 6 +++--- tools/include/nolibc/compiler.h | 15 +++++++++++++++ tools/include/nolibc/stackprotector.h | 10 +++------- tools/testing/selftests/nolibc/nolibc-test.c | 4 ++-- 11 files changed, 42 insertions(+), 30 deletions(-) create mode 100644 tools/include/nolibc/compiler.h (limited to 'tools/testing') diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile index e37c3ac86e23..64d67b080744 100644 --- a/tools/include/nolibc/Makefile +++ b/tools/include/nolibc/Makefile @@ -26,6 +26,7 @@ endif nolibc_arch := $(patsubst arm64,aarch64,$(ARCH)) arch_file := arch-$(nolibc_arch).h all_files := \ + compiler.h \ ctype.h \ errno.h \ nolibc.h \ diff --git a/tools/include/nolibc/arch-aarch64.h b/tools/include/nolibc/arch-aarch64.h index 6a859131c530..64ec65b4ee38 100644 --- a/tools/include/nolibc/arch-aarch64.h +++ b/tools/include/nolibc/arch-aarch64.h @@ -7,6 +7,8 @@ #ifndef _NOLIBC_ARCH_AARCH64_H #define _NOLIBC_ARCH_AARCH64_H +#include "compiler.h" + /* The struct returned by the newfstatat() syscall. Differs slightly from the * x86_64's stat one by field ordering, so be careful. */ @@ -172,13 +174,11 @@ struct sys_stat_struct { char **environ __attribute__((weak)); const unsigned long *_auxv __attribute__((weak)); -#define __ARCH_SUPPORTS_STACK_PROTECTOR - /* startup code */ void __attribute__((weak,noreturn,optimize("omit-frame-pointer"),no_stack_protector)) _start(void) { __asm__ volatile ( -#ifdef NOLIBC_STACKPROTECTOR +#ifdef _NOLIBC_STACKPROTECTOR "bl __stack_chk_init\n" /* initialize stack protector */ #endif "ldr x0, [sp]\n" /* argc (x0) was in the stack */ diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h index 202e64f537dc..924169522cf7 100644 --- a/tools/include/nolibc/arch-arm.h +++ b/tools/include/nolibc/arch-arm.h @@ -7,6 +7,8 @@ #ifndef _NOLIBC_ARCH_ARM_H #define _NOLIBC_ARCH_ARM_H +#include "compiler.h" + /* The struct returned by the stat() syscall, 32-bit only, the syscall returns * exactly 56 bytes (stops before the unused array). In big endian, the format * differs as devices are returned as short only. @@ -199,13 +201,11 @@ struct sys_stat_struct { char **environ __attribute__((weak)); const unsigned long *_auxv __attribute__((weak)); -#define __ARCH_SUPPORTS_STACK_PROTECTOR - /* startup code */ void __attribute__((weak,noreturn,optimize("omit-frame-pointer"),no_stack_protector)) _start(void) { __asm__ volatile ( -#ifdef NOLIBC_STACKPROTECTOR +#ifdef _NOLIBC_STACKPROTECTOR "bl __stack_chk_init\n" /* initialize stack protector */ #endif "pop {%r0}\n" /* argc was in the stack */ diff --git a/tools/include/nolibc/arch-i386.h b/tools/include/nolibc/arch-i386.h index 7c41897a08ce..37f813912957 100644 --- a/tools/include/nolibc/arch-i386.h +++ b/tools/include/nolibc/arch-i386.h @@ -7,6 +7,8 @@ #ifndef _NOLIBC_ARCH_I386_H #define _NOLIBC_ARCH_I386_H +#include "compiler.h" + /* The struct returned by the stat() syscall, 32-bit only, the syscall returns * exactly 56 bytes (stops before the unused array). */ @@ -181,8 +183,6 @@ struct sys_stat_struct { char **environ __attribute__((weak)); const unsigned long *_auxv __attribute__((weak)); -#define __ARCH_SUPPORTS_STACK_PROTECTOR - /* startup code */ /* * i386 System V ABI mandates: @@ -193,7 +193,7 @@ const unsigned long *_auxv __attribute__((weak)); void __attribute__((weak,noreturn,optimize("omit-frame-pointer"),no_stack_protector)) _start(void) { __asm__ volatile ( -#ifdef NOLIBC_STACKPROTECTOR +#ifdef _NOLIBC_STACKPROTECTOR "call __stack_chk_init\n" /* initialize stack protector */ #endif "pop %eax\n" /* argc (first arg, %eax) */ diff --git a/tools/include/nolibc/arch-loongarch.h b/tools/include/nolibc/arch-loongarch.h index 07e3b1fd7262..d8ea7e787df4 100644 --- a/tools/include/nolibc/arch-loongarch.h +++ b/tools/include/nolibc/arch-loongarch.h @@ -7,6 +7,8 @@ #ifndef _NOLIBC_ARCH_LOONGARCH_H #define _NOLIBC_ARCH_LOONGARCH_H +#include "compiler.h" + /* Syscalls for LoongArch : * - stack is 16-byte aligned * - syscall number is passed in a7 @@ -149,8 +151,6 @@ char **environ __attribute__((weak)); const unsigned long *_auxv __attribute__((weak)); -#define __ARCH_SUPPORTS_STACK_PROTECTOR - #if __loongarch_grlen == 32 #define LONGLOG "2" #define SZREG "4" @@ -175,7 +175,7 @@ const unsigned long *_auxv __attribute__((weak)); void __attribute__((weak,noreturn,optimize("omit-frame-pointer"),no_stack_protector)) _start(void) { __asm__ volatile ( -#ifdef NOLIBC_STACKPROTECTOR +#ifdef _NOLIBC_STACKPROTECTOR "bl __stack_chk_init\n" /* initialize stack protector */ #endif REG_L " $a0, $sp, 0\n" /* argc (a0) was in the stack */ diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h index 65c19ccc7f9d..9860236e5340 100644 --- a/tools/include/nolibc/arch-mips.h +++ b/tools/include/nolibc/arch-mips.h @@ -7,6 +7,8 @@ #ifndef _NOLIBC_ARCH_MIPS_H #define _NOLIBC_ARCH_MIPS_H +#include "compiler.h" + /* The struct returned by the stat() syscall. 88 bytes are returned by the * syscall. */ @@ -179,8 +181,6 @@ struct sys_stat_struct { char **environ __attribute__((weak)); const unsigned long *_auxv __attribute__((weak)); -#define __ARCH_SUPPORTS_STACK_PROTECTOR - /* startup code, note that it's called __start on MIPS */ void __attribute__((weak,noreturn,optimize("omit-frame-pointer"),no_stack_protector)) __start(void) { @@ -189,7 +189,7 @@ void __attribute__((weak,noreturn,optimize("omit-frame-pointer"),no_stack_protec ".set push\n" ".set noreorder\n" ".option pic0\n" -#ifdef NOLIBC_STACKPROTECTOR +#ifdef _NOLIBC_STACKPROTECTOR "jal __stack_chk_init\n" /* initialize stack protector */ "nop\n" /* delayed slot */ #endif diff --git a/tools/include/nolibc/arch-riscv.h b/tools/include/nolibc/arch-riscv.h index d0439249c9c9..86616aeb77a0 100644 --- a/tools/include/nolibc/arch-riscv.h +++ b/tools/include/nolibc/arch-riscv.h @@ -7,6 +7,8 @@ #ifndef _NOLIBC_ARCH_RISCV_H #define _NOLIBC_ARCH_RISCV_H +#include "compiler.h" + struct sys_stat_struct { unsigned long st_dev; /* Device. */ unsigned long st_ino; /* File serial number. */ @@ -177,8 +179,6 @@ struct sys_stat_struct { char **environ __attribute__((weak)); const unsigned long *_auxv __attribute__((weak)); -#define __ARCH_SUPPORTS_STACK_PROTECTOR - /* startup code */ void __attribute__((weak,noreturn,optimize("omit-frame-pointer"),no_stack_protector)) _start(void) { @@ -187,7 +187,7 @@ void __attribute__((weak,noreturn,optimize("omit-frame-pointer"),no_stack_protec ".option norelax\n" "lla gp, __global_pointer$\n" ".option pop\n" -#ifdef NOLIBC_STACKPROTECTOR +#ifdef _NOLIBC_STACKPROTECTOR "call __stack_chk_init\n" /* initialize stack protector */ #endif REG_L" a0, 0(sp)\n" /* argc (a0) was in the stack */ diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h index e201af15e142..485a7ff72a87 100644 --- a/tools/include/nolibc/arch-x86_64.h +++ b/tools/include/nolibc/arch-x86_64.h @@ -7,6 +7,8 @@ #ifndef _NOLIBC_ARCH_X86_64_H #define _NOLIBC_ARCH_X86_64_H +#include "compiler.h" + /* The struct returned by the stat() syscall, equivalent to stat64(). The * syscall returns 116 bytes and stops in the middle of __unused. */ @@ -181,8 +183,6 @@ struct sys_stat_struct { char **environ __attribute__((weak)); const unsigned long *_auxv __attribute__((weak)); -#define __ARCH_SUPPORTS_STACK_PROTECTOR - /* startup code */ /* * x86-64 System V ABI mandates: @@ -193,7 +193,7 @@ const unsigned long *_auxv __attribute__((weak)); void __attribute__((weak,noreturn,optimize("omit-frame-pointer"),no_stack_protector)) _start(void) { __asm__ volatile ( -#ifdef NOLIBC_STACKPROTECTOR +#ifdef _NOLIBC_STACKPROTECTOR "call __stack_chk_init\n" /* initialize stack protector */ #endif "pop %rdi\n" /* argc (first arg, %rdi) */ diff --git a/tools/include/nolibc/compiler.h b/tools/include/nolibc/compiler.h new file mode 100644 index 000000000000..57da75cea799 --- /dev/null +++ b/tools/include/nolibc/compiler.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * NOLIBC compiler support header + * Copyright (C) 2023 Thomas Weißschuh + */ +#ifndef _NOLIBC_COMPILER_H +#define _NOLIBC_COMPILER_H + +#if defined(__SSP__) || defined(__SSP_STRONG__) || defined(__SSP_ALL__) || defined(__SSP_EXPLICIT__) + +#define _NOLIBC_STACKPROTECTOR + +#endif /* defined(__SSP__) ... */ + +#endif /* _NOLIBC_COMPILER_H */ diff --git a/tools/include/nolibc/stackprotector.h b/tools/include/nolibc/stackprotector.h index b0156fc077a0..0a89e2b89ca6 100644 --- a/tools/include/nolibc/stackprotector.h +++ b/tools/include/nolibc/stackprotector.h @@ -7,13 +7,9 @@ #ifndef _NOLIBC_STACKPROTECTOR_H #define _NOLIBC_STACKPROTECTOR_H -#include "arch.h" +#include "compiler.h" -#if defined(NOLIBC_STACKPROTECTOR) - -#if !defined(__ARCH_SUPPORTS_STACK_PROTECTOR) -#error "nolibc does not support stack protectors on this arch" -#endif +#if defined(_NOLIBC_STACKPROTECTOR) #include "sys.h" #include "stdlib.h" @@ -49,6 +45,6 @@ void __stack_chk_init(void) if (__stack_chk_guard != (uintptr_t) &__stack_chk_guard) __stack_chk_guard ^= (uintptr_t) &__stack_chk_guard; } -#endif /* defined(NOLIBC_STACKPROTECTOR) */ +#endif /* defined(_NOLIBC_STACKPROTECTOR) */ #endif /* _NOLIBC_STACKPROTECTOR_H */ diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 861b9a74b71f..b50b5a8bcc90 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -802,13 +802,13 @@ static int run_protection(int min, int max) llen += printf("0 -fstackprotector "); -#if !defined(NOLIBC_STACKPROTECTOR) +#if !defined(_NOLIBC_STACKPROTECTOR) llen += printf("not supported"); pad_spc(llen, 64, "[SKIPPED]\n"); return 0; #endif -#if defined(NOLIBC_STACKPROTECTOR) +#if defined(_NOLIBC_STACKPROTECTOR) if (!__stack_chk_guard) { llen += printf("__stack_chk_guard not initialized"); pad_spc(llen, 64, "[FAIL]\n"); -- cgit v1.2.3 From 0093c2dae8d37595c3c7fcc626b51300699a003b Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Sun, 21 May 2023 11:36:35 +0200 Subject: tools/nolibc: simplify stackprotector compiler flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that nolibc enable stackprotector support automatically when the compiler enables it we only have to get the -fstack-protector flags correct. The cc-options are structured so that -fstack-protector-all is only enabled if -mstack-protector=guard works, as that is the only mode supported by nolibc. Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/Makefile | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index bd41102ea299..47c3c89092e4 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -76,21 +76,11 @@ else Q=@ endif -CFLAGS_STACKPROTECTOR = -DNOLIBC_STACKPROTECTOR \ - $(call cc-option,-mstack-protector-guard=global) \ - $(call cc-option,-fstack-protector-all) -CFLAGS_STKP_i386 = $(CFLAGS_STACKPROTECTOR) -CFLAGS_STKP_x86_64 = $(CFLAGS_STACKPROTECTOR) -CFLAGS_STKP_x86 = $(CFLAGS_STACKPROTECTOR) -CFLAGS_STKP_arm64 = $(CFLAGS_STACKPROTECTOR) -CFLAGS_STKP_arm = $(CFLAGS_STACKPROTECTOR) -CFLAGS_STKP_mips = $(CFLAGS_STACKPROTECTOR) -CFLAGS_STKP_riscv = $(CFLAGS_STACKPROTECTOR) -CFLAGS_STKP_loongarch = $(CFLAGS_STACKPROTECTOR) CFLAGS_s390 = -m64 +CFLAGS_STACKPROTECTOR ?= $(call cc-option,-mstack-protector-guard=global $(call cc-option,-fstack-protector-all)) CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 \ $(call cc-option,-fno-stack-protector) \ - $(CFLAGS_STKP_$(ARCH)) $(CFLAGS_$(ARCH)) + $(CFLAGS_$(ARCH)) $(CFLAGS_STACKPROTECTOR) LDFLAGS := -s help: -- cgit v1.2.3 From 208aa9d94c1181d8dff8e60d681e3b6cf0b37fae Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Fri, 26 May 2023 09:51:19 +0200 Subject: tools/nolibc: add support for prctl() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It will be used to disable core dumps from the child spawned to validate the stack protector functionality. Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/sys.h | 27 +++++++++++++++++++++++++++ tools/testing/selftests/nolibc/nolibc-test.c | 2 ++ 2 files changed, 29 insertions(+) (limited to 'tools/testing') diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index d5792a5de70b..c688b410f9e4 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -22,6 +22,7 @@ #include /* for O_* and AT_* */ #include /* for statx() */ #include /* for LINUX_REBOOT_* */ +#include #include "arch.h" #include "errno.h" @@ -875,6 +876,32 @@ int open(const char *path, int flags, ...) } +/* + * int prctl(int option, unsigned long arg2, unsigned long arg3, + * unsigned long arg4, unsigned long arg5); + */ + +static __attribute__((unused)) +int sys_prctl(int option, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5) +{ + return my_syscall5(__NR_prctl, option, arg2, arg3, arg4, arg5); +} + +static __attribute__((unused)) +int prctl(int option, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5) +{ + int ret = sys_prctl(option, arg2, arg3, arg4, arg5); + + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +} + + /* * int pivot_root(const char *new, const char *old); */ diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index b50b5a8bcc90..6db788603a34 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -580,6 +581,7 @@ int run_syscall(int min, int max) CASE_TEST(poll_null); EXPECT_SYSZR(1, poll(NULL, 0, 0)); break; CASE_TEST(poll_stdout); EXPECT_SYSNE(1, ({ struct pollfd fds = { 1, POLLOUT, 0}; poll(&fds, 1, 0); }), -1); break; CASE_TEST(poll_fault); EXPECT_SYSER(1, poll((void *)1, 1, 0), -1, EFAULT); break; + CASE_TEST(prctl); EXPECT_SYSER(1, prctl(PR_SET_NAME, (unsigned long)NULL, 0, 0, 0), -1, EFAULT); break; CASE_TEST(read_badf); EXPECT_SYSER(1, read(-1, &tmp, 1), -1, EBADF); break; CASE_TEST(sched_yield); EXPECT_SYSZR(1, sched_yield()); break; CASE_TEST(select_null); EXPECT_SYSZR(1, ({ struct timeval tv = { 0 }; select(0, NULL, NULL, NULL, &tv); })); break; -- cgit v1.2.3 From 9a75575b81b5639f7ca82c9701fb199401fd6471 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Fri, 26 May 2023 09:51:20 +0200 Subject: selftests/nolibc: prevent coredumps during test execution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The child process forked during stackprotector tests intentionally gets killed with SIGABRT. By default this will trigger writing a coredump. The writing of the coredump can spam the systems coredump machinery and take some time. Timings for the full run of nolibc-test: Before: 200ms After: 20ms This is on a desktop x86 system with systemd-coredumpd enabled. Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/nolibc-test.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 6db788603a34..84a1b02eb6f9 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -831,6 +831,7 @@ static int run_protection(int min, int max) close(STDOUT_FILENO); close(STDERR_FILENO); + prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); smash_stack(); return 1; -- cgit v1.2.3 From 87b9fa66af9ad92097c0593626dea3654ec19fd0 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Sat, 27 May 2023 14:56:42 +0200 Subject: tools/nolibc: support nanoseconds in stat() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep backwards compatibility through unions. The compatibility macros like #define st_atime st_atim.tv_sec as documented in stat(3type) don't work for nolibc because it would break with other stat-like structures that contain the field st_atime. The stx_atime, stx_mtime, stx_ctime are in type of 'struct statx_timestamp', which is incompatible with 'struct timespec', should be converted explicitly. /* include/uapi/linux/stat.h */ struct statx_timestamp { __s64 tv_sec; __u32 tv_nsec; __s32 __reserved; }; /* include/uapi/linux/time.h */ struct timespec { __kernel_old_time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ }; Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/linux-riscv/3a3edd48-1ace-4c89-89e8-9c594dd1b3c9@t-8ch.de/ Co-authored-by: Zhangjin Wu Signed-off-by: Zhangjin Wu [wt: squashed Zhangjin & Thomas' patches into one to preserve "bisectability"] Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/sys.h | 66 +++++++++++++++------------- tools/include/nolibc/types.h | 6 +-- tools/testing/selftests/nolibc/nolibc-test.c | 23 ++++++++++ 3 files changed, 62 insertions(+), 33 deletions(-) (limited to 'tools/testing') diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index c688b410f9e4..7836d7e7760d 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -1161,23 +1161,26 @@ int sys_stat(const char *path, struct stat *buf) long ret; ret = sys_statx(AT_FDCWD, path, AT_NO_AUTOMOUNT, STATX_BASIC_STATS, &statx); - buf->st_dev = ((statx.stx_dev_minor & 0xff) - | (statx.stx_dev_major << 8) - | ((statx.stx_dev_minor & ~0xff) << 12)); - buf->st_ino = statx.stx_ino; - buf->st_mode = statx.stx_mode; - buf->st_nlink = statx.stx_nlink; - buf->st_uid = statx.stx_uid; - buf->st_gid = statx.stx_gid; - buf->st_rdev = ((statx.stx_rdev_minor & 0xff) - | (statx.stx_rdev_major << 8) - | ((statx.stx_rdev_minor & ~0xff) << 12)); - buf->st_size = statx.stx_size; - buf->st_blksize = statx.stx_blksize; - buf->st_blocks = statx.stx_blocks; - buf->st_atime = statx.stx_atime.tv_sec; - buf->st_mtime = statx.stx_mtime.tv_sec; - buf->st_ctime = statx.stx_ctime.tv_sec; + buf->st_dev = ((statx.stx_dev_minor & 0xff) + | (statx.stx_dev_major << 8) + | ((statx.stx_dev_minor & ~0xff) << 12)); + buf->st_ino = statx.stx_ino; + buf->st_mode = statx.stx_mode; + buf->st_nlink = statx.stx_nlink; + buf->st_uid = statx.stx_uid; + buf->st_gid = statx.stx_gid; + buf->st_rdev = ((statx.stx_rdev_minor & 0xff) + | (statx.stx_rdev_major << 8) + | ((statx.stx_rdev_minor & ~0xff) << 12)); + buf->st_size = statx.stx_size; + buf->st_blksize = statx.stx_blksize; + buf->st_blocks = statx.stx_blocks; + buf->st_atim.tv_sec = statx.stx_atime.tv_sec; + buf->st_atim.tv_nsec = statx.stx_atime.tv_nsec; + buf->st_mtim.tv_sec = statx.stx_mtime.tv_sec; + buf->st_mtim.tv_nsec = statx.stx_mtime.tv_nsec; + buf->st_ctim.tv_sec = statx.stx_ctime.tv_sec; + buf->st_ctim.tv_nsec = statx.stx_ctime.tv_nsec; return ret; } #else @@ -1195,19 +1198,22 @@ int sys_stat(const char *path, struct stat *buf) #else #error Neither __NR_newfstatat nor __NR_stat defined, cannot implement sys_stat() #endif - buf->st_dev = stat.st_dev; - buf->st_ino = stat.st_ino; - buf->st_mode = stat.st_mode; - buf->st_nlink = stat.st_nlink; - buf->st_uid = stat.st_uid; - buf->st_gid = stat.st_gid; - buf->st_rdev = stat.st_rdev; - buf->st_size = stat.st_size; - buf->st_blksize = stat.st_blksize; - buf->st_blocks = stat.st_blocks; - buf->st_atime = stat.st_atime; - buf->st_mtime = stat.st_mtime; - buf->st_ctime = stat.st_ctime; + buf->st_dev = stat.st_dev; + buf->st_ino = stat.st_ino; + buf->st_mode = stat.st_mode; + buf->st_nlink = stat.st_nlink; + buf->st_uid = stat.st_uid; + buf->st_gid = stat.st_gid; + buf->st_rdev = stat.st_rdev; + buf->st_size = stat.st_size; + buf->st_blksize = stat.st_blksize; + buf->st_blocks = stat.st_blocks; + buf->st_atim.tv_sec = stat.st_atime; + buf->st_atim.tv_nsec = stat.st_atime_nsec; + buf->st_mtim.tv_sec = stat.st_mtime; + buf->st_mtim.tv_nsec = stat.st_mtime_nsec; + buf->st_ctim.tv_sec = stat.st_ctime; + buf->st_ctim.tv_nsec = stat.st_ctime_nsec; return ret; } #endif diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h index 15b0baffd336..f96e28bff4ba 100644 --- a/tools/include/nolibc/types.h +++ b/tools/include/nolibc/types.h @@ -198,9 +198,9 @@ struct stat { off_t st_size; /* total size, in bytes */ blksize_t st_blksize; /* blocksize for file system I/O */ blkcnt_t st_blocks; /* number of 512B blocks allocated */ - time_t st_atime; /* time of last access */ - time_t st_mtime; /* time of last modification */ - time_t st_ctime; /* time of last status change */ + union { time_t st_atime; struct timespec st_atim; }; /* time of last access */ + union { time_t st_mtime; struct timespec st_mtim; }; /* time of last modification */ + union { time_t st_ctime; struct timespec st_ctim; }; /* time of last status change */ }; /* WARNING, it only deals with the 4096 first majors and 256 first minors */ diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 84a1b02eb6f9..0d76790ffb0d 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -501,6 +501,28 @@ static int test_fork(void) } } +static int test_stat_timestamps(void) +{ + struct stat st; + + if (sizeof(st.st_atim.tv_sec) != sizeof(st.st_atime)) + return 1; + + if (stat("/proc/self/", &st)) + return 1; + + if (st.st_atim.tv_sec != st.st_atime || st.st_atim.tv_nsec > 1000000000) + return 1; + + if (st.st_mtim.tv_sec != st.st_mtime || st.st_mtim.tv_nsec > 1000000000) + return 1; + + if (st.st_ctim.tv_sec != st.st_ctime || st.st_ctim.tv_nsec > 1000000000) + return 1; + + return 0; +} + /* Run syscall tests between IDs and . * Return 0 on success, non-zero on failure. */ @@ -589,6 +611,7 @@ int run_syscall(int min, int max) CASE_TEST(select_fault); EXPECT_SYSER(1, select(1, (void *)1, NULL, NULL, 0), -1, EFAULT); break; CASE_TEST(stat_blah); EXPECT_SYSER(1, stat("/proc/self/blah", &stat_buf), -1, ENOENT); break; CASE_TEST(stat_fault); EXPECT_SYSER(1, stat(NULL, &stat_buf), -1, EFAULT); break; + CASE_TEST(stat_timestamps); EXPECT_SYSZR(1, test_stat_timestamps()); break; CASE_TEST(symlink_root); EXPECT_SYSER(1, symlink("/", "/"), -1, EEXIST); break; CASE_TEST(unlink_root); EXPECT_SYSER(1, unlink("/"), -1, EISDIR); break; CASE_TEST(unlink_blah); EXPECT_SYSER(1, unlink("/proc/self/blah"), -1, ENOENT); break; -- cgit v1.2.3 From 758f970f4204d17b4e14774d6eb2b8bdecda067e Mon Sep 17 00:00:00 2001 From: Zhangjin Wu Date: Thu, 25 May 2023 01:46:54 +0800 Subject: selftests/nolibc: print name instead of number for EOVERFLOW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EOVERFLOW will be used in the coming time64 syscalls support. Signed-off-by: Zhangjin Wu Reviewed-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/nolibc-test.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 0d76790ffb0d..ffdf1e8c305c 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -107,6 +107,7 @@ const char *errorname(int err) CASE_ERR(EDOM); CASE_ERR(ERANGE); CASE_ERR(ENOSYS); + CASE_ERR(EOVERFLOW); default: return itoa(err); } -- cgit v1.2.3 From da1affc5cedacb91ce0a15ad768e56383d1e48b7 Mon Sep 17 00:00:00 2001 From: Zhangjin Wu Date: Thu, 25 May 2023 01:54:19 +0800 Subject: selftests/nolibc: remove the duplicated gettimeofday_bad2 There were two exactly similar occurrences of this test. Signed-off-by: Zhangjin Wu Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/nolibc-test.c | 1 - 1 file changed, 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index ffdf1e8c305c..d417ca5d976f 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -587,7 +587,6 @@ int run_syscall(int min, int max) #ifdef NOLIBC CASE_TEST(gettimeofday_bad1); EXPECT_SYSER(1, gettimeofday((void *)1, NULL), -1, EFAULT); break; CASE_TEST(gettimeofday_bad2); EXPECT_SYSER(1, gettimeofday(NULL, (void *)1), -1, EFAULT); break; - CASE_TEST(gettimeofday_bad2); EXPECT_SYSER(1, gettimeofday(NULL, (void *)1), -1, EFAULT); break; #endif CASE_TEST(getpagesize); EXPECT_SYSZR(1, test_getpagesize()); break; CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break; -- cgit v1.2.3 From ed495f0945e732c55bb8c21e660c2c86f5e57812 Mon Sep 17 00:00:00 2001 From: Zhangjin Wu Date: Tue, 30 May 2023 14:03:33 +0800 Subject: selftests/nolibc: test_fork: fix up duplicated print MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit running nolibc-test with glibc on x86_64 got such print issue: 29 execve_root = -1 EACCES [OK] 30 fork30 fork = 0 [OK] 31 getdents64_root = 712 [OK] The fork test case has three printf calls: (1) llen += printf("%d %s", test, #name); (2) llen += printf(" = %d %s ", expr, errorname(errno)); (3) llen += pad_spc(llen, 64, "[FAIL]\n"); --> vfprintf() In the following scene, the above issue happens: (a) The parent calls (1) (b) The parent calls fork() (c) The child runs and shares the print buffer of (1) (d) The child exits, flushs the print buffer and closes its own stdout/stderr * "30 fork" is printed at the first time. (e) The parent calls (2) and (3), with "\n" in (3), it flushs the whole buffer * "30 fork = 0 ..." is printed Therefore, there are two "30 fork" in the stdout. Between (a) and (b), if flush the stdout (and the sterr), the child in stage (c) will not be able to 'see' the print buffer. Signed-off-by: Zhangjin Wu Reviewed-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/nolibc-test.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index d417ca5d976f..fa18e7dc35c8 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -486,7 +486,13 @@ static int test_getpagesize(void) static int test_fork(void) { int status; - pid_t pid = fork(); + pid_t pid; + + /* flush the printf buffer to avoid child flush it */ + fflush(stdout); + fflush(stderr); + + pid = fork(); switch (pid) { case -1: -- cgit v1.2.3 From f9bf5944d37b75b8238349d4fb5b7a97bbecfc9d Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Tue, 30 May 2023 11:18:00 +0200 Subject: tools/nolibc: ensure fast64 integer types have 64 bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On 32bit platforms size_t is not enough to represent [u]int_fast64_t. Fixes: 3e9fd4e9a1d5 ("tools/nolibc: add integer types and integer limit macros") Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/stdint.h | 10 +++++----- tools/testing/selftests/nolibc/nolibc-test.c | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'tools/testing') diff --git a/tools/include/nolibc/stdint.h b/tools/include/nolibc/stdint.h index c1ce4f5e0603..661d942862c0 100644 --- a/tools/include/nolibc/stdint.h +++ b/tools/include/nolibc/stdint.h @@ -36,8 +36,8 @@ typedef ssize_t int_fast16_t; typedef size_t uint_fast16_t; typedef ssize_t int_fast32_t; typedef size_t uint_fast32_t; -typedef ssize_t int_fast64_t; -typedef size_t uint_fast64_t; +typedef int64_t int_fast64_t; +typedef uint64_t uint_fast64_t; typedef int64_t intmax_t; typedef uint64_t uintmax_t; @@ -84,16 +84,16 @@ typedef uint64_t uintmax_t; #define INT_FAST8_MIN INT8_MIN #define INT_FAST16_MIN INTPTR_MIN #define INT_FAST32_MIN INTPTR_MIN -#define INT_FAST64_MIN INTPTR_MIN +#define INT_FAST64_MIN INT64_MIN #define INT_FAST8_MAX INT8_MAX #define INT_FAST16_MAX INTPTR_MAX #define INT_FAST32_MAX INTPTR_MAX -#define INT_FAST64_MAX INTPTR_MAX +#define INT_FAST64_MAX INT64_MAX #define UINT_FAST8_MAX UINT8_MAX #define UINT_FAST16_MAX SIZE_MAX #define UINT_FAST32_MAX SIZE_MAX -#define UINT_FAST64_MAX SIZE_MAX +#define UINT_FAST64_MAX UINT64_MAX #endif /* _NOLIBC_STDINT_H */ diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index fa18e7dc35c8..bfcbc05e6b5b 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -702,9 +702,9 @@ int run_stdlib(int min, int max) CASE_TEST(limit_int_fast32_min); EXPECT_EQ(1, INT_FAST32_MIN, (int_fast32_t) INTPTR_MIN); break; CASE_TEST(limit_int_fast32_max); EXPECT_EQ(1, INT_FAST32_MAX, (int_fast32_t) INTPTR_MAX); break; CASE_TEST(limit_uint_fast32_max); EXPECT_EQ(1, UINT_FAST32_MAX, (uint_fast32_t) UINTPTR_MAX); break; - CASE_TEST(limit_int_fast64_min); EXPECT_EQ(1, INT_FAST64_MIN, (int_fast64_t) INTPTR_MIN); break; - CASE_TEST(limit_int_fast64_max); EXPECT_EQ(1, INT_FAST64_MAX, (int_fast64_t) INTPTR_MAX); break; - CASE_TEST(limit_uint_fast64_max); EXPECT_EQ(1, UINT_FAST64_MAX, (uint_fast64_t) UINTPTR_MAX); break; + CASE_TEST(limit_int_fast64_min); EXPECT_EQ(1, INT_FAST64_MIN, (int_fast64_t) INT64_MIN); break; + CASE_TEST(limit_int_fast64_max); EXPECT_EQ(1, INT_FAST64_MAX, (int_fast64_t) INT64_MAX); break; + CASE_TEST(limit_uint_fast64_max); EXPECT_EQ(1, UINT_FAST64_MAX, (uint_fast64_t) UINT64_MAX); break; #if __SIZEOF_LONG__ == 8 CASE_TEST(limit_intptr_min); EXPECT_EQ(1, INTPTR_MIN, (intptr_t) 0x8000000000000000LL); break; CASE_TEST(limit_intptr_max); EXPECT_EQ(1, INTPTR_MAX, (intptr_t) 0x7fffffffffffffffLL); break; -- cgit v1.2.3 From a4c65af1511c8cf14ada10a957250c5051b8ccac Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Tue, 30 May 2023 15:48:48 +0200 Subject: selftests/nolibc: remove test gettimeofday_null MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gettimeofday() is not guaranteed by posix to handle a NULL value as first argument gracefully. On glibc for example it crashes. (When not going through the vdso) Link: https://lore.kernel.org/lkml/96f1134d-ce6e-4d82-ae00-1cd4038809c4@t-8ch.de/ Signed-off-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/nolibc-test.c | 1 - 1 file changed, 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index bfcbc05e6b5b..cfc7b270c397 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -589,7 +589,6 @@ int run_syscall(int min, int max) CASE_TEST(fork); EXPECT_SYSZR(1, test_fork()); break; CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break; CASE_TEST(getdents64_null); EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break; - CASE_TEST(gettimeofday_null); EXPECT_SYSZR(1, gettimeofday(NULL, NULL)); break; #ifdef NOLIBC CASE_TEST(gettimeofday_bad1); EXPECT_SYSER(1, gettimeofday((void *)1, NULL), -1, EFAULT); break; CASE_TEST(gettimeofday_bad2); EXPECT_SYSER(1, gettimeofday(NULL, (void *)1), -1, EFAULT); break; -- cgit v1.2.3 From c88e46d6d63b789bb2d5050e62ec0a0a477d4dfb Mon Sep 17 00:00:00 2001 From: Zhangjin Wu Date: Sat, 3 Jun 2023 16:04:10 +0800 Subject: selftests/nolibc: allow specify extra arguments for qemu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The opensbi package from Ubuntu 20.04 only provides rv64 firmwares: $ dpkg -S opensbi | grep -E "fw_.*bin|fw_.*elf" | uniq opensbi: /usr/lib/riscv64-linux-gnu/opensbi/generic/fw_dynamic.bin opensbi: /usr/lib/riscv64-linux-gnu/opensbi/generic/fw_jump.bin opensbi: /usr/lib/riscv64-linux-gnu/opensbi/generic/fw_dynamic.elf opensbi: /usr/lib/riscv64-linux-gnu/opensbi/generic/fw_jump.elf To run this nolibc test for rv32, users must build opensbi or download a prebuilt one from qemu repository: https://gitlab.com/qemu-project/qemu/-/blob/master/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin And then use -bios to tell qemu use it to avoid such failure: $ qemu-system-riscv32 -display none -no-reboot -kernel /path/to/arch/riscv/boot/Image -serial stdio -M virt -append "console=ttyS0 panic=-1" qemu-system-riscv32: Unable to load the RISC-V firmware "opensbi-riscv32-generic-fw_dynamic.bin" To run from makefile, QEMU_ARGS_EXTRA is added to allow pass extra arguments like -bios: $ make run QEMU_ARGS_EXTRA="-bios /path/to/opensbi-riscv32-generic-fw_dynamic.bin" ... Suggested-by: Thomas Weißschuh Link: https://lore.kernel.org/linux-riscv/2ab94136-d341-4a26-964e-6d6c32e66c9b@t-8ch.de/ Signed-off-by: Zhangjin Wu Reviewed-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index 47c3c89092e4..44088535682e 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -64,7 +64,7 @@ QEMU_ARGS_mips = -M malta -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)" QEMU_ARGS_riscv = -M virt -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" QEMU_ARGS_s390 = -M s390-ccw-virtio -m 1G -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" QEMU_ARGS_loongarch = -M virt -append "console=ttyS0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)" -QEMU_ARGS = $(QEMU_ARGS_$(ARCH)) +QEMU_ARGS = $(QEMU_ARGS_$(ARCH)) $(QEMU_ARGS_EXTRA) # OUTPUT is only set when run from the main makefile, otherwise # it defaults to this nolibc directory. -- cgit v1.2.3 From 0858aec4359636e539c6f26a1f3c9a3eceb87494 Mon Sep 17 00:00:00 2001 From: Zhangjin Wu Date: Sat, 3 Jun 2023 16:05:30 +0800 Subject: selftests/nolibc: fix up compile warning with glibc on x86_64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compiling nolibc-test.c with gcc on x86_64 got such warning: tools/testing/selftests/nolibc/nolibc-test.c: In function ‘expect_eq’: tools/testing/selftests/nolibc/nolibc-test.c:177:24: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 2 has type ‘uint64_t’ {aka ‘long unsigned int’} [-Wformat=] 177 | llen += printf(" = %lld ", expr); | ~~~^ ~~~~ | | | | | uint64_t {aka long unsigned int} | long long int | %ld It because that glibc defines uint64_t as "unsigned long int" when word size (means sizeof(long)) is 64bit (see include/bits/types.h), but nolibc directly use the 64bit "unsigned long long" (see tools/include/nolibc/stdint.h), which is simpler, seems kernel uses it too (include/uapi/asm-generic/int-ll64.h). use a simple conversion to solve it. Suggested-by: Willy Tarreau Link: https://lore.kernel.org/linux-riscv/20230529130449.GA2813@1wt.eu/ Signed-off-by: Zhangjin Wu Reviewed-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/nolibc-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index cfc7b270c397..dcb0bd079d15 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -174,7 +174,7 @@ static int expect_eq(uint64_t expr, int llen, uint64_t val) { int ret = !(expr == val); - llen += printf(" = %lld ", expr); + llen += printf(" = %lld ", (long long)expr); pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n"); return ret; } -- cgit v1.2.3 From bd27fef32960f5c9da57a50d58aa9f0bf0a3ff54 Mon Sep 17 00:00:00 2001 From: Zhangjin Wu Date: Sat, 3 Jun 2023 16:06:57 +0800 Subject: selftests/nolibc: not include limits.h for nolibc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When compile nolibc-test.c with 2.31 glibc, we got such error: In file included from /usr/riscv64-linux-gnu/include/sys/cdefs.h:452, from /usr/riscv64-linux-gnu/include/features.h:461, from /usr/riscv64-linux-gnu/include/bits/libc-header-start.h:33, from /usr/riscv64-linux-gnu/include/limits.h:26, from /usr/lib/gcc-cross/riscv64-linux-gnu/9/include/limits.h:194, from /usr/lib/gcc-cross/riscv64-linux-gnu/9/include/syslimits.h:7, from /usr/lib/gcc-cross/riscv64-linux-gnu/9/include/limits.h:34, from /labs/linux-lab/src/linux-stable/tools/testing/selftests/nolibc/nolibc-test.c:6: /usr/riscv64-linux-gnu/include/bits/wordsize.h:28:3: error: #error "rv32i-based targets are not supported" 28 | # error "rv32i-based targets are not supported" Glibc (>= 2.33) commit 5b6113d62efa ("RISC-V: Support the 32-bit ABI implementation") fixed up above error. As suggested by Thomas, defining INT_MIN/INT_MAX for nolibc can remove the including of limits.h, and therefore no above error. of course, the other libcs still require limits.h, move it to the right place. The LONG_MIN/LONG_MAX are also defined too. Suggested-by: Thomas Weißschuh Link: https://lore.kernel.org/linux-riscv/09d60dc2-e298-4c22-8e2f-8375861bd9be@t-8ch.de/ Signed-off-by: Zhangjin Wu Reviewed-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/stdint.h | 14 ++++++++++++++ tools/testing/selftests/nolibc/nolibc-test.c | 4 +--- 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/include/nolibc/stdint.h b/tools/include/nolibc/stdint.h index 661d942862c0..4b282435a59a 100644 --- a/tools/include/nolibc/stdint.h +++ b/tools/include/nolibc/stdint.h @@ -96,4 +96,18 @@ typedef uint64_t uintmax_t; #define UINT_FAST32_MAX SIZE_MAX #define UINT_FAST64_MAX UINT64_MAX +#ifndef INT_MIN +#define INT_MIN (-__INT_MAX__ - 1) +#endif +#ifndef INT_MAX +#define INT_MAX __INT_MAX__ +#endif + +#ifndef LONG_MIN +#define LONG_MIN (-__LONG_MAX__ - 1) +#endif +#ifndef LONG_MAX +#define LONG_MAX __LONG_MAX__ +#endif + #endif /* _NOLIBC_STDINT_H */ diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index dcb0bd079d15..7d4b8d12050d 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -2,9 +2,6 @@ #define _GNU_SOURCE -/* platform-specific include files coming from the compiler */ -#include - /* libc-specific include files * The program may be built in 3 ways: * $(CC) -nostdlib -include /path/to/nolibc.h => NOLIBC already defined @@ -39,6 +36,7 @@ #include #include #include +#include #endif #endif -- cgit v1.2.3 From a36cfc5e483e7bf609b3d39d83150626d92355e0 Mon Sep 17 00:00:00 2001 From: Zhangjin Wu Date: Sat, 3 Jun 2023 16:08:12 +0800 Subject: selftests/nolibc: use INT_MAX instead of __INT_MAX__ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nolibc now has INT_MAX in stdint.h, so, don't mix INT_MAX and __INT_MAX__, unify them to INT_MAX. Signed-off-by: Zhangjin Wu Reviewed-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/nolibc-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 7d4b8d12050d..ff3da9539809 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -936,7 +936,7 @@ static const struct test test_names[] = { int main(int argc, char **argv, char **envp) { int min = 0; - int max = __INT_MAX__; + int max = INT_MAX; int ret = 0; int err; int idx; @@ -984,7 +984,7 @@ int main(int argc, char **argv, char **envp) * here, which defaults to the full range. */ do { - min = 0; max = __INT_MAX__; + min = 0; max = INT_MAX; value = colon; if (value && *value) { colon = strchr(value, ':'); -- cgit v1.2.3 From 75d75a7b2803173c376b01e1f992f6364a5fdb33 Mon Sep 17 00:00:00 2001 From: Zhangjin Wu Date: Sat, 3 Jun 2023 16:13:40 +0800 Subject: selftests/nolibc: support two errnos with EXPECT_SYSER2() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some functions may be implemented with different syscalls in different platforms, these syscalls may set different errnos for the same arguments, let's support such cases. Suggested-by: Willy Tarreau Link: https://lore.kernel.org/linux-riscv/20230528113325.GJ1956@1wt.eu/ Signed-off-by: Zhangjin Wu Reviewed-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/nolibc-test.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index ff3da9539809..7896bc3f609e 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -300,18 +300,24 @@ static int expect_sysne(int expr, int llen, int val) } +#define EXPECT_SYSER2(cond, expr, expret, experr1, experr2) \ + do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_syserr2(expr, expret, experr1, experr2, llen); } while (0) + #define EXPECT_SYSER(cond, expr, expret, experr) \ - do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_syserr(expr, expret, experr, llen); } while (0) + EXPECT_SYSER2(cond, expr, expret, experr, 0) -static int expect_syserr(int expr, int expret, int experr, int llen) +static int expect_syserr2(int expr, int expret, int experr1, int experr2, int llen) { int ret = 0; int _errno = errno; llen += printf(" = %d %s ", expr, errorname(_errno)); - if (expr != expret || _errno != experr) { + if (expr != expret || (_errno != experr1 && _errno != experr2)) { ret = 1; - llen += printf(" != (%d %s) ", expret, errorname(experr)); + if (experr2 == 0) + llen += printf(" != (%d %s) ", expret, errorname(experr1)); + else + llen += printf(" != (%d %s %s) ", expret, errorname(experr1), errorname(experr2)); llen += pad_spc(llen, 64, "[FAIL]\n"); } else { llen += pad_spc(llen, 64, " [OK]\n"); -- cgit v1.2.3 From 4cbab2eca009ca022ae17596b5f3d4024c52a65b Mon Sep 17 00:00:00 2001 From: Zhangjin Wu Date: Sat, 3 Jun 2023 16:14:55 +0800 Subject: selftests/nolibc: remove gettimeofday_bad1/2 completely MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the clock_gettime / clock_gettime64 syscalls based gettimeofday(), there is no way to let kernel space 'fixup' the invalid data pointer of 'struct timeval' and 'struct timezone' for us for we need to read timespec from kernel space and then convert to timeval in user-space ourselves and also we need to simply ignore and reset timezone in user-space. Without this removal, the invalid (void *)1 address will trigger a sigsegv (signum = 11) signal and stop the whole test. Suggested-by: Willy Tarreau Link: https://lore.kernel.org/linux-riscv/20230528113325.GJ1956@1wt.eu/ Signed-off-by: Zhangjin Wu Reviewed-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/nolibc-test.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 7896bc3f609e..b1f3ad25de35 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -593,10 +593,6 @@ int run_syscall(int min, int max) CASE_TEST(fork); EXPECT_SYSZR(1, test_fork()); break; CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break; CASE_TEST(getdents64_null); EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break; -#ifdef NOLIBC - CASE_TEST(gettimeofday_bad1); EXPECT_SYSER(1, gettimeofday((void *)1, NULL), -1, EFAULT); break; - CASE_TEST(gettimeofday_bad2); EXPECT_SYSER(1, gettimeofday(NULL, (void *)1), -1, EFAULT); break; -#endif CASE_TEST(getpagesize); EXPECT_SYSZR(1, test_getpagesize()); break; CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break; CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break; -- cgit v1.2.3 From 957bfa31f1d93ba7ea9fda2a401b0f3c79129d5e Mon Sep 17 00:00:00 2001 From: Zhangjin Wu Date: Sat, 3 Jun 2023 16:16:07 +0800 Subject: selftests/nolibc: add new gettimeofday test cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These 2 test cases are added to cover the normal using scenes of gettimeofday(). They have been used to trigger and fix up such issue with nolibc: nolibc-test.c:(.text.gettimeofday+0x54): undefined reference to `__aeabi_ldivmod' This issue happens while there is no "unsigned int" conversion in the coming new clock_gettime / clock_gettime64 syscall path of gettimeofday(): tv->tv_usec = ts.tv_nsec / 1000; Suggested-by: Thomas Weißschuh Link: https://lore.kernel.org/linux-riscv/280867a8-7601-4a96-9b85-87668e1f1282@t-8ch.de/ Signed-off-by: Zhangjin Wu Reviewed-by: Thomas Weißschuh Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/nolibc-test.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index b1f3ad25de35..486334981e60 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -539,6 +539,8 @@ static int test_stat_timestamps(void) */ int run_syscall(int min, int max) { + struct timeval tv; + struct timezone tz; struct stat stat_buf; int euid0; int proc; @@ -593,6 +595,8 @@ int run_syscall(int min, int max) CASE_TEST(fork); EXPECT_SYSZR(1, test_fork()); break; CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break; CASE_TEST(getdents64_null); EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break; + CASE_TEST(gettimeofday_tv); EXPECT_SYSZR(1, gettimeofday(&tv, NULL)); break; + CASE_TEST(gettimeofday_tv_tz);EXPECT_SYSZR(1, gettimeofday(&tv, &tz)); break; CASE_TEST(getpagesize); EXPECT_SYSZR(1, test_getpagesize()); break; CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break; CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break; -- cgit v1.2.3 From fa0df56a804b9b1df6caea7f178771665e46d218 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 4 Jun 2023 14:14:27 +0200 Subject: selftests/nolibc: also count skipped and failed tests in output Right now skipped and failed test counts are not reported, and a few times already we missed skipped ones that ought not to. Let's now count each category and continue to invite the user to check the report file when skipped+fail > 0. E.g: $ make run-user (...) CC nolibc-test 136 test(s) passed, 2 skipped, 0 failed. See all results in .../run.out Note that it's important to be careful about the trailing \r on the qemu output (thanks Zhangjin for noticing). Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/Makefile | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index 44088535682e..4a3a105e1fdf 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -130,7 +130,10 @@ libc-test: nolibc-test.c # qemu user-land test run-user: nolibc-test $(Q)qemu-$(QEMU_ARCH) ./nolibc-test > "$(CURDIR)/run.out" || : - $(Q)grep -w FAIL "$(CURDIR)/run.out" && echo "See all results in $(CURDIR)/run.out" || echo "$$(grep -c ^[0-9].*OK $(CURDIR)/run.out) test(s) passed." + $(Q)awk '/\[OK\][\r]*$$/{p++} /\[FAIL\][\r]*$$/{f++} /\[SKIPPED\][\r]*$$/{s++} \ + END{ printf("%d test(s) passed, %d skipped, %d failed.", p, s, f); \ + if (s+f > 0) printf(" See all results in %s\n", ARGV[1]); else print; }' \ + $(CURDIR)/run.out initramfs: nolibc-test $(QUIET_MKDIR)mkdir -p initramfs @@ -146,12 +149,18 @@ kernel: initramfs # run the tests after building the kernel run: kernel $(Q)qemu-system-$(QEMU_ARCH) -display none -no-reboot -kernel "$(srctree)/$(IMAGE)" -serial stdio $(QEMU_ARGS) > "$(CURDIR)/run.out" - $(Q)grep -w FAIL "$(CURDIR)/run.out" && echo "See all results in $(CURDIR)/run.out" || echo "$$(grep -c ^[0-9].*OK $(CURDIR)/run.out) test(s) passed." + $(Q)awk '/\[OK\][\r]*$$/{p++} /\[FAIL\][\r]*$$/{f++} /\[SKIPPED\][\r]*$$/{s++} \ + END{ printf("%d test(s) passed, %d skipped, %d failed.", p, s, f); \ + if (s+f > 0) printf(" See all results in %s\n", ARGV[1]); else print; }' \ + $(CURDIR)/run.out # re-run the tests from an existing kernel rerun: $(Q)qemu-system-$(QEMU_ARCH) -display none -no-reboot -kernel "$(srctree)/$(IMAGE)" -serial stdio $(QEMU_ARGS) > "$(CURDIR)/run.out" - $(Q)grep -w FAIL "$(CURDIR)/run.out" && echo "See all results in $(CURDIR)/run.out" || echo "$$(grep -c ^[0-9].*OK $(CURDIR)/run.out) test(s) passed." + $(Q)awk '/\[OK\][\r]*$$/{p++} /\[FAIL\][\r]*$$/{f++} /\[SKIPPED\][\r]*$$/{s++} \ + END{ printf("%d test(s) passed, %d skipped, %d failed.", p, s, f); \ + if (s+f > 0) printf(" See all results in %s\n", ARGV[1]); else print; }' \ + $(CURDIR)/run.out clean: $(call QUIET_CLEAN, sysroot) -- cgit v1.2.3 From dd58d666ac08eb5eb81e4956172fc52b3bf0ab38 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Wed, 7 Jun 2023 22:28:58 +0200 Subject: selftests/nolibc: make sure gcc always use little endian on MIPS The test on MIPS stopped working after I upgraded some of my toolchains to use the ones from kernel.org because the mips toolchain defaults to big endian, even though it supports both endians. Let's just add an explicit -EL to make sure it always succeeds like the kernel does. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/nolibc/Makefile | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index 4a3a105e1fdf..1b7b3c82f8ad 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -77,6 +77,7 @@ Q=@ endif CFLAGS_s390 = -m64 +CFLAGS_mips = -EL CFLAGS_STACKPROTECTOR ?= $(call cc-option,-mstack-protector-guard=global $(call cc-option,-fstack-protector-all)) CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 \ $(call cc-option,-fno-stack-protector) \ -- cgit v1.2.3 From 88537aac0b3840314d3a5cc401a7fc400c069bc9 Mon Sep 17 00:00:00 2001 From: Nhat Pham Date: Tue, 2 May 2023 18:36:08 -0700 Subject: selftests: add selftests for cachestat Test cachestat on a newly created file, /dev/ files, /proc/ files and a directory. Also test on a shmem file (which can also be tested with huge pages since tmpfs supports huge pages). [colin.i.king@gmail.com: fix spelling mistake "trucate" -> "truncate"] Link: https://lkml.kernel.org/r/20230505110855.2493457-1-colin.i.king@gmail.com [mpe@ellerman.id.au: avoid excessive stack allocation] Link: https://lkml.kernel.org/r/877ctfa6yv.fsf@mail.lhotse Link: https://lkml.kernel.org/r/20230503013608.2431726-4-nphamcs@gmail.com Signed-off-by: Nhat Pham Signed-off-by: Colin Ian King Signed-off-by: Michael Ellerman Acked-by: Johannes Weiner Cc: Brian Foster Cc: Matthew Wilcox (Oracle) Cc: Michael Kerrisk Cc: Colin Ian King Cc: Michael Ellerman Signed-off-by: Andrew Morton --- MAINTAINERS | 7 + tools/testing/selftests/Makefile | 1 + tools/testing/selftests/cachestat/.gitignore | 2 + tools/testing/selftests/cachestat/Makefile | 8 + tools/testing/selftests/cachestat/test_cachestat.c | 269 +++++++++++++++++++++ 5 files changed, 287 insertions(+) create mode 100644 tools/testing/selftests/cachestat/.gitignore create mode 100644 tools/testing/selftests/cachestat/Makefile create mode 100644 tools/testing/selftests/cachestat/test_cachestat.c (limited to 'tools/testing') diff --git a/MAINTAINERS b/MAINTAINERS index 250518fc70ff..ce5f343c1443 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4486,6 +4486,13 @@ S: Supported F: Documentation/filesystems/caching/cachefiles.rst F: fs/cachefiles/ +CACHESTAT: PAGE CACHE STATS FOR A FILE +M: Nhat Pham +M: Johannes Weiner +L: linux-mm@kvack.org +S: Maintained +F: tools/testing/selftests/cachestat/test_cachestat.c + CADENCE MIPI-CSI2 BRIDGES M: Maxime Ripard L: linux-media@vger.kernel.org diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 90a62cf75008..5d6fc3f39284 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -4,6 +4,7 @@ TARGETS += amd-pstate TARGETS += arm64 TARGETS += bpf TARGETS += breakpoints +TARGETS += cachestat TARGETS += capabilities TARGETS += cgroup TARGETS += clone3 diff --git a/tools/testing/selftests/cachestat/.gitignore b/tools/testing/selftests/cachestat/.gitignore new file mode 100644 index 000000000000..d6c30b43a4bb --- /dev/null +++ b/tools/testing/selftests/cachestat/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +test_cachestat diff --git a/tools/testing/selftests/cachestat/Makefile b/tools/testing/selftests/cachestat/Makefile new file mode 100644 index 000000000000..fca73aaa7d14 --- /dev/null +++ b/tools/testing/selftests/cachestat/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +TEST_GEN_PROGS := test_cachestat + +CFLAGS += $(KHDR_INCLUDES) +CFLAGS += -Wall +CFLAGS += -lrt + +include ../lib.mk diff --git a/tools/testing/selftests/cachestat/test_cachestat.c b/tools/testing/selftests/cachestat/test_cachestat.c new file mode 100644 index 000000000000..54d09b820ed4 --- /dev/null +++ b/tools/testing/selftests/cachestat/test_cachestat.c @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../kselftest.h" + +static const char * const dev_files[] = { + "/dev/zero", "/dev/null", "/dev/urandom", + "/proc/version", "/proc" +}; +static const int cachestat_nr = 451; + +void print_cachestat(struct cachestat *cs) +{ + ksft_print_msg( + "Using cachestat: Cached: %lu, Dirty: %lu, Writeback: %lu, Evicted: %lu, Recently Evicted: %lu\n", + cs->nr_cache, cs->nr_dirty, cs->nr_writeback, + cs->nr_evicted, cs->nr_recently_evicted); +} + +bool write_exactly(int fd, size_t filesize) +{ + int random_fd = open("/dev/urandom", O_RDONLY); + char *cursor, *data; + int remained; + bool ret; + + if (random_fd < 0) { + ksft_print_msg("Unable to access urandom.\n"); + ret = false; + goto out; + } + + data = malloc(filesize); + if (!data) { + ksft_print_msg("Unable to allocate data.\n"); + ret = false; + goto close_random_fd; + } + + remained = filesize; + cursor = data; + + while (remained) { + ssize_t read_len = read(random_fd, cursor, remained); + + if (read_len <= 0) { + ksft_print_msg("Unable to read from urandom.\n"); + ret = false; + goto out_free_data; + } + + remained -= read_len; + cursor += read_len; + } + + /* write random data to fd */ + remained = filesize; + cursor = data; + while (remained) { + ssize_t write_len = write(fd, cursor, remained); + + if (write_len <= 0) { + ksft_print_msg("Unable write random data to file.\n"); + ret = false; + goto out_free_data; + } + + remained -= write_len; + cursor += write_len; + } + + ret = true; +out_free_data: + free(data); +close_random_fd: + close(random_fd); +out: + return ret; +} + +/* + * Open/create the file at filename, (optionally) write random data to it + * (exactly num_pages), then test the cachestat syscall on this file. + * + * If test_fsync == true, fsync the file, then check the number of dirty + * pages. + */ +bool test_cachestat(const char *filename, bool write_random, bool create, + bool test_fsync, unsigned long num_pages, int open_flags, + mode_t open_mode) +{ + size_t PS = sysconf(_SC_PAGESIZE); + int filesize = num_pages * PS; + bool ret = true; + long syscall_ret; + struct cachestat cs; + struct cachestat_range cs_range = { 0, filesize }; + + int fd = open(filename, open_flags, open_mode); + + if (fd == -1) { + ksft_print_msg("Unable to create/open file.\n"); + ret = false; + goto out; + } else { + ksft_print_msg("Create/open %s\n", filename); + } + + if (write_random) { + if (!write_exactly(fd, filesize)) { + ksft_print_msg("Unable to access urandom.\n"); + ret = false; + goto out1; + } + } + + syscall_ret = syscall(cachestat_nr, fd, &cs_range, &cs, 0); + + ksft_print_msg("Cachestat call returned %ld\n", syscall_ret); + + if (syscall_ret) { + ksft_print_msg("Cachestat returned non-zero.\n"); + ret = false; + goto out1; + + } else { + print_cachestat(&cs); + + if (write_random) { + if (cs.nr_cache + cs.nr_evicted != num_pages) { + ksft_print_msg( + "Total number of cached and evicted pages is off.\n"); + ret = false; + } + } + } + + if (test_fsync) { + if (fsync(fd)) { + ksft_print_msg("fsync fails.\n"); + ret = false; + } else { + syscall_ret = syscall(cachestat_nr, fd, &cs_range, &cs, 0); + + ksft_print_msg("Cachestat call (after fsync) returned %ld\n", + syscall_ret); + + if (!syscall_ret) { + print_cachestat(&cs); + + if (cs.nr_dirty) { + ret = false; + ksft_print_msg( + "Number of dirty should be zero after fsync.\n"); + } + } else { + ksft_print_msg("Cachestat (after fsync) returned non-zero.\n"); + ret = false; + goto out1; + } + } + } + +out1: + close(fd); + + if (create) + remove(filename); +out: + return ret; +} + +bool test_cachestat_shmem(void) +{ + size_t PS = sysconf(_SC_PAGESIZE); + size_t filesize = PS * 512 * 2; /* 2 2MB huge pages */ + int syscall_ret; + size_t compute_len = PS * 512; + struct cachestat_range cs_range = { PS, compute_len }; + char *filename = "tmpshmcstat"; + struct cachestat cs; + bool ret = true; + unsigned long num_pages = compute_len / PS; + int fd = shm_open(filename, O_CREAT | O_RDWR, 0600); + + if (fd < 0) { + ksft_print_msg("Unable to create shmem file.\n"); + ret = false; + goto out; + } + + if (ftruncate(fd, filesize)) { + ksft_print_msg("Unable to truncate shmem file.\n"); + ret = false; + goto close_fd; + } + + if (!write_exactly(fd, filesize)) { + ksft_print_msg("Unable to write to shmem file.\n"); + ret = false; + goto close_fd; + } + + syscall_ret = syscall(cachestat_nr, fd, &cs_range, &cs, 0); + + if (syscall_ret) { + ksft_print_msg("Cachestat returned non-zero.\n"); + ret = false; + goto close_fd; + } else { + print_cachestat(&cs); + if (cs.nr_cache + cs.nr_evicted != num_pages) { + ksft_print_msg( + "Total number of cached and evicted pages is off.\n"); + ret = false; + } + } + +close_fd: + shm_unlink(filename); +out: + return ret; +} + +int main(void) +{ + int ret = 0; + + for (int i = 0; i < 5; i++) { + const char *dev_filename = dev_files[i]; + + if (test_cachestat(dev_filename, false, false, false, + 4, O_RDONLY, 0400)) + ksft_test_result_pass("cachestat works with %s\n", dev_filename); + else { + ksft_test_result_fail("cachestat fails with %s\n", dev_filename); + ret = 1; + } + } + + if (test_cachestat("tmpfilecachestat", true, true, + true, 4, O_CREAT | O_RDWR, 0400 | 0600)) + ksft_test_result_pass("cachestat works with a normal file\n"); + else { + ksft_test_result_fail("cachestat fails with normal file\n"); + ret = 1; + } + + if (test_cachestat_shmem()) + ksft_test_result_pass("cachestat works with a shmem file\n"); + else { + ksft_test_result_fail("cachestat fails with a shmem file\n"); + ret = 1; + } + + return ret; +} -- cgit v1.2.3 From 633769c9267fadadffd31e27655bf028538238ad Mon Sep 17 00:00:00 2001 From: "Liam R. Howlett" Date: Thu, 18 May 2023 10:55:12 -0400 Subject: maple_tree: avoid unnecessary ascending The maple tree node limits are implied by the parent. When walking up the tree, the limit may not be known until a slot that does not have implied limits are encountered. However, if the node is the left-most or right-most node, the walking up to find that limit can be skipped. This commit also fixes the debug/testing code that was not setting the limit on walking down the tree as that optimization is not compatible with this change. Link: https://lkml.kernel.org/r/20230518145544.1722059-4-Liam.Howlett@oracle.com Signed-off-by: Liam R. Howlett Reviewed-by: Peng Zhang Cc: David Binderman Cc: Sergey Senozhatsky Cc: Vernon Yang Cc: Wei Yang Signed-off-by: Andrew Morton --- lib/maple_tree.c | 11 ++++++++--- tools/testing/radix-tree/maple.c | 4 ++++ 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/lib/maple_tree.c b/lib/maple_tree.c index 0471215e5761..ccd834d624ed 100644 --- a/lib/maple_tree.c +++ b/lib/maple_tree.c @@ -1103,7 +1103,6 @@ static int mas_ascend(struct ma_state *mas) enum maple_type a_type; unsigned long min, max; unsigned long *pivots; - unsigned char offset; bool set_max = false, set_min = false; a_node = mas_mn(mas); @@ -1115,8 +1114,9 @@ static int mas_ascend(struct ma_state *mas) p_node = mte_parent(mas->node); if (unlikely(a_node == p_node)) return 1; + a_type = mas_parent_type(mas, mas->node); - offset = mte_parent_slot(mas->node); + mas->offset = mte_parent_slot(mas->node); a_enode = mt_mk_node(p_node, a_type); /* Check to make sure all parent information is still accurate */ @@ -1124,7 +1124,6 @@ static int mas_ascend(struct ma_state *mas) return 1; mas->node = a_enode; - mas->offset = offset; if (mte_is_root(a_enode)) { mas->max = ULONG_MAX; @@ -1132,6 +1131,12 @@ static int mas_ascend(struct ma_state *mas) return 0; } + if (!mas->min) + set_min = true; + + if (mas->max == ULONG_MAX) + set_max = true; + min = 0; max = ULONG_MAX; do { diff --git a/tools/testing/radix-tree/maple.c b/tools/testing/radix-tree/maple.c index 9286d3baa12d..75df543e019c 100644 --- a/tools/testing/radix-tree/maple.c +++ b/tools/testing/radix-tree/maple.c @@ -35259,6 +35259,7 @@ static void mas_dfs_preorder(struct ma_state *mas) struct maple_enode *prev; unsigned char end, slot = 0; + unsigned long *pivots; if (mas->node == MAS_START) { mas_start(mas); @@ -35291,6 +35292,9 @@ walk_up: mas_ascend(mas); goto walk_up; } + pivots = ma_pivots(mte_to_node(prev), mte_node_type(prev)); + mas->max = mas_safe_pivot(mas, pivots, slot, mte_node_type(prev)); + mas->min = mas_safe_min(mas, pivots, slot); return; done: -- cgit v1.2.3 From 89f499f35c11af61ba7075ddc23209d10805a25a Mon Sep 17 00:00:00 2001 From: "Liam R. Howlett" Date: Thu, 18 May 2023 10:55:14 -0400 Subject: maple_tree: add format option to mt_dump() Allow different formatting strings to be used when dumping the tree. Currently supports hex and decimal. Link: https://lkml.kernel.org/r/20230518145544.1722059-6-Liam.Howlett@oracle.com Signed-off-by: Liam R. Howlett Cc: David Binderman Cc: Peng Zhang Cc: Sergey Senozhatsky Cc: Vernon Yang Cc: Wei Yang Signed-off-by: Andrew Morton --- include/linux/maple_tree.h | 9 ++++- lib/maple_tree.c | 87 ++++++++++++++++++++++++++-------------- lib/test_maple_tree.c | 10 ++--- mm/internal.h | 4 +- mm/mmap.c | 8 ++-- tools/testing/radix-tree/maple.c | 12 +++--- 6 files changed, 82 insertions(+), 48 deletions(-) (limited to 'tools/testing') diff --git a/include/linux/maple_tree.h b/include/linux/maple_tree.h index 1fadb5f5978b..140fb271be4a 100644 --- a/include/linux/maple_tree.h +++ b/include/linux/maple_tree.h @@ -670,10 +670,15 @@ void *mt_next(struct maple_tree *mt, unsigned long index, unsigned long max); #ifdef CONFIG_DEBUG_MAPLE_TREE +enum mt_dump_format { + mt_dump_dec, + mt_dump_hex, +}; + extern atomic_t maple_tree_tests_run; extern atomic_t maple_tree_tests_passed; -void mt_dump(const struct maple_tree *mt); +void mt_dump(const struct maple_tree *mt, enum mt_dump_format format); void mt_validate(struct maple_tree *mt); void mt_cache_shrink(void); #define MT_BUG_ON(__tree, __x) do { \ @@ -681,7 +686,7 @@ void mt_cache_shrink(void); if (__x) { \ pr_info("BUG at %s:%d (%u)\n", \ __func__, __LINE__, __x); \ - mt_dump(__tree); \ + mt_dump(__tree, mt_dump_hex); \ pr_info("Pass: %u Run:%u\n", \ atomic_read(&maple_tree_tests_passed), \ atomic_read(&maple_tree_tests_run)); \ diff --git a/lib/maple_tree.c b/lib/maple_tree.c index e095e2c39a1b..dfa0271101d2 100644 --- a/lib/maple_tree.c +++ b/lib/maple_tree.c @@ -5694,7 +5694,7 @@ void *mas_store(struct ma_state *mas, void *entry) trace_ma_write(__func__, mas, 0, entry); #ifdef CONFIG_DEBUG_MAPLE_TREE if (mas->index > mas->last) - pr_err("Error %lu > %lu %p\n", mas->index, mas->last, entry); + pr_err("Error %lX > %lX %p\n", mas->index, mas->last, entry); MT_BUG_ON(mas->tree, mas->index > mas->last); if (mas->index > mas->last) { mas_set_err(mas, -EINVAL); @@ -6748,22 +6748,33 @@ static void mas_dfs_postorder(struct ma_state *mas, unsigned long max) /* Tree validations */ static void mt_dump_node(const struct maple_tree *mt, void *entry, - unsigned long min, unsigned long max, unsigned int depth); + unsigned long min, unsigned long max, unsigned int depth, + enum mt_dump_format format); static void mt_dump_range(unsigned long min, unsigned long max, - unsigned int depth) + unsigned int depth, enum mt_dump_format format) { static const char spaces[] = " "; - if (min == max) - pr_info("%.*s%lu: ", depth * 2, spaces, min); - else - pr_info("%.*s%lu-%lu: ", depth * 2, spaces, min, max); + switch(format) { + case mt_dump_hex: + if (min == max) + pr_info("%.*s%lx: ", depth * 2, spaces, min); + else + pr_info("%.*s%lx-%lx: ", depth * 2, spaces, min, max); + break; + default: + case mt_dump_dec: + if (min == max) + pr_info("%.*s%lu: ", depth * 2, spaces, min); + else + pr_info("%.*s%lu-%lu: ", depth * 2, spaces, min, max); + } } static void mt_dump_entry(void *entry, unsigned long min, unsigned long max, - unsigned int depth) + unsigned int depth, enum mt_dump_format format) { - mt_dump_range(min, max, depth); + mt_dump_range(min, max, depth, format); if (xa_is_value(entry)) pr_cont("value %ld (0x%lx) [%p]\n", xa_to_value(entry), @@ -6777,7 +6788,8 @@ static void mt_dump_entry(void *entry, unsigned long min, unsigned long max, } static void mt_dump_range64(const struct maple_tree *mt, void *entry, - unsigned long min, unsigned long max, unsigned int depth) + unsigned long min, unsigned long max, unsigned int depth, + enum mt_dump_format format) { struct maple_range_64 *node = &mte_to_node(entry)->mr64; bool leaf = mte_is_leaf(entry); @@ -6785,8 +6797,16 @@ static void mt_dump_range64(const struct maple_tree *mt, void *entry, int i; pr_cont(" contents: "); - for (i = 0; i < MAPLE_RANGE64_SLOTS - 1; i++) - pr_cont("%p %lu ", node->slot[i], node->pivot[i]); + for (i = 0; i < MAPLE_RANGE64_SLOTS - 1; i++) { + switch(format) { + case mt_dump_hex: + pr_cont("%p %lX ", node->slot[i], node->pivot[i]); + break; + default: + case mt_dump_dec: + pr_cont("%p %lu ", node->slot[i], node->pivot[i]); + } + } pr_cont("%p\n", node->slot[i]); for (i = 0; i < MAPLE_RANGE64_SLOTS; i++) { unsigned long last = max; @@ -6799,24 +6819,32 @@ static void mt_dump_range64(const struct maple_tree *mt, void *entry, break; if (leaf) mt_dump_entry(mt_slot(mt, node->slot, i), - first, last, depth + 1); + first, last, depth + 1, format); else if (node->slot[i]) mt_dump_node(mt, mt_slot(mt, node->slot, i), - first, last, depth + 1); + first, last, depth + 1, format); if (last == max) break; if (last > max) { - pr_err("node %p last (%lu) > max (%lu) at pivot %d!\n", + switch(format) { + case mt_dump_hex: + pr_err("node %p last (%lx) > max (%lx) at pivot %d!\n", node, last, max, i); - break; + break; + default: + case mt_dump_dec: + pr_err("node %p last (%lu) > max (%lu) at pivot %d!\n", + node, last, max, i); + } } first = last + 1; } } static void mt_dump_arange64(const struct maple_tree *mt, void *entry, - unsigned long min, unsigned long max, unsigned int depth) + unsigned long min, unsigned long max, unsigned int depth, + enum mt_dump_format format) { struct maple_arange_64 *node = &mte_to_node(entry)->ma64; bool leaf = mte_is_leaf(entry); @@ -6841,10 +6869,10 @@ static void mt_dump_arange64(const struct maple_tree *mt, void *entry, break; if (leaf) mt_dump_entry(mt_slot(mt, node->slot, i), - first, last, depth + 1); + first, last, depth + 1, format); else if (node->slot[i]) mt_dump_node(mt, mt_slot(mt, node->slot, i), - first, last, depth + 1); + first, last, depth + 1, format); if (last == max) break; @@ -6858,13 +6886,14 @@ static void mt_dump_arange64(const struct maple_tree *mt, void *entry, } static void mt_dump_node(const struct maple_tree *mt, void *entry, - unsigned long min, unsigned long max, unsigned int depth) + unsigned long min, unsigned long max, unsigned int depth, + enum mt_dump_format format) { struct maple_node *node = mte_to_node(entry); unsigned int type = mte_node_type(entry); unsigned int i; - mt_dump_range(min, max, depth); + mt_dump_range(min, max, depth, format); pr_cont("node %p depth %d type %d parent %p", node, depth, type, node ? node->parent : NULL); @@ -6875,15 +6904,15 @@ static void mt_dump_node(const struct maple_tree *mt, void *entry, if (min + i > max) pr_cont("OUT OF RANGE: "); mt_dump_entry(mt_slot(mt, node->slot, i), - min + i, min + i, depth); + min + i, min + i, depth, format); } break; case maple_leaf_64: case maple_range_64: - mt_dump_range64(mt, entry, min, max, depth); + mt_dump_range64(mt, entry, min, max, depth, format); break; case maple_arange_64: - mt_dump_arange64(mt, entry, min, max, depth); + mt_dump_arange64(mt, entry, min, max, depth, format); break; default: @@ -6891,16 +6920,16 @@ static void mt_dump_node(const struct maple_tree *mt, void *entry, } } -void mt_dump(const struct maple_tree *mt) +void mt_dump(const struct maple_tree *mt, enum mt_dump_format format) { void *entry = rcu_dereference_check(mt->ma_root, mt_locked(mt)); pr_info("maple_tree(%p) flags %X, height %u root %p\n", mt, mt->ma_flags, mt_height(mt), entry); if (!xa_is_node(entry)) - mt_dump_entry(entry, 0, 0, 0); + mt_dump_entry(entry, 0, 0, 0, format); else if (entry) - mt_dump_node(mt, entry, 0, mt_node_max(entry), 0); + mt_dump_node(mt, entry, 0, mt_node_max(entry), 0, format); } EXPORT_SYMBOL_GPL(mt_dump); @@ -6953,7 +6982,7 @@ static void mas_validate_gaps(struct ma_state *mas) mas_mn(mas), i, mas_get_slot(mas, i), gap, p_end, p_start); - mt_dump(mas->tree); + mt_dump(mas->tree, mt_dump_hex); MT_BUG_ON(mas->tree, gap != p_end - p_start + 1); @@ -6986,7 +7015,7 @@ counted: MT_BUG_ON(mas->tree, max_gap > mas->max); if (ma_gaps(p_mn, mas_parent_type(mas, mte))[p_slot] != max_gap) { pr_err("gap %p[%u] != %lu\n", p_mn, p_slot, max_gap); - mt_dump(mas->tree); + mt_dump(mas->tree, mt_dump_hex); } MT_BUG_ON(mas->tree, diff --git a/lib/test_maple_tree.c b/lib/test_maple_tree.c index f1db333270e9..d6929270dd36 100644 --- a/lib/test_maple_tree.c +++ b/lib/test_maple_tree.c @@ -219,7 +219,7 @@ static noinline void check_rev_seq(struct maple_tree *mt, unsigned long max, #ifndef __KERNEL__ if (verbose) { rcu_barrier(); - mt_dump(mt); + mt_dump(mt, mt_dump_dec); pr_info(" %s test of 0-%lu %luK in %d active (%d total)\n", __func__, max, mt_get_alloc_size()/1024, mt_nr_allocated(), mt_nr_tallocated()); @@ -248,7 +248,7 @@ static noinline void check_seq(struct maple_tree *mt, unsigned long max, #ifndef __KERNEL__ if (verbose) { rcu_barrier(); - mt_dump(mt); + mt_dump(mt, mt_dump_dec); pr_info(" seq test of 0-%lu %luK in %d active (%d total)\n", max, mt_get_alloc_size()/1024, mt_nr_allocated(), mt_nr_tallocated()); @@ -893,7 +893,7 @@ static noinline void check_alloc_range(struct maple_tree *mt) #if DEBUG_ALLOC_RANGE pr_debug("\tInsert %lu-%lu\n", range[i] >> 12, (range[i + 1] >> 12) - 1); - mt_dump(mt); + mt_dump(mt, mt_dump_hex); #endif check_insert_range(mt, range[i] >> 12, (range[i + 1] >> 12) - 1, xa_mk_value(range[i] >> 12), 0); @@ -934,7 +934,7 @@ static noinline void check_alloc_range(struct maple_tree *mt) xa_mk_value(req_range[i] >> 12)); /* pointer */ mt_validate(mt); #if DEBUG_ALLOC_RANGE - mt_dump(mt); + mt_dump(mt, mt_dump_hex); #endif } @@ -1572,7 +1572,7 @@ static noinline void check_node_overwrite(struct maple_tree *mt) mtree_test_store_range(mt, i*100, i*100 + 50, xa_mk_value(i*100)); mtree_test_store_range(mt, 319951, 367950, NULL); - /*mt_dump(mt); */ + /*mt_dump(mt, mt_dump_dec); */ mt_validate(mt); } diff --git a/mm/internal.h b/mm/internal.h index ec55da813c13..692498a84fde 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -1064,13 +1064,13 @@ static inline void vma_iter_store(struct vma_iterator *vmi, printk("%lu > %lu\n", vmi->mas.index, vma->vm_start); printk("store of vma %lu-%lu", vma->vm_start, vma->vm_end); printk("into slot %lu-%lu", vmi->mas.index, vmi->mas.last); - mt_dump(vmi->mas.tree); + mt_dump(vmi->mas.tree, mt_dump_hex); } if (WARN_ON(vmi->mas.node != MAS_START && vmi->mas.last < vma->vm_start)) { printk("%lu < %lu\n", vmi->mas.last, vma->vm_start); printk("store of vma %lu-%lu", vma->vm_start, vma->vm_end); printk("into slot %lu-%lu", vmi->mas.index, vmi->mas.last); - mt_dump(vmi->mas.tree); + mt_dump(vmi->mas.tree, mt_dump_hex); } #endif diff --git a/mm/mmap.c b/mm/mmap.c index 13678edaa22c..04bcf3b3c720 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -301,7 +301,7 @@ out: #if defined(CONFIG_DEBUG_VM_MAPLE_TREE) extern void mt_validate(struct maple_tree *mt); -extern void mt_dump(const struct maple_tree *mt); +extern void mt_dump(const struct maple_tree *mt, enum mt_dump_format fmt); /* Validate the maple tree */ static void validate_mm_mt(struct mm_struct *mm) @@ -323,18 +323,18 @@ static void validate_mm_mt(struct mm_struct *mm) pr_emerg("mt vma: %p %lu - %lu\n", vma_mt, vma_mt->vm_start, vma_mt->vm_end); - mt_dump(mas.tree); + mt_dump(mas.tree, mt_dump_hex); if (vma_mt->vm_end != mas.last + 1) { pr_err("vma: %p vma_mt %lu-%lu\tmt %lu-%lu\n", mm, vma_mt->vm_start, vma_mt->vm_end, mas.index, mas.last); - mt_dump(mas.tree); + mt_dump(mas.tree, mt_dump_hex); } VM_BUG_ON_MM(vma_mt->vm_end != mas.last + 1, mm); if (vma_mt->vm_start != mas.index) { pr_err("vma: %p vma_mt %p %lu - %lu doesn't match\n", mm, vma_mt, vma_mt->vm_start, vma_mt->vm_end); - mt_dump(mas.tree); + mt_dump(mas.tree, mt_dump_hex); } VM_BUG_ON_MM(vma_mt->vm_start != mas.index, mm); } diff --git a/tools/testing/radix-tree/maple.c b/tools/testing/radix-tree/maple.c index 75df543e019c..ebcb3faf85ea 100644 --- a/tools/testing/radix-tree/maple.c +++ b/tools/testing/radix-tree/maple.c @@ -1054,7 +1054,7 @@ static noinline void check_erase2_testset(struct maple_tree *mt, if (entry_count) MT_BUG_ON(mt, !mt_height(mt)); #if check_erase2_debug > 1 - mt_dump(mt); + mt_dump(mt, mt_dump_hex); #endif #if check_erase2_debug pr_err("Done\n"); @@ -1085,7 +1085,7 @@ static noinline void check_erase2_testset(struct maple_tree *mt, mas_for_each(&mas, foo, ULONG_MAX) { if (xa_is_zero(foo)) { if (addr == mas.index) { - mt_dump(mas.tree); + mt_dump(mas.tree, mt_dump_hex); pr_err("retry failed %lu - %lu\n", mas.index, mas.last); MT_BUG_ON(mt, 1); @@ -34513,7 +34513,7 @@ static void *rcu_reader_rev(void *ptr) if (mas.index != r_start) { alt = xa_mk_value(index + i * 2 + 1 + RCU_RANGE_COUNT); - mt_dump(test->mt); + mt_dump(test->mt, mt_dump_dec); printk("Error: %lu-%lu %p != %lu-%lu %p %p line %d i %d\n", mas.index, mas.last, entry, r_start, r_end, expected, alt, @@ -35784,10 +35784,10 @@ void farmer_tests(void) struct maple_node *node; DEFINE_MTREE(tree); - mt_dump(&tree); + mt_dump(&tree, mt_dump_dec); tree.ma_root = xa_mk_value(0); - mt_dump(&tree); + mt_dump(&tree, mt_dump_dec); node = mt_alloc_one(GFP_KERNEL); node->parent = (void *)((unsigned long)(&tree) | 1); @@ -35797,7 +35797,7 @@ void farmer_tests(void) node->mr64.pivot[1] = 1; node->mr64.pivot[2] = 0; tree.ma_root = mt_mk_node(node, maple_leaf_64); - mt_dump(&tree); + mt_dump(&tree, mt_dump_dec); node->parent = ma_parent_ptr(node); ma_free_rcu(node); -- cgit v1.2.3 From a5199577b1ddae696528d7e4e7a406d5a8f23a7b Mon Sep 17 00:00:00 2001 From: "Liam R. Howlett" Date: Thu, 18 May 2023 10:55:25 -0400 Subject: maple_tree: make test code work without debug enabled The test code is less useful without debug, but can still do general validations. Define mt_dump(), mas_dump() and mas_wr_dump() as a noop if debug is not enabled and document it in the test module information that more information can be obtained with another kernel config option. MT_BUG_ON() will report a failures without tree dumps, and the output will be less useful. Link: https://lkml.kernel.org/r/20230518145544.1722059-17-Liam.Howlett@oracle.com Signed-off-by: Liam R. Howlett Cc: David Binderman Cc: Peng Zhang Cc: Sergey Senozhatsky Cc: Vernon Yang Cc: Wei Yang Signed-off-by: Andrew Morton --- lib/Kconfig.debug | 10 +++++++--- lib/test_maple_tree.c | 27 ++++++++++++++++++++++++--- tools/testing/radix-tree/maple.c | 1 - 3 files changed, 31 insertions(+), 7 deletions(-) (limited to 'tools/testing') diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index ce51d4dc6803..f202648dead9 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2302,9 +2302,13 @@ config TEST_XARRAY tristate "Test the XArray code at runtime" config TEST_MAPLE_TREE - depends on DEBUG_KERNEL - select DEBUG_MAPLE_TREE - tristate "Test the Maple Tree code at runtime" + tristate "Test the Maple Tree code at runtime or module load" + help + Enable this option to test the maple tree code functions at boot, or + when the module is loaded. Enable "Debug Maple Trees" will enable + more verbose output on failures. + + If unsure, say N. config TEST_RHASHTABLE tristate "Perform selftest on resizable hash table" diff --git a/lib/test_maple_tree.c b/lib/test_maple_tree.c index d6929270dd36..93b40a78c4f5 100644 --- a/lib/test_maple_tree.c +++ b/lib/test_maple_tree.c @@ -11,12 +11,33 @@ #include #define MTREE_ALLOC_MAX 0x2000000000000Ul -#ifndef CONFIG_DEBUG_MAPLE_TREE -#define CONFIG_DEBUG_MAPLE_TREE -#endif #define CONFIG_MAPLE_SEARCH #define MAPLE_32BIT (MAPLE_NODE_SLOTS > 31) +#ifndef CONFIG_DEBUG_MAPLE_TREE +#define mt_dump(mt, fmt) do {} while (0) +#define mt_validate(mt) do {} while (0) +#define mt_cache_shrink() do {} while (0) +#define mas_dump(mas) do {} while (0) +#define mas_wr_dump(mas) do {} while (0) +atomic_t maple_tree_tests_run; +atomic_t maple_tree_tests_passed; +#undef MT_BUG_ON + +#define MT_BUG_ON(__tree, __x) do { \ + atomic_inc(&maple_tree_tests_run); \ + if (__x) { \ + pr_info("BUG at %s:%d (%u)\n", \ + __func__, __LINE__, __x); \ + pr_info("Pass: %u Run:%u\n", \ + atomic_read(&maple_tree_tests_passed), \ + atomic_read(&maple_tree_tests_run)); \ + } else { \ + atomic_inc(&maple_tree_tests_passed); \ + } \ +} while (0) +#endif + /* #define BENCH_SLOT_STORE */ /* #define BENCH_NODE_STORE */ /* #define BENCH_AWALK */ diff --git a/tools/testing/radix-tree/maple.c b/tools/testing/radix-tree/maple.c index ebcb3faf85ea..cf37ed9ab6c4 100644 --- a/tools/testing/radix-tree/maple.c +++ b/tools/testing/radix-tree/maple.c @@ -22,7 +22,6 @@ #define dump_stack() assert(0) #include "../../../lib/maple_tree.c" -#undef CONFIG_DEBUG_MAPLE_TREE #include "../../../lib/test_maple_tree.c" #define RCU_RANGE_COUNT 1000 -- cgit v1.2.3 From eaf9790d3bc6e157a2134c01c7d707a5a712fab1 Mon Sep 17 00:00:00 2001 From: "Liam R. Howlett" Date: Thu, 18 May 2023 10:55:28 -0400 Subject: maple_tree: add __init and __exit to test module The test functions are not needed after the module is removed, so mark them as such. Add __exit to the module removal function. Some other variables have been marked as const static as well. Link: https://lkml.kernel.org/r/20230518145544.1722059-20-Liam.Howlett@oracle.com Signed-off-by: Liam R. Howlett Suggested-by: Andrew Morton Cc: David Binderman Cc: Peng Zhang Cc: Sergey Senozhatsky Cc: Vernon Yang Cc: Wei Yang Signed-off-by: Andrew Morton --- lib/test_maple_tree.c | 158 +++++++++++++++++----------------- tools/testing/radix-tree/linux/init.h | 1 + tools/testing/radix-tree/maple.c | 147 +++++++++++++++---------------- 3 files changed, 155 insertions(+), 151 deletions(-) (limited to 'tools/testing') diff --git a/lib/test_maple_tree.c b/lib/test_maple_tree.c index 93b40a78c4f5..19b130c9ddde 100644 --- a/lib/test_maple_tree.c +++ b/lib/test_maple_tree.c @@ -51,54 +51,54 @@ atomic_t maple_tree_tests_passed; #else #define cond_resched() do {} while (0) #endif -static -int mtree_insert_index(struct maple_tree *mt, unsigned long index, gfp_t gfp) +static int __init mtree_insert_index(struct maple_tree *mt, + unsigned long index, gfp_t gfp) { return mtree_insert(mt, index, xa_mk_value(index & LONG_MAX), gfp); } -static void mtree_erase_index(struct maple_tree *mt, unsigned long index) +static void __init mtree_erase_index(struct maple_tree *mt, unsigned long index) { MT_BUG_ON(mt, mtree_erase(mt, index) != xa_mk_value(index & LONG_MAX)); MT_BUG_ON(mt, mtree_load(mt, index) != NULL); } -static int mtree_test_insert(struct maple_tree *mt, unsigned long index, +static int __init mtree_test_insert(struct maple_tree *mt, unsigned long index, void *ptr) { return mtree_insert(mt, index, ptr, GFP_KERNEL); } -static int mtree_test_store_range(struct maple_tree *mt, unsigned long start, - unsigned long end, void *ptr) +static int __init mtree_test_store_range(struct maple_tree *mt, + unsigned long start, unsigned long end, void *ptr) { return mtree_store_range(mt, start, end, ptr, GFP_KERNEL); } -static int mtree_test_store(struct maple_tree *mt, unsigned long start, +static int __init mtree_test_store(struct maple_tree *mt, unsigned long start, void *ptr) { return mtree_test_store_range(mt, start, start, ptr); } -static int mtree_test_insert_range(struct maple_tree *mt, unsigned long start, - unsigned long end, void *ptr) +static int __init mtree_test_insert_range(struct maple_tree *mt, + unsigned long start, unsigned long end, void *ptr) { return mtree_insert_range(mt, start, end, ptr, GFP_KERNEL); } -static void *mtree_test_load(struct maple_tree *mt, unsigned long index) +static void __init *mtree_test_load(struct maple_tree *mt, unsigned long index) { return mtree_load(mt, index); } -static void *mtree_test_erase(struct maple_tree *mt, unsigned long index) +static void __init *mtree_test_erase(struct maple_tree *mt, unsigned long index) { return mtree_erase(mt, index); } #if defined(CONFIG_64BIT) -static noinline void check_mtree_alloc_range(struct maple_tree *mt, +static noinline void __init check_mtree_alloc_range(struct maple_tree *mt, unsigned long start, unsigned long end, unsigned long size, unsigned long expected, int eret, void *ptr) { @@ -115,7 +115,7 @@ static noinline void check_mtree_alloc_range(struct maple_tree *mt, MT_BUG_ON(mt, result != expected); } -static noinline void check_mtree_alloc_rrange(struct maple_tree *mt, +static noinline void __init check_mtree_alloc_rrange(struct maple_tree *mt, unsigned long start, unsigned long end, unsigned long size, unsigned long expected, int eret, void *ptr) { @@ -133,8 +133,8 @@ static noinline void check_mtree_alloc_rrange(struct maple_tree *mt, } #endif -static noinline void check_load(struct maple_tree *mt, unsigned long index, - void *ptr) +static noinline void __init check_load(struct maple_tree *mt, + unsigned long index, void *ptr) { void *ret = mtree_test_load(mt, index); @@ -143,7 +143,7 @@ static noinline void check_load(struct maple_tree *mt, unsigned long index, MT_BUG_ON(mt, ret != ptr); } -static noinline void check_store_range(struct maple_tree *mt, +static noinline void __init check_store_range(struct maple_tree *mt, unsigned long start, unsigned long end, void *ptr, int expected) { int ret = -EINVAL; @@ -159,7 +159,7 @@ static noinline void check_store_range(struct maple_tree *mt, check_load(mt, i, ptr); } -static noinline void check_insert_range(struct maple_tree *mt, +static noinline void __init check_insert_range(struct maple_tree *mt, unsigned long start, unsigned long end, void *ptr, int expected) { int ret = -EINVAL; @@ -175,8 +175,8 @@ static noinline void check_insert_range(struct maple_tree *mt, check_load(mt, i, ptr); } -static noinline void check_insert(struct maple_tree *mt, unsigned long index, - void *ptr) +static noinline void __init check_insert(struct maple_tree *mt, + unsigned long index, void *ptr) { int ret = -EINVAL; @@ -184,7 +184,7 @@ static noinline void check_insert(struct maple_tree *mt, unsigned long index, MT_BUG_ON(mt, ret != 0); } -static noinline void check_dup_insert(struct maple_tree *mt, +static noinline void __init check_dup_insert(struct maple_tree *mt, unsigned long index, void *ptr) { int ret = -EINVAL; @@ -194,13 +194,13 @@ static noinline void check_dup_insert(struct maple_tree *mt, } -static noinline -void check_index_load(struct maple_tree *mt, unsigned long index) +static noinline void __init check_index_load(struct maple_tree *mt, + unsigned long index) { return check_load(mt, index, xa_mk_value(index & LONG_MAX)); } -static inline int not_empty(struct maple_node *node) +static inline __init int not_empty(struct maple_node *node) { int i; @@ -215,8 +215,8 @@ static inline int not_empty(struct maple_node *node) } -static noinline void check_rev_seq(struct maple_tree *mt, unsigned long max, - bool verbose) +static noinline void __init check_rev_seq(struct maple_tree *mt, + unsigned long max, bool verbose) { unsigned long i = max, j; @@ -248,7 +248,7 @@ static noinline void check_rev_seq(struct maple_tree *mt, unsigned long max, #endif } -static noinline void check_seq(struct maple_tree *mt, unsigned long max, +static noinline void __init check_seq(struct maple_tree *mt, unsigned long max, bool verbose) { unsigned long i, j; @@ -277,7 +277,7 @@ static noinline void check_seq(struct maple_tree *mt, unsigned long max, #endif } -static noinline void check_lb_not_empty(struct maple_tree *mt) +static noinline void __init check_lb_not_empty(struct maple_tree *mt) { unsigned long i, j; unsigned long huge = 4000UL * 1000 * 1000; @@ -296,13 +296,13 @@ static noinline void check_lb_not_empty(struct maple_tree *mt) mtree_destroy(mt); } -static noinline void check_lower_bound_split(struct maple_tree *mt) +static noinline void __init check_lower_bound_split(struct maple_tree *mt) { MT_BUG_ON(mt, !mtree_empty(mt)); check_lb_not_empty(mt); } -static noinline void check_upper_bound_split(struct maple_tree *mt) +static noinline void __init check_upper_bound_split(struct maple_tree *mt) { unsigned long i, j; unsigned long huge; @@ -327,7 +327,7 @@ static noinline void check_upper_bound_split(struct maple_tree *mt) mtree_destroy(mt); } -static noinline void check_mid_split(struct maple_tree *mt) +static noinline void __init check_mid_split(struct maple_tree *mt) { unsigned long huge = 8000UL * 1000 * 1000; @@ -336,7 +336,7 @@ static noinline void check_mid_split(struct maple_tree *mt) check_lb_not_empty(mt); } -static noinline void check_rev_find(struct maple_tree *mt) +static noinline void __init check_rev_find(struct maple_tree *mt) { int i, nr_entries = 200; void *val; @@ -375,7 +375,7 @@ static noinline void check_rev_find(struct maple_tree *mt) rcu_read_unlock(); } -static noinline void check_find(struct maple_tree *mt) +static noinline void __init check_find(struct maple_tree *mt) { unsigned long val = 0; unsigned long count; @@ -592,7 +592,7 @@ static noinline void check_find(struct maple_tree *mt) mtree_destroy(mt); } -static noinline void check_find_2(struct maple_tree *mt) +static noinline void __init check_find_2(struct maple_tree *mt) { unsigned long i, j; void *entry; @@ -637,7 +637,7 @@ static noinline void check_find_2(struct maple_tree *mt) #if defined(CONFIG_64BIT) -static noinline void check_alloc_rev_range(struct maple_tree *mt) +static noinline void __init check_alloc_rev_range(struct maple_tree *mt) { /* * Generated by: @@ -645,7 +645,7 @@ static noinline void check_alloc_rev_range(struct maple_tree *mt) * awk -F "-" '{printf "0x%s, 0x%s, ", $1, $2}' */ - unsigned long range[] = { + static const unsigned long range[] = { /* Inclusive , Exclusive. */ 0x565234af2000, 0x565234af4000, 0x565234af4000, 0x565234af9000, @@ -673,7 +673,7 @@ static noinline void check_alloc_rev_range(struct maple_tree *mt) 0x7fff58791000, 0x7fff58793000, }; - unsigned long holes[] = { + static const unsigned long holes[] = { /* * Note: start of hole is INCLUSIVE * end of hole is EXCLUSIVE @@ -693,7 +693,7 @@ static noinline void check_alloc_rev_range(struct maple_tree *mt) * 4. number that should be returned. * 5. return value */ - unsigned long req_range[] = { + static const unsigned long req_range[] = { 0x565234af9000, /* Min */ 0x7fff58791000, /* Max */ 0x1000, /* Size */ @@ -804,7 +804,7 @@ static noinline void check_alloc_rev_range(struct maple_tree *mt) mtree_destroy(mt); } -static noinline void check_alloc_range(struct maple_tree *mt) +static noinline void __init check_alloc_range(struct maple_tree *mt) { /* * Generated by: @@ -812,7 +812,7 @@ static noinline void check_alloc_range(struct maple_tree *mt) * awk -F "-" '{printf "0x%s, 0x%s, ", $1, $2}' */ - unsigned long range[] = { + static const unsigned long range[] = { /* Inclusive , Exclusive. */ 0x565234af2000, 0x565234af4000, 0x565234af4000, 0x565234af9000, @@ -839,7 +839,7 @@ static noinline void check_alloc_range(struct maple_tree *mt) 0x7fff5878e000, 0x7fff58791000, 0x7fff58791000, 0x7fff58793000, }; - unsigned long holes[] = { + static const unsigned long holes[] = { /* Start of hole, end of hole, size of hole (+1) */ 0x565234afb000, 0x565234afc000, 0x1000, 0x565234afe000, 0x565235def000, 0x12F1000, @@ -854,7 +854,7 @@ static noinline void check_alloc_range(struct maple_tree *mt) * 4. number that should be returned. * 5. return value */ - unsigned long req_range[] = { + static const unsigned long req_range[] = { 0x565234af9000, /* Min */ 0x7fff58791000, /* Max */ 0x1000, /* Size */ @@ -963,10 +963,10 @@ static noinline void check_alloc_range(struct maple_tree *mt) } #endif -static noinline void check_ranges(struct maple_tree *mt) +static noinline void __init check_ranges(struct maple_tree *mt) { int i, val, val2; - unsigned long r[] = { + static const unsigned long r[] = { 10, 15, 20, 25, 17, 22, /* Overlaps previous range. */ @@ -1231,7 +1231,7 @@ static noinline void check_ranges(struct maple_tree *mt) MT_BUG_ON(mt, mt_height(mt) != 4); } -static noinline void check_next_entry(struct maple_tree *mt) +static noinline void __init check_next_entry(struct maple_tree *mt) { void *entry = NULL; unsigned long limit = 30, i = 0; @@ -1255,7 +1255,7 @@ static noinline void check_next_entry(struct maple_tree *mt) mtree_destroy(mt); } -static noinline void check_prev_entry(struct maple_tree *mt) +static noinline void __init check_prev_entry(struct maple_tree *mt) { unsigned long index = 16; void *value; @@ -1299,7 +1299,7 @@ static noinline void check_prev_entry(struct maple_tree *mt) mas_unlock(&mas); } -static noinline void check_root_expand(struct maple_tree *mt) +static noinline void __init check_root_expand(struct maple_tree *mt) { MA_STATE(mas, mt, 0, 0); void *ptr; @@ -1388,13 +1388,13 @@ static noinline void check_root_expand(struct maple_tree *mt) mas_unlock(&mas); } -static noinline void check_gap_combining(struct maple_tree *mt) +static noinline void __init check_gap_combining(struct maple_tree *mt) { struct maple_enode *mn1, *mn2; void *entry; unsigned long singletons = 100; - unsigned long *seq100; - unsigned long seq100_64[] = { + static const unsigned long *seq100; + static const unsigned long seq100_64[] = { /* 0-5 */ 74, 75, 76, 50, 100, 2, @@ -1408,7 +1408,7 @@ static noinline void check_gap_combining(struct maple_tree *mt) 76, 2, 79, 85, 4, }; - unsigned long seq100_32[] = { + static const unsigned long seq100_32[] = { /* 0-5 */ 61, 62, 63, 50, 100, 2, @@ -1422,11 +1422,11 @@ static noinline void check_gap_combining(struct maple_tree *mt) 76, 2, 79, 85, 4, }; - unsigned long seq2000[] = { + static const unsigned long seq2000[] = { 1152, 1151, 1100, 1200, 2, }; - unsigned long seq400[] = { + static const unsigned long seq400[] = { 286, 318, 256, 260, 266, 270, 275, 280, 290, 398, 286, 310, @@ -1585,7 +1585,7 @@ static noinline void check_gap_combining(struct maple_tree *mt) mt_set_non_kernel(0); mtree_destroy(mt); } -static noinline void check_node_overwrite(struct maple_tree *mt) +static noinline void __init check_node_overwrite(struct maple_tree *mt) { int i, max = 4000; @@ -1598,7 +1598,7 @@ static noinline void check_node_overwrite(struct maple_tree *mt) } #if defined(BENCH_SLOT_STORE) -static noinline void bench_slot_store(struct maple_tree *mt) +static noinline void __init bench_slot_store(struct maple_tree *mt) { int i, brk = 105, max = 1040, brk_start = 100, count = 20000000; @@ -1614,7 +1614,7 @@ static noinline void bench_slot_store(struct maple_tree *mt) #endif #if defined(BENCH_NODE_STORE) -static noinline void bench_node_store(struct maple_tree *mt) +static noinline void __init bench_node_store(struct maple_tree *mt) { int i, overwrite = 76, max = 240, count = 20000000; @@ -1633,7 +1633,7 @@ static noinline void bench_node_store(struct maple_tree *mt) #endif #if defined(BENCH_AWALK) -static noinline void bench_awalk(struct maple_tree *mt) +static noinline void __init bench_awalk(struct maple_tree *mt) { int i, max = 2500, count = 50000000; MA_STATE(mas, mt, 1470, 1470); @@ -1650,7 +1650,7 @@ static noinline void bench_awalk(struct maple_tree *mt) } #endif #if defined(BENCH_WALK) -static noinline void bench_walk(struct maple_tree *mt) +static noinline void __init bench_walk(struct maple_tree *mt) { int i, max = 2500, count = 550000000; MA_STATE(mas, mt, 1470, 1470); @@ -1667,7 +1667,7 @@ static noinline void bench_walk(struct maple_tree *mt) #endif #if defined(BENCH_MT_FOR_EACH) -static noinline void bench_mt_for_each(struct maple_tree *mt) +static noinline void __init bench_mt_for_each(struct maple_tree *mt) { int i, count = 1000000; unsigned long max = 2500, index = 0; @@ -1691,7 +1691,7 @@ static noinline void bench_mt_for_each(struct maple_tree *mt) #endif /* check_forking - simulate the kernel forking sequence with the tree. */ -static noinline void check_forking(struct maple_tree *mt) +static noinline void __init check_forking(struct maple_tree *mt) { struct maple_tree newmt; @@ -1730,7 +1730,7 @@ static noinline void check_forking(struct maple_tree *mt) mtree_destroy(&newmt); } -static noinline void check_iteration(struct maple_tree *mt) +static noinline void __init check_iteration(struct maple_tree *mt) { int i, nr_entries = 125; void *val; @@ -1798,7 +1798,7 @@ static noinline void check_iteration(struct maple_tree *mt) mt_set_non_kernel(0); } -static noinline void check_mas_store_gfp(struct maple_tree *mt) +static noinline void __init check_mas_store_gfp(struct maple_tree *mt) { struct maple_tree newmt; @@ -1831,7 +1831,7 @@ static noinline void check_mas_store_gfp(struct maple_tree *mt) } #if defined(BENCH_FORK) -static noinline void bench_forking(struct maple_tree *mt) +static noinline void __init bench_forking(struct maple_tree *mt) { struct maple_tree newmt; @@ -1873,15 +1873,17 @@ static noinline void bench_forking(struct maple_tree *mt) } #endif -static noinline void next_prev_test(struct maple_tree *mt) +static noinline void __init next_prev_test(struct maple_tree *mt) { int i, nr_entries; void *val; MA_STATE(mas, mt, 0, 0); struct maple_enode *mn; - unsigned long *level2; - unsigned long level2_64[] = {707, 1000, 710, 715, 720, 725}; - unsigned long level2_32[] = {1747, 2000, 1750, 1755, 1760, 1765}; + static const unsigned long *level2; + static const unsigned long level2_64[] = { 707, 1000, 710, 715, 720, + 725}; + static const unsigned long level2_32[] = { 1747, 2000, 1750, 1755, + 1760, 1765}; if (MAPLE_32BIT) { nr_entries = 500; @@ -2049,7 +2051,7 @@ static noinline void next_prev_test(struct maple_tree *mt) /* Test spanning writes that require balancing right sibling or right cousin */ -static noinline void check_spanning_relatives(struct maple_tree *mt) +static noinline void __init check_spanning_relatives(struct maple_tree *mt) { unsigned long i, nr_entries = 1000; @@ -2062,7 +2064,7 @@ static noinline void check_spanning_relatives(struct maple_tree *mt) mtree_store_range(mt, 9365, 9955, NULL, GFP_KERNEL); } -static noinline void check_fuzzer(struct maple_tree *mt) +static noinline void __init check_fuzzer(struct maple_tree *mt) { /* * 1. Causes a spanning rebalance of a single root node. @@ -2459,7 +2461,7 @@ static noinline void check_fuzzer(struct maple_tree *mt) } /* duplicate the tree with a specific gap */ -static noinline void check_dup_gaps(struct maple_tree *mt, +static noinline void __init check_dup_gaps(struct maple_tree *mt, unsigned long nr_entries, bool zero_start, unsigned long gap) { @@ -2499,7 +2501,7 @@ static noinline void check_dup_gaps(struct maple_tree *mt, } /* Duplicate many sizes of trees. Mainly to test expected entry values */ -static noinline void check_dup(struct maple_tree *mt) +static noinline void __init check_dup(struct maple_tree *mt) { int i; int big_start = 100010; @@ -2587,7 +2589,7 @@ static noinline void check_dup(struct maple_tree *mt) } } -static noinline void check_bnode_min_spanning(struct maple_tree *mt) +static noinline void __init check_bnode_min_spanning(struct maple_tree *mt) { int i = 50; MA_STATE(mas, mt, 0, 0); @@ -2606,7 +2608,7 @@ static noinline void check_bnode_min_spanning(struct maple_tree *mt) mt_set_non_kernel(0); } -static noinline void check_empty_area_window(struct maple_tree *mt) +static noinline void __init check_empty_area_window(struct maple_tree *mt) { unsigned long i, nr_entries = 20; MA_STATE(mas, mt, 0, 0); @@ -2691,7 +2693,7 @@ static noinline void check_empty_area_window(struct maple_tree *mt) rcu_read_unlock(); } -static noinline void check_empty_area_fill(struct maple_tree *mt) +static noinline void __init check_empty_area_fill(struct maple_tree *mt) { const unsigned long max = 0x25D78000; unsigned long size; @@ -2735,11 +2737,11 @@ static noinline void check_empty_area_fill(struct maple_tree *mt) } static DEFINE_MTREE(tree); -static int maple_tree_seed(void) +static int __init maple_tree_seed(void) { - unsigned long set[] = {5015, 5014, 5017, 25, 1000, - 1001, 1002, 1003, 1005, 0, - 5003, 5002}; + unsigned long set[] = { 5015, 5014, 5017, 25, 1000, + 1001, 1002, 1003, 1005, 0, + 5003, 5002}; void *ptr = &set; pr_info("\nTEST STARTING\n\n"); @@ -3009,7 +3011,7 @@ skip: return -EINVAL; } -static void maple_tree_harvest(void) +static void __exit maple_tree_harvest(void) { } diff --git a/tools/testing/radix-tree/linux/init.h b/tools/testing/radix-tree/linux/init.h index 1bb0afc21309..81563c3dfce7 100644 --- a/tools/testing/radix-tree/linux/init.h +++ b/tools/testing/radix-tree/linux/init.h @@ -1 +1,2 @@ #define __init +#define __exit diff --git a/tools/testing/radix-tree/maple.c b/tools/testing/radix-tree/maple.c index cf37ed9ab6c4..03539d86cdf0 100644 --- a/tools/testing/radix-tree/maple.c +++ b/tools/testing/radix-tree/maple.c @@ -14,6 +14,7 @@ #include "test.h" #include #include +#include "linux/init.h" #define module_init(x) #define module_exit(x) @@ -80,7 +81,7 @@ static void check_mas_alloc_node_count(struct ma_state *mas) * check_new_node() - Check the creation of new nodes and error path * verification. */ -static noinline void check_new_node(struct maple_tree *mt) +static noinline void __init check_new_node(struct maple_tree *mt) { struct maple_node *mn, *mn2, *mn3; @@ -454,7 +455,7 @@ static noinline void check_new_node(struct maple_tree *mt) /* * Check erasing including RCU. */ -static noinline void check_erase(struct maple_tree *mt, unsigned long index, +static noinline void __init check_erase(struct maple_tree *mt, unsigned long index, void *ptr) { MT_BUG_ON(mt, mtree_test_erase(mt, index) != ptr); @@ -464,24 +465,24 @@ static noinline void check_erase(struct maple_tree *mt, unsigned long index, #define erase_check_insert(mt, i) check_insert(mt, set[i], entry[i%2]) #define erase_check_erase(mt, i) check_erase(mt, set[i], entry[i%2]) -static noinline void check_erase_testset(struct maple_tree *mt) +static noinline void __init check_erase_testset(struct maple_tree *mt) { - unsigned long set[] = { 5015, 5014, 5017, 25, 1000, - 1001, 1002, 1003, 1005, 0, - 6003, 6002, 6008, 6012, 6015, - 7003, 7002, 7008, 7012, 7015, - 8003, 8002, 8008, 8012, 8015, - 9003, 9002, 9008, 9012, 9015, - 10003, 10002, 10008, 10012, 10015, - 11003, 11002, 11008, 11012, 11015, - 12003, 12002, 12008, 12012, 12015, - 13003, 13002, 13008, 13012, 13015, - 14003, 14002, 14008, 14012, 14015, - 15003, 15002, 15008, 15012, 15015, - }; - - - void *ptr = &set; + static const unsigned long set[] = { 5015, 5014, 5017, 25, 1000, + 1001, 1002, 1003, 1005, 0, + 6003, 6002, 6008, 6012, 6015, + 7003, 7002, 7008, 7012, 7015, + 8003, 8002, 8008, 8012, 8015, + 9003, 9002, 9008, 9012, 9015, + 10003, 10002, 10008, 10012, 10015, + 11003, 11002, 11008, 11012, 11015, + 12003, 12002, 12008, 12012, 12015, + 13003, 13002, 13008, 13012, 13015, + 14003, 14002, 14008, 14012, 14015, + 15003, 15002, 15008, 15012, 15015, + }; + + + void *ptr = &check_erase_testset; void *entry[2] = { ptr, mt }; void *root_node; @@ -738,7 +739,7 @@ static noinline void check_erase_testset(struct maple_tree *mt) int mas_ce2_over_count(struct ma_state *mas_start, struct ma_state *mas_end, void *s_entry, unsigned long s_min, void *e_entry, unsigned long e_max, - unsigned long *set, int i, bool null_entry) + const unsigned long *set, int i, bool null_entry) { int count = 0, span = 0; unsigned long retry = 0; @@ -968,8 +969,8 @@ retry: } #if defined(CONFIG_64BIT) -static noinline void check_erase2_testset(struct maple_tree *mt, - unsigned long *set, unsigned long size) +static noinline void __init check_erase2_testset(struct maple_tree *mt, + const unsigned long *set, unsigned long size) { int entry_count = 0; int check = 0; @@ -1113,11 +1114,11 @@ static noinline void check_erase2_testset(struct maple_tree *mt, /* These tests were pulled from KVM tree modifications which failed. */ -static noinline void check_erase2_sets(struct maple_tree *mt) +static noinline void __init check_erase2_sets(struct maple_tree *mt) { void *entry; unsigned long start = 0; - unsigned long set[] = { + static const unsigned long set[] = { STORE, 140737488347136, 140737488351231, STORE, 140721266458624, 140737488351231, ERASE, 140721266458624, 140737488351231, @@ -1135,7 +1136,7 @@ ERASE, 140253902692352, 140253902864383, STORE, 140253902692352, 140253902696447, STORE, 140253902696448, 140253902864383, }; - unsigned long set2[] = { + static const unsigned long set2[] = { STORE, 140737488347136, 140737488351231, STORE, 140735933583360, 140737488351231, ERASE, 140735933583360, 140737488351231, @@ -1159,7 +1160,7 @@ STORE, 140277094813696, 140277094821887, STORE, 140277094821888, 140277094825983, STORE, 140735933906944, 140735933911039, }; - unsigned long set3[] = { + static const unsigned long set3[] = { STORE, 140737488347136, 140737488351231, STORE, 140735790264320, 140737488351231, ERASE, 140735790264320, 140737488351231, @@ -1202,7 +1203,7 @@ STORE, 47135835840512, 47135835885567, STORE, 47135835885568, 47135835893759, }; - unsigned long set4[] = { + static const unsigned long set4[] = { STORE, 140737488347136, 140737488351231, STORE, 140728251703296, 140737488351231, ERASE, 140728251703296, 140737488351231, @@ -1223,7 +1224,7 @@ ERASE, 47646523277312, 47646523445247, STORE, 47646523277312, 47646523400191, }; - unsigned long set5[] = { + static const unsigned long set5[] = { STORE, 140737488347136, 140737488351231, STORE, 140726874062848, 140737488351231, ERASE, 140726874062848, 140737488351231, @@ -1356,7 +1357,7 @@ STORE, 47884791619584, 47884791623679, STORE, 47884791623680, 47884791627775, }; - unsigned long set6[] = { + static const unsigned long set6[] = { STORE, 140737488347136, 140737488351231, STORE, 140722999021568, 140737488351231, ERASE, 140722999021568, 140737488351231, @@ -1488,7 +1489,7 @@ ERASE, 47430432014336, 47430432022527, STORE, 47430432014336, 47430432018431, STORE, 47430432018432, 47430432022527, }; - unsigned long set7[] = { + static const unsigned long set7[] = { STORE, 140737488347136, 140737488351231, STORE, 140729808330752, 140737488351231, ERASE, 140729808330752, 140737488351231, @@ -1620,7 +1621,7 @@ ERASE, 47439987130368, 47439987138559, STORE, 47439987130368, 47439987134463, STORE, 47439987134464, 47439987138559, }; - unsigned long set8[] = { + static const unsigned long set8[] = { STORE, 140737488347136, 140737488351231, STORE, 140722482974720, 140737488351231, ERASE, 140722482974720, 140737488351231, @@ -1753,7 +1754,7 @@ STORE, 47708488638464, 47708488642559, STORE, 47708488642560, 47708488646655, }; - unsigned long set9[] = { + static const unsigned long set9[] = { STORE, 140737488347136, 140737488351231, STORE, 140736427839488, 140737488351231, ERASE, 140736427839488, 140736427839488, @@ -5619,7 +5620,7 @@ ERASE, 47906195480576, 47906195480576, STORE, 94641242615808, 94641242750975, }; - unsigned long set10[] = { + static const unsigned long set10[] = { STORE, 140737488347136, 140737488351231, STORE, 140736427839488, 140737488351231, ERASE, 140736427839488, 140736427839488, @@ -9483,7 +9484,7 @@ STORE, 139726599680000, 139726599684095, ERASE, 47906195480576, 47906195480576, STORE, 94641242615808, 94641242750975, }; - unsigned long set11[] = { + static const unsigned long set11[] = { STORE, 140737488347136, 140737488351231, STORE, 140732658499584, 140737488351231, ERASE, 140732658499584, 140732658499584, @@ -9509,7 +9510,7 @@ STORE, 140732658565120, 140732658569215, STORE, 140732658552832, 140732658565119, }; - unsigned long set12[] = { /* contains 12 values. */ + static const unsigned long set12[] = { /* contains 12 values. */ STORE, 140737488347136, 140737488351231, STORE, 140732658499584, 140737488351231, ERASE, 140732658499584, 140732658499584, @@ -9536,7 +9537,7 @@ STORE, 140732658552832, 140732658565119, STORE, 140014592741375, 140014592741375, /* contrived */ STORE, 140014592733184, 140014592741376, /* creates first entry retry. */ }; - unsigned long set13[] = { + static const unsigned long set13[] = { STORE, 140373516247040, 140373516251135,/*: ffffa2e7b0e10d80 */ STORE, 140373516251136, 140373516255231,/*: ffffa2e7b1195d80 */ STORE, 140373516255232, 140373516443647,/*: ffffa2e7b0e109c0 */ @@ -9549,7 +9550,7 @@ STORE, 140373518684160, 140373518688254,/*: ffffa2e7b05fec00 */ STORE, 140373518688256, 140373518692351,/*: ffffa2e7bfbdcd80 */ STORE, 140373518692352, 140373518696447,/*: ffffa2e7b0749e40 */ }; - unsigned long set14[] = { + static const unsigned long set14[] = { STORE, 140737488347136, 140737488351231, STORE, 140731667996672, 140737488351231, SNULL, 140731668000767, 140737488351231, @@ -9833,7 +9834,7 @@ SNULL, 139826136543232, 139826136809471, STORE, 139826136809472, 139826136842239, STORE, 139826136543232, 139826136809471, }; - unsigned long set15[] = { + static const unsigned long set15[] = { STORE, 140737488347136, 140737488351231, STORE, 140722061451264, 140737488351231, SNULL, 140722061455359, 140737488351231, @@ -10118,7 +10119,7 @@ STORE, 139906808958976, 139906808991743, STORE, 139906808692736, 139906808958975, }; - unsigned long set16[] = { + static const unsigned long set16[] = { STORE, 94174808662016, 94174809321471, STORE, 94174811414528, 94174811426815, STORE, 94174811426816, 94174811430911, @@ -10329,7 +10330,7 @@ STORE, 139921865613312, 139921865617407, STORE, 139921865547776, 139921865564159, }; - unsigned long set17[] = { + static const unsigned long set17[] = { STORE, 94397057224704, 94397057646591, STORE, 94397057650688, 94397057691647, STORE, 94397057691648, 94397057695743, @@ -10391,7 +10392,7 @@ STORE, 140720477511680, 140720477646847, STORE, 140720478302208, 140720478314495, STORE, 140720478314496, 140720478318591, }; - unsigned long set18[] = { + static const unsigned long set18[] = { STORE, 140737488347136, 140737488351231, STORE, 140724953673728, 140737488351231, SNULL, 140724953677823, 140737488351231, @@ -10424,7 +10425,7 @@ STORE, 140222970597376, 140222970605567, ERASE, 140222970597376, 140222970605567, STORE, 140222970597376, 140222970605567, }; - unsigned long set19[] = { + static const unsigned long set19[] = { STORE, 140737488347136, 140737488351231, STORE, 140725182459904, 140737488351231, SNULL, 140725182463999, 140737488351231, @@ -10693,7 +10694,7 @@ STORE, 140656836775936, 140656836780031, STORE, 140656787476480, 140656791920639, ERASE, 140656774639616, 140656779083775, }; - unsigned long set20[] = { + static const unsigned long set20[] = { STORE, 140737488347136, 140737488351231, STORE, 140735952392192, 140737488351231, SNULL, 140735952396287, 140737488351231, @@ -10849,7 +10850,7 @@ STORE, 140590386819072, 140590386823167, STORE, 140590386823168, 140590386827263, SNULL, 140590376591359, 140590376595455, }; - unsigned long set21[] = { + static const unsigned long set21[] = { STORE, 93874710941696, 93874711363583, STORE, 93874711367680, 93874711408639, STORE, 93874711408640, 93874711412735, @@ -10919,7 +10920,7 @@ ERASE, 140708393312256, 140708393316351, ERASE, 140708393308160, 140708393312255, ERASE, 140708393291776, 140708393308159, }; - unsigned long set22[] = { + static const unsigned long set22[] = { STORE, 93951397134336, 93951397183487, STORE, 93951397183488, 93951397728255, STORE, 93951397728256, 93951397826559, @@ -11046,7 +11047,7 @@ STORE, 140551361253376, 140551361519615, ERASE, 140551361253376, 140551361519615, }; - unsigned long set23[] = { + static const unsigned long set23[] = { STORE, 94014447943680, 94014448156671, STORE, 94014450253824, 94014450257919, STORE, 94014450257920, 94014450266111, @@ -14370,7 +14371,7 @@ SNULL, 140175956627455, 140175985139711, STORE, 140175927242752, 140175956627455, STORE, 140175956627456, 140175985139711, }; - unsigned long set24[] = { + static const unsigned long set24[] = { STORE, 140737488347136, 140737488351231, STORE, 140735281639424, 140737488351231, SNULL, 140735281643519, 140737488351231, @@ -15532,7 +15533,7 @@ ERASE, 139635393024000, 139635401412607, ERASE, 139635384627200, 139635384631295, ERASE, 139635384631296, 139635393019903, }; - unsigned long set25[] = { + static const unsigned long set25[] = { STORE, 140737488347136, 140737488351231, STORE, 140737488343040, 140737488351231, STORE, 140722547441664, 140737488351231, @@ -22320,7 +22321,7 @@ STORE, 140249652703232, 140249682087935, STORE, 140249682087936, 140249710600191, }; - unsigned long set26[] = { + static const unsigned long set26[] = { STORE, 140737488347136, 140737488351231, STORE, 140729464770560, 140737488351231, SNULL, 140729464774655, 140737488351231, @@ -22344,7 +22345,7 @@ ERASE, 140109040951296, 140109040959487, STORE, 140109040955392, 140109040959487, ERASE, 140109040955392, 140109040959487, }; - unsigned long set27[] = { + static const unsigned long set27[] = { STORE, 140737488347136, 140737488351231, STORE, 140726128070656, 140737488351231, SNULL, 140726128074751, 140737488351231, @@ -22740,7 +22741,7 @@ STORE, 140415509696512, 140415535910911, ERASE, 140415537422336, 140415562588159, STORE, 140415482433536, 140415509696511, }; - unsigned long set28[] = { + static const unsigned long set28[] = { STORE, 140737488347136, 140737488351231, STORE, 140722475622400, 140737488351231, SNULL, 140722475626495, 140737488351231, @@ -22808,7 +22809,7 @@ STORE, 139918413348864, 139918413352959, ERASE, 139918413316096, 139918413344767, STORE, 93865848528896, 93865848664063, }; - unsigned long set29[] = { + static const unsigned long set29[] = { STORE, 140737488347136, 140737488351231, STORE, 140734467944448, 140737488351231, SNULL, 140734467948543, 140737488351231, @@ -23683,7 +23684,7 @@ ERASE, 140143079972864, 140143088361471, ERASE, 140143205793792, 140143205797887, ERASE, 140143205797888, 140143214186495, }; - unsigned long set30[] = { + static const unsigned long set30[] = { STORE, 140737488347136, 140737488351231, STORE, 140733436743680, 140737488351231, SNULL, 140733436747775, 140737488351231, @@ -24565,7 +24566,7 @@ ERASE, 140165225893888, 140165225897983, ERASE, 140165225897984, 140165234286591, ERASE, 140165058105344, 140165058109439, }; - unsigned long set31[] = { + static const unsigned long set31[] = { STORE, 140737488347136, 140737488351231, STORE, 140730890784768, 140737488351231, SNULL, 140730890788863, 140737488351231, @@ -25378,7 +25379,7 @@ ERASE, 140623906590720, 140623914979327, ERASE, 140622950277120, 140622950281215, ERASE, 140622950281216, 140622958669823, }; - unsigned long set32[] = { + static const unsigned long set32[] = { STORE, 140737488347136, 140737488351231, STORE, 140731244212224, 140737488351231, SNULL, 140731244216319, 140737488351231, @@ -26174,7 +26175,7 @@ ERASE, 140400417288192, 140400425676799, ERASE, 140400283066368, 140400283070463, ERASE, 140400283070464, 140400291459071, }; - unsigned long set33[] = { + static const unsigned long set33[] = { STORE, 140737488347136, 140737488351231, STORE, 140734562918400, 140737488351231, SNULL, 140734562922495, 140737488351231, @@ -26316,7 +26317,7 @@ STORE, 140582961786880, 140583003750399, ERASE, 140582961786880, 140583003750399, }; - unsigned long set34[] = { + static const unsigned long set34[] = { STORE, 140737488347136, 140737488351231, STORE, 140731327180800, 140737488351231, SNULL, 140731327184895, 140737488351231, @@ -27197,7 +27198,7 @@ ERASE, 140012522094592, 140012530483199, ERASE, 140012033142784, 140012033146879, ERASE, 140012033146880, 140012041535487, }; - unsigned long set35[] = { + static const unsigned long set35[] = { STORE, 140737488347136, 140737488351231, STORE, 140730536939520, 140737488351231, SNULL, 140730536943615, 140737488351231, @@ -27954,7 +27955,7 @@ ERASE, 140474471936000, 140474480324607, ERASE, 140474396430336, 140474396434431, ERASE, 140474396434432, 140474404823039, }; - unsigned long set36[] = { + static const unsigned long set36[] = { STORE, 140737488347136, 140737488351231, STORE, 140723893125120, 140737488351231, SNULL, 140723893129215, 140737488351231, @@ -28815,7 +28816,7 @@ ERASE, 140121890357248, 140121898745855, ERASE, 140121269587968, 140121269592063, ERASE, 140121269592064, 140121277980671, }; - unsigned long set37[] = { + static const unsigned long set37[] = { STORE, 140737488347136, 140737488351231, STORE, 140722404016128, 140737488351231, SNULL, 140722404020223, 140737488351231, @@ -28941,7 +28942,7 @@ STORE, 139759821246464, 139759888355327, ERASE, 139759821246464, 139759888355327, ERASE, 139759888355328, 139759955464191, }; - unsigned long set38[] = { + static const unsigned long set38[] = { STORE, 140737488347136, 140737488351231, STORE, 140730666221568, 140737488351231, SNULL, 140730666225663, 140737488351231, @@ -29751,7 +29752,7 @@ ERASE, 140613504712704, 140613504716799, ERASE, 140613504716800, 140613513105407, }; - unsigned long set39[] = { + static const unsigned long set39[] = { STORE, 140737488347136, 140737488351231, STORE, 140736271417344, 140737488351231, SNULL, 140736271421439, 140737488351231, @@ -30123,7 +30124,7 @@ STORE, 140325364428800, 140325372821503, STORE, 140325356036096, 140325364428799, SNULL, 140325364432895, 140325372821503, }; - unsigned long set40[] = { + static const unsigned long set40[] = { STORE, 140737488347136, 140737488351231, STORE, 140734309167104, 140737488351231, SNULL, 140734309171199, 140737488351231, @@ -30874,7 +30875,7 @@ ERASE, 140320289300480, 140320289304575, ERASE, 140320289304576, 140320297693183, ERASE, 140320163409920, 140320163414015, }; - unsigned long set41[] = { + static const unsigned long set41[] = { STORE, 140737488347136, 140737488351231, STORE, 140728157171712, 140737488351231, SNULL, 140728157175807, 140737488351231, @@ -31184,7 +31185,7 @@ STORE, 94376135090176, 94376135094271, STORE, 94376135094272, 94376135098367, SNULL, 94376135094272, 94377208836095, }; - unsigned long set42[] = { + static const unsigned long set42[] = { STORE, 314572800, 1388314623, STORE, 1462157312, 1462169599, STORE, 1462169600, 1462185983, @@ -33861,7 +33862,7 @@ SNULL, 3798999040, 3799101439, */ }; - unsigned long set43[] = { + static const unsigned long set43[] = { STORE, 140737488347136, 140737488351231, STORE, 140734187720704, 140737488351231, SNULL, 140734187724800, 140737488351231, @@ -34995,7 +34996,7 @@ void run_check_rcu_slowread(struct maple_tree *mt, struct rcu_test_struct *vals) MT_BUG_ON(mt, !vals->seen_entry3); MT_BUG_ON(mt, !vals->seen_both); } -static noinline void check_rcu_simulated(struct maple_tree *mt) +static noinline void __init check_rcu_simulated(struct maple_tree *mt) { unsigned long i, nr_entries = 1000; unsigned long target = 4320; @@ -35156,7 +35157,7 @@ static noinline void check_rcu_simulated(struct maple_tree *mt) rcu_unregister_thread(); } -static noinline void check_rcu_threaded(struct maple_tree *mt) +static noinline void __init check_rcu_threaded(struct maple_tree *mt) { unsigned long i, nr_entries = 1000; struct rcu_test_struct vals; @@ -35369,7 +35370,7 @@ static void check_dfs_preorder(struct maple_tree *mt) /* End of depth first search tests */ /* Preallocation testing */ -static noinline void check_prealloc(struct maple_tree *mt) +static noinline void __init check_prealloc(struct maple_tree *mt) { unsigned long i, max = 100; unsigned long allocated; @@ -35497,7 +35498,7 @@ static noinline void check_prealloc(struct maple_tree *mt) /* End of preallocation testing */ /* Spanning writes, writes that span nodes and layers of the tree */ -static noinline void check_spanning_write(struct maple_tree *mt) +static noinline void __init check_spanning_write(struct maple_tree *mt) { unsigned long i, max = 5000; MA_STATE(mas, mt, 1200, 2380); @@ -35665,7 +35666,7 @@ static noinline void check_spanning_write(struct maple_tree *mt) /* End of spanning write testing */ /* Writes to a NULL area that are adjacent to other NULLs */ -static noinline void check_null_expand(struct maple_tree *mt) +static noinline void __init check_null_expand(struct maple_tree *mt) { unsigned long i, max = 100; unsigned char data_end; @@ -35726,7 +35727,7 @@ static noinline void check_null_expand(struct maple_tree *mt) /* End of NULL area expansions */ /* Checking for no memory is best done outside the kernel */ -static noinline void check_nomem(struct maple_tree *mt) +static noinline void __init check_nomem(struct maple_tree *mt) { MA_STATE(ms, mt, 1, 1); @@ -35761,7 +35762,7 @@ static noinline void check_nomem(struct maple_tree *mt) mtree_destroy(mt); } -static noinline void check_locky(struct maple_tree *mt) +static noinline void __init check_locky(struct maple_tree *mt) { MA_STATE(ms, mt, 2, 2); MA_STATE(reader, mt, 2, 2); -- cgit v1.2.3 From 81b1e3f91d77564611ab10d2c61774cf6a46ec78 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 19 May 2023 12:27:21 +0200 Subject: selftests/mm: factor out detection of hugetlb page sizes into vm_util Patch series "selftests/mm: new test for FOLL_LONGTERM on file mappings". Let's add some selftests to make sure that: * R/O long-term pinning always works of file mappings * R/W long-term pinning always works in MAP_PRIVATE file mappings * R/W long-term pinning only works in MAP_SHARED mappings with special filesystems (shmem, hugetlb) and fails with other filesystems (ext4, btrfs, xfs). The tests make use of the gup_test kernel module to trigger ordinary GUP and GUP-fast, and liburing (similar to our COW selftests). Test with memfd, memfd hugetlb, tmpfile() and mkstemp(). The latter usually gives us a "real" filesystem (ext4, btrfs, xfs) where long-term pinning is expected to fail. Note that these selftests don't contain any actual reproducers for data corruptions in case R/W long-term pinning on problematic filesystems "would" work. Maybe we can later come up with a racy !FOLL_LONGTERM reproducer that can reuse an existing interface to trigger short-term pinning (I'll look into that next). On current mm/mm-unstable: # ./gup_longterm # [INFO] detected hugetlb page size: 2048 KiB # [INFO] detected hugetlb page size: 1048576 KiB TAP version 13 1..50 # [RUN] R/W longterm GUP pin in MAP_SHARED file mapping ... with memfd ok 1 Should have worked # [RUN] R/W longterm GUP pin in MAP_SHARED file mapping ... with tmpfile ok 2 Should have worked # [RUN] R/W longterm GUP pin in MAP_SHARED file mapping ... with local tmpfile ok 3 Should have failed # [RUN] R/W longterm GUP pin in MAP_SHARED file mapping ... with memfd hugetlb (2048 kB) ok 4 Should have worked # [RUN] R/W longterm GUP pin in MAP_SHARED file mapping ... with memfd hugetlb (1048576 kB) ok 5 Should have worked # [RUN] R/W longterm GUP-fast pin in MAP_SHARED file mapping ... with memfd ok 6 Should have worked # [RUN] R/W longterm GUP-fast pin in MAP_SHARED file mapping ... with tmpfile ok 7 Should have worked # [RUN] R/W longterm GUP-fast pin in MAP_SHARED file mapping ... with local tmpfile ok 8 Should have failed # [RUN] R/W longterm GUP-fast pin in MAP_SHARED file mapping ... with memfd hugetlb (2048 kB) ok 9 Should have worked # [RUN] R/W longterm GUP-fast pin in MAP_SHARED file mapping ... with memfd hugetlb (1048576 kB) ok 10 Should have worked # [RUN] R/O longterm GUP pin in MAP_SHARED file mapping ... with memfd ok 11 Should have worked # [RUN] R/O longterm GUP pin in MAP_SHARED file mapping ... with tmpfile ok 12 Should have worked # [RUN] R/O longterm GUP pin in MAP_SHARED file mapping ... with local tmpfile ok 13 Should have worked # [RUN] R/O longterm GUP pin in MAP_SHARED file mapping ... with memfd hugetlb (2048 kB) ok 14 Should have worked # [RUN] R/O longterm GUP pin in MAP_SHARED file mapping ... with memfd hugetlb (1048576 kB) ok 15 Should have worked # [RUN] R/O longterm GUP-fast pin in MAP_SHARED file mapping ... with memfd ok 16 Should have worked # [RUN] R/O longterm GUP-fast pin in MAP_SHARED file mapping ... with tmpfile ok 17 Should have worked # [RUN] R/O longterm GUP-fast pin in MAP_SHARED file mapping ... with local tmpfile ok 18 Should have worked # [RUN] R/O longterm GUP-fast pin in MAP_SHARED file mapping ... with memfd hugetlb (2048 kB) ok 19 Should have worked # [RUN] R/O longterm GUP-fast pin in MAP_SHARED file mapping ... with memfd hugetlb (1048576 kB) ok 20 Should have worked # [RUN] R/W longterm GUP pin in MAP_PRIVATE file mapping ... with memfd ok 21 Should have worked # [RUN] R/W longterm GUP pin in MAP_PRIVATE file mapping ... with tmpfile ok 22 Should have worked # [RUN] R/W longterm GUP pin in MAP_PRIVATE file mapping ... with local tmpfile ok 23 Should have worked # [RUN] R/W longterm GUP pin in MAP_PRIVATE file mapping ... with memfd hugetlb (2048 kB) ok 24 Should have worked # [RUN] R/W longterm GUP pin in MAP_PRIVATE file mapping ... with memfd hugetlb (1048576 kB) ok 25 Should have worked # [RUN] R/W longterm GUP-fast pin in MAP_PRIVATE file mapping ... with memfd ok 26 Should have worked # [RUN] R/W longterm GUP-fast pin in MAP_PRIVATE file mapping ... with tmpfile ok 27 Should have worked # [RUN] R/W longterm GUP-fast pin in MAP_PRIVATE file mapping ... with local tmpfile ok 28 Should have worked # [RUN] R/W longterm GUP-fast pin in MAP_PRIVATE file mapping ... with memfd hugetlb (2048 kB) ok 29 Should have worked # [RUN] R/W longterm GUP-fast pin in MAP_PRIVATE file mapping ... with memfd hugetlb (1048576 kB) ok 30 Should have worked # [RUN] R/O longterm GUP pin in MAP_PRIVATE file mapping ... with memfd ok 31 Should have worked # [RUN] R/O longterm GUP pin in MAP_PRIVATE file mapping ... with tmpfile ok 32 Should have worked # [RUN] R/O longterm GUP pin in MAP_PRIVATE file mapping ... with local tmpfile ok 33 Should have worked # [RUN] R/O longterm GUP pin in MAP_PRIVATE file mapping ... with memfd hugetlb (2048 kB) ok 34 Should have worked # [RUN] R/O longterm GUP pin in MAP_PRIVATE file mapping ... with memfd hugetlb (1048576 kB) ok 35 Should have worked # [RUN] R/O longterm GUP-fast pin in MAP_PRIVATE file mapping ... with memfd ok 36 Should have worked # [RUN] R/O longterm GUP-fast pin in MAP_PRIVATE file mapping ... with tmpfile ok 37 Should have worked # [RUN] R/O longterm GUP-fast pin in MAP_PRIVATE file mapping ... with local tmpfile ok 38 Should have worked # [RUN] R/O longterm GUP-fast pin in MAP_PRIVATE file mapping ... with memfd hugetlb (2048 kB) ok 39 Should have worked # [RUN] R/O longterm GUP-fast pin in MAP_PRIVATE file mapping ... with memfd hugetlb (1048576 kB) ok 40 Should have worked # [RUN] io_uring fixed buffer with MAP_SHARED file mapping ... with memfd ok 41 Should have worked # [RUN] io_uring fixed buffer with MAP_SHARED file mapping ... with tmpfile ok 42 Should have worked # [RUN] io_uring fixed buffer with MAP_SHARED file mapping ... with local tmpfile ok 43 Should have failed # [RUN] io_uring fixed buffer with MAP_SHARED file mapping ... with memfd hugetlb (2048 kB) ok 44 Should have worked # [RUN] io_uring fixed buffer with MAP_SHARED file mapping ... with memfd hugetlb (1048576 kB) ok 45 Should have worked # [RUN] io_uring fixed buffer with MAP_PRIVATE file mapping ... with memfd ok 46 Should have worked # [RUN] io_uring fixed buffer with MAP_PRIVATE file mapping ... with tmpfile ok 47 Should have worked # [RUN] io_uring fixed buffer with MAP_PRIVATE file mapping ... with local tmpfile ok 48 Should have worked # [RUN] io_uring fixed buffer with MAP_PRIVATE file mapping ... with memfd hugetlb (2048 kB) ok 49 Should have worked # [RUN] io_uring fixed buffer with MAP_PRIVATE file mapping ... with memfd hugetlb (1048576 kB) ok 50 Should have worked # Totals: pass:50 fail:0 xfail:0 xpass:0 skip:0 error:0 This patch (of 3): Let's factor detection out into vm_util, to be reused by a new test. Link: https://lkml.kernel.org/r/20230519102723.185721-1-david@redhat.com Link: https://lkml.kernel.org/r/20230519102723.185721-2-david@redhat.com Signed-off-by: David Hildenbrand Reviewed-by: Lorenzo Stoakes Cc: Jan Kara Cc: Jason Gunthorpe Cc: Jens Axboe Cc: John Hubbard Cc: Peter Xu Cc: Shuah Khan Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/cow.c | 29 ++--------------------------- tools/testing/selftests/mm/vm_util.c | 27 +++++++++++++++++++++++++++ tools/testing/selftests/mm/vm_util.h | 1 + 3 files changed, 30 insertions(+), 27 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/mm/cow.c b/tools/testing/selftests/mm/cow.c index dc9d6fe86028..7f3b620d9cb7 100644 --- a/tools/testing/selftests/mm/cow.c +++ b/tools/testing/selftests/mm/cow.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -70,31 +69,6 @@ static void detect_huge_zeropage(void) close(fd); } -static void detect_hugetlbsizes(void) -{ - DIR *dir = opendir("/sys/kernel/mm/hugepages/"); - - if (!dir) - return; - - while (nr_hugetlbsizes < ARRAY_SIZE(hugetlbsizes)) { - struct dirent *entry = readdir(dir); - size_t kb; - - if (!entry) - break; - if (entry->d_type != DT_DIR) - continue; - if (sscanf(entry->d_name, "hugepages-%zukB", &kb) != 1) - continue; - hugetlbsizes[nr_hugetlbsizes] = kb * 1024; - nr_hugetlbsizes++; - ksft_print_msg("[INFO] detected hugetlb size: %zu KiB\n", - kb); - } - closedir(dir); -} - static bool range_is_swapped(void *addr, size_t size) { for (; size; addr += pagesize, size -= pagesize) @@ -1717,7 +1691,8 @@ int main(int argc, char **argv) if (thpsize) ksft_print_msg("[INFO] detected THP size: %zu KiB\n", thpsize / 1024); - detect_hugetlbsizes(); + nr_hugetlbsizes = detect_hugetlb_page_sizes(hugetlbsizes, + ARRAY_SIZE(hugetlbsizes)); detect_huge_zeropage(); ksft_print_header(); diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c index 9b06a5034808..5cf84d860076 100644 --- a/tools/testing/selftests/mm/vm_util.c +++ b/tools/testing/selftests/mm/vm_util.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include #include +#include #include #include #include @@ -198,6 +199,32 @@ unsigned long default_huge_page_size(void) return hps; } +int detect_hugetlb_page_sizes(size_t sizes[], int max) +{ + DIR *dir = opendir("/sys/kernel/mm/hugepages/"); + int count = 0; + + if (!dir) + return 0; + + while (count < max) { + struct dirent *entry = readdir(dir); + size_t kb; + + if (!entry) + break; + if (entry->d_type != DT_DIR) + continue; + if (sscanf(entry->d_name, "hugepages-%zukB", &kb) != 1) + continue; + sizes[count++] = kb * 1024; + ksft_print_msg("[INFO] detected hugetlb page size: %zu KiB\n", + kb); + } + closedir(dir); + return count; +} + /* If `ioctls' non-NULL, the allowed ioctls will be returned into the var */ int uffd_register_with_ioctls(int uffd, void *addr, uint64_t len, bool miss, bool wp, bool minor, uint64_t *ioctls) diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h index b950bd16083a..99b795528716 100644 --- a/tools/testing/selftests/mm/vm_util.h +++ b/tools/testing/selftests/mm/vm_util.h @@ -44,6 +44,7 @@ bool check_huge_file(void *addr, int nr_hpages, uint64_t hpage_size); bool check_huge_shmem(void *addr, int nr_hpages, uint64_t hpage_size); int64_t allocate_transhuge(void *ptr, int pagemap_fd); unsigned long default_huge_page_size(void); +int detect_hugetlb_page_sizes(size_t sizes[], int max); int uffd_register(int uffd, void *addr, uint64_t len, bool miss, bool wp, bool minor); -- cgit v1.2.3 From c879462a08feafe1bc10f34089f39932a2e1d712 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 19 May 2023 12:27:22 +0200 Subject: selftests/mm: gup_longterm: new functional test for FOLL_LONGTERM Let's add a new test for checking whether GUP long-term page pinning works as expected (R/O vs. R/W, MAP_PRIVATE vs. MAP_SHARED, GUP vs. GUP-fast). Note that COW handling with long-term R/O pinning in private mappings, and pinning of anonymous memory in general, is tested by the COW selftest. This test, therefore, focuses on page pinning in file mappings. The most interesting case is probably the "local tmpfile" case, as that will likely end up on a "real" filesystem such as ext4 or xfs, not on a virtual one like tmpfs or hugetlb where any long-term page pinning is always expected to succeed. For now, only add tests that use the "/sys/kernel/debug/gup_test" interface. We'll add tests based on liburing separately next. [akpm@linux-foundation.org: update .gitignore for gup_longterm, per Peter] Link: https://lkml.kernel.org/r/20230519102723.185721-3-david@redhat.com Signed-off-by: David Hildenbrand Reviewed-by: Lorenzo Stoakes Cc: Jan Kara Cc: Jason Gunthorpe Cc: Jens Axboe Cc: John Hubbard Cc: Peter Xu Cc: Shuah Khan Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/.gitignore | 1 + tools/testing/selftests/mm/Makefile | 3 + tools/testing/selftests/mm/gup_longterm.c | 386 ++++++++++++++++++++++++++++++ tools/testing/selftests/mm/run_vmtests.sh | 4 +- 4 files changed, 393 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/mm/gup_longterm.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/mm/.gitignore b/tools/testing/selftests/mm/.gitignore index 8917455f4f51..5599cf287694 100644 --- a/tools/testing/selftests/mm/.gitignore +++ b/tools/testing/selftests/mm/.gitignore @@ -39,3 +39,4 @@ local_config.h local_config.mk ksm_functional_tests mdwe_test +gup_longterm diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile index 23af4633f0f4..95acb099315e 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -34,6 +34,7 @@ LDLIBS = -lrt -lpthread TEST_GEN_PROGS = cow TEST_GEN_PROGS += compaction_test +TEST_GEN_PROGS += gup_longterm TEST_GEN_PROGS += gup_test TEST_GEN_PROGS += hmm-tests TEST_GEN_PROGS += hugetlb-madvise @@ -164,6 +165,8 @@ endif # IOURING_EXTRA_LIBS may get set in local_config.mk, or it may be left empty. $(OUTPUT)/cow: LDLIBS += $(IOURING_EXTRA_LIBS) +$(OUTPUT)/gup_longterm: LDLIBS += $(IOURING_EXTRA_LIBS) + $(OUTPUT)/mlock-random-test $(OUTPUT)/memfd_secret: LDLIBS += -lcap $(OUTPUT)/ksm_tests: LDLIBS += -lnuma diff --git a/tools/testing/selftests/mm/gup_longterm.c b/tools/testing/selftests/mm/gup_longterm.c new file mode 100644 index 000000000000..44a3617fd423 --- /dev/null +++ b/tools/testing/selftests/mm/gup_longterm.c @@ -0,0 +1,386 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * GUP long-term page pinning tests. + * + * Copyright 2023, Red Hat, Inc. + * + * Author(s): David Hildenbrand + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "local_config.h" + +#include "../../../../mm/gup_test.h" +#include "../kselftest.h" +#include "vm_util.h" + +static size_t pagesize; +static int nr_hugetlbsizes; +static size_t hugetlbsizes[10]; +static int gup_fd; + +static __fsword_t get_fs_type(int fd) +{ + struct statfs fs; + int ret; + + do { + ret = fstatfs(fd, &fs); + } while (ret && errno == EINTR); + + return ret ? 0 : fs.f_type; +} + +static bool fs_is_unknown(__fsword_t fs_type) +{ + /* + * We only support some filesystems in our tests when dealing with + * R/W long-term pinning. For these filesystems, we can be fairly sure + * whether they support it or not. + */ + switch (fs_type) { + case TMPFS_MAGIC: + case HUGETLBFS_MAGIC: + case BTRFS_SUPER_MAGIC: + case EXT4_SUPER_MAGIC: + case XFS_SUPER_MAGIC: + return false; + default: + return true; + } +} + +static bool fs_supports_writable_longterm_pinning(__fsword_t fs_type) +{ + assert(!fs_is_unknown(fs_type)); + switch (fs_type) { + case TMPFS_MAGIC: + case HUGETLBFS_MAGIC: + return true; + default: + return false; + } +} + +enum test_type { + TEST_TYPE_RO, + TEST_TYPE_RO_FAST, + TEST_TYPE_RW, + TEST_TYPE_RW_FAST, +}; + +static void do_test(int fd, size_t size, enum test_type type, bool shared) +{ + __fsword_t fs_type = get_fs_type(fd); + bool should_work; + char *mem; + int ret; + + if (ftruncate(fd, size)) { + ksft_test_result_fail("ftruncate() failed\n"); + return; + } + + if (fallocate(fd, 0, 0, size)) { + if (size == pagesize) + ksft_test_result_fail("fallocate() failed\n"); + else + ksft_test_result_skip("need more free huge pages\n"); + return; + } + + mem = mmap(NULL, size, PROT_READ | PROT_WRITE, + shared ? MAP_SHARED : MAP_PRIVATE, fd, 0); + if (mem == MAP_FAILED) { + if (size == pagesize || shared) + ksft_test_result_fail("mmap() failed\n"); + else + ksft_test_result_skip("need more free huge pages\n"); + return; + } + + /* + * Fault in the page writable such that GUP-fast can eventually pin + * it immediately. + */ + memset(mem, 0, size); + + switch (type) { + case TEST_TYPE_RO: + case TEST_TYPE_RO_FAST: + case TEST_TYPE_RW: + case TEST_TYPE_RW_FAST: { + struct pin_longterm_test args; + const bool fast = type == TEST_TYPE_RO_FAST || + type == TEST_TYPE_RW_FAST; + const bool rw = type == TEST_TYPE_RW || + type == TEST_TYPE_RW_FAST; + + if (gup_fd < 0) { + ksft_test_result_skip("gup_test not available\n"); + break; + } + + if (rw && shared && fs_is_unknown(fs_type)) { + ksft_test_result_skip("Unknown filesystem\n"); + return; + } + /* + * R/O pinning or pinning in a private mapping is always + * expected to work. Otherwise, we expect long-term R/W pinning + * to only succeed for special fielesystems. + */ + should_work = !shared || !rw || + fs_supports_writable_longterm_pinning(fs_type); + + args.addr = (__u64)(uintptr_t)mem; + args.size = size; + args.flags = fast ? PIN_LONGTERM_TEST_FLAG_USE_FAST : 0; + args.flags |= rw ? PIN_LONGTERM_TEST_FLAG_USE_WRITE : 0; + ret = ioctl(gup_fd, PIN_LONGTERM_TEST_START, &args); + if (ret && errno == EINVAL) { + ksft_test_result_skip("PIN_LONGTERM_TEST_START failed\n"); + break; + } else if (ret && errno == EFAULT) { + ksft_test_result(!should_work, "Should have failed\n"); + break; + } else if (ret) { + ksft_test_result_fail("PIN_LONGTERM_TEST_START failed\n"); + break; + } + + if (ioctl(gup_fd, PIN_LONGTERM_TEST_STOP)) + ksft_print_msg("[INFO] PIN_LONGTERM_TEST_STOP failed\n"); + + /* + * TODO: if the kernel ever supports long-term R/W pinning on + * some previously unsupported filesystems, we might want to + * perform some additional tests for possible data corruptions. + */ + ksft_test_result(should_work, "Should have worked\n"); + break; + } + default: + assert(false); + } + + munmap(mem, size); +} + +typedef void (*test_fn)(int fd, size_t size); + +static void run_with_memfd(test_fn fn, const char *desc) +{ + int fd; + + ksft_print_msg("[RUN] %s ... with memfd\n", desc); + + fd = memfd_create("test", 0); + if (fd < 0) { + ksft_test_result_fail("memfd_create() failed\n"); + return; + } + + fn(fd, pagesize); + close(fd); +} + +static void run_with_tmpfile(test_fn fn, const char *desc) +{ + FILE *file; + int fd; + + ksft_print_msg("[RUN] %s ... with tmpfile\n", desc); + + file = tmpfile(); + if (!file) { + ksft_test_result_fail("tmpfile() failed\n"); + return; + } + + fd = fileno(file); + if (fd < 0) { + ksft_test_result_fail("fileno() failed\n"); + return; + } + + fn(fd, pagesize); + fclose(file); +} + +static void run_with_local_tmpfile(test_fn fn, const char *desc) +{ + char filename[] = __FILE__"_tmpfile_XXXXXX"; + int fd; + + ksft_print_msg("[RUN] %s ... with local tmpfile\n", desc); + + fd = mkstemp(filename); + if (fd < 0) { + ksft_test_result_fail("mkstemp() failed\n"); + return; + } + + if (unlink(filename)) { + ksft_test_result_fail("unlink() failed\n"); + goto close; + } + + fn(fd, pagesize); +close: + close(fd); +} + +static void run_with_memfd_hugetlb(test_fn fn, const char *desc, + size_t hugetlbsize) +{ + int flags = MFD_HUGETLB; + int fd; + + ksft_print_msg("[RUN] %s ... with memfd hugetlb (%zu kB)\n", desc, + hugetlbsize / 1024); + + flags |= __builtin_ctzll(hugetlbsize) << MFD_HUGE_SHIFT; + + fd = memfd_create("test", flags); + if (fd < 0) { + ksft_test_result_skip("memfd_create() failed\n"); + return; + } + + fn(fd, hugetlbsize); + close(fd); +} + +struct test_case { + const char *desc; + test_fn fn; +}; + +static void test_shared_rw_pin(int fd, size_t size) +{ + do_test(fd, size, TEST_TYPE_RW, true); +} + +static void test_shared_rw_fast_pin(int fd, size_t size) +{ + do_test(fd, size, TEST_TYPE_RW_FAST, true); +} + +static void test_shared_ro_pin(int fd, size_t size) +{ + do_test(fd, size, TEST_TYPE_RO, true); +} + +static void test_shared_ro_fast_pin(int fd, size_t size) +{ + do_test(fd, size, TEST_TYPE_RO_FAST, true); +} + +static void test_private_rw_pin(int fd, size_t size) +{ + do_test(fd, size, TEST_TYPE_RW, false); +} + +static void test_private_rw_fast_pin(int fd, size_t size) +{ + do_test(fd, size, TEST_TYPE_RW_FAST, false); +} + +static void test_private_ro_pin(int fd, size_t size) +{ + do_test(fd, size, TEST_TYPE_RO, false); +} + +static void test_private_ro_fast_pin(int fd, size_t size) +{ + do_test(fd, size, TEST_TYPE_RO_FAST, false); +} + +static const struct test_case test_cases[] = { + { + "R/W longterm GUP pin in MAP_SHARED file mapping", + test_shared_rw_pin, + }, + { + "R/W longterm GUP-fast pin in MAP_SHARED file mapping", + test_shared_rw_fast_pin, + }, + { + "R/O longterm GUP pin in MAP_SHARED file mapping", + test_shared_ro_pin, + }, + { + "R/O longterm GUP-fast pin in MAP_SHARED file mapping", + test_shared_ro_fast_pin, + }, + { + "R/W longterm GUP pin in MAP_PRIVATE file mapping", + test_private_rw_pin, + }, + { + "R/W longterm GUP-fast pin in MAP_PRIVATE file mapping", + test_private_rw_fast_pin, + }, + { + "R/O longterm GUP pin in MAP_PRIVATE file mapping", + test_private_ro_pin, + }, + { + "R/O longterm GUP-fast pin in MAP_PRIVATE file mapping", + test_private_ro_fast_pin, + }, +}; + +static void run_test_case(struct test_case const *test_case) +{ + int i; + + run_with_memfd(test_case->fn, test_case->desc); + run_with_tmpfile(test_case->fn, test_case->desc); + run_with_local_tmpfile(test_case->fn, test_case->desc); + for (i = 0; i < nr_hugetlbsizes; i++) + run_with_memfd_hugetlb(test_case->fn, test_case->desc, + hugetlbsizes[i]); +} + +static int tests_per_test_case(void) +{ + return 3 + nr_hugetlbsizes; +} + +int main(int argc, char **argv) +{ + int i, err; + + pagesize = getpagesize(); + nr_hugetlbsizes = detect_hugetlb_page_sizes(hugetlbsizes, + ARRAY_SIZE(hugetlbsizes)); + + ksft_print_header(); + ksft_set_plan(ARRAY_SIZE(test_cases) * tests_per_test_case()); + + gup_fd = open("/sys/kernel/debug/gup_test", O_RDWR); + + for (i = 0; i < ARRAY_SIZE(test_cases); i++) + run_test_case(&test_cases[i]); + + err = ksft_get_fail_cnt(); + if (err) + ksft_exit_fail_msg("%d out of %d tests failed\n", + err, ksft_test_num()); + return ksft_exit_pass(); +} diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/selftests/mm/run_vmtests.sh index 4893eb60d96d..b6b1eb6a8a6b 100644 --- a/tools/testing/selftests/mm/run_vmtests.sh +++ b/tools/testing/selftests/mm/run_vmtests.sh @@ -24,7 +24,7 @@ separated by spaces: - mmap tests for mmap(2) - gup_test - tests for gup using gup_test interface + tests for gup - userfaultfd tests for userfaultfd(2) - compaction @@ -196,6 +196,8 @@ CATEGORY="gup_test" run_test ./gup_test -a # Dump pages 0, 19, and 4096, using pin_user_pages: CATEGORY="gup_test" run_test ./gup_test -ct -F 0x1 0 19 0x1000 +CATEGORY="gup_test" run_test ./gup_longterm + CATEGORY="userfaultfd" run_test ./uffd-unit-tests uffd_stress_bin=./uffd-stress CATEGORY="userfaultfd" run_test ${uffd_stress_bin} anon 20 16 -- cgit v1.2.3 From 89207c669bbf464c81e1561d8206f120a679aaf7 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 19 May 2023 12:27:23 +0200 Subject: selftests/mm: gup_longterm: add liburing tests Similar to the COW selftests, also use io_uring fixed buffers to test if long-term page pinning works as expected. Link: https://lkml.kernel.org/r/20230519102723.185721-4-david@redhat.com Signed-off-by: David Hildenbrand Reviewed-by: Lorenzo Stoakes Cc: Jan Kara Cc: Jason Gunthorpe Cc: Jens Axboe Cc: John Hubbard Cc: Peter Xu Cc: Shuah Khan Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/gup_longterm.c | 73 +++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/mm/gup_longterm.c b/tools/testing/selftests/mm/gup_longterm.c index 44a3617fd423..d33d3e68ffab 100644 --- a/tools/testing/selftests/mm/gup_longterm.c +++ b/tools/testing/selftests/mm/gup_longterm.c @@ -22,6 +22,9 @@ #include #include "local_config.h" +#ifdef LOCAL_CONFIG_HAVE_LIBURING +#include +#endif /* LOCAL_CONFIG_HAVE_LIBURING */ #include "../../../../mm/gup_test.h" #include "../kselftest.h" @@ -80,6 +83,9 @@ enum test_type { TEST_TYPE_RO_FAST, TEST_TYPE_RW, TEST_TYPE_RW_FAST, +#ifdef LOCAL_CONFIG_HAVE_LIBURING + TEST_TYPE_IOURING, +#endif /* LOCAL_CONFIG_HAVE_LIBURING */ }; static void do_test(int fd, size_t size, enum test_type type, bool shared) @@ -173,6 +179,51 @@ static void do_test(int fd, size_t size, enum test_type type, bool shared) ksft_test_result(should_work, "Should have worked\n"); break; } +#ifdef LOCAL_CONFIG_HAVE_LIBURING + case TEST_TYPE_IOURING: { + struct io_uring ring; + struct iovec iov; + + /* io_uring always pins pages writable. */ + if (shared && fs_is_unknown(fs_type)) { + ksft_test_result_skip("Unknown filesystem\n"); + return; + } + should_work = !shared || + fs_supports_writable_longterm_pinning(fs_type); + + /* Skip on errors, as we might just lack kernel support. */ + ret = io_uring_queue_init(1, &ring, 0); + if (ret < 0) { + ksft_test_result_skip("io_uring_queue_init() failed\n"); + break; + } + /* + * Register the range as a fixed buffer. This will FOLL_WRITE | + * FOLL_PIN | FOLL_LONGTERM the range. + */ + iov.iov_base = mem; + iov.iov_len = size; + ret = io_uring_register_buffers(&ring, &iov, 1); + /* Only new kernels return EFAULT. */ + if (ret && (errno == ENOSPC || errno == EOPNOTSUPP || + errno == EFAULT)) { + ksft_test_result(!should_work, "Should have failed\n"); + } else if (ret) { + /* + * We might just lack support or have insufficient + * MEMLOCK limits. + */ + ksft_test_result_skip("io_uring_register_buffers() failed\n"); + } else { + ksft_test_result(should_work, "Should have worked\n"); + io_uring_unregister_buffers(&ring); + } + + io_uring_queue_exit(&ring); + break; + } +#endif /* LOCAL_CONFIG_HAVE_LIBURING */ default: assert(false); } @@ -310,6 +361,18 @@ static void test_private_ro_fast_pin(int fd, size_t size) do_test(fd, size, TEST_TYPE_RO_FAST, false); } +#ifdef LOCAL_CONFIG_HAVE_LIBURING +static void test_shared_iouring(int fd, size_t size) +{ + do_test(fd, size, TEST_TYPE_IOURING, true); +} + +static void test_private_iouring(int fd, size_t size) +{ + do_test(fd, size, TEST_TYPE_IOURING, false); +} +#endif /* LOCAL_CONFIG_HAVE_LIBURING */ + static const struct test_case test_cases[] = { { "R/W longterm GUP pin in MAP_SHARED file mapping", @@ -343,6 +406,16 @@ static const struct test_case test_cases[] = { "R/O longterm GUP-fast pin in MAP_PRIVATE file mapping", test_private_ro_fast_pin, }, +#ifdef LOCAL_CONFIG_HAVE_LIBURING + { + "io_uring fixed buffer with MAP_SHARED file mapping", + test_shared_iouring, + }, + { + "io_uring fixed buffer with MAP_PRIVATE file mapping", + test_private_iouring, + }, +#endif /* LOCAL_CONFIG_HAVE_LIBURING */ }; static void run_test_case(struct test_case const *test_case) -- cgit v1.2.3 From 19ab365762c6cc39dfdee9e13ab0d12fe4b5540d Mon Sep 17 00:00:00 2001 From: Haifeng Xu Date: Mon, 22 May 2023 09:52:33 +0000 Subject: selftests: cgroup: fix unexpected failure on test_memcg_low Since commit f079a020ba95 ("selftests: memcg: factor out common parts of memory.{low,min} tests"), the value used in second alloc_anon has changed from 148M to 170M. Because memory.low allows reclaiming page cache in child cgroups, so the memory.current is close to 30M instead of 50M. Therefore, adjust the expected value of parent cgroup. Link: https://lkml.kernel.org/r/20230522095233.4246-2-haifeng.xu@shopee.com Fixes: f079a020ba95 ("selftests: memcg: factor out common parts of memory.{low,min} tests") Signed-off-by: Haifeng Xu Cc: Johannes Weiner Cc: Michal Hocko Cc: Roman Gushchin Cc: Shakeel Butt Signed-off-by: Andrew Morton --- tools/testing/selftests/cgroup/test_memcontrol.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/cgroup/test_memcontrol.c b/tools/testing/selftests/cgroup/test_memcontrol.c index f4f7c0aef702..a2a90f4bfe9f 100644 --- a/tools/testing/selftests/cgroup/test_memcontrol.c +++ b/tools/testing/selftests/cgroup/test_memcontrol.c @@ -292,6 +292,7 @@ static int test_memcg_protection(const char *root, bool min) char *children[4] = {NULL}; const char *attribute = min ? "memory.min" : "memory.low"; long c[4]; + long current; int i, attempts; int fd; @@ -400,7 +401,8 @@ static int test_memcg_protection(const char *root, bool min) goto cleanup; } - if (!values_close(cg_read_long(parent[1], "memory.current"), MB(50), 3)) + current = min ? MB(50) : MB(30); + if (!values_close(cg_read_long(parent[1], "memory.current"), current, 3)) goto cleanup; if (!reclaim_until(children[0], MB(10))) -- cgit v1.2.3 From 26a4dd839eeba3638df8441223903baa49c6f0da Mon Sep 17 00:00:00 2001 From: Vladimir Nikishkin Date: Thu, 8 Jun 2023 14:44:48 +0800 Subject: selftests: net: vxlan: Fix selftest regression after changes in iproute2. The iproute2 output that eventually landed upstream is different than the one used in this test, resulting in failures. Fix by adjusting the test to use iproute2's JSON output, which is more stable than regular output. Fixes: 305c04189997 ("selftests: net: vxlan: Add tests for vxlan nolocalbypass option.") Signed-off-by: Vladimir Nikishkin Reviewed-by: Ido Schimmel Tested-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/test_vxlan_nolocalbypass.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh b/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh index 46067db53068..f75212bf142c 100755 --- a/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh +++ b/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh @@ -130,7 +130,7 @@ nolocalbypass() run_cmd "tc -n ns1 qdisc add dev lo clsact" run_cmd "tc -n ns1 filter add dev lo ingress pref 1 handle 101 proto ip flower ip_proto udp dst_port 4790 action drop" - run_cmd "ip -n ns1 -d link show dev vx0 | grep ' localbypass'" + run_cmd "ip -n ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == true'" log_test $? 0 "localbypass enabled" run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q" @@ -140,7 +140,7 @@ nolocalbypass() run_cmd "ip -n ns1 link set dev vx0 type vxlan nolocalbypass" - run_cmd "ip -n ns1 -d link show dev vx0 | grep 'nolocalbypass'" + run_cmd "ip -n ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == false'" log_test $? 0 "localbypass disabled" run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q" @@ -150,7 +150,7 @@ nolocalbypass() run_cmd "ip -n ns1 link set dev vx0 type vxlan localbypass" - run_cmd "ip -n ns1 -d link show dev vx0 | grep ' localbypass'" + run_cmd "ip -n ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == true'" log_test $? 0 "localbypass enabled" run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q" -- cgit v1.2.3 From ec80f488252b9ce0536c397364dd2c9cc820c1e1 Mon Sep 17 00:00:00 2001 From: Alexander Mikhalitsyn Date: Thu, 8 Jun 2023 22:26:27 +0200 Subject: selftests: net: add SCM_PIDFD / SO_PEERPIDFD test Basic test to check consistency between: - SCM_CREDENTIALS and SCM_PIDFD - SO_PEERCRED and SO_PEERPIDFD Cc: "David S. Miller" Cc: Eric Dumazet Cc: Jakub Kicinski Cc: Paolo Abeni Cc: Leon Romanovsky Cc: David Ahern Cc: Arnd Bergmann Cc: Kees Cook Cc: Christian Brauner Cc: Kuniyuki Iwashima Cc: linux-kernel@vger.kernel.org Cc: netdev@vger.kernel.org Cc: linux-arch@vger.kernel.org Cc: linux-kselftest@vger.kernel.org Signed-off-by: Alexander Mikhalitsyn Signed-off-by: David S. Miller --- tools/testing/selftests/net/.gitignore | 1 + tools/testing/selftests/net/af_unix/Makefile | 3 +- tools/testing/selftests/net/af_unix/scm_pidfd.c | 430 ++++++++++++++++++++++++ 3 files changed, 433 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/net/af_unix/scm_pidfd.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore index f27a7338b60e..501854a89cc0 100644 --- a/tools/testing/selftests/net/.gitignore +++ b/tools/testing/selftests/net/.gitignore @@ -29,6 +29,7 @@ reuseport_bpf_numa reuseport_dualstack rxtimestamp sctp_hello +scm_pidfd sk_bind_sendto_listen sk_connect_zero_addr socket diff --git a/tools/testing/selftests/net/af_unix/Makefile b/tools/testing/selftests/net/af_unix/Makefile index 1e4b397cece6..221c387a7d7f 100644 --- a/tools/testing/selftests/net/af_unix/Makefile +++ b/tools/testing/selftests/net/af_unix/Makefile @@ -1,3 +1,4 @@ -TEST_GEN_PROGS := diag_uid test_unix_oob unix_connect +CFLAGS += $(KHDR_INCLUDES) +TEST_GEN_PROGS := diag_uid test_unix_oob unix_connect scm_pidfd include ../../lib.mk diff --git a/tools/testing/selftests/net/af_unix/scm_pidfd.c b/tools/testing/selftests/net/af_unix/scm_pidfd.c new file mode 100644 index 000000000000..a86222143d79 --- /dev/null +++ b/tools/testing/selftests/net/af_unix/scm_pidfd.c @@ -0,0 +1,430 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../kselftest_harness.h" + +#define clean_errno() (errno == 0 ? "None" : strerror(errno)) +#define log_err(MSG, ...) \ + fprintf(stderr, "(%s:%d: errno: %s) " MSG "\n", __FILE__, __LINE__, \ + clean_errno(), ##__VA_ARGS__) + +#ifndef SCM_PIDFD +#define SCM_PIDFD 0x04 +#endif + +static void child_die() +{ + exit(1); +} + +static int safe_int(const char *numstr, int *converted) +{ + char *err = NULL; + long sli; + + errno = 0; + sli = strtol(numstr, &err, 0); + if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN)) + return -ERANGE; + + if (errno != 0 && sli == 0) + return -EINVAL; + + if (err == numstr || *err != '\0') + return -EINVAL; + + if (sli > INT_MAX || sli < INT_MIN) + return -ERANGE; + + *converted = (int)sli; + return 0; +} + +static int char_left_gc(const char *buffer, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) { + if (buffer[i] == ' ' || buffer[i] == '\t') + continue; + + return i; + } + + return 0; +} + +static int char_right_gc(const char *buffer, size_t len) +{ + int i; + + for (i = len - 1; i >= 0; i--) { + if (buffer[i] == ' ' || buffer[i] == '\t' || + buffer[i] == '\n' || buffer[i] == '\0') + continue; + + return i + 1; + } + + return 0; +} + +static char *trim_whitespace_in_place(char *buffer) +{ + buffer += char_left_gc(buffer, strlen(buffer)); + buffer[char_right_gc(buffer, strlen(buffer))] = '\0'; + return buffer; +} + +/* borrowed (with all helpers) from pidfd/pidfd_open_test.c */ +static pid_t get_pid_from_fdinfo_file(int pidfd, const char *key, size_t keylen) +{ + int ret; + char path[512]; + FILE *f; + size_t n = 0; + pid_t result = -1; + char *line = NULL; + + snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", pidfd); + + f = fopen(path, "re"); + if (!f) + return -1; + + while (getline(&line, &n, f) != -1) { + char *numstr; + + if (strncmp(line, key, keylen)) + continue; + + numstr = trim_whitespace_in_place(line + 4); + ret = safe_int(numstr, &result); + if (ret < 0) + goto out; + + break; + } + +out: + free(line); + fclose(f); + return result; +} + +static int cmsg_check(int fd) +{ + struct msghdr msg = { 0 }; + struct cmsghdr *cmsg; + struct iovec iov; + struct ucred *ucred = NULL; + int data = 0; + char control[CMSG_SPACE(sizeof(struct ucred)) + + CMSG_SPACE(sizeof(int))] = { 0 }; + int *pidfd = NULL; + pid_t parent_pid; + int err; + + iov.iov_base = &data; + iov.iov_len = sizeof(data); + + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = control; + msg.msg_controllen = sizeof(control); + + err = recvmsg(fd, &msg, 0); + if (err < 0) { + log_err("recvmsg"); + return 1; + } + + if (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) { + log_err("recvmsg: truncated"); + return 1; + } + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_PIDFD) { + if (cmsg->cmsg_len < sizeof(*pidfd)) { + log_err("CMSG parse: SCM_PIDFD wrong len"); + return 1; + } + + pidfd = (void *)CMSG_DATA(cmsg); + } + + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS) { + if (cmsg->cmsg_len < sizeof(*ucred)) { + log_err("CMSG parse: SCM_CREDENTIALS wrong len"); + return 1; + } + + ucred = (void *)CMSG_DATA(cmsg); + } + } + + /* send(pfd, "x", sizeof(char), 0) */ + if (data != 'x') { + log_err("recvmsg: data corruption"); + return 1; + } + + if (!pidfd) { + log_err("CMSG parse: SCM_PIDFD not found"); + return 1; + } + + if (!ucred) { + log_err("CMSG parse: SCM_CREDENTIALS not found"); + return 1; + } + + /* pidfd from SCM_PIDFD should point to the parent process PID */ + parent_pid = + get_pid_from_fdinfo_file(*pidfd, "Pid:", sizeof("Pid:") - 1); + if (parent_pid != getppid()) { + log_err("wrong SCM_PIDFD %d != %d", parent_pid, getppid()); + return 1; + } + + return 0; +} + +struct sock_addr { + char sock_name[32]; + struct sockaddr_un listen_addr; + socklen_t addrlen; +}; + +FIXTURE(scm_pidfd) +{ + int server; + pid_t client_pid; + int startup_pipe[2]; + struct sock_addr server_addr; + struct sock_addr *client_addr; +}; + +FIXTURE_VARIANT(scm_pidfd) +{ + int type; + bool abstract; +}; + +FIXTURE_VARIANT_ADD(scm_pidfd, stream_pathname) +{ + .type = SOCK_STREAM, + .abstract = 0, +}; + +FIXTURE_VARIANT_ADD(scm_pidfd, stream_abstract) +{ + .type = SOCK_STREAM, + .abstract = 1, +}; + +FIXTURE_VARIANT_ADD(scm_pidfd, dgram_pathname) +{ + .type = SOCK_DGRAM, + .abstract = 0, +}; + +FIXTURE_VARIANT_ADD(scm_pidfd, dgram_abstract) +{ + .type = SOCK_DGRAM, + .abstract = 1, +}; + +FIXTURE_SETUP(scm_pidfd) +{ + self->client_addr = mmap(NULL, sizeof(*self->client_addr), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + ASSERT_NE(MAP_FAILED, self->client_addr); +} + +FIXTURE_TEARDOWN(scm_pidfd) +{ + close(self->server); + + kill(self->client_pid, SIGKILL); + waitpid(self->client_pid, NULL, 0); + + if (!variant->abstract) { + unlink(self->server_addr.sock_name); + unlink(self->client_addr->sock_name); + } +} + +static void fill_sockaddr(struct sock_addr *addr, bool abstract) +{ + char *sun_path_buf = (char *)&addr->listen_addr.sun_path; + + addr->listen_addr.sun_family = AF_UNIX; + addr->addrlen = offsetof(struct sockaddr_un, sun_path); + snprintf(addr->sock_name, sizeof(addr->sock_name), "scm_pidfd_%d", getpid()); + addr->addrlen += strlen(addr->sock_name); + if (abstract) { + *sun_path_buf = '\0'; + addr->addrlen++; + sun_path_buf++; + } else { + unlink(addr->sock_name); + } + memcpy(sun_path_buf, addr->sock_name, strlen(addr->sock_name)); +} + +static void client(FIXTURE_DATA(scm_pidfd) *self, + const FIXTURE_VARIANT(scm_pidfd) *variant) +{ + int err; + int cfd; + socklen_t len; + struct ucred peer_cred; + int peer_pidfd; + pid_t peer_pid; + int on = 0; + + cfd = socket(AF_UNIX, variant->type, 0); + if (cfd < 0) { + log_err("socket"); + child_die(); + } + + if (variant->type == SOCK_DGRAM) { + fill_sockaddr(self->client_addr, variant->abstract); + + if (bind(cfd, (struct sockaddr *)&self->client_addr->listen_addr, self->client_addr->addrlen)) { + log_err("bind"); + child_die(); + } + } + + if (connect(cfd, (struct sockaddr *)&self->server_addr.listen_addr, + self->server_addr.addrlen) != 0) { + log_err("connect"); + child_die(); + } + + on = 1; + if (setsockopt(cfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) { + log_err("Failed to set SO_PASSCRED"); + child_die(); + } + + if (setsockopt(cfd, SOL_SOCKET, SO_PASSPIDFD, &on, sizeof(on))) { + log_err("Failed to set SO_PASSPIDFD"); + child_die(); + } + + close(self->startup_pipe[1]); + + if (cmsg_check(cfd)) { + log_err("cmsg_check failed"); + child_die(); + } + + /* skip further for SOCK_DGRAM as it's not applicable */ + if (variant->type == SOCK_DGRAM) + return; + + len = sizeof(peer_cred); + if (getsockopt(cfd, SOL_SOCKET, SO_PEERCRED, &peer_cred, &len)) { + log_err("Failed to get SO_PEERCRED"); + child_die(); + } + + len = sizeof(peer_pidfd); + if (getsockopt(cfd, SOL_SOCKET, SO_PEERPIDFD, &peer_pidfd, &len)) { + log_err("Failed to get SO_PEERPIDFD"); + child_die(); + } + + /* pid from SO_PEERCRED should point to the parent process PID */ + if (peer_cred.pid != getppid()) { + log_err("peer_cred.pid != getppid(): %d != %d", peer_cred.pid, getppid()); + child_die(); + } + + peer_pid = get_pid_from_fdinfo_file(peer_pidfd, + "Pid:", sizeof("Pid:") - 1); + if (peer_pid != peer_cred.pid) { + log_err("peer_pid != peer_cred.pid: %d != %d", peer_pid, peer_cred.pid); + child_die(); + } +} + +TEST_F(scm_pidfd, test) +{ + int err; + int pfd; + int child_status = 0; + + self->server = socket(AF_UNIX, variant->type, 0); + ASSERT_NE(-1, self->server); + + fill_sockaddr(&self->server_addr, variant->abstract); + + err = bind(self->server, (struct sockaddr *)&self->server_addr.listen_addr, self->server_addr.addrlen); + ASSERT_EQ(0, err); + + if (variant->type == SOCK_STREAM) { + err = listen(self->server, 1); + ASSERT_EQ(0, err); + } + + err = pipe(self->startup_pipe); + ASSERT_NE(-1, err); + + self->client_pid = fork(); + ASSERT_NE(-1, self->client_pid); + if (self->client_pid == 0) { + close(self->server); + close(self->startup_pipe[0]); + client(self, variant); + exit(0); + } + close(self->startup_pipe[1]); + + if (variant->type == SOCK_STREAM) { + pfd = accept(self->server, NULL, NULL); + ASSERT_NE(-1, pfd); + } else { + pfd = self->server; + } + + /* wait until the child arrives at checkpoint */ + read(self->startup_pipe[0], &err, sizeof(int)); + close(self->startup_pipe[0]); + + if (variant->type == SOCK_DGRAM) { + err = sendto(pfd, "x", sizeof(char), 0, (struct sockaddr *)&self->client_addr->listen_addr, self->client_addr->addrlen); + ASSERT_NE(-1, err); + } else { + err = send(pfd, "x", sizeof(char), 0); + ASSERT_NE(-1, err); + } + + close(pfd); + waitpid(self->client_pid, &child_status, 0); + ASSERT_EQ(0, WIFEXITED(child_status) ? WEXITSTATUS(child_status) : 1); +} + +TEST_HARNESS_MAIN -- cgit v1.2.3 From b23ed4d74c4d583b5f621ee4c776699442833554 Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Sat, 10 Jun 2023 01:16:37 +0300 Subject: selftests/bpf: Fix invalid pointer check in get_xlated_program() Dan Carpenter reported invalid check for calloc() result in test_verifier.c:get_xlated_program(): ./tools/testing/selftests/bpf/test_verifier.c:1365 get_xlated_program() warn: variable dereferenced before check 'buf' (see line 1364) ./tools/testing/selftests/bpf/test_verifier.c 1363 *cnt = xlated_prog_len / buf_element_size; 1364 *buf = calloc(*cnt, buf_element_size); 1365 if (!buf) { This should be if (!*buf) { 1366 perror("can't allocate xlated program buffer"); 1367 return -ENOMEM; This commit refactors the get_xlated_program() to avoid using double pointer type. Fixes: 933ff53191eb ("selftests/bpf: specify expected instructions in test_verifier tests") Reported-by: Dan Carpenter Signed-off-by: Eduard Zingerman Signed-off-by: Daniel Borkmann Closes: https://lore.kernel.org/bpf/ZH7u0hEGVB4MjGZq@moroto/ Link: https://lore.kernel.org/bpf/20230609221637.2631800-1-eddyz87@gmail.com --- tools/testing/selftests/bpf/test_verifier.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 71704a38cac3..31f1c935cd07 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -1341,45 +1341,46 @@ static bool cmp_str_seq(const char *log, const char *exp) return true; } -static int get_xlated_program(int fd_prog, struct bpf_insn **buf, int *cnt) +static struct bpf_insn *get_xlated_program(int fd_prog, int *cnt) { + __u32 buf_element_size = sizeof(struct bpf_insn); struct bpf_prog_info info = {}; __u32 info_len = sizeof(info); __u32 xlated_prog_len; - __u32 buf_element_size = sizeof(struct bpf_insn); + struct bpf_insn *buf; if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) { perror("bpf_prog_get_info_by_fd failed"); - return -1; + return NULL; } xlated_prog_len = info.xlated_prog_len; if (xlated_prog_len % buf_element_size) { printf("Program length %d is not multiple of %d\n", xlated_prog_len, buf_element_size); - return -1; + return NULL; } *cnt = xlated_prog_len / buf_element_size; - *buf = calloc(*cnt, buf_element_size); + buf = calloc(*cnt, buf_element_size); if (!buf) { perror("can't allocate xlated program buffer"); - return -ENOMEM; + return NULL; } bzero(&info, sizeof(info)); info.xlated_prog_len = xlated_prog_len; - info.xlated_prog_insns = (__u64)(unsigned long)*buf; + info.xlated_prog_insns = (__u64)(unsigned long)buf; if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) { perror("second bpf_prog_get_info_by_fd failed"); goto out_free_buf; } - return 0; + return buf; out_free_buf: - free(*buf); - return -1; + free(buf); + return NULL; } static bool is_null_insn(struct bpf_insn *insn) @@ -1512,7 +1513,8 @@ static bool check_xlated_program(struct bpf_test *test, int fd_prog) if (!check_expected && !check_unexpected) goto out; - if (get_xlated_program(fd_prog, &buf, &cnt)) { + buf = get_xlated_program(fd_prog, &cnt); + if (!buf) { printf("FAIL: can't get xlated program\n"); result = false; goto out; -- cgit v1.2.3 From 592efeb4a07ee46204c0f87001455c28f4743dea Mon Sep 17 00:00:00 2001 From: Mickaël Salaün Date: Mon, 12 Jun 2023 21:14:26 +0200 Subject: selftests/landlock: Don't create useless file layouts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add and use a layout0 test fixture to not populate the tmpfs filesystem if it is not required for tests: unknown_access_rights, proc_nsfs, unpriv and max_layers. This doesn't change these tests but it speeds up their setup and makes them less prone to error. This prepare the ground for a next commit. Link: https://lore.kernel.org/r/20230612191430.339153-3-mic@digikod.net Signed-off-by: Mickaël Salaün --- tools/testing/selftests/landlock/fs_test.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index b6c4be3faf7a..0438651f61d2 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -231,6 +231,20 @@ static void cleanup_layout(struct __test_metadata *const _metadata) EXPECT_EQ(0, remove_path(TMP_DIR)); } +/* clang-format off */ +FIXTURE(layout0) {}; +/* clang-format on */ + +FIXTURE_SETUP(layout0) +{ + prepare_layout(_metadata); +} + +FIXTURE_TEARDOWN(layout0) +{ + cleanup_layout(_metadata); +} + static void create_layout1(struct __test_metadata *const _metadata) { create_file(_metadata, file1_s1d1); @@ -510,7 +524,7 @@ TEST_F_FORK(layout1, file_and_dir_access_rights) ASSERT_EQ(0, close(ruleset_fd)); } -TEST_F_FORK(layout1, unknown_access_rights) +TEST_F_FORK(layout0, unknown_access_rights) { __u64 access_mask; @@ -608,7 +622,7 @@ static void enforce_ruleset(struct __test_metadata *const _metadata, } } -TEST_F_FORK(layout1, proc_nsfs) +TEST_F_FORK(layout0, proc_nsfs) { const struct rule rules[] = { { @@ -657,11 +671,11 @@ TEST_F_FORK(layout1, proc_nsfs) ASSERT_EQ(0, close(path_beneath.parent_fd)); } -TEST_F_FORK(layout1, unpriv) +TEST_F_FORK(layout0, unpriv) { const struct rule rules[] = { { - .path = dir_s1d2, + .path = TMP_DIR, .access = ACCESS_RO, }, {}, @@ -1301,12 +1315,12 @@ TEST_F_FORK(layout1, inherit_superset) ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); } -TEST_F_FORK(layout1, max_layers) +TEST_F_FORK(layout0, max_layers) { int i, err; const struct rule rules[] = { { - .path = dir_s1d2, + .path = TMP_DIR, .access = ACCESS_RO, }, {}, -- cgit v1.2.3 From 3de64b656b3c827d7d194558b0ae3a09400b116d Mon Sep 17 00:00:00 2001 From: Mickaël Salaün Date: Mon, 12 Jun 2023 21:14:27 +0200 Subject: selftests/landlock: Add supports_filesystem() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace supports_overlayfs() with supports_filesystem() to be able to check several filesystems. This will be useful in a following commit. Only check for overlay filesystem once in the setup step, and then rely on self->skip_test. Cc: Guenter Roeck Cc: Jeff Xu Link: https://lore.kernel.org/r/20230612191430.339153-4-mic@digikod.net Signed-off-by: Mickaël Salaün --- tools/testing/selftests/landlock/fs_test.c | 36 +++++++++++++++++++----------- 1 file changed, 23 insertions(+), 13 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index 0438651f61d2..c1e655fc06bb 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -107,8 +107,10 @@ static bool fgrep(FILE *const inf, const char *const str) return false; } -static bool supports_overlayfs(void) +static bool supports_filesystem(const char *const filesystem) { + char str[32]; + int len; bool res; FILE *const inf = fopen("/proc/filesystems", "r"); @@ -119,7 +121,12 @@ static bool supports_overlayfs(void) if (!inf) return true; - res = fgrep(inf, "nodev\toverlay\n"); + len = snprintf(str, sizeof(str), "nodev\t%s\n", filesystem); + if (len >= sizeof(str)) + /* Ignores too-long filesystem names. */ + return true; + + res = fgrep(inf, str); fclose(inf); return res; } @@ -4044,14 +4051,17 @@ static const char (*merge_sub_files[])[] = { * └── work */ -/* clang-format off */ -FIXTURE(layout2_overlay) {}; -/* clang-format on */ +FIXTURE(layout2_overlay) +{ + bool skip_test; +}; FIXTURE_SETUP(layout2_overlay) { - if (!supports_overlayfs()) - SKIP(return, "overlayfs is not supported"); + if (!supports_filesystem("overlay")) { + self->skip_test = true; + SKIP(return, "overlayfs is not supported (setup)"); + } prepare_layout(_metadata); @@ -4089,8 +4099,8 @@ FIXTURE_SETUP(layout2_overlay) FIXTURE_TEARDOWN(layout2_overlay) { - if (!supports_overlayfs()) - SKIP(return, "overlayfs is not supported"); + if (self->skip_test) + SKIP(return, "overlayfs is not supported (teardown)"); EXPECT_EQ(0, remove_path(lower_do1_fl3)); EXPECT_EQ(0, remove_path(lower_dl1_fl2)); @@ -4123,8 +4133,8 @@ FIXTURE_TEARDOWN(layout2_overlay) TEST_F_FORK(layout2_overlay, no_restriction) { - if (!supports_overlayfs()) - SKIP(return, "overlayfs is not supported"); + if (self->skip_test) + SKIP(return, "overlayfs is not supported (test)"); ASSERT_EQ(0, test_open(lower_fl1, O_RDONLY)); ASSERT_EQ(0, test_open(lower_dl1, O_RDONLY)); @@ -4289,8 +4299,8 @@ TEST_F_FORK(layout2_overlay, same_content_different_file) size_t i; const char *path_entry; - if (!supports_overlayfs()) - SKIP(return, "overlayfs is not supported"); + if (self->skip_test) + SKIP(return, "overlayfs is not supported (test)"); /* Sets rules on base directories (i.e. outside overlay scope). */ ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_base); -- cgit v1.2.3 From 55ab3fbe8333148e9c21477ffdc4edbe1f568f55 Mon Sep 17 00:00:00 2001 From: Mickaël Salaün Date: Mon, 12 Jun 2023 21:14:28 +0200 Subject: selftests/landlock: Make mounts configurable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new struct mnt_opt to define a mount point with the mount_opt() helper. This doesn't change tests but prepare for the next commit. Link: https://lore.kernel.org/r/20230612191430.339153-5-mic@digikod.net Signed-off-by: Mickaël Salaün --- tools/testing/selftests/landlock/fs_test.c | 45 ++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 5 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index c1e655fc06bb..737047a81547 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -213,7 +213,26 @@ out: return err; } -static void prepare_layout(struct __test_metadata *const _metadata) +struct mnt_opt { + const char *const source; + const char *const type; + const unsigned long flags; + const char *const data; +}; + +const struct mnt_opt mnt_tmp = { + .type = "tmpfs", + .data = "size=4m,mode=700", +}; + +static int mount_opt(const struct mnt_opt *const mnt, const char *const target) +{ + return mount(mnt->source ?: mnt->type, target, mnt->type, mnt->flags, + mnt->data); +} + +static void prepare_layout_opt(struct __test_metadata *const _metadata, + const struct mnt_opt *const mnt) { disable_caps(_metadata); umask(0077); @@ -225,11 +244,27 @@ static void prepare_layout(struct __test_metadata *const _metadata) */ set_cap(_metadata, CAP_SYS_ADMIN); ASSERT_EQ(0, unshare(CLONE_NEWNS)); - ASSERT_EQ(0, mount("tmp", TMP_DIR, "tmpfs", 0, "size=4m,mode=700")); + ASSERT_EQ(0, mount_opt(mnt, TMP_DIR)) + { + TH_LOG("Failed to mount the %s filesystem: %s", mnt->type, + strerror(errno)); + /* + * FIXTURE_TEARDOWN() is not called when FIXTURE_SETUP() + * failed, so we need to explicitly do a minimal cleanup to + * avoid cascading errors with other tests that don't depend on + * the same filesystem. + */ + remove_path(TMP_DIR); + } ASSERT_EQ(0, mount(NULL, TMP_DIR, NULL, MS_PRIVATE | MS_REC, NULL)); clear_cap(_metadata, CAP_SYS_ADMIN); } +static void prepare_layout(struct __test_metadata *const _metadata) +{ + prepare_layout_opt(_metadata, &mnt_tmp); +} + static void cleanup_layout(struct __test_metadata *const _metadata) { set_cap(_metadata, CAP_SYS_ADMIN); @@ -269,7 +304,7 @@ static void create_layout1(struct __test_metadata *const _metadata) create_file(_metadata, file1_s3d1); create_directory(_metadata, dir_s3d2); set_cap(_metadata, CAP_SYS_ADMIN); - ASSERT_EQ(0, mount("tmp", dir_s3d2, "tmpfs", 0, "size=4m,mode=700")); + ASSERT_EQ(0, mount_opt(&mnt_tmp, dir_s3d2)); clear_cap(_metadata, CAP_SYS_ADMIN); ASSERT_EQ(0, mkdir(dir_s3d3, 0700)); @@ -4068,7 +4103,7 @@ FIXTURE_SETUP(layout2_overlay) create_directory(_metadata, LOWER_BASE); set_cap(_metadata, CAP_SYS_ADMIN); /* Creates tmpfs mount points to get deterministic overlayfs. */ - ASSERT_EQ(0, mount("tmp", LOWER_BASE, "tmpfs", 0, "size=4m,mode=700")); + ASSERT_EQ(0, mount_opt(&mnt_tmp, LOWER_BASE)); clear_cap(_metadata, CAP_SYS_ADMIN); create_file(_metadata, lower_fl1); create_file(_metadata, lower_dl1_fl2); @@ -4078,7 +4113,7 @@ FIXTURE_SETUP(layout2_overlay) create_directory(_metadata, UPPER_BASE); set_cap(_metadata, CAP_SYS_ADMIN); - ASSERT_EQ(0, mount("tmp", UPPER_BASE, "tmpfs", 0, "size=4m,mode=700")); + ASSERT_EQ(0, mount_opt(&mnt_tmp, UPPER_BASE)); clear_cap(_metadata, CAP_SYS_ADMIN); create_file(_metadata, upper_fu1); create_file(_metadata, upper_du1_fu2); -- cgit v1.2.3 From 04f9070e99a4c5d60f05436f63e470c19b579e24 Mon Sep 17 00:00:00 2001 From: Mickaël Salaün Date: Mon, 12 Jun 2023 21:14:29 +0200 Subject: selftests/landlock: Add tests for pseudo filesystems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add generic and read-only tests for 6 pseudo filesystems to make sure they have a consistent inode management, which is required for Landlock's file hierarchy identification: - tmpfs - ramfs - cgroup2 - proc - sysfs Update related kernel configuration to support these new filesystems, remove useless CONFIG_SECURITY_PATH, and sort all entries. If these filesystems are not supported by the kernel running tests, the related tests are skipped. Expanding variants, this adds 25 new tests for layout3_fs: - tag_inode_dir_parent - tag_inode_dir_mnt - tag_inode_dir_child - tag_inode_dir_file - release_inodes Test coverage for security/landlock with kernel debug code: - 94.7% of 835 lines according to gcc/gcov-12 - 93.0% of 852 lines according to gcc/gcov-13 Test coverage for security/landlock without kernel debug code: - 95.5% of 624 lines according to gcc/gcov-12 - 93.1% of 641 lines according to gcc/gcov-13 Link: https://lore.kernel.org/r/20230612191430.339153-6-mic@digikod.net Signed-off-by: Mickaël Salaün --- tools/testing/selftests/landlock/config | 9 +- tools/testing/selftests/landlock/fs_test.c | 254 ++++++++++++++++++++++++++++- 2 files changed, 259 insertions(+), 4 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/landlock/config b/tools/testing/selftests/landlock/config index 0f0a65287bac..3dc9e438eab1 100644 --- a/tools/testing/selftests/landlock/config +++ b/tools/testing/selftests/landlock/config @@ -1,7 +1,10 @@ +CONFIG_CGROUPS=y +CONFIG_CGROUP_SCHED=y CONFIG_OVERLAY_FS=y -CONFIG_SECURITY_LANDLOCK=y -CONFIG_SECURITY_PATH=y +CONFIG_PROC_FS=y CONFIG_SECURITY=y +CONFIG_SECURITY_LANDLOCK=y CONFIG_SHMEM=y -CONFIG_TMPFS_XATTR=y +CONFIG_SYSFS=y CONFIG_TMPFS=y +CONFIG_TMPFS_XATTR=y diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index 737047a81547..2911b5241583 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -121,6 +121,10 @@ static bool supports_filesystem(const char *const filesystem) if (!inf) return true; + /* filesystem can be null for bind mounts. */ + if (!filesystem) + return true; + len = snprintf(str, sizeof(str), "nodev\t%s\n", filesystem); if (len >= sizeof(str)) /* Ignores too-long filesystem names. */ @@ -243,7 +247,7 @@ static void prepare_layout_opt(struct __test_metadata *const _metadata, * for tests relying on pivot_root(2) and move_mount(2). */ set_cap(_metadata, CAP_SYS_ADMIN); - ASSERT_EQ(0, unshare(CLONE_NEWNS)); + ASSERT_EQ(0, unshare(CLONE_NEWNS | CLONE_NEWCGROUP)); ASSERT_EQ(0, mount_opt(mnt, TMP_DIR)) { TH_LOG("Failed to mount the %s filesystem: %s", mnt->type, @@ -318,11 +322,13 @@ static void remove_layout1(struct __test_metadata *const _metadata) EXPECT_EQ(0, remove_path(file1_s1d3)); EXPECT_EQ(0, remove_path(file1_s1d2)); EXPECT_EQ(0, remove_path(file1_s1d1)); + EXPECT_EQ(0, remove_path(dir_s1d3)); EXPECT_EQ(0, remove_path(file2_s2d3)); EXPECT_EQ(0, remove_path(file1_s2d3)); EXPECT_EQ(0, remove_path(file1_s2d2)); EXPECT_EQ(0, remove_path(file1_s2d1)); + EXPECT_EQ(0, remove_path(dir_s2d2)); EXPECT_EQ(0, remove_path(file1_s3d1)); EXPECT_EQ(0, remove_path(dir_s3d3)); @@ -4482,4 +4488,250 @@ TEST_F_FORK(layout2_overlay, same_content_different_file) } } +FIXTURE(layout3_fs) +{ + bool has_created_dir; + bool has_created_file; + char *dir_path; + bool skip_test; +}; + +FIXTURE_VARIANT(layout3_fs) +{ + const struct mnt_opt mnt; + const char *const file_path; +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout3_fs, tmpfs) { + /* clang-format on */ + .mnt = mnt_tmp, + .file_path = file1_s1d1, +}; + +FIXTURE_VARIANT_ADD(layout3_fs, ramfs) { + .mnt = { + .type = "ramfs", + .data = "mode=700", + }, + .file_path = TMP_DIR "/dir/file", +}; + +FIXTURE_VARIANT_ADD(layout3_fs, cgroup2) { + .mnt = { + .type = "cgroup2", + }, + .file_path = TMP_DIR "/test/cgroup.procs", +}; + +FIXTURE_VARIANT_ADD(layout3_fs, proc) { + .mnt = { + .type = "proc", + }, + .file_path = TMP_DIR "/self/status", +}; + +FIXTURE_VARIANT_ADD(layout3_fs, sysfs) { + .mnt = { + .type = "sysfs", + }, + .file_path = TMP_DIR "/kernel/notes", +}; + +FIXTURE_SETUP(layout3_fs) +{ + struct stat statbuf; + const char *slash; + size_t dir_len; + + if (!supports_filesystem(variant->mnt.type)) { + self->skip_test = true; + SKIP(return, "this filesystem is not supported (setup)"); + } + + slash = strrchr(variant->file_path, '/'); + ASSERT_NE(slash, NULL); + dir_len = (size_t)slash - (size_t)variant->file_path; + ASSERT_LT(0, dir_len); + self->dir_path = malloc(dir_len + 1); + self->dir_path[dir_len] = '\0'; + strncpy(self->dir_path, variant->file_path, dir_len); + + prepare_layout_opt(_metadata, &variant->mnt); + + /* Creates directory when required. */ + if (stat(self->dir_path, &statbuf)) { + set_cap(_metadata, CAP_DAC_OVERRIDE); + EXPECT_EQ(0, mkdir(self->dir_path, 0700)) + { + TH_LOG("Failed to create directory \"%s\": %s", + self->dir_path, strerror(errno)); + free(self->dir_path); + self->dir_path = NULL; + } + self->has_created_dir = true; + clear_cap(_metadata, CAP_DAC_OVERRIDE); + } + + /* Creates file when required. */ + if (stat(variant->file_path, &statbuf)) { + int fd; + + set_cap(_metadata, CAP_DAC_OVERRIDE); + fd = creat(variant->file_path, 0600); + EXPECT_LE(0, fd) + { + TH_LOG("Failed to create file \"%s\": %s", + variant->file_path, strerror(errno)); + } + EXPECT_EQ(0, close(fd)); + self->has_created_file = true; + clear_cap(_metadata, CAP_DAC_OVERRIDE); + } +} + +FIXTURE_TEARDOWN(layout3_fs) +{ + if (self->skip_test) + SKIP(return, "this filesystem is not supported (teardown)"); + + if (self->has_created_file) { + set_cap(_metadata, CAP_DAC_OVERRIDE); + /* + * Don't check for error because the file might already + * have been removed (cf. release_inode test). + */ + unlink(variant->file_path); + clear_cap(_metadata, CAP_DAC_OVERRIDE); + } + + if (self->has_created_dir) { + set_cap(_metadata, CAP_DAC_OVERRIDE); + /* + * Don't check for error because the directory might already + * have been removed (cf. release_inode test). + */ + rmdir(self->dir_path); + clear_cap(_metadata, CAP_DAC_OVERRIDE); + } + free(self->dir_path); + self->dir_path = NULL; + + cleanup_layout(_metadata); +} + +static void layer3_fs_tag_inode(struct __test_metadata *const _metadata, + FIXTURE_DATA(layout3_fs) * self, + const FIXTURE_VARIANT(layout3_fs) * variant, + const char *const rule_path) +{ + const struct rule layer1_allow_read_file[] = { + { + .path = rule_path, + .access = LANDLOCK_ACCESS_FS_READ_FILE, + }, + {}, + }; + const struct landlock_ruleset_attr layer2_deny_everything_attr = { + .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE, + }; + const char *const dev_null_path = "/dev/null"; + int ruleset_fd; + + if (self->skip_test) + SKIP(return, "this filesystem is not supported (test)"); + + /* Checks without Landlock. */ + EXPECT_EQ(0, test_open(dev_null_path, O_RDONLY | O_CLOEXEC)); + EXPECT_EQ(0, test_open(variant->file_path, O_RDONLY | O_CLOEXEC)); + + ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, + layer1_allow_read_file); + EXPECT_LE(0, ruleset_fd); + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + + EXPECT_EQ(EACCES, test_open(dev_null_path, O_RDONLY | O_CLOEXEC)); + EXPECT_EQ(0, test_open(variant->file_path, O_RDONLY | O_CLOEXEC)); + + /* Forbids directory reading. */ + ruleset_fd = + landlock_create_ruleset(&layer2_deny_everything_attr, + sizeof(layer2_deny_everything_attr), 0); + EXPECT_LE(0, ruleset_fd); + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + + /* Checks with Landlock and forbidden access. */ + EXPECT_EQ(EACCES, test_open(dev_null_path, O_RDONLY | O_CLOEXEC)); + EXPECT_EQ(EACCES, test_open(variant->file_path, O_RDONLY | O_CLOEXEC)); +} + +/* Matrix of tests to check file hierarchy evaluation. */ + +TEST_F_FORK(layout3_fs, tag_inode_dir_parent) +{ + /* The current directory must not be the root for this test. */ + layer3_fs_tag_inode(_metadata, self, variant, "."); +} + +TEST_F_FORK(layout3_fs, tag_inode_dir_mnt) +{ + layer3_fs_tag_inode(_metadata, self, variant, TMP_DIR); +} + +TEST_F_FORK(layout3_fs, tag_inode_dir_child) +{ + layer3_fs_tag_inode(_metadata, self, variant, self->dir_path); +} + +TEST_F_FORK(layout3_fs, tag_inode_file) +{ + layer3_fs_tag_inode(_metadata, self, variant, variant->file_path); +} + +/* Light version of layout1.release_inodes */ +TEST_F_FORK(layout3_fs, release_inodes) +{ + const struct rule layer1[] = { + { + .path = TMP_DIR, + .access = LANDLOCK_ACCESS_FS_READ_DIR, + }, + {}, + }; + int ruleset_fd; + + if (self->skip_test) + SKIP(return, "this filesystem is not supported (test)"); + + /* Clean up for the teardown to not fail. */ + if (self->has_created_file) + EXPECT_EQ(0, remove_path(variant->file_path)); + + if (self->has_created_dir) + /* Don't check for error because of cgroup specificities. */ + remove_path(self->dir_path); + + ruleset_fd = + create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_DIR, layer1); + ASSERT_LE(0, ruleset_fd); + + /* Unmount the filesystem while it is being used by a ruleset. */ + set_cap(_metadata, CAP_SYS_ADMIN); + ASSERT_EQ(0, umount(TMP_DIR)); + clear_cap(_metadata, CAP_SYS_ADMIN); + + /* Replaces with a new mount point to simplify FIXTURE_TEARDOWN. */ + set_cap(_metadata, CAP_SYS_ADMIN); + ASSERT_EQ(0, mount_opt(&mnt_tmp, TMP_DIR)); + clear_cap(_metadata, CAP_SYS_ADMIN); + + enforce_ruleset(_metadata, ruleset_fd); + ASSERT_EQ(0, close(ruleset_fd)); + + /* Checks that access to the new mount point is denied. */ + ASSERT_EQ(EACCES, test_open(TMP_DIR, O_RDONLY)); +} + TEST_HARNESS_MAIN -- cgit v1.2.3 From 35ca4239929737bdc021ee923f97ebe7aff8fcc4 Mon Sep 17 00:00:00 2001 From: Mickaël Salaün Date: Mon, 12 Jun 2023 21:14:30 +0200 Subject: selftests/landlock: Add hostfs tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add tests for the hostfs filesystems to make sure it has a consistent inode management, which is required for Landlock's file hierarchy identification. This adds 5 new tests for layout3_fs with the hostfs variant. Add hostfs to the new (architecture-specific) config.um file. The hostfs filesystem, only available for an User-Mode Linux kernel, is special because we cannot explicitly mount it. The layout3_fs.hostfs variant tests are skipped if the current test directory is not backed by this filesystem. The layout3_fs.hostfs.tag_inode_dir_child and layout3_fs.hostfs.tag_inode_file tests pass thanks to a previous commit fixing hostfs inode management. Without this fix, the deny-by-default policy would apply and all access requests would be denied. Link: https://lore.kernel.org/r/20230612191430.339153-7-mic@digikod.net Signed-off-by: Mickaël Salaün --- tools/testing/selftests/landlock/config.um | 1 + tools/testing/selftests/landlock/fs_test.c | 28 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/landlock/config.um (limited to 'tools/testing') diff --git a/tools/testing/selftests/landlock/config.um b/tools/testing/selftests/landlock/config.um new file mode 100644 index 000000000000..40937c0395d6 --- /dev/null +++ b/tools/testing/selftests/landlock/config.um @@ -0,0 +1 @@ +CONFIG_HOSTFS=y diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index 2911b5241583..83d565569512 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -10,6 +10,7 @@ #define _GNU_SOURCE #include #include +#include #include #include #include @@ -19,6 +20,7 @@ #include #include #include +#include #include #include "common.h" @@ -135,6 +137,19 @@ static bool supports_filesystem(const char *const filesystem) return res; } +static bool cwd_matches_fs(unsigned int fs_magic) +{ + struct statfs statfs_buf; + + if (!fs_magic) + return true; + + if (statfs(".", &statfs_buf)) + return true; + + return statfs_buf.f_type == fs_magic; +} + static void mkdir_parents(struct __test_metadata *const _metadata, const char *const path) { @@ -4500,6 +4515,7 @@ FIXTURE_VARIANT(layout3_fs) { const struct mnt_opt mnt; const char *const file_path; + unsigned int cwd_fs_magic; }; /* clang-format off */ @@ -4538,13 +4554,23 @@ FIXTURE_VARIANT_ADD(layout3_fs, sysfs) { .file_path = TMP_DIR "/kernel/notes", }; +FIXTURE_VARIANT_ADD(layout3_fs, hostfs) { + .mnt = { + .source = TMP_DIR, + .flags = MS_BIND, + }, + .file_path = TMP_DIR "/dir/file", + .cwd_fs_magic = HOSTFS_SUPER_MAGIC, +}; + FIXTURE_SETUP(layout3_fs) { struct stat statbuf; const char *slash; size_t dir_len; - if (!supports_filesystem(variant->mnt.type)) { + if (!supports_filesystem(variant->mnt.type) || + !cwd_matches_fs(variant->cwd_fs_magic)) { self->skip_test = true; SKIP(return, "this filesystem is not supported (setup)"); } -- cgit v1.2.3 From 58476d8a24bd94b96ac1ab78baba8af1cc89fbeb Mon Sep 17 00:00:00 2001 From: David Vernet Date: Fri, 9 Jun 2023 22:50:50 -0500 Subject: selftests/bpf: Add test for new bpf_cpumask_first_and() kfunc A prior patch added a new kfunc called bpf_cpumask_first_and() which wraps cpumask_first_and(). This patch adds a selftest to validate its behavior. Signed-off-by: David Vernet Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20230610035053.117605-2-void@manifault.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/prog_tests/cpumask.c | 1 + tools/testing/selftests/bpf/progs/cpumask_common.h | 2 ++ .../testing/selftests/bpf/progs/cpumask_success.c | 32 ++++++++++++++++++++++ 3 files changed, 35 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/cpumask.c b/tools/testing/selftests/bpf/prog_tests/cpumask.c index d89191440fb1..756ea8b590b6 100644 --- a/tools/testing/selftests/bpf/prog_tests/cpumask.c +++ b/tools/testing/selftests/bpf/prog_tests/cpumask.c @@ -10,6 +10,7 @@ static const char * const cpumask_success_testcases[] = { "test_set_clear_cpu", "test_setall_clear_cpu", "test_first_firstzero_cpu", + "test_firstand_nocpu", "test_test_and_set_clear", "test_and_or_xor", "test_intersects_subset", diff --git a/tools/testing/selftests/bpf/progs/cpumask_common.h b/tools/testing/selftests/bpf/progs/cpumask_common.h index 0c5b785a93e4..b3493d5d263e 100644 --- a/tools/testing/selftests/bpf/progs/cpumask_common.h +++ b/tools/testing/selftests/bpf/progs/cpumask_common.h @@ -28,6 +28,8 @@ void bpf_cpumask_release(struct bpf_cpumask *cpumask) __ksym; struct bpf_cpumask *bpf_cpumask_acquire(struct bpf_cpumask *cpumask) __ksym; u32 bpf_cpumask_first(const struct cpumask *cpumask) __ksym; u32 bpf_cpumask_first_zero(const struct cpumask *cpumask) __ksym; +u32 bpf_cpumask_first_and(const struct cpumask *src1, + const struct cpumask *src2) __ksym; void bpf_cpumask_set_cpu(u32 cpu, struct bpf_cpumask *cpumask) __ksym; void bpf_cpumask_clear_cpu(u32 cpu, struct bpf_cpumask *cpumask) __ksym; bool bpf_cpumask_test_cpu(u32 cpu, const struct cpumask *cpumask) __ksym; diff --git a/tools/testing/selftests/bpf/progs/cpumask_success.c b/tools/testing/selftests/bpf/progs/cpumask_success.c index 602a88b03dbc..fbaf510f4ab5 100644 --- a/tools/testing/selftests/bpf/progs/cpumask_success.c +++ b/tools/testing/selftests/bpf/progs/cpumask_success.c @@ -175,6 +175,38 @@ release_exit: return 0; } +SEC("tp_btf/task_newtask") +int BPF_PROG(test_firstand_nocpu, struct task_struct *task, u64 clone_flags) +{ + struct bpf_cpumask *mask1, *mask2; + u32 first; + + if (!is_test_task()) + return 0; + + mask1 = create_cpumask(); + if (!mask1) + return 0; + + mask2 = create_cpumask(); + if (!mask2) + goto release_exit; + + bpf_cpumask_set_cpu(0, mask1); + bpf_cpumask_set_cpu(1, mask2); + + first = bpf_cpumask_first_and(cast(mask1), cast(mask2)); + if (first <= 1) + err = 3; + +release_exit: + if (mask1) + bpf_cpumask_release(mask1); + if (mask2) + bpf_cpumask_release(mask2); + return 0; +} + SEC("tp_btf/task_newtask") int BPF_PROG(test_test_and_set_clear, struct task_struct *task, u64 clone_flags) { -- cgit v1.2.3 From 5a73efc7d1b4b48ccb74fb399a818dfbd2250c89 Mon Sep 17 00:00:00 2001 From: David Vernet Date: Fri, 9 Jun 2023 22:50:52 -0500 Subject: selftests/bpf: Update bpf_cpumask_any* tests to use bpf_cpumask_any_distribute* In a prior patch, we removed the bpf_cpumask_any() and bpf_cpumask_any_and() kfuncs, and replaced them with bpf_cpumask_any_distribute() and bpf_cpumask_any_distribute_and(). The advertised semantics between the two kfuncs were identical, with the former always returning the first CPU, and the latter actually returning any CPU. This patch updates the selftests for these kfuncs to use the new names. Signed-off-by: David Vernet Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20230610035053.117605-4-void@manifault.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/progs/cpumask_common.h | 4 ++-- tools/testing/selftests/bpf/progs/cpumask_success.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/progs/cpumask_common.h b/tools/testing/selftests/bpf/progs/cpumask_common.h index b3493d5d263e..b15c588ace15 100644 --- a/tools/testing/selftests/bpf/progs/cpumask_common.h +++ b/tools/testing/selftests/bpf/progs/cpumask_common.h @@ -52,8 +52,8 @@ bool bpf_cpumask_subset(const struct cpumask *src1, const struct cpumask *src2) bool bpf_cpumask_empty(const struct cpumask *cpumask) __ksym; bool bpf_cpumask_full(const struct cpumask *cpumask) __ksym; void bpf_cpumask_copy(struct bpf_cpumask *dst, const struct cpumask *src) __ksym; -u32 bpf_cpumask_any(const struct cpumask *src) __ksym; -u32 bpf_cpumask_any_and(const struct cpumask *src1, const struct cpumask *src2) __ksym; +u32 bpf_cpumask_any_distribute(const struct cpumask *src) __ksym; +u32 bpf_cpumask_any_and_distribute(const struct cpumask *src1, const struct cpumask *src2) __ksym; void bpf_rcu_read_lock(void) __ksym; void bpf_rcu_read_unlock(void) __ksym; diff --git a/tools/testing/selftests/bpf/progs/cpumask_success.c b/tools/testing/selftests/bpf/progs/cpumask_success.c index fbaf510f4ab5..674a63424dee 100644 --- a/tools/testing/selftests/bpf/progs/cpumask_success.c +++ b/tools/testing/selftests/bpf/progs/cpumask_success.c @@ -344,13 +344,13 @@ int BPF_PROG(test_copy_any_anyand, struct task_struct *task, u64 clone_flags) bpf_cpumask_set_cpu(1, mask2); bpf_cpumask_or(dst1, cast(mask1), cast(mask2)); - cpu = bpf_cpumask_any(cast(mask1)); + cpu = bpf_cpumask_any_distribute(cast(mask1)); if (cpu != 0) { err = 6; goto release_exit; } - cpu = bpf_cpumask_any(cast(dst2)); + cpu = bpf_cpumask_any_distribute(cast(dst2)); if (cpu < nr_cpus) { err = 7; goto release_exit; @@ -362,13 +362,13 @@ int BPF_PROG(test_copy_any_anyand, struct task_struct *task, u64 clone_flags) goto release_exit; } - cpu = bpf_cpumask_any(cast(dst2)); + cpu = bpf_cpumask_any_distribute(cast(dst2)); if (cpu > 1) { err = 9; goto release_exit; } - cpu = bpf_cpumask_any_and(cast(mask1), cast(mask2)); + cpu = bpf_cpumask_any_and_distribute(cast(mask1), cast(mask2)); if (cpu < nr_cpus) { err = 10; goto release_exit; -- cgit v1.2.3 From e42bf3cfedec2bd759976ad202f8383ef8f17473 Mon Sep 17 00:00:00 2001 From: Ivan Orlov Date: Thu, 6 Apr 2023 00:04:50 +0400 Subject: selftests: media_tests: Add new subtest to video_device_test Add new subtest to video_device_test to cover the VIDIOC_G_PRIORITY and VIDIOC_S_PRIORITY ioctl calls. This test tries to set the priority associated with the file descriptior via ioctl VIDIOC_S_PRIORITY command from V4L2 API. After that, the test tries to get the new priority via VIDIOC_G_PRIORITY ioctl command and compares the result with the v4l2_priority it set before. At the end, the test restores the old priority. This test will increase the code coverage for video_device_test, so I think it might be useful. Additionally, this patch will refactor the video_device_test a little bit, according to the new functionality. Signed-off-by: Ivan Orlov Signed-off-by: Shuah Khan --- .../selftests/media_tests/video_device_test.c | 111 +++++++++++++++------ 1 file changed, 83 insertions(+), 28 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/media_tests/video_device_test.c b/tools/testing/selftests/media_tests/video_device_test.c index 0f6aef2e2593..2c44e115f2f0 100644 --- a/tools/testing/selftests/media_tests/video_device_test.c +++ b/tools/testing/selftests/media_tests/video_device_test.c @@ -37,45 +37,58 @@ #include #include -int main(int argc, char **argv) +#define PRIORITY_MAX 4 + +int priority_test(int fd) { - int opt; - char video_dev[256]; - int count; - struct v4l2_tuner vtuner; - struct v4l2_capability vcap; + /* This test will try to update the priority associated with a file descriptor */ + + enum v4l2_priority old_priority, new_priority, priority_to_compare; int ret; - int fd; + int result = 0; - if (argc < 2) { - printf("Usage: %s [-d ]\n", argv[0]); - exit(-1); + ret = ioctl(fd, VIDIOC_G_PRIORITY, &old_priority); + if (ret < 0) { + printf("Failed to get priority: %s\n", strerror(errno)); + return -1; + } + new_priority = (old_priority + 1) % PRIORITY_MAX; + ret = ioctl(fd, VIDIOC_S_PRIORITY, &new_priority); + if (ret < 0) { + printf("Failed to set priority: %s\n", strerror(errno)); + return -1; + } + ret = ioctl(fd, VIDIOC_G_PRIORITY, &priority_to_compare); + if (ret < 0) { + printf("Failed to get new priority: %s\n", strerror(errno)); + result = -1; + goto cleanup; + } + if (priority_to_compare != new_priority) { + printf("Priority wasn't set - test failed\n"); + result = -1; } - /* Process arguments */ - while ((opt = getopt(argc, argv, "d:")) != -1) { - switch (opt) { - case 'd': - strncpy(video_dev, optarg, sizeof(video_dev) - 1); - video_dev[sizeof(video_dev)-1] = '\0'; - break; - default: - printf("Usage: %s [-d ]\n", argv[0]); - exit(-1); - } +cleanup: + ret = ioctl(fd, VIDIOC_S_PRIORITY, &old_priority); + if (ret < 0) { + printf("Failed to restore priority: %s\n", strerror(errno)); + return -1; } + return result; +} + +int loop_test(int fd) +{ + int count; + struct v4l2_tuner vtuner; + struct v4l2_capability vcap; + int ret; /* Generate random number of interations */ srand((unsigned int) time(NULL)); count = rand(); - /* Open Video device and keep it open */ - fd = open(video_dev, O_RDWR); - if (fd == -1) { - printf("Video Device open errno %s\n", strerror(errno)); - exit(-1); - } - printf("\nNote:\n" "While test is running, remove the device or unbind\n" "driver and ensure there are no use after free errors\n" @@ -98,4 +111,46 @@ int main(int argc, char **argv) sleep(10); count--; } + return 0; +} + +int main(int argc, char **argv) +{ + int opt; + char video_dev[256]; + int fd; + int test_result; + + if (argc < 2) { + printf("Usage: %s [-d ]\n", argv[0]); + exit(-1); + } + + /* Process arguments */ + while ((opt = getopt(argc, argv, "d:")) != -1) { + switch (opt) { + case 'd': + strncpy(video_dev, optarg, sizeof(video_dev) - 1); + video_dev[sizeof(video_dev)-1] = '\0'; + break; + default: + printf("Usage: %s [-d ]\n", argv[0]); + exit(-1); + } + } + + /* Open Video device and keep it open */ + fd = open(video_dev, O_RDWR); + if (fd == -1) { + printf("Video Device open errno %s\n", strerror(errno)); + exit(-1); + } + + test_result = priority_test(fd); + if (!test_result) + printf("Priority test - PASSED\n"); + else + printf("Priority test - FAILED\n"); + + loop_test(fd); } -- cgit v1.2.3 From 17cb2f17ed50d55ca4598b3cfa58fbc3bf019280 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 29 Mar 2023 10:34:12 +0100 Subject: selftests: prctl: Fix spelling mistake "anonynous" -> "anonymous" There is a spelling mistake in an log message. Fix it. Signed-off-by: Colin Ian King Signed-off-by: Shuah Khan --- tools/testing/selftests/prctl/set-anon-vma-name-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/prctl/set-anon-vma-name-test.c b/tools/testing/selftests/prctl/set-anon-vma-name-test.c index 26d853c5a0c1..4275cb256dce 100644 --- a/tools/testing/selftests/prctl/set-anon-vma-name-test.c +++ b/tools/testing/selftests/prctl/set-anon-vma-name-test.c @@ -97,7 +97,7 @@ TEST_F(vma, renaming) { TH_LOG("Try to pass invalid name (with non-printable character \\1) to rename the VMA"); EXPECT_EQ(rename_vma((unsigned long)self->ptr_anon, AREA_SIZE, BAD_NAME), -EINVAL); - TH_LOG("Try to rename non-anonynous VMA"); + TH_LOG("Try to rename non-anonymous VMA"); EXPECT_EQ(rename_vma((unsigned long) self->ptr_not_anon, AREA_SIZE, GOOD_NAME), -EINVAL); } -- cgit v1.2.3 From 375b9ff53cb6f9c042817b75f2be0a650626dc4f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 17 Apr 2023 11:47:43 +0100 Subject: kselftest: vDSO: Fix accumulation of uninitialized ret when CLOCK_REALTIME is undefined In the unlikely case that CLOCK_REALTIME is not defined, variable ret is not initialized and further accumulation of return values to ret can leave ret in an undefined state. Fix this by initialized ret to zero and changing the assignment of ret to an accumulation for the CLOCK_REALTIME case. Fixes: 03f55c7952c9 ("kselftest: Extend vDSO selftest to clock_getres") Signed-off-by: Colin Ian King Reviewed-by: Vincenzo Frascino Signed-off-by: Shuah Khan --- tools/testing/selftests/vDSO/vdso_test_clock_getres.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/vDSO/vdso_test_clock_getres.c b/tools/testing/selftests/vDSO/vdso_test_clock_getres.c index 15dcee16ff72..38d46a8bf7cb 100644 --- a/tools/testing/selftests/vDSO/vdso_test_clock_getres.c +++ b/tools/testing/selftests/vDSO/vdso_test_clock_getres.c @@ -84,12 +84,12 @@ static inline int vdso_test_clock(unsigned int clock_id) int main(int argc, char **argv) { - int ret; + int ret = 0; #if _POSIX_TIMERS > 0 #ifdef CLOCK_REALTIME - ret = vdso_test_clock(CLOCK_REALTIME); + ret += vdso_test_clock(CLOCK_REALTIME); #endif #ifdef CLOCK_BOOTTIME -- cgit v1.2.3 From c4f461a113ec3a523a0b5b35ed9ebd90d4145672 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Thu, 4 May 2023 10:59:30 +0200 Subject: selftests/clone3: test clone3 with exit signal in flags Verify that calling clone3 with an exit signal (SIGCHLD) in flags will fail. Signed-off-by: Tobias Klauser Reviewed-by: Christian Brauner Signed-off-by: Shuah Khan --- tools/testing/selftests/clone3/clone3.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/clone3/clone3.c b/tools/testing/selftests/clone3/clone3.c index e495f895a2cd..e60cf4da8fb0 100644 --- a/tools/testing/selftests/clone3/clone3.c +++ b/tools/testing/selftests/clone3/clone3.c @@ -129,7 +129,7 @@ int main(int argc, char *argv[]) uid_t uid = getuid(); ksft_print_header(); - ksft_set_plan(18); + ksft_set_plan(19); test_clone3_supported(); /* Just a simple clone3() should return 0.*/ @@ -198,5 +198,8 @@ int main(int argc, char *argv[]) /* Do a clone3() in a new time namespace */ test_clone3(CLONE_NEWTIME, 0, 0, CLONE3_ARGS_NO_TEST); + /* Do a clone3() with exit signal (SIGCHLD) in flags */ + test_clone3(SIGCHLD, 0, -EINVAL, CLONE3_ARGS_NO_TEST); + ksft_finished(); } -- cgit v1.2.3 From 1977ecea8c75547a35fdab8827937eb2dc6048be Mon Sep 17 00:00:00 2001 From: Akanksha J N Date: Fri, 28 Apr 2023 22:08:42 +0530 Subject: selftests/ftrace: Add new test case which checks for optimized probes Add new test case kprobe_opt_types.tc which enables and checks if each probe has been optimized in order to test potential issues with optimized probes. The '|| continue' is added with the echo statement to ignore errors that are caused by trying to add kprobes to non probeable lines and continue with the test. Signed-off-by: Akanksha J N Acked-by: Masami Hiramatsu (Google) Acked-by: Shuah Khan Acked-by: Steven Rostedt (Google) Signed-off-by: Shuah Khan --- .../ftrace/test.d/kprobe/kprobe_opt_types.tc | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_opt_types.tc (limited to 'tools/testing') diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_opt_types.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_opt_types.tc new file mode 100644 index 000000000000..9f5d99328086 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_opt_types.tc @@ -0,0 +1,34 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2023 Akanksha J N, IBM corporation +# description: Register/unregister optimized probe +# requires: kprobe_events + +case `uname -m` in +x86_64) +;; +arm*) +;; +ppc*) +;; +*) + echo "Please implement other architecture here" + exit_unsupported +esac + +DEFAULT=$(cat /proc/sys/debug/kprobes-optimization) +echo 1 > /proc/sys/debug/kprobes-optimization +for i in `seq 0 255`; do + echo "p:testprobe $FUNCTION_FORK+${i}" > kprobe_events || continue + echo 1 > events/kprobes/enable || continue + (echo "forked") + PROBE=$(grep $FUNCTION_FORK /sys/kernel/debug/kprobes/list) + echo 0 > events/kprobes/enable + echo > kprobe_events + if echo $PROBE | grep -q OPTIMIZED; then + echo "$DEFAULT" > /proc/sys/debug/kprobes-optimization + exit_pass + fi +done +echo "$DEFAULT" > /proc/sys/debug/kprobes-optimization +exit_unresolved -- cgit v1.2.3 From f6a01213e3f812b645cd1079167bf47fc45bb0c8 Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Fri, 14 Apr 2023 12:38:45 -0700 Subject: selftests: allow runners to override the timeout The default timeout for selftests tests is 45 seconds. Although we already have 13 settings for tests of about 96 sefltests which use a timeout greater than this, we want to try to avoid encouraging more tests to forcing a higher test timeout as selftests strives to run all tests quickly. Selftests also uses the timeout as a non-fatal error. Only tests runners which have control over a system would know if to treat a timeout as fatal or not. To help with all this: o Enhance documentation to avoid future increases of insane timeouts o Add the option to allow overriding the default timeout with test runners with a command line option Suggested-by: Shuah Khan Signed-off-by: Luis Chamberlain Reviewed-by: Muhammad Usama Anjum Tested-by:Muhammad Usama Anjum Signed-off-by: Shuah Khan --- Documentation/dev-tools/kselftest.rst | 22 ++++++++++++++++++++++ tools/testing/selftests/kselftest/runner.sh | 11 ++++++++++- tools/testing/selftests/run_kselftest.sh | 5 +++++ 3 files changed, 37 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/Documentation/dev-tools/kselftest.rst b/Documentation/dev-tools/kselftest.rst index 12b575b76b20..dd214af7b7ff 100644 --- a/Documentation/dev-tools/kselftest.rst +++ b/Documentation/dev-tools/kselftest.rst @@ -168,6 +168,28 @@ the `-t` option for specific single tests. Either can be used multiple times:: For other features see the script usage output, seen with the `-h` option. +Timeout for selftests +===================== + +Selftests are designed to be quick and so a default timeout is used of 45 +seconds for each test. Tests can override the default timeout by adding +a settings file in their directory and set a timeout variable there to the +configured a desired upper timeout for the test. Only a few tests override +the timeout with a value higher than 45 seconds, selftests strives to keep +it that way. Timeouts in selftests are not considered fatal because the +system under which a test runs may change and this can also modify the +expected time it takes to run a test. If you have control over the systems +which will run the tests you can configure a test runner on those systems to +use a greater or lower timeout on the command line as with the `-o` or +the `--override-timeout` argument. For example to use 165 seconds instead +one would use: + + $ ./run_kselftest.sh --override-timeout 165 + +You can look at the TAP output to see if you ran into the timeout. Test +runners which know a test must run under a specific time can then optionally +treat these timeouts then as fatal. + Packaging selftests =================== diff --git a/tools/testing/selftests/kselftest/runner.sh b/tools/testing/selftests/kselftest/runner.sh index 294619ade49f..1c952d1401d4 100644 --- a/tools/testing/selftests/kselftest/runner.sh +++ b/tools/testing/selftests/kselftest/runner.sh @@ -8,7 +8,8 @@ export logfile=/dev/stdout export per_test_logging= # Defaults for "settings" file fields: -# "timeout" how many seconds to let each test run before failing. +# "timeout" how many seconds to let each test run before running +# over our soft timeout limit. export kselftest_default_timeout=45 # There isn't a shell-agnostic way to find the path of a sourced file, @@ -90,6 +91,14 @@ run_one() done < "$settings" fi + # Command line timeout overrides the settings file + if [ -n "$kselftest_override_timeout" ]; then + kselftest_timeout="$kselftest_override_timeout" + echo "# overriding timeout to $kselftest_timeout" >> "$logfile" + else + echo "# timeout set to $kselftest_timeout" >> "$logfile" + fi + TEST_HDR_MSG="selftests: $DIR: $BASENAME_TEST" echo "# $TEST_HDR_MSG" if [ ! -e "$TEST" ]; then diff --git a/tools/testing/selftests/run_kselftest.sh b/tools/testing/selftests/run_kselftest.sh index 97165a83df63..9a981b36bd7f 100755 --- a/tools/testing/selftests/run_kselftest.sh +++ b/tools/testing/selftests/run_kselftest.sh @@ -26,6 +26,7 @@ Usage: $0 [OPTIONS] -l | --list List the available collection:test entries -d | --dry-run Don't actually run any tests -h | --help Show this usage info + -o | --override-timeout Number of seconds after which we timeout EOF exit $1 } @@ -33,6 +34,7 @@ EOF COLLECTIONS="" TESTS="" dryrun="" +kselftest_override_timeout="" while true; do case "$1" in -s | --summary) @@ -51,6 +53,9 @@ while true; do -d | --dry-run) dryrun="echo" shift ;; + -o | --override-timeout) + kselftest_override_timeout="$2" + shift 2 ;; -h | --help) usage 0 ;; "") -- cgit v1.2.3 From bcda4c863efdd038c4f8ade63ff435ed663cc286 Mon Sep 17 00:00:00 2001 From: Ziqi Zhao Date: Tue, 23 May 2023 23:22:07 +0000 Subject: selftest: pidfd: Omit long and repeating outputs An output message: > # # waitpid WEXITSTATUS=0 will be printed for 30,000+ times in the `pidfd_test` selftest, which does not seem ideal. This patch removes the print logic in the `wait_for_pid` function, so each call to this function does not output a line by default. Any existing call sites where the extra line might be beneficial have been modified to include extra print statements outside of the function calls. Signed-off-by: Ziqi Zhao Reviewed-by: Christian Brauner Signed-off-by: Shuah Khan --- tools/testing/selftests/pidfd/pidfd.h | 1 - tools/testing/selftests/pidfd/pidfd_fdinfo_test.c | 1 + tools/testing/selftests/pidfd/pidfd_test.c | 3 ++- 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/pidfd/pidfd.h b/tools/testing/selftests/pidfd/pidfd.h index 6922d6417e1c..88d6830ee004 100644 --- a/tools/testing/selftests/pidfd/pidfd.h +++ b/tools/testing/selftests/pidfd/pidfd.h @@ -90,7 +90,6 @@ again: } ret = WEXITSTATUS(status); - ksft_print_msg("waitpid WEXITSTATUS=%d\n", ret); return ret; } diff --git a/tools/testing/selftests/pidfd/pidfd_fdinfo_test.c b/tools/testing/selftests/pidfd/pidfd_fdinfo_test.c index 3fd8e903118f..4e86f927880c 100644 --- a/tools/testing/selftests/pidfd/pidfd_fdinfo_test.c +++ b/tools/testing/selftests/pidfd/pidfd_fdinfo_test.c @@ -143,6 +143,7 @@ static inline int child_join(struct child *child, struct error *err) r = -1; } + ksft_print_msg("waitpid WEXITSTATUS=%d\n", r); return r; } diff --git a/tools/testing/selftests/pidfd/pidfd_test.c b/tools/testing/selftests/pidfd/pidfd_test.c index e2dd4ed84984..00a07e7c571c 100644 --- a/tools/testing/selftests/pidfd/pidfd_test.c +++ b/tools/testing/selftests/pidfd/pidfd_test.c @@ -115,7 +115,8 @@ static int test_pidfd_send_signal_exited_fail(void) pidfd = open(buf, O_DIRECTORY | O_CLOEXEC); - (void)wait_for_pid(pid); + ret = wait_for_pid(pid); + ksft_print_msg("waitpid WEXITSTATUS=%d\n", ret); if (pidfd < 0) ksft_exit_fail_msg( -- cgit v1.2.3 From 301d6815cdb3c5de9159d4564cb27e56c6cebd0b Mon Sep 17 00:00:00 2001 From: Rishabh Bhatnagar Date: Thu, 1 Jun 2023 21:11:12 +0000 Subject: kselftests: Sort the collections list to avoid duplicate tests If the collections list is not sorted uniq doesn't weed out duplicate tests correctly. Make sure to sort it before running uniq. Signed-off-by: Rishabh Bhatnagar Signed-off-by: Shuah Khan --- tools/testing/selftests/run_kselftest.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/run_kselftest.sh b/tools/testing/selftests/run_kselftest.sh index 9a981b36bd7f..92743980e553 100755 --- a/tools/testing/selftests/run_kselftest.sh +++ b/tools/testing/selftests/run_kselftest.sh @@ -90,7 +90,7 @@ if [ -n "$TESTS" ]; then available="$(echo "$valid" | sed -e 's/ /\n/g')" fi -collections=$(echo "$available" | cut -d: -f1 | uniq) +collections=$(echo "$available" | cut -d: -f1 | sort | uniq) for collection in $collections ; do [ -w /dev/kmsg ] && echo "kselftest: Running tests in $collection" >> /dev/kmsg tests=$(echo "$available" | grep "^$collection:" | cut -d: -f2) -- cgit v1.2.3 From 1e2c44992788886e536b52c1bf9d77eeb6e5969d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 6 Jun 2023 15:11:49 +0100 Subject: selftests/cpufreq: Don't enable generic lock debugging options Currently the the config fragment for cpufreq enables a lot of generic lock debugging. While these options are useful when testing cpufreq they aren't actually required to run the tests and are therefore out of scope for the cpufreq fragement, they are more of a thing that it's good to enable while doing testing than an actual requirement for cpufreq testing specifically. Having these debugging options enabled, especially the mutex and spinlock instrumentation, mean that any build that includes the cpufreq fragment is both very much larger than a standard defconfig (eg, I'm seeing 35% on x86_64) and also slower at runtime. This is causing real problems for CI systems. In order to avoid building large numbers of kernels they try to group kselftest fragments together, frequently just grouping all the kselftest fragments into a single block. The increased size is an issue for memory constrained systems and is also problematic for systems with fixed storage allocations for kernel images (eg, typical u-boot systems) where it frequently causes the kernel to overflow the storage space allocated for kernels. The reduced performance isn't too bad with real hardware but can be disruptive on emulated platforms. In order to avoid these issues remove these generic instrumentation options from the cpufreq fragment, bringing the cpufreq fragment into line with other fragments which generally set requirements for testing rather than nice to haves. Signed-off-by: Mark Brown Acked-by: Viresh Kumar Signed-off-by: Shuah Khan --- tools/testing/selftests/cpufreq/config | 8 -------- 1 file changed, 8 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/cpufreq/config b/tools/testing/selftests/cpufreq/config index 75e900793e8a..ce5068f5a6a2 100644 --- a/tools/testing/selftests/cpufreq/config +++ b/tools/testing/selftests/cpufreq/config @@ -5,11 +5,3 @@ CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y -CONFIG_DEBUG_RT_MUTEXES=y -CONFIG_DEBUG_PLIST=y -CONFIG_DEBUG_SPINLOCK=y -CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_LOCK_ALLOC=y -CONFIG_PROVE_LOCKING=y -CONFIG_LOCKDEP=y -CONFIG_DEBUG_ATOMIC_SLEEP=y -- cgit v1.2.3 From 8cd0d8633e2de4e6dd9ddae7980432e726220fdb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 10 Jun 2023 15:27:55 +0100 Subject: selftests/ftace: Fix KTAP output ordering The KTAP parser I used to test the KTAP output for ftracetest was overly robust and did not notice that the test number and pass/fail result were reversed. Fix this. Fixes: dbcf76390eb9 ("selftests/ftrace: Improve integration with kselftest runner") Signed-off-by: Mark Brown Acked-by: Masami Hiramatsu (Google) Acked-by: Steven Rostedt (Google) Signed-off-by: Shuah Khan --- tools/testing/selftests/ftrace/ftracetest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/ftrace/ftracetest b/tools/testing/selftests/ftrace/ftracetest index 2506621e75df..cb5f18c06593 100755 --- a/tools/testing/selftests/ftrace/ftracetest +++ b/tools/testing/selftests/ftrace/ftracetest @@ -301,7 +301,7 @@ ktaptest() { # result comment comment="# $comment" fi - echo $CASENO $result $INSTANCE$CASENAME $comment + echo $result $CASENO $INSTANCE$CASENAME $comment } eval_result() { # sigval -- cgit v1.2.3 From 1668a55a73f5a3ddde1019695223eed8e23b9436 Mon Sep 17 00:00:00 2001 From: Zahari Doychev Date: Thu, 8 Jun 2023 12:56:48 +0200 Subject: selftests: net: add tc flower cfm test New cfm flower test case is added to the net forwarding selfttests. Example output: # ./tc_flower_cfm.sh p1 p2 TEST: CFM opcode match test [ OK ] TEST: CFM level match test [ OK ] TEST: CFM opcode and level match test [ OK ] Signed-off-by: Zahari Doychev Reviewed-by: Ido Schimmel Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/Makefile | 1 + .../selftests/net/forwarding/tc_flower_cfm.sh | 206 +++++++++++++++++++++ 2 files changed, 207 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/tc_flower_cfm.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/Makefile b/tools/testing/selftests/net/forwarding/Makefile index 9d0062b542e5..770efbe24f0d 100644 --- a/tools/testing/selftests/net/forwarding/Makefile +++ b/tools/testing/selftests/net/forwarding/Makefile @@ -84,6 +84,7 @@ TEST_PROGS = bridge_igmp.sh \ tc_flower_router.sh \ tc_flower.sh \ tc_flower_l2_miss.sh \ + tc_flower_cfm.sh \ tc_mpls_l2vpn.sh \ tc_police.sh \ tc_shblocks.sh \ diff --git a/tools/testing/selftests/net/forwarding/tc_flower_cfm.sh b/tools/testing/selftests/net/forwarding/tc_flower_cfm.sh new file mode 100755 index 000000000000..3ca20df952eb --- /dev/null +++ b/tools/testing/selftests/net/forwarding/tc_flower_cfm.sh @@ -0,0 +1,206 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +ALL_TESTS="match_cfm_opcode match_cfm_level match_cfm_level_and_opcode" +NUM_NETIFS=2 +source tc_common.sh +source lib.sh + +h1_create() +{ + simple_if_init $h1 +} + +h1_destroy() +{ + simple_if_fini $h1 +} + +h2_create() +{ + simple_if_init $h2 + tc qdisc add dev $h2 clsact +} + +h2_destroy() +{ + tc qdisc del dev $h2 clsact + simple_if_fini $h2 +} + +u8_to_hex() +{ + local u8=$1; shift + + printf "%02x" $u8 +} + +generate_cfm_hdr() +{ + local mdl=$1; shift + local op=$1; shift + local flags=$1; shift + local tlv_offset=$1; shift + + local cfm_hdr=$(: + )"$(u8_to_hex $((mdl << 5))):"$( : MD level and Version + )"$(u8_to_hex $op):"$( : OpCode + )"$(u8_to_hex $flags):"$( : Flags + )"$(u8_to_hex $tlv_offset)"$( : TLV offset + ) + + echo $cfm_hdr +} + +match_cfm_opcode() +{ + local ethtype="89 02"; readonly ethtype + RET=0 + + tc filter add dev $h2 ingress protocol cfm pref 1 handle 101 \ + flower cfm op 47 action drop + tc filter add dev $h2 ingress protocol cfm pref 1 handle 102 \ + flower cfm op 43 action drop + + pkt="$ethtype $(generate_cfm_hdr 7 47 0 32)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + pkt="$ethtype $(generate_cfm_hdr 6 5 0 4)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Did not match on correct opcode" + + tc_check_packets "dev $h2 ingress" 102 0 + check_err $? "Matched on the wrong opcode" + + pkt="$ethtype $(generate_cfm_hdr 0 43 0 12)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Matched on the wrong opcode" + + tc_check_packets "dev $h2 ingress" 102 1 + check_err $? "Did not match on correct opcode" + + tc filter del dev $h2 ingress protocol cfm pref 1 handle 101 flower + tc filter del dev $h2 ingress protocol cfm pref 1 handle 102 flower + + log_test "CFM opcode match test" +} + +match_cfm_level() +{ + local ethtype="89 02"; readonly ethtype + RET=0 + + tc filter add dev $h2 ingress protocol cfm pref 1 handle 101 \ + flower cfm mdl 5 action drop + tc filter add dev $h2 ingress protocol cfm pref 1 handle 102 \ + flower cfm mdl 3 action drop + tc filter add dev $h2 ingress protocol cfm pref 1 handle 103 \ + flower cfm mdl 0 action drop + + pkt="$ethtype $(generate_cfm_hdr 5 42 0 12)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + pkt="$ethtype $(generate_cfm_hdr 6 1 0 70)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + pkt="$ethtype $(generate_cfm_hdr 0 1 0 70)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Did not match on correct level" + + tc_check_packets "dev $h2 ingress" 102 0 + check_err $? "Matched on the wrong level" + + tc_check_packets "dev $h2 ingress" 103 1 + check_err $? "Did not match on correct level" + + pkt="$ethtype $(generate_cfm_hdr 3 0 0 4)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Matched on the wrong level" + + tc_check_packets "dev $h2 ingress" 102 1 + check_err $? "Did not match on correct level" + + tc_check_packets "dev $h2 ingress" 103 1 + check_err $? "Matched on the wrong level" + + tc filter del dev $h2 ingress protocol cfm pref 1 handle 101 flower + tc filter del dev $h2 ingress protocol cfm pref 1 handle 102 flower + tc filter del dev $h2 ingress protocol cfm pref 1 handle 103 flower + + log_test "CFM level match test" +} + +match_cfm_level_and_opcode() +{ + local ethtype="89 02"; readonly ethtype + RET=0 + + tc filter add dev $h2 ingress protocol cfm pref 1 handle 101 \ + flower cfm mdl 5 op 41 action drop + tc filter add dev $h2 ingress protocol cfm pref 1 handle 102 \ + flower cfm mdl 7 op 42 action drop + + pkt="$ethtype $(generate_cfm_hdr 5 41 0 4)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + pkt="$ethtype $(generate_cfm_hdr 7 3 0 4)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + pkt="$ethtype $(generate_cfm_hdr 3 42 0 12)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Did not match on correct level and opcode" + + tc_check_packets "dev $h2 ingress" 102 0 + check_err $? "Matched on the wrong level and opcode" + + pkt="$ethtype $(generate_cfm_hdr 7 42 0 12)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Matched on the wrong level and opcode" + + tc_check_packets "dev $h2 ingress" 102 1 + check_err $? "Did not match on correct level and opcode" + + tc filter del dev $h2 ingress protocol cfm pref 1 handle 101 flower + tc filter del dev $h2 ingress protocol cfm pref 1 handle 102 flower + + log_test "CFM opcode and level match test" +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + h2=${NETIFS[p2]} + h1mac=$(mac_get $h1) + h2mac=$(mac_get $h2) + + vrf_prepare + + h1_create + h2_create +} + +cleanup() +{ + pre_cleanup + + h2_destroy + h1_destroy + + vrf_cleanup +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +tests_run + +exit $EXIT_STATUS -- cgit v1.2.3 From c29e012eae29c13f092a95f1ffab40a269fe5bc2 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 11 Jun 2023 14:22:18 +0300 Subject: selftests: forwarding: Fix layer 2 miss test syntax The test currently specifies "l2_miss" as "true" / "false", but the version that eventually landed in iproute2 uses "1" / "0" [1]. Align the test accordingly. [1] https://lore.kernel.org/netdev/20230607153550.3829340-1-idosch@nvidia.com/ Fixes: 8c33266ae26a ("selftests: forwarding: Add layer 2 miss test cases") Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- .../testing/selftests/net/forwarding/tc_flower_l2_miss.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh b/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh index 37b0369b5246..e22c2d28b6eb 100755 --- a/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh +++ b/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh @@ -78,11 +78,11 @@ test_l2_miss_unicast() # Unknown unicast. tc filter add dev $swp2 egress protocol ipv4 handle 101 pref 1 \ - flower indev $swp1 l2_miss true dst_mac $dmac src_ip $sip \ + flower indev $swp1 l2_miss 1 dst_mac $dmac src_ip $sip \ dst_ip $dip action pass # Known unicast. tc filter add dev $swp2 egress protocol ipv4 handle 102 pref 1 \ - flower indev $swp1 l2_miss false dst_mac $dmac src_ip $sip \ + flower indev $swp1 l2_miss 0 dst_mac $dmac src_ip $sip \ dst_ip $dip action pass # Before adding FDB entry. @@ -134,11 +134,11 @@ test_l2_miss_multicast_common() # Unregistered multicast. tc filter add dev $swp2 egress protocol $proto handle 101 pref 1 \ - flower indev $swp1 l2_miss true src_ip $sip dst_ip $dip \ + flower indev $swp1 l2_miss 1 src_ip $sip dst_ip $dip \ action pass # Registered multicast. tc filter add dev $swp2 egress protocol $proto handle 102 pref 1 \ - flower indev $swp1 l2_miss false src_ip $sip dst_ip $dip \ + flower indev $swp1 l2_miss 0 src_ip $sip dst_ip $dip \ action pass # Before adding MDB entry. @@ -245,7 +245,7 @@ test_l2_miss_ll_multicast_common() RET=0 tc filter add dev $swp2 egress protocol $proto handle 101 pref 1 \ - flower indev $swp1 l2_miss true dst_mac $dmac src_ip $sip \ + flower indev $swp1 l2_miss 1 dst_mac $dmac src_ip $sip \ dst_ip $dip action pass $MZ $mode $h1 -a own -b $dmac -t ip -A $sip -B $dip -c 1 -p 100 -q @@ -296,10 +296,10 @@ test_l2_miss_broadcast() RET=0 tc filter add dev $swp2 egress protocol all handle 101 pref 1 \ - flower l2_miss true dst_mac $dmac src_mac $smac \ + flower l2_miss 1 dst_mac $dmac src_mac $smac \ action pass tc filter add dev $swp2 egress protocol all handle 102 pref 1 \ - flower l2_miss false dst_mac $dmac src_mac $smac \ + flower l2_miss 0 dst_mac $dmac src_mac $smac \ action pass $MZ $h1 -a $smac -b $dmac -c 1 -p 100 -q -- cgit v1.2.3 From 904e6ddf4133c52fdb9654c2cd2ad90f320d48b9 Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Tue, 13 Jun 2023 18:38:21 +0300 Subject: bpf: Use scalar ids in mark_chain_precision() Change mark_chain_precision() to track precision in situations like below: r2 = unknown value ... --- state #0 --- ... r1 = r2 // r1 and r2 now share the same ID ... --- state #1 {r1.id = A, r2.id = A} --- ... if (r2 > 10) goto exit; // find_equal_scalars() assigns range to r1 ... --- state #2 {r1.id = A, r2.id = A} --- r3 = r10 r3 += r1 // need to mark both r1 and r2 At the beginning of the processing of each state, ensure that if a register with a scalar ID is marked as precise, all registers sharing this ID are also marked as precise. This property would be used by a follow-up change in regsafe(). Signed-off-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20230613153824.3324830-2-eddyz87@gmail.com --- include/linux/bpf_verifier.h | 10 ++- kernel/bpf/verifier.c | 115 +++++++++++++++++++++++++ tools/testing/selftests/bpf/verifier/precise.c | 8 +- 3 files changed, 128 insertions(+), 5 deletions(-) (limited to 'tools/testing') diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 5b11a3b0fec0..22fb13c738a9 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -557,6 +557,11 @@ struct backtrack_state { u64 stack_masks[MAX_CALL_FRAMES]; }; +struct bpf_idset { + u32 count; + u32 ids[BPF_ID_MAP_SIZE]; +}; + /* single container for all structs * one verifier_env per bpf_check() call */ @@ -588,7 +593,10 @@ struct bpf_verifier_env { const struct bpf_line_info *prev_linfo; struct bpf_verifier_log log; struct bpf_subprog_info subprog_info[BPF_MAX_SUBPROGS + 1]; - struct bpf_id_pair idmap_scratch[BPF_ID_MAP_SIZE]; + union { + struct bpf_id_pair idmap_scratch[BPF_ID_MAP_SIZE]; + struct bpf_idset idset_scratch; + }; struct { int *insn_state; int *insn_stack; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 1e38584d497c..064aef5cd186 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -3779,6 +3779,96 @@ static void mark_all_scalars_imprecise(struct bpf_verifier_env *env, struct bpf_ } } +static bool idset_contains(struct bpf_idset *s, u32 id) +{ + u32 i; + + for (i = 0; i < s->count; ++i) + if (s->ids[i] == id) + return true; + + return false; +} + +static int idset_push(struct bpf_idset *s, u32 id) +{ + if (WARN_ON_ONCE(s->count >= ARRAY_SIZE(s->ids))) + return -EFAULT; + s->ids[s->count++] = id; + return 0; +} + +static void idset_reset(struct bpf_idset *s) +{ + s->count = 0; +} + +/* Collect a set of IDs for all registers currently marked as precise in env->bt. + * Mark all registers with these IDs as precise. + */ +static int mark_precise_scalar_ids(struct bpf_verifier_env *env, struct bpf_verifier_state *st) +{ + struct bpf_idset *precise_ids = &env->idset_scratch; + struct backtrack_state *bt = &env->bt; + struct bpf_func_state *func; + struct bpf_reg_state *reg; + DECLARE_BITMAP(mask, 64); + int i, fr; + + idset_reset(precise_ids); + + for (fr = bt->frame; fr >= 0; fr--) { + func = st->frame[fr]; + + bitmap_from_u64(mask, bt_frame_reg_mask(bt, fr)); + for_each_set_bit(i, mask, 32) { + reg = &func->regs[i]; + if (!reg->id || reg->type != SCALAR_VALUE) + continue; + if (idset_push(precise_ids, reg->id)) + return -EFAULT; + } + + bitmap_from_u64(mask, bt_frame_stack_mask(bt, fr)); + for_each_set_bit(i, mask, 64) { + if (i >= func->allocated_stack / BPF_REG_SIZE) + break; + if (!is_spilled_scalar_reg(&func->stack[i])) + continue; + reg = &func->stack[i].spilled_ptr; + if (!reg->id) + continue; + if (idset_push(precise_ids, reg->id)) + return -EFAULT; + } + } + + for (fr = 0; fr <= st->curframe; ++fr) { + func = st->frame[fr]; + + for (i = BPF_REG_0; i < BPF_REG_10; ++i) { + reg = &func->regs[i]; + if (!reg->id) + continue; + if (!idset_contains(precise_ids, reg->id)) + continue; + bt_set_frame_reg(bt, fr, i); + } + for (i = 0; i < func->allocated_stack / BPF_REG_SIZE; ++i) { + if (!is_spilled_scalar_reg(&func->stack[i])) + continue; + reg = &func->stack[i].spilled_ptr; + if (!reg->id) + continue; + if (!idset_contains(precise_ids, reg->id)) + continue; + bt_set_frame_slot(bt, fr, i); + } + } + + return 0; +} + /* * __mark_chain_precision() backtracks BPF program instruction sequence and * chain of verifier states making sure that register *regno* (if regno >= 0) @@ -3910,6 +4000,31 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) bt->frame, last_idx, first_idx, subseq_idx); } + /* If some register with scalar ID is marked as precise, + * make sure that all registers sharing this ID are also precise. + * This is needed to estimate effect of find_equal_scalars(). + * Do this at the last instruction of each state, + * bpf_reg_state::id fields are valid for these instructions. + * + * Allows to track precision in situation like below: + * + * r2 = unknown value + * ... + * --- state #0 --- + * ... + * r1 = r2 // r1 and r2 now share the same ID + * ... + * --- state #1 {r1.id = A, r2.id = A} --- + * ... + * if (r2 > 10) goto exit; // find_equal_scalars() assigns range to r1 + * ... + * --- state #2 {r1.id = A, r2.id = A} --- + * r3 = r10 + * r3 += r1 // need to mark both r1 and r2 + */ + if (mark_precise_scalar_ids(env, st)) + return -EFAULT; + if (last_idx < 0) { /* we are at the entry into subprog, which * is expected for global funcs, but only if diff --git a/tools/testing/selftests/bpf/verifier/precise.c b/tools/testing/selftests/bpf/verifier/precise.c index b8c0aae8e7ec..99272bb890da 100644 --- a/tools/testing/selftests/bpf/verifier/precise.c +++ b/tools/testing/selftests/bpf/verifier/precise.c @@ -46,7 +46,7 @@ mark_precise: frame0: regs=r2 stack= before 20\ mark_precise: frame0: parent state regs=r2 stack=:\ mark_precise: frame0: last_idx 19 first_idx 10\ - mark_precise: frame0: regs=r2 stack= before 19\ + mark_precise: frame0: regs=r2,r9 stack= before 19\ mark_precise: frame0: regs=r9 stack= before 18\ mark_precise: frame0: regs=r8,r9 stack= before 17\ mark_precise: frame0: regs=r0,r9 stack= before 15\ @@ -106,10 +106,10 @@ mark_precise: frame0: regs=r2 stack= before 22\ mark_precise: frame0: parent state regs=r2 stack=:\ mark_precise: frame0: last_idx 20 first_idx 20\ - mark_precise: frame0: regs=r2 stack= before 20\ - mark_precise: frame0: parent state regs=r2 stack=:\ + mark_precise: frame0: regs=r2,r9 stack= before 20\ + mark_precise: frame0: parent state regs=r2,r9 stack=:\ mark_precise: frame0: last_idx 19 first_idx 17\ - mark_precise: frame0: regs=r2 stack= before 19\ + mark_precise: frame0: regs=r2,r9 stack= before 19\ mark_precise: frame0: regs=r9 stack= before 18\ mark_precise: frame0: regs=r8,r9 stack= before 17\ mark_precise: frame0: parent state regs= stack=:", -- cgit v1.2.3 From dec020280373c60d6df48d1954e72dd6c5640282 Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Tue, 13 Jun 2023 18:38:22 +0300 Subject: selftests/bpf: Check if mark_chain_precision() follows scalar ids Check __mark_chain_precision() log to verify that scalars with same IDs are marked as precise. Use several scenarios to test that precision marks are propagated through: - registers of scalar type with the same ID within one state; - registers of scalar type with the same ID cross several states; - registers of scalar type with the same ID cross several stack frames; - stack slot of scalar type with the same ID; - multiple scalar IDs are tracked independently. Signed-off-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20230613153824.3324830-3-eddyz87@gmail.com --- tools/testing/selftests/bpf/prog_tests/verifier.c | 2 + .../selftests/bpf/progs/verifier_scalar_ids.c | 344 +++++++++++++++++++++ 2 files changed, 346 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/verifier_scalar_ids.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c index 531621adef42..070a13833c3f 100644 --- a/tools/testing/selftests/bpf/prog_tests/verifier.c +++ b/tools/testing/selftests/bpf/prog_tests/verifier.c @@ -50,6 +50,7 @@ #include "verifier_regalloc.skel.h" #include "verifier_ringbuf.skel.h" #include "verifier_runtime_jit.skel.h" +#include "verifier_scalar_ids.skel.h" #include "verifier_search_pruning.skel.h" #include "verifier_sock.skel.h" #include "verifier_spill_fill.skel.h" @@ -150,6 +151,7 @@ void test_verifier_ref_tracking(void) { RUN(verifier_ref_tracking); } void test_verifier_regalloc(void) { RUN(verifier_regalloc); } void test_verifier_ringbuf(void) { RUN(verifier_ringbuf); } void test_verifier_runtime_jit(void) { RUN(verifier_runtime_jit); } +void test_verifier_scalar_ids(void) { RUN(verifier_scalar_ids); } void test_verifier_search_pruning(void) { RUN(verifier_search_pruning); } void test_verifier_sock(void) { RUN(verifier_sock); } void test_verifier_spill_fill(void) { RUN(verifier_spill_fill); } diff --git a/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c new file mode 100644 index 000000000000..8a5203fb14ca --- /dev/null +++ b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include "bpf_misc.h" + +/* Check that precision marks propagate through scalar IDs. + * Registers r{0,1,2} have the same scalar ID at the moment when r0 is + * marked to be precise, this mark is immediately propagated to r{1,2}. + */ +SEC("socket") +__success __log_level(2) +__msg("frame0: regs=r0,r1,r2 stack= before 4: (bf) r3 = r10") +__msg("frame0: regs=r0,r1,r2 stack= before 3: (bf) r2 = r0") +__msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") +__msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") +__msg("frame0: regs=r0 stack= before 0: (85) call bpf_ktime_get_ns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void precision_same_state(void) +{ + asm volatile ( + /* r0 = random number up to 0xff */ + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + /* tie r0.id == r1.id == r2.id */ + "r1 = r0;" + "r2 = r0;" + /* force r0 to be precise, this immediately marks r1 and r2 as + * precise as well because of shared IDs + */ + "r3 = r10;" + "r3 += r0;" + "r0 = 0;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Same as precision_same_state, but mark propagates through state / + * parent state boundary. + */ +SEC("socket") +__success __log_level(2) +__msg("frame0: last_idx 6 first_idx 5 subseq_idx -1") +__msg("frame0: regs=r0,r1,r2 stack= before 5: (bf) r3 = r10") +__msg("frame0: parent state regs=r0,r1,r2 stack=:") +__msg("frame0: regs=r0,r1,r2 stack= before 4: (05) goto pc+0") +__msg("frame0: regs=r0,r1,r2 stack= before 3: (bf) r2 = r0") +__msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") +__msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") +__msg("frame0: parent state regs=r0 stack=:") +__msg("frame0: regs=r0 stack= before 0: (85) call bpf_ktime_get_ns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void precision_cross_state(void) +{ + asm volatile ( + /* r0 = random number up to 0xff */ + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + /* tie r0.id == r1.id == r2.id */ + "r1 = r0;" + "r2 = r0;" + /* force checkpoint */ + "goto +0;" + /* force r0 to be precise, this immediately marks r1 and r2 as + * precise as well because of shared IDs + */ + "r3 = r10;" + "r3 += r0;" + "r0 = 0;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Same as precision_same_state, but break one of the + * links, note that r1 is absent from regs=... in __msg below. + */ +SEC("socket") +__success __log_level(2) +__msg("frame0: regs=r0,r2 stack= before 5: (bf) r3 = r10") +__msg("frame0: regs=r0,r2 stack= before 4: (b7) r1 = 0") +__msg("frame0: regs=r0,r2 stack= before 3: (bf) r2 = r0") +__msg("frame0: regs=r0 stack= before 2: (bf) r1 = r0") +__msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") +__msg("frame0: regs=r0 stack= before 0: (85) call bpf_ktime_get_ns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void precision_same_state_broken_link(void) +{ + asm volatile ( + /* r0 = random number up to 0xff */ + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + /* tie r0.id == r1.id == r2.id */ + "r1 = r0;" + "r2 = r0;" + /* break link for r1, this is the only line that differs + * compared to the previous test + */ + "r1 = 0;" + /* force r0 to be precise, this immediately marks r1 and r2 as + * precise as well because of shared IDs + */ + "r3 = r10;" + "r3 += r0;" + "r0 = 0;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Same as precision_same_state_broken_link, but with state / + * parent state boundary. + */ +SEC("socket") +__success __log_level(2) +__msg("frame0: regs=r0,r2 stack= before 6: (bf) r3 = r10") +__msg("frame0: regs=r0,r2 stack= before 5: (b7) r1 = 0") +__msg("frame0: parent state regs=r0,r2 stack=:") +__msg("frame0: regs=r0,r1,r2 stack= before 4: (05) goto pc+0") +__msg("frame0: regs=r0,r1,r2 stack= before 3: (bf) r2 = r0") +__msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") +__msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") +__msg("frame0: parent state regs=r0 stack=:") +__msg("frame0: regs=r0 stack= before 0: (85) call bpf_ktime_get_ns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void precision_cross_state_broken_link(void) +{ + asm volatile ( + /* r0 = random number up to 0xff */ + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + /* tie r0.id == r1.id == r2.id */ + "r1 = r0;" + "r2 = r0;" + /* force checkpoint, although link between r1 and r{0,2} is + * broken by the next statement current precision tracking + * algorithm can't react to it and propagates mark for r1 to + * the parent state. + */ + "goto +0;" + /* break link for r1, this is the only line that differs + * compared to precision_cross_state() + */ + "r1 = 0;" + /* force r0 to be precise, this immediately marks r1 and r2 as + * precise as well because of shared IDs + */ + "r3 = r10;" + "r3 += r0;" + "r0 = 0;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Check that precision marks propagate through scalar IDs. + * Use the same scalar ID in multiple stack frames, check that + * precision information is propagated up the call stack. + */ +SEC("socket") +__success __log_level(2) +__msg("11: (0f) r2 += r1") +/* Current state */ +__msg("frame2: last_idx 11 first_idx 10 subseq_idx -1") +__msg("frame2: regs=r1 stack= before 10: (bf) r2 = r10") +__msg("frame2: parent state regs=r1 stack=") +/* frame1.r{6,7} are marked because mark_precise_scalar_ids() + * looks for all registers with frame2.r1.id in the current state + */ +__msg("frame1: parent state regs=r6,r7 stack=") +__msg("frame0: parent state regs=r6 stack=") +/* Parent state */ +__msg("frame2: last_idx 8 first_idx 8 subseq_idx 10") +__msg("frame2: regs=r1 stack= before 8: (85) call pc+1") +/* frame1.r1 is marked because of backtracking of call instruction */ +__msg("frame1: parent state regs=r1,r6,r7 stack=") +__msg("frame0: parent state regs=r6 stack=") +/* Parent state */ +__msg("frame1: last_idx 7 first_idx 6 subseq_idx 8") +__msg("frame1: regs=r1,r6,r7 stack= before 7: (bf) r7 = r1") +__msg("frame1: regs=r1,r6 stack= before 6: (bf) r6 = r1") +__msg("frame1: parent state regs=r1 stack=") +__msg("frame0: parent state regs=r6 stack=") +/* Parent state */ +__msg("frame1: last_idx 4 first_idx 4 subseq_idx 6") +__msg("frame1: regs=r1 stack= before 4: (85) call pc+1") +__msg("frame0: parent state regs=r1,r6 stack=") +/* Parent state */ +__msg("frame0: last_idx 3 first_idx 1 subseq_idx 4") +__msg("frame0: regs=r0,r1,r6 stack= before 3: (bf) r6 = r0") +__msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") +__msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void precision_many_frames(void) +{ + asm volatile ( + /* r0 = random number up to 0xff */ + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + /* tie r0.id == r1.id == r6.id */ + "r1 = r0;" + "r6 = r0;" + "call precision_many_frames__foo;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +static __naked __noinline __used +void precision_many_frames__foo(void) +{ + asm volatile ( + /* conflate one of the register numbers (r6) with outer frame, + * to verify that those are tracked independently + */ + "r6 = r1;" + "r7 = r1;" + "call precision_many_frames__bar;" + "exit" + ::: __clobber_all); +} + +static __naked __noinline __used +void precision_many_frames__bar(void) +{ + asm volatile ( + /* force r1 to be precise, this immediately marks: + * - bar frame r1 + * - foo frame r{1,6,7} + * - main frame r{1,6} + */ + "r2 = r10;" + "r2 += r1;" + "r0 = 0;" + "exit;" + ::: __clobber_all); +} + +/* Check that scalars with the same IDs are marked precise on stack as + * well as in registers. + */ +SEC("socket") +__success __log_level(2) +/* foo frame */ +__msg("frame1: regs=r1 stack=-8,-16 before 9: (bf) r2 = r10") +__msg("frame1: regs=r1 stack=-8,-16 before 8: (7b) *(u64 *)(r10 -16) = r1") +__msg("frame1: regs=r1 stack=-8 before 7: (7b) *(u64 *)(r10 -8) = r1") +__msg("frame1: regs=r1 stack= before 4: (85) call pc+2") +/* main frame */ +__msg("frame0: regs=r0,r1 stack=-8 before 3: (7b) *(u64 *)(r10 -8) = r1") +__msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") +__msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void precision_stack(void) +{ + asm volatile ( + /* r0 = random number up to 0xff */ + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + /* tie r0.id == r1.id == fp[-8].id */ + "r1 = r0;" + "*(u64*)(r10 - 8) = r1;" + "call precision_stack__foo;" + "r0 = 0;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +static __naked __noinline __used +void precision_stack__foo(void) +{ + asm volatile ( + /* conflate one of the register numbers (r6) with outer frame, + * to verify that those are tracked independently + */ + "*(u64*)(r10 - 8) = r1;" + "*(u64*)(r10 - 16) = r1;" + /* force r1 to be precise, this immediately marks: + * - foo frame r1,fp{-8,-16} + * - main frame r1,fp{-8} + */ + "r2 = r10;" + "r2 += r1;" + "exit" + ::: __clobber_all); +} + +/* Use two separate scalar IDs to check that these are propagated + * independently. + */ +SEC("socket") +__success __log_level(2) +/* r{6,7} */ +__msg("11: (0f) r3 += r7") +__msg("frame0: regs=r6,r7 stack= before 10: (bf) r3 = r10") +/* ... skip some insns ... */ +__msg("frame0: regs=r6,r7 stack= before 3: (bf) r7 = r0") +__msg("frame0: regs=r0,r6 stack= before 2: (bf) r6 = r0") +/* r{8,9} */ +__msg("12: (0f) r3 += r9") +__msg("frame0: regs=r8,r9 stack= before 11: (0f) r3 += r7") +/* ... skip some insns ... */ +__msg("frame0: regs=r8,r9 stack= before 7: (bf) r9 = r0") +__msg("frame0: regs=r0,r8 stack= before 6: (bf) r8 = r0") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void precision_two_ids(void) +{ + asm volatile ( + /* r6 = random number up to 0xff + * r6.id == r7.id + */ + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + "r6 = r0;" + "r7 = r0;" + /* same, but for r{8,9} */ + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + "r8 = r0;" + "r9 = r0;" + /* clear r0 id */ + "r0 = 0;" + /* force checkpoint */ + "goto +0;" + "r3 = r10;" + /* force r7 to be precise, this also marks r6 */ + "r3 += r7;" + /* force r9 to be precise, this also marks r8 */ + "r3 += r9;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +char _license[] SEC("license") = "GPL"; -- cgit v1.2.3 From 18b89265572b5c899522b6c1f8698e87edfad369 Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Tue, 13 Jun 2023 18:38:24 +0300 Subject: selftests/bpf: Verify that check_ids() is used for scalars in regsafe() Verify that the following example is rejected by verifier: r9 = ... some pointer with range X ... r6 = ... unbound scalar ID=a ... r7 = ... unbound scalar ID=b ... if (r6 > r7) goto +1 r7 = r6 if (r7 > X) goto exit r9 += r6 *(u64 *)r9 = Y Also add test cases to: - check that check_alu_op() for BPF_MOV instruction does not allocate scalar ID if source register is a constant; - check that unique scalar IDs are ignored when new verifier state is compared to cached verifier state; - check that two different scalar IDs in a verified state can't be mapped to the same scalar ID in current state. Signed-off-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20230613153824.3324830-5-eddyz87@gmail.com --- .../selftests/bpf/progs/verifier_scalar_ids.c | 315 +++++++++++++++++++++ 1 file changed, 315 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c index 8a5203fb14ca..13b29a7faa71 100644 --- a/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c +++ b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c @@ -341,4 +341,319 @@ __naked void precision_two_ids(void) : __clobber_all); } +/* Verify that check_ids() is used by regsafe() for scalars. + * + * r9 = ... some pointer with range X ... + * r6 = ... unbound scalar ID=a ... + * r7 = ... unbound scalar ID=b ... + * if (r6 > r7) goto +1 + * r7 = r6 + * if (r7 > X) goto exit + * r9 += r6 + * ... access memory using r9 ... + * + * The memory access is safe only if r7 is bounded, + * which is true for one branch and not true for another. + */ +SEC("socket") +__failure __msg("register with unbounded min value") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void check_ids_in_regsafe(void) +{ + asm volatile ( + /* Bump allocated stack */ + "r1 = 0;" + "*(u64*)(r10 - 8) = r1;" + /* r9 = pointer to stack */ + "r9 = r10;" + "r9 += -8;" + /* r7 = ktime_get_ns() */ + "call %[bpf_ktime_get_ns];" + "r7 = r0;" + /* r6 = ktime_get_ns() */ + "call %[bpf_ktime_get_ns];" + "r6 = r0;" + /* if r6 > r7 is an unpredictable jump */ + "if r6 > r7 goto l1_%=;" + "r7 = r6;" +"l1_%=:" + /* if r7 > 4 ...; transfers range to r6 on one execution path + * but does not transfer on another + */ + "if r7 > 4 goto l2_%=;" + /* Access memory at r9[r6], r6 is not always bounded */ + "r9 += r6;" + "r0 = *(u8*)(r9 + 0);" +"l2_%=:" + "r0 = 0;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Similar to check_ids_in_regsafe. + * The l0 could be reached in two states: + * + * (1) r6{.id=A}, r7{.id=A}, r8{.id=B} + * (2) r6{.id=B}, r7{.id=A}, r8{.id=B} + * + * Where (2) is not safe, as "r7 > 4" check won't propagate range for it. + * This example would be considered safe without changes to + * mark_chain_precision() to track scalar values with equal IDs. + */ +SEC("socket") +__failure __msg("register with unbounded min value") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void check_ids_in_regsafe_2(void) +{ + asm volatile ( + /* Bump allocated stack */ + "r1 = 0;" + "*(u64*)(r10 - 8) = r1;" + /* r9 = pointer to stack */ + "r9 = r10;" + "r9 += -8;" + /* r8 = ktime_get_ns() */ + "call %[bpf_ktime_get_ns];" + "r8 = r0;" + /* r7 = ktime_get_ns() */ + "call %[bpf_ktime_get_ns];" + "r7 = r0;" + /* r6 = ktime_get_ns() */ + "call %[bpf_ktime_get_ns];" + "r6 = r0;" + /* scratch .id from r0 */ + "r0 = 0;" + /* if r6 > r7 is an unpredictable jump */ + "if r6 > r7 goto l1_%=;" + /* tie r6 and r7 .id */ + "r6 = r7;" +"l0_%=:" + /* if r7 > 4 exit(0) */ + "if r7 > 4 goto l2_%=;" + /* Access memory at r9[r6] */ + "r9 += r6;" + "r0 = *(u8*)(r9 + 0);" +"l2_%=:" + "r0 = 0;" + "exit;" +"l1_%=:" + /* tie r6 and r8 .id */ + "r6 = r8;" + "goto l0_%=;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Check that scalar IDs *are not* generated on register to register + * assignments if source register is a constant. + * + * If such IDs *are* generated the 'l1' below would be reached in + * two states: + * + * (1) r1{.id=A}, r2{.id=A} + * (2) r1{.id=C}, r2{.id=C} + * + * Thus forcing 'if r1 == r2' verification twice. + */ +SEC("socket") +__success __log_level(2) +__msg("11: (1d) if r3 == r4 goto pc+0") +__msg("frame 0: propagating r3,r4") +__msg("11: safe") +__msg("processed 15 insns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void no_scalar_id_for_const(void) +{ + asm volatile ( + "call %[bpf_ktime_get_ns];" + /* unpredictable jump */ + "if r0 > 7 goto l0_%=;" + /* possibly generate same scalar ids for r3 and r4 */ + "r1 = 0;" + "r1 = r1;" + "r3 = r1;" + "r4 = r1;" + "goto l1_%=;" +"l0_%=:" + /* possibly generate different scalar ids for r3 and r4 */ + "r1 = 0;" + "r2 = 0;" + "r3 = r1;" + "r4 = r2;" +"l1_%=:" + /* predictable jump, marks r3 and r4 precise */ + "if r3 == r4 goto +0;" + "r0 = 0;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Same as no_scalar_id_for_const() but for 32-bit values */ +SEC("socket") +__success __log_level(2) +__msg("11: (1e) if w3 == w4 goto pc+0") +__msg("frame 0: propagating r3,r4") +__msg("11: safe") +__msg("processed 15 insns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void no_scalar_id_for_const32(void) +{ + asm volatile ( + "call %[bpf_ktime_get_ns];" + /* unpredictable jump */ + "if r0 > 7 goto l0_%=;" + /* possibly generate same scalar ids for r3 and r4 */ + "w1 = 0;" + "w1 = w1;" + "w3 = w1;" + "w4 = w1;" + "goto l1_%=;" +"l0_%=:" + /* possibly generate different scalar ids for r3 and r4 */ + "w1 = 0;" + "w2 = 0;" + "w3 = w1;" + "w4 = w2;" +"l1_%=:" + /* predictable jump, marks r1 and r2 precise */ + "if w3 == w4 goto +0;" + "r0 = 0;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Check that unique scalar IDs are ignored when new verifier state is + * compared to cached verifier state. For this test: + * - cached state has no id on r1 + * - new state has a unique id on r1 + */ +SEC("socket") +__success __log_level(2) +__msg("6: (25) if r6 > 0x7 goto pc+1") +__msg("7: (57) r1 &= 255") +__msg("8: (bf) r2 = r10") +__msg("from 6 to 8: safe") +__msg("processed 12 insns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void ignore_unique_scalar_ids_cur(void) +{ + asm volatile ( + "call %[bpf_ktime_get_ns];" + "r6 = r0;" + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + /* r1.id == r0.id */ + "r1 = r0;" + /* make r1.id unique */ + "r0 = 0;" + "if r6 > 7 goto l0_%=;" + /* clear r1 id, but keep the range compatible */ + "r1 &= 0xff;" +"l0_%=:" + /* get here in two states: + * - first: r1 has no id (cached state) + * - second: r1 has a unique id (should be considered equivalent) + */ + "r2 = r10;" + "r2 += r1;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Check that unique scalar IDs are ignored when new verifier state is + * compared to cached verifier state. For this test: + * - cached state has a unique id on r1 + * - new state has no id on r1 + */ +SEC("socket") +__success __log_level(2) +__msg("6: (25) if r6 > 0x7 goto pc+1") +__msg("7: (05) goto pc+1") +__msg("9: (bf) r2 = r10") +__msg("9: safe") +__msg("processed 13 insns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void ignore_unique_scalar_ids_old(void) +{ + asm volatile ( + "call %[bpf_ktime_get_ns];" + "r6 = r0;" + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + /* r1.id == r0.id */ + "r1 = r0;" + /* make r1.id unique */ + "r0 = 0;" + "if r6 > 7 goto l1_%=;" + "goto l0_%=;" +"l1_%=:" + /* clear r1 id, but keep the range compatible */ + "r1 &= 0xff;" +"l0_%=:" + /* get here in two states: + * - first: r1 has a unique id (cached state) + * - second: r1 has no id (should be considered equivalent) + */ + "r2 = r10;" + "r2 += r1;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Check that two different scalar IDs in a verified state can't be + * mapped to the same scalar ID in current state. + */ +SEC("socket") +__success __log_level(2) +/* The exit instruction should be reachable from two states, + * use two matches and "processed .. insns" to ensure this. + */ +__msg("13: (95) exit") +__msg("13: (95) exit") +__msg("processed 18 insns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void two_old_ids_one_cur_id(void) +{ + asm volatile ( + /* Give unique scalar IDs to r{6,7} */ + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + "r6 = r0;" + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + "r7 = r0;" + "r0 = 0;" + /* Maybe make r{6,7} IDs identical */ + "if r6 > r7 goto l0_%=;" + "goto l1_%=;" +"l0_%=:" + "r6 = r7;" +"l1_%=:" + /* Mark r{6,7} precise. + * Get here in two states: + * - first: r6{.id=A}, r7{.id=B} (cached state) + * - second: r6{.id=A}, r7{.id=A} + * Currently we don't want to consider such states equivalent. + * Thus "exit;" would be verified twice. + */ + "r2 = r10;" + "r2 += r6;" + "r2 += r7;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + char _license[] SEC("license") = "GPL"; -- cgit v1.2.3 From 61c65a8b50c22ef17839df6f342df44a5631400a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 11 Apr 2023 20:15:21 +0300 Subject: selftests: gpio: gpio-sim: Use same variable name for sysfs pathname SYSFS_PATH can be used locally and globally, especially that has the same content. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- tools/testing/selftests/gpio/gpio-sim.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/gpio/gpio-sim.sh b/tools/testing/selftests/gpio/gpio-sim.sh index 9f539d454ee4..9f0df867b509 100755 --- a/tools/testing/selftests/gpio/gpio-sim.sh +++ b/tools/testing/selftests/gpio/gpio-sim.sh @@ -152,9 +152,9 @@ sysfs_set_pull() { local PULL=$4 local DEVNAME=`configfs_dev_name $DEV` local CHIPNAME=`configfs_chip_name $DEV $BANK` - local SYSFSPATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio$OFFSET/pull" + local SYSFS_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio$OFFSET/pull" - echo $PULL > $SYSFSPATH || fail "Unable to set line pull in sysfs" + echo $PULL > $SYSFS_PATH || fail "Unable to set line pull in sysfs" } # Load the gpio-sim module. This will pull in configfs if needed too. -- cgit v1.2.3 From a40b702789a480904b15f5843c4ed79f969ee4d5 Mon Sep 17 00:00:00 2001 From: Joel Granados Date: Fri, 16 Jun 2023 10:59:16 +0200 Subject: test_sysctl: Fix test metadata getters The functions get_test_{count,enabled,target} use awk to get the N'th field in the ALL_TESTS variable. A variable with leading zeros (e.g. 0009) is misinterpreted as an entire line instead of the N'th field. Remove the leading zeros so this does not happen. We can now use the helper in tests 6, 7 and 8. Signed-off-by: Joel Granados Signed-off-by: Luis Chamberlain --- tools/testing/selftests/sysctl/sysctl.sh | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/sysctl/sysctl.sh b/tools/testing/selftests/sysctl/sysctl.sh index bfc54b422f25..cb8f83dfe16b 100755 --- a/tools/testing/selftests/sysctl/sysctl.sh +++ b/tools/testing/selftests/sysctl/sysctl.sh @@ -730,7 +730,7 @@ sysctl_test_0005() sysctl_test_0006() { - TARGET="${SYSCTL}/bitmap_0001" + TARGET="${SYSCTL}/$(get_test_target 0006)" reset_vals ORIG="" run_bitmaptest @@ -738,7 +738,7 @@ sysctl_test_0006() sysctl_test_0007() { - TARGET="${SYSCTL}/boot_int" + TARGET="${SYSCTL}/$(get_test_target 0007)" if [ ! -f $TARGET ]; then echo "Skipping test for $TARGET as it is not present ..." return $ksft_skip @@ -778,7 +778,7 @@ sysctl_test_0007() sysctl_test_0008() { - TARGET="${SYSCTL}/match_int" + TARGET="${SYSCTL}/$(get_test_target 0008)" if [ ! -f $TARGET ]; then echo "Skipping test for $TARGET as it is not present ..." return $ksft_skip @@ -857,25 +857,32 @@ function test_num() usage fi } +function remove_leading_zeros() +{ + echo $1 | sed 's/^0*//' +} function get_test_count() { test_num $1 - TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}') + awk_field=$(remove_leading_zeros $1) + TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$awk_field'}') echo ${TEST_DATA} | awk -F":" '{print $2}' } function get_test_enabled() { test_num $1 - TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}') + awk_field=$(remove_leading_zeros $1) + TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$awk_field'}') echo ${TEST_DATA} | awk -F":" '{print $3}' } function get_test_target() { test_num $1 - TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}') + awk_field=$(remove_leading_zeros $1) + TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$awk_field'}') echo ${TEST_DATA} | awk -F":" '{print $4}' } -- cgit v1.2.3 From 35576438591e8d37c7651e6ff56f2e07c7f9615a Mon Sep 17 00:00:00 2001 From: Joel Granados Date: Fri, 16 Jun 2023 10:59:18 +0200 Subject: test_sysctl: Add an unregister sysctl test Add a test that checks that the unregistered directory is removed from /proc/sys/debug Signed-off-by: Joel Granados Signed-off-by: Luis Chamberlain --- lib/test_sysctl.c | 30 ++++++++++++++++++++++++++++++ tools/testing/selftests/sysctl/sysctl.sh | 16 ++++++++++++++++ 2 files changed, 46 insertions(+) (limited to 'tools/testing') diff --git a/lib/test_sysctl.c b/lib/test_sysctl.c index 0cf7c547d61a..555244687443 100644 --- a/lib/test_sysctl.c +++ b/lib/test_sysctl.c @@ -170,12 +170,42 @@ static int test_sysctl_setup_node_tests(void) return 0; } +/* Used to test that unregister actually removes the directory */ +static struct ctl_table test_table_unregister[] = { + { + .procname = "unregister_error", + .data = &test_data.int_0001, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + }, + {} +}; + +static int test_sysctl_run_unregister_nested(void) +{ + struct ctl_table_header *unregister; + + unregister = register_sysctl("debug/test_sysctl/unregister_error", + test_table_unregister); + if (!unregister) + return -ENOMEM; + + unregister_sysctl_table(unregister); + return 0; +} + static int __init test_sysctl_init(void) { int err; err = test_sysctl_setup_node_tests(); + if (err) + goto out; + + err = test_sysctl_run_unregister_nested(); +out: return err; } module_init(test_sysctl_init); diff --git a/tools/testing/selftests/sysctl/sysctl.sh b/tools/testing/selftests/sysctl/sysctl.sh index cb8f83dfe16b..a6d79d7a36e4 100755 --- a/tools/testing/selftests/sysctl/sysctl.sh +++ b/tools/testing/selftests/sysctl/sysctl.sh @@ -31,6 +31,7 @@ ALL_TESTS="$ALL_TESTS 0005:3:1:int_0003" ALL_TESTS="$ALL_TESTS 0006:50:1:bitmap_0001" ALL_TESTS="$ALL_TESTS 0007:1:1:boot_int" ALL_TESTS="$ALL_TESTS 0008:1:1:match_int" +ALL_TESTS="$ALL_TESTS 0009:1:1:unregister_error" function allow_user_defaults() { @@ -797,6 +798,20 @@ sysctl_test_0008() return 0 } +sysctl_test_0009() +{ + TARGET="${SYSCTL}/$(get_test_target 0009)" + echo -n "Testing if $TARGET unregistered correctly ..." + if [ -d $TARGET ]; then + echo "TEST FAILED" + rc=1 + test_rc + fi + + echo "ok" + return 0 +} + list_tests() { echo "Test ID list:" @@ -813,6 +828,7 @@ list_tests() echo "0006 x $(get_test_count 0006) - tests proc_do_large_bitmap()" echo "0007 x $(get_test_count 0007) - tests setting sysctl from kernel boot param" echo "0008 x $(get_test_count 0008) - tests sysctl macro values match" + echo "0009 x $(get_test_count 0009) - tests sysct unregister" } usage() -- cgit v1.2.3 From ec866cc6f8a90a65cd085377405c34f0f6d9ba60 Mon Sep 17 00:00:00 2001 From: Joel Granados Date: Fri, 16 Jun 2023 10:59:19 +0200 Subject: test_sysctl: Add an option to prevent test skip Tests were being skipped because the target was not present. Add a flag that controls whether to skip a test based on the presence of the target. Actually skip tests in the test_case function with a "return" instead of a "continue". Signed-off-by: Joel Granados Signed-off-by: Luis Chamberlain --- tools/testing/selftests/sysctl/sysctl.sh | 66 +++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 22 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/sysctl/sysctl.sh b/tools/testing/selftests/sysctl/sysctl.sh index a6d79d7a36e4..9c0e9711138b 100755 --- a/tools/testing/selftests/sysctl/sysctl.sh +++ b/tools/testing/selftests/sysctl/sysctl.sh @@ -14,24 +14,26 @@ TEST_FILE=$(mktemp) # This represents # -# TEST_ID:TEST_COUNT:ENABLED:TARGET +# TEST_ID:TEST_COUNT:ENABLED:TARGET:SKIP_NO_TARGET # # TEST_ID: is the test id number # TEST_COUNT: number of times we should run the test # ENABLED: 1 if enabled, 0 otherwise # TARGET: test target file required on the test_sysctl module +# SKIP_NO_TARGET: 1 skip if TARGET not there +# 0 run eventhough TARGET not there # # Once these are enabled please leave them as-is. Write your own test, # we have tons of space. -ALL_TESTS="0001:1:1:int_0001" -ALL_TESTS="$ALL_TESTS 0002:1:1:string_0001" -ALL_TESTS="$ALL_TESTS 0003:1:1:int_0002" -ALL_TESTS="$ALL_TESTS 0004:1:1:uint_0001" -ALL_TESTS="$ALL_TESTS 0005:3:1:int_0003" -ALL_TESTS="$ALL_TESTS 0006:50:1:bitmap_0001" -ALL_TESTS="$ALL_TESTS 0007:1:1:boot_int" -ALL_TESTS="$ALL_TESTS 0008:1:1:match_int" -ALL_TESTS="$ALL_TESTS 0009:1:1:unregister_error" +ALL_TESTS="0001:1:1:int_0001:1" +ALL_TESTS="$ALL_TESTS 0002:1:1:string_0001:1" +ALL_TESTS="$ALL_TESTS 0003:1:1:int_0002:1" +ALL_TESTS="$ALL_TESTS 0004:1:1:uint_0001:1" +ALL_TESTS="$ALL_TESTS 0005:3:1:int_0003:1" +ALL_TESTS="$ALL_TESTS 0006:50:1:bitmap_0001:1" +ALL_TESTS="$ALL_TESTS 0007:1:1:boot_int:1" +ALL_TESTS="$ALL_TESTS 0008:1:1:match_int:1" +ALL_TESTS="$ALL_TESTS 0009:1:1:unregister_error:0" function allow_user_defaults() { @@ -614,7 +616,6 @@ target_exists() TEST_ID="$2" if [ ! -f ${TARGET} ] ; then - echo "Target for test $TEST_ID: $TARGET not exist, skipping test ..." return 0 fi return 1 @@ -902,16 +903,36 @@ function get_test_target() echo ${TEST_DATA} | awk -F":" '{print $4}' } +function get_test_skip_no_target() +{ + test_num $1 + awk_field=$(remove_leading_zeros $1) + TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$awk_field'}') + echo ${TEST_DATA} | awk -F":" '{print $5}' +} + +function skip_test() +{ + TEST_ID=$1 + TEST_TARGET=$2 + if target_exists $TEST_TARGET $TEST_ID; then + TEST_SKIP=$(get_test_skip_no_target $TEST_ID) + if [[ $TEST_SKIP -eq "1" ]]; then + echo "Target for test $TEST_ID: $TEST_TARGET not exist, skipping test ..." + return 0 + fi + fi + return 1 +} + function run_all_tests() { for i in $ALL_TESTS ; do - TEST_ID=${i%:*:*:*} + TEST_ID=${i%:*:*:*:*} ENABLED=$(get_test_enabled $TEST_ID) TEST_COUNT=$(get_test_count $TEST_ID) TEST_TARGET=$(get_test_target $TEST_ID) - if target_exists $TEST_TARGET $TEST_ID; then - continue - fi + if [[ $ENABLED -eq "1" ]]; then test_case $TEST_ID $TEST_COUNT $TEST_TARGET fi @@ -946,18 +967,19 @@ function watch_case() function test_case() { + TEST_ID=$1 NUM_TESTS=$2 + TARGET=$3 - i=0 - - if target_exists $3 $1; then - continue + if skip_test $TEST_ID $TARGET; then + return fi + i=0 while [ $i -lt $NUM_TESTS ]; do - test_num $1 - watch_log $i ${TEST_NAME}_test_$1 noclear - RUN_TEST=${TEST_NAME}_test_$1 + test_num $TEST_ID + watch_log $i ${TEST_NAME}_test_${TEST_ID} noclear + RUN_TEST=${TEST_NAME}_test_${TEST_ID} $RUN_TEST let i=$i+1 done -- cgit v1.2.3 From f2e7a6265e5a5e02ee663eda3d0527dd8230b832 Mon Sep 17 00:00:00 2001 From: Joel Granados Date: Fri, 16 Jun 2023 10:59:20 +0200 Subject: test_sysclt: Test for registering a mount point Test that target gets created by register_sysctl_mount_point and that no additional target can be created "on top" of a permanently empty sysctl table. Create a mount point target (mnt) in the sysctl test driver; try to create another on top of that (mnt_error). Output an error if "mnt_error" is present when we run the sysctl selftests. Signed-off-by: Joel Granados Signed-off-by: Luis Chamberlain --- lib/test_sysctl.c | 45 +++++++++++++++++++++++++++----- tools/testing/selftests/sysctl/sysctl.sh | 16 ++++++++++++ 2 files changed, 55 insertions(+), 6 deletions(-) (limited to 'tools/testing') diff --git a/lib/test_sysctl.c b/lib/test_sysctl.c index 555244687443..8036aa91a1cb 100644 --- a/lib/test_sysctl.c +++ b/lib/test_sysctl.c @@ -30,6 +30,13 @@ static int i_zero; static int i_one_hundred = 100; static int match_int_ok = 1; + +static struct { + struct ctl_table_header *test_h_setup_node; + struct ctl_table_header *test_h_mnt; + struct ctl_table_header *test_h_mnterror; +} sysctl_test_headers; + struct test_sysctl_data { int int_0001; int int_0002; @@ -153,16 +160,14 @@ static void test_sysctl_calc_match_int_ok(void) match_int_ok = 0; } -static struct ctl_table_header *test_sysctl_header; - static int test_sysctl_setup_node_tests(void) { test_sysctl_calc_match_int_ok(); test_data.bitmap_0001 = kzalloc(SYSCTL_TEST_BITMAP_SIZE/8, GFP_KERNEL); if (!test_data.bitmap_0001) return -ENOMEM; - test_sysctl_header = register_sysctl("debug/test_sysctl", test_table); - if (!test_sysctl_header) { + sysctl_test_headers.test_h_setup_node = register_sysctl("debug/test_sysctl", test_table); + if (!sysctl_test_headers.test_h_setup_node) { kfree(test_data.bitmap_0001); return -ENOMEM; } @@ -195,6 +200,26 @@ static int test_sysctl_run_unregister_nested(void) return 0; } +static int test_sysctl_run_register_mount_point(void) +{ + sysctl_test_headers.test_h_mnt + = register_sysctl_mount_point("debug/test_sysctl/mnt"); + if (!sysctl_test_headers.test_h_mnt) + return -ENOMEM; + + sysctl_test_headers.test_h_mnterror + = register_sysctl("debug/test_sysctl/mnt/mnt_error", + test_table_unregister); + /* + * Don't check the result.: + * If it fails (expected behavior), return 0. + * If successful (missbehavior of register mount point), we want to see + * mnt_error when we run the sysctl test script + */ + + return 0; +} + static int __init test_sysctl_init(void) { int err; @@ -204,6 +229,10 @@ static int __init test_sysctl_init(void) goto out; err = test_sysctl_run_unregister_nested(); + if (err) + goto out; + + err = test_sysctl_run_register_mount_point(); out: return err; @@ -213,8 +242,12 @@ module_init(test_sysctl_init); static void __exit test_sysctl_exit(void) { kfree(test_data.bitmap_0001); - if (test_sysctl_header) - unregister_sysctl_table(test_sysctl_header); + if (sysctl_test_headers.test_h_setup_node) + unregister_sysctl_table(sysctl_test_headers.test_h_setup_node); + if (sysctl_test_headers.test_h_mnt) + unregister_sysctl_table(sysctl_test_headers.test_h_mnt); + if (sysctl_test_headers.test_h_mnterror) + unregister_sysctl_table(sysctl_test_headers.test_h_mnterror); } module_exit(test_sysctl_exit); diff --git a/tools/testing/selftests/sysctl/sysctl.sh b/tools/testing/selftests/sysctl/sysctl.sh index 9c0e9711138b..444b2befda82 100755 --- a/tools/testing/selftests/sysctl/sysctl.sh +++ b/tools/testing/selftests/sysctl/sysctl.sh @@ -34,6 +34,7 @@ ALL_TESTS="$ALL_TESTS 0006:50:1:bitmap_0001:1" ALL_TESTS="$ALL_TESTS 0007:1:1:boot_int:1" ALL_TESTS="$ALL_TESTS 0008:1:1:match_int:1" ALL_TESTS="$ALL_TESTS 0009:1:1:unregister_error:0" +ALL_TESTS="$ALL_TESTS 0010:1:1:mnt/mnt_error:0" function allow_user_defaults() { @@ -813,6 +814,20 @@ sysctl_test_0009() return 0 } +sysctl_test_0010() +{ + TARGET="${SYSCTL}/$(get_test_target 0010)" + echo -n "Testing that $TARGET was not created ..." + if [ -d $TARGET ]; then + echo "TEST FAILED" + rc=1 + test_rc + fi + + echo "ok" + return 0 +} + list_tests() { echo "Test ID list:" @@ -830,6 +845,7 @@ list_tests() echo "0007 x $(get_test_count 0007) - tests setting sysctl from kernel boot param" echo "0008 x $(get_test_count 0008) - tests sysctl macro values match" echo "0009 x $(get_test_count 0009) - tests sysct unregister" + echo "0010 x $(get_test_count 0010) - tests sysct mount point" } usage() -- cgit v1.2.3 From 6c3eba1c5e283fd2bb1c076dbfcb47f569c3bfde Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 13 Jun 2023 15:35:32 -0700 Subject: bpf: Centralize permissions checks for all BPF map types This allows to do more centralized decisions later on, and generally makes it very explicit which maps are privileged and which are not (e.g., LRU_HASH and LRU_PERCPU_HASH, which are privileged HASH variants, as opposed to unprivileged HASH and HASH_PERCPU; now this is explicit and easy to verify). Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20230613223533.3689589-4-andrii@kernel.org --- kernel/bpf/bloom_filter.c | 3 -- kernel/bpf/bpf_local_storage.c | 3 -- kernel/bpf/bpf_struct_ops.c | 3 -- kernel/bpf/cpumap.c | 4 -- kernel/bpf/devmap.c | 3 -- kernel/bpf/hashtab.c | 6 --- kernel/bpf/lpm_trie.c | 3 -- kernel/bpf/queue_stack_maps.c | 4 -- kernel/bpf/reuseport_array.c | 3 -- kernel/bpf/stackmap.c | 3 -- kernel/bpf/syscall.c | 47 ++++++++++++++++++++++ net/core/sock_map.c | 4 -- net/xdp/xskmap.c | 4 -- .../selftests/bpf/prog_tests/unpriv_bpf_disabled.c | 6 ++- 14 files changed, 52 insertions(+), 44 deletions(-) (limited to 'tools/testing') diff --git a/kernel/bpf/bloom_filter.c b/kernel/bpf/bloom_filter.c index 540331b610a9..addf3dd57b59 100644 --- a/kernel/bpf/bloom_filter.c +++ b/kernel/bpf/bloom_filter.c @@ -86,9 +86,6 @@ static struct bpf_map *bloom_map_alloc(union bpf_attr *attr) int numa_node = bpf_map_attr_numa_node(attr); struct bpf_bloom_filter *bloom; - if (!bpf_capable()) - return ERR_PTR(-EPERM); - if (attr->key_size != 0 || attr->value_size == 0 || attr->max_entries == 0 || attr->map_flags & ~BLOOM_CREATE_FLAG_MASK || diff --git a/kernel/bpf/bpf_local_storage.c b/kernel/bpf/bpf_local_storage.c index 47d9948d768f..b5149cfce7d4 100644 --- a/kernel/bpf/bpf_local_storage.c +++ b/kernel/bpf/bpf_local_storage.c @@ -723,9 +723,6 @@ int bpf_local_storage_map_alloc_check(union bpf_attr *attr) !attr->btf_key_type_id || !attr->btf_value_type_id) return -EINVAL; - if (!bpf_capable()) - return -EPERM; - if (attr->value_size > BPF_LOCAL_STORAGE_MAX_VALUE_SIZE) return -E2BIG; diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index d3f0a4825fa6..116a0ce378ec 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -655,9 +655,6 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) const struct btf_type *t, *vt; struct bpf_map *map; - if (!bpf_capable()) - return ERR_PTR(-EPERM); - st_ops = bpf_struct_ops_find_value(attr->btf_vmlinux_value_type_id); if (!st_ops) return ERR_PTR(-ENOTSUPP); diff --git a/kernel/bpf/cpumap.c b/kernel/bpf/cpumap.c index 8ec18faa74ac..8a33e8747a0e 100644 --- a/kernel/bpf/cpumap.c +++ b/kernel/bpf/cpumap.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -89,9 +88,6 @@ static struct bpf_map *cpu_map_alloc(union bpf_attr *attr) u32 value_size = attr->value_size; struct bpf_cpu_map *cmap; - if (!bpf_capable()) - return ERR_PTR(-EPERM); - /* check sanity of attributes */ if (attr->max_entries == 0 || attr->key_size != 4 || (value_size != offsetofend(struct bpf_cpumap_val, qsize) && diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c index 802692fa3905..49cc0b5671c6 100644 --- a/kernel/bpf/devmap.c +++ b/kernel/bpf/devmap.c @@ -160,9 +160,6 @@ static struct bpf_map *dev_map_alloc(union bpf_attr *attr) struct bpf_dtab *dtab; int err; - if (!capable(CAP_NET_ADMIN)) - return ERR_PTR(-EPERM); - dtab = bpf_map_area_alloc(sizeof(*dtab), NUMA_NO_NODE); if (!dtab) return ERR_PTR(-ENOMEM); diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c index 9901efee4339..56d3da7d0bc6 100644 --- a/kernel/bpf/hashtab.c +++ b/kernel/bpf/hashtab.c @@ -422,12 +422,6 @@ static int htab_map_alloc_check(union bpf_attr *attr) BUILD_BUG_ON(offsetof(struct htab_elem, fnode.next) != offsetof(struct htab_elem, hash_node.pprev)); - if (lru && !bpf_capable()) - /* LRU implementation is much complicated than other - * maps. Hence, limit to CAP_BPF. - */ - return -EPERM; - if (zero_seed && !capable(CAP_SYS_ADMIN)) /* Guard against local DoS, and discourage production use. */ return -EPERM; diff --git a/kernel/bpf/lpm_trie.c b/kernel/bpf/lpm_trie.c index e0d3ddf2037a..17c7e7782a1f 100644 --- a/kernel/bpf/lpm_trie.c +++ b/kernel/bpf/lpm_trie.c @@ -544,9 +544,6 @@ static struct bpf_map *trie_alloc(union bpf_attr *attr) { struct lpm_trie *trie; - if (!bpf_capable()) - return ERR_PTR(-EPERM); - /* check sanity of attributes */ if (attr->max_entries == 0 || !(attr->map_flags & BPF_F_NO_PREALLOC) || diff --git a/kernel/bpf/queue_stack_maps.c b/kernel/bpf/queue_stack_maps.c index 601609164ef3..8d2ddcb7566b 100644 --- a/kernel/bpf/queue_stack_maps.c +++ b/kernel/bpf/queue_stack_maps.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include "percpu_freelist.h" @@ -46,9 +45,6 @@ static bool queue_stack_map_is_full(struct bpf_queue_stack *qs) /* Called from syscall */ static int queue_stack_map_alloc_check(union bpf_attr *attr) { - if (!bpf_capable()) - return -EPERM; - /* check sanity of attributes */ if (attr->max_entries == 0 || attr->key_size != 0 || attr->value_size == 0 || diff --git a/kernel/bpf/reuseport_array.c b/kernel/bpf/reuseport_array.c index cbf2d8d784b8..4b4f9670f1a9 100644 --- a/kernel/bpf/reuseport_array.c +++ b/kernel/bpf/reuseport_array.c @@ -151,9 +151,6 @@ static struct bpf_map *reuseport_array_alloc(union bpf_attr *attr) int numa_node = bpf_map_attr_numa_node(attr); struct reuseport_array *array; - if (!bpf_capable()) - return ERR_PTR(-EPERM); - /* allocate all map elements and zero-initialize them */ array = bpf_map_area_alloc(struct_size(array, ptrs, attr->max_entries), numa_node); if (!array) diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index b25fce425b2c..458bb80b14d5 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -74,9 +74,6 @@ static struct bpf_map *stack_map_alloc(union bpf_attr *attr) u64 cost, n_buckets; int err; - if (!bpf_capable()) - return ERR_PTR(-EPERM); - if (attr->map_flags & ~STACK_CREATE_FLAG_MASK) return ERR_PTR(-EINVAL); diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 6ef302709ab0..658d1154f221 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1156,6 +1156,53 @@ static int map_create(union bpf_attr *attr) if (sysctl_unprivileged_bpf_disabled && !bpf_capable()) return -EPERM; + /* check privileged map type permissions */ + switch (map_type) { + case BPF_MAP_TYPE_ARRAY: + case BPF_MAP_TYPE_PERCPU_ARRAY: + case BPF_MAP_TYPE_PROG_ARRAY: + case BPF_MAP_TYPE_PERF_EVENT_ARRAY: + case BPF_MAP_TYPE_CGROUP_ARRAY: + case BPF_MAP_TYPE_ARRAY_OF_MAPS: + case BPF_MAP_TYPE_HASH: + case BPF_MAP_TYPE_PERCPU_HASH: + case BPF_MAP_TYPE_HASH_OF_MAPS: + case BPF_MAP_TYPE_RINGBUF: + case BPF_MAP_TYPE_USER_RINGBUF: + case BPF_MAP_TYPE_CGROUP_STORAGE: + case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE: + /* unprivileged */ + break; + case BPF_MAP_TYPE_SK_STORAGE: + case BPF_MAP_TYPE_INODE_STORAGE: + case BPF_MAP_TYPE_TASK_STORAGE: + case BPF_MAP_TYPE_CGRP_STORAGE: + case BPF_MAP_TYPE_BLOOM_FILTER: + case BPF_MAP_TYPE_LPM_TRIE: + case BPF_MAP_TYPE_REUSEPORT_SOCKARRAY: + case BPF_MAP_TYPE_STACK_TRACE: + case BPF_MAP_TYPE_QUEUE: + case BPF_MAP_TYPE_STACK: + case BPF_MAP_TYPE_LRU_HASH: + case BPF_MAP_TYPE_LRU_PERCPU_HASH: + case BPF_MAP_TYPE_STRUCT_OPS: + case BPF_MAP_TYPE_CPUMAP: + if (!bpf_capable()) + return -EPERM; + break; + case BPF_MAP_TYPE_SOCKMAP: + case BPF_MAP_TYPE_SOCKHASH: + case BPF_MAP_TYPE_DEVMAP: + case BPF_MAP_TYPE_DEVMAP_HASH: + case BPF_MAP_TYPE_XSKMAP: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + break; + default: + WARN(1, "unsupported map type %d", map_type); + return -EPERM; + } + map = ops->map_alloc(attr); if (IS_ERR(map)) return PTR_ERR(map); diff --git a/net/core/sock_map.c b/net/core/sock_map.c index 00afb66cd095..19538d628714 100644 --- a/net/core/sock_map.c +++ b/net/core/sock_map.c @@ -32,8 +32,6 @@ static struct bpf_map *sock_map_alloc(union bpf_attr *attr) { struct bpf_stab *stab; - if (!capable(CAP_NET_ADMIN)) - return ERR_PTR(-EPERM); if (attr->max_entries == 0 || attr->key_size != 4 || (attr->value_size != sizeof(u32) && @@ -1085,8 +1083,6 @@ static struct bpf_map *sock_hash_alloc(union bpf_attr *attr) struct bpf_shtab *htab; int i, err; - if (!capable(CAP_NET_ADMIN)) - return ERR_PTR(-EPERM); if (attr->max_entries == 0 || attr->key_size == 0 || (attr->value_size != sizeof(u32) && diff --git a/net/xdp/xskmap.c b/net/xdp/xskmap.c index 2c1427074a3b..e1c526f97ce3 100644 --- a/net/xdp/xskmap.c +++ b/net/xdp/xskmap.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -68,9 +67,6 @@ static struct bpf_map *xsk_map_alloc(union bpf_attr *attr) int numa_node; u64 size; - if (!capable(CAP_NET_ADMIN)) - return ERR_PTR(-EPERM); - if (attr->max_entries == 0 || attr->key_size != 4 || attr->value_size != 4 || attr->map_flags & ~(BPF_F_NUMA_NODE | BPF_F_RDONLY | BPF_F_WRONLY)) diff --git a/tools/testing/selftests/bpf/prog_tests/unpriv_bpf_disabled.c b/tools/testing/selftests/bpf/prog_tests/unpriv_bpf_disabled.c index 8383a99f610f..0adf8d9475cb 100644 --- a/tools/testing/selftests/bpf/prog_tests/unpriv_bpf_disabled.c +++ b/tools/testing/selftests/bpf/prog_tests/unpriv_bpf_disabled.c @@ -171,7 +171,11 @@ static void test_unpriv_bpf_disabled_negative(struct test_unpriv_bpf_disabled *s prog_insns, prog_insn_cnt, &load_opts), -EPERM, "prog_load_fails"); - for (i = BPF_MAP_TYPE_HASH; i <= BPF_MAP_TYPE_BLOOM_FILTER; i++) + /* some map types require particular correct parameters which could be + * sanity-checked before enforcing -EPERM, so only validate that + * the simple ARRAY and HASH maps are failing with -EPERM + */ + for (i = BPF_MAP_TYPE_HASH; i <= BPF_MAP_TYPE_ARRAY; i++) ASSERT_EQ(bpf_map_create(i, NULL, sizeof(int), sizeof(int), 1, NULL), -EPERM, "map_create_fails"); -- cgit v1.2.3 From 8ad663d3dfac95cbcc4121d0655bd18ad9de826f Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Tue, 13 Jun 2023 16:09:17 +0800 Subject: selftests/bpf: Use producer_cnt to allocate local counter array For count-local benchmark, use producer_cnt instead of consumer_cnt when allocating local counter array. Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20230613080921.1623219-2-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/benchs/bench_count.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/benchs/bench_count.c b/tools/testing/selftests/bpf/benchs/bench_count.c index 078972ce208e..3768945ad08e 100644 --- a/tools/testing/selftests/bpf/benchs/bench_count.c +++ b/tools/testing/selftests/bpf/benchs/bench_count.c @@ -40,7 +40,7 @@ static void count_local_setup(void) { struct count_local_ctx *ctx = &count_local_ctx; - ctx->hits = calloc(env.consumer_cnt, sizeof(*ctx->hits)); + ctx->hits = calloc(env.producer_cnt, sizeof(*ctx->hits)); if (!ctx->hits) exit(1); } -- cgit v1.2.3 From ea400d13fc92ec66578b068e661a162e01d4b641 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Tue, 13 Jun 2023 16:09:18 +0800 Subject: selftests/bpf: Output the correct error code for pthread APIs The return value of pthread API is the error code when the called API fails, so output the return value instead of errno. Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20230613080921.1623219-3-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/bench.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/bench.c b/tools/testing/selftests/bpf/bench.c index d9c080ac1796..0b5d2b5303c9 100644 --- a/tools/testing/selftests/bpf/bench.c +++ b/tools/testing/selftests/bpf/bench.c @@ -441,12 +441,14 @@ static void setup_timer() static void set_thread_affinity(pthread_t thread, int cpu) { cpu_set_t cpuset; + int err; CPU_ZERO(&cpuset); CPU_SET(cpu, &cpuset); - if (pthread_setaffinity_np(thread, sizeof(cpuset), &cpuset)) { + err = pthread_setaffinity_np(thread, sizeof(cpuset), &cpuset); + if (err) { fprintf(stderr, "setting affinity to CPU #%d failed: %d\n", - cpu, errno); + cpu, -err); exit(1); } } @@ -605,7 +607,7 @@ static void setup_benchmark(void) bench->consumer_thread, (void *)(long)i); if (err) { fprintf(stderr, "failed to create consumer thread #%d: %d\n", - i, -errno); + i, -err); exit(1); } if (env.affinity) @@ -624,7 +626,7 @@ static void setup_benchmark(void) bench->producer_thread, (void *)(long)i); if (err) { fprintf(stderr, "failed to create producer thread #%d: %d\n", - i, -errno); + i, -err); exit(1); } if (env.affinity) -- cgit v1.2.3 From da77ae2b27ec73a644624a6d4bffc206e2df6bb8 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Tue, 13 Jun 2023 16:09:19 +0800 Subject: selftests/bpf: Ensure that next_cpu() returns a valid CPU number When using option -a without --prod-affinity or --cons-affinity, if the number of producers and consumers is greater than the number of online CPUs, the benchmark will fail to run as shown below: $ getconf _NPROCESSORS_ONLN 8 $ ./bench bpf-loop -a -p9 Setting up benchmark 'bpf-loop'... setting affinity to CPU #8 failed: -22 Fix it by returning the remainder of next_cpu divided by the number of online CPUs in next_cpu(). Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20230613080921.1623219-4-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/bench.c | 3 ++- tools/testing/selftests/bpf/bench.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/bench.c b/tools/testing/selftests/bpf/bench.c index 0b5d2b5303c9..56f1c166a57b 100644 --- a/tools/testing/selftests/bpf/bench.c +++ b/tools/testing/selftests/bpf/bench.c @@ -469,7 +469,7 @@ static int next_cpu(struct cpu_set *cpu_set) exit(1); } - return cpu_set->next_cpu++; + return cpu_set->next_cpu++ % env.nr_cpus; } static struct bench_state { @@ -659,6 +659,7 @@ static void collect_measurements(long delta_ns) { int main(int argc, char **argv) { + env.nr_cpus = get_nprocs(); parse_cmdline_args_init(argc, argv); if (env.list) { diff --git a/tools/testing/selftests/bpf/bench.h b/tools/testing/selftests/bpf/bench.h index 402729c6a3ac..7ff32be3d730 100644 --- a/tools/testing/selftests/bpf/bench.h +++ b/tools/testing/selftests/bpf/bench.h @@ -27,6 +27,7 @@ struct env { bool quiet; int consumer_cnt; int producer_cnt; + int nr_cpus; struct cpu_set prod_cpus; struct cpu_set cons_cpus; }; -- cgit v1.2.3 From 970308a7b544fa1c7ee98a2721faba3765be8dd8 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Tue, 13 Jun 2023 16:09:20 +0800 Subject: selftests/bpf: Set the default value of consumer_cnt as 0 Considering that only bench_ringbufs.c supports consumer, just set the default value of consumer_cnt as 0. After that, update the validity check of consumer_cnt, remove unused consumer_thread code snippets and set consumer_cnt as 1 in run_bench_ringbufs.sh accordingly. Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20230613080921.1623219-5-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/bench.c | 2 +- .../selftests/bpf/benchs/bench_bloom_filter_map.c | 14 ++---------- .../bpf/benchs/bench_bpf_hashmap_full_update.c | 10 ++------- .../bpf/benchs/bench_bpf_hashmap_lookup.c | 10 ++------- .../testing/selftests/bpf/benchs/bench_bpf_loop.c | 10 ++------- tools/testing/selftests/bpf/benchs/bench_count.c | 12 ---------- .../selftests/bpf/benchs/bench_local_storage.c | 12 ++-------- .../bpf/benchs/bench_local_storage_create.c | 8 +------ .../benchs/bench_local_storage_rcu_tasks_trace.c | 10 ++------- tools/testing/selftests/bpf/benchs/bench_rename.c | 15 ++----------- .../testing/selftests/bpf/benchs/bench_ringbufs.c | 2 +- tools/testing/selftests/bpf/benchs/bench_strncmp.c | 11 ++------- tools/testing/selftests/bpf/benchs/bench_trigger.c | 21 ++--------------- .../selftests/bpf/benchs/run_bench_ringbufs.sh | 26 ++++++++++++---------- 14 files changed, 35 insertions(+), 128 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/bench.c b/tools/testing/selftests/bpf/bench.c index 56f1c166a57b..41fe5a82b88b 100644 --- a/tools/testing/selftests/bpf/bench.c +++ b/tools/testing/selftests/bpf/bench.c @@ -17,7 +17,7 @@ struct env env = { .duration_sec = 5, .affinity = false, .quiet = false, - .consumer_cnt = 1, + .consumer_cnt = 0, .producer_cnt = 1, }; diff --git a/tools/testing/selftests/bpf/benchs/bench_bloom_filter_map.c b/tools/testing/selftests/bpf/benchs/bench_bloom_filter_map.c index 7c8ccc108313..e289dd1a14ee 100644 --- a/tools/testing/selftests/bpf/benchs/bench_bloom_filter_map.c +++ b/tools/testing/selftests/bpf/benchs/bench_bloom_filter_map.c @@ -107,9 +107,9 @@ const struct argp bench_bloom_map_argp = { static void validate(void) { - if (env.consumer_cnt != 1) { + if (env.consumer_cnt != 0) { fprintf(stderr, - "The bloom filter benchmarks do not support multi-consumer use\n"); + "The bloom filter benchmarks do not support consumer\n"); exit(1); } } @@ -421,18 +421,12 @@ static void measure(struct bench_res *res) last_false_hits = total_false_hits; } -static void *consumer(void *input) -{ - return NULL; -} - const struct bench bench_bloom_lookup = { .name = "bloom-lookup", .argp = &bench_bloom_map_argp, .validate = validate, .setup = bloom_lookup_setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -444,7 +438,6 @@ const struct bench bench_bloom_update = { .validate = validate, .setup = bloom_update_setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -456,7 +449,6 @@ const struct bench bench_bloom_false_positive = { .validate = validate, .setup = false_positive_setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = false_hits_report_progress, .report_final = false_hits_report_final, @@ -468,7 +460,6 @@ const struct bench bench_hashmap_without_bloom = { .validate = validate, .setup = hashmap_no_bloom_setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -480,7 +471,6 @@ const struct bench bench_hashmap_with_bloom = { .validate = validate, .setup = hashmap_with_bloom_setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_full_update.c b/tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_full_update.c index 75abe8137b6c..ee1dc12c5e5e 100644 --- a/tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_full_update.c +++ b/tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_full_update.c @@ -14,8 +14,8 @@ static struct ctx { static void validate(void) { - if (env.consumer_cnt != 1) { - fprintf(stderr, "benchmark doesn't support multi-consumer!\n"); + if (env.consumer_cnt != 0) { + fprintf(stderr, "benchmark doesn't support consumer!\n"); exit(1); } } @@ -30,11 +30,6 @@ static void *producer(void *input) return NULL; } -static void *consumer(void *input) -{ - return NULL; -} - static void measure(struct bench_res *res) { } @@ -88,7 +83,6 @@ const struct bench bench_bpf_hashmap_full_update = { .validate = validate, .setup = setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = NULL, .report_final = hashmap_report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_lookup.c b/tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_lookup.c index 8dbb02f75cff..279ff1b8b5b2 100644 --- a/tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_lookup.c +++ b/tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_lookup.c @@ -113,8 +113,8 @@ const struct argp bench_hashmap_lookup_argp = { static void validate(void) { - if (env.consumer_cnt != 1) { - fprintf(stderr, "benchmark doesn't support multi-consumer!\n"); + if (env.consumer_cnt != 0) { + fprintf(stderr, "benchmark doesn't support consumer!\n"); exit(1); } @@ -134,11 +134,6 @@ static void *producer(void *input) return NULL; } -static void *consumer(void *input) -{ - return NULL; -} - static void measure(struct bench_res *res) { } @@ -276,7 +271,6 @@ const struct bench bench_bpf_hashmap_lookup = { .validate = validate, .setup = setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = NULL, .report_final = hashmap_report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_bpf_loop.c b/tools/testing/selftests/bpf/benchs/bench_bpf_loop.c index d8a0394e10b1..a705cfb2bccc 100644 --- a/tools/testing/selftests/bpf/benchs/bench_bpf_loop.c +++ b/tools/testing/selftests/bpf/benchs/bench_bpf_loop.c @@ -47,8 +47,8 @@ const struct argp bench_bpf_loop_argp = { static void validate(void) { - if (env.consumer_cnt != 1) { - fprintf(stderr, "benchmark doesn't support multi-consumer!\n"); + if (env.consumer_cnt != 0) { + fprintf(stderr, "benchmark doesn't support consumer!\n"); exit(1); } } @@ -62,11 +62,6 @@ static void *producer(void *input) return NULL; } -static void *consumer(void *input) -{ - return NULL; -} - static void measure(struct bench_res *res) { res->hits = atomic_swap(&ctx.skel->bss->hits, 0); @@ -99,7 +94,6 @@ const struct bench bench_bpf_loop = { .validate = validate, .setup = setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = ops_report_progress, .report_final = ops_report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_count.c b/tools/testing/selftests/bpf/benchs/bench_count.c index 3768945ad08e..ba89ed3936b7 100644 --- a/tools/testing/selftests/bpf/benchs/bench_count.c +++ b/tools/testing/selftests/bpf/benchs/bench_count.c @@ -18,11 +18,6 @@ static void *count_global_producer(void *input) return NULL; } -static void *count_global_consumer(void *input) -{ - return NULL; -} - static void count_global_measure(struct bench_res *res) { struct count_global_ctx *ctx = &count_global_ctx; @@ -56,11 +51,6 @@ static void *count_local_producer(void *input) return NULL; } -static void *count_local_consumer(void *input) -{ - return NULL; -} - static void count_local_measure(struct bench_res *res) { struct count_local_ctx *ctx = &count_local_ctx; @@ -74,7 +64,6 @@ static void count_local_measure(struct bench_res *res) const struct bench bench_count_global = { .name = "count-global", .producer_thread = count_global_producer, - .consumer_thread = count_global_consumer, .measure = count_global_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -84,7 +73,6 @@ const struct bench bench_count_local = { .name = "count-local", .setup = count_local_setup, .producer_thread = count_local_producer, - .consumer_thread = count_local_consumer, .measure = count_local_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_local_storage.c b/tools/testing/selftests/bpf/benchs/bench_local_storage.c index d4b2817306d4..452499428ceb 100644 --- a/tools/testing/selftests/bpf/benchs/bench_local_storage.c +++ b/tools/testing/selftests/bpf/benchs/bench_local_storage.c @@ -74,8 +74,8 @@ static void validate(void) fprintf(stderr, "benchmark doesn't support multi-producer!\n"); exit(1); } - if (env.consumer_cnt != 1) { - fprintf(stderr, "benchmark doesn't support multi-consumer!\n"); + if (env.consumer_cnt != 0) { + fprintf(stderr, "benchmark doesn't support consumer!\n"); exit(1); } @@ -230,11 +230,6 @@ static inline void trigger_bpf_program(void) syscall(__NR_getpgid); } -static void *consumer(void *input) -{ - return NULL; -} - static void *producer(void *input) { while (true) @@ -259,7 +254,6 @@ const struct bench bench_local_storage_cache_seq_get = { .validate = validate, .setup = local_storage_cache_get_setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = local_storage_report_progress, .report_final = local_storage_report_final, @@ -271,7 +265,6 @@ const struct bench bench_local_storage_cache_interleaved_get = { .validate = validate, .setup = local_storage_cache_get_interleaved_setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = local_storage_report_progress, .report_final = local_storage_report_final, @@ -283,7 +276,6 @@ const struct bench bench_local_storage_cache_hashmap_control = { .validate = validate, .setup = hashmap_setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = local_storage_report_progress, .report_final = local_storage_report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_local_storage_create.c b/tools/testing/selftests/bpf/benchs/bench_local_storage_create.c index cff703f90e95..b36de42ee4d9 100644 --- a/tools/testing/selftests/bpf/benchs/bench_local_storage_create.c +++ b/tools/testing/selftests/bpf/benchs/bench_local_storage_create.c @@ -71,7 +71,7 @@ const struct argp bench_local_storage_create_argp = { static void validate(void) { - if (env.consumer_cnt > 1) { + if (env.consumer_cnt != 0) { fprintf(stderr, "local-storage-create benchmark does not need consumer\n"); exit(1); @@ -143,11 +143,6 @@ static void measure(struct bench_res *res) res->drops = atomic_swap(&skel->bss->kmalloc_cnts, 0); } -static void *consumer(void *input) -{ - return NULL; -} - static void *sk_producer(void *input) { struct thread *t = &threads[(long)(input)]; @@ -257,7 +252,6 @@ const struct bench bench_local_storage_create = { .validate = validate, .setup = setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = report_progress, .report_final = report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_local_storage_rcu_tasks_trace.c b/tools/testing/selftests/bpf/benchs/bench_local_storage_rcu_tasks_trace.c index d5eb5587f2aa..edf0b00418c1 100644 --- a/tools/testing/selftests/bpf/benchs/bench_local_storage_rcu_tasks_trace.c +++ b/tools/testing/selftests/bpf/benchs/bench_local_storage_rcu_tasks_trace.c @@ -72,8 +72,8 @@ static void validate(void) fprintf(stderr, "benchmark doesn't support multi-producer!\n"); exit(1); } - if (env.consumer_cnt != 1) { - fprintf(stderr, "benchmark doesn't support multi-consumer!\n"); + if (env.consumer_cnt != 0) { + fprintf(stderr, "benchmark doesn't support consumer!\n"); exit(1); } @@ -197,11 +197,6 @@ static void measure(struct bench_res *res) ctx.prev_kthread_stime = ticks; } -static void *consumer(void *input) -{ - return NULL; -} - static void *producer(void *input) { while (true) @@ -262,7 +257,6 @@ const struct bench bench_local_storage_tasks_trace = { .validate = validate, .setup = local_storage_tasks_trace_setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = report_progress, .report_final = report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_rename.c b/tools/testing/selftests/bpf/benchs/bench_rename.c index 3c203b6d6a6e..bf66893c7a33 100644 --- a/tools/testing/selftests/bpf/benchs/bench_rename.c +++ b/tools/testing/selftests/bpf/benchs/bench_rename.c @@ -17,8 +17,8 @@ static void validate(void) fprintf(stderr, "benchmark doesn't support multi-producer!\n"); exit(1); } - if (env.consumer_cnt != 1) { - fprintf(stderr, "benchmark doesn't support multi-consumer!\n"); + if (env.consumer_cnt != 0) { + fprintf(stderr, "benchmark doesn't support consumer!\n"); exit(1); } } @@ -106,17 +106,11 @@ static void setup_fexit(void) attach_bpf(ctx.skel->progs.prog5); } -static void *consumer(void *input) -{ - return NULL; -} - const struct bench bench_rename_base = { .name = "rename-base", .validate = validate, .setup = setup_base, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -127,7 +121,6 @@ const struct bench bench_rename_kprobe = { .validate = validate, .setup = setup_kprobe, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -138,7 +131,6 @@ const struct bench bench_rename_kretprobe = { .validate = validate, .setup = setup_kretprobe, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -149,7 +141,6 @@ const struct bench bench_rename_rawtp = { .validate = validate, .setup = setup_rawtp, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -160,7 +151,6 @@ const struct bench bench_rename_fentry = { .validate = validate, .setup = setup_fentry, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -171,7 +161,6 @@ const struct bench bench_rename_fexit = { .validate = validate, .setup = setup_fexit, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_ringbufs.c b/tools/testing/selftests/bpf/benchs/bench_ringbufs.c index fc91fdac4faa..3ca14ad36607 100644 --- a/tools/testing/selftests/bpf/benchs/bench_ringbufs.c +++ b/tools/testing/selftests/bpf/benchs/bench_ringbufs.c @@ -96,7 +96,7 @@ static inline void bufs_trigger_batch(void) static void bufs_validate(void) { if (env.consumer_cnt != 1) { - fprintf(stderr, "rb-libbpf benchmark doesn't support multi-consumer!\n"); + fprintf(stderr, "rb-libbpf benchmark needs one consumer!\n"); exit(1); } diff --git a/tools/testing/selftests/bpf/benchs/bench_strncmp.c b/tools/testing/selftests/bpf/benchs/bench_strncmp.c index d3fad2ba6916..a5e1428fd7a0 100644 --- a/tools/testing/selftests/bpf/benchs/bench_strncmp.c +++ b/tools/testing/selftests/bpf/benchs/bench_strncmp.c @@ -50,8 +50,8 @@ const struct argp bench_strncmp_argp = { static void strncmp_validate(void) { - if (env.consumer_cnt != 1) { - fprintf(stderr, "strncmp benchmark doesn't support multi-consumer!\n"); + if (env.consumer_cnt != 0) { + fprintf(stderr, "strncmp benchmark doesn't support consumer!\n"); exit(1); } } @@ -128,11 +128,6 @@ static void *strncmp_producer(void *ctx) return NULL; } -static void *strncmp_consumer(void *ctx) -{ - return NULL; -} - static void strncmp_measure(struct bench_res *res) { res->hits = atomic_swap(&ctx.skel->bss->hits, 0); @@ -144,7 +139,6 @@ const struct bench bench_strncmp_no_helper = { .validate = strncmp_validate, .setup = strncmp_no_helper_setup, .producer_thread = strncmp_producer, - .consumer_thread = strncmp_consumer, .measure = strncmp_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -156,7 +150,6 @@ const struct bench bench_strncmp_helper = { .validate = strncmp_validate, .setup = strncmp_helper_setup, .producer_thread = strncmp_producer, - .consumer_thread = strncmp_consumer, .measure = strncmp_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_trigger.c b/tools/testing/selftests/bpf/benchs/bench_trigger.c index 0c481de2833d..dbd362771d6a 100644 --- a/tools/testing/selftests/bpf/benchs/bench_trigger.c +++ b/tools/testing/selftests/bpf/benchs/bench_trigger.c @@ -13,8 +13,8 @@ static struct counter base_hits; static void trigger_validate(void) { - if (env.consumer_cnt != 1) { - fprintf(stderr, "benchmark doesn't support multi-consumer!\n"); + if (env.consumer_cnt != 0) { + fprintf(stderr, "benchmark doesn't support consumer!\n"); exit(1); } } @@ -103,11 +103,6 @@ static void trigger_fmodret_setup(void) attach_bpf(ctx.skel->progs.bench_trigger_fmodret); } -static void *trigger_consumer(void *input) -{ - return NULL; -} - /* make sure call is not inlined and not avoided by compiler, so __weak and * inline asm volatile in the body of the function * @@ -205,7 +200,6 @@ const struct bench bench_trig_base = { .name = "trig-base", .validate = trigger_validate, .producer_thread = trigger_base_producer, - .consumer_thread = trigger_consumer, .measure = trigger_base_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -216,7 +210,6 @@ const struct bench bench_trig_tp = { .validate = trigger_validate, .setup = trigger_tp_setup, .producer_thread = trigger_producer, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -227,7 +220,6 @@ const struct bench bench_trig_rawtp = { .validate = trigger_validate, .setup = trigger_rawtp_setup, .producer_thread = trigger_producer, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -238,7 +230,6 @@ const struct bench bench_trig_kprobe = { .validate = trigger_validate, .setup = trigger_kprobe_setup, .producer_thread = trigger_producer, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -249,7 +240,6 @@ const struct bench bench_trig_fentry = { .validate = trigger_validate, .setup = trigger_fentry_setup, .producer_thread = trigger_producer, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -260,7 +250,6 @@ const struct bench bench_trig_fentry_sleep = { .validate = trigger_validate, .setup = trigger_fentry_sleep_setup, .producer_thread = trigger_producer, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -271,7 +260,6 @@ const struct bench bench_trig_fmodret = { .validate = trigger_validate, .setup = trigger_fmodret_setup, .producer_thread = trigger_producer, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -281,7 +269,6 @@ const struct bench bench_trig_uprobe_base = { .name = "trig-uprobe-base", .setup = NULL, /* no uprobe/uretprobe is attached */ .producer_thread = uprobe_base_producer, - .consumer_thread = trigger_consumer, .measure = trigger_base_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -291,7 +278,6 @@ const struct bench bench_trig_uprobe_with_nop = { .name = "trig-uprobe-with-nop", .setup = uprobe_setup_with_nop, .producer_thread = uprobe_producer_with_nop, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -301,7 +287,6 @@ const struct bench bench_trig_uretprobe_with_nop = { .name = "trig-uretprobe-with-nop", .setup = uretprobe_setup_with_nop, .producer_thread = uprobe_producer_with_nop, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -311,7 +296,6 @@ const struct bench bench_trig_uprobe_without_nop = { .name = "trig-uprobe-without-nop", .setup = uprobe_setup_without_nop, .producer_thread = uprobe_producer_without_nop, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -321,7 +305,6 @@ const struct bench bench_trig_uretprobe_without_nop = { .name = "trig-uretprobe-without-nop", .setup = uretprobe_setup_without_nop, .producer_thread = uprobe_producer_without_nop, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, diff --git a/tools/testing/selftests/bpf/benchs/run_bench_ringbufs.sh b/tools/testing/selftests/bpf/benchs/run_bench_ringbufs.sh index ada028aa9007..91e3567962ff 100755 --- a/tools/testing/selftests/bpf/benchs/run_bench_ringbufs.sh +++ b/tools/testing/selftests/bpf/benchs/run_bench_ringbufs.sh @@ -4,46 +4,48 @@ source ./benchs/run_common.sh set -eufo pipefail +RUN_RB_BENCH="$RUN_BENCH -c1" + header "Single-producer, parallel producer" for b in rb-libbpf rb-custom pb-libbpf pb-custom; do - summarize $b "$($RUN_BENCH $b)" + summarize $b "$($RUN_RB_BENCH $b)" done header "Single-producer, parallel producer, sampled notification" for b in rb-libbpf rb-custom pb-libbpf pb-custom; do - summarize $b "$($RUN_BENCH --rb-sampled $b)" + summarize $b "$($RUN_RB_BENCH --rb-sampled $b)" done header "Single-producer, back-to-back mode" for b in rb-libbpf rb-custom pb-libbpf pb-custom; do - summarize $b "$($RUN_BENCH --rb-b2b $b)" - summarize $b-sampled "$($RUN_BENCH --rb-sampled --rb-b2b $b)" + summarize $b "$($RUN_RB_BENCH --rb-b2b $b)" + summarize $b-sampled "$($RUN_RB_BENCH --rb-sampled --rb-b2b $b)" done header "Ringbuf back-to-back, effect of sample rate" for b in 1 5 10 25 50 100 250 500 1000 2000 3000; do - summarize "rb-sampled-$b" "$($RUN_BENCH --rb-b2b --rb-batch-cnt $b --rb-sampled --rb-sample-rate $b rb-custom)" + summarize "rb-sampled-$b" "$($RUN_RB_BENCH --rb-b2b --rb-batch-cnt $b --rb-sampled --rb-sample-rate $b rb-custom)" done header "Perfbuf back-to-back, effect of sample rate" for b in 1 5 10 25 50 100 250 500 1000 2000 3000; do - summarize "pb-sampled-$b" "$($RUN_BENCH --rb-b2b --rb-batch-cnt $b --rb-sampled --rb-sample-rate $b pb-custom)" + summarize "pb-sampled-$b" "$($RUN_RB_BENCH --rb-b2b --rb-batch-cnt $b --rb-sampled --rb-sample-rate $b pb-custom)" done header "Ringbuf back-to-back, reserve+commit vs output" -summarize "reserve" "$($RUN_BENCH --rb-b2b rb-custom)" -summarize "output" "$($RUN_BENCH --rb-b2b --rb-use-output rb-custom)" +summarize "reserve" "$($RUN_RB_BENCH --rb-b2b rb-custom)" +summarize "output" "$($RUN_RB_BENCH --rb-b2b --rb-use-output rb-custom)" header "Ringbuf sampled, reserve+commit vs output" -summarize "reserve-sampled" "$($RUN_BENCH --rb-sampled rb-custom)" -summarize "output-sampled" "$($RUN_BENCH --rb-sampled --rb-use-output rb-custom)" +summarize "reserve-sampled" "$($RUN_RB_BENCH --rb-sampled rb-custom)" +summarize "output-sampled" "$($RUN_RB_BENCH --rb-sampled --rb-use-output rb-custom)" header "Single-producer, consumer/producer competing on the same CPU, low batch count" for b in rb-libbpf rb-custom pb-libbpf pb-custom; do - summarize $b "$($RUN_BENCH --rb-batch-cnt 1 --rb-sample-rate 1 --prod-affinity 0 --cons-affinity 0 $b)" + summarize $b "$($RUN_RB_BENCH --rb-batch-cnt 1 --rb-sample-rate 1 --prod-affinity 0 --cons-affinity 0 $b)" done header "Ringbuf, multi-producer contention" for b in 1 2 3 4 8 12 16 20 24 28 32 36 40 44 48 52; do - summarize "rb-libbpf nr_prod $b" "$($RUN_BENCH -p$b --rb-batch-cnt 50 rb-libbpf)" + summarize "rb-libbpf nr_prod $b" "$($RUN_RB_BENCH -p$b --rb-batch-cnt 50 rb-libbpf)" done -- cgit v1.2.3 From 9a61100e686eaa2229343505f0183f8ea790d120 Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Tue, 6 Jun 2023 00:16:27 -0700 Subject: selftests/mm: fix uffd-stress unused function warning Patch series "A minor flurry of selftest/mm fixes", v3. A series that fixes up build errors and warnings for at least the 64-bit builds on x86 with clang. The series also includes an optional "improvement" of moving some uffd code into uffd-common.[ch], which is proving to be somewhat controversial, and so if that doesn't get resolved, then patches 9 and 10 may just get dropped. They are not required in order to get a clean build, now that "make headers" is happening. [1]: https://lore.kernel.org/all/20230602013358.900637-1-jhubbard@nvidia.com/ This patch (of 11): uffd_minor_feature() was unused. Remove it in order to fix the associated clang build warning. Link: https://lkml.kernel.org/r/20230606071637.267103-1-jhubbard@nvidia.com Link: https://lkml.kernel.org/r/20230606071637.267103-2-jhubbard@nvidia.com Signed-off-by: John Hubbard Reviewed-by: David Hildenbrand Reviewed-by: Peter Xu Cc: Jonathan Corbet Cc: Muhammad Usama Anjum Cc: Nathan Chancellor Cc: Shuah Khan Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/uffd-stress.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/mm/uffd-stress.c b/tools/testing/selftests/mm/uffd-stress.c index f1ad9eef1c3a..995ff13e74c7 100644 --- a/tools/testing/selftests/mm/uffd-stress.c +++ b/tools/testing/selftests/mm/uffd-stress.c @@ -88,16 +88,6 @@ static void uffd_stats_reset(struct uffd_args *args, unsigned long n_cpus) } } -static inline uint64_t uffd_minor_feature(void) -{ - if (test_type == TEST_HUGETLB && map_shared) - return UFFD_FEATURE_MINOR_HUGETLBFS; - else if (test_type == TEST_SHMEM) - return UFFD_FEATURE_MINOR_SHMEM; - else - return 0; -} - static void *locking_thread(void *arg) { unsigned long cpu = (unsigned long) arg; -- cgit v1.2.3 From 2f29d16c9d30357a27432e2b35fe70833b5c7762 Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Tue, 6 Jun 2023 00:16:28 -0700 Subject: selftests/mm: fix unused variable warnings in hugetlb-madvise.c, migration.c Dummy variables are required in order to make these two (similar) routines work, so in both cases, declare the variables as volatile in order to avoid the clang compiler warning. Furthermore, in order to ensure that each test actually does what is intended, add an asm volatile invocation (thanks to David Hildenbrand for the suggestion), with a clarifying comment so that it survives future maintenance. Link: https://lkml.kernel.org/r/20230606071637.267103-3-jhubbard@nvidia.com Signed-off-by: John Hubbard Reviewed-by: David Hildenbrand Reviewed-by: Peter Xu Tested-by: Muhammad Usama Anjum Cc: Jonathan Corbet Cc: Nathan Chancellor Cc: Shuah Khan Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/hugetlb-madvise.c | 8 ++++++-- tools/testing/selftests/mm/migration.c | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/mm/hugetlb-madvise.c b/tools/testing/selftests/mm/hugetlb-madvise.c index 28426e30d9bc..d55322df4b73 100644 --- a/tools/testing/selftests/mm/hugetlb-madvise.c +++ b/tools/testing/selftests/mm/hugetlb-madvise.c @@ -65,11 +65,15 @@ void write_fault_pages(void *addr, unsigned long nr_pages) void read_fault_pages(void *addr, unsigned long nr_pages) { - unsigned long dummy = 0; + volatile unsigned long dummy = 0; unsigned long i; - for (i = 0; i < nr_pages; i++) + for (i = 0; i < nr_pages; i++) { dummy += *((unsigned long *)(addr + (i * huge_page_size))); + + /* Prevent the compiler from optimizing out the entire loop: */ + asm volatile("" : "+r" (dummy)); + } } int main(int argc, char **argv) diff --git a/tools/testing/selftests/mm/migration.c b/tools/testing/selftests/mm/migration.c index 1cec8425e3ca..379581567f27 100644 --- a/tools/testing/selftests/mm/migration.c +++ b/tools/testing/selftests/mm/migration.c @@ -95,12 +95,15 @@ int migrate(uint64_t *ptr, int n1, int n2) void *access_mem(void *ptr) { - uint64_t y = 0; + volatile uint64_t y = 0; volatile uint64_t *x = ptr; while (1) { pthread_testcancel(); y += *x; + + /* Prevent the compiler from optimizing out the writes to y: */ + asm volatile("" : "+r" (y)); } return NULL; -- cgit v1.2.3 From b764253c18821da31c49a260f92f5d093cf1637e Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Tue, 6 Jun 2023 00:16:29 -0700 Subject: selftests/mm: fix "warning: expression which evaluates to zero..." in mlock2-tests.c The stop variable is a char*, and the code was assigning a char value to it. This was generating a warning when compiling with clang. However, as both David and Peter pointed out, stop is not even used after the problematic assignment to a char type. So just delete that line entirely. Link: https://lkml.kernel.org/r/20230606071637.267103-4-jhubbard@nvidia.com Signed-off-by: John Hubbard Reviewed-by: David Hildenbrand Reviewed-by: Peter Xu Tested-by: Muhammad Usama Anjum Cc: Jonathan Corbet Cc: Nathan Chancellor Cc: Shuah Khan Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/mlock2-tests.c | 1 - 1 file changed, 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/mm/mlock2-tests.c b/tools/testing/selftests/mm/mlock2-tests.c index 11b2301f3aa3..80cddc0de206 100644 --- a/tools/testing/selftests/mm/mlock2-tests.c +++ b/tools/testing/selftests/mm/mlock2-tests.c @@ -50,7 +50,6 @@ static int get_vm_area(unsigned long addr, struct vm_boundaries *area) printf("cannot parse /proc/self/maps\n"); goto out; } - stop = '\0'; sscanf(line, "%lx", &start); sscanf(end_addr, "%lx", &end); -- cgit v1.2.3 From 3ff47a5837ef00121fe880338255f8e2d1a5621f Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Tue, 6 Jun 2023 00:16:30 -0700 Subject: selftests/mm: fix invocation of tests that are run via shell scripts We cannot depend upon git to reliably retain the executable bit on shell scripts, or so I was told several years ago while working on this same run_vmtests.sh script. And sure enough, things such as test_hmm.sh are lately failing to run, due to lacking execute permissions. Fix this by explicitly adding "bash" to each of the shell script invocations. Leave fixing the overall approach to another day. Link: https://lkml.kernel.org/r/20230606071637.267103-5-jhubbard@nvidia.com Signed-off-by: John Hubbard Acked-by: David Hildenbrand Tested-by: Muhammad Usama Anjum Cc: Peter Xu Cc: Jonathan Corbet Cc: Nathan Chancellor Cc: Shuah Khan Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/run_vmtests.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/selftests/mm/run_vmtests.sh index b6b1eb6a8a6b..3f26f6e15b2a 100644 --- a/tools/testing/selftests/mm/run_vmtests.sh +++ b/tools/testing/selftests/mm/run_vmtests.sh @@ -244,18 +244,18 @@ if [ $VADDR64 -ne 0 ]; then if [ "$ARCH" == "$ARCH_ARM64" ]; then echo 6 > /proc/sys/vm/nr_hugepages fi - CATEGORY="hugevm" run_test ./va_high_addr_switch.sh + CATEGORY="hugevm" run_test bash ./va_high_addr_switch.sh if [ "$ARCH" == "$ARCH_ARM64" ]; then echo $prev_nr_hugepages > /proc/sys/vm/nr_hugepages fi fi # VADDR64 # vmalloc stability smoke test -CATEGORY="vmalloc" run_test ./test_vmalloc.sh smoke +CATEGORY="vmalloc" run_test bash ./test_vmalloc.sh smoke CATEGORY="mremap" run_test ./mremap_dontunmap -CATEGORY="hmm" run_test ./test_hmm.sh smoke +CATEGORY="hmm" run_test bash ./test_hmm.sh smoke # MADV_POPULATE_READ and MADV_POPULATE_WRITE tests CATEGORY="madv_populate" run_test ./madv_populate -- cgit v1.2.3 From 7bddd2263e3781429f72f05e59fdf5e531e0bf26 Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Tue, 6 Jun 2023 00:16:31 -0700 Subject: selftests/mm: .gitignore: add mkdirty, va_high_addr_switch These new build products were left out of .gitignore, so add them now. Link: https://lkml.kernel.org/r/20230606071637.267103-6-jhubbard@nvidia.com Signed-off-by: John Hubbard Reviewed-by: David Hildenbrand Reviewed-by: Peter Xu Tested-by: Muhammad Usama Anjum Cc: Jonathan Corbet Cc: Nathan Chancellor Cc: Shuah Khan Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/.gitignore | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/mm/.gitignore b/tools/testing/selftests/mm/.gitignore index 5599cf287694..7e2a982383c0 100644 --- a/tools/testing/selftests/mm/.gitignore +++ b/tools/testing/selftests/mm/.gitignore @@ -40,3 +40,5 @@ local_config.mk ksm_functional_tests mdwe_test gup_longterm +mkdirty +va_high_addr_switch -- cgit v1.2.3 From 0e14e7e9f16ffe8f0761bc627829e8bd1cb32793 Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Tue, 6 Jun 2023 00:16:32 -0700 Subject: selftests/mm: fix two -Wformat-security warnings in uffd builds The uffd tests generate two compile time warnings from clang's -Wformat-security setting. These trigger at the call sites for uffd_test_start() and uffd_test_skip(). 1) Fix the uffd_test_start() issue by removing the intermediate test_name variable (thanks to David Hildenbrand for showing how to do this). 2) Fix the uffd_test_skip() issue by observing that there is no need for a macro and a variable args approach, because all callers of uffd_test_skip() pass in a simple char* string, without any format specifiers. So just change uffd_test_skip() into a regular C function. Link: https://lkml.kernel.org/r/20230606071637.267103-7-jhubbard@nvidia.com Signed-off-by: John Hubbard Reviewed-by: David Hildenbrand Reviewed-by: Peter Xu Tested-by: Muhammad Usama Anjum Cc: Jonathan Corbet Cc: Nathan Chancellor Cc: Shuah Khan Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/uffd-unit-tests.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/mm/uffd-unit-tests.c b/tools/testing/selftests/mm/uffd-unit-tests.c index 269c86768a02..04d91f144d1c 100644 --- a/tools/testing/selftests/mm/uffd-unit-tests.c +++ b/tools/testing/selftests/mm/uffd-unit-tests.c @@ -109,12 +109,11 @@ static void uffd_test_pass(void) ksft_inc_fail_cnt(); \ } while (0) -#define uffd_test_skip(...) do { \ - printf("skipped [reason: "); \ - printf(__VA_ARGS__); \ - printf("]\n"); \ - ksft_inc_xskip_cnt(); \ - } while (0) +static void uffd_test_skip(const char *message) +{ + printf("skipped [reason: %s]\n", message); + ksft_inc_xskip_cnt(); +} /* * Returns 1 if specific userfaultfd supported, 0 otherwise. Note, we'll @@ -1149,7 +1148,6 @@ int main(int argc, char *argv[]) uffd_test_case_t *test; mem_type_t *mem_type; uffd_test_args_t args; - char test_name[128]; const char *errmsg; int has_uffd, opt; int i, j; @@ -1192,10 +1190,8 @@ int main(int argc, char *argv[]) mem_type = &mem_types[j]; if (!(test->mem_targets & mem_type->mem_flag)) continue; - snprintf(test_name, sizeof(test_name), - "%s on %s", test->name, mem_type->name); - uffd_test_start(test_name); + uffd_test_start("%s on %s", test->name, mem_type->name); if (!uffd_feature_supported(test)) { uffd_test_skip("feature missing"); continue; -- cgit v1.2.3 From 97deb66ed4f9390fd585210fe6d72088000d9110 Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Tue, 6 Jun 2023 00:16:33 -0700 Subject: selftests/mm: fix a "possibly uninitialized" warning in pkey-x86.h This fixes a real bug, too, because xstate_size() was assuming that the stack variable xstate_size was initialized to zero. That's not guaranteed nor even especially likely. Link: https://lkml.kernel.org/r/20230606071637.267103-8-jhubbard@nvidia.com Signed-off-by: John Hubbard Reviewed-by: David Hildenbrand Tested-by: Muhammad Usama Anjum Cc: Peter Xu Cc: Jonathan Corbet Cc: Nathan Chancellor Cc: Shuah Khan Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/pkey-x86.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/mm/pkey-x86.h b/tools/testing/selftests/mm/pkey-x86.h index 72c14cd3ddc7..e32ae8a1cd99 100644 --- a/tools/testing/selftests/mm/pkey-x86.h +++ b/tools/testing/selftests/mm/pkey-x86.h @@ -132,7 +132,7 @@ int pkey_reg_xstate_offset(void) unsigned int ecx; unsigned int edx; int xstate_offset; - int xstate_size; + int xstate_size = 0; unsigned long XSTATE_CPUID = 0xd; int leaf; -- cgit v1.2.3 From 3972ea2469385777d0ebc67794f30cdb0cdbffd9 Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Tue, 6 Jun 2023 00:16:34 -0700 Subject: selftests/mm: fix build failures due to missing MADV_COLLAPSE MADV_PAGEOUT, MADV_POPULATE_READ, MADV_COLLAPSE are conditionally defined as necessary. However, that was being done in .c files, and a new build failure came up that would have been automatically avoided had these been in a common header file. So consolidate and move them all to vm_util.h, which fixes the build failure. An alternative approach from Muhammad Usama Anjum was: rely on "make headers" being required, and include asm-generic/mman-common.h. This works in the sense that it builds, but it still generates warnings about duplicate MADV_* symbols, and the goal here is to get a fully clean (no warnings) build here. Link: https://lkml.kernel.org/r/20230606071637.267103-9-jhubbard@nvidia.com Signed-off-by: John Hubbard Reviewed-by: David Hildenbrand Tested-by: Muhammad Usama Anjum Cc: Peter Xu Cc: Jonathan Corbet Cc: Nathan Chancellor Cc: Shuah Khan Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/cow.c | 7 ------- tools/testing/selftests/mm/khugepaged.c | 10 ---------- tools/testing/selftests/mm/vm_util.h | 10 ++++++++++ 3 files changed, 10 insertions(+), 17 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/mm/cow.c b/tools/testing/selftests/mm/cow.c index 7f3b620d9cb7..e4c5095e74fc 100644 --- a/tools/testing/selftests/mm/cow.c +++ b/tools/testing/selftests/mm/cow.c @@ -29,13 +29,6 @@ #include "../kselftest.h" #include "vm_util.h" -#ifndef MADV_PAGEOUT -#define MADV_PAGEOUT 21 -#endif -#ifndef MADV_COLLAPSE -#define MADV_COLLAPSE 25 -#endif - static size_t pagesize; static int pagemap_fd; static size_t thpsize; diff --git a/tools/testing/selftests/mm/khugepaged.c b/tools/testing/selftests/mm/khugepaged.c index 97adc0f34f9c..e88ee039d0eb 100644 --- a/tools/testing/selftests/mm/khugepaged.c +++ b/tools/testing/selftests/mm/khugepaged.c @@ -22,16 +22,6 @@ #include "vm_util.h" -#ifndef MADV_PAGEOUT -#define MADV_PAGEOUT 21 -#endif -#ifndef MADV_POPULATE_READ -#define MADV_POPULATE_READ 22 -#endif -#ifndef MADV_COLLAPSE -#define MADV_COLLAPSE 25 -#endif - #define BASE_ADDR ((void *)(1UL << 30)) static unsigned long hpage_pmd_size; static unsigned long page_size; diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h index 99b795528716..0df1cf77048c 100644 --- a/tools/testing/selftests/mm/vm_util.h +++ b/tools/testing/selftests/mm/vm_util.h @@ -64,3 +64,13 @@ int uffd_register_with_ioctls(int uffd, void *addr, uint64_t len, #define PAGEMAP_PRESENT(ent) (((ent) & (1ull << 63)) != 0) #define PAGEMAP_PFN(ent) ((ent) & ((1ull << 55) - 1)) + +#ifndef MADV_PAGEOUT +#define MADV_PAGEOUT 21 +#endif +#ifndef MADV_POPULATE_READ +#define MADV_POPULATE_READ 22 +#endif +#ifndef MADV_COLLAPSE +#define MADV_COLLAPSE 25 +#endif -- cgit v1.2.3 From 56d2afff13834020b91a81220684be946a4e1ef3 Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Tue, 6 Jun 2023 00:16:35 -0700 Subject: selftests/mm: move certain uffd*() routines from vm_util.c to uffd-common.c There are only three uffd*() routines that are used outside of the uffd selftests. Leave these in vm_util.c, where they are available to any mm selftest program: uffd_register() uffd_unregister() uffd_register_with_ioctls(). A few other uffd*() routines, however, are only used by the uffd-focused tests found in uffd-stress.c and uffd-unit-tests.c. Move those routines into uffd-common.c. Link: https://lkml.kernel.org/r/20230606071637.267103-10-jhubbard@nvidia.com Signed-off-by: John Hubbard Acked-by: David Hildenbrand Tested-by: Muhammad Usama Anjum Cc: Peter Xu Cc: Jonathan Corbet Cc: Nathan Chancellor Cc: Shuah Khan Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/uffd-common.c | 59 ++++++++++++++++++++++++++++++++ tools/testing/selftests/mm/uffd-common.h | 5 +++ tools/testing/selftests/mm/vm_util.c | 59 -------------------------------- tools/testing/selftests/mm/vm_util.h | 4 --- 4 files changed, 64 insertions(+), 63 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/mm/uffd-common.c b/tools/testing/selftests/mm/uffd-common.c index 61c6250adf93..ba20d7504022 100644 --- a/tools/testing/selftests/mm/uffd-common.c +++ b/tools/testing/selftests/mm/uffd-common.c @@ -616,3 +616,62 @@ int copy_page(int ufd, unsigned long offset, bool wp) { return __copy_page(ufd, offset, false, wp); } + +int uffd_open_dev(unsigned int flags) +{ + int fd, uffd; + + fd = open("/dev/userfaultfd", O_RDWR | O_CLOEXEC); + if (fd < 0) + return fd; + uffd = ioctl(fd, USERFAULTFD_IOC_NEW, flags); + close(fd); + + return uffd; +} + +int uffd_open_sys(unsigned int flags) +{ +#ifdef __NR_userfaultfd + return syscall(__NR_userfaultfd, flags); +#else + return -1; +#endif +} + +int uffd_open(unsigned int flags) +{ + int uffd = uffd_open_sys(flags); + + if (uffd < 0) + uffd = uffd_open_dev(flags); + + return uffd; +} + +int uffd_get_features(uint64_t *features) +{ + struct uffdio_api uffdio_api = { .api = UFFD_API, .features = 0 }; + /* + * This should by default work in most kernels; the feature list + * will be the same no matter what we pass in here. + */ + int fd = uffd_open(UFFD_USER_MODE_ONLY); + + if (fd < 0) + /* Maybe the kernel is older than user-only mode? */ + fd = uffd_open(0); + + if (fd < 0) + return fd; + + if (ioctl(fd, UFFDIO_API, &uffdio_api)) { + close(fd); + return -errno; + } + + *features = uffdio_api.features; + close(fd); + + return 0; +} diff --git a/tools/testing/selftests/mm/uffd-common.h b/tools/testing/selftests/mm/uffd-common.h index 6068f2346b86..197f5262fe0d 100644 --- a/tools/testing/selftests/mm/uffd-common.h +++ b/tools/testing/selftests/mm/uffd-common.h @@ -110,6 +110,11 @@ int __copy_page(int ufd, unsigned long offset, bool retry, bool wp); int copy_page(int ufd, unsigned long offset, bool wp); void *uffd_poll_thread(void *arg); +int uffd_open_dev(unsigned int flags); +int uffd_open_sys(unsigned int flags); +int uffd_open(unsigned int flags); +int uffd_get_features(uint64_t *features); + #define TEST_ANON 1 #define TEST_HUGETLB 2 #define TEST_SHMEM 3 diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c index 5cf84d860076..558c9cd8901c 100644 --- a/tools/testing/selftests/mm/vm_util.c +++ b/tools/testing/selftests/mm/vm_util.c @@ -269,62 +269,3 @@ int uffd_unregister(int uffd, void *addr, uint64_t len) return ret; } - -int uffd_open_dev(unsigned int flags) -{ - int fd, uffd; - - fd = open("/dev/userfaultfd", O_RDWR | O_CLOEXEC); - if (fd < 0) - return fd; - uffd = ioctl(fd, USERFAULTFD_IOC_NEW, flags); - close(fd); - - return uffd; -} - -int uffd_open_sys(unsigned int flags) -{ -#ifdef __NR_userfaultfd - return syscall(__NR_userfaultfd, flags); -#else - return -1; -#endif -} - -int uffd_open(unsigned int flags) -{ - int uffd = uffd_open_sys(flags); - - if (uffd < 0) - uffd = uffd_open_dev(flags); - - return uffd; -} - -int uffd_get_features(uint64_t *features) -{ - struct uffdio_api uffdio_api = { .api = UFFD_API, .features = 0 }; - /* - * This should by default work in most kernels; the feature list - * will be the same no matter what we pass in here. - */ - int fd = uffd_open(UFFD_USER_MODE_ONLY); - - if (fd < 0) - /* Maybe the kernel is older than user-only mode? */ - fd = uffd_open(0); - - if (fd < 0) - return fd; - - if (ioctl(fd, UFFDIO_API, &uffdio_api)) { - close(fd); - return -errno; - } - - *features = uffdio_api.features; - close(fd); - - return 0; -} diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h index 0df1cf77048c..e57ace1323a7 100644 --- a/tools/testing/selftests/mm/vm_util.h +++ b/tools/testing/selftests/mm/vm_util.h @@ -49,10 +49,6 @@ int detect_hugetlb_page_sizes(size_t sizes[], int max); int uffd_register(int uffd, void *addr, uint64_t len, bool miss, bool wp, bool minor); int uffd_unregister(int uffd, void *addr, uint64_t len); -int uffd_open_dev(unsigned int flags); -int uffd_open_sys(unsigned int flags); -int uffd_open(unsigned int flags); -int uffd_get_features(uint64_t *features); int uffd_register_with_ioctls(int uffd, void *addr, uint64_t len, bool miss, bool wp, bool minor, uint64_t *ioctls); -- cgit v1.2.3 From 9fc96c7c19dfab67bf81b25fbc4f49b7752d5060 Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Tue, 6 Jun 2023 00:16:37 -0700 Subject: selftests: error out if kernel header files are not yet built As per a discussion with Muhammad Usama Anjum [1], the following is how one is supposed to build selftests: make headers && make -C tools/testing/selftests/mm Change the selftest build system's lib.mk to fail out with a helpful message if that prerequisite "make headers" has not been done yet. [1] https://lore.kernel.org/all/bf910fa5-0c96-3707-cce4-5bcc656b6274@collabora.com/ [jhubbard@nvidia.com: abort the make process the first time headers aren't detected] Link: https://lkml.kernel.org/r/14573e7e-f2ad-ff34-dfbd-3efdebee51ed@nvidia.com [anders.roxell@linaro.org: fix out-of-tree builds] Link: https://lkml.kernel.org/r/20230613074931.666966-1-anders.roxell@linaro.org Link: https://lkml.kernel.org/r/20230606071637.267103-12-jhubbard@nvidia.com Signed-off-by: John Hubbard Signed-off-by: Anders Roxell Reviewed-by: Muhammad Usama Anjum Tested-by: Muhammad Usama Anjum Cc: David Hildenbrand Cc: Peter Xu Cc: Jonathan Corbet Cc: Nathan Chancellor Cc: Shuah Khan Signed-off-by: Andrew Morton --- tools/testing/selftests/Makefile | 21 ++++++++++++++++++++- tools/testing/selftests/lib.mk | 40 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 4 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 5d6fc3f39284..6b456c5ecec1 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -145,10 +145,12 @@ ifneq ($(KBUILD_OUTPUT),) abs_objtree := $(realpath $(abs_objtree)) BUILD := $(abs_objtree)/kselftest KHDR_INCLUDES := -isystem ${abs_objtree}/usr/include + KHDR_DIR := ${abs_objtree}/usr/include else BUILD := $(CURDIR) abs_srctree := $(shell cd $(top_srcdir) && pwd) KHDR_INCLUDES := -isystem ${abs_srctree}/usr/include + KHDR_DIR := ${abs_srctree}/usr/include DEFAULT_INSTALL_HDR_PATH := 1 endif @@ -162,7 +164,7 @@ export KHDR_INCLUDES # all isn't the first target in the file. .DEFAULT_GOAL := all -all: +all: kernel_header_files @ret=1; \ for TARGET in $(TARGETS); do \ BUILD_TARGET=$$BUILD/$$TARGET; \ @@ -173,6 +175,23 @@ all: ret=$$((ret * $$?)); \ done; exit $$ret; +kernel_header_files: + @ls $(KHDR_DIR)/linux/*.h >/dev/null 2>/dev/null; \ + if [ $$? -ne 0 ]; then \ + RED='\033[1;31m'; \ + NOCOLOR='\033[0m'; \ + echo; \ + echo -e "$${RED}error$${NOCOLOR}: missing kernel header files."; \ + echo "Please run this and try again:"; \ + echo; \ + echo " cd $(top_srcdir)"; \ + echo " make headers"; \ + echo; \ + exit 1; \ + fi + +.PHONY: kernel_header_files + run_tests: all @for TARGET in $(TARGETS); do \ BUILD_TARGET=$$BUILD/$$TARGET; \ diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk index 05400462c779..d17854285f2b 100644 --- a/tools/testing/selftests/lib.mk +++ b/tools/testing/selftests/lib.mk @@ -44,10 +44,26 @@ endif selfdir = $(realpath $(dir $(filter %/lib.mk,$(MAKEFILE_LIST)))) top_srcdir = $(selfdir)/../../.. -ifeq ($(KHDR_INCLUDES),) -KHDR_INCLUDES := -isystem $(top_srcdir)/usr/include +ifeq ("$(origin O)", "command line") + KBUILD_OUTPUT := $(O) endif +ifneq ($(KBUILD_OUTPUT),) + # Make's built-in functions such as $(abspath ...), $(realpath ...) cannot + # expand a shell special character '~'. We use a somewhat tedious way here. + abs_objtree := $(shell cd $(top_srcdir) && mkdir -p $(KBUILD_OUTPUT) && cd $(KBUILD_OUTPUT) && pwd) + $(if $(abs_objtree),, \ + $(error failed to create output directory "$(KBUILD_OUTPUT)")) + # $(realpath ...) resolves symlinks + abs_objtree := $(realpath $(abs_objtree)) + KHDR_DIR := ${abs_objtree}/usr/include +else + abs_srctree := $(shell cd $(top_srcdir) && pwd) + KHDR_DIR := ${abs_srctree}/usr/include +endif + +KHDR_INCLUDES := -isystem $(KHDR_DIR) + # The following are built by lib.mk common compile rules. # TEST_CUSTOM_PROGS should be used by tests that require # custom build rule and prevent common build rule use. @@ -58,7 +74,25 @@ TEST_GEN_PROGS := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_PROGS)) TEST_GEN_PROGS_EXTENDED := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_PROGS_EXTENDED)) TEST_GEN_FILES := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_FILES)) -all: $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) +all: kernel_header_files $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) \ + $(TEST_GEN_FILES) + +kernel_header_files: + @ls $(KHDR_DIR)/linux/*.h >/dev/null 2>/dev/null; \ + if [ $$? -ne 0 ]; then \ + RED='\033[1;31m'; \ + NOCOLOR='\033[0m'; \ + echo; \ + echo -e "$${RED}error$${NOCOLOR}: missing kernel header files."; \ + echo "Please run this and try again:"; \ + echo; \ + echo " cd $(top_srcdir)"; \ + echo " make headers"; \ + echo; \ + exit 1; \ + fi + +.PHONY: kernel_header_files define RUN_TESTS BASE_DIR="$(selfdir)"; \ -- cgit v1.2.3 From 7b1798ec9836670d221dcc162dc18f8b64e959e5 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Wed, 12 Apr 2023 11:28:54 +0200 Subject: selftests: damon: add config file Building and running the subsuite 'damon' of kselftest, shows the following issues: selftests: damon: debugfs_attrs.sh /sys/kernel/debug/damon not found By creating a config file enabling DAMON fragments in the selftests/damon/ directory the tests pass. Link: https://lkml.kernel.org/r/20230412092854.3306197-1-anders.roxell@linaro.org Fixes: b348eb7abd09 ("mm/damon: add user space selftests") Signed-off-by: Anders Roxell Reported-by: Naresh Kamboju Reviewed-by: SeongJae Park Acked-by: Shuah Khan Signed-off-by: Andrew Morton --- tools/testing/selftests/damon/config | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tools/testing/selftests/damon/config (limited to 'tools/testing') diff --git a/tools/testing/selftests/damon/config b/tools/testing/selftests/damon/config new file mode 100644 index 000000000000..0daf38974eb0 --- /dev/null +++ b/tools/testing/selftests/damon/config @@ -0,0 +1,7 @@ +CONFIG_DAMON=y +CONFIG_DAMON_SYSFS=y +CONFIG_DAMON_DBGFS=y +CONFIG_DAMON_PADDR=y +CONFIG_DAMON_VADDR=y +CONFIG_DAMON_RECLAIM=y +CONFIG_DAMON_LRU_SORT=y -- cgit v1.2.3 From 1e6d1e3645603bc9c9985dd6a437f22d06960b2d Mon Sep 17 00:00:00 2001 From: Muhammad Usama Anjum Date: Mon, 12 Jun 2023 14:53:46 +0500 Subject: selftests: mm: remove wrong kernel header inclusion It is wrong to include unprocessed user header files directly. They are processed to "/usr/include" by running "make headers" and they are included in selftests by kselftest makefiles automatically with help of KHDR_INCLUDES variable. These headers should always bulilt first before building kselftests. Link: https://lkml.kernel.org/r/20230612095347.996335-1-usama.anjum@collabora.com Fixes: 07115fcc15b4 ("selftests/mm: add new selftests for KSM") Signed-off-by: Muhammad Usama Anjum Acked-by: David Hildenbrand Cc: Shuah Khan Cc: Stefan Roesch Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile index 95acb099315e..e6cd60ca9e48 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -29,7 +29,7 @@ MACHINE ?= $(shell echo $(uname_M) | sed -e 's/aarch64.*/arm64/' -e 's/ppc64.*/p # LDLIBS. MAKEFLAGS += --no-builtin-rules -CFLAGS = -Wall -I $(top_srcdir) -I $(top_srcdir)/tools/include/uapi $(EXTRA_CFLAGS) $(KHDR_INCLUDES) +CFLAGS = -Wall -I $(top_srcdir) $(EXTRA_CFLAGS) $(KHDR_INCLUDES) LDLIBS = -lrt -lpthread TEST_GEN_PROGS = cow -- cgit v1.2.3 From 0183d777c29ab12c2b0c19f3d4f5c6df016815fb Mon Sep 17 00:00:00 2001 From: Muhammad Usama Anjum Date: Mon, 12 Jun 2023 14:53:47 +0500 Subject: selftests: mm: remove duplicate unneeded defines Remove all defines which aren't needed after correctly including the kernel header files. Link: https://lkml.kernel.org/r/20230612095347.996335-2-usama.anjum@collabora.com Signed-off-by: Muhammad Usama Anjum Cc: David Hildenbrand Cc: Shuah Khan Cc: Stefan Roesch Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/cow.c | 1 + tools/testing/selftests/mm/hugepage-shm.c | 4 ---- tools/testing/selftests/mm/hugepage-vmemmap.c | 4 ---- tools/testing/selftests/mm/khugepaged.c | 1 + tools/testing/selftests/mm/madv_populate.c | 7 ------- tools/testing/selftests/mm/map_fixed_noreplace.c | 4 ---- tools/testing/selftests/mm/map_hugetlb.c | 12 ------------ tools/testing/selftests/mm/map_populate.c | 2 -- tools/testing/selftests/mm/mlock-random-test.c | 1 + tools/testing/selftests/mm/mlock2.h | 8 -------- tools/testing/selftests/mm/mrelease_test.c | 10 +--------- tools/testing/selftests/mm/mremap_dontunmap.c | 4 ---- tools/testing/selftests/mm/on-fault-limit.c | 4 ---- tools/testing/selftests/mm/pkey-powerpc.h | 3 --- tools/testing/selftests/mm/pkey-x86.h | 18 ------------------ tools/testing/selftests/mm/protection_keys.c | 13 ++----------- tools/testing/selftests/mm/vm_util.h | 10 ---------- 17 files changed, 6 insertions(+), 100 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/mm/cow.c b/tools/testing/selftests/mm/cow.c index e4c5095e74fc..7324ce5363c0 100644 --- a/tools/testing/selftests/mm/cow.c +++ b/tools/testing/selftests/mm/cow.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/tools/testing/selftests/mm/hugepage-shm.c b/tools/testing/selftests/mm/hugepage-shm.c index e2527f32005b..478bb1e989e9 100644 --- a/tools/testing/selftests/mm/hugepage-shm.c +++ b/tools/testing/selftests/mm/hugepage-shm.c @@ -35,10 +35,6 @@ #include #include -#ifndef SHM_HUGETLB -#define SHM_HUGETLB 04000 -#endif - #define LENGTH (256UL*1024*1024) #define dprintf(x) printf(x) diff --git a/tools/testing/selftests/mm/hugepage-vmemmap.c b/tools/testing/selftests/mm/hugepage-vmemmap.c index 557bdbd4f87e..5b354c209e93 100644 --- a/tools/testing/selftests/mm/hugepage-vmemmap.c +++ b/tools/testing/selftests/mm/hugepage-vmemmap.c @@ -13,10 +13,6 @@ #define MAP_LENGTH (2UL * 1024 * 1024) -#ifndef MAP_HUGETLB -#define MAP_HUGETLB 0x40000 /* arch specific */ -#endif - #define PAGE_SIZE 4096 #define PAGE_COMPOUND_HEAD (1UL << 15) diff --git a/tools/testing/selftests/mm/khugepaged.c b/tools/testing/selftests/mm/khugepaged.c index e88ee039d0eb..030667cb5533 100644 --- a/tools/testing/selftests/mm/khugepaged.c +++ b/tools/testing/selftests/mm/khugepaged.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include diff --git a/tools/testing/selftests/mm/madv_populate.c b/tools/testing/selftests/mm/madv_populate.c index 262eae6b58f2..60547245e479 100644 --- a/tools/testing/selftests/mm/madv_populate.c +++ b/tools/testing/selftests/mm/madv_populate.c @@ -20,13 +20,6 @@ #include "../kselftest.h" #include "vm_util.h" -#ifndef MADV_POPULATE_READ -#define MADV_POPULATE_READ 22 -#endif /* MADV_POPULATE_READ */ -#ifndef MADV_POPULATE_WRITE -#define MADV_POPULATE_WRITE 23 -#endif /* MADV_POPULATE_WRITE */ - /* * For now, we're using 2 MiB of private anonymous memory for all tests. */ diff --git a/tools/testing/selftests/mm/map_fixed_noreplace.c b/tools/testing/selftests/mm/map_fixed_noreplace.c index eed44322d1a6..598159f3df1f 100644 --- a/tools/testing/selftests/mm/map_fixed_noreplace.c +++ b/tools/testing/selftests/mm/map_fixed_noreplace.c @@ -13,10 +13,6 @@ #include #include -#ifndef MAP_FIXED_NOREPLACE -#define MAP_FIXED_NOREPLACE 0x100000 -#endif - static void dump_maps(void) { char cmd[32]; diff --git a/tools/testing/selftests/mm/map_hugetlb.c b/tools/testing/selftests/mm/map_hugetlb.c index 312889edb84a..193281560b61 100644 --- a/tools/testing/selftests/mm/map_hugetlb.c +++ b/tools/testing/selftests/mm/map_hugetlb.c @@ -19,18 +19,6 @@ #define LENGTH (256UL*1024*1024) #define PROTECTION (PROT_READ | PROT_WRITE) -#ifndef MAP_HUGETLB -#define MAP_HUGETLB 0x40000 /* arch specific */ -#endif - -#ifndef MAP_HUGE_SHIFT -#define MAP_HUGE_SHIFT 26 -#endif - -#ifndef MAP_HUGE_MASK -#define MAP_HUGE_MASK 0x3f -#endif - /* Only ia64 requires this */ #ifdef __ia64__ #define ADDR (void *)(0x8000000000000000UL) diff --git a/tools/testing/selftests/mm/map_populate.c b/tools/testing/selftests/mm/map_populate.c index 6b8aeaa0bf7a..240f2d9dae7a 100644 --- a/tools/testing/selftests/mm/map_populate.c +++ b/tools/testing/selftests/mm/map_populate.c @@ -17,9 +17,7 @@ #include #include -#ifndef MMAP_SZ #define MMAP_SZ 4096 -#endif #define BUG_ON(condition, description) \ do { \ diff --git a/tools/testing/selftests/mm/mlock-random-test.c b/tools/testing/selftests/mm/mlock-random-test.c index 782ea94dee2f..1fba77df7f62 100644 --- a/tools/testing/selftests/mm/mlock-random-test.c +++ b/tools/testing/selftests/mm/mlock-random-test.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/tools/testing/selftests/mm/mlock2.h b/tools/testing/selftests/mm/mlock2.h index 2a6e76c226bc..8e02991b313c 100644 --- a/tools/testing/selftests/mm/mlock2.h +++ b/tools/testing/selftests/mm/mlock2.h @@ -4,14 +4,6 @@ #include #include -#ifndef MLOCK_ONFAULT -#define MLOCK_ONFAULT 1 -#endif - -#ifndef MCL_ONFAULT -#define MCL_ONFAULT (MCL_FUTURE << 1) -#endif - static int mlock2_(void *start, size_t len, int flags) { #ifdef __NR_mlock2 diff --git a/tools/testing/selftests/mm/mrelease_test.c b/tools/testing/selftests/mm/mrelease_test.c index 37b6d33b9e84..dca21042b679 100644 --- a/tools/testing/selftests/mm/mrelease_test.c +++ b/tools/testing/selftests/mm/mrelease_test.c @@ -9,18 +9,10 @@ #include #include #include +#include #include "vm_util.h" - #include "../kselftest.h" -#ifndef __NR_pidfd_open -#define __NR_pidfd_open -1 -#endif - -#ifndef __NR_process_mrelease -#define __NR_process_mrelease -1 -#endif - #define MB(x) (x << 20) #define MAX_SIZE_MB 1024 diff --git a/tools/testing/selftests/mm/mremap_dontunmap.c b/tools/testing/selftests/mm/mremap_dontunmap.c index f01dc4a85b0b..ca2359835e75 100644 --- a/tools/testing/selftests/mm/mremap_dontunmap.c +++ b/tools/testing/selftests/mm/mremap_dontunmap.c @@ -15,10 +15,6 @@ #include "../kselftest.h" -#ifndef MREMAP_DONTUNMAP -#define MREMAP_DONTUNMAP 4 -#endif - unsigned long page_size; char *page_buffer; diff --git a/tools/testing/selftests/mm/on-fault-limit.c b/tools/testing/selftests/mm/on-fault-limit.c index 634d87dfb2a4..b5888d613f34 100644 --- a/tools/testing/selftests/mm/on-fault-limit.c +++ b/tools/testing/selftests/mm/on-fault-limit.c @@ -6,10 +6,6 @@ #include #include -#ifndef MCL_ONFAULT -#define MCL_ONFAULT (MCL_FUTURE << 1) -#endif - static int test_limit(void) { int ret = 1; diff --git a/tools/testing/selftests/mm/pkey-powerpc.h b/tools/testing/selftests/mm/pkey-powerpc.h index 1ebb586b2fbc..ae5df26104e5 100644 --- a/tools/testing/selftests/mm/pkey-powerpc.h +++ b/tools/testing/selftests/mm/pkey-powerpc.h @@ -3,9 +3,6 @@ #ifndef _PKEYS_POWERPC_H #define _PKEYS_POWERPC_H -#ifndef SYS_mprotect_key -# define SYS_mprotect_key 386 -#endif #ifndef SYS_pkey_alloc # define SYS_pkey_alloc 384 # define SYS_pkey_free 385 diff --git a/tools/testing/selftests/mm/pkey-x86.h b/tools/testing/selftests/mm/pkey-x86.h index e32ae8a1cd99..814758e109c0 100644 --- a/tools/testing/selftests/mm/pkey-x86.h +++ b/tools/testing/selftests/mm/pkey-x86.h @@ -5,29 +5,11 @@ #ifdef __i386__ -#ifndef SYS_mprotect_key -# define SYS_mprotect_key 380 -#endif - -#ifndef SYS_pkey_alloc -# define SYS_pkey_alloc 381 -# define SYS_pkey_free 382 -#endif - #define REG_IP_IDX REG_EIP #define si_pkey_offset 0x14 #else -#ifndef SYS_mprotect_key -# define SYS_mprotect_key 329 -#endif - -#ifndef SYS_pkey_alloc -# define SYS_pkey_alloc 330 -# define SYS_pkey_free 331 -#endif - #define REG_IP_IDX REG_RIP #define si_pkey_offset 0x20 diff --git a/tools/testing/selftests/mm/protection_keys.c b/tools/testing/selftests/mm/protection_keys.c index 0381c34fdd56..48dc151f8fca 100644 --- a/tools/testing/selftests/mm/protection_keys.c +++ b/tools/testing/selftests/mm/protection_keys.c @@ -294,15 +294,6 @@ void pkey_access_deny(int pkey) pkey_disable_set(pkey, PKEY_DISABLE_ACCESS); } -/* Failed address bound checks: */ -#ifndef SEGV_BNDERR -# define SEGV_BNDERR 3 -#endif - -#ifndef SEGV_PKUERR -# define SEGV_PKUERR 4 -#endif - static char *si_code_str(int si_code) { if (si_code == SEGV_MAPERR) @@ -476,7 +467,7 @@ int sys_mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot, ptr, size, orig_prot, pkey); errno = 0; - sret = syscall(SYS_mprotect_key, ptr, size, orig_prot, pkey); + sret = syscall(__NR_pkey_mprotect, ptr, size, orig_prot, pkey); if (errno) { dprintf2("SYS_mprotect_key sret: %d\n", sret); dprintf2("SYS_mprotect_key prot: 0x%lx\n", orig_prot); @@ -1684,7 +1675,7 @@ void test_mprotect_pkey_on_unsupported_cpu(int *ptr, u16 pkey) return; } - sret = syscall(SYS_mprotect_key, ptr, size, PROT_READ, pkey); + sret = syscall(__NR_pkey_mprotect, ptr, size, PROT_READ, pkey); pkey_assert(sret < 0); } diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h index e57ace1323a7..c7fa61f0dff8 100644 --- a/tools/testing/selftests/mm/vm_util.h +++ b/tools/testing/selftests/mm/vm_util.h @@ -60,13 +60,3 @@ int uffd_register_with_ioctls(int uffd, void *addr, uint64_t len, #define PAGEMAP_PRESENT(ent) (((ent) & (1ull << 63)) != 0) #define PAGEMAP_PFN(ent) ((ent) & ((1ull << 55) - 1)) - -#ifndef MADV_PAGEOUT -#define MADV_PAGEOUT 21 -#endif -#ifndef MADV_POPULATE_READ -#define MADV_POPULATE_READ 22 -#endif -#ifndef MADV_COLLAPSE -#define MADV_COLLAPSE 25 -#endif -- cgit v1.2.3 From 048f6d998eacabed143d6524395573f8868a4f34 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Mon, 12 Jun 2023 14:14:54 -0700 Subject: testptp: Remove magic numbers related to nanosecond to second conversion Use existing NSEC_PER_SEC declaration in place of hardcoded magic numbers. Cc: Jakub Kicinski Cc: Shuah Khan Cc: Richard Cochran Cc: Maciek Machnikowski Signed-off-by: Rahul Rameshbabu Acked-by: Richard Cochran Signed-off-by: David S. Miller --- tools/testing/selftests/ptp/testptp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/ptp/testptp.c b/tools/testing/selftests/ptp/testptp.c index cfa9562f3cd8..36a1ea3d48af 100644 --- a/tools/testing/selftests/ptp/testptp.c +++ b/tools/testing/selftests/ptp/testptp.c @@ -110,7 +110,7 @@ static long ppb_to_scaled_ppm(int ppb) static int64_t pctns(struct ptp_clock_time *t) { - return t->sec * 1000000000LL + t->nsec; + return t->sec * NSEC_PER_SEC + t->nsec; } static void usage(char *progname) @@ -317,7 +317,7 @@ int main(int argc, char *argv[]) tx.time.tv_usec = adjns; while (tx.time.tv_usec < 0) { tx.time.tv_sec -= 1; - tx.time.tv_usec += 1000000000; + tx.time.tv_usec += NSEC_PER_SEC; } if (clock_adjtime(clkid, &tx) < 0) { -- cgit v1.2.3 From 3a9a9a6139286584d1199f555fa4f96f592a3217 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Mon, 12 Jun 2023 14:14:55 -0700 Subject: testptp: Add support for testing ptp_clock_info .adjphase callback Invoke clock_adjtime syscall with tx.modes set with ADJ_OFFSET when testptp is invoked with a phase adjustment offset value. Support seconds and nanoseconds for the offset value. Cc: Jakub Kicinski Cc: Shuah Khan Cc: Richard Cochran Cc: Maciek Machnikowski Signed-off-by: Rahul Rameshbabu Acked-by: Richard Cochran Signed-off-by: David S. Miller --- tools/testing/selftests/ptp/testptp.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/ptp/testptp.c b/tools/testing/selftests/ptp/testptp.c index 36a1ea3d48af..cc535f76db99 100644 --- a/tools/testing/selftests/ptp/testptp.c +++ b/tools/testing/selftests/ptp/testptp.c @@ -134,6 +134,7 @@ static void usage(char *progname) " 1 - external time stamp\n" " 2 - periodic output\n" " -n val shift the ptp clock time by 'val' nanoseconds\n" + " -o val phase offset (in nanoseconds) to be provided to the PHC servo\n" " -p val enable output with a period of 'val' nanoseconds\n" " -H val set output phase to 'val' nanoseconds (requires -p)\n" " -w val set output pulse width to 'val' nanoseconds (requires -p)\n" @@ -167,6 +168,7 @@ int main(int argc, char *argv[]) int adjfreq = 0x7fffffff; int adjtime = 0; int adjns = 0; + int adjphase = 0; int capabilities = 0; int extts = 0; int flagtest = 0; @@ -188,7 +190,7 @@ int main(int argc, char *argv[]) progname = strrchr(argv[0], '/'); progname = progname ? 1+progname : argv[0]; - while (EOF != (c = getopt(argc, argv, "cd:e:f:ghH:i:k:lL:n:p:P:sSt:T:w:z"))) { + while (EOF != (c = getopt(argc, argv, "cd:e:f:ghH:i:k:lL:n:o:p:P:sSt:T:w:z"))) { switch (c) { case 'c': capabilities = 1; @@ -228,6 +230,9 @@ int main(int argc, char *argv[]) case 'n': adjns = atoi(optarg); break; + case 'o': + adjphase = atoi(optarg); + break; case 'p': perout = atoll(optarg); break; @@ -327,6 +332,18 @@ int main(int argc, char *argv[]) } } + if (adjphase) { + memset(&tx, 0, sizeof(tx)); + tx.modes = ADJ_OFFSET | ADJ_NANO; + tx.offset = adjphase; + + if (clock_adjtime(clkid, &tx) < 0) { + perror("clock_adjtime"); + } else { + puts("phase adjustment okay"); + } + } + if (gettime) { if (clock_gettime(clkid, &ts)) { perror("clock_gettime"); -- cgit v1.2.3 From c3b60ab7a4dff6e6e608e685b70ddc3d6b2aca81 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Mon, 12 Jun 2023 14:14:56 -0700 Subject: ptp: Add .getmaxphase callback to ptp_clock_info Enables advertisement of the maximum offset supported by the phase control functionality of PHCs. The callback is used to return an error if an offset not supported by the PHC is used in ADJ_OFFSET. The ioctls PTP_CLOCK_GETCAPS and PTP_CLOCK_GETCAPS2 now advertise the maximum offset a PHC's phase control functionality is capable of supporting. Introduce new sysfs node, max_phase_adjustment. Cc: Jakub Kicinski Cc: Shuah Khan Cc: Richard Cochran Cc: Maciek Machnikowski Signed-off-by: Rahul Rameshbabu Acked-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/ptp/ptp_chardev.c | 5 ++++- drivers/ptp/ptp_clock.c | 4 ++++ drivers/ptp/ptp_sysfs.c | 12 ++++++++++++ include/linux/ptp_clock_kernel.h | 5 +++++ include/uapi/linux/ptp_clock.h | 3 ++- tools/testing/selftests/ptp/testptp.c | 6 ++++-- 6 files changed, 31 insertions(+), 4 deletions(-) (limited to 'tools/testing') diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index af3bc65c4595..362bf756e6b7 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c @@ -136,7 +136,10 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg) caps.pps = ptp->info->pps; caps.n_pins = ptp->info->n_pins; caps.cross_timestamping = ptp->info->getcrosststamp != NULL; - caps.adjust_phase = ptp->info->adjphase != NULL; + caps.adjust_phase = ptp->info->adjphase != NULL && + ptp->info->getmaxphase != NULL; + if (caps.adjust_phase) + caps.max_phase_adj = ptp->info->getmaxphase(ptp->info); if (copy_to_user((void __user *)arg, &caps, sizeof(caps))) err = -EFAULT; break; diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index 790f9250b381..80f74e38c2da 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -135,11 +135,15 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct __kernel_timex *tx) ptp->dialed_frequency = tx->freq; } else if (tx->modes & ADJ_OFFSET) { if (ops->adjphase) { + s32 max_phase_adj = ops->getmaxphase(ops); s32 offset = tx->offset; if (!(tx->modes & ADJ_NANO)) offset *= NSEC_PER_USEC; + if (offset > max_phase_adj || offset < -max_phase_adj) + return -ERANGE; + err = ops->adjphase(ops, offset); } } else if (tx->modes == 0) { diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c index f30b0a439470..77219cdcd683 100644 --- a/drivers/ptp/ptp_sysfs.c +++ b/drivers/ptp/ptp_sysfs.c @@ -18,6 +18,17 @@ static ssize_t clock_name_show(struct device *dev, } static DEVICE_ATTR_RO(clock_name); +static ssize_t max_phase_adjustment_show(struct device *dev, + struct device_attribute *attr, + char *page) +{ + struct ptp_clock *ptp = dev_get_drvdata(dev); + + return snprintf(page, PAGE_SIZE - 1, "%d\n", + ptp->info->getmaxphase(ptp->info)); +} +static DEVICE_ATTR_RO(max_phase_adjustment); + #define PTP_SHOW_INT(name, var) \ static ssize_t var##_show(struct device *dev, \ struct device_attribute *attr, char *page) \ @@ -309,6 +320,7 @@ static struct attribute *ptp_attrs[] = { &dev_attr_clock_name.attr, &dev_attr_max_adjustment.attr, + &dev_attr_max_phase_adjustment.attr, &dev_attr_n_alarms.attr, &dev_attr_n_external_timestamps.attr, &dev_attr_n_periodic_outputs.attr, diff --git a/include/linux/ptp_clock_kernel.h b/include/linux/ptp_clock_kernel.h index f8e8443a8b35..1ef4e0f9bd2a 100644 --- a/include/linux/ptp_clock_kernel.h +++ b/include/linux/ptp_clock_kernel.h @@ -82,6 +82,10 @@ struct ptp_system_timestamp { * parameter delta: PHC servo phase adjustment target * in nanoseconds. * + * @getmaxphase: Advertises maximum offset that can be provided + * to the hardware clock's phase control functionality + * through adjphase. + * * @adjtime: Shifts the time of the hardware clock. * parameter delta: Desired change in nanoseconds. * @@ -171,6 +175,7 @@ struct ptp_clock_info { struct ptp_pin_desc *pin_config; int (*adjfine)(struct ptp_clock_info *ptp, long scaled_ppm); int (*adjphase)(struct ptp_clock_info *ptp, s32 phase); + s32 (*getmaxphase)(struct ptp_clock_info *ptp); int (*adjtime)(struct ptp_clock_info *ptp, s64 delta); int (*gettime64)(struct ptp_clock_info *ptp, struct timespec64 *ts); int (*gettimex64)(struct ptp_clock_info *ptp, struct timespec64 *ts, diff --git a/include/uapi/linux/ptp_clock.h b/include/uapi/linux/ptp_clock.h index 1d108d597f66..05cc35fc94ac 100644 --- a/include/uapi/linux/ptp_clock.h +++ b/include/uapi/linux/ptp_clock.h @@ -95,7 +95,8 @@ struct ptp_clock_caps { int cross_timestamping; /* Whether the clock supports adjust phase */ int adjust_phase; - int rsv[12]; /* Reserved for future use. */ + int max_phase_adj; /* Maximum phase adjustment in nanoseconds. */ + int rsv[11]; /* Reserved for future use. */ }; struct ptp_extts_request { diff --git a/tools/testing/selftests/ptp/testptp.c b/tools/testing/selftests/ptp/testptp.c index cc535f76db99..e9438a1862ad 100644 --- a/tools/testing/selftests/ptp/testptp.c +++ b/tools/testing/selftests/ptp/testptp.c @@ -292,7 +292,8 @@ int main(int argc, char *argv[]) " %d pulse per second\n" " %d programmable pins\n" " %d cross timestamping\n" - " %d adjust_phase\n", + " %d adjust_phase\n" + " %d maximum phase adjustment (ns)\n", caps.max_adj, caps.n_alarm, caps.n_ext_ts, @@ -300,7 +301,8 @@ int main(int argc, char *argv[]) caps.pps, caps.n_pins, caps.cross_timestamping, - caps.adjust_phase); + caps.adjust_phase, + caps.max_phase_adj); } } -- cgit v1.2.3 From 833b0f07b915f40db352063df0e13bc91fb0f42f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 21 Jun 2023 02:36:06 +0100 Subject: kselftest/arm64: Log signal code and address for unexpected signals If we get an unexpected signal during a signal test log a bit more data to aid diagnostics. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230620-arm64-selftest-log-wrong-signal-v1-1-3fe29bdaaf38@kernel.org Signed-off-by: Catalin Marinas --- tools/testing/selftests/arm64/signal/test_signals_utils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c index 40be8443949d..0dc948db3a4a 100644 --- a/tools/testing/selftests/arm64/signal/test_signals_utils.c +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c @@ -249,7 +249,8 @@ static void default_handler(int signum, siginfo_t *si, void *uc) fprintf(stderr, "-- Timeout !\n"); } else { fprintf(stderr, - "-- RX UNEXPECTED SIGNAL: %d\n", signum); + "-- RX UNEXPECTED SIGNAL: %d code %d address %p\n", + signum, si->si_code, si->si_addr); } default_result(current, 1); } -- cgit v1.2.3 From 8c3736ce595bccb6322c44a1f853216e278aa635 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:47 +0200 Subject: selftests: forwarding: q_in_vni: Disable IPv6 autogen on bridges In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. This will cause this selftest to fail spuriously. The swp enslavement to the 802.1ad bridge is not allowed, because RIFs are not allowed to be created for 802.1ad bridges, but the address indicates one needs to be created. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridge in this selftest, thus exempting it from mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/q_in_vni.sh | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/q_in_vni.sh b/tools/testing/selftests/net/forwarding/q_in_vni.sh index 4c50c0234bce..798b13525c02 100755 --- a/tools/testing/selftests/net/forwarding/q_in_vni.sh +++ b/tools/testing/selftests/net/forwarding/q_in_vni.sh @@ -137,6 +137,7 @@ switch_create() { ip link add name br1 type bridge vlan_filtering 1 vlan_protocol 802.1ad \ vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br1 addrgenmode none # Make sure the bridge uses the MAC address of the local port and not # that of the VxLAN's device. ip link set dev br1 address $(mac_get $swp1) -- cgit v1.2.3 From c801533304ca87e314ecc6fc43b9a7822f159f18 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:48 +0200 Subject: selftests: forwarding: dual_vxlan_bridge: Disable IPv6 autogen on bridges In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. This will cause this selftest to fail spuriously. The swp enslavement to the 802.1ad bridge is not allowed, because RIFs are not allowed to be created for 802.1ad bridges, but the address indicates one needs to be created. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridge in this selftest, thus exempting it from mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/dual_vxlan_bridge.sh | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/dual_vxlan_bridge.sh b/tools/testing/selftests/net/forwarding/dual_vxlan_bridge.sh index 5148d97a5df8..68ee92df3e07 100755 --- a/tools/testing/selftests/net/forwarding/dual_vxlan_bridge.sh +++ b/tools/testing/selftests/net/forwarding/dual_vxlan_bridge.sh @@ -132,6 +132,7 @@ switch_create() #### BR1 #### ip link add name br1 type bridge vlan_filtering 1 \ vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br1 addrgenmode none # Make sure the bridge uses the MAC address of the local port and not # that of the VxLAN's device. ip link set dev br1 address $(mac_get $swp1) -- cgit v1.2.3 From d7442b7d288e8a00290808623f77bc5ed87ba8e6 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:49 +0200 Subject: selftests: forwarding: skbedit_priority: Disable IPv6 autogen on a bridge In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge, the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The selftest itself however checks operation of pedit on IPv4 and IPv6 dsfield and its parts. The bridge thus does not need to participate in routing traffic and the IP address or the RIF are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridge in this selftest, thus exempting it from mlxsw router attention. Since the bridge is only used for L2 forwarding, this change should not hinder usefulness of this selftest for testing SW datapath or HW datapaths in other devices. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/pedit_dsfield.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/pedit_dsfield.sh b/tools/testing/selftests/net/forwarding/pedit_dsfield.sh index 64fbd211d907..af008fbf2725 100755 --- a/tools/testing/selftests/net/forwarding/pedit_dsfield.sh +++ b/tools/testing/selftests/net/forwarding/pedit_dsfield.sh @@ -60,7 +60,9 @@ h2_destroy() switch_create() { - ip link add name br1 up type bridge vlan_filtering 1 + ip link add name br1 type bridge vlan_filtering 1 + ip link set dev br1 addrgenmode none + ip link set dev br1 up ip link set dev $swp1 master br1 ip link set dev $swp1 up ip link set dev $swp2 master br1 -- cgit v1.2.3 From f61018dc3e21ba0bee9caadf3015a65a7b4ce09f Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:50 +0200 Subject: selftests: forwarding: pedit_dsfield: Disable IPv6 autogen on a bridge In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge, the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The selftest itself however checks whether skbedit changes packet priority as appropriate. The bridge thus does not need to participate in routing traffic and the IP address or the RIF are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridge in this selftest, thus exempting it from mlxsw router attention. Since the bridge is only used for L2 forwarding, this change should not hinder usefulness of this selftest for testing SW datapath or HW datapaths in other devices. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/skbedit_priority.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/skbedit_priority.sh b/tools/testing/selftests/net/forwarding/skbedit_priority.sh index bde11dc27873..3dd5fcbd3eaa 100755 --- a/tools/testing/selftests/net/forwarding/skbedit_priority.sh +++ b/tools/testing/selftests/net/forwarding/skbedit_priority.sh @@ -54,7 +54,9 @@ h2_destroy() switch_create() { - ip link add name br1 up type bridge vlan_filtering 1 + ip link add name br1 type bridge vlan_filtering 1 + ip link set dev br1 addrgenmode none + ip link set dev br1 up ip link set dev $swp1 master br1 ip link set dev $swp1 up ip link set dev $swp2 master br1 -- cgit v1.2.3 From 92c3bb5393db2f36e6a23ba7bb50b34c18c523f5 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:51 +0200 Subject: selftests: forwarding: mirror_gre_*: Disable IPv6 autogen on bridges In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge, the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. These two selftests however check mirroring traffic to a gretap netdevice. The bridge here does not participate in routing traffic and the IP address or the RIF are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridges in these selftests, thus exempting them from mlxsw router attention. Since the bridges are only used for L2 forwarding, this change should not hinder usefulness of this selftest for testing SW datapath or HW datapaths in other devices. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/mirror_gre_bound.sh | 1 + tools/testing/selftests/net/forwarding/mirror_topo_lib.sh | 1 + 2 files changed, 2 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bound.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bound.sh index 360ca133bead..6c257ec03756 100755 --- a/tools/testing/selftests/net/forwarding/mirror_gre_bound.sh +++ b/tools/testing/selftests/net/forwarding/mirror_gre_bound.sh @@ -98,6 +98,7 @@ switch_create() # Bridge between H1 and H2. ip link add name br1 type bridge vlan_filtering 1 + ip link set dev br1 addrgenmode none ip link set dev br1 up ip link set dev $swp1 master br1 diff --git a/tools/testing/selftests/net/forwarding/mirror_topo_lib.sh b/tools/testing/selftests/net/forwarding/mirror_topo_lib.sh index 04979e5962e7..bb1adbb7b98a 100644 --- a/tools/testing/selftests/net/forwarding/mirror_topo_lib.sh +++ b/tools/testing/selftests/net/forwarding/mirror_topo_lib.sh @@ -60,6 +60,7 @@ mirror_topo_switch_create() ip link set dev $swp3 up ip link add name br1 type bridge vlan_filtering 1 + ip link set dev br1 addrgenmode none ip link set dev br1 up ip link set dev $swp1 master br1 -- cgit v1.2.3 From 8fd32576e650efe88e396febd494f12adf18262a Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:52 +0200 Subject: selftests: forwarding: mirror_gre_*: Use port MAC for bridge address In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge, the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The bridge eventually inherits MAC address from its first member, after the enslavement is acked. A number of (mainly VXLAN) selftests already work around the problem by setting the MAC address to whatever it will eventually be anyway. Do the same for several mirror_gre selftests. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh | 3 ++- tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh | 3 ++- tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh index c5095da7f6bf..8ce3d95f1add 100755 --- a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh +++ b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh @@ -65,7 +65,8 @@ setup_prepare() vrf_prepare mirror_gre_topo_create - ip link add name br2 type bridge vlan_filtering 0 + ip link add name br2 address $(mac_get $swp3) \ + type bridge vlan_filtering 0 ip link set dev br2 up ip link set dev $swp3 master br2 diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh index 1b27f2b0f196..f35313c76fac 100755 --- a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh +++ b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh @@ -35,7 +35,8 @@ setup_prepare() vrf_prepare mirror_gre_topo_create - ip link add name br2 type bridge vlan_filtering 0 + ip link add name br2 address $(mac_get $swp3) \ + type bridge vlan_filtering 0 ip link set dev br2 up vlan_create $swp3 555 diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh index 91e431cd919e..c53148b1dc63 100755 --- a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh +++ b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh @@ -140,7 +140,8 @@ switch_create() ip link set dev $swp3 up ip link set dev $swp4 up - ip link add name br1 type bridge vlan_filtering 1 + ip link add name br1 address $(mac_get $swp3) \ + type bridge vlan_filtering 1 team_create lag loadbalance $swp3 $swp4 ip link set dev lag master br1 -- cgit v1.2.3 From 5e71bf50c2e284e4b287d55336a1b2f47027624c Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:53 +0200 Subject: selftests: forwarding: router_bridge: Use port MAC for bridge address In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge, the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The bridge eventually inherits MAC address from its first member, after the enslavement is acked. A number of (mainly VXLAN) selftests already work around the problem by setting the MAC address to whatever it will eventually be anyway. Do the same here. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/router_bridge.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/router_bridge.sh b/tools/testing/selftests/net/forwarding/router_bridge.sh index ebc596a272f7..8ce0aed54ece 100755 --- a/tools/testing/selftests/net/forwarding/router_bridge.sh +++ b/tools/testing/selftests/net/forwarding/router_bridge.sh @@ -38,7 +38,8 @@ h2_destroy() router_create() { - ip link add name br1 type bridge vlan_filtering 1 + ip link add name br1 address $(mac_get $swp1) \ + type bridge vlan_filtering 1 ip link set dev br1 up ip link set dev $swp1 master br1 -- cgit v1.2.3 From 8cfdd300a5e95fea14050cd86259bafb35244a2f Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:54 +0200 Subject: selftests: mlxsw: q_in_q_veto: Disable IPv6 autogen on bridges In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. The swp enslavement to the 802.1ad bridge is not allowed, because RIFs are not allowed to be created for 802.1ad bridges, but the address indicates one needs to be created. Thus the veto selftests fail already during the port enslavement. Then the attempt to create a VLAN on top of the same bridge is not vetoed, because the bridge is not related to mlxsw, and the selftest fails. Fix by disabling automatic IPv6 address generation for the bridges in this selftest, thus exempting them from the mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/q_in_q_veto.sh | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/drivers/net/mlxsw/q_in_q_veto.sh b/tools/testing/selftests/drivers/net/mlxsw/q_in_q_veto.sh index 7edaed8eb86a..00d55b0e98c1 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/q_in_q_veto.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/q_in_q_veto.sh @@ -48,6 +48,7 @@ create_vlan_upper_on_top_of_bridge() ip link add dev br0 type bridge vlan_filtering 1 \ vlan_protocol $bridge_proto vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br0 addrgenmode none ip link set dev br0 up ip link set dev $swp1 master br0 @@ -88,6 +89,7 @@ create_8021ad_vlan_upper_on_top_bridge_port() ip link add dev br0 type bridge vlan_filtering 1 \ vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br0 addrgenmode none ip link set dev $swp1 master br0 ip link set dev br0 up @@ -155,6 +157,7 @@ create_vlan_upper_on_top_front_panel_enslaved_to_8021ad_bridge() ip link add dev br0 type bridge vlan_filtering 1 \ vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br0 addrgenmode none ip link set dev br0 up ip link set dev $swp1 master br0 @@ -177,6 +180,7 @@ create_vlan_upper_on_top_lag_enslaved_to_8021ad_bridge() ip link add dev br0 type bridge vlan_filtering 1 \ vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br0 addrgenmode none ip link set dev br0 up ip link add name bond1 type bond mode 802.3ad @@ -203,6 +207,7 @@ enslave_front_panel_with_vlan_upper_to_8021ad_bridge() ip link add dev br0 type bridge vlan_filtering 1 \ vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br0 addrgenmode none ip link set dev br0 up ip link add name $swp1.100 link $swp1 type vlan id 100 @@ -225,6 +230,7 @@ enslave_lag_with_vlan_upper_to_8021ad_bridge() ip link add dev br0 type bridge vlan_filtering 1 \ vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br0 addrgenmode none ip link set dev br0 up ip link add name bond1 type bond mode 802.3ad @@ -252,6 +258,7 @@ add_ip_address_to_8021ad_bridge() ip link add dev br0 type bridge vlan_filtering 1 \ vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br0 addrgenmode none ip link set dev br0 up ip link set dev $swp1 master br0 @@ -273,6 +280,7 @@ switch_bridge_protocol_from_8021q_to_8021ad() ip link add dev br0 type bridge vlan_filtering 1 \ vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br0 addrgenmode none ip link set dev br0 up ip link set dev $swp1 master br0 -- cgit v1.2.3 From a758dc469a9caf958c0f02426aa76162c89faa97 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:55 +0200 Subject: selftests: mlxsw: extack: Disable IPv6 autogen on bridges In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge (this holds for all bridges used here), the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The selftest itself however checks whether a different vetoed aspect of the configuration provides an extack. The IP address or the RIF are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridges in this selftest, thus exempting them from mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- .../testing/selftests/drivers/net/mlxsw/extack.sh | 24 ++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/drivers/net/mlxsw/extack.sh b/tools/testing/selftests/drivers/net/mlxsw/extack.sh index 7a0a99c1d22f..6fd422d38fe8 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/extack.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/extack.sh @@ -35,7 +35,9 @@ netdev_pre_up_test() { RET=0 - ip link add name br1 up type bridge vlan_filtering 0 mcast_snooping 0 + ip link add name br1 type bridge vlan_filtering 0 mcast_snooping 0 + ip link set dev br1 addrgenmode none + ip link set dev br1 up ip link add name vx1 up type vxlan id 1000 \ local 192.0.2.17 remote 192.0.2.18 \ dstport 4789 nolearning noudpcsum tos inherit ttl 100 @@ -46,7 +48,9 @@ netdev_pre_up_test() ip link set dev $swp1 master br1 check_err $? - ip link add name br2 up type bridge vlan_filtering 0 mcast_snooping 0 + ip link add name br2 type bridge vlan_filtering 0 mcast_snooping 0 + ip link set dev br2 addrgenmode none + ip link set dev br2 up ip link add name vx2 up type vxlan id 2000 \ local 192.0.2.17 remote 192.0.2.18 \ dstport 4789 nolearning noudpcsum tos inherit ttl 100 @@ -81,7 +85,9 @@ vxlan_vlan_add_test() { RET=0 - ip link add name br1 up type bridge vlan_filtering 1 mcast_snooping 0 + ip link add name br1 type bridge vlan_filtering 1 mcast_snooping 0 + ip link set dev br1 addrgenmode none + ip link set dev br1 up # Unsupported configuration: mlxsw demands VXLAN with "noudpcsum". ip link add name vx1 up type vxlan id 1000 \ @@ -117,7 +123,9 @@ vxlan_bridge_create_test() dstport 4789 tos inherit ttl 100 # Test with VLAN-aware bridge. - ip link add name br1 up type bridge vlan_filtering 1 mcast_snooping 0 + ip link add name br1 type bridge vlan_filtering 1 mcast_snooping 0 + ip link set dev br1 addrgenmode none + ip link set dev br1 up ip link set dev vx1 master br1 @@ -142,8 +150,12 @@ bridge_create_test() { RET=0 - ip link add name br1 up type bridge vlan_filtering 1 - ip link add name br2 up type bridge vlan_filtering 1 + ip link add name br1 type bridge vlan_filtering 1 + ip link set dev br1 addrgenmode none + ip link set dev br1 up + ip link add name br2 type bridge vlan_filtering 1 + ip link set dev br2 addrgenmode none + ip link set dev br2 up ip link set dev $swp1 master br1 check_err $? -- cgit v1.2.3 From 32b3a7bf8570d24b30d1961fb3eaddb9f1c3250a Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:56 +0200 Subject: selftests: mlxsw: mirror_gre_scale: Disable IPv6 autogen on a bridge In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge, the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The selftest itself however checks how many mirroring sessions a machine is capable of offloading. The IP address or the RIF are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridge in this selftest, thus exempting it from mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh index e00435753008..e5589e2fca85 100644 --- a/tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh @@ -165,6 +165,7 @@ mirror_gre_setup_prepare() simple_if_init $h3 ip link add name br1 type bridge vlan_filtering 1 + ip link set dev br1 addrgenmode none ip link set dev br1 up ip link set dev $swp1 master br1 -- cgit v1.2.3 From 6349f9bbbfb2bda12c0a633965d03435d18d930f Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:57 +0200 Subject: selftests: mlxsw: qos_dscp_bridge: Disable IPv6 autogen on a bridge In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge, the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The selftest itself however checks DCB DSCP-based prioritization, and the bridge serves for its L2 forwarding capabilities, and does not need to participate in routing traffic. The IP address or the RIF are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridge in this selftest, thus exempting it from mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh index 87c41f5727c9..914c63d6318a 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh @@ -65,6 +65,7 @@ h2_destroy() switch_create() { ip link add name br1 type bridge vlan_filtering 1 + ip link set dev br1 addrgenmode none ip link set dev br1 up ip link set dev $swp1 master br1 ip link set dev $swp1 up -- cgit v1.2.3 From ec7023e6745e6fb34cd855522cb8f995194bdbf1 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:58 +0200 Subject: selftests: mlxsw: qos_ets_strict: Disable IPv6 autogen on bridges In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge (this holds for both bridges used here), the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The selftest itself however checks traffic prioritization and scheduling, and the bridges serve for their L2 forwarding capabilities, and do not need to participate in routing traffic. The IP addresses or the RIFs are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridges in this selftest, thus exempting them from mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/qos_ets_strict.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_ets_strict.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_ets_strict.sh index 690d8daa71b4..fee74f215cec 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/qos_ets_strict.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_ets_strict.sh @@ -138,11 +138,15 @@ switch_create() vlan_create $swp3 111 vlan_create $swp3 222 - ip link add name br111 up type bridge vlan_filtering 0 + ip link add name br111 type bridge vlan_filtering 0 + ip link set dev br111 addrgenmode none + ip link set dev br111 up ip link set dev $swp1.111 master br111 ip link set dev $swp3.111 master br111 - ip link add name br222 up type bridge vlan_filtering 0 + ip link add name br222 type bridge vlan_filtering 0 + ip link set dev br222 addrgenmode none + ip link set dev br222 up ip link set dev $swp2.222 master br222 ip link set dev $swp3.222 master br222 -- cgit v1.2.3 From ea2d5f757e914fa0f82949e130ee9da0ee931e59 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:59 +0200 Subject: selftests: mlxsw: qos_mc_aware: Disable IPv6 autogen on bridges In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge (this holds for both bridges used here), the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The selftest itself however checks traffic prioritization and scheduling, and the bridges serve for their L2 forwarding capabilities, and do not need to participate in routing traffic. The IP addresses or the RIFs are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridges in this selftest, thus exempting them from mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh index c8e55fa91660..6d892de43fa8 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh @@ -135,11 +135,13 @@ switch_create() prio bands 8 priomap 7 7 7 7 7 7 7 7 ip link add name br1 type bridge vlan_filtering 0 + ip link set dev br1 addrgenmode none ip link set dev br1 up ip link set dev $swp1 master br1 ip link set dev $swp3 master br1 ip link add name br111 type bridge vlan_filtering 0 + ip link set dev br111 addrgenmode none ip link set dev br111 up ip link set dev $swp2.111 master br111 ip link set dev $swp3.111 master br111 -- cgit v1.2.3 From 08035d8e354d9fc652c9d12668e89d83edc8f974 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:56:00 +0200 Subject: selftests: mlxsw: spectrum: q_in_vni_veto: Disable IPv6 autogen on a bridge In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge, the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The selftest itself however checks vetoing of a different aspect of the configuration and the bridge does not need to participate in routing traffic. The IP address or the RIF are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridge in this selftest, thus exempting it from mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/spectrum/q_in_vni_veto.sh | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum/q_in_vni_veto.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum/q_in_vni_veto.sh index f0443b1b05b9..60753d46a2d4 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/spectrum/q_in_vni_veto.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/spectrum/q_in_vni_veto.sh @@ -34,6 +34,7 @@ create_vxlan_on_top_of_8021ad_bridge() ip link add dev br0 type bridge vlan_filtering 1 vlan_protocol 802.1ad \ vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br0 addrgenmode none ip link set dev br0 up ip link add name vx100 type vxlan id 1000 local 192.0.2.17 dstport \ -- cgit v1.2.3 From 5541577521cc2e22bc84ba92be24959671006283 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:56:01 +0200 Subject: selftests: mlxsw: vxlan: Disable IPv6 autogen on bridges In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge (this holds for all bridges used here), the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The selftest itself however checks various aspects of VXLAN offloading and the bridges do not need to participate in routing traffic. The IP addresses or the RIFs are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridges in this selftest, thus exempting them from mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/vxlan.sh | 41 ++++++++++++++++------ 1 file changed, 31 insertions(+), 10 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/drivers/net/mlxsw/vxlan.sh b/tools/testing/selftests/drivers/net/mlxsw/vxlan.sh index 99a332b712f0..4687b0a7dffb 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/vxlan.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/vxlan.sh @@ -444,8 +444,12 @@ offload_indication_setup_create() { # Create a simple setup with two bridges, each with a VxLAN device # and one local port - ip link add name br0 up type bridge mcast_snooping 0 - ip link add name br1 up type bridge mcast_snooping 0 + ip link add name br0 type bridge mcast_snooping 0 + ip link set dev br0 addrgenmode none + ip link set dev br0 up + ip link add name br1 type bridge mcast_snooping 0 + ip link set dev br1 addrgenmode none + ip link set dev br1 up ip link set dev $swp1 master br0 ip link set dev $swp2 master br1 @@ -646,8 +650,12 @@ offload_indication_decap_route_test() RET=0 - ip link add name br0 up type bridge mcast_snooping 0 - ip link add name br1 up type bridge mcast_snooping 0 + ip link add name br0 type bridge mcast_snooping 0 + ip link set dev br0 addrgenmode none + ip link set dev br0 up + ip link add name br1 type bridge mcast_snooping 0 + ip link set dev br1 addrgenmode none + ip link set dev br1 up ip link set dev $swp1 master br0 ip link set dev $swp2 master br1 ip link set dev vxlan0 master br0 @@ -780,7 +788,9 @@ __offload_indication_join_vxlan_first() offload_indication_join_vxlan_first() { - ip link add dev br0 up type bridge mcast_snooping 0 + ip link add dev br0 type bridge mcast_snooping 0 + ip link set dev br0 addrgenmode none + ip link set dev br0 up ip link add name vxlan0 up type vxlan id 10 nolearning $UDPCSUM_FLAFS \ ttl 20 tos inherit local $LOCAL_IP_1 dstport 4789 @@ -815,7 +825,9 @@ __offload_indication_join_vxlan_last() offload_indication_join_vxlan_last() { - ip link add dev br0 up type bridge mcast_snooping 0 + ip link add dev br0 type bridge mcast_snooping 0 + ip link set dev br0 addrgenmode none + ip link set dev br0 up ip link add name vxlan0 up type vxlan id 10 nolearning $UDPCSUM_FLAFS \ ttl 20 tos inherit local $LOCAL_IP_1 dstport 4789 @@ -842,6 +854,7 @@ sanitization_vlan_aware_test() RET=0 ip link add dev br0 type bridge mcast_snooping 0 vlan_filtering 1 + ip link set dev br0 addrgenmode none ip link add name vxlan10 up master br0 type vxlan id 10 nolearning \ $UDPCSUM_FLAFS ttl 20 tos inherit local $LOCAL_IP_1 dstport 4789 @@ -915,8 +928,10 @@ offload_indication_vlan_aware_setup_create() { # Create a simple setup with two VxLAN devices and a single VLAN-aware # bridge - ip link add name br0 up type bridge mcast_snooping 0 vlan_filtering 1 \ + ip link add name br0 type bridge mcast_snooping 0 vlan_filtering 1 \ vlan_default_pvid 0 + ip link set dev br0 addrgenmode none + ip link set dev br0 up ip link set dev $swp1 master br0 @@ -1060,8 +1075,10 @@ offload_indication_vlan_aware_decap_route_test() offload_indication_vlan_aware_join_vxlan_first() { - ip link add dev br0 up type bridge mcast_snooping 0 \ + ip link add dev br0 type bridge mcast_snooping 0 \ vlan_filtering 1 vlan_default_pvid 1 + ip link set dev br0 addrgenmode none + ip link set dev br0 up ip link add name vxlan0 up type vxlan id 10 nolearning $UDPCSUM_FLAFS \ ttl 20 tos inherit local $LOCAL_IP_1 dstport 4789 @@ -1073,8 +1090,10 @@ offload_indication_vlan_aware_join_vxlan_first() offload_indication_vlan_aware_join_vxlan_last() { - ip link add dev br0 up type bridge mcast_snooping 0 \ + ip link add dev br0 type bridge mcast_snooping 0 \ vlan_filtering 1 vlan_default_pvid 1 + ip link set dev br0 addrgenmode none + ip link set dev br0 up ip link add name vxlan0 up type vxlan id 10 nolearning $UDPCSUM_FLAFS \ ttl 20 tos inherit local $LOCAL_IP_1 dstport 4789 @@ -1091,8 +1110,10 @@ offload_indication_vlan_aware_l3vni_test() RET=0 sysctl_set net.ipv6.conf.default.disable_ipv6 1 - ip link add dev br0 up type bridge mcast_snooping 0 \ + ip link add dev br0 type bridge mcast_snooping 0 \ vlan_filtering 1 vlan_default_pvid 0 + ip link set dev br0 addrgenmode none + ip link set dev br0 up ip link add name vxlan0 up type vxlan id 10 nolearning $UDPCSUM_FLAFS \ ttl 20 tos inherit local $LOCAL_IP_1 dstport 4789 -- cgit v1.2.3 From 664bc72dd20073be227f9e68b3db75313c6926f8 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:56:02 +0200 Subject: selftests: mlxsw: one_armed_router: Use port MAC for bridge address In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge, the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The bridge eventually inherits MAC address from its first member, after the enslavement is acked. A number of (mainly VXLAN) selftests already work around the problem by setting the MAC address to whatever it will eventually be anyway. Do the same for this selftest. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/one_armed_router.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/drivers/net/mlxsw/one_armed_router.sh b/tools/testing/selftests/drivers/net/mlxsw/one_armed_router.sh index f02d83e94576..fca0e1e642c6 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/one_armed_router.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/one_armed_router.sh @@ -83,7 +83,8 @@ h2_destroy() switch_create() { - ip link add name br0 type bridge mcast_snooping 0 + ip link add name br0 address $(mac_get $swp1) \ + type bridge mcast_snooping 0 ip link set dev br0 up ip link set dev $swp1 master br0 -- cgit v1.2.3 From 3d5786ea472c3aff14e931d52ba05627c075d432 Mon Sep 17 00:00:00 2001 From: Gilad Sever Date: Wed, 21 Jun 2023 13:42:11 +0300 Subject: selftests/bpf: Add vrf_socket_lookup tests Verify that socket lookup via TC/XDP with all BPF APIs is VRF aware. Signed-off-by: Gilad Sever Signed-off-by: Daniel Borkmann Reviewed-by: Eyal Birger Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20230621104211.301902-5-gilad9366@gmail.com --- .../selftests/bpf/prog_tests/vrf_socket_lookup.c | 312 +++++++++++++++++++++ .../selftests/bpf/progs/vrf_socket_lookup.c | 88 ++++++ 2 files changed, 400 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/vrf_socket_lookup.c create mode 100644 tools/testing/selftests/bpf/progs/vrf_socket_lookup.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/prog_tests/vrf_socket_lookup.c b/tools/testing/selftests/bpf/prog_tests/vrf_socket_lookup.c new file mode 100644 index 000000000000..2a5e207edad6 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/vrf_socket_lookup.c @@ -0,0 +1,312 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + +/* + * Topology: + * --------- + * NS0 namespace | NS1 namespace + * | + * +--------------+ | +--------------+ + * | veth01 |----------| veth10 | + * | 172.16.1.100 | | | 172.16.1.200 | + * | bpf | | +--------------+ + * +--------------+ | + * server(UDP/TCP) | + * +-------------------+ | + * | vrf1 | | + * | +--------------+ | | +--------------+ + * | | veth02 |----------| veth20 | + * | | 172.16.2.100 | | | | 172.16.2.200 | + * | | bpf | | | +--------------+ + * | +--------------+ | | + * | server(UDP/TCP) | | + * +-------------------+ | + * + * Test flow + * ----------- + * The tests verifies that socket lookup via TC is VRF aware: + * 1) Creates two veth pairs between NS0 and NS1: + * a) veth01 <-> veth10 outside the VRF + * b) veth02 <-> veth20 in the VRF + * 2) Attaches to veth01 and veth02 a program that calls: + * a) bpf_skc_lookup_tcp() with TCP and tcp_skc is true + * b) bpf_sk_lookup_tcp() with TCP and tcp_skc is false + * c) bpf_sk_lookup_udp() with UDP + * The program stores the lookup result in bss->lookup_status. + * 3) Creates a socket TCP/UDP server in/outside the VRF. + * 4) The test expects lookup_status to be: + * a) 0 from device in VRF to server outside VRF + * b) 0 from device outside VRF to server in VRF + * c) 1 from device in VRF to server in VRF + * d) 1 from device outside VRF to server outside VRF + */ + +#include + +#include "test_progs.h" +#include "network_helpers.h" +#include "vrf_socket_lookup.skel.h" + +#define NS0 "vrf_socket_lookup_0" +#define NS1 "vrf_socket_lookup_1" + +#define IP4_ADDR_VETH01 "172.16.1.100" +#define IP4_ADDR_VETH10 "172.16.1.200" +#define IP4_ADDR_VETH02 "172.16.2.100" +#define IP4_ADDR_VETH20 "172.16.2.200" + +#define NON_VRF_PORT 5000 +#define IN_VRF_PORT 5001 + +#define TIMEOUT_MS 3000 + +static int make_socket(int sotype, const char *ip, int port, + struct sockaddr_storage *addr) +{ + int err, fd; + + err = make_sockaddr(AF_INET, ip, port, addr, NULL); + if (!ASSERT_OK(err, "make_address")) + return -1; + + fd = socket(AF_INET, sotype, 0); + if (!ASSERT_GE(fd, 0, "socket")) + return -1; + + if (!ASSERT_OK(settimeo(fd, TIMEOUT_MS), "settimeo")) + goto fail; + + return fd; +fail: + close(fd); + return -1; +} + +static int make_server(int sotype, const char *ip, int port, const char *ifname) +{ + int err, fd = -1; + + fd = start_server(AF_INET, sotype, ip, port, TIMEOUT_MS); + if (!ASSERT_GE(fd, 0, "start_server")) + return -1; + + if (ifname) { + err = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, + ifname, strlen(ifname) + 1); + if (!ASSERT_OK(err, "setsockopt(SO_BINDTODEVICE)")) + goto fail; + } + + return fd; +fail: + close(fd); + return -1; +} + +static int attach_progs(char *ifname, int tc_prog_fd, int xdp_prog_fd) +{ + LIBBPF_OPTS(bpf_tc_hook, hook, .attach_point = BPF_TC_INGRESS); + LIBBPF_OPTS(bpf_tc_opts, opts, .handle = 1, .priority = 1, + .prog_fd = tc_prog_fd); + int ret, ifindex; + + ifindex = if_nametoindex(ifname); + if (!ASSERT_NEQ(ifindex, 0, "if_nametoindex")) + return -1; + hook.ifindex = ifindex; + + ret = bpf_tc_hook_create(&hook); + if (!ASSERT_OK(ret, "bpf_tc_hook_create")) + return ret; + + ret = bpf_tc_attach(&hook, &opts); + if (!ASSERT_OK(ret, "bpf_tc_attach")) { + bpf_tc_hook_destroy(&hook); + return ret; + } + ret = bpf_xdp_attach(ifindex, xdp_prog_fd, 0, NULL); + if (!ASSERT_OK(ret, "bpf_xdp_attach")) { + bpf_tc_hook_destroy(&hook); + return ret; + } + + return 0; +} + +static void cleanup(void) +{ + SYS_NOFAIL("test -f /var/run/netns/" NS0 " && ip netns delete " + NS0); + SYS_NOFAIL("test -f /var/run/netns/" NS1 " && ip netns delete " + NS1); +} + +static int setup(struct vrf_socket_lookup *skel) +{ + int tc_prog_fd, xdp_prog_fd, ret = 0; + struct nstoken *nstoken = NULL; + + SYS(fail, "ip netns add " NS0); + SYS(fail, "ip netns add " NS1); + + /* NS0 <-> NS1 [veth01 <-> veth10] */ + SYS(fail, "ip link add veth01 netns " NS0 " type veth peer name veth10" + " netns " NS1); + SYS(fail, "ip -net " NS0 " addr add " IP4_ADDR_VETH01 "/24 dev veth01"); + SYS(fail, "ip -net " NS0 " link set dev veth01 up"); + SYS(fail, "ip -net " NS1 " addr add " IP4_ADDR_VETH10 "/24 dev veth10"); + SYS(fail, "ip -net " NS1 " link set dev veth10 up"); + + /* NS0 <-> NS1 [veth02 <-> veth20] */ + SYS(fail, "ip link add veth02 netns " NS0 " type veth peer name veth20" + " netns " NS1); + SYS(fail, "ip -net " NS0 " addr add " IP4_ADDR_VETH02 "/24 dev veth02"); + SYS(fail, "ip -net " NS0 " link set dev veth02 up"); + SYS(fail, "ip -net " NS1 " addr add " IP4_ADDR_VETH20 "/24 dev veth20"); + SYS(fail, "ip -net " NS1 " link set dev veth20 up"); + + /* veth02 -> vrf1 */ + SYS(fail, "ip -net " NS0 " link add vrf1 type vrf table 11"); + SYS(fail, "ip -net " NS0 " route add vrf vrf1 unreachable default" + " metric 4278198272"); + SYS(fail, "ip -net " NS0 " link set vrf1 alias vrf"); + SYS(fail, "ip -net " NS0 " link set vrf1 up"); + SYS(fail, "ip -net " NS0 " link set veth02 master vrf1"); + + /* Attach TC and XDP progs to veth devices in NS0 */ + nstoken = open_netns(NS0); + if (!ASSERT_OK_PTR(nstoken, "setns " NS0)) + goto fail; + tc_prog_fd = bpf_program__fd(skel->progs.tc_socket_lookup); + if (!ASSERT_GE(tc_prog_fd, 0, "bpf_program__tc_fd")) + goto fail; + xdp_prog_fd = bpf_program__fd(skel->progs.xdp_socket_lookup); + if (!ASSERT_GE(xdp_prog_fd, 0, "bpf_program__xdp_fd")) + goto fail; + + if (attach_progs("veth01", tc_prog_fd, xdp_prog_fd)) + goto fail; + + if (attach_progs("veth02", tc_prog_fd, xdp_prog_fd)) + goto fail; + + goto close; +fail: + ret = -1; +close: + if (nstoken) + close_netns(nstoken); + return ret; +} + +static int test_lookup(struct vrf_socket_lookup *skel, int sotype, + const char *ip, int port, bool test_xdp, bool tcp_skc, + int lookup_status_exp) +{ + static const char msg[] = "Hello Server"; + struct sockaddr_storage addr = {}; + int fd, ret = 0; + + fd = make_socket(sotype, ip, port, &addr); + if (fd < 0) + return -1; + + skel->bss->test_xdp = test_xdp; + skel->bss->tcp_skc = tcp_skc; + skel->bss->lookup_status = -1; + + if (sotype == SOCK_STREAM) + connect(fd, (void *)&addr, sizeof(struct sockaddr_in)); + else + sendto(fd, msg, sizeof(msg), 0, (void *)&addr, + sizeof(struct sockaddr_in)); + + if (!ASSERT_EQ(skel->bss->lookup_status, lookup_status_exp, + "lookup_status")) + goto fail; + + goto close; + +fail: + ret = -1; +close: + close(fd); + return ret; +} + +static void _test_vrf_socket_lookup(struct vrf_socket_lookup *skel, int sotype, + bool test_xdp, bool tcp_skc) +{ + int in_vrf_server = -1, non_vrf_server = -1; + struct nstoken *nstoken = NULL; + + nstoken = open_netns(NS0); + if (!ASSERT_OK_PTR(nstoken, "setns " NS0)) + goto done; + + /* Open sockets in and outside VRF */ + non_vrf_server = make_server(sotype, "0.0.0.0", NON_VRF_PORT, NULL); + if (!ASSERT_GE(non_vrf_server, 0, "make_server__outside_vrf_fd")) + goto done; + + in_vrf_server = make_server(sotype, "0.0.0.0", IN_VRF_PORT, "veth02"); + if (!ASSERT_GE(in_vrf_server, 0, "make_server__in_vrf_fd")) + goto done; + + /* Perform test from NS1 */ + close_netns(nstoken); + nstoken = open_netns(NS1); + if (!ASSERT_OK_PTR(nstoken, "setns " NS1)) + goto done; + + if (!ASSERT_OK(test_lookup(skel, sotype, IP4_ADDR_VETH02, NON_VRF_PORT, + test_xdp, tcp_skc, 0), "in_to_out")) + goto done; + if (!ASSERT_OK(test_lookup(skel, sotype, IP4_ADDR_VETH02, IN_VRF_PORT, + test_xdp, tcp_skc, 1), "in_to_in")) + goto done; + if (!ASSERT_OK(test_lookup(skel, sotype, IP4_ADDR_VETH01, NON_VRF_PORT, + test_xdp, tcp_skc, 1), "out_to_out")) + goto done; + if (!ASSERT_OK(test_lookup(skel, sotype, IP4_ADDR_VETH01, IN_VRF_PORT, + test_xdp, tcp_skc, 0), "out_to_in")) + goto done; + +done: + if (non_vrf_server >= 0) + close(non_vrf_server); + if (in_vrf_server >= 0) + close(in_vrf_server); + if (nstoken) + close_netns(nstoken); +} + +void test_vrf_socket_lookup(void) +{ + struct vrf_socket_lookup *skel; + + cleanup(); + + skel = vrf_socket_lookup__open_and_load(); + if (!ASSERT_OK_PTR(skel, "vrf_socket_lookup__open_and_load")) + return; + + if (!ASSERT_OK(setup(skel), "setup")) + goto done; + + if (test__start_subtest("tc_socket_lookup_tcp")) + _test_vrf_socket_lookup(skel, SOCK_STREAM, false, false); + if (test__start_subtest("tc_socket_lookup_tcp_skc")) + _test_vrf_socket_lookup(skel, SOCK_STREAM, false, false); + if (test__start_subtest("tc_socket_lookup_udp")) + _test_vrf_socket_lookup(skel, SOCK_STREAM, false, false); + if (test__start_subtest("xdp_socket_lookup_tcp")) + _test_vrf_socket_lookup(skel, SOCK_STREAM, true, false); + if (test__start_subtest("xdp_socket_lookup_tcp_skc")) + _test_vrf_socket_lookup(skel, SOCK_STREAM, true, false); + if (test__start_subtest("xdp_socket_lookup_udp")) + _test_vrf_socket_lookup(skel, SOCK_STREAM, true, false); + +done: + vrf_socket_lookup__destroy(skel); + cleanup(); +} diff --git a/tools/testing/selftests/bpf/progs/vrf_socket_lookup.c b/tools/testing/selftests/bpf/progs/vrf_socket_lookup.c new file mode 100644 index 000000000000..26e07a252585 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/vrf_socket_lookup.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include + +int lookup_status; +bool test_xdp; +bool tcp_skc; + +#define CUR_NS BPF_F_CURRENT_NETNS + +static void socket_lookup(void *ctx, void *data_end, void *data) +{ + struct ethhdr *eth = data; + struct bpf_sock_tuple *tp; + struct bpf_sock *sk; + struct iphdr *iph; + int tplen; + + if (eth + 1 > data_end) + return; + + if (eth->h_proto != bpf_htons(ETH_P_IP)) + return; + + iph = (struct iphdr *)(eth + 1); + if (iph + 1 > data_end) + return; + + tp = (struct bpf_sock_tuple *)&iph->saddr; + tplen = sizeof(tp->ipv4); + if ((void *)tp + tplen > data_end) + return; + + switch (iph->protocol) { + case IPPROTO_TCP: + if (tcp_skc) + sk = bpf_skc_lookup_tcp(ctx, tp, tplen, CUR_NS, 0); + else + sk = bpf_sk_lookup_tcp(ctx, tp, tplen, CUR_NS, 0); + break; + case IPPROTO_UDP: + sk = bpf_sk_lookup_udp(ctx, tp, tplen, CUR_NS, 0); + break; + default: + return; + } + + lookup_status = 0; + + if (sk) { + bpf_sk_release(sk); + lookup_status = 1; + } +} + +SEC("tc") +int tc_socket_lookup(struct __sk_buff *skb) +{ + void *data_end = (void *)(long)skb->data_end; + void *data = (void *)(long)skb->data; + + if (test_xdp) + return TC_ACT_UNSPEC; + + socket_lookup(skb, data_end, data); + return TC_ACT_UNSPEC; +} + +SEC("xdp") +int xdp_socket_lookup(struct xdp_md *xdp) +{ + void *data_end = (void *)(long)xdp->data_end; + void *data = (void *)(long)xdp->data; + + if (!test_xdp) + return XDP_PASS; + + socket_lookup(xdp, data_end, data); + return XDP_PASS; +} + +char _license[] SEC("license") = "GPL"; -- cgit v1.2.3 From ca4fa87435370747cac535cecfd08672bb679487 Mon Sep 17 00:00:00 2001 From: renmingshuai Date: Tue, 20 Jun 2023 09:49:39 +0800 Subject: selftests: tc-testing: add one test for flushing explicitly created chain Add the test for additional reference to chains that are explicitly created by RTM_NEWCHAIN message. The test result: 1..1 ok 1 c2b4 - soft lockup alarm will be not generated after delete the prio 0 filter of the chain This is a follow up to commit c9a82bec02c3 ("net/sched: cls_api: Fix lockup on flushing explicitly created chain"). Signed-off-by: Mingshuai Ren Acked-by: Pedro Tammela Acked-by: Victor Nogueira Link: https://lore.kernel.org/r/20230620014939.2034054-1-renmingshuai@huawei.com Signed-off-by: Jakub Kicinski --- .../tc-testing/tc-tests/infra/filter.json | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tools/testing/selftests/tc-testing/tc-tests/infra/filter.json (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tc-tests/infra/filter.json b/tools/testing/selftests/tc-testing/tc-tests/infra/filter.json new file mode 100644 index 000000000000..c4c778e83da2 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/infra/filter.json @@ -0,0 +1,25 @@ +[ + { + "id": "c2b4", + "name": "soft lockup alarm will be not generated after delete the prio 0 filter of the chain", + "category": [ + "filter", + "chain" + ], + "setup": [ + "$IP link add dev $DUMMY type dummy || /bin/true", + "$TC qdisc add dev $DUMMY root handle 1: htb default 1", + "$TC chain add dev $DUMMY", + "$TC filter del dev $DUMMY chain 0 parent 1: prio 0" + ], + "cmdUnderTest": "$TC filter add dev $DUMMY chain 0 parent 1:", + "expExitCode": "2", + "verifyCmd": "$TC chain ls dev $DUMMY", + "matchPattern": "chain parent 1: chain 0", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DUMMY root handle 1: htb default 1", + "$IP link del dev $DUMMY type dummy" + ] + } +] -- cgit v1.2.3 From 5dcff89e14555a4ee6cfa132b82f7d13dcb1e80a Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 20 Jun 2023 18:30:16 +0200 Subject: selftests: mptcp: explicitly tests aggregate counters Update the existing sockopt test-case to do some basic checks on the newly added counters. Link: https://github.com/multipath-tcp/mptcp_net-next/issues/385 Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts Signed-off-by: Matthieu Baerts Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_sockopt.c | 27 ++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c index b35148edbf02..5ee710b30f10 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c +++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c @@ -51,6 +51,11 @@ struct mptcp_info { __u8 mptcpi_local_addr_used; __u8 mptcpi_local_addr_max; __u8 mptcpi_csum_enabled; + __u32 mptcpi_retransmits; + __u64 mptcpi_bytes_retrans; + __u64 mptcpi_bytes_sent; + __u64 mptcpi_bytes_received; + __u64 mptcpi_bytes_acked; }; struct mptcp_subflow_data { @@ -83,8 +88,10 @@ struct mptcp_subflow_addrs { struct so_state { struct mptcp_info mi; + struct mptcp_info last_sample; uint64_t mptcpi_rcv_delta; uint64_t tcpi_rcv_delta; + bool pkt_stats_avail; }; #ifndef MIN @@ -322,8 +329,9 @@ static void do_getsockopt_mptcp_info(struct so_state *s, int fd, size_t w) if (ret < 0) die_perror("getsockopt MPTCP_INFO"); - assert(olen == sizeof(i)); + s->pkt_stats_avail = olen >= sizeof(i); + s->last_sample = i; if (s->mi.mptcpi_write_seq == 0) s->mi = i; @@ -562,6 +570,23 @@ static void process_one_client(int fd, int pipefd) do_getsockopts(&s, fd, ret, ret2); if (s.mptcpi_rcv_delta != (uint64_t)ret + 1) xerror("mptcpi_rcv_delta %" PRIu64 ", expect %" PRIu64, s.mptcpi_rcv_delta, ret + 1, s.mptcpi_rcv_delta - ret); + + /* be nice when running on top of older kernel */ + if (s.pkt_stats_avail) { + if (s.last_sample.mptcpi_bytes_sent != ret2) + xerror("mptcpi_bytes_sent %" PRIu64 ", expect %" PRIu64, + s.last_sample.mptcpi_bytes_sent, ret2, + s.last_sample.mptcpi_bytes_sent - ret2); + if (s.last_sample.mptcpi_bytes_received != ret) + xerror("mptcpi_bytes_received %" PRIu64 ", expect %" PRIu64, + s.last_sample.mptcpi_bytes_received, ret, + s.last_sample.mptcpi_bytes_received - ret); + if (s.last_sample.mptcpi_bytes_acked != ret) + xerror("mptcpi_bytes_acked %" PRIu64 ", expect %" PRIu64, + s.last_sample.mptcpi_bytes_acked, ret2, + s.last_sample.mptcpi_bytes_acked - ret2); + } + close(fd); } -- cgit v1.2.3 From aa723d5b3541bfcf9b7493fc1c47e6af6a11b765 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 20 Jun 2023 18:30:19 +0200 Subject: selftests: mptcp: add MPTCP_FULL_INFO testcase Add a testcase explicitly triggering the newly introduce MPTCP_FULL_INFO getsockopt. Link: https://github.com/multipath-tcp/mptcp_net-next/issues/388 Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts Co-developed-by: Matthieu Baerts Signed-off-by: Matthieu Baerts Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_sockopt.c | 93 ++++++++++++++++++++++- 1 file changed, 91 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c index 5ee710b30f10..926b0be87c99 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c +++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c @@ -86,9 +86,38 @@ struct mptcp_subflow_addrs { #define MPTCP_SUBFLOW_ADDRS 3 #endif +#ifndef MPTCP_FULL_INFO +struct mptcp_subflow_info { + __u32 id; + struct mptcp_subflow_addrs addrs; +}; + +struct mptcp_full_info { + __u32 size_tcpinfo_kernel; /* must be 0, set by kernel */ + __u32 size_tcpinfo_user; + __u32 size_sfinfo_kernel; /* must be 0, set by kernel */ + __u32 size_sfinfo_user; + __u32 num_subflows; /* must be 0, set by kernel (real subflow count) */ + __u32 size_arrays_user; /* max subflows that userspace is interested in; + * the buffers at subflow_info/tcp_info + * are respectively at least: + * size_arrays * size_sfinfo_user + * size_arrays * size_tcpinfo_user + * bytes wide + */ + __aligned_u64 subflow_info; + __aligned_u64 tcp_info; + struct mptcp_info mptcp_info; +}; + +#define MPTCP_FULL_INFO 4 +#endif + struct so_state { struct mptcp_info mi; struct mptcp_info last_sample; + struct tcp_info tcp_info; + struct mptcp_subflow_addrs addrs; uint64_t mptcpi_rcv_delta; uint64_t tcpi_rcv_delta; bool pkt_stats_avail; @@ -370,6 +399,8 @@ static void do_getsockopt_tcp_info(struct so_state *s, int fd, size_t r, size_t olen -= sizeof(struct mptcp_subflow_data); assert(olen == ti.d.size_user); + s->tcp_info = ti.ti[0]; + if (ti.ti[0].tcpi_bytes_sent == w && ti.ti[0].tcpi_bytes_received == r) goto done; @@ -391,7 +422,7 @@ done: do_getsockopt_bogus_sf_data(fd, MPTCP_TCPINFO); } -static void do_getsockopt_subflow_addrs(int fd) +static void do_getsockopt_subflow_addrs(struct so_state *s, int fd) { struct sockaddr_storage remote, local; socklen_t olen, rlen, llen; @@ -439,6 +470,7 @@ static void do_getsockopt_subflow_addrs(int fd) assert(memcmp(&local, &addrs.addr[0].ss_local, sizeof(local)) == 0); assert(memcmp(&remote, &addrs.addr[0].ss_remote, sizeof(remote)) == 0); + s->addrs = addrs.addr[0]; memset(&addrs, 0, sizeof(addrs)); @@ -459,13 +491,70 @@ static void do_getsockopt_subflow_addrs(int fd) do_getsockopt_bogus_sf_data(fd, MPTCP_SUBFLOW_ADDRS); } +static void do_getsockopt_mptcp_full_info(struct so_state *s, int fd) +{ + size_t data_size = sizeof(struct mptcp_full_info); + struct mptcp_subflow_info sfinfo[2]; + struct tcp_info tcp_info[2]; + struct mptcp_full_info mfi; + socklen_t olen; + int ret; + + memset(&mfi, 0, data_size); + memset(tcp_info, 0, sizeof(tcp_info)); + memset(sfinfo, 0, sizeof(sfinfo)); + + mfi.size_tcpinfo_user = sizeof(struct tcp_info); + mfi.size_sfinfo_user = sizeof(struct mptcp_subflow_info); + mfi.size_arrays_user = 2; + mfi.subflow_info = (unsigned long)&sfinfo[0]; + mfi.tcp_info = (unsigned long)&tcp_info[0]; + olen = data_size; + + ret = getsockopt(fd, SOL_MPTCP, MPTCP_FULL_INFO, &mfi, &olen); + if (ret < 0) { + if (errno == EOPNOTSUPP) { + perror("MPTCP_FULL_INFO test skipped"); + return; + } + xerror("getsockopt MPTCP_FULL_INFO"); + } + + assert(olen <= data_size); + assert(mfi.size_tcpinfo_kernel > 0); + assert(mfi.size_tcpinfo_user == + MIN(mfi.size_tcpinfo_kernel, sizeof(struct tcp_info))); + assert(mfi.size_sfinfo_kernel > 0); + assert(mfi.size_sfinfo_user == + MIN(mfi.size_sfinfo_kernel, sizeof(struct mptcp_subflow_info))); + assert(mfi.num_subflows == 1); + + /* Tolerate future extension to mptcp_info struct and running newer + * test on top of older kernel. + * Anyway any kernel supporting MPTCP_FULL_INFO must at least include + * the following in mptcp_info. + */ + assert(olen > (socklen_t)__builtin_offsetof(struct mptcp_full_info, tcp_info)); + assert(mfi.mptcp_info.mptcpi_subflows == 0); + assert(mfi.mptcp_info.mptcpi_bytes_sent == s->last_sample.mptcpi_bytes_sent); + assert(mfi.mptcp_info.mptcpi_bytes_received == s->last_sample.mptcpi_bytes_received); + + assert(sfinfo[0].id == 1); + assert(tcp_info[0].tcpi_bytes_sent == s->tcp_info.tcpi_bytes_sent); + assert(tcp_info[0].tcpi_bytes_received == s->tcp_info.tcpi_bytes_received); + assert(!memcmp(&sfinfo->addrs, &s->addrs, sizeof(struct mptcp_subflow_addrs))); +} + static void do_getsockopts(struct so_state *s, int fd, size_t r, size_t w) { do_getsockopt_mptcp_info(s, fd, w); do_getsockopt_tcp_info(s, fd, r, w); - do_getsockopt_subflow_addrs(fd); + do_getsockopt_subflow_addrs(s, fd); + + if (r) + do_getsockopt_mptcp_full_info(s, fd); } static void connect_one_server(int fd, int pipefd) -- cgit v1.2.3 From 00079f18c24f373797cc38273c1bc0b475469d2b Mon Sep 17 00:00:00 2001 From: Matthieu Baerts Date: Tue, 20 Jun 2023 18:30:20 +0200 Subject: selftests: mptcp: join: skip check if MIB counter not supported (part 2) Selftests are supposed to run on any kernels, including the old ones not supporting all MPTCP features. One of them is the MPTCP MIB counters introduced in commit fc518953bc9c ("mptcp: add and use MIB counter infrastructure") and more later. The MPTCP Join selftest heavily relies on these counters. If a counter is not supported by the kernel, it is not displayed when using 'nstat -z'. We can then detect that and skip the verification. A new helper (get_counter()) has been added recently in the -net tree to do the required checks and return an error if the counter is not available. This commit is similar to the one with the same title applied in the -net tree but it modifies code only present in net-next for the moment, see the Fixes commit below. While at it, we can also remove the use of ${extra_msg} variable which is never assigned in chk_rm_tx_nr() function and use 'echo' without '-n' parameter. Link: https://github.com/multipath-tcp/mptcp_net-next/issues/368 Fixes: 0639fa230a21 ("selftests: mptcp: add explicit check for new mibs") Signed-off-by: Matthieu Baerts Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 33 +++++++++++++------------ 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 1b68fe1c0885..a7973d6a40a0 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -1683,12 +1683,12 @@ chk_add_tx_nr() timeout=$(ip netns exec $ns1 sysctl -n net.mptcp.add_addr_timeout) printf "%-${nr_blank}s %s" " " "add TX" - count=$(ip netns exec $ns1 nstat -as MPTcpExtAddAddrTx | grep MPTcpExtAddAddrTx | awk '{print $2}') - [ -z "$count" ] && count=0 - + count=$(get_counter ${ns1} "MPTcpExtAddAddrTx") + if [ -z "$count" ]; then + echo -n "[skip]" # if the test configured a short timeout tolerate greater then expected # add addrs options, due to retransmissions - if [ "$count" != "$add_tx_nr" ] && { [ "$timeout" -gt 1 ] || [ "$count" -lt "$add_tx_nr" ]; }; then + elif [ "$count" != "$add_tx_nr" ] && { [ "$timeout" -gt 1 ] || [ "$count" -lt "$add_tx_nr" ]; }; then echo "[fail] got $count ADD_ADDR[s] TX, expected $add_tx_nr" fail_test else @@ -1696,9 +1696,10 @@ chk_add_tx_nr() fi echo -n " - echo TX " - count=$(ip netns exec $ns2 nstat -as MPTcpExtEchoAddTx | grep MPTcpExtEchoAddTx | awk '{print $2}') - [ -z "$count" ] && count=0 - if [ "$count" != "$echo_tx_nr" ]; then + count=$(get_counter ${ns2} "MPTcpExtEchoAddTx") + if [ -z "$count" ]; then + echo "[skip]" + elif [ "$count" != "$echo_tx_nr" ]; then echo "[fail] got $count ADD_ADDR echo[s] TX, expected $echo_tx_nr" fail_test else @@ -1734,9 +1735,10 @@ chk_rm_nr() fi printf "%-${nr_blank}s %s" " " "rm " - count=$(ip netns exec $addr_ns nstat -as MPTcpExtRmAddr | grep MPTcpExtRmAddr | awk '{print $2}') - [ -z "$count" ] && count=0 - if [ "$count" != "$rm_addr_nr" ]; then + count=$(get_counter ${addr_ns} "MPTcpExtRmAddr") + if [ -z "$count" ]; then + echo -n "[skip]" + elif [ "$count" != "$rm_addr_nr" ]; then echo "[fail] got $count RM_ADDR[s] expected $rm_addr_nr" fail_test else @@ -1778,16 +1780,15 @@ chk_rm_tx_nr() local rm_addr_tx_nr=$1 printf "%-${nr_blank}s %s" " " "rm TX " - count=$(ip netns exec $ns2 nstat -as MPTcpExtRmAddrTx | grep MPTcpExtRmAddrTx | awk '{print $2}') - [ -z "$count" ] && count=0 - if [ "$count" != "$rm_addr_tx_nr" ]; then + count=$(get_counter ${ns2} "MPTcpExtRmAddrTx") + if [ -z "$count" ]; then + echo "[skip]" + elif [ "$count" != "$rm_addr_tx_nr" ]; then echo "[fail] got $count RM_ADDR[s] expected $rm_addr_tx_nr" fail_test else - echo -n "[ ok ]" + echo "[ ok ]" fi - - echo "$extra_msg" } chk_prio_nr() -- cgit v1.2.3 From ee77f3d602b0116203151fee372817c194970213 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Wed, 21 Jun 2023 23:19:21 -0700 Subject: selftests/bpf: Fix compilation failure for prog vrf_socket_lookup When building the latest kernel/selftest with clang17 compiler: make LLVM=1 -j <== for kernel make -C tools/testing/selftests/bpf LLVM=1 -j <== for selftest I hit the following compilation error: [...] In file included from progs/vrf_socket_lookup.c:3: In file included from /usr/include/linux/ip.h:21: In file included from /usr/include/asm/byteorder.h:5: In file included from /usr/include/linux/byteorder/little_endian.h:13: /usr/include/linux/swab.h:136:8: error: unknown type name '__always_inline' 136 | static __always_inline unsigned long __swab(const unsigned long y) | ^ /usr/include/linux/swab.h:171:8: error: unknown type name '__always_inline' 171 | static __always_inline __u16 __swab16p(const __u16 *p) | ^ /usr/include/linux/swab.h:171:29: error: expected ';' after top level declarator 171 | static __always_inline __u16 __swab16p(const __u16 *p) | ^ [...] Basically, with header files in my local host which is based on 5.12 kernel, __always_inline is not defined and this caused compilation failure. Since __always_inline is defined in bpf_helpers.h, let us move bpf_helpers.h to an early position which fixed the problem. Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230622061921.816772-1-yhs@fb.com --- tools/testing/selftests/bpf/progs/vrf_socket_lookup.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/progs/vrf_socket_lookup.c b/tools/testing/selftests/bpf/progs/vrf_socket_lookup.c index 26e07a252585..bcfb6feb38c0 100644 --- a/tools/testing/selftests/bpf/progs/vrf_socket_lookup.c +++ b/tools/testing/selftests/bpf/progs/vrf_socket_lookup.c @@ -1,11 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include +#include + #include #include #include #include -#include -#include #include int lookup_status; -- cgit v1.2.3 From f7a5d72edc522b9210521d9b3969eac221eb6ecb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 22 Jun 2023 14:39:46 +0100 Subject: kselftest/arm64: Add a test case for TPIDR2 restore Due to the fact that TPIDR2 is intended to be managed by libc we don't currently test modifying it via the signal context since that might disrupt libc's usage of it and cause instability. We can however test the opposite case with less risk, modifying TPIDR2 in a signal handler and making sure that the original value is restored after returning from the signal handler. Add a test which does this. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230621-arm64-fix-tpidr2-signal-restore-v2-2-c8e8fcc10302@kernel.org Signed-off-by: Catalin Marinas --- tools/testing/selftests/arm64/signal/.gitignore | 2 +- .../arm64/signal/testcases/tpidr2_restore.c | 86 ++++++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/arm64/signal/testcases/tpidr2_restore.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/arm64/signal/.gitignore b/tools/testing/selftests/arm64/signal/.gitignore index 8ab4c86837fd..839e3a252629 100644 --- a/tools/testing/selftests/arm64/signal/.gitignore +++ b/tools/testing/selftests/arm64/signal/.gitignore @@ -4,7 +4,7 @@ fake_sigreturn_* sme_* ssve_* sve_* -tpidr2_siginfo +tpidr2_* za_* zt_* !*.[ch] diff --git a/tools/testing/selftests/arm64/signal/testcases/tpidr2_restore.c b/tools/testing/selftests/arm64/signal/testcases/tpidr2_restore.c new file mode 100644 index 000000000000..f9a86c00c28c --- /dev/null +++ b/tools/testing/selftests/arm64/signal/testcases/tpidr2_restore.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 ARM Limited + * + * Verify that the TPIDR2 register context in signal frames is restored. + */ + +#include +#include +#include +#include +#include +#include + +#include "test_signals_utils.h" +#include "testcases.h" + +#define SYS_TPIDR2 "S3_3_C13_C0_5" + +static uint64_t get_tpidr2(void) +{ + uint64_t val; + + asm volatile ( + "mrs %0, " SYS_TPIDR2 "\n" + : "=r"(val) + : + : "cc"); + + return val; +} + +static void set_tpidr2(uint64_t val) +{ + asm volatile ( + "msr " SYS_TPIDR2 ", %0\n" + : + : "r"(val) + : "cc"); +} + + +static uint64_t initial_tpidr2; + +static bool save_tpidr2(struct tdescr *td) +{ + initial_tpidr2 = get_tpidr2(); + fprintf(stderr, "Initial TPIDR2: %lx\n", initial_tpidr2); + + return true; +} + +static int modify_tpidr2(struct tdescr *td, siginfo_t *si, ucontext_t *uc) +{ + uint64_t my_tpidr2 = get_tpidr2(); + + my_tpidr2++; + fprintf(stderr, "Setting TPIDR2 to %lx\n", my_tpidr2); + set_tpidr2(my_tpidr2); + + return 0; +} + +static void check_tpidr2(struct tdescr *td) +{ + uint64_t tpidr2 = get_tpidr2(); + + td->pass = tpidr2 == initial_tpidr2; + + if (td->pass) + fprintf(stderr, "TPIDR2 restored\n"); + else + fprintf(stderr, "TPIDR2 was %lx but is now %lx\n", + initial_tpidr2, tpidr2); +} + +struct tdescr tde = { + .name = "TPIDR2 restore", + .descr = "Validate that TPIDR2 is restored from the sigframe", + .feats_required = FEAT_SME, + .timeout = 3, + .sig_trig = SIGUSR1, + .init = save_tpidr2, + .run = modify_tpidr2, + .check_result = check_tpidr2, +}; -- cgit v1.2.3 From 3360cd30a4c569eb601e737e2c10b7bd153210ca Mon Sep 17 00:00:00 2001 From: Haifeng Xu Date: Mon, 19 Jun 2023 12:47:35 +0000 Subject: selftests: cgroup: fix unexpected failure on test_memcg_sock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before server got a client connection, there were some memory allocations in the test memcg, such as user stack. So do not count those allocations which are not related to socket when checking socket memory accounting. Link: https://lkml.kernel.org/r/20230619124735.2124-1-haifeng.xu@shopee.com Signed-off-by: Haifeng Xu Cc: Johannes Weiner Cc: Michal Hocko Cc: Michal Koutný Cc: Roman Gushchin Cc: Shakeel Butt Signed-off-by: Andrew Morton --- tools/testing/selftests/cgroup/test_memcontrol.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/cgroup/test_memcontrol.c b/tools/testing/selftests/cgroup/test_memcontrol.c index a2a90f4bfe9f..c7c9572003a8 100644 --- a/tools/testing/selftests/cgroup/test_memcontrol.c +++ b/tools/testing/selftests/cgroup/test_memcontrol.c @@ -989,7 +989,9 @@ static int tcp_client(const char *cgroup, unsigned short port) char servport[6]; int retries = 0x10; /* nice round number */ int sk, ret; + long allocated; + allocated = cg_read_long(cgroup, "memory.current"); snprintf(servport, sizeof(servport), "%hd", port); ret = getaddrinfo(server, servport, NULL, &ai); if (ret) @@ -1017,7 +1019,8 @@ static int tcp_client(const char *cgroup, unsigned short port) if (current < 0 || sock < 0) goto close_sk; - if (values_close(current, sock, 10)) { + /* exclude the memory not related to socket connection */ + if (values_close(current - allocated, sock, 10)) { ret = KSFT_PASS; break; } -- cgit v1.2.3 From 5f789f103671fec3733ebe756e56adf15c90c21d Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Thu, 22 Jun 2023 23:03:34 +0200 Subject: selftests: rtnetlink: remove netdevsim device after ipsec offload test On systems where netdevsim is built-in or loaded before the test starts, kci_test_ipsec_offload doesn't remove the netdevsim device it created during the test. Fixes: e05b2d141fef ("netdevsim: move netdev creation/destruction to dev probe") Signed-off-by: Sabrina Dubroca Reviewed-by: Simon Horman Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/e1cb94f4f82f4eca4a444feec4488a1323396357.1687466906.git.sd@queasysnail.net Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/rtnetlink.sh | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/rtnetlink.sh b/tools/testing/selftests/net/rtnetlink.sh index 383ac6fc037d..ba286d680fd9 100755 --- a/tools/testing/selftests/net/rtnetlink.sh +++ b/tools/testing/selftests/net/rtnetlink.sh @@ -860,6 +860,7 @@ EOF fi # clean up any leftovers + echo 0 > /sys/bus/netdevsim/del_device $probed && rmmod netdevsim if [ $ret -ne 0 ]; then -- cgit v1.2.3 From 4369c198e5990ee077b97c979d678b5abd8a91ba Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 23 Jun 2023 10:34:07 -0700 Subject: selftests: mptcp: test userspace pm out of transfer This patch moves userspace pm tests out of do_transfer(). Move add address test into a new function userspace_pm_add_addr(), and remove address test into userspace_pm_rm_sf_addr_ns1(). Move add subflow test into userspace_pm_add_sf() and remove subflow into userspace_pm_rm_sf_addr_ns2(). Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20230623-send-net-next-20230623-v1-1-a883213c8ba9@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 145 ++++++++++++++++-------- 1 file changed, 99 insertions(+), 46 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index a7973d6a40a0..3baa6ac3b03e 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -589,6 +589,26 @@ wait_rm_addr() done } +rm_sf_count() +{ + get_counter "${1}" "MPTcpExtRmSubflow" +} + +# $1: ns, $2: old rm_sf counter in $ns +wait_rm_sf() +{ + local ns="${1}" + local old_cnt="${2}" + local cnt + + local i + for i in $(seq 10); do + cnt=$(rm_sf_count ${ns}) + [ "$cnt" = "${old_cnt}" ] || break + sleep 0.1 + done +} + wait_mpj() { local ns="${1}" @@ -813,7 +833,6 @@ do_transfer() local port=$((10000 + TEST_COUNT - 1)) local cappid - local userspace_pm=0 :> "$cout" :> "$sout" @@ -850,11 +869,6 @@ do_transfer() extra_args="-r ${speed:6}" fi - if [[ "${addr_nr_ns1}" = "userspace_"* ]]; then - userspace_pm=1 - addr_nr_ns1=${addr_nr_ns1:10} - fi - local flags="subflow" local extra_cl_args="" local extra_srv_args="" @@ -882,9 +896,6 @@ do_transfer() return 1 fi addr_nr_ns2=0 - elif [[ "${addr_nr_ns2}" = "userspace_"* ]]; then - userspace_pm=1 - addr_nr_ns2=${addr_nr_ns2:10} elif [[ "${addr_nr_ns2}" = "fullmesh_"* ]]; then flags="${flags},fullmesh" addr_nr_ns2=${addr_nr_ns2:9} @@ -938,7 +949,6 @@ do_transfer() local counter=2 local add_nr_ns1=${addr_nr_ns1} local id=10 - local tk while [ $add_nr_ns1 -gt 0 ]; do local addr if is_v6 "${connect_addr}"; then @@ -946,24 +956,7 @@ do_transfer() else addr="10.0.$counter.1" fi - if [ $userspace_pm -eq 0 ]; then - pm_nl_add_endpoint $ns1 $addr flags signal - else - tk=$(grep "type:1," "$evts_ns1" | - sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q') - ip netns exec ${listener_ns} ./pm_nl_ctl ann $addr token $tk id $id - sleep 1 - sp=$(grep "type:10" "$evts_ns1" | - sed -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q') - da=$(grep "type:10" "$evts_ns1" | - sed -n 's/.*\(daddr6:\)\([0-9a-f:.]*\).*$/\2/p;q') - dp=$(grep "type:10" "$evts_ns1" | - sed -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q') - ip netns exec ${listener_ns} ./pm_nl_ctl rem token $tk id $id - ip netns exec ${listener_ns} ./pm_nl_ctl dsf lip "::ffff:$addr" \ - lport $sp rip $da rport $dp token $tk - fi - + pm_nl_add_endpoint $ns1 $addr flags signal counter=$((counter + 1)) add_nr_ns1=$((add_nr_ns1 - 1)) id=$((id + 1)) @@ -1008,7 +1001,6 @@ do_transfer() local add_nr_ns2=${addr_nr_ns2} local counter=3 local id=20 - local tk da dp sp while [ $add_nr_ns2 -gt 0 ]; do local addr if is_v6 "${connect_addr}"; then @@ -1016,21 +1008,7 @@ do_transfer() else addr="10.0.$counter.2" fi - if [ $userspace_pm -eq 0 ]; then - pm_nl_add_endpoint $ns2 $addr flags $flags - else - tk=$(sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q' "$evts_ns2") - da=$(sed -n 's/.*\(daddr4:\)\([0-9.]*\).*$/\2/p;q' "$evts_ns2") - dp=$(sed -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q' "$evts_ns2") - ip netns exec ${connector_ns} ./pm_nl_ctl csf lip $addr lid $id \ - rip $da rport $dp token $tk - sleep 1 - sp=$(grep "type:10" "$evts_ns2" | - sed -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q') - ip netns exec ${connector_ns} ./pm_nl_ctl rem token $tk id $id - ip netns exec ${connector_ns} ./pm_nl_ctl dsf lip $addr lport $sp \ - rip $da rport $dp token $tk - fi + pm_nl_add_endpoint $ns2 $addr flags $flags counter=$((counter + 1)) add_nr_ns2=$((add_nr_ns2 - 1)) id=$((id + 1)) @@ -3205,6 +3183,71 @@ fail_tests() fi } +userspace_pm_add_addr() +{ + local addr=$1 + local id=$2 + local tk + + tk=$(grep "type:1," "$evts_ns1" | + sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q') + ip netns exec $ns1 ./pm_nl_ctl ann $addr token $tk id $id + sleep 1 +} + +userspace_pm_rm_sf_addr_ns1() +{ + local addr=$1 + local id=$2 + local tk sp da dp + + tk=$(grep "type:1," "$evts_ns1" | + sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q') + sp=$(grep "type:10" "$evts_ns1" | + sed -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q') + da=$(grep "type:10" "$evts_ns1" | + sed -n 's/.*\(daddr6:\)\([0-9a-f:.]*\).*$/\2/p;q') + dp=$(grep "type:10" "$evts_ns1" | + sed -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q') + ip netns exec $ns1 ./pm_nl_ctl rem token $tk id $id + ip netns exec $ns1 ./pm_nl_ctl dsf lip "::ffff:$addr" \ + lport $sp rip $da rport $dp token $tk + wait_rm_addr $ns1 1 + wait_rm_sf $ns1 1 +} + +userspace_pm_add_sf() +{ + local addr=$1 + local id=$2 + local tk da dp + + tk=$(sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q' "$evts_ns2") + da=$(sed -n 's/.*\(daddr4:\)\([0-9.]*\).*$/\2/p;q' "$evts_ns2") + dp=$(sed -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q' "$evts_ns2") + ip netns exec $ns2 ./pm_nl_ctl csf lip $addr lid $id \ + rip $da rport $dp token $tk + sleep 1 +} + +userspace_pm_rm_sf_addr_ns2() +{ + local addr=$1 + local id=$2 + local tk da dp sp + + tk=$(sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q' "$evts_ns2") + da=$(sed -n 's/.*\(daddr4:\)\([0-9.]*\).*$/\2/p;q' "$evts_ns2") + dp=$(sed -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q' "$evts_ns2") + sp=$(grep "type:10" "$evts_ns2" | + sed -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q') + ip netns exec $ns2 ./pm_nl_ctl rem token $tk id $id + ip netns exec $ns2 ./pm_nl_ctl dsf lip $addr lport $sp \ + rip $da rport $dp token $tk + wait_rm_addr $ns2 1 + wait_rm_sf $ns2 1 +} + userspace_tests() { # userspace pm type prevents add_addr @@ -3283,11 +3326,16 @@ userspace_tests() continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then set_userspace_pm $ns1 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 userspace_1 0 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 0 speed_10 & + local tests_pid=$! + wait_mpj $ns1 + userspace_pm_add_addr 10.0.2.1 10 chk_join_nr 1 1 1 chk_add_nr 1 1 + userspace_pm_rm_sf_addr_ns1 10.0.2.1 10 chk_rm_nr 1 1 invert kill_events_pids + wait $tests_pid fi # userspace pm create destroy subflow @@ -3295,10 +3343,15 @@ userspace_tests() continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then set_userspace_pm $ns2 pm_nl_set_limits $ns1 0 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 userspace_1 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 0 speed_10 & + local tests_pid=$! + wait_mpj $ns2 + userspace_pm_add_sf 10.0.3.2 20 chk_join_nr 1 1 1 + userspace_pm_rm_sf_addr_ns2 10.0.3.2 20 chk_rm_nr 1 1 kill_events_pids + wait $tests_pid fi } -- cgit v1.2.3 From d7ced753aa851f54735d20ca49ddf4710e43f1d1 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 23 Jun 2023 10:34:08 -0700 Subject: selftests: mptcp: check subflow and addr infos New MPTCP info are being checked in multiple places to improve the code coverage when using the userspace PM. This patch makes chk_mptcp_info() more generic to be able to check subflows, add_addr_signal and add_addr_accepted info (and even more later). New arguments are now required to get different infos from the two namespaces because some counters are specific to the client or the server. Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20230623-send-net-next-20230623-v1-2-a883213c8ba9@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 44 +++++++++++++------------ 1 file changed, 23 insertions(+), 21 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 3baa6ac3b03e..95a56384294f 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -1832,31 +1832,26 @@ chk_subflow_nr() chk_mptcp_info() { - local nr_info=$1 - local info + local info1=$1 + local exp1=$2 + local info2=$3 + local exp2=$4 local cnt1 local cnt2 local dump_stats - if [[ $nr_info = "subflows_"* ]]; then - info="subflows" - nr_info=${nr_info:9} - else - echo "[fail] unsupported argument: $nr_info" - fail_test - return 1 - fi - - printf "%-${nr_blank}s %-30s" " " "mptcp_info $info=$nr_info" + printf "%-${nr_blank}s %-30s" " " "mptcp_info $info1:$info2=$exp1:$exp2" - cnt1=$(ss -N $ns1 -inmHM | grep "$info:" | - sed -n 's/.*\('"$info"':\)\([[:digit:]]*\).*$/\2/p;q') + cnt1=$(ss -N $ns1 -inmHM | grep "$info1:" | + sed -n 's/.*\('"$info1"':\)\([[:digit:]]*\).*$/\2/p;q') + cnt2=$(ss -N $ns2 -inmHM | grep "$info2:" | + sed -n 's/.*\('"$info2"':\)\([[:digit:]]*\).*$/\2/p;q') + # 'ss' only display active connections and counters that are not 0. [ -z "$cnt1" ] && cnt1=0 - cnt2=$(ss -N $ns2 -inmHM | grep "$info:" | - sed -n 's/.*\('"$info"':\)\([[:digit:]]*\).*$/\2/p;q') [ -z "$cnt2" ] && cnt2=0 - if [ "$cnt1" != "$nr_info" ] || [ "$cnt2" != "$nr_info" ]; then - echo "[fail] got $cnt1:$cnt2 $info expected $nr_info" + + if [ "$cnt1" != "$exp1" ] || [ "$cnt2" != "$exp2" ]; then + echo "[fail] got $cnt1:$cnt2 $info1:$info2 expected $exp1:$exp2" fail_test dump_stats=1 else @@ -3332,8 +3327,11 @@ userspace_tests() userspace_pm_add_addr 10.0.2.1 10 chk_join_nr 1 1 1 chk_add_nr 1 1 + chk_mptcp_info subflows 1 subflows 1 + chk_mptcp_info add_addr_signal 1 add_addr_accepted 1 userspace_pm_rm_sf_addr_ns1 10.0.2.1 10 chk_rm_nr 1 1 invert + chk_mptcp_info subflows 0 subflows 0 kill_events_pids wait $tests_pid fi @@ -3348,8 +3346,10 @@ userspace_tests() wait_mpj $ns2 userspace_pm_add_sf 10.0.3.2 20 chk_join_nr 1 1 1 + chk_mptcp_info subflows 1 subflows 1 userspace_pm_rm_sf_addr_ns2 10.0.3.2 20 chk_rm_nr 1 1 + chk_mptcp_info subflows 0 subflows 0 kill_events_pids wait $tests_pid fi @@ -3369,6 +3369,8 @@ endpoint_tests() wait_mpj $ns1 pm_nl_check_endpoint 1 "creation" \ $ns2 10.0.2.2 id 1 flags implicit + chk_mptcp_info subflows 1 subflows 1 + chk_mptcp_info add_addr_signal 1 add_addr_accepted 1 pm_nl_add_endpoint $ns2 10.0.2.2 id 33 pm_nl_check_endpoint 0 "ID change is prevented" \ @@ -3389,17 +3391,17 @@ endpoint_tests() wait_mpj $ns2 chk_subflow_nr needtitle "before delete" 2 - chk_mptcp_info subflows_1 + chk_mptcp_info subflows 1 subflows 1 pm_nl_del_endpoint $ns2 2 10.0.2.2 sleep 0.5 chk_subflow_nr "" "after delete" 1 - chk_mptcp_info subflows_0 + chk_mptcp_info subflows 0 subflows 0 pm_nl_add_endpoint $ns2 10.0.2.2 dev ns2eth2 flags subflow wait_mpj $ns2 chk_subflow_nr "" "after re-add" 2 - chk_mptcp_info subflows_1 + chk_mptcp_info subflows 1 subflows 1 kill_tests_wait fi } -- cgit v1.2.3 From be7e9786c9155c2942cd53b813e4723be67e07c4 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 23 Jun 2023 10:34:09 -0700 Subject: selftests: mptcp: set FAILING_LINKS in run_tests Set FAILING_LINKS as an env var with a limited scope only when calling run_tests(). Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20230623-send-net-next-20230623-v1-3-a883213c8ba9@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 95a56384294f..000c561bf622 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -2177,9 +2177,9 @@ link_failure_tests() pm_nl_set_limits $ns1 0 2 pm_nl_add_endpoint $ns1 10.0.2.1 dev ns1eth2 flags signal pm_nl_set_limits $ns2 1 2 - FAILING_LINKS="1" pm_nl_add_endpoint $ns2 10.0.3.2 dev ns2eth3 flags subflow,backup - run_tests $ns1 $ns2 10.0.1.1 1 + FAILING_LINKS="1" \ + run_tests $ns1 $ns2 10.0.1.1 1 chk_join_nr 2 2 2 chk_add_nr 1 1 chk_link_usage $ns2 ns2eth3 $cinsent 0 @@ -2193,8 +2193,8 @@ link_failure_tests() pm_nl_add_endpoint $ns1 10.0.2.1 dev ns1eth2 flags signal pm_nl_set_limits $ns2 1 2 pm_nl_add_endpoint $ns2 10.0.3.2 dev ns2eth3 flags subflow,backup - FAILING_LINKS="1 2" - run_tests $ns1 $ns2 10.0.1.1 1 + FAILING_LINKS="1 2" \ + run_tests $ns1 $ns2 10.0.1.1 1 chk_join_nr 2 2 2 chk_add_nr 1 1 chk_stale_nr $ns2 2 4 2 @@ -2209,8 +2209,8 @@ link_failure_tests() pm_nl_add_endpoint $ns1 10.0.2.1 dev ns1eth2 flags signal pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 dev ns2eth3 flags subflow,backup - FAILING_LINKS="1 2" - run_tests $ns1 $ns2 10.0.1.1 2 + FAILING_LINKS="1 2" \ + run_tests $ns1 $ns2 10.0.1.1 2 chk_join_nr 2 2 2 chk_add_nr 1 1 chk_stale_nr $ns2 1 -1 2 -- cgit v1.2.3 From 0c93af1f8907902692014fd7072d54e275034800 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 23 Jun 2023 10:34:10 -0700 Subject: selftests: mptcp: drop test_linkfail parameter run_tests() accepts too many optional parameters. Before this modification, it was required to set all of then when only the last one had to be changed. That's not clear to see all these 0 and it makes the maintenance harder: run_tests $ns1 $ns2 10.0.1.1 1 2 3 slow Instead, the parameter can be set as an env var with a limited scope: foo=1 bar=2 next=3 \ run_tests $ns1 $ns2 10.0.1.1 slow This patch switches to key/value "test_linkfail=*" instead of positional parameter test_linkfail of do_transfer() and run_tests(). Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20230623-send-net-next-20230623-v1-4-a883213c8ba9@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 192 ++++++++++++------------ 1 file changed, 99 insertions(+), 93 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 000c561bf622..bc6a26d357bb 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -50,6 +50,7 @@ TEST_NAME="" nr_blank=40 export FAILING_LINKS="" +export test_linkfail=0 # generated using "nfbpf_compile '(ip && (ip[54] & 0xf0) == 0x30) || # (ip6 && (ip6[74] & 0xf0) == 0x30)'" @@ -825,11 +826,10 @@ do_transfer() local cl_proto="$3" local srv_proto="$4" local connect_addr="$5" - local test_link_fail="$6" - local addr_nr_ns1="$7" - local addr_nr_ns2="$8" - local speed="$9" - local sflags="${10}" + local addr_nr_ns1="$6" + local addr_nr_ns2="$7" + local speed="$8" + local sflags="${9}" local port=$((10000 + TEST_COUNT - 1)) local cappid @@ -874,21 +874,21 @@ do_transfer() local extra_srv_args="" local trunc_size="" if [[ "${addr_nr_ns2}" = "fastclose_"* ]]; then - if [ ${test_link_fail} -le 1 ]; then - echo "fastclose tests need test_link_fail argument" + if [ ${test_linkfail} -le 1 ]; then + echo "fastclose tests need test_linkfail argument" fail_test return 1 fi # disconnect - trunc_size=${test_link_fail} + trunc_size=${test_linkfail} local side=${addr_nr_ns2:10} if [ ${side} = "client" ]; then - extra_cl_args="-f ${test_link_fail}" + extra_cl_args="-f ${test_linkfail}" extra_srv_args="-f -1" elif [ ${side} = "server" ]; then - extra_srv_args="-f ${test_link_fail}" + extra_srv_args="-f ${test_linkfail}" extra_cl_args="-f -1" else echo "wrong/unknown fastclose spec ${side}" @@ -902,7 +902,7 @@ do_transfer() fi extra_srv_args="$extra_args $extra_srv_args" - if [ "$test_link_fail" -gt 1 ];then + if [ "$test_linkfail" -gt 1 ];then timeout ${timeout_test} \ ip netns exec ${listener_ns} \ ./mptcp_connect -t ${timeout_poll} -l -p $port -s ${srv_proto} \ @@ -918,12 +918,12 @@ do_transfer() wait_local_port_listen "${listener_ns}" "${port}" extra_cl_args="$extra_args $extra_cl_args" - if [ "$test_link_fail" -eq 0 ];then + if [ "$test_linkfail" -eq 0 ];then timeout ${timeout_test} \ ip netns exec ${connector_ns} \ ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ $extra_cl_args $connect_addr < "$cin" > "$cout" & - elif [ "$test_link_fail" -eq 1 ] || [ "$test_link_fail" -eq 2 ];then + elif [ "$test_linkfail" -eq 1 ] || [ "$test_linkfail" -eq 2 ];then ( cat "$cinfail" ; sleep 2; link_failure $listener_ns ; cat "$cinfail" ) | \ tee "$cinsent" | \ timeout ${timeout_test} \ @@ -1107,13 +1107,13 @@ do_transfer() return 1 fi - if [ "$test_link_fail" -gt 1 ];then + if [ "$test_linkfail" -gt 1 ];then check_transfer $sinfail $cout "file received by client" $trunc_size else check_transfer $sin $cout "file received by client" $trunc_size fi retc=$? - if [ "$test_link_fail" -eq 0 ];then + if [ "$test_linkfail" -eq 0 ];then check_transfer $cin $sout "file received by server" $trunc_size else check_transfer $cinsent $sout "file received by server" $trunc_size @@ -1146,11 +1146,10 @@ run_tests() local listener_ns="$1" local connector_ns="$2" local connect_addr="$3" - local test_linkfail="${4:-0}" - local addr_nr_ns1="${5:-0}" - local addr_nr_ns2="${6:-0}" - local speed="${7:-fast}" - local sflags="${8:-""}" + local addr_nr_ns1="${4:-0}" + local addr_nr_ns2="${5:-0}" + local speed="${6:-fast}" + local sflags="${7:-""}" local size @@ -1195,7 +1194,7 @@ run_tests() fi do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr} \ - ${test_linkfail} ${addr_nr_ns1} ${addr_nr_ns2} ${speed} ${sflags} + ${addr_nr_ns1} ${addr_nr_ns2} ${speed} ${sflags} } dump_stats() @@ -1984,7 +1983,7 @@ subflows_error_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 slow chk_join_nr 0 0 0 fi @@ -1995,7 +1994,7 @@ subflows_error_tests() pm_nl_set_limits $ns2 0 2 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 slow chk_join_nr 1 1 1 fi @@ -2006,7 +2005,7 @@ subflows_error_tests() pm_nl_set_limits $ns2 0 2 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 slow chk_join_nr 1 1 1 fi @@ -2018,7 +2017,7 @@ subflows_error_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow & + run_tests $ns1 $ns2 10.0.1.1 0 0 slow & # mpj subflow will be in TW after the reset wait_attempt_fail $ns2 @@ -2117,7 +2116,7 @@ signal_address_tests() # the peer could possibly miss some addr notification, allow retransmission ip netns exec $ns1 sysctl -q net.mptcp.add_addr_timeout=1 - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 slow # It is not directly linked to the commit introducing this # symbol but for the parent one which is linked anyway. @@ -2149,7 +2148,8 @@ link_failure_tests() pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 dev ns2eth3 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 dev ns2eth4 flags subflow - run_tests $ns1 $ns2 10.0.1.1 1 + test_linkfail=1 \ + run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 3 3 3 chk_add_nr 1 1 chk_stale_nr $ns2 1 5 1 @@ -2164,7 +2164,8 @@ link_failure_tests() pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 dev ns2eth3 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 dev ns2eth4 flags subflow - run_tests $ns1 $ns2 10.0.1.1 2 + test_linkfail=2 \ + run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 3 3 3 chk_add_nr 1 1 chk_stale_nr $ns2 1 -1 1 @@ -2178,8 +2179,8 @@ link_failure_tests() pm_nl_add_endpoint $ns1 10.0.2.1 dev ns1eth2 flags signal pm_nl_set_limits $ns2 1 2 pm_nl_add_endpoint $ns2 10.0.3.2 dev ns2eth3 flags subflow,backup - FAILING_LINKS="1" \ - run_tests $ns1 $ns2 10.0.1.1 1 + FAILING_LINKS="1" test_linkfail=1 \ + run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 2 2 2 chk_add_nr 1 1 chk_link_usage $ns2 ns2eth3 $cinsent 0 @@ -2193,8 +2194,8 @@ link_failure_tests() pm_nl_add_endpoint $ns1 10.0.2.1 dev ns1eth2 flags signal pm_nl_set_limits $ns2 1 2 pm_nl_add_endpoint $ns2 10.0.3.2 dev ns2eth3 flags subflow,backup - FAILING_LINKS="1 2" \ - run_tests $ns1 $ns2 10.0.1.1 1 + FAILING_LINKS="1 2" test_linkfail=1 \ + run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 2 2 2 chk_add_nr 1 1 chk_stale_nr $ns2 2 4 2 @@ -2209,8 +2210,8 @@ link_failure_tests() pm_nl_add_endpoint $ns1 10.0.2.1 dev ns1eth2 flags signal pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 dev ns2eth3 flags subflow,backup - FAILING_LINKS="1 2" \ - run_tests $ns1 $ns2 10.0.1.1 2 + FAILING_LINKS="1 2" test_linkfail=2 \ + run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 2 2 2 chk_add_nr 1 1 chk_stale_nr $ns2 1 -1 2 @@ -2225,7 +2226,7 @@ add_addr_timeout_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 slow chk_join_nr 1 1 1 chk_add_tx_nr 4 4 chk_add_nr 4 0 @@ -2236,7 +2237,7 @@ add_addr_timeout_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal - run_tests $ns1 $ns2 dead:beef:1::1 0 0 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 0 0 slow chk_join_nr 1 1 1 chk_add_nr 4 0 fi @@ -2247,7 +2248,7 @@ add_addr_timeout_tests() pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_set_limits $ns2 2 2 - run_tests $ns1 $ns2 10.0.1.1 0 0 0 speed_10 + run_tests $ns1 $ns2 10.0.1.1 0 0 speed_10 chk_join_nr 2 2 2 chk_add_nr 8 0 fi @@ -2258,7 +2259,7 @@ add_addr_timeout_tests() pm_nl_add_endpoint $ns1 10.0.12.1 flags signal pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_set_limits $ns2 2 2 - run_tests $ns1 $ns2 10.0.1.1 0 0 0 speed_10 + run_tests $ns1 $ns2 10.0.1.1 0 0 speed_10 chk_join_nr 1 1 1 chk_add_nr 8 0 fi @@ -2271,7 +2272,7 @@ remove_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 -1 slow + run_tests $ns1 $ns2 10.0.1.1 0 -1 slow chk_join_nr 1 1 1 chk_rm_tx_nr 1 chk_rm_nr 1 1 @@ -2283,7 +2284,7 @@ remove_tests() pm_nl_set_limits $ns2 0 2 pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 -2 slow + run_tests $ns1 $ns2 10.0.1.1 0 -2 slow chk_join_nr 2 2 2 chk_rm_nr 2 2 fi @@ -2293,7 +2294,7 @@ remove_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 -1 0 slow + run_tests $ns1 $ns2 10.0.1.1 -1 0 slow chk_join_nr 1 1 1 chk_add_nr 1 1 chk_rm_nr 1 1 invert @@ -2305,7 +2306,7 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_set_limits $ns2 1 2 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -1 -1 slow + run_tests $ns1 $ns2 10.0.1.1 -1 -1 slow chk_join_nr 2 2 2 chk_add_nr 1 1 chk_rm_nr 1 1 @@ -2318,7 +2319,7 @@ remove_tests() pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -1 -2 speed_10 + run_tests $ns1 $ns2 10.0.1.1 -1 -2 speed_10 chk_join_nr 3 3 3 chk_add_nr 1 1 chk_rm_nr 2 2 @@ -2331,7 +2332,7 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.4.1 flags signal pm_nl_set_limits $ns2 3 3 - run_tests $ns1 $ns2 10.0.1.1 0 -3 0 speed_10 + run_tests $ns1 $ns2 10.0.1.1 -3 0 speed_10 chk_join_nr 3 3 3 chk_add_nr 3 3 chk_rm_nr 3 3 invert @@ -2344,7 +2345,7 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.14.1 flags signal pm_nl_set_limits $ns2 3 3 - run_tests $ns1 $ns2 10.0.1.1 0 -3 0 speed_10 + run_tests $ns1 $ns2 10.0.1.1 -3 0 speed_10 chk_join_nr 1 1 1 chk_add_nr 3 3 chk_rm_nr 3 1 invert @@ -2357,7 +2358,7 @@ remove_tests() pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -8 -8 slow + run_tests $ns1 $ns2 10.0.1.1 -8 -8 slow chk_join_nr 3 3 3 chk_add_nr 1 1 chk_rm_nr 1 3 invert simult @@ -2370,7 +2371,7 @@ remove_tests() pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow id 150 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -8 -8 slow + run_tests $ns1 $ns2 10.0.1.1 -8 -8 slow chk_join_nr 3 3 3 if mptcp_lib_kversion_ge 5.18; then @@ -2388,7 +2389,7 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.4.1 flags signal pm_nl_set_limits $ns2 3 3 - run_tests $ns1 $ns2 10.0.1.1 0 -8 -8 slow + run_tests $ns1 $ns2 10.0.1.1 -8 -8 slow chk_join_nr 3 3 3 chk_add_nr 3 3 chk_rm_nr 3 3 invert simult @@ -2401,7 +2402,7 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.14.1 flags signal pm_nl_set_limits $ns2 3 3 - run_tests $ns1 $ns2 10.0.1.1 0 -8 0 slow + run_tests $ns1 $ns2 10.0.1.1 -8 0 slow chk_join_nr 1 1 1 chk_add_nr 3 3 chk_rm_nr 3 1 invert @@ -2412,7 +2413,7 @@ remove_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 -9 slow + run_tests $ns1 $ns2 10.0.1.1 0 -9 slow chk_join_nr 1 1 1 chk_rm_nr 1 1 fi @@ -2422,7 +2423,7 @@ remove_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 -9 0 slow + run_tests $ns1 $ns2 10.0.1.1 -9 0 slow chk_join_nr 1 1 1 chk_add_nr 1 1 chk_rm_nr 1 1 invert @@ -2435,7 +2436,7 @@ add_tests() if reset "add single subflow"; then pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 1 slow + run_tests $ns1 $ns2 10.0.1.1 0 1 slow chk_join_nr 1 1 1 fi @@ -2443,7 +2444,7 @@ add_tests() if reset "add signal address"; then pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 1 0 slow + run_tests $ns1 $ns2 10.0.1.1 1 0 slow chk_join_nr 1 1 1 chk_add_nr 1 1 fi @@ -2452,7 +2453,7 @@ add_tests() if reset "add multiple subflows"; then pm_nl_set_limits $ns1 0 2 pm_nl_set_limits $ns2 0 2 - run_tests $ns1 $ns2 10.0.1.1 0 0 2 slow + run_tests $ns1 $ns2 10.0.1.1 0 2 slow chk_join_nr 2 2 2 fi @@ -2460,7 +2461,7 @@ add_tests() if reset "add multiple subflows IPv6"; then pm_nl_set_limits $ns1 0 2 pm_nl_set_limits $ns2 0 2 - run_tests $ns1 $ns2 dead:beef:1::1 0 0 2 slow + run_tests $ns1 $ns2 dead:beef:1::1 0 2 slow chk_join_nr 2 2 2 fi @@ -2468,7 +2469,7 @@ add_tests() if reset "add multiple addresses IPv6"; then pm_nl_set_limits $ns1 0 2 pm_nl_set_limits $ns2 2 2 - run_tests $ns1 $ns2 dead:beef:1::1 0 2 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 2 0 slow chk_join_nr 2 2 2 chk_add_nr 2 2 fi @@ -2481,14 +2482,14 @@ ipv6_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 dead:beef:3::2 dev ns2eth3 flags subflow - run_tests $ns1 $ns2 dead:beef:1::1 0 0 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 0 0 slow chk_join_nr 1 1 1 fi # add_address, unused IPv6 if reset "unused signal address IPv6"; then pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal - run_tests $ns1 $ns2 dead:beef:1::1 0 0 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 0 0 slow chk_join_nr 0 0 0 chk_add_nr 1 1 fi @@ -2498,7 +2499,7 @@ ipv6_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 dead:beef:1::1 0 0 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 0 0 slow chk_join_nr 1 1 1 chk_add_nr 1 1 fi @@ -2508,7 +2509,7 @@ ipv6_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 dead:beef:1::1 0 -1 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 -1 0 slow chk_join_nr 1 1 1 chk_add_nr 1 1 chk_rm_nr 1 1 invert @@ -2520,7 +2521,7 @@ ipv6_tests() pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal pm_nl_set_limits $ns2 1 2 pm_nl_add_endpoint $ns2 dead:beef:3::2 dev ns2eth3 flags subflow - run_tests $ns1 $ns2 dead:beef:1::1 0 -1 -1 slow + run_tests $ns1 $ns2 dead:beef:1::1 -1 -1 slow chk_join_nr 2 2 2 chk_add_nr 1 1 chk_rm_nr 1 1 @@ -2621,7 +2622,7 @@ mixed_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 slow chk_join_nr 0 0 0 fi @@ -2631,7 +2632,7 @@ mixed_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns1 10.0.1.1 flags signal - run_tests $ns1 $ns2 dead:beef:2::1 0 0 0 slow + run_tests $ns1 $ns2 dead:beef:2::1 0 0 slow chk_join_nr 1 1 1 fi @@ -2642,7 +2643,7 @@ mixed_tests() pm_nl_set_limits $ns2 1 4 pm_nl_add_endpoint $ns2 dead:beef:2::2 flags subflow,fullmesh pm_nl_add_endpoint $ns1 10.0.1.1 flags signal - run_tests $ns1 $ns2 dead:beef:2::1 0 0 0 slow + run_tests $ns1 $ns2 dead:beef:2::1 0 0 slow chk_join_nr 1 1 1 fi @@ -2654,7 +2655,7 @@ mixed_tests() pm_nl_set_limits $ns2 2 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal - run_tests $ns1 $ns2 dead:beef:1::1 0 0 fullmesh_1 slow + run_tests $ns1 $ns2 dead:beef:1::1 0 fullmesh_1 slow chk_join_nr 4 4 4 fi } @@ -2667,7 +2668,7 @@ backup_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow nobackup + run_tests $ns1 $ns2 10.0.1.1 0 0 slow nobackup chk_join_nr 1 1 1 chk_prio_nr 0 1 fi @@ -2678,7 +2679,7 @@ backup_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup chk_join_nr 1 1 1 chk_add_nr 1 1 chk_prio_nr 1 1 @@ -2690,7 +2691,7 @@ backup_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal port 10100 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup chk_join_nr 1 1 1 chk_add_nr 1 1 chk_prio_nr 1 1 @@ -2699,7 +2700,7 @@ backup_tests() if reset "mpc backup" && continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow,backup - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 slow chk_join_nr 0 0 0 chk_prio_nr 0 1 fi @@ -2708,7 +2709,7 @@ backup_tests() continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns1 10.0.1.1 flags subflow,backup pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow,backup - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 slow chk_join_nr 0 0 0 chk_prio_nr 1 1 fi @@ -2716,7 +2717,7 @@ backup_tests() if reset "mpc switch to backup" && continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup chk_join_nr 0 0 0 chk_prio_nr 0 1 fi @@ -2725,7 +2726,7 @@ backup_tests() continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns1 10.0.1.1 flags subflow pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup chk_join_nr 0 0 0 chk_prio_nr 1 1 fi @@ -2814,7 +2815,7 @@ add_addr_ports_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal port 10100 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 -1 0 slow + run_tests $ns1 $ns2 10.0.1.1 -1 0 slow chk_join_nr 1 1 1 chk_add_nr 1 1 1 chk_rm_nr 1 1 invert @@ -2830,7 +2831,7 @@ add_addr_ports_tests() pm_nl_add_endpoint $ns1 10.0.2.1 flags signal port 10100 pm_nl_set_limits $ns2 1 2 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -1 -1 slow + run_tests $ns1 $ns2 10.0.1.1 -1 -1 slow chk_join_nr 2 2 2 chk_add_nr 1 1 1 chk_rm_nr 1 1 @@ -2843,7 +2844,7 @@ add_addr_ports_tests() pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -8 -2 slow + run_tests $ns1 $ns2 10.0.1.1 -8 -2 slow chk_join_nr 3 3 3 chk_add_nr 1 1 chk_rm_nr 1 3 invert simult @@ -3045,7 +3046,7 @@ fullmesh_tests() pm_nl_set_limits $ns2 1 4 pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow,fullmesh pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,fullmesh - run_tests $ns1 $ns2 10.0.1.1 0 1 0 slow + run_tests $ns1 $ns2 10.0.1.1 1 0 slow chk_join_nr 4 4 4 chk_add_nr 1 1 fi @@ -3057,7 +3058,7 @@ fullmesh_tests() pm_nl_set_limits $ns1 1 3 pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 0 fullmesh_1 slow + run_tests $ns1 $ns2 10.0.1.1 0 fullmesh_1 slow chk_join_nr 3 3 3 chk_add_nr 1 1 fi @@ -3069,7 +3070,7 @@ fullmesh_tests() pm_nl_set_limits $ns1 2 5 pm_nl_set_limits $ns2 1 5 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 0 fullmesh_2 slow + run_tests $ns1 $ns2 10.0.1.1 0 fullmesh_2 slow chk_join_nr 5 5 5 chk_add_nr 1 1 fi @@ -3082,7 +3083,7 @@ fullmesh_tests() pm_nl_set_limits $ns1 2 4 pm_nl_set_limits $ns2 1 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 0 fullmesh_2 slow + run_tests $ns1 $ns2 10.0.1.1 0 fullmesh_2 slow chk_join_nr 4 4 4 chk_add_nr 1 1 fi @@ -3093,7 +3094,7 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow pm_nl_set_limits $ns2 4 4 - run_tests $ns1 $ns2 10.0.1.1 0 0 1 slow fullmesh + run_tests $ns1 $ns2 10.0.1.1 0 1 slow fullmesh chk_join_nr 2 2 2 chk_rm_nr 0 1 fi @@ -3104,7 +3105,7 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow,fullmesh pm_nl_set_limits $ns2 4 4 - run_tests $ns1 $ns2 10.0.1.1 0 0 fullmesh_1 slow nofullmesh + run_tests $ns1 $ns2 10.0.1.1 0 fullmesh_1 slow nofullmesh chk_join_nr 2 2 2 chk_rm_nr 0 1 fi @@ -3115,7 +3116,7 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow pm_nl_set_limits $ns2 4 4 - run_tests $ns1 $ns2 10.0.1.1 0 0 1 slow backup,fullmesh + run_tests $ns1 $ns2 10.0.1.1 0 1 slow backup,fullmesh chk_join_nr 2 2 2 chk_prio_nr 0 1 chk_rm_nr 0 1 @@ -3127,7 +3128,7 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_set_limits $ns2 4 4 pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow,backup,fullmesh - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow nobackup,nofullmesh + run_tests $ns1 $ns2 10.0.1.1 0 0 slow nobackup,nofullmesh chk_join_nr 2 2 2 chk_prio_nr 0 1 chk_rm_nr 0 1 @@ -3137,14 +3138,16 @@ fullmesh_tests() fastclose_tests() { if reset_check_counter "fastclose test" "MPTcpExtMPFastcloseTx"; then - run_tests $ns1 $ns2 10.0.1.1 1024 0 fastclose_client + test_linkfail=1024 \ + run_tests $ns1 $ns2 10.0.1.1 0 fastclose_client chk_join_nr 0 0 0 chk_fclose_nr 1 1 chk_rst_nr 1 1 invert fi if reset_check_counter "fastclose server test" "MPTcpExtMPFastcloseRx"; then - run_tests $ns1 $ns2 10.0.1.1 1024 0 fastclose_server + test_linkfail=1024 \ + run_tests $ns1 $ns2 10.0.1.1 0 fastclose_server chk_join_nr 0 0 0 chk_fclose_nr 1 1 invert chk_rst_nr 1 1 @@ -3162,7 +3165,8 @@ fail_tests() { # single subflow if reset_with_fail "Infinite map" 1; then - run_tests $ns1 $ns2 10.0.1.1 128 + test_linkfail=128 \ + run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 0 0 0 +1 +0 1 0 1 "$(pedit_action_pkts)" chk_fail_nr 1 -1 invert fi @@ -3173,7 +3177,8 @@ fail_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.2.2 dev ns2eth2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 1024 + test_linkfail=1024 \ + run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 1 1 1 1 0 1 1 0 "$(pedit_action_pkts)" fi } @@ -3298,7 +3303,7 @@ userspace_tests() pm_nl_set_limits $ns1 1 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup chk_join_nr 1 1 0 chk_prio_nr 0 0 fi @@ -3311,7 +3316,7 @@ userspace_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 -1 slow + run_tests $ns1 $ns2 10.0.1.1 0 -1 slow chk_join_nr 0 0 0 chk_rm_nr 0 0 fi @@ -3321,7 +3326,7 @@ userspace_tests() continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then set_userspace_pm $ns1 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 0 speed_10 & + run_tests $ns1 $ns2 10.0.1.1 0 0 speed_10 & local tests_pid=$! wait_mpj $ns1 userspace_pm_add_addr 10.0.2.1 10 @@ -3341,7 +3346,7 @@ userspace_tests() continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then set_userspace_pm $ns2 pm_nl_set_limits $ns1 0 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 0 speed_10 & + run_tests $ns1 $ns2 10.0.1.1 0 0 speed_10 & local tests_pid=$! wait_mpj $ns2 userspace_pm_add_sf 10.0.3.2 20 @@ -3364,7 +3369,7 @@ endpoint_tests() pm_nl_set_limits $ns1 2 2 pm_nl_set_limits $ns2 2 2 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow 2>/dev/null & + run_tests $ns1 $ns2 10.0.1.1 0 0 slow 2>/dev/null & wait_mpj $ns1 pm_nl_check_endpoint 1 "creation" \ @@ -3387,7 +3392,8 @@ endpoint_tests() pm_nl_set_limits $ns1 1 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns2 10.0.2.2 id 2 dev ns2eth2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 4 0 0 speed_20 2>/dev/null & + test_linkfail=4 \ + run_tests $ns1 $ns2 10.0.1.1 0 0 speed_20 2>/dev/null & wait_mpj $ns2 chk_subflow_nr needtitle "before delete" 2 -- cgit v1.2.3 From 595ef566a2ef9af9e799491580e57c09c64c4e6d Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 23 Jun 2023 10:34:11 -0700 Subject: selftests: mptcp: drop addr_nr_ns1/2 parameters run_tests() accepts too many optional parameters. Before this modification, it was required to set all of then when only the last one had to be changed. That's not clear to see all these 0 and it makes the maintenance harder: run_tests $ns1 $ns2 10.0.1.1 1 2 3 slow Instead, the parameter can be set as an env var with a limited scope: foo=1 bar=2 next=3 \ run_tests $ns1 $ns2 10.0.1.1 slow This patch switches to key/value "addr_nr_ns1=*, addr_nr_ns2=*" instead of positional parameters addr_nr_ns1 and addr_nr_ns2 of do_transfer() and run_tests(). Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20230623-send-net-next-20230623-v1-5-a883213c8ba9@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 176 ++++++++++++++---------- 1 file changed, 103 insertions(+), 73 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index bc6a26d357bb..93f941fd51f2 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -51,6 +51,8 @@ nr_blank=40 export FAILING_LINKS="" export test_linkfail=0 +export addr_nr_ns1=0 +export addr_nr_ns2=0 # generated using "nfbpf_compile '(ip && (ip[54] & 0xf0) == 0x30) || # (ip6 && (ip6[74] & 0xf0) == 0x30)'" @@ -826,10 +828,8 @@ do_transfer() local cl_proto="$3" local srv_proto="$4" local connect_addr="$5" - local addr_nr_ns1="$6" - local addr_nr_ns2="$7" - local speed="$8" - local sflags="${9}" + local speed="$6" + local sflags="${7}" local port=$((10000 + TEST_COUNT - 1)) local cappid @@ -1146,10 +1146,8 @@ run_tests() local listener_ns="$1" local connector_ns="$2" local connect_addr="$3" - local addr_nr_ns1="${4:-0}" - local addr_nr_ns2="${5:-0}" - local speed="${6:-fast}" - local sflags="${7:-""}" + local speed="${4:-fast}" + local sflags="${5:-""}" local size @@ -1194,7 +1192,7 @@ run_tests() fi do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr} \ - ${addr_nr_ns1} ${addr_nr_ns2} ${speed} ${sflags} + ${speed} ${sflags} } dump_stats() @@ -1983,7 +1981,7 @@ subflows_error_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 0 0 0 fi @@ -1994,7 +1992,7 @@ subflows_error_tests() pm_nl_set_limits $ns2 0 2 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 fi @@ -2005,7 +2003,7 @@ subflows_error_tests() pm_nl_set_limits $ns2 0 2 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 fi @@ -2017,7 +2015,7 @@ subflows_error_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 slow & + run_tests $ns1 $ns2 10.0.1.1 slow & # mpj subflow will be in TW after the reset wait_attempt_fail $ns2 @@ -2116,7 +2114,7 @@ signal_address_tests() # the peer could possibly miss some addr notification, allow retransmission ip netns exec $ns1 sysctl -q net.mptcp.add_addr_timeout=1 - run_tests $ns1 $ns2 10.0.1.1 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 slow # It is not directly linked to the commit introducing this # symbol but for the parent one which is linked anyway. @@ -2226,7 +2224,7 @@ add_addr_timeout_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_add_tx_nr 4 4 chk_add_nr 4 0 @@ -2237,7 +2235,7 @@ add_addr_timeout_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal - run_tests $ns1 $ns2 dead:beef:1::1 0 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 slow chk_join_nr 1 1 1 chk_add_nr 4 0 fi @@ -2248,7 +2246,7 @@ add_addr_timeout_tests() pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_set_limits $ns2 2 2 - run_tests $ns1 $ns2 10.0.1.1 0 0 speed_10 + run_tests $ns1 $ns2 10.0.1.1 speed_10 chk_join_nr 2 2 2 chk_add_nr 8 0 fi @@ -2259,7 +2257,7 @@ add_addr_timeout_tests() pm_nl_add_endpoint $ns1 10.0.12.1 flags signal pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_set_limits $ns2 2 2 - run_tests $ns1 $ns2 10.0.1.1 0 0 speed_10 + run_tests $ns1 $ns2 10.0.1.1 speed_10 chk_join_nr 1 1 1 chk_add_nr 8 0 fi @@ -2272,7 +2270,8 @@ remove_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -1 slow + addr_nr_ns2=-1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_rm_tx_nr 1 chk_rm_nr 1 1 @@ -2284,7 +2283,8 @@ remove_tests() pm_nl_set_limits $ns2 0 2 pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -2 slow + addr_nr_ns2=-2 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 2 2 2 chk_rm_nr 2 2 fi @@ -2294,7 +2294,8 @@ remove_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 -1 0 slow + addr_nr_ns1=-1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_add_nr 1 1 chk_rm_nr 1 1 invert @@ -2306,7 +2307,8 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_set_limits $ns2 1 2 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 -1 -1 slow + addr_nr_ns1=-1 addr_nr_ns2=-1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 2 2 2 chk_add_nr 1 1 chk_rm_nr 1 1 @@ -2319,7 +2321,8 @@ remove_tests() pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 -1 -2 speed_10 + addr_nr_ns1=-1 addr_nr_ns2=-2 \ + run_tests $ns1 $ns2 10.0.1.1 speed_10 chk_join_nr 3 3 3 chk_add_nr 1 1 chk_rm_nr 2 2 @@ -2332,7 +2335,8 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.4.1 flags signal pm_nl_set_limits $ns2 3 3 - run_tests $ns1 $ns2 10.0.1.1 -3 0 speed_10 + addr_nr_ns1=-3 \ + run_tests $ns1 $ns2 10.0.1.1 speed_10 chk_join_nr 3 3 3 chk_add_nr 3 3 chk_rm_nr 3 3 invert @@ -2345,7 +2349,8 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.14.1 flags signal pm_nl_set_limits $ns2 3 3 - run_tests $ns1 $ns2 10.0.1.1 -3 0 speed_10 + addr_nr_ns1=-3 \ + run_tests $ns1 $ns2 10.0.1.1 speed_10 chk_join_nr 1 1 1 chk_add_nr 3 3 chk_rm_nr 3 1 invert @@ -2358,7 +2363,8 @@ remove_tests() pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 -8 -8 slow + addr_nr_ns1=-8 addr_nr_ns2=-8 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 3 3 3 chk_add_nr 1 1 chk_rm_nr 1 3 invert simult @@ -2371,7 +2377,8 @@ remove_tests() pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow id 150 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 -8 -8 slow + addr_nr_ns1=-8 addr_nr_ns2=-8 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 3 3 3 if mptcp_lib_kversion_ge 5.18; then @@ -2389,7 +2396,8 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.4.1 flags signal pm_nl_set_limits $ns2 3 3 - run_tests $ns1 $ns2 10.0.1.1 -8 -8 slow + addr_nr_ns1=-8 addr_nr_ns2=-8 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 3 3 3 chk_add_nr 3 3 chk_rm_nr 3 3 invert simult @@ -2402,7 +2410,8 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.14.1 flags signal pm_nl_set_limits $ns2 3 3 - run_tests $ns1 $ns2 10.0.1.1 -8 0 slow + addr_nr_ns1=-8 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_add_nr 3 3 chk_rm_nr 3 1 invert @@ -2413,7 +2422,8 @@ remove_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -9 slow + addr_nr_ns2=-9 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_rm_nr 1 1 fi @@ -2423,7 +2433,8 @@ remove_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 -9 0 slow + addr_nr_ns1=-9 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_add_nr 1 1 chk_rm_nr 1 1 invert @@ -2436,7 +2447,8 @@ add_tests() if reset "add single subflow"; then pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 - run_tests $ns1 $ns2 10.0.1.1 0 1 slow + addr_nr_ns2=1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 fi @@ -2444,7 +2456,8 @@ add_tests() if reset "add signal address"; then pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 1 0 slow + addr_nr_ns1=1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_add_nr 1 1 fi @@ -2453,7 +2466,8 @@ add_tests() if reset "add multiple subflows"; then pm_nl_set_limits $ns1 0 2 pm_nl_set_limits $ns2 0 2 - run_tests $ns1 $ns2 10.0.1.1 0 2 slow + addr_nr_ns2=2 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 2 2 2 fi @@ -2461,7 +2475,8 @@ add_tests() if reset "add multiple subflows IPv6"; then pm_nl_set_limits $ns1 0 2 pm_nl_set_limits $ns2 0 2 - run_tests $ns1 $ns2 dead:beef:1::1 0 2 slow + addr_nr_ns2=2 \ + run_tests $ns1 $ns2 dead:beef:1::1 slow chk_join_nr 2 2 2 fi @@ -2469,7 +2484,8 @@ add_tests() if reset "add multiple addresses IPv6"; then pm_nl_set_limits $ns1 0 2 pm_nl_set_limits $ns2 2 2 - run_tests $ns1 $ns2 dead:beef:1::1 2 0 slow + addr_nr_ns1=2 \ + run_tests $ns1 $ns2 dead:beef:1::1 slow chk_join_nr 2 2 2 chk_add_nr 2 2 fi @@ -2482,14 +2498,14 @@ ipv6_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 dead:beef:3::2 dev ns2eth3 flags subflow - run_tests $ns1 $ns2 dead:beef:1::1 0 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 slow chk_join_nr 1 1 1 fi # add_address, unused IPv6 if reset "unused signal address IPv6"; then pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal - run_tests $ns1 $ns2 dead:beef:1::1 0 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 slow chk_join_nr 0 0 0 chk_add_nr 1 1 fi @@ -2499,7 +2515,7 @@ ipv6_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 dead:beef:1::1 0 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 slow chk_join_nr 1 1 1 chk_add_nr 1 1 fi @@ -2509,7 +2525,8 @@ ipv6_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 dead:beef:1::1 -1 0 slow + addr_nr_ns1=-1 \ + run_tests $ns1 $ns2 dead:beef:1::1 slow chk_join_nr 1 1 1 chk_add_nr 1 1 chk_rm_nr 1 1 invert @@ -2521,7 +2538,8 @@ ipv6_tests() pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal pm_nl_set_limits $ns2 1 2 pm_nl_add_endpoint $ns2 dead:beef:3::2 dev ns2eth3 flags subflow - run_tests $ns1 $ns2 dead:beef:1::1 -1 -1 slow + addr_nr_ns1=-1 addr_nr_ns2=-1 \ + run_tests $ns1 $ns2 dead:beef:1::1 slow chk_join_nr 2 2 2 chk_add_nr 1 1 chk_rm_nr 1 1 @@ -2622,7 +2640,7 @@ mixed_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 0 0 0 fi @@ -2632,7 +2650,7 @@ mixed_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns1 10.0.1.1 flags signal - run_tests $ns1 $ns2 dead:beef:2::1 0 0 slow + run_tests $ns1 $ns2 dead:beef:2::1 slow chk_join_nr 1 1 1 fi @@ -2643,7 +2661,7 @@ mixed_tests() pm_nl_set_limits $ns2 1 4 pm_nl_add_endpoint $ns2 dead:beef:2::2 flags subflow,fullmesh pm_nl_add_endpoint $ns1 10.0.1.1 flags signal - run_tests $ns1 $ns2 dead:beef:2::1 0 0 slow + run_tests $ns1 $ns2 dead:beef:2::1 slow chk_join_nr 1 1 1 fi @@ -2655,7 +2673,8 @@ mixed_tests() pm_nl_set_limits $ns2 2 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal - run_tests $ns1 $ns2 dead:beef:1::1 0 fullmesh_1 slow + addr_nr_ns2=fullmesh_1 \ + run_tests $ns1 $ns2 dead:beef:1::1 slow chk_join_nr 4 4 4 fi } @@ -2668,7 +2687,7 @@ backup_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup - run_tests $ns1 $ns2 10.0.1.1 0 0 slow nobackup + run_tests $ns1 $ns2 10.0.1.1 slow nobackup chk_join_nr 1 1 1 chk_prio_nr 0 1 fi @@ -2679,7 +2698,7 @@ backup_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 slow backup chk_join_nr 1 1 1 chk_add_nr 1 1 chk_prio_nr 1 1 @@ -2691,7 +2710,7 @@ backup_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal port 10100 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 slow backup chk_join_nr 1 1 1 chk_add_nr 1 1 chk_prio_nr 1 1 @@ -2700,7 +2719,7 @@ backup_tests() if reset "mpc backup" && continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow,backup - run_tests $ns1 $ns2 10.0.1.1 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 0 0 0 chk_prio_nr 0 1 fi @@ -2709,7 +2728,7 @@ backup_tests() continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns1 10.0.1.1 flags subflow,backup pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow,backup - run_tests $ns1 $ns2 10.0.1.1 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 0 0 0 chk_prio_nr 1 1 fi @@ -2717,7 +2736,7 @@ backup_tests() if reset "mpc switch to backup" && continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 slow backup chk_join_nr 0 0 0 chk_prio_nr 0 1 fi @@ -2726,7 +2745,7 @@ backup_tests() continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns1 10.0.1.1 flags subflow pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 slow backup chk_join_nr 0 0 0 chk_prio_nr 1 1 fi @@ -2815,7 +2834,8 @@ add_addr_ports_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal port 10100 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 -1 0 slow + addr_nr_ns1=-1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_add_nr 1 1 1 chk_rm_nr 1 1 invert @@ -2831,7 +2851,8 @@ add_addr_ports_tests() pm_nl_add_endpoint $ns1 10.0.2.1 flags signal port 10100 pm_nl_set_limits $ns2 1 2 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 -1 -1 slow + addr_nr_ns1=-1 addr_nr_ns2=-1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 2 2 2 chk_add_nr 1 1 1 chk_rm_nr 1 1 @@ -2844,7 +2865,8 @@ add_addr_ports_tests() pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 -8 -2 slow + addr_nr_ns1=-8 addr_nr_ns2=-2 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 3 3 3 chk_add_nr 1 1 chk_rm_nr 1 3 invert simult @@ -3046,7 +3068,8 @@ fullmesh_tests() pm_nl_set_limits $ns2 1 4 pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow,fullmesh pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,fullmesh - run_tests $ns1 $ns2 10.0.1.1 1 0 slow + addr_nr_ns1=1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 4 4 4 chk_add_nr 1 1 fi @@ -3058,7 +3081,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 1 3 pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 fullmesh_1 slow + addr_nr_ns2=fullmesh_1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 3 3 3 chk_add_nr 1 1 fi @@ -3070,7 +3094,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 2 5 pm_nl_set_limits $ns2 1 5 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 fullmesh_2 slow + addr_nr_ns2=fullmesh_2 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 5 5 5 chk_add_nr 1 1 fi @@ -3083,7 +3108,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 2 4 pm_nl_set_limits $ns2 1 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 fullmesh_2 slow + addr_nr_ns2=fullmesh_2 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 4 4 4 chk_add_nr 1 1 fi @@ -3094,7 +3120,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow pm_nl_set_limits $ns2 4 4 - run_tests $ns1 $ns2 10.0.1.1 0 1 slow fullmesh + addr_nr_ns2=1 \ + run_tests $ns1 $ns2 10.0.1.1 slow fullmesh chk_join_nr 2 2 2 chk_rm_nr 0 1 fi @@ -3105,7 +3132,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow,fullmesh pm_nl_set_limits $ns2 4 4 - run_tests $ns1 $ns2 10.0.1.1 0 fullmesh_1 slow nofullmesh + addr_nr_ns2=fullmesh_1 \ + run_tests $ns1 $ns2 10.0.1.1 slow nofullmesh chk_join_nr 2 2 2 chk_rm_nr 0 1 fi @@ -3116,7 +3144,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow pm_nl_set_limits $ns2 4 4 - run_tests $ns1 $ns2 10.0.1.1 0 1 slow backup,fullmesh + addr_nr_ns2=1 run_tests \ + $ns1 $ns2 10.0.1.1 slow backup,fullmesh chk_join_nr 2 2 2 chk_prio_nr 0 1 chk_rm_nr 0 1 @@ -3128,7 +3157,7 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_set_limits $ns2 4 4 pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow,backup,fullmesh - run_tests $ns1 $ns2 10.0.1.1 0 0 slow nobackup,nofullmesh + run_tests $ns1 $ns2 10.0.1.1 slow nobackup,nofullmesh chk_join_nr 2 2 2 chk_prio_nr 0 1 chk_rm_nr 0 1 @@ -3138,16 +3167,16 @@ fullmesh_tests() fastclose_tests() { if reset_check_counter "fastclose test" "MPTcpExtMPFastcloseTx"; then - test_linkfail=1024 \ - run_tests $ns1 $ns2 10.0.1.1 0 fastclose_client + test_linkfail=1024 addr_nr_ns2=fastclose_client \ + run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 0 0 0 chk_fclose_nr 1 1 chk_rst_nr 1 1 invert fi if reset_check_counter "fastclose server test" "MPTcpExtMPFastcloseRx"; then - test_linkfail=1024 \ - run_tests $ns1 $ns2 10.0.1.1 0 fastclose_server + test_linkfail=1024 addr_nr_ns2=fastclose_server \ + run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 0 0 0 chk_fclose_nr 1 1 invert chk_rst_nr 1 1 @@ -3303,7 +3332,7 @@ userspace_tests() pm_nl_set_limits $ns1 1 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 slow backup chk_join_nr 1 1 0 chk_prio_nr 0 0 fi @@ -3316,7 +3345,8 @@ userspace_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -1 slow + addr_nr_ns2=-1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 0 0 0 chk_rm_nr 0 0 fi @@ -3326,7 +3356,7 @@ userspace_tests() continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then set_userspace_pm $ns1 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 speed_10 & + run_tests $ns1 $ns2 10.0.1.1 speed_10 & local tests_pid=$! wait_mpj $ns1 userspace_pm_add_addr 10.0.2.1 10 @@ -3346,7 +3376,7 @@ userspace_tests() continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then set_userspace_pm $ns2 pm_nl_set_limits $ns1 0 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 speed_10 & + run_tests $ns1 $ns2 10.0.1.1 speed_10 & local tests_pid=$! wait_mpj $ns2 userspace_pm_add_sf 10.0.3.2 20 @@ -3369,7 +3399,7 @@ endpoint_tests() pm_nl_set_limits $ns1 2 2 pm_nl_set_limits $ns2 2 2 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 0 slow 2>/dev/null & + run_tests $ns1 $ns2 10.0.1.1 slow 2>/dev/null & wait_mpj $ns1 pm_nl_check_endpoint 1 "creation" \ @@ -3393,7 +3423,7 @@ endpoint_tests() pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns2 10.0.2.2 id 2 dev ns2eth2 flags subflow test_linkfail=4 \ - run_tests $ns1 $ns2 10.0.1.1 0 0 speed_20 2>/dev/null & + run_tests $ns1 $ns2 10.0.1.1 speed_20 2>/dev/null & wait_mpj $ns2 chk_subflow_nr needtitle "before delete" 2 -- cgit v1.2.3 From 1534f87ee0dc1328043f7d0872fbf34937185682 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 23 Jun 2023 10:34:12 -0700 Subject: selftests: mptcp: drop sflags parameter run_tests() accepts too many optional parameters. Before this modification, it was required to set all of then when only the last one had to be changed. That's not clear to see all these 0 and it makes the maintenance harder: run_tests $ns1 $ns2 10.0.1.1 1 2 3 slow Instead, the parameter can be set as an env var with a limited scope: foo=1 bar=2 next=3 \ run_tests $ns1 $ns2 10.0.1.1 slow This patch switches to key/value "sflags=*" instead of positional parameter sflags of do_transfer() and run_tests(). Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20230623-send-net-next-20230623-v1-6-a883213c8ba9@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 39 ++++++++++++++----------- 1 file changed, 22 insertions(+), 17 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 93f941fd51f2..5cb66f85c88f 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -53,6 +53,7 @@ export FAILING_LINKS="" export test_linkfail=0 export addr_nr_ns1=0 export addr_nr_ns2=0 +export sflags="" # generated using "nfbpf_compile '(ip && (ip[54] & 0xf0) == 0x30) || # (ip6 && (ip6[74] & 0xf0) == 0x30)'" @@ -829,7 +830,6 @@ do_transfer() local srv_proto="$4" local connect_addr="$5" local speed="$6" - local sflags="${7}" local port=$((10000 + TEST_COUNT - 1)) local cappid @@ -1147,7 +1147,6 @@ run_tests() local connector_ns="$2" local connect_addr="$3" local speed="${4:-fast}" - local sflags="${5:-""}" local size @@ -1191,8 +1190,7 @@ run_tests() make_file "$sinfail" "server" $size fi - do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr} \ - ${speed} ${sflags} + do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr} ${speed} } dump_stats() @@ -2687,7 +2685,8 @@ backup_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup - run_tests $ns1 $ns2 10.0.1.1 slow nobackup + sflags=nobackup \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_prio_nr 0 1 fi @@ -2698,7 +2697,8 @@ backup_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 slow backup + sflags=backup \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_add_nr 1 1 chk_prio_nr 1 1 @@ -2710,7 +2710,8 @@ backup_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal port 10100 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 slow backup + sflags=backup \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_add_nr 1 1 chk_prio_nr 1 1 @@ -2736,7 +2737,8 @@ backup_tests() if reset "mpc switch to backup" && continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 slow backup + sflags=backup \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 0 0 0 chk_prio_nr 0 1 fi @@ -2745,7 +2747,8 @@ backup_tests() continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns1 10.0.1.1 flags subflow pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 slow backup + sflags=backup \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 0 0 0 chk_prio_nr 1 1 fi @@ -3120,8 +3123,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow pm_nl_set_limits $ns2 4 4 - addr_nr_ns2=1 \ - run_tests $ns1 $ns2 10.0.1.1 slow fullmesh + addr_nr_ns2=1 sflags=fullmesh \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 2 2 2 chk_rm_nr 0 1 fi @@ -3132,8 +3135,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow,fullmesh pm_nl_set_limits $ns2 4 4 - addr_nr_ns2=fullmesh_1 \ - run_tests $ns1 $ns2 10.0.1.1 slow nofullmesh + addr_nr_ns2=fullmesh_1 sflags=nofullmesh \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 2 2 2 chk_rm_nr 0 1 fi @@ -3144,8 +3147,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow pm_nl_set_limits $ns2 4 4 - addr_nr_ns2=1 run_tests \ - $ns1 $ns2 10.0.1.1 slow backup,fullmesh + addr_nr_ns2=1 sflags=backup,fullmesh \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 2 2 2 chk_prio_nr 0 1 chk_rm_nr 0 1 @@ -3157,7 +3160,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_set_limits $ns2 4 4 pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow,backup,fullmesh - run_tests $ns1 $ns2 10.0.1.1 slow nobackup,nofullmesh + sflags=nobackup,nofullmesh \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 2 2 2 chk_prio_nr 0 1 chk_rm_nr 0 1 @@ -3332,7 +3336,8 @@ userspace_tests() pm_nl_set_limits $ns1 1 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 slow backup + sflags=backup \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 0 chk_prio_nr 0 0 fi -- cgit v1.2.3 From 9e9d176df8e9aa74c9efc09ac1b4d348261cb630 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 23 Jun 2023 10:34:13 -0700 Subject: selftests: mptcp: add pm_nl_set_endpoint helper This patch moves endpoint settings out of do_transfer() into a new helper pm_nl_set_endpoint(). And invoke this helper in do_transfer(). This makes the code much more clearer. Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20230623-send-net-next-20230623-v1-7-a883213c8ba9@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 235 ++++++++++++------------ 1 file changed, 122 insertions(+), 113 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 5cb66f85c88f..e6c9d5451c5b 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -822,122 +822,11 @@ pm_nl_check_endpoint() fi } -do_transfer() +pm_nl_set_endpoint() { local listener_ns="$1" local connector_ns="$2" - local cl_proto="$3" - local srv_proto="$4" - local connect_addr="$5" - local speed="$6" - - local port=$((10000 + TEST_COUNT - 1)) - local cappid - - :> "$cout" - :> "$sout" - :> "$capout" - - if [ $capture -eq 1 ]; then - local capuser - if [ -z $SUDO_USER ] ; then - capuser="" - else - capuser="-Z $SUDO_USER" - fi - - capfile=$(printf "mp_join-%02u-%s.pcap" "$TEST_COUNT" "${listener_ns}") - - echo "Capturing traffic for test $TEST_COUNT into $capfile" - ip netns exec ${listener_ns} tcpdump -i any -s 65535 -B 32768 $capuser -w $capfile > "$capout" 2>&1 & - cappid=$! - - sleep 1 - fi - - NSTAT_HISTORY=/tmp/${listener_ns}.nstat ip netns exec ${listener_ns} \ - nstat -n - NSTAT_HISTORY=/tmp/${connector_ns}.nstat ip netns exec ${connector_ns} \ - nstat -n - - local extra_args - if [ $speed = "fast" ]; then - extra_args="-j" - elif [ $speed = "slow" ]; then - extra_args="-r 50" - elif [[ $speed = "speed_"* ]]; then - extra_args="-r ${speed:6}" - fi - - local flags="subflow" - local extra_cl_args="" - local extra_srv_args="" - local trunc_size="" - if [[ "${addr_nr_ns2}" = "fastclose_"* ]]; then - if [ ${test_linkfail} -le 1 ]; then - echo "fastclose tests need test_linkfail argument" - fail_test - return 1 - fi - - # disconnect - trunc_size=${test_linkfail} - local side=${addr_nr_ns2:10} - - if [ ${side} = "client" ]; then - extra_cl_args="-f ${test_linkfail}" - extra_srv_args="-f -1" - elif [ ${side} = "server" ]; then - extra_srv_args="-f ${test_linkfail}" - extra_cl_args="-f -1" - else - echo "wrong/unknown fastclose spec ${side}" - fail_test - return 1 - fi - addr_nr_ns2=0 - elif [[ "${addr_nr_ns2}" = "fullmesh_"* ]]; then - flags="${flags},fullmesh" - addr_nr_ns2=${addr_nr_ns2:9} - fi - - extra_srv_args="$extra_args $extra_srv_args" - if [ "$test_linkfail" -gt 1 ];then - timeout ${timeout_test} \ - ip netns exec ${listener_ns} \ - ./mptcp_connect -t ${timeout_poll} -l -p $port -s ${srv_proto} \ - $extra_srv_args "::" < "$sinfail" > "$sout" & - else - timeout ${timeout_test} \ - ip netns exec ${listener_ns} \ - ./mptcp_connect -t ${timeout_poll} -l -p $port -s ${srv_proto} \ - $extra_srv_args "::" < "$sin" > "$sout" & - fi - local spid=$! - - wait_local_port_listen "${listener_ns}" "${port}" - - extra_cl_args="$extra_args $extra_cl_args" - if [ "$test_linkfail" -eq 0 ];then - timeout ${timeout_test} \ - ip netns exec ${connector_ns} \ - ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ - $extra_cl_args $connect_addr < "$cin" > "$cout" & - elif [ "$test_linkfail" -eq 1 ] || [ "$test_linkfail" -eq 2 ];then - ( cat "$cinfail" ; sleep 2; link_failure $listener_ns ; cat "$cinfail" ) | \ - tee "$cinsent" | \ - timeout ${timeout_test} \ - ip netns exec ${connector_ns} \ - ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ - $extra_cl_args $connect_addr > "$cout" & - else - tee "$cinsent" < "$cinfail" | \ - timeout ${timeout_test} \ - ip netns exec ${connector_ns} \ - ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ - $extra_cl_args $connect_addr > "$cout" & - fi - local cpid=$! + local connect_addr="$3" # let the mptcp subflow be established in background before # do endpoint manipulation @@ -1077,6 +966,126 @@ do_transfer() done done fi +} + +do_transfer() +{ + local listener_ns="$1" + local connector_ns="$2" + local cl_proto="$3" + local srv_proto="$4" + local connect_addr="$5" + local speed="$6" + + local port=$((10000 + TEST_COUNT - 1)) + local cappid + + :> "$cout" + :> "$sout" + :> "$capout" + + if [ $capture -eq 1 ]; then + local capuser + if [ -z $SUDO_USER ] ; then + capuser="" + else + capuser="-Z $SUDO_USER" + fi + + capfile=$(printf "mp_join-%02u-%s.pcap" "$TEST_COUNT" "${listener_ns}") + + echo "Capturing traffic for test $TEST_COUNT into $capfile" + ip netns exec ${listener_ns} tcpdump -i any -s 65535 -B 32768 $capuser -w $capfile > "$capout" 2>&1 & + cappid=$! + + sleep 1 + fi + + NSTAT_HISTORY=/tmp/${listener_ns}.nstat ip netns exec ${listener_ns} \ + nstat -n + NSTAT_HISTORY=/tmp/${connector_ns}.nstat ip netns exec ${connector_ns} \ + nstat -n + + local extra_args + if [ $speed = "fast" ]; then + extra_args="-j" + elif [ $speed = "slow" ]; then + extra_args="-r 50" + elif [[ $speed = "speed_"* ]]; then + extra_args="-r ${speed:6}" + fi + + local flags="subflow" + local extra_cl_args="" + local extra_srv_args="" + local trunc_size="" + if [[ "${addr_nr_ns2}" = "fastclose_"* ]]; then + if [ ${test_linkfail} -le 1 ]; then + echo "fastclose tests need test_linkfail argument" + fail_test + return 1 + fi + + # disconnect + trunc_size=${test_linkfail} + local side=${addr_nr_ns2:10} + + if [ ${side} = "client" ]; then + extra_cl_args="-f ${test_linkfail}" + extra_srv_args="-f -1" + elif [ ${side} = "server" ]; then + extra_srv_args="-f ${test_linkfail}" + extra_cl_args="-f -1" + else + echo "wrong/unknown fastclose spec ${side}" + fail_test + return 1 + fi + addr_nr_ns2=0 + elif [[ "${addr_nr_ns2}" = "fullmesh_"* ]]; then + flags="${flags},fullmesh" + addr_nr_ns2=${addr_nr_ns2:9} + fi + + extra_srv_args="$extra_args $extra_srv_args" + if [ "$test_linkfail" -gt 1 ];then + timeout ${timeout_test} \ + ip netns exec ${listener_ns} \ + ./mptcp_connect -t ${timeout_poll} -l -p $port -s ${srv_proto} \ + $extra_srv_args "::" < "$sinfail" > "$sout" & + else + timeout ${timeout_test} \ + ip netns exec ${listener_ns} \ + ./mptcp_connect -t ${timeout_poll} -l -p $port -s ${srv_proto} \ + $extra_srv_args "::" < "$sin" > "$sout" & + fi + local spid=$! + + wait_local_port_listen "${listener_ns}" "${port}" + + extra_cl_args="$extra_args $extra_cl_args" + if [ "$test_linkfail" -eq 0 ];then + timeout ${timeout_test} \ + ip netns exec ${connector_ns} \ + ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ + $extra_cl_args $connect_addr < "$cin" > "$cout" & + elif [ "$test_linkfail" -eq 1 ] || [ "$test_linkfail" -eq 2 ];then + ( cat "$cinfail" ; sleep 2; link_failure $listener_ns ; cat "$cinfail" ) | \ + tee "$cinsent" | \ + timeout ${timeout_test} \ + ip netns exec ${connector_ns} \ + ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ + $extra_cl_args $connect_addr > "$cout" & + else + tee "$cinsent" < "$cinfail" | \ + timeout ${timeout_test} \ + ip netns exec ${connector_ns} \ + ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ + $extra_cl_args $connect_addr > "$cout" & + fi + local cpid=$! + + pm_nl_set_endpoint $listener_ns $connector_ns $connect_addr wait $cpid local retc=$? -- cgit v1.2.3 From e6b8a78ea266a2feeb3ac8cc6ed45bf667f6e405 Mon Sep 17 00:00:00 2001 From: Yueh-Shun Li Date: Fri, 23 Jun 2023 10:34:14 -0700 Subject: selftests: mptcp: connect: fix comment typo Spell "transmissions" properly. Found by searching for keyword "tranm". Reviewed-by: Matthieu Baerts Signed-off-by: Yueh-Shun Li Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20230623-send-net-next-20230623-v1-8-a883213c8ba9@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_connect.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.sh b/tools/testing/selftests/net/mptcp/mptcp_connect.sh index 773dd770a567..13561e5bc0cd 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_connect.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.sh @@ -809,7 +809,7 @@ run_tests_disconnect() cat $cin $cin $cin > "$cin".disconnect - # force do_transfer to cope with the multiple tranmissions + # force do_transfer to cope with the multiple transmissions sin="$cin.disconnect" cin="$cin.disconnect" cin_disconnect="$old_cin" -- cgit v1.2.3 From c27b40cf919254459698d6622828152b509b9980 Mon Sep 17 00:00:00 2001 From: sunliming Date: Mon, 26 Jun 2023 19:13:43 +0800 Subject: selftests/user_events: Enable the event before write_fault test in ftrace self-test The user_event has not be enabled in write_fault test in ftrace self-test, Just enable it. Link: https://lkml.kernel.org/r/20230626111344.19136-3-sunliming@kylinos.cn Acked-by: Beau Belgrave Signed-off-by: sunliming Signed-off-by: Steven Rostedt (Google) --- tools/testing/selftests/user_events/ftrace_test.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/user_events/ftrace_test.c b/tools/testing/selftests/user_events/ftrace_test.c index eb6904d89f14..88898749e5b7 100644 --- a/tools/testing/selftests/user_events/ftrace_test.c +++ b/tools/testing/selftests/user_events/ftrace_test.c @@ -400,6 +400,10 @@ TEST_F(user, write_fault) { ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, ®)); ASSERT_EQ(0, reg.write_index); + /* Enable event */ + self->enable_fd = open(enable_file, O_RDWR); + ASSERT_NE(-1, write(self->enable_fd, "1", sizeof("1"))) + /* Write should work normally */ ASSERT_NE(-1, writev(self->data_fd, (const struct iovec *)io, 2)); -- cgit v1.2.3 From d34a271accf8fad00e05aad2cecb9fb53a840a94 Mon Sep 17 00:00:00 2001 From: sunliming Date: Mon, 26 Jun 2023 19:13:44 +0800 Subject: selftests/user_events: Add test cases when event is disabled When user_events are disabled, it's write operation should return -EBADF. Add this test cases. Link: https://lkml.kernel.org/r/20230626111344.19136-4-sunliming@kylinos.cn Acked-by: Beau Belgrave Signed-off-by: sunliming Signed-off-by: Steven Rostedt (Google) --- tools/testing/selftests/user_events/ftrace_test.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/user_events/ftrace_test.c b/tools/testing/selftests/user_events/ftrace_test.c index 88898749e5b7..5beb0aef1d81 100644 --- a/tools/testing/selftests/user_events/ftrace_test.c +++ b/tools/testing/selftests/user_events/ftrace_test.c @@ -324,6 +324,10 @@ TEST_F(user, write_events) { io[0].iov_base = ®.write_index; io[0].iov_len = sizeof(reg.write_index); + /* Write should return -EBADF when event is not enabled */ + ASSERT_EQ(-1, writev(self->data_fd, (const struct iovec *)io, 3)); + ASSERT_EQ(EBADF, errno); + /* Enable event */ self->enable_fd = open(enable_file, O_RDWR); ASSERT_NE(-1, write(self->enable_fd, "1", sizeof("1"))) -- cgit v1.2.3