1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2020 Facebook */
3#include "bpf_iter.h"
4#include <bpf/bpf_helpers.h>
5
6char _license[] SEC("license") = "GPL";
7
8struct key_t {
9	int a;
10	int b;
11	int c;
12};
13
14struct {
15	__uint(type, BPF_MAP_TYPE_HASH);
16	__uint(max_entries, 3);
17	__type(key, struct key_t);
18	__type(value, __u64);
19} hashmap1 SEC(".maps");
20
21struct {
22	__uint(type, BPF_MAP_TYPE_HASH);
23	__uint(max_entries, 3);
24	__type(key, __u64);
25	__type(value, __u64);
26} hashmap2 SEC(".maps");
27
28struct {
29	__uint(type, BPF_MAP_TYPE_HASH);
30	__uint(max_entries, 3);
31	__type(key, struct key_t);
32	__type(value, __u32);
33} hashmap3 SEC(".maps");
34
35/* will set before prog run */
36bool in_test_mode = 0;
37
38/* will collect results during prog run */
39__u32 key_sum_a = 0, key_sum_b = 0, key_sum_c = 0;
40__u64 val_sum = 0;
41
42SEC("iter/bpf_map_elem")
43int dump_bpf_hash_map(struct bpf_iter__bpf_map_elem *ctx)
44{
45	struct seq_file *seq = ctx->meta->seq;
46	__u32 seq_num = ctx->meta->seq_num;
47	struct bpf_map *map = ctx->map;
48	struct key_t *key = ctx->key;
49	struct key_t tmp_key;
50	__u64 *val = ctx->value;
51	__u64 tmp_val = 0;
52	int ret;
53
54	if (in_test_mode) {
55		/* test mode is used by selftests to
56		 * test functionality of bpf_hash_map iter.
57		 *
58		 * the above hashmap1 will have correct size
59		 * and will be accepted, hashmap2 and hashmap3
60		 * should be rejected due to smaller key/value
61		 * size.
62		 */
63		if (key == (void *)0 || val == (void *)0)
64			return 0;
65
66		/* update the value and then delete the <key, value> pair.
67		 * it should not impact the existing 'val' which is still
68		 * accessible under rcu.
69		 */
70		__builtin_memcpy(&tmp_key, key, sizeof(struct key_t));
71		ret = bpf_map_update_elem(&hashmap1, &tmp_key, &tmp_val, 0);
72		if (ret)
73			return 0;
74		ret = bpf_map_delete_elem(&hashmap1, &tmp_key);
75		if (ret)
76			return 0;
77
78		key_sum_a += key->a;
79		key_sum_b += key->b;
80		key_sum_c += key->c;
81		val_sum += *val;
82		return 0;
83	}
84
85	/* non-test mode, the map is prepared with the
86	 * below bpftool command sequence:
87	 *   bpftool map create /sys/fs/bpf/m1 type hash \
88	 *   	key 12 value 8 entries 3 name map1
89	 *   bpftool map update id 77 key 0 0 0 1 0 0 0 0 0 0 0 1 \
90	 *   	value 0 0 0 1 0 0 0 1
91	 *   bpftool map update id 77 key 0 0 0 1 0 0 0 0 0 0 0 2 \
92	 *   	value 0 0 0 1 0 0 0 2
93	 * The bpftool iter command line:
94	 *   bpftool iter pin ./bpf_iter_bpf_hash_map.o /sys/fs/bpf/p1 \
95	 *   	map id 77
96	 * The below output will be:
97	 *   map dump starts
98	 *   77: (1000000 0 2000000) (200000001000000)
99	 *   77: (1000000 0 1000000) (100000001000000)
100	 *   map dump ends
101	 */
102	if (seq_num == 0)
103		BPF_SEQ_PRINTF(seq, "map dump starts\n");
104
105	if (key == (void *)0 || val == (void *)0) {
106		BPF_SEQ_PRINTF(seq, "map dump ends\n");
107		return 0;
108	}
109
110	BPF_SEQ_PRINTF(seq, "%d: (%x %d %x) (%llx)\n", map->id,
111		       key->a, key->b, key->c, *val);
112
113	return 0;
114}
115
116SEC("iter.s/bpf_map_elem")
117int sleepable_dummy_dump(struct bpf_iter__bpf_map_elem *ctx)
118{
119	if (ctx->meta->seq_num == 0)
120		BPF_SEQ_PRINTF(ctx->meta->seq, "map dump starts\n");
121
122	return 0;
123}
124