]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Remember last valid SLURM in case of syntax error with newer SLURM(s).
authorpcarana <pc.moreno2099@gmail.com>
Fri, 11 Oct 2019 22:30:12 +0000 (17:30 -0500)
committerpcarana <pc.moreno2099@gmail.com>
Thu, 31 Oct 2019 19:17:06 +0000 (13:17 -0600)
-Remove 'comment' member from slurm structs, there's no need to store its value.
-Rename 'slurm/slurm_db.*' to 'slurm/db_slurm.*'.
-Allocate SLURM data, so that the last valid SLURM can be used if needed; so, now the SLURM lives on the heap and is 'remembered' as part of the VRPs state. Also remember the date and time when the last valid SLURM was loaded.
-Move 'slurm_bgpsec' and 'slurm_prefix' structs, and SLURM data flags to 'db_slurm.h'.
-Update 'slurm_parser' to return a specific error in case of a syntax error, so that further actions can be taken (ignore slurm, use last valid version, or store as the last valid version).
-In case a previous valid version of SLURM is utilized, log a WARNING indicating that such action is being taken, and log SLURM content at INFO level.
-Fix bug at common function 'process_file', there was an issue before releasing temporal pointers.

12 files changed:
src/Makefile.am
src/common.c
src/rtr/db/vrps.c
src/slurm/db_slurm.c [moved from src/slurm/slurm_db.c with 59% similarity]
src/slurm/db_slurm.h [new file with mode: 0644]
src/slurm/slurm_db.h [deleted file]
src/slurm/slurm_loader.c
src/slurm/slurm_loader.h
src/slurm/slurm_parser.c
src/slurm/slurm_parser.h
test/rtr/db/vrps_test.c
test/rtr/pdu_handler_test.c

index 78b75eaca2486e090474496019643168b0ea2733..cbfb567f0fbb4c3ce8dbb1d3ddd74320796bb2bf 100644 (file)
@@ -94,7 +94,7 @@ fort_SOURCES += rtr/db/roa.c rtr/db/roa.h
 fort_SOURCES += rtr/db/vrp.h
 fort_SOURCES += rtr/db/vrps.c rtr/db/vrps.h
 
-fort_SOURCES += slurm/slurm_db.c slurm/slurm_db.h
+fort_SOURCES += slurm/db_slurm.c slurm/db_slurm.h
 fort_SOURCES += slurm/slurm_loader.c slurm/slurm_loader.h
 fort_SOURCES += slurm/slurm_parser.c slurm/slurm_parser.h
 
index 8ef84aca89c465c0a1ea08f413f940e94f309b91..5083adc7d55b4b2789df92bc0bf491cf3e0f938e 100644 (file)
@@ -120,8 +120,8 @@ process_file(char const *dir_name, char const *file_name, char const *file_ext,
        }
 
        error = cb(fullpath, arg);
-       free(tmp);
        free(fullpath);
+       free(tmp);
        return error;
 }
 
index 9d5dd0b1cc9d94219fcd6b9fe1bf7f29d0f15e98..aad6646a7b3792457f79a4a9bae592949a8eedb1 100644 (file)
@@ -51,13 +51,15 @@ struct state {
         * during the current iteration.)
         */
        struct db_table *base;
-       /** ROA changes to @base over time. */
+       /** DB changes to @base over time. */
        struct deltas_db deltas;
 
+       /* Last valid SLURM applied to base */
+       struct db_slurm *slurm;
+
        serial_t next_serial;
        uint16_t v0_session_id;
        uint16_t v1_session_id;
-       time_t last_modified_date;
 } state;
 
 /** Read/write lock, which protects @state and its inhabitants. */
@@ -95,6 +97,8 @@ vrps_init(void)
            ? (state.v0_session_id - 1)
            : (0xFFFFu);
 
