*new = (struct trie_node) {
.parent = NULL,
.child = { NULL, NULL },
+ .bucket = NULL,
.potential_buckets_count = 0,
};
* Insert prefix in @addr to prefix trie with root at @node
*/
static void
-trie_insert_prefix(const union net_addr_union *addr, struct aggregator_bucket *bucket, struct trie_node *node, slab *trie_slab)
+trie_insert_prefix(const union net_addr_union *addr, const struct aggregator_bucket *bucket, struct trie_node * const root, slab *trie_slab)
{
assert(addr != NULL);
- assert(node != NULL);
+ assert(bucket != NULL);
+ assert(root != NULL);
+ assert(trie_slab != NULL);
if (addr->n.type != NET_IP4)
return;
const struct net_addr_ip4 * const ip4 = &addr->ip4;
+ struct trie_node *node = root;
+
+ if (root->bucket == NULL) // default bucket (nexthop)?
+ root->bucket = bucket;
for (u32 i = 0; i < ip4->pxlen; i++)
{
{
struct trie_node *new = new_node(trie_slab);
new->parent = node;
+ new->bucket = bucket;
node->child[bit] = new;
}
node = node->child[bit];
+ //node->bucket = bucket;
+
+ //if ((int)i == ip4->pxlen - 1)
+ //node->bucket = bucket;
+ // node->potential_buckets[node->potential_buckets_count++] = bucket;
+ }
+}
+
+static struct aggregator_bucket *
+get_ancestor_bucket(const struct trie_node *node)
+{
+ /* Defined for other than root nodes */
+ assert(node->parent != NULL);
+
+ while (1)
+ {
+ if (node->parent == NULL)
+ return NULL;
+
+ if (node->parent->bucket != NULL)
+ return node->parent->bucket;
- if ((int)i == ip4->pxlen - 1)
- node->bucket = bucket;
+ node = node->parent;
}
}
first_pass(struct trie_node *node, slab *trie_slab)
{
assert(node != NULL);
+ assert(trie_slab != NULL);
+ //assert(node->bucket != NULL);
if (is_leaf(node))
+ {
+ //assert(node->bucket != NULL);
+
+ //if (node->bucket != NULL)
+ //node->potential_buckets[node->potential_buckets_count++] = node->bucket;
+
+ node->potential_buckets[node->potential_buckets_count++] = get_ancestor_bucket(node);
return;
+ }
for (int i = 0; i < 2; i++)
{
if (!node->child[i])
{
+ /*
node->child[i] = new_node(trie_slab);
*node->child[i] = (struct trie_node) {
.parent = node,
- .child[0] = NULL,
- .child[1] = NULL,
+ .child = { NULL, NULL },
.bucket = node->parent ? node->parent->bucket : NULL,
.potential_buckets_count = 0,
};
+ */
+
+ struct trie_node *new = new_node(trie_slab);
+
+ *new = (struct trie_node) {
+ .parent = node,
+ };
+
+ //new->potential_buckets[new->potential_buckets_count++] = get_ancestor_bucket(new);
+ node->child[i] = new;
}
}
+ /* Preorder traversal */
first_pass(node->child[0], trie_slab);
first_pass(node->child[1], trie_slab);
+
+ /* Discard bucket in interior nodes */
+ node->bucket = NULL;
}
static int
{
assert(node != NULL);
- /* Potential nexthop is assigned to nexthop assigned during first pass */
+ if (is_leaf(node))
+ {
+ assert(node->potential_buckets_count > 0);
+ return;
+ }
+
+ /*
+ // Potential nexthop is assigned to nexthop which was assigned during first pass
if (is_leaf(node))
{
node->potential_buckets[node->potential_buckets_count++] = node->bucket;
return;
}
+ */
struct trie_node * const left = node->child[0];
struct trie_node * const right = node->child[1];
aggregator_bucket_union(node, left, right);
else
aggregator_bucket_intersection(node, left, right);
+
+ log("node: %p, potential buckets count: %d", node, node->potential_buckets_count);
+
+ assert(node->potential_buckets_count > 0);
}
/*
return 0;
}
+/*
static void
third_pass_helper(struct trie_node *node)
{
if (!node)
return;
+ //third_pass_helper(node->child[0]);
+ //third_pass_helper(node->child[1]);
+
assert(node->parent != NULL);
if (node->parent->bucket == NULL || bucket_is_present(node->parent->bucket, node))
node->bucket = node->potential_buckets[0];
}
- third_pass_helper(node->child[0]);
- third_pass_helper(node->child[1]);
+ //third_pass_helper(node->child[0]);
+ //third_pass_helper(node->child[1]);
- /* Leaf node with unassigned nexthop is deleted */
+ // Leaf node with unassigned nexthop is deleted
if (is_leaf(node) && node->bucket == NULL)
remove_node(node);
}
if (!node)
return;
- /* Node is a root */
+ // Node is a root
if (!node->parent)
{
assert(node->child[0] != NULL);
}
}
}
+*/
+
+static void
+remove_potential_buckets(struct trie_node *node)
+{
+ for (int i = 0; i < node->potential_buckets_count; i++)
+ node->potential_buckets[i] = NULL;
+
+ node->potential_buckets_count = 0;
+}
+
+static void
+third_pass(struct trie_node *node)
+{
+ if (node == NULL)
+ return;
+
+ if (node->parent == NULL)
+ return;
+
+ const struct aggregator_bucket *inherited_bucket = get_ancestor_bucket(node);
+
+ if (bucket_is_present(inherited_bucket, node))
+ {
+ node->bucket = NULL;
+ }
+ else
+ {
+ assert(node->potential_buckets_count > 0);
+ node->bucket = node->potential_buckets[0];
+ }
+
+ third_pass(node->child[0]);
+ third_pass(node->child[1]);
+}
+
+/*
+static void
+third_pass(struct trie_node *node)
+{
+ // End of recursion
+ if (is_leaf(node))
+ {
+ assert(node->potential_buckets_count > 0);
+ node->bucket = node->potential_buckets[0];
+ return;
+ }
+
+ // Root
+ if (node->parent == NULL)
+ {
+ assert(node->potential_buckets_count > 0);
+ node->bucket = node->potential_buckets[0];
+ }
+
+ for (int i = 0; i < 2; i++)
+ {
+ const struct aggregator_bucket *inherited = get_ancestor_bucket(node);
+
+ if (bucket_is_present(inherited, node->child[i]))
+ {
+ remove_potential_buckets(node->child[i]);
+ node->bucket = NULL;
+ }
+ else
+ {
+ assert(node->potential_buckets_count > 0);
+ node->bucket = node->potential_buckets[i];
+ }
+
+ third_pass(node->child[i]);
+ }
+}
+*/
static void
get_trie_prefix_count_helper(const struct trie_node *node, int *count)
if (node->child[0])
get_trie_prefix_count_helper(node->child[0], count);
-
+
if (node->child[1])
get_trie_prefix_count_helper(node->child[1], count);
}
log("WARNING: root is leaf!");
const int prefix_count = get_trie_prefix_count(p->root);
-
+
struct aggregated_prefixes *prefixes = allocz(sizeof(struct aggregated_prefixes) + sizeof(struct prefix_bucket) * prefix_count);
prefixes->capacity = prefix_count;
prefixes->count = 0;
}
log("%s", buf.start);
-
+
/* Announce changes */
if (old_bucket)
aggregator_bucket_update(p, old_bucket, net);