From aaf376bddf68d0afe5f4b5f25fc555da358e2287 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 3 Nov 2020 13:34:48 -0800 Subject: [PATCH 1/5] selftests/bpf: Move test_tcppbf_user into test_progs Recently a bug was missed due to the fact that test_tcpbpf_user is not a part of test_progs. In order to prevent similar issues in the future move the test functionality into test_progs. By doing this we can make certain that it is a part of standard testing and will not be overlooked. As a part of moving the functionality into test_progs it is necessary to integrate with the test_progs framework and to drop any redundant code. This patch: 1. Cleans up the include headers 2. Dropped a duplicate definition of bpf_find_map 3. Switched over to using test_progs specific cgroup functions 4. Renamed main to test_tcpbpf_user 5. Dropped return value in favor of CHECK_FAIL to check for errors The general idea is that I wanted to keep the changes as small as possible while moving the file into the test_progs framework. The follow-on patches are meant to clean up the remaining issues such as the use of CHECK_FAIL. Signed-off-by: Alexander Duyck Signed-off-by: Alexei Starovoitov Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/160443928881.1086697.17661359319919165370.stgit@localhost.localdomain --- tools/testing/selftests/bpf/.gitignore | 1 - tools/testing/selftests/bpf/Makefile | 3 +- .../tcpbpf_user.c} | 42 ++++--------------- 3 files changed, 10 insertions(+), 36 deletions(-) rename tools/testing/selftests/bpf/{test_tcpbpf_user.c => prog_tests/tcpbpf_user.c} (81%) diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore index 3ab1200e172f..395ae040ce1f 100644 --- a/tools/testing/selftests/bpf/.gitignore +++ b/tools/testing/selftests/bpf/.gitignore @@ -8,7 +8,6 @@ FEATURE-DUMP.libbpf fixdep test_dev_cgroup /test_progs* -test_tcpbpf_user test_verifier_log feature test_sock diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 542768f5195b..50e5b18fc455 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -32,7 +32,7 @@ LDLIBS += -lcap -lelf -lz -lrt -lpthread # Order correspond to 'make run_tests' order TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ - test_verifier_log test_dev_cgroup test_tcpbpf_user \ + test_verifier_log test_dev_cgroup \ test_sock test_sockmap get_cgroup_id_user test_socket_cookie \ test_cgroup_storage \ test_netcnt test_tcpnotify_user test_sysctl \ @@ -163,7 +163,6 @@ $(OUTPUT)/test_sock: cgroup_helpers.c $(OUTPUT)/test_sock_addr: cgroup_helpers.c $(OUTPUT)/test_socket_cookie: cgroup_helpers.c $(OUTPUT)/test_sockmap: cgroup_helpers.c -$(OUTPUT)/test_tcpbpf_user: cgroup_helpers.c $(OUTPUT)/test_tcpnotify_user: cgroup_helpers.c trace_helpers.c $(OUTPUT)/get_cgroup_id_user: cgroup_helpers.c $(OUTPUT)/test_cgroup_storage: cgroup_helpers.c diff --git a/tools/testing/selftests/bpf/test_tcpbpf_user.c b/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c similarity index 81% rename from tools/testing/selftests/bpf/test_tcpbpf_user.c rename to tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c index 74a9e49988b6..caa8d3adec8a 100644 --- a/tools/testing/selftests/bpf/test_tcpbpf_user.c +++ b/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c @@ -1,21 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 #include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bpf_rlimit.h" -#include "bpf_util.h" -#include "cgroup_helpers.h" +#include #include "test_tcpbpf.h" +#define CG_NAME "/tcpbpf-user-test" + /* 3 comes from one listening socket + both ends of the connection */ #define EXPECTED_CLOSE_EVENTS 3 @@ -76,25 +66,11 @@ int verify_sockopt_result(int sock_map_fd) return ret; } -static int bpf_find_map(const char *test, struct bpf_object *obj, - const char *name) -{ - struct bpf_map *map; - - map = bpf_object__find_map_by_name(obj, name); - if (!map) { - printf("%s:FAIL:map '%s' not found\n", test, name); - return -1; - } - return bpf_map__fd(map); -} - -int main(int argc, char **argv) +void test_tcpbpf_user(void) { const char *file = "test_tcpbpf_kern.o"; int prog_fd, map_fd, sock_map_fd; struct tcpbpf_globals g = {0}; - const char *cg_path = "/foo"; int error = EXIT_FAILURE; struct bpf_object *obj; int cg_fd = -1; @@ -102,7 +78,7 @@ int main(int argc, char **argv) __u32 key = 0; int rv; - cg_fd = cgroup_setup_and_join(cg_path); + cg_fd = test__join_cgroup(CG_NAME); if (cg_fd < 0) goto err; @@ -155,11 +131,11 @@ retry_lookup: goto err; } - printf("PASSED!\n"); error = 0; err: bpf_prog_detach(cg_fd, BPF_CGROUP_SOCK_OPS); - close(cg_fd); - cleanup_cgroup_environment(); - return error; + if (cg_fd != -1) + close(cg_fd); + + CHECK_FAIL(error); } From 247f0ec361b7e0c5c67db8222873182fb8be5146 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 3 Nov 2020 13:34:56 -0800 Subject: [PATCH 2/5] selftests/bpf: Drop python client/server in favor of threads Drop the tcp_client/server.py files in favor of using a client and server thread within the test case. Specifically we spawn a new thread to play the role of the server, and the main testing thread plays the role of client. Add logic to the end of the run_test function to guarantee that the sockets are closed when we begin verifying results. Doing this we are able to reduce overhead since we don't have two python workers possibly floating around. In addition we don't have to worry about synchronization issues and as such the retry loop waiting for the threads to close the sockets can be dropped as we will have already closed the sockets in the local executable and synchronized the server thread. Signed-off-by: Alexander Duyck Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/160443929638.1086697.2430242340980315521.stgit@localhost.localdomain --- .../selftests/bpf/prog_tests/tcpbpf_user.c | 95 +++++++++++++++---- tools/testing/selftests/bpf/tcp_client.py | 50 ---------- tools/testing/selftests/bpf/tcp_server.py | 80 ---------------- 3 files changed, 78 insertions(+), 147 deletions(-) delete mode 100755 tools/testing/selftests/bpf/tcp_client.py delete mode 100755 tools/testing/selftests/bpf/tcp_server.py diff --git a/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c b/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c index caa8d3adec8a..616269abdb41 100644 --- a/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c +++ b/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c @@ -1,13 +1,14 @@ // SPDX-License-Identifier: GPL-2.0 #include #include +#include #include "test_tcpbpf.h" +#define LO_ADDR6 "::1" #define CG_NAME "/tcpbpf-user-test" -/* 3 comes from one listening socket + both ends of the connection */ -#define EXPECTED_CLOSE_EVENTS 3 +static __u32 duration; #define EXPECT_EQ(expected, actual, fmt) \ do { \ @@ -42,7 +43,9 @@ int verify_result(const struct tcpbpf_globals *result) EXPECT_EQ(0x80, result->bad_cb_test_rv, PRIu32); EXPECT_EQ(0, result->good_cb_test_rv, PRIu32); EXPECT_EQ(1, result->num_listen, PRIu32); - EXPECT_EQ(EXPECTED_CLOSE_EVENTS, result->num_close_events, PRIu32); + + /* 3 comes from one listening socket + both ends of the connection */ + EXPECT_EQ(3, result->num_close_events, PRIu32); return ret; } @@ -66,6 +69,75 @@ int verify_sockopt_result(int sock_map_fd) return ret; } +static int run_test(void) +{ + int listen_fd = -1, cli_fd = -1, accept_fd = -1; + char buf[1000]; + int err = -1; + int i, rv; + + listen_fd = start_server(AF_INET6, SOCK_STREAM, LO_ADDR6, 0, 0); + if (CHECK(listen_fd == -1, "start_server", "listen_fd:%d errno:%d\n", + listen_fd, errno)) + goto done; + + cli_fd = connect_to_fd(listen_fd, 0); + if (CHECK(cli_fd == -1, "connect_to_fd(listen_fd)", + "cli_fd:%d errno:%d\n", cli_fd, errno)) + goto done; + + accept_fd = accept(listen_fd, NULL, NULL); + if (CHECK(accept_fd == -1, "accept(listen_fd)", + "accept_fd:%d errno:%d\n", accept_fd, errno)) + goto done; + + /* Send 1000B of '+'s from cli_fd -> accept_fd */ + for (i = 0; i < 1000; i++) + buf[i] = '+'; + + rv = send(cli_fd, buf, 1000, 0); + if (CHECK(rv != 1000, "send(cli_fd)", "rv:%d errno:%d\n", rv, errno)) + goto done; + + rv = recv(accept_fd, buf, 1000, 0); + if (CHECK(rv != 1000, "recv(accept_fd)", "rv:%d errno:%d\n", rv, errno)) + goto done; + + /* Send 500B of '.'s from accept_fd ->cli_fd */ + for (i = 0; i < 500; i++) + buf[i] = '.'; + + rv = send(accept_fd, buf, 500, 0); + if (CHECK(rv != 500, "send(accept_fd)", "rv:%d errno:%d\n", rv, errno)) + goto done; + + rv = recv(cli_fd, buf, 500, 0); + if (CHECK(rv != 500, "recv(cli_fd)", "rv:%d errno:%d\n", rv, errno)) + goto done; + + /* + * shutdown accept first to guarantee correct ordering for + * bytes_received and bytes_acked when we go to verify the results. + */ + shutdown(accept_fd, SHUT_WR); + err = recv(cli_fd, buf, 1, 0); + if (CHECK(err, "recv(cli_fd) for fin", "err:%d errno:%d\n", err, errno)) + goto done; + + shutdown(cli_fd, SHUT_WR); + err = recv(accept_fd, buf, 1, 0); + CHECK(err, "recv(accept_fd) for fin", "err:%d errno:%d\n", err, errno); +done: + if (accept_fd != -1) + close(accept_fd); + if (cli_fd != -1) + close(cli_fd); + if (listen_fd != -1) + close(listen_fd); + + return err; +} + void test_tcpbpf_user(void) { const char *file = "test_tcpbpf_kern.o"; @@ -74,7 +146,6 @@ void test_tcpbpf_user(void) int error = EXIT_FAILURE; struct bpf_object *obj; int cg_fd = -1; - int retry = 10; __u32 key = 0; int rv; @@ -94,11 +165,6 @@ void test_tcpbpf_user(void) goto err; } - if (system("./tcp_server.py")) { - printf("FAILED: TCP server\n"); - goto err; - } - map_fd = bpf_find_map(__func__, obj, "global_map"); if (map_fd < 0) goto err; @@ -107,20 +173,15 @@ void test_tcpbpf_user(void) if (sock_map_fd < 0) goto err; -retry_lookup: + if (run_test()) + goto err; + rv = bpf_map_lookup_elem(map_fd, &key, &g); if (rv != 0) { printf("FAILED: bpf_map_lookup_elem returns %d\n", rv); goto err; } - if (g.num_close_events != EXPECTED_CLOSE_EVENTS && retry--) { - printf("Unexpected number of close events (%d), retrying!\n", - g.num_close_events); - usleep(100); - goto retry_lookup; - } - if (verify_result(&g)) { printf("FAILED: Wrong stats\n"); goto err; diff --git a/tools/testing/selftests/bpf/tcp_client.py b/tools/testing/selftests/bpf/tcp_client.py deleted file mode 100755 index bfff82be3fc1..000000000000 --- a/tools/testing/selftests/bpf/tcp_client.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 -# -# SPDX-License-Identifier: GPL-2.0 -# - -import sys, os, os.path, getopt -import socket, time -import subprocess -import select - -def read(sock, n): - buf = b'' - while len(buf) < n: - rem = n - len(buf) - try: s = sock.recv(rem) - except (socket.error) as e: return b'' - buf += s - return buf - -def send(sock, s): - total = len(s) - count = 0 - while count < total: - try: n = sock.send(s) - except (socket.error) as e: n = 0 - if n == 0: - return count; - count += n - return count - - -serverPort = int(sys.argv[1]) - -# create active socket -sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) -try: - sock.connect(('::1', serverPort)) -except socket.error as e: - sys.exit(1) - -buf = b'' -n = 0 -while n < 1000: - buf += b'+' - n += 1 - -sock.settimeout(1); -n = send(sock, buf) -n = read(sock, 500) -sys.exit(0) diff --git a/tools/testing/selftests/bpf/tcp_server.py b/tools/testing/selftests/bpf/tcp_server.py deleted file mode 100755 index 42ab8882f00f..000000000000 --- a/tools/testing/selftests/bpf/tcp_server.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python3 -# -# SPDX-License-Identifier: GPL-2.0 -# - -import sys, os, os.path, getopt -import socket, time -import subprocess -import select - -def read(sock, n): - buf = b'' - while len(buf) < n: - rem = n - len(buf) - try: s = sock.recv(rem) - except (socket.error) as e: return b'' - buf += s - return buf - -def send(sock, s): - total = len(s) - count = 0 - while count < total: - try: n = sock.send(s) - except (socket.error) as e: n = 0 - if n == 0: - return count; - count += n - return count - - -SERVER_PORT = 12877 -MAX_PORTS = 2 - -serverPort = SERVER_PORT -serverSocket = None - -# create passive socket -serverSocket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) - -try: serverSocket.bind(('::1', 0)) -except socket.error as msg: - print('bind fails: ' + str(msg)) - -sn = serverSocket.getsockname() -serverPort = sn[1] - -cmdStr = ("./tcp_client.py %d &") % (serverPort) -os.system(cmdStr) - -buf = b'' -n = 0 -while n < 500: - buf += b'.' - n += 1 - -serverSocket.listen(MAX_PORTS) -readList = [serverSocket] - -while True: - readyRead, readyWrite, inError = \ - select.select(readList, [], [], 2) - - if len(readyRead) > 0: - waitCount = 0 - for sock in readyRead: - if sock == serverSocket: - (clientSocket, address) = serverSocket.accept() - address = str(address[0]) - readList.append(clientSocket) - else: - sock.settimeout(1); - s = read(sock, 1000) - n = send(sock, buf) - sock.close() - serverSocket.close() - sys.exit(0) - else: - print('Select timeout!') - sys.exit(1) From d3813ea14b696053c076123239093822b527f0f7 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 3 Nov 2020 13:35:04 -0800 Subject: [PATCH 3/5] selftests/bpf: Replace EXPECT_EQ with ASSERT_EQ and refactor verify_results There is already logic in test_progs.h for asserting that a value is expected to be another value. So instead of reinventing it we should just make use of ASSERT_EQ in tcpbpf_user.c. This will allow for better debugging and integrates much more closely with the test_progs framework. In addition we can refactor the code a bit to merge together the two verify functions and tie them together into a single function. Doing this helps to clean the code up a bit and makes it more readable as all the verification is now done in one function. Lastly we can relocate the verification to the end of the run_test since it is logically part of the test itself. With this we can drop the need for a return value from run_test since verification becomes the last step of the call and then immediately following is the tear down of the test setup. Signed-off-by: Alexander Duyck Signed-off-by: Alexei Starovoitov Acked-by: Martin KaFai Lau Link: https://lore.kernel.org/bpf/160443930408.1086697.16101205859962113000.stgit@localhost.localdomain --- .../selftests/bpf/prog_tests/tcpbpf_user.c | 111 +++++++----------- 1 file changed, 41 insertions(+), 70 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c b/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c index 616269abdb41..22c359871af6 100644 --- a/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c +++ b/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#include #include #include @@ -10,66 +9,56 @@ static __u32 duration; -#define EXPECT_EQ(expected, actual, fmt) \ - do { \ - if ((expected) != (actual)) { \ - printf(" Value of: " #actual "\n" \ - " Actual: %" fmt "\n" \ - " Expected: %" fmt "\n", \ - (actual), (expected)); \ - ret--; \ - } \ - } while (0) - -int verify_result(const struct tcpbpf_globals *result) +static void verify_result(int map_fd, int sock_map_fd) { - __u32 expected_events; - int ret = 0; + __u32 expected_events = ((1 << BPF_SOCK_OPS_TIMEOUT_INIT) | + (1 << BPF_SOCK_OPS_RWND_INIT) | + (1 << BPF_SOCK_OPS_TCP_CONNECT_CB) | + (1 << BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB) | + (1 << BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB) | + (1 << BPF_SOCK_OPS_NEEDS_ECN) | + (1 << BPF_SOCK_OPS_STATE_CB) | + (1 << BPF_SOCK_OPS_TCP_LISTEN_CB)); + struct tcpbpf_globals result; + __u32 key = 0; + int res, rv; - expected_events = ((1 << BPF_SOCK_OPS_TIMEOUT_INIT) | - (1 << BPF_SOCK_OPS_RWND_INIT) | - (1 << BPF_SOCK_OPS_TCP_CONNECT_CB) | - (1 << BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB) | - (1 << BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB) | - (1 << BPF_SOCK_OPS_NEEDS_ECN) | - (1 << BPF_SOCK_OPS_STATE_CB) | - (1 << BPF_SOCK_OPS_TCP_LISTEN_CB)); + rv = bpf_map_lookup_elem(map_fd, &key, &result); + if (CHECK(rv, "bpf_map_lookup_elem(map_fd)", "err:%d errno:%d", + rv, errno)) + return; - EXPECT_EQ(expected_events, result->event_map, "#" PRIx32); - EXPECT_EQ(501ULL, result->bytes_received, "llu"); - EXPECT_EQ(1002ULL, result->bytes_acked, "llu"); - EXPECT_EQ(1, result->data_segs_in, PRIu32); - EXPECT_EQ(1, result->data_segs_out, PRIu32); - EXPECT_EQ(0x80, result->bad_cb_test_rv, PRIu32); - EXPECT_EQ(0, result->good_cb_test_rv, PRIu32); - EXPECT_EQ(1, result->num_listen, PRIu32); + /* check global map */ + CHECK(expected_events != result.event_map, "event_map", + "unexpected event_map: actual 0x%08x != expected 0x%08x\n", + result.event_map, expected_events); + + ASSERT_EQ(result.bytes_received, 501, "bytes_received"); + ASSERT_EQ(result.bytes_acked, 1002, "bytes_acked"); + ASSERT_EQ(result.data_segs_in, 1, "data_segs_in"); + ASSERT_EQ(result.data_segs_out, 1, "data_segs_out"); + ASSERT_EQ(result.bad_cb_test_rv, 0x80, "bad_cb_test_rv"); + ASSERT_EQ(result.good_cb_test_rv, 0, "good_cb_test_rv"); + ASSERT_EQ(result.num_listen, 1, "num_listen"); /* 3 comes from one listening socket + both ends of the connection */ - EXPECT_EQ(3, result->num_close_events, PRIu32); - - return ret; -} - -int verify_sockopt_result(int sock_map_fd) -{ - __u32 key = 0; - int ret = 0; - int res; - int rv; + ASSERT_EQ(result.num_close_events, 3, "num_close_events"); /* check setsockopt for SAVE_SYN */ rv = bpf_map_lookup_elem(sock_map_fd, &key, &res); - EXPECT_EQ(0, rv, "d"); - EXPECT_EQ(0, res, "d"); - key = 1; + CHECK(rv, "bpf_map_lookup_elem(sock_map_fd)", "err:%d errno:%d", + rv, errno); + ASSERT_EQ(res, 0, "bpf_setsockopt(TCP_SAVE_SYN)"); + /* check getsockopt for SAVED_SYN */ + key = 1; rv = bpf_map_lookup_elem(sock_map_fd, &key, &res); - EXPECT_EQ(0, rv, "d"); - EXPECT_EQ(1, res, "d"); - return ret; + CHECK(rv, "bpf_map_lookup_elem(sock_map_fd)", "err:%d errno:%d", + rv, errno); + ASSERT_EQ(res, 1, "bpf_getsockopt(TCP_SAVED_SYN)"); } -static int run_test(void) +static void run_test(int map_fd, int sock_map_fd) { int listen_fd = -1, cli_fd = -1, accept_fd = -1; char buf[1000]; @@ -135,18 +124,17 @@ done: if (listen_fd != -1) close(listen_fd); - return err; + if (!err) + verify_result(map_fd, sock_map_fd); } void test_tcpbpf_user(void) { const char *file = "test_tcpbpf_kern.o"; int prog_fd, map_fd, sock_map_fd; - struct tcpbpf_globals g = {0}; int error = EXIT_FAILURE; struct bpf_object *obj; int cg_fd = -1; - __u32 key = 0; int rv; cg_fd = test__join_cgroup(CG_NAME); @@ -173,24 +161,7 @@ void test_tcpbpf_user(void) if (sock_map_fd < 0) goto err; - if (run_test()) - goto err; - - rv = bpf_map_lookup_elem(map_fd, &key, &g); - if (rv != 0) { - printf("FAILED: bpf_map_lookup_elem returns %d\n", rv); - goto err; - } - - if (verify_result(&g)) { - printf("FAILED: Wrong stats\n"); - goto err; - } - - if (verify_sockopt_result(sock_map_fd)) { - printf("FAILED: Wrong sockopt stats\n"); - goto err; - } + run_test(map_fd, sock_map_fd); error = 0; err: From 0a099d1429c709020277d24a460d11ff8356a080 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 3 Nov 2020 13:35:11 -0800 Subject: [PATCH 4/5] selftests/bpf: Migrate tcpbpf_user.c to use BPF skeleton Update tcpbpf_user.c to make use of the BPF skeleton. Doing this we can simplify test_tcpbpf_user and reduce the overhead involved in setting up the test. In addition we can clean up the remaining bits such as the one remaining CHECK_FAIL at the end of test_tcpbpf_user so that the function only makes use of CHECK as needed. Signed-off-by: Alexander Duyck Signed-off-by: Alexei Starovoitov Acked-by: Martin KaFai Lau Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/160443931155.1086697.17869006617113525162.stgit@localhost.localdomain --- .../selftests/bpf/prog_tests/tcpbpf_user.c | 41 +++++++------------ 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c b/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c index 22c359871af6..bef81648797a 100644 --- a/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c +++ b/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c @@ -3,6 +3,7 @@ #include #include "test_tcpbpf.h" +#include "test_tcpbpf_kern.skel.h" #define LO_ADDR6 "::1" #define CG_NAME "/tcpbpf-user-test" @@ -130,44 +131,30 @@ done: void test_tcpbpf_user(void) { - const char *file = "test_tcpbpf_kern.o"; - int prog_fd, map_fd, sock_map_fd; - int error = EXIT_FAILURE; - struct bpf_object *obj; + struct test_tcpbpf_kern *skel; + int map_fd, sock_map_fd; int cg_fd = -1; - int rv; + + skel = test_tcpbpf_kern__open_and_load(); + if (CHECK(!skel, "open and load skel", "failed")) + return; cg_fd = test__join_cgroup(CG_NAME); - if (cg_fd < 0) + if (CHECK(cg_fd < 0, "test__join_cgroup(" CG_NAME ")", + "cg_fd:%d errno:%d", cg_fd, errno)) goto err; - if (bpf_prog_load(file, BPF_PROG_TYPE_SOCK_OPS, &obj, &prog_fd)) { - printf("FAILED: load_bpf_file failed for: %s\n", file); - goto err; - } + map_fd = bpf_map__fd(skel->maps.global_map); + sock_map_fd = bpf_map__fd(skel->maps.sockopt_results); - rv = bpf_prog_attach(prog_fd, cg_fd, BPF_CGROUP_SOCK_OPS, 0); - if (rv) { - printf("FAILED: bpf_prog_attach: %d (%s)\n", - error, strerror(errno)); - goto err; - } - - map_fd = bpf_find_map(__func__, obj, "global_map"); - if (map_fd < 0) - goto err; - - sock_map_fd = bpf_find_map(__func__, obj, "sockopt_results"); - if (sock_map_fd < 0) + skel->links.bpf_testcb = bpf_program__attach_cgroup(skel->progs.bpf_testcb, cg_fd); + if (!ASSERT_OK_PTR(skel->links.bpf_testcb, "attach_cgroup(bpf_testcb)")) goto err; run_test(map_fd, sock_map_fd); - error = 0; err: - bpf_prog_detach(cg_fd, BPF_CGROUP_SOCK_OPS); if (cg_fd != -1) close(cg_fd); - - CHECK_FAIL(error); + test_tcpbpf_kern__destroy(skel); } From 21b5177e997c98643eaabd4b917f2e287395af86 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 3 Nov 2020 13:35:19 -0800 Subject: [PATCH 5/5] selftest/bpf: Use global variables instead of maps for test_tcpbpf_kern Use global variables instead of global_map and sockopt_results_map to track test data. Doing this greatly simplifies the code as there is not need to take the extra steps of updating the maps or looking up elements. Signed-off-by: Alexander Duyck Signed-off-by: Alexei Starovoitov Acked-by: Martin KaFai Lau Link: https://lore.kernel.org/bpf/160443931900.1086697.6588858453575682351.stgit@localhost.localdomain --- .../selftests/bpf/prog_tests/tcpbpf_user.c | 51 ++++------- .../selftests/bpf/progs/test_tcpbpf_kern.c | 86 +++---------------- tools/testing/selftests/bpf/test_tcpbpf.h | 2 + 3 files changed, 31 insertions(+), 108 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c b/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c index bef81648797a..ab5281475f44 100644 --- a/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c +++ b/tools/testing/selftests/bpf/prog_tests/tcpbpf_user.c @@ -10,7 +10,7 @@ static __u32 duration; -static void verify_result(int map_fd, int sock_map_fd) +static void verify_result(struct tcpbpf_globals *result) { __u32 expected_events = ((1 << BPF_SOCK_OPS_TIMEOUT_INIT) | (1 << BPF_SOCK_OPS_RWND_INIT) | @@ -20,46 +20,31 @@ static void verify_result(int map_fd, int sock_map_fd) (1 << BPF_SOCK_OPS_NEEDS_ECN) | (1 << BPF_SOCK_OPS_STATE_CB) | (1 << BPF_SOCK_OPS_TCP_LISTEN_CB)); - struct tcpbpf_globals result; - __u32 key = 0; - int res, rv; - - rv = bpf_map_lookup_elem(map_fd, &key, &result); - if (CHECK(rv, "bpf_map_lookup_elem(map_fd)", "err:%d errno:%d", - rv, errno)) - return; /* check global map */ - CHECK(expected_events != result.event_map, "event_map", + CHECK(expected_events != result->event_map, "event_map", "unexpected event_map: actual 0x%08x != expected 0x%08x\n", - result.event_map, expected_events); + result->event_map, expected_events); - ASSERT_EQ(result.bytes_received, 501, "bytes_received"); - ASSERT_EQ(result.bytes_acked, 1002, "bytes_acked"); - ASSERT_EQ(result.data_segs_in, 1, "data_segs_in"); - ASSERT_EQ(result.data_segs_out, 1, "data_segs_out"); - ASSERT_EQ(result.bad_cb_test_rv, 0x80, "bad_cb_test_rv"); - ASSERT_EQ(result.good_cb_test_rv, 0, "good_cb_test_rv"); - ASSERT_EQ(result.num_listen, 1, "num_listen"); + ASSERT_EQ(result->bytes_received, 501, "bytes_received"); + ASSERT_EQ(result->bytes_acked, 1002, "bytes_acked"); + ASSERT_EQ(result->data_segs_in, 1, "data_segs_in"); + ASSERT_EQ(result->data_segs_out, 1, "data_segs_out"); + ASSERT_EQ(result->bad_cb_test_rv, 0x80, "bad_cb_test_rv"); + ASSERT_EQ(result->good_cb_test_rv, 0, "good_cb_test_rv"); + ASSERT_EQ(result->num_listen, 1, "num_listen"); /* 3 comes from one listening socket + both ends of the connection */ - ASSERT_EQ(result.num_close_events, 3, "num_close_events"); + ASSERT_EQ(result->num_close_events, 3, "num_close_events"); /* check setsockopt for SAVE_SYN */ - rv = bpf_map_lookup_elem(sock_map_fd, &key, &res); - CHECK(rv, "bpf_map_lookup_elem(sock_map_fd)", "err:%d errno:%d", - rv, errno); - ASSERT_EQ(res, 0, "bpf_setsockopt(TCP_SAVE_SYN)"); + ASSERT_EQ(result->tcp_save_syn, 0, "tcp_save_syn"); /* check getsockopt for SAVED_SYN */ - key = 1; - rv = bpf_map_lookup_elem(sock_map_fd, &key, &res); - CHECK(rv, "bpf_map_lookup_elem(sock_map_fd)", "err:%d errno:%d", - rv, errno); - ASSERT_EQ(res, 1, "bpf_getsockopt(TCP_SAVED_SYN)"); + ASSERT_EQ(result->tcp_saved_syn, 1, "tcp_saved_syn"); } -static void run_test(int map_fd, int sock_map_fd) +static void run_test(struct tcpbpf_globals *result) { int listen_fd = -1, cli_fd = -1, accept_fd = -1; char buf[1000]; @@ -126,13 +111,12 @@ done: close(listen_fd); if (!err) - verify_result(map_fd, sock_map_fd); + verify_result(result); } void test_tcpbpf_user(void) { struct test_tcpbpf_kern *skel; - int map_fd, sock_map_fd; int cg_fd = -1; skel = test_tcpbpf_kern__open_and_load(); @@ -144,14 +128,11 @@ void test_tcpbpf_user(void) "cg_fd:%d errno:%d", cg_fd, errno)) goto err; - map_fd = bpf_map__fd(skel->maps.global_map); - sock_map_fd = bpf_map__fd(skel->maps.sockopt_results); - skel->links.bpf_testcb = bpf_program__attach_cgroup(skel->progs.bpf_testcb, cg_fd); if (!ASSERT_OK_PTR(skel->links.bpf_testcb, "attach_cgroup(bpf_testcb)")) goto err; - run_test(map_fd, sock_map_fd); + run_test(&skel->bss->global); err: if (cg_fd != -1) diff --git a/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c b/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c index 3e6912e4df3d..e85e49deba70 100644 --- a/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c +++ b/tools/testing/selftests/bpf/progs/test_tcpbpf_kern.c @@ -14,40 +14,7 @@ #include #include "test_tcpbpf.h" -struct { - __uint(type, BPF_MAP_TYPE_ARRAY); - __uint(max_entries, 4); - __type(key, __u32); - __type(value, struct tcpbpf_globals); -} global_map SEC(".maps"); - -struct { - __uint(type, BPF_MAP_TYPE_ARRAY); - __uint(max_entries, 2); - __type(key, __u32); - __type(value, int); -} sockopt_results SEC(".maps"); - -static inline void update_event_map(int event) -{ - __u32 key = 0; - struct tcpbpf_globals g, *gp; - - gp = bpf_map_lookup_elem(&global_map, &key); - if (gp == NULL) { - struct tcpbpf_globals g = {0}; - - g.event_map |= (1 << event); - bpf_map_update_elem(&global_map, &key, &g, - BPF_ANY); - } else { - g = *gp; - g.event_map |= (1 << event); - bpf_map_update_elem(&global_map, &key, &g, - BPF_ANY); - } -} - +struct tcpbpf_globals global = {}; int _version SEC("version") = 1; SEC("sockops") @@ -105,29 +72,15 @@ int bpf_testcb(struct bpf_sock_ops *skops) op = (int) skops->op; - update_event_map(op); + global.event_map |= (1 << op); switch (op) { case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: /* Test failure to set largest cb flag (assumes not defined) */ - bad_call_rv = bpf_sock_ops_cb_flags_set(skops, 0x80); + global.bad_cb_test_rv = bpf_sock_ops_cb_flags_set(skops, 0x80); /* Set callback */ - good_call_rv = bpf_sock_ops_cb_flags_set(skops, + global.good_cb_test_rv = bpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_STATE_CB_FLAG); - /* Update results */ - { - __u32 key = 0; - struct tcpbpf_globals g, *gp; - - gp = bpf_map_lookup_elem(&global_map, &key); - if (!gp) - break; - g = *gp; - g.bad_cb_test_rv = bad_call_rv; - g.good_cb_test_rv = good_call_rv; - bpf_map_update_elem(&global_map, &key, &g, - BPF_ANY); - } break; case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: skops->sk_txhash = 0x12345f; @@ -143,10 +96,8 @@ int bpf_testcb(struct bpf_sock_ops *skops) thdr = (struct tcphdr *)(header + offset); v = thdr->syn; - __u32 key = 1; - bpf_map_update_elem(&sockopt_results, &key, &v, - BPF_ANY); + global.tcp_saved_syn = v; } } break; @@ -156,25 +107,16 @@ int bpf_testcb(struct bpf_sock_ops *skops) break; case BPF_SOCK_OPS_STATE_CB: if (skops->args[1] == BPF_TCP_CLOSE) { - __u32 key = 0; - struct tcpbpf_globals g, *gp; - - gp = bpf_map_lookup_elem(&global_map, &key); - if (!gp) - break; - g = *gp; if (skops->args[0] == BPF_TCP_LISTEN) { - g.num_listen++; + global.num_listen++; } else { - g.total_retrans = skops->total_retrans; - g.data_segs_in = skops->data_segs_in; - g.data_segs_out = skops->data_segs_out; - g.bytes_received = skops->bytes_received; - g.bytes_acked = skops->bytes_acked; + global.total_retrans = skops->total_retrans; + global.data_segs_in = skops->data_segs_in; + global.data_segs_out = skops->data_segs_out; + global.bytes_received = skops->bytes_received; + global.bytes_acked = skops->bytes_acked; } - g.num_close_events++; - bpf_map_update_elem(&global_map, &key, &g, - BPF_ANY); + global.num_close_events++; } break; case BPF_SOCK_OPS_TCP_LISTEN_CB: @@ -182,9 +124,7 @@ int bpf_testcb(struct bpf_sock_ops *skops) v = bpf_setsockopt(skops, IPPROTO_TCP, TCP_SAVE_SYN, &save_syn, sizeof(save_syn)); /* Update global map w/ result of setsock opt */ - __u32 key = 0; - - bpf_map_update_elem(&sockopt_results, &key, &v, BPF_ANY); + global.tcp_save_syn = v; break; default: rv = -1; diff --git a/tools/testing/selftests/bpf/test_tcpbpf.h b/tools/testing/selftests/bpf/test_tcpbpf.h index 6220b95cbd02..0ed33521cbbb 100644 --- a/tools/testing/selftests/bpf/test_tcpbpf.h +++ b/tools/testing/selftests/bpf/test_tcpbpf.h @@ -14,5 +14,7 @@ struct tcpbpf_globals { __u64 bytes_acked; __u32 num_listen; __u32 num_close_events; + __u32 tcp_save_syn; + __u32 tcp_saved_syn; }; #endif