blob: eccf6d96e551e187d25f883a64cb4cd118b6b071 [file] [log] [blame]
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -08001/*
2 * Copyright (c) 2016 Facebook
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of version 2 of the GNU General Public
6 * License as published by the Free Software Foundation.
7 */
8#define _GNU_SOURCE
9#include <stdio.h>
10#include <unistd.h>
11#include <errno.h>
12#include <string.h>
13#include <assert.h>
14#include <sched.h>
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -080015#include <stdlib.h>
16#include <time.h>
Daniel Borkmanne00c7b22016-11-26 01:28:09 +010017
18#include <sys/wait.h>
19#include <sys/resource.h>
20
Mickaël Salaün10ecc722017-02-10 00:21:39 +010021#include <bpf/bpf.h>
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -080022#include "bpf_sys.h"
Daniel Borkmanne00c7b22016-11-26 01:28:09 +010023#include "bpf_util.h"
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -080024
25#define LOCAL_FREE_TARGET (128)
26#define PERCPU_FREE_TARGET (16)
27
28static int nr_cpus;
29
30static int create_map(int map_type, int map_flags, unsigned int size)
31{
32 int map_fd;
33
34 map_fd = bpf_map_create(map_type, sizeof(unsigned long long),
35 sizeof(unsigned long long), size, map_flags);
36
37 if (map_fd == -1)
38 perror("bpf_map_create");
39
40 return map_fd;
41}
42
43static int map_subset(int map0, int map1)
44{
45 unsigned long long next_key = 0;
46 unsigned long long value0[nr_cpus], value1[nr_cpus];
47 int ret;
48
49 while (!bpf_map_next_key(map1, &next_key, &next_key)) {
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +010050 assert(!bpf_map_lookup_elem(map1, &next_key, value1));
51 ret = bpf_map_lookup_elem(map0, &next_key, value0);
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -080052 if (ret) {
53 printf("key:%llu not found from map. %s(%d)\n",
54 next_key, strerror(errno), errno);
55 return 0;
56 }
57 if (value0[0] != value1[0]) {
58 printf("key:%llu value0:%llu != value1:%llu\n",
59 next_key, value0[0], value1[0]);
60 return 0;
61 }
62 }
63 return 1;
64}
65
66static int map_equal(int lru_map, int expected)
67{
68 return map_subset(lru_map, expected) && map_subset(expected, lru_map);
69}
70
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -080071static int sched_next_online(int pid, int *next_to_try)
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -080072{
73 cpu_set_t cpuset;
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -080074 int next = *next_to_try;
75 int ret = -1;
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -080076
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -080077 while (next < nr_cpus) {
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -080078 CPU_ZERO(&cpuset);
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -080079 CPU_SET(next++, &cpuset);
80 if (!sched_setaffinity(pid, sizeof(cpuset), &cpuset)) {
81 ret = 0;
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -080082 break;
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -080083 }
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -080084 }
85
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -080086 *next_to_try = next;
87 return ret;
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -080088}
89
90/* Size of the LRU amp is 2
91 * Add key=1 (+1 key)
92 * Add key=2 (+1 key)
93 * Lookup Key=1
94 * Add Key=3
95 * => Key=2 will be removed by LRU
96 * Iterate map. Only found key=1 and key=3
97 */
98static void test_lru_sanity0(int map_type, int map_flags)
99{
100 unsigned long long key, value[nr_cpus];
101 int lru_map_fd, expected_map_fd;
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -0800102 int next_cpu = 0;
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800103
104 printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
105 map_flags);
106
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -0800107 assert(sched_next_online(0, &next_cpu) != -1);
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800108
109 if (map_flags & BPF_F_NO_COMMON_LRU)
110 lru_map_fd = create_map(map_type, map_flags, 2 * nr_cpus);
111 else
112 lru_map_fd = create_map(map_type, map_flags, 2);
113 assert(lru_map_fd != -1);
114
115 expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, 2);
116 assert(expected_map_fd != -1);
117
118 value[0] = 1234;
119
120 /* insert key=1 element */
121
122 key = 1;
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100123 assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
124 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
125 BPF_NOEXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800126
127 /* BPF_NOEXIST means: add new element if it doesn't exist */
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100128 assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST) == -1
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800129 /* key=1 already exists */
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100130 && errno == EEXIST);
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800131
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100132 assert(bpf_map_update_elem(lru_map_fd, &key, value, -1) == -1 &&
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800133 errno == EINVAL);
134
135 /* insert key=2 element */
136
137 /* check that key=2 is not found */
138 key = 2;
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100139 assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800140 errno == ENOENT);
141
142 /* BPF_EXIST means: update existing element */
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100143 assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_EXIST) == -1 &&
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800144 /* key=2 is not there */
145 errno == ENOENT);
146
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100147 assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800148
149 /* insert key=3 element */
150
151 /* check that key=3 is not found */
152 key = 3;
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100153 assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800154 errno == ENOENT);
155
156 /* check that key=1 can be found and mark the ref bit to
157 * stop LRU from removing key=1
158 */
159 key = 1;
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100160 assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800161 assert(value[0] == 1234);
162
163 key = 3;
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100164 assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
165 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
166 BPF_NOEXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800167
168 /* key=2 has been removed from the LRU */
169 key = 2;
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100170 assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1);
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800171
172 assert(map_equal(lru_map_fd, expected_map_fd));
173
174 close(expected_map_fd);
175 close(lru_map_fd);
176
177 printf("Pass\n");
178}
179
180/* Size of the LRU map is 1.5*tgt_free
181 * Insert 1 to tgt_free (+tgt_free keys)
182 * Lookup 1 to tgt_free/2
183 * Insert 1+tgt_free to 2*tgt_free (+tgt_free keys)
184 * => 1+tgt_free/2 to LOCALFREE_TARGET will be removed by LRU
185 */
186static void test_lru_sanity1(int map_type, int map_flags, unsigned int tgt_free)
187{
188 unsigned long long key, end_key, value[nr_cpus];
189 int lru_map_fd, expected_map_fd;
190 unsigned int batch_size;
191 unsigned int map_size;
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -0800192 int next_cpu = 0;
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800193
194 if (map_flags & BPF_F_NO_COMMON_LRU)
195 /* Ther percpu lru list (i.e each cpu has its own LRU
196 * list) does not have a local free list. Hence,
197 * it will only free old nodes till there is no free
198 * from the LRU list. Hence, this test does not apply
199 * to BPF_F_NO_COMMON_LRU
200 */
201 return;
202
203 printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
204 map_flags);
205
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -0800206 assert(sched_next_online(0, &next_cpu) != -1);
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800207
208 batch_size = tgt_free / 2;
209 assert(batch_size * 2 == tgt_free);
210
211 map_size = tgt_free + batch_size;
212 lru_map_fd = create_map(map_type, map_flags, map_size);
213 assert(lru_map_fd != -1);
214
215 expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size);
216 assert(expected_map_fd != -1);
217
218 value[0] = 1234;
219
220 /* Insert 1 to tgt_free (+tgt_free keys) */
221 end_key = 1 + tgt_free;
222 for (key = 1; key < end_key; key++)
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100223 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
224 BPF_NOEXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800225
226 /* Lookup 1 to tgt_free/2 */
227 end_key = 1 + batch_size;
228 for (key = 1; key < end_key; key++) {
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100229 assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100230 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
231 BPF_NOEXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800232 }
233
234 /* Insert 1+tgt_free to 2*tgt_free
235 * => 1+tgt_free/2 to LOCALFREE_TARGET will be
236 * removed by LRU
237 */
238 key = 1 + tgt_free;
239 end_key = key + tgt_free;
240 for (; key < end_key; key++) {
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100241 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
242 BPF_NOEXIST));
243 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
244 BPF_NOEXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800245 }
246
247 assert(map_equal(lru_map_fd, expected_map_fd));
248
249 close(expected_map_fd);
250 close(lru_map_fd);
251
252 printf("Pass\n");
253}
254
255/* Size of the LRU map 1.5 * tgt_free
256 * Insert 1 to tgt_free (+tgt_free keys)
257 * Update 1 to tgt_free/2
258 * => The original 1 to tgt_free/2 will be removed due to
259 * the LRU shrink process
260 * Re-insert 1 to tgt_free/2 again and do a lookup immeidately
261 * Insert 1+tgt_free to tgt_free*3/2
262 * Insert 1+tgt_free*3/2 to tgt_free*5/2
263 * => Key 1+tgt_free to tgt_free*3/2
264 * will be removed from LRU because it has never
265 * been lookup and ref bit is not set
266 */
267static void test_lru_sanity2(int map_type, int map_flags, unsigned int tgt_free)
268{
269 unsigned long long key, value[nr_cpus];
270 unsigned long long end_key;
271 int lru_map_fd, expected_map_fd;
272 unsigned int batch_size;
273 unsigned int map_size;
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -0800274 int next_cpu = 0;
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800275
276 if (map_flags & BPF_F_NO_COMMON_LRU)
277 /* Ther percpu lru list (i.e each cpu has its own LRU
278 * list) does not have a local free list. Hence,
279 * it will only free old nodes till there is no free
280 * from the LRU list. Hence, this test does not apply
281 * to BPF_F_NO_COMMON_LRU
282 */
283 return;
284
285 printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
286 map_flags);
287
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -0800288 assert(sched_next_online(0, &next_cpu) != -1);
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800289
290 batch_size = tgt_free / 2;
291 assert(batch_size * 2 == tgt_free);
292
293 map_size = tgt_free + batch_size;
294 if (map_flags & BPF_F_NO_COMMON_LRU)
295 lru_map_fd = create_map(map_type, map_flags,
296 map_size * nr_cpus);
297 else
298 lru_map_fd = create_map(map_type, map_flags, map_size);
299 assert(lru_map_fd != -1);
300
301 expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size);
302 assert(expected_map_fd != -1);
303
304 value[0] = 1234;
305
306 /* Insert 1 to tgt_free (+tgt_free keys) */
307 end_key = 1 + tgt_free;
308 for (key = 1; key < end_key; key++)
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100309 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
310 BPF_NOEXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800311
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100312 /* Any bpf_map_update_elem will require to acquire a new node
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800313 * from LRU first.
314 *
315 * The local list is running out of free nodes.
316 * It gets from the global LRU list which tries to
317 * shrink the inactive list to get tgt_free
318 * number of free nodes.
319 *
320 * Hence, the oldest key 1 to tgt_free/2
321 * are removed from the LRU list.
322 */
323 key = 1;
324 if (map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100325 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
326 BPF_NOEXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800327 assert(!bpf_map_delete(lru_map_fd, &key));
328 } else {
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100329 assert(bpf_map_update_elem(lru_map_fd, &key, value,
330 BPF_EXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800331 }
332
333 /* Re-insert 1 to tgt_free/2 again and do a lookup
334 * immeidately.
335 */
336 end_key = 1 + batch_size;
337 value[0] = 4321;
338 for (key = 1; key < end_key; key++) {
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100339 assert(bpf_map_lookup_elem(lru_map_fd, &key, value));
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100340 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
341 BPF_NOEXIST));
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100342 assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800343 assert(value[0] == 4321);
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100344 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
345 BPF_NOEXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800346 }
347
348 value[0] = 1234;
349
350 /* Insert 1+tgt_free to tgt_free*3/2 */
351 end_key = 1 + tgt_free + batch_size;
352 for (key = 1 + tgt_free; key < end_key; key++)
353 /* These newly added but not referenced keys will be
354 * gone during the next LRU shrink.
355 */
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100356 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
357 BPF_NOEXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800358
359 /* Insert 1+tgt_free*3/2 to tgt_free*5/2 */
360 end_key = key + tgt_free;
361 for (; key < end_key; key++) {
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100362 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
363 BPF_NOEXIST));
364 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
365 BPF_NOEXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800366 }
367
368 assert(map_equal(lru_map_fd, expected_map_fd));
369
370 close(expected_map_fd);
371 close(lru_map_fd);
372
373 printf("Pass\n");
374}
375
376/* Size of the LRU map is 2*tgt_free
377 * It is to test the active/inactive list rotation
378 * Insert 1 to 2*tgt_free (+2*tgt_free keys)
379 * Lookup key 1 to tgt_free*3/2
380 * Add 1+2*tgt_free to tgt_free*5/2 (+tgt_free/2 keys)
381 * => key 1+tgt_free*3/2 to 2*tgt_free are removed from LRU
382 */
383static void test_lru_sanity3(int map_type, int map_flags, unsigned int tgt_free)
384{
385 unsigned long long key, end_key, value[nr_cpus];
386 int lru_map_fd, expected_map_fd;
387 unsigned int batch_size;
388 unsigned int map_size;
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -0800389 int next_cpu = 0;
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800390
391 printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
392 map_flags);
393
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -0800394 assert(sched_next_online(0, &next_cpu) != -1);
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800395
396 batch_size = tgt_free / 2;
397 assert(batch_size * 2 == tgt_free);
398
399 map_size = tgt_free * 2;
400 if (map_flags & BPF_F_NO_COMMON_LRU)
401 lru_map_fd = create_map(map_type, map_flags,
402 map_size * nr_cpus);
403 else
404 lru_map_fd = create_map(map_type, map_flags, map_size);
405 assert(lru_map_fd != -1);
406
407 expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size);
408 assert(expected_map_fd != -1);
409
410 value[0] = 1234;
411
412 /* Insert 1 to 2*tgt_free (+2*tgt_free keys) */
413 end_key = 1 + (2 * tgt_free);
414 for (key = 1; key < end_key; key++)
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100415 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
416 BPF_NOEXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800417
418 /* Lookup key 1 to tgt_free*3/2 */
419 end_key = tgt_free + batch_size;
420 for (key = 1; key < end_key; key++) {
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100421 assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100422 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
423 BPF_NOEXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800424 }
425
426 /* Add 1+2*tgt_free to tgt_free*5/2
427 * (+tgt_free/2 keys)
428 */
429 key = 2 * tgt_free + 1;
430 end_key = key + batch_size;
431 for (; key < end_key; key++) {
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100432 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
433 BPF_NOEXIST));
434 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
435 BPF_NOEXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800436 }
437
438 assert(map_equal(lru_map_fd, expected_map_fd));
439
440 close(expected_map_fd);
441 close(lru_map_fd);
442
443 printf("Pass\n");
444}
445
446/* Test deletion */
447static void test_lru_sanity4(int map_type, int map_flags, unsigned int tgt_free)
448{
449 int lru_map_fd, expected_map_fd;
450 unsigned long long key, value[nr_cpus];
451 unsigned long long end_key;
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -0800452 int next_cpu = 0;
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800453
454 printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
455 map_flags);
456
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -0800457 assert(sched_next_online(0, &next_cpu) != -1);
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800458
459 if (map_flags & BPF_F_NO_COMMON_LRU)
460 lru_map_fd = create_map(map_type, map_flags,
461 3 * tgt_free * nr_cpus);
462 else
463 lru_map_fd = create_map(map_type, map_flags, 3 * tgt_free);
464 assert(lru_map_fd != -1);
465
466 expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0,
467 3 * tgt_free);
468 assert(expected_map_fd != -1);
469
470 value[0] = 1234;
471
472 for (key = 1; key <= 2 * tgt_free; key++)
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100473 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
474 BPF_NOEXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800475
476 key = 1;
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100477 assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800478
479 for (key = 1; key <= tgt_free; key++) {
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100480 assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100481 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
482 BPF_NOEXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800483 }
484
485 for (; key <= 2 * tgt_free; key++) {
486 assert(!bpf_map_delete(lru_map_fd, &key));
487 assert(bpf_map_delete(lru_map_fd, &key));
488 }
489
490 end_key = key + 2 * tgt_free;
491 for (; key < end_key; key++) {
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100492 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
493 BPF_NOEXIST));
494 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
495 BPF_NOEXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800496 }
497
498 assert(map_equal(lru_map_fd, expected_map_fd));
499
500 close(expected_map_fd);
501 close(lru_map_fd);
502
503 printf("Pass\n");
504}
505
506static void do_test_lru_sanity5(unsigned long long last_key, int map_fd)
507{
508 unsigned long long key, value[nr_cpus];
509
510 /* Ensure the last key inserted by previous CPU can be found */
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100511 assert(!bpf_map_lookup_elem(map_fd, &last_key, value));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800512
513 value[0] = 1234;
514
515 key = last_key + 1;
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100516 assert(!bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST));
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100517 assert(!bpf_map_lookup_elem(map_fd, &key, value));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800518
519 /* Cannot find the last key because it was removed by LRU */
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100520 assert(bpf_map_lookup_elem(map_fd, &last_key, value));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800521}
522
523/* Test map with only one element */
524static void test_lru_sanity5(int map_type, int map_flags)
525{
526 unsigned long long key, value[nr_cpus];
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -0800527 int next_cpu = 0;
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800528 int map_fd;
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800529
530 if (map_flags & BPF_F_NO_COMMON_LRU)
531 return;
532
533 printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
534 map_flags);
535
536 map_fd = create_map(map_type, map_flags, 1);
537 assert(map_fd != -1);
538
539 value[0] = 1234;
540 key = 0;
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100541 assert(!bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800542
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -0800543 while (sched_next_online(0, &next_cpu) != -1) {
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800544 pid_t pid;
545
546 pid = fork();
547 if (pid == 0) {
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -0800548 do_test_lru_sanity5(key, map_fd);
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800549 exit(0);
550 } else if (pid == -1) {
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -0800551 printf("couldn't spawn process to test key:%llu\n",
552 key);
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800553 exit(1);
554 } else {
555 int status;
556
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800557 assert(waitpid(pid, &status, 0) == pid);
558 assert(status == 0);
559 key++;
560 }
561 }
562
563 close(map_fd);
Martin KaFai Lau3fbfadc2017-01-16 22:17:29 -0800564 /* At least one key should be tested */
565 assert(key > 0);
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800566
567 printf("Pass\n");
568}
569
570int main(int argc, char **argv)
571{
572 struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
573 int map_types[] = {BPF_MAP_TYPE_LRU_HASH,
574 BPF_MAP_TYPE_LRU_PERCPU_HASH};
575 int map_flags[] = {0, BPF_F_NO_COMMON_LRU};
576 int t, f;
577
578 setbuf(stdout, NULL);
579
580 assert(!setrlimit(RLIMIT_MEMLOCK, &r));
581
Daniel Borkmanne00c7b22016-11-26 01:28:09 +0100582 nr_cpus = bpf_num_possible_cpus();
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800583 assert(nr_cpus != -1);
584 printf("nr_cpus:%d\n\n", nr_cpus);
585
586 for (f = 0; f < sizeof(map_flags) / sizeof(*map_flags); f++) {
587 unsigned int tgt_free = (map_flags[f] & BPF_F_NO_COMMON_LRU) ?
588 PERCPU_FREE_TARGET : LOCAL_FREE_TARGET;
589
590 for (t = 0; t < sizeof(map_types) / sizeof(*map_types); t++) {
591 test_lru_sanity0(map_types[t], map_flags[f]);
592 test_lru_sanity1(map_types[t], map_flags[f], tgt_free);
593 test_lru_sanity2(map_types[t], map_flags[f], tgt_free);
594 test_lru_sanity3(map_types[t], map_flags[f], tgt_free);
595 test_lru_sanity4(map_types[t], map_flags[f], tgt_free);
596 test_lru_sanity5(map_types[t], map_flags[f]);
597
598 printf("\n");
599 }
600 }
601
602 return 0;
603}