1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2020 Cloudflare 3 #include <error.h> 4 #include <netinet/tcp.h> 5 6 #include "test_progs.h" 7 #include "test_skmsg_load_helpers.skel.h" 8 #include "test_sockmap_update.skel.h" 9 #include "test_sockmap_invalid_update.skel.h" 10 #include "bpf_iter_sockmap.skel.h" 11 12 #define TCP_REPAIR 19 /* TCP sock is under repair right now */ 13 14 #define TCP_REPAIR_ON 1 15 #define TCP_REPAIR_OFF_NO_WP -1 /* Turn off without window probes */ 16 17 static int connected_socket_v4(void) 18 { 19 struct sockaddr_in addr = { 20 .sin_family = AF_INET, 21 .sin_port = htons(80), 22 .sin_addr = { inet_addr("127.0.0.1") }, 23 }; 24 socklen_t len = sizeof(addr); 25 int s, repair, err; 26 27 s = socket(AF_INET, SOCK_STREAM, 0); 28 if (CHECK_FAIL(s == -1)) 29 goto error; 30 31 repair = TCP_REPAIR_ON; 32 err = setsockopt(s, SOL_TCP, TCP_REPAIR, &repair, sizeof(repair)); 33 if (CHECK_FAIL(err)) 34 goto error; 35 36 err = connect(s, (struct sockaddr *)&addr, len); 37 if (CHECK_FAIL(err)) 38 goto error; 39 40 repair = TCP_REPAIR_OFF_NO_WP; 41 err = setsockopt(s, SOL_TCP, TCP_REPAIR, &repair, sizeof(repair)); 42 if (CHECK_FAIL(err)) 43 goto error; 44 45 return s; 46 error: 47 perror(__func__); 48 close(s); 49 return -1; 50 } 51 52 static void compare_cookies(struct bpf_map *src, struct bpf_map *dst) 53 { 54 __u32 i, max_entries = bpf_map__max_entries(src); 55 int err, duration = 0, src_fd, dst_fd; 56 57 src_fd = bpf_map__fd(src); 58 dst_fd = bpf_map__fd(dst); 59 60 for (i = 0; i < max_entries; i++) { 61 __u64 src_cookie, dst_cookie; 62 63 err = bpf_map_lookup_elem(src_fd, &i, &src_cookie); 64 if (err && errno == ENOENT) { 65 err = bpf_map_lookup_elem(dst_fd, &i, &dst_cookie); 66 CHECK(!err, "map_lookup_elem(dst)", "element %u not deleted\n", i); 67 CHECK(err && errno != ENOENT, "map_lookup_elem(dst)", "%s\n", 68 strerror(errno)); 69 continue; 70 } 71 if (CHECK(err, "lookup_elem(src)", "%s\n", strerror(errno))) 72 continue; 73 74 err = bpf_map_lookup_elem(dst_fd, &i, &dst_cookie); 75 if (CHECK(err, "lookup_elem(dst)", "%s\n", strerror(errno))) 76 continue; 77 78 CHECK(dst_cookie != src_cookie, "cookie mismatch", 79 "%llu != %llu (pos %u)\n", dst_cookie, src_cookie, i); 80 } 81 } 82 83 /* Create a map, populate it with one socket, and free the map. */ 84 static void test_sockmap_create_update_free(enum bpf_map_type map_type) 85 { 86 const int zero = 0; 87 int s, map, err; 88 89 s = connected_socket_v4(); 90 if (CHECK_FAIL(s == -1)) 91 return; 92 93 map = bpf_create_map(map_type, sizeof(int), sizeof(int), 1, 0); 94 if (CHECK_FAIL(map == -1)) { 95 perror("bpf_create_map"); 96 goto out; 97 } 98 99 err = bpf_map_update_elem(map, &zero, &s, BPF_NOEXIST); 100 if (CHECK_FAIL(err)) { 101 perror("bpf_map_update"); 102 goto out; 103 } 104 105 out: 106 close(map); 107 close(s); 108 } 109 110 static void test_skmsg_helpers(enum bpf_map_type map_type) 111 { 112 struct test_skmsg_load_helpers *skel; 113 int err, map, verdict; 114 115 skel = test_skmsg_load_helpers__open_and_load(); 116 if (CHECK_FAIL(!skel)) { 117 perror("test_skmsg_load_helpers__open_and_load"); 118 return; 119 } 120 121 verdict = bpf_program__fd(skel->progs.prog_msg_verdict); 122 map = bpf_map__fd(skel->maps.sock_map); 123 124 err = bpf_prog_attach(verdict, map, BPF_SK_MSG_VERDICT, 0); 125 if (CHECK_FAIL(err)) { 126 perror("bpf_prog_attach"); 127 goto out; 128 } 129 130 err = bpf_prog_detach2(verdict, map, BPF_SK_MSG_VERDICT); 131 if (CHECK_FAIL(err)) { 132 perror("bpf_prog_detach2"); 133 goto out; 134 } 135 out: 136 test_skmsg_load_helpers__destroy(skel); 137 } 138 139 static void test_sockmap_update(enum bpf_map_type map_type) 140 { 141 struct bpf_prog_test_run_attr tattr; 142 int err, prog, src, duration = 0; 143 struct test_sockmap_update *skel; 144 struct bpf_map *dst_map; 145 const __u32 zero = 0; 146 char dummy[14] = {0}; 147 __s64 sk; 148 149 sk = connected_socket_v4(); 150 if (CHECK(sk == -1, "connected_socket_v4", "cannot connect\n")) 151 return; 152 153 skel = test_sockmap_update__open_and_load(); 154 if (CHECK(!skel, "open_and_load", "cannot load skeleton\n")) 155 goto close_sk; 156 157 prog = bpf_program__fd(skel->progs.copy_sock_map); 158 src = bpf_map__fd(skel->maps.src); 159 if (map_type == BPF_MAP_TYPE_SOCKMAP) 160 dst_map = skel->maps.dst_sock_map; 161 else 162 dst_map = skel->maps.dst_sock_hash; 163 164 err = bpf_map_update_elem(src, &zero, &sk, BPF_NOEXIST); 165 if (CHECK(err, "update_elem(src)", "errno=%u\n", errno)) 166 goto out; 167 168 tattr = (struct bpf_prog_test_run_attr){ 169 .prog_fd = prog, 170 .repeat = 1, 171 .data_in = dummy, 172 .data_size_in = sizeof(dummy), 173 }; 174 175 err = bpf_prog_test_run_xattr(&tattr); 176 if (CHECK_ATTR(err || !tattr.retval, "bpf_prog_test_run", 177 "errno=%u retval=%u\n", errno, tattr.retval)) 178 goto out; 179 180 compare_cookies(skel->maps.src, dst_map); 181 182 out: 183 test_sockmap_update__destroy(skel); 184 close_sk: 185 close(sk); 186 } 187 188 static void test_sockmap_invalid_update(void) 189 { 190 struct test_sockmap_invalid_update *skel; 191 int duration = 0; 192 193 skel = test_sockmap_invalid_update__open_and_load(); 194 if (CHECK(skel, "open_and_load", "verifier accepted map_update\n")) 195 test_sockmap_invalid_update__destroy(skel); 196 } 197 198 static void test_sockmap_copy(enum bpf_map_type map_type) 199 { 200 DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts); 201 int err, len, src_fd, iter_fd, duration = 0; 202 union bpf_iter_link_info linfo = {}; 203 __u32 i, num_sockets, num_elems; 204 struct bpf_iter_sockmap *skel; 205 __s64 *sock_fd = NULL; 206 struct bpf_link *link; 207 struct bpf_map *src; 208 char buf[64]; 209 210 skel = bpf_iter_sockmap__open_and_load(); 211 if (CHECK(!skel, "bpf_iter_sockmap__open_and_load", "skeleton open_and_load failed\n")) 212 return; 213 214 if (map_type == BPF_MAP_TYPE_SOCKMAP) { 215 src = skel->maps.sockmap; 216 num_elems = bpf_map__max_entries(src); 217 num_sockets = num_elems - 1; 218 } else { 219 src = skel->maps.sockhash; 220 num_elems = bpf_map__max_entries(src) - 1; 221 num_sockets = num_elems; 222 } 223 224 sock_fd = calloc(num_sockets, sizeof(*sock_fd)); 225 if (CHECK(!sock_fd, "calloc(sock_fd)", "failed to allocate\n")) 226 goto out; 227 228 for (i = 0; i < num_sockets; i++) 229 sock_fd[i] = -1; 230 231 src_fd = bpf_map__fd(src); 232 233 for (i = 0; i < num_sockets; i++) { 234 sock_fd[i] = connected_socket_v4(); 235 if (CHECK(sock_fd[i] == -1, "connected_socket_v4", "cannot connect\n")) 236 goto out; 237 238 err = bpf_map_update_elem(src_fd, &i, &sock_fd[i], BPF_NOEXIST); 239 if (CHECK(err, "map_update", "failed: %s\n", strerror(errno))) 240 goto out; 241 } 242 243 linfo.map.map_fd = src_fd; 244 opts.link_info = &linfo; 245 opts.link_info_len = sizeof(linfo); 246 link = bpf_program__attach_iter(skel->progs.copy, &opts); 247 if (CHECK(IS_ERR(link), "attach_iter", "attach_iter failed\n")) 248 goto out; 249 250 iter_fd = bpf_iter_create(bpf_link__fd(link)); 251 if (CHECK(iter_fd < 0, "create_iter", "create_iter failed\n")) 252 goto free_link; 253 254 /* do some tests */ 255 while ((len = read(iter_fd, buf, sizeof(buf))) > 0) 256 ; 257 if (CHECK(len < 0, "read", "failed: %s\n", strerror(errno))) 258 goto close_iter; 259 260 /* test results */ 261 if (CHECK(skel->bss->elems != num_elems, "elems", "got %u expected %u\n", 262 skel->bss->elems, num_elems)) 263 goto close_iter; 264 265 if (CHECK(skel->bss->socks != num_sockets, "socks", "got %u expected %u\n", 266 skel->bss->socks, num_sockets)) 267 goto close_iter; 268 269 compare_cookies(src, skel->maps.dst); 270 271 close_iter: 272 close(iter_fd); 273 free_link: 274 bpf_link__destroy(link); 275 out: 276 for (i = 0; sock_fd && i < num_sockets; i++) 277 if (sock_fd[i] >= 0) 278 close(sock_fd[i]); 279 if (sock_fd) 280 free(sock_fd); 281 bpf_iter_sockmap__destroy(skel); 282 } 283 284 void test_sockmap_basic(void) 285 { 286 if (test__start_subtest("sockmap create_update_free")) 287 test_sockmap_create_update_free(BPF_MAP_TYPE_SOCKMAP); 288 if (test__start_subtest("sockhash create_update_free")) 289 test_sockmap_create_update_free(BPF_MAP_TYPE_SOCKHASH); 290 if (test__start_subtest("sockmap sk_msg load helpers")) 291 test_skmsg_helpers(BPF_MAP_TYPE_SOCKMAP); 292 if (test__start_subtest("sockhash sk_msg load helpers")) 293 test_skmsg_helpers(BPF_MAP_TYPE_SOCKHASH); 294 if (test__start_subtest("sockmap update")) 295 test_sockmap_update(BPF_MAP_TYPE_SOCKMAP); 296 if (test__start_subtest("sockhash update")) 297 test_sockmap_update(BPF_MAP_TYPE_SOCKHASH); 298 if (test__start_subtest("sockmap update in unsafe context")) 299 test_sockmap_invalid_update(); 300 if (test__start_subtest("sockmap copy")) 301 test_sockmap_copy(BPF_MAP_TYPE_SOCKMAP); 302 if (test__start_subtest("sockhash copy")) 303 test_sockmap_copy(BPF_MAP_TYPE_SOCKHASH); 304 } 305