+       state.slurm = NULL;
+
        error = pthread_rwlock_init(&state_lock, NULL);
        if (error) {
                deltas_db_cleanup(&state.deltas, deltagroup_cleanup);
@@ -116,6 +120,8 @@ vrps_destroy(void)
 {
        if (state.base != NULL)
                db_table_destroy(state.base);
+       if (state.slurm != NULL)
+               db_slurm_destroy(state.slurm);
        deltas_db_cleanup(&state.deltas, deltagroup_cleanup);
        /* Nothing to do with error codes from now on */
        pthread_rwlock_destroy(&state_lock);
@@ -274,16 +280,11 @@ vrps_update(bool *changed)
 
        rwlock_write_lock(&state_lock);
 
-       /*
-        * TODO (next iteration) Remember the last valid SLURM
-        *
-        * Currently SLURM is ignored if it has errors, the error is logged and
-        * the new_base isn't altered. Instead of this, the last valid SLURM
-        * should be remembered, and will be applied when a new SLURM has
-        * errors; a warning should be logged to indicate which version of the
-        * SLURM is being applied.
-        */
-       slurm_apply(&new_base);
+       error = slurm_apply(&new_base, &state.slurm);
+       if (error) {
+               rwlock_unlock(&state_lock);
+               goto revert_base;
+       }
 
        if (state.base != NULL) {
                error = compute_deltas(state.base, new_base, &deltas);
similarity index 59%
rename from src/slurm/slurm_db.c
rename to src/slurm/db_slurm.c
index be592d85d7009ffc2ecd8ffd33d9a8762ba66bae..06297beed9f28c861513efd86defb6570269d352 100644 (file)
@@ -1,9 +1,12 @@
-#include "slurm_db.h"
+#include "db_slurm.h"
 
 #include <string.h>
+#include <time.h>
+#include <arpa/inet.h>
 #include <sys/types.h> /* AF_INET, AF_INET6 (needed in OpenBSD) */
 #include <sys/socket.h> /* AF_INET, AF_INET6 (needed in OpenBSD) */
 
+#include "crypto/base64.h"
 #include "data_structure/array_list.h"
 #include "object/router_key.h"
 
@@ -22,20 +25,35 @@ 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)
 
-struct arraylist_db {
+struct db_slurm {
        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;
-} array_lists_db;
+       bool loaded_date_set;
+       time_t loaded_date;
+};
 
-void
-slurm_db_init(void)
+char addr_buf[INET6_ADDRSTRLEN];
+
+int
+db_slurm_create(struct db_slurm **result)
 {
-       al_filter_prefix_init(&array_lists_db.filter_pfx_al);
-       al_assertion_prefix_init(&array_lists_db.assertion_pfx_al);
-       al_filter_bgpsec_init(&array_lists_db.filter_bgps_al);
-       al_assertion_bgpsec_init(&array_lists_db.assertion_bgps_al);
+       struct db_slurm *db;
+
+       db = malloc(sizeof(struct db_slurm));
+       if (db == NULL)
+               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);
+       db->loaded_date_set = false;
+
+       *result = db;
+       return 0;
 }
 
 static bool
@@ -221,19 +239,19 @@ bgpsec_equal(struct slurm_bgpsec_ctx *left_ctx, struct slurm_bgpsec *right,
 #define ADD_FUNCS(name, type, list_name, db_list, db_alt_list, equal_cb,\
     cont_cb, filter)                                                   \
        static type *                                                   \
-       name##_locate(type *obj, bool flt, int ctx)                     \
+       name##_locate(struct db_slurm *db, type *obj, bool flt, int ctx)\
        {                                                               \
                type##_ctx *cursor;                                     \
                array_index i;                                          \
                                                                        \
-               ARRAYLIST_FOREACH(db_list, cursor, 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_alt_list, cursor, i)               \
+               ARRAYLIST_FOREACH(&db->db_alt_list, cursor, i)  \
                        if (cont_cb(cursor, obj, ctx))                  \
                                return &cursor->element;                \
                                                                        \
@@ -241,66 +259,68 @@ bgpsec_equal(struct slurm_bgpsec_ctx *left_ctx, struct slurm_bgpsec *right,
        }                                                               \
                                                                        \
        static bool                                                     \
-       name##_exists(type *obj, bool flt, int ctx)                     \
+       name##_exists(struct db_slurm *db, type *obj, bool flt, int ctx)\
        {                                                               \
-               return name##_locate(obj, flt, ctx) != NULL;            \
+               return name##_locate(db, obj, flt, ctx) != NULL;        \
        }                                                               \
                                                                        \
        int                                                             \
-       slurm_db_add_##name(type *elem, int ctx)                        \
+       db_slurm_add_##name(struct db_slurm *db, type *elem, int ctx)   \
        {                                                               \
                type##_ctx new_elem;                                    \
-               if (name##_exists(elem, !filter, ctx))                  \
+               if (name##_exists(db, elem, !filter, ctx))              \
                        return -EEXIST;                                 \
                new_elem.element = *elem;                               \
                new_elem.ctx = ctx;                                     \
-               return list_name##_add(db_list, &new_elem);             \
+               return list_name##_add(&db->db_list, &new_elem);        \
        }
 
-ADD_FUNCS(prefix_filter, struct slurm_prefix, al_filter_prefix,
-    &array_lists_db.filter_pfx_al, &array_lists_db.assertion_pfx_al,
-    prefix_equal, prefix_contained, true)
-ADD_FUNCS(bgpsec_filter, struct slurm_bgpsec, al_filter_bgpsec,
-    &array_lists_db.filter_bgps_al, &array_lists_db.assertion_bgps_al,
-    bgpsec_equal, bgpsec_contained, true)
+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,
-    &array_lists_db.assertion_pfx_al, &array_lists_db.filter_pfx_al,
-    prefix_equal, prefix_contained, false)
+    assertion_pfx_al, filter_pfx_al, prefix_equal, prefix_contained, false)
 ADD_FUNCS(bgpsec_assertion, struct slurm_bgpsec, al_assertion_bgpsec,
-    &array_lists_db.assertion_bgps_al, &array_lists_db.filter_bgps_al,
-    bgpsec_equal, bgpsec_contained, false)
+    assertion_bgps_al, filter_bgps_al, bgpsec_equal, bgpsec_contained, false)
 
 bool
-slurm_db_vrp_is_filtered(struct vrp const *vrp)
+db_slurm_vrp_is_filtered(struct db_slurm *db, struct vrp const *vrp)
 {
        struct slurm_prefix slurm_prefix;
 
        slurm_prefix.data_flag = SLURM_COM_FLAG_ASN | SLURM_PFX_FLAG_PREFIX
            | SLURM_PFX_FLAG_MAX_LENGTH;
        slurm_prefix.vrp = *vrp;
-       slurm_prefix.comment = NULL;
 
-       return prefix_filter_exists(&slurm_prefix, true, -1);
+       return prefix_filter_exists(db, &slurm_prefix, true, -1);
 }
 
-int
-slurm_db_foreach_assertion_prefix(assertion_pfx_foreach_cb cb, void *arg)
-{
-       struct slurm_prefix_ctx *cursor;
-       array_index i;
-       int error;
-
-       ARRAYLIST_FOREACH(&array_lists_db.assertion_pfx_al, cursor, i) {
-               error = cb(&cursor->element, arg);
-               if (error)
-                       return error;
+#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;                                               \
        }
 
-       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
-slurm_db_bgpsec_is_filtered(struct router_key const *key)
+db_slurm_bgpsec_is_filtered(struct db_slurm *db, struct router_key const *key)
 {
        struct slurm_bgpsec slurm_bgpsec;
        unsigned char *tmp;
@@ -317,56 +337,150 @@ slurm_db_bgpsec_is_filtered(struct router_key const *key)
        slurm_bgpsec.ski = tmp;
        /* Router public key isn't used at filters */
        slurm_bgpsec.router_public_key = NULL;
-       slurm_bgpsec.comment = NULL;
 
-       result = bgpsec_filter_exists(&slurm_bgpsec, true, -1);
+       result = bgpsec_filter_exists(db, &slurm_bgpsec, true, -1);
        free(tmp);
        return result;
 }
 
-int
-slurm_db_foreach_assertion_bgpsec(assertion_bgpsec_foreach_cb cb, void *arg)
+static void
+clean_slurm_bgpsec(struct slurm_bgpsec_ctx *bgpsec)
 {
-       struct slurm_bgpsec_ctx *cursor;
-       array_index i;
-       int error;
+       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);
+}
 
-       ARRAYLIST_FOREACH(&array_lists_db.assertion_bgps_al, cursor, i) {
-               error = cb(&cursor->element, arg);
-               if (error)
-                       return error;
+void
+db_slurm_update_time(struct db_slurm *db)
+{
+       db->loaded_date = time(NULL);
+       db->loaded_date_set = true;
+}
+
+static char const *
+strv4addr(struct in_addr const *addr)
+{
+       return inet_ntop(AF_INET, addr, addr_buf, INET6_ADDRSTRLEN);
+}
+
+static char const *
+strv6addr(struct in6_addr const *addr)
+{
+       return inet_ntop(AF_INET6, addr, addr_buf, INET6_ADDRSTRLEN);
+}
+
+static int
+print_prefix_data(struct slurm_prefix *prefix, void *arg)
+{
+       char *pad = "     ";
+
+       pr_info("    {");
+       if (prefix->data_flag & SLURM_COM_FLAG_ASN)
+               pr_info("%s ASN: %u", pad, prefix->vrp.asn);
+
+       if (prefix->data_flag & SLURM_PFX_FLAG_PREFIX) {
+               switch(prefix->vrp.addr_fam) {
+               case AF_INET:
+                       pr_info("%s Prefix: %s/%u", pad,
+                           strv4addr(&prefix->vrp.prefix.v4),
+                           prefix->vrp.prefix_length);
+                       break;
+               case AF_INET6:
+                       pr_info("%s Prefix: %s/%u", pad,
+                           strv6addr(&prefix->vrp.prefix.v6),
+                           prefix->vrp.prefix_length);
+                       break;
+               default:
+                       pr_crit("Unknown addr family type: %u",
+                           prefix->vrp.addr_fam);
+               }
        }
 
+       if (prefix->data_flag & SLURM_PFX_FLAG_MAX_LENGTH)
+               pr_info("%s Max prefix length: %u", pad,
+                   prefix->vrp.max_prefix_length);
+       pr_info("    }");
+
        return 0;
 }
 
-static void
-clean_slurm_prefix(struct slurm_prefix_ctx *prefix)
+static int
+print_bgpsec_data(struct slurm_bgpsec *bgpsec, void *arg)
 {
-       if ((prefix->element.data_flag & SLURM_COM_FLAG_COMMENT) > 0)
-               free(prefix->element.comment);
+       char *pad = "     ";
+       char *buf;
+       int error;
+
+       pr_info("    {");
+       if (bgpsec->data_flag & SLURM_COM_FLAG_ASN)
+               pr_info("%s ASN: %u", pad, bgpsec->asn);
+
+       if (bgpsec->data_flag & SLURM_BGPS_FLAG_SKI) {
+               do {
+                       error = base64url_encode(bgpsec->ski, RK_SKI_LEN, &buf);
+                       if (error) {
+                               pr_info("%s SKI: <error encoding value>", pad);
+                               break;
+                       }
+                       pr_info("%s SKI: %s", pad, buf);
+                       free(buf);
+               } while (0);
+       }
+
+       if (bgpsec->data_flag & SLURM_BGPS_FLAG_ROUTER_KEY) {
+               do {
+                       error = base64url_encode(bgpsec->router_public_key,
+                           RK_SPKI_LEN, &buf);
+                       if (error) {
+                               pr_info("%s Router public key: <error encoding value>",
+                                   pad);
+                               break;
+                       }
+                       pr_info("%s Router public key: %s", pad, buf);
+                       free(buf);
+               } while (0);
+       }
+       pr_info("    }");
+
+       return 0;
 }
 
-static void
-clean_slurm_bgpsec(struct slurm_bgpsec_ctx *bgpsec)
+void
+db_slurm_log(struct db_slurm *db)
 {
-       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);
-       if ((bgpsec->element.data_flag & SLURM_COM_FLAG_COMMENT) > 0)
-               free(bgpsec->element.comment);
+       if (db->loaded_date_set)
+               pr_info("SLURM loaded at %s",
+                   asctime(localtime(&db->loaded_date)));
+       pr_info("Validation output filters {");
+       pr_info("  Prefix filters {");
+       db_slurm_foreach_filter_prefix(db, print_prefix_data, NULL);
+       pr_info("  }");
+       pr_info("  BGPsec filters {");
+       db_slurm_foreach_filter_bgpsec(db, 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);
+       pr_info("  }");
+       pr_info("  BGPsec assertions {");
+       db_slurm_foreach_assertion_bgpsec(db, print_bgpsec_data, NULL);
+       pr_info("  }");
+       pr_info("}");
 }
 
 void
-slurm_db_cleanup(void)
+db_slurm_destroy(struct db_slurm *db)
 {
-       al_filter_prefix_cleanup(&array_lists_db.filter_pfx_al,
-           clean_slurm_prefix);
-       al_filter_bgpsec_cleanup(&array_lists_db.filter_bgps_al,
+       /* 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(&array_lists_db.assertion_pfx_al,
-           clean_slurm_prefix);
-       al_assertion_bgpsec_cleanup(&array_lists_db.assertion_bgps_al,
+       al_assertion_prefix_cleanup(&db->assertion_pfx_al, NULL);
+       al_assertion_bgpsec_cleanup(&db->assertion_bgps_al,
            clean_slurm_bgpsec);
+       free(db);
 }
diff --git a/src/slurm/db_slurm.h b/src/slurm/db_slurm.h
new file mode 100644 (file)
index 0000000..03227dc
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef SRC_SLURM_db_slurm_H_
+#define SRC_SLURM_db_slurm_H_
+
+#include <stdbool.h>
+#include "rtr/db/vrp.h"
+
+/* Flags to get data from structs */
+#define SLURM_COM_FLAG_NONE            0x00
+#define SLURM_COM_FLAG_ASN             0x01
+#define SLURM_COM_FLAG_COMMENT         0x02
+
+#define SLURM_PFX_FLAG_PREFIX          0x04
+#define SLURM_PFX_FLAG_MAX_LENGTH      0x08
+
+#define SLURM_BGPS_FLAG_SKI            0x04
+#define SLURM_BGPS_FLAG_ROUTER_KEY     0x08
+
+struct slurm_prefix {
+       uint8_t         data_flag;
+       struct vrp      vrp;
+};
+
+struct slurm_bgpsec {
+       uint8_t         data_flag;
+       uint32_t        asn;
+       unsigned char   *ski;
+       unsigned char   *router_public_key;
+};
+
+struct db_slurm;
+
+typedef int (*prefix_foreach_cb)(struct slurm_prefix *, void *);
+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);
+
+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,
+    void *);
+
+/* Set the last update to current datetime */
+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 *);
+
+void db_slurm_destroy(struct db_slurm *);
+
+#endif /* SRC_SLURM_db_slurm_H_ */
diff --git a/src/slurm/slurm_db.h b/src/slurm/slurm_db.h
deleted file mode 100644 (file)
index 7b5d919..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef SRC_SLURM_SLURM_DB_H_
-#define SRC_SLURM_SLURM_DB_H_
-
-#include <stdbool.h>
-#include "slurm/slurm_parser.h"
-#include "rtr/db/vrp.h"
-
-typedef int (*assertion_pfx_foreach_cb)(struct slurm_prefix *, void *);
-typedef int (*assertion_bgpsec_foreach_cb)(struct slurm_bgpsec *, void *);
-
-void slurm_db_init(void);
-
-int slurm_db_add_prefix_filter(struct slurm_prefix *, int);
-int slurm_db_add_prefix_assertion(struct slurm_prefix *, int);
-int slurm_db_add_bgpsec_filter(struct slurm_bgpsec *, int);
-int slurm_db_add_bgpsec_assertion(struct slurm_bgpsec *, int);
-
-bool slurm_db_vrp_is_filtered(struct vrp const *);
-int slurm_db_foreach_assertion_prefix(assertion_pfx_foreach_cb, void *);
-
-bool slurm_db_bgpsec_is_filtered(struct router_key const *);
-int slurm_db_foreach_assertion_bgpsec(assertion_bgpsec_foreach_cb, void *);
-
-void slurm_db_cleanup(void);
-
-#endif /* SRC_SLURM_SLURM_DB_H_ */
index 1e65a36bfd1d15f54de10211435ac0228a3b1d52..517dbe9c332309c357220a1a257ccddfc7e7c7ec 100644 (file)
@@ -8,42 +8,53 @@
 #include "log.h"
 #include "config.h"
 #include "common.h"
