]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Update SLURM loading logic (use a cache to load new data).
authorpcarana <pc.moreno2099@gmail.com>
Thu, 19 Mar 2020 22:55:20 +0000 (16:55 -0600)
committerpcarana <pc.moreno2099@gmail.com>
Thu, 19 Mar 2020 22:55:20 +0000 (16:55 -0600)
+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.

src/slurm/db_slurm.c
src/slurm/db_slurm.h
src/slurm/slurm_loader.c
src/slurm/slurm_parser.c
src/slurm/slurm_parser.h

index 3f6d38b241aea8d075957b202c8c68ab6dbc35fd..7a3e4250617de8f005310bf36e47484906b2ad0f 100644 (file)
@@ -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);
 }
index 03227dcf66a5f04b321d08668e67f94aaed9476c..9bb12abe4f3aaeb1a42fadbc7cb0b17a91ee62e8 100644 (file)
@@ -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_ */
index a9436f58132c1c3d71dc53f40b753f9d5c26510e..17bbab4973bbd830a530b87c49cfe2cc829992eb 100644 (file)
@@ -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;
index d9eba1fa4cf0591e0fce30366b71661914523bbc..d06514a976dcca6c929e49c9acac508962d64de6 100644 (file)
        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;
 }
index a5fec8be0dc240061f49a8aba951de7d2c3e231a..143c04f69a9480a60f11df7a54924659bab01be0 100644 (file)
@@ -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 *);