]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Relocate VRPs override function, and complete unit tests.
authorpcarana <pc.moreno2099@gmail.com>
Sat, 1 Jun 2019 01:01:09 +0000 (20:01 -0500)
committerpcarana <pc.moreno2099@gmail.com>
Sat, 1 Jun 2019 01:01:09 +0000 (20:01 -0500)
- The function that checks and removes VRPs that override eachother (before being sent by RTR), has been placed where VRPs functions are located.
- Fix the impersonator function that returns the minimum client serial.
- Add unit test to:
+   Check that deltas that won't be sent or used anymore, will be forgotten.
+   Check that a range of deltas that'll be sent by RTR, don't contain VRP announcements/withdrawals that override eachother.
+   Chech that a PDU with a wrong session ID is correctly handled.

src/rtr/db/vrps.c
src/rtr/db/vrps.h
src/rtr/pdu_sender.c
test/rtr/db/impersonator.c
test/rtr/db/vrps_test.c
test/rtr/pdu_handler_test.c

index aebc7d8e6e09a77bc7a4b6d4808381d24832ea29..de7c10f52d68f59ad6f16096201d89c4e4ab3e3a 100644 (file)
@@ -3,6 +3,7 @@
 #include <pthread.h>
 #include <string.h>
 #include <time.h>
+#include <sys/queue.h>
 #include "clients.h"
 #include "common.h"
 #include "validation_handler.h"
 
 DEFINE_ARRAY_LIST_FUNCTIONS(deltas_db, struct delta_group, )
 
+struct vrp_node {
+       struct delta delta;
+       SLIST_ENTRY(vrp_node) next;
+};
+
+/** Sorted list to filter deltas */
+SLIST_HEAD(vrp_slist, vrp_node);
+
 struct state {
        /**
         * All the current valid ROAs.
@@ -349,6 +358,79 @@ vrps_foreach_base_roa(vrp_foreach_cb cb, void *arg, serial_t *serial)
        return error;
 }
 
+/*
+ * Remove the announcements/withdrawals that override each other.
+ *
+ * (Note: We're assuming the array is already duplicateless enough thanks to the
+ * hash table.)
+ */
+static int
+vrp_ovrd_remove(struct delta const *delta, void *arg)
+{
+       struct vrp_node *ptr;
+       struct vrp_slist *filtered_vrps = arg;
+
+       SLIST_FOREACH(ptr, filtered_vrps, next)
+               if (VRP_EQ(&delta->vrp, &ptr->delta.vrp) &&
+                   delta->flags != ptr->delta.flags) {
+                       SLIST_REMOVE(filtered_vrps, ptr, vrp_node, next);
+                       free(ptr);
+                       return 0;
+               }
+
+       ptr = malloc(sizeof(struct vrp_node));
+       if (ptr == NULL)
+               return pr_enomem();
+
+       ptr->delta = *delta;
+       SLIST_INSERT_HEAD(filtered_vrps, ptr, next);
+       return 0;
+}
+
+/*
+ * Remove all operations on @deltas that override each other, and do @cb (with
+ * @arg) on each element of the resultant delta.
+ */
+int
+vrps_foreach_filtered_delta(struct deltas_db *deltas, delta_foreach_cb cb,
+    void *arg)
+{
+       struct vrp_slist filtered_vrps;
+       struct delta_group *group;
+       struct vrp_node *ptr;
+       array_index i;
+       int error = 0;
+
+       /*
+        * Filter: Remove entries that cancel each other.
+        * (We'll have to build a separate list because the database nodes
+        * are immutable.)
+        */
+       SLIST_INIT(&filtered_vrps);
+       ARRAYLIST_FOREACH(deltas, group, i) {
+               error = deltas_foreach(group->serial, group->deltas,
+                   vrp_ovrd_remove, &filtered_vrps);
+               if (error)
+                       goto release_list;
+       }
+
+       /* Now do the callback on the filtered deltas */
+       SLIST_FOREACH(ptr, &filtered_vrps, next) {
+               error = cb(&ptr->delta, arg);
+               if (error)
+                       break;
+       }
+
+release_list:
+       while (!SLIST_EMPTY(&filtered_vrps)) {
+               ptr = filtered_vrps.slh_first;
+               SLIST_REMOVE_HEAD(&filtered_vrps, next);
+               free(ptr);
+       }
+
+       return error;
+}
+
 /**
  * Adds to @result the deltas whose serial > @from.
  *
index 631f0c52157ad6121ada9ffa139fbc8141a590f1..86f2b2b6dea2fab360d95dd38f69cfb101b86e2c 100644 (file)
@@ -32,6 +32,8 @@ int vrps_foreach_base_roa(vrp_foreach_cb, void *, serial_t *);
 int vrps_get_deltas_from(serial_t, serial_t *, struct deltas_db *);
 int get_last_serial_number(serial_t *);
 
+int vrps_foreach_filtered_delta(struct deltas_db *, delta_foreach_cb, void *);
+
 uint16_t get_current_session_id(uint8_t);
 
 #endif /* SRC_VRPS_H_ */
index a54872fe57653d540be0eab081ac0de7716800b9..47a8f8ffca525f0c231073770cb21c895eb92bb8 100644 (file)
@@ -5,7 +5,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <sys/queue.h>
 
 #include "clients.h"
 #include "config.h"
 #include "rtr/pdu_serializer.h"
 #include "rtr/db/vrps.h"
 
-struct vrp_node {
-       struct delta delta;
-       SLIST_ENTRY(vrp_node) next;
-};
-
-/** Sorted list to filter deltas */
-SLIST_HEAD(vrp_slist, vrp_node);
-
 /*
  * Set all the header values, EXCEPT length field.
  */
@@ -179,43 +170,10 @@ vrp_simply_send(struct delta const *delta, void *arg)
        return send_prefix_pdu(*fd, &delta->vrp, delta->flags);
 }
 