-#include "slurm/slurm_db.h"
 #include "slurm/slurm_parser.h"
 
 #define SLURM_FILE_EXTENSION   ".slurm"
 
+/*
+ * Load the SLURM file(s) from the configured path, if the path is valid but no
+ * data is loaded (specific error for a SLURM folder) return -ENOENT error.
+ *
+ * Expect an EEXIST error from slurm_parse() if there's a syntax error.
+ */
 static int
-slurm_load(bool *loaded)
+slurm_load(struct slurm_parser_params *params)
 {
-       int ctx = 0; /* Context (file number) */
-       /* Optional configuration */
-       *loaded = false;
-       if (config_get_slurm() == NULL)
-               return 0;
+       struct db_slurm *db;
+       int error;
 
-       *loaded = true;
-       slurm_db_init();
+       error = db_slurm_create(&db);
+       if (error)
+               return error;
 
-       return process_file_or_dir(config_get_slurm(), SLURM_FILE_EXTENSION,
-           slurm_parse, &ctx);
-}
+       params->db_slurm = db;
 
-static void
-slurm_cleanup(void)
-{
-       /* Only if the SLURM was configured */
-       if (config_get_slurm() != NULL)
-               slurm_db_cleanup();
+       error = process_file_or_dir(config_get_slurm(), SLURM_FILE_EXTENSION,
+           slurm_parse, params);
+       if (error)
+               goto err;
+
+       /* A unmodified context means that no SLURM was loaded */
+       if(params->cur_ctx == 0) {
+               error = -ENOENT;
+               goto err;
+       }
+
+       return 0;
+err:
+       db_slurm_destroy(db);
+       params->db_slurm = NULL;
+       return error;
 }
 
 static int
 slurm_pfx_filters_apply(struct vrp const *vrp, void *arg)
 {
-       struct db_table *table = arg;
+       struct slurm_parser_params *params = arg;
 
-       if (slurm_db_vrp_is_filtered(vrp))
-               db_table_remove_roa(table, vrp);
+       if (db_slurm_vrp_is_filtered(params->db_slurm, vrp))
+               db_table_remove_roa(params->db_table, vrp);
 
        return 0;
 }
