diff options
author | rgirada <rgirada@vmware.com> | 2020-08-22 19:49:30 +0200 |
---|---|---|
committer | rgirada <rgirada@vmware.com> | 2020-09-22 09:02:37 +0200 |
commit | df074ec33a0496d259b619bdcca77a394044aad6 (patch) | |
tree | 45008be54aa70cf4dcfcbd5da459a361703faa26 | |
parent | ospfd: GR Helper functionality changes (diff) | |
download | frr-df074ec33a0496d259b619bdcca77a394044aad6.tar.xz frr-df074ec33a0496d259b619bdcca77a394044aad6.zip |
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>
-rw-r--r-- | ospfd/ospf_gr_helper.c | 163 | ||||
-rw-r--r-- | ospfd/ospf_gr_helper.h | 7 | ||||
-rw-r--r-- | ospfd/ospf_interface.c | 27 | ||||
-rw-r--r-- | ospfd/ospf_ism.c | 2 | ||||
-rw-r--r-- | ospfd/ospf_ism.h | 1 | ||||
-rw-r--r-- | ospfd/ospf_lsa.c | 14 | ||||
-rw-r--r-- | ospfd/ospf_lsa.h | 5 |
7 files changed, 212 insertions, 7 deletions
diff --git a/ospfd/ospf_gr_helper.c b/ospfd/ospf_gr_helper.c index ea68d6acd..1c2c4f5f9 100644 --- a/ospfd/ospf_gr_helper.c +++ b/ospfd/ospf_gr_helper.c @@ -490,6 +490,71 @@ static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr) } /* + * 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. * Ref rfc3623 section 3.2 @@ -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); } diff --git a/ospfd/ospf_gr_helper.h b/ospfd/ospf_gr_helper.h index 21cbb2ac1..a6a7bebcf 100644 --- a/ospfd/ospf_gr_helper.h +++ b/ospfd/ospf_gr_helper.h @@ -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 */ diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 6bfdb1e9e..3d2c28b1e 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -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; diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c index 86712c619..e9faa415f 100644 --- a/ospfd/ospf_ism.c +++ b/ospfd/ospf_ism.c @@ -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; diff --git a/ospfd/ospf_ism.h b/ospfd/ospf_ism.h index 8d2140369..67ea4c468 100644 --- a/ospfd/ospf_ism.h +++ b/ospfd/ospf_ism.h @@ -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), diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 809521914..0200bf5e2 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -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) diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index 61afb169f..90f7b5363 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -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); |