From ce98d0f4063e3bc0172f2ab20fbfe05210784776 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 22 Mar 2024 16:22:16 +0800 Subject: [PATCH] Squash to "selftests/bpf: Add bpf_first test" ''' This patch extends the MPTCP test base to support MPTCP packet scheduler tests. Add a new test to use the default in-kernel scheduler. In the new helper sched_init(), invoke create_netns() to create a net namespace, and invoke endpoint_init() to add two veth net devices to simulate the multiple addresses case and add the new endpoint ADDR_2 to PM netlink. Use sysctl to set net.mptcp.scheduler to use the given sched. Invoke start_mptcp_server() to start the server on ADDR_1, and invoke connect_to_fd() to connect with the server from the client. Then invoke send_data() to send data. Some code in send_data() is from prog_tests/bpf_tcp_ca.c. Add time metrics for BPF tests to compare the performance of each schedulers. Run prog_tests with '-v' option can print out the running time of each test. Use the new helper has_bytes_sent() to check the bytes_sent filed of 'ss' output after send_data() to make sure no data has been sent on ADDR_2. All data has been sent on the first subflow. Invoke the new helper sched_cleanup() to set back net.mptcp.scheduler to default, flush all mptcp endpoints, and delete the veth net devices. Then this patch adds the bpf_first scheduler test: test_first(). Use sysctl to set net.mptcp.scheduler to use this sched. Add two veth net devices to simulate the multiple addresses case. Use 'ip mptcp endpoint' command to add the new endpoint ADDR_2 to PM netlink. Send data and check bytes_sent of 'ss' output after it to make sure the data has been only sent on the first subflow ADDR_1. ''' Signed-off-by: Geliang Tang --- .../testing/selftests/bpf/prog_tests/mptcp.c | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c index 30f8dc0a3060..e08d46baae2b 100644 --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "cgroup_helpers.h" #include "network_helpers.h" #include "mptcp_sock.skel.h" @@ -415,6 +416,125 @@ void test_subflow(void) close(cgroup_fd); } +static const unsigned int total_bytes = 10 * 1024 * 1024; +static int stop; + +static void *server(void *arg) +{ + int lfd = (int)(long)arg, err = 0, fd; + ssize_t nr_sent = 0, bytes = 0; + char batch[1500]; + + fd = accept(lfd, NULL, NULL); + while (fd == -1) { + if (errno == EINTR) + continue; + err = -errno; + goto done; + } + + if (settimeo(fd, 0)) { + err = -errno; + goto done; + } + + 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) + continue; + if (nr_sent == -1) { + err = -errno; + break; + } + bytes += nr_sent; + } + + ASSERT_EQ(bytes, total_bytes, "send"); + +done: + if (fd >= 0) + close(fd); + if (err) { + WRITE_ONCE(stop, 1); + return ERR_PTR(err); + } + return NULL; +} + +static void send_data(int lfd, int fd, char *msg) +{ + ssize_t nr_recv = 0, bytes = 0; + struct timespec start, end; + unsigned int delta_ms; + pthread_t srv_thread; + void *thread_ret; + char batch[1500]; + 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 (!ASSERT_OK(err, "pthread_create")) + return; + + /* recv total_bytes */ + 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) + continue; + if (nr_recv == -1) + break; + bytes += nr_recv; + } + + if (clock_gettime(CLOCK_MONOTONIC, &end) < 0) + return; + + delta_ms = (end.tv_sec - start.tv_sec) * 1000 + (end.tv_nsec - start.tv_nsec) / 1000000; + + ASSERT_EQ(bytes, total_bytes, "recv"); + + printf("%s: %u ms\n", msg, delta_ms); + + WRITE_ONCE(stop, 1); + + pthread_join(srv_thread, &thread_ret); + ASSERT_OK(IS_ERR(thread_ret), "thread_ret"); +} + +static struct nstoken *sched_init(char *flags, char *sched) +{ + struct nstoken *nstoken; + + nstoken = create_netns(); + if (!ASSERT_OK_PTR(nstoken, "create_netns")) + goto fail; + + if (!ASSERT_OK(endpoint_init("subflow"), "endpoint_init")) + goto fail; + + SYS(fail, "ip netns exec %s sysctl -qw net.mptcp.scheduler=%s", NS_TEST, sched); + + return nstoken; +fail: + return NULL; +} + +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, dst, "grep -q bytes_sent:"); + return system(cmd); +} + static void test_first(void) { struct mptcp_bpf_first *first_skel;