FILE
btf_skc_cls_ingress.c
File preview with syntax highlighting.
linux-6.19.14/tools/testing/selftests/bpf/prog_tests/btf_skc_cls_ingress.c
1// SPDX-License-Identifier: GPL-2.0 2/* Copyright (c) 2020 Facebook */ 3 4#define _GNU_SOURCE 5#include <netinet/in.h> 6#include <arpa/inet.h> 7#include <unistd.h> 8#include <stdlib.h> 9#include <string.h> 10#include <errno.h> 11#include <sched.h> 12#include <net/if.h> 13#include <linux/compiler.h> 14#include <bpf/libbpf.h> 15 16#include "network_helpers.h" 17#include "test_progs.h" 18#include "test_btf_skc_cls_ingress.skel.h" 19 20#define TEST_NS "skc_cls_ingress" 21 22#define BIT(n) (1 << (n)) 23#define TEST_MODE_IPV4 BIT(0) 24#define TEST_MODE_IPV6 BIT(1) 25#define TEST_MODE_DUAL (TEST_MODE_IPV4 | TEST_MODE_IPV6) 26 27#define SERVER_ADDR_IPV4 "127.0.0.1" 28#define SERVER_ADDR_IPV6 "::1" 29#define SERVER_ADDR_DUAL "::0" 30/* RFC791, 576 for minimal IPv4 datagram, minus 40 bytes of TCP header */ 31#define MIN_IPV4_MSS 536 32 33static struct netns_obj *prepare_netns(struct test_btf_skc_cls_ingress *skel) 34{ 35 LIBBPF_OPTS(bpf_tc_hook, qdisc_lo, .attach_point = BPF_TC_INGRESS); 36 LIBBPF_OPTS(bpf_tc_opts, tc_attach, 37 .prog_fd = bpf_program__fd(skel->progs.cls_ingress)); 38 struct netns_obj *ns = NULL; 39 40 ns = netns_new(TEST_NS, true); 41 if (!ASSERT_OK_PTR(ns, "create and join netns")) 42 return ns; 43 44 qdisc_lo.ifindex = if_nametoindex("lo"); 45 if (!ASSERT_OK(bpf_tc_hook_create(&qdisc_lo), "qdisc add dev lo clsact")) 46 goto free_ns; 47 48 if (!ASSERT_OK(bpf_tc_attach(&qdisc_lo, &tc_attach), 49 "filter add dev lo ingress")) 50 goto free_ns; 51 52 /* Ensure 20 bytes options (i.e. in total 40 bytes tcp header) for the 53 * bpf_tcp_gen_syncookie() helper. 54 */ 55 if (write_sysctl("/proc/sys/net/ipv4/tcp_window_scaling", "1") || 56 write_sysctl("/proc/sys/net/ipv4/tcp_timestamps", "1") || 57 write_sysctl("/proc/sys/net/ipv4/tcp_sack", "1")) 58 goto free_ns; 59 60 return ns; 61 62free_ns: 63 netns_free(ns); 64 return NULL; 65} 66 67static void reset_test(struct test_btf_skc_cls_ingress *skel) 68{ 69 memset(&skel->bss->srv_sa4, 0, sizeof(skel->bss->srv_sa4)); 70 memset(&skel->bss->srv_sa6, 0, sizeof(skel->bss->srv_sa6)); 71 skel->bss->listen_tp_sport = 0; 72 skel->bss->req_sk_sport = 0; 73 skel->bss->recv_cookie = 0; 74 skel->bss->gen_cookie = 0; 75 skel->bss->linum = 0; 76 skel->bss->mss = 0; 77} 78 79static void print_err_line(struct test_btf_skc_cls_ingress *skel) 80{ 81 if (skel->bss->linum) 82 printf("bpf prog error at line %u\n", skel->bss->linum); 83} 84 85static int v6only_true(int fd, void *opts) 86{ 87 int mode = true; 88 89 return setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &mode, sizeof(mode)); 90} 91 92static int v6only_false(int fd, void *opts) 93{ 94 int mode = false; 95 96 return setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &mode, sizeof(mode)); 97} 98 99static void run_test(struct test_btf_skc_cls_ingress *skel, bool gen_cookies, 100 int ip_mode) 101{ 102 const char *tcp_syncookies = gen_cookies ? "2" : "1"; 103 int listen_fd = -1, cli_fd = -1, srv_fd = -1, err; 104 struct network_helper_opts opts = { 0 }; 105 struct sockaddr_storage *addr; 106 struct sockaddr_in6 srv_sa6; 107 struct sockaddr_in srv_sa4; 108 socklen_t addr_len; 109 int sock_family; 110 char *srv_addr; 111 int srv_port; 112 113 switch (ip_mode) { 114 case TEST_MODE_IPV4: 115 sock_family = AF_INET; 116 srv_addr = SERVER_ADDR_IPV4; 117 addr = (struct sockaddr_storage *)&srv_sa4; 118 addr_len = sizeof(srv_sa4); 119 break; 120 case TEST_MODE_IPV6: 121 opts.post_socket_cb = v6only_true; 122 sock_family = AF_INET6; 123 srv_addr = SERVER_ADDR_IPV6; 124 addr = (struct sockaddr_storage *)&srv_sa6; 125 addr_len = sizeof(srv_sa6); 126 break; 127 case TEST_MODE_DUAL: 128 opts.post_socket_cb = v6only_false; 129 sock_family = AF_INET6; 130 srv_addr = SERVER_ADDR_DUAL; 131 addr = (struct sockaddr_storage *)&srv_sa6; 132 addr_len = sizeof(srv_sa6); 133 break; 134 default: 135 PRINT_FAIL("Unknown IP mode %d", ip_mode); 136 return; 137 } 138 139 if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", tcp_syncookies)) 140 return; 141 142 listen_fd = start_server_str(sock_family, SOCK_STREAM, srv_addr, 0, 143 &opts); 144 if (!ASSERT_OK_FD(listen_fd, "start server")) 145 return; 146 147 err = getsockname(listen_fd, (struct sockaddr *)addr, &addr_len); 148 if (!ASSERT_OK(err, "getsockname(listen_fd)")) 149 goto done; 150 151 switch (ip_mode) { 152 case TEST_MODE_IPV4: 153 memcpy(&skel->bss->srv_sa4, &srv_sa4, sizeof(srv_sa4)); 154 srv_port = ntohs(srv_sa4.sin_port); 155 break; 156 case TEST_MODE_IPV6: 157 case TEST_MODE_DUAL: 158 memcpy(&skel->bss->srv_sa6, &srv_sa6, sizeof(srv_sa6)); 159 srv_port = ntohs(srv_sa6.sin6_port); 160 break; 161 default: 162 goto done; 163 } 164 165 cli_fd = connect_to_fd(listen_fd, 0); 166 if (!ASSERT_OK_FD(cli_fd, "connect client")) 167 goto done; 168 169 srv_fd = accept(listen_fd, NULL, NULL); 170 if (!ASSERT_OK_FD(srv_fd, "accept connection")) 171 goto done; 172 173 ASSERT_EQ(skel->bss->listen_tp_sport, srv_port, "listen tp src port"); 174 175 if (!gen_cookies) { 176 ASSERT_EQ(skel->bss->req_sk_sport, srv_port, 177 "request socket source port with syncookies disabled"); 178 ASSERT_EQ(skel->bss->gen_cookie, 0, 179 "generated syncookie with syncookies disabled"); 180 ASSERT_EQ(skel->bss->recv_cookie, 0, 181 "received syncookie with syncookies disabled"); 182 } else { 183 ASSERT_EQ(skel->bss->req_sk_sport, 0, 184 "request socket source port with syncookies enabled"); 185 ASSERT_NEQ(skel->bss->gen_cookie, 0, 186 "syncookie properly generated"); 187 ASSERT_EQ(skel->bss->gen_cookie, skel->bss->recv_cookie, 188 "matching syncookies on client and server"); 189 ASSERT_GT(skel->bss->mss, MIN_IPV4_MSS, 190 "MSS in cookie min value"); 191 ASSERT_LT(skel->bss->mss, USHRT_MAX, 192 "MSS in cookie max value"); 193 } 194 195done: 196 if (listen_fd != -1) 197 close(listen_fd); 198 if (cli_fd != -1) 199 close(cli_fd); 200 if (srv_fd != -1) 201 close(srv_fd); 202} 203 204static void test_conn_ipv4(struct test_btf_skc_cls_ingress *skel) 205{ 206 run_test(skel, false, TEST_MODE_IPV4); 207} 208 209static void test_conn_ipv6(struct test_btf_skc_cls_ingress *skel) 210{ 211 run_test(skel, false, TEST_MODE_IPV6); 212} 213 214static void test_conn_dual(struct test_btf_skc_cls_ingress *skel) 215{ 216 run_test(skel, false, TEST_MODE_DUAL); 217} 218 219static void test_syncookie_ipv4(struct test_btf_skc_cls_ingress *skel) 220{ 221 run_test(skel, true, TEST_MODE_IPV4); 222} 223 224static void test_syncookie_ipv6(struct test_btf_skc_cls_ingress *skel) 225{ 226 run_test(skel, true, TEST_MODE_IPV6); 227} 228 229static void test_syncookie_dual(struct test_btf_skc_cls_ingress *skel) 230{ 231 run_test(skel, true, TEST_MODE_DUAL); 232} 233 234struct test { 235 const char *desc; 236 void (*run)(struct test_btf_skc_cls_ingress *skel); 237}; 238 239#define DEF_TEST(name) { #name, test_##name } 240static struct test tests[] = { 241 DEF_TEST(conn_ipv4), 242 DEF_TEST(conn_ipv6), 243 DEF_TEST(conn_dual), 244 DEF_TEST(syncookie_ipv4), 245 DEF_TEST(syncookie_ipv6), 246 DEF_TEST(syncookie_dual), 247}; 248 249void test_btf_skc_cls_ingress(void) 250{ 251 struct test_btf_skc_cls_ingress *skel; 252 struct netns_obj *ns; 253 int i; 254 255 skel = test_btf_skc_cls_ingress__open_and_load(); 256 if (!ASSERT_OK_PTR(skel, "test_btf_skc_cls_ingress__open_and_load")) 257 return; 258 259 for (i = 0; i < ARRAY_SIZE(tests); i++) { 260 if (!test__start_subtest(tests[i].desc)) 261 continue; 262 263 ns = prepare_netns(skel); 264 if (!ns) 265 break; 266 267 tests[i].run(skel); 268 269 print_err_line(skel); 270 reset_test(skel); 271 netns_free(ns); 272 } 273 274 test_btf_skc_cls_ingress__destroy(skel); 275}
~/
Read-only file preview.