1 #include "slurm/db_slurm.h"
2
3 #include <string.h>
4 #include <time.h>
5 #include <arpa/inet.h>
6
7 #include "common.h"
8 #include "crypto/base64.h"
9 #include "data_structure/array_list.h"
10 #include "types/router_key.h"
11
12 struct slurm_prefix_wrap {
13 struct slurm_prefix element;
14 unsigned int references;
15 };
16
17 struct slurm_bgpsec_wrap {
18 struct slurm_bgpsec element;
19 unsigned int references;
20 };
21
22 STATIC_ARRAY_LIST(al_filter_prefix, struct slurm_prefix_wrap)
23 STATIC_ARRAY_LIST(al_assertion_prefix, struct slurm_prefix_wrap)
24 STATIC_ARRAY_LIST(al_filter_bgpsec, struct slurm_bgpsec_wrap)
25 STATIC_ARRAY_LIST(al_assertion_bgpsec, struct slurm_bgpsec_wrap)
26
27 struct slurm_lists {
28 struct al_filter_prefix filter_pfx_al;
29 struct al_assertion_prefix assertion_pfx_al;
30 struct al_filter_bgpsec filter_bgps_al;
31 struct al_assertion_bgpsec assertion_bgps_al;
32 };
33
34 struct db_slurm {
35 struct slurm_lists lists;
36 struct slurm_lists *cache;
37 time_t loaded_date;
38 struct slurm_csum_list csum_list;
39 };
40
41 static char addr_buf[INET6_ADDRSTRLEN];
42
43 static void
slurm_bgpsec_wrap_refget(struct slurm_bgpsec_wrap * elem)44 slurm_bgpsec_wrap_refget(struct slurm_bgpsec_wrap *elem)
45 {
46 elem->references++;
47 }
48
49 static void
slurm_bgpsec_wrap_refput(struct slurm_bgpsec_wrap * elem)50 slurm_bgpsec_wrap_refput(struct slurm_bgpsec_wrap *elem)
51 {
52 elem->references--;
53 if (elem->references == 0) {
54 if ((elem->element.data_flag & SLURM_BGPS_FLAG_SKI) > 0)
55 free(elem->element.ski);
56 if ((elem->element.data_flag & SLURM_BGPS_FLAG_ROUTER_KEY) > 0)
57 free(elem->element.router_public_key);
58 }
59 }
60
61 static int
slurm_lists_create(struct slurm_lists ** result)62 slurm_lists_create(struct slurm_lists **result)
63 {
64 struct slurm_lists *cache;
65
66 cache = malloc(sizeof(struct slurm_lists));
67 if (cache == NULL)
68 return pr_enomem();
69
70 al_filter_prefix_init(&cache->filter_pfx_al);
71 al_assertion_prefix_init(&cache->assertion_pfx_al);
72 al_filter_bgpsec_init(&cache->filter_bgps_al);
73 al_assertion_bgpsec_init(&cache->assertion_bgps_al);
74
75 *result = cache;
76 return 0;
77 }
78
79 static void
slurm_lists_cleanup(struct slurm_lists * lists)80 slurm_lists_cleanup(struct slurm_lists *lists)
81 {
82 /* No need to cleanup prefixes (filters or assertions) */
83 al_filter_prefix_cleanup(&lists->filter_pfx_al, NULL);
84 al_filter_bgpsec_cleanup(&lists->filter_bgps_al,
85 slurm_bgpsec_wrap_refput);
86 al_assertion_prefix_cleanup(&lists->assertion_pfx_al, NULL);
87 al_assertion_bgpsec_cleanup(&lists->assertion_bgps_al,
88 slurm_bgpsec_wrap_refput);
89 }
90
91 static void
slurm_lists_destroy(struct slurm_lists * lists)92 slurm_lists_destroy(struct slurm_lists *lists)
93 {
94 slurm_lists_cleanup(lists);
95 free(lists);
96 }
97
98 int
db_slurm_create(struct slurm_csum_list * csums,struct db_slurm ** result)99 db_slurm_create(struct slurm_csum_list *csums, struct db_slurm **result)
100 {
101 struct db_slurm *db;
102 int error;
103
104 db = malloc(sizeof(struct db_slurm));
105 if (db == NULL)
106 return pr_enomem();
107
108 error = get_current_time(&db->loaded_date);
109 if (error) {
110 free(db);
111 return error;
112 }
113
114 /* Not ready yet (nor required yet) for multithreading */
115 al_filter_prefix_init(&db->lists.filter_pfx_al);
116 al_assertion_prefix_init(&db->lists.assertion_pfx_al);
117 al_filter_bgpsec_init(&db->lists.filter_bgps_al);
118 al_assertion_bgpsec_init(&db->lists.assertion_bgps_al);
119 db->cache = NULL;
120 db->csum_list = *csums;
121
122 /*
123 * Slight hack: Clean up csums, so caller can always call
124 * destroy_local_csum_list().
125 */
126 csums->slh_first = NULL;
127 csums->list_size = 0;
128
129 *result = db;
130 return 0;
131 }
132
133 /*
134 * @filter_wrap is the prefix loaded from SLURM, @prefix is the VRP "masked" as
135 * a slurm_prefix
136 */
137 static bool
prefix_filtered_by(struct slurm_prefix_wrap * filter_wrap,struct slurm_prefix * prefix)138 prefix_filtered_by(struct slurm_prefix_wrap *filter_wrap,
139 struct slurm_prefix *prefix)
140 {
141 struct slurm_prefix *filter;
142 struct vrp *filter_vrp, *prefix_vrp;
143 bool equal;
144
145 filter = &filter_wrap->element;
146 filter_vrp = &filter->vrp;
147 prefix_vrp = &prefix->vrp;
148
149 /*
150 * Ignore the comments, remember: FILTERS don't have the same data (no
151 * max_length is declared), while ASSERTIONS do.
152 */
153 if ((filter->data_flag & ~SLURM_COM_FLAG_COMMENT) !=
154 (prefix->data_flag & ~SLURM_COM_FLAG_COMMENT)) {
155 /* The filter has ASN and prefix */
156 if ((filter->data_flag & ~SLURM_COM_FLAG_COMMENT) ==
157 (SLURM_COM_FLAG_ASN | SLURM_PFX_FLAG_PREFIX))
158 return (filter_vrp->asn == prefix_vrp->asn) &&
159 vrp_prefix_cov(filter_vrp, prefix_vrp);
160
161 /* Both have ASN */
162 if ((filter->data_flag & SLURM_COM_FLAG_ASN) > 0 &&
163 (prefix->data_flag & SLURM_COM_FLAG_ASN) > 0)
164 return filter_vrp->asn == prefix_vrp->asn;
165
166 /* Both have a prefix of the same type */
167 if ((filter->data_flag & SLURM_PFX_FLAG_PREFIX) > 0 &&
168 (prefix->data_flag & SLURM_PFX_FLAG_PREFIX) > 0)
169 return vrp_prefix_cov(filter_vrp, prefix_vrp);
170
171 return false;
172 }
173
174 /* It has the same data, compare it */
175 equal = true;
176 if (equal && (filter->data_flag & SLURM_COM_FLAG_ASN) > 0)
177 equal = filter_vrp->asn == prefix_vrp->asn;
178
179 if (equal && (filter->data_flag & SLURM_PFX_FLAG_PREFIX) > 0)
180 equal = vrp_prefix_cov(filter_vrp, prefix_vrp);
181
182 return equal;
183 }
184
185 static bool
prefix_filtered(struct db_slurm * db,struct slurm_prefix * prefix)186 prefix_filtered(struct db_slurm *db, struct slurm_prefix *prefix)
187 {
188 struct slurm_prefix_wrap *cursor;
189 array_index i;
190
191 ARRAYLIST_FOREACH(&db->lists.filter_pfx_al, cursor, i)
192 if (prefix_filtered_by(cursor, prefix))
193 return true;
194
195 return false;
196 }
197
198 static bool
bgpsec_filtered_by(struct slurm_bgpsec_wrap * filter_wrap,struct slurm_bgpsec * bgpsec)199 bgpsec_filtered_by(struct slurm_bgpsec_wrap *filter_wrap,
200 struct slurm_bgpsec *bgpsec)
201 {
202 struct slurm_bgpsec *filter;
203 bool equal;
204
205 filter = &filter_wrap->element;
206
207 /* Ignore the comments */
208 if ((filter->data_flag & ~SLURM_COM_FLAG_COMMENT) !=
209 (bgpsec->data_flag & ~SLURM_COM_FLAG_COMMENT)) {
210 /* The filter has ASN and SKI */
211 if ((filter->data_flag & ~SLURM_COM_FLAG_COMMENT) ==
212 (SLURM_COM_FLAG_ASN | SLURM_BGPS_FLAG_SKI))
213 return bgpsec->asn == filter->asn &&
214 memcmp(bgpsec->ski, filter->ski, RK_SKI_LEN) == 0;
215
216 /* Both have ASN */
217 if ((bgpsec->data_flag & SLURM_COM_FLAG_ASN) > 0 &&
218 (filter->data_flag & SLURM_COM_FLAG_ASN) > 0)
219 return bgpsec->asn == filter->asn;
220
221 /* Both have a SKI */
222 if ((bgpsec->data_flag & SLURM_BGPS_FLAG_SKI) > 0 &&
223 (filter->data_flag & SLURM_BGPS_FLAG_SKI) > 0)
224 return memcmp(bgpsec->ski, filter->ski, RK_SKI_LEN)
225 == 0;
226
227 return false;
228 }
229
230 /* It has the same data, compare it */
231 equal = true;
232 if (equal && (filter->data_flag & SLURM_COM_FLAG_ASN) > 0)
233 equal = filter->asn == bgpsec->asn;
234
235 if (equal && (filter->data_flag & SLURM_BGPS_FLAG_SKI) > 0)
236 equal = memcmp(filter->ski, bgpsec->ski, RK_SKI_LEN) == 0;
237
238 return equal;
239 }
240
241 static bool
bgpsec_filtered(struct db_slurm * db,struct slurm_bgpsec * bgpsec)242 bgpsec_filtered(struct db_slurm *db, struct slurm_bgpsec *bgpsec)
243 {
244 struct slurm_bgpsec_wrap *cursor;
245 array_index i;
246
247 ARRAYLIST_FOREACH(&db->lists.filter_bgps_al, cursor, i)
248 if (bgpsec_filtered_by(cursor, bgpsec))
249 return true;
250
251 return false;
252 }
253
254 static bool
prefix_contained(struct slurm_prefix * left,struct slurm_prefix * right)255 prefix_contained(struct slurm_prefix *left, struct slurm_prefix *right)
256 {
257 struct vrp *left_vrp, *right_vrp;
258
259 left_vrp = &left->vrp;
260 right_vrp = &right->vrp;
261
262 return (left->data_flag & SLURM_PFX_FLAG_PREFIX) > 0 &&
263 (right->data_flag & SLURM_PFX_FLAG_PREFIX) > 0 &&
264 vrp_prefix_cov(left_vrp, right_vrp);
265 }
266
267 /*
268 * rfc8416#section-4.2:
269 * 1. There may be conflicting changes to ROA Prefix Assertions if an
270 * IP address X and distinct SLURM files Y and Z exist such that X
271 * is contained by any prefix in any "prefixAssertions" or
272 * "prefixFilters" in file Y and X is contained by any prefix in any
273 * "prefixAssertions" or "prefixFilters" in file Z.
274 */
275 static bool
prefix_exists(struct db_slurm * db,struct slurm_prefix * elem)276 prefix_exists(struct db_slurm *db, struct slurm_prefix *elem)
277 {
278 struct slurm_prefix_wrap *cursor;
279 array_index i;
280
281 ARRAYLIST_FOREACH(&db->lists.filter_pfx_al, cursor, i)
282 if (prefix_contained(&cursor->element, elem) ||
283 prefix_contained(elem, &cursor->element))
284 return true;
285
286 ARRAYLIST_FOREACH(&db->lists.assertion_pfx_al, cursor, i)
287 if (prefix_contained(&cursor->element, elem) ||
288 prefix_contained(elem, &cursor->element))
289 return true;
290
291 return false;
292 }
293
294 int
db_slurm_add_prefix_filter(struct db_slurm * db,struct slurm_prefix * elem)295 db_slurm_add_prefix_filter(struct db_slurm *db, struct slurm_prefix *elem)
296 {
297 struct slurm_prefix_wrap new;
298
299 if (prefix_exists(db, elem))
300 return -EEXIST;
301
302 new.element = *elem;
303 new.references = 1;
304
305 return al_filter_prefix_add(&db->cache->filter_pfx_al, &new);
306 }
307
308 int
db_slurm_add_prefix_assertion(struct db_slurm * db,struct slurm_prefix * elem)309 db_slurm_add_prefix_assertion(struct db_slurm *db, struct slurm_prefix *elem)
310 {
311 struct slurm_prefix_wrap new;
312
313 if (prefix_exists(db, elem))
314 return -EEXIST;
315
316 new.element = *elem;
317 new.references = 1;
318
319 return al_assertion_prefix_add(&db->cache->assertion_pfx_al, &new);
320 }
321
322 static bool
bgpsec_contained(struct slurm_bgpsec * left,struct slurm_bgpsec * right)323 bgpsec_contained(struct slurm_bgpsec *left, struct slurm_bgpsec *right)
324 {
325 return (left->data_flag & SLURM_COM_FLAG_ASN) > 0 &&
326 (right->data_flag & SLURM_COM_FLAG_ASN) > 0 &&
327 left->asn == right->asn;
328 }
329
330 /*
331 * rfc8416#section-4.2:
332 * 2. There may be conflicting changes to BGPsec Assertions if an ASN X
333 * and distinct SLURM files Y and Z exist such that X is used in any
334 * "bgpsecAssertions" or "bgpsecFilters" in file Y and X is used in
335 * any "bgpsecAssertions" or "bgpsecFilters" in file Z.
336 */
337 static bool
bgpsec_exists(struct db_slurm * db,struct slurm_bgpsec * elem)338 bgpsec_exists(struct db_slurm *db, struct slurm_bgpsec *elem)
339 {
340 struct slurm_bgpsec_wrap *cursor;
341 array_index i;
342
343 ARRAYLIST_FOREACH(&db->lists.filter_bgps_al, cursor, i)
344 if (bgpsec_contained(&cursor->element, elem) ||
345 bgpsec_contained(elem, &cursor->element))
346 return true;
347
348 ARRAYLIST_FOREACH(&db->lists.assertion_bgps_al, cursor, i)
349 if (bgpsec_contained(&cursor->element, elem) ||
350 bgpsec_contained(elem, &cursor->element))
351 return true;
352
353 return false;
354 }
355
356 int
db_slurm_add_bgpsec_filter(struct db_slurm * db,struct slurm_bgpsec * elem)357 db_slurm_add_bgpsec_filter(struct db_slurm *db, struct slurm_bgpsec *elem)
358 {
359 struct slurm_bgpsec_wrap new;
360
361 if (bgpsec_exists(db, elem))
362 return -EEXIST;
363
364 new.element = *elem;
365 new.references = 1;
366
367 return al_filter_bgpsec_add(&db->cache->filter_bgps_al, &new);
368 }
369
370 int
db_slurm_add_bgpsec_assertion(struct db_slurm * db,struct slurm_bgpsec * elem)371 db_slurm_add_bgpsec_assertion(struct db_slurm *db, struct slurm_bgpsec *elem)
372 {
373 struct slurm_bgpsec_wrap new;
374
375 if (bgpsec_exists(db, elem))
376 return -EEXIST;
377
378 new.element = *elem;
379 new.references = 1;
380
381 return al_assertion_bgpsec_add(&db->cache->assertion_bgps_al, &new);
382 }
383
384 bool
db_slurm_vrp_is_filtered(struct db_slurm * db,struct vrp const * vrp)385 db_slurm_vrp_is_filtered(struct db_slurm *db, struct vrp const *vrp)
386 {
387 struct slurm_prefix slurm_prefix;
388
389 slurm_prefix.data_flag = SLURM_COM_FLAG_ASN | SLURM_PFX_FLAG_PREFIX
390 | SLURM_PFX_FLAG_MAX_LENGTH;
391 slurm_prefix.vrp = *vrp;
392
393 return prefix_filtered(db, &slurm_prefix);
394 }
395
396 bool
db_slurm_bgpsec_is_filtered(struct db_slurm * db,struct router_key const * key)397 db_slurm_bgpsec_is_filtered(struct db_slurm *db, struct router_key const *key)
398 {
399 unsigned char ski[RK_SKI_LEN];
400 struct slurm_bgpsec slurm_bgpsec;
401
402 slurm_bgpsec.data_flag = SLURM_COM_FLAG_ASN | SLURM_BGPS_FLAG_SKI;
403 slurm_bgpsec.asn = key->as;
404 memcpy(ski, key->ski, RK_SKI_LEN);
405 slurm_bgpsec.ski = ski;
406 /* Router public key isn't used at filters */
407 slurm_bgpsec.router_public_key = NULL;
408
409 return bgpsec_filtered(db, &slurm_bgpsec);
410 }
411
412 #define ITERATE_LIST_FUNC(type, object, db_list) \
413 static int \
414 foreach_##type##_##object(struct slurm_lists *lists, \
415 object##_foreach_cb cb, void *arg) \
416 { \
417 struct slurm_##object##_wrap *cursor; \
418 array_index i; \
419 int error; \
420 \
421 ARRAYLIST_FOREACH(&lists->db_list, cursor, i) { \
422 error = cb(&cursor->element, arg); \
423 if (error) \
424 return error; \
425 } \
426 \
427 return 0; \
428 }
429
ITERATE_LIST_FUNC(filter,prefix,filter_pfx_al)430 ITERATE_LIST_FUNC(filter, prefix, filter_pfx_al)
431 ITERATE_LIST_FUNC(filter, bgpsec, filter_bgps_al)
432 ITERATE_LIST_FUNC(assertion, prefix, assertion_pfx_al)
433 ITERATE_LIST_FUNC(assertion, bgpsec, assertion_bgps_al)
434
435 int
436 db_slurm_foreach_assertion_prefix(struct db_slurm *db, prefix_foreach_cb cb,
437 void *arg)
438 {
439 return foreach_assertion_prefix(&db->lists, cb, arg);
440 }
441
442 int
db_slurm_foreach_assertion_bgpsec(struct db_slurm * db,bgpsec_foreach_cb cb,void * arg)443 db_slurm_foreach_assertion_bgpsec(struct db_slurm *db, bgpsec_foreach_cb cb,
444 void *arg)
445 {
446 return foreach_assertion_bgpsec(&db->lists, cb, arg);
447 }
448
449 static int
print_prefix_data(struct slurm_prefix * prefix,void * arg)450 print_prefix_data(struct slurm_prefix *prefix, void *arg)
451 {
452 char *pad = " ";
453
454 pr_op_info(" {");
455 if (prefix->data_flag & SLURM_COM_FLAG_ASN)
456 pr_op_info("%s ASN: %u", pad, prefix->vrp.asn);
457
458 if (prefix->data_flag & SLURM_PFX_FLAG_PREFIX) {
459 pr_op_info("%s Prefix: %s/%u", pad,
460 inet_ntop(prefix->vrp.addr_fam, &prefix->vrp.prefix,
461 addr_buf, INET6_ADDRSTRLEN), prefix->vrp.prefix_length);
462 }
463
464 if (prefix->data_flag & SLURM_PFX_FLAG_MAX_LENGTH)
465 pr_op_info("%s Max prefix length: %u", pad,
466 prefix->vrp.max_prefix_length);
467 pr_op_info(" }");
468
469 return 0;
470 }
471
472 static int
print_bgpsec_data(struct slurm_bgpsec * bgpsec,void * arg)473 print_bgpsec_data(struct slurm_bgpsec *bgpsec, void *arg)
474 {
475 char *pad = " ";
476 char *buf;
477 int error;
478
479 pr_op_info(" {");
480 if (bgpsec->data_flag & SLURM_COM_FLAG_ASN)
481 pr_op_info("%s ASN: %u", pad, bgpsec->asn);
482
483 if (bgpsec->data_flag & SLURM_BGPS_FLAG_SKI) {
484 do {
485 error = base64url_encode(bgpsec->ski, RK_SKI_LEN, &buf);
486 if (error) {
487 pr_op_info("%s SKI: <error encoding value>",
488 pad);
489 break;
490 }
491 pr_op_info("%s SKI: %s", pad, buf);
492 free(buf);
493 } while (0);
494 }
495
496 if (bgpsec->data_flag & SLURM_BGPS_FLAG_ROUTER_KEY) {
497 do {
498 error = base64url_encode(bgpsec->router_public_key,
499 RK_SPKI_LEN, &buf);
500 if (error) {
501 pr_op_info("%s Router public key: <error encoding value>",
502 pad);
503 break;
504 }
505 pr_op_info("%s Router public key: %s", pad, buf);
506 free(buf);
507 } while (0);
508 }
509 pr_op_info(" }");
510
511 return 0;
512 }
513
514 void
db_slurm_log(struct db_slurm * db)515 db_slurm_log(struct db_slurm *db)
516 {
517 pr_op_info("SLURM loaded at %s", asctime(localtime(&db->loaded_date)));
518 pr_op_info("Validation output filters {");
519 pr_op_info(" Prefix filters {");
520 foreach_filter_prefix(&db->lists, print_prefix_data, NULL);
521 pr_op_info(" }");
522 pr_op_info(" BGPsec filters {");
523 foreach_filter_bgpsec(&db->lists, print_bgpsec_data, NULL);
524 pr_op_info(" }");
525 pr_op_info("}");
526
527 pr_op_info("Locally added assertions {");
528 pr_op_info(" Prefix assertions {");
529 foreach_assertion_prefix(&db->lists, print_prefix_data, NULL);
530 pr_op_info(" }");
531 pr_op_info(" BGPsec assertions {");
532 foreach_assertion_bgpsec(&db->lists, print_bgpsec_data, NULL);
533 pr_op_info(" }");
534 pr_op_info("}");
535 }
536
537 int
db_slurm_start_cache(struct db_slurm * db)538 db_slurm_start_cache(struct db_slurm *db)
539 {
540 struct slurm_lists *cache;
541 int error;
542
543 cache = NULL;
544 error = slurm_lists_create(&cache);
545 if (error)
546 return error;
547
548 db->cache = cache;
549
550 return 0;
551 }
552
553 static int
persist_filter_prefix(struct db_slurm * db)554 persist_filter_prefix(struct db_slurm *db)
555 {
556 struct slurm_prefix_wrap *cursor;
557 array_index i;
558 int error;
559
560 ARRAYLIST_FOREACH(&db->cache->filter_pfx_al, cursor, i) {
561 error = al_filter_prefix_add(&db->lists.filter_pfx_al, cursor);
562 if (error)
563 return error;
564 }
565
566 return 0;
567 }
568
569 static int
persist_filter_bgpsec(struct db_slurm * db)570 persist_filter_bgpsec(struct db_slurm *db)
571 {
572 struct slurm_bgpsec_wrap *cursor;
573 array_index i;
574 int error;
575
576 ARRAYLIST_FOREACH(&db->cache->filter_bgps_al, cursor, i) {
577 error = al_filter_bgpsec_add(&db->lists.filter_bgps_al, cursor);
578 if (error)
579 return error;
580 slurm_bgpsec_wrap_refget(cursor);
581 }
582
583 return 0;
584 }
585
586 static int
persist_assertion_prefix(struct db_slurm * db)587 persist_assertion_prefix(struct db_slurm *db)
588 {
589 struct slurm_prefix_wrap *cursor;
590 array_index i;
591 int error;
592
593 ARRAYLIST_FOREACH(&db->cache->assertion_pfx_al, cursor, i) {
594 error = al_assertion_prefix_add(&db->lists.assertion_pfx_al,
595 cursor);
596 if (error)
597 return error;
598 }
599
600 return 0;
601 }
602
603 static int
persist_assertion_bgpsec(struct db_slurm * db)604 persist_assertion_bgpsec(struct db_slurm *db)
605 {
606 struct slurm_bgpsec_wrap *cursor;
607 array_index i;
608 int error;
609
610 ARRAYLIST_FOREACH(&db->cache->assertion_bgps_al, cursor, i) {
611 error = al_assertion_bgpsec_add(&db->lists.assertion_bgps_al,
612 cursor);
613 if (error)
614 return error;
615 slurm_bgpsec_wrap_refget(cursor);
616 }
617
618 return 0;
619 }
620
621 int
db_slurm_flush_cache(struct db_slurm * db)622 db_slurm_flush_cache(struct db_slurm *db)
623 {
624 /* Copy all data in cache to the main lists */
625 int error;
626
627 error = persist_filter_prefix(db);
628 if (error)
629 return error;
630
631 error = persist_filter_bgpsec(db);
632 if (error)
633 return error;
634
635 error = persist_assertion_prefix(db);
636 if (error)
637 return error;
638
639 error = persist_assertion_bgpsec(db);
640 if (error)
641 return error;
642
643 slurm_lists_destroy(db->cache);
644 db->cache = NULL;
645
646 return 0;
647 }
648
649 bool
db_slurm_has_data(struct db_slurm * db)650 db_slurm_has_data(struct db_slurm *db)
651 {
652 return db->lists.filter_pfx_al.len > 0
653 || db->lists.filter_bgps_al.len > 0
654 || db->lists.assertion_pfx_al.len > 0
655 || db->lists.assertion_bgps_al.len > 0;
656 }
657
658 void
db_slurm_destroy(struct db_slurm * db)659 db_slurm_destroy(struct db_slurm *db)
660 {
661 struct slurm_file_csum *tmp;
662
663 slurm_lists_cleanup(&db->lists);
664 if (db->cache)
665 slurm_lists_destroy(db->cache);
666
667 while (!SLIST_EMPTY(&db->csum_list)) {
668 tmp = SLIST_FIRST(&db->csum_list);
669 SLIST_REMOVE_HEAD(&db->csum_list, next);
670 free(tmp);
671 }
672
673 free(db);
674 }
675
676 void
db_slurm_get_csum_list(struct db_slurm * db,struct slurm_csum_list * result)677 db_slurm_get_csum_list(struct db_slurm *db, struct slurm_csum_list *result)
678 {
679 result->list_size = db->csum_list.list_size;
680 result->slh_first = db->csum_list.slh_first;
681 }
682
683