125763b3cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25db58fafSMartin KaFai Lau /*
35db58fafSMartin KaFai Lau * Copyright (c) 2016 Facebook
45db58fafSMartin KaFai Lau */
55db58fafSMartin KaFai Lau #define _GNU_SOURCE
65db58fafSMartin KaFai Lau #include <stdio.h>
75db58fafSMartin KaFai Lau #include <unistd.h>
85db58fafSMartin KaFai Lau #include <errno.h>
95db58fafSMartin KaFai Lau #include <string.h>
105db58fafSMartin KaFai Lau #include <assert.h>
115db58fafSMartin KaFai Lau #include <sched.h>
125db58fafSMartin KaFai Lau #include <stdlib.h>
135db58fafSMartin KaFai Lau #include <time.h>
14e00c7b21SDaniel Borkmann
15e00c7b21SDaniel Borkmann #include <sys/wait.h>
16e00c7b21SDaniel Borkmann
1710ecc728SMickaël Salaün #include <bpf/bpf.h>
18d2baab62SDaniel Borkmann #include <bpf/libbpf.h>
19fe8d662aSDaniel Borkmann
20e00c7b21SDaniel Borkmann #include "bpf_util.h"
21d2baab62SDaniel Borkmann #include "../../../include/linux/filter.h"
225db58fafSMartin KaFai Lau
235db58fafSMartin KaFai Lau #define LOCAL_FREE_TARGET (128)
24695ba265SMartin KaFai Lau #define PERCPU_FREE_TARGET (4)
255db58fafSMartin KaFai Lau
265db58fafSMartin KaFai Lau static int nr_cpus;
275db58fafSMartin KaFai Lau
create_map(int map_type,int map_flags,unsigned int size)285db58fafSMartin KaFai Lau static int create_map(int map_type, int map_flags, unsigned int size)
295db58fafSMartin KaFai Lau {
302fe256a4SAndrii Nakryiko LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = map_flags);
315db58fafSMartin KaFai Lau int map_fd;
325db58fafSMartin KaFai Lau
332fe256a4SAndrii Nakryiko map_fd = bpf_map_create(map_type, NULL, sizeof(unsigned long long),
342fe256a4SAndrii Nakryiko sizeof(unsigned long long), size, &opts);
355db58fafSMartin KaFai Lau
365db58fafSMartin KaFai Lau if (map_fd == -1)
372fe256a4SAndrii Nakryiko perror("bpf_map_create");
385db58fafSMartin KaFai Lau
395db58fafSMartin KaFai Lau return map_fd;
405db58fafSMartin KaFai Lau }
415db58fafSMartin KaFai Lau
bpf_map_lookup_elem_with_ref_bit(int fd,unsigned long long key,void * value)42d2baab62SDaniel Borkmann static int bpf_map_lookup_elem_with_ref_bit(int fd, unsigned long long key,
43d2baab62SDaniel Borkmann void *value)
44d2baab62SDaniel Borkmann {
45d2baab62SDaniel Borkmann struct bpf_insn insns[] = {
46d2baab62SDaniel Borkmann BPF_LD_MAP_VALUE(BPF_REG_9, 0, 0),
47d2baab62SDaniel Borkmann BPF_LD_MAP_FD(BPF_REG_1, fd),
48d2baab62SDaniel Borkmann BPF_LD_IMM64(BPF_REG_3, key),
49d2baab62SDaniel Borkmann BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
50d2baab62SDaniel Borkmann BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
51d2baab62SDaniel Borkmann BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, 0),
52d2baab62SDaniel Borkmann BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
53d2baab62SDaniel Borkmann BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
54d2baab62SDaniel Borkmann BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0),
55d2baab62SDaniel Borkmann BPF_STX_MEM(BPF_DW, BPF_REG_9, BPF_REG_1, 0),
56d2baab62SDaniel Borkmann BPF_MOV64_IMM(BPF_REG_0, 42),
57d2baab62SDaniel Borkmann BPF_JMP_IMM(BPF_JA, 0, 0, 1),
58d2baab62SDaniel Borkmann BPF_MOV64_IMM(BPF_REG_0, 1),
59d2baab62SDaniel Borkmann BPF_EXIT_INSN(),
60d2baab62SDaniel Borkmann };
61d2baab62SDaniel Borkmann __u8 data[64] = {};
62d2baab62SDaniel Borkmann int mfd, pfd, ret, zero = 0;
6304fcb5f9SDelyan Kratunov LIBBPF_OPTS(bpf_test_run_opts, topts,
6404fcb5f9SDelyan Kratunov .data_in = data,
6504fcb5f9SDelyan Kratunov .data_size_in = sizeof(data),
6604fcb5f9SDelyan Kratunov .repeat = 1,
6704fcb5f9SDelyan Kratunov );
68d2baab62SDaniel Borkmann
692fe256a4SAndrii Nakryiko mfd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, sizeof(int), sizeof(__u64), 1, NULL);
70d2baab62SDaniel Borkmann if (mfd < 0)
71d2baab62SDaniel Borkmann return -1;
72d2baab62SDaniel Borkmann
73d2baab62SDaniel Borkmann insns[0].imm = mfd;
74d2baab62SDaniel Borkmann
75d8e86407SAndrii Nakryiko pfd = bpf_prog_load(BPF_PROG_TYPE_SCHED_CLS, NULL, "GPL", insns, ARRAY_SIZE(insns), NULL);
76d2baab62SDaniel Borkmann if (pfd < 0) {
77d2baab62SDaniel Borkmann close(mfd);
78d2baab62SDaniel Borkmann return -1;
79d2baab62SDaniel Borkmann }
80d2baab62SDaniel Borkmann
8104fcb5f9SDelyan Kratunov ret = bpf_prog_test_run_opts(pfd, &topts);
8204fcb5f9SDelyan Kratunov if (ret < 0 || topts.retval != 42) {
83d2baab62SDaniel Borkmann ret = -1;
84d2baab62SDaniel Borkmann } else {
85d2baab62SDaniel Borkmann assert(!bpf_map_lookup_elem(mfd, &zero, value));
86d2baab62SDaniel Borkmann ret = 0;
87d2baab62SDaniel Borkmann }
88d2baab62SDaniel Borkmann close(pfd);
89d2baab62SDaniel Borkmann close(mfd);
90d2baab62SDaniel Borkmann return ret;
91d2baab62SDaniel Borkmann }
92d2baab62SDaniel Borkmann
map_subset(int map0,int map1)935db58fafSMartin KaFai Lau static int map_subset(int map0, int map1)
945db58fafSMartin KaFai Lau {
955db58fafSMartin KaFai Lau unsigned long long next_key = 0;
965db58fafSMartin KaFai Lau unsigned long long value0[nr_cpus], value1[nr_cpus];
975db58fafSMartin KaFai Lau int ret;
985db58fafSMartin KaFai Lau
995f155c25SMickaël Salaün while (!bpf_map_get_next_key(map1, &next_key, &next_key)) {
100e5ff7c40SMickaël Salaün assert(!bpf_map_lookup_elem(map1, &next_key, value1));
101e5ff7c40SMickaël Salaün ret = bpf_map_lookup_elem(map0, &next_key, value0);
1025db58fafSMartin KaFai Lau if (ret) {
1035db58fafSMartin KaFai Lau printf("key:%llu not found from map. %s(%d)\n",
1045db58fafSMartin KaFai Lau next_key, strerror(errno), errno);
1055db58fafSMartin KaFai Lau return 0;
1065db58fafSMartin KaFai Lau }
1075db58fafSMartin KaFai Lau if (value0[0] != value1[0]) {
1085db58fafSMartin KaFai Lau printf("key:%llu value0:%llu != value1:%llu\n",
1095db58fafSMartin KaFai Lau next_key, value0[0], value1[0]);
1105db58fafSMartin KaFai Lau return 0;
1115db58fafSMartin KaFai Lau }
1125db58fafSMartin KaFai Lau }
1135db58fafSMartin KaFai Lau return 1;
1145db58fafSMartin KaFai Lau }
1155db58fafSMartin KaFai Lau
map_equal(int lru_map,int expected)1165db58fafSMartin KaFai Lau static int map_equal(int lru_map, int expected)
1175db58fafSMartin KaFai Lau {
1185db58fafSMartin KaFai Lau return map_subset(lru_map, expected) && map_subset(expected, lru_map);
1195db58fafSMartin KaFai Lau }
1205db58fafSMartin KaFai Lau
sched_next_online(int pid,int * next_to_try)1213fbfadceSMartin KaFai Lau static int sched_next_online(int pid, int *next_to_try)
1225db58fafSMartin KaFai Lau {
1235db58fafSMartin KaFai Lau cpu_set_t cpuset;
1243fbfadceSMartin KaFai Lau int next = *next_to_try;
1253fbfadceSMartin KaFai Lau int ret = -1;
1265db58fafSMartin KaFai Lau
1273fbfadceSMartin KaFai Lau while (next < nr_cpus) {
1285db58fafSMartin KaFai Lau CPU_ZERO(&cpuset);
129*99c03869STony Ambardar CPU_SET(next, &cpuset);
130*99c03869STony Ambardar next++;
1313fbfadceSMartin KaFai Lau if (!sched_setaffinity(pid, sizeof(cpuset), &cpuset)) {
1323fbfadceSMartin KaFai Lau ret = 0;
1335db58fafSMartin KaFai Lau break;
1345db58fafSMartin KaFai Lau }
1353fbfadceSMartin KaFai Lau }
1365db58fafSMartin KaFai Lau
1373fbfadceSMartin KaFai Lau *next_to_try = next;
1383fbfadceSMartin KaFai Lau return ret;
1395db58fafSMartin KaFai Lau }
1405db58fafSMartin KaFai Lau
141d2baab62SDaniel Borkmann /* Size of the LRU map is 2
1425db58fafSMartin KaFai Lau * Add key=1 (+1 key)
1435db58fafSMartin KaFai Lau * Add key=2 (+1 key)
1445db58fafSMartin KaFai Lau * Lookup Key=1
1455db58fafSMartin KaFai Lau * Add Key=3
1465db58fafSMartin KaFai Lau * => Key=2 will be removed by LRU
1475db58fafSMartin KaFai Lau * Iterate map. Only found key=1 and key=3
1485db58fafSMartin KaFai Lau */
test_lru_sanity0(int map_type,int map_flags)1495db58fafSMartin KaFai Lau static void test_lru_sanity0(int map_type, int map_flags)
1505db58fafSMartin KaFai Lau {
1515db58fafSMartin KaFai Lau unsigned long long key, value[nr_cpus];
1525db58fafSMartin KaFai Lau int lru_map_fd, expected_map_fd;
1533fbfadceSMartin KaFai Lau int next_cpu = 0;
1545db58fafSMartin KaFai Lau
1555db58fafSMartin KaFai Lau printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
1565db58fafSMartin KaFai Lau map_flags);
1575db58fafSMartin KaFai Lau
1583fbfadceSMartin KaFai Lau assert(sched_next_online(0, &next_cpu) != -1);
1595db58fafSMartin KaFai Lau
1605db58fafSMartin KaFai Lau if (map_flags & BPF_F_NO_COMMON_LRU)
1615db58fafSMartin KaFai Lau lru_map_fd = create_map(map_type, map_flags, 2 * nr_cpus);
1625db58fafSMartin KaFai Lau else
1635db58fafSMartin KaFai Lau lru_map_fd = create_map(map_type, map_flags, 2);
1645db58fafSMartin KaFai Lau assert(lru_map_fd != -1);
1655db58fafSMartin KaFai Lau
1665db58fafSMartin KaFai Lau expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, 2);
1675db58fafSMartin KaFai Lau assert(expected_map_fd != -1);
1685db58fafSMartin KaFai Lau
1695db58fafSMartin KaFai Lau value[0] = 1234;
1705db58fafSMartin KaFai Lau
1715db58fafSMartin KaFai Lau /* insert key=1 element */
1725db58fafSMartin KaFai Lau
1735db58fafSMartin KaFai Lau key = 1;
17410ecc728SMickaël Salaün assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
17510ecc728SMickaël Salaün assert(!bpf_map_update_elem(expected_map_fd, &key, value,
17610ecc728SMickaël Salaün BPF_NOEXIST));
1775db58fafSMartin KaFai Lau
1785db58fafSMartin KaFai Lau /* BPF_NOEXIST means: add new element if it doesn't exist */
179c14766a8SArtem Savkov assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST) == -EEXIST);
1805db58fafSMartin KaFai Lau /* key=1 already exists */
1815db58fafSMartin KaFai Lau
182c14766a8SArtem Savkov assert(bpf_map_update_elem(lru_map_fd, &key, value, -1) == -EINVAL);
1835db58fafSMartin KaFai Lau
1845db58fafSMartin KaFai Lau /* insert key=2 element */
1855db58fafSMartin KaFai Lau
1865db58fafSMartin KaFai Lau /* check that key=2 is not found */
1875db58fafSMartin KaFai Lau key = 2;
188c14766a8SArtem Savkov assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
1895db58fafSMartin KaFai Lau
1905db58fafSMartin KaFai Lau /* BPF_EXIST means: update existing element */
191c14766a8SArtem Savkov assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_EXIST) == -ENOENT);
1925db58fafSMartin KaFai Lau /* key=2 is not there */
1935db58fafSMartin KaFai Lau
19410ecc728SMickaël Salaün assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
1955db58fafSMartin KaFai Lau
1965db58fafSMartin KaFai Lau /* insert key=3 element */
1975db58fafSMartin KaFai Lau
1985db58fafSMartin KaFai Lau /* check that key=3 is not found */
1995db58fafSMartin KaFai Lau key = 3;
200c14766a8SArtem Savkov assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
2015db58fafSMartin KaFai Lau
2025db58fafSMartin KaFai Lau /* check that key=1 can be found and mark the ref bit to
2035db58fafSMartin KaFai Lau * stop LRU from removing key=1
2045db58fafSMartin KaFai Lau */
2055db58fafSMartin KaFai Lau key = 1;
206d2baab62SDaniel Borkmann assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
2075db58fafSMartin KaFai Lau assert(value[0] == 1234);
2085db58fafSMartin KaFai Lau
2095db58fafSMartin KaFai Lau key = 3;
21010ecc728SMickaël Salaün assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
21110ecc728SMickaël Salaün assert(!bpf_map_update_elem(expected_map_fd, &key, value,
21210ecc728SMickaël Salaün BPF_NOEXIST));
2135db58fafSMartin KaFai Lau
2145db58fafSMartin KaFai Lau /* key=2 has been removed from the LRU */
2155db58fafSMartin KaFai Lau key = 2;
216c14766a8SArtem Savkov assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
2175db58fafSMartin KaFai Lau
21849c299b6SDenis Salopek /* lookup elem key=1 and delete it, then check it doesn't exist */
21949c299b6SDenis Salopek key = 1;
22049c299b6SDenis Salopek assert(!bpf_map_lookup_and_delete_elem(lru_map_fd, &key, &value));
22149c299b6SDenis Salopek assert(value[0] == 1234);
22249c299b6SDenis Salopek
22349c299b6SDenis Salopek /* remove the same element from the expected map */
22449c299b6SDenis Salopek assert(!bpf_map_delete_elem(expected_map_fd, &key));
22549c299b6SDenis Salopek
2265db58fafSMartin KaFai Lau assert(map_equal(lru_map_fd, expected_map_fd));
2275db58fafSMartin KaFai Lau
2285db58fafSMartin KaFai Lau close(expected_map_fd);
2295db58fafSMartin KaFai Lau close(lru_map_fd);
2305db58fafSMartin KaFai Lau
2315db58fafSMartin KaFai Lau printf("Pass\n");
2325db58fafSMartin KaFai Lau }
2335db58fafSMartin KaFai Lau
2345db58fafSMartin KaFai Lau /* Size of the LRU map is 1.5*tgt_free
2355db58fafSMartin KaFai Lau * Insert 1 to tgt_free (+tgt_free keys)
2365db58fafSMartin KaFai Lau * Lookup 1 to tgt_free/2
2375db58fafSMartin KaFai Lau * Insert 1+tgt_free to 2*tgt_free (+tgt_free keys)
2385db58fafSMartin KaFai Lau * => 1+tgt_free/2 to LOCALFREE_TARGET will be removed by LRU
2395db58fafSMartin KaFai Lau */
test_lru_sanity1(int map_type,int map_flags,unsigned int tgt_free)2405db58fafSMartin KaFai Lau static void test_lru_sanity1(int map_type, int map_flags, unsigned int tgt_free)
2415db58fafSMartin KaFai Lau {
2425db58fafSMartin KaFai Lau unsigned long long key, end_key, value[nr_cpus];
2435db58fafSMartin KaFai Lau int lru_map_fd, expected_map_fd;
2445db58fafSMartin KaFai Lau unsigned int batch_size;
2455db58fafSMartin KaFai Lau unsigned int map_size;
2463fbfadceSMartin KaFai Lau int next_cpu = 0;
2475db58fafSMartin KaFai Lau
2485db58fafSMartin KaFai Lau if (map_flags & BPF_F_NO_COMMON_LRU)
2496467acbcSMartin KaFai Lau /* This test is only applicable to common LRU list */
2505db58fafSMartin KaFai Lau return;
2515db58fafSMartin KaFai Lau
2525db58fafSMartin KaFai Lau printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
2535db58fafSMartin KaFai Lau map_flags);
2545db58fafSMartin KaFai Lau
2553fbfadceSMartin KaFai Lau assert(sched_next_online(0, &next_cpu) != -1);
2565db58fafSMartin KaFai Lau
2575db58fafSMartin KaFai Lau batch_size = tgt_free / 2;
2585db58fafSMartin KaFai Lau assert(batch_size * 2 == tgt_free);
2595db58fafSMartin KaFai Lau
2605db58fafSMartin KaFai Lau map_size = tgt_free + batch_size;
2615db58fafSMartin KaFai Lau lru_map_fd = create_map(map_type, map_flags, map_size);
2625db58fafSMartin KaFai Lau assert(lru_map_fd != -1);
2635db58fafSMartin KaFai Lau
2645db58fafSMartin KaFai Lau expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size);
2655db58fafSMartin KaFai Lau assert(expected_map_fd != -1);
2665db58fafSMartin KaFai Lau
2675db58fafSMartin KaFai Lau value[0] = 1234;
2685db58fafSMartin KaFai Lau
2695db58fafSMartin KaFai Lau /* Insert 1 to tgt_free (+tgt_free keys) */
2705db58fafSMartin KaFai Lau end_key = 1 + tgt_free;
2715db58fafSMartin KaFai Lau for (key = 1; key < end_key; key++)
27210ecc728SMickaël Salaün assert(!bpf_map_update_elem(lru_map_fd, &key, value,
27310ecc728SMickaël Salaün BPF_NOEXIST));
2745db58fafSMartin KaFai Lau
2755db58fafSMartin KaFai Lau /* Lookup 1 to tgt_free/2 */
2765db58fafSMartin KaFai Lau end_key = 1 + batch_size;
2775db58fafSMartin KaFai Lau for (key = 1; key < end_key; key++) {
278d2baab62SDaniel Borkmann assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
27910ecc728SMickaël Salaün assert(!bpf_map_update_elem(expected_map_fd, &key, value,
2805db58fafSMartin KaFai Lau BPF_NOEXIST));
2815db58fafSMartin KaFai Lau }
2825db58fafSMartin KaFai Lau
2835db58fafSMartin KaFai Lau /* Insert 1+tgt_free to 2*tgt_free
2845db58fafSMartin KaFai Lau * => 1+tgt_free/2 to LOCALFREE_TARGET will be
2855db58fafSMartin KaFai Lau * removed by LRU
2865db58fafSMartin KaFai Lau */
2875db58fafSMartin KaFai Lau key = 1 + tgt_free;
2885db58fafSMartin KaFai Lau end_key = key + tgt_free;
2895db58fafSMartin KaFai Lau for (; key < end_key; key++) {
29010ecc728SMickaël Salaün assert(!bpf_map_update_elem(lru_map_fd, &key, value,
29110ecc728SMickaël Salaün BPF_NOEXIST));
29210ecc728SMickaël Salaün assert(!bpf_map_update_elem(expected_map_fd, &key, value,
2935db58fafSMartin KaFai Lau BPF_NOEXIST));
2945db58fafSMartin KaFai Lau }
2955db58fafSMartin KaFai Lau
2965db58fafSMartin KaFai Lau assert(map_equal(lru_map_fd, expected_map_fd));
2975db58fafSMartin KaFai Lau
2985db58fafSMartin KaFai Lau close(expected_map_fd);
2995db58fafSMartin KaFai Lau close(lru_map_fd);
3005db58fafSMartin KaFai Lau
3015db58fafSMartin KaFai Lau printf("Pass\n");
3025db58fafSMartin KaFai Lau }
3035db58fafSMartin KaFai Lau
3045db58fafSMartin KaFai Lau /* Size of the LRU map 1.5 * tgt_free
3055db58fafSMartin KaFai Lau * Insert 1 to tgt_free (+tgt_free keys)
3065db58fafSMartin KaFai Lau * Update 1 to tgt_free/2
3075db58fafSMartin KaFai Lau * => The original 1 to tgt_free/2 will be removed due to
3085db58fafSMartin KaFai Lau * the LRU shrink process
3095db58fafSMartin KaFai Lau * Re-insert 1 to tgt_free/2 again and do a lookup immeidately
3105db58fafSMartin KaFai Lau * Insert 1+tgt_free to tgt_free*3/2
3115db58fafSMartin KaFai Lau * Insert 1+tgt_free*3/2 to tgt_free*5/2
3125db58fafSMartin KaFai Lau * => Key 1+tgt_free to tgt_free*3/2
3135db58fafSMartin KaFai Lau * will be removed from LRU because it has never
3145db58fafSMartin KaFai Lau * been lookup and ref bit is not set
3155db58fafSMartin KaFai Lau */
test_lru_sanity2(int map_type,int map_flags,unsigned int tgt_free)3165db58fafSMartin KaFai Lau static void test_lru_sanity2(int map_type, int map_flags, unsigned int tgt_free)
3175db58fafSMartin KaFai Lau {
3185db58fafSMartin KaFai Lau unsigned long long key, value[nr_cpus];
3195db58fafSMartin KaFai Lau unsigned long long end_key;
3205db58fafSMartin KaFai Lau int lru_map_fd, expected_map_fd;
3215db58fafSMartin KaFai Lau unsigned int batch_size;
3225db58fafSMartin KaFai Lau unsigned int map_size;
3233fbfadceSMartin KaFai Lau int next_cpu = 0;
3245db58fafSMartin KaFai Lau
3255db58fafSMartin KaFai Lau if (map_flags & BPF_F_NO_COMMON_LRU)
3266467acbcSMartin KaFai Lau /* This test is only applicable to common LRU list */
3275db58fafSMartin KaFai Lau return;
3285db58fafSMartin KaFai Lau
3295db58fafSMartin KaFai Lau printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
3305db58fafSMartin KaFai Lau map_flags);
3315db58fafSMartin KaFai Lau
3323fbfadceSMartin KaFai Lau assert(sched_next_online(0, &next_cpu) != -1);
3335db58fafSMartin KaFai Lau
3345db58fafSMartin KaFai Lau batch_size = tgt_free / 2;
3355db58fafSMartin KaFai Lau assert(batch_size * 2 == tgt_free);
3365db58fafSMartin KaFai Lau
3375db58fafSMartin KaFai Lau map_size = tgt_free + batch_size;
3385db58fafSMartin KaFai Lau lru_map_fd = create_map(map_type, map_flags, map_size);
3395db58fafSMartin KaFai Lau assert(lru_map_fd != -1);
3405db58fafSMartin KaFai Lau
3415db58fafSMartin KaFai Lau expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size);
3425db58fafSMartin KaFai Lau assert(expected_map_fd != -1);
3435db58fafSMartin KaFai Lau
3445db58fafSMartin KaFai Lau value[0] = 1234;
3455db58fafSMartin KaFai Lau
3465db58fafSMartin KaFai Lau /* Insert 1 to tgt_free (+tgt_free keys) */
3475db58fafSMartin KaFai Lau end_key = 1 + tgt_free;
3485db58fafSMartin KaFai Lau for (key = 1; key < end_key; key++)
34910ecc728SMickaël Salaün assert(!bpf_map_update_elem(lru_map_fd, &key, value,
35010ecc728SMickaël Salaün BPF_NOEXIST));
3515db58fafSMartin KaFai Lau
35210ecc728SMickaël Salaün /* Any bpf_map_update_elem will require to acquire a new node
3535db58fafSMartin KaFai Lau * from LRU first.
3545db58fafSMartin KaFai Lau *
3555db58fafSMartin KaFai Lau * The local list is running out of free nodes.
3565db58fafSMartin KaFai Lau * It gets from the global LRU list which tries to
3575db58fafSMartin KaFai Lau * shrink the inactive list to get tgt_free
3585db58fafSMartin KaFai Lau * number of free nodes.
3595db58fafSMartin KaFai Lau *
3605db58fafSMartin KaFai Lau * Hence, the oldest key 1 to tgt_free/2
3615db58fafSMartin KaFai Lau * are removed from the LRU list.
3625db58fafSMartin KaFai Lau */
3635db58fafSMartin KaFai Lau key = 1;
3645db58fafSMartin KaFai Lau if (map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
36510ecc728SMickaël Salaün assert(!bpf_map_update_elem(lru_map_fd, &key, value,
36610ecc728SMickaël Salaün BPF_NOEXIST));
367e58383b8SMickaël Salaün assert(!bpf_map_delete_elem(lru_map_fd, &key));
3685db58fafSMartin KaFai Lau } else {
36910ecc728SMickaël Salaün assert(bpf_map_update_elem(lru_map_fd, &key, value,
37010ecc728SMickaël Salaün BPF_EXIST));
3715db58fafSMartin KaFai Lau }
3725db58fafSMartin KaFai Lau
3735db58fafSMartin KaFai Lau /* Re-insert 1 to tgt_free/2 again and do a lookup
3745db58fafSMartin KaFai Lau * immeidately.
3755db58fafSMartin KaFai Lau */
3765db58fafSMartin KaFai Lau end_key = 1 + batch_size;
3775db58fafSMartin KaFai Lau value[0] = 4321;
3785db58fafSMartin KaFai Lau for (key = 1; key < end_key; key++) {
379c14766a8SArtem Savkov assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
38010ecc728SMickaël Salaün assert(!bpf_map_update_elem(lru_map_fd, &key, value,
38110ecc728SMickaël Salaün BPF_NOEXIST));
382d2baab62SDaniel Borkmann assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
3835db58fafSMartin KaFai Lau assert(value[0] == 4321);
38410ecc728SMickaël Salaün assert(!bpf_map_update_elem(expected_map_fd, &key, value,
3855db58fafSMartin KaFai Lau BPF_NOEXIST));
3865db58fafSMartin KaFai Lau }
3875db58fafSMartin KaFai Lau
3885db58fafSMartin KaFai Lau value[0] = 1234;
3895db58fafSMartin KaFai Lau
3905db58fafSMartin KaFai Lau /* Insert 1+tgt_free to tgt_free*3/2 */
3915db58fafSMartin KaFai Lau end_key = 1 + tgt_free + batch_size;
3925db58fafSMartin KaFai Lau for (key = 1 + tgt_free; key < end_key; key++)
3935db58fafSMartin KaFai Lau /* These newly added but not referenced keys will be
3945db58fafSMartin KaFai Lau * gone during the next LRU shrink.
3955db58fafSMartin KaFai Lau */
39610ecc728SMickaël Salaün assert(!bpf_map_update_elem(lru_map_fd, &key, value,
39710ecc728SMickaël Salaün BPF_NOEXIST));
3985db58fafSMartin KaFai Lau
3995db58fafSMartin KaFai Lau /* Insert 1+tgt_free*3/2 to tgt_free*5/2 */
4005db58fafSMartin KaFai Lau end_key = key + tgt_free;
4015db58fafSMartin KaFai Lau for (; key < end_key; key++) {
40210ecc728SMickaël Salaün assert(!bpf_map_update_elem(lru_map_fd, &key, value,
40310ecc728SMickaël Salaün BPF_NOEXIST));
40410ecc728SMickaël Salaün assert(!bpf_map_update_elem(expected_map_fd, &key, value,
4055db58fafSMartin KaFai Lau BPF_NOEXIST));
4065db58fafSMartin KaFai Lau }
4075db58fafSMartin KaFai Lau
4085db58fafSMartin KaFai Lau assert(map_equal(lru_map_fd, expected_map_fd));
4095db58fafSMartin KaFai Lau
4105db58fafSMartin KaFai Lau close(expected_map_fd);
4115db58fafSMartin KaFai Lau close(lru_map_fd);
4125db58fafSMartin KaFai Lau
4135db58fafSMartin KaFai Lau printf("Pass\n");
4145db58fafSMartin KaFai Lau }
4155db58fafSMartin KaFai Lau
4165db58fafSMartin KaFai Lau /* Size of the LRU map is 2*tgt_free
4175db58fafSMartin KaFai Lau * It is to test the active/inactive list rotation
4185db58fafSMartin KaFai Lau * Insert 1 to 2*tgt_free (+2*tgt_free keys)
4195db58fafSMartin KaFai Lau * Lookup key 1 to tgt_free*3/2
4205db58fafSMartin KaFai Lau * Add 1+2*tgt_free to tgt_free*5/2 (+tgt_free/2 keys)
4215db58fafSMartin KaFai Lau * => key 1+tgt_free*3/2 to 2*tgt_free are removed from LRU
4225db58fafSMartin KaFai Lau */
test_lru_sanity3(int map_type,int map_flags,unsigned int tgt_free)4235db58fafSMartin KaFai Lau static void test_lru_sanity3(int map_type, int map_flags, unsigned int tgt_free)
4245db58fafSMartin KaFai Lau {
4255db58fafSMartin KaFai Lau unsigned long long key, end_key, value[nr_cpus];
4265db58fafSMartin KaFai Lau int lru_map_fd, expected_map_fd;
4275db58fafSMartin KaFai Lau unsigned int batch_size;
4285db58fafSMartin KaFai Lau unsigned int map_size;
4293fbfadceSMartin KaFai Lau int next_cpu = 0;
4305db58fafSMartin KaFai Lau
4319746f856SMartin KaFai Lau if (map_flags & BPF_F_NO_COMMON_LRU)
4329746f856SMartin KaFai Lau /* This test is only applicable to common LRU list */
4339746f856SMartin KaFai Lau return;
4349746f856SMartin KaFai Lau
4355db58fafSMartin KaFai Lau printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
4365db58fafSMartin KaFai Lau map_flags);
4375db58fafSMartin KaFai Lau
4383fbfadceSMartin KaFai Lau assert(sched_next_online(0, &next_cpu) != -1);
4395db58fafSMartin KaFai Lau
4405db58fafSMartin KaFai Lau batch_size = tgt_free / 2;
4415db58fafSMartin KaFai Lau assert(batch_size * 2 == tgt_free);
4425db58fafSMartin KaFai Lau
4435db58fafSMartin KaFai Lau map_size = tgt_free * 2;
4445db58fafSMartin KaFai Lau lru_map_fd = create_map(map_type, map_flags, map_size);
4455db58fafSMartin KaFai Lau assert(lru_map_fd != -1);
4465db58fafSMartin KaFai Lau
4475db58fafSMartin KaFai Lau expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size);
4485db58fafSMartin KaFai Lau assert(expected_map_fd != -1);
4495db58fafSMartin KaFai Lau
4505db58fafSMartin KaFai Lau value[0] = 1234;
4515db58fafSMartin KaFai Lau
4525db58fafSMartin KaFai Lau /* Insert 1 to 2*tgt_free (+2*tgt_free keys) */
4535db58fafSMartin KaFai Lau end_key = 1 + (2 * tgt_free);
4545db58fafSMartin KaFai Lau for (key = 1; key < end_key; key++)
45510ecc728SMickaël Salaün assert(!bpf_map_update_elem(lru_map_fd, &key, value,
45610ecc728SMickaël Salaün BPF_NOEXIST));
4575db58fafSMartin KaFai Lau
4585db58fafSMartin KaFai Lau /* Lookup key 1 to tgt_free*3/2 */
4595db58fafSMartin KaFai Lau end_key = tgt_free + batch_size;
4605db58fafSMartin KaFai Lau for (key = 1; key < end_key; key++) {
461d2baab62SDaniel Borkmann assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
46210ecc728SMickaël Salaün assert(!bpf_map_update_elem(expected_map_fd, &key, value,
4635db58fafSMartin KaFai Lau BPF_NOEXIST));
4645db58fafSMartin KaFai Lau }
4655db58fafSMartin KaFai Lau
4665db58fafSMartin KaFai Lau /* Add 1+2*tgt_free to tgt_free*5/2
4675db58fafSMartin KaFai Lau * (+tgt_free/2 keys)
4685db58fafSMartin KaFai Lau */
4695db58fafSMartin KaFai Lau key = 2 * tgt_free + 1;
4705db58fafSMartin KaFai Lau end_key = key + batch_size;
4715db58fafSMartin KaFai Lau for (; key < end_key; key++) {
47210ecc728SMickaël Salaün assert(!bpf_map_update_elem(lru_map_fd, &key, value,
47310ecc728SMickaël Salaün BPF_NOEXIST));
47410ecc728SMickaël Salaün assert(!bpf_map_update_elem(expected_map_fd, &key, value,
4755db58fafSMartin KaFai Lau BPF_NOEXIST));
4765db58fafSMartin KaFai Lau }
4775db58fafSMartin KaFai Lau
4785db58fafSMartin KaFai Lau assert(map_equal(lru_map_fd, expected_map_fd));
4795db58fafSMartin KaFai Lau
4805db58fafSMartin KaFai Lau close(expected_map_fd);
4815db58fafSMartin KaFai Lau close(lru_map_fd);
4825db58fafSMartin KaFai Lau
4835db58fafSMartin KaFai Lau printf("Pass\n");
4845db58fafSMartin KaFai Lau }
4855db58fafSMartin KaFai Lau
4865db58fafSMartin KaFai Lau /* Test deletion */
test_lru_sanity4(int map_type,int map_flags,unsigned int tgt_free)4875db58fafSMartin KaFai Lau static void test_lru_sanity4(int map_type, int map_flags, unsigned int tgt_free)
4885db58fafSMartin KaFai Lau {
4895db58fafSMartin KaFai Lau int lru_map_fd, expected_map_fd;
4905db58fafSMartin KaFai Lau unsigned long long key, value[nr_cpus];
4915db58fafSMartin KaFai Lau unsigned long long end_key;
4923fbfadceSMartin KaFai Lau int next_cpu = 0;
4935db58fafSMartin KaFai Lau
4945db58fafSMartin KaFai Lau printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
4955db58fafSMartin KaFai Lau map_flags);
4965db58fafSMartin KaFai Lau
4973fbfadceSMartin KaFai Lau assert(sched_next_online(0, &next_cpu) != -1);
4985db58fafSMartin KaFai Lau
4995db58fafSMartin KaFai Lau if (map_flags & BPF_F_NO_COMMON_LRU)
5005db58fafSMartin KaFai Lau lru_map_fd = create_map(map_type, map_flags,
5015db58fafSMartin KaFai Lau 3 * tgt_free * nr_cpus);
5025db58fafSMartin KaFai Lau else
5035db58fafSMartin KaFai Lau lru_map_fd = create_map(map_type, map_flags, 3 * tgt_free);
5045db58fafSMartin KaFai Lau assert(lru_map_fd != -1);
5055db58fafSMartin KaFai Lau
5065db58fafSMartin KaFai Lau expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0,
5075db58fafSMartin KaFai Lau 3 * tgt_free);
5085db58fafSMartin KaFai Lau assert(expected_map_fd != -1);
5095db58fafSMartin KaFai Lau
5105db58fafSMartin KaFai Lau value[0] = 1234;
5115db58fafSMartin KaFai Lau
5125db58fafSMartin KaFai Lau for (key = 1; key <= 2 * tgt_free; key++)
51310ecc728SMickaël Salaün assert(!bpf_map_update_elem(lru_map_fd, &key, value,
51410ecc728SMickaël Salaün BPF_NOEXIST));
5155db58fafSMartin KaFai Lau
5165db58fafSMartin KaFai Lau key = 1;
51710ecc728SMickaël Salaün assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
5185db58fafSMartin KaFai Lau
5195db58fafSMartin KaFai Lau for (key = 1; key <= tgt_free; key++) {
520d2baab62SDaniel Borkmann assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
52110ecc728SMickaël Salaün assert(!bpf_map_update_elem(expected_map_fd, &key, value,
5225db58fafSMartin KaFai Lau BPF_NOEXIST));
5235db58fafSMartin KaFai Lau }
5245db58fafSMartin KaFai Lau
5255db58fafSMartin KaFai Lau for (; key <= 2 * tgt_free; key++) {
526e58383b8SMickaël Salaün assert(!bpf_map_delete_elem(lru_map_fd, &key));
527e58383b8SMickaël Salaün assert(bpf_map_delete_elem(lru_map_fd, &key));
5285db58fafSMartin KaFai Lau }
5295db58fafSMartin KaFai Lau
5305db58fafSMartin KaFai Lau end_key = key + 2 * tgt_free;
5315db58fafSMartin KaFai Lau for (; key < end_key; key++) {
53210ecc728SMickaël Salaün assert(!bpf_map_update_elem(lru_map_fd, &key, value,
53310ecc728SMickaël Salaün BPF_NOEXIST));
53410ecc728SMickaël Salaün assert(!bpf_map_update_elem(expected_map_fd, &key, value,
5355db58fafSMartin KaFai Lau BPF_NOEXIST));
5365db58fafSMartin KaFai Lau }
5375db58fafSMartin KaFai Lau
5385db58fafSMartin KaFai Lau assert(map_equal(lru_map_fd, expected_map_fd));
5395db58fafSMartin KaFai Lau
5405db58fafSMartin KaFai Lau close(expected_map_fd);
5415db58fafSMartin KaFai Lau close(lru_map_fd);
5425db58fafSMartin KaFai Lau
5435db58fafSMartin KaFai Lau printf("Pass\n");
5445db58fafSMartin KaFai Lau }
5455db58fafSMartin KaFai Lau
do_test_lru_sanity5(unsigned long long last_key,int map_fd)5465db58fafSMartin KaFai Lau static void do_test_lru_sanity5(unsigned long long last_key, int map_fd)
5475db58fafSMartin KaFai Lau {
5485db58fafSMartin KaFai Lau unsigned long long key, value[nr_cpus];
5495db58fafSMartin KaFai Lau
5505db58fafSMartin KaFai Lau /* Ensure the last key inserted by previous CPU can be found */
551d2baab62SDaniel Borkmann assert(!bpf_map_lookup_elem_with_ref_bit(map_fd, last_key, value));
5525db58fafSMartin KaFai Lau value[0] = 1234;
5535db58fafSMartin KaFai Lau
5545db58fafSMartin KaFai Lau key = last_key + 1;
55510ecc728SMickaël Salaün assert(!bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST));
556d2baab62SDaniel Borkmann assert(!bpf_map_lookup_elem_with_ref_bit(map_fd, key, value));
5575db58fafSMartin KaFai Lau
5585db58fafSMartin KaFai Lau /* Cannot find the last key because it was removed by LRU */
559c14766a8SArtem Savkov assert(bpf_map_lookup_elem(map_fd, &last_key, value) == -ENOENT);
5605db58fafSMartin KaFai Lau }
5615db58fafSMartin KaFai Lau
5625db58fafSMartin KaFai Lau /* Test map with only one element */
test_lru_sanity5(int map_type,int map_flags)5635db58fafSMartin KaFai Lau static void test_lru_sanity5(int map_type, int map_flags)
5645db58fafSMartin KaFai Lau {
5655db58fafSMartin KaFai Lau unsigned long long key, value[nr_cpus];
5663fbfadceSMartin KaFai Lau int next_cpu = 0;
5675db58fafSMartin KaFai Lau int map_fd;
5685db58fafSMartin KaFai Lau
5695db58fafSMartin KaFai Lau if (map_flags & BPF_F_NO_COMMON_LRU)
5705db58fafSMartin KaFai Lau return;
5715db58fafSMartin KaFai Lau
5725db58fafSMartin KaFai Lau printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
5735db58fafSMartin KaFai Lau map_flags);
5745db58fafSMartin KaFai Lau
5755db58fafSMartin KaFai Lau map_fd = create_map(map_type, map_flags, 1);
5765db58fafSMartin KaFai Lau assert(map_fd != -1);
5775db58fafSMartin KaFai Lau
5785db58fafSMartin KaFai Lau value[0] = 1234;
5795db58fafSMartin KaFai Lau key = 0;
58010ecc728SMickaël Salaün assert(!bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST));
5815db58fafSMartin KaFai Lau
5823fbfadceSMartin KaFai Lau while (sched_next_online(0, &next_cpu) != -1) {
5835db58fafSMartin KaFai Lau pid_t pid;
5845db58fafSMartin KaFai Lau
5855db58fafSMartin KaFai Lau pid = fork();
5865db58fafSMartin KaFai Lau if (pid == 0) {
5875db58fafSMartin KaFai Lau do_test_lru_sanity5(key, map_fd);
5885db58fafSMartin KaFai Lau exit(0);
5895db58fafSMartin KaFai Lau } else if (pid == -1) {
5903fbfadceSMartin KaFai Lau printf("couldn't spawn process to test key:%llu\n",
5913fbfadceSMartin KaFai Lau key);
5925db58fafSMartin KaFai Lau exit(1);
5935db58fafSMartin KaFai Lau } else {
5945db58fafSMartin KaFai Lau int status;
5955db58fafSMartin KaFai Lau
5965db58fafSMartin KaFai Lau assert(waitpid(pid, &status, 0) == pid);
5975db58fafSMartin KaFai Lau assert(status == 0);
5985db58fafSMartin KaFai Lau key++;
5995db58fafSMartin KaFai Lau }
6005db58fafSMartin KaFai Lau }
6015db58fafSMartin KaFai Lau
6025db58fafSMartin KaFai Lau close(map_fd);
6033fbfadceSMartin KaFai Lau /* At least one key should be tested */
6043fbfadceSMartin KaFai Lau assert(key > 0);
6055db58fafSMartin KaFai Lau
6065db58fafSMartin KaFai Lau printf("Pass\n");
6075db58fafSMartin KaFai Lau }
6085db58fafSMartin KaFai Lau
6099746f856SMartin KaFai Lau /* Test list rotation for BPF_F_NO_COMMON_LRU map */
test_lru_sanity6(int map_type,int map_flags,int tgt_free)6109746f856SMartin KaFai Lau static void test_lru_sanity6(int map_type, int map_flags, int tgt_free)
6119746f856SMartin KaFai Lau {
6129746f856SMartin KaFai Lau int lru_map_fd, expected_map_fd;
6139746f856SMartin KaFai Lau unsigned long long key, value[nr_cpus];
6149746f856SMartin KaFai Lau unsigned int map_size = tgt_free * 2;
6159746f856SMartin KaFai Lau int next_cpu = 0;
6169746f856SMartin KaFai Lau
6179746f856SMartin KaFai Lau if (!(map_flags & BPF_F_NO_COMMON_LRU))
6189746f856SMartin KaFai Lau return;
6199746f856SMartin KaFai Lau
6209746f856SMartin KaFai Lau printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
6219746f856SMartin KaFai Lau map_flags);
6229746f856SMartin KaFai Lau
6239746f856SMartin KaFai Lau assert(sched_next_online(0, &next_cpu) != -1);
6249746f856SMartin KaFai Lau
6259746f856SMartin KaFai Lau expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size);
6269746f856SMartin KaFai Lau assert(expected_map_fd != -1);
6279746f856SMartin KaFai Lau
6289746f856SMartin KaFai Lau lru_map_fd = create_map(map_type, map_flags, map_size * nr_cpus);
6299746f856SMartin KaFai Lau assert(lru_map_fd != -1);
6309746f856SMartin KaFai Lau
6319746f856SMartin KaFai Lau value[0] = 1234;
6329746f856SMartin KaFai Lau
6339746f856SMartin KaFai Lau for (key = 1; key <= tgt_free; key++) {
6349746f856SMartin KaFai Lau assert(!bpf_map_update_elem(lru_map_fd, &key, value,
6359746f856SMartin KaFai Lau BPF_NOEXIST));
6369746f856SMartin KaFai Lau assert(!bpf_map_update_elem(expected_map_fd, &key, value,
6379746f856SMartin KaFai Lau BPF_NOEXIST));
6389746f856SMartin KaFai Lau }
6399746f856SMartin KaFai Lau
6409746f856SMartin KaFai Lau for (; key <= tgt_free * 2; key++) {
6419746f856SMartin KaFai Lau unsigned long long stable_key;
6429746f856SMartin KaFai Lau
6439746f856SMartin KaFai Lau /* Make ref bit sticky for key: [1, tgt_free] */
6449746f856SMartin KaFai Lau for (stable_key = 1; stable_key <= tgt_free; stable_key++) {
6459746f856SMartin KaFai Lau /* Mark the ref bit */
646d2baab62SDaniel Borkmann assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd,
647d2baab62SDaniel Borkmann stable_key, value));
6489746f856SMartin KaFai Lau }
6499746f856SMartin KaFai Lau assert(!bpf_map_update_elem(lru_map_fd, &key, value,
6509746f856SMartin KaFai Lau BPF_NOEXIST));
6519746f856SMartin KaFai Lau }
6529746f856SMartin KaFai Lau
6539746f856SMartin KaFai Lau for (; key <= tgt_free * 3; key++) {
6549746f856SMartin KaFai Lau assert(!bpf_map_update_elem(lru_map_fd, &key, value,
6559746f856SMartin KaFai Lau BPF_NOEXIST));
6569746f856SMartin KaFai Lau assert(!bpf_map_update_elem(expected_map_fd, &key, value,
6579746f856SMartin KaFai Lau BPF_NOEXIST));
6589746f856SMartin KaFai Lau }
6599746f856SMartin KaFai Lau
6609746f856SMartin KaFai Lau assert(map_equal(lru_map_fd, expected_map_fd));
6619746f856SMartin KaFai Lau
6629746f856SMartin KaFai Lau close(expected_map_fd);
6639746f856SMartin KaFai Lau close(lru_map_fd);
6649746f856SMartin KaFai Lau
6659746f856SMartin KaFai Lau printf("Pass\n");
6669746f856SMartin KaFai Lau }
6679746f856SMartin KaFai Lau
668d2baab62SDaniel Borkmann /* Size of the LRU map is 2
669d2baab62SDaniel Borkmann * Add key=1 (+1 key)
670d2baab62SDaniel Borkmann * Add key=2 (+1 key)
671d2baab62SDaniel Borkmann * Lookup Key=1 (datapath)
672d2baab62SDaniel Borkmann * Lookup Key=2 (syscall)
673d2baab62SDaniel Borkmann * Add Key=3
674d2baab62SDaniel Borkmann * => Key=2 will be removed by LRU
675d2baab62SDaniel Borkmann * Iterate map. Only found key=1 and key=3
676d2baab62SDaniel Borkmann */
test_lru_sanity7(int map_type,int map_flags)677d2baab62SDaniel Borkmann static void test_lru_sanity7(int map_type, int map_flags)
678d2baab62SDaniel Borkmann {
679d2baab62SDaniel Borkmann unsigned long long key, value[nr_cpus];
680d2baab62SDaniel Borkmann int lru_map_fd, expected_map_fd;
681d2baab62SDaniel Borkmann int next_cpu = 0;
682d2baab62SDaniel Borkmann
683d2baab62SDaniel Borkmann printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
684d2baab62SDaniel Borkmann map_flags);
685d2baab62SDaniel Borkmann
686d2baab62SDaniel Borkmann assert(sched_next_online(0, &next_cpu) != -1);
687d2baab62SDaniel Borkmann
688d2baab62SDaniel Borkmann if (map_flags & BPF_F_NO_COMMON_LRU)
689d2baab62SDaniel Borkmann lru_map_fd = create_map(map_type, map_flags, 2 * nr_cpus);
690d2baab62SDaniel Borkmann else
691d2baab62SDaniel Borkmann lru_map_fd = create_map(map_type, map_flags, 2);
692d2baab62SDaniel Borkmann assert(lru_map_fd != -1);
693d2baab62SDaniel Borkmann
694d2baab62SDaniel Borkmann expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, 2);
695d2baab62SDaniel Borkmann assert(expected_map_fd != -1);
696d2baab62SDaniel Borkmann
697d2baab62SDaniel Borkmann value[0] = 1234;
698d2baab62SDaniel Borkmann
699d2baab62SDaniel Borkmann /* insert key=1 element */
700d2baab62SDaniel Borkmann
701d2baab62SDaniel Borkmann key = 1;
702d2baab62SDaniel Borkmann assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
703d2baab62SDaniel Borkmann assert(!bpf_map_update_elem(expected_map_fd, &key, value,
704d2baab62SDaniel Borkmann BPF_NOEXIST));
705d2baab62SDaniel Borkmann
706d2baab62SDaniel Borkmann /* BPF_NOEXIST means: add new element if it doesn't exist */
707c14766a8SArtem Savkov assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST) == -EEXIST);
708d2baab62SDaniel Borkmann /* key=1 already exists */
709d2baab62SDaniel Borkmann
710d2baab62SDaniel Borkmann /* insert key=2 element */
711d2baab62SDaniel Borkmann
712d2baab62SDaniel Borkmann /* check that key=2 is not found */
713d2baab62SDaniel Borkmann key = 2;
714c14766a8SArtem Savkov assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
715d2baab62SDaniel Borkmann
716d2baab62SDaniel Borkmann /* BPF_EXIST means: update existing element */
717c14766a8SArtem Savkov assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_EXIST) == -ENOENT);
718d2baab62SDaniel Borkmann /* key=2 is not there */
719d2baab62SDaniel Borkmann
720d2baab62SDaniel Borkmann assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
721d2baab62SDaniel Borkmann
722d2baab62SDaniel Borkmann /* insert key=3 element */
723d2baab62SDaniel Borkmann
724d2baab62SDaniel Borkmann /* check that key=3 is not found */
725d2baab62SDaniel Borkmann key = 3;
726c14766a8SArtem Savkov assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
727d2baab62SDaniel Borkmann
728d2baab62SDaniel Borkmann /* check that key=1 can be found and mark the ref bit to
729d2baab62SDaniel Borkmann * stop LRU from removing key=1
730d2baab62SDaniel Borkmann */
731d2baab62SDaniel Borkmann key = 1;
732d2baab62SDaniel Borkmann assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
733d2baab62SDaniel Borkmann assert(value[0] == 1234);
734d2baab62SDaniel Borkmann
735d2baab62SDaniel Borkmann /* check that key=2 can be found and do _not_ mark ref bit.
736d2baab62SDaniel Borkmann * this will be evicted on next update.
737d2baab62SDaniel Borkmann */
738d2baab62SDaniel Borkmann key = 2;
739d2baab62SDaniel Borkmann assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
740d2baab62SDaniel Borkmann assert(value[0] == 1234);
741d2baab62SDaniel Borkmann
742d2baab62SDaniel Borkmann key = 3;
743d2baab62SDaniel Borkmann assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
744d2baab62SDaniel Borkmann assert(!bpf_map_update_elem(expected_map_fd, &key, value,
745d2baab62SDaniel Borkmann BPF_NOEXIST));
746d2baab62SDaniel Borkmann
747d2baab62SDaniel Borkmann /* key=2 has been removed from the LRU */
748d2baab62SDaniel Borkmann key = 2;
749c14766a8SArtem Savkov assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
750d2baab62SDaniel Borkmann
751d2baab62SDaniel Borkmann assert(map_equal(lru_map_fd, expected_map_fd));
752d2baab62SDaniel Borkmann
753d2baab62SDaniel Borkmann close(expected_map_fd);
754d2baab62SDaniel Borkmann close(lru_map_fd);
755d2baab62SDaniel Borkmann
756d2baab62SDaniel Borkmann printf("Pass\n");
757d2baab62SDaniel Borkmann }
758d2baab62SDaniel Borkmann
759d2baab62SDaniel Borkmann /* Size of the LRU map is 2
760d2baab62SDaniel Borkmann * Add key=1 (+1 key)
761d2baab62SDaniel Borkmann * Add key=2 (+1 key)
762d2baab62SDaniel Borkmann * Lookup Key=1 (syscall)
763d2baab62SDaniel Borkmann * Lookup Key=2 (datapath)
764d2baab62SDaniel Borkmann * Add Key=3
765d2baab62SDaniel Borkmann * => Key=1 will be removed by LRU
766d2baab62SDaniel Borkmann * Iterate map. Only found key=2 and key=3
767d2baab62SDaniel Borkmann */
test_lru_sanity8(int map_type,int map_flags)768d2baab62SDaniel Borkmann static void test_lru_sanity8(int map_type, int map_flags)
769d2baab62SDaniel Borkmann {
770d2baab62SDaniel Borkmann unsigned long long key, value[nr_cpus];
771d2baab62SDaniel Borkmann int lru_map_fd, expected_map_fd;
772d2baab62SDaniel Borkmann int next_cpu = 0;
773d2baab62SDaniel Borkmann
774d2baab62SDaniel Borkmann printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
775d2baab62SDaniel Borkmann map_flags);
776d2baab62SDaniel Borkmann
777d2baab62SDaniel Borkmann assert(sched_next_online(0, &next_cpu) != -1);
778d2baab62SDaniel Borkmann
779d2baab62SDaniel Borkmann if (map_flags & BPF_F_NO_COMMON_LRU)
780d2baab62SDaniel Borkmann lru_map_fd = create_map(map_type, map_flags, 2 * nr_cpus);
781d2baab62SDaniel Borkmann else
782d2baab62SDaniel Borkmann lru_map_fd = create_map(map_type, map_flags, 2);
783d2baab62SDaniel Borkmann assert(lru_map_fd != -1);
784d2baab62SDaniel Borkmann
785d2baab62SDaniel Borkmann expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, 2);
786d2baab62SDaniel Borkmann assert(expected_map_fd != -1);
787d2baab62SDaniel Borkmann
788d2baab62SDaniel Borkmann value[0] = 1234;
789d2baab62SDaniel Borkmann
790d2baab62SDaniel Borkmann /* insert key=1 element */
791d2baab62SDaniel Borkmann
792d2baab62SDaniel Borkmann key = 1;
793d2baab62SDaniel Borkmann assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
794d2baab62SDaniel Borkmann
795d2baab62SDaniel Borkmann /* BPF_NOEXIST means: add new element if it doesn't exist */
796c14766a8SArtem Savkov assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST) == -EEXIST);
797d2baab62SDaniel Borkmann /* key=1 already exists */
798d2baab62SDaniel Borkmann
799d2baab62SDaniel Borkmann /* insert key=2 element */
800d2baab62SDaniel Borkmann
801d2baab62SDaniel Borkmann /* check that key=2 is not found */
802d2baab62SDaniel Borkmann key = 2;
803c14766a8SArtem Savkov assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
804d2baab62SDaniel Borkmann
805d2baab62SDaniel Borkmann /* BPF_EXIST means: update existing element */
806c14766a8SArtem Savkov assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_EXIST) == -ENOENT);
807d2baab62SDaniel Borkmann /* key=2 is not there */
808d2baab62SDaniel Borkmann
809d2baab62SDaniel Borkmann assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
810d2baab62SDaniel Borkmann assert(!bpf_map_update_elem(expected_map_fd, &key, value,
811d2baab62SDaniel Borkmann BPF_NOEXIST));
812d2baab62SDaniel Borkmann
813d2baab62SDaniel Borkmann /* insert key=3 element */
814d2baab62SDaniel Borkmann
815d2baab62SDaniel Borkmann /* check that key=3 is not found */
816d2baab62SDaniel Borkmann key = 3;
817c14766a8SArtem Savkov assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
818d2baab62SDaniel Borkmann
819d2baab62SDaniel Borkmann /* check that key=1 can be found and do _not_ mark ref bit.
820d2baab62SDaniel Borkmann * this will be evicted on next update.
821d2baab62SDaniel Borkmann */
822d2baab62SDaniel Borkmann key = 1;
823d2baab62SDaniel Borkmann assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
824d2baab62SDaniel Borkmann assert(value[0] == 1234);
825d2baab62SDaniel Borkmann
826d2baab62SDaniel Borkmann /* check that key=2 can be found and mark the ref bit to
827d2baab62SDaniel Borkmann * stop LRU from removing key=2
828d2baab62SDaniel Borkmann */
829d2baab62SDaniel Borkmann key = 2;
830d2baab62SDaniel Borkmann assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
831d2baab62SDaniel Borkmann assert(value[0] == 1234);
832d2baab62SDaniel Borkmann
833d2baab62SDaniel Borkmann key = 3;
834d2baab62SDaniel Borkmann assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
835d2baab62SDaniel Borkmann assert(!bpf_map_update_elem(expected_map_fd, &key, value,
836d2baab62SDaniel Borkmann BPF_NOEXIST));
837d2baab62SDaniel Borkmann
838d2baab62SDaniel Borkmann /* key=1 has been removed from the LRU */
839d2baab62SDaniel Borkmann key = 1;
840c14766a8SArtem Savkov assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
841d2baab62SDaniel Borkmann
842d2baab62SDaniel Borkmann assert(map_equal(lru_map_fd, expected_map_fd));
843d2baab62SDaniel Borkmann
844d2baab62SDaniel Borkmann close(expected_map_fd);
845d2baab62SDaniel Borkmann close(lru_map_fd);
846d2baab62SDaniel Borkmann
847d2baab62SDaniel Borkmann printf("Pass\n");
848d2baab62SDaniel Borkmann }
849d2baab62SDaniel Borkmann
main(int argc,char ** argv)8505db58fafSMartin KaFai Lau int main(int argc, char **argv)
8515db58fafSMartin KaFai Lau {
8525db58fafSMartin KaFai Lau int map_types[] = {BPF_MAP_TYPE_LRU_HASH,
8535db58fafSMartin KaFai Lau BPF_MAP_TYPE_LRU_PERCPU_HASH};
8545db58fafSMartin KaFai Lau int map_flags[] = {0, BPF_F_NO_COMMON_LRU};
8555db58fafSMartin KaFai Lau int t, f;
8565db58fafSMartin KaFai Lau
8575db58fafSMartin KaFai Lau setbuf(stdout, NULL);
8585db58fafSMartin KaFai Lau
859e00c7b21SDaniel Borkmann nr_cpus = bpf_num_possible_cpus();
8605db58fafSMartin KaFai Lau assert(nr_cpus != -1);
8615db58fafSMartin KaFai Lau printf("nr_cpus:%d\n\n", nr_cpus);
8625db58fafSMartin KaFai Lau
863b858ba8cSYafang Shao /* Use libbpf 1.0 API mode */
864b858ba8cSYafang Shao libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
865b858ba8cSYafang Shao
866f98d6dd1SGuo Zhengkui for (f = 0; f < ARRAY_SIZE(map_flags); f++) {
8675db58fafSMartin KaFai Lau unsigned int tgt_free = (map_flags[f] & BPF_F_NO_COMMON_LRU) ?
8685db58fafSMartin KaFai Lau PERCPU_FREE_TARGET : LOCAL_FREE_TARGET;
8695db58fafSMartin KaFai Lau
870f98d6dd1SGuo Zhengkui for (t = 0; t < ARRAY_SIZE(map_types); t++) {
8715db58fafSMartin KaFai Lau test_lru_sanity0(map_types[t], map_flags[f]);
8725db58fafSMartin KaFai Lau test_lru_sanity1(map_types[t], map_flags[f], tgt_free);
8735db58fafSMartin KaFai Lau test_lru_sanity2(map_types[t], map_flags[f], tgt_free);
8745db58fafSMartin KaFai Lau test_lru_sanity3(map_types[t], map_flags[f], tgt_free);
8755db58fafSMartin KaFai Lau test_lru_sanity4(map_types[t], map_flags[f], tgt_free);
8765db58fafSMartin KaFai Lau test_lru_sanity5(map_types[t], map_flags[f]);
8779746f856SMartin KaFai Lau test_lru_sanity6(map_types[t], map_flags[f], tgt_free);
878d2baab62SDaniel Borkmann test_lru_sanity7(map_types[t], map_flags[f]);
879d2baab62SDaniel Borkmann test_lru_sanity8(map_types[t], map_flags[f]);
8805db58fafSMartin KaFai Lau
8815db58fafSMartin KaFai Lau printf("\n");
8825db58fafSMartin KaFai Lau }
8835db58fafSMartin KaFai Lau }
8845db58fafSMartin KaFai Lau
8855db58fafSMartin KaFai Lau return 0;
8865db58fafSMartin KaFai Lau }
887