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