Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0-only */
2 : : /*
3 : : * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
4 : : */
5 : :
6 : : #pragma once
7 : :
8 : : #include <stddef.h>
9 : : #include <stdint.h>
10 : :
11 : : #include <bpfilter/chain.h>
12 : : #include <bpfilter/core/list.h>
13 : : #include <bpfilter/core/vector.h>
14 : : #include <bpfilter/dump.h>
15 : : #include <bpfilter/elfstub.h>
16 : : #include <bpfilter/flavor.h>
17 : : #include <bpfilter/helper.h>
18 : : #include <bpfilter/pack.h>
19 : :
20 : : #include "cgen/fixup.h"
21 : : #include "cgen/printer.h"
22 : : #include "cgen/runtime.h"
23 : : #include "filter.h"
24 : :
25 : : /**
26 : : * @file program.h
27 : : *
28 : : * @ref bf_program is used to represent a BPF program. It contains the BPF
29 : : * bytecode, as well as the required maps and metadata.
30 : : *
31 : : * **Workflow**
32 : : *
33 : : * The program is composed of different steps:
34 : : * 1. Initialize the generic context
35 : : * 2. Preprocess the packet's headers: gather information about the packet's
36 : : * size, the protocols available, the input interface...
37 : : * 3. Execute the filtering rules: execute all the rules defined in the program
38 : : * sequentially. If a rule matches the packet, apply its verdict and return.
39 : : * 4. Apply the policy if no rule matched: if no rule matched the packet, return
40 : : * the chain's policy (default action).
41 : : *
42 : : * **Memory layout**
43 : : *
44 : : * The program will use the BPF registers to following way:
45 : : * - @c r0 : return value
46 : : * - @c r1 to @c r5 (included): general purpose registers
47 : : * - @c r6 : address of the header currently filtered on
48 : : * - @c r7 : L3 protocol ID
49 : : * - @c r8 : L4 protocol ID
50 : : * - @c r9 : unused
51 : : * - @c r10 : frame pointer
52 : : *
53 : : * This convention is followed throughout the project and must be followed all
54 : : * the time to prevent incompatibilities. Debugging this kind of issues is not
55 : : * fun, so stick to it.
56 : : *
57 : : * @warning L3 and L4 protocol IDs **must** be stored in registers, no on the
58 : : * stack, as older verifier aren't able to keep track of scalar values located
59 : : * on the stack. This means the verification will fail because the verifier
60 : : * can't verify branches properly.
61 : : *
62 : : * `bf_runtime` is used to represent the layout of the first stack frame in the
63 : : * program. It is filled during preprocessing and contains data required for
64 : : * packet filtering.
65 : : *
66 : : * **About preprocessing**
67 : : *
68 : : * The packets are preprocessed according to the program type (i.e. BPF flavor).
69 : : * Each flavor needs to perform the following steps during preprocessing:
70 : : * - Store the packet size and the input interface index into the runtime context
71 : : * - Create a BPF dynamic pointer for the packet
72 : : * - Preprocess the L2, L3, and L4 headers
73 : : *
74 : : * The header's preprocessing is required to discover the protocols used in the
75 : : * packet: processing L2 will provide us with information about L3, and so on. The
76 : : * logic used to process layer X is responsible for discovering layer X+1: the L2
77 : : * header preprocessing logic will discover the L3 protocol ID. When processing
78 : : * layer X, if the protocol is not supported, the protocol ID is reset to 0 (so
79 : : * we won't execute the rules for this layer) and subsequent layers are not
80 : : * processed (because we can't discover their protocol).
81 : : *
82 : : * For example, assuming IPv6 and TCP are the only supported protocols:
83 : : * - L2 processing: discover the packet's ethertype (IPv6), and store it into
84 : : * @c r7 .
85 : : * - L3 processing: the protocol ID in @c r7 is supported (IPv6), so a slice is
86 : : * created, and the L4 protocol ID is read from the IPV6 header into @c r8 .
87 : : * - L4 processing: the protocol ID in @c r8 is supported (TCP), so a slice
88 : : * is created.
89 : : * - The program can now start executing the rules.
90 : : *
91 : : * However, assuming only IPv6 and UDP are supported:
92 : : * - L2 processing: discover the packet's ethertype (IPv6), and store it into
93 : : * @c r7 .
94 : : * - L3 processing: the protocol ID in @c r7 is supported (IPv6), so a slice is
95 : : * created, and the L4 protocol ID is read from the IPV6 header into @c r8 .
96 : : * - L4 processing: the protocol ID in @c r8 is no supported (TCP), @c r8 is
97 : : * set to 0 and we stop processing this layer.
98 : : * - The program can now start executing the rules. No layer 4 rule will be
99 : : * executed as @c r8 won't match any protocol ID.
100 : : */
101 : :
102 : : #define EMIT(program, x) \
103 : : ({ \
104 : : int __r = bf_program_emit((program), (x)); \
105 : : if (__r < 0) \
106 : : return __r; \
107 : : })
108 : :
109 : : #define EMIT_KFUNC_CALL(program, function) \
110 : : ({ \
111 : : int __r = bf_program_emit_kfunc_call((program), (function)); \
112 : : if (__r < 0) \
113 : : return __r; \
114 : : })
115 : :
116 : : #define EMIT_FIXUP(program, type, insn) \
117 : : ({ \
118 : : int __r = bf_program_emit_fixup((program), (type), (insn), NULL); \
119 : : if (__r < 0) \
120 : : return __r; \
121 : : })
122 : :
123 : : #define EMIT_FIXUP_ELFSTUB(program, elfstub_id) \
124 : : ({ \
125 : : int __r = bf_program_emit_fixup_elfstub((program), (elfstub_id)); \
126 : : if (__r < 0) \
127 : : return __r; \
128 : : })
129 : :
130 : : #define EMIT_FIXUP_JMP_NEXT_RULE(program, insn) \
131 : : ({ \
132 : : int __r = bf_program_emit_fixup( \
133 : : (program), BF_FIXUP_TYPE_JMP_NEXT_RULE, (insn), NULL); \
134 : : if (__r < 0) \
135 : : return __r; \
136 : : })
137 : :
138 : : #define EMIT_LOAD_COUNTERS_FD_FIXUP(program, reg) \
139 : : ({ \
140 : : const struct bpf_insn ld_insn[2] = {BPF_LD_MAP_FD(reg, 0)}; \
141 : : int __r = bf_program_emit_fixup( \
142 : : (program), BF_FIXUP_TYPE_COUNTERS_MAP_FD, ld_insn[0], NULL); \
143 : : if (__r < 0) \
144 : : return __r; \
145 : : __r = bf_program_emit((program), ld_insn[1]); \
146 : : if (__r < 0) \
147 : : return __r; \
148 : : })
149 : :
150 : : #define EMIT_LOAD_LOG_FD_FIXUP(program, reg) \
151 : : ({ \
152 : : const struct bpf_insn ld_insn[2] = {BPF_LD_MAP_FD(reg, 0)}; \
153 : : int __r = bf_program_emit_fixup((program), BF_FIXUP_TYPE_LOG_MAP_FD, \
154 : : ld_insn[0], NULL); \
155 : : if (__r < 0) \
156 : : return __r; \
157 : : __r = bf_program_emit((program), ld_insn[1]); \
158 : : if (__r < 0) \
159 : : return __r; \
160 : : })
161 : :
162 : : #define EMIT_LOAD_STATE_FD_FIXUP(program, reg) \
163 : : ({ \
164 : : const struct bpf_insn ld_insn[2] = {BPF_LD_MAP_FD(reg, 0)}; \
165 : : int __r = bf_program_emit_fixup((program), BF_FIXUP_TYPE_STATE_MAP_FD, \
166 : : ld_insn[0], NULL); \
167 : : if (__r < 0) \
168 : : return __r; \
169 : : __r = bf_program_emit((program), ld_insn[1]); \
170 : : if (__r < 0) \
171 : : return __r; \
172 : : })
173 : :
174 : : /**
175 : : * Load a specific set's file descriptor.
176 : : *
177 : : * @note Similarly to every @c EMIT_* macro, it must be called from a function
178 : : * returning an @c int , if the call fails, the macro will return a negative
179 : : * errno value.
180 : : *
181 : : * @param program Program to generate the bytecode for. Can't be NULL.
182 : : * @param reg Register to store the set file descriptor in.
183 : : * @param set Non-owning pointer to the referenced `bf_set`. The set must
184 : : * live at least until `bf_program_load()` returns.
185 : : */
186 : : #define EMIT_LOAD_SET_FD_FIXUP(program, reg, set) \
187 : : ({ \
188 : : union bf_fixup_attr __attr; \
189 : : memset(&__attr, 0, sizeof(__attr)); \
190 : : __attr.set_ptr = (set); \
191 : : const struct bpf_insn ld_insn[2] = {BPF_LD_MAP_FD(reg, 0)}; \
192 : : int __r = bf_program_emit_fixup((program), BF_FIXUP_TYPE_SET_MAP_FD, \
193 : : ld_insn[0], &__attr); \
194 : : if (__r < 0) \
195 : : return __r; \
196 : : __r = bf_program_emit((program), ld_insn[1]); \
197 : : if (__r < 0) \
198 : : return __r; \
199 : : })
200 : :
201 : : struct bf_chain;
202 : : struct bf_counter;
203 : : struct bf_hookopts;
204 : : struct bf_handle;
205 : : struct bf_set;
206 : : struct bf_set_group;
207 : :
208 : : struct bf_program
209 : : {
210 : : enum bf_flavor flavor;
211 : :
212 : : /// Log messages printer
213 : : struct bf_printer *printer;
214 : :
215 : : /** Handle containing BPF object references (prog_fd, maps, link).
216 : : * Non-owning pointer, passed in from `bf_cgen` via `bf_program_new()`.
217 : : * Populated during load/attach. */
218 : : struct bf_handle *handle;
219 : :
220 : : /* Bytecode */
221 : : uint32_t elfstubs_location[_BF_ELFSTUB_MAX];
222 : : bf_vector img;
223 : : bf_list fixups;
224 : :
225 : : /** Non-empty sets from `runtime.chain->sets`, partitioned into groups
226 : : * that each back a single BPF map. Hash-keyed sets sharing a key
227 : : * format are placed in the same group; each LPM trie set sits in a
228 : : * group of its own. A set's position within a group is its bit index
229 : : * in the map's bitmask value. Not serialized. */
230 : : bf_list set_groups;
231 : :
232 : : /** Runtime data used to interact with the program and cache information.
233 : : * This data is not serialized. */
234 : : struct
235 : : {
236 : : /** Hook-specific ops to use to generate the program. */
237 : : const struct bf_flavor_ops *ops;
238 : :
239 : : /** Chain the program is generated from. This is a non-owning pointer:
240 : : * the @ref bf_program doesn't have to manage its lifetime. */
241 : : const struct bf_chain *chain;
242 : : } runtime;
243 : : };
244 : :
245 : : #define _free_bf_program_ __attribute__((__cleanup__(bf_program_free)))
246 : :
247 : : /**
248 : : * @brief Allocate and initialize a new `bf_program` object.
249 : : *
250 : : * @param program `bf_program` object to allocate and initialize. Can't be NULL.
251 : : * @param chain Chain the program is generated from. Can't be NULL.
252 : : * @param handle Handle to store BPF object references in. The program borrows
253 : : * this pointer (non-owning). Can't be NULL.
254 : : * @return 0 on success, or a negative error value on failure.
255 : : */
256 : : int bf_program_new(struct bf_program **program, const struct bf_chain *chain,
257 : : struct bf_handle *handle);
258 : :
259 : : void bf_program_free(struct bf_program **program);
260 : :
261 : : void bf_program_dump(const struct bf_program *program, prefix_t *prefix);
262 : :
263 : : static inline int bf_program_emit(struct bf_program *program,
264 : : struct bpf_insn insn)
265 : : {
266 : : assert(program);
267 : :
268 : 296302 : return bf_vector_add(&program->img, &insn);
269 : : }
270 : :
271 : : int bf_program_emit_kfunc_call(struct bf_program *program, const char *name);
272 : : int bf_program_emit_fixup(struct bf_program *program, enum bf_fixup_type type,
273 : : struct bpf_insn insn,
274 : : const union bf_fixup_attr *attr);
275 : : int bf_program_emit_fixup_elfstub(struct bf_program *program,
276 : : enum bf_elfstub_id id);
277 : : int bf_program_generate(struct bf_program *program);
278 : :
279 : : /**
280 : : * @brief Get the bit position of a set within its group.
281 : : *
282 : : * Hash-keyed sets sharing a key format are grouped together and share a
283 : : * single BPF map; LPM trie sets each live in a group of size 1. Either
284 : : * way, each set's elements are stored in the group's map with a bitmask
285 : : * value where one bit identifies which set owns the element. This
286 : : * function returns that bit's position for `set` within its group (always
287 : : * 0 for LPM trie sets).
288 : : *
289 : : * @param program Program whose groups have been built. Can't be NULL.
290 : : * @param set Set to locate in the program's groups. Can't be NULL.
291 : : * @param bit_index Output: position of `set` within its group's bit layout.
292 : : * Can't be NULL.
293 : : * @return 0 on success, `-ENOENT` if `set` is not part of any group (for
294 : : * example, because it is empty).
295 : : */
296 : : int bf_program_set_bit_index(const struct bf_program *program,
297 : : const struct bf_set *set, size_t *bit_index);
298 : :
299 : : /**
300 : : * Load the BPF program into the kernel.
301 : : *
302 : : * Prior to loading the BPF program, multiple BPF maps are created to store
303 : : * the counters, the debug strings, and the sets. If the program can't be
304 : : * loaded, all the maps are destroyed.
305 : : *
306 : : * Once the loading succeeds, the program and the maps are pinned to the
307 : : * filesystem. If the BPF objects can't be pinned, the program is unloaded and
308 : : * the maps destroyed.
309 : : *
310 : : * @param prog Program to load into the kernel. Can't be NULL and must contain
311 : : * instructions.
312 : : * @return 0 on success, or negative errno value on failure.
313 : : */
314 : : int bf_program_load(struct bf_program *prog);
315 : :
316 : : int bf_program_get_counter(const struct bf_program *program,
317 : : uint32_t counter_idx, struct bf_counter *counter);
318 : : int bf_program_set_counters(struct bf_program *program,
319 : : const struct bf_counter *counters);
320 : :
321 : : size_t bf_program_chain_counter_idx(const struct bf_program *program);
322 : : size_t bf_program_error_counter_idx(const struct bf_program *program);
|