xref: /linux/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c (revision 0deca83ff1118f305fc7fb11e5a4b13e876201e8)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2020 Cloudflare
3 #include <error.h>
4 
5 #include "test_progs.h"
6 #include "test_skmsg_load_helpers.skel.h"
7 #include "test_sockmap_update.skel.h"
8 #include "test_sockmap_invalid_update.skel.h"
9 
10 #define TCP_REPAIR		19	/* TCP sock is under repair right now */
11 
12 #define TCP_REPAIR_ON		1
13 #define TCP_REPAIR_OFF_NO_WP	-1	/* Turn off without window probes */
14 
15 static int connected_socket_v4(void)
16 {
17 	struct sockaddr_in addr = {
18 		.sin_family = AF_INET,
19 		.sin_port = htons(80),
20 		.sin_addr = { inet_addr("127.0.0.1") },
21 	};
22 	socklen_t len = sizeof(addr);
23 	int s, repair, err;
24 
25 	s = socket(AF_INET, SOCK_STREAM, 0);
26 	if (CHECK_FAIL(s == -1))
27 		goto error;
28 
29 	repair = TCP_REPAIR_ON;
30 	err = setsockopt(s, SOL_TCP, TCP_REPAIR, &repair, sizeof(repair));
31 	if (CHECK_FAIL(err))
32 		goto error;
33 
34 	err = connect(s, (struct sockaddr *)&addr, len);
35 	if (CHECK_FAIL(err))
36 		goto error;
37 
38 	repair = TCP_REPAIR_OFF_NO_WP;
39 	err = setsockopt(s, SOL_TCP, TCP_REPAIR, &repair, sizeof(repair));
40 	if (CHECK_FAIL(err))
41 		goto error;
42 
43 	return s;
44 error:
45 	perror(__func__);
46 	close(s);
47 	return -1;
48 }
49 
50 /* Create a map, populate it with one socket, and free the map. */
51 static void test_sockmap_create_update_free(enum bpf_map_type map_type)
52 {
53 	const int zero = 0;
54 	int s, map, err;
55 
56 	s = connected_socket_v4();
57 	if (CHECK_FAIL(s == -1))
58 		return;
59 
60 	map = bpf_create_map(map_type, sizeof(int), sizeof(int), 1, 0);
61 	if (CHECK_FAIL(map == -1)) {
62 		perror("bpf_create_map");
63 		goto out;
64 	}
65 
66 	err = bpf_map_update_elem(map, &zero, &s, BPF_NOEXIST);
67 	if (CHECK_FAIL(err)) {
68 		perror("bpf_map_update");
69 		goto out;
70 	}
71 
72 out:
73 	close(map);
74 	close(s);
75 }
76 
77 static void test_skmsg_helpers(enum bpf_map_type map_type)
78 {
79 	struct test_skmsg_load_helpers *skel;
80 	int err, map, verdict;
81 
82 	skel = test_skmsg_load_helpers__open_and_load();
83 	if (CHECK_FAIL(!skel)) {
84 		perror("test_skmsg_load_helpers__open_and_load");
85 		return;
86 	}
87 
88 	verdict = bpf_program__fd(skel->progs.prog_msg_verdict);
89 	map = bpf_map__fd(skel->maps.sock_map);
90 
91 	err = bpf_prog_attach(verdict, map, BPF_SK_MSG_VERDICT, 0);
92 	if (CHECK_FAIL(err)) {
93 		perror("bpf_prog_attach");
94 		goto out;
95 	}
96 
97 	err = bpf_prog_detach2(verdict, map, BPF_SK_MSG_VERDICT);
98 	if (CHECK_FAIL(err)) {
99 		perror("bpf_prog_detach2");
100 		goto out;
101 	}
102 out:
103 	test_skmsg_load_helpers__destroy(skel);
104 }
105 
106 static void test_sockmap_update(enum bpf_map_type map_type)
107 {
108 	struct bpf_prog_test_run_attr tattr;
109 	int err, prog, src, dst, duration = 0;
110 	struct test_sockmap_update *skel;
111 	__u64 src_cookie, dst_cookie;
112 	const __u32 zero = 0;
113 	char dummy[14] = {0};
114 	__s64 sk;
115 
116 	sk = connected_socket_v4();
117 	if (CHECK(sk == -1, "connected_socket_v4", "cannot connect\n"))
118 		return;
119 
120 	skel = test_sockmap_update__open_and_load();
121 	if (CHECK(!skel, "open_and_load", "cannot load skeleton\n"))
122 		goto close_sk;
123 
124 	prog = bpf_program__fd(skel->progs.copy_sock_map);
125 	src = bpf_map__fd(skel->maps.src);
126 	if (map_type == BPF_MAP_TYPE_SOCKMAP)
127 		dst = bpf_map__fd(skel->maps.dst_sock_map);
128 	else
129 		dst = bpf_map__fd(skel->maps.dst_sock_hash);
130 
131 	err = bpf_map_update_elem(src, &zero, &sk, BPF_NOEXIST);
132 	if (CHECK(err, "update_elem(src)", "errno=%u\n", errno))
133 		goto out;
134 
135 	err = bpf_map_lookup_elem(src, &zero, &src_cookie);
136 	if (CHECK(err, "lookup_elem(src, cookie)", "errno=%u\n", errno))
137 		goto out;
138 
139 	tattr = (struct bpf_prog_test_run_attr){
140 		.prog_fd = prog,
141 		.repeat = 1,
142 		.data_in = dummy,
143 		.data_size_in = sizeof(dummy),
144 	};
145 
146 	err = bpf_prog_test_run_xattr(&tattr);
147 	if (CHECK_ATTR(err || !tattr.retval, "bpf_prog_test_run",
148 		       "errno=%u retval=%u\n", errno, tattr.retval))
149 		goto out;
150 
151 	err = bpf_map_lookup_elem(dst, &zero, &dst_cookie);
152 	if (CHECK(err, "lookup_elem(dst, cookie)", "errno=%u\n", errno))
153 		goto out;
154 
155 	CHECK(dst_cookie != src_cookie, "cookie mismatch", "%llu != %llu\n",
156 	      dst_cookie, src_cookie);
157 
158 out:
159 	test_sockmap_update__destroy(skel);
160 close_sk:
161 	close(sk);
162 }
163 
164 static void test_sockmap_invalid_update(void)
165 {
166 	struct test_sockmap_invalid_update *skel;
167 	int duration = 0;
168 
169 	skel = test_sockmap_invalid_update__open_and_load();
170 	if (CHECK(skel, "open_and_load", "verifier accepted map_update\n"))
171 		test_sockmap_invalid_update__destroy(skel);
172 }
173 
174 void test_sockmap_basic(void)
175 {
176 	if (test__start_subtest("sockmap create_update_free"))
177 		test_sockmap_create_update_free(BPF_MAP_TYPE_SOCKMAP);
178 	if (test__start_subtest("sockhash create_update_free"))
179 		test_sockmap_create_update_free(BPF_MAP_TYPE_SOCKHASH);
180 	if (test__start_subtest("sockmap sk_msg load helpers"))
181 		test_skmsg_helpers(BPF_MAP_TYPE_SOCKMAP);
182 	if (test__start_subtest("sockhash sk_msg load helpers"))
183 		test_skmsg_helpers(BPF_MAP_TYPE_SOCKHASH);
184 	if (test__start_subtest("sockmap update"))
185 		test_sockmap_update(BPF_MAP_TYPE_SOCKMAP);
186 	if (test__start_subtest("sockhash update"))
187 		test_sockmap_update(BPF_MAP_TYPE_SOCKHASH);
188 	if (test__start_subtest("sockmap update in unsafe context"))
189 		test_sockmap_invalid_update();
190 }
191