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