Line data Source code
1 : /* SPDX-License-Identifier: GPL-2.0-only */
2 : /*
3 : * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
4 : */
5 :
6 : #include "chain.h"
7 :
8 : #include <errno.h>
9 : #include <stdlib.h>
10 : #include <string.h>
11 :
12 : #include "core/dump.h"
13 : #include "core/helper.h"
14 : #include "core/hook.h"
15 : #include "core/list.h"
16 : #include "core/logger.h"
17 : #include "core/marsh.h"
18 : #include "core/rule.h"
19 : #include "core/set.h"
20 : #include "core/verdict.h"
21 :
22 10 : int bf_chain_new(struct bf_chain **chain, enum bf_hook hook,
23 : enum bf_verdict policy, bf_list *sets, bf_list *rules)
24 : {
25 9 : _cleanup_bf_chain_ struct bf_chain *_chain = NULL;
26 : int r;
27 :
28 10 : bf_assert(chain);
29 10 : bf_assert(0 <= policy && policy < _BF_TERMINAL_VERDICT_MAX);
30 :
31 9 : _chain = malloc(sizeof(*_chain));
32 9 : if (!_chain)
33 : return -ENOMEM;
34 :
35 9 : _chain->hook = hook;
36 9 : _chain->hook_opts = (struct bf_hook_opts) {};
37 9 : _chain->policy = policy;
38 :
39 9 : _chain->sets = bf_set_list();
40 9 : if (sets)
41 0 : bf_swap(_chain->sets, *sets);
42 :
43 9 : _chain->rules = bf_rule_list();
44 9 : if (rules) {
45 0 : bf_list_foreach (rules, rule_node) {
46 0 : r = bf_chain_add_rule(_chain, bf_list_node_get_data(rule_node));
47 0 : if (r)
48 : return r;
49 :
50 0 : bf_list_node_take_data(rule_node);
51 : }
52 : }
53 :
54 9 : *chain = TAKE_PTR(_chain);
55 :
56 9 : return 0;
57 : }
58 :
59 1 : int bf_chain_new_from_marsh(struct bf_chain **chain,
60 : const struct bf_marsh *marsh)
61 : {
62 1 : _cleanup_bf_chain_ struct bf_chain *_chain = NULL;
63 : struct bf_marsh *chain_elem = NULL;
64 : struct bf_marsh *list_elem = NULL;
65 : enum bf_hook hook;
66 : enum bf_verdict policy;
67 : int r;
68 :
69 1 : bf_assert(chain);
70 1 : bf_assert(marsh);
71 :
72 1 : if (!(chain_elem = bf_marsh_next_child(marsh, chain_elem)))
73 : return -EINVAL;
74 1 : memcpy(&hook, chain_elem->data, sizeof(hook));
75 :
76 1 : if (!(chain_elem = bf_marsh_next_child(marsh, chain_elem)))
77 : return -EINVAL;
78 1 : memcpy(&policy, chain_elem->data, sizeof(policy));
79 :
80 1 : r = bf_chain_new(&_chain, hook, policy, NULL, NULL);
81 1 : if (r)
82 : return r;
83 :
84 : // Unmarsh bf_chain.hook_opts
85 1 : if (!(chain_elem = bf_marsh_next_child(marsh, chain_elem)))
86 : return -EINVAL;
87 : {
88 1 : if (!(list_elem = bf_marsh_next_child(chain_elem, NULL)))
89 : return -EINVAL;
90 1 : memcpy(&_chain->hook_opts.used_opts, list_elem->data,
91 : sizeof(_chain->hook_opts.used_opts));
92 :
93 1 : if (!(list_elem = bf_marsh_next_child(chain_elem, list_elem)))
94 : return -EINVAL;
95 1 : memcpy(&_chain->hook_opts.ifindex, list_elem->data,
96 : sizeof(_chain->hook_opts.ifindex));
97 :
98 1 : if (!(list_elem = bf_marsh_next_child(chain_elem, list_elem)))
99 : return -EINVAL;
100 :
101 1 : if (list_elem->data_len) {
102 0 : _chain->hook_opts.cgroup = strdup(list_elem->data);
103 0 : if (!_chain->hook_opts.cgroup)
104 : return -ENOMEM;
105 : }
106 :
107 1 : if (!(list_elem = bf_marsh_next_child(chain_elem, list_elem)))
108 : return -EINVAL;
109 :
110 1 : if (list_elem->data_len) {
111 0 : _chain->hook_opts.name = strdup(list_elem->data);
112 0 : if (!_chain->hook_opts.name)
113 : return -ENOMEM;
114 : }
115 :
116 1 : if (!(list_elem = bf_marsh_next_child(chain_elem, list_elem)))
117 : return -EINVAL;
118 1 : memcpy(&_chain->hook_opts.attach, list_elem->data,
119 : sizeof(_chain->hook_opts.attach));
120 :
121 1 : if (bf_marsh_next_child(chain_elem, list_elem)) {
122 0 : return bf_err_r(-E2BIG,
123 : "too many serialized fields for bf_hook_opts");
124 : }
125 : }
126 :
127 : // Unmarsh bf_chain.sets
128 1 : if (!(chain_elem = bf_marsh_next_child(marsh, chain_elem)))
129 : return -EINVAL;
130 :
131 : list_elem = NULL;
132 1 : while ((list_elem = bf_marsh_next_child(chain_elem, list_elem))) {
133 0 : _cleanup_bf_set_ struct bf_set *set = NULL;
134 :
135 0 : r = bf_set_new_from_marsh(&set, list_elem);
136 0 : if (r)
137 : return r;
138 :
139 0 : r = bf_list_add_tail(&_chain->sets, set);
140 0 : if (r)
141 : return r;
142 :
143 0 : TAKE_PTR(set);
144 : }
145 :
146 : // Unmarsh bf_chain.rules
147 1 : if (!(chain_elem = bf_marsh_next_child(marsh, chain_elem)))
148 : return -EINVAL;
149 : list_elem = NULL;
150 1 : while ((list_elem = bf_marsh_next_child(chain_elem, list_elem))) {
151 0 : _cleanup_bf_rule_ struct bf_rule *rule = NULL;
152 :
153 0 : r = bf_rule_unmarsh(list_elem, &rule);
154 0 : if (r)
155 : return r;
156 :
157 0 : r = bf_list_add_tail(&_chain->rules, rule);
158 0 : if (r)
159 : return r;
160 :
161 0 : TAKE_PTR(rule);
162 : }
163 :
164 1 : *chain = TAKE_PTR(_chain);
165 :
166 1 : return 0;
167 : }
168 :
169 23 : void bf_chain_free(struct bf_chain **chain)
170 : {
171 23 : bf_assert(chain);
172 :
173 23 : if (!*chain)
174 : return;
175 :
176 9 : bf_list_clean(&(*chain)->sets);
177 9 : bf_list_clean(&(*chain)->rules);
178 9 : bf_hook_opts_clean(&(*chain)->hook_opts);
179 : freep((void *)chain);
180 : }
181 :
182 1 : int bf_chain_marsh(const struct bf_chain *chain, struct bf_marsh **marsh)
183 : {
184 1 : _cleanup_bf_marsh_ struct bf_marsh *_marsh = NULL;
185 : int r;
186 :
187 1 : bf_assert(chain);
188 1 : bf_assert(marsh);
189 :
190 1 : r = bf_marsh_new(&_marsh, NULL, 0);
191 1 : if (r)
192 : return r;
193 :
194 1 : r = bf_marsh_add_child_raw(&_marsh, &chain->hook, sizeof(chain->hook));
195 1 : if (r < 0)
196 : return r;
197 :
198 1 : r = bf_marsh_add_child_raw(&_marsh, &chain->policy, sizeof(chain->policy));
199 1 : if (r)
200 : return r;
201 :
202 : {
203 : // Serialize bf_chain.hook_opts
204 1 : _cleanup_bf_marsh_ struct bf_marsh *child = NULL;
205 1 : const char *cg_path = chain->hook_opts.cgroup;
206 1 : const char *name = chain->hook_opts.name;
207 :
208 1 : r = bf_marsh_new(&child, NULL, 0);
209 1 : if (r < 0)
210 0 : return bf_err_r(r, "failed to creaet marsh for bf_chain");
211 :
212 1 : r = bf_marsh_add_child_raw(&child, &chain->hook_opts.used_opts,
213 : sizeof(chain->hook_opts.used_opts));
214 1 : if (r < 0)
215 : return r;
216 :
217 1 : r = bf_marsh_add_child_raw(&child, &chain->hook_opts.ifindex,
218 : sizeof(chain->hook_opts.ifindex));
219 1 : if (r)
220 : return r;
221 :
222 : /* If a cgroup path is defined, serialize it, including the nul
223 : * termination character (to simplify deserializing with strdup()).
224 : * Otherwise, create an empty child marsh (NULL data and 0 length). */
225 1 : r = bf_marsh_add_child_raw(&child, cg_path,
226 0 : cg_path ? strlen(cg_path) + 1 : 0);
227 1 : if (r)
228 : return r;
229 :
230 : // Similar to cg_path
231 1 : r = bf_marsh_add_child_raw(&child, name, name ? strlen(name) + 1 : 0);
232 1 : if (r)
233 : return r;
234 :
235 1 : r = bf_marsh_add_child_raw(&child, &chain->hook_opts.attach,
236 : sizeof(chain->hook_opts.attach));
237 1 : if (r < 0)
238 : return r;
239 :
240 1 : r = bf_marsh_add_child_obj(&_marsh, child);
241 1 : if (r < 0)
242 : return r;
243 : }
244 :
245 : {
246 : // Serialize bf_chain.sets
247 1 : _cleanup_bf_marsh_ struct bf_marsh *child = NULL;
248 :
249 1 : r = bf_list_marsh(&chain->sets, &child);
250 1 : if (r < 0)
251 : return r;
252 :
253 1 : r = bf_marsh_add_child_obj(&_marsh, child);
254 1 : if (r < 0)
255 : return r;
256 : }
257 :
258 : {
259 : // Serialize bf_chain.rules
260 1 : _cleanup_bf_marsh_ struct bf_marsh *child = NULL;
261 :
262 1 : r = bf_list_marsh(&chain->rules, &child);
263 1 : if (r < 0)
264 : return r;
265 :
266 1 : r = bf_marsh_add_child_obj(&_marsh, child);
267 1 : if (r < 0)
268 : return r;
269 : }
270 :
271 1 : *marsh = TAKE_PTR(_marsh);
272 :
273 1 : return 0;
274 : }
275 :
276 0 : void bf_chain_dump(const struct bf_chain *chain, prefix_t *prefix)
277 : {
278 0 : bf_assert(chain);
279 0 : bf_assert(prefix);
280 :
281 0 : DUMP(prefix, "struct bf_chain at %p", chain);
282 :
283 0 : bf_dump_prefix_push(prefix);
284 0 : DUMP(prefix, "hook: %s", bf_hook_to_str(chain->hook));
285 0 : DUMP(prefix, "hook_opts: struct bf_hook_opts");
286 0 : bf_hook_opts_dump(&chain->hook_opts, prefix, chain->hook);
287 0 : DUMP(prefix, "policy: %s", bf_verdict_to_str(chain->policy));
288 :
289 0 : DUMP(prefix, "sets: bf_list<bf_set>[%lu]", bf_list_size(&chain->sets));
290 0 : bf_dump_prefix_push(prefix);
291 0 : bf_list_foreach (&chain->sets, set_node) {
292 0 : struct bf_set *set = bf_list_node_get_data(set_node);
293 :
294 0 : if (bf_list_is_tail(&chain->sets, set_node))
295 0 : bf_dump_prefix_last(prefix);
296 :
297 0 : bf_set_dump(set, prefix);
298 : }
299 0 : bf_dump_prefix_pop(prefix);
300 :
301 0 : DUMP(bf_dump_prefix_last(prefix), "rules: bf_list<bf_rule>[%lu]",
302 : bf_list_size(&chain->rules));
303 0 : bf_dump_prefix_push(prefix);
304 0 : bf_list_foreach (&chain->rules, rule_node) {
305 0 : struct bf_rule *rule = bf_list_node_get_data(rule_node);
306 :
307 0 : if (bf_list_is_tail(&chain->rules, rule_node))
308 0 : bf_dump_prefix_last(prefix);
309 :
310 0 : bf_rule_dump(rule, prefix);
311 : }
312 :
313 0 : bf_dump_prefix_pop(prefix);
314 0 : bf_dump_prefix_pop(prefix);
315 0 : }
316 :
317 0 : int bf_chain_add_rule(struct bf_chain *chain, struct bf_rule *rule)
318 : {
319 0 : bf_assert(chain);
320 0 : bf_assert(rule);
321 :
322 0 : rule->index = bf_list_size(&chain->rules);
323 :
324 0 : return bf_list_add_tail(&chain->rules, rule);
325 : }
|