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

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/progs/setget_sockopt.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ 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) Meta Platforms, Inc. and affiliates. */
  3 
  4 #include "vmlinux.h"
  5 #include "bpf_tracing_net.h"
  6 #include <bpf/bpf_core_read.h>
  7 #include <bpf/bpf_helpers.h>
  8 #include <bpf/bpf_tracing.h>
  9 #include "bpf_misc.h"
 10 
 11 extern unsigned long CONFIG_HZ __kconfig;
 12 
 13 const volatile char veth[IFNAMSIZ];
 14 const volatile int veth_ifindex;
 15 
 16 int nr_listen;
 17 int nr_passive;
 18 int nr_active;
 19 int nr_connect;
 20 int nr_binddev;
 21 int nr_socket_post_create;
 22 int nr_fin_wait1;
 23 
 24 struct sockopt_test {
 25         int opt;
 26         int new;
 27         int restore;
 28         int expected;
 29         int tcp_expected;
 30         unsigned int flip:1;
 31 };
 32 
 33 static const char not_exist_cc[] = "not_exist";
 34 static const char cubic_cc[] = "cubic";
 35 static const char reno_cc[] = "reno";
 36 
 37 static const struct sockopt_test sol_socket_tests[] = {
 38         { .opt = SO_REUSEADDR, .flip = 1, },
 39         { .opt = SO_SNDBUF, .new = 8123, .expected = 8123 * 2, },
 40         { .opt = SO_RCVBUF, .new = 8123, .expected = 8123 * 2, },
 41         { .opt = SO_KEEPALIVE, .flip = 1, },
 42         { .opt = SO_PRIORITY, .new = 0xeb9f, .expected = 0xeb9f, },
 43         { .opt = SO_REUSEPORT, .flip = 1, },
 44         { .opt = SO_RCVLOWAT, .new = 8123, .expected = 8123, },
 45         { .opt = SO_MARK, .new = 0xeb9f, .expected = 0xeb9f, },
 46         { .opt = SO_MAX_PACING_RATE, .new = 0xeb9f, .expected = 0xeb9f, },
 47         { .opt = SO_TXREHASH, .flip = 1, },
 48         { .opt = 0, },
 49 };
 50 
 51 static const struct sockopt_test sol_tcp_tests[] = {
 52         { .opt = TCP_NODELAY, .flip = 1, },
 53         { .opt = TCP_KEEPIDLE, .new = 123, .expected = 123, .restore = 321, },
 54         { .opt = TCP_KEEPINTVL, .new = 123, .expected = 123, .restore = 321, },
 55         { .opt = TCP_KEEPCNT, .new = 123, .expected = 123, .restore = 124, },
 56         { .opt = TCP_SYNCNT, .new = 123, .expected = 123, .restore = 124, },
 57         { .opt = TCP_WINDOW_CLAMP, .new = 8123, .expected = 8123, .restore = 8124, },
 58         { .opt = TCP_CONGESTION, },
 59         { .opt = TCP_THIN_LINEAR_TIMEOUTS, .flip = 1, },
 60         { .opt = TCP_USER_TIMEOUT, .new = 123400, .expected = 123400, },
 61         { .opt = TCP_NOTSENT_LOWAT, .new = 1314, .expected = 1314, },
 62         { .opt = 0, },
 63 };
 64 
 65 static const struct sockopt_test sol_ip_tests[] = {
 66         { .opt = IP_TOS, .new = 0xe1, .expected = 0xe1, .tcp_expected = 0xe0, },
 67         { .opt = 0, },
 68 };
 69 
 70 static const struct sockopt_test sol_ipv6_tests[] = {
 71         { .opt = IPV6_TCLASS, .new = 0xe1, .expected = 0xe1, .tcp_expected = 0xe0, },
 72         { .opt = IPV6_AUTOFLOWLABEL, .flip = 1, },
 73         { .opt = 0, },
 74 };
 75 
 76 struct loop_ctx {
 77         void *ctx;
 78         struct sock *sk;
 79 };
 80 
 81 static int bpf_test_sockopt_flip(void *ctx, struct sock *sk,
 82                                  const struct sockopt_test *t,
 83                                  int level)
 84 {
 85         int old, tmp, new, opt = t->opt;
 86 
 87         opt = t->opt;
 88 
 89         if (bpf_getsockopt(ctx, level, opt, &old, sizeof(old)))
 90                 return 1;
 91         /* kernel initialized txrehash to 255 */
 92         if (level == SOL_SOCKET && opt == SO_TXREHASH && old != 0 && old != 1)
 93                 old = 1;
 94 
 95         new = !old;
 96         if (bpf_setsockopt(ctx, level, opt, &new, sizeof(new)))
 97                 return 1;
 98         if (bpf_getsockopt(ctx, level, opt, &tmp, sizeof(tmp)) ||
 99             tmp != new)
100                 return 1;
101 
102         if (bpf_setsockopt(ctx, level, opt, &old, sizeof(old)))
103                 return 1;
104 
105         return 0;
106 }
107 
108 static int bpf_test_sockopt_int(void *ctx, struct sock *sk,
109                                 const struct sockopt_test *t,
110                                 int level)
111 {
112         int old, tmp, new, expected, opt;
113 
114         opt = t->opt;
115         new = t->new;
116         if (sk->sk_type == SOCK_STREAM && t->tcp_expected)
117                 expected = t->tcp_expected;
118         else
119                 expected = t->expected;
120 
121         if (bpf_getsockopt(ctx, level, opt, &old, sizeof(old)) ||
122             old == new)
123                 return 1;
124 
125         if (bpf_setsockopt(ctx, level, opt, &new, sizeof(new)))
126                 return 1;
127         if (bpf_getsockopt(ctx, level, opt, &tmp, sizeof(tmp)) ||
128             tmp != expected)
129                 return 1;
130 
131         if (t->restore)
132                 old = t->restore;
133         if (bpf_setsockopt(ctx, level, opt, &old, sizeof(old)))
134                 return 1;
135 
136         return 0;
137 }
138 
139 static int bpf_test_socket_sockopt(__u32 i, struct loop_ctx *lc)
140 {
141         const struct sockopt_test *t;
142 
143         if (i >= ARRAY_SIZE(sol_socket_tests))
144                 return 1;
145 
146         t = &sol_socket_tests[i];
147         if (!t->opt)
148                 return 1;
149 
150         if (t->flip)
151                 return bpf_test_sockopt_flip(lc->ctx, lc->sk, t, SOL_SOCKET);
152 
153         return bpf_test_sockopt_int(lc->ctx, lc->sk, t, SOL_SOCKET);
154 }
155 
156 static int bpf_test_ip_sockopt(__u32 i, struct loop_ctx *lc)
157 {
158         const struct sockopt_test *t;
159 
160         if (i >= ARRAY_SIZE(sol_ip_tests))
161                 return 1;
162 
163         t = &sol_ip_tests[i];
164         if (!t->opt)
165                 return 1;
166 
167         if (t->flip)
168                 return bpf_test_sockopt_flip(lc->ctx, lc->sk, t, IPPROTO_IP);
169 
170         return bpf_test_sockopt_int(lc->ctx, lc->sk, t, IPPROTO_IP);
171 }
172 
173 static int bpf_test_ipv6_sockopt(__u32 i, struct loop_ctx *lc)
174 {
175         const struct sockopt_test *t;
176 
177         if (i >= ARRAY_SIZE(sol_ipv6_tests))
178                 return 1;
179 
180         t = &sol_ipv6_tests[i];
181         if (!t->opt)
182                 return 1;
183 
184         if (t->flip)
185                 return bpf_test_sockopt_flip(lc->ctx, lc->sk, t, IPPROTO_IPV6);
186 
187         return bpf_test_sockopt_int(lc->ctx, lc->sk, t, IPPROTO_IPV6);
188 }
189 
190 static int bpf_test_tcp_sockopt(__u32 i, struct loop_ctx *lc)
191 {
192         const struct sockopt_test *t;
193         struct sock *sk;
194         void *ctx;
195 
196         if (i >= ARRAY_SIZE(sol_tcp_tests))
197                 return 1;
198 
199         t = &sol_tcp_tests[i];
200         if (!t->opt)
201                 return 1;
202 
203         ctx = lc->ctx;
204         sk = lc->sk;
205 
206         if (t->opt == TCP_CONGESTION) {
207                 char old_cc[16], tmp_cc[16];
208                 const char *new_cc;
209                 int new_cc_len;
210 
211                 if (!bpf_setsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION,
212                                     (void *)not_exist_cc, sizeof(not_exist_cc)))
213                         return 1;
214                 if (bpf_getsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, old_cc, sizeof(old_cc)))
215                         return 1;
216                 if (!bpf_strncmp(old_cc, sizeof(old_cc), cubic_cc)) {
217                         new_cc = reno_cc;
218                         new_cc_len = sizeof(reno_cc);
219                 } else {
220                         new_cc = cubic_cc;
221                         new_cc_len = sizeof(cubic_cc);
222                 }
223                 if (bpf_setsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, (void *)new_cc,
224                                    new_cc_len))
225                         return 1;
226                 if (bpf_getsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, tmp_cc, sizeof(tmp_cc)))
227                         return 1;
228                 if (bpf_strncmp(tmp_cc, sizeof(tmp_cc), new_cc))
229                         return 1;
230                 if (bpf_setsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, old_cc, sizeof(old_cc)))
231                         return 1;
232                 return 0;
233         }
234 
235         if (t->flip)
236                 return bpf_test_sockopt_flip(ctx, sk, t, IPPROTO_TCP);
237 
238         return bpf_test_sockopt_int(ctx, sk, t, IPPROTO_TCP);
239 }
240 
241 static int bpf_test_sockopt(void *ctx, struct sock *sk)
242 {
243         struct loop_ctx lc = { .ctx = ctx, .sk = sk, };
244         __u16 family, proto;
245         int n;
246 
247         family = sk->sk_family;
248         proto = sk->sk_protocol;
249 
250         n = bpf_loop(ARRAY_SIZE(sol_socket_tests), bpf_test_socket_sockopt, &lc, 0);
251         if (n != ARRAY_SIZE(sol_socket_tests))
252                 return -1;
253 
254         if (proto == IPPROTO_TCP) {
255                 n = bpf_loop(ARRAY_SIZE(sol_tcp_tests), bpf_test_tcp_sockopt, &lc, 0);
256                 if (n != ARRAY_SIZE(sol_tcp_tests))
257                         return -1;
258         }
259 
260         if (family == AF_INET) {
261                 n = bpf_loop(ARRAY_SIZE(sol_ip_tests), bpf_test_ip_sockopt, &lc, 0);
262                 if (n != ARRAY_SIZE(sol_ip_tests))
263                         return -1;
264         } else {
265                 n = bpf_loop(ARRAY_SIZE(sol_ipv6_tests), bpf_test_ipv6_sockopt, &lc, 0);
266                 if (n != ARRAY_SIZE(sol_ipv6_tests))
267                         return -1;
268         }
269 
270         return 0;
271 }
272 
273 static int binddev_test(void *ctx)
274 {
275         const char empty_ifname[] = "";
276         int ifindex, zero = 0;
277 
278         if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
279                            (void *)veth, sizeof(veth)))
280                 return -1;
281         if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
282                            &ifindex, sizeof(int)) ||
283             ifindex != veth_ifindex)
284                 return -1;
285 
286         if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
287                            (void *)empty_ifname, sizeof(empty_ifname)))
288                 return -1;
289         if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
290                            &ifindex, sizeof(int)) ||
291             ifindex != 0)
292                 return -1;
293 
294         if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
295                            (void *)&veth_ifindex, sizeof(int)))
296                 return -1;
297         if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
298                            &ifindex, sizeof(int)) ||
299             ifindex != veth_ifindex)
300                 return -1;
301 
302         if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
303                            &zero, sizeof(int)))
304                 return -1;
305         if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
306                            &ifindex, sizeof(int)) ||
307             ifindex != 0)
308                 return -1;
309 
310         return 0;
311 }
312 
313 static int test_tcp_maxseg(void *ctx, struct sock *sk)
314 {
315         int val = 1314, tmp;
316 
317         if (sk->sk_state != TCP_ESTABLISHED)
318                 return bpf_setsockopt(ctx, IPPROTO_TCP, TCP_MAXSEG,
319                                       &val, sizeof(val));
320 
321         if (bpf_getsockopt(ctx, IPPROTO_TCP, TCP_MAXSEG, &tmp, sizeof(tmp)) ||
322             tmp > val)
323                 return -1;
324 
325         return 0;
326 }
327 
328 static int test_tcp_saved_syn(void *ctx, struct sock *sk)
329 {
330         __u8 saved_syn[20];
331         int one = 1;
332 
333         if (sk->sk_state == TCP_LISTEN)
334                 return bpf_setsockopt(ctx, IPPROTO_TCP, TCP_SAVE_SYN,
335                                       &one, sizeof(one));
336 
337         return bpf_getsockopt(ctx, IPPROTO_TCP, TCP_SAVED_SYN,
338                               saved_syn, sizeof(saved_syn));
339 }
340 
341 SEC("lsm_cgroup/socket_post_create")
342 int BPF_PROG(socket_post_create, struct socket *sock, int family,
343              int type, int protocol, int kern)
344 {
345         struct sock *sk = sock->sk;
346 
347         if (!sk)
348                 return 1;
349 
350         nr_socket_post_create += !bpf_test_sockopt(sk, sk);
351         nr_binddev += !binddev_test(sk);
352 
353         return 1;
354 }
355 
356 SEC("sockops")
357 int skops_sockopt(struct bpf_sock_ops *skops)
358 {
359         struct bpf_sock *bpf_sk = skops->sk;
360         struct sock *sk;
361 
362         if (!bpf_sk)
363                 return 1;
364 
365         sk = (struct sock *)bpf_skc_to_tcp_sock(bpf_sk);
366         if (!sk)
367                 return 1;
368 
369         switch (skops->op) {
370         case BPF_SOCK_OPS_TCP_LISTEN_CB:
371                 nr_listen += !(bpf_test_sockopt(skops, sk) ||
372                                test_tcp_maxseg(skops, sk) ||
373                                test_tcp_saved_syn(skops, sk));
374                 break;
375         case BPF_SOCK_OPS_TCP_CONNECT_CB:
376                 nr_connect += !(bpf_test_sockopt(skops, sk) ||
377                                 test_tcp_maxseg(skops, sk));
378                 break;
379         case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
380                 nr_active += !(bpf_test_sockopt(skops, sk) ||
381                                test_tcp_maxseg(skops, sk));
382                 break;
383         case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
384                 nr_passive += !(bpf_test_sockopt(skops, sk) ||
385                                 test_tcp_maxseg(skops, sk) ||
386                                 test_tcp_saved_syn(skops, sk));
387                 bpf_sock_ops_cb_flags_set(skops,
388                                           skops->bpf_sock_ops_cb_flags |
389                                           BPF_SOCK_OPS_STATE_CB_FLAG);
390                 break;
391         case BPF_SOCK_OPS_STATE_CB:
392                 if (skops->args[1] == BPF_TCP_CLOSE_WAIT)
393                         nr_fin_wait1 += !bpf_test_sockopt(skops, sk);
394                 break;
395         }
396 
397         return 1;
398 }
399 
400 char _license[] SEC("license") = "GPL";
401 

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

kernel.org | git.kernel.org | LWN.net | Project Home | 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.

sflogo.php