Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
4 : : */
5 : :
6 : : #include "bpfilter/set.h"
7 : :
8 : : #include <endian.h>
9 : : #include <errno.h>
10 : : #include <stdint.h>
11 : : #include <stdlib.h>
12 : : #include <string.h>
13 : :
14 : : #include "bpfilter/core/hashset.h"
15 : : #include "bpfilter/dump.h"
16 : : #include "bpfilter/helper.h"
17 : : #include "bpfilter/logger.h"
18 : : #include "bpfilter/pack.h"
19 : :
20 : : #define _BF_SET_NAME_CHARS \
21 : : "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-"
22 : :
23 : : /// Mask value of matcher types supporting LPM trie maps.
24 : : #define _BF_SET_USE_TRIE_MASK \
25 : : (BF_FLAGS(BF_MATCHER_IP4_SNET, BF_MATCHER_IP4_DNET, BF_MATCHER_IP6_SNET, \
26 : : BF_MATCHER_IP6_DNET))
27 : :
28 : 5565 : static uint64_t _bf_set_elem_hash(const void *data, void *ctx)
29 : : {
30 : 5565 : return bf_fnv1a(data, *(const size_t *)ctx, bf_fnv1a_init());
31 : : }
32 : :
33 : 1038 : static bool _bf_set_elem_equal(const void *lhs, const void *rhs, void *ctx)
34 : : {
35 : 1038 : return memcmp(lhs, rhs, *(const size_t *)ctx) == 0;
36 : : }
37 : :
38 : 4601 : static void _bf_set_elem_free(void **data, void *ctx)
39 : : {
40 : : (void)ctx;
41 : 4601 : BF_FREEP(data);
42 : 4601 : }
43 : :
44 : : static const bf_hashset_ops _bf_set_elem_ops = {
45 : : .hash = _bf_set_elem_hash,
46 : : .equal = _bf_set_elem_equal,
47 : : .free = _bf_set_elem_free,
48 : : };
49 : :
50 : 1931 : static uint64_t _bf_set_name_hash(const void *data, void *ctx)
51 : : {
52 : : const struct bf_set *set = data;
53 : :
54 : : (void)ctx;
55 : :
56 : 1931 : return bf_fnv1a(set->name, strlen(set->name), bf_fnv1a_init());
57 : : }
58 : :
59 : 1483 : static bool _bf_set_name_equal(const void *lhs, const void *rhs, void *ctx)
60 : : {
61 : : const struct bf_set *left = lhs;
62 : : const struct bf_set *right = rhs;
63 : :
64 : : (void)ctx;
65 : :
66 : 1483 : return bf_streq(left->name, right->name);
67 : : }
68 : :
69 : 375 : static void _bf_set_collection_free(void **data, void *ctx)
70 : : {
71 : : (void)ctx;
72 : :
73 : 375 : bf_set_free((struct bf_set **)data);
74 : 375 : }
75 : :
76 : 16612 : bf_hashset bf_set_hashset_default(void)
77 : : {
78 : : const bf_hashset_ops ops = {
79 : : .hash = _bf_set_name_hash,
80 : : .equal = _bf_set_name_equal,
81 : : .free = _bf_set_collection_free,
82 : : };
83 : :
84 : 16612 : return bf_hashset_default(&ops, NULL);
85 : : }
86 : :
87 : 1095 : bool bf_set_is_valid_name(const char *name)
88 : : {
89 [ + + + + : 1095 : return name && *name && name[strspn(name, _BF_SET_NAME_CHARS)] == '\0';
+ + ]
90 : : }
91 : :
92 : 13462 : bool bf_set_is_anonymous(const struct bf_set *set)
93 : : {
94 : : assert(set);
95 : :
96 : 13462 : return !set->name;
97 : : }
98 : :
99 : 2746 : int bf_set_new(struct bf_set **set, const char *name,
100 : : const enum bf_matcher_type *key, size_t n_comps)
101 : : {
102 : 2746 : _free_bf_set_ struct bf_set *_set = NULL;
103 : : uint64_t mask = 0;
104 : :
105 : : assert(set);
106 : : assert(key);
107 : :
108 [ + + + + ]: 2746 : if (name && !bf_set_is_valid_name(name))
109 [ + - ]: 16 : return bf_err_r(-EINVAL, "invalid set name '%s'", name);
110 : :
111 [ + + ]: 2730 : if (n_comps == 0)
112 [ + - ]: 2 : return bf_err_r(-EINVAL, "at least 1 key component is required");
113 : :
114 [ + + ]: 2728 : if (n_comps > BF_SET_MAX_N_COMPS) {
115 [ + - ]: 1 : return bf_err_r(-E2BIG,
116 : : "a set key can't contain more than %d components",
117 : : BF_SET_MAX_N_COMPS);
118 : : }
119 : :
120 : 2727 : _set = calloc(1, sizeof(*_set));
121 [ + - ]: 2727 : if (!_set)
122 : : return -ENOMEM;
123 : :
124 [ + + ]: 2727 : if (name) {
125 : 522 : _set->name = strdup(name);
126 [ - + ]: 522 : if (!_set->name)
127 [ # # ]: 0 : return bf_err_r(-ENOMEM, "failed to allocate memory for set name");
128 : : }
129 : :
130 : 2727 : memcpy(&_set->key, key, n_comps * sizeof(enum bf_matcher_type));
131 : 2727 : _set->n_comps = n_comps;
132 : 2727 : _set->elem_size = 0;
133 : 2727 : _set->min_size = 0;
134 : 2727 : bf_hashset_init(&_set->elems, &_bf_set_elem_ops, &_set->elem_size);
135 : :
136 [ + + ]: 5872 : for (size_t i = 0; i < n_comps; ++i) {
137 : : const struct bf_matcher_ops *ops;
138 : :
139 : 3145 : ops = bf_matcher_get_ops(_set->key[i], BF_MATCHER_IN);
140 [ - + ]: 3145 : if (!ops) {
141 [ # # ]: 0 : return bf_err_r(-ENOTSUP,
142 : : "matcher '%s' (%d) is not supported as a set key",
143 : : bf_matcher_type_to_str(_set->key[i]), _set->key[i]);
144 : : }
145 : 3145 : _set->elem_size += ops->ref_payload_size;
146 : :
147 : 3145 : mask |= BF_FLAG(_set->key[i]);
148 : : }
149 : :
150 [ + + + + ]: 2727 : _set->use_trie = n_comps == 1 && mask & _BF_SET_USE_TRIE_MASK;
151 : :
152 [ + + + + ]: 2727 : if (n_comps > 1 && mask & _BF_SET_USE_TRIE_MASK) {
153 [ + - ]: 3 : return bf_err_r(
154 : : -EINVAL,
155 : : "network matchers can't be used in combination with other matchers in a set");
156 : : }
157 : :
158 : 2724 : *set = TAKE_PTR(_set);
159 : :
160 : 2724 : return 0;
161 : : }
162 : :
163 : : /**
164 : : * @brief Parse a set's raw key into an array of `bf_matcher_type`.
165 : : *
166 : : * @param raw_key Raw set key, as a string of comma-separated matcher types
167 : : * enclosed in parentheses. Can't be NULL.
168 : : * @param key Set key, parsed from `raw_key`. Can't be NULL.
169 : : * @param n_comps Number of components in `key`. Can't be NULL.
170 : : * @return 0 on success, or a negative error value on failure.
171 : : */
172 : 444 : static int _bf_set_parse_key(const char *raw_key, enum bf_matcher_type *key,
173 : : size_t *n_comps)
174 : : {
175 : : _cleanup_free_ char *_raw_key = NULL;
176 : : char *tmp, *saveptr, *token;
177 : :
178 : : assert(raw_key);
179 : : assert(key);
180 : : assert(n_comps);
181 : :
182 : 444 : _raw_key = strdup(raw_key);
183 [ - + ]: 444 : if (!_raw_key) {
184 [ # # ]: 0 : return bf_err_r(-ENOMEM, "failed to duplicate set raw key '%s'",
185 : : raw_key);
186 : : }
187 : :
188 : 444 : *n_comps = 0;
189 : :
190 : : tmp = _raw_key;
191 [ + + ]: 972 : while ((token = strtok_r(tmp, "(),", &saveptr))) {
192 : : int r;
193 : :
194 [ - + ]: 531 : if (*n_comps == BF_SET_MAX_N_COMPS) {
195 [ # # ]: 0 : return bf_err_r(-E2BIG, "set keys are limited to %d components",
196 : : BF_SET_MAX_N_COMPS);
197 : : }
198 : :
199 : 531 : token = bf_trim(token);
200 : :
201 : 531 : r = bf_matcher_type_from_str(token, &key[*n_comps]);
202 [ + + ]: 531 : if (r)
203 [ + - ]: 3 : return bf_err_r(r, "failed to parse set key component '%s'", token);
204 : :
205 : : tmp = NULL;
206 : 528 : ++*n_comps;
207 : : }
208 : :
209 [ + + ]: 441 : if (!*n_comps)
210 [ + - ]: 1 : return bf_err_r(-EINVAL, "set key can't have no component");
211 : :
212 : : return 0;
213 : : }
214 : :
215 : 15 : static int _bf_set_expand_range(struct bf_set *set, const char *token,
216 : : const struct bf_matcher_ops *range_ops)
217 : : {
218 : : uint16_t bounds[2];
219 : : int r;
220 : :
221 : : assert(set);
222 : : assert(token);
223 : : assert(range_ops);
224 : :
225 : 15 : r = range_ops->parse(set->key[0], BF_MATCHER_RANGE, bounds, token);
226 [ + + ]: 15 : if (r)
227 [ + - ]: 3 : return bf_err_r(r, "failed to parse set element range '%s'", token);
228 : :
229 [ + + ]: 47 : for (uint32_t value = bounds[0]; value <= bounds[1]; ++value) {
230 : : _cleanup_free_ uint16_t *range_elem = NULL;
231 : : void *range_data;
232 : :
233 : 35 : range_elem = malloc(set->elem_size);
234 [ - + ]: 35 : if (!range_elem)
235 [ # # ]: 0 : return bf_err_r(-ENOMEM, "failed to allocate a new set element");
236 : :
237 : 35 : *range_elem = htobe16((uint16_t)value);
238 : :
239 : 35 : range_data = range_elem;
240 : 35 : r = bf_hashset_add(&set->elems, &range_data);
241 [ + + ]: 35 : if (!r)
242 : : range_elem = NULL;
243 [ - + ]: 35 : if (r && r != -EEXIST)
244 [ # # ]: 0 : return bf_err_r(r, "failed to insert element into set");
245 : : }
246 : :
247 : : return 0;
248 : : }
249 : :
250 : 542 : int bf_set_add_elem_raw(struct bf_set *set, const char *raw_elem)
251 : : {
252 : 542 : _cleanup_free_ void *elem = NULL;
253 : : _cleanup_free_ char *_raw_elem = NULL;
254 : : const struct bf_matcher_ops *range_ops = NULL;
255 : : char *tmp, *saveptr, *token;
256 : : size_t elem_offset = 0;
257 : : size_t comp_idx = 0;
258 : : int r;
259 : :
260 : : assert(set);
261 : : assert(raw_elem);
262 : :
263 : 542 : _raw_elem = strdup(raw_elem);
264 [ - + ]: 542 : if (!_raw_elem) {
265 [ # # ]: 0 : return bf_err_r(-ENOMEM,
266 : : "failed to create a copy of the raw element '%s'",
267 : : raw_elem);
268 : : }
269 : :
270 : 542 : elem = calloc(1, set->elem_size);
271 [ - + ]: 542 : if (!elem)
272 [ # # ]: 0 : return bf_err_r(-ENOMEM, "failed to allocate a new set element");
273 : :
274 [ + + ]: 542 : if (set->n_comps == 1 && (set->key[0] == BF_MATCHER_TCP_SPORT ||
275 [ + + ]: 423 : set->key[0] == BF_MATCHER_TCP_DPORT ||
276 : : set->key[0] == BF_MATCHER_UDP_SPORT ||
277 : : set->key[0] == BF_MATCHER_UDP_DPORT ||
278 : : set->key[0] == BF_MATCHER_META_SPORT ||
279 : : set->key[0] == BF_MATCHER_META_DPORT)) {
280 : 183 : range_ops = bf_matcher_get_ops(set->key[0], BF_MATCHER_RANGE);
281 : : }
282 : :
283 : : tmp = _raw_elem;
284 [ + + ]: 1177 : while ((token = strtok_r(tmp, ",", &saveptr))) {
285 : : const struct bf_matcher_ops *ops;
286 : :
287 [ + + ]: 659 : if (comp_idx >= set->n_comps) {
288 [ + - ]: 2 : return bf_err_r(
289 : : -EINVAL,
290 : : "set element has more components than defined in the key '%s'",
291 : : token);
292 : : }
293 : :
294 : 657 : token = bf_trim(token);
295 : :
296 : 657 : ops = bf_matcher_get_ops(set->key[comp_idx], BF_MATCHER_IN);
297 [ - + ]: 657 : if (!ops) {
298 [ # # ]: 0 : return bf_err_r(-EINVAL, "matcher type '%s' has no matcher_ops",
299 : : bf_matcher_type_to_str(set->key[comp_idx]));
300 : : }
301 : :
302 [ + + + + ]: 657 : if (range_ops && strchr(token, '-')) {
303 [ + + ]: 16 : if (strchr(raw_elem, ',')) {
304 [ + - ]: 1 : return bf_err_r(
305 : : -EINVAL,
306 : : "set element has more components than defined in the key: '%s'",
307 : : token);
308 : : }
309 : 15 : return _bf_set_expand_range(set, token, range_ops);
310 : : }
311 : :
312 : 641 : r = ops->parse(set->key[comp_idx], BF_MATCHER_IN, elem + elem_offset,
313 : : token);
314 [ + + ]: 641 : if (r) {
315 [ + - ]: 6 : return bf_err_r(r, "failed to parse set element component '%s'",
316 : : token);
317 : : }
318 : :
319 : 635 : elem_offset += ops->ref_payload_size;
320 : : tmp = NULL;
321 : 635 : ++comp_idx;
322 : : }
323 : :
324 [ + + ]: 518 : if (comp_idx != set->n_comps) {
325 [ + - ]: 3 : return bf_err_r(-EINVAL, "missing component in set element '%s'",
326 : : raw_elem);
327 : : }
328 : :
329 : 515 : r = bf_hashset_add(&set->elems, &elem);
330 [ + + ]: 515 : if (r == -EEXIST)
331 : : return 0;
332 [ - + ]: 514 : if (r)
333 [ # # ]: 0 : return bf_err_r(r, "failed to insert element into set");
334 : :
335 : : return 0;
336 : : }
337 : :
338 : 444 : int bf_set_new_from_raw(struct bf_set **set, const char *name,
339 : : const char *raw_key, const char *raw_payload)
340 : : {
341 : 444 : _free_bf_set_ struct bf_set *_set = NULL;
342 : : _cleanup_free_ char *_raw_payload = NULL;
343 : : enum bf_matcher_type key[BF_SET_MAX_N_COMPS];
344 : : char *raw_elem, *tmp, *saveptr;
345 : : size_t n_comps;
346 : : int r;
347 : :
348 : : assert(set);
349 : : assert(raw_key);
350 : : assert(raw_payload);
351 : :
352 : 444 : r = _bf_set_parse_key(raw_key, key, &n_comps);
353 [ + + ]: 444 : if (r)
354 [ + - ]: 4 : return bf_err_r(r, "failed to parse set key '%s'", raw_key);
355 : :
356 : 440 : r = bf_set_new(&_set, name, key, n_comps);
357 [ + + ]: 440 : if (r)
358 : : return r;
359 : :
360 : 433 : _raw_payload = strdup(raw_payload);
361 [ - + ]: 433 : if (!_raw_payload)
362 [ # # ]: 0 : return bf_err_r(-ENOMEM, "failed to copy set raw payload '%s'",
363 : : raw_payload);
364 : :
365 : : tmp = _raw_payload;
366 [ + + ]: 983 : while ((raw_elem = strtok_r(tmp, "{};\n", &saveptr))) {
367 : : tmp = NULL;
368 : 564 : raw_elem = bf_trim(raw_elem);
369 : :
370 : : /* While strtok_r() won't return empty token, the trimmed version of the
371 : : * token can be empty! */
372 [ + + ]: 564 : if (raw_elem[0] == '\0')
373 : 60 : continue;
374 : :
375 : 504 : r = bf_set_add_elem_raw(_set, raw_elem);
376 [ + + ]: 504 : if (r)
377 [ + - ]: 14 : return bf_err_r(r, "failed to parse set element '%s'", raw_elem);
378 : : }
379 : :
380 : 419 : *set = TAKE_PTR(_set);
381 : :
382 : 419 : return 0;
383 : : }
384 : :
385 : 1280 : int bf_set_new_from_pack(struct bf_set **set, bf_rpack_node_t node)
386 : : {
387 : 1280 : _free_bf_set_ struct bf_set *_set = NULL;
388 : 1280 : _cleanup_free_ char *name = NULL;
389 : : bf_rpack_node_t child, comp_node, elem_node;
390 : : size_t n_comps = 0;
391 : : enum bf_matcher_type key[BF_SET_MAX_N_COMPS];
392 : : int r;
393 : :
394 : : assert(set);
395 : :
396 : 1280 : r = bf_rpack_kv_node(node, "name", &child);
397 [ - + ]: 1280 : if (r)
398 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_set.name");
399 : :
400 [ + + ]: 1280 : if (!bf_rpack_is_nil(child)) {
401 : 117 : r = bf_rpack_str(child, &name);
402 [ - + ]: 117 : if (r)
403 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_set.name");
404 : : }
405 : :
406 : 1280 : r = bf_rpack_kv_array(node, "key", &child);
407 [ - + ]: 1280 : if (r)
408 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_set.key");
409 [ + - + + : 4170 : bf_rpack_array_foreach (child, comp_node) {
+ + ]
410 : 1445 : ++n_comps;
411 [ - + ]: 1445 : if (n_comps > BF_SET_MAX_N_COMPS) {
412 [ # # ]: 0 : return bf_err_r(
413 : : -E2BIG,
414 : : "bf_set.key in pack contains %lu key components, only %d allowed",
415 : : n_comps, BF_SET_MAX_N_COMPS);
416 : : }
417 : :
418 [ - + - + : 1445 : r = bf_rpack_enum(comp_node, &key[i], 0, _BF_MATCHER_TYPE_MAX);
- - ]
419 : : if (r)
420 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_set.key");
421 : : }
422 : :
423 : 1280 : r = bf_set_new(&_set, name, key, n_comps);
424 [ + + ]: 1280 : if (r)
425 [ + - ]: 6 : return bf_err_r(r, "failed to create bf_set from pack");
426 : :
427 : 1274 : r = bf_rpack_kv_size(node, "min_size", &_set->min_size);
428 [ - + ]: 1274 : if (r)
429 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_set.min_size");
430 : :
431 : 1274 : r = bf_rpack_kv_array(node, "elements", &child);
432 [ - + ]: 1274 : if (r)
433 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_set.elements");
434 [ + + + + : 5796 : bf_rpack_array_foreach (child, elem_node) {
+ + ]
435 : : const void *elem;
436 : : size_t elem_len;
437 : :
438 : 2261 : r = bf_rpack_bin(elem_node, &elem, &elem_len);
439 [ - + ]: 2261 : if (r)
440 [ # # ]: 0 : return bf_rpack_key_err(r, "bf_set.elements");
441 : :
442 [ - + ]: 2261 : if (elem_len != _set->elem_size) {
443 [ # # ]: 0 : return bf_err_r(-EINVAL,
444 : : "bf_set pack element is %lu bytes, it must be %lu",
445 : : elem_len, _set->elem_size);
446 : : }
447 : :
448 : 2261 : r = bf_set_add_elem(_set, elem);
449 [ - + ]: 2261 : if (r)
450 [ # # ]: 0 : return bf_err_r(r, "failed to insert element to bf_set");
451 : : }
452 : :
453 : 1274 : *set = TAKE_PTR(_set);
454 : :
455 : 1274 : return 0;
456 : : }
457 : :
458 : 464 : int bf_set_new_from_copy(struct bf_set **dest, const struct bf_set *src)
459 : : {
460 : 464 : _free_bf_set_ struct bf_set *copy = NULL;
461 : : int r;
462 : :
463 : : assert(dest);
464 : : assert(src);
465 : :
466 : 464 : r = bf_set_new(©, src->name, src->key, src->n_comps);
467 [ + - ]: 464 : if (r)
468 : : return r;
469 : :
470 : 464 : copy->min_size = src->min_size;
471 : :
472 [ + + - + ]: 464 : if (!bf_set_is_empty(src) && copy->elem_size != src->elem_size)
473 [ # # ]: 0 : return bf_err_r(-EINVAL, "invalid source set element size");
474 : :
475 : 464 : r = bf_set_reserve(copy, bf_hashset_size(&src->elems));
476 [ + - ]: 464 : if (r)
477 : : return r;
478 : :
479 [ + + + + : 2530 : bf_hashset_foreach (&src->elems, elem) {
+ + ]
480 : 801 : r = bf_set_add_elem(copy, elem->data);
481 [ + - ]: 801 : if (r)
482 : : return r;
483 : : }
484 : :
485 : 464 : *dest = TAKE_PTR(copy);
486 : :
487 : 464 : return 0;
488 : : }
489 : :
490 : 10031 : void bf_set_free(struct bf_set **set)
491 : : {
492 : : assert(set);
493 : :
494 [ + + ]: 10031 : if (!*set)
495 : : return;
496 : :
497 : 2727 : bf_hashset_clean(&(*set)->elems);
498 : 2727 : BF_FREEP(&(*set)->name);
499 : 2727 : BF_FREEP(set);
500 : : }
501 : :
502 : 446 : int bf_set_pack(const struct bf_set *set, bf_wpack_t *pack)
503 : : {
504 : : assert(set);
505 : : assert(pack);
506 : :
507 [ + + ]: 446 : if (set->name)
508 : : bf_wpack_kv_str(pack, "name", set->name);
509 : : else
510 : : bf_wpack_kv_nil(pack, "name");
511 : :
512 : 446 : bf_wpack_open_array(pack, "key");
513 [ + + ]: 970 : for (size_t i = 0; i < set->n_comps; ++i)
514 : 524 : bf_wpack_enum(pack, set->key[i]);
515 : 446 : bf_wpack_close_array(pack);
516 : :
517 : 446 : bf_wpack_kv_u64(pack, "min_size", set->min_size);
518 : :
519 : 446 : bf_wpack_open_array(pack, "elements");
520 [ + + + + : 2534 : bf_hashset_foreach (&set->elems, elem)
+ + ]
521 : 821 : bf_wpack_bin(pack, elem->data, set->elem_size);
522 : 446 : bf_wpack_close_array(pack);
523 : :
524 [ - + ]: 446 : return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
525 : : }
526 : :
527 : 5 : void bf_set_dump(const struct bf_set *set, prefix_t *prefix)
528 : : {
529 : : size_t dump_idx = 0;
530 : :
531 : : assert(set);
532 : : assert(prefix);
533 : :
534 [ - + ]: 5 : DUMP(prefix, "struct bf_set at %p", set);
535 : 5 : bf_dump_prefix_push(prefix);
536 : :
537 [ - + - - ]: 5 : DUMP(prefix, "name: %s", set->name ?: "<anonymous>");
538 [ - + ]: 5 : DUMP(prefix, "key: bf_matcher_type[%zu]", set->n_comps);
539 : 5 : bf_dump_prefix_push(prefix);
540 [ + + ]: 14 : for (size_t i = 0; i < set->n_comps; ++i) {
541 [ + + ]: 9 : if (i == set->n_comps - 1)
542 : 5 : bf_dump_prefix_last(prefix);
543 : :
544 [ - + ]: 9 : DUMP(prefix, "%s", bf_matcher_type_to_str(set->key[i]));
545 : : }
546 : 5 : bf_dump_prefix_pop(prefix);
547 : :
548 [ - + ]: 5 : DUMP(prefix, "elem_size: %lu", set->elem_size);
549 [ - + ]: 5 : DUMP(prefix, "min_size: %lu", set->min_size);
550 [ - + ]: 5 : DUMP(bf_dump_prefix_last(prefix), "elems: bf_hashset<bytes>[%lu]",
551 : : bf_hashset_size(&set->elems));
552 : :
553 : 5 : bf_dump_prefix_push(prefix);
554 [ + + + + : 42 : bf_hashset_foreach (&set->elems, elem) {
+ + ]
555 [ + + ]: 16 : if (++dump_idx == bf_hashset_size(&set->elems))
556 : 4 : bf_dump_prefix_last(prefix);
557 : :
558 [ - + ]: 16 : DUMP(prefix, "void * @ %p", elem->data);
559 : 16 : bf_dump_prefix_push(prefix);
560 : 16 : bf_dump_hex(prefix, elem->data, set->elem_size);
561 : 16 : bf_dump_prefix_pop(prefix);
562 : : }
563 : 5 : bf_dump_prefix_pop(prefix);
564 : :
565 : 5 : bf_dump_prefix_pop(prefix);
566 : 5 : }
567 : :
568 : 4057 : int bf_set_add_elem(struct bf_set *set, const void *elem)
569 : : {
570 : : _cleanup_free_ void *_elem = NULL;
571 : : int r;
572 : :
573 : : assert(set);
574 : : assert(elem);
575 : :
576 : 4057 : _elem = malloc(set->elem_size);
577 [ + - ]: 4057 : if (!_elem)
578 : : return -ENOMEM;
579 : :
580 : 4057 : memcpy(_elem, elem, set->elem_size);
581 : :
582 : 4057 : r = bf_hashset_add(&set->elems, &_elem);
583 [ + + ]: 4057 : if (r == -EEXIST)
584 : 2 : return 0;
585 : : if (r)
586 : : return r;
587 : :
588 : : return 0;
589 : : }
590 : :
591 : 2986 : bool bf_set_is_empty(const struct bf_set *set)
592 : : {
593 : : assert(set);
594 : :
595 : 2986 : return bf_hashset_is_empty(&set->elems);
596 : : }
597 : :
598 : 698 : int bf_set_reserve(struct bf_set *set, size_t count)
599 : : {
600 : : assert(set);
601 : :
602 : 698 : return bf_hashset_reserve(&set->elems, count);
603 : : }
604 : :
605 : 212 : bool bf_set_same_key(const struct bf_set *lhs, const struct bf_set *rhs)
606 : : {
607 : : assert(lhs);
608 : : assert(rhs);
609 : :
610 [ + + ]: 212 : if (lhs->n_comps != rhs->n_comps)
611 : : return false;
612 : :
613 : 170 : return memcmp(lhs->key, rhs->key,
614 : 170 : lhs->n_comps * sizeof(enum bf_matcher_type)) == 0;
615 : : }
616 : :
617 : 22 : int bf_set_add_many(struct bf_set *dest, struct bf_set **to_add)
618 : : {
619 : : int r;
620 : :
621 : : assert(dest);
622 : : assert(to_add);
623 : : assert(*to_add);
624 : :
625 [ + + ]: 22 : if (!bf_set_same_key(dest, *to_add))
626 [ + - ]: 2 : return bf_err_r(-EINVAL, "set key format mismatch");
627 : :
628 [ + + + + : 86 : bf_hashset_foreach (&(*to_add)->elems, elem) {
+ + ]
629 : 23 : _cleanup_free_ void *data = NULL;
630 : :
631 : 23 : r = bf_hashset_take(&(*to_add)->elems, elem->data, &data);
632 [ - + ]: 23 : if (r)
633 [ # # ]: 0 : return bf_err_r(r, "failed to take element from source set");
634 : :
635 : 23 : r = bf_hashset_add(&dest->elems, &data);
636 [ + + ]: 23 : if (r == -EEXIST)
637 : : continue;
638 [ - + ]: 21 : if (r)
639 [ # # ]: 0 : return bf_err_r(r, "failed to add element to set");
640 : : }
641 : :
642 : 20 : bf_set_free(to_add);
643 : :
644 : 20 : return 0;
645 : : }
646 : :
647 : 23 : int bf_set_remove_many(struct bf_set *dest, struct bf_set **to_remove)
648 : : {
649 : : int r;
650 : :
651 : : assert(dest);
652 : : assert(to_remove);
653 : : assert(*to_remove);
654 : :
655 [ + + ]: 23 : if (!bf_set_same_key(dest, *to_remove))
656 [ + - ]: 2 : return bf_err_r(-EINVAL, "set key format mismatch");
657 : :
658 [ + + + + : 66 : bf_hashset_foreach (&(*to_remove)->elems, elem) {
+ + ]
659 : 12 : r = bf_hashset_delete(&dest->elems, elem->data);
660 [ - + ]: 12 : if (r && r != -ENOENT)
661 [ # # ]: 0 : return bf_err_r(r, "failed to remove element from set");
662 : : }
663 : :
664 : 21 : bf_set_free(to_remove);
665 : :
666 : 21 : return 0;
667 : : }
|