@@ -51,7 +62,7 @@ slurm_pfx_filters_apply(struct vrp const *vrp, void *arg)
 static int
 slurm_pfx_assertions_add(struct slurm_prefix *prefix, void *arg)
 {
-       struct db_table *table = arg;
+       struct slurm_parser_params *params = arg;
        struct ipv4_prefix prefix4;
        struct ipv6_prefix prefix6;
        struct vrp vrp;
@@ -63,33 +74,33 @@ slurm_pfx_assertions_add(struct slurm_prefix *prefix, void *arg)
        if (vrp.addr_fam == AF_INET) {
                prefix4.addr = vrp.prefix.v4;
                prefix4.len = vrp.prefix_length;
-               return rtrhandler_handle_roa_v4(table, vrp.asn, &prefix4,
-                   vrp.max_prefix_length);
+               return rtrhandler_handle_roa_v4(params->db_table, vrp.asn,
+                   &prefix4, vrp.max_prefix_length);
        }
        if (vrp.addr_fam == AF_INET6) {
                prefix6.addr = vrp.prefix.v6;
                prefix6.len = vrp.prefix_length;
-               return rtrhandler_handle_roa_v6(table, vrp.asn, &prefix6,
-                   vrp.max_prefix_length);
+               return rtrhandler_handle_roa_v6(params->db_table, vrp.asn,
+                   &prefix6, vrp.max_prefix_length);
        }
 
        pr_crit("Unknown addr family type: %u", vrp.addr_fam);
 }
 
 static int
