| // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) |
| // Copyright (c) 2020 Anton Protopopov |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <errno.h> |
| |
| #include "map_helpers.h" |
| |
| #define warn(...) fprintf(stderr, __VA_ARGS__) |
| |
| static bool batch_map_ops = true; /* hope for the best */ |
| |
| static int |
| dump_hash_iter(int map_fd, void *keys, __u32 key_size, |
| void *values, __u32 value_size, __u32 *count, |
| void *invalid_key) |
| { |
| __u8 key[key_size], next_key[key_size]; |
| __u32 n = 0; |
| int i, err; |
| |
| /* First get keys */ |
| __builtin_memcpy(key, invalid_key, key_size); |
| while (n < *count) { |
| err = bpf_map_get_next_key(map_fd, key, next_key); |
| if (err && errno != ENOENT) { |
| return -1; |
| } else if (err) { |
| break; |
| } |
| __builtin_memcpy(key, next_key, key_size); |
| __builtin_memcpy(keys + key_size * n, next_key, key_size); |
| n++; |
| } |
| |
| /* Now read values */ |
| for (i = 0; i < n; i++) { |
| err = bpf_map_lookup_elem(map_fd, keys + key_size * i, |
| values + value_size * i); |
| if (err) |
| return -1; |
| } |
| |
| *count = n; |
| return 0; |
| } |
| |
| static int |
| dump_hash_batch(int map_fd, void *keys, __u32 key_size, |
| void *values, __u32 value_size, __u32 *count) |
| { |
| void *in = NULL, *out; |
| __u32 n, n_read = 0; |
| int err = 0; |
| |
| while (n_read < *count && !err) { |
| n = *count - n_read; |
| err = bpf_map_lookup_batch(map_fd, &in, &out, |
| keys + n_read * key_size, |
| values + n_read * value_size, |
| &n, NULL); |
| if (err && errno != ENOENT) { |
| return -1; |
| } |
| n_read += n; |
| in = out; |
| } |
| |
| *count = n_read; |
| return 0; |
| } |
| |
| int dump_hash(int map_fd, |
| void *keys, __u32 key_size, |
| void *values, __u32 value_size, |
| __u32 *count, void *invalid_key) |
| { |
| int err; |
| |
| if (!keys || !values || !count || !key_size || !value_size) { |
| errno = EINVAL; |
| return -1; |
| } |
| |
| if (batch_map_ops) { |
| err = dump_hash_batch(map_fd, keys, key_size, |
| values, value_size, count); |
| if (err) { |
| if (errno != EINVAL) { |
| return -1; |
| |
| /* assume that batch operations are not |
| * supported and try non-batch mode */ |
| batch_map_ops = false; |
| } |
| } |
| } |
| |
| if (!invalid_key) { |
| errno = EINVAL; |
| return -1; |
| } |
| |
| return dump_hash_iter(map_fd, keys, key_size, |
| values, value_size, count, invalid_key); |
| } |