]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
OSPF: Fix handling of external routes on graceful restart
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Tue, 9 Jul 2019 01:31:54 +0000 (03:31 +0200)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Tue, 9 Jul 2019 01:39:19 +0000 (03:39 +0200)
We need to flush learned external LSAs a bit later than other LSAs (after
first feed after end of the graceful restart) to avoid flap of external
routes.

proto/ospf/iface.c
proto/ospf/ospf.c
proto/ospf/ospf.h
proto/ospf/rt.c
proto/ospf/topology.c
proto/ospf/topology.h

index 6e7e498f27400066ce54bdaa478f3ad563241b0b..f5c691993014ff1896516bb9f55ceacc80ffadcc 100644 (file)
@@ -880,7 +880,6 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
               ifname, ifa->priority, new->priority);
 
     ifa->priority = new->priority;
-    ospf_iface_sm(ifa, ISM_NEICH);
     ospf_notify_link_lsa(ifa);
   }
 
index 968d7aa0dbc27db443c239d1edb03b7dc6dbf462..abd4cd8415240aa7f289a5ffc9ba14ab167a4c1b 100644 (file)
@@ -246,18 +246,33 @@ void
 ospf_stop_gr_recovery(struct ospf_proto *p)
 {
   p->gr_recovery = 0;
+  p->gr_cleanup = 1;
   p->gr_timeout = 0;
-  channel_graceful_restart_unlock(p->p.main_channel);
 
   /* Reorigination of router/network LSAs is already scheduled */
-  ospf_mark_lsadb(p);
 
-  /*
-   * NOTE: We should move channel_graceful_restart_unlock() to the end of
-   * ospf_disp() in order to have local LSA reorigination / LSAdb cleanup /
-   * routing table recomputation before official end of GR. It does not matter
-   * when we are single-threaded.
-   */
+  /* Rest is done in ospf_cleanup_gr_recovery() */
+}
+
+static void
+ospf_cleanup_gr_recovery(struct ospf_proto *p)
+{
+  struct top_hash_entry *en;
+
+  /* Flush dirty LSAa except external ones, these will be handled by feed */
+  WALK_SLIST(en, p->lsal)
+    if (en->gr_dirty)
+    {
+      if ((en->lsa_type == LSA_T_EXT) || (en->lsa_type == LSA_T_NSSA))
+       en->mode = LSA_M_EXPORT;
+      else
+       ospf_flush_lsa(p, en);
+    }
+
+  /* End graceful restart on channel, will also schedule feed */
+  channel_graceful_restart_unlock(p->p.main_channel);
+
+  p->gr_cleanup = 0;
 }
 
 static int
@@ -361,6 +376,8 @@ ospf_init(struct proto_config *CF)
   P->ifa_notify = cf->ospf2 ? ospf_ifa_notify2 : ospf_ifa_notify3;
   P->preexport = ospf_preexport;
   P->reload_routes = ospf_reload_routes;
+  P->feed_begin = ospf_feed_begin;
+  P->feed_end = ospf_feed_end;
   P->make_tmp_attrs = ospf_make_tmp_attrs;
   P->store_tmp_attrs = ospf_store_tmp_attrs;
   P->rte_better = ospf_rte_better;
@@ -436,6 +453,7 @@ ospf_disp(timer * timer)
 {
   struct ospf_proto *p = timer->data;
 
+  /* Check for end of graceful restart */
   if (p->gr_recovery)
     ospf_update_gr_recovery(p);
 
@@ -448,6 +466,10 @@ ospf_disp(timer * timer)
   /* Calculate routing table */
   if (p->calcrt)
     ospf_rt_spf(p);
+
+  /* Cleanup after graceful restart */
+  if (p->gr_cleanup)
+    ospf_cleanup_gr_recovery(p);
 }
 
 
index aac135120f43b80463792416da960e2eb1bed40a..3fd1c363f8b0f2a6e5aced94f417a1f62edc0da7 100644 (file)
@@ -223,7 +223,8 @@ struct ospf_proto
   int areano;                  /* Number of area I belong to */
   int padj;                    /* Number of neighbors in Exchange or Loading state */
   int gr_count;                        /* Number of neighbors in graceful restart state */