-slurm_pfx_assertions_apply(struct db_table *base)
+slurm_pfx_assertions_apply(struct slurm_parser_params *params)
 {
-       return slurm_db_foreach_assertion_prefix(slurm_pfx_assertions_add,
-           base);
+       return db_slurm_foreach_assertion_prefix(params->db_slurm,
+           slurm_pfx_assertions_add, params);
 }
 
 static int
 slurm_bgpsec_filters_apply(struct router_key const *key, void *arg)
 {
-       struct db_table *table = arg;
+       struct slurm_parser_params *params = arg;
 
-       if (slurm_db_bgpsec_is_filtered(key))
-               db_table_remove_router_key(table, key);
+       if (db_slurm_bgpsec_is_filtered(params->db_slurm, key))
+               db_table_remove_router_key(params->db_table, key);
 
        return 0;
 }
@@ -97,69 +108,112 @@ slurm_bgpsec_filters_apply(struct router_key const *key, void *arg)
 static int
 slurm_bgpsec_assertions_add(struct slurm_bgpsec *bgpsec, void *arg)
 {
-       struct db_table *table = arg;
+       struct slurm_parser_params *params = arg;
 
-       return rtrhandler_handle_router_key(table, bgpsec->ski,
+       return rtrhandler_handle_router_key(params->db_table, bgpsec->ski,
            bgpsec->asn, bgpsec->router_public_key);
 }
 
 static int
-slurm_bgpsec_assertions_apply(struct db_table *base)
+slurm_bgpsec_assertions_apply(struct slurm_parser_params *params)
 {
-       return slurm_db_foreach_assertion_bgpsec(slurm_bgpsec_assertions_add,
-           base);
+       return db_slurm_foreach_assertion_bgpsec(params->db_slurm,
+           slurm_bgpsec_assertions_add, params);
+}
+
+static int
+slurm_create_parser_params(struct slurm_parser_params **result)
+{
+       struct slurm_parser_params *params;
+
+       params = malloc(sizeof(struct slurm_parser_params));
+       if (params == NULL)
+               return pr_enomem();
+
+       params->db_table = NULL;
+       params->db_slurm = NULL;
+       params->cur_ctx = 0;
+
+       *result = params;
+       return 0;
 }
 
-/*
- * Load the SLURM file/dir and try to apply it on @base.
- *
- * On any error the SLURM won't be applied to @base.
- */
 int
-slurm_apply(struct db_table **base)
+slurm_apply(struct db_table **base, struct db_slurm **last_slurm)
 {
-       struct db_table *new_base;
-       bool loaded;
+       struct slurm_parser_params *params = NULL;
        int error;
 
-       loaded = false;
-       error = slurm_load(&loaded);
+       if (config_get_slurm() == NULL)
+               return 0;
+
+       error = slurm_create_parser_params(&params);
        if (error)
-               goto cleanup;
+               return error;
+
+       error = slurm_load(params);
+       switch(error) {
+       case 0:
+               /* Use as last valid slurm */
+               if (*last_slurm != NULL)
+                       db_slurm_destroy(*last_slurm);
+               *last_slurm = params->db_slurm;
+               db_slurm_update_time(*last_slurm);
+               break;
+       case -EEXIST:
+               /* Syntax error, use last valid slurm, log as info */
+               if (*last_slurm != NULL) {
+                       pr_warn("A previous valid version of the SLURM exists and will be applied");
+                       params->db_slurm = *last_slurm;
+                       db_slurm_log(params->db_slurm);
+               }
+               break;
+       default:
+               /* Some other error, discard SLURM */
+               if (*last_slurm != NULL) {
+                       pr_info("Discarding previous valid SLURM");
+                       db_slurm_destroy(*last_slurm);
+               }
+               goto success;
+       }
 
-       if (!loaded)
-               return 0;
+       /* If there's no SLURM, stop */
+       if (params->db_slurm == NULL)
+               goto success;
 
        /* Deep copy of the base so that updates can be reverted */
-       error = db_table_clone(&new_base, *base);
+       error = db_table_clone(&params->db_table, *base);
        if (error)
-               goto cleanup;
+               goto release_slurm;
 
-       error = db_table_foreach_roa(new_base, slurm_pfx_filters_apply,
-           new_base);
+       error = db_table_foreach_roa(params->db_table, slurm_pfx_filters_apply,
+           params);
        if (error)
-               goto release_new;
+               goto release_table;
 
-       error = db_table_foreach_router_key(new_base,
-           slurm_bgpsec_filters_apply, new_base);
+       error = db_table_foreach_router_key(params->db_table,
+           slurm_bgpsec_filters_apply, params);
        if (error)
-               goto release_new;
+               goto release_table;
 
-       error = slurm_pfx_assertions_apply(new_base);
-       if (error) {
-               goto release_new;
-       }
+       error = slurm_pfx_assertions_apply(params);
+       if (error)
+               goto release_table;
 
-       error = slurm_bgpsec_assertions_apply(new_base);
-       if (!error) {
-               db_table_destroy(*base);
-               *base = new_base;
-               goto cleanup;
+       error = slurm_bgpsec_assertions_apply(params);
+       if (error) {
+               goto release_table;
        }
 
-release_new:
-       db_table_destroy(new_base);
-cleanup:
-       slurm_cleanup();
+       db_table_destroy(*base);
+       *base = params->db_table;
+success:
+       free(params);
+       return 0;
+release_table:
+       db_table_destroy(params->db_table);
+release_slurm:
+       db_slurm_destroy(params->db_slurm);
+       free(params);
        return error;
 }
index c9801cc03359805bc4cf6130289af05e3acedfed..cf4845a35424887d861134927b14c15f961da6ad 100644 (file)
@@ -2,7 +2,21 @@
 #define SRC_SLURM_SLURM_LOADER_H_
 
 #include "rtr/db/db_table.h"
+#include "slurm/db_slurm.h"
 
-int slurm_apply(struct db_table **);
+/*
+ * Load the SLURM file/dir and try to apply it on @db_table, point to the SLURM
+ * applied at @db_slurm.
+ *
+ * Return error only when there's a major issue on the process (no memory,
+ * SLURM loaded but something happened applying it).
+ *
+ * Return 0 when there's no problem applying the SLURM:
+ * - There's no SLURM configured
+ * - The SLURM was successfully applied
+ * - The @last_slurm was applied due to a syntax problem with a newer SLURM
+ * - SLURM configured but couldn't be read (file doesn't exists, no permission)
+ */
+int slurm_apply(struct db_table **, struct db_slurm **);
 
 #endif /* SRC_SLURM_SLURM_LOADER_H_ */
index edba6d1a8268fa21a2b27a122feb128a3fcd0eff..2ef266c5e2207743bd348a64e24ca1aef629c7d5 100644 (file)
@@ -14,7 +14,6 @@
 #include "address.h"
 #include "json_parser.h"
 #include "object/router_key.h"
-#include "slurm/slurm_db.h"
 
 /* JSON members */
 #define SLURM_VERSION                  "slurmVersion"
                return pr_err("SLURM member '%s' is required", name);
 
 /* Context value, local to avoid forwarding the parameter */
-int cur_ctx;
+struct db_slurm *db;
+unsigned int cur_ctx;
 
-static int handle_json(json_t *, int *);
+static int handle_json(json_t *, struct db_slurm *, unsigned int *);
 
+/*
+ * Try to parse the SLURM file(s), any syntax error will return an EEXIST error
+ */
 int
 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;
+
        json_root = json_load_file(location, JSON_REJECT_DUPLICATES,
            &json_error);
        if (json_root == NULL) {
                pr_err("SLURM JSON error on line %d, column %d: %s",
                    json_error.line, json_error.column, json_error.text);
+               /* File was read, but has a content error */
+               if (json_error.position > 0)
+                       goto syntax_err;
                return -ENOENT;
        }
 
-       error = handle_json(json_root, arg);
-
+       ctx = params->cur_ctx;
+       error = handle_json(json_root, params->db_slurm, &ctx);
        json_decref(json_root);
-       return error;
+       if (error)
+               goto syntax_err;
+
+       params->cur_ctx = ctx;
+       return 0;
+
+syntax_err:
+       /* File exists, but has a syntax/content error */
+       return -EEXIST;
 }
 
 static int
@@ -89,9 +107,9 @@ set_asn(json_t *object, bool is_assertion, uint32_t *result, uint8_t *flag,
        return 0;
 }
 
+/* There's no need to store the comment */
 static int
-set_comment(json_t *object, char **comment, uint8_t *flag,
-    size_t *members_loaded)
+set_comment(json_t *object, uint8_t *flag, size_t *members_loaded)
 {
        char const *tmp;
        int error;
@@ -102,7 +120,6 @@ set_comment(json_t *object, char **comment, uint8_t *flag,
        else if (error)
                return error;
 
-       *comment = strdup(tmp);
        *flag = *flag | SLURM_COM_FLAG_COMMENT;
        (*members_loaded)++;
 
@@ -314,7 +331,8 @@ set_router_pub_key(json_t *object, bool is_assertion,
        /* Required by assertions */
        if (error && is_assertion) {
                if (error == -ENOENT)
-                       return pr_err("SLURM assertion %s is required", ROUTER_PUBLIC_KEY);
+                       return pr_err("SLURM assertion %s is required",
+                           ROUTER_PUBLIC_KEY);
                return error;
        }
 
@@ -356,7 +374,6 @@ init_slurm_prefix(struct slurm_prefix *slurm_prefix)
        slurm_prefix->vrp.prefix_length = 0;
        slurm_prefix->vrp.max_prefix_length = 0;
        slurm_prefix->vrp.addr_fam = 0;
-       slurm_prefix->comment = NULL;
 }
 
 static int
@@ -387,37 +404,27 @@ load_single_prefix(json_t *object, bool is_assertion)
        if (error)
                return error;
 
-       error = set_comment(object, &result.comment, &result.data_flag,
-           &member_count);
+       error = set_comment(object, &result.data_flag, &member_count);
        if (error)
                return error;
 
        /* A single comment isn't valid */
-       if (result.data_flag == SLURM_COM_FLAG_COMMENT) {
-               pr_err("Single comments aren't valid");
-               error = -EINVAL;
-               goto release_comment;
-       }
+       if (result.data_flag == SLURM_COM_FLAG_COMMENT)
+               return pr_err("Single comments aren't valid");
 
        /* A filter must have ASN and/or prefix */
        if (!is_assertion) {
                if ((result.data_flag &
-                   (SLURM_COM_FLAG_ASN | SLURM_PFX_FLAG_PREFIX)) == 0) {
-                       pr_err("Prefix filter must have an asn and/or prefix");
-                       error = -EINVAL;
-                       goto release_comment;
-               }
+                   (SLURM_COM_FLAG_ASN | SLURM_PFX_FLAG_PREFIX)) == 0)
+                       return pr_err("Prefix filter must have an asn and/or prefix");
 
                /* Validate expected members */
-               if (!json_valid_members_count(object, member_count)) {
-                       pr_err("Prefix filter has unknown members (see RFC 8416 section 3.3.1)");
-                       error = -EINVAL;
-                       goto release_comment;
-               }
+               if (!json_valid_members_count(object, member_count))
+                       return pr_err("Prefix filter has unknown members (see RFC 8416 section 3.3.1)");
 
-               error = slurm_db_add_prefix_filter(&result, cur_ctx);
+               error = db_slurm_add_prefix_filter(db, &result, cur_ctx);
                if (error)
-                       goto release_comment;
+                       return error;
 
                return 0;
        }
@@ -427,30 +434,19 @@ load_single_prefix(json_t *object, bool is_assertion)
         * set_asn and set_prefix
         */
 
-       if ((result.data_flag & SLURM_PFX_FLAG_MAX_LENGTH) > 0)
-               if (result.vrp.prefix_length > result.vrp.max_prefix_length) {
-                       pr_err(
-                           "Prefix length is greater than max prefix length");
-                       error = -EINVAL;
-                       goto release_comment;
-               }
+       if ((result.data_flag & SLURM_PFX_FLAG_MAX_LENGTH) > 0 &&
+           result.vrp.prefix_length > result.vrp.max_prefix_length)
+               return pr_err("Prefix length is greater than max prefix length");
 
        /* Validate expected members */
-       if (!json_valid_members_count(object, member_count)) {
-               pr_err("Prefix assertion has unknown members (see RFC 8416 section 3.4.1)");
-               error = -EINVAL;
-               goto release_comment;
-       }
+       if (!json_valid_members_count(object, member_count))
+               return pr_err("Prefix assertion has unknown members (see RFC 8416 section 3.4.1)");
 
-       error = slurm_db_add_prefix_assertion(&result, cur_ctx);
+       error = db_slurm_add_prefix_assertion(db, &result, cur_ctx);
        if (error)
-               goto release_comment;
+               return error;
 
        return 0;
-
-release_comment:
-       free(result.comment);
-       return error;
 }
 
 static int
