1 // SPDX-License-Identifier: GPL-2.0-only 2 3 /* 4 * Copyright 2020 Google LLC. 5 */ 6 7 #include <test_progs.h> 8 #include <cgroup_helpers.h> 9 #include <network_helpers.h> 10 11 #include "cg_storage_multi_egress_only.skel.h" 12 13 #define PARENT_CGROUP "/cgroup_storage" 14 #define CHILD_CGROUP "/cgroup_storage/child" 15 16 static int duration; 17 18 static bool assert_storage(struct bpf_map *map, const char *cgroup_path, 19 __u32 expected) 20 { 21 struct bpf_cgroup_storage_key key = {0}; 22 __u32 value; 23 int map_fd; 24 25 map_fd = bpf_map__fd(map); 26 27 key.cgroup_inode_id = get_cgroup_id(cgroup_path); 28 key.attach_type = BPF_CGROUP_INET_EGRESS; 29 if (CHECK(bpf_map_lookup_elem(map_fd, &key, &value) < 0, 30 "map-lookup", "errno %d", errno)) 31 return true; 32 if (CHECK(value != expected, 33 "assert-storage", "got %u expected %u", value, expected)) 34 return true; 35 36 return false; 37 } 38 39 static bool assert_storage_noexist(struct bpf_map *map, const char *cgroup_path) 40 { 41 struct bpf_cgroup_storage_key key = {0}; 42 __u32 value; 43 int map_fd; 44 45 map_fd = bpf_map__fd(map); 46 47 key.cgroup_inode_id = get_cgroup_id(cgroup_path); 48 key.attach_type = BPF_CGROUP_INET_EGRESS; 49 if (CHECK(bpf_map_lookup_elem(map_fd, &key, &value) == 0, 50 "map-lookup", "succeeded, expected ENOENT")) 51 return true; 52 if (CHECK(errno != ENOENT, 53 "map-lookup", "errno %d, expected ENOENT", errno)) 54 return true; 55 56 return false; 57 } 58 59 static bool connect_send(const char *cgroup_path) 60 { 61 bool res = true; 62 int server_fd = -1, client_fd = -1; 63 64 if (join_cgroup(cgroup_path)) 65 goto out_clean; 66 67 server_fd = start_server(AF_INET, SOCK_DGRAM, NULL, 0, 0); 68 if (server_fd < 0) 69 goto out_clean; 70 71 client_fd = connect_to_fd(server_fd, 0); 72 if (client_fd < 0) 73 goto out_clean; 74 75 if (send(client_fd, "message", strlen("message"), 0) < 0) 76 goto out_clean; 77 78 res = false; 79 80 out_clean: 81 close(client_fd); 82 close(server_fd); 83 return res; 84 } 85 86 static void test_egress_only(int parent_cgroup_fd, int child_cgroup_fd) 87 { 88 struct cg_storage_multi_egress_only *obj; 89 struct bpf_link *parent_link = NULL, *child_link = NULL; 90 bool err; 91 92 obj = cg_storage_multi_egress_only__open_and_load(); 93 if (CHECK(!obj, "skel-load", "errno %d", errno)) 94 return; 95 96 /* Attach to parent cgroup, trigger packet from child. 97 * Assert that there is only one run and in that run the storage is 98 * parent cgroup's storage. 99 * Also assert that child cgroup's storage does not exist 100 */ 101 parent_link = bpf_program__attach_cgroup(obj->progs.egress, 102 parent_cgroup_fd); 103 if (CHECK(IS_ERR(parent_link), "parent-cg-attach", 104 "err %ld", PTR_ERR(parent_link))) 105 goto close_bpf_object; 106 err = connect_send(CHILD_CGROUP); 107 if (CHECK(err, "first-connect-send", "errno %d", errno)) 108 goto close_bpf_object; 109 if (CHECK(obj->bss->invocations != 1, 110 "first-invoke", "invocations=%d", obj->bss->invocations)) 111 goto close_bpf_object; 112 if (assert_storage(obj->maps.cgroup_storage, PARENT_CGROUP, 1)) 113 goto close_bpf_object; 114 if (assert_storage_noexist(obj->maps.cgroup_storage, CHILD_CGROUP)) 115 goto close_bpf_object; 116 117 /* Attach to parent and child cgroup, trigger packet from child. 118 * Assert that there are two additional runs, one that run with parent 119 * cgroup's storage and one with child cgroup's storage. 120 */ 121 child_link = bpf_program__attach_cgroup(obj->progs.egress, 122 child_cgroup_fd); 123 if (CHECK(IS_ERR(child_link), "child-cg-attach", 124 "err %ld", PTR_ERR(child_link))) 125 goto close_bpf_object; 126 err = connect_send(CHILD_CGROUP); 127 if (CHECK(err, "second-connect-send", "errno %d", errno)) 128 goto close_bpf_object; 129 if (CHECK(obj->bss->invocations != 3, 130 "second-invoke", "invocations=%d", obj->bss->invocations)) 131 goto close_bpf_object; 132 if (assert_storage(obj->maps.cgroup_storage, PARENT_CGROUP, 2)) 133 goto close_bpf_object; 134 if (assert_storage(obj->maps.cgroup_storage, CHILD_CGROUP, 1)) 135 goto close_bpf_object; 136 137 close_bpf_object: 138 bpf_link__destroy(parent_link); 139 bpf_link__destroy(child_link); 140 141 cg_storage_multi_egress_only__destroy(obj); 142 } 143 144 void test_cg_storage_multi(void) 145 { 146 int parent_cgroup_fd = -1, child_cgroup_fd = -1; 147 148 parent_cgroup_fd = test__join_cgroup(PARENT_CGROUP); 149 if (CHECK(parent_cgroup_fd < 0, "cg-create-parent", "errno %d", errno)) 150 goto close_cgroup_fd; 151 child_cgroup_fd = create_and_get_cgroup(CHILD_CGROUP); 152 if (CHECK(child_cgroup_fd < 0, "cg-create-child", "errno %d", errno)) 153 goto close_cgroup_fd; 154 155 if (test__start_subtest("egress_only")) 156 test_egress_only(parent_cgroup_fd, child_cgroup_fd); 157 158 close_cgroup_fd: 159 close(child_cgroup_fd); 160 close(parent_cgroup_fd); 161 } 162