-  int gr_recovery;             /* Graceful restart recovery is active */
+  u8 gr_recovery;              /* Graceful restart recovery is active */
+  u8 gr_cleanup;               /* GR cleanup scheduled */
   btime gr_timeout;            /* The end time of grace restart recovery */
   struct fib rtf;              /* Routing table */
   struct idm idm;              /* OSPFv3 LSA ID map */
index 126ef201e714e31c23020f2ef728f725eec766c6..b5787b540d6f9f104e213fc17d91ea7ea25b9f7a 100644 (file)
@@ -1640,7 +1640,7 @@ ospf_rt_reset(struct ospf_proto *p)
     en->lb = IPA_NONE;
 
     if (en->mode == LSA_M_RTCALC)
-      en->mode = LSA_M_STALE;
+      en->mode = LSA_M_RTCALC_STALE;
   }
 
   WALK_LIST(oa, p->area_list)
@@ -2117,7 +2117,7 @@ again2:
 
   /* Cleanup stale LSAs */
   WALK_SLIST(en, p->lsal)
-    if (en->mode == LSA_M_STALE)
+    if (en->mode == LSA_M_RTCALC_STALE)
       ospf_flush_lsa(p, en);
 }
 
index efd03b54e0dafe6cdf8231967750655530f7ca93..a58757709de1c06cd156747a3ca9e4caed6e5b38 100644 (file)
@@ -71,6 +71,7 @@ ospf_install_lsa(struct ospf_proto *p, struct ospf_lsa_header *lsa, u32 type, u3
   en->lsa = *lsa;
   en->init_age = en->lsa.age;
   en->inst_time = current_time();
+  en->gr_dirty = p->gr_recovery && (lsa->rt == p->router_id);
 
   /*
    * We do not set en->mode. It is either default LSA_M_BASIC, or in a special
@@ -246,7 +247,7 @@ ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa
   en->lsa.age = 0;
   en->init_age = 0;
   en->inst_time = current_time();
-  en->dirty = 0;
+  en->gr_dirty = 0;
   lsa_generate_checksum(&en->lsa, en->lsa_body);
 
   OSPF_TRACE(D_EVENTS, "Originating LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
@@ -329,7 +330,7 @@ ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa)
       (lsa_length == en->lsa.length) &&
       !memcmp(lsa_body, en->lsa_body, lsa_blen) &&
       (!ospf_is_v2(p) || (lsa->opts == lsa_get_options(&en->lsa))) &&
-      !en->dirty)
+      !en->gr_dirty)
     goto drop;
 
   lsa_body = lsab_flush(p);
@@ -422,6 +423,7 @@ void
 ospf_flush_lsa(struct ospf_proto *p, struct top_hash_entry *en)
 {
   en->nf = NULL;
+  en->gr_dirty = 0;
 
   if (en->next_lsa_body)
   {
@@ -520,12 +522,6 @@ ospf_update_lsadb(struct ospf_proto *p)
       continue;
     }
 
-    if (en->dirty)
-    {
-      ospf_flush_lsa(p, en);
-      continue;
-    }
-
     if ((en->lsa.rt == p->router_id) && (real_age >= LSREFRESHTIME))
     {
       ospf_refresh_lsa(p, en);
@@ -543,14 +539,27 @@ ospf_update_lsadb(struct ospf_proto *p)
 }
 
 void
-ospf_mark_lsadb(struct ospf_proto *p)
+ospf_feed_begin(struct channel *C, int initial UNUSED)
 {
+  struct ospf_proto *p = (struct ospf_proto *) C->proto;
   struct top_hash_entry *en;
 
-  /* Mark all local LSAs as dirty */
+  /* Mark all external LSAs as stale */
   WALK_SLIST(en, p->lsal)
-    if (en->lsa.rt == p->router_id)
-      en->dirty = 1;
+    if (en->mode == LSA_M_EXPORT)
+      en->mode = LSA_M_EXPORT_STALE;
+}
+
+void
+ospf_feed_end(struct channel *C)
+{
+  struct ospf_proto *p = (struct ospf_proto *) C->proto;
+  struct top_hash_entry *en;
+
+  /* Flush stale LSAs */
+  WALK_SLIST(en, p->lsal)
+    if (en->mode == LSA_M_EXPORT_STALE)
+      ospf_flush_lsa(p, en);
 }
 
 static u32