-/**
- * Remove the announcements/withdrawals that override each other.
- *
- * (Note: We're assuming the array is already duplicateless enough thanks to the
- * hash table.)
- */
-static int
-vrp_ovrd_remove(struct delta const *delta, void *arg)
-{
-       struct vrp_node *ptr;
-       struct vrp_slist *filtered_vrps = arg;
-
-       SLIST_FOREACH(ptr, filtered_vrps, next)
-               if (VRP_EQ(&delta->vrp, &ptr->delta.vrp) &&
-                   delta->flags != ptr->delta.flags) {
-                       SLIST_REMOVE(filtered_vrps, ptr, vrp_node, next);
-                       free(ptr);
-                       return 0;
-               }
-
-       ptr = malloc(sizeof(struct vrp_node));
-       if (ptr == NULL)
-               return pr_enomem();
-
-       ptr->delta = *delta;
-       SLIST_INSERT_HEAD(filtered_vrps, ptr, next);
-       return 0;
-}
-
 int
 send_delta_pdus(int fd, struct deltas_db *deltas)
 {
-       struct vrp_slist filtered_vrps;
        struct delta_group *group;
-       array_index i;
-       struct vrp_node *ptr;
-       int error = 0;
 
        /*
         * Short circuit: Entries that share serial are already guaranteed to
@@ -227,34 +185,7 @@ send_delta_pdus(int fd, struct deltas_db *deltas)
                    vrp_simply_send, &fd);
        }
 
-       /*
-        * Filter: Remove entries that cancel each other.
-        * (We'll have to build a separate list because the database nodes
-        * are immutable.)
-        */
-       SLIST_INIT(&filtered_vrps);
-       ARRAYLIST_FOREACH(deltas, group, i) {
-               error = deltas_foreach(group->serial, group->deltas,
-                   vrp_ovrd_remove, &filtered_vrps);
-               if (error)
-                       goto release_list;
-       }
-
-       /* Now send the filtered deltas */
-       SLIST_FOREACH(ptr, &filtered_vrps, next) {
-               error = send_prefix_pdu(fd, &ptr->delta.vrp, ptr->delta.flags);
-               if (error)
-                       break;
-       }
-
-release_list:
-       while (!SLIST_EMPTY(&filtered_vrps)) {
-               ptr = filtered_vrps.slh_first;
-               SLIST_REMOVE_HEAD(&filtered_vrps, next);
-               free(ptr);
-       }
-
-       return error;
+       return vrps_foreach_filtered_delta(deltas, vrp_simply_send, &fd);
 }
 
 int
index 5ea4cbf4f11a890203dfd476205a0a1bfa6100f3..d5233e833dfc1ee6997bedf2a452ee762e25a6f9 100644 (file)
@@ -41,10 +41,13 @@ perform_standalone_validation(struct validation_handler *handler)
                add_v6(handler, 1);
                break;
        case 2:
-       case 3:
                add_v4(handler, 1);
                add_v6(handler, 1);
                break;
+       case 3:
+               add_v4(handler, 0);
+               add_v6(handler, 0);
+               break;
        default:
                ck_abort_msg("perform_standalone_validation() was called too many times (%d).",
                    iteration);
