]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Delete old RTR serials over time
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Thu, 28 May 2026 18:31:15 +0000 (12:31 -0600)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Thu, 28 May 2026 18:31:15 +0000 (12:31 -0600)
Was missing from the previous refactor.

12 files changed:
docs/usage.md
src/config.c
src/file.c
src/rtr/db/db_table.c
src/rtr/meta.c
src/rtr/meta.h
src/rtr/pdu_handler.c
src/rtr/pdu_sender.c
src/rtr/rtr.c
src/types/serial.c
src/types/serial.h
test/rtr/db/db_table_test.c

index 842234720408214a8438e97e112c63dfe0e8e3a1..9899ce74ced834be1815f5db3ca0003c17823d03 100644 (file)
@@ -456,12 +456,14 @@ See [RFC 8210, section 6](https://tools.ietf.org/html/rfc8210#section-6).
 
 - **Type:** Integer
 - **Availability:** `argv` and JSON
-- **Default:** 2
-- **Range:** [0, [`UINT_MAX`](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)]
+- **Default:** 21600 (6 hours)
+- **Range:** [1, [`UINT_MAX`](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)]
+
+RTR delta lifetime, measured in validation cycles.
 
-When routers first connect to Fort, they request a _snapshot_ of the validation results. (ROAs and Router Keys.) Because they need to keep their validated objects updated, and snapshots tend to be relatively large amounts of information, they request _deltas_ afterwards over configurable intervals. ("Deltas" being the differences between snapshots.)
+When routers first connect to Fort, they request a _snapshot_ of the validation results. (ROAs, Router Keys and ASPAs.) Because they need to keep their validated objects updated, and snapshots tend to be relatively large amounts of information, they request _deltas_ afterwards over configurable intervals. ("Deltas" being the differences between snapshots.)
 
-During each validation cycle, Fort generates a new snapshot, as well as the deltas needed to build the new snapshot from the previous one. These are all stored in RAM. `--server.deltas.lifetime` is the number of iterations a set of deltas will be kept before being deallocated. (Recall that every iteration lasts [`--server.interval.validation`](#--serverintervalvalidation) seconds, plus however long the validation takes.)
+Fort stores the information necessary to serve these deltas in the cache. `--server.deltas.lifetime` is the number of validation cycles a delta will be preserved before being expired.
 
 If a router lags behind, to the point Fort has already deleted the deltas it needs to update the router's snapshot, Fort will have to fall back to fetch the entire latest snapshot instead.
 
index 83be8f995b7bb6b37e2c91e3d4430e6107ed56f5..b36c71d0cdb183fbc1084338007e2cc9bde45bf1 100644 (file)
@@ -370,7 +370,11 @@ static const struct option_field options[] = {
                 * minute.
                 */
                .min = 60,
-               .max = UINT_MAX,
+               /*
+                * 7 days.
+                * Must not overflow when multiplied by deltas.lifetime.
+                */
+               .max = 604800,
        }, {
                .id = 5004,
                .name = "server.interval.refresh",
@@ -432,6 +436,7 @@ static const struct option_field options[] = {
                /*
                 * It's a serial, which means the technical maximum is about
                 * 2^31 - 1. But that's too much.
+                * Must not overflow when multiplied by interval.validation.
                 */
                .max = 1000,
        },
@@ -1012,7 +1017,7 @@ set_default_values(void)
        rpki_config.server.interval.refresh = 3600;
        rpki_config.server.interval.retry = 600;
        rpki_config.server.interval.expire = 7200;
-       rpki_config.server.deltas_lifetime = 2;
+       rpki_config.server.deltas_lifetime = 6;
 
        rpki_config.prometheus.port = 0;
 
index 58f59edb2c86652e336c3ca0e6cf1abc09efc60b..dbcccb1d21869d00fb7d317a53af24c42d83e02a 100644 (file)
@@ -127,7 +127,7 @@ file_exists(char const *path)
 static int
 rm(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
 {
-       pr_op_debug("Deleting %s.", fpath);
+       pr_op_debug("Deleting %s", fpath);
        return (remove(fpath) != 0) ? errno : 0;
 }
 
@@ -135,6 +135,7 @@ rm(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
 int
 file_rm_rf(char const *path)
 {
+       pr_op_debug("rm -rf %s", path);
        /* TODO (performance) optimize that 32 */
        return nftw(path, rm, 32, FTW_DEPTH | FTW_PHYS);
 }
index 782f05f044b5021f3e818afbf078928e1021ae37..5b51983a52573fb1ef1da369e33acb1459632d2f 100644 (file)
@@ -36,7 +36,7 @@ struct db_table {
        unsigned int total_roas_v4;
        unsigned int total_roas_v6;
 
-       struct rtr_metadata rtr;
+       struct rtr_index rtr;
 };
 
 struct db_table *
@@ -71,6 +71,8 @@ db_table_destroy(struct db_table *table)
                free(aspa);
        }
 
+       rtridx_cleanup(&table->rtr);
+
        free(table);
 }
 
@@ -361,7 +363,7 @@ write_addr(FILE *file, struct vrp *vrp)
 }
 
 static int
-cache_vrps(struct db_table *table)
+cache_vrps(struct db_table *table, serial_t serial)
 {
        FILE *f4 = NULL;
        FILE *f6 = NULL;
@@ -370,10 +372,10 @@ cache_vrps(struct db_table *table)
        struct vrp *vrp;
        int err;
 
-       err = rtr_open_file(table->rtr.serial, "vrp4", "w", &f4);
+       err = rtr_open_file(serial, "vrp4", "w", &f4);
        if (err)
                return err;
-       err = rtr_open_file(table->rtr.serial, "vrp6", "w", &f6);
+       err = rtr_open_file(serial, "vrp6", "w", &f6);
        if (err)
                goto end;
 
@@ -402,13 +404,13 @@ end:      if (f4) fclose(f4);
 }
 
 static int
-cache_rks(struct db_table *table)
+cache_rks(struct db_table *table, serial_t serial)
 {
        FILE *file = NULL;
        struct hashable_key *rk, *tmpr;
        int err;
 
-       err = rtr_open_file(table->rtr.serial, "rk", "w", &file);
+       err = rtr_open_file(serial, "rk", "w", &file);
        if (err)
                return err;
 
@@ -426,14 +428,14 @@ cache_rks(struct db_table *table)
 }
 
 static int
-cache_aspas(struct db_table *table)
+cache_aspas(struct db_table *table, serial_t serial)
 {
        FILE *file = NULL;
        struct hashable_aspa *aspa, *tmpa;
        array_index i;
        int err;
 
-       err = rtr_open_file(table->rtr.serial, "aspa", "w", &file);
+       err = rtr_open_file(serial, "aspa", "w", &file);
        if (err)
                return err;
 
@@ -457,7 +459,7 @@ cache_metadata(struct db_table *table)
        char *dir;
        int error;
 
-       error = rtr_save_metadata(&table->rtr);
+       error = rtridx_save(&table->rtr);
        if (error) {
                pr_op_err("Could not save RTR metadata; RTR can no longer be served.");
                dir = rtr_filename(NULL, NULL);
@@ -468,117 +470,52 @@ cache_metadata(struct db_table *table)
        return error;
 }
 
-static bool
-is_number(char const *str)
-{
-       if (*str == 0)
-               return false;
-
-       for (; *str != 0; str++)
-               if (*str < '0' || '9' < *str)
-                       return false;
-
-       return true;
-}
-
-static void
-delete_old_serials(serial_t current)
-{
-       char *path;
-       serial_t lowest;
-       DIR *dir;
-       struct dirent *file;
-       unsigned long serial;
-       int ret;
-
-       lowest = current - ((serial_t)config_get_deltas_lifetime());
-
-       path = rtr_filename(NULL, NULL);
-       dir = opendir(path);
-       free(path);
-       if (!dir) {
-               if (errno != ENOENT)
-                       pr_op_warn("Cannot clean rtr directory: %s",
-                           strerror(errno));
-               return;
-       }
-
-       FOREACH_DIR_FILE(dir, file) {
-               if (!is_number(file->d_name))
-                       continue;
-
-               errno = 0;
-               serial = strtoul(file->d_name, NULL, 10);
-               if (errno) {
-                       pr_op_warn("Cannot delete rtr/%s: %s",
-                           file->d_name, strerror(errno));
-                       continue;
-               }
-               if (serial > UINT32_MAX) {
-                       pr_op_warn("Cannot delete rtr/%s: Serial too big",
-                           file->d_name);
-                       continue;
-               }
-
-               if (!serial_lt(serial, lowest))
-                       continue;
-
-               path = rtr_filename2(serial, NULL);
-               ret = file_rm_rf(path);
-               free(path);
-               if (ret < 0)
-                       pr_op_warn("Cannot delete rtr/%s: nftw returned %d",
-                           file->d_name, ret);
-               else if (ret)
-                       pr_op_warn("Cannot delete rtr/%s: %s",
-                           file->d_name, strerror(ret));
-       }
-       if (errno)
-               pr_op_warn("Cleanup rtr directory traversal interrupted: %s",
-                   strerror(errno));
-
-       closedir(dir);
-}
-
 int
 db_table_cache(struct db_table *table)
 {
        char *path;
+       serial_t serial;
        int ret;
 
-       if (rtr_load_metadata(&table->rtr) != 0)
-               rtr_new_metadata(&table->rtr);
-       table->rtr.serial++;
+       ret = rtridx_load(&table->rtr, true);
+       if (ret == ENOENT)
+               rtridx_init(&table->rtr);
+       else if (ret) {
+               pr_op_err("Cannot access RTR index file: %s", strerror(ret));
+               return ret;
+       }
+
+       serial = rtridx_add_serial(&table->rtr);
 
-       path = rtr_filename(NULL, NULL);
+       path = rtr_filename(NULL, NULL); /* cache/rtr */
        ret = mkdir_f(path);
        free(path);
        if (ret)
                return ret;
 
-       path = rtr_filename2(table->rtr.serial, NULL);
+       path = rtr_filename2(serial, NULL); /* cache/rtr/1234 */
        ret = mkdir_f(path);
        free(path);
        if (ret)
                return ret;
 
-       ret = cache_vrps(table);
+       ret = cache_vrps(table, serial);
        if (ret)
                goto fail;
-       ret = cache_rks(table);
+       ret = cache_rks(table, serial);
        if (ret)
                goto fail;
-       ret = cache_aspas(table);
+       ret = cache_aspas(table, serial);
        if (ret)
                goto fail;
        ret = cache_metadata(table);
        if (ret)
                goto fail;
-       delete_old_serials(table->rtr.serial);
+       rtridx_clean(&table->rtr);
 
        return 0;
 
-fail:  path = rtr_filename2(table->rtr.serial, NULL);
+fail:  path = rtr_filename2(serial, NULL);
        file_rm_rf(path);
        free(path);
        return ret;
@@ -670,7 +607,7 @@ db_table_session(struct db_table *table)
 serial_t
 db_table_serial(struct db_table *table)
 {
-       return table ? table->rtr.serial : 0;
+       return (table && table->rtr.serials) ? table->rtr.serials->serial : 0;
 }
 
 void
index 6e7d8115429570692f394cf45e85f337673c390f..d26d89894c7d45b8eedd6f082ee1466513b41430 100644 (file)
@@ -8,6 +8,7 @@
 #include "alloc.h"
 #include "common.h"
 #include "config.h"
+#include "data_structure/common.h"
 #include "log.h"
 #include "file.h"
 
@@ -78,69 +79,372 @@ rtr_filename2(serial_t serial, char const *b)
 }
 
 void
-rtr_new_metadata(struct rtr_metadata *rtr)
+rtridx_init(struct rtr_index *idx)
 {
-       time_t now = 0x1234u;
-       get_current_time(&now);
-       rtr->session = now & 0xFFFFu;
-       rtr->serial = 0;
+       time_t now;
+
+       now = time(NULL);
+       if (now == (time_t)-1)
+               pr_crit("time(NULL) returned (time_t) -1.");
+
+       idx->session = now & 0xFFFF;
+       idx->serials = NULL;
 }
 
 int
-rtr_save_metadata(struct rtr_metadata *rtr)
+rtridx_save(struct rtr_index *idx)
 {
-       char *filepath;
+       char *path;
        FILE *file;
-       int error = 0;
+       struct rtr_serial *srl;
+       int error;
 
-       filepath = rtr_filename("metadata", NULL);
+       path = rtr_filename("index", NULL);
 
-       file = fopen(filepath, "w");
+       file = fopen(path, "w");
        if (!file) {
                error = errno;
                pr_op_err("Cannot open '%s' for writing: %s",
-                   filepath, strerror(error));
-               free(filepath);
+                   path, strerror(error));
+               free(path);
                return error;
        }
 
-       free(filepath);
+       free(path);
+
+       if (fprintf(file, "session:%u\n", idx->session) < 0) {
+               error = pr_op_err("fprintf(session) failed.");
+               goto end;
+       }
 
-       if (fprintf(file, "session:%u serial:%u", rtr->session, rtr->serial) < 0)
-               error = pr_op_err("fprintf(serial) failed.");
+       for (srl = idx->serials; srl; srl = srl->next) {
+               if (fprintf(file, "serial:%u date:%04d-%02d-%02dT%02d:%02d:%02dZ\n",
+                   srl->serial, srl->date.tm_year + 1900, srl->date.tm_mon + 1,
+                   srl->date.tm_mday, srl->date.tm_hour, srl->date.tm_min,
+                   srl->date.tm_sec) < 0) {
+                       error = pr_op_err("fprintf(serial) failed.");
+                       goto end;
+               }
+       }
 
-       fclose(file);
+       error = 0;
+
+end:   fclose(file);
        return error;
 }
 
+/*
+ * If @all is true, loads all the serials from the index.
+ * Otherwise loads only the most recent one.
+ */
 int
-rtr_load_metadata(struct rtr_metadata *rtr)
+rtridx_load(struct rtr_index *idx, bool all)
 {
        char *filepath;
        FILE *file;
-       unsigned int session;
-       unsigned int serial;
-       int error = 0;
+       char buf[64];
+       unsigned int se;
+       struct rtr_serial *srl, *prev;
+       int error;
+
+       idx->serials = NULL;
 
-       filepath = rtr_filename("metadata", NULL);
+       filepath = rtr_filename("index", NULL); /* cache/rtr/index */
 
        file = fopen(filepath, "r");
        if (!file) {
+               error = errno;
+               if (error != ENOENT)
+                       pr_op_warn("Cannot open RTR index: %s", strerror(error));
                free(filepath);
-               return errno;
+               return error;
        }
 
        free(filepath);
 
-       if (fscanf(file, "session:%u serial:%u", &session, &serial) >= 2) {
-               rtr->session = session;
-               rtr->serial = serial;
-       } else {
-               error = EINVAL;
+       if (!fgets(buf, sizeof(buf), file)) {
+               pr_op_debug("RTR index seems empty.");
+               goto fail;
+       }
+       if (sscanf(buf, "session:%u", &se) < 1 || se > UINT16_MAX) {
+               pr_op_debug("First line of RTR index is not a session.");
+               goto fail;
+       }
+
+       idx->session = se;
+       prev = NULL;
+
+       while (fgets(buf, sizeof(buf), file) != NULL) {
+               srl = pzalloc(sizeof(struct rtr_serial));
+
+               if (sscanf(buf, "serial:%u date:%d-%d-%dT%d:%d:%dZ",
+                   &se, &srl->date.tm_year, &srl->date.tm_mon,
+                   &srl->date.tm_mday, &srl->date.tm_hour, &srl->date.tm_min,
+                   &srl->date.tm_sec) < 1 || se > UINT32_MAX) {
+                       pr_op_debug("Malformed serial in RTR index.");
+                       goto fail;
+               }
+               srl->serial = se;
+
+               if (idx->serials) {
+                       if (serial_le(idx->serials->serial, srl->serial)) {
+                               pr_op_debug("RTR index serials are not sorted.");
+                               goto fail;
+                       }
+               }
+
+               srl->date.tm_year -= 1900;
+               srl->date.tm_mon -= 1;
+               if (prev)
+                       prev->next = srl;
+               else
+                       idx->serials = srl;
+               prev = srl;
+
+               if (!all)
+                       break;
        }
 
        fclose(file);
-       return error;
+       return 0;
+
+fail:  fclose(file);
+       rtridx_cleanup(idx);
+       return ENOENT;
+}
+
+serial_t
+rtridx_add_serial(struct rtr_index *idx)
+{
+       struct rtr_serial *srl;
+       time_t now;
+
+       srl = pmalloc(sizeof(struct rtr_serial));
+
+       srl->serial = idx->serials ? (idx->serials->serial + 1) : 1;
+
+       now = time(NULL);
+       if (now == (time_t)-1)
+               pr_crit("time(NULL) returned (time_t) -1.");
+       if (gmtime_r(&now, &srl->date) == NULL)
+               pr_crit("gmtime_r(now) failed: %s", strerror(errno));
+
+       srl->next = idx->serials;
+       idx->serials = srl;
+
+       return srl->serial;
+}
+
+void
+rtridx_cleanup(struct rtr_index *idx)
+{
+       struct rtr_serial *srl;
+
+       while (idx->serials) {
+               srl = idx->serials;
+               idx->serials = srl->next;
+               free(srl);
+       }
+}
+
+void
+rtridx_print(struct rtr_index *idx)
+{
+       struct rtr_serial *srl;
+
+       printf("==== RTR index ====\n");
+
+       if (!idx) {
+               printf("<Empty>\n");
+               return;
+       }
+
+       printf("session:%u\n", idx->session);
+       printf("serials:\n");
+
+       for (srl = idx->serials; srl; srl = srl->next)
+               printf("  serial:%u date:%04d-%02d-%02dT%02d:%02d:%02dZ\n",
+                   srl->serial,
+                   srl->date.tm_year + 1900, srl->date.tm_mon + 1, srl->date.tm_mday,
+                   srl->date.tm_hour, srl->date.tm_min + 1, srl->date.tm_sec);
+}
+
+static bool
+is_number(char const *str)
+{
+       if (*str == 0)
+               return false;
+
+       for (; *str != 0; str++)
+               if (*str < '0' || '9' < *str)
+                       return false;
+
+       return true;
+}
+
+static void
+rm_rf(char *path)
+{
+       int error;
+
+       error = file_rm_rf(path);
+       if (error < 0)
+               pr_op_warn("Cannot delete %s: nftw returned %d", path, error);
+       else if (error)
+               pr_op_warn("Cannot delete %s: %s", path, strerror(error));
+
+       free(path);
+}
+
+static void
+delete_unindexed_serials(serial_t min, serial_t max)
+{
+       char *path;
+       DIR *dir;
+       struct dirent *file;
+       serial_t serial;
+
+       path = rtr_filename(NULL, NULL);
+       dir = opendir(path);
+       free(path);
+       if (!dir) {
+               if (errno != ENOENT)
+                       pr_op_warn("Cannot clean rtr directory: %s",
+                           strerror(errno));
+               return;
+       }
+
+       FOREACH_DIR_FILE(dir, file) {
+               if (S_ISDOTS(file) || strcmp(file->d_name, "index") == 0)
+                       continue;
+               if (!is_number(file->d_name))
+                       goto rm;
+
+               errno = 0;
+               serial = strtoul(file->d_name, NULL, 10);
+               if (errno || serial > UINT32_MAX)
+                       goto rm;
+
+               if (serial_le(min, serial) && serial_le(serial, max))
+                       continue;
+
+rm:            pr_op_warn("Deleting stray filesystem entry rtr/%s", file->d_name);
+               rm_rf(rtr_filename(file->d_name, NULL));
+       }
+       if (errno)
+               pr_op_warn("Cleanup rtr directory traversal interrupted: %s",
+                   strerror(errno));
+
+       closedir(dir);
+}
+
+/*
+ * Cleans cache/rtr.
+ * This means dropping serials that exceed the threshold
+ * (config_get_deltas_lifetime()) and unknown files or directories
+ * directly in cache/rtr.
+ */
+void
+rtridx_clean(struct rtr_index *idx)
+{
+       struct rtr_serial *srl, **prev;
+       serial_t min, max;
+
+       max = idx->serials[0].serial;
+       min = max - config_get_deltas_lifetime();
+
+       for (srl = idx->serials, prev = &idx->serials; srl; srl = *prev) {
+               if (serial_lt(srl->serial, min) || serial_lt(max, srl->serial)) {
+                       pr_op_debug("Dropping serial by FIFO: %u", srl->serial);
+                       rm_rf(rtr_filename2(srl->serial, NULL));
+                       *prev = srl->next;
+                       free(srl);
+               } else {
+                       prev = &srl->next;
+               }
+       }
+
+       if (!idx->serials) {
+               /* The session died; we'll create a new one later. */
+               pr_op_debug("All serials expired; clearing RTR cache.");
+               rm_rf(rtr_filename(NULL, NULL));
+               return;
+       }
+
+       rtridx_save(idx);
+
+       /* Clean up unindexed serials for paranoia */
+       delete_unindexed_serials(min, max);
+}
+
+static bool
+too_old(struct rtr_serial *srl, time_t now)
+{
+       time_t serial_date;
+       double diff;
+       unsigned int lifetime;
+
+       serial_date = timegm(&srl->date);
+       if (serial_date == (time_t)-1)
+               return true; /* Dunno; delete it */
+
+       diff = difftime(serial_date, now);
+       if (diff > 0)
+               return true; /* Dunno; delete it */
+
+       /*
+        * This is an estimate. In reality, I'd like deltas_lifetime to be the
+        * timestamp, but I can't because of historical reasons, and also
+        * because it's a lot easier to test as a cycle count.
+        */
+       lifetime = config_get_deltas_lifetime() * config_get_validation_interval();
+
+       return (-diff) > lifetime;
+}
+
+/* Deletes serials that are too old, based on time. */
+void
+rtridx_expire(void)
+{
+       time_t now;
+       struct rtr_index idx;
+       struct rtr_serial *srl, **prev;
+       int error;
+
+       now = time(NULL);
+       if (now == (time_t)-1) {
+               pr_op_warn("Can't ditch old RTR: time() returned -1.");
+               return;
+       }
+
+       error = rtridx_load(&idx, true);
+       if (error == ENOENT)
+               return;
+       if (error) {
+               pr_op_warn("Can't ditch old RTR: %s", strerror(error));
+               return;
+       }
+
+       for (srl = idx.serials, prev = &idx.serials; srl; srl = *prev) {
+               if (too_old(srl, now)) {
+                       pr_op_debug("Dropping expired serial: %u", srl->serial);
+                       rm_rf(rtr_filename2(srl->serial, NULL));
+                       *prev = srl->next;
+                       free(srl);
+               } else {
+                       prev = &srl->next;
+               }
+       }
+
+       if (!idx.serials) {
+               /* The session died; we'll create a new one later. */
+               pr_op_debug("All serials expired; clearing RTR cache.");
+               rm_rf(rtr_filename(NULL, NULL));
+               goto end;
+       }
+
+       rtridx_save(&idx);
+end:   rtridx_cleanup(&idx);
 }
 
 int
index 67af12af452956d9991f43fabe42288562137710..738221485bf353e9f998c66b22c385d4aebd2d6a 100644 (file)
@@ -2,6 +2,8 @@
 #define SRC_RTR_META_H_
 
 #include <stdio.h>
+#include <time.h>
+#include <sys/queue.h>
 #include "types/serial.h"
 
 struct rtr_metadata {
@@ -21,12 +23,35 @@ struct rtr_metadata {
        serial_t serial;
 };
 
+struct rtr_serial {
+       serial_t serial;
+       struct tm date;
+       struct rtr_serial *next;
+};
+
+struct rtr_index {
+       uint16_t session;
+       /*
+        * Linked list; sorted from newest to oldest.
+        *
+        * Can't use SLIST because clean() and expire() want safe traversal
+        * with cursor removals.
+        */
+       struct rtr_serial *serials;
+};
+
 char *rtr_filename(char const *, char const *);
 char *rtr_filename2(serial_t, char const *);
 
-void rtr_new_metadata(struct rtr_metadata *);
-int rtr_save_metadata(struct rtr_metadata *);
-int rtr_load_metadata(struct rtr_metadata *);
+void rtridx_init(struct rtr_index *);
+int rtridx_save(struct rtr_index *);
+int rtridx_load(struct rtr_index *, bool);
+serial_t rtridx_add_serial(struct rtr_index *);
+void rtridx_cleanup(struct rtr_index *);
+void rtridx_print(struct rtr_index *);
+
+void rtridx_clean(struct rtr_index *);
+void rtridx_expire(void);
 
 int rtr_serial_stat(serial_t serial);
 
index 98f63eceafdb289abfae36a8fb9bf059537b7dbb..a02b077a3e74a5f79a30515d4a8f0932f202dc5b 100644 (file)
@@ -229,6 +229,27 @@ send_aspas(int fd, uint8_t ver, serial_t serial)
        return error;
 }
 
+static int
+load_rtr_metadata(struct rtr_metadata *rtr)
+{
+       struct rtr_index idx;
+       int error;
+
+       error = rtridx_load(&idx, false);
+       if (error)
+               return error;
+       if (idx.serials == NULL) {
+               error = ENOENT;
+               goto end;
+       }
+
+       rtr->session = idx.session;
+       rtr->serial = idx.serials->serial;
+
+end:   rtridx_cleanup(&idx);
+       return error;
+}
+
 int
 handle_reset_query_pdu(struct rtr_request *request)
 {
@@ -242,7 +263,7 @@ handle_reset_query_pdu(struct rtr_request *request)
        stream.fd = request->fd;
        stream.ver = request->pdu.rtr_version;
 
-       error = rtr_load_metadata(&rtr);
+       error = load_rtr_metadata(&rtr);
        switch (error) {
        case 0:
                break;
@@ -493,7 +514,7 @@ handle_serial_query_pdu(struct rtr_request *request)
        stream.fd = request->fd;
        stream.ver = request->pdu.rtr_version;
 
-       error = rtr_load_metadata(&rtr);
+       error = load_rtr_metadata(&rtr);
        switch (error) {
        case 0:      break;
        case ENOENT: return err_pdu_send_no_data_available(stream.fd, stream.ver);
@@ -520,6 +541,8 @@ handle_serial_query_pdu(struct rtr_request *request)
        default:     goto internal_error;
        }
 
+       pr_op_debug("Sending RTR delta: %u-%u", oserial, nserial);
+
        error = send_cache_response_pdu(stream.fd, stream.ver, rtr.session);
        if (error)
                return error;
index 1d3ac7716bf201f5e948d8a3d7d805d734469249..baf7d610fb2f7c71e285178eeb97fa9aa5d9eb35 100644 (file)
@@ -92,6 +92,8 @@ send_serial_notify_pdu(int fd, uint8_t version, struct rtr_metadata *meta)
        unsigned char data[RTRPDU_SERIAL_NOTIFY_LEN];
        unsigned char *buf;
 
+       pr_op_debug("Sending Serial Notify PDU.");
+
        buf = serialize_hdr(data, version, type, meta->session, len);
        buf = write_uint32(buf, meta->serial);
 
@@ -105,8 +107,8 @@ send_cache_reset_pdu(int fd, uint8_t version)
        static const uint32_t len = RTRPDU_CACHE_RESET_LEN;
        unsigned char data[RTRPDU_CACHE_RESET_LEN];
 
+       pr_op_debug("Sending Cache Reset PDU.");
        serialize_hdr(data, version, type, 0, len);
-
        return send_response(fd, type, data, len);
 }
 
@@ -117,8 +119,8 @@ send_cache_response_pdu(int fd, uint8_t version, uint16_t session)
        static const uint32_t len = RTRPDU_CACHE_RESPONSE_LEN;
        unsigned char data[RTRPDU_CACHE_RESPONSE_LEN];
 
+       pr_op_debug("Sending Cache Response PDU.");
        serialize_hdr(data, version, type, session, len);
-
        return send_response(fd, type, data, len);
 }
 
@@ -165,6 +167,8 @@ send_ipv6_prefix_pdu(int fd, uint8_t version, struct vrp const *vrp,
 int
 send_prefix_pdu(int fd, uint8_t version, struct vrp const *vrp, uint8_t flags)
 {
+       pr_op_debug("Sending Prefix PDU.");
+
        switch (vrp->addr_fam) {
        case AF_INET:
                return send_ipv4_prefix_pdu(fd, version, vrp, flags);
@@ -187,6 +191,8 @@ send_router_key_pdu(int fd, uint8_t version,
        if (version < RTR_V1)
                return 0;
 
+       pr_op_debug("Sending RK PDU.");
+
        buf = serialize_hdr(data, version, type, flags << 8, len);
        memcpy(buf, router_key->ski, sizeof(router_key->ski));
        buf += sizeof(router_key->ski);
@@ -209,6 +215,8 @@ send_aspa_announce_pdu(int fd, uint8_t version, struct aspa const *aspa)
        if (version < RTR_V2)
                return 0;
 
+       pr_op_debug("Sending ASPA announcement PDU.");
+
        bufsize = 12 + 4 * aspa->providers.count;
        if (bufsize > 1024)
                bufsize = 1024;
@@ -246,6 +254,8 @@ send_aspa_withdraw_pdu(int fd, uint8_t version, uint32_t customer)
        unsigned char data[12];
        unsigned char *buf;
 
+       pr_op_debug("Sending ASPA withdraw PDU.");
+
        buf = serialize_hdr(data, version, type, FLAG_WITHDRAWAL << 8, 12);
        write_uint32(buf, customer);
 
@@ -264,6 +274,8 @@ send_end_of_data_pdu(int fd, uint8_t version, uint16_t session, serial_t serial)
        unsigned char *buf;
        uint32_t len;
 
+       pr_op_debug("Sending End of Data PDU.");
+
        switch (version) {
        case RTR_V0:
                len = RTRPDU_END_OF_DATA_V0_LEN;
@@ -314,6 +326,8 @@ send_error_report_pdu(int fd, uint8_t version, uint16_t code,
        size_t len;
        int error;
 
+       pr_op_debug("Sending error PDU: %s", message);
+
        error_pdu_len = compute_error_pdu_len(request);
        error_msg_len = (message != NULL) ? strlen(message) : 0;
        len = rtrpdu_error_report_len(error_pdu_len, error_msg_len);
index e3fedaedb639b3cae746b669a35659e408868347..2e7d4da79a5e258196b09474ee9f9c2075714f55 100644 (file)
@@ -682,6 +682,8 @@ rtr_start(void)
 {
        int error;
 
+       rtridx_expire();
+
        server_arraylist_init(&servers);
        client_arraylist_init(&clients);
 
index 9fbe6558682e5c8df0e409783e1f4bff65d1aea8..ad80da1c42cc7f15e4e7ee8d83c29a4d9b18b4ae 100644 (file)
@@ -12,3 +12,9 @@ serial_lt(serial_t s1, serial_t s2)
        return ((s1 < s2) && ((s2 - s1) < 0x80000000u)) ||
               ((s1 > s2) && ((s1 - s2) > 0x80000000u));
 }
+
+bool
+serial_le(serial_t s1, serial_t s2)
+{
+       return (s1 == s2) ? true : serial_lt(s1, s2);
+}
index a9b1683d455979aeae360ddfede4fffe3198ed32..72af8bfc59367ba274ade6d1ec5544987846dcff 100644 (file)
@@ -7,5 +7,6 @@
 typedef uint32_t serial_t;
 
 bool serial_lt(serial_t s1, serial_t s2);
+bool serial_le(serial_t s1, serial_t s2);
 
 #endif /* SRC_TYPES_SERIAL_H_ */
index 3bcd93886d63d7b36e80b7719babecfc112b342f..31c6a9b1f0202ab1f21e5bb5a1c91d22bc140d4e 100644 (file)
@@ -23,9 +23,9 @@ static unsigned int total_found;
 __MOCK_ABORT(config_get_deltas_lifetime, unsigned int, 0, void)
 __MOCK_ABORT(config_get_local_repository, char const *, "tmp/dbt", void)
 MOCK_UINT(config_get_max_aspa_providers, 10, void)
-MOCK_ABORT_VOID(rtr_new_metadata, struct rtr_metadata *m)
-MOCK_ABORT_INT(rtr_save_metadata, struct rtr_metadata *m)
-MOCK_ABORT_INT(rtr_load_metadata, struct rtr_metadata *m)
+MOCK_ABORT_VOID(rtridx_init, struct rtr_index *i)
+MOCK_ABORT_INT(rtridx_save, struct rtr_index *i)
+MOCK_ABORT_INT(rtridx_load, struct rtr_index *i, bool b)
 MOCK_ABORT_INT(rtr_open_file, serial_t serial, char const *basename,
     char const *mode, FILE **result)
 __MOCK_ABORT(rtr_filename, char *, NULL, char const *a, char const *b)