mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-02 20:27:14 +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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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),
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user