summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrgirada <rgirada@vmware.com>2020-08-22 19:49:30 +0200
committerrgirada <rgirada@vmware.com>2020-09-22 09:02:37 +0200
commitdf074ec33a0496d259b619bdcca77a394044aad6 (patch)
tree45008be54aa70cf4dcfcbd5da459a361703faa26
parentospfd: GR Helper functionality changes (diff)
downloadfrr-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.c163
-rw-r--r--ospfd/ospf_gr_helper.h7
-rw-r--r--ospfd/ospf_interface.c27
-rw-r--r--ospfd/ospf_ism.c2
-rw-r--r--ospfd/ospf_ism.h1
-rw-r--r--ospfd/ospf_lsa.c14
-rw-r--r--ospfd/ospf_lsa.h5
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);