index 8fb14de4fbcb7310fa44edea6f78f32168e7b9c4..6ad42b397c567ceee5f66892c23614a22473a3a6 100644 (file)
@@ -19,6 +19,7 @@
 static const bool iteration0_base[] = { 1, 0, 1, 0, };
 static const bool iteration1_base[] = { 1, 1, 1, 1, };
 static const bool iteration2_base[] = { 0, 1, 0, 1, };
+static const bool iteration3_base[] = { 1, 0, 1, 0, };
 
 /*
  * DELTA
@@ -37,11 +38,26 @@ static const bool deltas_0to2[] = { 1, 0, 1, 0, 0, 1, 0, 1, };
 static const bool deltas_1to2[] = { 1, 0, 1, 0, 0, 0, 0, 0, };
 static const bool deltas_2to2[] = { 0, 0, 0, 0, 0, 0, 0, 0, };
 
+/* Deltas with rules that override each other */
+static const bool deltas_0to3_ovrd[] = { 1, 1, 1, 1, 1, 1, 1, 1, };
+static const bool deltas_1to3_ovrd[] = { 1, 1, 1, 1, 1, 0, 1, 0, };
+static const bool deltas_2to3_ovrd[] = { 0, 1, 0, 1, 1, 0, 1, 0, };
+static const bool deltas_3to3_ovrd[] = { 0, 0, 0, 0, 0, 0, 0, 0, };
+
+/* Deltas cleaned up */
+static const bool deltas_0to3_clean[] = { 0, 0, 0, 0, 0, 0, 0, 0, };
+static const bool deltas_1to3_clean[] = { 0, 1, 0, 1, 0, 0, 0, 0, };
+static const bool deltas_2to3_clean[] = { 0, 1, 0, 1, 1, 0, 1, 0, };
+static const bool deltas_3to3_clean[] = { 0, 0, 0, 0, 0, 0, 0, 0, };
+
 /* Impersonator functions */
 
+serial_t current_min_serial = 0;
+
 serial_t
-clients_get_min_serial(void)
+clients_get_min_serial(serial_t *result)
 {
+       *result = current_min_serial;
        return 0;
 }
 
@@ -65,6 +81,7 @@ vrp_fail(struct vrp const *vrp, void *arg)
 
        ck_abort_msg("Expected no callbacks, got VRP %u/%s/%u/%u.",
            vrp->asn, addr, vrp->prefix_length, vrp->max_prefix_length);
+       return -EINVAL;
 }
 
 static array_index
@@ -133,7 +150,6 @@ delta_check(struct delta const *delta, void *arg)
        array[index] = true;
 
        return 0;
-
 }
 
 static void
@@ -159,8 +175,55 @@ check_base(serial_t expected_serial, bool const *expected_base)
                ck_assert_uint_eq(expected_base[i], actual_base[i]);
 }
 
+static int
+vrp_add(struct delta const *delta, void *arg)
+{
+       struct deltas *deltas = arg;
+       struct vrp const *vrp;
+       struct v4_address v4;
+       struct v6_address v6;
+
+       vrp = &delta->vrp;
+       switch (vrp->addr_fam) {
+       case AF_INET:
+               v4.prefix.len = vrp->prefix_length;
+               v4.prefix.addr = vrp->prefix.v4;
+               v4.max_length = vrp->max_prefix_length;
+               deltas_add_roa_v4(deltas, vrp->asn, &v4, delta->flags);
+               break;
+       case AF_INET6:
+               v6.prefix.len = vrp->prefix_length;
+               v6.prefix.addr = vrp->prefix.v6;
+               v6.max_length = vrp->max_prefix_length;
+               deltas_add_roa_v6(deltas, vrp->asn, &v6, delta->flags);
+               break;
+       default:
+               ck_abort_msg("Unknown addr family");
+       }
+       return 0;
+}
+
+static void
+filter_deltas(struct deltas_db *db)
+{
+       struct deltas_db tmp;
+       struct delta_group group;
+       struct deltas *deltas;
+
+       group.serial = 0;
+       ck_assert_int_eq(0, deltas_create(&deltas));
+       group.deltas = deltas;
+       ck_assert_int_eq(0, vrps_foreach_filtered_delta(db, vrp_add,
+           group.deltas));
+       deltas_db_init(&tmp);
+       ck_assert_int_eq(0, deltas_db_add(&tmp, &group));
+
+       *db = tmp;
+}
+
 static void
