Linux Audio

Check our new training course

Linux kernel drivers training

May 6-19, 2025
Register
Loading...
Note: File does not exist in v6.2.
  1// SPDX-License-Identifier: GPL-2.0
  2
  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 4
 11#define WAIT_AUTO_IP_MAX_ATTEMPT 10
 12#define DST_ADDR "::1"
 13#define DST_PORT 1234
 14#define MAX_ASSERT_NAME 32
 15
 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}