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 : static void _bf_chain_update_features(struct bf_chain *chain,
23 : const struct bf_rule *rule)
24 : {
25 10 : bf_assert(rule);
26 :
27 10 : if (rule->log)
28 0 : chain->flags |= BF_FLAG(BF_CHAIN_LOG);
29 :
30 80 : bf_list_foreach (&rule->matchers, matcher_node) {
31 30 : struct bf_matcher *matcher = bf_list_node_get_data(matcher_node);
32 30 : if (matcher->type == BF_MATCHER_IP6_NEXTHDR) {
33 0 : chain->flags |= BF_FLAG(BF_CHAIN_STORE_NEXTHDR);
34 0 : break;
35 : }
36 : }
37 10 : }
38 :
39 19 : int bf_chain_new(struct bf_chain **chain, const char *name, enum bf_hook hook,
40 : enum bf_verdict policy, bf_list *sets, bf_list *rules)
41 : {
42 15 : _free_bf_chain_ struct bf_chain *_chain = NULL;
43 : size_t ridx = 0;
44 :
45 19 : bf_assert(chain && name);
46 17 : bf_assert(policy < _BF_TERMINAL_VERDICT_MAX);
47 :
48 15 : _chain = malloc(sizeof(*_chain));
49 15 : if (!_chain)
50 : return -ENOMEM;
51 :
52 15 : _chain->name = strdup(name);
53 15 : if (!_chain->name)
54 : return -ENOMEM;
55 :
56 15 : _chain->flags = 0;
57 15 : _chain->hook = hook;
58 15 : _chain->policy = policy;
59 :
60 15 : _chain->sets = bf_list_default(bf_set_free, bf_set_marsh);
61 15 : if (sets)
62 1 : _chain->sets = bf_list_move(*sets);
63 :
64 15 : _chain->rules = bf_list_default(bf_rule_free, bf_rule_marsh);
65 15 : if (rules)
66 2 : _chain->rules = bf_list_move(*rules);
67 42 : bf_list_foreach (&_chain->rules, rule_node) {
68 6 : struct bf_rule *rule = bf_list_node_get_data(rule_node);
69 :
70 6 : rule->index = ridx++;
71 6 : _bf_chain_update_features(_chain, rule);
72 : }
73 :
74 15 : *chain = TAKE_PTR(_chain);
75 :
76 15 : return 0;
77 : }
78 :
79 2 : int bf_chain_new_from_marsh(struct bf_chain **chain,
80 : const struct bf_marsh *marsh)
81 : {
82 2 : _free_bf_chain_ struct bf_chain *_chain = NULL;
83 : struct bf_marsh *child = NULL;
84 : struct bf_marsh *list_elem;
85 : enum bf_hook hook;
86 : enum bf_verdict policy;
87 : _cleanup_free_ const char *name = NULL;
88 : int r;
89 :
90 2 : bf_assert(chain && marsh);
91 :
92 2 : if (!(child = bf_marsh_next_child(marsh, child)))
93 : return -EINVAL;
94 2 : if (child->data_len == 0)
95 0 : return bf_err_r(-EINVAL, "serialized bf_chain.name is empty");
96 2 : name = strdup(child->data);
97 2 : if (!name)
98 : return -ENOMEM;
99 :
100 2 : if (!(child = bf_marsh_next_child(marsh, child)))
101 : return -EINVAL;
102 2 : memcpy(&hook, child->data, sizeof(hook));
103 :
104 2 : if (!(child = bf_marsh_next_child(marsh, child)))
105 : return -EINVAL;
106 2 : memcpy(&policy, child->data, sizeof(policy));
107 :
108 2 : r = bf_chain_new(&_chain, name, hook, policy, NULL, NULL);
109 2 : if (r)
110 : return r;
111 :
112 : // Unmarsh bf_chain.sets
113 : list_elem = NULL;
114 2 : if (!(child = bf_marsh_next_child(marsh, child)))
115 : return -EINVAL;
116 2 : while ((list_elem = bf_marsh_next_child(child, list_elem))) {
117 0 : _free_bf_set_ struct bf_set *set = NULL;
118 :
119 0 : r = bf_set_new_from_marsh(&set, list_elem);
120 0 : if (r)
121 : return r;
122 :
123 0 : r = bf_list_add_tail(&_chain->sets, set);
124 0 : if (r)
125 : return r;
126 :
127 0 : TAKE_PTR(set);
128 : }
129 :
130 : // Unmarsh bf_chain.rules
131 : list_elem = NULL;
132 2 : if (!(child = bf_marsh_next_child(marsh, child)))
133 : return -EINVAL;
134 6 : while ((list_elem = bf_marsh_next_child(child, list_elem))) {
135 0 : _free_bf_rule_ struct bf_rule *rule = NULL;
136 :
137 4 : r = bf_rule_unmarsh(list_elem, &rule);
138 4 : if (r)
139 : return r;
140 :
141 : // Using bf_chain_add_rule() will automatically update chain->flags
142 4 : r = bf_chain_add_rule(_chain, rule);
143 4 : if (r)
144 : return r;
145 :
146 4 : TAKE_PTR(rule);
147 : }
148 :
149 2 : *chain = TAKE_PTR(_chain);
150 :
151 2 : return 0;
152 : }
153 :
154 38 : void bf_chain_free(struct bf_chain **chain)
155 : {
156 38 : bf_assert(chain);
157 :
158 37 : if (!*chain)
159 : return;
160 :
161 15 : bf_list_clean(&(*chain)->sets);
162 15 : bf_list_clean(&(*chain)->rules);
163 15 : freep((void *)&(*chain)->name);
164 : freep((void *)chain);
165 : }
166 :
167 2 : int bf_chain_marsh(const struct bf_chain *chain, struct bf_marsh **marsh)
168 : {
169 2 : _free_bf_marsh_ struct bf_marsh *_marsh = NULL;
170 : int r;
171 :
172 2 : bf_assert(chain && marsh);
173 :
174 2 : r = bf_marsh_new(&_marsh, NULL, 0);
175 2 : if (r)
176 : return r;
177 :
178 2 : r = bf_marsh_add_child_raw(&_marsh, chain->name, strlen(chain->name) + 1);
179 2 : if (r < 0)
180 : return r;
181 :
182 2 : r = bf_marsh_add_child_raw(&_marsh, &chain->hook, sizeof(chain->hook));
183 2 : if (r < 0)
184 : return r;
185 :
186 2 : r = bf_marsh_add_child_raw(&_marsh, &chain->policy, sizeof(chain->policy));
187 2 : if (r)
188 : return r;
189 :
190 : {
191 : // Serialize bf_chain.sets
192 2 : _free_bf_marsh_ struct bf_marsh *child = NULL;
193 :
194 2 : r = bf_list_marsh(&chain->sets, &child);
195 2 : if (r < 0)
196 : return r;
197 :
198 2 : r = bf_marsh_add_child_obj(&_marsh, child);
199 2 : if (r < 0)
200 : return r;
201 : }
202 :
203 : {
204 : // Serialize bf_chain.rules
205 2 : _free_bf_marsh_ struct bf_marsh *child = NULL;
206 :
207 2 : r = bf_list_marsh(&chain->rules, &child);
208 2 : if (r < 0)
209 : return r;
210 :
211 2 : r = bf_marsh_add_child_obj(&_marsh, child);
212 2 : if (r < 0)
213 : return r;
214 : }
215 :
216 2 : *marsh = TAKE_PTR(_marsh);
217 :
218 2 : return 0;
219 : }
220 :
221 0 : void bf_chain_dump(const struct bf_chain *chain, prefix_t *prefix)
222 : {
223 0 : bf_assert(chain && prefix);
224 :
225 0 : DUMP(prefix, "struct bf_chain at %p", chain);
226 0 : bf_dump_prefix_push(prefix);
227 :
228 0 : DUMP(prefix, "name: %s", chain->name);
229 0 : DUMP(prefix, "flags: %02x", chain->flags);
230 0 : DUMP(prefix, "hook: %s", bf_hook_to_str(chain->hook));
231 0 : DUMP(prefix, "policy: %s", bf_verdict_to_str(chain->policy));
232 :
233 0 : DUMP(prefix, "sets: bf_list<bf_set>[%lu]", bf_list_size(&chain->sets));
234 0 : bf_dump_prefix_push(prefix);
235 0 : bf_list_foreach (&chain->sets, set_node) {
236 0 : if (bf_list_is_tail(&chain->sets, set_node))
237 0 : bf_dump_prefix_last(prefix);
238 :
239 0 : bf_set_dump(bf_list_node_get_data(set_node), prefix);
240 : }
241 0 : bf_dump_prefix_pop(prefix);
242 :
243 0 : DUMP(bf_dump_prefix_last(prefix), "rules: bf_list<bf_rule>[%lu]",
244 : bf_list_size(&chain->rules));
245 0 : bf_dump_prefix_push(prefix);
246 0 : bf_list_foreach (&chain->rules, rule_node) {
247 0 : if (bf_list_is_tail(&chain->rules, rule_node))
248 0 : bf_dump_prefix_last(prefix);
249 :
250 0 : bf_rule_dump(bf_list_node_get_data(rule_node), prefix);
251 : }
252 0 : bf_dump_prefix_pop(prefix);
253 :
254 0 : bf_dump_prefix_pop(prefix);
255 0 : }
256 :
257 4 : int bf_chain_add_rule(struct bf_chain *chain, struct bf_rule *rule)
258 : {
259 4 : bf_assert(chain && rule);
260 :
261 4 : rule->index = bf_list_size(&chain->rules);
262 4 : _bf_chain_update_features(chain, rule);
263 :
264 4 : return bf_list_add_tail(&chain->rules, rule);
265 : }
266 :
267 0 : struct bf_set *bf_chain_get_set_for_matcher(const struct bf_chain *chain,
268 : const struct bf_matcher *matcher)
269 : {
270 0 : bf_assert(chain && matcher);
271 :
272 : uint32_t set_id;
273 :
274 0 : if (matcher->type != BF_MATCHER_SET)
275 : return NULL;
276 :
277 0 : set_id = *(uint32_t *)matcher->payload;
278 :
279 0 : return bf_list_get_at(&chain->sets, set_id);
280 : }
|