@@ -491,7 +487,6 @@ init_slurm_bgpsec(struct slurm_bgpsec *slurm_bgpsec)
        slurm_bgpsec->asn = 0;
        slurm_bgpsec->ski = NULL;
        slurm_bgpsec->router_public_key = NULL;
-       slurm_bgpsec->comment = NULL;
 }
 
 static int
@@ -521,8 +516,7 @@ load_single_bgpsec(json_t *object, bool is_assertion)
        if (error)
                goto release_ski;
 
-       error = set_comment(object, &result.comment, &result.data_flag,
-           &member_count);
+       error = set_comment(object, &result.data_flag, &member_count);
        if (error)
                goto release_router_key;
 
@@ -530,7 +524,7 @@ load_single_bgpsec(json_t *object, bool is_assertion)
        if (result.data_flag == SLURM_COM_FLAG_COMMENT) {
                pr_err("Single comments aren't valid");
                error = -EINVAL;
-               goto release_comment;
+               goto release_router_key;
        }
 
        /* A filter must have ASN and/or SKI */
@@ -539,19 +533,19 @@ load_single_bgpsec(json_t *object, bool is_assertion)
                    (SLURM_COM_FLAG_ASN | SLURM_BGPS_FLAG_SKI)) == 0) {
                        pr_err("BGPsec filter must have an asn and/or SKI");
                        error = -EINVAL;
-                       goto release_comment;
+                       goto release_router_key;
                }
 
                /* Validate expected members */
                if (!json_valid_members_count(object, member_count)) {
                        pr_err("BGPsec filter has unknown members (see RFC 8416 section 3.3.2)");
                        error = -EINVAL;
-                       goto release_comment;
+                       goto release_router_key;
                }
 