-check_deltas(serial_t from, serial_t to, bool const *expected_deltas)
+check_deltas(serial_t from, serial_t to, bool const *expected_deltas,
+    bool filter)
 {
        serial_t actual_serial;
        bool actual_deltas[8];
@@ -173,6 +236,9 @@ check_deltas(serial_t from, serial_t to, bool const *expected_deltas)
            &deltas));
        ck_assert_uint_eq(to, actual_serial);
 
+       if (filter)
+               filter_deltas(&deltas);
+
        memset(actual_deltas, 0, sizeof(actual_deltas));
        ARRAYLIST_FOREACH(&deltas, group, i)
                ck_assert_int_eq(0, deltas_foreach(group->serial, group->deltas,
@@ -181,45 +247,134 @@ check_deltas(serial_t from, serial_t to, bool const *expected_deltas)
                ck_assert_uint_eq(expected_deltas[i], actual_deltas[i]);
 }
 
-START_TEST(test_basic)
+static void
+check_no_deltas(serial_t from, serial_t to)
 {
+       serial_t actual_serial;
        struct deltas_db deltas;
-       serial_t serial;
-       bool changed;
-       bool iterated_entries[8];
 
        deltas_db_init(&deltas);
+       ck_assert_int_eq(-ESRCH, vrps_get_deltas_from(from, &actual_serial,
+           &deltas));
+}
+
+static void
+create_deltas_0to1(struct deltas_db *deltas, serial_t *serial, bool *changed,
+    bool *iterated_entries)
+{
+       current_min_serial = 0;
+
+       deltas_db_init(deltas);
 
        ck_assert_int_eq(0, vrps_init());
 
        /* First validation not yet performed: Tell routers to wait */
-       ck_assert_int_eq(-EAGAIN, get_last_serial_number(&serial));
+       ck_assert_int_eq(-EAGAIN, get_last_serial_number(serial));
        ck_assert_int_eq(-EAGAIN, vrps_foreach_base_roa(vrp_fail,
-           iterated_entries, &serial));
-       ck_assert_int_eq(-EAGAIN, vrps_get_deltas_from(0, &serial, &deltas));
+           iterated_entries, serial));
+       ck_assert_int_eq(-EAGAIN, vrps_get_deltas_from(0, serial, deltas));
 
        /* First validation: One tree, no deltas */
-       ck_assert_int_eq(0, vrps_update(&changed));
+       ck_assert_int_eq(0, vrps_update(changed));
        check_serial(0);
        check_base(0, iteration0_base);
-       check_deltas(0, 0, deltas_0to0);
+       check_deltas(0, 0, deltas_0to0, false);
 
        /* Second validation: One tree, added deltas */
-       ck_assert_int_eq(0, vrps_update(&changed));
+       ck_assert_int_eq(0, vrps_update(changed));
        check_serial(1);
        check_base(1, iteration1_base);
-       check_deltas(0, 1, deltas_0to1);
-       check_deltas(1, 1, deltas_1to1);
+       check_deltas(0, 1, deltas_0to1, false);
+       check_deltas(1, 1, deltas_1to1, false);
+}
+
+START_TEST(test_basic)
+{
+       struct deltas_db deltas;
+       serial_t serial;
+       bool changed;
+       bool iterated_entries[8];
+
+       create_deltas_0to1(&deltas, &serial, &changed, iterated_entries);
+
+       /* Third validation: One tree, removed deltas */
+       ck_assert_int_eq(0, vrps_update(&changed));
+       check_serial(2);
+       check_base(2, iteration2_base);
+       check_deltas(0, 2, deltas_0to2, false);
+       check_deltas(1, 2, deltas_1to2, false);
+       check_deltas(2, 2, deltas_2to2, false);
+
+       vrps_destroy();
+}
+END_TEST
+
+START_TEST(test_delta_forget)
+{
+       struct deltas_db deltas;
+       serial_t serial;
+       bool changed;
+       bool iterated_entries[8];
+
+       create_deltas_0to1(&deltas, &serial, &changed, iterated_entries);
+
+       /*
+        * Assume that the client(s) already have serial 1 (serial 2 will be
+        * created) so serial 0 isn't needed anymore.
+        */
+       current_min_serial = 1;
+
+       /* Third validation: One tree, removed deltas and delta 0 removed */
+       ck_assert_int_eq(0, vrps_update(&changed));
+       check_serial(2);
+       check_base(2, iteration2_base);
+       check_no_deltas(0, 2);
+       check_deltas(1, 2, deltas_1to2, false);
+       check_deltas(2, 2, deltas_2to2, false);
+
+       vrps_destroy();
+
+       /* Return to its initial value */
+       current_min_serial = 0;
+}
+END_TEST
+
+START_TEST(test_delta_ovrd)
+{
+       struct deltas_db deltas;
+       serial_t serial;
+       bool changed;
+       bool iterated_entries[8];
+
+       create_deltas_0to1(&deltas, &serial, &changed, iterated_entries);
 
        /* Third validation: One tree, removed deltas */
        ck_assert_int_eq(0, vrps_update(&changed));
        check_serial(2);
        check_base(2, iteration2_base);
-       check_deltas(0, 2, deltas_0to2);
-       check_deltas(1, 2, deltas_1to2);
-       check_deltas(2, 2, deltas_2to2);
+       check_deltas(0, 2, deltas_0to2, false);
+       check_deltas(1, 2, deltas_1to2, false);
+       check_deltas(2, 2, deltas_2to2, false);
+
+       /* Fourth validation with deltas that override each other */
+       ck_assert_int_eq(0, vrps_update(&changed));
+       check_serial(3);
+       check_base(3, iteration3_base);
+       check_deltas(0, 3, deltas_0to3_ovrd, false);
+       check_deltas(1, 3, deltas_1to3_ovrd, false);
+       check_deltas(2, 3, deltas_2to3_ovrd, false);
+       check_deltas(3, 3, deltas_3to3_ovrd, false);
+
+       /* Check "cleaned up" deltas */
+       check_deltas(0, 3, deltas_0to3_clean, true);
+       check_deltas(1, 3, deltas_1to3_clean, true);
+       check_deltas(2, 3, deltas_2to3_clean, true);
+       check_deltas(3, 3, deltas_3to3_clean, true);
 
        vrps_destroy();
+
+       /* Return to its initial value */
+       current_min_serial = 0;
 }
 END_TEST
 
