WIP FPC-III support
[linux/fpc-iii.git] / tools / testing / selftests / bpf / prog_tests / flow_dissector_reattach.c
blob172c586b69969b29d1e67c108f9649ea69c1ea1f
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Tests for attaching, detaching, and replacing flow_dissector BPF program.
4 */
6 #define _GNU_SOURCE
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <sched.h>
10 #include <stdbool.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
14 #include <linux/bpf.h>
15 #include <bpf/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);
25 int err;
27 err = bpf_prog_query(netns, BPF_FLOW_DISSECTOR, 0, NULL,
28 prog_ids, &prog_cnt);
29 if (CHECK_FAIL(err)) {
30 perror("bpf_prog_query");
31 return 0;
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),
46 BPF_EXIT_INSN(),
48 int fd;
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");
54 return fd;
57 static __u32 query_prog_id(int prog)
59 struct bpf_prog_info info = {};
60 __u32 info_len = sizeof(info);
61 int err;
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");
66 return 0;
69 return info.id;
72 static int unshare_net(int old_net)
74 int err, new_net;
76 err = unshare(CLONE_NEWNET);
77 if (CHECK_FAIL(err)) {
78 perror("unshare(CLONE_NEWNET)");
79 return -1;
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);
85 return -1;
87 return new_net;
90 static void test_prog_attach_prog_attach(int netns, int prog1, int prog2)
92 int err;
94 err = bpf_prog_attach(prog1, 0, BPF_FLOW_DISSECTOR, 0);
95 if (CHECK_FAIL(err)) {
96 perror("bpf_prog_attach(prog1)");
97 return;
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");
105 goto out_detach;
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));
115 out_detach:
116 err = bpf_prog_detach2(prog2, 0, BPF_FLOW_DISSECTOR);
117 if (CHECK_FAIL(err))
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);
125 int link1, link2;
127 link1 = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &opts);
128 if (CHECK_FAIL(link < 0)) {
129 perror("bpf_link_create(prog1)");
130 return;
132 CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));
134 /* Expect failure creating link when another link exists */
135 errno = 0;
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");
139 if (link2 != -1)
140 close(link2);
141 CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));
143 close(link1);
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);
150 int err, link;
152 err = bpf_prog_attach(prog1, 0, BPF_FLOW_DISSECTOR, 0);
153 if (CHECK_FAIL(err)) {
154 perror("bpf_prog_attach(prog1)");
155 return;
157 CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));
159 /* Expect failure creating link when prog attached */
160 errno = 0;
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");
164 if (link != -1)
165 close(link);
166 CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));
168 err = bpf_prog_detach2(prog1, 0, BPF_FLOW_DISSECTOR);
169 if (CHECK_FAIL(err))
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);
177 int err, link;
179 link = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &opts);
180 if (CHECK_FAIL(link < 0)) {
181 perror("bpf_link_create(prog1)");
182 return;
184 CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));
186 /* Expect failure attaching prog when link exists */
187 errno = 0;
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));
193 close(link);
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);
200 int err, link;
202 link = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &opts);
203 if (CHECK_FAIL(link < 0)) {
204 perror("bpf_link_create(prog1)");
205 return;
207 CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));
209 /* Expect failure detaching prog when link exists */
210 errno = 0;
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));
216 close(link);
217 CHECK_FAIL(prog_is_attached(netns));
220 static void test_prog_attach_detach_query(int netns, int prog1, int prog2)
222 int err;
224 err = bpf_prog_attach(prog1, 0, BPF_FLOW_DISSECTOR, 0);
225 if (CHECK_FAIL(err)) {
226 perror("bpf_prog_attach(prog1)");
227 return;
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");
234 return;
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);
244 int link;
246 link = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &opts);
247 if (CHECK_FAIL(link < 0)) {
248 perror("bpf_link_create(prog1)");
249 return;
251 CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));
253 close(link);
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);
262 int err, link;
264 link = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &create_opts);
265 if (CHECK_FAIL(link < 0)) {
266 perror("bpf_link_create(prog1)");
267 return;
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);
275 if (CHECK_FAIL(err))
276 perror("bpf_link_update");
277 CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog2));
279 close(link);
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);
287 int err, link;
289 link = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &create_opts);
290 if (CHECK_FAIL(link < 0)) {
291 perror("bpf_link_create(prog1)");
292 return;
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);
300 if (CHECK_FAIL(err))
301 perror("bpf_link_update");
302 CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog2));
304 close(link);
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);
312 int err, link;
314 link = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &create_opts);
315 if (CHECK_FAIL(link < 0)) {
316 perror("bpf_link_create(prog1)");
317 return;
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);
325 if (CHECK_FAIL(err))
326 perror("bpf_link_update");
327 CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));
329 close(link);
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);
337 int err, link;
339 link = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &create_opts);
340 if (CHECK_FAIL(link < 0)) {
341 perror("bpf_link_create(prog1)");
342 return;
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*/
347 errno = 0;
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");
353 goto out_close;
355 CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));
357 /* Expect update to fail on old prog FD mismatch */
358 errno = 0;
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");
364 goto out_close;
366 CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));
368 /* Expect update to fail for invalid old prog FD */
369 errno = 0;
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");
375 goto out_close;
377 CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));
379 /* Expect update to fail with invalid flags */
380 errno = 0;
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));
388 out_close:
389 close(link);
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)");
402 return;
404 CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));
406 /* Expect failure when new prog FD is not valid */
407 errno = 0;
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");
413 goto out_close_link;
415 CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));
417 prog3 = load_prog(BPF_PROG_TYPE_SOCKET_FILTER);
418 if (prog3 < 0)
419 goto out_close_link;
421 /* Expect failure when new prog FD type doesn't match */
422 errno = 0;
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));
430 close(prog3);
431 out_close_link:
432 close(link);
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;
442 old_net = netns;
443 netns = unshare_net(old_net);
444 if (netns < 0)
445 return;
447 link = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &create_opts);
448 if (CHECK_FAIL(link < 0)) {
449 perror("bpf_link_create(prog1)");
450 return;
452 CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));
454 close(netns);
455 err = setns(old_net, CLONE_NEWNET);
456 if (CHECK_FAIL(err)) {
457 perror("setns(CLONE_NEWNET)");
458 close(link);
459 return;
462 /* Expect failure when netns destroyed */
463 errno = 0;
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");
470 close(link);
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;
482 old_net = netns;
483 netns = unshare_net(old_net);
484 if (netns < 0)
485 return;
487 err = fstat(netns, &netns_stat);
488 if (CHECK_FAIL(err)) {
489 perror("stat(netns)");
490 goto out_resetns;
493 link = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &create_opts);
494 if (CHECK_FAIL(link < 0)) {
495 perror("bpf_link_create(prog1)");
496 goto out_resetns;
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");
503 goto out_unlink;
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)");
519 goto out_unlink;
522 link_id = info.id;
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");
527 goto out_unlink;
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)");
542 goto out_unlink;
544 close(netns);
545 old_net = -1;
546 netns = -1;
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");
552 goto out_unlink;
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);
563 out_unlink:
564 close(link);
565 out_resetns:
566 if (old_net != -1)
567 setns(old_net, CLONE_NEWNET);
568 if (netns != -1)
569 close(netns);
572 static void run_tests(int netns)
574 struct test {
575 const char *test_name;
576 void (*test_func)(int netns, int prog1, int prog2);
577 } tests[] = {
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 },
604 { "link get info",
605 test_link_get_info },
607 int i, progs[2] = { -1, -1 };
608 char test_name[80];
610 for (i = 0; i < ARRAY_SIZE(progs); i++) {
611 progs[i] = load_prog(BPF_PROG_TYPE_FLOW_DISSECTOR);
612 if (progs[i] < 0)
613 goto out_close;
616 for (i = 0; i < ARRAY_SIZE(tests); i++) {
617 snprintf(test_name, sizeof(test_name),
618 "flow dissector %s%s",
619 tests[i].test_name,
620 netns == init_net ? " (init_net)" : "");
621 if (test__start_subtest(test_name))
622 tests[i].test_func(netns, progs[0], progs[1]);
624 out_close:
625 for (i = 0; i < ARRAY_SIZE(progs); i++) {
626 if (progs[i] != -1)
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");
638 return;
641 init_net = open("/proc/1/ns/net", O_RDONLY);
642 if (CHECK_FAIL(init_net < 0)) {
643 perror("open(/proc/1/ns/net)");
644 goto out_close;
647 err = setns(init_net, CLONE_NEWNET);
648 if (CHECK_FAIL(err)) {
649 perror("setns(/proc/1/ns/net)");
650 goto out_close;
653 if (prog_is_attached(init_net)) {
654 test__skip();
655 printf("Can't test with flow dissector attached to init_net\n");
656 goto out_setns;
659 /* First run tests in root network namespace */
660 run_tests(init_net);
662 /* Then repeat tests in a non-root namespace */
663 new_net = unshare_net(init_net);
664 if (new_net < 0)
665 goto out_setns;
666 run_tests(new_net);
667 close(new_net);
669 out_setns:
670 /* Move back to netns we started in. */
671 err = setns(saved_net, CLONE_NEWNET);
672 if (CHECK_FAIL(err))
673 perror("setns(/proc/self/ns/net)");
675 out_close:
676 close(init_net);
677 close(saved_net);