Branch data 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 "bpfilter/rule.h"
7 : :
8 : : #include <errno.h>
9 : : #include <inttypes.h>
10 : : #include <stdlib.h>
11 : : #include <string.h>
12 : :
13 : : #include "bpfilter/core/list.h"
14 : : #include "bpfilter/dump.h"
15 : : #include "bpfilter/helper.h"
16 : : #include "bpfilter/logger.h"
17 : : #include "bpfilter/matcher.h"
18 : : #include "bpfilter/pack.h"
19 : : #include "bpfilter/runtime.h"
20 : : #include "bpfilter/verdict.h"
21 : :
22 : : static const char *_bf_log_opt_strs[] = {
23 : : [BF_LOG_OPT_LINK] = "link",
24 : : [BF_LOG_OPT_INTERNET] = "internet",
25 : : [BF_LOG_OPT_TRANSPORT] = "transport",
26 : : };
27 : : static_assert_enum_mapping(_bf_log_opt_strs, _BF_LOG_OPT_MAX);
28 : :
29 : 9 : const char *bf_log_opt_to_str(enum bf_log_opt hdr)
30 : : {
31 [ + + ]: 9 : if (hdr < 0 || hdr >= _BF_LOG_OPT_MAX)
32 : : return "<bf_log_opt unknown>";
33 : :
34 : 7 : return _bf_log_opt_strs[hdr];
35 : : }
36 : :
37 : 67 : int bf_log_opt_from_str(const char *str, enum bf_log_opt *hdr)
38 : : {
39 : : assert(hdr);
40 : :
41 [ + + ]: 131 : for (int i = 0; i < _BF_LOG_OPT_MAX; ++i) {
42 [ + + ]: 126 : if (bf_streq_i(str, _bf_log_opt_strs[i])) {
43 : 62 : *hdr = (enum bf_log_opt)i;
44 : 62 : return 0;
45 : : }
46 : : }
47 : :
48 : : return -EINVAL;
49 : : }
50 : :
51 : 9078 : int bf_rule_new(struct bf_rule **rule)
52 : : {
53 : 9078 : _free_bf_rule_ struct bf_rule *_rule = NULL;
54 : :
55 : : assert(rule);
56 : :
57 : 9078 : _rule = calloc(1, sizeof(*_rule));
58 [ + - ]: 9078 : if (!_rule)
59 : : return -ENOMEM;
60 : :
61 : 9078 : _rule->matchers = bf_list_default(bf_matcher_free, bf_matcher_pack);
62 : :
63 : 9078 : *rule = TAKE_PTR(_rule);
64 : :
65 : 9078 : return 0;
66 : : }
67 : :
68 : 6883 : int bf_rule_new_from_pack(struct bf_rule **rule, bf_rpack_node_t node)
69 : : {
70 : 6883 : _free_bf_rule_ struct bf_rule *_rule = NULL;
71 : : bf_rpack_node_t m_nodes, m_node;
72 : : bool has_counters;
73 : : int r;
74 : :
75 : : assert(rule);
76 : :
77 : 6883 : r = bf_rule_new(&_rule);
78 [ - + ]: 6883 : if (r)
79 [ # # ]: 0 : return bf_err_r(r, "failed to create bf_rule from pack");
80 : :
81 : 6883 : r = bf_rpack_kv_u32(node, "index", &_rule->index);
82 [ - + ]: 6883 : if (r)
83 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_rule.index");
84 : :
85 : 6883 : r = bf_rpack_kv_u8(node, "log", &_rule->log);
86 [ + + ]: 6883 : if (r)
87 [ + - ]: 1 : return bf_rpack_key_err(r, "bf_rule.log");
88 : :
89 [ + - ]: 6882 : if (bf_rpack_kv_contains(node, "log_rate_ns")) {
90 : 6882 : r = bf_rpack_kv_u64(node, "log_rate_ns", &_rule->log_rate_ns);
91 [ - + ]: 6882 : if (r)
92 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_rule.log_rate_ns");
93 : : }
94 : :
95 [ + - ]: 6882 : if (bf_rpack_kv_contains(node, "has_counters")) {
96 : 6882 : r = bf_rpack_kv_bool(node, "has_counters", &has_counters);
97 [ - + ]: 6882 : if (r)
98 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_rule.has_counters");
99 [ # # ]: 0 : } else if (bf_rpack_kv_contains(node, "counters")) {
100 : 0 : r = bf_rpack_kv_bool(node, "counters", &has_counters);
101 [ # # ]: 0 : if (r)
102 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_rule.counters");
103 : : } else {
104 [ # # ]: 0 : return bf_err_r(-ENOENT, "missing bf_rule counters flag in pack");
105 : : }
106 : 6882 : _rule->has_counters = has_counters;
107 : :
108 : 6882 : r = bf_rpack_kv_u64(node, "mark", &_rule->mark);
109 [ - + ]: 6882 : if (r)
110 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_rule.mark");
111 : :
112 [ - + - + : 6882 : r = bf_rpack_kv_enum(node, "verdict", &_rule->verdict, 0, _BF_VERDICT_MAX);
- - ]
113 : : if (r)
114 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_rule.verdict");
115 : :
116 [ + - ]: 6882 : if (bf_rpack_kv_contains(node, "redirect_ifindex")) {
117 : 6882 : r = bf_rpack_kv_u32(node, "redirect_ifindex", &_rule->redirect_ifindex);
118 [ - + ]: 6882 : if (r)
119 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_rule.redirect_ifindex");
120 : : }
121 : :
122 [ + - ]: 6882 : if (bf_rpack_kv_contains(node, "redirect_dir")) {
123 [ - + - + : 6882 : r = bf_rpack_kv_enum(node, "redirect_dir", &_rule->redirect_dir, 0,
- - ]
124 : : _BF_REDIRECT_DIR_MAX);
125 : : if (r)
126 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_rule.redirect_dir");
127 : : }
128 : :
129 : 6882 : r = bf_rpack_kv_array(node, "matchers", &m_nodes);
130 [ - + ]: 6882 : if (r)
131 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_rule.matchers");
132 [ + - + + : 23118 : bf_rpack_array_foreach (m_nodes, m_node) {
+ + ]
133 : 16236 : _free_bf_matcher_ struct bf_matcher *matcher = NULL;
134 : :
135 [ + - + - : 8118 : r = bf_list_emplace(&_rule->matchers, bf_matcher_new_from_pack, matcher,
- - - - ]
136 : : m_node);
137 : : if (r) {
138 [ # # ]: 0 : return bf_err_r(
139 : : r, "failed to unpack bf_matcher into bf_rule.matchers");
140 : : }
141 : : }
142 : :
143 : 6882 : *rule = TAKE_PTR(_rule);
144 : :
145 : 6882 : return 0;
146 : : }
147 : :
148 : 32991 : void bf_rule_free(struct bf_rule **rule)
149 : : {
150 : : assert(rule);
151 : :
152 [ + + ]: 32991 : if (!*rule)
153 : : return;
154 : :
155 : 9078 : bf_list_clean(&(*rule)->matchers);
156 : :
157 : 9078 : free(*rule);
158 : 9078 : *rule = NULL;
159 : : }
160 : :
161 : 3173 : int bf_rule_pack(const struct bf_rule *rule, bf_wpack_t *pack)
162 : : {
163 : : assert(rule);
164 : : assert(pack);
165 : :
166 : 3173 : bf_wpack_kv_u32(pack, "index", rule->index);
167 : 6346 : bf_wpack_kv_u8(pack, "log", rule->log);
168 : 3173 : bf_wpack_kv_u64(pack, "log_rate_ns", rule->log_rate_ns);
169 : 3173 : bf_wpack_kv_bool(pack, "has_counters", rule->has_counters);
170 : 3173 : bf_wpack_kv_u64(pack, "mark", rule->mark);
171 : 3173 : bf_wpack_kv_int(pack, "verdict", rule->verdict);
172 : 3173 : bf_wpack_kv_u32(pack, "redirect_ifindex", rule->redirect_ifindex);
173 : 3173 : bf_wpack_kv_int(pack, "redirect_dir", rule->redirect_dir);
174 : :
175 : 3173 : bf_wpack_kv_list(pack, "matchers", &rule->matchers);
176 : :
177 [ - + ]: 3173 : return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
178 : : }
179 : :
180 : 14 : void bf_rule_dump(const struct bf_rule *rule, prefix_t *prefix)
181 : : {
182 : : assert(rule);
183 : : assert(prefix);
184 : :
185 [ - + ]: 14 : DUMP(prefix, "struct bf_rule at %p", rule);
186 : :
187 : 14 : bf_dump_prefix_push(prefix);
188 : :
189 [ - + ]: 14 : DUMP(prefix, "index: %u", rule->index);
190 : :
191 : : // Matchers
192 [ - + ]: 14 : DUMP(prefix, "matchers: %lu", bf_list_size(&rule->matchers));
193 : 14 : bf_dump_prefix_push(prefix);
194 [ + + + + : 96 : bf_list_foreach (&rule->matchers, matcher_node) {
+ + ]
195 : : struct bf_matcher *matcher = bf_list_node_get_data(matcher_node);
196 : :
197 [ + + ]: 34 : if (bf_list_is_tail(&rule->matchers, matcher_node))
198 : 13 : bf_dump_prefix_last(prefix);
199 : :
200 : 34 : bf_matcher_dump(matcher, prefix);
201 : : }
202 : 14 : bf_dump_prefix_pop(prefix);
203 : :
204 [ - + ]: 14 : DUMP(prefix, "log: %02x", rule->log);
205 : :
206 [ - + - - ]: 14 : DUMP(prefix, "has_counters: %s", rule->has_counters ? "yes" : "no");
207 [ + + ]: 14 : if (rule->has_counters) {
208 [ - + ]: 10 : DUMP(prefix, "counters: struct bf_counter");
209 : 10 : bf_dump_prefix_push(prefix);
210 [ - + ]: 10 : DUMP(prefix, "count: %lu", rule->counters.count);
211 [ - + ]: 10 : DUMP(prefix, "size: %lu", rule->counters.size);
212 : 10 : bf_dump_prefix_pop(prefix);
213 : : }
214 : :
215 [ - + - - ]: 14 : DUMP(prefix, "disabled: %s", rule->disabled ? "yes" : "no");
216 [ - + ]: 14 : DUMP(prefix, "mark: 0x%" PRIx64, rule->mark);
217 [ - + ]: 14 : DUMP(prefix, "verdict: %s", bf_verdict_to_str(rule->verdict));
218 [ - + ]: 14 : if (bf_rule_has_redirect(rule)) {
219 [ # # ]: 0 : DUMP(prefix, "redirect_ifindex: %u", rule->redirect_ifindex);
220 [ # # ]: 0 : DUMP(bf_dump_prefix_last(prefix), "redirect_dir: %s",
221 : : bf_redirect_dir_to_str(rule->redirect_dir));
222 : : } else {
223 [ - + ]: 14 : DUMP(prefix, "redirect_ifindex: <not set>");
224 [ - + ]: 14 : DUMP(bf_dump_prefix_last(prefix), "redirect_dir: <not set>");
225 : : }
226 : :
227 : 14 : bf_dump_prefix_pop(prefix);
228 : 14 : }
229 : :
230 : 1167 : int bf_rule_add_matcher(struct bf_rule *rule, enum bf_matcher_type type,
231 : : enum bf_matcher_op op, const void *payload,
232 : : size_t payload_len, bool negate)
233 : : {
234 : 1167 : _free_bf_matcher_ struct bf_matcher *matcher = NULL;
235 : : int r;
236 : :
237 : : assert(rule);
238 : :
239 : 1167 : r = bf_matcher_new(&matcher, type, op, payload, payload_len, negate);
240 [ + - ]: 1167 : if (r)
241 : : return r;
242 : :
243 : 1167 : r = bf_list_add_tail(&rule->matchers, matcher);
244 [ + - ]: 1167 : if (r)
245 : : return r;
246 : :
247 : 1167 : TAKE_PTR(matcher);
248 : :
249 : 1167 : return 0;
250 : : }
|