1*387f9dfdSAndroid Build Coastguard Worker // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2*387f9dfdSAndroid Build Coastguard Worker // Copyright (c) 2020 Anton Protopopov
3*387f9dfdSAndroid Build Coastguard Worker #include <stdlib.h>
4*387f9dfdSAndroid Build Coastguard Worker #include <stdio.h>
5*387f9dfdSAndroid Build Coastguard Worker #include <errno.h>
6*387f9dfdSAndroid Build Coastguard Worker
7*387f9dfdSAndroid Build Coastguard Worker #include "map_helpers.h"
8*387f9dfdSAndroid Build Coastguard Worker
9*387f9dfdSAndroid Build Coastguard Worker #define warn(...) fprintf(stderr, __VA_ARGS__)
10*387f9dfdSAndroid Build Coastguard Worker
11*387f9dfdSAndroid Build Coastguard Worker static bool batch_map_ops = true; /* hope for the best */
12*387f9dfdSAndroid Build Coastguard Worker
13*387f9dfdSAndroid Build Coastguard Worker static int
dump_hash_iter(int map_fd,void * keys,__u32 key_size,void * values,__u32 value_size,__u32 * count,void * invalid_key)14*387f9dfdSAndroid Build Coastguard Worker dump_hash_iter(int map_fd, void *keys, __u32 key_size,
15*387f9dfdSAndroid Build Coastguard Worker void *values, __u32 value_size, __u32 *count,
16*387f9dfdSAndroid Build Coastguard Worker void *invalid_key)
17*387f9dfdSAndroid Build Coastguard Worker {
18*387f9dfdSAndroid Build Coastguard Worker __u8 key[key_size], next_key[key_size];
19*387f9dfdSAndroid Build Coastguard Worker __u32 n = 0;
20*387f9dfdSAndroid Build Coastguard Worker int i, err;
21*387f9dfdSAndroid Build Coastguard Worker
22*387f9dfdSAndroid Build Coastguard Worker /* First get keys */
23*387f9dfdSAndroid Build Coastguard Worker __builtin_memcpy(key, invalid_key, key_size);
24*387f9dfdSAndroid Build Coastguard Worker while (n < *count) {
25*387f9dfdSAndroid Build Coastguard Worker err = bpf_map_get_next_key(map_fd, key, next_key);
26*387f9dfdSAndroid Build Coastguard Worker if (err && errno != ENOENT) {
27*387f9dfdSAndroid Build Coastguard Worker return -1;
28*387f9dfdSAndroid Build Coastguard Worker } else if (err) {
29*387f9dfdSAndroid Build Coastguard Worker break;
30*387f9dfdSAndroid Build Coastguard Worker }
31*387f9dfdSAndroid Build Coastguard Worker __builtin_memcpy(key, next_key, key_size);
32*387f9dfdSAndroid Build Coastguard Worker __builtin_memcpy(keys + key_size * n, next_key, key_size);
33*387f9dfdSAndroid Build Coastguard Worker n++;
34*387f9dfdSAndroid Build Coastguard Worker }
35*387f9dfdSAndroid Build Coastguard Worker
36*387f9dfdSAndroid Build Coastguard Worker /* Now read values */
37*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < n; i++) {
38*387f9dfdSAndroid Build Coastguard Worker err = bpf_map_lookup_elem(map_fd, keys + key_size * i,
39*387f9dfdSAndroid Build Coastguard Worker values + value_size * i);
40*387f9dfdSAndroid Build Coastguard Worker if (err)
41*387f9dfdSAndroid Build Coastguard Worker return -1;
42*387f9dfdSAndroid Build Coastguard Worker }
43*387f9dfdSAndroid Build Coastguard Worker
44*387f9dfdSAndroid Build Coastguard Worker *count = n;
45*387f9dfdSAndroid Build Coastguard Worker return 0;
46*387f9dfdSAndroid Build Coastguard Worker }
47*387f9dfdSAndroid Build Coastguard Worker
48*387f9dfdSAndroid Build Coastguard Worker static int
dump_hash_batch(int map_fd,void * keys,__u32 key_size,void * values,__u32 value_size,__u32 * count)49*387f9dfdSAndroid Build Coastguard Worker dump_hash_batch(int map_fd, void *keys, __u32 key_size,
50*387f9dfdSAndroid Build Coastguard Worker void *values, __u32 value_size, __u32 *count)
51*387f9dfdSAndroid Build Coastguard Worker {
52*387f9dfdSAndroid Build Coastguard Worker void *in = NULL, *out;
53*387f9dfdSAndroid Build Coastguard Worker __u32 n, n_read = 0;
54*387f9dfdSAndroid Build Coastguard Worker int err = 0;
55*387f9dfdSAndroid Build Coastguard Worker
56*387f9dfdSAndroid Build Coastguard Worker while (n_read < *count && !err) {
57*387f9dfdSAndroid Build Coastguard Worker n = *count - n_read;
58*387f9dfdSAndroid Build Coastguard Worker err = bpf_map_lookup_batch(map_fd, &in, &out,
59*387f9dfdSAndroid Build Coastguard Worker keys + n_read * key_size,
60*387f9dfdSAndroid Build Coastguard Worker values + n_read * value_size,
61*387f9dfdSAndroid Build Coastguard Worker &n, NULL);
62*387f9dfdSAndroid Build Coastguard Worker if (err && errno != ENOENT) {
63*387f9dfdSAndroid Build Coastguard Worker return -1;
64*387f9dfdSAndroid Build Coastguard Worker }
65*387f9dfdSAndroid Build Coastguard Worker n_read += n;
66*387f9dfdSAndroid Build Coastguard Worker in = out;
67*387f9dfdSAndroid Build Coastguard Worker }
68*387f9dfdSAndroid Build Coastguard Worker
69*387f9dfdSAndroid Build Coastguard Worker *count = n_read;
70*387f9dfdSAndroid Build Coastguard Worker return 0;
71*387f9dfdSAndroid Build Coastguard Worker }
72*387f9dfdSAndroid Build Coastguard Worker
dump_hash(int map_fd,void * keys,__u32 key_size,void * values,__u32 value_size,__u32 * count,void * invalid_key)73*387f9dfdSAndroid Build Coastguard Worker int dump_hash(int map_fd,
74*387f9dfdSAndroid Build Coastguard Worker void *keys, __u32 key_size,
75*387f9dfdSAndroid Build Coastguard Worker void *values, __u32 value_size,
76*387f9dfdSAndroid Build Coastguard Worker __u32 *count, void *invalid_key)
77*387f9dfdSAndroid Build Coastguard Worker {
78*387f9dfdSAndroid Build Coastguard Worker int err;
79*387f9dfdSAndroid Build Coastguard Worker
80*387f9dfdSAndroid Build Coastguard Worker if (!keys || !values || !count || !key_size || !value_size) {
81*387f9dfdSAndroid Build Coastguard Worker errno = EINVAL;
82*387f9dfdSAndroid Build Coastguard Worker return -1;
83*387f9dfdSAndroid Build Coastguard Worker }
84*387f9dfdSAndroid Build Coastguard Worker
85*387f9dfdSAndroid Build Coastguard Worker if (batch_map_ops) {
86*387f9dfdSAndroid Build Coastguard Worker err = dump_hash_batch(map_fd, keys, key_size,
87*387f9dfdSAndroid Build Coastguard Worker values, value_size, count);
88*387f9dfdSAndroid Build Coastguard Worker if (err) {
89*387f9dfdSAndroid Build Coastguard Worker if (errno != EINVAL) {
90*387f9dfdSAndroid Build Coastguard Worker return -1;
91*387f9dfdSAndroid Build Coastguard Worker
92*387f9dfdSAndroid Build Coastguard Worker /* assume that batch operations are not
93*387f9dfdSAndroid Build Coastguard Worker * supported and try non-batch mode */
94*387f9dfdSAndroid Build Coastguard Worker batch_map_ops = false;
95*387f9dfdSAndroid Build Coastguard Worker }
96*387f9dfdSAndroid Build Coastguard Worker }
97*387f9dfdSAndroid Build Coastguard Worker }
98*387f9dfdSAndroid Build Coastguard Worker
99*387f9dfdSAndroid Build Coastguard Worker if (!invalid_key) {
100*387f9dfdSAndroid Build Coastguard Worker errno = EINVAL;
101*387f9dfdSAndroid Build Coastguard Worker return -1;
102*387f9dfdSAndroid Build Coastguard Worker }
103*387f9dfdSAndroid Build Coastguard Worker
104*387f9dfdSAndroid Build Coastguard Worker return dump_hash_iter(map_fd, keys, key_size,
105*387f9dfdSAndroid Build Coastguard Worker values, value_size, count, invalid_key);
106*387f9dfdSAndroid Build Coastguard Worker }
107