]> git.puffer.fish Git - mirror/frr.git/commitdiff
ospfd: GR helper exit scenarios
authorrgirada <rgirada@vmware.com>
Sat, 22 Aug 2020 17:49:30 +0000 (10:49 -0700)
committerrgirada <rgirada@vmware.com>
Tue, 22 Sep 2020 07:02:37 +0000 (00:02 -0700)
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>
ospfd/ospf_gr_helper.c
ospfd/ospf_gr_helper.h
ospfd/ospf_interface.c
ospfd/ospf_ism.c
ospfd/ospf_ism.h
ospfd/ospf_lsa.c
ospfd/ospf_lsa.h

index ea68d6acd66615778d1fbe137490158d4171f916..1c2c4f5f9dff78e3ac811a219a5dd33c93aea88c 100644 (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);
 }
index 21cbb2ac18fb89aeb7e4711bb550efa13d787141..a6a7bebcf0b4181de233f227c98e80905459df5e 100644 (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 */
index 6bfdb1e9e0c019f6b54caef7d27db02f52f7e32a..3d2c28b1e4684300b55f694b40ef41280eeeb1e3 100644 (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;
index 86712c61985d1344fa616cc0c68623c13661c01a..e9faa415fe3c615ac3ff650e281d668362fd2dd2 100644 (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;
index 8d21403695faf7a8657ca5bcd4f84bdbe7aa3328..67ea4c4684f5d929d8affd9051c388e767c443c4 100644 (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),
index 8095219146457679a4edeb46a2e12f01c0c69658..0200bf5e260384de9fee4a5dd6da0fb0489f488e 100644 (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)
index 61afb169fbd7ba8729c5d90b49f9b3e1ecf7961b..90f7b5363258a2b1c6def579689110908697c6f5 100644 (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);