-               error = slurm_db_add_bgpsec_filter(&result, cur_ctx);
+               error = db_slurm_add_bgpsec_filter(db, &result, cur_ctx);
                if (error)
-                       goto release_comment;
+                       goto release_router_key;
 
                return 0;
        }
@@ -560,17 +554,15 @@ load_single_bgpsec(json_t *object, bool is_assertion)
        if (!json_valid_members_count(object, member_count)) {
                pr_err("BGPsec assertion has unknown members (see RFC 8416 section 3.4.2)");
                error = -EINVAL;
-               goto release_comment;
+               goto release_router_key;
        }
 
-       error = slurm_db_add_bgpsec_assertion(&result, cur_ctx);
+       error = db_slurm_add_bgpsec_assertion(db, &result, cur_ctx);
        if (error)
-               goto release_comment;
+               goto release_router_key;
 
        return 0;
 
-release_comment:
-       free(result.comment);
 release_router_key:
        free(result.router_public_key);
 release_ski:
@@ -697,7 +689,7 @@ load_assertions(json_t *root)
 }
 
 static int
-handle_json(json_t *root, int *ctx)
+handle_json(json_t *root, struct db_slurm *db_slurm, unsigned int *ctx)
 {
        size_t expected_members;
        int error;
@@ -706,6 +698,7 @@ handle_json(json_t *root, int *ctx)
                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)
