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 "core/matcher.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/logger.h"
15 : #include "core/marsh.h"
16 :
17 71 : int bf_matcher_new(struct bf_matcher **matcher, enum bf_matcher_type type,
18 : enum bf_matcher_op op, const void *payload,
19 : size_t payload_len)
20 : {
21 69 : _free_bf_matcher_ struct bf_matcher *_matcher = NULL;
22 :
23 71 : bf_assert(matcher);
24 70 : bf_assert((payload && payload_len) || (!payload && !payload_len));
25 :
26 69 : _matcher = malloc(sizeof(struct bf_matcher) + payload_len);
27 69 : if (!_matcher)
28 : return -ENOMEM;
29 :
30 66 : _matcher->type = type;
31 66 : _matcher->op = op;
32 66 : _matcher->len = sizeof(struct bf_matcher) + payload_len;
33 66 : bf_memcpy(_matcher->payload, payload, payload_len);
34 :
35 66 : *matcher = TAKE_PTR(_matcher);
36 :
37 66 : return 0;
38 : }
39 :
40 26 : int bf_matcher_new_from_marsh(struct bf_matcher **matcher,
41 : const struct bf_marsh *marsh)
42 : {
43 : struct bf_marsh *child = NULL;
44 : enum bf_matcher_type type;
45 : enum bf_matcher_op op;
46 : size_t payload_len;
47 : const void *payload;
48 : int r;
49 :
50 26 : bf_assert(matcher);
51 25 : bf_assert(marsh);
52 :
53 24 : if (!(child = bf_marsh_next_child(marsh, child)))
54 : return -EINVAL;
55 24 : memcpy(&type, child->data, sizeof(type));
56 :
57 24 : if (!(child = bf_marsh_next_child(marsh, child)))
58 : return -EINVAL;
59 24 : memcpy(&op, child->data, sizeof(op));
60 :
61 24 : if (!(child = bf_marsh_next_child(marsh, child)))
62 : return -EINVAL;
63 24 : memcpy(&payload_len, child->data, sizeof(payload_len));
64 24 : payload_len -= sizeof(struct bf_matcher);
65 :
66 24 : if (!(child = bf_marsh_next_child(marsh, child)))
67 : return -EINVAL;
68 24 : payload = child->data;
69 :
70 24 : r = bf_matcher_new(matcher, type, op, payload, payload_len);
71 24 : if (r)
72 1 : return bf_err_r(r, "failed to restore bf_matcher from serialised data");
73 :
74 : return 0;
75 : }
76 :
77 178 : void bf_matcher_free(struct bf_matcher **matcher)
78 : {
79 178 : bf_assert(matcher);
80 :
81 177 : if (!*matcher)
82 : return;
83 :
84 66 : free(*matcher);
85 66 : *matcher = NULL;
86 : }
87 :
88 27 : int bf_matcher_marsh(const struct bf_matcher *matcher, struct bf_marsh **marsh)
89 : {
90 25 : _free_bf_marsh_ struct bf_marsh *_marsh = NULL;
91 : int r;
92 :
93 27 : bf_assert(matcher);
94 26 : bf_assert(marsh);
95 :
96 25 : r = bf_marsh_new(&_marsh, NULL, 0);
97 25 : if (r < 0)
98 : return r;
99 :
100 24 : r |= bf_marsh_add_child_raw(&_marsh, &matcher->type, sizeof(matcher->type));
101 24 : r |= bf_marsh_add_child_raw(&_marsh, &matcher->op, sizeof(matcher->op));
102 24 : r |= bf_marsh_add_child_raw(&_marsh, &matcher->len, sizeof(matcher->len));
103 48 : r |= bf_marsh_add_child_raw(&_marsh, matcher->payload,
104 24 : matcher->len - sizeof(struct bf_matcher));
105 24 : if (r)
106 0 : return bf_err_r(r, "failed to serialise bf_matcher object");
107 :
108 24 : *marsh = TAKE_PTR(_marsh);
109 :
110 24 : return 0;
111 : }
112 :
113 0 : void bf_matcher_dump(const struct bf_matcher *matcher, prefix_t *prefix)
114 : {
115 0 : bf_assert(matcher);
116 0 : bf_assert(prefix);
117 :
118 0 : DUMP(prefix, "struct bf_matcher at %p", matcher);
119 :
120 0 : bf_dump_prefix_push(prefix);
121 :
122 0 : DUMP(prefix, "type: %s", bf_matcher_type_to_str(matcher->type));
123 0 : DUMP(prefix, "op: %s", bf_matcher_op_to_str(matcher->op));
124 0 : DUMP(prefix, "len: %ld", matcher->len);
125 0 : DUMP(bf_dump_prefix_last(prefix), "payload:");
126 0 : bf_dump_prefix_push(prefix);
127 0 : bf_dump_hex(prefix, matcher->payload,
128 0 : matcher->len - sizeof(struct bf_matcher));
129 0 : bf_dump_prefix_pop(prefix);
130 :
131 0 : bf_dump_prefix_pop(prefix);
132 0 : }
133 :
134 : static const char *_bf_matcher_type_strs[] = {
135 : [BF_MATCHER_META_IFINDEX] = "meta.ifindex",
136 : [BF_MATCHER_META_L3_PROTO] = "meta.l3_proto",
137 : [BF_MATCHER_META_L4_PROTO] = "meta.l4_proto",
138 : [BF_MATCHER_META_PROBABILITY] = "meta.probability",
139 : [BF_MATCHER_META_SPORT] = "meta.sport",
140 : [BF_MATCHER_META_DPORT] = "meta.dport",
141 : [BF_MATCHER_IP4_SADDR] = "ip4.saddr",
142 : [BF_MATCHER_IP4_SNET] = "ip4.snet",
143 : [BF_MATCHER_IP4_DADDR] = "ip4.daddr",
144 : [BF_MATCHER_IP4_DNET] = "ip4.dnet",
145 : [BF_MATCHER_IP4_PROTO] = "ip4.proto",
146 : [BF_MATCHER_IP6_SADDR] = "ip6.saddr",
147 : [BF_MATCHER_IP6_SNET] = "ip6.snet",
148 : [BF_MATCHER_IP6_DADDR] = "ip6.daddr",
149 : [BF_MATCHER_IP6_DNET] = "ip6.dnet",
150 : [BF_MATCHER_TCP_SPORT] = "tcp.sport",
151 : [BF_MATCHER_TCP_DPORT] = "tcp.dport",
152 : [BF_MATCHER_TCP_FLAGS] = "tcp.flags",
153 : [BF_MATCHER_UDP_SPORT] = "udp.sport",
154 : [BF_MATCHER_UDP_DPORT] = "udp.dport",
155 : [BF_MATCHER_SET_SRCIP6PORT] = "set.srcip6port",
156 : [BF_MATCHER_SET_SRCIP6] = "set.srcip6",
157 : [BF_MATCHER_ICMP_TYPE] = "icmp.type",
158 : [BF_MATCHER_ICMP_CODE] = "icmp.code",
159 : [BF_MATCHER_ICMPV6_TYPE] = "icmpv6.type",
160 : [BF_MATCHER_ICMPV6_CODE] = "icmpv6.code",
161 : };
162 :
163 : static_assert(ARRAY_SIZE(_bf_matcher_type_strs) == _BF_MATCHER_TYPE_MAX,
164 : "missing entries in the matcher type array");
165 :
166 28 : const char *bf_matcher_type_to_str(enum bf_matcher_type type)
167 : {
168 28 : bf_assert(0 <= type && type < _BF_MATCHER_TYPE_MAX);
169 :
170 26 : return _bf_matcher_type_strs[type];
171 : }
172 :
173 30 : int bf_matcher_type_from_str(const char *str, enum bf_matcher_type *type)
174 : {
175 30 : bf_assert(str);
176 29 : bf_assert(type);
177 :
178 405 : for (size_t i = 0; i < _BF_MATCHER_TYPE_MAX; ++i) {
179 403 : if (bf_streq(_bf_matcher_type_strs[i], str)) {
180 26 : *type = i;
181 26 : return 0;
182 : }
183 : }
184 :
185 : return -EINVAL;
186 : }
187 :
188 : static const char *_bf_matcher_ops_strs[] = {
189 : [BF_MATCHER_EQ] = "eq", [BF_MATCHER_NE] = "not",
190 : [BF_MATCHER_ANY] = "any", [BF_MATCHER_ALL] = "all",
191 : [BF_MATCHER_IN] = "in", [BF_MATCHER_RANGE] = "range",
192 : };
193 :
194 : static_assert(ARRAY_SIZE(_bf_matcher_ops_strs) == _BF_MATCHER_OP_MAX);
195 :
196 8 : const char *bf_matcher_op_to_str(enum bf_matcher_op op)
197 : {
198 8 : bf_assert(0 <= op && op < _BF_MATCHER_OP_MAX);
199 :
200 6 : return _bf_matcher_ops_strs[op];
201 : }
202 :
203 0 : int bf_matcher_op_from_str(const char *str, enum bf_matcher_op *op)
204 : {
205 0 : bf_assert(str);
206 0 : bf_assert(op);
207 :
208 0 : for (size_t i = 0; i < _BF_MATCHER_OP_MAX; ++i) {
209 0 : if (bf_streq(_bf_matcher_ops_strs[i], str)) {
210 0 : *op = i;
211 0 : return 0;
212 : }
213 : }
214 :
215 : return -EINVAL;
216 : }
217 :
218 : static const char *_bf_matcher_tcp_flags_strs[] = {
219 : [BF_MATCHER_TCP_FLAG_FIN] = "FIN", [BF_MATCHER_TCP_FLAG_SYN] = "SYN",
220 : [BF_MATCHER_TCP_FLAG_RST] = "RST", [BF_MATCHER_TCP_FLAG_PSH] = "PSH",
221 : [BF_MATCHER_TCP_FLAG_ACK] = "ACK", [BF_MATCHER_TCP_FLAG_URG] = "URG",
222 : [BF_MATCHER_TCP_FLAG_ECE] = "ECE", [BF_MATCHER_TCP_FLAG_CWR] = "CWR",
223 : };
224 :
225 0 : const char *bf_matcher_tcp_flag_to_str(enum bf_matcher_tcp_flag flag)
226 : {
227 0 : bf_assert(0 <= flag && flag < _BF_MATCHER_TCP_FLAG_MAX);
228 :
229 0 : return _bf_matcher_tcp_flags_strs[flag];
230 : }
231 :
232 0 : int bf_matcher_tcp_flag_from_str(const char *str,
233 : enum bf_matcher_tcp_flag *flag)
234 : {
235 0 : bf_assert(str);
236 0 : bf_assert(flag);
237 :
238 0 : for (size_t i = 0; i < _BF_MATCHER_TCP_FLAG_MAX; ++i) {
239 0 : if (bf_streq(_bf_matcher_tcp_flags_strs[i], str)) {
240 0 : *flag = i;
241 0 : return 0;
242 : }
243 : }
244 :
245 : return -EINVAL;
246 : }
|