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.
This commit is contained in:
parent
05e3933c06
commit
85840d4c03
6 changed files with 75 additions and 35 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
@ -118,7 +118,8 @@ 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_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; } }
|
||||
|
|
Loading…
Reference in a new issue