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;