]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Implement serial logic, prepare to calculate diff between serials
authorpcarana <pc.moreno2099@gmail.com>
Tue, 26 Feb 2019 22:45:18 +0000 (16:45 -0600)
committerpcarana <pc.moreno2099@gmail.com>
Tue, 26 Feb 2019 22:45:18 +0000 (16:45 -0600)
src/csv.c
src/rtr/pdu_handler.c
src/rtr/pdu_sender.c
src/rtr/pdu_sender.h
src/vrps.c
src/vrps.h

index 77faa3b12cfb98b1e8ee40ff5896af5b2fe2d857..b9275f8839568cef5dc342f9b8bab39c66f784da 100644 (file)
--- a/src/csv.c
+++ b/src/csv.c
@@ -165,7 +165,7 @@ add_vrp(char *line, struct delta *delta)
 
        error = delta_add_vrp(delta, vrp);
        if (error) {
-               vrp_destroy(&vrp);
+               vrp_destroy(vrp);
                goto error;
        }
 
index 7eaba7d3de51f728b9cc30e990cc1294dd052ab7..f34aa29bbbe9b7792d7e28c39de359944e17f014 100644 (file)
@@ -2,9 +2,11 @@
 
 #include <err.h>
 #include <errno.h>
+#include <stddef.h>
 
 #include "pdu.h"
 #include "pdu_sender.h"
+#include "vrps.h"
 
 static int warn_unexpected_pdu(char *);
 
@@ -22,54 +24,93 @@ handle_serial_notify_pdu(int fd, void *pdu)
        return warn_unexpected_pdu("Serial Notify");
 }
 
+static int
+send_commmon_exchange(struct sender_common *common)
+{
+       int error;
+
+       // Send Cache response PDU
+       error = send_cache_response_pdu(common);
+       if (error)
+               return error;
+
+       // Send Payload PDUs
+       error = send_payload_pdus(common);
+       if (error)
+               return error;
+
+       // Send End of data PDU
+       return send_end_of_data_pdu(common);
+}
+
 int
 handle_serial_query_pdu(int fd, void *pdu)
 {
-       struct reset_query_pdu *received = pdu;
-       u_int8_t version;
-
-       version = received->header.protocol_version;
-       /*
-        * TODO The Serial should be read to get updates, so
-        * more work needs to be done here.
-        */
-       return send_cache_reset_pdu(fd, version);
+       struct serial_query_pdu *received = pdu;
+       struct sender_common common;
+       int error, updates;
+       u_int32_t current_serial;
+
+       current_serial = last_serial_number();
+       /* TODO Handle sessions and its ID */
+       init_sender_common(&common, fd, received->header.protocol_version,
+           &received->header.session_id, &received->serial_number,
+           &current_serial);
+
+       updates = deltas_db_status(common.start_serial);
+       switch (updates) {
+       /* TODO Implement error */
+//     case NO_DATA_AVAILABLE:
+               /* https://tools.ietf.org/html/rfc8210#section-8.4 */
+//             return send_error_pdu;
+       case DIFF_UNDETERMINED:
+               /* https://tools.ietf.org/html/rfc8210#section-8.3 */
+               return send_cache_reset_pdu(&common);
+       case DIFF_AVAILABLE:
+               /* https://tools.ietf.org/html/rfc8210#section-8.2 */
+               return send_commmon_exchange(&common);
+       case NO_DIFF:
+               /* Typical exchange with no Payloads */
+               error = send_cache_response_pdu(&common);
+               if (error)
+                       return error;
+               return send_end_of_data_pdu(&common);
+       default:
+               error = -EINVAL;
+               err(error, "Reached 'unreachable' code");
+               return error;
+       }
 }
 
 int
 handle_reset_query_pdu(int fd, void *pdu)
 {
        struct reset_query_pdu *received = pdu;
+       struct sender_common common;
+       u_int32_t current_serial;
        u_int16_t session_id;
-       u_int8_t version;
-       int error;
-
-       /*
-        * FIXME Complete behaviour:
-        * - Do I have data?
-        *   + NO: Send error
-        *         https://tools.ietf.org/html/rfc8210#section-8.4
-        *   + YES: Send data (cache response -> payloads -> end of data)
-        *          https://tools.ietf.org/html/rfc8210#section-8.1
-        */
+       int error, updates;
 
-       /* FIXME Handle sessions and its ID */
+       current_serial = last_serial_number();
+       /* TODO Handle sessions and its ID */
        session_id = 1;
-       version = received->header.protocol_version;
-
-       // Send Cache response PDU
-       error = send_cache_response_pdu(fd, version, session_id);
-       if (error)
+       init_sender_common(&common, fd, received->header.protocol_version,
+           &session_id, NULL, &current_serial);
+
+       updates = deltas_db_status(common.start_serial);
+       switch (updates) {
+       /* TODO Implement error */
+//     case NO_DATA_AVAILABLE:
+               /* https://tools.ietf.org/html/rfc8210#section-8.4 */
+//             return send_error_pdu;
+       case DIFF_AVAILABLE:
+               /* https://tools.ietf.org/html/rfc8210#section-8.1 */
+               return send_commmon_exchange(&common);
+       default:
+               error = -EINVAL;
+               err(error, "Reached 'unreachable' code");
                return error;
-
-       // Send Payload PDUs
-       // TODO ..and handle Serial Number
-       error = send_payload_pdus(fd, version, 1);
-       if (error)
-               return error;
-
-       // Send End of data PDU
-       return send_end_of_data_pdu(fd, version, session_id);
+       }
 }
 
 int
