mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-28 13:20:12 +00:00
ospf6d: Handle Premature Aging of LSAs
RFC 2328 (14.1) Premature aging of LSAs from routing domain : When ospf6d is going away (router going down), send MAXAGEd self originated LSAs to all neighbors in routing domain to trigger Premature aging to remove from resepective LSDBs. Neighbor Router Reboot: Upon receiving Self-originate MAXAGEd LSA, simply discard, Current copy could be non maxaged latest. For neighbor advertised LSA's (current copy in LSDB) is set to MAXAGE but received new LSA with Non-MAXAGE (with current age), discard the current MAXAGE LSA, Send latest copy of LSA to neighbors and update the LSDB with new LSA. When a neighbor transition to FULL, trigger AS-External LSAs update from external LSDB to new neighbor. Testing: R1 ---- DUT --- R5 | \ R2 R3 | R4 Area 1: R5 and DUT Area 0: DUT, R1, R2, R3 Area 2: R2 R4 Add IPv6 static routes at R5 Redistribute kernel routes at R5, Validate routes at R4, redistributed via backbone to area 2. Stop n start frr.service at R5 and validated MAXAGE LSAs then recent age LSAs in Database at DUT-R4. Validated external routes installed DUT to R4. Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
This commit is contained in:
parent
d0a6f3e0c5
commit
76249532fa
@ -148,6 +148,32 @@ static void ospf6_as_external_lsa_originate(struct ospf6_route *route)
|
||||
ospf6_lsa_originate_process(lsa, ospf6);
|
||||
}
|
||||
|
||||
int ospf6_orig_as_external_lsa(struct thread *thread)
|
||||
{
|
||||
struct ospf6_interface *oi;
|
||||
struct ospf6_lsa *lsa;
|
||||
uint32_t type, adv_router;
|
||||
|
||||
oi = (struct ospf6_interface *)THREAD_ARG(thread);
|
||||
oi->thread_as_extern_lsa = NULL;
|
||||
|
||||
if (oi->state == OSPF6_INTERFACE_DOWN)
|
||||
return 0;
|
||||
|
||||
type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
|
||||
adv_router = oi->area->ospf6->router_id;
|
||||
for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, adv_router, lsa)) {
|
||||
if (IS_OSPF6_DEBUG_ASBR)
|
||||
zlog_debug("%s: Send update of AS-External LSA %s seq 0x%x",
|
||||
__PRETTY_FUNCTION__, lsa->name,
|
||||
ntohl(lsa->header->seqnum));
|
||||
|
||||
ospf6_flood_interface(NULL, lsa, oi);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static route_tag_t ospf6_as_external_lsa_get_tag(struct ospf6_lsa *lsa)
|
||||
{
|
||||
struct ospf6_as_external_lsa *external;
|
||||
|
@ -192,10 +192,6 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa)
|
||||
struct timeval now;
|
||||
struct ospf6_lsa *old;
|
||||
|
||||
if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type)
|
||||
|| IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type))
|
||||
zlog_debug("Install LSA: %s", lsa->name);
|
||||
|
||||
/* Remove the old instance from all neighbors' Link state
|
||||
retransmission list (RFC2328 13.2 last paragraph) */
|
||||
old = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
|
||||
@ -237,6 +233,13 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa)
|
||||
ospf6_lsa_checksum(lsa->header);
|
||||
}
|
||||
|
||||
if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type)
|
||||
|| IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type))
|
||||
zlog_debug("%s Install LSA: %s age %d seqnum %x in LSDB.",
|
||||
__PRETTY_FUNCTION__, lsa->name,
|
||||
ntohs(lsa->header->age),
|
||||
ntohl(lsa->header->seqnum));
|
||||
|
||||
/* actually install */
|
||||
lsa->installed = now;
|
||||
ospf6_lsdb_add(lsa, lsa->lsdb);
|
||||
@ -246,7 +249,7 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa)
|
||||
|
||||
/* RFC2740 section 3.5.2. Sending Link State Update packets */
|
||||
/* RFC2328 section 13.3 Next step in the flooding procedure */
|
||||
static void ospf6_flood_interface(struct ospf6_neighbor *from,
|
||||
void ospf6_flood_interface(struct ospf6_neighbor *from,
|
||||
struct ospf6_lsa *lsa,
|
||||
struct ospf6_interface *oi)
|
||||
{
|
||||
@ -343,15 +346,24 @@ static void ospf6_flood_interface(struct ospf6_neighbor *from,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* (d) add retrans-list, schedule retransmission */
|
||||
if (is_debug)
|
||||
zlog_debug("Add retrans-list of this neighbor");
|
||||
ospf6_increment_retrans_count(lsa);
|
||||
ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list);
|
||||
thread_add_timer(master, ospf6_lsupdate_send_neighbor, on,
|
||||
on->ospf6_if->rxmt_interval,
|
||||
&on->thread_send_lsupdate);
|
||||
retrans_added++;
|
||||
if (ospf6->inst_shutdown) {
|
||||
if (is_debug)
|
||||
zlog_debug("%s: Send LSA %s (age %d) update now",
|
||||
__PRETTY_FUNCTION__, lsa->name,
|
||||
ntohs(lsa->header->age));
|
||||
ospf6_lsupdate_send_neighbor_now(on, lsa);
|
||||
continue;
|
||||
} else {
|
||||
/* (d) add retrans-list, schedule retransmission */
|
||||
if (is_debug)
|
||||
zlog_debug("Add retrans-list of this neighbor");
|
||||
ospf6_increment_retrans_count(lsa);
|
||||
ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list);
|
||||
thread_add_timer(master, ospf6_lsupdate_send_neighbor,
|
||||
on, on->ospf6_if->rxmt_interval,
|
||||
&on->thread_send_lsupdate);
|
||||
retrans_added++;
|
||||
}
|
||||
}
|
||||
|
||||
/* (2) examin next interface if not added to retrans-list */
|
||||
@ -806,6 +818,17 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
|
||||
zlog_debug("Received is duplicated LSA");
|
||||
SET_FLAG(new->flag, OSPF6_LSA_DUPLICATE);
|
||||
}
|
||||
if (old->header->adv_router ==
|
||||
from->ospf6_if->area->ospf6->router_id
|
||||
&& OSPF6_LSA_IS_MAXAGE(new)) {
|
||||
ospf6_acknowledge_lsa(new, ismore_recent, from);
|
||||
ospf6_lsa_delete(new);
|
||||
if (is_debug)
|
||||
zlog_debug("%s: Received is self orig MAXAGE LSA %s, discard (ismore_recent %d)",
|
||||
__PRETTY_FUNCTION__, old->name,
|
||||
ismore_recent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* if no database copy or received is more recent */
|
||||
@ -959,12 +982,34 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
|
||||
"Send back directly and then discard");
|
||||
}
|
||||
|
||||
/* Neighbor router sent recent age for LSA,
|
||||
* Router could be restarted while current copy is
|
||||
* MAXAGEd and not removed.*/
|
||||
if (OSPF6_LSA_IS_MAXAGE(old) &&
|
||||
!OSPF6_LSA_IS_MAXAGE(new)) {
|
||||
|
||||
if (is_debug)
|
||||
zlog_debug("%s: Current copy of LSA %s is MAXAGE, but new has recent Age.",
|
||||
old->name,
|
||||
__PRETTY_FUNCTION__);
|
||||
|
||||
ospf6_lsa_purge(old);
|
||||
if (new->header->adv_router
|
||||
!= from->ospf6_if->area->
|
||||
ospf6->router_id)
|
||||
ospf6_flood(from, new);
|
||||
|
||||
ospf6_install_lsa(new);
|
||||
return;
|
||||
}
|
||||
|
||||
/* XXX, MinLSArrival check !? RFC 2328 13 (8) */
|
||||
|
||||
ospf6_lsdb_add(ospf6_lsa_copy(old),
|
||||
from->lsupdate_list);
|
||||
thread_add_event(master, ospf6_lsupdate_send_neighbor,
|
||||
from, 0, &from->thread_send_lsupdate);
|
||||
|
||||
ospf6_lsa_delete(new);
|
||||
return;
|
||||
}
|
||||
@ -972,7 +1017,6 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DEFUN (debug_ospf6_flooding,
|
||||
debug_ospf6_flooding_cmd,
|
||||
"debug ospf6 flooding",
|
||||
|
@ -58,5 +58,10 @@ extern void ospf6_install_lsa(struct ospf6_lsa *lsa);
|
||||
|
||||
extern int config_write_ospf6_debug_flood(struct vty *vty);
|
||||
extern void install_element_ospf6_debug_flood(void);
|
||||
extern void ospf6_flood_interface(struct ospf6_neighbor *from,
|
||||
struct ospf6_lsa *lsa,
|
||||
struct ospf6_interface *oi);
|
||||
extern int ospf6_lsupdate_send_neighbor_now(struct ospf6_neighbor *on,
|
||||
struct ospf6_lsa *lsa);
|
||||
|
||||
#endif /* OSPF6_FLOOD_H */
|
||||
|
@ -301,6 +301,7 @@ void ospf6_interface_disable(struct ospf6_interface *oi)
|
||||
THREAD_OFF(oi->thread_network_lsa);
|
||||
THREAD_OFF(oi->thread_link_lsa);
|
||||
THREAD_OFF(oi->thread_intra_prefix_lsa);
|
||||
THREAD_OFF(oi->thread_as_extern_lsa);
|
||||
}
|
||||
|
||||
static struct in6_addr *
|
||||
@ -532,6 +533,7 @@ static void ospf6_interface_state_change(u_char next_state,
|
||||
OSPF6_NETWORK_LSA_EXECUTE(oi);
|
||||
OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT(oi);
|
||||
OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oi->area);
|
||||
OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT(oi);
|
||||
} else if (prev_state == OSPF6_INTERFACE_DR
|
||||
|| next_state == OSPF6_INTERFACE_DR) {
|
||||
OSPF6_NETWORK_LSA_SCHEDULE(oi);
|
||||
|
@ -108,6 +108,7 @@ struct ospf6_interface {
|
||||
struct thread *thread_network_lsa;
|
||||
struct thread *thread_link_lsa;
|
||||
struct thread *thread_intra_prefix_lsa;
|
||||
struct thread *thread_as_extern_lsa;
|
||||
|
||||
struct ospf6_route_table *route_connected;
|
||||
|
||||
|
@ -185,11 +185,21 @@ struct ospf6_intra_prefix_lsa {
|
||||
0, &(oi)->thread_intra_prefix_lsa); \
|
||||
} while (0)
|
||||
|
||||
#define OSPF6_AS_EXTERN_LSA_SCHEDULE(oi) \
|
||||
do { \
|
||||
if (!CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \
|
||||
thread_add_event( \
|
||||
master, \
|
||||
ospf6_orig_as_external_lsa, oi, \
|
||||
0, &(oi)->thread_as_extern_lsa); \
|
||||
} while (0)
|
||||
|
||||
#define OSPF6_NETWORK_LSA_EXECUTE(oi) \
|
||||
do { \
|
||||
THREAD_OFF((oi)->thread_network_lsa); \
|
||||
thread_execute(master, ospf6_network_lsa_originate, oi, 0); \
|
||||
} while (0)
|
||||
|
||||
#define OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT(oi) \
|
||||
do { \
|
||||
THREAD_OFF((oi)->thread_intra_prefix_lsa); \
|
||||
@ -198,6 +208,11 @@ struct ospf6_intra_prefix_lsa {
|
||||
0); \
|
||||
} while (0)
|
||||
|
||||
#define OSPF6_AS_EXTERN_LSA_EXECUTE(oi) \
|
||||
do { \
|
||||
THREAD_OFF((oi)->thread_as_extern_lsa); \
|
||||
thread_execute(master, ospf6_orig_as_external_lsa, oi, 0); \
|
||||
} while (0)
|
||||
|
||||
/* Function Prototypes */
|
||||
extern char *ospf6_router_lsdesc_lookup(u_char type, u_int32_t interface_id,
|
||||
@ -215,7 +230,7 @@ extern int ospf6_intra_prefix_lsa_originate_transit(struct thread *);
|
||||
extern int ospf6_intra_prefix_lsa_originate_stub(struct thread *);
|
||||
extern void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa);
|
||||
extern void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa);
|
||||
|
||||
extern int ospf6_orig_as_external_lsa(struct thread *thread);
|
||||
extern void ospf6_intra_route_calculation(struct ospf6_area *oa);
|
||||
extern void ospf6_intra_brouter_calculation(struct ospf6_area *oa);
|
||||
|
||||
|
@ -706,6 +706,37 @@ int ospf6_lsa_refresh(struct thread *thread)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ospf6_flush_self_originated_lsas_now(void)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct ospf6_area *oa;
|
||||
struct ospf6_lsa *lsa;
|
||||
const struct route_node *end = NULL;
|
||||
uint32_t type, adv_router;
|
||||
|
||||
ospf6->inst_shutdown = 1;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
|
||||
end = ospf6_lsdb_head(oa->lsdb_self, 0, 0,
|
||||
ospf6->router_id, &lsa);
|
||||
while (lsa) {
|
||||
/* RFC 2328 (14.1): Set MAXAGE */
|
||||
lsa->header->age = htons(OSPF_LSA_MAXAGE);
|
||||
/* Flood MAXAGE LSA*/
|
||||
ospf6_flood(NULL, lsa);
|
||||
|
||||
lsa = ospf6_lsdb_next(end, lsa);
|
||||
}
|
||||
}
|
||||
|
||||
type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
|
||||
adv_router = ospf6->router_id;
|
||||
for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, adv_router, lsa)) {
|
||||
/* RFC 2328 (14.1): Set MAXAGE */
|
||||
lsa->header->age = htons(OSPF_LSA_MAXAGE);
|
||||
ospf6_flood(NULL, lsa);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fletcher Checksum -- Refer to RFC1008. */
|
||||
|
||||
|
@ -253,5 +253,6 @@ extern void ospf6_lsa_terminate(void);
|
||||
extern int config_write_ospf6_debug_lsa(struct vty *vty);
|
||||
extern void install_element_ospf6_debug_lsa(void);
|
||||
extern void ospf6_lsa_age_set(struct ospf6_lsa *lsa);
|
||||
extern void ospf6_flush_self_originated_lsas_now(void);
|
||||
|
||||
#endif /* OSPF6_LSA_H */
|
||||
|
@ -334,6 +334,7 @@ int ospf6_lsdb_maxage_remover(struct ospf6_lsdb *lsdb)
|
||||
}
|
||||
if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type))
|
||||
zlog_debug("Remove MaxAge %s", lsa->name);
|
||||
|
||||
if (CHECK_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED)) {
|
||||
UNSET_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED);
|
||||
/*
|
||||
|
@ -2163,6 +2163,40 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ospf6_lsupdate_send_neighbor_now(struct ospf6_neighbor *on,
|
||||
struct ospf6_lsa *lsa)
|
||||
{
|
||||
struct ospf6_header *oh;
|
||||
struct ospf6_lsupdate *lsupdate;
|
||||
u_char *p;
|
||||
int lsa_cnt = 0;
|
||||
|
||||
memset(sendbuf, 0, iobuflen);
|
||||
oh = (struct ospf6_header *)sendbuf;
|
||||
lsupdate = (struct ospf6_lsupdate *)((caddr_t)oh
|
||||
+ sizeof(struct ospf6_header));
|
||||
|
||||
p = (u_char *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate));
|
||||
ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
|
||||
memcpy(p, lsa->header, OSPF6_LSA_SIZE(lsa->header));
|
||||
p += OSPF6_LSA_SIZE(lsa->header);
|
||||
lsa_cnt++;
|
||||
|
||||
oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
|
||||
oh->length = htons(p - sendbuf);
|
||||
lsupdate->lsa_number = htonl(lsa_cnt);
|
||||
|
||||
if (IS_OSPF6_DEBUG_FLOODING ||
|
||||
IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE, SEND))
|
||||
zlog_debug("%s: Send lsupdate with lsa %s (age %u)",
|
||||
__PRETTY_FUNCTION__, lsa->name,
|
||||
ntohs(lsa->header->age));
|
||||
|
||||
ospf6_send_lsupdate(on, NULL, oh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ospf6_lsupdate_send_interface(struct thread *thread)
|
||||
{
|
||||
struct ospf6_interface *oi;
|
||||
|
@ -189,6 +189,11 @@ static void ospf6_neighbor_state_change(u_char next_state,
|
||||
OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT(on->ospf6_if);
|
||||
}
|
||||
OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(on->ospf6_if->area);
|
||||
|
||||
if (prev_state == OSPF6_NEIGHBOR_LOADING &&
|
||||
next_state == OSPF6_NEIGHBOR_FULL) {
|
||||
OSPF6_AS_EXTERN_LSA_SCHEDULE(on->ospf6_if);
|
||||
}
|
||||
}
|
||||
|
||||
if ((prev_state == OSPF6_NEIGHBOR_EXCHANGE
|
||||
|
@ -180,6 +180,8 @@ void ospf6_delete(struct ospf6 *o)
|
||||
struct ospf6_area *oa;
|
||||
|
||||
QOBJ_UNREG(o);
|
||||
|
||||
ospf6_flush_self_originated_lsas_now();
|
||||
ospf6_disable(ospf6);
|
||||
|
||||
for (ALL_LIST_ELEMENTS(o->area_list, node, nnode, oa))
|
||||
|
@ -94,6 +94,10 @@ struct ospf6 {
|
||||
|
||||
struct route_table *distance_table;
|
||||
|
||||
/* Used during ospf instance going down send LSDB
|
||||
* update to neighbors immediatly */
|
||||
uint8_t inst_shutdown;
|
||||
|
||||
QOBJ_FIELDS
|
||||
};
|
||||
DECLARE_QOBJ_TYPE(ospf6)
|
||||
|
Loading…
Reference in New Issue
Block a user