index 3e5338a8a5be335ca3dd53967f1aeab4d9ea55ed..a5fec8be0dc240061f49a8aba951de7d2c3e231a 100644 (file)
@@ -1,34 +1,15 @@
 #ifndef SRC_SLURM_SLURM_PARSER_H_
 #define SRC_SLURM_SLURM_PARSER_H_
 
-#include "rtr/db/vrp.h"
+#include "rtr/db/db_table.h"
+#include "slurm/db_slurm.h"
 
-/* Flags to get data from structs */
-#define SLURM_COM_FLAG_NONE            0x00
-#define SLURM_COM_FLAG_ASN             0x01
-#define SLURM_COM_FLAG_COMMENT         0x02
-
-#define SLURM_PFX_FLAG_PREFIX          0x04
-#define SLURM_PFX_FLAG_MAX_LENGTH      0x08
-
-#define SLURM_BGPS_FLAG_SKI            0x04
-#define SLURM_BGPS_FLAG_ROUTER_KEY     0x08
-
-struct slurm_prefix {
-       uint8_t         data_flag;
-       struct vrp      vrp;
-       char            *comment;
+struct slurm_parser_params {
+       struct db_table *db_table;
+       struct db_slurm *db_slurm;
+       unsigned int    cur_ctx; /* Context (file number) */
 };
 
-struct slurm_bgpsec {
-       uint8_t         data_flag;
-       uint32_t        asn;
-       unsigned char   *ski;
-       unsigned char   *router_public_key;
-       char            *comment;
-};
-
-
 int slurm_parse(char const *, void *);
 
 
index d6b0c66963711a15e21b59388ac82c101165aaba..962cc4477333750350ad12b10dbdba82f5698aeb 100644 (file)
@@ -15,7 +15,7 @@
 #include "rtr/db/db_table.c"
 #include "rtr/db/rtr_db_impersonator.c"
 #include "rtr/db/vrps.c"
-#include "slurm/slurm_db.c"
+#include "slurm/db_slurm.c"
 #include "slurm/slurm_loader.c"
 #include "slurm/slurm_parser.c"
 
index ab338e70352fd3d6a2109d1cbd2253aa5d18b7f7..efe1e3588f4fac5e589e1fba67d9a26795f5087e 100644 (file)
@@ -22,7 +22,7 @@
 #include "rtr/db/db_table.c"
 #include "rtr/db/rtr_db_impersonator.c"
 #include "rtr/db/vrps.c"
-#include "slurm/slurm_db.c"
+#include "slurm/db_slurm.c"
 #include "slurm/slurm_loader.c"
 #include "slurm/slurm_parser.c"