if ((p->addr_type == NET_IP4 && p->rte_withdrawal_count > IP4_WITHDRAWAL_MAX_EXPECTED_LIMIT) ||
(p->addr_type == NET_IP6 && p->rte_withdrawal_count > IP6_WITHDRAWAL_MAX_EXPECTED_LIMIT))
log(L_WARN "This number of updates was not expected."
- "They will be processed, but please, contact the developers.");
+ "They will be processed. Please, report this to developers.");
struct rte_withdrawal_item *node = NULL;
}
else if (p->aggr_mode == PREFIX_AGGR)
{
+ /* When receiving initial feed, whole trie is aggregated at once */
if (!p->initial_feed)
{
+ /* After initial feed, recompute after receiving incremental update */
aggregator_recompute(p, old_route, new_route);
/* Process route withdrawals triggered by recomputation */
new_bucket->id = hmap_first_zero(&p->bucket_id_map);
hmap_set(&p->bucket_id_map, new_bucket->id);
+ /* Add bucket pointer to the list of pointers */
aggregator_add_bucket(p, new_bucket);
struct aggregator_route *arte = lp_allocz(p->route_pool, sizeof(*arte));
arte->rte.net = default_net;
default_net->routes = &arte->rte;
+ /* Insert bucket and route into their hash chains */
HASH_INSERT2(p->routes, AGGR_RTE, p->p.pool, arte);
HASH_INSERT2(p->buckets, AGGR_BUCK, p->p.pool, new_bucket);
/*
- * BIRD Internet Routing Daemon -- Prefix aggregation
+ * BIRD Internet Routing Daemon -- Prefix aggregation
*
- * (c) 2023--2025 Igor Putovny <igor.putovny@nic.cz>
- * (c) 2025 CZ.NIC, z.s.p.o.
+ * (c) 2023--2025 Igor Putovny <igor.putovny@nic.cz>
+ * (c) 2025 CZ.NIC, z.s.p.o.
*
- * Can be freely distributed and used under the terms of the GNU GPL.
+ * Can be freely distributed and used under the terms of the GNU GPL.
*/
/**
*
* Description of this implementation follows.
*
+ * Routes are put in the hash table based on their attributes.
* Route attributes are represented as buckets. All routes with the same set of
- * attributes matched by the "aggregate on" config clause get the same bucket.
+ * attributes matched by the "aggregate on" config clause are put in the same
+ * bucket.
*
* The trie contains three different kinds of nodes: original, aggregated and
* fillers.
* 1. The corresponding node is found in the trie and its original bucket
* is updated. The trie now needs to be recomputed to reflect this update.
* 2. The trie is traversed from the updated node upwards until its closest
- * IN_FIB ancestor is found. This is the prefix node that covers an
- * address space which is directly affected by the received update.
+ * IN_FIB ancestor is found. This is the prefix node that covers an
+ * address space which is directly affected by the received update.
* 3. The propagate_and_merge() pass is started for the subtree rooted in
- * the node found in the previous step. This pass propagates buckets
- * eligible for selection from the leaves upwards.
+ * the node found in the previous step. This pass propagates buckets
+ * eligible for selection from the leaves upwards.
* 4. Merging of sets of eligible buckets may leak from the subtree upwards
* by computing a different eligible bucket set for the node selected in
- * step 2. In this case, we continue upwards until the computed set is equal
- * with the previous one.
+ * step 2. In this case, we continue upwards until the computed set is
+ * equal to previous one.
* 5. From the last node changed in the last step, the group_prefixes()
- * is started downwards.
+ * is started downwards.
* 6. When this function decides to change IN_FIB status or exchange the
* selected bucket, either route update is done immediately, or route
* retraction is scheduled for later to avoid short-term misroutings.
/*
* First and second pass of Optimal Route Table Construction (ORTC) algorithm
*
- * This function is called after the trie is changed. This function is called recursively.
+ * This function is called after the trie is changed. This function is called
+ * recursively.
*
* First, this function propagates original bucket information from the node's
- * parent to the current one. (This is basically the first pass in the original algorithm.)
+ * parent to the current one. (This is basically the first pass in the original
+ * algorithm.)
*
* Then this function calls itself to its children.
*
- * After the recursion returns, sets of potential buckets from the children are merged
- * to form the potential_buckets bitmap.
+ * After the recursion returns, sets of potential buckets from the children are
+ * merged to form the potential_buckets bitmap of the current node.
*
* With this, the function both propagates changes down and up during one pass.
- *
+ *
* The argument is the node from which to descend.
+ * @node: node from which to descend
*/
static void
aggregator_propagate_and_merge(struct trie_node *node)
ASSERT_DIE(node->parent->original_bucket != NULL);
node->original_bucket = node->parent->original_bucket;
- /* This node will be recalculated anyway, therefore for now we indicate
+ /*
+ * This node will be recalculated anyway, therefore for now we indicate
* by FILLER that the trie state is not consistent with the routes
- * in the target routing table. */
+ * in the target routing table.
+ */
node->px_origin = FILLER;
}
node->potential_buckets_count = 0;
memset(node->potential_buckets, 0, sizeof(node->potential_buckets));
- /* For the leaf node, by definition, the only bucket in the bitmap is the
- * original bucket. */
+ /*
+ * For the leaf node, by definition, the only bucket in the bitmap is the
+ * original bucket.
+ */
aggregator_node_add_potential_bucket(node, node->original_bucket->id);
/* No children, no further work. Done! */
return;
}
- /* Prepare an imaginary node in case some children are missing.
- * This node's potential buckets is just this node's original bucket
- * and nothing else. This fixes the (kinda) missing first pass
- * when comparing our algorithm to the original one. */
+ /*
+ * Prepare an imaginary node in case some children are missing. This node's
+ * potential buckets is just this node's original bucket and nothing else.
+ * This fixes the (kinda) missing first pass when comparing our algorithm
+ * to the original one.
+ */
struct trie_node imaginary_node = { 0 };
aggregator_node_add_potential_bucket(&imaginary_node, node->original_bucket->id);
}
/*
- * Export prefix of the current node to FIB and mark node as IN_FIB
+ * Export prefix of the current node to FIB and set node status to IN_FIB
*/
static void
aggregator_export_node_prefix(struct aggregator_proto *p, struct trie_node *node, ip_addr prefix, u32 pxlen)
{
ASSERT_DIE(old_bucket != NULL);
- /* Node's bucket has changed, remove old route */
+ /* Node's bucket has changed, remove old route before exporting new */
if (old_bucket && old_bucket != node->selected_bucket)
{
aggregator_prepare_rte_withdrawal(p, prefix, pxlen, old_bucket);
}
/*
- * Remove prefix of the current node from FIB and mark node as NON_FIB
+ * Remove prefix of the current node from FIB and set node status to NON_FIB
*/
static void
aggregator_remove_node_prefix(struct aggregator_proto *p, struct trie_node *node, ip_addr prefix, u32 pxlen)
/*
* Original prefix stays original, otherwise it was aggregated and becomes
- * a filler
+ * a filler.
*/
node->px_origin = (node->px_origin == ORIGINAL) ? ORIGINAL : FILLER;
}