Linux-libre 4.10.3-gnu
[librecmc/linux-libre.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
28 #include "libbpf.h"
29 #include "cgroup_helpers.h"
30
31 #define FOO             "/foo"
32 #define BAR             "/foo/bar/"
33 #define PING_CMD        "ping -c1 -w1 127.0.0.1"
34
35 char bpf_log_buf[BPF_LOG_BUF_SIZE];
36
37 static int prog_load(int verdict)
38 {
39         int ret;
40         struct bpf_insn prog[] = {
41                 BPF_MOV64_IMM(BPF_REG_0, verdict), /* r0 = verdict */
42                 BPF_EXIT_INSN(),
43         };
44         size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn);
45
46         ret = bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB,
47                                prog, insns_cnt, "GPL", 0,
48                                bpf_log_buf, BPF_LOG_BUF_SIZE);
49
50         if (ret < 0) {
51                 log_err("Loading program");
52                 printf("Output from verifier:\n%s\n-------\n", bpf_log_buf);
53                 return 0;
54         }
55         return ret;
56 }
57
58
59 int main(int argc, char **argv)
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, 1)) {
83                 log_err("Attaching prog to /foo");
84                 goto err;
85         }
86
87         printf("Attached DROP prog. This ping in cgroup /foo should fail...\n");
88         assert(system(PING_CMD) != 0);
89
90         /* Create cgroup /foo/bar, get fd, and join it */
91         bar = create_and_get_cgroup(BAR);
92         if (!bar)
93                 goto err;
94
95         if (join_cgroup(BAR))
96                 goto err;
97
98         printf("Attached DROP prog. This ping in cgroup /foo/bar should fail...\n");
99         assert(system(PING_CMD) != 0);
100
101         if (bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 1)) {
102                 log_err("Attaching prog to /foo/bar");
103                 goto err;
104         }
105
106         printf("Attached PASS prog. This ping in cgroup /foo/bar should pass...\n");
107         assert(system(PING_CMD) == 0);
108
109         if (bpf_prog_detach(bar, BPF_CGROUP_INET_EGRESS)) {
110                 log_err("Detaching program from /foo/bar");
111                 goto err;
112         }
113
114         printf("Detached PASS from /foo/bar while DROP is attached to /foo.\n"
115                "This ping in cgroup /foo/bar should fail...\n");
116         assert(system(PING_CMD) != 0);
117
118         if (bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 1)) {
119                 log_err("Attaching prog to /foo/bar");
120                 goto err;
121         }
122
123         if (bpf_prog_detach(foo, BPF_CGROUP_INET_EGRESS)) {
124                 log_err("Detaching program from /foo");
125                 goto err;
126         }
127
128         printf("Attached PASS from /foo/bar and detached DROP from /foo.\n"
129                "This ping in cgroup /foo/bar should pass...\n");
130         assert(system(PING_CMD) == 0);
131
132         if (bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 1)) {
133                 log_err("Attaching prog to /foo/bar");
134                 goto err;
135         }
136
137         if (!bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 0)) {
138                 errno = 0;
139                 log_err("Unexpected success attaching prog to /foo/bar");
140                 goto err;
141         }
142
143         if (bpf_prog_detach(bar, BPF_CGROUP_INET_EGRESS)) {
144                 log_err("Detaching program from /foo/bar");
145                 goto err;
146         }
147
148         if (!bpf_prog_detach(foo, BPF_CGROUP_INET_EGRESS)) {
149                 errno = 0;
150                 log_err("Unexpected success in double detach from /foo");
151                 goto err;
152         }
153
154         if (bpf_prog_attach(allow_prog, foo, BPF_CGROUP_INET_EGRESS, 0)) {
155                 log_err("Attaching non-overridable prog to /foo");
156                 goto err;
157         }
158
159         if (!bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 0)) {
160                 errno = 0;
161                 log_err("Unexpected success attaching non-overridable prog to /foo/bar");
162                 goto err;
163         }
164
165         if (!bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 1)) {
166                 errno = 0;
167                 log_err("Unexpected success attaching overridable prog to /foo/bar");
168                 goto err;
169         }
170
171         if (!bpf_prog_attach(allow_prog, foo, BPF_CGROUP_INET_EGRESS, 1)) {
172                 errno = 0;
173                 log_err("Unexpected success attaching overridable prog to /foo");
174                 goto err;
175         }
176
177         if (bpf_prog_attach(drop_prog, foo, BPF_CGROUP_INET_EGRESS, 0)) {
178                 log_err("Attaching different non-overridable prog to /foo");
179                 goto err;
180         }
181
182         goto out;
183
184 err:
185         rc = 1;
186
187 out:
188         close(foo);
189         close(bar);
190         cleanup_cgroup_environment();
191         if (!rc)
192                 printf("PASS\n");
193         else
194                 printf("FAIL\n");
195         return rc;
196 }