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/dump.h"
14 : #include "bpfilter/helper.h"
15 : #include "bpfilter/list.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_pkthdr_strs[] = {
23 : [BF_PKTHDR_LINK] = "link",
24 : [BF_PKTHDR_INTERNET] = "internet",
25 : [BF_PKTHDR_TRANSPORT] = "transport",
26 : };
27 : static_assert_enum_mapping(_bf_pkthdr_strs, _BF_PKTHDR_MAX);
28 :
29 0 : const char *bf_pkthdr_to_str(enum bf_pkthdr hdr)
30 : {
31 0 : bf_assert(hdr < _BF_PKTHDR_MAX);
32 :
33 0 : return _bf_pkthdr_strs[hdr];
34 : }
35 :
36 0 : int bf_pkthdr_from_str(const char *str, enum bf_pkthdr *hdr)
37 : {
38 0 : bf_assert(str);
39 :
40 0 : for (int i = 0; i < _BF_PKTHDR_MAX; ++i) {
41 0 : if (bf_streq_i(str, _bf_pkthdr_strs[i])) {
42 0 : *hdr = (enum bf_pkthdr)i;
43 0 : return 0;
44 : }
45 : }
46 :
47 : return -EINVAL;
48 : }
49 :
50 16 : int bf_rule_new(struct bf_rule **rule)
51 : {
52 : struct bf_rule *_rule;
53 :
54 16 : bf_assert(rule);
55 :
56 15 : _rule = calloc(1, sizeof(*_rule));
57 15 : if (!_rule)
58 : return -ENOMEM;
59 :
60 14 : _rule->matchers = bf_list_default(bf_matcher_free, bf_matcher_pack);
61 :
62 14 : *rule = _rule;
63 :
64 14 : return 0;
65 : }
66 :
67 5 : int bf_rule_new_from_pack(struct bf_rule **rule, bf_rpack_node_t node)
68 : {
69 5 : _free_bf_rule_ struct bf_rule *_rule = NULL;
70 : bf_rpack_node_t m_nodes, m_node;
71 : int r;
72 :
73 5 : bf_assert(rule);
74 :
75 5 : r = bf_rule_new(&_rule);
76 5 : if (r)
77 0 : return bf_err_r(r, "failed to create bf_rule from pack");
78 :
79 5 : r = bf_rpack_kv_u32(node, "index", &_rule->index);
80 5 : if (r)
81 0 : return bf_rpack_key_err(r, "bf_rule.index");
82 :
83 5 : r = bf_rpack_kv_u8(node, "log", &_rule->log);
84 5 : if (r)
85 0 : return bf_rpack_key_err(r, "bf_rule.log");
86 :
87 5 : r = bf_rpack_kv_bool(node, "counters", &_rule->counters);
88 5 : if (r)
89 0 : return bf_rpack_key_err(r, "bf_rule.counters");
90 :
91 5 : r = bf_rpack_kv_u64(node, "mark", &_rule->mark);
92 5 : if (r)
93 0 : return bf_rpack_key_err(r, "bf_rule.mark");
94 :
95 5 : r = bf_rpack_kv_enum(node, "verdict", &_rule->verdict);
96 : if (r)
97 0 : return bf_rpack_key_err(r, "bf_rule.verdict");
98 :
99 5 : r = bf_rpack_kv_array(node, "matchers", &m_nodes);
100 5 : if (r)
101 0 : return bf_rpack_key_err(r, "bf_rule.matchers");
102 54 : bf_rpack_array_foreach (m_nodes, m_node) {
103 44 : _free_bf_matcher_ struct bf_matcher *matcher = NULL;
104 :
105 22 : r = bf_list_emplace(&_rule->matchers, bf_matcher_new_from_pack, matcher,
106 : m_node);
107 : if (r) {
108 0 : return bf_err_r(
109 : r, "failed to unpack bf_matcher into bf_rule.matchers");
110 : }
111 : }
112 :
113 5 : *rule = TAKE_PTR(_rule);
114 :
115 5 : return 0;
116 : }
117 :
118 32 : void bf_rule_free(struct bf_rule **rule)
119 : {
120 32 : bf_assert(rule);
121 :
122 31 : if (!*rule)
123 : return;
124 :
125 14 : bf_list_clean(&(*rule)->matchers);
126 :
127 14 : free(*rule);
128 14 : *rule = NULL;
129 : }
130 :
131 7 : int bf_rule_pack(const struct bf_rule *rule, bf_wpack_t *pack)
132 : {
133 7 : bf_assert(rule);
134 6 : bf_assert(pack);
135 :
136 5 : bf_wpack_kv_u32(pack, "index", rule->index);
137 5 : bf_wpack_kv_u8(pack, "log", rule->log);
138 5 : bf_wpack_kv_bool(pack, "counters", rule->counters);
139 5 : bf_wpack_kv_u64(pack, "mark", rule->mark);
140 5 : bf_wpack_kv_int(pack, "verdict", rule->verdict);
141 :
142 5 : bf_wpack_kv_list(pack, "matchers", &rule->matchers);
143 :
144 5 : return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
145 : }
146 :
147 0 : void bf_rule_dump(const struct bf_rule *rule, prefix_t *prefix)
148 : {
149 0 : bf_assert(rule);
150 0 : bf_assert(prefix);
151 :
152 0 : DUMP(prefix, "struct bf_rule at %p", rule);
153 :
154 0 : bf_dump_prefix_push(prefix);
155 :
156 0 : DUMP(prefix, "index: %u", rule->index);
157 :
158 : // Matchers
159 0 : DUMP(prefix, "matchers: %lu", bf_list_size(&rule->matchers));
160 0 : bf_dump_prefix_push(prefix);
161 0 : bf_list_foreach (&rule->matchers, matcher_node) {
162 0 : struct bf_matcher *matcher = bf_list_node_get_data(matcher_node);
163 :
164 0 : if (bf_list_is_tail(&rule->matchers, matcher_node))
165 0 : bf_dump_prefix_last(prefix);
166 :
167 0 : bf_matcher_dump(matcher, prefix);
168 : }
169 0 : bf_dump_prefix_pop(prefix);
170 :
171 0 : DUMP(prefix, "log: %02x", rule->log);
172 0 : DUMP(prefix, "counters: %s", rule->counters ? "yes" : "no");
173 0 : DUMP(prefix, "mark: 0x%" PRIx64, rule->mark);
174 0 : DUMP(bf_dump_prefix_last(prefix), "verdict: %s",
175 : bf_verdict_to_str(rule->verdict));
176 :
177 0 : bf_dump_prefix_pop(prefix);
178 0 : }
179 :
180 10 : int bf_rule_add_matcher(struct bf_rule *rule, enum bf_matcher_type type,
181 : enum bf_matcher_op op, const void *payload,
182 : size_t payload_len)
183 : {
184 10 : _free_bf_matcher_ struct bf_matcher *matcher = NULL;
185 : int r;
186 :
187 10 : bf_assert(rule);
188 :
189 10 : r = bf_matcher_new(&matcher, type, op, payload, payload_len);
190 10 : if (r)
191 : return r;
192 :
193 10 : r = bf_list_add_tail(&rule->matchers, matcher);
194 10 : if (r)
195 : return r;
196 :
197 10 : TAKE_PTR(matcher);
198 :
199 10 : return 0;
200 : }
|