index ffae436ad839009399ae90ab35b74a8c69add362..535d1f1bb9aa3a83e779a1e631c2c8ac1b69b44d 100644 (file)
@@ -33,7 +33,7 @@ struct top_hash_entry
   u32 lb_id;                   /* Interface ID of link back iface (for bcast or NBMA networks) */
   u32 dist;                    /* Distance from the root */
   int ret_count;               /* Number of retransmission lists referencing the entry */
-  u8 dirty;                    /* Will be flushed during next LSAdb update unless reoriginated*/
+  u8 gr_dirty;                 /* Local LSA received during GR, will be removed unless reoriginated */
   u8 color;
 #define OUTSPF 0
 #define CANDIDATE 1
@@ -115,10 +115,11 @@ struct top_hash_entry
  */
 
 
-#define LSA_M_BASIC    0
-#define LSA_M_EXPORT   1
-#define LSA_M_RTCALC   2
-#define LSA_M_STALE    3
+#define LSA_M_BASIC            0
+#define LSA_M_EXPORT           1
+#define LSA_M_RTCALC           2
+#define LSA_M_EXPORT_STALE     3
+#define LSA_M_RTCALC_STALE     4
 
 /*
  * LSA entry modes:
@@ -128,9 +129,13 @@ struct top_hash_entry
  * routing table calculation is scheduled. This is also the mode used for LSAs
  * received from neighbors. Example: Router-LSAs, Network-LSAs.
  *
- * LSA_M_EXPORT - like LSA_M_BASIC, but the routing table calculation does not
- * depend on the LSA. Therefore, the calculation is not scheduled when the LSA
- * is changed. Example: AS-external-LSAs for exported routes.
+ * LSA_M_EXPORT - The LSA is originated using ospf_originate_lsa() as a
+ * consequence of route export to the OSPF instance. It has to be reoriginated
+ * during each channel feed, otherwise it is flushed automatically at the end of
+ * the feed. May be originated and flushed asynchronously. Also, routing table
+ * calculation does not depend on the LSA. Therefore, the routing table
+ * calculation is not scheduled when the LSA is changed. Example:
+ * AS-external-LSAs for exported routes.
  *
  * LSA_M_RTCALC - The LSA has to be requested using ospf_originate_lsa() during
  * each routing table calculation, otherwise it is flushed automatically at the
@@ -138,8 +143,11 @@ struct top_hash_entry
  * source for it. Therefore, the calculation is not scheduled when the LSA is
  * changed. Example: Summary-LSAs.
  *
- * LSA_M_STALE - Temporary state for LSA_M_RTCALC that is not requested during
- * the current routing table calculation.
+ * LSA_M_EXPORT_STALE - Temporary state for LSA_M_EXPORT that is not requested
+ * during current external route feed.
+ *
+ * LSA_M_RTCALC_STALE - Temporary state for LSA_M_RTCALC that is not requested
+ * during current routing table calculation.
  *
  *
  * Note that we do not schedule the routing table calculation when the age of
@@ -181,7 +189,8 @@ struct top_hash_entry * ospf_originate_lsa(struct ospf_proto *p, struct ospf_new
 void ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_lsa_header *lsa, u32 type, u32 domain, void *body);
 void ospf_flush_lsa(struct ospf_proto *p, struct top_hash_entry *en);
 void ospf_update_lsadb(struct ospf_proto *p);
-void ospf_mark_lsadb(struct ospf_proto *p);
+void ospf_feed_begin(struct channel *C, int initial);
+void ospf_feed_end(struct channel *C);
 
 static inline void ospf_flush2_lsa(struct ospf_proto *p, struct top_hash_entry **en)
 { if (*en) { ospf_flush_lsa(p, *en); *en = NULL; } }