1 // SPDX-License-Identifier: GPL-2.0
2
3 #define _GNU_SOURCE
4 #include <linux/bpf.h>
5 #include <stdio.h>
6 #include <stdbool.h>
7 #include <unistd.h>
8 #include <errno.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <pthread.h>
12
13 #include <bpf/bpf.h>
14 #include <bpf/libbpf.h>
15
16 #include <test_maps.h>
17
18 struct test_lpm_key {
19 __u32 prefix;
20 __u32 data;
21 };
22
23 struct get_next_key_ctx {
24 struct test_lpm_key key;
25 bool start;
26 bool stop;
27 int map_fd;
28 int loop;
29 };
30
get_next_key_fn(void * arg)31 static void *get_next_key_fn(void *arg)
32 {
33 struct get_next_key_ctx *ctx = arg;
34 struct test_lpm_key next_key;
35 int i = 0;
36
37 while (!ctx->start)
38 usleep(1);
39
40 while (!ctx->stop && i++ < ctx->loop)
41 bpf_map_get_next_key(ctx->map_fd, &ctx->key, &next_key);
42
43 return NULL;
44 }
45
abort_get_next_key(struct get_next_key_ctx * ctx,pthread_t * tids,unsigned int nr)46 static void abort_get_next_key(struct get_next_key_ctx *ctx, pthread_t *tids,
47 unsigned int nr)
48 {
49 unsigned int i;
50
51 ctx->stop = true;
52 ctx->start = true;
53 for (i = 0; i < nr; i++)
54 pthread_join(tids[i], NULL);
55 }
56
57 /* This test aims to prevent regression of future. As long as the kernel does
58 * not panic, it is considered as success.
59 */
test_lpm_trie_map_get_next_key(void)60 void test_lpm_trie_map_get_next_key(void)
61 {
62 #define MAX_NR_THREADS 8
63 LIBBPF_OPTS(bpf_map_create_opts, create_opts,
64 .map_flags = BPF_F_NO_PREALLOC);
65 struct test_lpm_key key = {};
66 __u32 val = 0;
67 int map_fd;
68 const __u32 max_prefixlen = 8 * (sizeof(key) - sizeof(key.prefix));
69 const __u32 max_entries = max_prefixlen + 1;
70 unsigned int i, nr = MAX_NR_THREADS, loop = 65536;
71 pthread_t tids[MAX_NR_THREADS];
72 struct get_next_key_ctx ctx;
73 int err;
74
75 map_fd = bpf_map_create(BPF_MAP_TYPE_LPM_TRIE, "lpm_trie_map",
76 sizeof(struct test_lpm_key), sizeof(__u32),
77 max_entries, &create_opts);
78 CHECK(map_fd == -1, "bpf_map_create()", "error:%s\n",
79 strerror(errno));
80
81 for (i = 0; i <= max_prefixlen; i++) {
82 key.prefix = i;
83 err = bpf_map_update_elem(map_fd, &key, &val, BPF_ANY);
84 CHECK(err, "bpf_map_update_elem()", "error:%s\n",
85 strerror(errno));
86 }
87
88 ctx.start = false;
89 ctx.stop = false;
90 ctx.map_fd = map_fd;
91 ctx.loop = loop;
92 memcpy(&ctx.key, &key, sizeof(key));
93
94 for (i = 0; i < nr; i++) {
95 err = pthread_create(&tids[i], NULL, get_next_key_fn, &ctx);
96 if (err) {
97 abort_get_next_key(&ctx, tids, i);
98 CHECK(err, "pthread_create", "error %d\n", err);
99 }
100 }
101
102 ctx.start = true;
103 for (i = 0; i < nr; i++)
104 pthread_join(tids[i], NULL);
105
106 printf("%s:PASS\n", __func__);
107
108 close(map_fd);
109 }
110