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