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 : #include "bpfilter/cgen/cgen.h"
7 :
8 : #include <errno.h>
9 : #include <stddef.h>
10 : #include <stdint.h>
11 : #include <stdlib.h>
12 : #include <string.h>
13 :
14 : #include "bpfilter/cgen/dump.h"
15 : #include "bpfilter/cgen/program.h"
16 : #include "core/chain.h"
17 : #include "core/dump.h"
18 : #include "core/front.h"
19 : #include "core/helper.h"
20 : #include "core/hook.h"
21 : #include "core/list.h"
22 : #include "core/logger.h"
23 : #include "core/marsh.h"
24 : #include "core/opts.h"
25 : #include "core/rule.h"
26 :
27 9 : int bf_cgen_new(struct bf_cgen **cgen, enum bf_front front,
28 : struct bf_chain **chain)
29 : {
30 12 : bf_assert(cgen && chain && *chain);
31 :
32 6 : *cgen = malloc(sizeof(struct bf_cgen));
33 6 : if (!*cgen)
34 : return -ENOMEM;
35 :
36 5 : (*cgen)->front = front;
37 5 : (*cgen)->program = NULL;
38 5 : (*cgen)->chain = TAKE_PTR(*chain);
39 :
40 5 : return 0;
41 : }
42 :
43 3 : int bf_cgen_new_from_marsh(struct bf_cgen **cgen, const struct bf_marsh *marsh)
44 : {
45 1 : _cleanup_bf_cgen_ struct bf_cgen *_cgen = NULL;
46 1 : _cleanup_bf_program_ struct bf_program *program = NULL;
47 1 : _cleanup_bf_chain_ struct bf_chain *chain = NULL;
48 : struct bf_marsh *marsh_elem = NULL;
49 : enum bf_front front;
50 : int r;
51 :
52 3 : bf_assert(cgen);
53 2 : bf_assert(marsh);
54 :
55 1 : if (!(marsh_elem = bf_marsh_next_child(marsh, marsh_elem)))
56 : return -EINVAL;
57 1 : memcpy(&front, marsh_elem->data, sizeof(front));
58 :
59 1 : if (!(marsh_elem = bf_marsh_next_child(marsh, marsh_elem)))
60 : return -EINVAL;
61 :
62 1 : r = bf_chain_new_from_marsh(&chain, marsh_elem);
63 1 : if (r < 0)
64 : return r;
65 :
66 1 : r = bf_cgen_new(&_cgen, front, &chain);
67 1 : if (r)
68 0 : return bf_err_r(r, "failed to allocate codegen object");
69 :
70 1 : if (!(marsh_elem = bf_marsh_next_child(marsh, marsh_elem)))
71 : return -EINVAL;
72 1 : if (!bf_marsh_is_empty(marsh_elem)) {
73 0 : r = bf_program_unmarsh(marsh_elem, &_cgen->program, _cgen->chain);
74 0 : if (r < 0)
75 : return r;
76 : }
77 :
78 1 : if (bf_marsh_next_child(marsh, marsh_elem))
79 0 : bf_warn("codegen marsh has more children than expected");
80 :
81 1 : *cgen = TAKE_PTR(_cgen);
82 :
83 1 : return 0;
84 : }
85 :
86 9 : void bf_cgen_free(struct bf_cgen **cgen)
87 : {
88 9 : bf_assert(cgen);
89 :
90 8 : if (!*cgen)
91 : return;
92 :
93 5 : bf_program_free(&(*cgen)->program);
94 5 : bf_chain_free(&(*cgen)->chain);
95 :
96 5 : free(*cgen);
97 5 : *cgen = NULL;
98 : }
99 :
100 3 : int bf_cgen_marsh(const struct bf_cgen *cgen, struct bf_marsh **marsh)
101 : {
102 1 : _cleanup_bf_marsh_ struct bf_marsh *_marsh = NULL;
103 : int r;
104 :
105 3 : bf_assert(cgen);
106 2 : bf_assert(marsh);
107 :
108 1 : r = bf_marsh_new(&_marsh, NULL, 0);
109 1 : if (r)
110 : return r;
111 :
112 1 : r = bf_marsh_add_child_raw(&_marsh, &cgen->front, sizeof(cgen->front));
113 1 : if (r < 0)
114 0 : return bf_err_r(r, "failed to serialize codegen");
115 :
116 : {
117 : // Serialize cgen.chain
118 1 : _cleanup_bf_marsh_ struct bf_marsh *chain_elem = NULL;
119 :
120 1 : r = bf_chain_marsh(cgen->chain, &chain_elem);
121 1 : if (r < 0)
122 : return r;
123 :
124 1 : r = bf_marsh_add_child_obj(&_marsh, chain_elem);
125 1 : if (r < 0)
126 : return r;
127 : }
128 :
129 : {
130 1 : _cleanup_bf_marsh_ struct bf_marsh *prog_elem = NULL;
131 :
132 1 : if (cgen->program) {
133 0 : r = bf_program_marsh(cgen->program, &prog_elem);
134 0 : if (r < 0)
135 : return r;
136 : } else {
137 1 : r = bf_marsh_new(&prog_elem, NULL, 0);
138 1 : if (r < 0)
139 : return r;
140 : }
141 :
142 1 : r = bf_marsh_add_child_obj(&_marsh, prog_elem);
143 1 : if (r)
144 : return r;
145 : }
146 :
147 1 : *marsh = TAKE_PTR(_marsh);
148 :
149 1 : return 0;
150 : }
151 :
152 0 : int bf_cgen_unload(struct bf_cgen *cgen)
153 : {
154 0 : bf_assert(cgen);
155 :
156 0 : return bf_program_unload(cgen->program);
157 : }
158 :
159 0 : void bf_cgen_dump(const struct bf_cgen *cgen, prefix_t *prefix)
160 : {
161 0 : bf_assert(cgen);
162 0 : bf_assert(prefix);
163 :
164 0 : DUMP(prefix, "struct bf_cgen at %p", cgen);
165 :
166 0 : bf_dump_prefix_push(prefix);
167 0 : DUMP(prefix, "front: %s", bf_front_to_str(cgen->front));
168 :
169 : // Chain
170 0 : DUMP(prefix, "chain: struct bf_chain *");
171 0 : bf_dump_prefix_push(prefix);
172 0 : bf_chain_dump(cgen->chain, bf_dump_prefix_last(prefix));
173 0 : bf_dump_prefix_pop(prefix);
174 :
175 : // Programs
176 0 : if (cgen->program) {
177 0 : DUMP(bf_dump_prefix_last(prefix), "program: struct bf_program *");
178 0 : bf_dump_prefix_push(prefix);
179 0 : bf_program_dump(cgen->program, bf_dump_prefix_last(prefix));
180 0 : bf_dump_prefix_pop(prefix);
181 : } else {
182 0 : DUMP(bf_dump_prefix_last(prefix), "program: (struct bf_program *)NULL");
183 : }
184 :
185 0 : bf_dump_prefix_pop(prefix);
186 0 : }
187 :
188 0 : int bf_cgen_get_counter(const struct bf_cgen *cgen,
189 : enum bf_counter_type counter_idx,
190 : struct bf_counter *counter)
191 : {
192 0 : bf_assert(cgen && counter);
193 :
194 : /* There are two more counter than rules. The special counters must
195 : * be accessed via the specific values, to avoid confusion. */
196 0 : enum bf_counter_type rule_count = bf_list_size(&cgen->chain->rules);
197 0 : if (counter_idx == BF_COUNTER_POLICY) {
198 : counter_idx = rule_count;
199 0 : } else if (counter_idx == BF_COUNTER_ERRORS) {
200 0 : counter_idx = rule_count + 1;
201 0 : } else if (counter_idx < 0 || counter_idx >= rule_count) {
202 : return -EINVAL;
203 : }
204 :
205 0 : return bf_program_get_counter(cgen->program, counter_idx, counter);
206 : }
207 :
208 0 : int bf_cgen_up(struct bf_cgen *cgen)
209 : {
210 0 : _cleanup_bf_program_ struct bf_program *prog = NULL;
211 : int r;
212 :
213 0 : bf_assert(cgen);
214 :
215 0 : if (bf_opts_is_verbose(BF_VERBOSE_DEBUG))
216 0 : bf_cgen_dump(cgen, EMPTY_PREFIX);
217 :
218 0 : r = bf_program_new(&prog, cgen->chain->hook, cgen->front, cgen->chain);
219 0 : if (r < 0)
220 : return r;
221 :
222 0 : r = bf_program_generate(prog);
223 0 : if (r < 0) {
224 0 : return bf_err_r(r, "failed to generate bf_program for %s",
225 : bf_hook_to_str(cgen->chain->hook));
226 : }
227 :
228 0 : r = bf_program_load(prog, NULL);
229 0 : if (r < 0)
230 : return r;
231 :
232 0 : cgen->program = TAKE_PTR(prog);
233 :
234 0 : return r;
235 : }
236 :
237 0 : int bf_cgen_update(struct bf_cgen *cgen, struct bf_chain **new_chain)
238 : {
239 0 : _cleanup_bf_program_ struct bf_program *new_prog = NULL;
240 : int r;
241 :
242 0 : bf_assert(cgen && new_chain);
243 :
244 0 : r = bf_program_new(&new_prog, (*new_chain)->hook, cgen->front, *new_chain);
245 0 : if (r < 0)
246 0 : return bf_err_r(r, "failed to create a new bf_program");
247 :
248 0 : r = bf_program_generate(new_prog);
249 0 : if (r < 0) {
250 0 : return bf_err_r(r,
251 : "failed to generate the bytecode for a new bf_program");
252 : }
253 :
254 0 : r = bf_program_load(new_prog, cgen->program);
255 0 : if (r < 0) {
256 0 : return bf_err_r(
257 : r, "failed to attach the new bf_program, keeping the old one");
258 : }
259 :
260 0 : bf_swap(cgen->program, new_prog);
261 0 : bf_swap(cgen->chain, *new_chain);
262 :
263 0 : if (bf_opts_is_verbose(BF_VERBOSE_DEBUG))
264 0 : bf_cgen_dump(cgen, EMPTY_PREFIX);
265 :
266 : return 0;
267 : }
|