From: pcarana Date: Thu, 19 Mar 2020 22:55:20 +0000 (-0600) Subject: Update SLURM loading logic (use a cache to load new data). X-Git-Tag: v1.2.1~14 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b511b33dd9f1a2f379ee2841eeb9120dac7dab9f;p=thirdparty%2FFORT-validator.git Update SLURM loading logic (use a cache to load new data). +Stop searching for duplicate elements in the same file or in distinct files, also stop searching for covered prefixes at the same file; those checks don't exist at the RFC and they had a huge processing cost. +Implement a SLURM cache when a new file is loaded, this way is easier to check RFC 8416 section 4.2 rule. +Remove the whole context properties that were utilized to know on which file the loader was working. --- diff --git a/src/slurm/db_slurm.c b/src/slurm/db_slurm.c index 3f6d38b2..7a3e4250 100644 --- a/src/slurm/db_slurm.c +++ b/src/slurm/db_slurm.c @@ -9,32 +9,92 @@ #include "object/router_key.h" #include "common.h" -struct slurm_prefix_ctx { +struct slurm_prefix_wrap { struct slurm_prefix element; - int ctx; + unsigned int references; }; -struct slurm_bgpsec_ctx { +struct slurm_bgpsec_wrap { struct slurm_bgpsec element; - int ctx; + unsigned int references; }; -ARRAY_LIST(al_filter_prefix, struct slurm_prefix_ctx) -ARRAY_LIST(al_assertion_prefix, struct slurm_prefix_ctx) -ARRAY_LIST(al_filter_bgpsec, struct slurm_bgpsec_ctx) -ARRAY_LIST(al_assertion_bgpsec, struct slurm_bgpsec_ctx) +ARRAY_LIST(al_filter_prefix, struct slurm_prefix_wrap) +ARRAY_LIST(al_assertion_prefix, struct slurm_prefix_wrap) +ARRAY_LIST(al_filter_bgpsec, struct slurm_bgpsec_wrap) +ARRAY_LIST(al_assertion_bgpsec, struct slurm_bgpsec_wrap) -struct db_slurm { +struct slurm_lists { struct al_filter_prefix filter_pfx_al; struct al_assertion_prefix assertion_pfx_al; struct al_filter_bgpsec filter_bgps_al; struct al_assertion_bgpsec assertion_bgps_al; +}; + +struct db_slurm { + struct slurm_lists lists; + struct slurm_lists *cache; bool loaded_date_set; time_t loaded_date; }; char addr_buf[INET6_ADDRSTRLEN]; +static void +slurm_bgpsec_wrap_refget(struct slurm_bgpsec_wrap *elem) +{ + elem->references++; +} + +static void +slurm_bgpsec_wrap_refput(struct slurm_bgpsec_wrap *elem) +{ + elem->references--; + if (elem->references == 0) { + if ((elem->element.data_flag & SLURM_BGPS_FLAG_SKI) > 0) + free(elem->element.ski); + if ((elem->element.data_flag & SLURM_BGPS_FLAG_ROUTER_KEY) > 0) + free(elem->element.router_public_key); + } +} + +static int +slurm_lists_create(struct slurm_lists **result) +{ + struct slurm_lists *cache; + + cache = malloc(sizeof(struct slurm_lists)); + if (cache == NULL) + return pr_enomem(); + + al_filter_prefix_init(&cache->filter_pfx_al); + al_assertion_prefix_init(&cache->assertion_pfx_al); + al_filter_bgpsec_init(&cache->filter_bgps_al); + al_assertion_bgpsec_init(&cache->assertion_bgps_al); + + *result = cache; + return 0; +} + +static void +slurm_lists_cleanup(struct slurm_lists *lists) +{ + /* No need to cleanup prefixes (filters or assertions) */ + al_filter_prefix_cleanup(&lists->filter_pfx_al, NULL); + al_filter_bgpsec_cleanup(&lists->filter_bgps_al, + slurm_bgpsec_wrap_refput); + al_assertion_prefix_cleanup(&lists->assertion_pfx_al, NULL); + al_assertion_bgpsec_cleanup(&lists->assertion_bgps_al, + slurm_bgpsec_wrap_refput); +} + +static void +slurm_lists_destroy(struct slurm_lists *lists) +{ + slurm_lists_cleanup(lists); + free(lists); +} + int db_slurm_create(struct db_slurm **result) { @@ -45,65 +105,143 @@ db_slurm_create(struct db_slurm **result) return pr_enomem(); /* Not ready yet (nor required yet) for multithreading */ - al_filter_prefix_init(&db->filter_pfx_al); - al_assertion_prefix_init(&db->assertion_pfx_al); - al_filter_bgpsec_init(&db->filter_bgps_al); - al_assertion_bgpsec_init(&db->assertion_bgps_al); + al_filter_prefix_init(&db->lists.filter_pfx_al); + al_assertion_prefix_init(&db->lists.assertion_pfx_al); + al_filter_bgpsec_init(&db->lists.filter_bgps_al); + al_assertion_bgpsec_init(&db->lists.assertion_bgps_al); db->loaded_date_set = false; + db->cache = NULL; *result = db; return 0; } +/* + * @filter_wrap is the prefix loaded from SLURM, @prefix is the VRP "masked" as + * a slurm_prefix + */ static bool -prefix_filtered_by(struct slurm_prefix *filter, struct slurm_prefix *prefix, - bool exact_match) +prefix_filtered_by(struct slurm_prefix_wrap *filter_wrap, + struct slurm_prefix *prefix) { + struct slurm_prefix *filter; struct vrp *filter_vrp, *prefix_vrp; + bool equal; + filter = &filter_wrap->element; filter_vrp = &filter->vrp; prefix_vrp = &prefix->vrp; - /* The filter has ASN and prefix */ - if (exact_match && (filter->data_flag & ~SLURM_COM_FLAG_COMMENT) == - (SLURM_COM_FLAG_ASN | SLURM_PFX_FLAG_PREFIX)) - return VRP_ASN_EQ(filter_vrp, prefix_vrp) && - VRP_PREFIX_COV(filter_vrp, prefix_vrp); + /* + * Ignore the comments, remember: FILTERS don't have the same data (no + * max_length is declared), while ASSERTIONS do. + */ + if ((filter->data_flag & ~SLURM_COM_FLAG_COMMENT) != + (prefix->data_flag & ~SLURM_COM_FLAG_COMMENT)) { + /* The filter has ASN and prefix */ + if ((filter->data_flag & ~SLURM_COM_FLAG_COMMENT) == + (SLURM_COM_FLAG_ASN | SLURM_PFX_FLAG_PREFIX)) + return VRP_ASN_EQ(filter_vrp, prefix_vrp) && + VRP_PREFIX_COV(filter_vrp, prefix_vrp); + + /* Both have ASN */ + if ((filter->data_flag & SLURM_COM_FLAG_ASN) > 0 && + (prefix->data_flag & SLURM_COM_FLAG_ASN) > 0) + return VRP_ASN_EQ(filter_vrp, prefix_vrp); + + /* Both have a prefix of the same type */ + if ((filter->data_flag & SLURM_PFX_FLAG_PREFIX) > 0 && + (prefix->data_flag & SLURM_PFX_FLAG_PREFIX) > 0) + return VRP_PREFIX_COV(filter_vrp, prefix_vrp); + + return false; + } + + /* It has the same data, compare it */ + equal = true; + if (equal && (filter->data_flag & SLURM_COM_FLAG_ASN) > 0) + equal = VRP_ASN_EQ(filter_vrp, prefix_vrp); + + if (equal && (filter->data_flag & SLURM_PFX_FLAG_PREFIX) > 0) + equal = VRP_PREFIX_COV(filter_vrp, prefix_vrp); - /* Both have ASN */ - if ((filter->data_flag & SLURM_COM_FLAG_ASN) > 0 && - (prefix->data_flag & SLURM_COM_FLAG_ASN) > 0) - return VRP_ASN_EQ(filter_vrp, prefix_vrp); + return equal; +} + +static bool +prefix_filtered(struct db_slurm *db, struct slurm_prefix *prefix) +{ + struct slurm_prefix_wrap *cursor; + array_index i; - /* Both have a prefix of the same type */ - if ((filter->data_flag & SLURM_PFX_FLAG_PREFIX) > 0 && - (prefix->data_flag & SLURM_PFX_FLAG_PREFIX) > 0) - return VRP_PREFIX_COV(filter_vrp, prefix_vrp); + ARRAYLIST_FOREACH(&db->lists.filter_pfx_al, cursor, i) + if (prefix_filtered_by(cursor, prefix)) + return true; return false; } static bool -prefix_contained(struct slurm_prefix_ctx *left_ctx, struct slurm_prefix *right, - int ctx) +bgpsec_filtered_by(struct slurm_bgpsec_wrap *filter_wrap, + struct slurm_bgpsec *bgpsec) { - struct slurm_prefix *left; - struct vrp *left_vrp, *right_vrp; + struct slurm_bgpsec *filter; + bool equal; + + filter = &filter_wrap->element; + + /* Ignore the comments */ + if ((filter->data_flag & ~SLURM_COM_FLAG_COMMENT) != + (bgpsec->data_flag & ~SLURM_COM_FLAG_COMMENT)) { + /* The filter has ASN and SKI */ + if ((filter->data_flag & ~SLURM_COM_FLAG_COMMENT) == + (SLURM_COM_FLAG_ASN | SLURM_BGPS_FLAG_SKI)) + return bgpsec->asn == filter->asn && + memcmp(bgpsec->ski, filter->ski, RK_SKI_LEN) == 0; + + /* Both have ASN */ + if ((bgpsec->data_flag & SLURM_COM_FLAG_ASN) > 0 && + (filter->data_flag & SLURM_COM_FLAG_ASN) > 0) + return bgpsec->asn == filter->asn; + + /* Both have a SKI */ + if ((bgpsec->data_flag & SLURM_BGPS_FLAG_SKI) > 0 && + (filter->data_flag & SLURM_BGPS_FLAG_SKI) > 0) + return memcmp(bgpsec->ski, filter->ski, RK_SPKI_LEN) + == 0; - /* - * rfc8416#section-4.2: - * 1. There may be conflicting changes to ROA Prefix Assertions if an - * IP address X and distinct SLURM files Y and Z exist such that X - * is contained by any prefix in any "prefixAssertions" or - * "prefixFilters" in file Y and X is contained by any prefix in any - * "prefixAssertions" or "prefixFilters" in file Z. - * - * A negative @ctx or an equal context will avoid this check. - */ - if (ctx < 0 || ctx == left_ctx->ctx) return false; + } + + /* It has the same data, compare it */ + equal = true; + if (equal && (filter->data_flag & SLURM_COM_FLAG_ASN) > 0) + equal = filter->asn == bgpsec->asn; + + if (equal && (filter->data_flag & SLURM_BGPS_FLAG_SKI) > 0) + equal = memcmp(filter->ski, bgpsec->ski, RK_SKI_LEN) == 0; + + return equal; +} + +static bool +bgpsec_filtered(struct db_slurm *db, struct slurm_bgpsec *bgpsec) +{ + struct slurm_bgpsec_wrap *cursor; + array_index i; + + ARRAYLIST_FOREACH(&db->lists.filter_bgps_al, cursor, i) + if (bgpsec_filtered_by(cursor, bgpsec)) + return true; + + return false; +} + +static bool +prefix_contained(struct slurm_prefix *left, struct slurm_prefix *right) +{ + struct vrp *left_vrp, *right_vrp; - left = &left_ctx->element; left_vrp = &left->vrp; right_vrp = &right->vrp; @@ -113,175 +251,121 @@ prefix_contained(struct slurm_prefix_ctx *left_ctx, struct slurm_prefix *right, } /* - * @left_ctx is the prefix loaded from SLURM, @right is the VRP "masked" as a - * slurm prefix + * rfc8416#section-4.2: + * 1. There may be conflicting changes to ROA Prefix Assertions if an + * IP address X and distinct SLURM files Y and Z exist such that X + * is contained by any prefix in any "prefixAssertions" or + * "prefixFilters" in file Y and X is contained by any prefix in any + * "prefixAssertions" or "prefixFilters" in file Z. */ static bool -prefix_equal(struct slurm_prefix_ctx *left_ctx, struct slurm_prefix *right, - int ctx, bool filter, bool exact_match) +prefix_exists(struct db_slurm *db, struct slurm_prefix *elem) { - struct slurm_prefix *left; - struct vrp *left_vrp, *right_vrp; - bool equal; + struct slurm_prefix_wrap *cursor; + array_index i; - left = &left_ctx->element; - left_vrp = &left->vrp; - right_vrp = &right->vrp; + ARRAYLIST_FOREACH(&db->lists.filter_pfx_al, cursor, i) + if (prefix_contained(&cursor->element, elem) || + prefix_contained(elem, &cursor->element)) + return true; - if (prefix_contained(left_ctx, right, ctx)) - return true; + ARRAYLIST_FOREACH(&db->lists.assertion_pfx_al, cursor, i) + if (prefix_contained(&cursor->element, elem) || + prefix_contained(elem, &cursor->element)) + return true; - /* - * Ignore the comments, remember: FILTERS don't have the same data (no - * max_length is declared), while ASSERTIONS do. - */ - if ((left->data_flag & ~SLURM_COM_FLAG_COMMENT) != - (right->data_flag & ~SLURM_COM_FLAG_COMMENT)) - return filter && prefix_filtered_by(left, right, exact_match); + return false; +} - /* It has the same data, compare it */ - equal = true; - if (equal && (left->data_flag & SLURM_COM_FLAG_ASN) > 0) - equal = VRP_ASN_EQ(left_vrp, right_vrp); +int +db_slurm_add_prefix_filter(struct db_slurm *db, struct slurm_prefix *elem) +{ + struct slurm_prefix_wrap new; - if (equal && (left->data_flag & SLURM_PFX_FLAG_PREFIX) > 0) - equal = (filter ? - VRP_PREFIX_COV(left_vrp, right_vrp) : - VRP_PREFIX_EQ(left_vrp, right_vrp)); + if (prefix_exists(db, elem)) + return -EEXIST; - if (equal && (left->data_flag & SLURM_PFX_FLAG_MAX_LENGTH) > 0) - equal = VRP_MAX_PREFIX_LEN_EQ(left_vrp, right_vrp); + new.element = *elem; + new.references = 1; - return equal; + return al_filter_prefix_add(&db->cache->filter_pfx_al, &new); } -static bool -bgpsec_filtered_by(struct slurm_bgpsec *bgpsec, struct slurm_bgpsec *filter, - bool exact_match) +int +db_slurm_add_prefix_assertion(struct db_slurm *db, struct slurm_prefix *elem) { - /* The filter has ASN and SKI */ - if (exact_match && (filter->data_flag & ~SLURM_COM_FLAG_COMMENT) == - (SLURM_COM_FLAG_ASN | SLURM_BGPS_FLAG_SKI)) - return bgpsec->asn == filter->asn && - memcmp(bgpsec->ski, filter->ski, RK_SKI_LEN) == 0; + struct slurm_prefix_wrap new; - /* Both have ASN */ - if ((bgpsec->data_flag & SLURM_COM_FLAG_ASN) > 0 && - (filter->data_flag & SLURM_COM_FLAG_ASN) > 0) - return bgpsec->asn == filter->asn; + if (prefix_exists(db, elem)) + return -EEXIST; - /* Both have a SKI */ - if ((bgpsec->data_flag & SLURM_BGPS_FLAG_SKI) > 0 && - (filter->data_flag & SLURM_BGPS_FLAG_SKI) > 0) - return memcmp(bgpsec->ski, filter->ski, RK_SPKI_LEN) == 0; + new.element = *elem; + new.references = 1; - return false; + return al_assertion_prefix_add(&db->cache->assertion_pfx_al, &new); } static bool -bgpsec_contained(struct slurm_bgpsec_ctx *left_ctx, struct slurm_bgpsec *right, - int ctx) +bgpsec_contained(struct slurm_bgpsec *left, struct slurm_bgpsec *right) { - struct slurm_bgpsec *left; - - /* - * rfc8416#section-4.2: - * 2. There may be conflicting changes to BGPsec Assertions if an ASN X - * and distinct SLURM files Y and Z exist such that X is used in any - * "bgpsecAssertions" or "bgpsecFilters" in file Y and X is used in - * any "bgpsecAssertions" or "bgpsecFilters" in file Z. - * - * A negative @ctx or an equal context will avoid this check. - */ - if (ctx < 0 || ctx == left_ctx->ctx) - return false; - - left = &left_ctx->element; - return (left->data_flag & SLURM_COM_FLAG_ASN) > 0 && (right->data_flag & SLURM_COM_FLAG_ASN) > 0 && left->asn == right->asn; } +/* + * rfc8416#section-4.2: + * 2. There may be conflicting changes to BGPsec Assertions if an ASN X + * and distinct SLURM files Y and Z exist such that X is used in any + * "bgpsecAssertions" or "bgpsecFilters" in file Y and X is used in + * any "bgpsecAssertions" or "bgpsecFilters" in file Z. + */ static bool -bgpsec_equal(struct slurm_bgpsec_ctx *left_ctx, struct slurm_bgpsec *right, - int ctx, bool filter, bool exact_filter) +bgpsec_exists(struct db_slurm *db, struct slurm_bgpsec *elem) { - struct slurm_bgpsec *left; - bool equal; + struct slurm_bgpsec_wrap *cursor; + array_index i; - left = &left_ctx->element; + ARRAYLIST_FOREACH(&db->lists.filter_bgps_al, cursor, i) + if (bgpsec_contained(&cursor->element, elem) || + bgpsec_contained(elem, &cursor->element)) + return true; - if (bgpsec_contained(left_ctx, right, ctx)) - return true; + ARRAYLIST_FOREACH(&db->lists.assertion_bgps_al, cursor, i) + if (bgpsec_contained(&cursor->element, elem) || + bgpsec_contained(elem, &cursor->element)) + return true; - /* Ignore the comments */ - if ((left->data_flag & ~SLURM_COM_FLAG_COMMENT) != - (right->data_flag & ~SLURM_COM_FLAG_COMMENT)) - return filter && bgpsec_filtered_by(left, right, exact_filter); + return false; +} - /* It has the same data, compare it */ - equal = true; - if (equal && (left->data_flag & SLURM_COM_FLAG_ASN) > 0) - equal = left->asn == right->asn; +int +db_slurm_add_bgpsec_filter(struct db_slurm *db, struct slurm_bgpsec *elem) +{ + struct slurm_bgpsec_wrap new; - if (equal && (left->data_flag & SLURM_BGPS_FLAG_SKI) > 0) - equal = memcmp(left->ski, right->ski, RK_SKI_LEN) == 0; + if (bgpsec_exists(db, elem)) + return -EEXIST; - if (equal && (left->data_flag & SLURM_BGPS_FLAG_ROUTER_KEY) > 0) - equal = memcmp(left->router_public_key, - right->router_public_key, RK_SPKI_LEN) == 0; + new.element = *elem; + new.references = 1; - return equal; + return al_filter_bgpsec_add(&db->cache->filter_bgps_al, &new); } -#define ADD_FUNCS(name, type, list_name, db_list, db_alt_list, equal_cb,\ - cont_cb, filter) \ - static type * \ - name##_locate(struct db_slurm *db, type *obj, bool flt, int ctx)\ - { \ - type##_ctx *cursor; \ - array_index i; \ - \ - ARRAYLIST_FOREACH(&db->db_list, cursor, i) \ - if (equal_cb(cursor, obj, ctx, filter, flt)) \ - return &cursor->element; \ - \ - if (ctx < 0) \ - return NULL; /* Avoid the next loop */ \ - \ - ARRAYLIST_FOREACH(&db->db_alt_list, cursor, i) \ - if (cont_cb(cursor, obj, ctx)) \ - return &cursor->element; \ - \ - return NULL; \ - } \ - \ - static bool \ - name##_exists(struct db_slurm *db, type *obj, bool flt, int ctx)\ - { \ - return name##_locate(db, obj, flt, ctx) != NULL; \ - } \ - \ - int \ - db_slurm_add_##name(struct db_slurm *db, type *elem, int ctx) \ - { \ - type##_ctx new_elem; \ - if (name##_exists(db, elem, !filter, ctx)) \ - return -EEXIST; \ - new_elem.element = *elem; \ - new_elem.ctx = ctx; \ - return list_name##_add(&db->db_list, &new_elem); \ - } +int +db_slurm_add_bgpsec_assertion(struct db_slurm *db, struct slurm_bgpsec *elem) +{ + struct slurm_bgpsec_wrap new; -ADD_FUNCS(prefix_filter, struct slurm_prefix, al_filter_prefix, filter_pfx_al, - assertion_pfx_al, prefix_equal, prefix_contained, true) -ADD_FUNCS(bgpsec_filter, struct slurm_bgpsec, al_filter_bgpsec, filter_bgps_al, - assertion_bgps_al, bgpsec_equal, bgpsec_contained, true) -ADD_FUNCS(prefix_assertion, struct slurm_prefix, al_assertion_prefix, - assertion_pfx_al, filter_pfx_al, prefix_equal, prefix_contained, false) -ADD_FUNCS(bgpsec_assertion, struct slurm_bgpsec, al_assertion_bgpsec, - assertion_bgps_al, filter_bgps_al, bgpsec_equal, bgpsec_contained, false) + if (bgpsec_exists(db, elem)) + return -EEXIST; + + new.element = *elem; + new.references = 1; + + return al_assertion_bgpsec_add(&db->cache->assertion_bgps_al, &new); +} bool db_slurm_vrp_is_filtered(struct db_slurm *db, struct vrp const *vrp) @@ -292,32 +376,9 @@ db_slurm_vrp_is_filtered(struct db_slurm *db, struct vrp const *vrp) | SLURM_PFX_FLAG_MAX_LENGTH; slurm_prefix.vrp = *vrp; - return prefix_filter_exists(db, &slurm_prefix, true, -1); + return prefix_filtered(db, &slurm_prefix); } -#define ITERATE_LIST_FUNC(type, object, db_list) \ - int \ - db_slurm_foreach_##type##_##object(struct db_slurm *db, \ - object##_foreach_cb cb, void *arg) \ - { \ - struct slurm_##object##_ctx *cursor; \ - array_index i; \ - int error; \ - \ - ARRAYLIST_FOREACH(&db->db_list, cursor, i) { \ - error = cb(&cursor->element, arg); \ - if (error) \ - return error; \ - } \ - \ - return 0; \ - } - -ITERATE_LIST_FUNC(filter, prefix, filter_pfx_al) -ITERATE_LIST_FUNC(filter, bgpsec, filter_bgps_al) -ITERATE_LIST_FUNC(assertion, prefix, assertion_pfx_al) -ITERATE_LIST_FUNC(assertion, bgpsec, assertion_bgps_al) - bool db_slurm_bgpsec_is_filtered(struct db_slurm *db, struct router_key const *key) { @@ -337,18 +398,46 @@ db_slurm_bgpsec_is_filtered(struct db_slurm *db, struct router_key const *key) /* Router public key isn't used at filters */ slurm_bgpsec.router_public_key = NULL; - result = bgpsec_filter_exists(db, &slurm_bgpsec, true, -1); + result = bgpsec_filtered(db, &slurm_bgpsec); free(tmp); return result; } -static void -clean_slurm_bgpsec(struct slurm_bgpsec_ctx *bgpsec) +#define ITERATE_LIST_FUNC(type, object, db_list) \ + static int \ + foreach_##type##_##object(struct slurm_lists *lists, \ + object##_foreach_cb cb, void *arg) \ + { \ + struct slurm_##object##_wrap *cursor; \ + array_index i; \ + int error; \ + \ + ARRAYLIST_FOREACH(&lists->db_list, cursor, i) { \ + error = cb(&cursor->element, arg); \ + if (error) \ + return error; \ + } \ + \ + return 0; \ + } + +ITERATE_LIST_FUNC(filter, prefix, filter_pfx_al) +ITERATE_LIST_FUNC(filter, bgpsec, filter_bgps_al) +ITERATE_LIST_FUNC(assertion, prefix, assertion_pfx_al) +ITERATE_LIST_FUNC(assertion, bgpsec, assertion_bgps_al) + +int +db_slurm_foreach_assertion_prefix(struct db_slurm *db, prefix_foreach_cb cb, + void *arg) +{ + return foreach_assertion_prefix(&db->lists, cb, arg); +} + +int +db_slurm_foreach_assertion_bgpsec(struct db_slurm *db, bgpsec_foreach_cb cb, + void *arg) { - if ((bgpsec->element.data_flag & SLURM_BGPS_FLAG_SKI) > 0) - free(bgpsec->element.ski); - if ((bgpsec->element.data_flag & SLURM_BGPS_FLAG_ROUTER_KEY) > 0) - free(bgpsec->element.router_public_key); + return foreach_assertion_bgpsec(&db->lists, cb, arg); } void @@ -442,32 +531,149 @@ db_slurm_log(struct db_slurm *db) asctime(localtime(&db->loaded_date))); pr_info("Validation output filters {"); pr_info(" Prefix filters {"); - db_slurm_foreach_filter_prefix(db, print_prefix_data, NULL); + foreach_filter_prefix(&db->lists, print_prefix_data, NULL); pr_info(" }"); pr_info(" BGPsec filters {"); - db_slurm_foreach_filter_bgpsec(db, print_bgpsec_data, NULL); + foreach_filter_bgpsec(&db->lists, print_bgpsec_data, NULL); pr_info(" }"); pr_info("}"); pr_info("Locally added assertions {"); pr_info(" Prefix assertions {"); - db_slurm_foreach_assertion_prefix(db, print_prefix_data, NULL); + foreach_assertion_prefix(&db->lists, print_prefix_data, NULL); pr_info(" }"); pr_info(" BGPsec assertions {"); - db_slurm_foreach_assertion_bgpsec(db, print_bgpsec_data, NULL); + foreach_assertion_bgpsec(&db->lists, print_bgpsec_data, NULL); pr_info(" }"); pr_info("}"); } +int +db_slurm_start_cache(struct db_slurm *db) +{ + struct slurm_lists *cache; + int error; + + cache = NULL; + error = slurm_lists_create(&cache); + if (error) + return error; + + db->cache = cache; + + return 0; +} + +static int +persist_filter_prefix(struct db_slurm *db) +{ + struct slurm_prefix_wrap *cursor; + array_index i; + int error; + + ARRAYLIST_FOREACH(&db->cache->filter_pfx_al, cursor, i) { + error = al_filter_prefix_add(&db->lists.filter_pfx_al, cursor); + if (error) + return error; + } + + return 0; +} + +static int +persist_filter_bgpsec(struct db_slurm *db) +{ + struct slurm_bgpsec_wrap *cursor; + array_index i; + int error; + + ARRAYLIST_FOREACH(&db->cache->filter_bgps_al, cursor, i) { + error = al_filter_bgpsec_add(&db->lists.filter_bgps_al, cursor); + if (error) + return error; + slurm_bgpsec_wrap_refget(cursor); + } + + return 0; +} + +static int +persist_assertion_prefix(struct db_slurm *db) +{ + struct slurm_prefix_wrap *cursor; + array_index i; + int error; + + ARRAYLIST_FOREACH(&db->cache->assertion_pfx_al, cursor, i) { + error = al_assertion_prefix_add(&db->lists.assertion_pfx_al, + cursor); + if (error) + return error; + } + + return 0; +} + +static int +persist_assertion_bgpsec(struct db_slurm *db) +{ + struct slurm_bgpsec_wrap *cursor; + array_index i; + int error; + + ARRAYLIST_FOREACH(&db->cache->assertion_bgps_al, cursor, i) { + error = al_assertion_bgpsec_add(&db->lists.assertion_bgps_al, + cursor); + if (error) + return error; + slurm_bgpsec_wrap_refget(cursor); + } + + return 0; +} + +int +db_slurm_flush_cache(struct db_slurm *db) +{ + /* Copy all data in cache to the main lists */ + int error; + + error = persist_filter_prefix(db); + if (error) + return error; + + error = persist_filter_bgpsec(db); + if (error) + return error; + + error = persist_assertion_prefix(db); + if (error) + return error; + + error = persist_assertion_bgpsec(db); + if (error) + return error; + + slurm_lists_destroy(db->cache); + db->cache = NULL; + + return 0; +} + +bool +db_slurm_has_data(struct db_slurm *db) +{ + return db->lists.filter_pfx_al.len > 0 + || db->lists.filter_bgps_al.len > 0 + || db->lists.assertion_pfx_al.len > 0 + || db->lists.assertion_bgps_al.len > 0; +} + void db_slurm_destroy(struct db_slurm *db) { - /* No need to cleanup prefixes (filters or assertions) */ - al_filter_prefix_cleanup(&db->filter_pfx_al, NULL); - al_filter_bgpsec_cleanup(&db->filter_bgps_al, - clean_slurm_bgpsec); - al_assertion_prefix_cleanup(&db->assertion_pfx_al, NULL); - al_assertion_bgpsec_cleanup(&db->assertion_bgps_al, - clean_slurm_bgpsec); + slurm_lists_cleanup(&db->lists); + if (db->cache) + slurm_lists_destroy(db->cache); free(db); } diff --git a/src/slurm/db_slurm.h b/src/slurm/db_slurm.h index 03227dcf..9bb12abe 100644 --- a/src/slurm/db_slurm.h +++ b/src/slurm/db_slurm.h @@ -34,20 +34,14 @@ typedef int (*bgpsec_foreach_cb)(struct slurm_bgpsec *, void *); int db_slurm_create(struct db_slurm **); -int db_slurm_add_prefix_filter(struct db_slurm *, struct slurm_prefix *, int); -int db_slurm_add_prefix_assertion(struct db_slurm *, struct slurm_prefix *, - int); -int db_slurm_add_bgpsec_filter(struct db_slurm *, struct slurm_bgpsec *, int); -int db_slurm_add_bgpsec_assertion(struct db_slurm *, struct slurm_bgpsec *, - int); +int db_slurm_add_prefix_filter(struct db_slurm *, struct slurm_prefix *); +int db_slurm_add_prefix_assertion(struct db_slurm *, struct slurm_prefix *); +int db_slurm_add_bgpsec_filter(struct db_slurm *, struct slurm_bgpsec *); +int db_slurm_add_bgpsec_assertion(struct db_slurm *, struct slurm_bgpsec *); bool db_slurm_vrp_is_filtered(struct db_slurm *, struct vrp const *); bool db_slurm_bgpsec_is_filtered(struct db_slurm *, struct router_key const *); -int db_slurm_foreach_filter_prefix(struct db_slurm *, prefix_foreach_cb, - void *); -int db_slurm_foreach_filter_bgpsec(struct db_slurm *, bgpsec_foreach_cb, - void *); int db_slurm_foreach_assertion_prefix(struct db_slurm *, prefix_foreach_cb, void *); int db_slurm_foreach_assertion_bgpsec(struct db_slurm *, bgpsec_foreach_cb, @@ -58,6 +52,14 @@ void db_slurm_update_time(struct db_slurm *); /* Log the DB in human readable form at INFO level */ void db_slurm_log(struct db_slurm *); +/* Start working on the cache */ +int db_slurm_start_cache(struct db_slurm *); +/* Persist all the data stored at cache and erase cache */ +int db_slurm_flush_cache(struct db_slurm *); + +/* Does the SLURM DB has data? */ +bool db_slurm_has_data(struct db_slurm *); + void db_slurm_destroy(struct db_slurm *); #endif /* SRC_SLURM_db_slurm_H_ */ diff --git a/src/slurm/slurm_loader.c b/src/slurm/slurm_loader.c index a9436f58..17bbab49 100644 --- a/src/slurm/slurm_loader.c +++ b/src/slurm/slurm_loader.c @@ -37,8 +37,8 @@ slurm_load(struct slurm_parser_params *params) return error; } - /* A unmodified context means that no SLURM was loaded (empty dir) */ - if(params->cur_ctx == 0) { + /* Empty SLURM dir, or empty SLURM file(s) */ + if (!db_slurm_has_data(db)) { db_slurm_destroy(db); params->db_slurm = NULL; } @@ -130,7 +130,6 @@ slurm_create_parser_params(struct slurm_parser_params **result) params->db_table = NULL; params->db_slurm = NULL; - params->cur_ctx = 0; *result = params; return 0; diff --git a/src/slurm/slurm_parser.c b/src/slurm/slurm_parser.c index d9eba1fa..d06514a9 100644 --- a/src/slurm/slurm_parser.c +++ b/src/slurm/slurm_parser.c @@ -36,11 +36,7 @@ if (element == NULL) \ return pr_err("SLURM member '%s' is required", name); -/* Context value, local to avoid forwarding the parameter */ -struct db_slurm *db; -unsigned int cur_ctx; - -static int handle_json(json_t *, struct db_slurm *, unsigned int *); +static int handle_json(json_t *, struct db_slurm *); /* * Try to parse the SLURM file(s) @@ -51,7 +47,6 @@ slurm_parse(char const *location, void *arg) struct slurm_parser_params *params; json_t *json_root; json_error_t json_error; - unsigned int ctx; int error; params = arg; @@ -63,13 +58,11 @@ slurm_parse(char const *location, void *arg) return pr_err("SLURM JSON error on line %d, column %d: %s", json_error.line, json_error.column, json_error.text); - ctx = params->cur_ctx; - error = handle_json(json_root, params->db_slurm, &ctx); + error = handle_json(json_root, params->db_slurm); json_decref(json_root); if (error) return error; /* File exists, but has a syntax error */ - params->cur_ctx = ctx; return 0; } @@ -369,7 +362,7 @@ init_slurm_prefix(struct slurm_prefix *slurm_prefix) } static int -load_single_prefix(json_t *object, bool is_assertion) +load_single_prefix(json_t *object, struct db_slurm *db, bool is_assertion) { struct slurm_prefix result; size_t member_count; @@ -414,7 +407,7 @@ load_single_prefix(json_t *object, bool is_assertion) if (!json_valid_members_count(object, member_count)) return pr_err("Prefix filter has unknown members (see RFC 8416 section 3.3.1)"); - error = db_slurm_add_prefix_filter(db, &result, cur_ctx); + error = db_slurm_add_prefix_filter(db, &result); if (error) return error; @@ -434,7 +427,7 @@ load_single_prefix(json_t *object, bool is_assertion) if (!json_valid_members_count(object, member_count)) return pr_err("Prefix assertion has unknown members (see RFC 8416 section 3.4.1)"); - error = db_slurm_add_prefix_assertion(db, &result, cur_ctx); + error = db_slurm_add_prefix_assertion(db, &result); if (error) return error; @@ -442,24 +435,21 @@ load_single_prefix(json_t *object, bool is_assertion) } static int -load_prefix_array(json_t *array, bool is_assertion) +load_prefix_array(json_t *array, struct db_slurm *db, bool is_assertion) { json_t *element; int index, error; json_array_foreach(array, index, element) { - error = load_single_prefix(element, is_assertion); + error = load_single_prefix(element, db, is_assertion); if (!error) continue; if (error == -EEXIST) pr_err( - "The prefix %s element \"%s\", is duplicated or covered by another %s; SLURM loading will be stopped.%s", + "The prefix %s element \"%s\", covers or is covered by another assertion/filter; SLURM loading will be stopped. %s", (is_assertion ? "assertion" : "filter"), json_dumps(element, 0), - (is_assertion ? "assertion" : "filter"), - (cur_ctx > 0 - ? " TIP: More than 1 SLURM files were found, check if the prefix is contained in multiple files (see RFC 8416 section 4.2)." - : "")); + "TIP: More than 1 SLURM files were found, check if the prefix is contained in multiple files (see RFC 8416 section 4.2)."); else pr_err( "Error at prefix %s, element \"%s\", SLURM loading will be stopped", @@ -482,7 +472,7 @@ init_slurm_bgpsec(struct slurm_bgpsec *slurm_bgpsec) } static int -load_single_bgpsec(json_t *object, bool is_assertion) +load_single_bgpsec(json_t *object, struct db_slurm *db, bool is_assertion) { struct slurm_bgpsec result; size_t member_count; @@ -535,7 +525,7 @@ load_single_bgpsec(json_t *object, bool is_assertion) goto release_router_key; } - error = db_slurm_add_bgpsec_filter(db, &result, cur_ctx); + error = db_slurm_add_bgpsec_filter(db, &result); if (error) goto release_router_key; @@ -549,7 +539,7 @@ load_single_bgpsec(json_t *object, bool is_assertion) goto release_router_key; } - error = db_slurm_add_bgpsec_assertion(db, &result, cur_ctx); + error = db_slurm_add_bgpsec_assertion(db, &result); if (error) goto release_router_key; @@ -563,24 +553,21 @@ release_ski: } static int -load_bgpsec_array(json_t *array, bool is_assertion) +load_bgpsec_array(json_t *array, struct db_slurm *db, bool is_assertion) { json_t *element; int index, error; json_array_foreach(array, index, element) { - error = load_single_bgpsec(element, is_assertion); + error = load_single_bgpsec(element, db, is_assertion); if (!error) continue; if (error == -EEXIST) pr_err( - "The bgpsec %s element \"%s\", is duplicated or covered by another %s; SLURM loading will be stopped.%s", + "The ASN at bgpsec %s element \"%s\", is duplicated in another assertion/filter; SLURM loading will be stopped. %s", (is_assertion ? "assertion" : "filter"), json_dumps(element, 0), - (is_assertion ? "assertion" : "filter"), - (cur_ctx > 0 - ? " TIP: More than 1 SLURM files were found, check if the ASN is contained in multiple files (see RFC 8416 section 4.2)." - : "")); + "TIP: More than 1 SLURM files were found, check if the ASN is contained in multiple files (see RFC 8416 section 4.2)."); else pr_err( "Error at bgpsec %s, element \"%s\", SLURM loading will be stopped", @@ -614,7 +601,7 @@ load_version(json_t *root) } static int -load_filters(json_t *root) +load_filters(json_t *root, struct db_slurm *db) { json_t *filters, *prefix, *bgpsec; size_t expected_members; @@ -637,11 +624,11 @@ load_filters(json_t *root) expected_members); /* Arrays loaded, now iterate */ - error = load_prefix_array(prefix, false); + error = load_prefix_array(prefix, db, false); if (error) return error; - error = load_bgpsec_array(bgpsec, false); + error = load_bgpsec_array(bgpsec, db, false); if (error) return error; @@ -649,7 +636,7 @@ load_filters(json_t *root) } static int -load_assertions(json_t *root) +load_assertions(json_t *root, struct db_slurm *db) { json_t *assertions, *prefix, *bgpsec; size_t expected_members; @@ -671,11 +658,11 @@ load_assertions(json_t *root) LOCALLY_ADDED_ASSERTIONS, expected_members); - error = load_prefix_array(prefix, true); + error = load_prefix_array(prefix, db, true); if (error) return error; - error = load_bgpsec_array(bgpsec, true); + error = load_bgpsec_array(bgpsec, db, true); if (error) return error; @@ -683,7 +670,7 @@ load_assertions(json_t *root) } static int -handle_json(json_t *root, struct db_slurm *db_slurm, unsigned int *ctx) +handle_json(json_t *root, struct db_slurm *db) { size_t expected_members; int error; @@ -691,18 +678,18 @@ handle_json(json_t *root, struct db_slurm *db_slurm, unsigned int *ctx) if (!json_is_object(root)) return pr_err("The root of the SLURM is not a JSON object."); - cur_ctx = *ctx; - db = db_slurm; - error = load_version(root); if (error) return error; - error = load_filters(root); + /* Start working on the cache */ + db_slurm_start_cache(db); + + error = load_filters(root, db); if (error) return error; - error = load_assertions(root); + error = load_assertions(root, db); if (error) return error; @@ -712,7 +699,8 @@ handle_json(json_t *root, struct db_slurm *db_slurm, unsigned int *ctx) "SLURM root must have only %lu members (RFC 8416 section 3.2)", expected_members); - (*ctx)++; /* Next time will be another context */ + /* Persist cached data */ + db_slurm_flush_cache(db); return 0; } diff --git a/src/slurm/slurm_parser.h b/src/slurm/slurm_parser.h index a5fec8be..143c04f6 100644 --- a/src/slurm/slurm_parser.h +++ b/src/slurm/slurm_parser.h @@ -7,7 +7,6 @@ struct slurm_parser_params { struct db_table *db_table; struct db_slurm *db_slurm; - unsigned int cur_ctx; /* Context (file number) */ }; int slurm_parse(char const *, void *);