15d3919a9SJakub Sitnicki // SPDX-License-Identifier: GPL-2.0
25d3919a9SJakub Sitnicki // Copyright (c) 2020 Cloudflare
31d9c037aSJohn Fastabend #include <error.h>
49cacf81fSStanislav Fomichev #include <netinet/tcp.h>
51fa1fe8fSJohn Fastabend #include <sys/epoll.h>
65d3919a9SJakub Sitnicki
75d3919a9SJakub Sitnicki #include "test_progs.h"
81d9c037aSJohn Fastabend #include "test_skmsg_load_helpers.skel.h"
9bb23c0e1SLorenz Bauer #include "test_sockmap_update.skel.h"
10bb23c0e1SLorenz Bauer #include "test_sockmap_invalid_update.skel.h"
118d7cb74fSCong Wang #include "test_sockmap_skb_verdict_attach.skel.h"
12820e6e22SDi Zhu #include "test_sockmap_progs_query.skel.h"
131fa1fe8fSJohn Fastabend #include "test_sockmap_pass_prog.skel.h"
1480e24d22SJohn Fastabend #include "test_sockmap_drop_prog.skel.h"
152f7de986SLorenz Bauer #include "bpf_iter_sockmap.skel.h"
162f7de986SLorenz Bauer
171fa1fe8fSJohn Fastabend #include "sockmap_helpers.h"
181fa1fe8fSJohn Fastabend
19f2e97dc1SJohn Fastabend #define TCP_REPAIR 19 /* TCP sock is under repair right now */
20f2e97dc1SJohn Fastabend
21f2e97dc1SJohn Fastabend #define TCP_REPAIR_ON 1
22f2e97dc1SJohn Fastabend #define TCP_REPAIR_OFF_NO_WP -1 /* Turn off without window probes */
23f2e97dc1SJohn Fastabend
connected_socket_v4(void)245d3919a9SJakub Sitnicki static int connected_socket_v4(void)
255d3919a9SJakub Sitnicki {
265d3919a9SJakub Sitnicki struct sockaddr_in addr = {
275d3919a9SJakub Sitnicki .sin_family = AF_INET,
285d3919a9SJakub Sitnicki .sin_port = htons(80),
295d3919a9SJakub Sitnicki .sin_addr = { inet_addr("127.0.0.1") },
305d3919a9SJakub Sitnicki };
315d3919a9SJakub Sitnicki socklen_t len = sizeof(addr);
325d3919a9SJakub Sitnicki int s, repair, err;
335d3919a9SJakub Sitnicki
345d3919a9SJakub Sitnicki s = socket(AF_INET, SOCK_STREAM, 0);
3538e35e1dSWang Yufen if (!ASSERT_GE(s, 0, "socket"))
365d3919a9SJakub Sitnicki goto error;
375d3919a9SJakub Sitnicki
385d3919a9SJakub Sitnicki repair = TCP_REPAIR_ON;
395d3919a9SJakub Sitnicki err = setsockopt(s, SOL_TCP, TCP_REPAIR, &repair, sizeof(repair));
4038e35e1dSWang Yufen if (!ASSERT_OK(err, "setsockopt(TCP_REPAIR)"))
415d3919a9SJakub Sitnicki goto error;
425d3919a9SJakub Sitnicki
435d3919a9SJakub Sitnicki err = connect(s, (struct sockaddr *)&addr, len);
4438e35e1dSWang Yufen if (!ASSERT_OK(err, "connect"))
455d3919a9SJakub Sitnicki goto error;
465d3919a9SJakub Sitnicki
475d3919a9SJakub Sitnicki repair = TCP_REPAIR_OFF_NO_WP;
485d3919a9SJakub Sitnicki err = setsockopt(s, SOL_TCP, TCP_REPAIR, &repair, sizeof(repair));
4938e35e1dSWang Yufen if (!ASSERT_OK(err, "setsockopt(TCP_REPAIR)"))
505d3919a9SJakub Sitnicki goto error;
515d3919a9SJakub Sitnicki
525d3919a9SJakub Sitnicki return s;
535d3919a9SJakub Sitnicki error:
545d3919a9SJakub Sitnicki perror(__func__);
555d3919a9SJakub Sitnicki close(s);
565d3919a9SJakub Sitnicki return -1;
575d3919a9SJakub Sitnicki }
585d3919a9SJakub Sitnicki
compare_cookies(struct bpf_map * src,struct bpf_map * dst)5926c3270dSLorenz Bauer static void compare_cookies(struct bpf_map *src, struct bpf_map *dst)
6026c3270dSLorenz Bauer {
6126c3270dSLorenz Bauer __u32 i, max_entries = bpf_map__max_entries(src);
6238e35e1dSWang Yufen int err, src_fd, dst_fd;
6326c3270dSLorenz Bauer
6426c3270dSLorenz Bauer src_fd = bpf_map__fd(src);
6526c3270dSLorenz Bauer dst_fd = bpf_map__fd(dst);
6626c3270dSLorenz Bauer
6726c3270dSLorenz Bauer for (i = 0; i < max_entries; i++) {
6826c3270dSLorenz Bauer __u64 src_cookie, dst_cookie;
6926c3270dSLorenz Bauer
7026c3270dSLorenz Bauer err = bpf_map_lookup_elem(src_fd, &i, &src_cookie);
7126c3270dSLorenz Bauer if (err && errno == ENOENT) {
7226c3270dSLorenz Bauer err = bpf_map_lookup_elem(dst_fd, &i, &dst_cookie);
7338e35e1dSWang Yufen ASSERT_ERR(err, "map_lookup_elem(dst)");
7438e35e1dSWang Yufen ASSERT_EQ(errno, ENOENT, "map_lookup_elem(dst)");
7526c3270dSLorenz Bauer continue;
7626c3270dSLorenz Bauer }
7738e35e1dSWang Yufen if (!ASSERT_OK(err, "lookup_elem(src)"))
7826c3270dSLorenz Bauer continue;
7926c3270dSLorenz Bauer
8026c3270dSLorenz Bauer err = bpf_map_lookup_elem(dst_fd, &i, &dst_cookie);
8138e35e1dSWang Yufen if (!ASSERT_OK(err, "lookup_elem(dst)"))
8226c3270dSLorenz Bauer continue;
8326c3270dSLorenz Bauer
8438e35e1dSWang Yufen ASSERT_EQ(dst_cookie, src_cookie, "cookie mismatch");
8526c3270dSLorenz Bauer }
8626c3270dSLorenz Bauer }
8726c3270dSLorenz Bauer
885d3919a9SJakub Sitnicki /* Create a map, populate it with one socket, and free the map. */
test_sockmap_create_update_free(enum bpf_map_type map_type)895d3919a9SJakub Sitnicki static void test_sockmap_create_update_free(enum bpf_map_type map_type)
905d3919a9SJakub Sitnicki {
915d3919a9SJakub Sitnicki const int zero = 0;
925d3919a9SJakub Sitnicki int s, map, err;
935d3919a9SJakub Sitnicki
945d3919a9SJakub Sitnicki s = connected_socket_v4();
9538e35e1dSWang Yufen if (!ASSERT_GE(s, 0, "connected_socket_v4"))
965d3919a9SJakub Sitnicki return;
975d3919a9SJakub Sitnicki
982fe256a4SAndrii Nakryiko map = bpf_map_create(map_type, NULL, sizeof(int), sizeof(int), 1, NULL);
9938e35e1dSWang Yufen if (!ASSERT_GE(map, 0, "bpf_map_create"))
1005d3919a9SJakub Sitnicki goto out;
1015d3919a9SJakub Sitnicki
1025d3919a9SJakub Sitnicki err = bpf_map_update_elem(map, &zero, &s, BPF_NOEXIST);
10338e35e1dSWang Yufen if (!ASSERT_OK(err, "bpf_map_update"))
1045d3919a9SJakub Sitnicki goto out;
1055d3919a9SJakub Sitnicki
1065d3919a9SJakub Sitnicki out:
1075d3919a9SJakub Sitnicki close(map);
1085d3919a9SJakub Sitnicki close(s);
1095d3919a9SJakub Sitnicki }
1105d3919a9SJakub Sitnicki
test_skmsg_helpers(enum bpf_map_type map_type)1111d9c037aSJohn Fastabend static void test_skmsg_helpers(enum bpf_map_type map_type)
1121d9c037aSJohn Fastabend {
1131d9c037aSJohn Fastabend struct test_skmsg_load_helpers *skel;
1141d9c037aSJohn Fastabend int err, map, verdict;
1151d9c037aSJohn Fastabend
1161d9c037aSJohn Fastabend skel = test_skmsg_load_helpers__open_and_load();
11738e35e1dSWang Yufen if (!ASSERT_OK_PTR(skel, "test_skmsg_load_helpers__open_and_load"))
1181d9c037aSJohn Fastabend return;
1191d9c037aSJohn Fastabend
1201d9c037aSJohn Fastabend verdict = bpf_program__fd(skel->progs.prog_msg_verdict);
1211d9c037aSJohn Fastabend map = bpf_map__fd(skel->maps.sock_map);
1221d9c037aSJohn Fastabend
1231d9c037aSJohn Fastabend err = bpf_prog_attach(verdict, map, BPF_SK_MSG_VERDICT, 0);
12438e35e1dSWang Yufen if (!ASSERT_OK(err, "bpf_prog_attach"))
1251d9c037aSJohn Fastabend goto out;
1261d9c037aSJohn Fastabend
1271d9c037aSJohn Fastabend err = bpf_prog_detach2(verdict, map, BPF_SK_MSG_VERDICT);
12838e35e1dSWang Yufen if (!ASSERT_OK(err, "bpf_prog_detach2"))
1291d9c037aSJohn Fastabend goto out;
1301d9c037aSJohn Fastabend out:
1311d9c037aSJohn Fastabend test_skmsg_load_helpers__destroy(skel);
1321d9c037aSJohn Fastabend }
1331d9c037aSJohn Fastabend
test_sockmap_update(enum bpf_map_type map_type)134bb23c0e1SLorenz Bauer static void test_sockmap_update(enum bpf_map_type map_type)
135bb23c0e1SLorenz Bauer {
13638e35e1dSWang Yufen int err, prog, src;
137bb23c0e1SLorenz Bauer struct test_sockmap_update *skel;
13826c3270dSLorenz Bauer struct bpf_map *dst_map;
139bb23c0e1SLorenz Bauer const __u32 zero = 0;
140bb23c0e1SLorenz Bauer char dummy[14] = {0};
14139316183SDelyan Kratunov LIBBPF_OPTS(bpf_test_run_opts, topts,
14239316183SDelyan Kratunov .data_in = dummy,
14339316183SDelyan Kratunov .data_size_in = sizeof(dummy),
14439316183SDelyan Kratunov .repeat = 1,
14539316183SDelyan Kratunov );
146bb23c0e1SLorenz Bauer __s64 sk;
147bb23c0e1SLorenz Bauer
148bb23c0e1SLorenz Bauer sk = connected_socket_v4();
14938e35e1dSWang Yufen if (!ASSERT_NEQ(sk, -1, "connected_socket_v4"))
150bb23c0e1SLorenz Bauer return;
151bb23c0e1SLorenz Bauer
152bb23c0e1SLorenz Bauer skel = test_sockmap_update__open_and_load();
15338e35e1dSWang Yufen if (!ASSERT_OK_PTR(skel, "open_and_load"))
1548c3b3d97SLorenz Bauer goto close_sk;
155bb23c0e1SLorenz Bauer
156bb23c0e1SLorenz Bauer prog = bpf_program__fd(skel->progs.copy_sock_map);
157bb23c0e1SLorenz Bauer src = bpf_map__fd(skel->maps.src);
158bb23c0e1SLorenz Bauer if (map_type == BPF_MAP_TYPE_SOCKMAP)
15926c3270dSLorenz Bauer dst_map = skel->maps.dst_sock_map;
160bb23c0e1SLorenz Bauer else
16126c3270dSLorenz Bauer dst_map = skel->maps.dst_sock_hash;
162bb23c0e1SLorenz Bauer
163bb23c0e1SLorenz Bauer err = bpf_map_update_elem(src, &zero, &sk, BPF_NOEXIST);
16438e35e1dSWang Yufen if (!ASSERT_OK(err, "update_elem(src)"))
165bb23c0e1SLorenz Bauer goto out;
166bb23c0e1SLorenz Bauer
16739316183SDelyan Kratunov err = bpf_prog_test_run_opts(prog, &topts);
16839316183SDelyan Kratunov if (!ASSERT_OK(err, "test_run"))
16939316183SDelyan Kratunov goto out;
17039316183SDelyan Kratunov if (!ASSERT_NEQ(topts.retval, 0, "test_run retval"))
171bb23c0e1SLorenz Bauer goto out;
172bb23c0e1SLorenz Bauer
17326c3270dSLorenz Bauer compare_cookies(skel->maps.src, dst_map);
174bb23c0e1SLorenz Bauer
175bb23c0e1SLorenz Bauer out:
176bb23c0e1SLorenz Bauer test_sockmap_update__destroy(skel);
1778c3b3d97SLorenz Bauer close_sk:
1788c3b3d97SLorenz Bauer close(sk);
179bb23c0e1SLorenz Bauer }
180bb23c0e1SLorenz Bauer
test_sockmap_invalid_update(void)181bb23c0e1SLorenz Bauer static void test_sockmap_invalid_update(void)
182bb23c0e1SLorenz Bauer {
183bb23c0e1SLorenz Bauer struct test_sockmap_invalid_update *skel;
184bb23c0e1SLorenz Bauer
185bb23c0e1SLorenz Bauer skel = test_sockmap_invalid_update__open_and_load();
18638e35e1dSWang Yufen if (!ASSERT_NULL(skel, "open_and_load"))
187bb23c0e1SLorenz Bauer test_sockmap_invalid_update__destroy(skel);
188bb23c0e1SLorenz Bauer }
189bb23c0e1SLorenz Bauer
test_sockmap_copy(enum bpf_map_type map_type)1905b87adc3SLorenz Bauer static void test_sockmap_copy(enum bpf_map_type map_type)
1912f7de986SLorenz Bauer {
1922f7de986SLorenz Bauer DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
19338e35e1dSWang Yufen int err, len, src_fd, iter_fd;
19448ca6243SStanislav Fomichev union bpf_iter_link_info linfo = {};
19527870317SLorenz Bauer __u32 i, num_sockets, num_elems;
1962f7de986SLorenz Bauer struct bpf_iter_sockmap *skel;
19727870317SLorenz Bauer __s64 *sock_fd = NULL;
1982f7de986SLorenz Bauer struct bpf_link *link;
1992f7de986SLorenz Bauer struct bpf_map *src;
2002f7de986SLorenz Bauer char buf[64];
2012f7de986SLorenz Bauer
2022f7de986SLorenz Bauer skel = bpf_iter_sockmap__open_and_load();
20338e35e1dSWang Yufen if (!ASSERT_OK_PTR(skel, "bpf_iter_sockmap__open_and_load"))
2042f7de986SLorenz Bauer return;
2052f7de986SLorenz Bauer
2062f7de986SLorenz Bauer if (map_type == BPF_MAP_TYPE_SOCKMAP) {
2072f7de986SLorenz Bauer src = skel->maps.sockmap;
20827870317SLorenz Bauer num_elems = bpf_map__max_entries(src);
20927870317SLorenz Bauer num_sockets = num_elems - 1;
2102f7de986SLorenz Bauer } else {
2112f7de986SLorenz Bauer src = skel->maps.sockhash;
21227870317SLorenz Bauer num_elems = bpf_map__max_entries(src) - 1;
21327870317SLorenz Bauer num_sockets = num_elems;
2142f7de986SLorenz Bauer }
2152f7de986SLorenz Bauer
21627870317SLorenz Bauer sock_fd = calloc(num_sockets, sizeof(*sock_fd));
21738e35e1dSWang Yufen if (!ASSERT_OK_PTR(sock_fd, "calloc(sock_fd)"))
21827870317SLorenz Bauer goto out;
21927870317SLorenz Bauer
22027870317SLorenz Bauer for (i = 0; i < num_sockets; i++)
22127870317SLorenz Bauer sock_fd[i] = -1;
22227870317SLorenz Bauer
2232f7de986SLorenz Bauer src_fd = bpf_map__fd(src);
2242f7de986SLorenz Bauer
2252f7de986SLorenz Bauer for (i = 0; i < num_sockets; i++) {
2262f7de986SLorenz Bauer sock_fd[i] = connected_socket_v4();
22738e35e1dSWang Yufen if (!ASSERT_NEQ(sock_fd[i], -1, "connected_socket_v4"))
2282f7de986SLorenz Bauer goto out;
2292f7de986SLorenz Bauer
2302f7de986SLorenz Bauer err = bpf_map_update_elem(src_fd, &i, &sock_fd[i], BPF_NOEXIST);
23138e35e1dSWang Yufen if (!ASSERT_OK(err, "map_update"))
2322f7de986SLorenz Bauer goto out;
2332f7de986SLorenz Bauer }
2342f7de986SLorenz Bauer
2352f7de986SLorenz Bauer linfo.map.map_fd = src_fd;
2362f7de986SLorenz Bauer opts.link_info = &linfo;
2372f7de986SLorenz Bauer opts.link_info_len = sizeof(linfo);
2385b87adc3SLorenz Bauer link = bpf_program__attach_iter(skel->progs.copy, &opts);
239bad2e478SAndrii Nakryiko if (!ASSERT_OK_PTR(link, "attach_iter"))
2402f7de986SLorenz Bauer goto out;
2412f7de986SLorenz Bauer
2422f7de986SLorenz Bauer iter_fd = bpf_iter_create(bpf_link__fd(link));
24338e35e1dSWang Yufen if (!ASSERT_GE(iter_fd, 0, "create_iter"))
2442f7de986SLorenz Bauer goto free_link;
2452f7de986SLorenz Bauer
2462f7de986SLorenz Bauer /* do some tests */
2472f7de986SLorenz Bauer while ((len = read(iter_fd, buf, sizeof(buf))) > 0)
2482f7de986SLorenz Bauer ;
24938e35e1dSWang Yufen if (!ASSERT_GE(len, 0, "read"))
2502f7de986SLorenz Bauer goto close_iter;
2512f7de986SLorenz Bauer
2522f7de986SLorenz Bauer /* test results */
25338e35e1dSWang Yufen if (!ASSERT_EQ(skel->bss->elems, num_elems, "elems"))
2542f7de986SLorenz Bauer goto close_iter;
2552f7de986SLorenz Bauer
25638e35e1dSWang Yufen if (!ASSERT_EQ(skel->bss->socks, num_sockets, "socks"))
2572f7de986SLorenz Bauer goto close_iter;
2582f7de986SLorenz Bauer
2595b87adc3SLorenz Bauer compare_cookies(src, skel->maps.dst);
2605b87adc3SLorenz Bauer
2612f7de986SLorenz Bauer close_iter:
2622f7de986SLorenz Bauer close(iter_fd);
2632f7de986SLorenz Bauer free_link:
2642f7de986SLorenz Bauer bpf_link__destroy(link);
2652f7de986SLorenz Bauer out:
26627870317SLorenz Bauer for (i = 0; sock_fd && i < num_sockets; i++)
2672f7de986SLorenz Bauer if (sock_fd[i] >= 0)
2682f7de986SLorenz Bauer close(sock_fd[i]);
26927870317SLorenz Bauer if (sock_fd)
27027870317SLorenz Bauer free(sock_fd);
2712f7de986SLorenz Bauer bpf_iter_sockmap__destroy(skel);
2722f7de986SLorenz Bauer }
2732f7de986SLorenz Bauer
test_sockmap_skb_verdict_attach(enum bpf_attach_type first,enum bpf_attach_type second)2748d7cb74fSCong Wang static void test_sockmap_skb_verdict_attach(enum bpf_attach_type first,
2758d7cb74fSCong Wang enum bpf_attach_type second)
2768d7cb74fSCong Wang {
2778d7cb74fSCong Wang struct test_sockmap_skb_verdict_attach *skel;
2788d7cb74fSCong Wang int err, map, verdict;
2798d7cb74fSCong Wang
2808d7cb74fSCong Wang skel = test_sockmap_skb_verdict_attach__open_and_load();
28138e35e1dSWang Yufen if (!ASSERT_OK_PTR(skel, "open_and_load"))
2828d7cb74fSCong Wang return;
2838d7cb74fSCong Wang
2848d7cb74fSCong Wang verdict = bpf_program__fd(skel->progs.prog_skb_verdict);
2858d7cb74fSCong Wang map = bpf_map__fd(skel->maps.sock_map);
2868d7cb74fSCong Wang
2878d7cb74fSCong Wang err = bpf_prog_attach(verdict, map, first, 0);
28838e35e1dSWang Yufen if (!ASSERT_OK(err, "bpf_prog_attach"))
2898d7cb74fSCong Wang goto out;
2908d7cb74fSCong Wang
2918d7cb74fSCong Wang err = bpf_prog_attach(verdict, map, second, 0);
292bad2e478SAndrii Nakryiko ASSERT_EQ(err, -EBUSY, "prog_attach_fail");
2938d7cb74fSCong Wang
2948d7cb74fSCong Wang err = bpf_prog_detach2(verdict, map, first);
29538e35e1dSWang Yufen if (!ASSERT_OK(err, "bpf_prog_detach2"))
2968d7cb74fSCong Wang goto out;
2978d7cb74fSCong Wang out:
2988d7cb74fSCong Wang test_sockmap_skb_verdict_attach__destroy(skel);
2998d7cb74fSCong Wang }
3008d7cb74fSCong Wang
query_prog_id(int prog_fd)301820e6e22SDi Zhu static __u32 query_prog_id(int prog_fd)
302820e6e22SDi Zhu {
303820e6e22SDi Zhu struct bpf_prog_info info = {};
304820e6e22SDi Zhu __u32 info_len = sizeof(info);
305820e6e22SDi Zhu int err;
306820e6e22SDi Zhu
307c5a237a4SIlya Leoshkevich err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len);
308c5a237a4SIlya Leoshkevich if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd") ||
309c5a237a4SIlya Leoshkevich !ASSERT_EQ(info_len, sizeof(info), "bpf_prog_get_info_by_fd"))
310820e6e22SDi Zhu return 0;
311820e6e22SDi Zhu
312820e6e22SDi Zhu return info.id;
313820e6e22SDi Zhu }
314820e6e22SDi Zhu
test_sockmap_progs_query(enum bpf_attach_type attach_type)315820e6e22SDi Zhu static void test_sockmap_progs_query(enum bpf_attach_type attach_type)
316820e6e22SDi Zhu {
317820e6e22SDi Zhu struct test_sockmap_progs_query *skel;
318820e6e22SDi Zhu int err, map_fd, verdict_fd;
319820e6e22SDi Zhu __u32 attach_flags = 0;
320820e6e22SDi Zhu __u32 prog_ids[3] = {};
321820e6e22SDi Zhu __u32 prog_cnt = 3;
322820e6e22SDi Zhu
323820e6e22SDi Zhu skel = test_sockmap_progs_query__open_and_load();
324820e6e22SDi Zhu if (!ASSERT_OK_PTR(skel, "test_sockmap_progs_query__open_and_load"))
325820e6e22SDi Zhu return;
326820e6e22SDi Zhu
327820e6e22SDi Zhu map_fd = bpf_map__fd(skel->maps.sock_map);
328820e6e22SDi Zhu
329820e6e22SDi Zhu if (attach_type == BPF_SK_MSG_VERDICT)
330820e6e22SDi Zhu verdict_fd = bpf_program__fd(skel->progs.prog_skmsg_verdict);
331820e6e22SDi Zhu else
332820e6e22SDi Zhu verdict_fd = bpf_program__fd(skel->progs.prog_skb_verdict);
333820e6e22SDi Zhu
334820e6e22SDi Zhu err = bpf_prog_query(map_fd, attach_type, 0 /* query flags */,
335820e6e22SDi Zhu &attach_flags, prog_ids, &prog_cnt);
336820e6e22SDi Zhu ASSERT_OK(err, "bpf_prog_query failed");
337820e6e22SDi Zhu ASSERT_EQ(attach_flags, 0, "wrong attach_flags on query");
338820e6e22SDi Zhu ASSERT_EQ(prog_cnt, 0, "wrong program count on query");
339820e6e22SDi Zhu
340820e6e22SDi Zhu err = bpf_prog_attach(verdict_fd, map_fd, attach_type, 0);
341820e6e22SDi Zhu if (!ASSERT_OK(err, "bpf_prog_attach failed"))
342820e6e22SDi Zhu goto out;
343820e6e22SDi Zhu
344820e6e22SDi Zhu prog_cnt = 1;
345820e6e22SDi Zhu err = bpf_prog_query(map_fd, attach_type, 0 /* query flags */,
346820e6e22SDi Zhu &attach_flags, prog_ids, &prog_cnt);
347820e6e22SDi Zhu ASSERT_OK(err, "bpf_prog_query failed");
348820e6e22SDi Zhu ASSERT_EQ(attach_flags, 0, "wrong attach_flags on query");
349820e6e22SDi Zhu ASSERT_EQ(prog_cnt, 1, "wrong program count on query");
350820e6e22SDi Zhu ASSERT_EQ(prog_ids[0], query_prog_id(verdict_fd),
351820e6e22SDi Zhu "wrong prog_ids on query");
352820e6e22SDi Zhu
353820e6e22SDi Zhu bpf_prog_detach2(verdict_fd, map_fd, attach_type);
354820e6e22SDi Zhu out:
355820e6e22SDi Zhu test_sockmap_progs_query__destroy(skel);
356820e6e22SDi Zhu }
357820e6e22SDi Zhu
3581fa1fe8fSJohn Fastabend #define MAX_EVENTS 10
test_sockmap_skb_verdict_shutdown(void)3591fa1fe8fSJohn Fastabend static void test_sockmap_skb_verdict_shutdown(void)
3601fa1fe8fSJohn Fastabend {
3611fa1fe8fSJohn Fastabend struct epoll_event ev, events[MAX_EVENTS];
3621fa1fe8fSJohn Fastabend int n, err, map, verdict, s, c1, p1;
3631fa1fe8fSJohn Fastabend struct test_sockmap_pass_prog *skel;
3641fa1fe8fSJohn Fastabend int epollfd;
3651fa1fe8fSJohn Fastabend int zero = 0;
3661fa1fe8fSJohn Fastabend char b;
3671fa1fe8fSJohn Fastabend
3681fa1fe8fSJohn Fastabend skel = test_sockmap_pass_prog__open_and_load();
3691fa1fe8fSJohn Fastabend if (!ASSERT_OK_PTR(skel, "open_and_load"))
3701fa1fe8fSJohn Fastabend return;
3711fa1fe8fSJohn Fastabend
3721fa1fe8fSJohn Fastabend verdict = bpf_program__fd(skel->progs.prog_skb_verdict);
3731fa1fe8fSJohn Fastabend map = bpf_map__fd(skel->maps.sock_map_rx);
3741fa1fe8fSJohn Fastabend
3751fa1fe8fSJohn Fastabend err = bpf_prog_attach(verdict, map, BPF_SK_SKB_STREAM_VERDICT, 0);
3761fa1fe8fSJohn Fastabend if (!ASSERT_OK(err, "bpf_prog_attach"))
3771fa1fe8fSJohn Fastabend goto out;
3781fa1fe8fSJohn Fastabend
3791fa1fe8fSJohn Fastabend s = socket_loopback(AF_INET, SOCK_STREAM);
3801fa1fe8fSJohn Fastabend if (s < 0)
3811fa1fe8fSJohn Fastabend goto out;
3821fa1fe8fSJohn Fastabend err = create_pair(s, AF_INET, SOCK_STREAM, &c1, &p1);
3831fa1fe8fSJohn Fastabend if (err < 0)
3841fa1fe8fSJohn Fastabend goto out;
3851fa1fe8fSJohn Fastabend
3861fa1fe8fSJohn Fastabend err = bpf_map_update_elem(map, &zero, &c1, BPF_NOEXIST);
3871fa1fe8fSJohn Fastabend if (err < 0)
3881fa1fe8fSJohn Fastabend goto out_close;
3891fa1fe8fSJohn Fastabend
3901fa1fe8fSJohn Fastabend shutdown(p1, SHUT_WR);
3911fa1fe8fSJohn Fastabend
3921fa1fe8fSJohn Fastabend ev.events = EPOLLIN;
3931fa1fe8fSJohn Fastabend ev.data.fd = c1;
3941fa1fe8fSJohn Fastabend
3951fa1fe8fSJohn Fastabend epollfd = epoll_create1(0);
3961fa1fe8fSJohn Fastabend if (!ASSERT_GT(epollfd, -1, "epoll_create(0)"))
3971fa1fe8fSJohn Fastabend goto out_close;
3981fa1fe8fSJohn Fastabend err = epoll_ctl(epollfd, EPOLL_CTL_ADD, c1, &ev);
3991fa1fe8fSJohn Fastabend if (!ASSERT_OK(err, "epoll_ctl(EPOLL_CTL_ADD)"))
4001fa1fe8fSJohn Fastabend goto out_close;
4011fa1fe8fSJohn Fastabend err = epoll_wait(epollfd, events, MAX_EVENTS, -1);
4021fa1fe8fSJohn Fastabend if (!ASSERT_EQ(err, 1, "epoll_wait(fd)"))
4031fa1fe8fSJohn Fastabend goto out_close;
4041fa1fe8fSJohn Fastabend
405*dfbaf8a6SJiayuan Chen n = recv(c1, &b, 1, MSG_DONTWAIT);
406*dfbaf8a6SJiayuan Chen ASSERT_EQ(n, 0, "recv(fin)");
4071fa1fe8fSJohn Fastabend out_close:
4081fa1fe8fSJohn Fastabend close(c1);
4091fa1fe8fSJohn Fastabend close(p1);
4101fa1fe8fSJohn Fastabend out:
4111fa1fe8fSJohn Fastabend test_sockmap_pass_prog__destroy(skel);
4121fa1fe8fSJohn Fastabend }
4131fa1fe8fSJohn Fastabend
test_sockmap_skb_verdict_fionread(bool pass_prog)41480e24d22SJohn Fastabend static void test_sockmap_skb_verdict_fionread(bool pass_prog)
415bb516f98SJohn Fastabend {
41680e24d22SJohn Fastabend int expected, zero = 0, sent, recvd, avail;
417bb516f98SJohn Fastabend int err, map, verdict, s, c0, c1, p0, p1;
41880e24d22SJohn Fastabend struct test_sockmap_pass_prog *pass;
41980e24d22SJohn Fastabend struct test_sockmap_drop_prog *drop;
420bb516f98SJohn Fastabend char buf[256] = "0123456789";
421bb516f98SJohn Fastabend
42280e24d22SJohn Fastabend if (pass_prog) {
42380e24d22SJohn Fastabend pass = test_sockmap_pass_prog__open_and_load();
42480e24d22SJohn Fastabend if (!ASSERT_OK_PTR(pass, "open_and_load"))
425bb516f98SJohn Fastabend return;
42680e24d22SJohn Fastabend verdict = bpf_program__fd(pass->progs.prog_skb_verdict);
42780e24d22SJohn Fastabend map = bpf_map__fd(pass->maps.sock_map_rx);
42880e24d22SJohn Fastabend expected = sizeof(buf);
42980e24d22SJohn Fastabend } else {
43080e24d22SJohn Fastabend drop = test_sockmap_drop_prog__open_and_load();
43180e24d22SJohn Fastabend if (!ASSERT_OK_PTR(drop, "open_and_load"))
43280e24d22SJohn Fastabend return;
43380e24d22SJohn Fastabend verdict = bpf_program__fd(drop->progs.prog_skb_verdict);
43480e24d22SJohn Fastabend map = bpf_map__fd(drop->maps.sock_map_rx);
43580e24d22SJohn Fastabend /* On drop data is consumed immediately and copied_seq inc'd */
43680e24d22SJohn Fastabend expected = 0;
43780e24d22SJohn Fastabend }
438bb516f98SJohn Fastabend
439bb516f98SJohn Fastabend
440bb516f98SJohn Fastabend err = bpf_prog_attach(verdict, map, BPF_SK_SKB_STREAM_VERDICT, 0);
441bb516f98SJohn Fastabend if (!ASSERT_OK(err, "bpf_prog_attach"))
442bb516f98SJohn Fastabend goto out;
443bb516f98SJohn Fastabend
444bb516f98SJohn Fastabend s = socket_loopback(AF_INET, SOCK_STREAM);
445bb516f98SJohn Fastabend if (!ASSERT_GT(s, -1, "socket_loopback(s)"))
446bb516f98SJohn Fastabend goto out;
447bb516f98SJohn Fastabend err = create_socket_pairs(s, AF_INET, SOCK_STREAM, &c0, &c1, &p0, &p1);
448bb516f98SJohn Fastabend if (!ASSERT_OK(err, "create_socket_pairs(s)"))
449bb516f98SJohn Fastabend goto out;
450bb516f98SJohn Fastabend
451bb516f98SJohn Fastabend err = bpf_map_update_elem(map, &zero, &c1, BPF_NOEXIST);
452bb516f98SJohn Fastabend if (!ASSERT_OK(err, "bpf_map_update_elem(c1)"))
453bb516f98SJohn Fastabend goto out_close;
454bb516f98SJohn Fastabend
455bb516f98SJohn Fastabend sent = xsend(p1, &buf, sizeof(buf), 0);
456bb516f98SJohn Fastabend ASSERT_EQ(sent, sizeof(buf), "xsend(p0)");
457bb516f98SJohn Fastabend err = ioctl(c1, FIONREAD, &avail);
458bb516f98SJohn Fastabend ASSERT_OK(err, "ioctl(FIONREAD) error");
45980e24d22SJohn Fastabend ASSERT_EQ(avail, expected, "ioctl(FIONREAD)");
46080e24d22SJohn Fastabend /* On DROP test there will be no data to read */
46180e24d22SJohn Fastabend if (pass_prog) {
462*dfbaf8a6SJiayuan Chen recvd = recv_timeout(c1, &buf, sizeof(buf), MSG_DONTWAIT, IO_TIMEOUT_SEC);
463bb516f98SJohn Fastabend ASSERT_EQ(recvd, sizeof(buf), "recv_timeout(c0)");
46480e24d22SJohn Fastabend }
465bb516f98SJohn Fastabend
466bb516f98SJohn Fastabend out_close:
467bb516f98SJohn Fastabend close(c0);
468bb516f98SJohn Fastabend close(p0);
469bb516f98SJohn Fastabend close(c1);
470bb516f98SJohn Fastabend close(p1);
471bb516f98SJohn Fastabend out:
47280e24d22SJohn Fastabend if (pass_prog)
47380e24d22SJohn Fastabend test_sockmap_pass_prog__destroy(pass);
47480e24d22SJohn Fastabend else
47580e24d22SJohn Fastabend test_sockmap_drop_prog__destroy(drop);
476bb516f98SJohn Fastabend }
477bb516f98SJohn Fastabend
test_sockmap_skb_verdict_peek(void)4785f405c0cSJohn Fastabend static void test_sockmap_skb_verdict_peek(void)
4795f405c0cSJohn Fastabend {
4805f405c0cSJohn Fastabend int err, map, verdict, s, c1, p1, zero = 0, sent, recvd, avail;
4815f405c0cSJohn Fastabend struct test_sockmap_pass_prog *pass;
4825f405c0cSJohn Fastabend char snd[256] = "0123456789";
4835f405c0cSJohn Fastabend char rcv[256] = "0";
4845f405c0cSJohn Fastabend
4855f405c0cSJohn Fastabend pass = test_sockmap_pass_prog__open_and_load();
4865f405c0cSJohn Fastabend if (!ASSERT_OK_PTR(pass, "open_and_load"))
4875f405c0cSJohn Fastabend return;
4885f405c0cSJohn Fastabend verdict = bpf_program__fd(pass->progs.prog_skb_verdict);
4895f405c0cSJohn Fastabend map = bpf_map__fd(pass->maps.sock_map_rx);
4905f405c0cSJohn Fastabend
4915f405c0cSJohn Fastabend err = bpf_prog_attach(verdict, map, BPF_SK_SKB_STREAM_VERDICT, 0);
4925f405c0cSJohn Fastabend if (!ASSERT_OK(err, "bpf_prog_attach"))
4935f405c0cSJohn Fastabend goto out;
4945f405c0cSJohn Fastabend
4955f405c0cSJohn Fastabend s = socket_loopback(AF_INET, SOCK_STREAM);
4965f405c0cSJohn Fastabend if (!ASSERT_GT(s, -1, "socket_loopback(s)"))
4975f405c0cSJohn Fastabend goto out;
4985f405c0cSJohn Fastabend
4995f405c0cSJohn Fastabend err = create_pair(s, AF_INET, SOCK_STREAM, &c1, &p1);
5005f405c0cSJohn Fastabend if (!ASSERT_OK(err, "create_pairs(s)"))
5015f405c0cSJohn Fastabend goto out;
5025f405c0cSJohn Fastabend
5035f405c0cSJohn Fastabend err = bpf_map_update_elem(map, &zero, &c1, BPF_NOEXIST);
5045f405c0cSJohn Fastabend if (!ASSERT_OK(err, "bpf_map_update_elem(c1)"))
5055f405c0cSJohn Fastabend goto out_close;
5065f405c0cSJohn Fastabend
5075f405c0cSJohn Fastabend sent = xsend(p1, snd, sizeof(snd), 0);
5085f405c0cSJohn Fastabend ASSERT_EQ(sent, sizeof(snd), "xsend(p1)");
5095f405c0cSJohn Fastabend recvd = recv(c1, rcv, sizeof(rcv), MSG_PEEK);
5105f405c0cSJohn Fastabend ASSERT_EQ(recvd, sizeof(rcv), "recv(c1)");
5115f405c0cSJohn Fastabend err = ioctl(c1, FIONREAD, &avail);
5125f405c0cSJohn Fastabend ASSERT_OK(err, "ioctl(FIONREAD) error");
5135f405c0cSJohn Fastabend ASSERT_EQ(avail, sizeof(snd), "after peek ioctl(FIONREAD)");
5145f405c0cSJohn Fastabend recvd = recv(c1, rcv, sizeof(rcv), 0);
5155f405c0cSJohn Fastabend ASSERT_EQ(recvd, sizeof(rcv), "recv(p0)");
5165f405c0cSJohn Fastabend err = ioctl(c1, FIONREAD, &avail);
5175f405c0cSJohn Fastabend ASSERT_OK(err, "ioctl(FIONREAD) error");
5185f405c0cSJohn Fastabend ASSERT_EQ(avail, 0, "after read ioctl(FIONREAD)");
5195f405c0cSJohn Fastabend
5205f405c0cSJohn Fastabend out_close:
5215f405c0cSJohn Fastabend close(c1);
5225f405c0cSJohn Fastabend close(p1);
5235f405c0cSJohn Fastabend out:
5245f405c0cSJohn Fastabend test_sockmap_pass_prog__destroy(pass);
5255f405c0cSJohn Fastabend }
5265f405c0cSJohn Fastabend
test_sockmap_basic(void)5275d3919a9SJakub Sitnicki void test_sockmap_basic(void)
5285d3919a9SJakub Sitnicki {
5295d3919a9SJakub Sitnicki if (test__start_subtest("sockmap create_update_free"))
5305d3919a9SJakub Sitnicki test_sockmap_create_update_free(BPF_MAP_TYPE_SOCKMAP);
5315d3919a9SJakub Sitnicki if (test__start_subtest("sockhash create_update_free"))
5325d3919a9SJakub Sitnicki test_sockmap_create_update_free(BPF_MAP_TYPE_SOCKHASH);
5331d9c037aSJohn Fastabend if (test__start_subtest("sockmap sk_msg load helpers"))
5341d9c037aSJohn Fastabend test_skmsg_helpers(BPF_MAP_TYPE_SOCKMAP);
5351d9c037aSJohn Fastabend if (test__start_subtest("sockhash sk_msg load helpers"))
5361d9c037aSJohn Fastabend test_skmsg_helpers(BPF_MAP_TYPE_SOCKHASH);
537bb23c0e1SLorenz Bauer if (test__start_subtest("sockmap update"))
538bb23c0e1SLorenz Bauer test_sockmap_update(BPF_MAP_TYPE_SOCKMAP);
539bb23c0e1SLorenz Bauer if (test__start_subtest("sockhash update"))
540bb23c0e1SLorenz Bauer test_sockmap_update(BPF_MAP_TYPE_SOCKHASH);
541bb23c0e1SLorenz Bauer if (test__start_subtest("sockmap update in unsafe context"))
542bb23c0e1SLorenz Bauer test_sockmap_invalid_update();
5435b87adc3SLorenz Bauer if (test__start_subtest("sockmap copy"))
5445b87adc3SLorenz Bauer test_sockmap_copy(BPF_MAP_TYPE_SOCKMAP);
5455b87adc3SLorenz Bauer if (test__start_subtest("sockhash copy"))
5465b87adc3SLorenz Bauer test_sockmap_copy(BPF_MAP_TYPE_SOCKHASH);
5478d7cb74fSCong Wang if (test__start_subtest("sockmap skb_verdict attach")) {
5488d7cb74fSCong Wang test_sockmap_skb_verdict_attach(BPF_SK_SKB_VERDICT,
5498d7cb74fSCong Wang BPF_SK_SKB_STREAM_VERDICT);
5508d7cb74fSCong Wang test_sockmap_skb_verdict_attach(BPF_SK_SKB_STREAM_VERDICT,
5518d7cb74fSCong Wang BPF_SK_SKB_VERDICT);
5528d7cb74fSCong Wang }
553820e6e22SDi Zhu if (test__start_subtest("sockmap msg_verdict progs query"))
554820e6e22SDi Zhu test_sockmap_progs_query(BPF_SK_MSG_VERDICT);
555820e6e22SDi Zhu if (test__start_subtest("sockmap stream_parser progs query"))
556820e6e22SDi Zhu test_sockmap_progs_query(BPF_SK_SKB_STREAM_PARSER);
557820e6e22SDi Zhu if (test__start_subtest("sockmap stream_verdict progs query"))
558820e6e22SDi Zhu test_sockmap_progs_query(BPF_SK_SKB_STREAM_VERDICT);
559820e6e22SDi Zhu if (test__start_subtest("sockmap skb_verdict progs query"))
560820e6e22SDi Zhu test_sockmap_progs_query(BPF_SK_SKB_VERDICT);
5611fa1fe8fSJohn Fastabend if (test__start_subtest("sockmap skb_verdict shutdown"))
5621fa1fe8fSJohn Fastabend test_sockmap_skb_verdict_shutdown();
563bb516f98SJohn Fastabend if (test__start_subtest("sockmap skb_verdict fionread"))
56480e24d22SJohn Fastabend test_sockmap_skb_verdict_fionread(true);
56580e24d22SJohn Fastabend if (test__start_subtest("sockmap skb_verdict fionread on drop"))
56680e24d22SJohn Fastabend test_sockmap_skb_verdict_fionread(false);
5675f405c0cSJohn Fastabend if (test__start_subtest("sockmap skb_verdict msg_f_peek"))
5685f405c0cSJohn Fastabend test_sockmap_skb_verdict_peek();
5695d3919a9SJakub Sitnicki }
570