1d4a89c1eSYiFei Zhu // SPDX-License-Identifier: GPL-2.0-only 2d4a89c1eSYiFei Zhu 3d4a89c1eSYiFei Zhu /* 4d4a89c1eSYiFei Zhu * Copyright 2020 Google LLC. 5d4a89c1eSYiFei Zhu */ 6d4a89c1eSYiFei Zhu 7d4a89c1eSYiFei Zhu #include <test_progs.h> 8d4a89c1eSYiFei Zhu #include <cgroup_helpers.h> 9d4a89c1eSYiFei Zhu #include <network_helpers.h> 10d4a89c1eSYiFei Zhu 119e5bd1f7SYiFei Zhu #include "progs/cg_storage_multi.h" 129e5bd1f7SYiFei Zhu 13d4a89c1eSYiFei Zhu #include "cg_storage_multi_egress_only.skel.h" 149e5bd1f7SYiFei Zhu #include "cg_storage_multi_egress_ingress.skel.h" 15d4a89c1eSYiFei Zhu 16d4a89c1eSYiFei Zhu #define PARENT_CGROUP "/cgroup_storage" 17d4a89c1eSYiFei Zhu #define CHILD_CGROUP "/cgroup_storage/child" 18d4a89c1eSYiFei Zhu 19d4a89c1eSYiFei Zhu static int duration; 20d4a89c1eSYiFei Zhu 21d4a89c1eSYiFei Zhu static bool assert_storage(struct bpf_map *map, const char *cgroup_path, 229e5bd1f7SYiFei Zhu struct cgroup_value *expected) 23d4a89c1eSYiFei Zhu { 24d4a89c1eSYiFei Zhu struct bpf_cgroup_storage_key key = {0}; 259e5bd1f7SYiFei Zhu struct cgroup_value value; 26d4a89c1eSYiFei Zhu int map_fd; 27d4a89c1eSYiFei Zhu 28d4a89c1eSYiFei Zhu map_fd = bpf_map__fd(map); 29d4a89c1eSYiFei Zhu 30d4a89c1eSYiFei Zhu key.cgroup_inode_id = get_cgroup_id(cgroup_path); 31d4a89c1eSYiFei Zhu key.attach_type = BPF_CGROUP_INET_EGRESS; 32d4a89c1eSYiFei Zhu if (CHECK(bpf_map_lookup_elem(map_fd, &key, &value) < 0, 33d4a89c1eSYiFei Zhu "map-lookup", "errno %d", errno)) 34d4a89c1eSYiFei Zhu return true; 359e5bd1f7SYiFei Zhu if (CHECK(memcmp(&value, expected, sizeof(struct cgroup_value)), 369e5bd1f7SYiFei Zhu "assert-storage", "storages differ")) 37d4a89c1eSYiFei Zhu return true; 38d4a89c1eSYiFei Zhu 39d4a89c1eSYiFei Zhu return false; 40d4a89c1eSYiFei Zhu } 41d4a89c1eSYiFei Zhu 42d4a89c1eSYiFei Zhu static bool assert_storage_noexist(struct bpf_map *map, const char *cgroup_path) 43d4a89c1eSYiFei Zhu { 44d4a89c1eSYiFei Zhu struct bpf_cgroup_storage_key key = {0}; 459e5bd1f7SYiFei Zhu struct cgroup_value value; 46d4a89c1eSYiFei Zhu int map_fd; 47d4a89c1eSYiFei Zhu 48d4a89c1eSYiFei Zhu map_fd = bpf_map__fd(map); 49d4a89c1eSYiFei Zhu 50d4a89c1eSYiFei Zhu key.cgroup_inode_id = get_cgroup_id(cgroup_path); 51d4a89c1eSYiFei Zhu key.attach_type = BPF_CGROUP_INET_EGRESS; 52d4a89c1eSYiFei Zhu if (CHECK(bpf_map_lookup_elem(map_fd, &key, &value) == 0, 53d4a89c1eSYiFei Zhu "map-lookup", "succeeded, expected ENOENT")) 54d4a89c1eSYiFei Zhu return true; 55d4a89c1eSYiFei Zhu if (CHECK(errno != ENOENT, 56d4a89c1eSYiFei Zhu "map-lookup", "errno %d, expected ENOENT", errno)) 57d4a89c1eSYiFei Zhu return true; 58d4a89c1eSYiFei Zhu 59d4a89c1eSYiFei Zhu return false; 60d4a89c1eSYiFei Zhu } 61d4a89c1eSYiFei Zhu 62d4a89c1eSYiFei Zhu static bool connect_send(const char *cgroup_path) 63d4a89c1eSYiFei Zhu { 64d4a89c1eSYiFei Zhu bool res = true; 65d4a89c1eSYiFei Zhu int server_fd = -1, client_fd = -1; 66d4a89c1eSYiFei Zhu 67d4a89c1eSYiFei Zhu if (join_cgroup(cgroup_path)) 68d4a89c1eSYiFei Zhu goto out_clean; 69d4a89c1eSYiFei Zhu 70d4a89c1eSYiFei Zhu server_fd = start_server(AF_INET, SOCK_DGRAM, NULL, 0, 0); 71d4a89c1eSYiFei Zhu if (server_fd < 0) 72d4a89c1eSYiFei Zhu goto out_clean; 73d4a89c1eSYiFei Zhu 74d4a89c1eSYiFei Zhu client_fd = connect_to_fd(server_fd, 0); 75d4a89c1eSYiFei Zhu if (client_fd < 0) 76d4a89c1eSYiFei Zhu goto out_clean; 77d4a89c1eSYiFei Zhu 78d4a89c1eSYiFei Zhu if (send(client_fd, "message", strlen("message"), 0) < 0) 79d4a89c1eSYiFei Zhu goto out_clean; 80d4a89c1eSYiFei Zhu 81d4a89c1eSYiFei Zhu res = false; 82d4a89c1eSYiFei Zhu 83d4a89c1eSYiFei Zhu out_clean: 84d4a89c1eSYiFei Zhu close(client_fd); 85d4a89c1eSYiFei Zhu close(server_fd); 86d4a89c1eSYiFei Zhu return res; 87d4a89c1eSYiFei Zhu } 88d4a89c1eSYiFei Zhu 89d4a89c1eSYiFei Zhu static void test_egress_only(int parent_cgroup_fd, int child_cgroup_fd) 90d4a89c1eSYiFei Zhu { 91d4a89c1eSYiFei Zhu struct cg_storage_multi_egress_only *obj; 929e5bd1f7SYiFei Zhu struct cgroup_value expected_cgroup_value; 93d4a89c1eSYiFei Zhu struct bpf_link *parent_link = NULL, *child_link = NULL; 94d4a89c1eSYiFei Zhu bool err; 95d4a89c1eSYiFei Zhu 96d4a89c1eSYiFei Zhu obj = cg_storage_multi_egress_only__open_and_load(); 97d4a89c1eSYiFei Zhu if (CHECK(!obj, "skel-load", "errno %d", errno)) 98d4a89c1eSYiFei Zhu return; 99d4a89c1eSYiFei Zhu 100d4a89c1eSYiFei Zhu /* Attach to parent cgroup, trigger packet from child. 101d4a89c1eSYiFei Zhu * Assert that there is only one run and in that run the storage is 102d4a89c1eSYiFei Zhu * parent cgroup's storage. 103d4a89c1eSYiFei Zhu * Also assert that child cgroup's storage does not exist 104d4a89c1eSYiFei Zhu */ 105d4a89c1eSYiFei Zhu parent_link = bpf_program__attach_cgroup(obj->progs.egress, 106d4a89c1eSYiFei Zhu parent_cgroup_fd); 107d4a89c1eSYiFei Zhu if (CHECK(IS_ERR(parent_link), "parent-cg-attach", 108d4a89c1eSYiFei Zhu "err %ld", PTR_ERR(parent_link))) 109d4a89c1eSYiFei Zhu goto close_bpf_object; 110d4a89c1eSYiFei Zhu err = connect_send(CHILD_CGROUP); 111d4a89c1eSYiFei Zhu if (CHECK(err, "first-connect-send", "errno %d", errno)) 112d4a89c1eSYiFei Zhu goto close_bpf_object; 113d4a89c1eSYiFei Zhu if (CHECK(obj->bss->invocations != 1, 114d4a89c1eSYiFei Zhu "first-invoke", "invocations=%d", obj->bss->invocations)) 115d4a89c1eSYiFei Zhu goto close_bpf_object; 1169e5bd1f7SYiFei Zhu expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 1 }; 1179e5bd1f7SYiFei Zhu if (assert_storage(obj->maps.cgroup_storage, 1189e5bd1f7SYiFei Zhu PARENT_CGROUP, &expected_cgroup_value)) 119d4a89c1eSYiFei Zhu goto close_bpf_object; 120d4a89c1eSYiFei Zhu if (assert_storage_noexist(obj->maps.cgroup_storage, CHILD_CGROUP)) 121d4a89c1eSYiFei Zhu goto close_bpf_object; 122d4a89c1eSYiFei Zhu 123d4a89c1eSYiFei Zhu /* Attach to parent and child cgroup, trigger packet from child. 124d4a89c1eSYiFei Zhu * Assert that there are two additional runs, one that run with parent 125d4a89c1eSYiFei Zhu * cgroup's storage and one with child cgroup's storage. 126d4a89c1eSYiFei Zhu */ 127d4a89c1eSYiFei Zhu child_link = bpf_program__attach_cgroup(obj->progs.egress, 128d4a89c1eSYiFei Zhu child_cgroup_fd); 129d4a89c1eSYiFei Zhu if (CHECK(IS_ERR(child_link), "child-cg-attach", 130d4a89c1eSYiFei Zhu "err %ld", PTR_ERR(child_link))) 131d4a89c1eSYiFei Zhu goto close_bpf_object; 132d4a89c1eSYiFei Zhu err = connect_send(CHILD_CGROUP); 133d4a89c1eSYiFei Zhu if (CHECK(err, "second-connect-send", "errno %d", errno)) 134d4a89c1eSYiFei Zhu goto close_bpf_object; 135d4a89c1eSYiFei Zhu if (CHECK(obj->bss->invocations != 3, 136d4a89c1eSYiFei Zhu "second-invoke", "invocations=%d", obj->bss->invocations)) 137d4a89c1eSYiFei Zhu goto close_bpf_object; 1389e5bd1f7SYiFei Zhu expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 }; 1399e5bd1f7SYiFei Zhu if (assert_storage(obj->maps.cgroup_storage, 1409e5bd1f7SYiFei Zhu PARENT_CGROUP, &expected_cgroup_value)) 141d4a89c1eSYiFei Zhu goto close_bpf_object; 1429e5bd1f7SYiFei Zhu expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 1 }; 1439e5bd1f7SYiFei Zhu if (assert_storage(obj->maps.cgroup_storage, 1449e5bd1f7SYiFei Zhu CHILD_CGROUP, &expected_cgroup_value)) 145d4a89c1eSYiFei Zhu goto close_bpf_object; 146d4a89c1eSYiFei Zhu 147d4a89c1eSYiFei Zhu close_bpf_object: 148d4a89c1eSYiFei Zhu bpf_link__destroy(parent_link); 149d4a89c1eSYiFei Zhu bpf_link__destroy(child_link); 150d4a89c1eSYiFei Zhu 151d4a89c1eSYiFei Zhu cg_storage_multi_egress_only__destroy(obj); 152d4a89c1eSYiFei Zhu } 153d4a89c1eSYiFei Zhu 1549e5bd1f7SYiFei Zhu static void test_egress_ingress(int parent_cgroup_fd, int child_cgroup_fd) 1559e5bd1f7SYiFei Zhu { 1569e5bd1f7SYiFei Zhu struct cg_storage_multi_egress_ingress *obj; 1579e5bd1f7SYiFei Zhu 1589e5bd1f7SYiFei Zhu /* Cannot load both programs due to verifier failure: 1599e5bd1f7SYiFei Zhu * "only one cgroup storage of each type is allowed" 1609e5bd1f7SYiFei Zhu */ 1619e5bd1f7SYiFei Zhu obj = cg_storage_multi_egress_ingress__open_and_load(); 1629e5bd1f7SYiFei Zhu CHECK(obj || errno != EBUSY, 1639e5bd1f7SYiFei Zhu "skel-load", "errno %d, expected EBUSY", errno); 1649e5bd1f7SYiFei Zhu 1659e5bd1f7SYiFei Zhu cg_storage_multi_egress_ingress__destroy(obj); 1669e5bd1f7SYiFei Zhu } 1679e5bd1f7SYiFei Zhu 168d4a89c1eSYiFei Zhu void test_cg_storage_multi(void) 169d4a89c1eSYiFei Zhu { 170d4a89c1eSYiFei Zhu int parent_cgroup_fd = -1, child_cgroup_fd = -1; 171d4a89c1eSYiFei Zhu 172d4a89c1eSYiFei Zhu parent_cgroup_fd = test__join_cgroup(PARENT_CGROUP); 173d4a89c1eSYiFei Zhu if (CHECK(parent_cgroup_fd < 0, "cg-create-parent", "errno %d", errno)) 174d4a89c1eSYiFei Zhu goto close_cgroup_fd; 175d4a89c1eSYiFei Zhu child_cgroup_fd = create_and_get_cgroup(CHILD_CGROUP); 176d4a89c1eSYiFei Zhu if (CHECK(child_cgroup_fd < 0, "cg-create-child", "errno %d", errno)) 177d4a89c1eSYiFei Zhu goto close_cgroup_fd; 178d4a89c1eSYiFei Zhu 179d4a89c1eSYiFei Zhu if (test__start_subtest("egress_only")) 180d4a89c1eSYiFei Zhu test_egress_only(parent_cgroup_fd, child_cgroup_fd); 181d4a89c1eSYiFei Zhu 1829e5bd1f7SYiFei Zhu if (test__start_subtest("egress_ingress")) 1839e5bd1f7SYiFei Zhu test_egress_ingress(parent_cgroup_fd, child_cgroup_fd); 1849e5bd1f7SYiFei Zhu 185d4a89c1eSYiFei Zhu close_cgroup_fd: 186d4a89c1eSYiFei Zhu close(child_cgroup_fd); 187d4a89c1eSYiFei Zhu close(parent_cgroup_fd); 188d4a89c1eSYiFei Zhu } 189