ospfd: GR helper exit scenarios

Description:
	The follwoing helper exit scenarios are handled.
	1. Recv Max age grace LSA from RESTARTER.
	2. Grace timer expiry.
	3. Due to topo change if lsa check is enabled.

Signed-off-by: Rajesh Girada <rgirada@vmware.com>
This commit is contained in:
rgirada 2020-08-22 10:49:30 -07:00
parent 5a77dd8feb
commit df074ec33a
7 changed files with 212 additions and 7 deletions

View File

@ -489,6 +489,71 @@ static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr)
return OSPF_GR_FALSE;
}
/*
* Actions to be taken when topo change detected
* HELPER will exit upon topo change.
*
* ospf
* ospf pointer
* lsa
* topo change occured due to this lsa type (1 to 5 and 7)
*
* Returns:
* Nothing
*/
void ospf_helper_handle_topo_chg(struct ospf *ospf, struct ospf_lsa *lsa)
{
struct listnode *node;
struct ospf_interface *oi;
if (!ospf->active_restarter_cnt)
return;
/* Topo change not required to be hanlded if strict
* LSA check is disbaled for this router.
*/
if (!ospf->strict_lsa_check)
return;
if (IS_DEBUG_OSPF_GR_HELPER)
zlog_debug(
"%s, Topo change detected due to lsa LSID:%s type:%d",
__PRETTY_FUNCTION__, inet_ntoa(lsa->data->id),
lsa->data->type);
lsa->to_be_acknowledged = OSPF_GR_TRUE;
for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
struct route_node *rn = NULL;
if (ospf_interface_neighbor_count(oi) == 0)
continue;
/* Ref rfc3623 section 3.2.3.b
* If change due to external LSA and if the area is
* stub, then it is not a topo change. Since Type-5
* lsas will not be flooded in stub area.
*/
if ((oi->area->external_routing == OSPF_AREA_STUB)
&& (lsa->data->type == OSPF_AS_EXTERNAL_LSA)) {
continue;
}
for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
struct ospf_neighbor *nbr = NULL;
if (!rn->info)
continue;
nbr = rn->info;
if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
ospf_gr_helper_exit(nbr,
OSPF_GR_HELPER_TOPO_CHG);
}
}
}
/*
* Api to exit from HELPER role to take all actions
* required at exit.
@ -509,12 +574,65 @@ static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr)
void ospf_gr_helper_exit(struct ospf_neighbor *nbr,
enum ospf_helper_exit_reason reason)
{
return;
struct ospf_interface *oi = nbr->oi;
struct ospf *ospf = oi->ospf;
if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
return;
if (IS_DEBUG_OSPF_GR_HELPER)
zlog_debug("%s, Exiting from HELPER support to %s, due to %s",
__PRETTY_FUNCTION__, inet_ntoa(nbr->src),
ospf_exit_reason_desc[reason]);
/* Reset helper status*/
nbr->gr_helper_info.gr_helper_status = OSPF_GR_NOT_HELPER;
nbr->gr_helper_info.helper_exit_reason = reason;
nbr->gr_helper_info.actual_grace_period = 0;
nbr->gr_helper_info.recvd_grace_period = 0;
nbr->gr_helper_info.gr_restart_reason = 0;
ospf->last_exit_reason = reason;
if (ospf->active_restarter_cnt <= 0) {
zlog_err(
"OSPF GR-Helper: active_restarter_cnt should be greater than zero here.");
return;
}
/* Decrement active Restarter count */
ospf->active_restarter_cnt--;
/* If the exit not triggered due to grace timer
* expairy , stop the grace timer.
*/
if (reason != OSPF_GR_HELPER_GRACE_TIMEOUT)
THREAD_OFF(nbr->gr_helper_info.t_grace_timer);
/* check exit triggered due to successful completion
* of graceful restart.
* If no, bringdown the neighbour.
*/
if (reason != OSPF_GR_HELPER_COMPLETED) {
if (IS_DEBUG_OSPF_GR_HELPER)
zlog_debug(
"%s, Failed GR exit, so bringing down the neighbour",
__PRETTY_FUNCTION__);
OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr);
}
/*Recalculate the DR for the network segment */
ospf_dr_election(oi);
/* Originate a router LSA */
ospf_router_lsa_update_area(oi->area);
/* Originate network lsa if it is an DR in the LAN */
if (oi->state == ISM_DR)
ospf_network_lsa_update(oi);
}
/*
* Process Maxage Grace LSA.
* It is a indication for successfull completion of GR.
* It is a indication for successful completion of GR.
* If router acting as HELPER, It exits from helper role.
*
* ospf
@ -533,5 +651,44 @@ void ospf_gr_helper_exit(struct ospf_neighbor *nbr,
void ospf_process_maxage_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
struct ospf_neighbor *nbr)
{
return;
struct in_addr restartAddr = {0};
uint8_t restartReason = 0;
uint32_t graceInterval = 0;
struct ospf_neighbor *restarter = NULL;
struct ospf_interface *oi = nbr->oi;
int ret;
/* Extract the grace lsa packet fields */
ret = ospf_extract_grace_lsa_fields(lsa, &graceInterval, &restartAddr,
&restartReason);
if (ret != OSPF_GR_SUCCESS) {
if (IS_DEBUG_OSPF_GR_HELPER)
zlog_debug("%s, Wrong Grace LSA packet.",
__PRETTY_FUNCTION__);
return;
}
if (IS_DEBUG_OSPF_GR_HELPER)
zlog_debug("%s, GraceLSA received for neighbour %s.",
__PRETTY_FUNCTION__, inet_ntoa(restartAddr));
/* In case of broadcast links, if RESTARTER is DR_OTHER,
* grace LSA might be received from DR, so fetching the
* actual neighbour information using restarter address.
*/
if (oi->type != OSPF_IFTYPE_POINTOPOINT) {
restarter = ospf_nbr_lookup_by_addr(oi->nbrs, &restartAddr);
if (!restarter) {
if (IS_DEBUG_OSPF_GR_HELPER)
zlog_debug(
"%s, Restarter is not a neighbour for this router.",
__PRETTY_FUNCTION__);
return;
}
} else {
restarter = nbr;
}
ospf_gr_helper_exit(restarter, OSPF_GR_HELPER_COMPLETED);
}

