]> git.karo-electronics.de Git - karo-tx-linux.git/blob - samples/bpf/test_maps.c
Merge branch 'for-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
[karo-tx-linux.git] / samples / bpf / test_maps.c
1 /*
2  * Testsuite for eBPF maps
3  *
4  * Copyright (c) 2014 PLUMgrid, http://plumgrid.com
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of version 2 of the GNU General Public
8  * License as published by the Free Software Foundation.
9  */
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <linux/bpf.h>
13 #include <errno.h>
14 #include <string.h>
15 #include <assert.h>
16 #include <sys/wait.h>
17 #include <stdlib.h>
18 #include "libbpf.h"
19
20 /* sanity tests for map API */
21 static void test_hashmap_sanity(int i, void *data)
22 {
23         long long key, next_key, value;
24         int map_fd;
25
26         map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), 2);
27         if (map_fd < 0) {
28                 printf("failed to create hashmap '%s'\n", strerror(errno));
29                 exit(1);
30         }
31
32         key = 1;
33         value = 1234;
34         /* insert key=1 element */
35         assert(bpf_update_elem(map_fd, &key, &value, BPF_ANY) == 0);
36
37         value = 0;
38         /* BPF_NOEXIST means: add new element if it doesn't exist */
39         assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == -1 &&
40                /* key=1 already exists */
41                errno == EEXIST);
42
43         assert(bpf_update_elem(map_fd, &key, &value, -1) == -1 && errno == EINVAL);
44
45         /* check that key=1 can be found */
46         assert(bpf_lookup_elem(map_fd, &key, &value) == 0 && value == 1234);
47
48         key = 2;
49         /* check that key=2 is not found */
50         assert(bpf_lookup_elem(map_fd, &key, &value) == -1 && errno == ENOENT);
51
52         /* BPF_EXIST means: update existing element */
53         assert(bpf_update_elem(map_fd, &key, &value, BPF_EXIST) == -1 &&
54                /* key=2 is not there */
55                errno == ENOENT);
56
57         /* insert key=2 element */
58         assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == 0);
59
60         /* key=1 and key=2 were inserted, check that key=0 cannot be inserted
61          * due to max_entries limit
62          */
63         key = 0;
64         assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == -1 &&
65                errno == E2BIG);
66
67         /* check that key = 0 doesn't exist */
68         assert(bpf_delete_elem(map_fd, &key) == -1 && errno == ENOENT);
69
70         /* iterate over two elements */
71         assert(bpf_get_next_key(map_fd, &key, &next_key) == 0 &&
72                (next_key == 1 || next_key == 2));
73         assert(bpf_get_next_key(map_fd, &next_key, &next_key) == 0 &&
74                (next_key == 1 || next_key == 2));
75         assert(bpf_get_next_key(map_fd, &next_key, &next_key) == -1 &&
76                errno == ENOENT);
77
78         /* delete both elements */
79         key = 1;
80         assert(bpf_delete_elem(map_fd, &key) == 0);
81         key = 2;
82         assert(bpf_delete_elem(map_fd, &key) == 0);
83         assert(bpf_delete_elem(map_fd, &key) == -1 && errno == ENOENT);
84
85         key = 0;
86         /* check that map is empty */
87         assert(bpf_get_next_key(map_fd, &key, &next_key) == -1 &&
88                errno == ENOENT);
89         close(map_fd);
90 }
91
92 static void test_arraymap_sanity(int i, void *data)
93 {
94         int key, next_key, map_fd;
95         long long value;
96
97         map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value), 2);
98         if (map_fd < 0) {
99                 printf("failed to create arraymap '%s'\n", strerror(errno));
100                 exit(1);
101         }
102
103         key = 1;
104         value = 1234;
105         /* insert key=1 element */
106         assert(bpf_update_elem(map_fd, &key, &value, BPF_ANY) == 0);
107
108         value = 0;
109         assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == -1 &&
110                errno == EEXIST);
111
112         /* check that key=1 can be found */
113         assert(bpf_lookup_elem(map_fd, &key, &value) == 0 && value == 1234);
114
115         key = 0;
116         /* check that key=0 is also found and zero initialized */
117         assert(bpf_lookup_elem(map_fd, &key, &value) == 0 && value == 0);
118
119
120         /* key=0 and key=1 were inserted, check that key=2 cannot be inserted
121          * due to max_entries limit
122          */
123         key = 2;
124         assert(bpf_update_elem(map_fd, &key, &value, BPF_EXIST) == -1 &&
125                errno == E2BIG);
126
127         /* check that key = 2 doesn't exist */
128         assert(bpf_lookup_elem(map_fd, &key, &value) == -1 && errno == ENOENT);
129
130         /* iterate over two elements */
131         assert(bpf_get_next_key(map_fd, &key, &next_key) == 0 &&
132                next_key == 0);
133         assert(bpf_get_next_key(map_fd, &next_key, &next_key) == 0 &&
134                next_key == 1);
135         assert(bpf_get_next_key(map_fd, &next_key, &next_key) == -1 &&
136                errno == ENOENT);
137
138         /* delete shouldn't succeed */
139         key = 1;
140         assert(bpf_delete_elem(map_fd, &key) == -1 && errno == EINVAL);
141
142         close(map_fd);
143 }
144
145 #define MAP_SIZE (32 * 1024)
146 static void test_map_large(void)
147 {
148         struct bigkey {
149                 int a;
150                 char b[116];
151                 long long c;
152         } key;
153         int map_fd, i, value;
154
155         /* allocate 4Mbyte of memory */
156         map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
157                                 MAP_SIZE);
158         if (map_fd < 0) {
159                 printf("failed to create large map '%s'\n", strerror(errno));
160                 exit(1);
161         }
162
163         for (i = 0; i < MAP_SIZE; i++) {
164                 key = (struct bigkey) {.c = i};
165                 value = i;
166                 assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == 0);
167         }
168         key.c = -1;
169         assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == -1 &&
170                errno == E2BIG);
171
172         /* iterate through all elements */
173         for (i = 0; i < MAP_SIZE; i++)
174                 assert(bpf_get_next_key(map_fd, &key, &key) == 0);
175         assert(bpf_get_next_key(map_fd, &key, &key) == -1 && errno == ENOENT);
176
177         key.c = 0;
178         assert(bpf_lookup_elem(map_fd, &key, &value) == 0 && value == 0);
179         key.a = 1;
180         assert(bpf_lookup_elem(map_fd, &key, &value) == -1 && errno == ENOENT);
181
182         close(map_fd);
183 }
184
185 /* fork N children and wait for them to complete */
186 static void run_parallel(int tasks, void (*fn)(int i, void *data), void *data)
187 {
188         pid_t pid[tasks];
189         int i;
190
191         for (i = 0; i < tasks; i++) {
192                 pid[i] = fork();
193                 if (pid[i] == 0) {
194                         fn(i, data);
195                         exit(0);
196                 } else if (pid[i] == -1) {
197                         printf("couldn't spawn #%d process\n", i);
198                         exit(1);
199                 }
200         }
201         for (i = 0; i < tasks; i++) {
202                 int status;
203
204                 assert(waitpid(pid[i], &status, 0) == pid[i]);
205                 assert(status == 0);
206         }
207 }
208
209 static void test_map_stress(void)
210 {
211         run_parallel(100, test_hashmap_sanity, NULL);
212         run_parallel(100, test_arraymap_sanity, NULL);
213 }
214
215 #define TASKS 1024
216 #define DO_UPDATE 1
217 #define DO_DELETE 0
218 static void do_work(int fn, void *data)
219 {
220         int map_fd = ((int *)data)[0];
221         int do_update = ((int *)data)[1];
222         int i;
223         int key, value;
224
225         for (i = fn; i < MAP_SIZE; i += TASKS) {
226                 key = value = i;
227                 if (do_update)
228                         assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == 0);
229                 else
230                         assert(bpf_delete_elem(map_fd, &key) == 0);
231         }
232 }
233
234 static void test_map_parallel(void)
235 {
236         int i, map_fd, key = 0, value = 0;
237         int data[2];
238
239         map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
240                                 MAP_SIZE);
241         if (map_fd < 0) {
242                 printf("failed to create map for parallel test '%s'\n",
243                        strerror(errno));
244                 exit(1);
245         }
246
247         data[0] = map_fd;
248         data[1] = DO_UPDATE;
249         /* use the same map_fd in children to add elements to this map
250          * child_0 adds key=0, key=1024, key=2048, ...
251          * child_1 adds key=1, key=1025, key=2049, ...
252          * child_1023 adds key=1023, ...
253          */
254         run_parallel(TASKS, do_work, data);
255
256         /* check that key=0 is already there */
257         assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == -1 &&
258                errno == EEXIST);
259
260         /* check that all elements were inserted */
261         key = -1;
262         for (i = 0; i < MAP_SIZE; i++)
263                 assert(bpf_get_next_key(map_fd, &key, &key) == 0);
264         assert(bpf_get_next_key(map_fd, &key, &key) == -1 && errno == ENOENT);
265
266         /* another check for all elements */
267         for (i = 0; i < MAP_SIZE; i++) {
268                 key = MAP_SIZE - i - 1;
269                 assert(bpf_lookup_elem(map_fd, &key, &value) == 0 &&
270                        value == key);
271         }
272
273         /* now let's delete all elemenets in parallel */
274         data[1] = DO_DELETE;
275         run_parallel(TASKS, do_work, data);
276
277         /* nothing should be left */
278         key = -1;
279         assert(bpf_get_next_key(map_fd, &key, &key) == -1 && errno == ENOENT);
280 }
281
282 int main(void)
283 {
284         test_hashmap_sanity(0, NULL);
285         test_arraymap_sanity(0, NULL);
286         test_map_large();
287         test_map_parallel();
288         test_map_stress();
289         printf("test_maps: OK\n");
290         return 0;
291 }