]>
Commit | Line | Data |
---|---|---|
371e4fcc RG |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <stdio.h> | |
3 | #include <stdlib.h> | |
4 | #include <string.h> | |
5 | #include <errno.h> | |
6 | #include <assert.h> | |
7 | #include <sys/sysinfo.h> | |
8 | #include <sys/time.h> | |
9 | ||
10 | #include <linux/bpf.h> | |
11 | #include <bpf/bpf.h> | |
12 | #include <bpf/libbpf.h> | |
13 | ||
14 | #include "cgroup_helpers.h" | |
15 | #include "bpf_rlimit.h" | |
16 | #include "netcnt_common.h" | |
17 | ||
18 | #define BPF_PROG "./netcnt_prog.o" | |
19 | #define TEST_CGROUP "/test-network-counters/" | |
20 | ||
21 | static int bpf_find_map(const char *test, struct bpf_object *obj, | |
22 | const char *name) | |
23 | { | |
24 | struct bpf_map *map; | |
25 | ||
26 | map = bpf_object__find_map_by_name(obj, name); | |
27 | if (!map) { | |
28 | printf("%s:FAIL:map '%s' not found\n", test, name); | |
29 | return -1; | |
30 | } | |
31 | return bpf_map__fd(map); | |
32 | } | |
33 | ||
34 | int main(int argc, char **argv) | |
35 | { | |
36 | struct percpu_net_cnt *percpu_netcnt; | |
37 | struct bpf_cgroup_storage_key key; | |
38 | int map_fd, percpu_map_fd; | |
39 | int error = EXIT_FAILURE; | |
40 | struct net_cnt netcnt; | |
41 | struct bpf_object *obj; | |
42 | int prog_fd, cgroup_fd; | |
43 | unsigned long packets; | |
44 | unsigned long bytes; | |
45 | int cpu, nproc; | |
46 | __u32 prog_cnt; | |
47 | ||
48 | nproc = get_nprocs_conf(); | |
49 | percpu_netcnt = malloc(sizeof(*percpu_netcnt) * nproc); | |
50 | if (!percpu_netcnt) { | |
51 | printf("Not enough memory for per-cpu area (%d cpus)\n", nproc); | |
52 | goto err; | |
53 | } | |
54 | ||
55 | if (bpf_prog_load(BPF_PROG, BPF_PROG_TYPE_CGROUP_SKB, | |
56 | &obj, &prog_fd)) { | |
57 | printf("Failed to load bpf program\n"); | |
58 | goto out; | |
59 | } | |
60 | ||
61 | if (setup_cgroup_environment()) { | |
62 | printf("Failed to load bpf program\n"); | |
63 | goto err; | |
64 | } | |
65 | ||
66 | /* Create a cgroup, get fd, and join it */ | |
67 | cgroup_fd = create_and_get_cgroup(TEST_CGROUP); | |
68 | if (!cgroup_fd) { | |
69 | printf("Failed to create test cgroup\n"); | |
70 | goto err; | |
71 | } | |
72 | ||
73 | if (join_cgroup(TEST_CGROUP)) { | |
74 | printf("Failed to join cgroup\n"); | |
75 | goto err; | |
76 | } | |
77 | ||
78 | /* Attach bpf program */ | |
79 | if (bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_INET_EGRESS, 0)) { | |
80 | printf("Failed to attach bpf program"); | |
81 | goto err; | |
82 | } | |
83 | ||
da85d8bf LZ |
84 | if (system("which ping6 &>/dev/null") == 0) |
85 | assert(!system("ping6 localhost -c 10000 -f -q > /dev/null")); | |
86 | else | |
87 | assert(!system("ping -6 localhost -c 10000 -f -q > /dev/null")); | |
371e4fcc RG |
88 | |
89 | if (bpf_prog_query(cgroup_fd, BPF_CGROUP_INET_EGRESS, 0, NULL, NULL, | |
90 | &prog_cnt)) { | |
91 | printf("Failed to query attached programs"); | |
92 | goto err; | |
93 | } | |
94 | ||
95 | map_fd = bpf_find_map(__func__, obj, "netcnt"); | |
96 | if (map_fd < 0) { | |
97 | printf("Failed to find bpf map with net counters"); | |
98 | goto err; | |
99 | } | |
100 | ||
101 | percpu_map_fd = bpf_find_map(__func__, obj, "percpu_netcnt"); | |
102 | if (percpu_map_fd < 0) { | |
103 | printf("Failed to find bpf map with percpu net counters"); | |
104 | goto err; | |
105 | } | |
106 | ||
107 | if (bpf_map_get_next_key(map_fd, NULL, &key)) { | |
108 | printf("Failed to get key in cgroup storage\n"); | |
109 | goto err; | |
110 | } | |
111 | ||
112 | if (bpf_map_lookup_elem(map_fd, &key, &netcnt)) { | |
113 | printf("Failed to lookup cgroup storage\n"); | |
114 | goto err; | |
115 | } | |
116 | ||
117 | if (bpf_map_lookup_elem(percpu_map_fd, &key, &percpu_netcnt[0])) { | |
118 | printf("Failed to lookup percpu cgroup storage\n"); | |
119 | goto err; | |
120 | } | |
121 | ||
122 | /* Some packets can be still in per-cpu cache, but not more than | |
123 | * MAX_PERCPU_PACKETS. | |
124 | */ | |
125 | packets = netcnt.packets; | |
126 | bytes = netcnt.bytes; | |
127 | for (cpu = 0; cpu < nproc; cpu++) { | |
128 | if (percpu_netcnt[cpu].packets > MAX_PERCPU_PACKETS) { | |
129 | printf("Unexpected percpu value: %llu\n", | |
130 | percpu_netcnt[cpu].packets); | |
131 | goto err; | |
132 | } | |
133 | ||
134 | packets += percpu_netcnt[cpu].packets; | |
135 | bytes += percpu_netcnt[cpu].bytes; | |
136 | } | |
137 | ||
138 | /* No packets should be lost */ | |
139 | if (packets != 10000) { | |
140 | printf("Unexpected packet count: %lu\n", packets); | |
141 | goto err; | |
142 | } | |
143 | ||
144 | /* Let's check that bytes counter matches the number of packets | |
145 | * multiplied by the size of ipv6 ICMP packet. | |
146 | */ | |
147 | if (bytes != packets * 104) { | |
148 | printf("Unexpected bytes count: %lu\n", bytes); | |
149 | goto err; | |
150 | } | |
151 | ||
152 | error = 0; | |
153 | printf("test_netcnt:PASS\n"); | |
154 | ||
155 | err: | |
156 | cleanup_cgroup_environment(); | |
157 | free(percpu_netcnt); | |
158 | ||
159 | out: | |
160 | return error; | |
161 | } |