Commit 85840d4c authored by Ondrej Zajicek (work)'s avatar Ondrej Zajicek (work)
Browse files

OSPF: Fix handling of external routes on graceful restart

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.
parent 05e3933c
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -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);
  }

+30 −8
Original line number Diff line number Diff line
@@ -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);
}


+2 −1
Original line number Diff line number Diff line
@@ -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 */
+2 −2
Original line number Diff line number Diff line
@@ -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);
}

+21 −12
Original line number Diff line number Diff line
@@ -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
Loading