1 // SPDX-License-Identifier: GPL-2.0
8 #include <sys/socket.h>
9 #include <netinet/in.h>
11 #include <linux/filter.h>
13 #include <bpf/libbpf.h>
15 #include "bpf_rlimit.h"
17 #include "cgroup_helpers.h"
19 static int prog_attach(struct bpf_object
*obj
, int cgroup_fd
, const char *title
)
21 enum bpf_attach_type attach_type
;
22 enum bpf_prog_type prog_type
;
23 struct bpf_program
*prog
;
26 err
= libbpf_prog_type_by_name(title
, &prog_type
, &attach_type
);
28 log_err("Failed to deduct types for %s BPF program", title
);
32 prog
= bpf_object__find_program_by_title(obj
, title
);
34 log_err("Failed to find %s BPF program", title
);
38 err
= bpf_prog_attach(bpf_program__fd(prog
), cgroup_fd
,
39 attach_type
, BPF_F_ALLOW_MULTI
);
41 log_err("Failed to attach %s BPF program", title
);
48 static int prog_detach(struct bpf_object
*obj
, int cgroup_fd
, const char *title
)
50 enum bpf_attach_type attach_type
;
51 enum bpf_prog_type prog_type
;
52 struct bpf_program
*prog
;
55 err
= libbpf_prog_type_by_name(title
, &prog_type
, &attach_type
);
59 prog
= bpf_object__find_program_by_title(obj
, title
);
63 err
= bpf_prog_detach2(bpf_program__fd(prog
), cgroup_fd
,
71 static int run_getsockopt_test(struct bpf_object
*obj
, int cg_parent
,
72 int cg_child
, int sock_fd
)
78 /* Set IP_TOS to the expected value (0x80). */
81 err
= setsockopt(sock_fd
, SOL_IP
, IP_TOS
, &buf
, 1);
83 log_err("Failed to call setsockopt(IP_TOS)");
89 err
= getsockopt(sock_fd
, SOL_IP
, IP_TOS
, &buf
, &optlen
);
91 log_err("Failed to call getsockopt(IP_TOS)");
96 log_err("Unexpected getsockopt 0x%x != 0x80 without BPF", buf
);
101 /* Attach child program and make sure it returns new value:
103 * - child: 0x80 -> 0x90
106 err
= prog_attach(obj
, cg_child
, "cgroup/getsockopt/child");
112 err
= getsockopt(sock_fd
, SOL_IP
, IP_TOS
, &buf
, &optlen
);
114 log_err("Failed to call getsockopt(IP_TOS)");
119 log_err("Unexpected getsockopt 0x%x != 0x90", buf
);
124 /* Attach parent program and make sure it returns new value:
126 * - child: 0x80 -> 0x90
127 * - parent: 0x90 -> 0xA0
130 err
= prog_attach(obj
, cg_parent
, "cgroup/getsockopt/parent");
136 err
= getsockopt(sock_fd
, SOL_IP
, IP_TOS
, &buf
, &optlen
);
138 log_err("Failed to call getsockopt(IP_TOS)");
143 log_err("Unexpected getsockopt 0x%x != 0xA0", buf
);
148 /* Setting unexpected initial sockopt should return EPERM:
150 * - child: unexpected 0x40, EPERM
151 * - parent: unexpected 0x40, EPERM
155 if (setsockopt(sock_fd
, SOL_IP
, IP_TOS
, &buf
, 1) < 0) {
156 log_err("Failed to call setsockopt(IP_TOS)");
162 err
= getsockopt(sock_fd
, SOL_IP
, IP_TOS
, &buf
, &optlen
);
164 log_err("Unexpected success from getsockopt(IP_TOS)");
168 /* Detach child program and make sure we still get EPERM:
170 * - parent: unexpected 0x40, EPERM
173 err
= prog_detach(obj
, cg_child
, "cgroup/getsockopt/child");
175 log_err("Failed to detach child program");
181 err
= getsockopt(sock_fd
, SOL_IP
, IP_TOS
, &buf
, &optlen
);
183 log_err("Unexpected success from getsockopt(IP_TOS)");
187 /* Set initial value to the one the parent program expects:
189 * - parent: 0x90 -> 0xA0
193 err
= setsockopt(sock_fd
, SOL_IP
, IP_TOS
, &buf
, 1);
195 log_err("Failed to call setsockopt(IP_TOS)");
201 err
= getsockopt(sock_fd
, SOL_IP
, IP_TOS
, &buf
, &optlen
);
203 log_err("Failed to call getsockopt(IP_TOS)");
208 log_err("Unexpected getsockopt 0x%x != 0xA0", buf
);
214 prog_detach(obj
, cg_child
, "cgroup/getsockopt/child");
215 prog_detach(obj
, cg_parent
, "cgroup/getsockopt/parent");
220 static int run_setsockopt_test(struct bpf_object
*obj
, int cg_parent
,
221 int cg_child
, int sock_fd
)
227 /* Set IP_TOS to the expected value (0x80). */
230 err
= setsockopt(sock_fd
, SOL_IP
, IP_TOS
, &buf
, 1);
232 log_err("Failed to call setsockopt(IP_TOS)");
238 err
= getsockopt(sock_fd
, SOL_IP
, IP_TOS
, &buf
, &optlen
);
240 log_err("Failed to call getsockopt(IP_TOS)");
245 log_err("Unexpected getsockopt 0x%x != 0x80 without BPF", buf
);
250 /* Attach child program and make sure it adds 0x10. */
252 err
= prog_attach(obj
, cg_child
, "cgroup/setsockopt");
257 err
= setsockopt(sock_fd
, SOL_IP
, IP_TOS
, &buf
, 1);
259 log_err("Failed to call setsockopt(IP_TOS)");
265 err
= getsockopt(sock_fd
, SOL_IP
, IP_TOS
, &buf
, &optlen
);
267 log_err("Failed to call getsockopt(IP_TOS)");
271 if (buf
!= 0x80 + 0x10) {
272 log_err("Unexpected getsockopt 0x%x != 0x80 + 0x10", buf
);
277 /* Attach parent program and make sure it adds another 0x10. */
279 err
= prog_attach(obj
, cg_parent
, "cgroup/setsockopt");
284 err
= setsockopt(sock_fd
, SOL_IP
, IP_TOS
, &buf
, 1);
286 log_err("Failed to call setsockopt(IP_TOS)");
292 err
= getsockopt(sock_fd
, SOL_IP
, IP_TOS
, &buf
, &optlen
);
294 log_err("Failed to call getsockopt(IP_TOS)");
298 if (buf
!= 0x80 + 2 * 0x10) {
299 log_err("Unexpected getsockopt 0x%x != 0x80 + 2 * 0x10", buf
);
305 prog_detach(obj
, cg_child
, "cgroup/setsockopt");
306 prog_detach(obj
, cg_parent
, "cgroup/setsockopt");
311 int main(int argc
, char **argv
)
313 struct bpf_prog_load_attr attr
= {
314 .file
= "./sockopt_multi.o",
316 int cg_parent
= -1, cg_child
= -1;
317 struct bpf_object
*obj
= NULL
;
322 if (setup_cgroup_environment()) {
323 log_err("Failed to setup cgroup environment\n");
327 cg_parent
= create_and_get_cgroup("/parent");
329 log_err("Failed to create cgroup /parent\n");
333 cg_child
= create_and_get_cgroup("/parent/child");
335 log_err("Failed to create cgroup /parent/child\n");
339 if (join_cgroup("/parent/child")) {
340 log_err("Failed to join cgroup /parent/child\n");
344 err
= bpf_prog_load_xattr(&attr
, &obj
, &ignored
);
346 log_err("Failed to load BPF object");
350 sock_fd
= socket(AF_INET
, SOCK_STREAM
, 0);
352 log_err("Failed to create socket");
356 if (run_getsockopt_test(obj
, cg_parent
, cg_child
, sock_fd
))
358 printf("test_sockopt_multi: getsockopt %s\n",
359 err
? "FAILED" : "PASSED");
361 if (run_setsockopt_test(obj
, cg_parent
, cg_child
, sock_fd
))
363 printf("test_sockopt_multi: setsockopt %s\n",
364 err
? "FAILED" : "PASSED");
368 bpf_object__close(obj
);
372 printf("test_sockopt_multi: %s\n", err
? "FAILED" : "PASSED");
373 return err
? EXIT_FAILURE
: EXIT_SUCCESS
;