1
2
3
4
5
6
7
8
9
10
11
12#include <stdio.h>
13#include <unistd.h>
14#include <errno.h>
15#include <string.h>
16#include <assert.h>
17#include <stdlib.h>
18
19#include <sys/wait.h>
20#include <sys/resource.h>
21
22#include <linux/bpf.h>
23
24#include <bpf/bpf.h>
25#include <bpf/libbpf.h>
26#include "bpf_util.h"
27
28static int map_flags;
29
30static void test_hashmap(int task, void *data)
31{
32 long long key, next_key, first_key, value;
33 int fd;
34
35 fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
36 2, map_flags);
37 if (fd < 0) {
38 printf("Failed to create hashmap '%s'!\n", strerror(errno));
39 exit(1);
40 }
41
42 key = 1;
43 value = 1234;
44
45 assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0);
46
47 value = 0;
48
49 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == -1 &&
50
51 errno == EEXIST);
52
53
54 assert(bpf_map_update_elem(fd, &key, &value, -1) == -1 &&
55 errno == EINVAL);
56
57
58 assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 1234);
59
60 key = 2;
61
62 assert(bpf_map_lookup_elem(fd, &key, &value) == -1 && errno == ENOENT);
63
64
65 assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) == -1 &&
66
67 errno == ENOENT);
68
69
70 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == 0);
71
72
73
74
75 key = 0;
76 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == -1 &&
77 errno == E2BIG);
78
79
80 key = 1;
81 assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) == 0);
82 key = 2;
83 assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0);
84 key = 3;
85 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == -1 &&
86 errno == E2BIG);
87
88
89 key = 0;
90 assert(bpf_map_delete_elem(fd, &key) == -1 && errno == ENOENT);
91
92
93 assert(bpf_map_get_next_key(fd, NULL, &first_key) == 0 &&
94 (first_key == 1 || first_key == 2));
95 assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 &&
96 (next_key == first_key));
97 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 &&
98 (next_key == 1 || next_key == 2) &&
99 (next_key != first_key));
100 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == -1 &&
101 errno == ENOENT);
102
103
104 key = 1;
105 assert(bpf_map_delete_elem(fd, &key) == 0);
106 key = 2;
107 assert(bpf_map_delete_elem(fd, &key) == 0);
108 assert(bpf_map_delete_elem(fd, &key) == -1 && errno == ENOENT);
109
110 key = 0;
111
112 assert(bpf_map_get_next_key(fd, NULL, &next_key) == -1 &&
113 errno == ENOENT);
114 assert(bpf_map_get_next_key(fd, &key, &next_key) == -1 &&
115 errno == ENOENT);
116
117 close(fd);
118}
119
120static void test_hashmap_sizes(int task, void *data)
121{
122 int fd, i, j;
123
124 for (i = 1; i <= 512; i <<= 1)
125 for (j = 1; j <= 1 << 18; j <<= 1) {
126 fd = bpf_create_map(BPF_MAP_TYPE_HASH, i, j,
127 2, map_flags);
128 if (fd < 0) {
129 if (errno == ENOMEM)
130 return;
131 printf("Failed to create hashmap key=%d value=%d '%s'\n",
132 i, j, strerror(errno));
133 exit(1);
134 }
135 close(fd);
136 usleep(10);
137 }
138}
139
140static void test_hashmap_percpu(int task, void *data)
141{
142 unsigned int nr_cpus = bpf_num_possible_cpus();
143 BPF_DECLARE_PERCPU(long, value);
144 long long key, next_key, first_key;
145 int expected_key_mask = 0;
146 int fd, i;
147
148 fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_HASH, sizeof(key),
149 sizeof(bpf_percpu(value, 0)), 2, map_flags);
150 if (fd < 0) {
151 printf("Failed to create hashmap '%s'!\n", strerror(errno));
152 exit(1);
153 }
154
155 for (i = 0; i < nr_cpus; i++)
156 bpf_percpu(value, i) = i + 100;
157
158 key = 1;
159
160 assert(!(expected_key_mask & key));
161 assert(bpf_map_update_elem(fd, &key, value, BPF_ANY) == 0);
162 expected_key_mask |= key;
163
164
165 assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) == -1 &&
166
167 errno == EEXIST);
168
169
170 assert(bpf_map_update_elem(fd, &key, value, -1) == -1 &&
171 errno == EINVAL);
172
173
174
175
176 bpf_percpu(value, 0) = 1;
177 assert(bpf_map_lookup_elem(fd, &key, value) == 0 &&
178 bpf_percpu(value, 0) == 100);
179
180 key = 2;
181
182 assert(bpf_map_lookup_elem(fd, &key, value) == -1 && errno == ENOENT);
183
184
185 assert(bpf_map_update_elem(fd, &key, value, BPF_EXIST) == -1 &&
186
187 errno == ENOENT);
188
189
190 assert(!(expected_key_mask & key));
191 assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) == 0);
192 expected_key_mask |= key;
193
194
195
196
197 key = 0;
198 assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) == -1 &&
199 errno == E2BIG);
200
201
202 assert(bpf_map_delete_elem(fd, &key) == -1 && errno == ENOENT);
203
204
205 assert(bpf_map_get_next_key(fd, NULL, &first_key) == 0 &&
206 ((expected_key_mask & first_key) == first_key));
207 while (!bpf_map_get_next_key(fd, &key, &next_key)) {
208 if (first_key) {
209 assert(next_key == first_key);
210 first_key = 0;
211 }
212 assert((expected_key_mask & next_key) == next_key);
213 expected_key_mask &= ~next_key;
214
215 assert(bpf_map_lookup_elem(fd, &next_key, value) == 0);
216
217 for (i = 0; i < nr_cpus; i++)
218 assert(bpf_percpu(value, i) == i + 100);
219
220 key = next_key;
221 }
222 assert(errno == ENOENT);
223
224
225 key = 1;
226 assert(bpf_map_update_elem(fd, &key, value, BPF_EXIST) == 0);
227
228
229 key = 1;
230 assert(bpf_map_delete_elem(fd, &key) == 0);
231 key = 2;
232 assert(bpf_map_delete_elem(fd, &key) == 0);
233 assert(bpf_map_delete_elem(fd, &key) == -1 && errno == ENOENT);
234
235 key = 0;
236
237 assert(bpf_map_get_next_key(fd, NULL, &next_key) == -1 &&
238 errno == ENOENT);
239 assert(bpf_map_get_next_key(fd, &key, &next_key) == -1 &&
240 errno == ENOENT);
241
242 close(fd);
243}
244
245static void test_hashmap_walk(int task, void *data)
246{
247 int fd, i, max_entries = 1000;
248 long long key, value, next_key;
249 bool next_key_valid = true;
250
251 fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
252 max_entries, map_flags);
253 if (fd < 0) {
254 printf("Failed to create hashmap '%s'!\n", strerror(errno));
255 exit(1);
256 }
257
258 for (i = 0; i < max_entries; i++) {
259 key = i; value = key;
260 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == 0);
261 }
262
263 for (i = 0; bpf_map_get_next_key(fd, !i ? NULL : &key,
264 &next_key) == 0; i++) {
265 key = next_key;
266 assert(bpf_map_lookup_elem(fd, &key, &value) == 0);
267 }
268
269 assert(i == max_entries);
270
271 assert(bpf_map_get_next_key(fd, NULL, &key) == 0);
272 for (i = 0; next_key_valid; i++) {
273 next_key_valid = bpf_map_get_next_key(fd, &key, &next_key) == 0;
274 assert(bpf_map_lookup_elem(fd, &key, &value) == 0);
275 value++;
276 assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) == 0);
277 key = next_key;
278 }
279
280 assert(i == max_entries);
281
282 for (i = 0; bpf_map_get_next_key(fd, !i ? NULL : &key,
283 &next_key) == 0; i++) {
284 key = next_key;
285 assert(bpf_map_lookup_elem(fd, &key, &value) == 0);
286 assert(value - 1 == key);
287 }
288
289 assert(i == max_entries);
290 close(fd);
291}
292
293static void test_arraymap(int task, void *data)
294{
295 int key, next_key, fd;
296 long long value;
297
298 fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value),
299 2, 0);
300 if (fd < 0) {
301 printf("Failed to create arraymap '%s'!\n", strerror(errno));
302 exit(1);
303 }
304
305 key = 1;
306 value = 1234;
307
308 assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0);
309
310 value = 0;
311 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == -1 &&
312 errno == EEXIST);
313
314
315 assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 1234);
316
317 key = 0;
318
319 assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 0);
320
321
322
323
324 key = 2;
325 assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) == -1 &&
326 errno == E2BIG);
327
328
329 assert(bpf_map_lookup_elem(fd, &key, &value) == -1 && errno == ENOENT);
330
331
332 assert(bpf_map_get_next_key(fd, NULL, &next_key) == 0 &&
333 next_key == 0);
334 assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 &&
335 next_key == 0);
336 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 &&
337 next_key == 1);
338 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == -1 &&
339 errno == ENOENT);
340
341
342 key = 1;
343 assert(bpf_map_delete_elem(fd, &key) == -1 && errno == EINVAL);
344
345 close(fd);
346}
347
348static void test_arraymap_percpu(int task, void *data)
349{
350 unsigned int nr_cpus = bpf_num_possible_cpus();
351 BPF_DECLARE_PERCPU(long, values);
352 int key, next_key, fd, i;
353
354 fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key),
355 sizeof(bpf_percpu(values, 0)), 2, 0);
356 if (fd < 0) {
357 printf("Failed to create arraymap '%s'!\n", strerror(errno));
358 exit(1);
359 }
360
361 for (i = 0; i < nr_cpus; i++)
362 bpf_percpu(values, i) = i + 100;
363
364 key = 1;
365
366 assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0);
367
368 bpf_percpu(values, 0) = 0;
369 assert(bpf_map_update_elem(fd, &key, values, BPF_NOEXIST) == -1 &&
370 errno == EEXIST);
371
372
373 assert(bpf_map_lookup_elem(fd, &key, values) == 0 &&
374 bpf_percpu(values, 0) == 100);
375
376 key = 0;
377
378 assert(bpf_map_lookup_elem(fd, &key, values) == 0 &&
379 bpf_percpu(values, 0) == 0 &&
380 bpf_percpu(values, nr_cpus - 1) == 0);
381
382
383 key = 2;
384 assert(bpf_map_update_elem(fd, &key, values, BPF_EXIST) == -1 &&
385 errno == E2BIG);
386
387
388 assert(bpf_map_lookup_elem(fd, &key, values) == -1 && errno == ENOENT);
389
390
391 assert(bpf_map_get_next_key(fd, NULL, &next_key) == 0 &&
392 next_key == 0);
393 assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 &&
394 next_key == 0);
395 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 &&
396 next_key == 1);
397 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == -1 &&
398 errno == ENOENT);
399
400
401 key = 1;
402 assert(bpf_map_delete_elem(fd, &key) == -1 && errno == EINVAL);
403
404 close(fd);
405}
406
407static void test_arraymap_percpu_many_keys(void)
408{
409 unsigned int nr_cpus = bpf_num_possible_cpus();
410 BPF_DECLARE_PERCPU(long, values);
411
412
413
414 unsigned int nr_keys = 2000;
415 int key, fd, i;
416
417 fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key),
418 sizeof(bpf_percpu(values, 0)), nr_keys, 0);
419 if (fd < 0) {
420 printf("Failed to create per-cpu arraymap '%s'!\n",
421 strerror(errno));
422 exit(1);
423 }
424
425 for (i = 0; i < nr_cpus; i++)
426 bpf_percpu(values, i) = i + 10;
427
428 for (key = 0; key < nr_keys; key++)
429 assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0);
430
431 for (key = 0; key < nr_keys; key++) {
432 for (i = 0; i < nr_cpus; i++)
433 bpf_percpu(values, i) = 0;
434
435 assert(bpf_map_lookup_elem(fd, &key, values) == 0);
436
437 for (i = 0; i < nr_cpus; i++)
438 assert(bpf_percpu(values, i) == i + 10);
439 }
440
441 close(fd);
442}
443
444static void test_devmap(int task, void *data)
445{
446 int fd;
447 __u32 key, value;
448
449 fd = bpf_create_map(BPF_MAP_TYPE_DEVMAP, sizeof(key), sizeof(value),
450 2, 0);
451 if (fd < 0) {
452 printf("Failed to create arraymap '%s'!\n", strerror(errno));
453 exit(1);
454 }
455
456 close(fd);
457}
458
459#include <sys/socket.h>
460#include <sys/ioctl.h>
461#include <arpa/inet.h>
462#include <sys/select.h>
463#include <linux/err.h>
464#define SOCKMAP_PARSE_PROG "./sockmap_parse_prog.o"
465#define SOCKMAP_VERDICT_PROG "./sockmap_verdict_prog.o"
466__maybe_unused static void test_sockmap(int tasks, void *data)
467{
468 int one = 1, map_fd_rx = 0, map_fd_tx = 0, map_fd_break, s, sc, rc;
469 struct bpf_map *bpf_map_rx, *bpf_map_tx, *bpf_map_break;
470 int ports[] = {50200, 50201, 50202, 50204};
471 int err, i, fd, udp, sfd[6] = {0xdeadbeef};
472 u8 buf[20] = {0x0, 0x5, 0x3, 0x2, 0x1, 0x0};
473 int parse_prog, verdict_prog;
474 struct sockaddr_in addr;
475 struct bpf_object *obj;
476 struct timeval to;
477 __u32 key, value;
478 pid_t pid[tasks];
479 fd_set w;
480
481
482 for (i = 0; i < 2; i++) {
483 sfd[i] = socket(AF_INET, SOCK_STREAM, 0);
484 if (sfd[i] < 0)
485 goto out;
486 err = setsockopt(sfd[i], SOL_SOCKET, SO_REUSEADDR,
487 (char *)&one, sizeof(one));
488 if (err) {
489 printf("failed to setsockopt\n");
490 goto out;
491 }
492 err = ioctl(sfd[i], FIONBIO, (char *)&one);
493 if (err < 0) {
494 printf("failed to ioctl\n");
495 goto out;
496 }
497 memset(&addr, 0, sizeof(struct sockaddr_in));
498 addr.sin_family = AF_INET;
499 addr.sin_addr.s_addr = inet_addr("127.0.0.1");
500 addr.sin_port = htons(ports[i]);
501 err = bind(sfd[i], (struct sockaddr *)&addr, sizeof(addr));
502 if (err < 0) {
503 printf("failed to bind: err %i: %i:%i\n",
504 err, i, sfd[i]);
505 goto out;
506 }
507 err = listen(sfd[i], 32);
508 if (err < 0) {
509 printf("failed to listen\n");
510 goto out;
511 }
512 }
513
514 for (i = 2; i < 4; i++) {
515 sfd[i] = socket(AF_INET, SOCK_STREAM, 0);
516 if (sfd[i] < 0)
517 goto out;
518 err = setsockopt(sfd[i], SOL_SOCKET, SO_REUSEADDR,
519 (char *)&one, sizeof(one));
520 if (err) {
521 printf("set sock opt\n");
522 goto out;
523 }
524 memset(&addr, 0, sizeof(struct sockaddr_in));
525 addr.sin_family = AF_INET;
526 addr.sin_addr.s_addr = inet_addr("127.0.0.1");
527 addr.sin_port = htons(ports[i - 2]);
528 err = connect(sfd[i], (struct sockaddr *)&addr, sizeof(addr));
529 if (err) {
530 printf("failed to connect\n");
531 goto out;
532 }
533 }
534
535
536 for (i = 4; i < 6; i++) {
537 sfd[i] = accept(sfd[i - 4], NULL, NULL);
538 if (sfd[i] < 0) {
539 printf("accept failed\n");
540 goto out;
541 }
542 }
543
544
545 fd = bpf_create_map(BPF_MAP_TYPE_SOCKMAP,
546 sizeof(key), sizeof(value),
547 6, 0);
548 if (fd < 0) {
549 printf("Failed to create sockmap %i\n", fd);
550 goto out_sockmap;
551 }
552
553
554 udp = socket(AF_INET, SOCK_DGRAM, 0);
555 i = 0;
556 err = bpf_map_update_elem(fd, &i, &udp, BPF_ANY);
557 if (!err) {
558 printf("Failed socket SOCK_DGRAM allowed '%i:%i'\n",
559 i, udp);
560 goto out_sockmap;
561 }
562
563
564 for (i = 0; i < 6; i++) {
565 err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY);
566 if (err) {
567 printf("Failed noprog update sockmap '%i:%i'\n",
568 i, sfd[i]);
569 goto out_sockmap;
570 }
571 }
572
573
574 err = bpf_prog_attach(-1, fd, BPF_SK_SKB_STREAM_PARSER, 0);
575 if (!err) {
576 printf("Failed invalid parser prog attach\n");
577 goto out_sockmap;
578 }
579
580 err = bpf_prog_attach(-1, fd, BPF_SK_SKB_STREAM_VERDICT, 0);
581 if (!err) {
582 printf("Failed invalid verdict prog attach\n");
583 goto out_sockmap;
584 }
585
586 err = bpf_prog_attach(-1, fd, __MAX_BPF_ATTACH_TYPE, 0);
587 if (!err) {
588 printf("Failed unknown prog attach\n");
589 goto out_sockmap;
590 }
591
592 err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_PARSER);
593 if (err) {
594 printf("Failed empty parser prog detach\n");
595 goto out_sockmap;
596 }
597
598 err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_VERDICT);
599 if (err) {
600 printf("Failed empty verdict prog detach\n");
601 goto out_sockmap;
602 }
603
604 err = bpf_prog_detach(fd, __MAX_BPF_ATTACH_TYPE);
605 if (!err) {
606 printf("Detach invalid prog successful\n");
607 goto out_sockmap;
608 }
609
610
611 err = bpf_prog_load(SOCKMAP_PARSE_PROG,
612 BPF_PROG_TYPE_SK_SKB, &obj, &parse_prog);
613 if (err) {
614 printf("Failed to load SK_SKB parse prog\n");
615 goto out_sockmap;
616 }
617
618 err = bpf_prog_load(SOCKMAP_VERDICT_PROG,
619 BPF_PROG_TYPE_SK_SKB, &obj, &verdict_prog);
620 if (err) {
621 printf("Failed to load SK_SKB verdict prog\n");
622 goto out_sockmap;
623 }
624
625 bpf_map_rx = bpf_object__find_map_by_name(obj, "sock_map_rx");
626 if (IS_ERR(bpf_map_rx)) {
627 printf("Failed to load map rx from verdict prog\n");
628 goto out_sockmap;
629 }
630
631 map_fd_rx = bpf_map__fd(bpf_map_rx);
632 if (map_fd_rx < 0) {
633 printf("Failed to get map fd\n");
634 goto out_sockmap;
635 }
636
637 bpf_map_tx = bpf_object__find_map_by_name(obj, "sock_map_tx");
638 if (IS_ERR(bpf_map_tx)) {
639 printf("Failed to load map tx from verdict prog\n");
640 goto out_sockmap;
641 }
642
643 map_fd_tx = bpf_map__fd(bpf_map_tx);
644 if (map_fd_tx < 0) {
645 printf("Failed to get map tx fd\n");
646 goto out_sockmap;
647 }
648
649 bpf_map_break = bpf_object__find_map_by_name(obj, "sock_map_break");
650 if (IS_ERR(bpf_map_break)) {
651 printf("Failed to load map tx from verdict prog\n");
652 goto out_sockmap;
653 }
654
655 map_fd_break = bpf_map__fd(bpf_map_break);
656 if (map_fd_break < 0) {
657 printf("Failed to get map tx fd\n");
658 goto out_sockmap;
659 }
660
661 err = bpf_prog_attach(parse_prog, map_fd_break,
662 BPF_SK_SKB_STREAM_PARSER, 0);
663 if (!err) {
664 printf("Allowed attaching SK_SKB program to invalid map\n");
665 goto out_sockmap;
666 }
667
668 err = bpf_prog_attach(parse_prog, map_fd_rx,
669 BPF_SK_SKB_STREAM_PARSER, 0);
670 if (err) {
671 printf("Failed stream parser bpf prog attach\n");
672 goto out_sockmap;
673 }
674
675 err = bpf_prog_attach(verdict_prog, map_fd_rx,
676 BPF_SK_SKB_STREAM_VERDICT, 0);
677 if (err) {
678 printf("Failed stream verdict bpf prog attach\n");
679 goto out_sockmap;
680 }
681
682 err = bpf_prog_attach(verdict_prog, map_fd_rx,
683 __MAX_BPF_ATTACH_TYPE, 0);
684 if (!err) {
685 printf("Attached unknown bpf prog\n");
686 goto out_sockmap;
687 }
688
689
690 for (i = 0; i < 6; i++) {
691 err = bpf_map_update_elem(map_fd_rx, &i, &sfd[i], BPF_ANY);
692 if (err) {
693 printf("Failed map_fd_rx update sockmap %i '%i:%i'\n",
694 err, i, sfd[i]);
695 goto out_sockmap;
696 }
697 err = bpf_map_update_elem(map_fd_tx, &i, &sfd[i], BPF_ANY);
698 if (err) {
699 printf("Failed map_fd_tx update sockmap %i '%i:%i'\n",
700 err, i, sfd[i]);
701 goto out_sockmap;
702 }
703 }
704
705
706 for (i = 2; i < 4; i++) {
707 err = bpf_map_delete_elem(map_fd_rx, &i);
708 if (err) {
709 printf("Failed delete sockmap rx %i '%i:%i'\n",
710 err, i, sfd[i]);
711 goto out_sockmap;
712 }
713 err = bpf_map_delete_elem(map_fd_tx, &i);
714 if (err) {
715 printf("Failed delete sockmap tx %i '%i:%i'\n",
716 err, i, sfd[i]);
717 goto out_sockmap;
718 }
719 }
720
721
722 for (i = 0; i < 2; i++) {
723 buf[0] = i;
724 buf[1] = 0x5;
725 sc = send(sfd[2], buf, 20, 0);
726 if (sc < 0) {
727 printf("Failed sockmap send\n");
728 goto out_sockmap;
729 }
730
731 FD_ZERO(&w);
732 FD_SET(sfd[3], &w);
733 to.tv_sec = 1;
734 to.tv_usec = 0;
735 s = select(sfd[3] + 1, &w, NULL, NULL, &to);
736 if (s == -1) {
737 perror("Failed sockmap select()");
738 goto out_sockmap;
739 } else if (!s) {
740 printf("Failed sockmap unexpected timeout\n");
741 goto out_sockmap;
742 }
743
744 if (!FD_ISSET(sfd[3], &w)) {
745 printf("Failed sockmap select/recv\n");
746 goto out_sockmap;
747 }
748
749 rc = recv(sfd[3], buf, sizeof(buf), 0);
750 if (rc < 0) {
751 printf("Failed sockmap recv\n");
752 goto out_sockmap;
753 }
754 }
755
756
757 buf[0] = 1;
758 buf[1] = 12;
759 sc = send(sfd[2], buf, 20, 0);
760 if (sc < 0) {
761 printf("Failed sockmap send\n");
762 goto out_sockmap;
763 }
764
765
766 i = 2;
767 err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_NOEXIST);
768 if (!err) {
769 printf("Failed allowed sockmap dup slot BPF_NOEXIST\n");
770 goto out_sockmap;
771 }
772
773 err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY);
774 if (err) {
775 printf("Failed sockmap update new slot BPF_ANY\n");
776 goto out_sockmap;
777 }
778
779 err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_EXIST);
780 if (err) {
781 printf("Failed sockmap update new slot BPF_EXIST\n");
782 goto out_sockmap;
783 }
784
785
786 for (i = 0; i < 6; i++) {
787 err = bpf_map_delete_elem(fd, &i);
788 if (err) {
789 printf("Failed delete sockmap %i '%i:%i'\n",
790 err, i, sfd[i]);
791 }
792 }
793
794
795 err = bpf_prog_attach(parse_prog, fd,
796 BPF_SK_SKB_STREAM_PARSER, 0);
797 if (err) {
798 printf("Failed fd bpf parse prog attach\n");
799 goto out_sockmap;
800 }
801 err = bpf_prog_attach(verdict_prog, fd,
802 BPF_SK_SKB_STREAM_VERDICT, 0);
803 if (err) {
804 printf("Failed fd bpf verdict prog attach\n");
805 goto out_sockmap;
806 }
807
808 for (i = 4; i < 6; i++) {
809 err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY);
810 if (!err) {
811 printf("Failed allowed duplicate programs in update ANY sockmap %i '%i:%i'\n",
812 err, i, sfd[i]);
813 goto out_sockmap;
814 }
815 err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_NOEXIST);
816 if (!err) {
817 printf("Failed allowed duplicate program in update NOEXIST sockmap %i '%i:%i'\n",
818 err, i, sfd[i]);
819 goto out_sockmap;
820 }
821 err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_EXIST);
822 if (!err) {
823 printf("Failed allowed duplicate program in update EXIST sockmap %i '%i:%i'\n",
824 err, i, sfd[i]);
825 goto out_sockmap;
826 }
827 }
828
829
830 for (i = 0; i < tasks; i++) {
831 pid[i] = fork();
832 if (pid[i] == 0) {
833 for (i = 0; i < 6; i++) {
834 bpf_map_delete_elem(map_fd_tx, &i);
835 bpf_map_delete_elem(map_fd_rx, &i);
836 bpf_map_update_elem(map_fd_tx, &i,
837 &sfd[i], BPF_ANY);
838 bpf_map_update_elem(map_fd_rx, &i,
839 &sfd[i], BPF_ANY);
840 }
841 exit(0);
842 } else if (pid[i] == -1) {
843 printf("Couldn't spawn #%d process!\n", i);
844 exit(1);
845 }
846 }
847
848 for (i = 0; i < tasks; i++) {
849 int status;
850
851 assert(waitpid(pid[i], &status, 0) == pid[i]);
852 assert(status == 0);
853 }
854
855 err = bpf_prog_detach(map_fd_rx, __MAX_BPF_ATTACH_TYPE);
856 if (!err) {
857 printf("Detached an invalid prog type.\n");
858 goto out_sockmap;
859 }
860
861 err = bpf_prog_detach(map_fd_rx, BPF_SK_SKB_STREAM_PARSER);
862 if (err) {
863 printf("Failed parser prog detach\n");
864 goto out_sockmap;
865 }
866
867 err = bpf_prog_detach(map_fd_rx, BPF_SK_SKB_STREAM_VERDICT);
868 if (err) {
869 printf("Failed parser prog detach\n");
870 goto out_sockmap;
871 }
872
873
874 for (i = 0; i < 6; i++) {
875 bpf_map_delete_elem(map_fd_tx, &i);
876 bpf_map_delete_elem(map_fd_rx, &i);
877 close(sfd[i]);
878 }
879 close(fd);
880 close(map_fd_rx);
881 bpf_object__close(obj);
882 return;
883out:
884 for (i = 0; i < 6; i++)
885 close(sfd[i]);
886 printf("Failed to create sockmap '%i:%s'!\n", i, strerror(errno));
887 exit(1);
888out_sockmap:
889 for (i = 0; i < 6; i++) {
890 if (map_fd_tx)
891 bpf_map_delete_elem(map_fd_tx, &i);
892 if (map_fd_rx)
893 bpf_map_delete_elem(map_fd_rx, &i);
894 close(sfd[i]);
895 }
896 close(fd);
897 exit(1);
898}
899
900#define MAP_SIZE (32 * 1024)
901
902static void test_map_large(void)
903{
904 struct bigkey {
905 int a;
906 char b[116];
907 long long c;
908 } key;
909 int fd, i, value;
910
911 fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
912 MAP_SIZE, map_flags);
913 if (fd < 0) {
914 printf("Failed to create large map '%s'!\n", strerror(errno));
915 exit(1);
916 }
917
918 for (i = 0; i < MAP_SIZE; i++) {
919 key = (struct bigkey) { .c = i };
920 value = i;
921
922 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == 0);
923 }
924
925 key.c = -1;
926 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == -1 &&
927 errno == E2BIG);
928
929
930 assert(bpf_map_get_next_key(fd, NULL, &key) == 0);
931 key.c = -1;
932 for (i = 0; i < MAP_SIZE; i++)
933 assert(bpf_map_get_next_key(fd, &key, &key) == 0);
934 assert(bpf_map_get_next_key(fd, &key, &key) == -1 && errno == ENOENT);
935
936 key.c = 0;
937 assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 0);
938 key.a = 1;
939 assert(bpf_map_lookup_elem(fd, &key, &value) == -1 && errno == ENOENT);
940
941 close(fd);
942}
943
944#define run_parallel(N, FN, DATA) \
945 printf("Fork %d tasks to '" #FN "'\n", N); \
946 __run_parallel(N, FN, DATA)
947
948static void __run_parallel(int tasks, void (*fn)(int task, void *data),
949 void *data)
950{
951 pid_t pid[tasks];
952 int i;
953
954 for (i = 0; i < tasks; i++) {
955 pid[i] = fork();
956 if (pid[i] == 0) {
957 fn(i, data);
958 exit(0);
959 } else if (pid[i] == -1) {
960 printf("Couldn't spawn #%d process!\n", i);
961 exit(1);
962 }
963 }
964
965 for (i = 0; i < tasks; i++) {
966 int status;
967
968 assert(waitpid(pid[i], &status, 0) == pid[i]);
969 assert(status == 0);
970 }
971}
972
973__maybe_unused static void test_map_stress(void)
974{
975 run_parallel(100, test_hashmap, NULL);
976 run_parallel(100, test_hashmap_percpu, NULL);
977 run_parallel(100, test_hashmap_sizes, NULL);
978 run_parallel(100, test_hashmap_walk, NULL);
979
980 run_parallel(100, test_arraymap, NULL);
981 run_parallel(100, test_arraymap_percpu, NULL);
982}
983
984#define TASKS 1024
985
986#define DO_UPDATE 1
987#define DO_DELETE 0
988
989static void test_update_delete(int fn, void *data)
990{
991 int do_update = ((int *)data)[1];
992 int fd = ((int *)data)[0];
993 int i, key, value;
994
995 for (i = fn; i < MAP_SIZE; i += TASKS) {
996 key = value = i;
997
998 if (do_update) {
999 assert(bpf_map_update_elem(fd, &key, &value,
1000 BPF_NOEXIST) == 0);
1001 assert(bpf_map_update_elem(fd, &key, &value,
1002 BPF_EXIST) == 0);
1003 } else {
1004 assert(bpf_map_delete_elem(fd, &key) == 0);
1005 }
1006 }
1007}
1008
1009__maybe_unused static void test_map_parallel(void)
1010{
1011 int i, fd, key = 0, value = 0;
1012 int data[2];
1013
1014 fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
1015 MAP_SIZE, map_flags);
1016 if (fd < 0) {
1017 printf("Failed to create map for parallel test '%s'!\n",
1018 strerror(errno));
1019 exit(1);
1020 }
1021
1022
1023
1024
1025
1026
1027 data[0] = fd;
1028 data[1] = DO_UPDATE;
1029 run_parallel(TASKS, test_update_delete, data);
1030
1031
1032 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == -1 &&
1033 errno == EEXIST);
1034
1035
1036 assert(bpf_map_get_next_key(fd, NULL, &key) == 0);
1037 key = -1;
1038 for (i = 0; i < MAP_SIZE; i++)
1039 assert(bpf_map_get_next_key(fd, &key, &key) == 0);
1040 assert(bpf_map_get_next_key(fd, &key, &key) == -1 && errno == ENOENT);
1041
1042
1043 for (i = 0; i < MAP_SIZE; i++) {
1044 key = MAP_SIZE - i - 1;
1045
1046 assert(bpf_map_lookup_elem(fd, &key, &value) == 0 &&
1047 value == key);
1048 }
1049
1050
1051 data[1] = DO_DELETE;
1052 run_parallel(TASKS, test_update_delete, data);
1053
1054
1055 key = -1;
1056 assert(bpf_map_get_next_key(fd, NULL, &key) == -1 && errno == ENOENT);
1057 assert(bpf_map_get_next_key(fd, &key, &key) == -1 && errno == ENOENT);
1058}
1059
1060static void test_map_rdonly(void)
1061{
1062 int fd, key = 0, value = 0;
1063
1064 fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
1065 MAP_SIZE, map_flags | BPF_F_RDONLY);
1066 if (fd < 0) {
1067 printf("Failed to create map for read only test '%s'!\n",
1068 strerror(errno));
1069 exit(1);
1070 }
1071
1072 key = 1;
1073 value = 1234;
1074
1075 assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == -1 &&
1076 errno == EPERM);
1077
1078
1079 assert(bpf_map_lookup_elem(fd, &key, &value) == -1 && errno == ENOENT);
1080 assert(bpf_map_get_next_key(fd, &key, &value) == -1 && errno == ENOENT);
1081}
1082
1083static void test_map_wronly(void)
1084{
1085 int fd, key = 0, value = 0;
1086
1087 fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
1088 MAP_SIZE, map_flags | BPF_F_WRONLY);
1089 if (fd < 0) {
1090 printf("Failed to create map for read only test '%s'!\n",
1091 strerror(errno));
1092 exit(1);
1093 }
1094
1095 key = 1;
1096 value = 1234;
1097
1098 assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0);
1099
1100
1101 assert(bpf_map_lookup_elem(fd, &key, &value) == -1 && errno == EPERM);
1102 assert(bpf_map_get_next_key(fd, &key, &value) == -1 && errno == EPERM);
1103}
1104
1105static void run_all_tests(void)
1106{
1107 test_hashmap(0, NULL);
1108 test_hashmap_percpu(0, NULL);
1109 test_hashmap_walk(0, NULL);
1110
1111 test_arraymap(0, NULL);
1112 test_arraymap_percpu(0, NULL);
1113
1114 test_arraymap_percpu_many_keys();
1115
1116 test_devmap(0, NULL);
1117
1118#if 0
1119 RHEL7 - SOCKMAP is unsupported
1120 test_sockmap(0, NULL);
1121#endif
1122
1123 test_map_large();
1124
1125#ifndef __s390x__
1126 test_map_parallel();
1127 test_map_stress();
1128#endif
1129
1130 test_map_rdonly();
1131 test_map_wronly();
1132}
1133
1134int main(void)
1135{
1136 struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
1137
1138 setrlimit(RLIMIT_MEMLOCK, &rinf);
1139
1140 map_flags = 0;
1141 run_all_tests();
1142
1143 map_flags = BPF_F_NO_PREALLOC;
1144 run_all_tests();
1145
1146 printf("test_maps: OK\n");
1147 return 0;
1148}
1149