Commit | Line | Data |
---|---|---|
69e8cc13 JF |
1 | /* Copyright (c) 2017 Covalent IO, Inc. http://covalent.io |
2 | * | |
3 | * This program is free software; you can redistribute it and/or | |
4 | * modify it under the terms of version 2 of the GNU General Public | |
5 | * License as published by the Free Software Foundation. | |
6 | * | |
7 | * This program is distributed in the hope that it will be useful, but | |
8 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
10 | * General Public License for more details. | |
11 | */ | |
12 | #include <uapi/linux/bpf.h> | |
13 | #include <uapi/linux/if_ether.h> | |
14 | #include <uapi/linux/if_packet.h> | |
15 | #include <uapi/linux/ip.h> | |
16 | #include "../../tools/testing/selftests/bpf/bpf_helpers.h" | |
17 | #include "../../tools/testing/selftests/bpf/bpf_endian.h" | |
18 | ||
19 | /* Sockmap sample program connects a client and a backend together | |
20 | * using cgroups. | |
21 | * | |
22 | * client:X <---> frontend:80 client:X <---> backend:80 | |
23 | * | |
24 | * For simplicity we hard code values here and bind 1:1. The hard | |
25 | * coded values are part of the setup in sockmap.sh script that | |
26 | * is associated with this BPF program. | |
27 | * | |
28 | * The bpf_printk is verbose and prints information as connections | |
29 | * are established and verdicts are decided. | |
30 | */ | |
31 | ||
32 | #define bpf_printk(fmt, ...) \ | |
33 | ({ \ | |
34 | char ____fmt[] = fmt; \ | |
35 | bpf_trace_printk(____fmt, sizeof(____fmt), \ | |
36 | ##__VA_ARGS__); \ | |
37 | }) | |
38 | ||
39 | struct bpf_map_def SEC("maps") sock_map = { | |
40 | .type = BPF_MAP_TYPE_SOCKMAP, | |
41 | .key_size = sizeof(int), | |
42 | .value_size = sizeof(int), | |
43 | .max_entries = 20, | |
44 | }; | |
45 | ||
4c4c3c27 JF |
46 | struct bpf_map_def SEC("maps") sock_map_txmsg = { |
47 | .type = BPF_MAP_TYPE_SOCKMAP, | |
48 | .key_size = sizeof(int), | |
49 | .value_size = sizeof(int), | |
50 | .max_entries = 20, | |
51 | }; | |
52 | ||
53 | struct bpf_map_def SEC("maps") sock_map_redir = { | |
54 | .type = BPF_MAP_TYPE_SOCKMAP, | |
55 | .key_size = sizeof(int), | |
56 | .value_size = sizeof(int), | |
2596f64c | 57 | .max_entries = 20, |
4c4c3c27 JF |
58 | }; |
59 | ||
1c16c312 JF |
60 | struct bpf_map_def SEC("maps") sock_apply_bytes = { |
61 | .type = BPF_MAP_TYPE_ARRAY, | |
62 | .key_size = sizeof(int), | |
63 | .value_size = sizeof(int), | |
64 | .max_entries = 1 | |
65 | }; | |
66 | ||
468b3fde JF |
67 | struct bpf_map_def SEC("maps") sock_cork_bytes = { |
68 | .type = BPF_MAP_TYPE_ARRAY, | |
69 | .key_size = sizeof(int), | |
70 | .value_size = sizeof(int), | |
71 | .max_entries = 1 | |
72 | }; | |
73 | ||
0dcbbf67 JF |
74 | struct bpf_map_def SEC("maps") sock_pull_bytes = { |
75 | .type = BPF_MAP_TYPE_ARRAY, | |
76 | .key_size = sizeof(int), | |
77 | .value_size = sizeof(int), | |
78 | .max_entries = 2 | |
79 | }; | |
80 | ||
2596f64c JF |
81 | struct bpf_map_def SEC("maps") sock_redir_flags = { |
82 | .type = BPF_MAP_TYPE_ARRAY, | |
83 | .key_size = sizeof(int), | |
84 | .value_size = sizeof(int), | |
85 | .max_entries = 1 | |
86 | }; | |
87 | ||
2e3f6c5f JF |
88 | struct bpf_map_def SEC("maps") sock_skb_opts = { |
89 | .type = BPF_MAP_TYPE_ARRAY, | |
90 | .key_size = sizeof(int), | |
91 | .value_size = sizeof(int), | |
92 | .max_entries = 1 | |
93 | }; | |
0dcbbf67 | 94 | |
69e8cc13 JF |
95 | SEC("sk_skb1") |
96 | int bpf_prog1(struct __sk_buff *skb) | |
97 | { | |
98 | return skb->len; | |
99 | } | |
100 | ||
101 | SEC("sk_skb2") | |
102 | int bpf_prog2(struct __sk_buff *skb) | |
103 | { | |
104 | __u32 lport = skb->local_port; | |
105 | __u32 rport = skb->remote_port; | |
2e3f6c5f JF |
106 | int len, *f, ret, zero = 0; |
107 | __u64 flags = 0; | |
69e8cc13 JF |
108 | |
109 | if (lport == 10000) | |
110 | ret = 10; | |
111 | else | |
112 | ret = 1; | |
113 | ||
2e3f6c5f JF |
114 | len = (__u32)skb->data_end - (__u32)skb->data; |
115 | f = bpf_map_lookup_elem(&sock_skb_opts, &zero); | |
116 | if (f && *f) { | |
117 | ret = 3; | |
118 | flags = *f; | |
119 | } | |
120 | ||
121 | bpf_printk("sk_skb2: redirect(%iB) flags=%i\n", | |
122 | len, flags); | |
123 | return bpf_sk_redirect_map(skb, &sock_map, ret, flags); | |
69e8cc13 JF |
124 | } |
125 | ||
126 | SEC("sockops") | |
127 | int bpf_sockmap(struct bpf_sock_ops *skops) | |
128 | { | |
129 | __u32 lport, rport; | |
130 | int op, err = 0, index, key, ret; | |
131 | ||
132 | ||
133 | op = (int) skops->op; | |
134 | ||
135 | switch (op) { | |
136 | case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: | |
137 | lport = skops->local_port; | |
138 | rport = skops->remote_port; | |
139 | ||
140 | if (lport == 10000) { | |
141 | ret = 1; | |
142 | err = bpf_sock_map_update(skops, &sock_map, &ret, | |
464bc0fd | 143 | BPF_NOEXIST); |
69e8cc13 JF |
144 | bpf_printk("passive(%i -> %i) map ctx update err: %d\n", |
145 | lport, bpf_ntohl(rport), err); | |
146 | } | |
147 | break; | |
148 | case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: | |
149 | lport = skops->local_port; | |
150 | rport = skops->remote_port; | |
151 | ||
152 | if (bpf_ntohl(rport) == 10001) { | |
153 | ret = 10; | |
154 | err = bpf_sock_map_update(skops, &sock_map, &ret, | |
464bc0fd | 155 | BPF_NOEXIST); |
69e8cc13 JF |
156 | bpf_printk("active(%i -> %i) map ctx update err: %d\n", |
157 | lport, bpf_ntohl(rport), err); | |
158 | } | |
159 | break; | |
160 | default: | |
161 | break; | |
162 | } | |
163 | ||
164 | return 0; | |
165 | } | |
4c4c3c27 JF |
166 | |
167 | SEC("sk_msg1") | |
168 | int bpf_prog4(struct sk_msg_md *msg) | |
169 | { | |
0dcbbf67 JF |
170 | int *bytes, zero = 0, one = 1; |
171 | int *start, *end; | |
1c16c312 JF |
172 | |
173 | bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); | |
174 | if (bytes) | |
175 | bpf_msg_apply_bytes(msg, *bytes); | |
468b3fde JF |
176 | bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); |
177 | if (bytes) | |
178 | bpf_msg_cork_bytes(msg, *bytes); | |
0dcbbf67 JF |
179 | start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); |
180 | end = bpf_map_lookup_elem(&sock_pull_bytes, &one); | |
181 | if (start && end) | |
182 | bpf_msg_pull_data(msg, *start, *end, 0); | |
4c4c3c27 JF |
183 | return SK_PASS; |
184 | } | |
185 | ||
186 | SEC("sk_msg2") | |
187 | int bpf_prog5(struct sk_msg_md *msg) | |
188 | { | |
0dcbbf67 JF |
189 | int err1 = -1, err2 = -1, zero = 0, one = 1; |
190 | int *bytes, *start, *end, len1, len2; | |
4c4c3c27 | 191 | |
1c16c312 JF |
192 | bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); |
193 | if (bytes) | |
468b3fde JF |
194 | err1 = bpf_msg_apply_bytes(msg, *bytes); |
195 | bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); | |
196 | if (bytes) | |
197 | err2 = bpf_msg_cork_bytes(msg, *bytes); | |
0dcbbf67 JF |
198 | len1 = (__u64)msg->data_end - (__u64)msg->data; |
199 | start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); | |
200 | end = bpf_map_lookup_elem(&sock_pull_bytes, &one); | |
201 | if (start && end) { | |
202 | int err; | |
203 | ||
204 | bpf_printk("sk_msg2: pull(%i:%i)\n", | |
205 | start ? *start : 0, end ? *end : 0); | |
206 | err = bpf_msg_pull_data(msg, *start, *end, 0); | |
207 | if (err) | |
208 | bpf_printk("sk_msg2: pull_data err %i\n", | |
209 | err); | |
210 | len2 = (__u64)msg->data_end - (__u64)msg->data; | |
211 | bpf_printk("sk_msg2: length update %i->%i\n", | |
212 | len1, len2); | |
213 | } | |
468b3fde | 214 | bpf_printk("sk_msg2: data length %i err1 %i err2 %i\n", |
0dcbbf67 | 215 | len1, err1, err2); |
4c4c3c27 JF |
216 | return SK_PASS; |
217 | } | |
218 | ||
219 | SEC("sk_msg3") | |
220 | int bpf_prog6(struct sk_msg_md *msg) | |
221 | { | |
2596f64c JF |
222 | int *bytes, zero = 0, one = 1, key = 0; |
223 | int *start, *end, *f; | |
224 | __u64 flags = 0; | |
4c4c3c27 | 225 | |
1c16c312 JF |
226 | bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); |
227 | if (bytes) | |
228 | bpf_msg_apply_bytes(msg, *bytes); | |
468b3fde JF |
229 | bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); |
230 | if (bytes) | |
231 | bpf_msg_cork_bytes(msg, *bytes); | |
0dcbbf67 JF |
232 | start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); |
233 | end = bpf_map_lookup_elem(&sock_pull_bytes, &one); | |
234 | if (start && end) | |
235 | bpf_msg_pull_data(msg, *start, *end, 0); | |
2596f64c JF |
236 | f = bpf_map_lookup_elem(&sock_redir_flags, &zero); |
237 | if (f && *f) { | |
238 | key = 2; | |
239 | flags = *f; | |
240 | } | |
241 | return bpf_msg_redirect_map(msg, &sock_map_redir, key, flags); | |
4c4c3c27 JF |
242 | } |
243 | ||
244 | SEC("sk_msg4") | |
245 | int bpf_prog7(struct sk_msg_md *msg) | |
246 | { | |
2596f64c JF |
247 | int err1 = 0, err2 = 0, zero = 0, one = 1, key = 0; |
248 | int *f, *bytes, *start, *end, len1, len2; | |
249 | __u64 flags = 0; | |
1c16c312 | 250 | |
2596f64c | 251 | int err; |
1c16c312 JF |
252 | bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); |
253 | if (bytes) | |
468b3fde JF |
254 | err1 = bpf_msg_apply_bytes(msg, *bytes); |
255 | bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); | |
256 | if (bytes) | |
257 | err2 = bpf_msg_cork_bytes(msg, *bytes); | |
0dcbbf67 JF |
258 | len1 = (__u64)msg->data_end - (__u64)msg->data; |
259 | start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); | |
260 | end = bpf_map_lookup_elem(&sock_pull_bytes, &one); | |
261 | if (start && end) { | |
0dcbbf67 JF |
262 | |
263 | bpf_printk("sk_msg2: pull(%i:%i)\n", | |
264 | start ? *start : 0, end ? *end : 0); | |
265 | err = bpf_msg_pull_data(msg, *start, *end, 0); | |
266 | if (err) | |
267 | bpf_printk("sk_msg2: pull_data err %i\n", | |
268 | err); | |
269 | len2 = (__u64)msg->data_end - (__u64)msg->data; | |
270 | bpf_printk("sk_msg2: length update %i->%i\n", | |
271 | len1, len2); | |
272 | } | |
2596f64c JF |
273 | f = bpf_map_lookup_elem(&sock_redir_flags, &zero); |
274 | if (f && *f) { | |
275 | key = 2; | |
276 | flags = *f; | |
277 | } | |
278 | bpf_printk("sk_msg3: redirect(%iB) flags=%i err=%i\n", | |
279 | len1, flags, err1 ? err1 : err2); | |
280 | err = bpf_msg_redirect_map(msg, &sock_map_redir, key, flags); | |
281 | bpf_printk("sk_msg3: err %i\n", err); | |
282 | return err; | |
1c16c312 | 283 | } |
4c4c3c27 | 284 | |
1c16c312 JF |
285 | SEC("sk_msg5") |
286 | int bpf_prog8(struct sk_msg_md *msg) | |
287 | { | |
288 | void *data_end = (void *)(long) msg->data_end; | |
289 | void *data = (void *)(long) msg->data; | |
290 | int ret = 0, *bytes, zero = 0; | |
291 | ||
292 | bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); | |
293 | if (bytes) { | |
294 | ret = bpf_msg_apply_bytes(msg, *bytes); | |
295 | if (ret) | |
296 | return SK_DROP; | |
297 | } else { | |
298 | return SK_DROP; | |
299 | } | |
300 | return SK_PASS; | |
4c4c3c27 | 301 | } |
468b3fde JF |
302 | SEC("sk_msg6") |
303 | int bpf_prog9(struct sk_msg_md *msg) | |
304 | { | |
305 | void *data_end = (void *)(long) msg->data_end; | |
306 | void *data = (void *)(long) msg->data; | |
307 | int ret = 0, *bytes, zero = 0; | |
308 | ||
309 | bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); | |
310 | if (bytes) { | |
311 | if (((__u64)data_end - (__u64)data) >= *bytes) | |
312 | return SK_PASS; | |
313 | ret = bpf_msg_cork_bytes(msg, *bytes); | |
314 | if (ret) | |
315 | return SK_DROP; | |
316 | } | |
317 | return SK_PASS; | |
318 | } | |
4c4c3c27 | 319 | |
e6373ce7 JF |
320 | SEC("sk_msg7") |
321 | int bpf_prog10(struct sk_msg_md *msg) | |
322 | { | |
0dcbbf67 JF |
323 | int *bytes, zero = 0, one = 1; |
324 | int *start, *end; | |
e6373ce7 JF |
325 | |
326 | bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); | |
327 | if (bytes) | |
328 | bpf_msg_apply_bytes(msg, *bytes); | |
329 | bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); | |
330 | if (bytes) | |
331 | bpf_msg_cork_bytes(msg, *bytes); | |
0dcbbf67 JF |
332 | start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); |
333 | end = bpf_map_lookup_elem(&sock_pull_bytes, &one); | |
334 | if (start && end) | |
335 | bpf_msg_pull_data(msg, *start, *end, 0); | |
336 | ||
e6373ce7 JF |
337 | return SK_DROP; |
338 | } | |
339 | ||
340 | ||
69e8cc13 | 341 | char _license[] SEC("license") = "GPL"; |