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