fort_SOURCES += crypto/base64.h crypto/base64.c
fort_SOURCES += crypto/hash.h crypto/hash.c
-fort_SOURCES += data_structure/circular_indexer.h
-fort_SOURCES += data_structure/circular_indexer.c
+fort_SOURCES += data_structure/array_list.h
+fort_SOURCES += data_structure/common.h
+fort_SOURCES += data_structure/uthash.h
fort_SOURCES += object/certificate.h object/certificate.c
fort_SOURCES += object/crl.h object/crl.c
fort_SOURCES += rtr/rtr.c rtr/rtr.h
fort_SOURCES += rtr/db/delta.c rtr/db/delta.h
-fort_SOURCES += rtr/db/roa_tree.c rtr/db/roa_tree.h
+fort_SOURCES += rtr/db/roa_table.c rtr/db/roa_table.h
fort_SOURCES += rtr/db/roa.c rtr/db/roa.h
fort_SOURCES += rtr/db/vrps.c rtr/db/vrps.h
+++ /dev/null
-#include "data_structure/circular_indexer.h"
-
-#include <stdlib.h>
-#include "log.h"
-
-void
-arridx_init(struct circular_indexer *result, size_t len)
-{
- result->indexes = NULL;
- result->first = len - 1;
- result->current = len - 1;
- result->top = 0;
- result->len = len;
- result->allow_another_lap = false;
-}
-
-void
-arridx_cleanup(struct circular_indexer *indexer)
-{
- if (indexer->indexes != NULL)
- free(indexer->indexes);
-}
-
-static struct circular_indexer_node *
-get_node(struct circular_indexer *indexer, array_index index)
-{
- return &indexer->indexes[index - indexer->top];
-}
-
-static struct circular_indexer_node *
-get_current(struct circular_indexer *indexer)
-{
- return get_node(indexer, indexer->current);
-}
-
-array_index *
-arridx_first(struct circular_indexer *indexer)
-{
- indexer->allow_another_lap = true;
-
- if (arridx_next(indexer) == NULL)
- return NULL;
-
- indexer->first = indexer->current;
- indexer->allow_another_lap = false;
- return &indexer->current;
-}
-
-array_index *
-arridx_next(struct circular_indexer *indexer)
-{
- array_index result;
-
- if (indexer->len == 0)
- return NULL;
-
- if (indexer->indexes == NULL) {
- result = indexer->current + 1;
- if ((result - indexer->top) == indexer->len)
- result = indexer->top;
- } else {
- result = get_current(indexer)->next;
- }
-
- if (result == indexer->first) {
- if (!indexer->allow_another_lap)
- return NULL;
- indexer->allow_another_lap = false;
- }
-
- indexer->current = result;
- return &indexer->current;
-}
-
-static int
-initialize_indexes(struct circular_indexer *indexer)
-{
- struct circular_indexer_node *array;
- size_t len;
- array_index i;
-
- len = indexer->len;
- array = calloc(len, sizeof(struct circular_indexer_node));
- if (array == NULL)
- return pr_enomem();
-
- array[0].previous = len - 1;
- if (len > 1) {
- array[0].next = 1;
- for (i = 1; i < len - 1; i++) {
- array[i].previous = i - 1;
- array[i].next = i + 1;
- }
- array[len - 1].previous = len - 2;
- }
- array[len - 1].next = 0;
-
- indexer->indexes = array;
- return 0;
-}
-
-int
-arridx_remove(struct circular_indexer *indexer)
-{
- struct circular_indexer_node *node;
- int error;
-
- if (indexer->len == 0) {
- /*
- * BTW: This also means that calling code used this function
- * outside of a loop, so double no cookies.
- */
- return pr_crit("Attempting to remove an element from an empty circular array.");
- }
-
- if (indexer->indexes == NULL) {
- if (indexer->top == indexer->current) {
- indexer->top++;
- if (indexer->first == indexer->current) {
- indexer->first++;
- indexer->allow_another_lap = true;
- }
- goto success;
- }
-
- error = initialize_indexes(indexer);
- if (error)
- return error;
- }
-
- node = get_current(indexer);
-
- if (indexer->first == indexer->current) {
- indexer->first = node->next;
- indexer->allow_another_lap = true;
- }
-
- indexer->indexes[node->previous].next = node->next;
- indexer->indexes[node->next].previous = node->previous;
-
-success:
- indexer->len--;
- return 0;
-}
+++ /dev/null
-#ifndef SRC_DATA_STRUCTURE_CIRCULAR_INDEXER_H_
-#define SRC_DATA_STRUCTURE_CIRCULAR_INDEXER_H_
-
-#include <stdbool.h>
-#include "data_structure/common.h"
-
-/*
- * What I call a "circular indexer" is a data structure meant to add *temporal*
- * efficient list-like operations to an already existing array.
- *
- * (The operations are O(1) removal and subsequent circular bidirectional
- * iteration. Of course however, creating the indexer is O(n).)
- *
- * In pragmatic terms, a "circular indexer" is an iterator-like thingy which
- * will keep returning removal-sensitive indexes that can be used to dereference
- * another array. It's called "circular" because the iteration will wrap
- * (although each foreach will stop after one lap.)
- *
- * It's designed to be used by the ROA tree. While computing deltas, it's useful
- * to keep removing elements, not only to efficiently prevent re-traversal of
- * already handled nodes, but also to naturally end up with a list of unused
- * nodes. At the same time, delta computing is not supposed to destroy the tree.
- */
-
-struct circular_indexer_node {
- array_index previous;
- array_index next;
-};
-
-struct circular_indexer {
- /*
- * This is the array where we store the links between the nodes.
- *
- * Will be initialized lazily, because most iterations and removals will
- * actually require nothing more than the variables below, and we don't
- * want to allocate.
- *
- * `indexes[i]` always corresponds to `other_array[i + top]`
- */
- struct circular_indexer_node *indexes;
-
- /*
- * This is the index of some valid element in @indexes. It's called
- * "first" because iteration always begins at this element.
- *
- * In practice, the code is set up so this points to the successor of
- * the element in which the last iteration was interrupted. This is
- * because this element has a high chance of being the element that
- * calling code is going to be looking up in the next loop.
- */
- array_index first;
- /** Element the iteration is currently traversing. */
- array_index current;
- /**
- * Index of the first element that hasn't been removed.
- * For example, if @top is 10, then elements 0-9 have been removed,
- * and 10-* still exist.
- *
- * This is a white box optimization. We know that calling code most
- * often uses the circular indexer to compare two identical arrays, and
- * that any identical elements need to be removed along.
- *
- * So, most of the time, @top is all that is needed, and we can postpone
- * the initialization of @indexes to never.
- */
- array_index top;
-
- /**
- * Number of elements remaining. (ie. that haven't been removed.)
- * (The length of @indexes is not stored because it's never needed.)
- */
- size_t len;
-
- /**
- * Iteration normally stops when @current reaches @first a second time.
- * But when the first element is removed, @first now points to the next
- * one, so @current will need to "touch" @first again.
- *
- * This member reminds us that iteration needs to continue the next time
- * @current reaches @first.
- */
- bool allow_another_lap;
-};
-
-/*
- * Types:
- * @indexer: pointer to the struct circular_indexer you want to iterate.
- * @i: pointer to array_index. You will have to dereference it to get the index
- * cursor.
- *
- * Every time you start a foreach, iteration will continue where the last one
- * stopped. (But will do another full lap.)
- */
-#define ARRIDX_FOREACH(indexer, i) \
- for (i = arridx_first(indexer); i != NULL; i = arridx_next(indexer))
-
-void arridx_init(struct circular_indexer *, size_t);
-void arridx_cleanup(struct circular_indexer *);
-
-array_index *arridx_first(struct circular_indexer *);
-array_index *arridx_next(struct circular_indexer *);
-/* Removes the *current* element. (You must be iterating.) */
-int arridx_remove(struct circular_indexer *);
-
-#endif /* SRC_DATA_STRUCTURE_CIRCULAR_INDEXER_H_ */
#include "crypto/hash.h"
#include "object/name.h"
#include "rsync/rsync.h"
-#include "rtr/db/roa_tree.h"
-
#include <sys/socket.h>
/* Just to prevent some line breaking. */
#include "asn1/decode.h"
#include "asn1/oid.h"
#include "object/signed_object.h"
-#include "rtr/db/roa_tree.h"
static int
roa_decode(OCTET_STRING_t *string, void *arg)
--- /dev/null
+#include "rtr/db/roa_table.h"
+
+#include "data_structure/uthash.h"
+
+struct hashable_roa {
+ /*
+ * TODO (whatever) flags is not useful here.
+ * Maybe separate struct vrp into two structures: One that doesn't
+ * contain flags, and one that contains the other.
+ */
+ struct vrp data;
+ UT_hash_handle hh;
+};
+
+struct roa_table {
+ struct hashable_roa *roas;
+ unsigned int references;
+};
+
+struct roa_table *
+roa_table_create(void)
+{
+ struct roa_table *table;
+
+ table = malloc(sizeof(struct roa_table));
+ if (table == NULL)
+ return NULL;
+
+ table->roas = NULL;
+ table->references = 1;
+ return table;
+}
+
+static void
+roa_table_cleanup(struct roa_table *table)
+{
+ struct hashable_roa *node;
+ struct hashable_roa *tmp;
+
+ HASH_ITER(hh, table->roas, node, tmp) {
+ HASH_DEL(table->roas, node);
+ free(node);
+ }
+}
+
+void
+roa_table_get(struct roa_table *table)
+{
+ table->references++;
+}
+
+void
+roa_table_put(struct roa_table *table)
+{
+ table->references--;
+ if (table->references == 0) {
+ roa_table_cleanup(table);
+ free(table);
+ }
+}
+
+int
+roa_table_foreach_roa(struct roa_table *table, vrp_foreach_cb cb, void *arg)
+{
+ struct hashable_roa *node;
+ int error;
+
+ for (node = table->roas; node != NULL; node = node->hh.next) {
+ error = cb(&node->data, arg);
+ if (error)
+ return error;
+ }
+
+ return 0;
+}
+
+int
+rtrhandler_reset(struct roa_table *table)
+{
+ roa_table_cleanup(table);
+ return 0;
+}
+
+static struct hashable_roa *
+create_roa(uint32_t asn, uint8_t max_length)
+{
+ struct hashable_roa *roa;
+
+ roa = malloc(sizeof(struct hashable_roa));
+ if (roa == NULL)
+ return NULL;
+ /* Needed by uthash */
+ memset(roa, 0, sizeof(struct hashable_roa));
+
+ roa->data.asn = asn;
+ roa->data.max_prefix_length = max_length;
+ roa->data.flags = FLAG_ANNOUNCEMENT;
+
+ return roa;
+}
+
+static int
+add_roa(struct roa_table *table, struct hashable_roa *new)
+{
+ struct hashable_roa *old;
+
+ HASH_REPLACE(hh, table->roas, data, sizeof(new->data), new, old);
+ if (old != NULL)
+ free(old);
+
+ return 0;
+}
+
+int
+rtrhandler_handle_roa_v4(struct roa_table *table, uint32_t asn,
+ struct ipv4_prefix const *prefix4, uint8_t max_length)
+{
+ struct hashable_roa *roa;
+
+ roa = create_roa(asn, max_length);
+ if (roa == NULL)
+ return pr_enomem();
+ roa->data.prefix.v4 = prefix4->addr;
+ roa->data.prefix_length = prefix4->len;
+ roa->data.addr_fam = AF_INET;
+
+ return add_roa(table, roa);
+}
+
+int
+rtrhandler_handle_roa_v6(struct roa_table *table, uint32_t asn,
+ struct ipv6_prefix const *prefix6, uint8_t max_length)
+{
+ struct hashable_roa *roa;
+
+ roa = create_roa(asn, max_length);
+ if (roa == NULL)
+ return pr_enomem();
+ roa->data.prefix.v6 = prefix6->addr;
+ roa->data.prefix_length = prefix6->len;
+ roa->data.addr_fam = AF_INET6;
+
+ return add_roa(table, roa);
+}
+
+static int
+add_delta(struct deltas *deltas, struct hashable_roa *roa, enum delta_op op)
+{
+ union {
+ struct v4_address v4;
+ struct v6_address v6;
+ } addr;
+
+ switch (roa->data.addr_fam) {
+ case AF_INET:
+ addr.v4.prefix.addr = roa->data.prefix.v4;
+ addr.v4.prefix.len = roa->data.prefix_length;
+ addr.v4.max_length = roa->data.max_prefix_length;
+ return deltas_add_roa_v4(deltas, roa->data.asn, &addr.v4, op);
+ case AF_INET6:
+ addr.v6.prefix.addr = roa->data.prefix.v6;
+ addr.v6.prefix.len = roa->data.prefix_length;
+ addr.v6.max_length = roa->data.max_prefix_length;
+ return deltas_add_roa_v6(deltas, roa->data.asn, &addr.v6, op);
+ }
+
+ return pr_crit("Unknown address family: %d", roa->data.addr_fam);
+}
+
+/*
+ * Copies `@roas1 - roas2` into @deltas.
+ *
+ * (Places the ROAs that exist in @roas1 but not in @roas2 in @deltas.)
+ */
+static int
+add_deltas(struct hashable_roa *roas1, struct hashable_roa *roas2,
+ struct deltas *deltas, enum delta_op op)
+{
+ struct hashable_roa *n1; /* A node from @roas1 */
+ struct hashable_roa *n2; /* A node from @roas2 */
+ int error;
+
+ for (n1 = roas1; n1 != NULL; n1 = n1->hh.next) {
+ HASH_FIND(hh, roas2, &n1->data, sizeof(n1->data), n2);
+ if (n2 == NULL) {
+ error = add_delta(deltas, n1, op);
+ if (error)
+ return error;
+ }
+ }
+
+ return 0;
+}
+
+int
+compute_deltas(struct roa_table *old, struct roa_table *new,
+ struct deltas **result)
+{
+ struct deltas *deltas;
+ int error;
+
+ error = deltas_create(&deltas);
+ if (error)
+ return error;
+
+ error = add_deltas(new->roas, old->roas, deltas, DELTA_ADD);
+ if (error)
+ goto fail;
+ error = add_deltas(old->roas, new->roas, deltas, DELTA_RM);
+ if (error)
+ goto fail;
+
+ *result = deltas;
+ return 0;
+
+fail:
+ deltas_destroy(deltas);
+ return error;
+}
--- /dev/null
+#ifndef SRC_ROA_TABLE_H_
+#define SRC_ROA_TABLE_H_
+
+#include "rtr/db/delta.h"
+#include "rtr/db/vrp.h"
+
+struct roa_table;
+
+/* Constructor */
+struct roa_table *roa_table_create(void);
+/* Reference counting */
+void roa_table_get(struct roa_table *);
+void roa_table_put(struct roa_table *);
+
+int roa_table_foreach_roa(struct roa_table *, vrp_foreach_cb, void *);
+
+int rtrhandler_reset(struct roa_table *);
+int rtrhandler_handle_roa_v4(struct roa_table *, uint32_t,
+ struct ipv4_prefix const *, uint8_t);
+int rtrhandler_handle_roa_v6(struct roa_table *, uint32_t,
+ struct ipv6_prefix const *, uint8_t);
+
+int compute_deltas(struct roa_table *, struct roa_table *, struct deltas **);
+
+#endif /* SRC_ROA_TABLE_H_ */
+++ /dev/null
-#include "rtr/db/roa_tree.h"
-
-#include "common.h"
-#include "data_structure/array_list.h"
-#include "data_structure/circular_indexer.h"
-#include "rtr/db/roa.h"
-
-DEFINE_ARRAY_LIST_STRUCT(nodes, struct node);
-
-struct node {
- struct rfc5280_name *subject_name;
- struct node *parent;
- /*
- * BTW: There's nothing in this code stopping both children and roa from
- * being not null, but it should never happen naturally.
- */
- struct nodes children;
- struct roa *roa;
-};
-
-struct roa_tree {
- struct node *root;
- struct node *current;
- unsigned int references;
-};
-
-DEFINE_ARRAY_LIST_FUNCTIONS(nodes, struct node)
-
-static void
-node_init(struct node *node, struct rfc5280_name *subject_name,
- struct node *parent)
-{
- node->subject_name = subject_name;
- x509_name_get(subject_name);
- node->parent = parent;
- nodes_init(&node->children);
- node->roa = NULL;
-}
-
-static struct node *
-node_create(struct rfc5280_name *subject_name, struct node *parent)
-{
- struct node *node;
-
- node = malloc(sizeof(struct node));
- if (node == NULL)
- return NULL;
-
- node_init(node, subject_name, parent);
- return node;
-}
-
-static void
-node_cleanup(struct node *node)
-{
- if (node->subject_name != NULL)
- x509_name_put(node->subject_name);
- nodes_cleanup(&node->children, node_cleanup);
- if (node->roa != NULL)
- roa_destroy(node->roa);
-}
-
-static int
-node_add_child(struct node *parent, struct rfc5280_name *subject_name)
-{
- struct node child;
- int error;
-
- node_init(&child, subject_name, parent);
-
- error = nodes_add(&parent->children, &child);
- if (error)
- node_cleanup(&child);
-
- return error;
-}
-
-/**
- * Performs lazy initialization if the root does not exist.
- */
-static struct node *
-get_root(struct roa_tree *tree, struct rfc5280_name *subject_name)
-{
- if (tree->root == NULL)
- tree->root = node_create(subject_name, NULL);
- return tree->root;
-}
-
-struct roa_tree *
-roa_tree_create(void)
-{
- struct roa_tree *tree;
-
- tree = malloc(sizeof(struct roa_tree));
- if (tree == NULL)
- return NULL;
-
- tree->root = NULL;
- tree->current = NULL;
- tree->references = 1;
- return tree;
-}
-
-static void
-roa_tree_cleanup(struct roa_tree *tree)
-{
- if (tree->root != NULL) {
- node_cleanup(tree->root);
- free(tree->root);
- tree->root = NULL;
- }
- tree->current = NULL;
-}
-
-void
-roa_tree_get(struct roa_tree *tree)
-{
- tree->references++;
-}
-
-void
-roa_tree_put(struct roa_tree *tree)
-{
- tree->references--;
- if (tree->references == 0) {
- roa_tree_cleanup(tree);
- free(tree);
- }
-}
-
-static int
-__foreach_v4(struct roa *roa, vrp_foreach_cb cb, void *arg)
-{
- struct v4_address *addr;
- struct vrp vrp;
- int error;
-
- vrp.asn = roa->as;
- vrp.addr_fam = AF_INET;
- vrp.flags = FLAG_ANNOUNCEMENT;
-
- ARRAYLIST_FOREACH(&roa->addrs4, addr) {
- vrp.prefix.v4 = addr->prefix.addr;
- vrp.prefix_length = addr->prefix.len;
- vrp.max_prefix_length = addr->max_length;
- error = cb(&vrp, arg);
- if (error)
- return error;
- }
-
- return 0;
-}
-
-static int
-__foreach_v6(struct roa *roa, vrp_foreach_cb cb, void *arg)
-{
- struct v6_address *addr;
- struct vrp vrp;
- int error;
-
- vrp.asn = roa->as;
- vrp.addr_fam = AF_INET6;
- vrp.flags = FLAG_ANNOUNCEMENT;
-
- ARRAYLIST_FOREACH(&roa->addrs6, addr) {
- vrp.prefix.v6 = addr->prefix.addr;
- vrp.prefix_length = addr->prefix.len;
- vrp.max_prefix_length = addr->max_length;
- error = cb(&vrp, arg);
- if (error)
- return error;
- }
-
- return 0;
-}
-
-int
-__foreach(struct node *node, vrp_foreach_cb cb, void *arg)
-{
- struct node *child;
- int error;
-
- ARRAYLIST_FOREACH(&node->children, child) {
- error = __foreach(child, cb, arg);
- if (error)
- return error;
- }
-
- if (node->roa != NULL) {
- error = __foreach_v4(node->roa, cb, arg);
- if (error)
- return error;
- error = __foreach_v6(node->roa, cb, arg);
- if (error)
- return error;
- }
-
- return 0;
-}
-
-int
-roa_tree_foreach_roa(struct roa_tree *tree, vrp_foreach_cb cb, void *arg)
-{
- return (tree->root != NULL) ? __foreach(tree->root, cb, arg) : 0;
-}
-
-int
-forthandler_reset(struct roa_tree *tree)
-{
- roa_tree_cleanup(tree);
- return 0;
-}
-
-struct node *
-get_last_node(struct nodes *nodes)
-{
- if (nodes->array == NULL || nodes->len == 0)
- return NULL;
-
- return &nodes->array[nodes->len - 1];
-}
-
-int
-forthandler_go_down(struct roa_tree *tree,
- struct rfc5280_name *subject_name)
-{
- int error;
- if (tree->current != NULL) {
- error = node_add_child(tree->current, subject_name);
- if (error)
- return error;
- tree->current = get_last_node(&tree->current->children);
- return 0;
- }
-
- tree->current = get_root(tree, subject_name);
- return (tree->current != NULL) ? 0 : pr_enomem();
-}
-
-int
-forthandler_go_up(struct roa_tree *tree)
-{
- if (tree->current != NULL)
- tree->current = tree->current->parent;
- return 0;
-}
-
-static int
-get_current_roa(struct roa_tree *tree, uint32_t asn, struct roa **result)
-{
- struct roa *roa;
- int error;
-
- if (tree->current == NULL)
- return pr_crit("Validator posted ROA during incorrect context.");
-
- roa = tree->current->roa;
- if (roa == NULL) {
- error = roa_create(asn, &roa);
- if (error)
- return error;
- tree->current->roa = roa;
- }
-
- *result = roa;
- return 0;
-}
-
-int
-forthandler_handle_roa_v4(struct roa_tree *tree, uint32_t asn,
- struct ipv4_prefix const *prefix4, uint8_t max_length)
-{
- struct roa *roa;
- int error;
- error = get_current_roa(tree, asn, &roa);
- return error ? error : roa_add_v4(roa, asn, prefix4, max_length);
-}
-
-int
-forthandler_handle_roa_v6(struct roa_tree *tree, uint32_t asn,
- struct ipv6_prefix const *prefix6, uint8_t max_length)
-{
- struct roa *roa;
- int error;
- error = get_current_roa(tree, asn, &roa);
- return error ? error : roa_add_v6(roa, asn, prefix6, max_length);
-}
-
-static bool
-find_subject_name(struct circular_indexer *indexer,
- struct rfc5280_name *subject_name, struct node *c2array,
- array_index *result)
-{
- array_index *i;
-
- ARRIDX_FOREACH(indexer, i) {
- if (x509_name_equals(subject_name, c2array[*i].subject_name)) {
- *result = *i;
- return true;
- }
- }
-
- return false;
-}
-
-static int
-add_all_roas_v4(struct deltas *deltas, struct roa *roa, enum delta_op op)
-{
- struct v4_address *addr;
- int error;
-
- ARRAYLIST_FOREACH(&roa->addrs4, addr) {
- error = deltas_add_roa_v4(deltas, roa->as, addr, op);
- if (error)
- return error;
- }
-
- return 0;
-}
-
-static int
-add_all_roas_v6(struct deltas *deltas, struct roa *roa, enum delta_op op)
-{
- struct v6_address *addr;
- int error;
-
- ARRAYLIST_FOREACH(&roa->addrs6, addr) {
- error = deltas_add_roa_v6(deltas, roa->as, addr, op);
- if (error)
- return error;
- }
-
- return 0;
-}
-
-static int
-add_all_deltas(struct node *node, struct deltas *deltas, enum delta_op op)
-{
- struct node *child;
- int error;
-
- ARRAYLIST_FOREACH(&node->children, child) {
- error = add_all_deltas(child, deltas, op);
- if (error)
- return error;
- }
-
- if (child->roa != NULL) {
- error = add_all_roas_v4(deltas, child->roa, op);
- if (error)
- return error;
- error = add_all_roas_v6(deltas, child->roa, op);
- if (error)
- return error;
- }
-
- return 0;
-}
-
-static int compute_deltas_node(struct node *, struct node *, struct deltas *);
-
-static int
-handle_delta_children(struct nodes *children1, struct nodes *children2,
- struct deltas *deltas)
-{
- /*
- * Most of the time, the arrays will be identical.
- * When they are not, most of the time the arrays will be mostly
- * identical.
- *
- * We will try our hardest to traverse the arrays as sequentially as
- * possible to exploit these facts.
- *
- * Notice that this is the same algorithm as HANDLE_ROAS_FN().
- * Changes to one function might need to cascade to the other.
- */
-
- struct node *c1node;
-
- struct node *c2array;
- array_index c2; /* counter for c2array */
- array_index *c2p; /* counter for c2array, pointer */
-
- struct circular_indexer c2indexer;
-
- int error = 0;
-
- c2array = children2->array;
- arridx_init(&c2indexer, children2->len);
-
- ARRAYLIST_FOREACH(children1, c1node) {
- if (find_subject_name(&c2indexer, c1node->subject_name,
- c2array, &c2)) {
- error = compute_deltas_node(c1node, &c2array[c2],
- deltas);
- if (error)
- goto end;
-
- error = arridx_remove(&c2indexer);
- } else {
- error = add_all_deltas(c1node, deltas, DELTA_RM);
- }
- if (error)
- goto end;
- }
-
- ARRIDX_FOREACH(&c2indexer, c2p) {
- error = add_all_deltas(&c2array[*c2p], deltas, DELTA_ADD);
- if (error)
- goto end;
- }
-
-end: arridx_cleanup(&c2indexer);
- return error;
-}
-
-static bool
-find_addr_v4(struct v4_address *address, struct v4_addresses *array,
- struct circular_indexer *indexer)
-{
- array_index *i;
-
- ARRIDX_FOREACH(indexer, i)
- if (prefix4_equals(&address->prefix, &array->array[*i].prefix))
- return true;
-
- return false;
-}
-
-static bool
-find_addr_v6(struct v6_address *address, struct v6_addresses *array,
- struct circular_indexer *indexer)
-{
- array_index *i;
-
- ARRIDX_FOREACH(indexer, i)
- if (prefix6_equals(&address->prefix, &array->array[*i].prefix))
- return true;
-
- return false;
-}
-
-#define HANDLE_ROAS_FN(name, array_type, node_type, field, find_fn, \
- add_one_fn, add_all_fn) \
- static int \
- name(struct roa *roa1, struct roa *roa2, struct deltas *deltas) \
- { \
- /* Notice that this is the same algorithm as */ \
- /* handle_delta_children(). Changes to one function */ \
- /* might need to cascade to the other. */ \
- \
- struct array_type *addrs1; \
- struct node_type *a1; /* address cursor for addrs1 */ \
- \
- struct array_type *addrs2; \
- array_index *a2p; /* counter for addrs2, pointer */ \
- \
- struct circular_indexer r2indexer; \
- int error = 0; \
- \
- if (roa1->as != roa2->as) { \
- error = add_all_fn(deltas, roa1, DELTA_RM); \
- if (error) \
- return error; \
- return add_all_fn(deltas, roa2, DELTA_ADD); \
- } \
- \
- addrs1 = &roa1->field; \
- addrs2 = &roa2->field; \
- arridx_init(&r2indexer, addrs2->len); \
- \
- ARRAYLIST_FOREACH(addrs1, a1) { \
- if (find_fn(a1, addrs2, &r2indexer)) \
- error = arridx_remove(&r2indexer); \
- else \
- error = add_one_fn(deltas, \
- roa1->as, a1, DELTA_RM); \
- if (error) \
- goto end; \
- } \
- \
- ARRIDX_FOREACH(&r2indexer, a2p) { \
- error = add_one_fn(deltas, roa2->as, \
- &addrs2->array[*a2p], DELTA_ADD); \
- if (error) \
- goto end; \
- } \
- \
- end: arridx_cleanup(&r2indexer); \
- return error; \
- }
-
-HANDLE_ROAS_FN(handle_roas_v4, v4_addresses, v4_address, addrs4, find_addr_v4,
- deltas_add_roa_v4, add_all_roas_v4)
-HANDLE_ROAS_FN(handle_roas_v6, v6_addresses, v6_address, addrs6, find_addr_v6,
- deltas_add_roa_v6, add_all_roas_v6)
-
-static int
-compute_deltas_node(struct node *n1, struct node *n2, struct deltas *deltas)
-{
- int error;
-
- error = handle_delta_children(&n1->children, &n2->children, deltas);
- if (error)
- return error;
-
- /** TODO I still need to validate that this is ok */
- if (n1->roa == NULL || n2->roa == NULL)
- return 0;
-
- error = handle_roas_v4(n1->roa, n2->roa, deltas);
- if (error)
- return error;
-
- return handle_roas_v6(n1->roa, n2->roa, deltas);
-}
-
-int
-compute_deltas(struct roa_tree *t1, struct roa_tree *t2, struct deltas **result)
-{
- struct deltas *deltas;
- int error;
-
- assert(t1->root != NULL);
- assert(t2->root != NULL);
-
- error = deltas_create(&deltas);
- if (error)
- return error;
-
- error = compute_deltas_node(t1->root, t2->root, deltas);
- if (error) {
- deltas_destroy(deltas);
- return error;
- }
-
- *result = deltas;
- return 0;
-}
+++ /dev/null
-#ifndef SRC_ROA_TREE_H_
-#define SRC_ROA_TREE_H_
-
-#include "address.h"
-#include "object/name.h"
-#include "rtr/db/delta.h"
-#include "rtr/db/vrp.h"
-
-struct roa_tree;
-
-/* Constructor */
-struct roa_tree *roa_tree_create(void);
-/* Reference counting */
-void roa_tree_get(struct roa_tree *);
-void roa_tree_put(struct roa_tree *);
-
-int roa_tree_foreach_roa(struct roa_tree *, vrp_foreach_cb, void *);
-
-/* TODO (urgent) rename to tree handler or whatever */
-int forthandler_reset(struct roa_tree *);
-int forthandler_go_down(struct roa_tree *, struct rfc5280_name *);
-int forthandler_go_up(struct roa_tree *);
-int forthandler_handle_roa_v4(struct roa_tree *, uint32_t,
- struct ipv4_prefix const *, uint8_t);
-int forthandler_handle_roa_v6(struct roa_tree *, uint32_t,
- struct ipv6_prefix const *, uint8_t);
-
-int compute_deltas(struct roa_tree *, struct roa_tree *, struct deltas **);
-
-#endif /* SRC_ROA_TREE_H_ */
struct vrp {
uint32_t asn;
+ /*
+ * TODO (whatever) convert to ipv*_prefix? (from address.h)
+ * Most of the time, @prefix and @prefix_length are copied from or into
+ * ipv*_prefixes.
+ */
union {
struct in_addr v4;
struct in6_addr v6;
ARRAY_LIST(deltas_db, struct delta)
struct state {
- struct roa_tree *base; /** All the current valid ROAs */
+ struct roa_table *base; /** All the current valid ROAs */
struct deltas_db deltas; /** ROA changes to @base over time */
uint32_t current_serial;
void
vrps_destroy(void)
{
- roa_tree_put(state.base);
+ roa_table_put(state.base);
deltas_db_cleanup(&state.deltas, delta_destroy);
pthread_rwlock_destroy(&lock); /* Nothing to do with error code */
}
* @new_deltas can be NULL, @new_tree cannot.
*/
int
-vrps_update(struct roa_tree *new_tree, struct deltas *new_deltas)
+vrps_update(struct roa_table *new_roas, struct deltas *new_deltas)
{
struct delta new_delta;
int error = 0;
}
if (state.base != NULL)
- roa_tree_put(state.base);
- state.base = new_tree;
- roa_tree_get(new_tree);
+ roa_table_put(state.base);
+ state.base = new_roas;
+ roa_table_get(new_roas);
state.current_serial++;
end:
if (error)
return error;
- error = roa_tree_foreach_roa(state.base, cb, arg);
+ error = roa_table_foreach_roa(state.base, cb, arg);
rwlock_unlock(&lock);
#include <time.h>
#include <netinet/ip.h>
+
#include "rtr/db/delta.h"
-#include "rtr/db/roa_tree.h"
+#include "rtr/db/roa_table.h"
enum delta_status {
/** There's no data at the DB */
int vrps_init(void);
void vrps_destroy(void);
-int vrps_update(struct roa_tree *, struct deltas *);
+int vrps_update(struct roa_table *, struct deltas *);
int deltas_db_status(uint32_t *, enum delta_status *);
int vrps_foreach_base_roa(vrp_foreach_cb, void *);
static int
__reset(void *arg)
{
- return forthandler_reset(arg);
-}
-
-static int
-__traverse_down(struct rfc5280_name *subject_name, void *arg)
-{
- return forthandler_go_down(arg, subject_name);
-}
-
-static int
-__traverse_up(void *arg)
-{
- return forthandler_go_up(arg);
+ return rtrhandler_reset(arg);
}
int
__handle_roa_v4(uint32_t as, struct ipv4_prefix const *prefix,
uint8_t max_length, void *arg)
{
- return forthandler_handle_roa_v4(arg, as, prefix, max_length);
+ return rtrhandler_handle_roa_v4(arg, as, prefix, max_length);
}
int
__handle_roa_v6(uint32_t as, struct ipv6_prefix const * prefix,
uint8_t max_length, void *arg)
{
- return forthandler_handle_roa_v6(arg, as, prefix, max_length);
+ return rtrhandler_handle_roa_v6(arg, as, prefix, max_length);
}
static void *
check_vrps_updates(void *param_void)
{
struct validation_handler validation_handler;
- struct roa_tree *old_tree;
+ struct roa_table *old_roas;
struct deltas *deltas;
int error;
validation_handler.reset = __reset;
- validation_handler.traverse_down = __traverse_down;
- validation_handler.traverse_up = __traverse_up;
+ validation_handler.traverse_down = NULL;
+ validation_handler.traverse_up = NULL;
validation_handler.handle_roa_v4 = __handle_roa_v4;
validation_handler.handle_roa_v6 = __handle_roa_v6;
- old_tree = NULL;
+ old_roas = NULL;
do {
- validation_handler.arg = roa_tree_create();
+ validation_handler.arg = roa_table_create();
if (validation_handler.arg == NULL) {
pr_err("Memory allocation failed. Cannot validate. Sleeping...");
goto sleep;
error = perform_standalone_validation(&validation_handler);
if (error) {
- roa_tree_put(validation_handler.arg);
+ roa_table_put(validation_handler.arg);
pr_err("Validation failed (error code %d). Cannot udpate the ROA database. Sleeping...",
error);
goto sleep;
}
- if (old_tree == NULL) {
+ if (old_roas == NULL) {
error = vrps_update(validation_handler.arg, NULL);
if (error) {
- roa_tree_put(validation_handler.arg);
+ roa_table_put(validation_handler.arg);
pr_err("Error code %d while trying to update the ROA database. Sleeping...",
error);
} else {
- old_tree = validation_handler.arg;
+ old_roas = validation_handler.arg;
}
goto sleep;
}
- error = compute_deltas(old_tree, validation_handler.arg, &deltas);
+ error = compute_deltas(old_roas, validation_handler.arg, &deltas);
if (error) {
- roa_tree_put(validation_handler.arg);
+ roa_table_put(validation_handler.arg);
pr_err("Something went wrong while trying to compute the deltas. (error code %d.) Cannot update the ROA database. Sleeping...",
error);
goto sleep;
}
if (deltas_is_empty(deltas)) {
- roa_tree_put(validation_handler.arg);
+ roa_table_put(validation_handler.arg);
deltas_destroy(deltas);
pr_debug("No changes. Sleeping...");
goto sleep;
error = vrps_update(validation_handler.arg, deltas);
if (error) {
- roa_tree_put(validation_handler.arg);
+ roa_table_put(validation_handler.arg);
deltas_destroy(deltas);
pr_err("Error code %d while trying to store the deltas in the database. Cannot update the ROA database. Sleeping...",
error);
goto sleep;
}
- old_tree = validation_handler.arg;
+ old_roas = validation_handler.arg;
error = notify_clients();
if (error)
pr_debug("Could not notify clients of the new VRPs. (Error code %d.) Sleeping...",
BASIC_MODULES += impersonator.c
check_PROGRAMS = address.test
-check_PROGRAMS += circular_indexer.test
check_PROGRAMS += clients.test
check_PROGRAMS += line_file.test
check_PROGRAMS += rsync.test
+check_PROGRAMS += roa_table.test
#check_PROGRAMS += tal.test
check_PROGRAMS += vcard.test
#check_PROGRAMS += rtr/pdu.test
address_test_SOURCES += address_test.c
address_test_LDADD = ${MY_LDADD}
-circular_indexer_test_SOURCES = ${BASIC_MODULES}
-circular_indexer_test_SOURCES += ../src/data_structure/circular_indexer.c
-circular_indexer_test_SOURCES += data_structure/circular_indexer_test.c
-circular_indexer_test_LDADD = ${MY_LDADD}
-
clients_test_SOURCES = ${BASIC_MODULES}
clients_test_SOURCES += ../src/clients.c
clients_test_SOURCES += ../src/common.c
line_file_test_SOURCES += line_file_test.c
line_file_test_LDADD = ${MY_LDADD}
+roa_table_test_SOURCES = ${BASIC_MODULES}
+roa_table_test_SOURCES += ../src/rtr/db/delta.c
+roa_table_test_SOURCES += ../src/rtr/db/roa_table.c
+roa_table_test_SOURCES += rtr/db/roa_table_test.c
+roa_table_test_LDADD = ${MY_LDADD}
+
rsync_test_SOURCES = ${BASIC_MODULES}
rsync_test_SOURCES += ../src/str.c ../src/str.h
rsync_test_SOURCES += ../src/uri.c ../src/uri.h
+++ /dev/null
-#include "data_structure/circular_indexer.h"
-
-#include <check.h>
-#include <errno.h>
-#include <stdlib.h>
-
-/*
- * These are macros so CHECK will be able to report proper lines on errors.
- * Functions would ruin that.
- */
-
-static array_index *tmp;
-#define assert_index(expected, actual) \
- tmp = actual; \
- ck_assert_ptr_ne(NULL, tmp); \
- ck_assert_int_eq(expected, *tmp);
-
-#define assert_next_is_null(indexer) \
- /* Twice, to make sure it stays consistent. */ \
- ck_assert_ptr_eq(NULL, arridx_next(indexer)); \
- ck_assert_ptr_eq(NULL, arridx_next(indexer));
-
-#define assert_first_is_null(indexer) \
- ck_assert_ptr_eq(NULL, arridx_first(indexer)); \
- ck_assert_ptr_eq(NULL, arridx_first(indexer));
-
-START_TEST(no_removes)
-{
- struct circular_indexer indexer;
-
- arridx_init(&indexer, 4);
-
- /* Full traversal from 0 */
- assert_index(0, arridx_first(&indexer));
- assert_index(1, arridx_next(&indexer));
- assert_index(2, arridx_next(&indexer));
- assert_index(3, arridx_next(&indexer));
- assert_next_is_null(&indexer);
-
- assert_index(0, arridx_first(&indexer));
- assert_index(1, arridx_next(&indexer));
- assert_index(2, arridx_next(&indexer));
-
- /* Full traversal from 3 */
- assert_index(3, arridx_first(&indexer));
- assert_index(0, arridx_next(&indexer));
- assert_index(1, arridx_next(&indexer));
- assert_index(2, arridx_next(&indexer));
- assert_next_is_null(&indexer);
-
- assert_index(3, arridx_first(&indexer));
- assert_index(0, arridx_next(&indexer));
- assert_index(1, arridx_next(&indexer));
-
- /* Full traversal from 2 */
- assert_index(2, arridx_first(&indexer));
- assert_index(3, arridx_next(&indexer));
- assert_index(0, arridx_next(&indexer));
- assert_index(1, arridx_next(&indexer));
- assert_next_is_null(&indexer);
-
- assert_index(2, arridx_first(&indexer));
- assert_index(3, arridx_next(&indexer));
- assert_index(0, arridx_next(&indexer));
-
- /* Full traversal from 1 */
- assert_index(1, arridx_first(&indexer));
- assert_index(2, arridx_next(&indexer));
- assert_index(3, arridx_next(&indexer));
- assert_index(0, arridx_next(&indexer));
- assert_next_is_null(&indexer);
-
- ck_assert_ptr_eq(NULL, indexer.indexes);
- arridx_cleanup(&indexer);
-}
-END_TEST
-
-static void
-test_traversal_with_removal(array_index *(*traverser)(struct circular_indexer *))
-{
- struct circular_indexer indexer;
-
- arridx_init(&indexer, 5);
-
- assert_index(0, arridx_first(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_index(1, traverser(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_index(2, traverser(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_index(3, traverser(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_index(4, traverser(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
-
- assert_next_is_null(&indexer);
- assert_first_is_null(&indexer);
- assert_next_is_null(&indexer);
-
- ck_assert_ptr_eq(NULL, indexer.indexes);
- arridx_cleanup(&indexer);
-}
-
-START_TEST(always_remove_first)
-{
- test_traversal_with_removal(arridx_first);
-}
-END_TEST
-
-START_TEST(always_remove_next)
-{
- test_traversal_with_removal(arridx_next);
-}
-END_TEST
-
-START_TEST(remove_only_top)
-{
- /* This one is also unnecessary. */
-
- struct circular_indexer indexer;
-
- arridx_init(&indexer, 5);
-
- /* 0 1 2 3 4 */
- assert_index(0, arridx_first(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_index(1, arridx_next(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_index(2, arridx_next(&indexer));
- assert_index(3, arridx_next(&indexer));
- assert_index(4, arridx_next(&indexer));
- assert_next_is_null(&indexer);
-
- /* 2 3 4 (just make sure the indexer was left in a consistent state) */
- assert_index(2, arridx_first(&indexer));
- assert_index(3, arridx_next(&indexer));
- assert_index(4, arridx_next(&indexer));
- assert_next_is_null(&indexer);
-
- /* 2 3 4 */
- assert_index(2, arridx_first(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_index(3, arridx_next(&indexer));
- assert_index(4, arridx_next(&indexer));
- assert_next_is_null(&indexer);
-
- /* 3 4 */
- assert_index(3, arridx_first(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_index(4, arridx_next(&indexer));
- assert_next_is_null(&indexer);
-
- /* 4 */
- assert_index(4, arridx_first(&indexer));
- assert_next_is_null(&indexer);
-
- /* 4 */
- assert_index(4, arridx_first(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_next_is_null(&indexer);
-
- /* */
- assert_first_is_null(&indexer);
- assert_next_is_null(&indexer);
-
- ck_assert_ptr_eq(NULL, indexer.indexes);
- arridx_cleanup(&indexer);
-}
-END_TEST
-
-START_TEST(remove_top_mid_iteration)
-{
- struct circular_indexer indexer;
-
- arridx_init(&indexer, 4);
-
- /* 0 1 2 3 */
- assert_index(0, arridx_first(&indexer));
- assert_index(1, arridx_next(&indexer));
- assert_index(2, arridx_next(&indexer));
-
- /* 3 0 1 2 */
- assert_index(3, arridx_first(&indexer));
- assert_index(0, arridx_next(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_index(1, arridx_next(&indexer));
- assert_index(2, arridx_next(&indexer));
- assert_next_is_null(&indexer);
-
- /* 3 1 2 */
- assert_index(3, arridx_first(&indexer));
- assert_index(1, arridx_next(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_index(2, arridx_next(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_next_is_null(&indexer);
-
- /* 3 */
- assert_index(3, arridx_first(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_next_is_null(&indexer);
-
- /* */
- assert_first_is_null(&indexer);
- assert_next_is_null(&indexer);
-
- ck_assert_ptr_eq(NULL, indexer.indexes);
- arridx_cleanup(&indexer);
-}
-END_TEST
-
-static void
-traverse_mallocd_indexer_easy(array_index *(*traverser)(struct circular_indexer *))
-{
- struct circular_indexer indexer;
-
- arridx_init(&indexer, 4);
-
- /* (This iteration is mostly just intended to prepare the array) */
- /* 0 1 2 3 */
- assert_index(0, arridx_first(&indexer));
- assert_index(1, arridx_next(&indexer));
-
- ck_assert_ptr_eq(NULL, indexer.indexes);
- ck_assert_int_eq(0, arridx_remove(&indexer));
- ck_assert_ptr_ne(NULL, indexer.indexes);
-
- assert_index(2, arridx_next(&indexer));
- assert_index(3, arridx_next(&indexer));
- assert_next_is_null(&indexer);
-
- /* (This is the actual test) */
- /* 0 2 3 */
- assert_index(0, arridx_first(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_index(2, traverser(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_index(3, traverser(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_next_is_null(&indexer);
-
- /* */
- assert_first_is_null(&indexer);
- assert_next_is_null(&indexer);
-
- arridx_cleanup(&indexer);
-}
-
-START_TEST(malloc_always_remove_first_simple)
-{
- traverse_mallocd_indexer_easy(arridx_first);
-}
-END_TEST
-
-START_TEST(malloc_always_remove_next_simple)
-{
- traverse_mallocd_indexer_easy(arridx_next);
-}
-END_TEST
-
-/*
- * This is the same as traverse_mallocd_indexer(), except it has the first, last
- * and two contiguous elements pre-removed, cuz that's trickier.
- */
-static void
-traverse_mallocd_indexer_hard(array_index *(*traverser)(struct circular_indexer *))
-{
- struct circular_indexer indexer;
-
- arridx_init(&indexer, 8);
-
- /* -- Prepare the array -- */
- /*
- * Despite being initialization, this actually manhandles the indexer
- * quite a bit, which is good.
- */
- /* 0 1 2 3 4 5 6 7 */
- assert_index(0, arridx_first(&indexer));
- assert_index(1, arridx_next(&indexer));
- assert_index(2, arridx_next(&indexer));
-
- assert_index(3, arridx_next(&indexer));
- ck_assert_ptr_eq(NULL, indexer.indexes);
- ck_assert_int_eq(0, arridx_remove(&indexer));
- ck_assert_ptr_ne(NULL, indexer.indexes);
-
- assert_index(4, arridx_next(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
-
- assert_index(5, arridx_next(&indexer));
- assert_index(6, arridx_next(&indexer));
-
- assert_index(7, arridx_next(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
-
- assert_next_is_null(&indexer);
-
- /* 0 1 2 5 6 */
- assert_index(0, arridx_first(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
-
- /* -- Actual test -- */
- /* Let's do an innocent traversal first, just for shits and giggles. */
- /* 1 2 5 6 */
- assert_index(1, arridx_first(&indexer));
- assert_index(2, arridx_next(&indexer));
- assert_index(5, arridx_next(&indexer));
- assert_index(6, arridx_next(&indexer));
- assert_next_is_null(&indexer);
-
- /* Ok, begin. */
- /* 1 2 5 6 */
- assert_index(1, arridx_first(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_index(2, traverser(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_index(5, traverser(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_index(6, traverser(&indexer));
- ck_assert_int_eq(0, arridx_remove(&indexer));
- assert_next_is_null(&indexer);
-
- /* */
- assert_first_is_null(&indexer);
- assert_next_is_null(&indexer);
-
- arridx_cleanup(&indexer);
-}
-
-START_TEST(malloc_always_remove_first_complex)
-{
- traverse_mallocd_indexer_hard(arridx_first);
-}
-END_TEST
-
-START_TEST(malloc_always_remove_next_complex)
-{
- traverse_mallocd_indexer_hard(arridx_next);
-}
-END_TEST
-
-Suite *address_load_suite(void)
-{
- Suite *suite;
- TCase *malloc_no;
- TCase *malloc_yes;
-
- /* Tests in which the indexer.indexes array is not allocated. */
- malloc_no = tcase_create("No malloc tests");
- tcase_add_test(malloc_no, no_removes);
- tcase_add_test(malloc_no, always_remove_first);
- tcase_add_test(malloc_no, always_remove_next);
- tcase_add_test(malloc_no, remove_only_top);
- tcase_add_test(malloc_no, remove_top_mid_iteration);
-
- /* Tests that involve the indexer.indexes array. */
- malloc_yes = tcase_create("malloc tests");
- tcase_add_test(malloc_yes, malloc_always_remove_first_simple);
- tcase_add_test(malloc_yes, malloc_always_remove_next_simple);
- tcase_add_test(malloc_yes, malloc_always_remove_first_complex);
- tcase_add_test(malloc_yes, malloc_always_remove_next_complex);
-
- suite = suite_create("Circular indexer");
- suite_add_tcase(suite, malloc_no);
- suite_add_tcase(suite, malloc_yes);
- return suite;
-}
-
-int main(void)
-{
- Suite *suite;
- SRunner *runner;
- int tests_failed;
-
- suite = address_load_suite();
-
- runner = srunner_create(suite);
- srunner_run_all(runner, CK_NORMAL);
- tests_failed = srunner_ntests_failed(runner);
- srunner_free(runner);
-
- return (tests_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
-}
--- /dev/null
+#include <check.h>
+#include <stdlib.h>
+#include "thread_var.h"
+#include "rtr/db/roa_table.h"
+
+#define ADDR1 htonl(0xC0000201) /* 192.0.2.1 */
+#define ADDR2 htonl(0xC0000202) /* 192.0.2.2 */
+
+#define TOTAL_ROAS 10
+static bool roas_found[TOTAL_ROAS];
+static unsigned int total_found;
+
+static bool
+vrp_equals_v4(struct vrp *vrp, uint8_t as, uint32_t addr, uint8_t prefix_len,
+ uint8_t max_prefix_len)
+{
+ return (AF_INET == vrp->addr_fam)
+ && (as == vrp->asn)
+ && (addr == vrp->prefix.v4.s_addr)
+ && (prefix_len == vrp->prefix_length)
+ && (max_prefix_len == vrp->max_prefix_length);
+}
+
+static bool
+vrp_equals_v6(struct vrp *vrp, uint8_t as, uint32_t addr, uint8_t prefix_len,
+ uint8_t max_prefix_len)
+{
+ return (AF_INET6 == vrp->addr_fam)
+ && (as == vrp->asn)
+ && (htonl(0x20010DB8) == vrp->prefix.v6.s6_addr32[0])
+ && (0 == vrp->prefix.v6.s6_addr32[1])
+ && (0 == vrp->prefix.v6.s6_addr32[2])
+ && (htonl(addr) == vrp->prefix.v6.s6_addr32[3])
+ && (prefix_len == vrp->prefix_length)
+ && (max_prefix_len == vrp->max_prefix_length);
+}
+
+static int
+update_found(array_index index)
+{
+ ck_assert_int_eq(false, roas_found[index]);
+ roas_found[index] = true;
+ total_found++;
+ return 0;
+}
+
+static int
+foreach_cb(struct vrp *vrp, void *arg)
+{
+ char const *str;
+
+ if (vrp_equals_v4(vrp, 10, ADDR1, 24, 32))
+ return update_found(0);
+ if (vrp_equals_v4(vrp, 11, ADDR1, 24, 32))
+ return update_found(1);
+ if (vrp_equals_v4(vrp, 10, ADDR2, 24, 32))
+ return update_found(2);
+ if (vrp_equals_v4(vrp, 10, ADDR1, 25, 32))
+ return update_found(3);
+ if (vrp_equals_v4(vrp, 10, ADDR1, 24, 30))
+ return update_found(4);
+
+ if (vrp_equals_v6(vrp, 10, 1, 120, 128))
+ return update_found(5);
+ if (vrp_equals_v6(vrp, 11, 1, 120, 128))
+ return update_found(6);
+ if (vrp_equals_v6(vrp, 10, 2, 120, 128))
+ return update_found(7);
+ if (vrp_equals_v6(vrp, 10, 1, 121, 128))
+ return update_found(8);
+ if (vrp_equals_v6(vrp, 10, 1, 120, 127))
+ return update_found(9);
+
+ switch (vrp->addr_fam) {
+ case AF_INET:
+ str = v4addr2str(&vrp->prefix.v4);
+ break;
+ case AF_INET6:
+ str = v6addr2str(&vrp->prefix.v6);
+ break;
+ default:
+ ck_abort_msg("Unknown address family: %u", vrp->addr_fam);
+ }
+
+ ck_abort_msg("Foreach is looping over unknown VRP %u/%s/%u/%u.",
+ vrp->asn, str, vrp->prefix_length, vrp->max_prefix_length);
+}
+
+START_TEST(test_basic)
+{
+ struct ipv4_prefix prefix4;
+ struct ipv6_prefix prefix6;
+ struct roa_table *table;
+ array_index i;
+
+ table = roa_table_create();
+ ck_assert_ptr_ne(NULL, table);
+
+ prefix4.addr.s_addr = ADDR1;
+ prefix4.len = 24;
+ prefix6.addr.s6_addr32[0] = htonl(0x20010DB8);
+ prefix6.addr.s6_addr32[1] = 0;
+ prefix6.addr.s6_addr32[2] = 0;
+ prefix6.addr.s6_addr32[3] = htonl(0x00000001);
+ prefix6.len = 120;
+
+ /* Duplicates should be transparently not re-added. */
+
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v4(table, 10, &prefix4, 32));
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v4(table, 10, &prefix4, 32));
+
+ /* Change the AS slightly */
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v4(table, 11, &prefix4, 32));
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v4(table, 11, &prefix4, 32));
+
+ /* Change the prefix slightly */
+ prefix4.addr.s_addr = ADDR2;
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v4(table, 10, &prefix4, 32));
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v4(table, 10, &prefix4, 32));
+
+ prefix4.addr.s_addr = ADDR1;
+ prefix4.len = 25;
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v4(table, 10, &prefix4, 32));
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v4(table, 10, &prefix4, 32));
+
+ /* Change the max prefix length slightly */
+ prefix4.len = 24;
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v4(table, 10, &prefix4, 30));
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v4(table, 10, &prefix4, 30));
+
+ /* IPv6 */
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v6(table, 10, &prefix6, 128));
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v6(table, 10, &prefix6, 128));
+
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v6(table, 11, &prefix6, 128));
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v6(table, 11, &prefix6, 128));
+
+ prefix6.addr.s6_addr32[3] = htonl(0x00000002);
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v6(table, 10, &prefix6, 128));
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v6(table, 10, &prefix6, 128));
+
+ prefix6.addr.s6_addr32[3] = htonl(0x00000001);
+ prefix6.len = 121;
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v6(table, 10, &prefix6, 128));
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v6(table, 10, &prefix6, 128));
+
+ prefix6.len = 120;
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v6(table, 10, &prefix6, 127));
+ ck_assert_int_eq(0, rtrhandler_handle_roa_v6(table, 10, &prefix6, 127));
+
+ /* Check table contents */
+ memset(roas_found, 0, sizeof(roas_found));
+ total_found = 0;
+ ck_assert_int_eq(0, roa_table_foreach_roa(table, foreach_cb, NULL));
+ ck_assert_int_eq(TOTAL_ROAS, total_found);
+ for (i = 0; i < TOTAL_ROAS; i++)
+ ck_assert_int_eq(true, roas_found[i]);
+
+ roa_table_put(table);
+}
+END_TEST
+
+Suite *pdu_suite(void)
+{
+ Suite *suite;
+ TCase *core;
+
+ core = tcase_create("Core");
+ tcase_add_test(core, test_basic);
+
+ suite = suite_create("ROA Table");
+ suite_add_tcase(suite, core);
+ return suite;
+}
+
+int main(void)
+{
+ Suite *suite;
+ SRunner *runner;
+ int tests_failed;
+
+ suite = pdu_suite();
+
+ runner = srunner_create(suite);
+ srunner_run_all(runner, CK_NORMAL);
+ tests_failed = srunner_ntests_failed(runner);
+ srunner_free(runner);
+
+ return (tests_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}