@@ -230,6 +385,8 @@ Suite *pdu_suite(void)
 
        core = tcase_create("Core");
        tcase_add_test(core, test_basic);
+       tcase_add_test(core, test_delta_forget);
+       tcase_add_test(core, test_delta_ovrd);
 
        suite = suite_create("VRP Database");
        suite_add_tcase(suite, core);
index 0b40b1f6be5f0beefe744b6893da3aa9bdf7e918..0652e237af3802cb010311c16eddb7429bb1b629 100644 (file)
@@ -8,9 +8,6 @@
 #include "rtr/pdu_sender.h"
 #include "rtr/db/vrps.h"
 
-/* TODO (now) test the removal of deltas that cancel each other */
-/* TODO (now) test delta forgetting */
-
 /* Helper functions */
 
 struct expected_pdu {
@@ -93,8 +90,9 @@ init_serial_query(struct rtr_request *request, struct serial_query_pdu *query,
 /* Impersonator functions */
 
 serial_t
-clients_get_min_serial(void)
+clients_get_min_serial(serial_t *result)
 {
+       *result = 0;
        return 0;
 }
 
@@ -319,10 +317,36 @@ START_TEST(test_cache_has_no_data_available)
 }
 END_TEST
 
+START_TEST(test_bad_session_id)
+{
+       struct rtr_request request;
+       struct serial_query_pdu client_pdu;
+
+       pr_info("-- Bad Session ID--");
+
+       /* Prepare DB */
+       init_db_full();
+
+       /* From serial 0: Init client request */
+       init_serial_query(&request, &client_pdu, 0);
+       client_pdu.header.m.session_id++;
+
+       /* From serial 0: Define expected server response */
+       expected_pdu_add(PDU_TYPE_ERROR_REPORT);
+
+       /* From serial 0: Run and validate */
+       ck_assert_int_eq(-EINVAL, handle_serial_query_pdu(0, &request));
+       ck_assert_uint_eq(false, has_expected_pdus());
+
+       /* Clean up */
+       vrps_destroy();
+}
+END_TEST
+
 Suite *pdu_suite(void)
 {
        Suite *suite;
-       TCase *core;
+       TCase *core, *error;
 
        core = tcase_create("RFC6810-Defined Protocol Sequences");
        tcase_add_test(core, test_start_or_restart);
@@ -330,10 +354,12 @@ Suite *pdu_suite(void)
        tcase_add_test(core, test_no_incremental_update_available);
        tcase_add_test(core, test_cache_has_no_data_available);
 
-       /* TODO (now) add an unhappy path TCase. */
+       error = tcase_create("Unhappy path cases");
+       tcase_add_test(error, test_bad_session_id);
 
        suite = suite_create("PDU Handler");
        suite_add_tcase(suite, core);
+       suite_add_tcase(suite, error);
        return suite;
 }