142 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#include "test_progs.h"4#include "network_helpers.h"5#include "cgroup_helpers.h"6#include "cgroup_ancestor.skel.h"7 8#define CGROUP_PATH "/skb_cgroup_test"9#define TEST_NS "cgroup_ancestor_ns"10#define NUM_CGROUP_LEVELS 411#define WAIT_AUTO_IP_MAX_ATTEMPT 1012#define DST_ADDR "::1"13#define DST_PORT 123414#define MAX_ASSERT_NAME 3215 16struct test_data {17 struct cgroup_ancestor *skel;18 struct bpf_tc_hook qdisc;19 struct bpf_tc_opts tc_attach;20 struct nstoken *ns;21};22 23static int send_datagram(void)24{25 unsigned char buf[] = "some random test data";26 struct sockaddr_in6 addr = { .sin6_family = AF_INET6,27 .sin6_port = htons(DST_PORT), };28 int sock, n;29 30 if (!ASSERT_EQ(inet_pton(AF_INET6, DST_ADDR, &addr.sin6_addr), 1,31 "inet_pton"))32 return -1;33 34 sock = socket(AF_INET6, SOCK_DGRAM, 0);35 if (!ASSERT_OK_FD(sock, "create socket"))36 return sock;37 38 if (!ASSERT_OK(connect(sock, (struct sockaddr *)&addr, sizeof(addr)), "connect")) {39 close(sock);40 return -1;41 }42 43 n = sendto(sock, buf, sizeof(buf), 0, (const struct sockaddr *)&addr,44 sizeof(addr));45 close(sock);46 return ASSERT_EQ(n, sizeof(buf), "send data") ? 0 : -1;47}48 49static int setup_network(struct test_data *t)50{51 SYS(fail, "ip netns add %s", TEST_NS);52 t->ns = open_netns(TEST_NS);53 if (!ASSERT_OK_PTR(t->ns, "open netns"))54 goto cleanup_ns;55 56 SYS(close_ns, "ip link set lo up");57 58 memset(&t->qdisc, 0, sizeof(t->qdisc));59 t->qdisc.sz = sizeof(t->qdisc);60 t->qdisc.attach_point = BPF_TC_EGRESS;61 t->qdisc.ifindex = if_nametoindex("lo");62 if (!ASSERT_NEQ(t->qdisc.ifindex, 0, "if_nametoindex"))63 goto close_ns;64 if (!ASSERT_OK(bpf_tc_hook_create(&t->qdisc), "qdisc add"))65 goto close_ns;66 67 memset(&t->tc_attach, 0, sizeof(t->tc_attach));68 t->tc_attach.sz = sizeof(t->tc_attach);69 t->tc_attach.prog_fd = bpf_program__fd(t->skel->progs.log_cgroup_id);70 if (!ASSERT_OK(bpf_tc_attach(&t->qdisc, &t->tc_attach), "filter add"))71 goto cleanup_qdisc;72 73 return 0;74 75cleanup_qdisc:76 bpf_tc_hook_destroy(&t->qdisc);77close_ns:78 close_netns(t->ns);79cleanup_ns:80 SYS_NOFAIL("ip netns del %s", TEST_NS);81fail:82 return 1;83}84 85static void cleanup_network(struct test_data *t)86{87 bpf_tc_detach(&t->qdisc, &t->tc_attach);88 bpf_tc_hook_destroy(&t->qdisc);89 close_netns(t->ns);90 SYS_NOFAIL("ip netns del %s", TEST_NS);91}92 93static void check_ancestors_ids(struct test_data *t)94{95 __u64 expected_ids[NUM_CGROUP_LEVELS];96 char assert_name[MAX_ASSERT_NAME];97 __u32 level;98 99 expected_ids[0] = get_cgroup_id("/.."); /* root cgroup */100 expected_ids[1] = get_cgroup_id("");101 expected_ids[2] = get_cgroup_id(CGROUP_PATH);102 expected_ids[3] = 0; /* non-existent cgroup */103 104 for (level = 0; level < NUM_CGROUP_LEVELS; level++) {105 snprintf(assert_name, MAX_ASSERT_NAME,106 "ancestor id at level %d", level);107 ASSERT_EQ(t->skel->bss->cgroup_ids[level], expected_ids[level],108 assert_name);109 }110}111 112void test_cgroup_ancestor(void)113{114 struct test_data t;115 int cgroup_fd;116 117 t.skel = cgroup_ancestor__open_and_load();118 if (!ASSERT_OK_PTR(t.skel, "open and load"))119 return;120 121 t.skel->bss->dport = htons(DST_PORT);122 cgroup_fd = cgroup_setup_and_join(CGROUP_PATH);123 if (cgroup_fd < 0)124 goto cleanup_progs;125 126 if (setup_network(&t))127 goto cleanup_cgroups;128 129 if (send_datagram())130 goto cleanup_network;131 132 check_ancestors_ids(&t);133 134cleanup_network:135 cleanup_network(&t);136cleanup_cgroups:137 close(cgroup_fd);138 cleanup_cgroup_environment();139cleanup_progs:140 cgroup_ancestor__destroy(t.skel);141}142