]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
RIP: Properly handle route refeed
authorMaria Matejka <mq@ucw.cz>
Wed, 27 Sep 2023 14:29:44 +0000 (16:29 +0200)
committerMaria Matejka <mq@ucw.cz>
Wed, 27 Sep 2023 15:40:40 +0000 (17:40 +0200)
proto/rip/rip.c
proto/rip/rip.h

index dded05c713687b724cad52730d2b3b5cbc7b524e..9e6eed121b2a2f38f9e82e1f17ec094775c8b122 100644 (file)
@@ -328,6 +328,17 @@ rip_withdraw_rte(struct rip_proto *p, net_addr *n, struct rip_neighbor *from)
     rip_announce_rte(p, en);
 }
 
+static void
+rip_withdraw_entry(struct rip_proto *p, struct rip_entry *en)
+{
+  en->valid = RIP_ENTRY_STALE;
+  en->metric = p->infinity;
+  en->tag = 0;
+  en->from = NULL;
+  en->iface = NULL;
+  en->next_hop = IPA_NONE;
+}
+
 /*
  * rip_rt_notify - core tells us about new route, so store
  * it into our data structures.
@@ -392,17 +403,11 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *net, s
     /* Withdraw */
     en = fib_find(&p->rtable, net);
 
-    if (!en || en->valid != RIP_ENTRY_VALID)
+    if (!en || !(en->valid & RIP_ENTRY_VALID))
       return;
 
     old_metric = en->metric;
-
-    en->valid = RIP_ENTRY_STALE;
-    en->metric = p->infinity;
-    en->tag = 0;
-    en->from = NULL;
-    en->iface = NULL;
-    en->next_hop = IPA_NONE;
+    rip_withdraw_entry(p, en);
   }
 
   /* Activate triggered updates */
@@ -413,6 +418,43 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *net, s
   }
 }
 
+void
+rip_feed_begin(struct channel *C, int initial)
+{
+  if (initial)
+    return;
+
+  struct rip_proto *p = (struct rip_proto *) C->proto;
+
+  FIB_WALK(&p->rtable, struct rip_entry, en)
+  {
+    if (en->valid == RIP_ENTRY_VALID)
+      en->valid = RIP_ENTRY_REFEEDING;
+  }
+  FIB_WALK_END;
+}
+
+void
+rip_feed_end(struct channel *C)
+{
+  struct rip_proto *p = (struct rip_proto *) C->proto;
+  int changed = 0;
+
+  FIB_WALK(&p->rtable, struct rip_entry, en)
+  {
+    if (en->valid == RIP_ENTRY_REFEEDING)
+    {
+      rip_withdraw_entry(p, en);
+      changed++;
+    }
+  }
+  FIB_WALK_END;
+
+  if (changed)
+    rip_trigger_update(p);
+}
+
+
 void
 rip_flush_table(struct rip_proto *p, struct rip_neighbor *n)
 {
@@ -1159,6 +1201,8 @@ rip_init(struct proto_config *CF)
   P->iface_sub.neigh_notify = rip_neigh_notify;
   P->reload_routes = rip_reload_routes;
   P->sources.class = &rip_rte_owner_class;
+  P->feed_begin = rip_feed_begin;
+  P->feed_end = rip_feed_end;
 
   return P;
 }
index a01f8d3b4b36d5973ba0d41b050c3434f092dedf..6d70df46526c81a085f81efff49ffbc2ee22fc95 100644 (file)
@@ -194,6 +194,7 @@ struct rip_rte
 #define RIP_ENTRY_DUMMY                0       /* Only used to store list of incoming routes */
 #define RIP_ENTRY_VALID                1       /* Valid outgoing route */
 #define RIP_ENTRY_STALE                2       /* Stale outgoing route, waiting for GC */
+#define RIP_ENTRY_REFEEDING    3       /* Route valid until feed ends */
 
 static inline int rip_is_v2(struct rip_proto *p)
 { return p->rip2; }