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