1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* Copyright (c) 2020 Facebook */ |
3 | #include <linux/bpf.h> |
4 | #include <bpf/bpf_helpers.h> |
5 | |
6 | struct inner_map { |
7 | __uint(type, BPF_MAP_TYPE_ARRAY); |
8 | __uint(max_entries, 1); |
9 | __type(key, int); |
10 | __type(value, int); |
11 | } inner_map1 SEC(".maps" ), |
12 | inner_map2 SEC(".maps" ); |
13 | |
14 | struct inner_map_sz2 { |
15 | __uint(type, BPF_MAP_TYPE_ARRAY); |
16 | __uint(max_entries, 2); |
17 | __type(key, int); |
18 | __type(value, int); |
19 | } inner_map_sz2 SEC(".maps" ); |
20 | |
21 | struct outer_arr { |
22 | __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); |
23 | __uint(max_entries, 3); |
24 | __type(key, int); |
25 | __type(value, int); |
26 | /* it's possible to use anonymous struct as inner map definition here */ |
27 | __array(values, struct { |
28 | __uint(type, BPF_MAP_TYPE_ARRAY); |
29 | /* changing max_entries to 2 will fail during load |
30 | * due to incompatibility with inner_map definition */ |
31 | __uint(max_entries, 1); |
32 | __type(key, int); |
33 | __type(value, int); |
34 | }); |
35 | } outer_arr SEC(".maps" ) = { |
36 | /* (void *) cast is necessary because we didn't use `struct inner_map` |
37 | * in __inner(values, ...) |
38 | * Actually, a conscious effort is required to screw up initialization |
39 | * of inner map slots, which is a great thing! |
40 | */ |
41 | .values = { (void *)&inner_map1, 0, (void *)&inner_map2 }, |
42 | }; |
43 | |
44 | struct inner_map_sz3 { |
45 | __uint(type, BPF_MAP_TYPE_ARRAY); |
46 | __uint(map_flags, BPF_F_INNER_MAP); |
47 | __uint(max_entries, 3); |
48 | __type(key, int); |
49 | __type(value, int); |
50 | } inner_map3 SEC(".maps" ), |
51 | inner_map4 SEC(".maps" ); |
52 | |
53 | struct inner_map_sz4 { |
54 | __uint(type, BPF_MAP_TYPE_ARRAY); |
55 | __uint(map_flags, BPF_F_INNER_MAP); |
56 | __uint(max_entries, 5); |
57 | __type(key, int); |
58 | __type(value, int); |
59 | } inner_map5 SEC(".maps" ); |
60 | |
61 | struct outer_arr_dyn { |
62 | __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); |
63 | __uint(max_entries, 3); |
64 | __type(key, int); |
65 | __type(value, int); |
66 | __array(values, struct { |
67 | __uint(type, BPF_MAP_TYPE_ARRAY); |
68 | __uint(map_flags, BPF_F_INNER_MAP); |
69 | __uint(max_entries, 1); |
70 | __type(key, int); |
71 | __type(value, int); |
72 | }); |
73 | } outer_arr_dyn SEC(".maps" ) = { |
74 | .values = { |
75 | [0] = (void *)&inner_map3, |
76 | [1] = (void *)&inner_map4, |
77 | [2] = (void *)&inner_map5, |
78 | }, |
79 | }; |
80 | |
81 | struct outer_hash { |
82 | __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS); |
83 | __uint(max_entries, 5); |
84 | __type(key, int); |
85 | /* Here everything works flawlessly due to reuse of struct inner_map |
86 | * and compiler will complain at the attempt to use non-inner_map |
87 | * references below. This is great experience. |
88 | */ |
89 | __array(values, struct inner_map); |
90 | } outer_hash SEC(".maps" ) = { |
91 | .values = { |
92 | [0] = &inner_map2, |
93 | [4] = &inner_map1, |
94 | }, |
95 | }; |
96 | |
97 | struct sockarr_sz1 { |
98 | __uint(type, BPF_MAP_TYPE_REUSEPORT_SOCKARRAY); |
99 | __uint(max_entries, 1); |
100 | __type(key, int); |
101 | __type(value, int); |
102 | } sockarr_sz1 SEC(".maps" ); |
103 | |
104 | struct sockarr_sz2 { |
105 | __uint(type, BPF_MAP_TYPE_REUSEPORT_SOCKARRAY); |
106 | __uint(max_entries, 2); |
107 | __type(key, int); |
108 | __type(value, int); |
109 | } sockarr_sz2 SEC(".maps" ); |
110 | |
111 | struct outer_sockarr_sz1 { |
112 | __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); |
113 | __uint(max_entries, 1); |
114 | __type(key, int); |
115 | __type(value, int); |
116 | __array(values, struct sockarr_sz1); |
117 | } outer_sockarr SEC(".maps" ) = { |
118 | .values = { (void *)&sockarr_sz1 }, |
119 | }; |
120 | |
121 | int input = 0; |
122 | |
123 | SEC("raw_tp/sys_enter" ) |
124 | int handle__sys_enter(void *ctx) |
125 | { |
126 | struct inner_map *inner_map; |
127 | int key = 0, val; |
128 | |
129 | inner_map = bpf_map_lookup_elem(&outer_arr, &key); |
130 | if (!inner_map) |
131 | return 1; |
132 | val = input; |
133 | bpf_map_update_elem(inner_map, &key, &val, 0); |
134 | |
135 | inner_map = bpf_map_lookup_elem(&outer_hash, &key); |
136 | if (!inner_map) |
137 | return 1; |
138 | val = input + 1; |
139 | bpf_map_update_elem(inner_map, &key, &val, 0); |
140 | |
141 | inner_map = bpf_map_lookup_elem(&outer_arr_dyn, &key); |
142 | if (!inner_map) |
143 | return 1; |
144 | val = input + 2; |
145 | bpf_map_update_elem(inner_map, &key, &val, 0); |
146 | |
147 | return 0; |
148 | } |
149 | |
150 | char _license[] SEC("license" ) = "GPL" ; |
151 | |