1b0f82e7aSAlexis Lothoré (eBPF Foundation) // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2b0f82e7aSAlexis Lothoré (eBPF Foundation) 3b0f82e7aSAlexis Lothoré (eBPF Foundation) /* 4b0f82e7aSAlexis Lothoré (eBPF Foundation) * BPF-based flow shaping 5b0f82e7aSAlexis Lothoré (eBPF Foundation) * 6b0f82e7aSAlexis Lothoré (eBPF Foundation) * The test brings up two veth in two isolated namespaces, attach some flow 7b0f82e7aSAlexis Lothoré (eBPF Foundation) * shaping program onto it, and ensures that a manual speedtest maximum 8b0f82e7aSAlexis Lothoré (eBPF Foundation) * value matches the rate set in the BPF shapers. 9b0f82e7aSAlexis Lothoré (eBPF Foundation) */ 10b0f82e7aSAlexis Lothoré (eBPF Foundation) 11b0f82e7aSAlexis Lothoré (eBPF Foundation) #include <asm-generic/socket.h> 12b0f82e7aSAlexis Lothoré (eBPF Foundation) #include <stdio.h> 13b0f82e7aSAlexis Lothoré (eBPF Foundation) #include <unistd.h> 14b0f82e7aSAlexis Lothoré (eBPF Foundation) #include <fcntl.h> 15b0f82e7aSAlexis Lothoré (eBPF Foundation) #include <math.h> 16b0f82e7aSAlexis Lothoré (eBPF Foundation) #include <sys/time.h> 17b0f82e7aSAlexis Lothoré (eBPF Foundation) #include <sys/socket.h> 18b0f82e7aSAlexis Lothoré (eBPF Foundation) #include <bpf/libbpf.h> 19b0f82e7aSAlexis Lothoré (eBPF Foundation) #include <pthread.h> 20b0f82e7aSAlexis Lothoré (eBPF Foundation) #include "test_progs.h" 21b0f82e7aSAlexis Lothoré (eBPF Foundation) #include "network_helpers.h" 22b0f82e7aSAlexis Lothoré (eBPF Foundation) #include "test_tc_edt.skel.h" 23b0f82e7aSAlexis Lothoré (eBPF Foundation) 24b0f82e7aSAlexis Lothoré (eBPF Foundation) #define SERVER_NS "tc-edt-server-ns" 25b0f82e7aSAlexis Lothoré (eBPF Foundation) #define CLIENT_NS "tc-edt-client-ns" 26b0f82e7aSAlexis Lothoré (eBPF Foundation) #define IP4_ADDR_VETH1 "192.168.1.1" 27b0f82e7aSAlexis Lothoré (eBPF Foundation) #define IP4_ADDR_VETH2 "192.168.1.2" 28b0f82e7aSAlexis Lothoré (eBPF Foundation) #define IP4_ADDR_VETH2_HEX 0xC0A80102 29b0f82e7aSAlexis Lothoré (eBPF Foundation) 30b0f82e7aSAlexis Lothoré (eBPF Foundation) #define TIMEOUT_MS 2000 31b0f82e7aSAlexis Lothoré (eBPF Foundation) #define TEST_PORT 9000 32b0f82e7aSAlexis Lothoré (eBPF Foundation) #define TARGET_RATE_MBPS 5.0 33b0f82e7aSAlexis Lothoré (eBPF Foundation) #define TX_BYTES_COUNT (1 * 1000 * 1000) 34b0f82e7aSAlexis Lothoré (eBPF Foundation) #define RATE_ERROR_PERCENT 2.0 35b0f82e7aSAlexis Lothoré (eBPF Foundation) 36b0f82e7aSAlexis Lothoré (eBPF Foundation) struct connection { 37b0f82e7aSAlexis Lothoré (eBPF Foundation) int server_listen_fd; 38b0f82e7aSAlexis Lothoré (eBPF Foundation) int server_conn_fd; 39b0f82e7aSAlexis Lothoré (eBPF Foundation) int client_conn_fd; 40b0f82e7aSAlexis Lothoré (eBPF Foundation) }; 41b0f82e7aSAlexis Lothoré (eBPF Foundation) 42b0f82e7aSAlexis Lothoré (eBPF Foundation) static int setup(struct test_tc_edt *skel) 43b0f82e7aSAlexis Lothoré (eBPF Foundation) { 44b0f82e7aSAlexis Lothoré (eBPF Foundation) struct nstoken *nstoken_client, *nstoken_server; 45b0f82e7aSAlexis Lothoré (eBPF Foundation) int ret; 46b0f82e7aSAlexis Lothoré (eBPF Foundation) 47b0f82e7aSAlexis Lothoré (eBPF Foundation) if (!ASSERT_OK(make_netns(CLIENT_NS), "create client ns")) 48b0f82e7aSAlexis Lothoré (eBPF Foundation) goto fail; 49b0f82e7aSAlexis Lothoré (eBPF Foundation) if (!ASSERT_OK(make_netns(SERVER_NS), "create server ns")) 50b0f82e7aSAlexis Lothoré (eBPF Foundation) goto fail_delete_client_ns; 51b0f82e7aSAlexis Lothoré (eBPF Foundation) 52b0f82e7aSAlexis Lothoré (eBPF Foundation) nstoken_client = open_netns(CLIENT_NS); 53b0f82e7aSAlexis Lothoré (eBPF Foundation) if (!ASSERT_OK_PTR(nstoken_client, "open client ns")) 54b0f82e7aSAlexis Lothoré (eBPF Foundation) goto fail_delete_server_ns; 55b0f82e7aSAlexis Lothoré (eBPF Foundation) SYS(fail_close_client_ns, "ip link add veth1 type veth peer name %s", 56b0f82e7aSAlexis Lothoré (eBPF Foundation) "veth2 netns " SERVER_NS); 57b0f82e7aSAlexis Lothoré (eBPF Foundation) SYS(fail_close_client_ns, "ip -4 addr add " IP4_ADDR_VETH1 "/24 dev veth1"); 58b0f82e7aSAlexis Lothoré (eBPF Foundation) SYS(fail_close_client_ns, "ip link set veth1 up"); 59b0f82e7aSAlexis Lothoré (eBPF Foundation) 60b0f82e7aSAlexis Lothoré (eBPF Foundation) nstoken_server = open_netns(SERVER_NS); 61b0f82e7aSAlexis Lothoré (eBPF Foundation) if (!ASSERT_OK_PTR(nstoken_server, "enter server ns")) 62b0f82e7aSAlexis Lothoré (eBPF Foundation) goto fail_close_client_ns; 63b0f82e7aSAlexis Lothoré (eBPF Foundation) SYS(fail_close_server_ns, "ip -4 addr add " IP4_ADDR_VETH2 "/24 dev veth2"); 64b0f82e7aSAlexis Lothoré (eBPF Foundation) SYS(fail_close_server_ns, "ip link set veth2 up"); 65b0f82e7aSAlexis Lothoré (eBPF Foundation) SYS(fail_close_server_ns, "tc qdisc add dev veth2 root fq"); 66b0f82e7aSAlexis Lothoré (eBPF Foundation) ret = tc_prog_attach("veth2", -1, bpf_program__fd(skel->progs.tc_prog)); 67b0f82e7aSAlexis Lothoré (eBPF Foundation) if (!ASSERT_OK(ret, "attach bpf prog")) 68b0f82e7aSAlexis Lothoré (eBPF Foundation) goto fail_close_server_ns; 69*1d17bcceSAlexis Lothoré (eBPF Foundation) skel->bss->target_rate = TARGET_RATE_MBPS * 1000 * 1000; 70b0f82e7aSAlexis Lothoré (eBPF Foundation) close_netns(nstoken_server); 71b0f82e7aSAlexis Lothoré (eBPF Foundation) close_netns(nstoken_client); 72b0f82e7aSAlexis Lothoré (eBPF Foundation) 73b0f82e7aSAlexis Lothoré (eBPF Foundation) return 0; 74b0f82e7aSAlexis Lothoré (eBPF Foundation) 75b0f82e7aSAlexis Lothoré (eBPF Foundation) fail_close_server_ns: 76b0f82e7aSAlexis Lothoré (eBPF Foundation) close_netns(nstoken_server); 77b0f82e7aSAlexis Lothoré (eBPF Foundation) fail_close_client_ns: 78b0f82e7aSAlexis Lothoré (eBPF Foundation) close_netns(nstoken_client); 79b0f82e7aSAlexis Lothoré (eBPF Foundation) fail_delete_server_ns: 80b0f82e7aSAlexis Lothoré (eBPF Foundation) remove_netns(SERVER_NS); 81b0f82e7aSAlexis Lothoré (eBPF Foundation) fail_delete_client_ns: 82b0f82e7aSAlexis Lothoré (eBPF Foundation) remove_netns(CLIENT_NS); 83b0f82e7aSAlexis Lothoré (eBPF Foundation) fail: 84b0f82e7aSAlexis Lothoré (eBPF Foundation) return -1; 85b0f82e7aSAlexis Lothoré (eBPF Foundation) } 86b0f82e7aSAlexis Lothoré (eBPF Foundation) 87b0f82e7aSAlexis Lothoré (eBPF Foundation) static void cleanup(void) 88b0f82e7aSAlexis Lothoré (eBPF Foundation) { 89b0f82e7aSAlexis Lothoré (eBPF Foundation) remove_netns(CLIENT_NS); 90b0f82e7aSAlexis Lothoré (eBPF Foundation) remove_netns(SERVER_NS); 91b0f82e7aSAlexis Lothoré (eBPF Foundation) } 92b0f82e7aSAlexis Lothoré (eBPF Foundation) 93b0f82e7aSAlexis Lothoré (eBPF Foundation) static void run_test(void) 94b0f82e7aSAlexis Lothoré (eBPF Foundation) { 95b0f82e7aSAlexis Lothoré (eBPF Foundation) int server_fd, client_fd, err; 96b0f82e7aSAlexis Lothoré (eBPF Foundation) double rate_mbps, rate_error; 97b0f82e7aSAlexis Lothoré (eBPF Foundation) struct nstoken *nstoken; 98b0f82e7aSAlexis Lothoré (eBPF Foundation) __u64 ts_start, ts_end; 99b0f82e7aSAlexis Lothoré (eBPF Foundation) 100b0f82e7aSAlexis Lothoré (eBPF Foundation) nstoken = open_netns(SERVER_NS); 101b0f82e7aSAlexis Lothoré (eBPF Foundation) if (!ASSERT_OK_PTR(nstoken, "open server ns")) 102b0f82e7aSAlexis Lothoré (eBPF Foundation) return; 103b0f82e7aSAlexis Lothoré (eBPF Foundation) server_fd = start_server(AF_INET, SOCK_STREAM, IP4_ADDR_VETH2, 104b0f82e7aSAlexis Lothoré (eBPF Foundation) TEST_PORT, TIMEOUT_MS); 105b0f82e7aSAlexis Lothoré (eBPF Foundation) if (!ASSERT_OK_FD(server_fd, "start server")) 106b0f82e7aSAlexis Lothoré (eBPF Foundation) return; 107b0f82e7aSAlexis Lothoré (eBPF Foundation) 108b0f82e7aSAlexis Lothoré (eBPF Foundation) close_netns(nstoken); 109b0f82e7aSAlexis Lothoré (eBPF Foundation) nstoken = open_netns(CLIENT_NS); 110b0f82e7aSAlexis Lothoré (eBPF Foundation) if (!ASSERT_OK_PTR(nstoken, "open client ns")) 111b0f82e7aSAlexis Lothoré (eBPF Foundation) return; 112b0f82e7aSAlexis Lothoré (eBPF Foundation) client_fd = connect_to_fd(server_fd, 0); 113b0f82e7aSAlexis Lothoré (eBPF Foundation) if (!ASSERT_OK_FD(client_fd, "connect client")) 114b0f82e7aSAlexis Lothoré (eBPF Foundation) return; 115b0f82e7aSAlexis Lothoré (eBPF Foundation) 116b0f82e7aSAlexis Lothoré (eBPF Foundation) ts_start = get_time_ns(); 117b0f82e7aSAlexis Lothoré (eBPF Foundation) err = send_recv_data(server_fd, client_fd, TX_BYTES_COUNT); 118b0f82e7aSAlexis Lothoré (eBPF Foundation) ts_end = get_time_ns(); 119b0f82e7aSAlexis Lothoré (eBPF Foundation) close_netns(nstoken); 120b0f82e7aSAlexis Lothoré (eBPF Foundation) ASSERT_OK(err, "send_recv_data"); 121b0f82e7aSAlexis Lothoré (eBPF Foundation) 122b0f82e7aSAlexis Lothoré (eBPF Foundation) rate_mbps = TX_BYTES_COUNT / ((ts_end - ts_start) / 1000.0); 123b0f82e7aSAlexis Lothoré (eBPF Foundation) rate_error = 124b0f82e7aSAlexis Lothoré (eBPF Foundation) fabs((rate_mbps - TARGET_RATE_MBPS) * 100.0 / TARGET_RATE_MBPS); 125b0f82e7aSAlexis Lothoré (eBPF Foundation) 126b0f82e7aSAlexis Lothoré (eBPF Foundation) ASSERT_LE(rate_error, RATE_ERROR_PERCENT, 127b0f82e7aSAlexis Lothoré (eBPF Foundation) "rate error is lower than threshold"); 128b0f82e7aSAlexis Lothoré (eBPF Foundation) } 129b0f82e7aSAlexis Lothoré (eBPF Foundation) 130b0f82e7aSAlexis Lothoré (eBPF Foundation) void test_tc_edt(void) 131b0f82e7aSAlexis Lothoré (eBPF Foundation) { 132b0f82e7aSAlexis Lothoré (eBPF Foundation) struct test_tc_edt *skel; 133b0f82e7aSAlexis Lothoré (eBPF Foundation) 134b0f82e7aSAlexis Lothoré (eBPF Foundation) skel = test_tc_edt__open_and_load(); 135b0f82e7aSAlexis Lothoré (eBPF Foundation) if (!ASSERT_OK_PTR(skel, "skel open and load")) 136b0f82e7aSAlexis Lothoré (eBPF Foundation) return; 137b0f82e7aSAlexis Lothoré (eBPF Foundation) 138b0f82e7aSAlexis Lothoré (eBPF Foundation) if (!ASSERT_OK(setup(skel), "global setup")) 139b0f82e7aSAlexis Lothoré (eBPF Foundation) return; 140b0f82e7aSAlexis Lothoré (eBPF Foundation) 141b0f82e7aSAlexis Lothoré (eBPF Foundation) run_test(); 142b0f82e7aSAlexis Lothoré (eBPF Foundation) 143b0f82e7aSAlexis Lothoré (eBPF Foundation) cleanup(); 144b0f82e7aSAlexis Lothoré (eBPF Foundation) test_tc_edt__destroy(skel); 145b0f82e7aSAlexis Lothoré (eBPF Foundation) } 146