Merge tag 'regulator-v4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[linux-2.6-microblaze.git] / samples / bpf / test_cgrp2_attach2.c
1 /* eBPF example program:
2  *
3  * - Creates arraymap in kernel with 4 bytes keys and 8 byte values
4  *
5  * - Loads eBPF program
6  *
7  *   The eBPF program accesses the map passed in to store two pieces of
8  *   information. The number of invocations of the program, which maps
9  *   to the number of packets received, is stored to key 0. Key 1 is
10  *   incremented on each iteration by the number of bytes stored in
11  *   the skb.
12  *
13  * - Attaches the new program to a cgroup using BPF_PROG_ATTACH
14  *
15  * - Every second, reads map[0] and map[1] to see how many bytes and
16  *   packets were seen on any socket of tasks in the given cgroup.
17  */
18
19 #define _GNU_SOURCE
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <assert.h>
24 #include <unistd.h>
25
26 #include <linux/bpf.h>
27 #include <bpf/bpf.h>
28
29 #include "bpf_insn.h"
30 #include "cgroup_helpers.h"
31
32 #define FOO             "/foo"
33 #define BAR             "/foo/bar/"
34 #define PING_CMD        "ping -c1 -w1 127.0.0.1 > /dev/null"
35
36 char bpf_log_buf[BPF_LOG_BUF_SIZE];
37
38 static int prog_load(int verdict)
39 {
40         int ret;
41         struct bpf_insn prog[] = {
42                 BPF_MOV64_IMM(BPF_REG_0, verdict), /* r0 = verdict */
43                 BPF_EXIT_INSN(),
44         };
45         size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn);
46
47         ret = bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB,
48                                prog, insns_cnt, "GPL", 0,
49                                bpf_log_buf, BPF_LOG_BUF_SIZE);
50
51         if (ret < 0) {
52                 log_err("Loading program");
53                 printf("Output from verifier:\n%s\n-------\n", bpf_log_buf);
54                 return 0;
55         }
56         return ret;
57 }
58
59 static int test_foo_bar(void)
60 {
61         int drop_prog, allow_prog, foo = 0, bar = 0, rc = 0;
62
63         allow_prog = prog_load(1);
64         if (!allow_prog)
65                 goto err;
66
67         drop_prog = prog_load(0);
68         if (!drop_prog)
69                 goto err;
70
71         if (setup_cgroup_environment())
72                 goto err;
73
74         /* Create cgroup /foo, get fd, and join it */
75         foo = create_and_get_cgroup(FOO);
76         if (!foo)
77                 goto err;
78
79         if (join_cgroup(FOO))
80                 goto err;
81
82         if (bpf_prog_attach(drop_prog, foo, BPF_CGROUP_INET_EGRESS,
83                             BPF_F_ALLOW_OVERRIDE)) {
84                 log_err("Attaching prog to /foo");
85                 goto err;
86         }
87
88         printf("Attached DROP prog. This ping in cgroup /foo should fail...\n");
89         assert(system(PING_CMD) != 0);
90
91         /* Create cgroup /foo/bar, get fd, and join it */
92         bar = create_and_get_cgroup(BAR);
93         if (!bar)
94                 goto err;
95
96         if (join_cgroup(BAR))
97                 goto err;
98
99         printf("Attached DROP prog. This ping in cgroup /foo/bar should fail...\n");
100         assert(system(PING_CMD) != 0);
101
102         if (bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS,
103                             BPF_F_ALLOW_OVERRIDE)) {
104                 log_err("Attaching prog to /foo/bar");
105                 goto err;
106         }
107
108         printf("Attached PASS prog. This ping in cgroup /foo/bar should pass...\n");
109         assert(system(PING_CMD) == 0);
110
111         if (bpf_prog_detach(bar, BPF_CGROUP_INET_EGRESS)) {
112                 log_err("Detaching program from /foo/bar");
113                 goto err;
114         }
115
116         printf("Detached PASS from /foo/bar while DROP is attached to /foo.\n"
117                "This ping in cgroup /foo/bar should fail...\n");
118         assert(system(PING_CMD) != 0);
119
120         if (bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS,
121                             BPF_F_ALLOW_OVERRIDE)) {
122                 log_err("Attaching prog to /foo/bar");
123                 goto err;
124         }
125
126         if (bpf_prog_detach(foo, BPF_CGROUP_INET_EGRESS)) {
127                 log_err("Detaching program from /foo");
128                 goto err;
129         }
130
131         printf("Attached PASS from /foo/bar and detached DROP from /foo.\n"
132                "This ping in cgroup /foo/bar should pass...\n");
133         assert(system(PING_CMD) == 0);
134
135         if (bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS,
136                             BPF_F_ALLOW_OVERRIDE)) {
137                 log_err("Attaching prog to /foo/bar");
138                 goto err;
139         }
140
141         if (!bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 0)) {
142                 errno = 0;
143                 log_err("Unexpected success attaching prog to /foo/bar");
144                 goto err;
145         }
146
147         if (bpf_prog_detach(bar, BPF_CGROUP_INET_EGRESS)) {
148                 log_err("Detaching program from /foo/bar");
149                 goto err;
150         }
151
152         if (!bpf_prog_detach(foo, BPF_CGROUP_INET_EGRESS)) {
153                 errno = 0;
154                 log_err("Unexpected success in double detach from /foo");
155                 goto err;
156         }
157
158         if (bpf_prog_attach(allow_prog, foo, BPF_CGROUP_INET_EGRESS, 0)) {
159                 log_err("Attaching non-overridable prog to /foo");
160                 goto err;
161         }
162
163         if (!bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 0)) {
164                 errno = 0;
165                 log_err("Unexpected success attaching non-overridable prog to /foo/bar");
166                 goto err;
167         }
168
169         if (!bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS,
170                              BPF_F_ALLOW_OVERRIDE)) {
171                 errno = 0;
172                 log_err("Unexpected success attaching overridable prog to /foo/bar");
173                 goto err;
174         }
175
176         if (!bpf_prog_attach(allow_prog, foo, BPF_CGROUP_INET_EGRESS,
177                              BPF_F_ALLOW_OVERRIDE)) {
178                 errno = 0;
179                 log_err("Unexpected success attaching overridable prog to /foo");
180                 goto err;
181         }
182
183         if (bpf_prog_attach(drop_prog, foo, BPF_CGROUP_INET_EGRESS, 0)) {
184                 log_err("Attaching different non-overridable prog to /foo");
185                 goto err;
186         }
187
188         goto out;
189
190 err:
191         rc = 1;
192
193 out:
194         close(foo);
195         close(bar);
196         cleanup_cgroup_environment();
197         if (!rc)
198                 printf("### override:PASS\n");
199         else
200                 printf("### override:FAIL\n");
201         return rc;
202 }
203
204 static int map_fd = -1;
205
206 static int prog_load_cnt(int verdict, int val)
207 {
208         if (map_fd < 0)
209                 map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, 4, 8, 1, 0);
210         if (map_fd < 0) {
211                 printf("failed to create map '%s'\n", strerror(errno));
212                 return -1;
213         }
214
215         struct bpf_insn prog[] = {
216                 BPF_MOV32_IMM(BPF_REG_0, 0),
217                 BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 4) = r0 */
218                 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
219                 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), /* r2 = fp - 4 */
220                 BPF_LD_MAP_FD(BPF_REG_1, map_fd),
221                 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
222                 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
223                 BPF_MOV64_IMM(BPF_REG_1, val), /* r1 = 1 */
224                 BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */
225                 BPF_MOV64_IMM(BPF_REG_0, verdict), /* r0 = verdict */
226                 BPF_EXIT_INSN(),
227         };
228         size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn);
229         int ret;
230
231         ret = bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB,
232                                prog, insns_cnt, "GPL", 0,
233                                bpf_log_buf, BPF_LOG_BUF_SIZE);
234
235         if (ret < 0) {
236                 log_err("Loading program");
237                 printf("Output from verifier:\n%s\n-------\n", bpf_log_buf);
238                 return 0;
239         }
240         return ret;
241 }
242
243
244 static int test_multiprog(void)
245 {
246         __u32 prog_ids[4], prog_cnt = 0, attach_flags, saved_prog_id;
247         int cg1 = 0, cg2 = 0, cg3 = 0, cg4 = 0, cg5 = 0, key = 0;
248         int drop_prog, allow_prog[6] = {}, rc = 0;
249         unsigned long long value;
250         int i = 0;
251
252         for (i = 0; i < 6; i++) {
253                 allow_prog[i] = prog_load_cnt(1, 1 << i);
254                 if (!allow_prog[i])
255                         goto err;
256         }
257         drop_prog = prog_load_cnt(0, 1);
258         if (!drop_prog)
259                 goto err;
260
261         if (setup_cgroup_environment())
262                 goto err;
263
264         cg1 = create_and_get_cgroup("/cg1");
265         if (!cg1)
266                 goto err;
267         cg2 = create_and_get_cgroup("/cg1/cg2");
268         if (!cg2)
269                 goto err;
270         cg3 = create_and_get_cgroup("/cg1/cg2/cg3");
271         if (!cg3)
272                 goto err;
273         cg4 = create_and_get_cgroup("/cg1/cg2/cg3/cg4");
274         if (!cg4)
275                 goto err;
276         cg5 = create_and_get_cgroup("/cg1/cg2/cg3/cg4/cg5");
277         if (!cg5)
278                 goto err;
279
280         if (join_cgroup("/cg1/cg2/cg3/cg4/cg5"))
281                 goto err;
282
283         if (bpf_prog_attach(allow_prog[0], cg1, BPF_CGROUP_INET_EGRESS,
284                             BPF_F_ALLOW_MULTI)) {
285                 log_err("Attaching prog to cg1");
286                 goto err;
287         }
288         if (!bpf_prog_attach(allow_prog[0], cg1, BPF_CGROUP_INET_EGRESS,
289                              BPF_F_ALLOW_MULTI)) {
290                 log_err("Unexpected success attaching the same prog to cg1");
291                 goto err;
292         }
293         if (bpf_prog_attach(allow_prog[1], cg1, BPF_CGROUP_INET_EGRESS,
294                             BPF_F_ALLOW_MULTI)) {
295                 log_err("Attaching prog2 to cg1");
296                 goto err;
297         }
298         if (bpf_prog_attach(allow_prog[2], cg2, BPF_CGROUP_INET_EGRESS,
299                             BPF_F_ALLOW_OVERRIDE)) {
300                 log_err("Attaching prog to cg2");
301                 goto err;
302         }
303         if (bpf_prog_attach(allow_prog[3], cg3, BPF_CGROUP_INET_EGRESS,
304                             BPF_F_ALLOW_MULTI)) {
305                 log_err("Attaching prog to cg3");
306                 goto err;
307         }
308         if (bpf_prog_attach(allow_prog[4], cg4, BPF_CGROUP_INET_EGRESS,
309                             BPF_F_ALLOW_OVERRIDE)) {
310                 log_err("Attaching prog to cg4");
311                 goto err;
312         }
313         if (bpf_prog_attach(allow_prog[5], cg5, BPF_CGROUP_INET_EGRESS, 0)) {
314                 log_err("Attaching prog to cg5");
315                 goto err;
316         }
317         assert(system(PING_CMD) == 0);
318         assert(bpf_map_lookup_elem(map_fd, &key, &value) == 0);
319         assert(value == 1 + 2 + 8 + 32);
320
321         /* query the number of effective progs in cg5 */
322         assert(bpf_prog_query(cg5, BPF_CGROUP_INET_EGRESS, BPF_F_QUERY_EFFECTIVE,
323                               NULL, NULL, &prog_cnt) == 0);
324         assert(prog_cnt == 4);
325         /* retrieve prog_ids of effective progs in cg5 */
326         assert(bpf_prog_query(cg5, BPF_CGROUP_INET_EGRESS, BPF_F_QUERY_EFFECTIVE,
327                               &attach_flags, prog_ids, &prog_cnt) == 0);
328         assert(prog_cnt == 4);
329         assert(attach_flags == 0);
330         saved_prog_id = prog_ids[0];
331         /* check enospc handling */
332         prog_ids[0] = 0;
333         prog_cnt = 2;
334         assert(bpf_prog_query(cg5, BPF_CGROUP_INET_EGRESS, BPF_F_QUERY_EFFECTIVE,
335                               &attach_flags, prog_ids, &prog_cnt) == -1 &&
336                errno == ENOSPC);
337         assert(prog_cnt == 4);
338         /* check that prog_ids are returned even when buffer is too small */
339         assert(prog_ids[0] == saved_prog_id);
340         /* retrieve prog_id of single attached prog in cg5 */
341         prog_ids[0] = 0;
342         assert(bpf_prog_query(cg5, BPF_CGROUP_INET_EGRESS, 0,
343                               NULL, prog_ids, &prog_cnt) == 0);
344         assert(prog_cnt == 1);
345         assert(prog_ids[0] == saved_prog_id);
346
347         /* detach bottom program and ping again */
348         if (bpf_prog_detach2(-1, cg5, BPF_CGROUP_INET_EGRESS)) {
349                 log_err("Detaching prog from cg5");
350                 goto err;
351         }
352         value = 0;
353         assert(bpf_map_update_elem(map_fd, &key, &value, 0) == 0);
354         assert(system(PING_CMD) == 0);
355         assert(bpf_map_lookup_elem(map_fd, &key, &value) == 0);
356         assert(value == 1 + 2 + 8 + 16);
357
358         /* detach 3rd from bottom program and ping again */
359         errno = 0;
360         if (!bpf_prog_detach2(0, cg3, BPF_CGROUP_INET_EGRESS)) {
361                 log_err("Unexpected success on detach from cg3");
362                 goto err;
363         }
364         if (bpf_prog_detach2(allow_prog[3], cg3, BPF_CGROUP_INET_EGRESS)) {
365                 log_err("Detaching from cg3");
366                 goto err;
367         }
368         value = 0;
369         assert(bpf_map_update_elem(map_fd, &key, &value, 0) == 0);
370         assert(system(PING_CMD) == 0);
371         assert(bpf_map_lookup_elem(map_fd, &key, &value) == 0);
372         assert(value == 1 + 2 + 16);
373
374         /* detach 2nd from bottom program and ping again */
375         if (bpf_prog_detach2(-1, cg4, BPF_CGROUP_INET_EGRESS)) {
376                 log_err("Detaching prog from cg4");
377                 goto err;
378         }
379         value = 0;
380         assert(bpf_map_update_elem(map_fd, &key, &value, 0) == 0);
381         assert(system(PING_CMD) == 0);
382         assert(bpf_map_lookup_elem(map_fd, &key, &value) == 0);
383         assert(value == 1 + 2 + 4);
384
385         prog_cnt = 4;
386         assert(bpf_prog_query(cg5, BPF_CGROUP_INET_EGRESS, BPF_F_QUERY_EFFECTIVE,
387                               &attach_flags, prog_ids, &prog_cnt) == 0);
388         assert(prog_cnt == 3);
389         assert(attach_flags == 0);
390         assert(bpf_prog_query(cg5, BPF_CGROUP_INET_EGRESS, 0,
391                               NULL, prog_ids, &prog_cnt) == 0);
392         assert(prog_cnt == 0);
393         goto out;
394 err:
395         rc = 1;
396
397 out:
398         for (i = 0; i < 6; i++)
399                 if (allow_prog[i] > 0)
400                         close(allow_prog[i]);
401         close(cg1);
402         close(cg2);
403         close(cg3);
404         close(cg4);
405         close(cg5);
406         cleanup_cgroup_environment();
407         if (!rc)
408                 printf("### multi:PASS\n");
409         else
410                 printf("### multi:FAIL\n");
411         return rc;
412 }
413
414 int main(int argc, char **argv)
415 {
416         int rc = 0;
417
418         rc = test_foo_bar();
419         if (rc)
420                 return rc;
421
422         return test_multiprog();
423 }