~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c

Version: ~ [ linux-6.0-rc6 ] ~ [ linux-5.19.10 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.69 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.144 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.214 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.259 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.294 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.329 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.302 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /* Copyright (c) 2019 Facebook */
  3 
  4 #include <linux/err.h>
  5 #include <netinet/tcp.h>
  6 #include <test_progs.h>
  7 #include "network_helpers.h"
  8 #include "bpf_dctcp.skel.h"
  9 #include "bpf_cubic.skel.h"
 10 #include "bpf_tcp_nogpl.skel.h"
 11 #include "bpf_dctcp_release.skel.h"
 12 
 13 #define min(a, b) ((a) < (b) ? (a) : (b))
 14 
 15 #ifndef ENOTSUPP
 16 #define ENOTSUPP 524
 17 #endif
 18 
 19 static const unsigned int total_bytes = 10 * 1024 * 1024;
 20 static int expected_stg = 0xeB9F;
 21 static int stop, duration;
 22 
 23 static int settcpca(int fd, const char *tcp_ca)
 24 {
 25         int err;
 26 
 27         err = setsockopt(fd, IPPROTO_TCP, TCP_CONGESTION, tcp_ca, strlen(tcp_ca));
 28         if (CHECK(err == -1, "setsockopt(fd, TCP_CONGESTION)", "errno:%d\n",
 29                   errno))
 30                 return -1;
 31 
 32         return 0;
 33 }
 34 
 35 static void *server(void *arg)
 36 {
 37         int lfd = (int)(long)arg, err = 0, fd;
 38         ssize_t nr_sent = 0, bytes = 0;
 39         char batch[1500];
 40 
 41         fd = accept(lfd, NULL, NULL);
 42         while (fd == -1) {
 43                 if (errno == EINTR)
 44                         continue;
 45                 err = -errno;
 46                 goto done;
 47         }
 48 
 49         if (settimeo(fd, 0)) {
 50                 err = -errno;
 51                 goto done;
 52         }
 53 
 54         while (bytes < total_bytes && !READ_ONCE(stop)) {
 55                 nr_sent = send(fd, &batch,
 56                                min(total_bytes - bytes, sizeof(batch)), 0);
 57                 if (nr_sent == -1 && errno == EINTR)
 58                         continue;
 59                 if (nr_sent == -1) {
 60                         err = -errno;
 61                         break;
 62                 }
 63                 bytes += nr_sent;
 64         }
 65 
 66         CHECK(bytes != total_bytes, "send", "%zd != %u nr_sent:%zd errno:%d\n",
 67               bytes, total_bytes, nr_sent, errno);
 68 
 69 done:
 70         if (fd >= 0)
 71                 close(fd);
 72         if (err) {
 73                 WRITE_ONCE(stop, 1);
 74                 return ERR_PTR(err);
 75         }
 76         return NULL;
 77 }
 78 
 79 static void do_test(const char *tcp_ca, const struct bpf_map *sk_stg_map)
 80 {
 81         struct sockaddr_in6 sa6 = {};
 82         ssize_t nr_recv = 0, bytes = 0;
 83         int lfd = -1, fd = -1;
 84         pthread_t srv_thread;
 85         socklen_t addrlen = sizeof(sa6);
 86         void *thread_ret;
 87         char batch[1500];
 88         int err;
 89 
 90         WRITE_ONCE(stop, 0);
 91 
 92         lfd = socket(AF_INET6, SOCK_STREAM, 0);
 93         if (CHECK(lfd == -1, "socket", "errno:%d\n", errno))
 94                 return;
 95         fd = socket(AF_INET6, SOCK_STREAM, 0);
 96         if (CHECK(fd == -1, "socket", "errno:%d\n", errno)) {
 97                 close(lfd);
 98                 return;
 99         }
100 
101         if (settcpca(lfd, tcp_ca) || settcpca(fd, tcp_ca) ||
102             settimeo(lfd, 0) || settimeo(fd, 0))
103                 goto done;
104 
105         /* bind, listen and start server thread to accept */
106         sa6.sin6_family = AF_INET6;
107         sa6.sin6_addr = in6addr_loopback;
108         err = bind(lfd, (struct sockaddr *)&sa6, addrlen);
109         if (CHECK(err == -1, "bind", "errno:%d\n", errno))
110                 goto done;
111         err = getsockname(lfd, (struct sockaddr *)&sa6, &addrlen);
112         if (CHECK(err == -1, "getsockname", "errno:%d\n", errno))
113                 goto done;
114         err = listen(lfd, 1);
115         if (CHECK(err == -1, "listen", "errno:%d\n", errno))
116                 goto done;
117 
118         if (sk_stg_map) {
119                 err = bpf_map_update_elem(bpf_map__fd(sk_stg_map), &fd,
120                                           &expected_stg, BPF_NOEXIST);
121                 if (CHECK(err, "bpf_map_update_elem(sk_stg_map)",
122                           "err:%d errno:%d\n", err, errno))
123                         goto done;
124         }
125 
126         /* connect to server */
127         err = connect(fd, (struct sockaddr *)&sa6, addrlen);
128         if (CHECK(err == -1, "connect", "errno:%d\n", errno))
129                 goto done;
130 
131         if (sk_stg_map) {
132                 int tmp_stg;
133 
134                 err = bpf_map_lookup_elem(bpf_map__fd(sk_stg_map), &fd,
135                                           &tmp_stg);
136                 if (CHECK(!err || errno != ENOENT,
137                           "bpf_map_lookup_elem(sk_stg_map)",
138                           "err:%d errno:%d\n", err, errno))
139                         goto done;
140         }
141 
142         err = pthread_create(&srv_thread, NULL, server, (void *)(long)lfd);
143         if (CHECK(err != 0, "pthread_create", "err:%d errno:%d\n", err, errno))
144                 goto done;
145 
146         /* recv total_bytes */
147         while (bytes < total_bytes && !READ_ONCE(stop)) {
148                 nr_recv = recv(fd, &batch,
149                                min(total_bytes - bytes, sizeof(batch)), 0);
150                 if (nr_recv == -1 && errno == EINTR)
151                         continue;
152                 if (nr_recv == -1)
153                         break;
154                 bytes += nr_recv;
155         }
156 
157         CHECK(bytes != total_bytes, "recv", "%zd != %u nr_recv:%zd errno:%d\n",
158               bytes, total_bytes, nr_recv, errno);
159 
160         WRITE_ONCE(stop, 1);
161         pthread_join(srv_thread, &thread_ret);
162         CHECK(IS_ERR(thread_ret), "pthread_join", "thread_ret:%ld",
163               PTR_ERR(thread_ret));
164 done:
165         close(lfd);
166         close(fd);
167 }
168 
169 static void test_cubic(void)
170 {
171         struct bpf_cubic *cubic_skel;
172         struct bpf_link *link;
173 
174         cubic_skel = bpf_cubic__open_and_load();
175         if (CHECK(!cubic_skel, "bpf_cubic__open_and_load", "failed\n"))
176                 return;
177 
178         link = bpf_map__attach_struct_ops(cubic_skel->maps.cubic);
179         if (!ASSERT_OK_PTR(link, "bpf_map__attach_struct_ops")) {
180                 bpf_cubic__destroy(cubic_skel);
181                 return;
182         }
183 
184         do_test("bpf_cubic", NULL);
185 
186         bpf_link__destroy(link);
187         bpf_cubic__destroy(cubic_skel);
188 }
189 
190 static void test_dctcp(void)
191 {
192         struct bpf_dctcp *dctcp_skel;
193         struct bpf_link *link;
194 
195         dctcp_skel = bpf_dctcp__open_and_load();
196         if (CHECK(!dctcp_skel, "bpf_dctcp__open_and_load", "failed\n"))
197                 return;
198 
199         link = bpf_map__attach_struct_ops(dctcp_skel->maps.dctcp);
200         if (!ASSERT_OK_PTR(link, "bpf_map__attach_struct_ops")) {
201                 bpf_dctcp__destroy(dctcp_skel);
202                 return;
203         }
204 
205         do_test("bpf_dctcp", dctcp_skel->maps.sk_stg_map);
206         CHECK(dctcp_skel->bss->stg_result != expected_stg,
207               "Unexpected stg_result", "stg_result (%x) != expected_stg (%x)\n",
208               dctcp_skel->bss->stg_result, expected_stg);
209 
210         bpf_link__destroy(link);
211         bpf_dctcp__destroy(dctcp_skel);
212 }
213 
214 static char *err_str;
215 static bool found;
216 
217 static int libbpf_debug_print(enum libbpf_print_level level,
218                               const char *format, va_list args)
219 {
220         char *log_buf;
221 
222         if (level != LIBBPF_WARN ||
223             strcmp(format, "libbpf: \n%s\n")) {
224                 vprintf(format, args);
225                 return 0;
226         }
227 
228         log_buf = va_arg(args, char *);
229         if (!log_buf)
230                 goto out;
231         if (err_str && strstr(log_buf, err_str) != NULL)
232                 found = true;
233 out:
234         printf(format, log_buf);
235         return 0;
236 }
237 
238 static void test_invalid_license(void)
239 {
240         libbpf_print_fn_t old_print_fn;
241         struct bpf_tcp_nogpl *skel;
242 
243         err_str = "struct ops programs must have a GPL compatible license";
244         found = false;
245         old_print_fn = libbpf_set_print(libbpf_debug_print);
246 
247         skel = bpf_tcp_nogpl__open_and_load();
248         ASSERT_NULL(skel, "bpf_tcp_nogpl");
249         ASSERT_EQ(found, true, "expected_err_msg");
250 
251         bpf_tcp_nogpl__destroy(skel);
252         libbpf_set_print(old_print_fn);
253 }
254 
255 static void test_dctcp_fallback(void)
256 {
257         int err, lfd = -1, cli_fd = -1, srv_fd = -1;
258         struct network_helper_opts opts = {
259                 .cc = "cubic",
260         };
261         struct bpf_dctcp *dctcp_skel;
262         struct bpf_link *link = NULL;
263         char srv_cc[16];
264         socklen_t cc_len = sizeof(srv_cc);
265 
266         dctcp_skel = bpf_dctcp__open();
267         if (!ASSERT_OK_PTR(dctcp_skel, "dctcp_skel"))
268                 return;
269         strcpy(dctcp_skel->rodata->fallback, "cubic");
270         if (!ASSERT_OK(bpf_dctcp__load(dctcp_skel), "bpf_dctcp__load"))
271                 goto done;
272 
273         link = bpf_map__attach_struct_ops(dctcp_skel->maps.dctcp);
274         if (!ASSERT_OK_PTR(link, "dctcp link"))
275                 goto done;
276 
277         lfd = start_server(AF_INET6, SOCK_STREAM, "::1", 0, 0);
278         if (!ASSERT_GE(lfd, 0, "lfd") ||
279             !ASSERT_OK(settcpca(lfd, "bpf_dctcp"), "lfd=>bpf_dctcp"))
280                 goto done;
281 
282         cli_fd = connect_to_fd_opts(lfd, &opts);
283         if (!ASSERT_GE(cli_fd, 0, "cli_fd"))
284                 goto done;
285 
286         srv_fd = accept(lfd, NULL, 0);
287         if (!ASSERT_GE(srv_fd, 0, "srv_fd"))
288                 goto done;
289         ASSERT_STREQ(dctcp_skel->bss->cc_res, "cubic", "cc_res");
290         ASSERT_EQ(dctcp_skel->bss->tcp_cdg_res, -ENOTSUPP, "tcp_cdg_res");
291 
292         err = getsockopt(srv_fd, SOL_TCP, TCP_CONGESTION, srv_cc, &cc_len);
293         if (!ASSERT_OK(err, "getsockopt(srv_fd, TCP_CONGESTION)"))
294                 goto done;
295         ASSERT_STREQ(srv_cc, "cubic", "srv_fd cc");
296 
297 done:
298         bpf_link__destroy(link);
299         bpf_dctcp__destroy(dctcp_skel);
300         if (lfd != -1)
301                 close(lfd);
302         if (srv_fd != -1)
303                 close(srv_fd);
304         if (cli_fd != -1)
305                 close(cli_fd);
306 }
307 
308 static void test_rel_setsockopt(void)
309 {
310         struct bpf_dctcp_release *rel_skel;
311         libbpf_print_fn_t old_print_fn;
312 
313         err_str = "unknown func bpf_setsockopt";
314         found = false;
315 
316         old_print_fn = libbpf_set_print(libbpf_debug_print);
317         rel_skel = bpf_dctcp_release__open_and_load();
318         libbpf_set_print(old_print_fn);
319 
320         ASSERT_ERR_PTR(rel_skel, "rel_skel");
321         ASSERT_TRUE(found, "expected_err_msg");
322 
323         bpf_dctcp_release__destroy(rel_skel);
324 }
325 
326 void test_bpf_tcp_ca(void)
327 {
328         if (test__start_subtest("dctcp"))
329                 test_dctcp();
330         if (test__start_subtest("cubic"))
331                 test_cubic();
332         if (test__start_subtest("invalid_license"))
333                 test_invalid_license();
334         if (test__start_subtest("dctcp_fallback"))
335                 test_dctcp_fallback();
336         if (test__start_subtest("rel_setsockopt"))
337                 test_rel_setsockopt();
338 }
339 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp