162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2016 Facebook
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci#define _GNU_SOURCE
662306a36Sopenharmony_ci#include <stdio.h>
762306a36Sopenharmony_ci#include <unistd.h>
862306a36Sopenharmony_ci#include <errno.h>
962306a36Sopenharmony_ci#include <string.h>
1062306a36Sopenharmony_ci#include <assert.h>
1162306a36Sopenharmony_ci#include <sched.h>
1262306a36Sopenharmony_ci#include <stdlib.h>
1362306a36Sopenharmony_ci#include <time.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <sys/wait.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <bpf/bpf.h>
1862306a36Sopenharmony_ci#include <bpf/libbpf.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include "bpf_util.h"
2162306a36Sopenharmony_ci#include "../../../include/linux/filter.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define LOCAL_FREE_TARGET	(128)
2462306a36Sopenharmony_ci#define PERCPU_FREE_TARGET	(4)
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic int nr_cpus;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic int create_map(int map_type, int map_flags, unsigned int size)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = map_flags);
3162306a36Sopenharmony_ci	int map_fd;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	map_fd = bpf_map_create(map_type, NULL,  sizeof(unsigned long long),
3462306a36Sopenharmony_ci				sizeof(unsigned long long), size, &opts);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	if (map_fd == -1)
3762306a36Sopenharmony_ci		perror("bpf_map_create");
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	return map_fd;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic int bpf_map_lookup_elem_with_ref_bit(int fd, unsigned long long key,
4362306a36Sopenharmony_ci					    void *value)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	struct bpf_insn insns[] = {
4662306a36Sopenharmony_ci		BPF_LD_MAP_VALUE(BPF_REG_9, 0, 0),
4762306a36Sopenharmony_ci		BPF_LD_MAP_FD(BPF_REG_1, fd),
4862306a36Sopenharmony_ci		BPF_LD_IMM64(BPF_REG_3, key),
4962306a36Sopenharmony_ci		BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
5062306a36Sopenharmony_ci		BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
5162306a36Sopenharmony_ci		BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, 0),
5262306a36Sopenharmony_ci		BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
5362306a36Sopenharmony_ci		BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
5462306a36Sopenharmony_ci		BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0),
5562306a36Sopenharmony_ci		BPF_STX_MEM(BPF_DW, BPF_REG_9, BPF_REG_1, 0),
5662306a36Sopenharmony_ci		BPF_MOV64_IMM(BPF_REG_0, 42),
5762306a36Sopenharmony_ci		BPF_JMP_IMM(BPF_JA, 0, 0, 1),
5862306a36Sopenharmony_ci		BPF_MOV64_IMM(BPF_REG_0, 1),
5962306a36Sopenharmony_ci		BPF_EXIT_INSN(),
6062306a36Sopenharmony_ci	};
6162306a36Sopenharmony_ci	__u8 data[64] = {};
6262306a36Sopenharmony_ci	int mfd, pfd, ret, zero = 0;
6362306a36Sopenharmony_ci	LIBBPF_OPTS(bpf_test_run_opts, topts,
6462306a36Sopenharmony_ci		.data_in = data,
6562306a36Sopenharmony_ci		.data_size_in = sizeof(data),
6662306a36Sopenharmony_ci		.repeat = 1,
6762306a36Sopenharmony_ci	);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	mfd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, sizeof(int), sizeof(__u64), 1, NULL);
7062306a36Sopenharmony_ci	if (mfd < 0)
7162306a36Sopenharmony_ci		return -1;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	insns[0].imm = mfd;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	pfd = bpf_prog_load(BPF_PROG_TYPE_SCHED_CLS, NULL, "GPL", insns, ARRAY_SIZE(insns), NULL);
7662306a36Sopenharmony_ci	if (pfd < 0) {
7762306a36Sopenharmony_ci		close(mfd);
7862306a36Sopenharmony_ci		return -1;
7962306a36Sopenharmony_ci	}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	ret = bpf_prog_test_run_opts(pfd, &topts);
8262306a36Sopenharmony_ci	if (ret < 0 || topts.retval != 42) {
8362306a36Sopenharmony_ci		ret = -1;
8462306a36Sopenharmony_ci	} else {
8562306a36Sopenharmony_ci		assert(!bpf_map_lookup_elem(mfd, &zero, value));
8662306a36Sopenharmony_ci		ret = 0;
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci	close(pfd);
8962306a36Sopenharmony_ci	close(mfd);
9062306a36Sopenharmony_ci	return ret;
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic int map_subset(int map0, int map1)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	unsigned long long next_key = 0;
9662306a36Sopenharmony_ci	unsigned long long value0[nr_cpus], value1[nr_cpus];
9762306a36Sopenharmony_ci	int ret;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	while (!bpf_map_get_next_key(map1, &next_key, &next_key)) {
10062306a36Sopenharmony_ci		assert(!bpf_map_lookup_elem(map1, &next_key, value1));
10162306a36Sopenharmony_ci		ret = bpf_map_lookup_elem(map0, &next_key, value0);
10262306a36Sopenharmony_ci		if (ret) {
10362306a36Sopenharmony_ci			printf("key:%llu not found from map. %s(%d)\n",
10462306a36Sopenharmony_ci			       next_key, strerror(errno), errno);
10562306a36Sopenharmony_ci			return 0;
10662306a36Sopenharmony_ci		}
10762306a36Sopenharmony_ci		if (value0[0] != value1[0]) {
10862306a36Sopenharmony_ci			printf("key:%llu value0:%llu != value1:%llu\n",
10962306a36Sopenharmony_ci			       next_key, value0[0], value1[0]);
11062306a36Sopenharmony_ci			return 0;
11162306a36Sopenharmony_ci		}
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci	return 1;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic int map_equal(int lru_map, int expected)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	return map_subset(lru_map, expected) && map_subset(expected, lru_map);
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic int sched_next_online(int pid, int *next_to_try)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	cpu_set_t cpuset;
12462306a36Sopenharmony_ci	int next = *next_to_try;
12562306a36Sopenharmony_ci	int ret = -1;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	while (next < nr_cpus) {
12862306a36Sopenharmony_ci		CPU_ZERO(&cpuset);
12962306a36Sopenharmony_ci		CPU_SET(next++, &cpuset);
13062306a36Sopenharmony_ci		if (!sched_setaffinity(pid, sizeof(cpuset), &cpuset)) {
13162306a36Sopenharmony_ci			ret = 0;
13262306a36Sopenharmony_ci			break;
13362306a36Sopenharmony_ci		}
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	*next_to_try = next;
13762306a36Sopenharmony_ci	return ret;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci/* Size of the LRU map is 2
14162306a36Sopenharmony_ci * Add key=1 (+1 key)
14262306a36Sopenharmony_ci * Add key=2 (+1 key)
14362306a36Sopenharmony_ci * Lookup Key=1
14462306a36Sopenharmony_ci * Add Key=3
14562306a36Sopenharmony_ci *   => Key=2 will be removed by LRU
14662306a36Sopenharmony_ci * Iterate map.  Only found key=1 and key=3
14762306a36Sopenharmony_ci */
14862306a36Sopenharmony_cistatic void test_lru_sanity0(int map_type, int map_flags)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	unsigned long long key, value[nr_cpus];
15162306a36Sopenharmony_ci	int lru_map_fd, expected_map_fd;
15262306a36Sopenharmony_ci	int next_cpu = 0;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
15562306a36Sopenharmony_ci	       map_flags);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	assert(sched_next_online(0, &next_cpu) != -1);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	if (map_flags & BPF_F_NO_COMMON_LRU)
16062306a36Sopenharmony_ci		lru_map_fd = create_map(map_type, map_flags, 2 * nr_cpus);
16162306a36Sopenharmony_ci	else
16262306a36Sopenharmony_ci		lru_map_fd = create_map(map_type, map_flags, 2);
16362306a36Sopenharmony_ci	assert(lru_map_fd != -1);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, 2);
16662306a36Sopenharmony_ci	assert(expected_map_fd != -1);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	value[0] = 1234;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	/* insert key=1 element */
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	key = 1;
17362306a36Sopenharmony_ci	assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
17462306a36Sopenharmony_ci	assert(!bpf_map_update_elem(expected_map_fd, &key, value,
17562306a36Sopenharmony_ci				    BPF_NOEXIST));
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	/* BPF_NOEXIST means: add new element if it doesn't exist */
17862306a36Sopenharmony_ci	assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST) == -EEXIST);
17962306a36Sopenharmony_ci	/* key=1 already exists */
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	assert(bpf_map_update_elem(lru_map_fd, &key, value, -1) == -EINVAL);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/* insert key=2 element */
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	/* check that key=2 is not found */
18662306a36Sopenharmony_ci	key = 2;
18762306a36Sopenharmony_ci	assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	/* BPF_EXIST means: update existing element */
19062306a36Sopenharmony_ci	assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_EXIST) == -ENOENT);
19162306a36Sopenharmony_ci	/* key=2 is not there */
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	/* insert key=3 element */
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	/* check that key=3 is not found */
19862306a36Sopenharmony_ci	key = 3;
19962306a36Sopenharmony_ci	assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	/* check that key=1 can be found and mark the ref bit to
20262306a36Sopenharmony_ci	 * stop LRU from removing key=1
20362306a36Sopenharmony_ci	 */
20462306a36Sopenharmony_ci	key = 1;
20562306a36Sopenharmony_ci	assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
20662306a36Sopenharmony_ci	assert(value[0] == 1234);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	key = 3;
20962306a36Sopenharmony_ci	assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
21062306a36Sopenharmony_ci	assert(!bpf_map_update_elem(expected_map_fd, &key, value,
21162306a36Sopenharmony_ci				    BPF_NOEXIST));
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	/* key=2 has been removed from the LRU */
21462306a36Sopenharmony_ci	key = 2;
21562306a36Sopenharmony_ci	assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	/* lookup elem key=1 and delete it, then check it doesn't exist */
21862306a36Sopenharmony_ci	key = 1;
21962306a36Sopenharmony_ci	assert(!bpf_map_lookup_and_delete_elem(lru_map_fd, &key, &value));
22062306a36Sopenharmony_ci	assert(value[0] == 1234);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	/* remove the same element from the expected map */
22362306a36Sopenharmony_ci	assert(!bpf_map_delete_elem(expected_map_fd, &key));
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	assert(map_equal(lru_map_fd, expected_map_fd));
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	close(expected_map_fd);
22862306a36Sopenharmony_ci	close(lru_map_fd);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	printf("Pass\n");
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci/* Size of the LRU map is 1.5*tgt_free
23462306a36Sopenharmony_ci * Insert 1 to tgt_free (+tgt_free keys)
23562306a36Sopenharmony_ci * Lookup 1 to tgt_free/2
23662306a36Sopenharmony_ci * Insert 1+tgt_free to 2*tgt_free (+tgt_free keys)
23762306a36Sopenharmony_ci * => 1+tgt_free/2 to LOCALFREE_TARGET will be removed by LRU
23862306a36Sopenharmony_ci */
23962306a36Sopenharmony_cistatic void test_lru_sanity1(int map_type, int map_flags, unsigned int tgt_free)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	unsigned long long key, end_key, value[nr_cpus];
24262306a36Sopenharmony_ci	int lru_map_fd, expected_map_fd;
24362306a36Sopenharmony_ci	unsigned int batch_size;
24462306a36Sopenharmony_ci	unsigned int map_size;
24562306a36Sopenharmony_ci	int next_cpu = 0;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (map_flags & BPF_F_NO_COMMON_LRU)
24862306a36Sopenharmony_ci		/* This test is only applicable to common LRU list */
24962306a36Sopenharmony_ci		return;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
25262306a36Sopenharmony_ci	       map_flags);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	assert(sched_next_online(0, &next_cpu) != -1);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	batch_size = tgt_free / 2;
25762306a36Sopenharmony_ci	assert(batch_size * 2 == tgt_free);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	map_size = tgt_free + batch_size;
26062306a36Sopenharmony_ci	lru_map_fd = create_map(map_type, map_flags, map_size);
26162306a36Sopenharmony_ci	assert(lru_map_fd != -1);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size);
26462306a36Sopenharmony_ci	assert(expected_map_fd != -1);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	value[0] = 1234;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	/* Insert 1 to tgt_free (+tgt_free keys) */
26962306a36Sopenharmony_ci	end_key = 1 + tgt_free;
27062306a36Sopenharmony_ci	for (key = 1; key < end_key; key++)
27162306a36Sopenharmony_ci		assert(!bpf_map_update_elem(lru_map_fd, &key, value,
27262306a36Sopenharmony_ci					    BPF_NOEXIST));
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	/* Lookup 1 to tgt_free/2 */
27562306a36Sopenharmony_ci	end_key = 1 + batch_size;
27662306a36Sopenharmony_ci	for (key = 1; key < end_key; key++) {
27762306a36Sopenharmony_ci		assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
27862306a36Sopenharmony_ci		assert(!bpf_map_update_elem(expected_map_fd, &key, value,
27962306a36Sopenharmony_ci					    BPF_NOEXIST));
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	/* Insert 1+tgt_free to 2*tgt_free
28362306a36Sopenharmony_ci	 * => 1+tgt_free/2 to LOCALFREE_TARGET will be
28462306a36Sopenharmony_ci	 * removed by LRU
28562306a36Sopenharmony_ci	 */
28662306a36Sopenharmony_ci	key = 1 + tgt_free;
28762306a36Sopenharmony_ci	end_key = key + tgt_free;
28862306a36Sopenharmony_ci	for (; key < end_key; key++) {
28962306a36Sopenharmony_ci		assert(!bpf_map_update_elem(lru_map_fd, &key, value,
29062306a36Sopenharmony_ci					    BPF_NOEXIST));
29162306a36Sopenharmony_ci		assert(!bpf_map_update_elem(expected_map_fd, &key, value,
29262306a36Sopenharmony_ci					    BPF_NOEXIST));
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	assert(map_equal(lru_map_fd, expected_map_fd));
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	close(expected_map_fd);
29862306a36Sopenharmony_ci	close(lru_map_fd);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	printf("Pass\n");
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci/* Size of the LRU map 1.5 * tgt_free
30462306a36Sopenharmony_ci * Insert 1 to tgt_free (+tgt_free keys)
30562306a36Sopenharmony_ci * Update 1 to tgt_free/2
30662306a36Sopenharmony_ci *   => The original 1 to tgt_free/2 will be removed due to
30762306a36Sopenharmony_ci *      the LRU shrink process
30862306a36Sopenharmony_ci * Re-insert 1 to tgt_free/2 again and do a lookup immeidately
30962306a36Sopenharmony_ci * Insert 1+tgt_free to tgt_free*3/2
31062306a36Sopenharmony_ci * Insert 1+tgt_free*3/2 to tgt_free*5/2
31162306a36Sopenharmony_ci *   => Key 1+tgt_free to tgt_free*3/2
31262306a36Sopenharmony_ci *      will be removed from LRU because it has never
31362306a36Sopenharmony_ci *      been lookup and ref bit is not set
31462306a36Sopenharmony_ci */
31562306a36Sopenharmony_cistatic void test_lru_sanity2(int map_type, int map_flags, unsigned int tgt_free)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	unsigned long long key, value[nr_cpus];
31862306a36Sopenharmony_ci	unsigned long long end_key;
31962306a36Sopenharmony_ci	int lru_map_fd, expected_map_fd;
32062306a36Sopenharmony_ci	unsigned int batch_size;
32162306a36Sopenharmony_ci	unsigned int map_size;
32262306a36Sopenharmony_ci	int next_cpu = 0;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (map_flags & BPF_F_NO_COMMON_LRU)
32562306a36Sopenharmony_ci		/* This test is only applicable to common LRU list */
32662306a36Sopenharmony_ci		return;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
32962306a36Sopenharmony_ci	       map_flags);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	assert(sched_next_online(0, &next_cpu) != -1);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	batch_size = tgt_free / 2;
33462306a36Sopenharmony_ci	assert(batch_size * 2 == tgt_free);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	map_size = tgt_free + batch_size;
33762306a36Sopenharmony_ci	lru_map_fd = create_map(map_type, map_flags, map_size);
33862306a36Sopenharmony_ci	assert(lru_map_fd != -1);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size);
34162306a36Sopenharmony_ci	assert(expected_map_fd != -1);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	value[0] = 1234;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* Insert 1 to tgt_free (+tgt_free keys) */
34662306a36Sopenharmony_ci	end_key = 1 + tgt_free;
34762306a36Sopenharmony_ci	for (key = 1; key < end_key; key++)
34862306a36Sopenharmony_ci		assert(!bpf_map_update_elem(lru_map_fd, &key, value,
34962306a36Sopenharmony_ci					    BPF_NOEXIST));
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/* Any bpf_map_update_elem will require to acquire a new node
35262306a36Sopenharmony_ci	 * from LRU first.
35362306a36Sopenharmony_ci	 *
35462306a36Sopenharmony_ci	 * The local list is running out of free nodes.
35562306a36Sopenharmony_ci	 * It gets from the global LRU list which tries to
35662306a36Sopenharmony_ci	 * shrink the inactive list to get tgt_free
35762306a36Sopenharmony_ci	 * number of free nodes.
35862306a36Sopenharmony_ci	 *
35962306a36Sopenharmony_ci	 * Hence, the oldest key 1 to tgt_free/2
36062306a36Sopenharmony_ci	 * are removed from the LRU list.
36162306a36Sopenharmony_ci	 */
36262306a36Sopenharmony_ci	key = 1;
36362306a36Sopenharmony_ci	if (map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
36462306a36Sopenharmony_ci		assert(!bpf_map_update_elem(lru_map_fd, &key, value,
36562306a36Sopenharmony_ci					    BPF_NOEXIST));
36662306a36Sopenharmony_ci		assert(!bpf_map_delete_elem(lru_map_fd, &key));
36762306a36Sopenharmony_ci	} else {
36862306a36Sopenharmony_ci		assert(bpf_map_update_elem(lru_map_fd, &key, value,
36962306a36Sopenharmony_ci					   BPF_EXIST));
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	/* Re-insert 1 to tgt_free/2 again and do a lookup
37362306a36Sopenharmony_ci	 * immeidately.
37462306a36Sopenharmony_ci	 */
37562306a36Sopenharmony_ci	end_key = 1 + batch_size;
37662306a36Sopenharmony_ci	value[0] = 4321;
37762306a36Sopenharmony_ci	for (key = 1; key < end_key; key++) {
37862306a36Sopenharmony_ci		assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
37962306a36Sopenharmony_ci		assert(!bpf_map_update_elem(lru_map_fd, &key, value,
38062306a36Sopenharmony_ci					    BPF_NOEXIST));
38162306a36Sopenharmony_ci		assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
38262306a36Sopenharmony_ci		assert(value[0] == 4321);
38362306a36Sopenharmony_ci		assert(!bpf_map_update_elem(expected_map_fd, &key, value,
38462306a36Sopenharmony_ci					    BPF_NOEXIST));
38562306a36Sopenharmony_ci	}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	value[0] = 1234;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	/* Insert 1+tgt_free to tgt_free*3/2 */
39062306a36Sopenharmony_ci	end_key = 1 + tgt_free + batch_size;
39162306a36Sopenharmony_ci	for (key = 1 + tgt_free; key < end_key; key++)
39262306a36Sopenharmony_ci		/* These newly added but not referenced keys will be
39362306a36Sopenharmony_ci		 * gone during the next LRU shrink.
39462306a36Sopenharmony_ci		 */
39562306a36Sopenharmony_ci		assert(!bpf_map_update_elem(lru_map_fd, &key, value,
39662306a36Sopenharmony_ci					    BPF_NOEXIST));
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/* Insert 1+tgt_free*3/2 to  tgt_free*5/2 */
39962306a36Sopenharmony_ci	end_key = key + tgt_free;
40062306a36Sopenharmony_ci	for (; key < end_key; key++) {
40162306a36Sopenharmony_ci		assert(!bpf_map_update_elem(lru_map_fd, &key, value,
40262306a36Sopenharmony_ci					    BPF_NOEXIST));
40362306a36Sopenharmony_ci		assert(!bpf_map_update_elem(expected_map_fd, &key, value,
40462306a36Sopenharmony_ci					    BPF_NOEXIST));
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	assert(map_equal(lru_map_fd, expected_map_fd));
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	close(expected_map_fd);
41062306a36Sopenharmony_ci	close(lru_map_fd);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	printf("Pass\n");
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci/* Size of the LRU map is 2*tgt_free
41662306a36Sopenharmony_ci * It is to test the active/inactive list rotation
41762306a36Sopenharmony_ci * Insert 1 to 2*tgt_free (+2*tgt_free keys)
41862306a36Sopenharmony_ci * Lookup key 1 to tgt_free*3/2
41962306a36Sopenharmony_ci * Add 1+2*tgt_free to tgt_free*5/2 (+tgt_free/2 keys)
42062306a36Sopenharmony_ci *  => key 1+tgt_free*3/2 to 2*tgt_free are removed from LRU
42162306a36Sopenharmony_ci */
42262306a36Sopenharmony_cistatic void test_lru_sanity3(int map_type, int map_flags, unsigned int tgt_free)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	unsigned long long key, end_key, value[nr_cpus];
42562306a36Sopenharmony_ci	int lru_map_fd, expected_map_fd;
42662306a36Sopenharmony_ci	unsigned int batch_size;
42762306a36Sopenharmony_ci	unsigned int map_size;
42862306a36Sopenharmony_ci	int next_cpu = 0;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	if (map_flags & BPF_F_NO_COMMON_LRU)
43162306a36Sopenharmony_ci		/* This test is only applicable to common LRU list */
43262306a36Sopenharmony_ci		return;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
43562306a36Sopenharmony_ci	       map_flags);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	assert(sched_next_online(0, &next_cpu) != -1);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	batch_size = tgt_free / 2;
44062306a36Sopenharmony_ci	assert(batch_size * 2 == tgt_free);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	map_size = tgt_free * 2;
44362306a36Sopenharmony_ci	lru_map_fd = create_map(map_type, map_flags, map_size);
44462306a36Sopenharmony_ci	assert(lru_map_fd != -1);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size);
44762306a36Sopenharmony_ci	assert(expected_map_fd != -1);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	value[0] = 1234;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	/* Insert 1 to 2*tgt_free (+2*tgt_free keys) */
45262306a36Sopenharmony_ci	end_key = 1 + (2 * tgt_free);
45362306a36Sopenharmony_ci	for (key = 1; key < end_key; key++)
45462306a36Sopenharmony_ci		assert(!bpf_map_update_elem(lru_map_fd, &key, value,
45562306a36Sopenharmony_ci					    BPF_NOEXIST));
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	/* Lookup key 1 to tgt_free*3/2 */
45862306a36Sopenharmony_ci	end_key = tgt_free + batch_size;
45962306a36Sopenharmony_ci	for (key = 1; key < end_key; key++) {
46062306a36Sopenharmony_ci		assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
46162306a36Sopenharmony_ci		assert(!bpf_map_update_elem(expected_map_fd, &key, value,
46262306a36Sopenharmony_ci					    BPF_NOEXIST));
46362306a36Sopenharmony_ci	}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	/* Add 1+2*tgt_free to tgt_free*5/2
46662306a36Sopenharmony_ci	 * (+tgt_free/2 keys)
46762306a36Sopenharmony_ci	 */
46862306a36Sopenharmony_ci	key = 2 * tgt_free + 1;
46962306a36Sopenharmony_ci	end_key = key + batch_size;
47062306a36Sopenharmony_ci	for (; key < end_key; key++) {
47162306a36Sopenharmony_ci		assert(!bpf_map_update_elem(lru_map_fd, &key, value,
47262306a36Sopenharmony_ci					    BPF_NOEXIST));
47362306a36Sopenharmony_ci		assert(!bpf_map_update_elem(expected_map_fd, &key, value,
47462306a36Sopenharmony_ci					    BPF_NOEXIST));
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	assert(map_equal(lru_map_fd, expected_map_fd));
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	close(expected_map_fd);
48062306a36Sopenharmony_ci	close(lru_map_fd);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	printf("Pass\n");
48362306a36Sopenharmony_ci}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci/* Test deletion */
48662306a36Sopenharmony_cistatic void test_lru_sanity4(int map_type, int map_flags, unsigned int tgt_free)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	int lru_map_fd, expected_map_fd;
48962306a36Sopenharmony_ci	unsigned long long key, value[nr_cpus];
49062306a36Sopenharmony_ci	unsigned long long end_key;
49162306a36Sopenharmony_ci	int next_cpu = 0;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
49462306a36Sopenharmony_ci	       map_flags);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	assert(sched_next_online(0, &next_cpu) != -1);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	if (map_flags & BPF_F_NO_COMMON_LRU)
49962306a36Sopenharmony_ci		lru_map_fd = create_map(map_type, map_flags,
50062306a36Sopenharmony_ci					3 * tgt_free * nr_cpus);
50162306a36Sopenharmony_ci	else
50262306a36Sopenharmony_ci		lru_map_fd = create_map(map_type, map_flags, 3 * tgt_free);
50362306a36Sopenharmony_ci	assert(lru_map_fd != -1);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0,
50662306a36Sopenharmony_ci				     3 * tgt_free);
50762306a36Sopenharmony_ci	assert(expected_map_fd != -1);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	value[0] = 1234;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	for (key = 1; key <= 2 * tgt_free; key++)
51262306a36Sopenharmony_ci		assert(!bpf_map_update_elem(lru_map_fd, &key, value,
51362306a36Sopenharmony_ci					    BPF_NOEXIST));
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	key = 1;
51662306a36Sopenharmony_ci	assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	for (key = 1; key <= tgt_free; key++) {
51962306a36Sopenharmony_ci		assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
52062306a36Sopenharmony_ci		assert(!bpf_map_update_elem(expected_map_fd, &key, value,
52162306a36Sopenharmony_ci					    BPF_NOEXIST));
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	for (; key <= 2 * tgt_free; key++) {
52562306a36Sopenharmony_ci		assert(!bpf_map_delete_elem(lru_map_fd, &key));
52662306a36Sopenharmony_ci		assert(bpf_map_delete_elem(lru_map_fd, &key));
52762306a36Sopenharmony_ci	}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	end_key = key + 2 * tgt_free;
53062306a36Sopenharmony_ci	for (; key < end_key; key++) {
53162306a36Sopenharmony_ci		assert(!bpf_map_update_elem(lru_map_fd, &key, value,
53262306a36Sopenharmony_ci					    BPF_NOEXIST));
53362306a36Sopenharmony_ci		assert(!bpf_map_update_elem(expected_map_fd, &key, value,
53462306a36Sopenharmony_ci					    BPF_NOEXIST));
53562306a36Sopenharmony_ci	}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	assert(map_equal(lru_map_fd, expected_map_fd));
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	close(expected_map_fd);
54062306a36Sopenharmony_ci	close(lru_map_fd);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	printf("Pass\n");
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_cistatic void do_test_lru_sanity5(unsigned long long last_key, int map_fd)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	unsigned long long key, value[nr_cpus];
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	/* Ensure the last key inserted by previous CPU can be found */
55062306a36Sopenharmony_ci	assert(!bpf_map_lookup_elem_with_ref_bit(map_fd, last_key, value));
55162306a36Sopenharmony_ci	value[0] = 1234;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	key = last_key + 1;
55462306a36Sopenharmony_ci	assert(!bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST));
55562306a36Sopenharmony_ci	assert(!bpf_map_lookup_elem_with_ref_bit(map_fd, key, value));
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	/* Cannot find the last key because it was removed by LRU */
55862306a36Sopenharmony_ci	assert(bpf_map_lookup_elem(map_fd, &last_key, value) == -ENOENT);
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci/* Test map with only one element */
56262306a36Sopenharmony_cistatic void test_lru_sanity5(int map_type, int map_flags)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	unsigned long long key, value[nr_cpus];
56562306a36Sopenharmony_ci	int next_cpu = 0;
56662306a36Sopenharmony_ci	int map_fd;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	if (map_flags & BPF_F_NO_COMMON_LRU)
56962306a36Sopenharmony_ci		return;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
57262306a36Sopenharmony_ci	       map_flags);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	map_fd = create_map(map_type, map_flags, 1);
57562306a36Sopenharmony_ci	assert(map_fd != -1);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	value[0] = 1234;
57862306a36Sopenharmony_ci	key = 0;
57962306a36Sopenharmony_ci	assert(!bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST));
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	while (sched_next_online(0, &next_cpu) != -1) {
58262306a36Sopenharmony_ci		pid_t pid;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci		pid = fork();
58562306a36Sopenharmony_ci		if (pid == 0) {
58662306a36Sopenharmony_ci			do_test_lru_sanity5(key, map_fd);
58762306a36Sopenharmony_ci			exit(0);
58862306a36Sopenharmony_ci		} else if (pid == -1) {
58962306a36Sopenharmony_ci			printf("couldn't spawn process to test key:%llu\n",
59062306a36Sopenharmony_ci			       key);
59162306a36Sopenharmony_ci			exit(1);
59262306a36Sopenharmony_ci		} else {
59362306a36Sopenharmony_ci			int status;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci			assert(waitpid(pid, &status, 0) == pid);
59662306a36Sopenharmony_ci			assert(status == 0);
59762306a36Sopenharmony_ci			key++;
59862306a36Sopenharmony_ci		}
59962306a36Sopenharmony_ci	}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	close(map_fd);
60262306a36Sopenharmony_ci	/* At least one key should be tested */
60362306a36Sopenharmony_ci	assert(key > 0);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	printf("Pass\n");
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci/* Test list rotation for BPF_F_NO_COMMON_LRU map */
60962306a36Sopenharmony_cistatic void test_lru_sanity6(int map_type, int map_flags, int tgt_free)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	int lru_map_fd, expected_map_fd;
61262306a36Sopenharmony_ci	unsigned long long key, value[nr_cpus];
61362306a36Sopenharmony_ci	unsigned int map_size = tgt_free * 2;
61462306a36Sopenharmony_ci	int next_cpu = 0;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	if (!(map_flags & BPF_F_NO_COMMON_LRU))
61762306a36Sopenharmony_ci		return;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
62062306a36Sopenharmony_ci	       map_flags);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	assert(sched_next_online(0, &next_cpu) != -1);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size);
62562306a36Sopenharmony_ci	assert(expected_map_fd != -1);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	lru_map_fd = create_map(map_type, map_flags, map_size * nr_cpus);
62862306a36Sopenharmony_ci	assert(lru_map_fd != -1);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	value[0] = 1234;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	for (key = 1; key <= tgt_free; key++) {
63362306a36Sopenharmony_ci		assert(!bpf_map_update_elem(lru_map_fd, &key, value,
63462306a36Sopenharmony_ci					    BPF_NOEXIST));
63562306a36Sopenharmony_ci		assert(!bpf_map_update_elem(expected_map_fd, &key, value,
63662306a36Sopenharmony_ci					    BPF_NOEXIST));
63762306a36Sopenharmony_ci	}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	for (; key <= tgt_free * 2; key++) {
64062306a36Sopenharmony_ci		unsigned long long stable_key;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci		/* Make ref bit sticky for key: [1, tgt_free] */
64362306a36Sopenharmony_ci		for (stable_key = 1; stable_key <= tgt_free; stable_key++) {
64462306a36Sopenharmony_ci			/* Mark the ref bit */
64562306a36Sopenharmony_ci			assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd,
64662306a36Sopenharmony_ci								 stable_key, value));
64762306a36Sopenharmony_ci		}
64862306a36Sopenharmony_ci		assert(!bpf_map_update_elem(lru_map_fd, &key, value,
64962306a36Sopenharmony_ci					    BPF_NOEXIST));
65062306a36Sopenharmony_ci	}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	for (; key <= tgt_free * 3; key++) {
65362306a36Sopenharmony_ci		assert(!bpf_map_update_elem(lru_map_fd, &key, value,
65462306a36Sopenharmony_ci					    BPF_NOEXIST));
65562306a36Sopenharmony_ci		assert(!bpf_map_update_elem(expected_map_fd, &key, value,
65662306a36Sopenharmony_ci					    BPF_NOEXIST));
65762306a36Sopenharmony_ci	}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	assert(map_equal(lru_map_fd, expected_map_fd));
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	close(expected_map_fd);
66262306a36Sopenharmony_ci	close(lru_map_fd);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	printf("Pass\n");
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci/* Size of the LRU map is 2
66862306a36Sopenharmony_ci * Add key=1 (+1 key)
66962306a36Sopenharmony_ci * Add key=2 (+1 key)
67062306a36Sopenharmony_ci * Lookup Key=1 (datapath)
67162306a36Sopenharmony_ci * Lookup Key=2 (syscall)
67262306a36Sopenharmony_ci * Add Key=3
67362306a36Sopenharmony_ci *   => Key=2 will be removed by LRU
67462306a36Sopenharmony_ci * Iterate map.  Only found key=1 and key=3
67562306a36Sopenharmony_ci */
67662306a36Sopenharmony_cistatic void test_lru_sanity7(int map_type, int map_flags)
67762306a36Sopenharmony_ci{
67862306a36Sopenharmony_ci	unsigned long long key, value[nr_cpus];
67962306a36Sopenharmony_ci	int lru_map_fd, expected_map_fd;
68062306a36Sopenharmony_ci	int next_cpu = 0;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
68362306a36Sopenharmony_ci	       map_flags);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	assert(sched_next_online(0, &next_cpu) != -1);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	if (map_flags & BPF_F_NO_COMMON_LRU)
68862306a36Sopenharmony_ci		lru_map_fd = create_map(map_type, map_flags, 2 * nr_cpus);
68962306a36Sopenharmony_ci	else
69062306a36Sopenharmony_ci		lru_map_fd = create_map(map_type, map_flags, 2);
69162306a36Sopenharmony_ci	assert(lru_map_fd != -1);
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, 2);
69462306a36Sopenharmony_ci	assert(expected_map_fd != -1);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	value[0] = 1234;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	/* insert key=1 element */
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	key = 1;
70162306a36Sopenharmony_ci	assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
70262306a36Sopenharmony_ci	assert(!bpf_map_update_elem(expected_map_fd, &key, value,
70362306a36Sopenharmony_ci				    BPF_NOEXIST));
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	/* BPF_NOEXIST means: add new element if it doesn't exist */
70662306a36Sopenharmony_ci	assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST) == -EEXIST);
70762306a36Sopenharmony_ci	/* key=1 already exists */
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	/* insert key=2 element */
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	/* check that key=2 is not found */
71262306a36Sopenharmony_ci	key = 2;
71362306a36Sopenharmony_ci	assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	/* BPF_EXIST means: update existing element */
71662306a36Sopenharmony_ci	assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_EXIST) == -ENOENT);
71762306a36Sopenharmony_ci	/* key=2 is not there */
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	/* insert key=3 element */
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	/* check that key=3 is not found */
72462306a36Sopenharmony_ci	key = 3;
72562306a36Sopenharmony_ci	assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	/* check that key=1 can be found and mark the ref bit to
72862306a36Sopenharmony_ci	 * stop LRU from removing key=1
72962306a36Sopenharmony_ci	 */
73062306a36Sopenharmony_ci	key = 1;
73162306a36Sopenharmony_ci	assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
73262306a36Sopenharmony_ci	assert(value[0] == 1234);
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	/* check that key=2 can be found and do _not_ mark ref bit.
73562306a36Sopenharmony_ci	 * this will be evicted on next update.
73662306a36Sopenharmony_ci	 */
73762306a36Sopenharmony_ci	key = 2;
73862306a36Sopenharmony_ci	assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
73962306a36Sopenharmony_ci	assert(value[0] == 1234);
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	key = 3;
74262306a36Sopenharmony_ci	assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
74362306a36Sopenharmony_ci	assert(!bpf_map_update_elem(expected_map_fd, &key, value,
74462306a36Sopenharmony_ci				    BPF_NOEXIST));
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	/* key=2 has been removed from the LRU */
74762306a36Sopenharmony_ci	key = 2;
74862306a36Sopenharmony_ci	assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	assert(map_equal(lru_map_fd, expected_map_fd));
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	close(expected_map_fd);
75362306a36Sopenharmony_ci	close(lru_map_fd);
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	printf("Pass\n");
75662306a36Sopenharmony_ci}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci/* Size of the LRU map is 2
75962306a36Sopenharmony_ci * Add key=1 (+1 key)
76062306a36Sopenharmony_ci * Add key=2 (+1 key)
76162306a36Sopenharmony_ci * Lookup Key=1 (syscall)
76262306a36Sopenharmony_ci * Lookup Key=2 (datapath)
76362306a36Sopenharmony_ci * Add Key=3
76462306a36Sopenharmony_ci *   => Key=1 will be removed by LRU
76562306a36Sopenharmony_ci * Iterate map.  Only found key=2 and key=3
76662306a36Sopenharmony_ci */
76762306a36Sopenharmony_cistatic void test_lru_sanity8(int map_type, int map_flags)
76862306a36Sopenharmony_ci{
76962306a36Sopenharmony_ci	unsigned long long key, value[nr_cpus];
77062306a36Sopenharmony_ci	int lru_map_fd, expected_map_fd;
77162306a36Sopenharmony_ci	int next_cpu = 0;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
77462306a36Sopenharmony_ci	       map_flags);
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	assert(sched_next_online(0, &next_cpu) != -1);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	if (map_flags & BPF_F_NO_COMMON_LRU)
77962306a36Sopenharmony_ci		lru_map_fd = create_map(map_type, map_flags, 2 * nr_cpus);
78062306a36Sopenharmony_ci	else
78162306a36Sopenharmony_ci		lru_map_fd = create_map(map_type, map_flags, 2);
78262306a36Sopenharmony_ci	assert(lru_map_fd != -1);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, 2);
78562306a36Sopenharmony_ci	assert(expected_map_fd != -1);
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	value[0] = 1234;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	/* insert key=1 element */
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	key = 1;
79262306a36Sopenharmony_ci	assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	/* BPF_NOEXIST means: add new element if it doesn't exist */
79562306a36Sopenharmony_ci	assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST) == -EEXIST);
79662306a36Sopenharmony_ci	/* key=1 already exists */
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	/* insert key=2 element */
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	/* check that key=2 is not found */
80162306a36Sopenharmony_ci	key = 2;
80262306a36Sopenharmony_ci	assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	/* BPF_EXIST means: update existing element */
80562306a36Sopenharmony_ci	assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_EXIST) == -ENOENT);
80662306a36Sopenharmony_ci	/* key=2 is not there */
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
80962306a36Sopenharmony_ci	assert(!bpf_map_update_elem(expected_map_fd, &key, value,
81062306a36Sopenharmony_ci				    BPF_NOEXIST));
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	/* insert key=3 element */
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	/* check that key=3 is not found */
81562306a36Sopenharmony_ci	key = 3;
81662306a36Sopenharmony_ci	assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	/* check that key=1 can be found and do _not_ mark ref bit.
81962306a36Sopenharmony_ci	 * this will be evicted on next update.
82062306a36Sopenharmony_ci	 */
82162306a36Sopenharmony_ci	key = 1;
82262306a36Sopenharmony_ci	assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
82362306a36Sopenharmony_ci	assert(value[0] == 1234);
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	/* check that key=2 can be found and mark the ref bit to
82662306a36Sopenharmony_ci	 * stop LRU from removing key=2
82762306a36Sopenharmony_ci	 */
82862306a36Sopenharmony_ci	key = 2;
82962306a36Sopenharmony_ci	assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
83062306a36Sopenharmony_ci	assert(value[0] == 1234);
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	key = 3;
83362306a36Sopenharmony_ci	assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
83462306a36Sopenharmony_ci	assert(!bpf_map_update_elem(expected_map_fd, &key, value,
83562306a36Sopenharmony_ci				    BPF_NOEXIST));
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	/* key=1 has been removed from the LRU */
83862306a36Sopenharmony_ci	key = 1;
83962306a36Sopenharmony_ci	assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -ENOENT);
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	assert(map_equal(lru_map_fd, expected_map_fd));
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	close(expected_map_fd);
84462306a36Sopenharmony_ci	close(lru_map_fd);
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	printf("Pass\n");
84762306a36Sopenharmony_ci}
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ciint main(int argc, char **argv)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	int map_types[] = {BPF_MAP_TYPE_LRU_HASH,
85262306a36Sopenharmony_ci			     BPF_MAP_TYPE_LRU_PERCPU_HASH};
85362306a36Sopenharmony_ci	int map_flags[] = {0, BPF_F_NO_COMMON_LRU};
85462306a36Sopenharmony_ci	int t, f;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	setbuf(stdout, NULL);
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	nr_cpus = bpf_num_possible_cpus();
85962306a36Sopenharmony_ci	assert(nr_cpus != -1);
86062306a36Sopenharmony_ci	printf("nr_cpus:%d\n\n", nr_cpus);
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	/* Use libbpf 1.0 API mode */
86362306a36Sopenharmony_ci	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	for (f = 0; f < ARRAY_SIZE(map_flags); f++) {
86662306a36Sopenharmony_ci		unsigned int tgt_free = (map_flags[f] & BPF_F_NO_COMMON_LRU) ?
86762306a36Sopenharmony_ci			PERCPU_FREE_TARGET : LOCAL_FREE_TARGET;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci		for (t = 0; t < ARRAY_SIZE(map_types); t++) {
87062306a36Sopenharmony_ci			test_lru_sanity0(map_types[t], map_flags[f]);
87162306a36Sopenharmony_ci			test_lru_sanity1(map_types[t], map_flags[f], tgt_free);
87262306a36Sopenharmony_ci			test_lru_sanity2(map_types[t], map_flags[f], tgt_free);
87362306a36Sopenharmony_ci			test_lru_sanity3(map_types[t], map_flags[f], tgt_free);
87462306a36Sopenharmony_ci			test_lru_sanity4(map_types[t], map_flags[f], tgt_free);
87562306a36Sopenharmony_ci			test_lru_sanity5(map_types[t], map_flags[f]);
87662306a36Sopenharmony_ci			test_lru_sanity6(map_types[t], map_flags[f], tgt_free);
87762306a36Sopenharmony_ci			test_lru_sanity7(map_types[t], map_flags[f]);
87862306a36Sopenharmony_ci			test_lru_sanity8(map_types[t], map_flags[f]);
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci			printf("\n");
88162306a36Sopenharmony_ci		}
88262306a36Sopenharmony_ci	}
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	return 0;
88562306a36Sopenharmony_ci}
886