18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2016 Facebook 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#define _GNU_SOURCE 68c2ecf20Sopenharmony_ci#include <stdio.h> 78c2ecf20Sopenharmony_ci#include <unistd.h> 88c2ecf20Sopenharmony_ci#include <errno.h> 98c2ecf20Sopenharmony_ci#include <string.h> 108c2ecf20Sopenharmony_ci#include <assert.h> 118c2ecf20Sopenharmony_ci#include <sched.h> 128c2ecf20Sopenharmony_ci#include <stdlib.h> 138c2ecf20Sopenharmony_ci#include <time.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <sys/wait.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <bpf/bpf.h> 188c2ecf20Sopenharmony_ci#include <bpf/libbpf.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "bpf_util.h" 218c2ecf20Sopenharmony_ci#include "bpf_rlimit.h" 228c2ecf20Sopenharmony_ci#include "../../../include/linux/filter.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define LOCAL_FREE_TARGET (128) 258c2ecf20Sopenharmony_ci#define PERCPU_FREE_TARGET (4) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic int nr_cpus; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic int create_map(int map_type, int map_flags, unsigned int size) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci int map_fd; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci map_fd = bpf_create_map(map_type, sizeof(unsigned long long), 348c2ecf20Sopenharmony_ci sizeof(unsigned long long), size, map_flags); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci if (map_fd == -1) 378c2ecf20Sopenharmony_ci perror("bpf_create_map"); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci return map_fd; 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic int bpf_map_lookup_elem_with_ref_bit(int fd, unsigned long long key, 438c2ecf20Sopenharmony_ci void *value) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct bpf_load_program_attr prog; 468c2ecf20Sopenharmony_ci struct bpf_create_map_attr map; 478c2ecf20Sopenharmony_ci struct bpf_insn insns[] = { 488c2ecf20Sopenharmony_ci BPF_LD_MAP_VALUE(BPF_REG_9, 0, 0), 498c2ecf20Sopenharmony_ci BPF_LD_MAP_FD(BPF_REG_1, fd), 508c2ecf20Sopenharmony_ci BPF_LD_IMM64(BPF_REG_3, key), 518c2ecf20Sopenharmony_ci BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 528c2ecf20Sopenharmony_ci BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), 538c2ecf20Sopenharmony_ci BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, 0), 548c2ecf20Sopenharmony_ci BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), 558c2ecf20Sopenharmony_ci BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), 568c2ecf20Sopenharmony_ci BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0), 578c2ecf20Sopenharmony_ci BPF_STX_MEM(BPF_DW, BPF_REG_9, BPF_REG_1, 0), 588c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 42), 598c2ecf20Sopenharmony_ci BPF_JMP_IMM(BPF_JA, 0, 0, 1), 608c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 1), 618c2ecf20Sopenharmony_ci BPF_EXIT_INSN(), 628c2ecf20Sopenharmony_ci }; 638c2ecf20Sopenharmony_ci __u8 data[64] = {}; 648c2ecf20Sopenharmony_ci int mfd, pfd, ret, zero = 0; 658c2ecf20Sopenharmony_ci __u32 retval = 0; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci memset(&map, 0, sizeof(map)); 688c2ecf20Sopenharmony_ci map.map_type = BPF_MAP_TYPE_ARRAY; 698c2ecf20Sopenharmony_ci map.key_size = sizeof(int); 708c2ecf20Sopenharmony_ci map.value_size = sizeof(unsigned long long); 718c2ecf20Sopenharmony_ci map.max_entries = 1; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci mfd = bpf_create_map_xattr(&map); 748c2ecf20Sopenharmony_ci if (mfd < 0) 758c2ecf20Sopenharmony_ci return -1; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci insns[0].imm = mfd; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci memset(&prog, 0, sizeof(prog)); 808c2ecf20Sopenharmony_ci prog.prog_type = BPF_PROG_TYPE_SCHED_CLS; 818c2ecf20Sopenharmony_ci prog.insns = insns; 828c2ecf20Sopenharmony_ci prog.insns_cnt = ARRAY_SIZE(insns); 838c2ecf20Sopenharmony_ci prog.license = "GPL"; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci pfd = bpf_load_program_xattr(&prog, NULL, 0); 868c2ecf20Sopenharmony_ci if (pfd < 0) { 878c2ecf20Sopenharmony_ci close(mfd); 888c2ecf20Sopenharmony_ci return -1; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci ret = bpf_prog_test_run(pfd, 1, data, sizeof(data), 928c2ecf20Sopenharmony_ci NULL, NULL, &retval, NULL); 938c2ecf20Sopenharmony_ci if (ret < 0 || retval != 42) { 948c2ecf20Sopenharmony_ci ret = -1; 958c2ecf20Sopenharmony_ci } else { 968c2ecf20Sopenharmony_ci assert(!bpf_map_lookup_elem(mfd, &zero, value)); 978c2ecf20Sopenharmony_ci ret = 0; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci close(pfd); 1008c2ecf20Sopenharmony_ci close(mfd); 1018c2ecf20Sopenharmony_ci return ret; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic int map_subset(int map0, int map1) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci unsigned long long next_key = 0; 1078c2ecf20Sopenharmony_ci unsigned long long value0[nr_cpus], value1[nr_cpus]; 1088c2ecf20Sopenharmony_ci int ret; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci while (!bpf_map_get_next_key(map1, &next_key, &next_key)) { 1118c2ecf20Sopenharmony_ci assert(!bpf_map_lookup_elem(map1, &next_key, value1)); 1128c2ecf20Sopenharmony_ci ret = bpf_map_lookup_elem(map0, &next_key, value0); 1138c2ecf20Sopenharmony_ci if (ret) { 1148c2ecf20Sopenharmony_ci printf("key:%llu not found from map. %s(%d)\n", 1158c2ecf20Sopenharmony_ci next_key, strerror(errno), errno); 1168c2ecf20Sopenharmony_ci return 0; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci if (value0[0] != value1[0]) { 1198c2ecf20Sopenharmony_ci printf("key:%llu value0:%llu != value1:%llu\n", 1208c2ecf20Sopenharmony_ci next_key, value0[0], value1[0]); 1218c2ecf20Sopenharmony_ci return 0; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci return 1; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic int map_equal(int lru_map, int expected) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci return map_subset(lru_map, expected) && map_subset(expected, lru_map); 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int sched_next_online(int pid, int *next_to_try) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci cpu_set_t cpuset; 1358c2ecf20Sopenharmony_ci int next = *next_to_try; 1368c2ecf20Sopenharmony_ci int ret = -1; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci while (next < nr_cpus) { 1398c2ecf20Sopenharmony_ci CPU_ZERO(&cpuset); 1408c2ecf20Sopenharmony_ci CPU_SET(next++, &cpuset); 1418c2ecf20Sopenharmony_ci if (!sched_setaffinity(pid, sizeof(cpuset), &cpuset)) { 1428c2ecf20Sopenharmony_ci ret = 0; 1438c2ecf20Sopenharmony_ci break; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci *next_to_try = next; 1488c2ecf20Sopenharmony_ci return ret; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/* Size of the LRU map is 2 1528c2ecf20Sopenharmony_ci * Add key=1 (+1 key) 1538c2ecf20Sopenharmony_ci * Add key=2 (+1 key) 1548c2ecf20Sopenharmony_ci * Lookup Key=1 1558c2ecf20Sopenharmony_ci * Add Key=3 1568c2ecf20Sopenharmony_ci * => Key=2 will be removed by LRU 1578c2ecf20Sopenharmony_ci * Iterate map. Only found key=1 and key=3 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_cistatic void test_lru_sanity0(int map_type, int map_flags) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci unsigned long long key, value[nr_cpus]; 1628c2ecf20Sopenharmony_ci int lru_map_fd, expected_map_fd; 1638c2ecf20Sopenharmony_ci int next_cpu = 0; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type, 1668c2ecf20Sopenharmony_ci map_flags); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci assert(sched_next_online(0, &next_cpu) != -1); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (map_flags & BPF_F_NO_COMMON_LRU) 1718c2ecf20Sopenharmony_ci lru_map_fd = create_map(map_type, map_flags, 2 * nr_cpus); 1728c2ecf20Sopenharmony_ci else 1738c2ecf20Sopenharmony_ci lru_map_fd = create_map(map_type, map_flags, 2); 1748c2ecf20Sopenharmony_ci assert(lru_map_fd != -1); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, 2); 1778c2ecf20Sopenharmony_ci assert(expected_map_fd != -1); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci value[0] = 1234; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci /* insert key=1 element */ 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci key = 1; 1848c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST)); 1858c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(expected_map_fd, &key, value, 1868c2ecf20Sopenharmony_ci BPF_NOEXIST)); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* BPF_NOEXIST means: add new element if it doesn't exist */ 1898c2ecf20Sopenharmony_ci assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST) == -1 1908c2ecf20Sopenharmony_ci /* key=1 already exists */ 1918c2ecf20Sopenharmony_ci && errno == EEXIST); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci assert(bpf_map_update_elem(lru_map_fd, &key, value, -1) == -1 && 1948c2ecf20Sopenharmony_ci errno == EINVAL); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* insert key=2 element */ 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* check that key=2 is not found */ 1998c2ecf20Sopenharmony_ci key = 2; 2008c2ecf20Sopenharmony_ci assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 && 2018c2ecf20Sopenharmony_ci errno == ENOENT); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* BPF_EXIST means: update existing element */ 2048c2ecf20Sopenharmony_ci assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_EXIST) == -1 && 2058c2ecf20Sopenharmony_ci /* key=2 is not there */ 2068c2ecf20Sopenharmony_ci errno == ENOENT); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST)); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* insert key=3 element */ 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* check that key=3 is not found */ 2138c2ecf20Sopenharmony_ci key = 3; 2148c2ecf20Sopenharmony_ci assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 && 2158c2ecf20Sopenharmony_ci errno == ENOENT); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* check that key=1 can be found and mark the ref bit to 2188c2ecf20Sopenharmony_ci * stop LRU from removing key=1 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_ci key = 1; 2218c2ecf20Sopenharmony_ci assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value)); 2228c2ecf20Sopenharmony_ci assert(value[0] == 1234); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci key = 3; 2258c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST)); 2268c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(expected_map_fd, &key, value, 2278c2ecf20Sopenharmony_ci BPF_NOEXIST)); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* key=2 has been removed from the LRU */ 2308c2ecf20Sopenharmony_ci key = 2; 2318c2ecf20Sopenharmony_ci assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 && 2328c2ecf20Sopenharmony_ci errno == ENOENT); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci assert(map_equal(lru_map_fd, expected_map_fd)); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci close(expected_map_fd); 2378c2ecf20Sopenharmony_ci close(lru_map_fd); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci printf("Pass\n"); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci/* Size of the LRU map is 1.5*tgt_free 2438c2ecf20Sopenharmony_ci * Insert 1 to tgt_free (+tgt_free keys) 2448c2ecf20Sopenharmony_ci * Lookup 1 to tgt_free/2 2458c2ecf20Sopenharmony_ci * Insert 1+tgt_free to 2*tgt_free (+tgt_free keys) 2468c2ecf20Sopenharmony_ci * => 1+tgt_free/2 to LOCALFREE_TARGET will be removed by LRU 2478c2ecf20Sopenharmony_ci */ 2488c2ecf20Sopenharmony_cistatic void test_lru_sanity1(int map_type, int map_flags, unsigned int tgt_free) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci unsigned long long key, end_key, value[nr_cpus]; 2518c2ecf20Sopenharmony_ci int lru_map_fd, expected_map_fd; 2528c2ecf20Sopenharmony_ci unsigned int batch_size; 2538c2ecf20Sopenharmony_ci unsigned int map_size; 2548c2ecf20Sopenharmony_ci int next_cpu = 0; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (map_flags & BPF_F_NO_COMMON_LRU) 2578c2ecf20Sopenharmony_ci /* This test is only applicable to common LRU list */ 2588c2ecf20Sopenharmony_ci return; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type, 2618c2ecf20Sopenharmony_ci map_flags); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci assert(sched_next_online(0, &next_cpu) != -1); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci batch_size = tgt_free / 2; 2668c2ecf20Sopenharmony_ci assert(batch_size * 2 == tgt_free); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci map_size = tgt_free + batch_size; 2698c2ecf20Sopenharmony_ci lru_map_fd = create_map(map_type, map_flags, map_size); 2708c2ecf20Sopenharmony_ci assert(lru_map_fd != -1); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size); 2738c2ecf20Sopenharmony_ci assert(expected_map_fd != -1); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci value[0] = 1234; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* Insert 1 to tgt_free (+tgt_free keys) */ 2788c2ecf20Sopenharmony_ci end_key = 1 + tgt_free; 2798c2ecf20Sopenharmony_ci for (key = 1; key < end_key; key++) 2808c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, 2818c2ecf20Sopenharmony_ci BPF_NOEXIST)); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* Lookup 1 to tgt_free/2 */ 2848c2ecf20Sopenharmony_ci end_key = 1 + batch_size; 2858c2ecf20Sopenharmony_ci for (key = 1; key < end_key; key++) { 2868c2ecf20Sopenharmony_ci assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value)); 2878c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(expected_map_fd, &key, value, 2888c2ecf20Sopenharmony_ci BPF_NOEXIST)); 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* Insert 1+tgt_free to 2*tgt_free 2928c2ecf20Sopenharmony_ci * => 1+tgt_free/2 to LOCALFREE_TARGET will be 2938c2ecf20Sopenharmony_ci * removed by LRU 2948c2ecf20Sopenharmony_ci */ 2958c2ecf20Sopenharmony_ci key = 1 + tgt_free; 2968c2ecf20Sopenharmony_ci end_key = key + tgt_free; 2978c2ecf20Sopenharmony_ci for (; key < end_key; key++) { 2988c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, 2998c2ecf20Sopenharmony_ci BPF_NOEXIST)); 3008c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(expected_map_fd, &key, value, 3018c2ecf20Sopenharmony_ci BPF_NOEXIST)); 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci assert(map_equal(lru_map_fd, expected_map_fd)); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci close(expected_map_fd); 3078c2ecf20Sopenharmony_ci close(lru_map_fd); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci printf("Pass\n"); 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci/* Size of the LRU map 1.5 * tgt_free 3138c2ecf20Sopenharmony_ci * Insert 1 to tgt_free (+tgt_free keys) 3148c2ecf20Sopenharmony_ci * Update 1 to tgt_free/2 3158c2ecf20Sopenharmony_ci * => The original 1 to tgt_free/2 will be removed due to 3168c2ecf20Sopenharmony_ci * the LRU shrink process 3178c2ecf20Sopenharmony_ci * Re-insert 1 to tgt_free/2 again and do a lookup immeidately 3188c2ecf20Sopenharmony_ci * Insert 1+tgt_free to tgt_free*3/2 3198c2ecf20Sopenharmony_ci * Insert 1+tgt_free*3/2 to tgt_free*5/2 3208c2ecf20Sopenharmony_ci * => Key 1+tgt_free to tgt_free*3/2 3218c2ecf20Sopenharmony_ci * will be removed from LRU because it has never 3228c2ecf20Sopenharmony_ci * been lookup and ref bit is not set 3238c2ecf20Sopenharmony_ci */ 3248c2ecf20Sopenharmony_cistatic void test_lru_sanity2(int map_type, int map_flags, unsigned int tgt_free) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci unsigned long long key, value[nr_cpus]; 3278c2ecf20Sopenharmony_ci unsigned long long end_key; 3288c2ecf20Sopenharmony_ci int lru_map_fd, expected_map_fd; 3298c2ecf20Sopenharmony_ci unsigned int batch_size; 3308c2ecf20Sopenharmony_ci unsigned int map_size; 3318c2ecf20Sopenharmony_ci int next_cpu = 0; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (map_flags & BPF_F_NO_COMMON_LRU) 3348c2ecf20Sopenharmony_ci /* This test is only applicable to common LRU list */ 3358c2ecf20Sopenharmony_ci return; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type, 3388c2ecf20Sopenharmony_ci map_flags); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci assert(sched_next_online(0, &next_cpu) != -1); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci batch_size = tgt_free / 2; 3438c2ecf20Sopenharmony_ci assert(batch_size * 2 == tgt_free); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci map_size = tgt_free + batch_size; 3468c2ecf20Sopenharmony_ci lru_map_fd = create_map(map_type, map_flags, map_size); 3478c2ecf20Sopenharmony_ci assert(lru_map_fd != -1); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size); 3508c2ecf20Sopenharmony_ci assert(expected_map_fd != -1); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci value[0] = 1234; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* Insert 1 to tgt_free (+tgt_free keys) */ 3558c2ecf20Sopenharmony_ci end_key = 1 + tgt_free; 3568c2ecf20Sopenharmony_ci for (key = 1; key < end_key; key++) 3578c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, 3588c2ecf20Sopenharmony_ci BPF_NOEXIST)); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* Any bpf_map_update_elem will require to acquire a new node 3618c2ecf20Sopenharmony_ci * from LRU first. 3628c2ecf20Sopenharmony_ci * 3638c2ecf20Sopenharmony_ci * The local list is running out of free nodes. 3648c2ecf20Sopenharmony_ci * It gets from the global LRU list which tries to 3658c2ecf20Sopenharmony_ci * shrink the inactive list to get tgt_free 3668c2ecf20Sopenharmony_ci * number of free nodes. 3678c2ecf20Sopenharmony_ci * 3688c2ecf20Sopenharmony_ci * Hence, the oldest key 1 to tgt_free/2 3698c2ecf20Sopenharmony_ci * are removed from the LRU list. 3708c2ecf20Sopenharmony_ci */ 3718c2ecf20Sopenharmony_ci key = 1; 3728c2ecf20Sopenharmony_ci if (map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) { 3738c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, 3748c2ecf20Sopenharmony_ci BPF_NOEXIST)); 3758c2ecf20Sopenharmony_ci assert(!bpf_map_delete_elem(lru_map_fd, &key)); 3768c2ecf20Sopenharmony_ci } else { 3778c2ecf20Sopenharmony_ci assert(bpf_map_update_elem(lru_map_fd, &key, value, 3788c2ecf20Sopenharmony_ci BPF_EXIST)); 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* Re-insert 1 to tgt_free/2 again and do a lookup 3828c2ecf20Sopenharmony_ci * immeidately. 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_ci end_key = 1 + batch_size; 3858c2ecf20Sopenharmony_ci value[0] = 4321; 3868c2ecf20Sopenharmony_ci for (key = 1; key < end_key; key++) { 3878c2ecf20Sopenharmony_ci assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 && 3888c2ecf20Sopenharmony_ci errno == ENOENT); 3898c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, 3908c2ecf20Sopenharmony_ci BPF_NOEXIST)); 3918c2ecf20Sopenharmony_ci assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value)); 3928c2ecf20Sopenharmony_ci assert(value[0] == 4321); 3938c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(expected_map_fd, &key, value, 3948c2ecf20Sopenharmony_ci BPF_NOEXIST)); 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci value[0] = 1234; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* Insert 1+tgt_free to tgt_free*3/2 */ 4008c2ecf20Sopenharmony_ci end_key = 1 + tgt_free + batch_size; 4018c2ecf20Sopenharmony_ci for (key = 1 + tgt_free; key < end_key; key++) 4028c2ecf20Sopenharmony_ci /* These newly added but not referenced keys will be 4038c2ecf20Sopenharmony_ci * gone during the next LRU shrink. 4048c2ecf20Sopenharmony_ci */ 4058c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, 4068c2ecf20Sopenharmony_ci BPF_NOEXIST)); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* Insert 1+tgt_free*3/2 to tgt_free*5/2 */ 4098c2ecf20Sopenharmony_ci end_key = key + tgt_free; 4108c2ecf20Sopenharmony_ci for (; key < end_key; key++) { 4118c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, 4128c2ecf20Sopenharmony_ci BPF_NOEXIST)); 4138c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(expected_map_fd, &key, value, 4148c2ecf20Sopenharmony_ci BPF_NOEXIST)); 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci assert(map_equal(lru_map_fd, expected_map_fd)); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci close(expected_map_fd); 4208c2ecf20Sopenharmony_ci close(lru_map_fd); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci printf("Pass\n"); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci/* Size of the LRU map is 2*tgt_free 4268c2ecf20Sopenharmony_ci * It is to test the active/inactive list rotation 4278c2ecf20Sopenharmony_ci * Insert 1 to 2*tgt_free (+2*tgt_free keys) 4288c2ecf20Sopenharmony_ci * Lookup key 1 to tgt_free*3/2 4298c2ecf20Sopenharmony_ci * Add 1+2*tgt_free to tgt_free*5/2 (+tgt_free/2 keys) 4308c2ecf20Sopenharmony_ci * => key 1+tgt_free*3/2 to 2*tgt_free are removed from LRU 4318c2ecf20Sopenharmony_ci */ 4328c2ecf20Sopenharmony_cistatic void test_lru_sanity3(int map_type, int map_flags, unsigned int tgt_free) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci unsigned long long key, end_key, value[nr_cpus]; 4358c2ecf20Sopenharmony_ci int lru_map_fd, expected_map_fd; 4368c2ecf20Sopenharmony_ci unsigned int batch_size; 4378c2ecf20Sopenharmony_ci unsigned int map_size; 4388c2ecf20Sopenharmony_ci int next_cpu = 0; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (map_flags & BPF_F_NO_COMMON_LRU) 4418c2ecf20Sopenharmony_ci /* This test is only applicable to common LRU list */ 4428c2ecf20Sopenharmony_ci return; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type, 4458c2ecf20Sopenharmony_ci map_flags); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci assert(sched_next_online(0, &next_cpu) != -1); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci batch_size = tgt_free / 2; 4508c2ecf20Sopenharmony_ci assert(batch_size * 2 == tgt_free); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci map_size = tgt_free * 2; 4538c2ecf20Sopenharmony_ci lru_map_fd = create_map(map_type, map_flags, map_size); 4548c2ecf20Sopenharmony_ci assert(lru_map_fd != -1); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size); 4578c2ecf20Sopenharmony_ci assert(expected_map_fd != -1); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci value[0] = 1234; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* Insert 1 to 2*tgt_free (+2*tgt_free keys) */ 4628c2ecf20Sopenharmony_ci end_key = 1 + (2 * tgt_free); 4638c2ecf20Sopenharmony_ci for (key = 1; key < end_key; key++) 4648c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, 4658c2ecf20Sopenharmony_ci BPF_NOEXIST)); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* Lookup key 1 to tgt_free*3/2 */ 4688c2ecf20Sopenharmony_ci end_key = tgt_free + batch_size; 4698c2ecf20Sopenharmony_ci for (key = 1; key < end_key; key++) { 4708c2ecf20Sopenharmony_ci assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value)); 4718c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(expected_map_fd, &key, value, 4728c2ecf20Sopenharmony_ci BPF_NOEXIST)); 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* Add 1+2*tgt_free to tgt_free*5/2 4768c2ecf20Sopenharmony_ci * (+tgt_free/2 keys) 4778c2ecf20Sopenharmony_ci */ 4788c2ecf20Sopenharmony_ci key = 2 * tgt_free + 1; 4798c2ecf20Sopenharmony_ci end_key = key + batch_size; 4808c2ecf20Sopenharmony_ci for (; key < end_key; key++) { 4818c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, 4828c2ecf20Sopenharmony_ci BPF_NOEXIST)); 4838c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(expected_map_fd, &key, value, 4848c2ecf20Sopenharmony_ci BPF_NOEXIST)); 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci assert(map_equal(lru_map_fd, expected_map_fd)); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci close(expected_map_fd); 4908c2ecf20Sopenharmony_ci close(lru_map_fd); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci printf("Pass\n"); 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci/* Test deletion */ 4968c2ecf20Sopenharmony_cistatic void test_lru_sanity4(int map_type, int map_flags, unsigned int tgt_free) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci int lru_map_fd, expected_map_fd; 4998c2ecf20Sopenharmony_ci unsigned long long key, value[nr_cpus]; 5008c2ecf20Sopenharmony_ci unsigned long long end_key; 5018c2ecf20Sopenharmony_ci int next_cpu = 0; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type, 5048c2ecf20Sopenharmony_ci map_flags); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci assert(sched_next_online(0, &next_cpu) != -1); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci if (map_flags & BPF_F_NO_COMMON_LRU) 5098c2ecf20Sopenharmony_ci lru_map_fd = create_map(map_type, map_flags, 5108c2ecf20Sopenharmony_ci 3 * tgt_free * nr_cpus); 5118c2ecf20Sopenharmony_ci else 5128c2ecf20Sopenharmony_ci lru_map_fd = create_map(map_type, map_flags, 3 * tgt_free); 5138c2ecf20Sopenharmony_ci assert(lru_map_fd != -1); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, 5168c2ecf20Sopenharmony_ci 3 * tgt_free); 5178c2ecf20Sopenharmony_ci assert(expected_map_fd != -1); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci value[0] = 1234; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci for (key = 1; key <= 2 * tgt_free; key++) 5228c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, 5238c2ecf20Sopenharmony_ci BPF_NOEXIST)); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci key = 1; 5268c2ecf20Sopenharmony_ci assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST)); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci for (key = 1; key <= tgt_free; key++) { 5298c2ecf20Sopenharmony_ci assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value)); 5308c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(expected_map_fd, &key, value, 5318c2ecf20Sopenharmony_ci BPF_NOEXIST)); 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci for (; key <= 2 * tgt_free; key++) { 5358c2ecf20Sopenharmony_ci assert(!bpf_map_delete_elem(lru_map_fd, &key)); 5368c2ecf20Sopenharmony_ci assert(bpf_map_delete_elem(lru_map_fd, &key)); 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci end_key = key + 2 * tgt_free; 5408c2ecf20Sopenharmony_ci for (; key < end_key; key++) { 5418c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, 5428c2ecf20Sopenharmony_ci BPF_NOEXIST)); 5438c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(expected_map_fd, &key, value, 5448c2ecf20Sopenharmony_ci BPF_NOEXIST)); 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci assert(map_equal(lru_map_fd, expected_map_fd)); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci close(expected_map_fd); 5508c2ecf20Sopenharmony_ci close(lru_map_fd); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci printf("Pass\n"); 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic void do_test_lru_sanity5(unsigned long long last_key, int map_fd) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci unsigned long long key, value[nr_cpus]; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* Ensure the last key inserted by previous CPU can be found */ 5608c2ecf20Sopenharmony_ci assert(!bpf_map_lookup_elem_with_ref_bit(map_fd, last_key, value)); 5618c2ecf20Sopenharmony_ci value[0] = 1234; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci key = last_key + 1; 5648c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST)); 5658c2ecf20Sopenharmony_ci assert(!bpf_map_lookup_elem_with_ref_bit(map_fd, key, value)); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* Cannot find the last key because it was removed by LRU */ 5688c2ecf20Sopenharmony_ci assert(bpf_map_lookup_elem(map_fd, &last_key, value) == -1 && 5698c2ecf20Sopenharmony_ci errno == ENOENT); 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci/* Test map with only one element */ 5738c2ecf20Sopenharmony_cistatic void test_lru_sanity5(int map_type, int map_flags) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci unsigned long long key, value[nr_cpus]; 5768c2ecf20Sopenharmony_ci int next_cpu = 0; 5778c2ecf20Sopenharmony_ci int map_fd; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (map_flags & BPF_F_NO_COMMON_LRU) 5808c2ecf20Sopenharmony_ci return; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type, 5838c2ecf20Sopenharmony_ci map_flags); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci map_fd = create_map(map_type, map_flags, 1); 5868c2ecf20Sopenharmony_ci assert(map_fd != -1); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci value[0] = 1234; 5898c2ecf20Sopenharmony_ci key = 0; 5908c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST)); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci while (sched_next_online(0, &next_cpu) != -1) { 5938c2ecf20Sopenharmony_ci pid_t pid; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci pid = fork(); 5968c2ecf20Sopenharmony_ci if (pid == 0) { 5978c2ecf20Sopenharmony_ci do_test_lru_sanity5(key, map_fd); 5988c2ecf20Sopenharmony_ci exit(0); 5998c2ecf20Sopenharmony_ci } else if (pid == -1) { 6008c2ecf20Sopenharmony_ci printf("couldn't spawn process to test key:%llu\n", 6018c2ecf20Sopenharmony_ci key); 6028c2ecf20Sopenharmony_ci exit(1); 6038c2ecf20Sopenharmony_ci } else { 6048c2ecf20Sopenharmony_ci int status; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci assert(waitpid(pid, &status, 0) == pid); 6078c2ecf20Sopenharmony_ci assert(status == 0); 6088c2ecf20Sopenharmony_ci key++; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci close(map_fd); 6138c2ecf20Sopenharmony_ci /* At least one key should be tested */ 6148c2ecf20Sopenharmony_ci assert(key > 0); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci printf("Pass\n"); 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci/* Test list rotation for BPF_F_NO_COMMON_LRU map */ 6208c2ecf20Sopenharmony_cistatic void test_lru_sanity6(int map_type, int map_flags, int tgt_free) 6218c2ecf20Sopenharmony_ci{ 6228c2ecf20Sopenharmony_ci int lru_map_fd, expected_map_fd; 6238c2ecf20Sopenharmony_ci unsigned long long key, value[nr_cpus]; 6248c2ecf20Sopenharmony_ci unsigned int map_size = tgt_free * 2; 6258c2ecf20Sopenharmony_ci int next_cpu = 0; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (!(map_flags & BPF_F_NO_COMMON_LRU)) 6288c2ecf20Sopenharmony_ci return; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type, 6318c2ecf20Sopenharmony_ci map_flags); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci assert(sched_next_online(0, &next_cpu) != -1); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size); 6368c2ecf20Sopenharmony_ci assert(expected_map_fd != -1); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci lru_map_fd = create_map(map_type, map_flags, map_size * nr_cpus); 6398c2ecf20Sopenharmony_ci assert(lru_map_fd != -1); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci value[0] = 1234; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci for (key = 1; key <= tgt_free; key++) { 6448c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, 6458c2ecf20Sopenharmony_ci BPF_NOEXIST)); 6468c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(expected_map_fd, &key, value, 6478c2ecf20Sopenharmony_ci BPF_NOEXIST)); 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci for (; key <= tgt_free * 2; key++) { 6518c2ecf20Sopenharmony_ci unsigned long long stable_key; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci /* Make ref bit sticky for key: [1, tgt_free] */ 6548c2ecf20Sopenharmony_ci for (stable_key = 1; stable_key <= tgt_free; stable_key++) { 6558c2ecf20Sopenharmony_ci /* Mark the ref bit */ 6568c2ecf20Sopenharmony_ci assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, 6578c2ecf20Sopenharmony_ci stable_key, value)); 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, 6608c2ecf20Sopenharmony_ci BPF_NOEXIST)); 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci for (; key <= tgt_free * 3; key++) { 6648c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, 6658c2ecf20Sopenharmony_ci BPF_NOEXIST)); 6668c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(expected_map_fd, &key, value, 6678c2ecf20Sopenharmony_ci BPF_NOEXIST)); 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci assert(map_equal(lru_map_fd, expected_map_fd)); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci close(expected_map_fd); 6738c2ecf20Sopenharmony_ci close(lru_map_fd); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci printf("Pass\n"); 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci/* Size of the LRU map is 2 6798c2ecf20Sopenharmony_ci * Add key=1 (+1 key) 6808c2ecf20Sopenharmony_ci * Add key=2 (+1 key) 6818c2ecf20Sopenharmony_ci * Lookup Key=1 (datapath) 6828c2ecf20Sopenharmony_ci * Lookup Key=2 (syscall) 6838c2ecf20Sopenharmony_ci * Add Key=3 6848c2ecf20Sopenharmony_ci * => Key=2 will be removed by LRU 6858c2ecf20Sopenharmony_ci * Iterate map. Only found key=1 and key=3 6868c2ecf20Sopenharmony_ci */ 6878c2ecf20Sopenharmony_cistatic void test_lru_sanity7(int map_type, int map_flags) 6888c2ecf20Sopenharmony_ci{ 6898c2ecf20Sopenharmony_ci unsigned long long key, value[nr_cpus]; 6908c2ecf20Sopenharmony_ci int lru_map_fd, expected_map_fd; 6918c2ecf20Sopenharmony_ci int next_cpu = 0; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type, 6948c2ecf20Sopenharmony_ci map_flags); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci assert(sched_next_online(0, &next_cpu) != -1); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci if (map_flags & BPF_F_NO_COMMON_LRU) 6998c2ecf20Sopenharmony_ci lru_map_fd = create_map(map_type, map_flags, 2 * nr_cpus); 7008c2ecf20Sopenharmony_ci else 7018c2ecf20Sopenharmony_ci lru_map_fd = create_map(map_type, map_flags, 2); 7028c2ecf20Sopenharmony_ci assert(lru_map_fd != -1); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, 2); 7058c2ecf20Sopenharmony_ci assert(expected_map_fd != -1); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci value[0] = 1234; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci /* insert key=1 element */ 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci key = 1; 7128c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST)); 7138c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(expected_map_fd, &key, value, 7148c2ecf20Sopenharmony_ci BPF_NOEXIST)); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci /* BPF_NOEXIST means: add new element if it doesn't exist */ 7178c2ecf20Sopenharmony_ci assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST) == -1 7188c2ecf20Sopenharmony_ci /* key=1 already exists */ 7198c2ecf20Sopenharmony_ci && errno == EEXIST); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci /* insert key=2 element */ 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci /* check that key=2 is not found */ 7248c2ecf20Sopenharmony_ci key = 2; 7258c2ecf20Sopenharmony_ci assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 && 7268c2ecf20Sopenharmony_ci errno == ENOENT); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci /* BPF_EXIST means: update existing element */ 7298c2ecf20Sopenharmony_ci assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_EXIST) == -1 && 7308c2ecf20Sopenharmony_ci /* key=2 is not there */ 7318c2ecf20Sopenharmony_ci errno == ENOENT); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST)); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci /* insert key=3 element */ 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci /* check that key=3 is not found */ 7388c2ecf20Sopenharmony_ci key = 3; 7398c2ecf20Sopenharmony_ci assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 && 7408c2ecf20Sopenharmony_ci errno == ENOENT); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* check that key=1 can be found and mark the ref bit to 7438c2ecf20Sopenharmony_ci * stop LRU from removing key=1 7448c2ecf20Sopenharmony_ci */ 7458c2ecf20Sopenharmony_ci key = 1; 7468c2ecf20Sopenharmony_ci assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value)); 7478c2ecf20Sopenharmony_ci assert(value[0] == 1234); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci /* check that key=2 can be found and do _not_ mark ref bit. 7508c2ecf20Sopenharmony_ci * this will be evicted on next update. 7518c2ecf20Sopenharmony_ci */ 7528c2ecf20Sopenharmony_ci key = 2; 7538c2ecf20Sopenharmony_ci assert(!bpf_map_lookup_elem(lru_map_fd, &key, value)); 7548c2ecf20Sopenharmony_ci assert(value[0] == 1234); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci key = 3; 7578c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST)); 7588c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(expected_map_fd, &key, value, 7598c2ecf20Sopenharmony_ci BPF_NOEXIST)); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci /* key=2 has been removed from the LRU */ 7628c2ecf20Sopenharmony_ci key = 2; 7638c2ecf20Sopenharmony_ci assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 && 7648c2ecf20Sopenharmony_ci errno == ENOENT); 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci assert(map_equal(lru_map_fd, expected_map_fd)); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci close(expected_map_fd); 7698c2ecf20Sopenharmony_ci close(lru_map_fd); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci printf("Pass\n"); 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci/* Size of the LRU map is 2 7758c2ecf20Sopenharmony_ci * Add key=1 (+1 key) 7768c2ecf20Sopenharmony_ci * Add key=2 (+1 key) 7778c2ecf20Sopenharmony_ci * Lookup Key=1 (syscall) 7788c2ecf20Sopenharmony_ci * Lookup Key=2 (datapath) 7798c2ecf20Sopenharmony_ci * Add Key=3 7808c2ecf20Sopenharmony_ci * => Key=1 will be removed by LRU 7818c2ecf20Sopenharmony_ci * Iterate map. Only found key=2 and key=3 7828c2ecf20Sopenharmony_ci */ 7838c2ecf20Sopenharmony_cistatic void test_lru_sanity8(int map_type, int map_flags) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci unsigned long long key, value[nr_cpus]; 7868c2ecf20Sopenharmony_ci int lru_map_fd, expected_map_fd; 7878c2ecf20Sopenharmony_ci int next_cpu = 0; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type, 7908c2ecf20Sopenharmony_ci map_flags); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci assert(sched_next_online(0, &next_cpu) != -1); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci if (map_flags & BPF_F_NO_COMMON_LRU) 7958c2ecf20Sopenharmony_ci lru_map_fd = create_map(map_type, map_flags, 2 * nr_cpus); 7968c2ecf20Sopenharmony_ci else 7978c2ecf20Sopenharmony_ci lru_map_fd = create_map(map_type, map_flags, 2); 7988c2ecf20Sopenharmony_ci assert(lru_map_fd != -1); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, 2); 8018c2ecf20Sopenharmony_ci assert(expected_map_fd != -1); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci value[0] = 1234; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci /* insert key=1 element */ 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci key = 1; 8088c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST)); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci /* BPF_NOEXIST means: add new element if it doesn't exist */ 8118c2ecf20Sopenharmony_ci assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST) == -1 8128c2ecf20Sopenharmony_ci /* key=1 already exists */ 8138c2ecf20Sopenharmony_ci && errno == EEXIST); 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci /* insert key=2 element */ 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci /* check that key=2 is not found */ 8188c2ecf20Sopenharmony_ci key = 2; 8198c2ecf20Sopenharmony_ci assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 && 8208c2ecf20Sopenharmony_ci errno == ENOENT); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci /* BPF_EXIST means: update existing element */ 8238c2ecf20Sopenharmony_ci assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_EXIST) == -1 && 8248c2ecf20Sopenharmony_ci /* key=2 is not there */ 8258c2ecf20Sopenharmony_ci errno == ENOENT); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST)); 8288c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(expected_map_fd, &key, value, 8298c2ecf20Sopenharmony_ci BPF_NOEXIST)); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci /* insert key=3 element */ 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci /* check that key=3 is not found */ 8348c2ecf20Sopenharmony_ci key = 3; 8358c2ecf20Sopenharmony_ci assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 && 8368c2ecf20Sopenharmony_ci errno == ENOENT); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci /* check that key=1 can be found and do _not_ mark ref bit. 8398c2ecf20Sopenharmony_ci * this will be evicted on next update. 8408c2ecf20Sopenharmony_ci */ 8418c2ecf20Sopenharmony_ci key = 1; 8428c2ecf20Sopenharmony_ci assert(!bpf_map_lookup_elem(lru_map_fd, &key, value)); 8438c2ecf20Sopenharmony_ci assert(value[0] == 1234); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci /* check that key=2 can be found and mark the ref bit to 8468c2ecf20Sopenharmony_ci * stop LRU from removing key=2 8478c2ecf20Sopenharmony_ci */ 8488c2ecf20Sopenharmony_ci key = 2; 8498c2ecf20Sopenharmony_ci assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value)); 8508c2ecf20Sopenharmony_ci assert(value[0] == 1234); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci key = 3; 8538c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST)); 8548c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(expected_map_fd, &key, value, 8558c2ecf20Sopenharmony_ci BPF_NOEXIST)); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci /* key=1 has been removed from the LRU */ 8588c2ecf20Sopenharmony_ci key = 1; 8598c2ecf20Sopenharmony_ci assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 && 8608c2ecf20Sopenharmony_ci errno == ENOENT); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci assert(map_equal(lru_map_fd, expected_map_fd)); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci close(expected_map_fd); 8658c2ecf20Sopenharmony_ci close(lru_map_fd); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci printf("Pass\n"); 8688c2ecf20Sopenharmony_ci} 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ciint main(int argc, char **argv) 8718c2ecf20Sopenharmony_ci{ 8728c2ecf20Sopenharmony_ci int map_types[] = {BPF_MAP_TYPE_LRU_HASH, 8738c2ecf20Sopenharmony_ci BPF_MAP_TYPE_LRU_PERCPU_HASH}; 8748c2ecf20Sopenharmony_ci int map_flags[] = {0, BPF_F_NO_COMMON_LRU}; 8758c2ecf20Sopenharmony_ci int t, f; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci setbuf(stdout, NULL); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci nr_cpus = bpf_num_possible_cpus(); 8808c2ecf20Sopenharmony_ci assert(nr_cpus != -1); 8818c2ecf20Sopenharmony_ci printf("nr_cpus:%d\n\n", nr_cpus); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci for (f = 0; f < sizeof(map_flags) / sizeof(*map_flags); f++) { 8848c2ecf20Sopenharmony_ci unsigned int tgt_free = (map_flags[f] & BPF_F_NO_COMMON_LRU) ? 8858c2ecf20Sopenharmony_ci PERCPU_FREE_TARGET : LOCAL_FREE_TARGET; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci for (t = 0; t < sizeof(map_types) / sizeof(*map_types); t++) { 8888c2ecf20Sopenharmony_ci test_lru_sanity0(map_types[t], map_flags[f]); 8898c2ecf20Sopenharmony_ci test_lru_sanity1(map_types[t], map_flags[f], tgt_free); 8908c2ecf20Sopenharmony_ci test_lru_sanity2(map_types[t], map_flags[f], tgt_free); 8918c2ecf20Sopenharmony_ci test_lru_sanity3(map_types[t], map_flags[f], tgt_free); 8928c2ecf20Sopenharmony_ci test_lru_sanity4(map_types[t], map_flags[f], tgt_free); 8938c2ecf20Sopenharmony_ci test_lru_sanity5(map_types[t], map_flags[f]); 8948c2ecf20Sopenharmony_ci test_lru_sanity6(map_types[t], map_flags[f], tgt_free); 8958c2ecf20Sopenharmony_ci test_lru_sanity7(map_types[t], map_flags[f]); 8968c2ecf20Sopenharmony_ci test_lru_sanity8(map_types[t], map_flags[f]); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci printf("\n"); 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci return 0; 9038c2ecf20Sopenharmony_ci} 904