mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-07 05:42:21 +00:00
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:
parent
5a77dd8feb
commit
df074ec33a
@ -489,6 +489,71 @@ static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr)
|
|||||||
return OSPF_GR_FALSE;
|
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
|
* Api to exit from HELPER role to take all actions
|
||||||
* required at exit.
|
* 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,
|
void ospf_gr_helper_exit(struct ospf_neighbor *nbr,
|
||||||
enum ospf_helper_exit_reason reason)
|
enum ospf_helper_exit_reason reason)
|
||||||
{
|
{
|
||||||
|
struct ospf_interface *oi = nbr->oi;
|
||||||
|
struct ospf *ospf = oi->ospf;
|
||||||
|
|
||||||
|
if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
|
||||||
return;
|
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.
|
* 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.
|
* If router acting as HELPER, It exits from helper role.
|
||||||
*
|
*
|
||||||
* ospf
|
* 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,
|
void ospf_process_maxage_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
|
||||||
struct ospf_neighbor *nbr)
|
struct ospf_neighbor *nbr)
|
||||||
{
|
{
|
||||||
|
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;
|
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);
|
||||||
}
|
}
|
||||||
|
@ -158,6 +158,9 @@ extern int ospf_process_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
|
|||||||
struct ospf_neighbor *nbr);
|
struct ospf_neighbor *nbr);
|
||||||
extern void ospf_gr_helper_exit(struct ospf_neighbor *nbr,
|
extern void ospf_gr_helper_exit(struct ospf_neighbor *nbr,
|
||||||
enum ospf_helper_exit_reason reason);
|
enum ospf_helper_exit_reason reason);
|
||||||
void ospf_process_maxage_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
|
extern void ospf_process_maxage_grace_lsa(struct ospf *ospf,
|
||||||
|
struct ospf_lsa *lsa,
|
||||||
struct ospf_neighbor *nbr);
|
struct ospf_neighbor *nbr);
|
||||||
|
extern void ospf_helper_handle_topo_chg(struct ospf *ospf,
|
||||||
|
struct ospf_lsa *lsa);
|
||||||
#endif /* _ZEBRA_OSPF_HELPER_H */
|
#endif /* _ZEBRA_OSPF_HELPER_H */
|
||||||
|
@ -796,9 +796,36 @@ int ospf_if_up(struct ospf_interface *oi)
|
|||||||
|
|
||||||
int ospf_if_down(struct ospf_interface *oi)
|
int ospf_if_down(struct ospf_interface *oi)
|
||||||
{
|
{
|
||||||
|
struct ospf *ospf;
|
||||||
|
|
||||||
if (oi == NULL)
|
if (oi == NULL)
|
||||||
return 0;
|
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);
|
OSPF_ISM_EVENT_EXECUTE(oi, ISM_InterfaceDown);
|
||||||
/* delete position in router LSA */
|
/* delete position in router LSA */
|
||||||
oi->lsa_pos_beg = 0;
|
oi->lsa_pos_beg = 0;
|
||||||
|
@ -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;
|
struct in_addr old_dr, old_bdr;
|
||||||
int old_state, new_state;
|
int old_state, new_state;
|
||||||
|
@ -99,6 +99,7 @@
|
|||||||
extern int ospf_ism_event(struct thread *);
|
extern int ospf_ism_event(struct thread *);
|
||||||
extern void ism_change_status(struct ospf_interface *, int);
|
extern void ism_change_status(struct ospf_interface *, int);
|
||||||
extern int ospf_hello_timer(struct thread *thread);
|
extern int ospf_hello_timer(struct thread *thread);
|
||||||
|
extern int ospf_dr_election(struct ospf_interface *oi);
|
||||||
|
|
||||||
DECLARE_HOOK(ospf_ism_change,
|
DECLARE_HOOK(ospf_ism_change,
|
||||||
(struct ospf_interface * oi, int state, int oldstate),
|
(struct ospf_interface * oi, int state, int oldstate),
|
||||||
|
@ -164,6 +164,7 @@ struct ospf_lsa *ospf_lsa_new(void)
|
|||||||
new->tv_orig = new->tv_recv;
|
new->tv_orig = new->tv_recv;
|
||||||
new->refresh_list = -1;
|
new->refresh_list = -1;
|
||||||
new->vrf_id = VRF_DEFAULT;
|
new->vrf_id = VRF_DEFAULT;
|
||||||
|
new->to_be_acknowledged = 0;
|
||||||
|
|
||||||
return new;
|
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. */
|
/* Do comparision and record if recalc needed. */
|
||||||
rt_recalc = 0;
|
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;
|
rt_recalc = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Sequence number check (Section 14.1 of rfc 2328)
|
Sequence number check (Section 14.1 of rfc 2328)
|
||||||
|
@ -224,6 +224,11 @@ struct as_external_lsa {
|
|||||||
if (!(T)) \
|
if (!(T)) \
|
||||||
(T) = thread_add_timer(master, (F), 0, 2)
|
(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. */
|
/* Prototypes. */
|
||||||
/* XXX: Eek, time functions, similar are in lib/thread.c */
|
/* XXX: Eek, time functions, similar are in lib/thread.c */
|
||||||
extern struct timeval int2tv(int);
|
extern struct timeval int2tv(int);
|
||||||
|
Loading…
Reference in New Issue
Block a user