168cfa3acSRoman Gushchin // SPDX-License-Identifier: GPL-2.0
268cfa3acSRoman Gushchin #include <assert.h>
368cfa3acSRoman Gushchin #include <bpf/bpf.h>
468cfa3acSRoman Gushchin #include <linux/filter.h>
568cfa3acSRoman Gushchin #include <stdio.h>
668cfa3acSRoman Gushchin #include <stdlib.h>
7919646d2SRoman Gushchin #include <sys/sysinfo.h>
868cfa3acSRoman Gushchin
9ebaf24c5SArtem Savkov #include "bpf_util.h"
1068cfa3acSRoman Gushchin #include "cgroup_helpers.h"
11f19ddfe0SAndrii Nakryiko #include "testing_helpers.h"
1268cfa3acSRoman Gushchin
1368cfa3acSRoman Gushchin char bpf_log_buf[BPF_LOG_BUF_SIZE];
1468cfa3acSRoman Gushchin
1568cfa3acSRoman Gushchin #define TEST_CGROUP "/test-bpf-cgroup-storage-buf/"
1668cfa3acSRoman Gushchin
main(int argc,char ** argv)1768cfa3acSRoman Gushchin int main(int argc, char **argv)
1868cfa3acSRoman Gushchin {
1968cfa3acSRoman Gushchin struct bpf_insn prog[] = {
20919646d2SRoman Gushchin BPF_LD_MAP_FD(BPF_REG_1, 0), /* percpu map fd */
21919646d2SRoman Gushchin BPF_MOV64_IMM(BPF_REG_2, 0), /* flags, not used */
22919646d2SRoman Gushchin BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
23919646d2SRoman Gushchin BPF_FUNC_get_local_storage),
24806ce6e2SIlya Leoshkevich BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, 0),
25919646d2SRoman Gushchin BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 0x1),
26806ce6e2SIlya Leoshkevich BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_3, 0),
27919646d2SRoman Gushchin
2868cfa3acSRoman Gushchin BPF_LD_MAP_FD(BPF_REG_1, 0), /* map fd */
2968cfa3acSRoman Gushchin BPF_MOV64_IMM(BPF_REG_2, 0), /* flags, not used */
3068cfa3acSRoman Gushchin BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
3168cfa3acSRoman Gushchin BPF_FUNC_get_local_storage),
3268cfa3acSRoman Gushchin BPF_MOV64_IMM(BPF_REG_1, 1),
3391c960b0SBrendan Jackman BPF_ATOMIC_OP(BPF_DW, BPF_ADD, BPF_REG_0, BPF_REG_1, 0),
34806ce6e2SIlya Leoshkevich BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0),
3568cfa3acSRoman Gushchin BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x1),
3668cfa3acSRoman Gushchin BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
3768cfa3acSRoman Gushchin BPF_EXIT_INSN(),
3868cfa3acSRoman Gushchin };
39f98d6dd1SGuo Zhengkui size_t insns_cnt = ARRAY_SIZE(prog);
4068cfa3acSRoman Gushchin int error = EXIT_FAILURE;
41919646d2SRoman Gushchin int map_fd, percpu_map_fd, prog_fd, cgroup_fd;
4268cfa3acSRoman Gushchin struct bpf_cgroup_storage_key key;
4368cfa3acSRoman Gushchin unsigned long long value;
44919646d2SRoman Gushchin unsigned long long *percpu_value;
45919646d2SRoman Gushchin int cpu, nproc;
46919646d2SRoman Gushchin
47ebaf24c5SArtem Savkov nproc = bpf_num_possible_cpus();
48919646d2SRoman Gushchin percpu_value = malloc(sizeof(*percpu_value) * nproc);
49919646d2SRoman Gushchin if (!percpu_value) {
50919646d2SRoman Gushchin printf("Not enough memory for per-cpu area (%d cpus)\n", nproc);
51919646d2SRoman Gushchin goto err;
52919646d2SRoman Gushchin }
5368cfa3acSRoman Gushchin
54*b858ba8cSYafang Shao /* Use libbpf 1.0 API mode */
55*b858ba8cSYafang Shao libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
56*b858ba8cSYafang Shao
572fe256a4SAndrii Nakryiko map_fd = bpf_map_create(BPF_MAP_TYPE_CGROUP_STORAGE, NULL, sizeof(key),
582fe256a4SAndrii Nakryiko sizeof(value), 0, NULL);
5968cfa3acSRoman Gushchin if (map_fd < 0) {
6068cfa3acSRoman Gushchin printf("Failed to create map: %s\n", strerror(errno));
6168cfa3acSRoman Gushchin goto out;
6268cfa3acSRoman Gushchin }
6368cfa3acSRoman Gushchin
642fe256a4SAndrii Nakryiko percpu_map_fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, NULL,
652fe256a4SAndrii Nakryiko sizeof(key), sizeof(value), 0, NULL);
66919646d2SRoman Gushchin if (percpu_map_fd < 0) {
67919646d2SRoman Gushchin printf("Failed to create map: %s\n", strerror(errno));
68919646d2SRoman Gushchin goto out;
69919646d2SRoman Gushchin }
70919646d2SRoman Gushchin
71919646d2SRoman Gushchin prog[0].imm = percpu_map_fd;
72919646d2SRoman Gushchin prog[7].imm = map_fd;
73f19ddfe0SAndrii Nakryiko prog_fd = bpf_test_load_program(BPF_PROG_TYPE_CGROUP_SKB,
7468cfa3acSRoman Gushchin prog, insns_cnt, "GPL", 0,
7568cfa3acSRoman Gushchin bpf_log_buf, BPF_LOG_BUF_SIZE);
7668cfa3acSRoman Gushchin if (prog_fd < 0) {
7768cfa3acSRoman Gushchin printf("Failed to load bpf program: %s\n", bpf_log_buf);
7868cfa3acSRoman Gushchin goto out;
7968cfa3acSRoman Gushchin }
8068cfa3acSRoman Gushchin
814939b284SJohn Fastabend cgroup_fd = cgroup_setup_and_join(TEST_CGROUP);
8268cfa3acSRoman Gushchin
8368cfa3acSRoman Gushchin /* Attach the bpf program */
8468cfa3acSRoman Gushchin if (bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_INET_EGRESS, 0)) {
8568cfa3acSRoman Gushchin printf("Failed to attach bpf program\n");
8668cfa3acSRoman Gushchin goto err;
8768cfa3acSRoman Gushchin }
8868cfa3acSRoman Gushchin
8968cfa3acSRoman Gushchin if (bpf_map_get_next_key(map_fd, NULL, &key)) {
9068cfa3acSRoman Gushchin printf("Failed to get the first key in cgroup storage\n");
9168cfa3acSRoman Gushchin goto err;
9268cfa3acSRoman Gushchin }
9368cfa3acSRoman Gushchin
9468cfa3acSRoman Gushchin if (bpf_map_lookup_elem(map_fd, &key, &value)) {
95919646d2SRoman Gushchin printf("Failed to lookup cgroup storage 0\n");
96919646d2SRoman Gushchin goto err;
97919646d2SRoman Gushchin }
98919646d2SRoman Gushchin
99919646d2SRoman Gushchin for (cpu = 0; cpu < nproc; cpu++)
100919646d2SRoman Gushchin percpu_value[cpu] = 1000;
101919646d2SRoman Gushchin
102919646d2SRoman Gushchin if (bpf_map_update_elem(percpu_map_fd, &key, percpu_value, 0)) {
103919646d2SRoman Gushchin printf("Failed to update the data in the cgroup storage\n");
10468cfa3acSRoman Gushchin goto err;
10568cfa3acSRoman Gushchin }
10668cfa3acSRoman Gushchin
10768cfa3acSRoman Gushchin /* Every second packet should be dropped */
10868cfa3acSRoman Gushchin assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0);
10968cfa3acSRoman Gushchin assert(system("ping localhost -c 1 -W 1 -q > /dev/null"));
11068cfa3acSRoman Gushchin assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0);
11168cfa3acSRoman Gushchin
11268cfa3acSRoman Gushchin /* Check the counter in the cgroup local storage */
11368cfa3acSRoman Gushchin if (bpf_map_lookup_elem(map_fd, &key, &value)) {
11468cfa3acSRoman Gushchin printf("Failed to lookup cgroup storage\n");
11568cfa3acSRoman Gushchin goto err;
11668cfa3acSRoman Gushchin }
11768cfa3acSRoman Gushchin
11868cfa3acSRoman Gushchin if (value != 3) {
11968cfa3acSRoman Gushchin printf("Unexpected data in the cgroup storage: %llu\n", value);
12068cfa3acSRoman Gushchin goto err;
12168cfa3acSRoman Gushchin }
12268cfa3acSRoman Gushchin
12368cfa3acSRoman Gushchin /* Bump the counter in the cgroup local storage */
12468cfa3acSRoman Gushchin value++;
12568cfa3acSRoman Gushchin if (bpf_map_update_elem(map_fd, &key, &value, 0)) {
12668cfa3acSRoman Gushchin printf("Failed to update the data in the cgroup storage\n");
12768cfa3acSRoman Gushchin goto err;
12868cfa3acSRoman Gushchin }
12968cfa3acSRoman Gushchin
13068cfa3acSRoman Gushchin /* Every second packet should be dropped */
13168cfa3acSRoman Gushchin assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0);
13268cfa3acSRoman Gushchin assert(system("ping localhost -c 1 -W 1 -q > /dev/null"));
13368cfa3acSRoman Gushchin assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0);
13468cfa3acSRoman Gushchin
13568cfa3acSRoman Gushchin /* Check the final value of the counter in the cgroup local storage */
13668cfa3acSRoman Gushchin if (bpf_map_lookup_elem(map_fd, &key, &value)) {
13768cfa3acSRoman Gushchin printf("Failed to lookup the cgroup storage\n");
13868cfa3acSRoman Gushchin goto err;
13968cfa3acSRoman Gushchin }
14068cfa3acSRoman Gushchin
14168cfa3acSRoman Gushchin if (value != 7) {
14268cfa3acSRoman Gushchin printf("Unexpected data in the cgroup storage: %llu\n", value);
14368cfa3acSRoman Gushchin goto err;
14468cfa3acSRoman Gushchin }
14568cfa3acSRoman Gushchin
146919646d2SRoman Gushchin /* Check the final value of the counter in the percpu local storage */
147919646d2SRoman Gushchin
148919646d2SRoman Gushchin for (cpu = 0; cpu < nproc; cpu++)
149919646d2SRoman Gushchin percpu_value[cpu] = 0;
150919646d2SRoman Gushchin
151919646d2SRoman Gushchin if (bpf_map_lookup_elem(percpu_map_fd, &key, percpu_value)) {
152919646d2SRoman Gushchin printf("Failed to lookup the per-cpu cgroup storage\n");
153919646d2SRoman Gushchin goto err;
154919646d2SRoman Gushchin }
155919646d2SRoman Gushchin
156919646d2SRoman Gushchin value = 0;
157919646d2SRoman Gushchin for (cpu = 0; cpu < nproc; cpu++)
158919646d2SRoman Gushchin value += percpu_value[cpu];
159919646d2SRoman Gushchin
160919646d2SRoman Gushchin if (value != nproc * 1000 + 6) {
161919646d2SRoman Gushchin printf("Unexpected data in the per-cpu cgroup storage\n");
162919646d2SRoman Gushchin goto err;
163919646d2SRoman Gushchin }
164919646d2SRoman Gushchin
16568cfa3acSRoman Gushchin error = 0;
16668cfa3acSRoman Gushchin printf("test_cgroup_storage:PASS\n");
16768cfa3acSRoman Gushchin
16868cfa3acSRoman Gushchin err:
16968cfa3acSRoman Gushchin cleanup_cgroup_environment();
170919646d2SRoman Gushchin free(percpu_value);
17168cfa3acSRoman Gushchin
17268cfa3acSRoman Gushchin out:
17368cfa3acSRoman Gushchin return error;
17468cfa3acSRoman Gushchin }
175