@@ -105,6 +146,12 @@ handle_cache_reset_pdu(int fd, void *pdu)
 int
 handle_error_report_pdu(int fd, void *pdu)
 {
-       /* TODO */
-       return -EUNIMPLEMENTED;
+       struct error_report_pdu *received = pdu;
+       struct sender_common common;
+
+       init_sender_common(&common, fd, received->header.protocol_version,
+               NULL, NULL, NULL);
+
+       /* TODO complete handler */
+       return 0;
 }
index e302f64a5f0b79de3a88172e07321cbea1f1ab8b..b6e385af915ac54c071a2997237cacd1b49c96a5 100644 (file)
 #define IPV4_PREFIX_LENGTH 12
 #define IPV6_PREFIX_LENGTH 24
 
+void
+init_sender_common(struct sender_common *common, int fd, u_int8_t version,
+    u_int16_t *session_id, u_int32_t *start_serial, u_int32_t *end_serial)
+{
+       common->fd = fd;
+       common->version = version;
+       common->session_id = session_id == NULL ? 0 : session_id;
+       common->start_serial = start_serial;
+       common->end_serial = end_serial;
+}
 /*
  * Set all the header values, EXCEPT length field.
  */
@@ -79,46 +89,45 @@ send_response(int fd, char *data, size_t data_len)
 }
 
 int
-send_cache_reset_pdu(int fd, u_int8_t version)
+send_cache_reset_pdu(struct sender_common *common)
 {
        struct cache_reset_pdu pdu;
        char data[BUFFER_SIZE];
        size_t len;
 
        /* This PDU has only the header */
-       set_header_values(&pdu.header, version, CACHE_RESET_PDU_TYPE, 0);
+       set_header_values(&pdu.header, common->version, CACHE_RESET_PDU_TYPE, 0);
        pdu.header.length = HEADER_LENGTH;
 
        len = serialize_cache_reset_pdu(&pdu, data);
-       return send_response(fd, data, len);
+       return send_response(common->fd, data, len);
 }
 
 int
-send_cache_response_pdu(int fd, u_int8_t version, u_int16_t session_id)
+send_cache_response_pdu(struct sender_common *common)
 {
        struct cache_response_pdu pdu;
        char data[BUFFER_SIZE];
        size_t len;
 
        /* This PDU has only the header */
-       set_header_values(&pdu.header, version,
-           CACHE_RESPONSE_PDU_TYPE, session_id);
+       set_header_values(&pdu.header, common->version,
+           CACHE_RESPONSE_PDU_TYPE, *common->session_id);
        pdu.header.length = HEADER_LENGTH;
 
        len = serialize_cache_response_pdu(&pdu, data);
-       /* TODO wait for the ACK? */
-       return send_response(fd, data, len);
+
+       return send_response(common->fd, data, len);
 }
 
 static int
