1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright (c) 2020 Facebook */ |
3 | #include "bpf_iter.h" |
4 | #include <bpf/bpf_helpers.h> |
5 | |
6 | char _license[] SEC("license" ) = "GPL" ; |
7 | |
8 | struct key_t { |
9 | int a; |
10 | int b; |
11 | int c; |
12 | }; |
13 | |
14 | struct { |
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 | |
21 | struct { |
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 | |
28 | struct { |
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 */ |
36 | bool 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 | |
42 | SEC("iter/bpf_map_elem" ) |
43 | int 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 | |
116 | SEC("iter.s/bpf_map_elem" ) |
117 | int 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 | |