selftests/bpf: add auto-detach test
authorRoman Gushchin <guro@fb.com>
Sat, 25 May 2019 16:37:42 +0000 (09:37 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Tue, 28 May 2019 16:30:02 +0000 (09:30 -0700)
Add a kselftest to cover bpf auto-detachment functionality.
The test creates a cgroup, associates some resources with it,
attaches a couple of bpf programs and deletes the cgroup.

Then it checks that bpf programs are going away in 5 seconds.

Expected output:
  $ ./test_cgroup_attach
  #override:PASS
  #multi:PASS
  #autodetach:PASS
  test_cgroup_attach:PASS

On a kernel without auto-detaching:
  $ ./test_cgroup_attach
  #override:PASS
  #multi:PASS
  #autodetach:FAIL
  test_cgroup_attach:FAIL

Signed-off-by: Roman Gushchin <guro@fb.com>
Acked-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/testing/selftests/bpf/test_cgroup_attach.c

index 2d6d57f50e109aa967dc598467c1d5f2b1fd9438..7671909ee1cbdd4d140fa7836ede3895f59c0eb0 100644 (file)
@@ -456,9 +456,105 @@ out:
        return rc;
 }
 
+static int test_autodetach(void)
+{
+       __u32 prog_cnt = 4, attach_flags;
+       int allow_prog[2] = {0};
+       __u32 prog_ids[2] = {0};
+       int cg = 0, i, rc = -1;
+       void *ptr = NULL;
+       int attempts;
+
+       for (i = 0; i < ARRAY_SIZE(allow_prog); i++) {
+               allow_prog[i] = prog_load_cnt(1, 1 << i);
+               if (!allow_prog[i])
+                       goto err;
+       }
+
+       if (setup_cgroup_environment())
+               goto err;
+
+       /* create a cgroup, attach two programs and remember their ids */
+       cg = create_and_get_cgroup("/cg_autodetach");
+       if (cg < 0)
+               goto err;
+
+       if (join_cgroup("/cg_autodetach"))
+               goto err;
+
+       for (i = 0; i < ARRAY_SIZE(allow_prog); i++) {
+               if (bpf_prog_attach(allow_prog[i], cg, BPF_CGROUP_INET_EGRESS,
+                                   BPF_F_ALLOW_MULTI)) {
+                       log_err("Attaching prog[%d] to cg:egress", i);
+                       goto err;
+               }
+       }
+
+       /* make sure that programs are attached and run some traffic */
+       assert(bpf_prog_query(cg, BPF_CGROUP_INET_EGRESS, 0, &attach_flags,
+                             prog_ids, &prog_cnt) == 0);
+       assert(system(PING_CMD) == 0);
+
+       /* allocate some memory (4Mb) to pin the original cgroup */
+       ptr = malloc(4 * (1 << 20));
+       if (!ptr)
+               goto err;
+
+       /* close programs and cgroup fd */
+       for (i = 0; i < ARRAY_SIZE(allow_prog); i++) {
+               close(allow_prog[i]);
+               allow_prog[i] = 0;
+       }
+
+       close(cg);
+       cg = 0;
+
+       /* leave the cgroup and remove it. don't detach programs */
+       cleanup_cgroup_environment();
+
+       /* wait for the asynchronous auto-detachment.
+        * wait for no more than 5 sec and give up.
+        */
+       for (i = 0; i < ARRAY_SIZE(prog_ids); i++) {
+               for (attempts = 5; attempts >= 0; attempts--) {
+                       int fd = bpf_prog_get_fd_by_id(prog_ids[i]);
+
+                       if (fd < 0)
+                               break;
+
+                       /* don't leave the fd open */
+                       close(fd);
+
+                       if (!attempts)
+                               goto err;
+
+                       sleep(1);
+               }
+       }
+
+       rc = 0;
+err:
+       for (i = 0; i < ARRAY_SIZE(allow_prog); i++)
+               if (allow_prog[i] > 0)
+                       close(allow_prog[i]);
+       if (cg)
+               close(cg);
+       free(ptr);
+       cleanup_cgroup_environment();
+       if (!rc)
+               printf("#autodetach:PASS\n");
+       else
+               printf("#autodetach:FAIL\n");
+       return rc;
+}
+
 int main(void)
 {
-       int (*tests[])(void) = {test_foo_bar, test_multiprog};
+       int (*tests[])(void) = {
+               test_foo_bar,
+               test_multiprog,
+               test_autodetach,
+       };
        int errors = 0;
        int i;