]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Implement route withdrawal
authorIgor Putovny <igor.putovny@nic.cz>
Wed, 5 Feb 2025 18:09:55 +0000 (19:09 +0100)
committerIgor Putovny <igor.putovny@nic.cz>
Wed, 5 Feb 2025 18:10:12 +0000 (19:10 +0100)
proto/aggregator/aggregator.c
proto/aggregator/aggregator.h

index 937ed7f05bb0332a48349106876df3d839149d1b..fcfe64eb4f8597fdad312d7846881e0a267e8819 100644 (file)
@@ -332,6 +332,58 @@ proto_insert_bucket(struct aggregator_proto *p, struct aggregator_bucket *bucket
   assert(get_bucket_ptr(p, bucket->id) == bucket);
 }
 
+/*
+ * Each route which is to be withdrawed is pushed on the stack.
+ */
+static void
+push_rte_withdraw_ip4(struct aggregator_proto *p, const struct net_addr_ip4 *addr, struct aggregator_bucket *bucket)
+{
+  assert(p != NULL);
+  assert(addr != NULL);
+  assert(bucket != NULL);
+
+  struct rte_withdrawal *node = lp_allocz(p->rte_withdrawal_pool, sizeof(*node));
+
+  *node = (struct rte_withdrawal) {
+    .next = p->rte_withdrawal_stack,
+    .addr = *addr,
+    .bucket = bucket,
+  };
+
+  p->rte_withdrawal_stack = node;
+  p->rte_withdrawal_count++;
+
+  assert(p->rte_withdrawal_stack != NULL);
+}
+
+/*
+ * Withdraw all routes that are on the stack.
+ */
+static void
+aggregator_withdraw_rte(struct aggregator_proto *p)
+{
+  if ((NET_IP4 == p->addr_type && p->rte_withdrawal_count > IP4_WITHDRAWAL_LIMIT) ||
+      (NET_IP6 == p->addr_type && p->rte_withdrawal_count > IP6_WITHDRAWAL_LIMIT))
+    log(L_WARN "This number of updates was not expected."
+               "They will be processed, but please, contact the developers.");
+
+  struct rte_withdrawal *node = p->rte_withdrawal_stack;
+
+  while (node)
+  {
+    assert(node != NULL);
+    rte_update2(p->dst, (net_addr *)&node->addr, NULL, node->bucket->last_src);
+    node = node->next;
+    p->rte_withdrawal_stack = node;
+    p->rte_withdrawal_count--;
+  }
+
+  assert(p->rte_withdrawal_stack == NULL);
+  assert(p->rte_withdrawal_count == 0);
+
+  lp_flush(p->rte_withdrawal_pool);
+}
+
 /*
  * Insert prefix in @addr to prefix trie with beginning at @root and assign @bucket to this prefix.
  * If the prefix is already in the trie, update its bucket to @bucket and return updated node.
@@ -2376,6 +2428,9 @@ aggregator_start(struct proto *P)
   hmap_init(&p->bucket_id_map, p->p.pool, 1024);
   hmap_set(&p->bucket_id_map, 0);       /* 0 is default value, do not use it as ID */
 
+  p->rte_withdrawal_pool = lp_new(P->pool);
+  p->rte_withdrawal_count = 0;
+
   times_update(&main_timeloop);
   log("==== FEED START ====");
 
@@ -2400,6 +2455,7 @@ aggregator_cleanup(struct proto *P)
   p->bucket_pool = NULL;
   p->route_pool = NULL;
   p->trie_pool = NULL;
+  p->rte_withdrawal_pool = NULL;
 
   p->root = NULL;
 
@@ -2412,6 +2468,8 @@ aggregator_cleanup(struct proto *P)
   p->bucket_list_size = 0;
   p->bucket_list_count = 0;
 
+  p->rte_withdrawal_count = 0;
+
   p->bucket_id_map = (struct hmap) { 0 };
 }
 
index 114432ef8133bf7e39f6de3dd001f01c4e525be4..a956bc6ec00672f087b32b45067857807bdf7f33 100644 (file)
@@ -21,6 +21,9 @@
 #define POTENTIAL_BUCKETS_BITMAP_SIZE 8
 #define MAX_POTENTIAL_BUCKETS_COUNT   ((int)(sizeof(u32) * 8 * POTENTIAL_BUCKETS_BITMAP_SIZE))
 
+#define IP4_WITHDRAWAL_LIMIT 100
+#define IP6_WITHDRAWAL_LIMIT 200
+
 enum aggregation_mode {
   NET_AGGR, PREFIX_AGGR,
 };
@@ -52,6 +55,12 @@ struct aggregator_bucket {
   struct f_val aggr_data[0];
 };
 
+struct rte_withdrawal {
+  struct rte_withdrawal *next;
+  struct aggregator_bucket *bucket;
+  struct net_addr_ip4 addr;
+};
+
 struct aggregator_proto {
   struct proto p;
   struct channel *src, *dst;
@@ -90,6 +99,10 @@ struct aggregator_proto {
   size_t bucket_list_count;
 
   struct hmap bucket_id_map;
+
+  linpool *rte_withdrawal_pool;
+  struct rte_withdrawal *rte_withdrawal_stack;
+  int rte_withdrawal_count;
 };
 
 enum aggr_item_type {