1 // SPDX-License-Identifier: GPL-2.0
3 * Tests for attaching, detaching, and replacing flow_dissector BPF program.
14 #include <linux/bpf.h>
17 #include "test_progs.h"
19 static int init_net
= -1;
21 static __u32
query_attached_prog_id(int netns
)
23 __u32 prog_ids
[1] = {};
24 __u32 prog_cnt
= ARRAY_SIZE(prog_ids
);
27 err
= bpf_prog_query(netns
, BPF_FLOW_DISSECTOR
, 0, NULL
,
29 if (CHECK_FAIL(err
)) {
30 perror("bpf_prog_query");
34 return prog_cnt
== 1 ? prog_ids
[0] : 0;
37 static bool prog_is_attached(int netns
)
39 return query_attached_prog_id(netns
) > 0;
42 static int load_prog(enum bpf_prog_type type
)
44 struct bpf_insn prog
[] = {
45 BPF_MOV64_IMM(BPF_REG_0
, BPF_OK
),
50 fd
= bpf_load_program(type
, prog
, ARRAY_SIZE(prog
), "GPL", 0, NULL
, 0);
51 if (CHECK_FAIL(fd
< 0))
52 perror("bpf_load_program");
57 static __u32
query_prog_id(int prog
)
59 struct bpf_prog_info info
= {};
60 __u32 info_len
= sizeof(info
);
63 err
= bpf_obj_get_info_by_fd(prog
, &info
, &info_len
);
64 if (CHECK_FAIL(err
|| info_len
!= sizeof(info
))) {
65 perror("bpf_obj_get_info_by_fd");
72 static int unshare_net(int old_net
)
76 err
= unshare(CLONE_NEWNET
);
77 if (CHECK_FAIL(err
)) {
78 perror("unshare(CLONE_NEWNET)");
81 new_net
= open("/proc/self/ns/net", O_RDONLY
);
82 if (CHECK_FAIL(new_net
< 0)) {
83 perror("open(/proc/self/ns/net)");
84 setns(old_net
, CLONE_NEWNET
);
90 static void test_prog_attach_prog_attach(int netns
, int prog1
, int prog2
)
94 err
= bpf_prog_attach(prog1
, 0, BPF_FLOW_DISSECTOR
, 0);
95 if (CHECK_FAIL(err
)) {
96 perror("bpf_prog_attach(prog1)");
99 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
101 /* Expect success when attaching a different program */
102 err
= bpf_prog_attach(prog2
, 0, BPF_FLOW_DISSECTOR
, 0);
103 if (CHECK_FAIL(err
)) {
104 perror("bpf_prog_attach(prog2) #1");
107 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog2
));
109 /* Expect failure when attaching the same program twice */
110 err
= bpf_prog_attach(prog2
, 0, BPF_FLOW_DISSECTOR
, 0);
111 if (CHECK_FAIL(!err
|| errno
!= EINVAL
))
112 perror("bpf_prog_attach(prog2) #2");
113 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog2
));
116 err
= bpf_prog_detach2(prog2
, 0, BPF_FLOW_DISSECTOR
);
118 perror("bpf_prog_detach");
119 CHECK_FAIL(prog_is_attached(netns
));
122 static void test_link_create_link_create(int netns
, int prog1
, int prog2
)
124 DECLARE_LIBBPF_OPTS(bpf_link_create_opts
, opts
);
127 link1
= bpf_link_create(prog1
, netns
, BPF_FLOW_DISSECTOR
, &opts
);
128 if (CHECK_FAIL(link
< 0)) {
129 perror("bpf_link_create(prog1)");
132 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
134 /* Expect failure creating link when another link exists */
136 link2
= bpf_link_create(prog2
, netns
, BPF_FLOW_DISSECTOR
, &opts
);
137 if (CHECK_FAIL(link2
!= -1 || errno
!= E2BIG
))
138 perror("bpf_prog_attach(prog2) expected E2BIG");
141 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
144 CHECK_FAIL(prog_is_attached(netns
));
147 static void test_prog_attach_link_create(int netns
, int prog1
, int prog2
)
149 DECLARE_LIBBPF_OPTS(bpf_link_create_opts
, opts
);
152 err
= bpf_prog_attach(prog1
, 0, BPF_FLOW_DISSECTOR
, 0);
153 if (CHECK_FAIL(err
)) {
154 perror("bpf_prog_attach(prog1)");
157 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
159 /* Expect failure creating link when prog attached */
161 link
= bpf_link_create(prog2
, netns
, BPF_FLOW_DISSECTOR
, &opts
);
162 if (CHECK_FAIL(link
!= -1 || errno
!= EEXIST
))
163 perror("bpf_link_create(prog2) expected EEXIST");
166 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
168 err
= bpf_prog_detach2(prog1
, 0, BPF_FLOW_DISSECTOR
);
170 perror("bpf_prog_detach");
171 CHECK_FAIL(prog_is_attached(netns
));
174 static void test_link_create_prog_attach(int netns
, int prog1
, int prog2
)
176 DECLARE_LIBBPF_OPTS(bpf_link_create_opts
, opts
);
179 link
= bpf_link_create(prog1
, netns
, BPF_FLOW_DISSECTOR
, &opts
);
180 if (CHECK_FAIL(link
< 0)) {
181 perror("bpf_link_create(prog1)");
184 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
186 /* Expect failure attaching prog when link exists */
188 err
= bpf_prog_attach(prog2
, 0, BPF_FLOW_DISSECTOR
, 0);
189 if (CHECK_FAIL(!err
|| errno
!= EEXIST
))
190 perror("bpf_prog_attach(prog2) expected EEXIST");
191 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
194 CHECK_FAIL(prog_is_attached(netns
));
197 static void test_link_create_prog_detach(int netns
, int prog1
, int prog2
)
199 DECLARE_LIBBPF_OPTS(bpf_link_create_opts
, opts
);
202 link
= bpf_link_create(prog1
, netns
, BPF_FLOW_DISSECTOR
, &opts
);
203 if (CHECK_FAIL(link
< 0)) {
204 perror("bpf_link_create(prog1)");
207 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
209 /* Expect failure detaching prog when link exists */
211 err
= bpf_prog_detach2(prog1
, 0, BPF_FLOW_DISSECTOR
);
212 if (CHECK_FAIL(!err
|| errno
!= EINVAL
))
213 perror("bpf_prog_detach expected EINVAL");
214 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
217 CHECK_FAIL(prog_is_attached(netns
));
220 static void test_prog_attach_detach_query(int netns
, int prog1
, int prog2
)
224 err
= bpf_prog_attach(prog1
, 0, BPF_FLOW_DISSECTOR
, 0);
225 if (CHECK_FAIL(err
)) {
226 perror("bpf_prog_attach(prog1)");
229 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
231 err
= bpf_prog_detach2(prog1
, 0, BPF_FLOW_DISSECTOR
);
232 if (CHECK_FAIL(err
)) {
233 perror("bpf_prog_detach");
237 /* Expect no prog attached after successful detach */
238 CHECK_FAIL(prog_is_attached(netns
));
241 static void test_link_create_close_query(int netns
, int prog1
, int prog2
)
243 DECLARE_LIBBPF_OPTS(bpf_link_create_opts
, opts
);
246 link
= bpf_link_create(prog1
, netns
, BPF_FLOW_DISSECTOR
, &opts
);
247 if (CHECK_FAIL(link
< 0)) {
248 perror("bpf_link_create(prog1)");
251 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
254 /* Expect no prog attached after closing last link FD */
255 CHECK_FAIL(prog_is_attached(netns
));
258 static void test_link_update_no_old_prog(int netns
, int prog1
, int prog2
)
260 DECLARE_LIBBPF_OPTS(bpf_link_create_opts
, create_opts
);
261 DECLARE_LIBBPF_OPTS(bpf_link_update_opts
, update_opts
);
264 link
= bpf_link_create(prog1
, netns
, BPF_FLOW_DISSECTOR
, &create_opts
);
265 if (CHECK_FAIL(link
< 0)) {
266 perror("bpf_link_create(prog1)");
269 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
271 /* Expect success replacing the prog when old prog not specified */
272 update_opts
.flags
= 0;
273 update_opts
.old_prog_fd
= 0;
274 err
= bpf_link_update(link
, prog2
, &update_opts
);
276 perror("bpf_link_update");
277 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog2
));
280 CHECK_FAIL(prog_is_attached(netns
));
283 static void test_link_update_replace_old_prog(int netns
, int prog1
, int prog2
)
285 DECLARE_LIBBPF_OPTS(bpf_link_create_opts
, create_opts
);
286 DECLARE_LIBBPF_OPTS(bpf_link_update_opts
, update_opts
);
289 link
= bpf_link_create(prog1
, netns
, BPF_FLOW_DISSECTOR
, &create_opts
);
290 if (CHECK_FAIL(link
< 0)) {
291 perror("bpf_link_create(prog1)");
294 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
296 /* Expect success F_REPLACE and old prog specified to succeed */
297 update_opts
.flags
= BPF_F_REPLACE
;
298 update_opts
.old_prog_fd
= prog1
;
299 err
= bpf_link_update(link
, prog2
, &update_opts
);
301 perror("bpf_link_update");
302 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog2
));
305 CHECK_FAIL(prog_is_attached(netns
));
308 static void test_link_update_same_prog(int netns
, int prog1
, int prog2
)
310 DECLARE_LIBBPF_OPTS(bpf_link_create_opts
, create_opts
);
311 DECLARE_LIBBPF_OPTS(bpf_link_update_opts
, update_opts
);
314 link
= bpf_link_create(prog1
, netns
, BPF_FLOW_DISSECTOR
, &create_opts
);
315 if (CHECK_FAIL(link
< 0)) {
316 perror("bpf_link_create(prog1)");
319 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
321 /* Expect success updating the prog with the same one */
322 update_opts
.flags
= 0;
323 update_opts
.old_prog_fd
= 0;
324 err
= bpf_link_update(link
, prog1
, &update_opts
);
326 perror("bpf_link_update");
327 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
330 CHECK_FAIL(prog_is_attached(netns
));
333 static void test_link_update_invalid_opts(int netns
, int prog1
, int prog2
)
335 DECLARE_LIBBPF_OPTS(bpf_link_create_opts
, create_opts
);
336 DECLARE_LIBBPF_OPTS(bpf_link_update_opts
, update_opts
);
339 link
= bpf_link_create(prog1
, netns
, BPF_FLOW_DISSECTOR
, &create_opts
);
340 if (CHECK_FAIL(link
< 0)) {
341 perror("bpf_link_create(prog1)");
344 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
346 /* Expect update to fail w/ old prog FD but w/o F_REPLACE*/
348 update_opts
.flags
= 0;
349 update_opts
.old_prog_fd
= prog1
;
350 err
= bpf_link_update(link
, prog2
, &update_opts
);
351 if (CHECK_FAIL(!err
|| errno
!= EINVAL
)) {
352 perror("bpf_link_update expected EINVAL");
355 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
357 /* Expect update to fail on old prog FD mismatch */
359 update_opts
.flags
= BPF_F_REPLACE
;
360 update_opts
.old_prog_fd
= prog2
;
361 err
= bpf_link_update(link
, prog2
, &update_opts
);
362 if (CHECK_FAIL(!err
|| errno
!= EPERM
)) {
363 perror("bpf_link_update expected EPERM");
366 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
368 /* Expect update to fail for invalid old prog FD */
370 update_opts
.flags
= BPF_F_REPLACE
;
371 update_opts
.old_prog_fd
= -1;
372 err
= bpf_link_update(link
, prog2
, &update_opts
);
373 if (CHECK_FAIL(!err
|| errno
!= EBADF
)) {
374 perror("bpf_link_update expected EBADF");
377 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
379 /* Expect update to fail with invalid flags */
381 update_opts
.flags
= BPF_F_ALLOW_MULTI
;
382 update_opts
.old_prog_fd
= 0;
383 err
= bpf_link_update(link
, prog2
, &update_opts
);
384 if (CHECK_FAIL(!err
|| errno
!= EINVAL
))
385 perror("bpf_link_update expected EINVAL");
386 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
390 CHECK_FAIL(prog_is_attached(netns
));
393 static void test_link_update_invalid_prog(int netns
, int prog1
, int prog2
)
395 DECLARE_LIBBPF_OPTS(bpf_link_create_opts
, create_opts
);
396 DECLARE_LIBBPF_OPTS(bpf_link_update_opts
, update_opts
);
397 int err
, link
, prog3
;
399 link
= bpf_link_create(prog1
, netns
, BPF_FLOW_DISSECTOR
, &create_opts
);
400 if (CHECK_FAIL(link
< 0)) {
401 perror("bpf_link_create(prog1)");
404 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
406 /* Expect failure when new prog FD is not valid */
408 update_opts
.flags
= 0;
409 update_opts
.old_prog_fd
= 0;
410 err
= bpf_link_update(link
, -1, &update_opts
);
411 if (CHECK_FAIL(!err
|| errno
!= EBADF
)) {
412 perror("bpf_link_update expected EINVAL");
415 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
417 prog3
= load_prog(BPF_PROG_TYPE_SOCKET_FILTER
);
421 /* Expect failure when new prog FD type doesn't match */
423 update_opts
.flags
= 0;
424 update_opts
.old_prog_fd
= 0;
425 err
= bpf_link_update(link
, prog3
, &update_opts
);
426 if (CHECK_FAIL(!err
|| errno
!= EINVAL
))
427 perror("bpf_link_update expected EINVAL");
428 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
433 CHECK_FAIL(prog_is_attached(netns
));
436 static void test_link_update_netns_gone(int netns
, int prog1
, int prog2
)
438 DECLARE_LIBBPF_OPTS(bpf_link_create_opts
, create_opts
);
439 DECLARE_LIBBPF_OPTS(bpf_link_update_opts
, update_opts
);
440 int err
, link
, old_net
;
443 netns
= unshare_net(old_net
);
447 link
= bpf_link_create(prog1
, netns
, BPF_FLOW_DISSECTOR
, &create_opts
);
448 if (CHECK_FAIL(link
< 0)) {
449 perror("bpf_link_create(prog1)");
452 CHECK_FAIL(query_attached_prog_id(netns
) != query_prog_id(prog1
));
455 err
= setns(old_net
, CLONE_NEWNET
);
456 if (CHECK_FAIL(err
)) {
457 perror("setns(CLONE_NEWNET)");
462 /* Expect failure when netns destroyed */
464 update_opts
.flags
= 0;
465 update_opts
.old_prog_fd
= 0;
466 err
= bpf_link_update(link
, prog2
, &update_opts
);
467 if (CHECK_FAIL(!err
|| errno
!= ENOLINK
))
468 perror("bpf_link_update");
473 static void test_link_get_info(int netns
, int prog1
, int prog2
)
475 DECLARE_LIBBPF_OPTS(bpf_link_create_opts
, create_opts
);
476 DECLARE_LIBBPF_OPTS(bpf_link_update_opts
, update_opts
);
477 struct bpf_link_info info
= {};
478 struct stat netns_stat
= {};
479 __u32 info_len
, link_id
;
480 int err
, link
, old_net
;
483 netns
= unshare_net(old_net
);
487 err
= fstat(netns
, &netns_stat
);
488 if (CHECK_FAIL(err
)) {
489 perror("stat(netns)");
493 link
= bpf_link_create(prog1
, netns
, BPF_FLOW_DISSECTOR
, &create_opts
);
494 if (CHECK_FAIL(link
< 0)) {
495 perror("bpf_link_create(prog1)");
499 info_len
= sizeof(info
);
500 err
= bpf_obj_get_info_by_fd(link
, &info
, &info_len
);
501 if (CHECK_FAIL(err
)) {
502 perror("bpf_obj_get_info");
505 CHECK_FAIL(info_len
!= sizeof(info
));
507 /* Expect link info to be sane and match prog and netns details */
508 CHECK_FAIL(info
.type
!= BPF_LINK_TYPE_NETNS
);
509 CHECK_FAIL(info
.id
== 0);
510 CHECK_FAIL(info
.prog_id
!= query_prog_id(prog1
));
511 CHECK_FAIL(info
.netns
.netns_ino
!= netns_stat
.st_ino
);
512 CHECK_FAIL(info
.netns
.attach_type
!= BPF_FLOW_DISSECTOR
);
514 update_opts
.flags
= 0;
515 update_opts
.old_prog_fd
= 0;
516 err
= bpf_link_update(link
, prog2
, &update_opts
);
517 if (CHECK_FAIL(err
)) {
518 perror("bpf_link_update(prog2)");
523 info_len
= sizeof(info
);
524 err
= bpf_obj_get_info_by_fd(link
, &info
, &info_len
);
525 if (CHECK_FAIL(err
)) {
526 perror("bpf_obj_get_info");
529 CHECK_FAIL(info_len
!= sizeof(info
));
531 /* Expect no info change after update except in prog id */
532 CHECK_FAIL(info
.type
!= BPF_LINK_TYPE_NETNS
);
533 CHECK_FAIL(info
.id
!= link_id
);
534 CHECK_FAIL(info
.prog_id
!= query_prog_id(prog2
));
535 CHECK_FAIL(info
.netns
.netns_ino
!= netns_stat
.st_ino
);
536 CHECK_FAIL(info
.netns
.attach_type
!= BPF_FLOW_DISSECTOR
);
538 /* Leave netns link is attached to and close last FD to it */
539 err
= setns(old_net
, CLONE_NEWNET
);
540 if (CHECK_FAIL(err
)) {
541 perror("setns(NEWNET)");
548 info_len
= sizeof(info
);
549 err
= bpf_obj_get_info_by_fd(link
, &info
, &info_len
);
550 if (CHECK_FAIL(err
)) {
551 perror("bpf_obj_get_info");
554 CHECK_FAIL(info_len
!= sizeof(info
));
556 /* Expect netns_ino to change to 0 */
557 CHECK_FAIL(info
.type
!= BPF_LINK_TYPE_NETNS
);
558 CHECK_FAIL(info
.id
!= link_id
);
559 CHECK_FAIL(info
.prog_id
!= query_prog_id(prog2
));
560 CHECK_FAIL(info
.netns
.netns_ino
!= 0);
561 CHECK_FAIL(info
.netns
.attach_type
!= BPF_FLOW_DISSECTOR
);
567 setns(old_net
, CLONE_NEWNET
);
572 static void run_tests(int netns
)
575 const char *test_name
;
576 void (*test_func
)(int netns
, int prog1
, int prog2
);
578 { "prog attach, prog attach",
579 test_prog_attach_prog_attach
},
580 { "link create, link create",
581 test_link_create_link_create
},
582 { "prog attach, link create",
583 test_prog_attach_link_create
},
584 { "link create, prog attach",
585 test_link_create_prog_attach
},
586 { "link create, prog detach",
587 test_link_create_prog_detach
},
588 { "prog attach, detach, query",
589 test_prog_attach_detach_query
},
590 { "link create, close, query",
591 test_link_create_close_query
},
592 { "link update no old prog",
593 test_link_update_no_old_prog
},
594 { "link update with replace old prog",
595 test_link_update_replace_old_prog
},
596 { "link update with same prog",
597 test_link_update_same_prog
},
598 { "link update invalid opts",
599 test_link_update_invalid_opts
},
600 { "link update invalid prog",
601 test_link_update_invalid_prog
},
602 { "link update netns gone",
603 test_link_update_netns_gone
},
605 test_link_get_info
},
607 int i
, progs
[2] = { -1, -1 };
610 for (i
= 0; i
< ARRAY_SIZE(progs
); i
++) {
611 progs
[i
] = load_prog(BPF_PROG_TYPE_FLOW_DISSECTOR
);
616 for (i
= 0; i
< ARRAY_SIZE(tests
); i
++) {
617 snprintf(test_name
, sizeof(test_name
),
618 "flow dissector %s%s",
620 netns
== init_net
? " (init_net)" : "");
621 if (test__start_subtest(test_name
))
622 tests
[i
].test_func(netns
, progs
[0], progs
[1]);
625 for (i
= 0; i
< ARRAY_SIZE(progs
); i
++) {
627 CHECK_FAIL(close(progs
[i
]));
631 void test_flow_dissector_reattach(void)
633 int err
, new_net
, saved_net
;
635 saved_net
= open("/proc/self/ns/net", O_RDONLY
);
636 if (CHECK_FAIL(saved_net
< 0)) {
637 perror("open(/proc/self/ns/net");
641 init_net
= open("/proc/1/ns/net", O_RDONLY
);
642 if (CHECK_FAIL(init_net
< 0)) {
643 perror("open(/proc/1/ns/net)");
647 err
= setns(init_net
, CLONE_NEWNET
);
648 if (CHECK_FAIL(err
)) {
649 perror("setns(/proc/1/ns/net)");
653 if (prog_is_attached(init_net
)) {
655 printf("Can't test with flow dissector attached to init_net\n");
659 /* First run tests in root network namespace */
662 /* Then repeat tests in a non-root namespace */
663 new_net
= unshare_net(init_net
);
670 /* Move back to netns we started in. */
671 err
= setns(saved_net
, CLONE_NEWNET
);
673 perror("setns(/proc/self/ns/net)");