View File

@ -158,6 +158,9 @@ extern int ospf_process_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
struct ospf_neighbor *nbr);
extern void ospf_gr_helper_exit(struct ospf_neighbor *nbr,
enum ospf_helper_exit_reason reason);
void ospf_process_maxage_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
struct ospf_neighbor *nbr);
extern void ospf_process_maxage_grace_lsa(struct ospf *ospf,
struct ospf_lsa *lsa,
struct ospf_neighbor *nbr);
extern void ospf_helper_handle_topo_chg(struct ospf *ospf,
struct ospf_lsa *lsa);
#endif /* _ZEBRA_OSPF_HELPER_H */

View File

@ -796,9 +796,36 @@ int ospf_if_up(struct ospf_interface *oi)
int ospf_if_down(struct ospf_interface *oi)
{
struct ospf *ospf;
if (oi == NULL)
return 0;
ospf = oi->ospf;
/* Cease the HELPER role for all the neighbours
* of this interface.
*/
if (ospf->is_helper_supported) {
struct route_node *rn = NULL;
if (ospf_interface_neighbor_count(oi)) {
for (rn = route_top(oi->nbrs); rn;
rn = route_next(rn)) {
struct ospf_neighbor *nbr = NULL;
if (!rn->info)
continue;
nbr = rn->info;
if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
ospf_gr_helper_exit(
nbr, OSPF_GR_HELPER_TOPO_CHG);
}
}
}
OSPF_ISM_EVENT_EXECUTE(oi, ISM_InterfaceDown);
/* delete position in router LSA */
oi->lsa_pos_beg = 0;

View File

@ -201,7 +201,7 @@ static void ospf_dr_change(struct ospf *ospf, struct route_table *nbrs)
}
}
static int ospf_dr_election(struct ospf_interface *oi)
int ospf_dr_election(struct ospf_interface *oi)
{
struct in_addr old_dr, old_bdr;
int old_state, new_state;

View File

@ -99,6 +99,7 @@
extern int ospf_ism_event(struct thread *);
extern void ism_change_status(struct ospf_interface *, int);
extern int ospf_hello_timer(struct thread *thread);
extern int ospf_dr_election(struct ospf_interface *oi);
DECLARE_HOOK(ospf_ism_change,
(struct ospf_interface * oi, int state, int oldstate),

View File

@ -164,6 +164,7 @@ struct ospf_lsa *ospf_lsa_new(void)
new->tv_orig = new->tv_recv;
new->refresh_list = -1;
new->vrf_id = VRF_DEFAULT;
new->to_be_acknowledged = 0;
return new;
}
@ -2578,8 +2579,19 @@ struct ospf_lsa *ospf_lsa_install(struct ospf *ospf, struct ospf_interface *oi,
/* Do comparision and record if recalc needed. */
rt_recalc = 0;
if (old == NULL || ospf_lsa_different(old, lsa))
if (old == NULL || ospf_lsa_different(old, lsa)) {
/* Ref rfc3623 section 3.2.3
* Installing new lsa or change in the existing LSA
* or flushing existing LSA leads to topo change
* and trigger SPF caculation.
* So, router should be aborted from HELPER role
* if it is detected as TOPO change.
*/
if (CHECK_LSA_TYPE_1_TO_5_OR_7(lsa->data->type))
ospf_helper_handle_topo_chg(ospf, lsa);
rt_recalc = 1;
}
/*
Sequence number check (Section 14.1 of rfc 2328)

View File

@ -224,6 +224,11 @@ struct as_external_lsa {
if (!(T)) \
(T) = thread_add_timer(master, (F), 0, 2)
#define CHECK_LSA_TYPE_1_TO_5_OR_7(type) \
((type == OSPF_ROUTER_LSA) || (type == OSPF_NETWORK_LSA) \
|| (type == OSPF_SUMMARY_LSA) || (type == OSPF_ASBR_SUMMARY_LSA) \
|| (type == OSPF_AS_EXTERNAL_LSA) || (type == OSPF_AS_NSSA_LSA))
/* Prototypes. */
/* XXX: Eek, time functions, similar are in lib/thread.c */
extern struct timeval int2tv(int);