:p
atchew
Login
From: Geliang Tang <tanggeliang@kylinos.cn> v5: - #1-#7 Address #76: add new macros MPTCP_BASE_TEST and RUN_MPTCP_TEST. - #8-#14 add MPTCP_SCHED_TEST macro. v4: - #1-#5 Address #76: add a new macro RUN_MPTCP_TEST. - #6-#11 Cleanups: add send_data_and_verify and SCHED_TEST. v3: - deal with EAGAIN. - add _ss_search helper. v2: - fix checkpatch warnings. - cleanups. Geliang Tang (14): Squash to "selftests/bpf: Add bpf scheduler test" - fix selftests/bpf: Refactor mptcp_sock test selftests/bpf: Refactor mptcpify test selftests/bpf: Add MPTCP_BASE_TEST macro selftests/bpf: Add RUN_MPTCP_TEST macro selftests/bpf: Add mptcp subflow example selftests/bpf: Add mptcp subflow subtest Squash to "selftests/bpf: Add bpf scheduler test" - cleanups Squash to "selftests/bpf: Add bpf_first test" Squash to "selftests/bpf: Add bpf_bkup test" Squash to "selftests/bpf: Add bpf_rr test" Squash to "selftests/bpf: Add bpf_red test" Squash to "selftests/bpf: Add bpf_burst test" Squash to "selftests/bpf: Add bpf scheduler test" .../testing/selftests/bpf/prog_tests/mptcp.c | 465 +++++++----------- .../selftests/bpf/progs/mptcp_subflow.c | 73 +++ 2 files changed, 264 insertions(+), 274 deletions(-) create mode 100644 tools/testing/selftests/bpf/progs/mptcp_subflow.c -- 2.40.1
From: Geliang Tang <tanggeliang@kylinos.cn> BPF tests fail sometimes with "bytes != total_bytes" errors: # test_default:PASS:sched_init:default 0 nsec # send_data:PASS:pthread_create 0 nsec # send_data:FAIL:recv 936000 != 10485760 nr_recv:-1 errno:11 # default: 3041 ms # server:FAIL:send 7579500 != 10485760 nr_sent:-1 errno:11 # send_data:FAIL:pthread_join thread_ret:-11 \ test_default:PASS:has_bytes_sent addr_1 0 nsec # test_default:PASS:has_bytes_sent addr_2 0 nsec # close_netns:PASS:setns 0 nsec Here errno 11 is EAGAIN, sending should continue in this case, not break. This patch makes BPF tests stable. Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/bpf/prog_tests/mptcp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -XXX,XX +XXX,XX @@ static void *server(void *arg) while (bytes < total_bytes && !READ_ONCE(stop)) { nr_sent = send(fd, &batch, MIN(total_bytes - bytes, sizeof(batch)), 0); - if (nr_sent == -1 && errno == EINTR) + if (nr_sent == -1 && (errno == EINTR || errno == EAGAIN)) continue; if (nr_sent == -1) { err = -errno; @@ -XXX,XX +XXX,XX @@ static void send_data(int lfd, int fd, char *msg) while (bytes < total_bytes && !READ_ONCE(stop)) { nr_recv = recv(fd, &batch, MIN(total_bytes - bytes, sizeof(batch)), 0); - if (nr_recv == -1 && errno == EINTR) + if (nr_recv == -1 && (errno == EINTR || errno == EAGAIN)) continue; if (nr_recv == -1) break; -- 2.40.1
From: Geliang Tang <tanggeliang@kylinos.cn> This patch refactors mptcp_sock test, renames "base" to "mptcp_sock", extracts a new helper run_mptcp_sock() to start servers and run tests, moves all test skeleton operations, __open_and_load, __attach and __destroy from run_test() into test_mptcp_sock(). This prepares for the later unification of all MPTCP tests using a macro. Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- .../testing/selftests/bpf/prog_tests/mptcp.c | 63 +++++++++++-------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -XXX,XX +XXX,XX @@ static int verify_msk(int map_fd, int client_fd, __u32 token) return err; } -static int run_test(int cgroup_fd, int server_fd, bool is_mptcp) +static int run_test(int cgroup_fd, int server_fd, + struct mptcp_sock *sock_skel, bool is_mptcp) { int client_fd, prog_fd, map_fd, err; - struct mptcp_sock *sock_skel; - - sock_skel = mptcp_sock__open_and_load(); - if (!ASSERT_OK_PTR(sock_skel, "skel_open_load")) - return libbpf_get_error(sock_skel); - - err = mptcp_sock__attach(sock_skel); - if (!ASSERT_OK(err, "skel_attach")) - goto out; prog_fd = bpf_program__fd(sock_skel->progs._sockops); map_fd = bpf_map__fd(sock_skel->maps.socket_storage_map); @@ -XXX,XX +XXX,XX @@ static int run_test(int cgroup_fd, int server_fd, bool is_mptcp) close(client_fd); out: - mptcp_sock__destroy(sock_skel); return err; } -static void test_base(void) +static void run_mptcp_sock(int cgroup_fd, struct mptcp_sock *skel) { - struct nstoken *nstoken = NULL; - int server_fd, cgroup_fd; - - cgroup_fd = test__join_cgroup("/mptcp"); - if (!ASSERT_GE(cgroup_fd, 0, "test__join_cgroup")) - return; - - nstoken = create_netns(); - if (!ASSERT_OK_PTR(nstoken, "create_netns")) - goto fail; + int server_fd; /* without MPTCP */ server_fd = start_server(AF_INET, SOCK_STREAM, NULL, 0, 0); if (!ASSERT_GE(server_fd, 0, "start_server")) goto with_mptcp; - ASSERT_OK(run_test(cgroup_fd, server_fd, false), "run_test tcp"); + ASSERT_OK(run_test(cgroup_fd, server_fd, skel, false), "run_test tcp"); close(server_fd); @@ -XXX,XX +XXX,XX @@ static void test_base(void) /* with MPTCP */ server_fd = start_mptcp_server(AF_INET, NULL, 0, 0); if (!ASSERT_GE(server_fd, 0, "start_mptcp_server")) - goto fail; + return; - ASSERT_OK(run_test(cgroup_fd, server_fd, true), "run_test mptcp"); + ASSERT_OK(run_test(cgroup_fd, server_fd, skel, true), "run_test mptcp"); close(server_fd); +} + +static void test_mptcp_sock(void) +{ + struct nstoken *nstoken = NULL; + struct mptcp_sock *sock_skel; + int cgroup_fd, err; + + cgroup_fd = test__join_cgroup("/mptcp"); + if (!ASSERT_GE(cgroup_fd, 0, "test__join_cgroup")) + return; + + sock_skel = mptcp_sock__open_and_load(); + if (!ASSERT_OK_PTR(sock_skel, "skel_open_load")) + goto out; + + err = mptcp_sock__attach(sock_skel); + if (!ASSERT_OK(err, "skel_attach")) + goto out; + + nstoken = create_netns(); + if (!ASSERT_OK_PTR(nstoken, "create_netns")) + goto fail; + + run_mptcp_sock(cgroup_fd, sock_skel); fail: cleanup_netns(nstoken); + mptcp_sock__destroy(sock_skel); +out: close(cgroup_fd); } @@ -XXX,XX +XXX,XX @@ static void test_burst(void) void test_mptcp(void) { - if (test__start_subtest("base")) - test_base(); + if (test__start_subtest("mptcp_sock")) + test_mptcp_sock(); if (test__start_subtest("mptcpify")) test_mptcpify(); if (test__start_subtest("default")) -- 2.40.1
From: Geliang Tang <tanggeliang@kylinos.cn> This patch refactors mptcpify test, moves all test skeleton operations, __open_and_load, __attach and __destroy from run_mptcpify() into test_mptcpify(). This prepares for the later unification of all MPTCP tests using a macro. Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- .../testing/selftests/bpf/prog_tests/mptcp.c | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -XXX,XX +XXX,XX @@ static int verify_mptcpify(int server_fd, int client_fd) return err; } -static int run_mptcpify(int cgroup_fd) +static void run_mptcpify(int cgroup_fd, struct mptcpify *skel) { int server_fd, client_fd, err = 0; - struct mptcpify *mptcpify_skel; - - mptcpify_skel = mptcpify__open_and_load(); - if (!ASSERT_OK_PTR(mptcpify_skel, "skel_open_load")) - return libbpf_get_error(mptcpify_skel); - - err = mptcpify__attach(mptcpify_skel); - if (!ASSERT_OK(err, "skel_attach")) - goto out; /* without MPTCP */ server_fd = start_server(AF_INET, SOCK_STREAM, NULL, 0, 0); - if (!ASSERT_GE(server_fd, 0, "start_server")) { - err = -EIO; - goto out; - } + if (!ASSERT_GE(server_fd, 0, "start_server")) + return; client_fd = connect_to_fd(server_fd, 0); - if (!ASSERT_GE(client_fd, 0, "connect to fd")) { - err = -EIO; + if (!ASSERT_GE(client_fd, 0, "connect to fd")) goto close_server; - } send_byte(client_fd); err = verify_mptcpify(server_fd, client_fd); + ASSERT_OK(err, "verify_mptcpify"); close(client_fd); close_server: close(server_fd); -out: - mptcpify__destroy(mptcpify_skel); - return err; } static void test_mptcpify(void) { struct nstoken *nstoken = NULL; + struct mptcpify *mptcpify_skel; int cgroup_fd; + int err; cgroup_fd = test__join_cgroup("/mptcpify"); if (!ASSERT_GE(cgroup_fd, 0, "test__join_cgroup")) return; + mptcpify_skel = mptcpify__open_and_load(); + if (!ASSERT_OK_PTR(mptcpify_skel, "skel_open_load")) + goto out; + + err = mptcpify__attach(mptcpify_skel); + if (!ASSERT_OK(err, "skel_attach")) + goto out; + nstoken = create_netns(); if (!ASSERT_OK_PTR(nstoken, "create_netns")) goto fail; - ASSERT_OK(run_mptcpify(cgroup_fd), "run_mptcpify"); + run_mptcpify(cgroup_fd, mptcpify_skel); fail: cleanup_netns(nstoken); + mptcpify__destroy(mptcpify_skel); +out: close(cgroup_fd); } -- 2.40.1
From: Geliang Tang <tanggeliang@kylinos.cn> This patch adds a macro MPTCP_BASE_TEST to unify all MPTCP tests. test_mptcp_sock() can be replaced by MPTCP_BASE_TEST(mptcp_sock), and test_mptcpify() can be replaced by MPTCP_BASE_TEST(mptcpify). Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- .../testing/selftests/bpf/prog_tests/mptcp.c | 93 +++++++------------ 1 file changed, 33 insertions(+), 60 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -XXX,XX +XXX,XX @@ static void run_mptcp_sock(int cgroup_fd, struct mptcp_sock *skel) close(server_fd); } -static void test_mptcp_sock(void) -{ - struct nstoken *nstoken = NULL; - struct mptcp_sock *sock_skel; - int cgroup_fd, err; - - cgroup_fd = test__join_cgroup("/mptcp"); - if (!ASSERT_GE(cgroup_fd, 0, "test__join_cgroup")) - return; - - sock_skel = mptcp_sock__open_and_load(); - if (!ASSERT_OK_PTR(sock_skel, "skel_open_load")) - goto out; - - err = mptcp_sock__attach(sock_skel); - if (!ASSERT_OK(err, "skel_attach")) - goto out; - - nstoken = create_netns(); - if (!ASSERT_OK_PTR(nstoken, "create_netns")) - goto fail; - - run_mptcp_sock(cgroup_fd, sock_skel); - -fail: - cleanup_netns(nstoken); - mptcp_sock__destroy(sock_skel); -out: - close(cgroup_fd); +#define MPTCP_BASE_TEST(name) \ +static void test_##name(void) \ +{ \ + struct nstoken *nstoken; \ + struct name *skel; \ + int cgroup_fd, err; \ + \ + cgroup_fd = test__join_cgroup("/" #name); \ + if (!ASSERT_GE(cgroup_fd, 0, "test__join_cgroup")) \ + return; \ + \ + skel = name##__open_and_load(); \ + if (!ASSERT_OK_PTR(skel, "skel_open_load")) \ + goto out; \ + \ + err = name##__attach(skel); \ + if (!ASSERT_OK(err, "skel_attach")) \ + goto out; \ + \ + nstoken = create_netns(); \ + if (!ASSERT_OK_PTR(nstoken, "create_netns")) \ + goto fail; \ + \ + run_##name(cgroup_fd, skel); \ + \ +fail: \ + cleanup_netns(nstoken); \ + name##__destroy(skel); \ +out: \ + close(cgroup_fd); \ } +MPTCP_BASE_TEST(mptcp_sock); + static void send_byte(int fd) { char b = 0x55; @@ -XXX,XX +XXX,XX @@ static void run_mptcpify(int cgroup_fd, struct mptcpify *skel) close(server_fd); } -static void test_mptcpify(void) -{ - struct nstoken *nstoken = NULL; - struct mptcpify *mptcpify_skel; - int cgroup_fd; - int err; - - cgroup_fd = test__join_cgroup("/mptcpify"); - if (!ASSERT_GE(cgroup_fd, 0, "test__join_cgroup")) - return; - - mptcpify_skel = mptcpify__open_and_load(); - if (!ASSERT_OK_PTR(mptcpify_skel, "skel_open_load")) - goto out; - - err = mptcpify__attach(mptcpify_skel); - if (!ASSERT_OK(err, "skel_attach")) - goto out; - - nstoken = create_netns(); - if (!ASSERT_OK_PTR(nstoken, "create_netns")) - goto fail; - - run_mptcpify(cgroup_fd, mptcpify_skel); - -fail: - cleanup_netns(nstoken); - mptcpify__destroy(mptcpify_skel); -out: - close(cgroup_fd); -} +MPTCP_BASE_TEST(mptcpify); static const unsigned int total_bytes = 10 * 1024 * 1024; static int stop, duration; -- 2.40.1
From: Geliang Tang <tanggeliang@kylinos.cn> Each MPTCP subtest tests test__start_subtest(suffix), then invokes test_suffix(). It makes sense to add a new macro RUN_MPTCP_TEST to simpolify the code. Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/bpf/prog_tests/mptcp.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -XXX,XX +XXX,XX @@ static void test_burst(void) mptcp_bpf_burst__destroy(burst_skel); } +#define RUN_MPTCP_TEST(suffix) \ +do { \ + if (test__start_subtest(#suffix)) \ + test_##suffix(); \ +} while (0) + void test_mptcp(void) { - if (test__start_subtest("mptcp_sock")) - test_mptcp_sock(); - if (test__start_subtest("mptcpify")) - test_mptcpify(); + RUN_MPTCP_TEST(mptcp_sock); + RUN_MPTCP_TEST(mptcpify); if (test__start_subtest("default")) test_default(); if (test__start_subtest("first")) -- 2.40.1
From: Geliang Tang <tanggeliang@kylinos.cn> Move Nicolas's patch into bpf selftests directory. This example added a test that was adding a different mark (SO_MARK) on each subflow, and changing the TCP CC only on the first subflow. This example shows how it is possible to: Identify the parent msk of an MPTCP subflow. Put different sockopt for each subflow of a same MPTCP connection. Here especially, we implemented two different behaviours: A socket mark (SOL_SOCKET SO_MARK) is put on each subflow of a same MPTCP connection. The order of creation of the current subflow defines its mark. The TCP CC algorithm of the very first subflow of an MPTCP connection is set to "reno". Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/76 Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- .../selftests/bpf/progs/mptcp_subflow.c | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/mptcp_subflow.c diff --git a/tools/testing/selftests/bpf/progs/mptcp_subflow.c b/tools/testing/selftests/bpf/progs/mptcp_subflow.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tools/testing/selftests/bpf/progs/mptcp_subflow.c @@ -XXX,XX +XXX,XX @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2020, Tessares SA. */ +/* Copyright (c) 2024, Kylin Software */ +/* Author: Nicolas Rybowski */ + +#include <sys/socket.h> // SOL_SOCKET, SO_MARK, ... +#include <linux/tcp.h> // TCP_CONGESTION +#include <linux/bpf.h> +#include <bpf/bpf_helpers.h> +#include "bpf_tcp_helpers.h" + +char _license[] SEC("license") = "GPL"; + +#ifndef SOL_TCP +#define SOL_TCP 6 +#endif + +#ifndef TCP_CA_NAME_MAX +#define TCP_CA_NAME_MAX 16 +#endif + +char cc[TCP_CA_NAME_MAX] = "reno"; + +/* Associate a subflow counter to each token */ +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(__u32)); + __uint(max_entries, 100); +} mptcp_sf SEC(".maps"); + +SEC("sockops") +int mptcp_subflow(struct bpf_sock_ops *skops) +{ + __u32 init = 1, key, mark, *cnt; + struct mptcp_sock *msk; + struct bpf_sock *sk; + int err; + + if (skops->op != BPF_SOCK_OPS_TCP_CONNECT_CB) + return 1; + + sk = skops->sk; + if (!sk) + return 1; + + msk = bpf_skc_to_mptcp_sock(sk); + if (!msk) + return 1; + + key = msk->token; + cnt = bpf_map_lookup_elem(&mptcp_sf, &key); + if (cnt) { + /* A new subflow is added to an existing MPTCP connection */ + __sync_fetch_and_add(cnt, 1); + mark = *cnt; + } else { + /* A new MPTCP connection is just initiated and this is its primary + * subflow + */ + bpf_map_update_elem(&mptcp_sf, &key, &init, BPF_ANY); + mark = init; + } + + /* Set the mark of the subflow's socket to its apparition order */ + err = bpf_setsockopt(skops, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)); + if (err < 0) + return 1; + if (mark == 1) + err = bpf_setsockopt(skops, SOL_TCP, TCP_CONGESTION, cc, TCP_CA_NAME_MAX); + + return 1; +} -- 2.40.1
From: Geliang Tang <tanggeliang@kylinos.cn> This patch adds a subtest named test_subflow to load and verify the newly added mptcp subflow example in test_mptcp. Add a helper endpoint_init() to add a new subflow endpoint. Add another helper ss_search() to verify the fwmark and congestion values set by mptcp_subflow prog using setsockopts. Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/76 Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- .../testing/selftests/bpf/prog_tests/mptcp.c | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -XXX,XX +XXX,XX @@ #include "network_helpers.h" #include "mptcp_sock.skel.h" #include "mptcpify.skel.h" +#include "mptcp_subflow.skel.h" #include "mptcp_bpf_first.skel.h" #include "mptcp_bpf_bkup.skel.h" #include "mptcp_bpf_rr.skel.h" @@ -XXX,XX +XXX,XX @@ static void run_mptcpify(int cgroup_fd, struct mptcpify *skel) MPTCP_BASE_TEST(mptcpify); +#define ADDR1 "10.0.1.1" +#define ADDR2 "10.0.1.2" +#define PORT1 10001 + +static int endpoint_init(char *flags) +{ + SYS(fail, "ip -net %s link add veth1 type veth peer name veth2", NS_TEST); + SYS(fail, "ip -net %s addr add %s/24 dev veth1", NS_TEST, ADDR1); + SYS(fail, "ip -net %s link set dev veth1 up", NS_TEST); + SYS(fail, "ip -net %s addr add %s/24 dev veth2", NS_TEST, ADDR2); + SYS(fail, "ip -net %s link set dev veth2 up", NS_TEST); + SYS(fail, "ip -net %s mptcp endpoint add %s %s", NS_TEST, ADDR2, flags); + + return 0; +fail: + return -1; +} + +static int _ss_search(char *src, char *dst, char *port, char *keyword) +{ + char cmd[128]; + + snprintf(cmd, sizeof(cmd), + "ip netns exec %s ss -Menita src %s dst %s %s %d | grep -q '%s'", + NS_TEST, src, dst, port, PORT1, keyword); + return system(cmd); +} + +static int ss_search(char *src, char *keyword) +{ + return _ss_search(src, ADDR1, "dport", keyword); +} + +static void run_mptcp_subflow(int cgroup_fd, struct mptcp_subflow *skel) +{ + int server_fd, client_fd, prog_fd, err; + + if (!ASSERT_OK(endpoint_init("subflow"), "endpoint_init")) + return; + + err = mptcp_subflow__attach(skel); + if (!ASSERT_OK(err, "skel_attach")) + return; + + prog_fd = bpf_program__fd(skel->progs.mptcp_subflow); + err = bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS, 0); + if (!ASSERT_OK(err, "prog_attach")) + return; + + server_fd = start_mptcp_server(AF_INET, ADDR1, PORT1, 0); + if (!ASSERT_GE(server_fd, 0, "start_mptcp_server")) + return; + + client_fd = connect_to_fd(server_fd, 0); + if (!ASSERT_GE(client_fd, 0, "connect to fd")) + goto close_server; + + send_byte(client_fd); + + ASSERT_OK(ss_search(ADDR1, "fwmark:0x1"), "ss_search fwmark:0x1"); + ASSERT_OK(ss_search(ADDR2, "fwmark:0x2"), "ss_search fwmark:0x2"); + ASSERT_OK(ss_search(ADDR1, "reno"), "ss_search reno"); + ASSERT_OK(ss_search(ADDR2, "cubic"), "ss_search cubic"); + + close(client_fd); +close_server: + close(server_fd); +} + +MPTCP_BASE_TEST(mptcp_subflow); + static const unsigned int total_bytes = 10 * 1024 * 1024; static int stop, duration; @@ -XXX,XX +XXX,XX @@ void test_mptcp(void) { RUN_MPTCP_TEST(mptcp_sock); RUN_MPTCP_TEST(mptcpify); + RUN_MPTCP_TEST(mptcp_subflow); if (test__start_subtest("default")) test_default(); if (test__start_subtest("first")) -- 2.40.1
From: Geliang Tang <tanggeliang@kylinos.cn> Some cleanups. Use ASSERT_EQ and ASSERT_OK like below commit: selftests/bpf: Replaces the usage of CHECK calls for ASSERTs in bpf_tcp_ca Use newly added endpoint_init and _ss_search helpers. Add send_data_and_verify helper. Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- .../testing/selftests/bpf/prog_tests/mptcp.c | 75 +++++++++++-------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -XXX,XX +XXX,XX @@ #include <linux/const.h> #include <netinet/in.h> #include <test_progs.h> -#include <time.h> #include "cgroup_helpers.h" #include "network_helpers.h" #include "mptcp_sock.skel.h" @@ -XXX,XX +XXX,XX @@ static void run_mptcp_subflow(int cgroup_fd, struct mptcp_subflow *skel) MPTCP_BASE_TEST(mptcp_subflow); static const unsigned int total_bytes = 10 * 1024 * 1024; -static int stop, duration; +static int stop; static void *server(void *arg) { @@ -XXX,XX +XXX,XX @@ static void *server(void *arg) bytes += nr_sent; } - CHECK(bytes != total_bytes, "send", "%zd != %u nr_sent:%zd errno:%d\n", - bytes, total_bytes, nr_sent, errno); + ASSERT_EQ(bytes, total_bytes, "send"); done: if (fd >= 0) @@ -XXX,XX +XXX,XX @@ static void send_data(int lfd, int fd, char *msg) int err; WRITE_ONCE(stop, 0); + if (clock_gettime(CLOCK_MONOTONIC, &start) < 0) return; err = pthread_create(&srv_thread, NULL, server, (void *)(long)lfd); - if (CHECK(err != 0, "pthread_create", "err:%d errno:%d\n", err, errno)) + if (!ASSERT_OK(err, "pthread_create")) return; /* recv total_bytes */ @@ -XXX,XX +XXX,XX @@ static void send_data(int lfd, int fd, char *msg) return; delta_ms = (end.tv_sec - start.tv_sec) * 1000 + (end.tv_nsec - start.tv_nsec) / 1000000; - - CHECK(bytes != total_bytes, "recv", "%zd != %u nr_recv:%zd errno:%d\n", - bytes, total_bytes, nr_recv, errno); - printf("%s: %u ms\n", msg, delta_ms); - WRITE_ONCE(stop, 1); + ASSERT_EQ(bytes, total_bytes, "recv"); + WRITE_ONCE(stop, 1); pthread_join(srv_thread, &thread_ret); - CHECK(IS_ERR(thread_ret), "pthread_join", "thread_ret:%ld", - PTR_ERR(thread_ret)); + ASSERT_OK(IS_ERR(thread_ret), "thread_ret"); } #define ADDR_1 "10.0.1.1" @@ -XXX,XX +XXX,XX @@ static struct nstoken *sched_init(char *flags, char *sched) nstoken = create_netns(); if (!ASSERT_OK_PTR(nstoken, "create_netns")) + return NULL; + + if (!ASSERT_OK(endpoint_init("subflow"), "endpoint_init")) goto fail; - SYS(fail, "ip -net %s link add veth1 type veth peer name veth2", NS_TEST); - SYS(fail, "ip -net %s addr add %s/24 dev veth1", NS_TEST, ADDR_1); - SYS(fail, "ip -net %s link set dev veth1 up", NS_TEST); - SYS(fail, "ip -net %s addr add %s/24 dev veth2", NS_TEST, ADDR_2); - SYS(fail, "ip -net %s link set dev veth2 up", NS_TEST); - SYS(fail, "ip -net %s mptcp endpoint add %s %s", NS_TEST, ADDR_2, flags); SYS(fail, "ip netns exec %s sysctl -qw net.mptcp.scheduler=%s", NS_TEST, sched); return nstoken; fail: + cleanup_netns(nstoken); return NULL; } -static int has_bytes_sent(char *addr) +static int has_bytes_sent(char *dst) { - char cmd[128]; + return _ss_search(ADDR1, dst, "sport", "bytes_sent:"); +} - snprintf(cmd, sizeof(cmd), "ip netns exec %s ss -it src %s sport %d dst %s | %s", - NS_TEST, ADDR_1, PORT_1, addr, "grep -q bytes_sent:"); - return system(cmd); +static void send_data_and_verify(char *msg, int addr1, int addr2) +{ + int server_fd, client_fd; + + server_fd = start_mptcp_server(AF_INET, ADDR1, PORT1, 0); + if (!ASSERT_NEQ(server_fd, -1, "start_mptcp_server")) + return; + + client_fd = connect_to_fd(server_fd, 0); + if (!ASSERT_NEQ(client_fd, -1, "connect_to_fd")) { + close(server_fd); + return; + } + + send_data(server_fd, client_fd, msg); + if (addr1) + ASSERT_OK(has_bytes_sent(ADDR1), "Should have bytes_sent on addr1"); + else + ASSERT_GT(has_bytes_sent(ADDR1), 0, "Shouldn't have bytes_sent on addr1"); + if (addr2) + ASSERT_OK(has_bytes_sent(ADDR2), "Should have bytes_sent on addr2"); + else + ASSERT_GT(has_bytes_sent(ADDR2), 0, "Shouldn't have bytes_sent on addr2"); + + close(client_fd); + close(server_fd); } static void test_default(void) { - int server_fd, client_fd; struct nstoken *nstoken; nstoken = sched_init("subflow", "default"); if (!ASSERT_OK_PTR(nstoken, "sched_init:default")) goto fail; - server_fd = start_mptcp_server(AF_INET, ADDR_1, PORT_1, 0); - client_fd = connect_to_fd(server_fd, 0); - send_data(server_fd, client_fd, "default"); - ASSERT_OK(has_bytes_sent(ADDR_1), "has_bytes_sent addr_1"); - ASSERT_OK(has_bytes_sent(ADDR_2), "has_bytes_sent addr_2"); + send_data_and_verify("default", 1, 1); - close(client_fd); - close(server_fd); fail: cleanup_netns(nstoken); } @@ -XXX,XX +XXX,XX @@ void test_mptcp(void) RUN_MPTCP_TEST(mptcp_sock); RUN_MPTCP_TEST(mptcpify); RUN_MPTCP_TEST(mptcp_subflow); - if (test__start_subtest("default")) - test_default(); + RUN_MPTCP_TEST(default); if (test__start_subtest("first")) test_first(); if (test__start_subtest("bkup")) -- 2.40.1
From: Geliang Tang <tanggeliang@kylinos.cn> Add MPTCP_SCHED_TEST macro. Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- .../testing/selftests/bpf/prog_tests/mptcp.c | 66 +++++++++---------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -XXX,XX +XXX,XX @@ static void test_default(void) cleanup_netns(nstoken); } -static void test_first(void) -{ - struct mptcp_bpf_first *first_skel; - int server_fd, client_fd; - struct nstoken *nstoken; - struct bpf_link *link; - - first_skel = mptcp_bpf_first__open_and_load(); - if (!ASSERT_OK_PTR(first_skel, "bpf_first__open_and_load")) - return; - - link = bpf_map__attach_struct_ops(first_skel->maps.first); - if (!ASSERT_OK_PTR(link, "bpf_map__attach_struct_ops")) { - mptcp_bpf_first__destroy(first_skel); - return; - } - - nstoken = sched_init("subflow", "bpf_first"); - if (!ASSERT_OK_PTR(nstoken, "sched_init:bpf_first")) - goto fail; - server_fd = start_mptcp_server(AF_INET, ADDR_1, PORT_1, 0); - client_fd = connect_to_fd(server_fd, 0); - - send_data(server_fd, client_fd, "bpf_first"); - ASSERT_OK(has_bytes_sent(ADDR_1), "has_bytes_sent addr_1"); - ASSERT_GT(has_bytes_sent(ADDR_2), 0, "has_bytes_sent addr_2"); - - close(client_fd); - close(server_fd); -fail: - cleanup_netns(nstoken); - bpf_link__destroy(link); - mptcp_bpf_first__destroy(first_skel); +#define MPTCP_SCHED_TEST(name, addr1, addr2) \ +static void test_##name(void) \ +{ \ + struct mptcp_bpf_##name *skel; \ + struct nstoken *nstoken; \ + struct bpf_link *link; \ + struct bpf_map *map; \ + \ + skel = mptcp_bpf_##name##__open_and_load(); \ + if (!ASSERT_OK_PTR(skel, "open_and_load:" #name)) \ + return; \ + \ + map = bpf_object__find_map_by_name(skel->obj, #name); \ + link = bpf_map__attach_struct_ops(map); \ + if (!ASSERT_OK_PTR(link, "attach_struct_ops:" #name)) \ + goto fail; \ + \ + nstoken = sched_init("subflow", "bpf_" #name); \ + if (!ASSERT_OK_PTR(nstoken, "sched_init:" #name)) \ + goto out; \ + \ + send_data_and_verify(#name, atoi(#addr1), atoi(#addr2));\ + \ + cleanup_netns(nstoken); \ +out: \ + bpf_link__destroy(link); \ +fail: \ + mptcp_bpf_##name##__destroy(skel); \ } +MPTCP_SCHED_TEST(first, 1, 0); + static void test_bkup(void) { struct mptcp_bpf_bkup *bkup_skel; @@ -XXX,XX +XXX,XX @@ void test_mptcp(void) RUN_MPTCP_TEST(mptcpify); RUN_MPTCP_TEST(mptcp_subflow); RUN_MPTCP_TEST(default); - if (test__start_subtest("first")) - test_first(); + RUN_MPTCP_TEST(first); if (test__start_subtest("bkup")) test_bkup(); if (test__start_subtest("rr")) -- 2.40.1
From: Geliang Tang <tanggeliang@kylinos.cn> Use MPTCP_SCHED_TEST and RUN_MPTCP_TEST. Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- .../testing/selftests/bpf/prog_tests/mptcp.c | 39 +------------------ 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -XXX,XX +XXX,XX @@ fail: \ } MPTCP_SCHED_TEST(first, 1, 0); - -static void test_bkup(void) -{ - struct mptcp_bpf_bkup *bkup_skel; - int server_fd, client_fd; - struct nstoken *nstoken; - struct bpf_link *link; - - bkup_skel = mptcp_bpf_bkup__open_and_load(); - if (!ASSERT_OK_PTR(bkup_skel, "bpf_bkup__open_and_load")) - return; - - link = bpf_map__attach_struct_ops(bkup_skel->maps.bkup); - if (!ASSERT_OK_PTR(link, "bpf_map__attach_struct_ops")) { - mptcp_bpf_bkup__destroy(bkup_skel); - return; - } - - nstoken = sched_init("subflow backup", "bpf_bkup"); - if (!ASSERT_OK_PTR(nstoken, "sched_init:bpf_bkup")) - goto fail; - server_fd = start_mptcp_server(AF_INET, ADDR_1, PORT_1, 0); - client_fd = connect_to_fd(server_fd, 0); - - send_data(server_fd, client_fd, "bpf_bkup"); - ASSERT_OK(has_bytes_sent(ADDR_1), "has_bytes_sent addr_1"); - ASSERT_GT(has_bytes_sent(ADDR_2), 0, "has_bytes_sent addr_2"); - - close(client_fd); - close(server_fd); -fail: - cleanup_netns(nstoken); - bpf_link__destroy(link); - mptcp_bpf_bkup__destroy(bkup_skel); -} +MPTCP_SCHED_TEST(bkup, 1, 0); static void test_rr(void) { @@ -XXX,XX +XXX,XX @@ void test_mptcp(void) RUN_MPTCP_TEST(mptcp_subflow); RUN_MPTCP_TEST(default); RUN_MPTCP_TEST(first); - if (test__start_subtest("bkup")) - test_bkup(); + RUN_MPTCP_TEST(bkup); if (test__start_subtest("rr")) test_rr(); if (test__start_subtest("red")) -- 2.40.1
From: Geliang Tang <tanggeliang@kylinos.cn> Use MPTCP_SCHED_TEST and RUN_MPTCP_TEST. Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- .../testing/selftests/bpf/prog_tests/mptcp.c | 39 +------------------ 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -XXX,XX +XXX,XX @@ fail: \ MPTCP_SCHED_TEST(first, 1, 0); MPTCP_SCHED_TEST(bkup, 1, 0); - -static void test_rr(void) -{ - struct mptcp_bpf_rr *rr_skel; - int server_fd, client_fd; - struct nstoken *nstoken; - struct bpf_link *link; - - rr_skel = mptcp_bpf_rr__open_and_load(); - if (!ASSERT_OK_PTR(rr_skel, "bpf_rr__open_and_load")) - return; - - link = bpf_map__attach_struct_ops(rr_skel->maps.rr); - if (!ASSERT_OK_PTR(link, "bpf_map__attach_struct_ops")) { - mptcp_bpf_rr__destroy(rr_skel); - return; - } - - nstoken = sched_init("subflow", "bpf_rr"); - if (!ASSERT_OK_PTR(nstoken, "sched_init:bpf_rr")) - goto fail; - server_fd = start_mptcp_server(AF_INET, ADDR_1, PORT_1, 0); - client_fd = connect_to_fd(server_fd, 0); - - send_data(server_fd, client_fd, "bpf_rr"); - ASSERT_OK(has_bytes_sent(ADDR_1), "has_bytes_sent addr 1"); - ASSERT_OK(has_bytes_sent(ADDR_2), "has_bytes_sent addr 2"); - - close(client_fd); - close(server_fd); -fail: - cleanup_netns(nstoken); - bpf_link__destroy(link); - mptcp_bpf_rr__destroy(rr_skel); -} +MPTCP_SCHED_TEST(rr, 1, 1); static void test_red(void) { @@ -XXX,XX +XXX,XX @@ void test_mptcp(void) RUN_MPTCP_TEST(default); RUN_MPTCP_TEST(first); RUN_MPTCP_TEST(bkup); - if (test__start_subtest("rr")) - test_rr(); + RUN_MPTCP_TEST(rr); if (test__start_subtest("red")) test_red(); if (test__start_subtest("burst")) -- 2.40.1
From: Geliang Tang <tanggeliang@kylinos.cn> Use MPTCP_SCHED_TEST and RUN_MPTCP_TEST. Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- .../testing/selftests/bpf/prog_tests/mptcp.c | 39 +------------------ 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -XXX,XX +XXX,XX @@ fail: \ MPTCP_SCHED_TEST(first, 1, 0); MPTCP_SCHED_TEST(bkup, 1, 0); MPTCP_SCHED_TEST(rr, 1, 1); - -static void test_red(void) -{ - struct mptcp_bpf_red *red_skel; - int server_fd, client_fd; - struct nstoken *nstoken; - struct bpf_link *link; - - red_skel = mptcp_bpf_red__open_and_load(); - if (!ASSERT_OK_PTR(red_skel, "bpf_red__open_and_load")) - return; - - link = bpf_map__attach_struct_ops(red_skel->maps.red); - if (!ASSERT_OK_PTR(link, "bpf_map__attach_struct_ops")) { - mptcp_bpf_red__destroy(red_skel); - return; - } - - nstoken = sched_init("subflow", "bpf_red"); - if (!ASSERT_OK_PTR(nstoken, "sched_init:bpf_red")) - goto fail; - server_fd = start_mptcp_server(AF_INET, ADDR_1, PORT_1, 0); - client_fd = connect_to_fd(server_fd, 0); - - send_data(server_fd, client_fd, "bpf_red"); - ASSERT_OK(has_bytes_sent(ADDR_1), "has_bytes_sent addr 1"); - ASSERT_OK(has_bytes_sent(ADDR_2), "has_bytes_sent addr 2"); - - close(client_fd); - close(server_fd); -fail: - cleanup_netns(nstoken); - bpf_link__destroy(link); - mptcp_bpf_red__destroy(red_skel); -} +MPTCP_SCHED_TEST(red, 1, 1); static void test_burst(void) { @@ -XXX,XX +XXX,XX @@ void test_mptcp(void) RUN_MPTCP_TEST(first); RUN_MPTCP_TEST(bkup); RUN_MPTCP_TEST(rr); - if (test__start_subtest("red")) - test_red(); + RUN_MPTCP_TEST(red); if (test__start_subtest("burst")) test_burst(); } -- 2.40.1
From: Geliang Tang <tanggeliang@kylinos.cn> Now all ADDR_1, ADDR_2 and PORT_1 are replaced by ADDR1, ADDR2 and PORT1, drop the definations of ADDR_1, ADDR_2, PORT_1. Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- .../testing/selftests/bpf/prog_tests/mptcp.c | 39 +------------------ 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -XXX,XX +XXX,XX @@ MPTCP_SCHED_TEST(first, 1, 0); MPTCP_SCHED_TEST(bkup, 1, 0); MPTCP_SCHED_TEST(rr, 1, 1); MPTCP_SCHED_TEST(red, 1, 1); - -static void test_burst(void) -{ - struct mptcp_bpf_burst *burst_skel; - int server_fd, client_fd; - struct nstoken *nstoken; - struct bpf_link *link; - - burst_skel = mptcp_bpf_burst__open_and_load(); - if (!ASSERT_OK_PTR(burst_skel, "bpf_burst__open_and_load")) - return; - - link = bpf_map__attach_struct_ops(burst_skel->maps.burst); - if (!ASSERT_OK_PTR(link, "bpf_map__attach_struct_ops")) { - mptcp_bpf_burst__destroy(burst_skel); - return; - } - - nstoken = sched_init("subflow", "bpf_burst"); - if (!ASSERT_OK_PTR(nstoken, "sched_init:bpf_burst")) - goto fail; - server_fd = start_mptcp_server(AF_INET, ADDR_1, PORT_1, 0); - client_fd = connect_to_fd(server_fd, 0); - - send_data(server_fd, client_fd, "bpf_burst"); - ASSERT_OK(has_bytes_sent(ADDR_1), "has_bytes_sent addr 1"); - ASSERT_OK(has_bytes_sent(ADDR_2), "has_bytes_sent addr 2"); - - close(client_fd); - close(server_fd); -fail: - cleanup_netns(nstoken); - bpf_link__destroy(link); - mptcp_bpf_burst__destroy(burst_skel); -} +MPTCP_SCHED_TEST(burst, 1, 1); #define RUN_MPTCP_TEST(suffix) \ do { \ @@ -XXX,XX +XXX,XX @@ void test_mptcp(void) RUN_MPTCP_TEST(bkup); RUN_MPTCP_TEST(rr); RUN_MPTCP_TEST(red); - if (test__start_subtest("burst")) - test_burst(); + RUN_MPTCP_TEST(burst); } -- 2.40.1
From: Geliang Tang <tanggeliang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/bpf/prog_tests/mptcp.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -XXX,XX +XXX,XX @@ static void send_data(int lfd, int fd, char *msg) ASSERT_OK(IS_ERR(thread_ret), "thread_ret"); } -#define ADDR_1 "10.0.1.1" -#define ADDR_2 "10.0.1.2" -#define PORT_1 10001 - static struct nstoken *sched_init(char *flags, char *sched) { struct nstoken *nstoken; -- 2.40.1
From: Geliang Tang <tanggeliang@kylinos.cn> v9: - validate the return value of snprintf in patch 2 as Mat suggested. - patch 2 depends on "selftests/bpf: Add RUN_MPTCP_TEST macro", so this series could be merged in this order: 1 selftests/bpf: Add mptcp subflow example 2 selftests/bpf: Add RUN_MPTCP_TEST macro 3 selftests/bpf: Add mptcp subflow subtest 4 selftests/bpf: Handle SIGINT when creating netns v8: - update the git metadata to add Nicolas as the git "Author" and add a "Co-authored-by" tag with my name in patch 1 as Mat suggested in v7. - use send_byte in patch 2 instead of send_recv_data, to make this series independent of the commit "selftests/bpf: Export send_recv_data helper", which is in bpf-next, but not in mptcp_net-next at this moment. v7: - address Mat's comments in v6 (thanks): drop MPTCP_BASE_TEST and rebased. - depends on: "refactor mptcp bpf tests" v7 "export send_byte and send_recv_data" v2 v6: - Deponds on "[bpf-next] export send_byte and send_recv_data" series. v5: - #1-#7 Address #76: add new macros MPTCP_BASE_TEST and RUN_MPTCP_TEST. - #8-#14 add MPTCP_SCHED_TEST macro. v4: - #1-#5 Address #76: add a new macro RUN_MPTCP_TEST. - #6-#11 Cleanups: add send_data_and_verify and SCHED_TEST. v3: - deal with EAGAIN. - add _ss_search helper. v2: - fix checkpatch warnings. - cleanups. Geliang Tang (3): selftests/bpf: Add mptcp subflow subtest selftests/bpf: Handle SIGINT when creating netns Squash to "selftests/bpf: Add bpf scheduler test" Nicolas Rybowski (1): selftests/bpf: Add mptcp subflow example .../testing/selftests/bpf/prog_tests/mptcp.c | 143 +++++++++++++++--- .../selftests/bpf/progs/mptcp_subflow.c | 70 +++++++++ 2 files changed, 195 insertions(+), 18 deletions(-) create mode 100644 tools/testing/selftests/bpf/progs/mptcp_subflow.c -- 2.40.1
From: Nicolas Rybowski <nicolas.rybowski@tessares.net> Move Nicolas's patch into bpf selftests directory. This example added a test that was adding a different mark (SO_MARK) on each subflow, and changing the TCP CC only on the first subflow. This example shows how it is possible to: Identify the parent msk of an MPTCP subflow. Put different sockopt for each subflow of a same MPTCP connection. Here especially, we implemented two different behaviours: A socket mark (SOL_SOCKET SO_MARK) is put on each subflow of a same MPTCP connection. The order of creation of the current subflow defines its mark. The TCP CC algorithm of the very first subflow of an MPTCP connection is set to "reno". The code comes from commit 4d120186e4d6 ("bpf:examples: update mptcp_set_mark_kern.c") in MPTCP repo https://github.com/multipath-tcp/mptcp_net-next (the "scripts" branch). Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/76 Co-developed-by: Geliang Tang <tanggeliang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> Signed-off-by: Nicolas Rybowski <nicolas.rybowski@tessares.net> --- .../selftests/bpf/progs/mptcp_subflow.c | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/mptcp_subflow.c diff --git a/tools/testing/selftests/bpf/progs/mptcp_subflow.c b/tools/testing/selftests/bpf/progs/mptcp_subflow.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tools/testing/selftests/bpf/progs/mptcp_subflow.c @@ -XXX,XX +XXX,XX @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2020, Tessares SA. */ +/* Copyright (c) 2024, Kylin Software */ + +#include <sys/socket.h> // SOL_SOCKET, SO_MARK, ... +#include <linux/tcp.h> // TCP_CONGESTION +#include <linux/bpf.h> +#include <bpf/bpf_helpers.h> +#include "bpf_tcp_helpers.h" + +char _license[] SEC("license") = "GPL"; + +#ifndef SOL_TCP +#define SOL_TCP 6 +#endif + +#ifndef TCP_CA_NAME_MAX +#define TCP_CA_NAME_MAX 16 +#endif + +char cc[TCP_CA_NAME_MAX] = "reno"; + +/* Associate a subflow counter to each token */ +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(__u32)); + __uint(max_entries, 100); +} mptcp_sf SEC(".maps"); + +SEC("sockops") +int mptcp_subflow(struct bpf_sock_ops *skops) +{ + __u32 init = 1, key, mark, *cnt; + struct mptcp_sock *msk; + struct bpf_sock *sk; + int err; + + if (skops->op != BPF_SOCK_OPS_TCP_CONNECT_CB) + return 1; + + sk = skops->sk; + if (!sk) + return 1; + + msk = bpf_skc_to_mptcp_sock(sk); + if (!msk) + return 1; + + key = msk->token; + cnt = bpf_map_lookup_elem(&mptcp_sf, &key); + if (cnt) { + /* A new subflow is added to an existing MPTCP connection */ + __sync_fetch_and_add(cnt, 1); + mark = *cnt; + } else { + /* A new MPTCP connection is just initiated and this is its primary subflow */ + bpf_map_update_elem(&mptcp_sf, &key, &init, BPF_ANY); + mark = init; + } + + /* Set the mark of the subflow's socket based on appearance order */ + err = bpf_setsockopt(skops, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)); + if (err < 0) + return 1; + if (mark == 1) + err = bpf_setsockopt(skops, SOL_TCP, TCP_CONGESTION, cc, TCP_CA_NAME_MAX); + + return 1; +} -- 2.40.1
From: Geliang Tang <tanggeliang@kylinos.cn> This patch adds a subtest named test_subflow to load and verify the newly added mptcp subflow example in test_mptcp. Add a helper endpoint_init() to add a new subflow endpoint. Add another helper ss_search() to verify the fwmark and congestion values set by mptcp_subflow prog using setsockopts. Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/76 Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- .../testing/selftests/bpf/prog_tests/mptcp.c | 118 +++++++++++++++++- 1 file changed, 112 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -XXX,XX +XXX,XX @@ #include "network_helpers.h" #include "mptcp_sock.skel.h" #include "mptcpify.skel.h" +#include "mptcp_subflow.skel.h" #include "mptcp_bpf_first.skel.h" #include "mptcp_bpf_bkup.skel.h" #include "mptcp_bpf_rr.skel.h" @@ -XXX,XX +XXX,XX @@ #include "mptcp_bpf_burst.skel.h" #define NS_TEST "mptcp_ns" +#define ADDR_1 "10.0.1.1" +#define ADDR_2 "10.0.1.2" +#define PORT_1 10001 #define WITH_DATA true #define WITHOUT_DATA false @@ -XXX,XX +XXX,XX @@ #endif #define MPTCP_SCHED_NAME_MAX 16 +static const unsigned int total_bytes = 10 * 1024 * 1024; +static int duration; + struct __mptcp_info { __u8 mptcpi_subflows; __u8 mptcpi_add_addr_signal; @@ -XXX,XX +XXX,XX @@ static void test_mptcpify(void) close(cgroup_fd); } -static const unsigned int total_bytes = 10 * 1024 * 1024; -static int stop, duration; +static int endpoint_init(char *flags) +{ + SYS(fail, "ip -net %s link add veth1 type veth peer name veth2", NS_TEST); + SYS(fail, "ip -net %s addr add %s/24 dev veth1", NS_TEST, ADDR_1); + SYS(fail, "ip -net %s link set dev veth1 up", NS_TEST); + SYS(fail, "ip -net %s addr add %s/24 dev veth2", NS_TEST, ADDR_2); + SYS(fail, "ip -net %s link set dev veth2 up", NS_TEST); + SYS(fail, "ip -net %s mptcp endpoint add %s %s", NS_TEST, ADDR_2, flags); + + return 0; +fail: + return -1; +} + +static int _ss_search(char *src, char *dst, char *port, char *keyword) +{ + char cmd[128]; + int n; + + n = snprintf(cmd, sizeof(cmd), + "ip netns exec %s ss -Menita src %s dst %s %s %d | grep -q '%s'", + NS_TEST, src, dst, port, PORT_1, keyword); + if (n < 0 || n >= sizeof(cmd)) + return -1; + + return system(cmd); +} + +static int ss_search(char *src, char *keyword) +{ + return _ss_search(src, ADDR_1, "dport", keyword); +} + +static void run_subflow(char *new) +{ + int server_fd, client_fd, err; + char cc[TCP_CA_NAME_MAX]; + socklen_t len = sizeof(cc); + + server_fd = start_mptcp_server(AF_INET, ADDR_1, PORT_1, 0); + if (!ASSERT_GE(server_fd, 0, "start_mptcp_server")) + return; + + client_fd = connect_to_fd(server_fd, 0); + if (!ASSERT_GE(client_fd, 0, "connect to fd")) + goto fail; + + err = getsockopt(server_fd, SOL_TCP, TCP_CONGESTION, cc, &len); + if (!ASSERT_OK(err, "getsockopt(srv_fd, TCP_CONGESTION)")) + goto fail; + + send_byte(client_fd); + + ASSERT_OK(ss_search(ADDR_1, "fwmark:0x1"), "ss_search fwmark:0x1"); + ASSERT_OK(ss_search(ADDR_2, "fwmark:0x2"), "ss_search fwmark:0x2"); + ASSERT_OK(ss_search(ADDR_1, new), "ss_search new cc"); + ASSERT_OK(ss_search(ADDR_2, cc), "ss_search default cc"); + + close(client_fd); +fail: + close(server_fd); +} + +static void test_subflow(void) +{ + int cgroup_fd, prog_fd, err; + struct mptcp_subflow *skel; + struct nstoken *nstoken; + + cgroup_fd = test__join_cgroup("/mptcp_subflow"); + if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup: mptcp_subflow")) + return; + + skel = mptcp_subflow__open_and_load(); + if (!ASSERT_OK_PTR(skel, "skel_open_load: mptcp_subflow")) + goto close_cgroup; + + err = mptcp_subflow__attach(skel); + if (!ASSERT_OK(err, "skel_attach: mptcp_subflow")) + goto skel_destroy; + + prog_fd = bpf_program__fd(skel->progs.mptcp_subflow); + err = bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS, 0); + if (!ASSERT_OK(err, "prog_attach")) + goto skel_destroy; + + nstoken = create_netns(); + if (!ASSERT_OK_PTR(nstoken, "create_netns: mptcp_subflow")) + goto skel_destroy; + + if (!ASSERT_OK(endpoint_init("subflow"), "endpoint_init")) + goto close_netns; + + run_subflow(skel->data->cc); + +close_netns: + cleanup_netns(nstoken); +skel_destroy: + mptcp_subflow__destroy(skel); +close_cgroup: + close(cgroup_fd); +} + +static int stop; static void *server(void *arg) { @@ -XXX,XX +XXX,XX @@ static void send_data(int lfd, int fd, char *msg) PTR_ERR(thread_ret)); } -#define ADDR_1 "10.0.1.1" -#define ADDR_2 "10.0.1.2" -#define PORT_1 10001 - static struct nstoken *sched_init(char *flags, char *sched) { struct nstoken *nstoken; @@ -XXX,XX +XXX,XX @@ void test_mptcp(void) { RUN_MPTCP_TEST(base); RUN_MPTCP_TEST(mptcpify); + RUN_MPTCP_TEST(subflow); RUN_MPTCP_TEST(default); RUN_MPTCP_TEST(first); RUN_MPTCP_TEST(bkup); -- 2.40.1
From: Geliang Tang <tanggeliang@kylinos.cn> It's necessary to delete netns during the MPTCP bpf tests interrupt, otherwise the next tests run will fail due to unable to create netns. This patch adds a new SIGINT handle sig_int, and deletes NS_TEST in it. Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/bpf/prog_tests/mptcp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -XXX,XX +XXX,XX @@ struct mptcp_storage { char ca_name[TCP_CA_NAME_MAX]; }; +static void sig_int(int sig) +{ + signal(sig, SIG_IGN); + SYS_NOFAIL("ip netns del %s", NS_TEST); +} + static struct nstoken *create_netns(void) { SYS(fail, "ip netns add %s", NS_TEST); SYS(fail, "ip -net %s link set dev lo up", NS_TEST); + signal(SIGINT, sig_int); return open_netns(NS_TEST); fail: return NULL; -- 2.40.1
From: Geliang Tang <tanggeliang@kylinos.cn> Use endpoint_init in sched_init and use _ss_search in has_bytes_sent. Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/bpf/prog_tests/mptcp.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -XXX,XX +XXX,XX @@ static struct nstoken *sched_init(char *flags, char *sched) nstoken = create_netns(); if (!ASSERT_OK_PTR(nstoken, "create_netns")) + return NULL; + + if (!ASSERT_OK(endpoint_init("subflow"), "endpoint_init")) goto fail; - SYS(fail, "ip -net %s link add veth1 type veth peer name veth2", NS_TEST); - SYS(fail, "ip -net %s addr add %s/24 dev veth1", NS_TEST, ADDR_1); - SYS(fail, "ip -net %s link set dev veth1 up", NS_TEST); - SYS(fail, "ip -net %s addr add %s/24 dev veth2", NS_TEST, ADDR_2); - SYS(fail, "ip -net %s link set dev veth2 up", NS_TEST); - SYS(fail, "ip -net %s mptcp endpoint add %s %s", NS_TEST, ADDR_2, flags); SYS(fail, "ip netns exec %s sysctl -qw net.mptcp.scheduler=%s", NS_TEST, sched); return nstoken; fail: + cleanup_netns(nstoken); return NULL; } -static int has_bytes_sent(char *addr) +static int has_bytes_sent(char *dst) { - char cmd[128]; - - snprintf(cmd, sizeof(cmd), "ip netns exec %s ss -it src %s sport %d dst %s | %s", - NS_TEST, ADDR_1, PORT_1, addr, "grep -q bytes_sent:"); - return system(cmd); + return _ss_search(ADDR_1, dst, "sport", "bytes_sent:"); } static void send_data_and_verify(char *sched, bool addr1, bool addr2) -- 2.40.1