-send_ipv4_prefix_pdu(int fd, u_int8_t version, u_int32_t serial,
-    struct vrp *vrp)
+send_ipv4_prefix_pdu(struct sender_common *common, struct vrp *vrp)
 {
        struct ipv4_prefix_pdu pdu;
        char data[BUFFER_SIZE];
        size_t len;
 
-       set_header_values(&pdu.header, version, IPV4_PREFIX_PDU_TYPE, 0);
+       set_header_values(&pdu.header, common->version, IPV4_PREFIX_PDU_TYPE, 0);
 
        pdu.flags = vrp->flags;
        pdu.prefix_length = vrp->prefix_length;
@@ -129,19 +138,18 @@ send_ipv4_prefix_pdu(int fd, u_int8_t version, u_int32_t serial,
        pdu.header.length = length_ipvx_prefix_pdu(true);
 
        len = serialize_ipv4_prefix_pdu(&pdu, data);
-       /* TODO wait for the ACK? */
-       return send_response(fd, data, len);
+
+       return send_response(common->fd, data, len);
 }
 
 static int
-send_ipv6_prefix_pdu(int fd, u_int8_t version, u_int32_t serial,
-    struct vrp *vrp)
+send_ipv6_prefix_pdu(struct sender_common *common, struct vrp *vrp)
 {
        struct ipv6_prefix_pdu pdu;
        char data[BUFFER_SIZE];
        size_t len;
 
-       set_header_values(&pdu.header, version, IPV6_PREFIX_PDU_TYPE, 0);
+       set_header_values(&pdu.header, common->version, IPV6_PREFIX_PDU_TYPE, 0);
 
        pdu.flags = vrp->flags;
        pdu.prefix_length = vrp->prefix_length;
@@ -152,24 +160,27 @@ send_ipv6_prefix_pdu(int fd, u_int8_t version, u_int32_t serial,
        pdu.header.length = length_ipvx_prefix_pdu(false);
 
        len = serialize_ipv6_prefix_pdu(&pdu, data);
-       /* TODO wait for the ACK? */
-       return send_response(fd, data, len);
+
+       return send_response(common->fd, data, len);
 }
 
 int
-send_payload_pdus(int fd, u_int8_t version, u_int32_t serial)
+send_payload_pdus(struct sender_common *common)
 {
-       struct vrp **vrps, **ptr;
+       struct vrp *vrps, *ptr;
        unsigned int len, i;
        int error;
 
-       vrps = get_vrps_delta(serial, &len);
+       len = get_vrps_delta(common->start_serial, common->end_serial, &vrps);
+       if (len == 0)
+               return 0;
+
        ptr = vrps;
        for (i = 0; i < len; i++) {
-               if ((*ptr)->in_addr_len == INET_ADDRSTRLEN)
-                       error = send_ipv4_prefix_pdu(fd, version, serial, *ptr);
+               if (ptr->in_addr_len == INET_ADDRSTRLEN)
+                       error = send_ipv4_prefix_pdu(common, ptr);
                else
-                       error = send_ipv6_prefix_pdu(fd, version, serial, *ptr);
+                       error = send_ipv6_prefix_pdu(common, ptr);
 
                if (error)
                        return error;
@@ -180,15 +191,15 @@ send_payload_pdus(int fd, u_int8_t version, u_int32_t serial)
 }
 
 int
-send_end_of_data_pdu(int fd, u_int8_t version, u_int16_t session_id)
+send_end_of_data_pdu(struct sender_common *common)
 {
        struct end_of_data_pdu pdu;
        char data[BUFFER_SIZE];
        size_t len;
 
-       set_header_values(&pdu.header, version, END_OF_DATA_PDU_TYPE, session_id);
-       pdu.serial_number = last_serial_number();
-       if (version == RTR_V1) {
+       set_header_values(&pdu.header, common->version, END_OF_DATA_PDU_TYPE, *common->session_id);
+       pdu.serial_number = *common->end_serial;
+       if (common->version == RTR_V1) {
                pdu.refresh_interval = config_get_refresh_interval();
                pdu.retry_interval = config_get_retry_interval();
                pdu.expire_interval = config_get_expire_interval();
@@ -196,6 +207,6 @@ send_end_of_data_pdu(int fd, u_int8_t version, u_int16_t session_id)
        pdu.header.length = length_end_of_data_pdu(&pdu);
 
        len = serialize_end_of_data_pdu(&pdu, data);
-       /* TODO wait for the ACK? */
-       return send_response(fd, data, len);
+
+       return send_response(common->fd, data, len);
 }
index c49bcea9d09b03737cb8550d957b65901a12e7c4..d91bf40d351f7d8c29e9e3939fc2d63d9b01ef23 100644 (file)
@@ -3,11 +3,21 @@
 
 #include <sys/types.h>
 
+struct sender_common {
+       int fd;
+       u_int8_t version;
+       u_int16_t *session_id;
+       u_int32_t *start_serial;
+       u_int32_t *end_serial;
+};
 
-int send_cache_reset_pdu(int, u_int8_t);
-int send_cache_response_pdu(int, u_int8_t, u_int16_t);
-int send_payload_pdus(int, u_int8_t, u_int32_t);
-int send_end_of_data_pdu(int, u_int8_t, u_int16_t);
+void init_sender_common(struct sender_common *, int, u_int8_t, u_int16_t *,
+    u_int32_t *, u_int32_t *);
+
+int send_cache_reset_pdu(struct sender_common *);
+int send_cache_response_pdu(struct sender_common *);
+int send_payload_pdus(struct sender_common *);
+int send_end_of_data_pdu(struct sender_common *);
 
 
 #endif /* SRC_RTR_PDU_SENDER_H_ */
index 343e5e2a792fa0f547df6ba11a6e111428572f02..5ab42de21a436f91004bcf7ff2049188b42f3a91 100644 (file)
@@ -5,10 +5,17 @@
 #define FLAG_WITHDRAWAL                0
 #define FLAG_ANNOUNCEMENT      1
 
-ARRAY_LIST(delta, struct vrp *)
+ARRAY_LIST(vrps, struct vrp)
+
+struct delta {
+       u_int32_t serial;
+       struct vrps vrps;
+};
+
 ARRAY_LIST(deltasdb, struct delta)
 
 struct deltasdb db;
+u_int32_t current_serial;
 
 int
 deltas_db_init(void)
@@ -20,6 +27,7 @@ deltas_db_init(void)
                err(error, "Deltas DB couldn't be allocated");
                return error;
        }
+       current_serial = 0;
 
        return 0;
 }
@@ -33,7 +41,7 @@ create_delta(void)
        if (result == NULL)
                goto fail1;
 
-       if (delta_init(result) != 0)
+       if (vrps_init(&result->vrps) != 0)
                goto fail2;
 
        return result;
@@ -94,25 +102,26 @@ create_vrp6(u_int32_t asn, struct in6_addr ipv6_prefix, u_int8_t prefix_length,
 int
 deltas_db_add_delta(struct delta *delta)
 {
+       delta->serial = current_serial++;
        return deltasdb_add(&db, delta);
 }
 
 int
 delta_add_vrp(struct delta *delta, struct vrp *vrp)
 {
-       return delta_add(delta, &vrp);
+       return vrps_add(&delta->vrps, vrp);
 }
 
 void
-vrp_destroy(struct vrp **vrp)
+vrp_destroy(struct vrp *vrp)
 {
-       free(*vrp);
+       free(vrp);
 }
 
 void
 delta_destroy(struct delta *delta)
 {
-       delta_cleanup(delta, vrp_destroy);
+       vrps_cleanup(&delta->vrps, vrp_destroy);
        free(delta);
 }
 
@@ -122,21 +131,102 @@ deltas_db_destroy(void)
        deltasdb_cleanup(&db, delta_destroy);
 }
 
-struct vrp **
-get_vrps_delta(u_int32_t serial, unsigned int *len)
+static unsigned int
+get_delta_diff(struct delta *start_delta, struct delta *end_delta,
+    struct vrp **result)
+{
+       /* TODO Do some magic to get the diff */
+       *result = db.array[db.len - 1].vrps.array;
+       return db.array[db.len - 1].vrps.len;
+}
+
+/*
+ * Get a status to know the difference between the delta with serial SERIAL and
+ * the last delta at DB.
+ *
+ * If SERIAL is received as NULL, and there's data at DB then the status will
+ * be DIFF_AVAILABLE.
+ *
+ * The possible return values are:
+ *  NO_DATA_AVAILABLE -> There's no data at the DB
+ *  DIFF_UNDETERMINED -> The diff can't be determined
+ *  NO_DIFF -> There's no difference
+ *  DIFF_AVAILABLE -> There are differences between SERIAL and the last DB serial
+ */
+int
+deltas_db_status(u_int32_t *serial)
+{
+       struct delta *delta;
+
+       if (db.len == 0)
+               return NO_DATA_AVAILABLE;
+
+       // No serial to match, and there's data at DB
+       if (serial == NULL)
+               return DIFF_AVAILABLE;
+
+       /* Get the delta corresponding to the serial */
+       ARRAYLIST_FOREACH(&db, delta) {
+               if (delta->serial == *serial)
+                       break;
+       }
+
+       /* Reached end, diff can't be determined */
+       if (delta == NULL)
+               return DIFF_UNDETERMINED;
+
+       /* Is the last version? */
+       if (delta->serial == db.array[db.len-1].serial)
+               return NO_DIFF;
+
+       return DIFF_AVAILABLE;
+}
+
+/*
+ * Get the number of updates from serial START_SERIAL to END_SERIAL, set them
+ * at RESULT.
+ *
+ * Return 0 if no updates are available or couldn't be calculated with the
+ * received values.
+ */
+unsigned int
+get_vrps_delta(u_int32_t *start_serial, u_int32_t *end_serial,
+    struct vrp **result)
 {
-       /*
-        * TODO Return the VRPs according to delta
-        */
-       *len = db.array[0].len;
-       return db.array[0].array;
+       struct delta *delta0, *delta1;
+
+       /* No data */
+       if (db.len == 0)
+               return 0;
+
+       /* NULL start? Send the last version, there's no need to iterate DB */
+       if (start_serial == NULL) {
+               *result = db.array[db.len - 1].vrps.array;
+               return db.array[db.len - 1].vrps.len;
+               /* TODO Send all data as ANNOUNCEMENTS */
+       }
+
+       /* Apparently nothing to return */
+       if (*start_serial > *end_serial)
+               return 0;
+
+       /* Get the delta corresponding to the serials */
+       ARRAYLIST_FOREACH(&db, delta1) {
+               if (delta1->serial == *start_serial)
+                       delta0 = delta1;
+               if (delta1->serial == *end_serial)
+                       break;
+       }
+
+       /* Reached end or no delta0 found, diff can't be determined, send error */
+       if (delta1 == NULL || delta0 == NULL)
+               return 0;
+
+       return get_delta_diff(delta0, delta1, result);
 }
 
 u_int32_t
 last_serial_number(void)
 {
-       /*
-        * TODO Return the last serial number of the DB
-        */
-       return 1;
+       return current_serial;
 }
index a5a6e5f45f9045d03d8b76bbba501094544074dc..445ba62801c1f86a1eb6258dabeb9860abd6082d 100644 (file)
@@ -3,6 +3,11 @@
 
 #include <netinet/ip.h>
 
+#define NO_DATA_AVAILABLE      -2
+#define DIFF_UNDETERMINED      -1
+#define NO_DIFF                                0
+#define DIFF_AVAILABLE         1
+
 struct vrp {
        u_int32_t       asn;
        union {
@@ -22,12 +27,14 @@ int deltas_db_init(void);
 struct delta *create_delta(void);
 struct vrp *create_vrp4(u_int32_t, struct in_addr, u_int8_t, u_int8_t);
 struct vrp *create_vrp6(u_int32_t, struct in6_addr, u_int8_t, u_int8_t);
-struct vrp **get_vrps_delta(u_int32_t, unsigned int *);
 
 int delta_add_vrp(struct delta *, struct vrp *);
 int deltas_db_add_delta(struct delta *);
+int deltas_db_status(u_int32_t *);
+
+unsigned int get_vrps_delta(u_int32_t *, u_int32_t *, struct vrp **);
 
-void vrp_destroy(struct vrp **);
+void vrp_destroy(struct vrp *);
 void delta_destroy(struct delta *);
 void deltas_db_destroy(void);