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 <linux/compiler.h> 13 #include <bpf/libbpf.h> 14 15 #include "network_helpers.h" 16 #include "test_progs.h" 17 #include "test_btf_skc_cls_ingress.skel.h" 18 19 static struct test_btf_skc_cls_ingress *skel; 20 static struct sockaddr_in6 srv_sa6; 21 static __u32 duration; 22 23 #define PROG_PIN_FILE "/sys/fs/bpf/btf_skc_cls_ingress" 24 25 static int prepare_netns(void) 26 { 27 if (CHECK(unshare(CLONE_NEWNET), "create netns", 28 "unshare(CLONE_NEWNET): %s (%d)", 29 strerror(errno), errno)) 30 return -1; 31 32 if (CHECK(system("ip link set dev lo up"), 33 "ip link set dev lo up", "failed\n")) 34 return -1; 35 36 if (CHECK(system("tc qdisc add dev lo clsact"), 37 "tc qdisc add dev lo clsact", "failed\n")) 38 return -1; 39 40 if (CHECK(system("tc filter add dev lo ingress bpf direct-action object-pinned " PROG_PIN_FILE), 41 "install tc cls-prog at ingress", "failed\n")) 42 return -1; 43 44 /* Ensure 20 bytes options (i.e. in total 40 bytes tcp header) for the 45 * bpf_tcp_gen_syncookie() helper. 46 */ 47 if (write_sysctl("/proc/sys/net/ipv4/tcp_window_scaling", "1") || 48 write_sysctl("/proc/sys/net/ipv4/tcp_timestamps", "1") || 49 write_sysctl("/proc/sys/net/ipv4/tcp_sack", "1")) 50 return -1; 51 52 return 0; 53 } 54 55 static void reset_test(void) 56 { 57 memset(&skel->bss->srv_sa6, 0, sizeof(skel->bss->srv_sa6)); 58 skel->bss->listen_tp_sport = 0; 59 skel->bss->req_sk_sport = 0; 60 skel->bss->recv_cookie = 0; 61 skel->bss->gen_cookie = 0; 62 skel->bss->linum = 0; 63 } 64 65 static void print_err_line(void) 66 { 67 if (skel->bss->linum) 68 printf("bpf prog error at line %u\n", skel->bss->linum); 69 } 70 71 static void test_conn(void) 72 { 73 int listen_fd = -1, cli_fd = -1, srv_fd = -1, err; 74 socklen_t addrlen = sizeof(srv_sa6); 75 int srv_port; 76 77 if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1")) 78 return; 79 80 listen_fd = start_server(AF_INET6, SOCK_STREAM, "::1", 0, 0); 81 if (CHECK_FAIL(listen_fd == -1)) 82 return; 83 84 err = getsockname(listen_fd, (struct sockaddr *)&srv_sa6, &addrlen); 85 if (CHECK(err, "getsockname(listen_fd)", "err:%d errno:%d\n", err, 86 errno)) 87 goto done; 88 memcpy(&skel->bss->srv_sa6, &srv_sa6, sizeof(srv_sa6)); 89 srv_port = ntohs(srv_sa6.sin6_port); 90 91 cli_fd = connect_to_fd(listen_fd, 0); 92 if (CHECK_FAIL(cli_fd == -1)) 93 goto done; 94 95 srv_fd = accept(listen_fd, NULL, NULL); 96 if (CHECK_FAIL(srv_fd == -1)) 97 goto done; 98 99 if (CHECK(skel->bss->listen_tp_sport != srv_port || 100 skel->bss->req_sk_sport != srv_port, 101 "Unexpected sk src port", 102 "listen_tp_sport:%u req_sk_sport:%u expected:%u\n", 103 skel->bss->listen_tp_sport, skel->bss->req_sk_sport, 104 srv_port)) 105 goto done; 106 107 if (CHECK(skel->bss->gen_cookie || skel->bss->recv_cookie, 108 "Unexpected syncookie states", 109 "gen_cookie:%u recv_cookie:%u\n", 110 skel->bss->gen_cookie, skel->bss->recv_cookie)) 111 goto done; 112 113 CHECK(skel->bss->linum, "bpf prog detected error", "at line %u\n", 114 skel->bss->linum); 115 116 done: 117 if (listen_fd != -1) 118 close(listen_fd); 119 if (cli_fd != -1) 120 close(cli_fd); 121 if (srv_fd != -1) 122 close(srv_fd); 123 } 124 125 static void test_syncookie(void) 126 { 127 int listen_fd = -1, cli_fd = -1, srv_fd = -1, err; 128 socklen_t addrlen = sizeof(srv_sa6); 129 int srv_port; 130 131 /* Enforce syncookie mode */ 132 if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "2")) 133 return; 134 135 listen_fd = start_server(AF_INET6, SOCK_STREAM, "::1", 0, 0); 136 if (CHECK_FAIL(listen_fd == -1)) 137 return; 138 139 err = getsockname(listen_fd, (struct sockaddr *)&srv_sa6, &addrlen); 140 if (CHECK(err, "getsockname(listen_fd)", "err:%d errno:%d\n", err, 141 errno)) 142 goto done; 143 memcpy(&skel->bss->srv_sa6, &srv_sa6, sizeof(srv_sa6)); 144 srv_port = ntohs(srv_sa6.sin6_port); 145 146 cli_fd = connect_to_fd(listen_fd, 0); 147 if (CHECK_FAIL(cli_fd == -1)) 148 goto done; 149 150 srv_fd = accept(listen_fd, NULL, NULL); 151 if (CHECK_FAIL(srv_fd == -1)) 152 goto done; 153 154 if (CHECK(skel->bss->listen_tp_sport != srv_port, 155 "Unexpected tp src port", 156 "listen_tp_sport:%u expected:%u\n", 157 skel->bss->listen_tp_sport, srv_port)) 158 goto done; 159 160 if (CHECK(skel->bss->req_sk_sport, 161 "Unexpected req_sk src port", 162 "req_sk_sport:%u expected:0\n", 163 skel->bss->req_sk_sport)) 164 goto done; 165 166 if (CHECK(!skel->bss->gen_cookie || 167 skel->bss->gen_cookie != skel->bss->recv_cookie, 168 "Unexpected syncookie states", 169 "gen_cookie:%u recv_cookie:%u\n", 170 skel->bss->gen_cookie, skel->bss->recv_cookie)) 171 goto done; 172 173 CHECK(skel->bss->linum, "bpf prog detected error", "at line %u\n", 174 skel->bss->linum); 175 176 done: 177 if (listen_fd != -1) 178 close(listen_fd); 179 if (cli_fd != -1) 180 close(cli_fd); 181 if (srv_fd != -1) 182 close(srv_fd); 183 } 184 185 struct test { 186 const char *desc; 187 void (*run)(void); 188 }; 189 190 #define DEF_TEST(name) { #name, test_##name } 191 static struct test tests[] = { 192 DEF_TEST(conn), 193 DEF_TEST(syncookie), 194 }; 195 196 void test_btf_skc_cls_ingress(void) 197 { 198 int i, err; 199 200 skel = test_btf_skc_cls_ingress__open_and_load(); 201 if (CHECK(!skel, "test_btf_skc_cls_ingress__open_and_load", "failed\n")) 202 return; 203 204 err = bpf_program__pin(skel->progs.cls_ingress, PROG_PIN_FILE); 205 if (CHECK(err, "bpf_program__pin", 206 "cannot pin bpf prog to %s. err:%d\n", PROG_PIN_FILE, err)) { 207 test_btf_skc_cls_ingress__destroy(skel); 208 return; 209 } 210 211 for (i = 0; i < ARRAY_SIZE(tests); i++) { 212 if (!test__start_subtest(tests[i].desc)) 213 continue; 214 215 if (prepare_netns()) 216 break; 217 218 tests[i].run(); 219 220 print_err_line(); 221 reset_test(); 222 } 223 224 bpf_program__unpin(skel->progs.cls_ingress, PROG_PIN_FILE); 225 test_btf_skc_cls_ingress__destroy(skel); 226 } 227