1// SPDX-License-Identifier: GPL-2.0 2 3#include <stdio.h> 4#include <errno.h> 5#include <string.h> 6#include <unistd.h> 7 8#include <bpf/bpf.h> 9#include <bpf/libbpf.h> 10 11#include <test_maps.h> 12 13static int nr_cpus; 14 15static void map_batch_update(int map_fd, __u32 max_entries, int *keys, 16 __s64 *values, bool is_pcpu) 17{ 18 int i, j, err; 19 int cpu_offset = 0; 20 DECLARE_LIBBPF_OPTS(bpf_map_batch_opts, opts, 21 .elem_flags = 0, 22 .flags = 0, 23 ); 24 25 for (i = 0; i < max_entries; i++) { 26 keys[i] = i; 27 if (is_pcpu) { 28 cpu_offset = i * nr_cpus; 29 for (j = 0; j < nr_cpus; j++) 30 (values + cpu_offset)[j] = i + 1 + j; 31 } else { 32 values[i] = i + 1; 33 } 34 } 35 36 err = bpf_map_update_batch(map_fd, keys, values, &max_entries, &opts); 37 CHECK(err, "bpf_map_update_batch()", "error:%s\n", strerror(errno)); 38} 39 40static void map_batch_verify(int *visited, __u32 max_entries, int *keys, 41 __s64 *values, bool is_pcpu) 42{ 43 int i, j; 44 int cpu_offset = 0; 45 46 memset(visited, 0, max_entries * sizeof(*visited)); 47 for (i = 0; i < max_entries; i++) { 48 if (is_pcpu) { 49 cpu_offset = i * nr_cpus; 50 for (j = 0; j < nr_cpus; j++) { 51 __s64 value = (values + cpu_offset)[j]; 52 CHECK(keys[i] + j + 1 != value, 53 "key/value checking", 54 "error: i %d j %d key %d value %lld\n", i, 55 j, keys[i], value); 56 } 57 } else { 58 CHECK(keys[i] + 1 != values[i], "key/value checking", 59 "error: i %d key %d value %lld\n", i, keys[i], 60 values[i]); 61 } 62 visited[i] = 1; 63 } 64 for (i = 0; i < max_entries; i++) { 65 CHECK(visited[i] != 1, "visited checking", 66 "error: keys array at index %d missing\n", i); 67 } 68} 69 70static void __test_map_lookup_and_update_batch(bool is_pcpu) 71{ 72 int map_fd, *keys, *visited; 73 __u32 count, total, total_success; 74 const __u32 max_entries = 10; 75 __u64 batch = 0; 76 int err, step, value_size; 77 void *values; 78 DECLARE_LIBBPF_OPTS(bpf_map_batch_opts, opts, 79 .elem_flags = 0, 80 .flags = 0, 81 ); 82 83 map_fd = bpf_map_create(is_pcpu ? BPF_MAP_TYPE_PERCPU_ARRAY : BPF_MAP_TYPE_ARRAY, 84 "array_map", sizeof(int), sizeof(__s64), max_entries, NULL); 85 CHECK(map_fd == -1, 86 "bpf_map_create()", "error:%s\n", strerror(errno)); 87 88 value_size = sizeof(__s64); 89 if (is_pcpu) 90 value_size *= nr_cpus; 91 92 keys = calloc(max_entries, sizeof(*keys)); 93 values = calloc(max_entries, value_size); 94 visited = calloc(max_entries, sizeof(*visited)); 95 CHECK(!keys || !values || !visited, "malloc()", "error:%s\n", 96 strerror(errno)); 97 98 /* test 1: lookup in a loop with various steps. */ 99 total_success = 0; 100 for (step = 1; step < max_entries; step++) { 101 map_batch_update(map_fd, max_entries, keys, values, is_pcpu); 102 map_batch_verify(visited, max_entries, keys, values, is_pcpu); 103 memset(keys, 0, max_entries * sizeof(*keys)); 104 memset(values, 0, max_entries * value_size); 105 batch = 0; 106 total = 0; 107 /* iteratively lookup/delete elements with 'step' 108 * elements each. 109 */ 110 count = step; 111 while (true) { 112 err = bpf_map_lookup_batch(map_fd, 113 total ? &batch : NULL, 114 &batch, keys + total, 115 values + total * value_size, 116 &count, &opts); 117 118 CHECK((err && errno != ENOENT), "lookup with steps", 119 "error: %s\n", strerror(errno)); 120 121 total += count; 122 if (err) 123 break; 124 125 } 126 127 CHECK(total != max_entries, "lookup with steps", 128 "total = %u, max_entries = %u\n", total, max_entries); 129 130 map_batch_verify(visited, max_entries, keys, values, is_pcpu); 131 132 total_success++; 133 } 134 135 CHECK(total_success == 0, "check total_success", 136 "unexpected failure\n"); 137 138 free(keys); 139 free(values); 140 free(visited); 141 close(map_fd); 142} 143 144static void array_map_batch_ops(void) 145{ 146 __test_map_lookup_and_update_batch(false); 147 printf("test_%s:PASS\n", __func__); 148} 149 150static void array_percpu_map_batch_ops(void) 151{ 152 __test_map_lookup_and_update_batch(true); 153 printf("test_%s:PASS\n", __func__); 154} 155 156void test_array_map_batch_ops(void) 157{ 158 nr_cpus = libbpf_num_possible_cpus(); 159 160 CHECK(nr_cpus < 0, "nr_cpus checking", 161 "error: get possible cpus failed"); 162 163 array_map_batch_ops(); 164 array_percpu_map_batch_ops(); 165} 166