• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
prog_load(int verdict)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 
main(int argc,char ** argv)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 }
197