]> git.puffer.fish Git - mirror/frr.git/commitdiff
ospf6d: GR helper exit scenarios
authorrgirada <rgirada@vmware.com>
Thu, 1 Jul 2021 11:55:44 +0000 (04:55 -0700)
committerrgirada <rgirada@vmware.com>
Tue, 10 Aug 2021 09:57:23 +0000 (02:57 -0700)
Description:
Changes to cover all the following  GR helper exit scenarios.
1. Upon receiving max age grace lsa.( successful graceful restart)
2. Topo change
3. Grace timer expiry.
4. User changes( like config deletion , interface down)

Signed-off-by: Rajesh Girada <rgirada@vmware.com>
ospf6d/ospf6_flood.c
ospf6d/ospf6_gr.h
ospf6d/ospf6_gr_helper.c
ospf6d/ospf6_interface.c
ospf6d/ospf6_interface.h

index 77c2ad16281256f644feae967d1723fa9f9c80c9..458b81f2eaf3dea2fbbe2d4bdaffd7f35acbf877 100644 (file)
@@ -307,6 +307,22 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa)
 
        /* actually install */
        lsa->installed = now;
+
+       /* Topo change handling */
+       if (CHECK_LSA_TOPO_CHG_ELIGIBLE(ntohs(lsa->header->type))) {
+
+               /* check if it is new lsa ? or existing lsa got modified ?*/
+               if (!old || OSPF6_LSA_IS_CHANGED(old, lsa)) {
+                       struct ospf6 *ospf6;
+
+                       ospf6 = ospf6_get_by_lsdb(lsa);
+
+                       assert(ospf6);
+
+                       ospf6_helper_handle_topo_chg(ospf6, lsa);
+               }
+       }
+
        ospf6_lsdb_add(lsa, lsa->lsdb);
 
        if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7) {
@@ -1008,19 +1024,39 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
 
                        assert(ospf6);
 
-                       if (IS_DEBUG_OSPF6_GR_HELPER)
-                               zlog_debug(
-                                       "%s, Received a GraceLSA from router %d",
-                                       __PRETTY_FUNCTION__,
-                                       new->header->adv_router);
+                       if (OSPF6_LSA_IS_MAXAGE(new)) {
 
-                       if (ospf6_process_grace_lsa(ospf6, new, from)
-                           == OSPF6_GR_NOT_HELPER) {
                                if (IS_DEBUG_OSPF6_GR_HELPER)
                                        zlog_debug(
-                                               "%s, Not moving to HELPER role, So dicarding GraceLSA",
-                                               __PRETTY_FUNCTION__);
-                               return;
+                                               "%s, Received a maxage GraceLSA from router %pI4",
+                                               __func__,
+                                               &new->header->adv_router);
+                               if (old) {
+                                       ospf6_process_maxage_grace_lsa(
+                                               ospf6, new, from);
+                               } else {
+                                       if (IS_DEBUG_OSPF6_GR_HELPER)
+                                               zlog_debug(
+                                                       "%s, GraceLSA doesn't exist in lsdb, so discarding GraceLSA",
+                                                       __func__);
+                                       return;
+                               }
+                       } else {
+
+                               if (IS_DEBUG_OSPF6_GR_HELPER)
+                                       zlog_debug(
+                                               "%s, Received a GraceLSA from router %pI4",
+                                               __func__,
+                                               &new->header->adv_router);
+
+                               if (ospf6_process_grace_lsa(ospf6, new, from)
+                                   == OSPF6_GR_NOT_HELPER) {
+                                       if (IS_DEBUG_OSPF6_GR_HELPER)
+                                               zlog_debug(
+                                                       "%s, Not moving to HELPER role, So dicarding GraceLSA",
+                                                       __func__);
+                                       return;
+                               }
                        }
                }
 
index 6336363688e64460b5086576d8913ff1a00d95ea..49fc86a4e21a68c0dfa26a2c8c12d5e47e24826f 100644 (file)
@@ -148,6 +148,13 @@ extern const char *ospf6_rejected_reason_desc[];
 
 extern void ospf6_gr_helper_init(struct ospf6 *ospf6);
 extern void ospf6_gr_helper_deinit(struct ospf6 *ospf6);
+extern void ospf6_gr_helper_exit(struct ospf6_neighbor *nbr,
+                                enum ospf6_helper_exit_reason reason);
 extern int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa,
                                   struct ospf6_neighbor *nbr);
+extern void ospf6_process_maxage_grace_lsa(struct ospf6 *ospf,
+                                          struct ospf6_lsa *lsa,
+                                          struct ospf6_neighbor *nbr);
+extern void ospf6_helper_handle_topo_chg(struct ospf6 *ospf6,
+                                        struct ospf6_lsa *lsa);
 #endif /* OSPF6_GR_H */
index d0351711542f0c0891c3de3a6c17ce4b85c12214..60c62a9341988ee0b53c938a8600c75ec4e7c46d 100644 (file)
@@ -191,7 +191,7 @@ static int ospf6_handle_grace_timer_expiry(struct thread *thread)
 
        nbr->gr_helper_info.t_grace_timer = NULL;
 
-       // ospf6_gr_helper_exit(nbr, OSPF6_GR_HELPER_GRACE_TIMEOUT);
+       ospf6_gr_helper_exit(nbr, OSPF6_GR_HELPER_GRACE_TIMEOUT);
        return OSPF6_SUCCESS;
 }
 
@@ -403,6 +403,185 @@ int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa,
        return OSPF6_GR_ACTIVE_HELPER;
 }
 
+/*
+ * Api to exit from HELPER role to take all actions
+ * required at exit.
+ * Ref rfc3623 section 3. and rfc51872
+ *
+ * ospf6
+ *    Ospf6 pointer.
+ *
+ * nbr
+ *    Ospf6 neighbour for which it is acting as HELPER.
+ *
+ * reason
+ *    The reason for exiting from HELPER.
+ *
+ * Returns:
+ *    Nothing.
+ */
+void ospf6_gr_helper_exit(struct ospf6_neighbor *nbr,
+                         enum ospf6_helper_exit_reason reason)
+{
+       struct ospf6_interface *oi = nbr->ospf6_if;
+       struct ospf6 *ospf6;
+
+       if (!oi)
+               return;
+
+       ospf6 = oi->area->ospf6;
+
+       if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr))
+               return;
+
+       if (IS_DEBUG_OSPF6_GR_HELPER)
+               zlog_debug("%s, Exiting from HELPER support to %pI6, due to %s",
+                          __func__, &nbr->linklocal_addr,
+                          ospf6_exit_reason_desc[reason]);
+
+       /* Reset helper status*/
+       nbr->gr_helper_info.gr_helper_status = OSPF6_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;
+       ospf6->ospf6_helper_cfg.last_exit_reason = reason;
+
+       /* If the exit not triggered due to grace timer
+        * expairy , stop the grace timer.
+        */
+       if (reason != OSPF6_GR_HELPER_GRACE_TIMEOUT)
+               THREAD_OFF(nbr->gr_helper_info.t_grace_timer);
+
+       if (ospf6->ospf6_helper_cfg.active_restarter_cnt <= 0) {
+               zlog_err(
+                       "OSPF6 GR-Helper: Number of active Restarters should be greater than zero.");
+               return;
+       }
+       /* Decrement active Restarter count */
+       ospf6->ospf6_helper_cfg.active_restarter_cnt--;
+
+       /* check exit triggered due to successful completion
+        * of graceful restart.
+        */
+       if (reason != OSPF6_GR_HELPER_COMPLETED) {
+               if (IS_DEBUG_OSPF6_GR_HELPER)
+                       zlog_debug("%s, Unsuccessful GR exit. RESTARTER : %pI6",
+                                  __func__, &nbr->linklocal_addr);
+       }
+
+       /*Recalculate the DR for the network segment */
+       dr_election(oi);
+
+       /* Originate a router LSA */
+       OSPF6_ROUTER_LSA_SCHEDULE(nbr->ospf6_if->area);
+
+       /* Originate network lsa if it is an DR in the LAN */
+       if (nbr->ospf6_if->state == OSPF6_INTERFACE_DR)
+               OSPF6_NETWORK_LSA_SCHEDULE(nbr->ospf6_if);
+}
+
+/*
+ * Process Maxage Grace LSA.
+ * It is a indication for successfull completion of GR.
+ * If router acting as HELPER, It exits from helper role.
+ *
+ * ospf6
+ *    Ospf6 pointer.
+ *
+ * lsa
+ *    Grace LSA received from RESTARTER.
+ *
+ * nbr
+ *    ospf6 neighbour which requets the router to act as
+ *    HELPER.
+ *
+ * Returns:
+ *    Nothing.
+ */
+void ospf6_process_maxage_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa,
+                                   struct ospf6_neighbor *restarter)
+{
+       uint8_t restart_reason = 0;
+       uint32_t grace_interval = 0;
+       int ret;
+
+       /* Extract the grace lsa packet fields */
+       ret = ospf6_extract_grace_lsa_fields(lsa, &grace_interval,
+                                            &restart_reason);
+       if (ret != OSPF6_SUCCESS) {
+               if (IS_DEBUG_OSPF6_GR_HELPER)
+                       zlog_debug("%s, Wrong Grace LSA packet.",
+                                  __func__);
+               return;
+       }
+
+       if (IS_DEBUG_OSPF6_GR_HELPER)
+               zlog_debug("%s, GraceLSA received for neighbour %pI4.",
+                          __func__, &restarter->router_id);
+
+       ospf6_gr_helper_exit(restarter, OSPF6_GR_HELPER_COMPLETED);
+}
+
+/*
+ * Actions to be taken  when topo change detected
+ * HELPER will be exited upon a topo change.
+ *
+ * ospf6
+ *    ospf6 pointer
+ * lsa
+ *    topo change occured due to this lsa(type (1-5  and 7)
+ *
+ * Returns:
+ *    Nothing
+ */
+void ospf6_helper_handle_topo_chg(struct ospf6 *ospf6, struct ospf6_lsa *lsa)
+{
+       struct listnode *i, *j, *k;
+       struct ospf6_neighbor *nbr = NULL;
+       struct ospf6_area *oa = NULL;
+       struct ospf6_interface *oi = NULL;
+
+       if (!ospf6->ospf6_helper_cfg.active_restarter_cnt)
+               return;
+
+       /* Topo change not required to be hanlded if strict
+        * LSA check is disbaled for this router.
+        */
+       if (!ospf6->ospf6_helper_cfg.strict_lsa_check)
+               return;
+
+       if (IS_DEBUG_OSPF6_GR_HELPER)
+               zlog_debug(
+                       "%s, Topo change detected due to lsa details : %s",
+                       __func__, lsa->name);
+
+       lsa->tobe_acknowledged = OSPF6_TRUE;
+
+       for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
+               for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) {
+
+                       /* Ref rfc3623 section 3.2.3.b and rfc5187
+                        * 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 (IS_AREA_STUB(oi->area)
+                           && ((lsa->header->type == OSPF6_LSTYPE_AS_EXTERNAL)
+                               || (lsa->header->type == OSPF6_LSTYPE_TYPE_7)
+                               || (lsa->header->type
+                                   == OSPF6_LSTYPE_INTER_ROUTER))) {
+                               continue;
+                       }
+
+                       for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, nbr)) {
+
+                               ospf6_gr_helper_exit(nbr,
+                                                    OSPF6_GR_HELPER_TOPO_CHG);
+                       }
+               }
+}
+
 /* Debug commands */
 DEFPY(debug_ospf6_gr,
       debug_ospf6_gr_cmd,
index a169b9c60e9a3d3ce78f5fda2f46c532ff4f0554..bbb474ba1a183b248b677553dde25d6a6a33ab41 100644 (file)
 #include "ospf6d.h"
 #include "ospf6_bfd.h"
 #include "ospf6_zebra.h"
+#include "ospf6_gr.h"
 #include "lib/json.h"
 
-DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_IF,       "OSPF6 interface");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_IF, "OSPF6 interface");
 DEFINE_MTYPE_STATIC(OSPF6D, CFG_PLIST_NAME, "configured prefix list names");
 DEFINE_QOBJ_TYPE(ospf6_interface);
 DEFINE_HOOK(ospf6_interface_change,
@@ -59,6 +60,22 @@ const char *const ospf6_interface_state_str[] = {
        "None",    "Down", "Loopback", "Waiting", "PointToPoint",
        "DROther", "BDR",  "DR",       NULL};
 
+int ospf6_interface_neighbor_count(struct ospf6_interface *oi)
+{
+       int count = 0;
+       struct ospf6_neighbor *nbr = NULL;
+       struct listnode *node;
+
+       for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, node, nbr)) {
+               /* Down state is not shown. */
+               if (nbr->state == OSPF6_NEIGHBOR_DOWN)
+                       continue;
+               count++;
+       }
+
+       return count;
+}
+
 struct ospf6_interface *ospf6_interface_lookup_by_ifindex(ifindex_t ifindex,
                                                          vrf_id_t vrf_id)
 {
@@ -579,7 +596,7 @@ static struct ospf6_neighbor *better_drouter(struct ospf6_neighbor *a,
        return a;
 }
 
-static uint8_t dr_election(struct ospf6_interface *oi)
+uint8_t dr_election(struct ospf6_interface *oi)
 {
        struct listnode *node, *nnode;
        struct ospf6_neighbor *on, *drouter, *bdrouter, myself;
@@ -896,6 +913,17 @@ int interface_down(struct thread *thread)
        /* Stop trying to set socket options. */
        THREAD_OFF(oi->thread_sso);
 
+       /* Cease the HELPER role for all the neighbours
+        * of this interface.
+        */
+       if (ospf6_interface_neighbor_count(oi)) {
+               struct listnode *ln;
+               struct ospf6_neighbor *nbr = NULL;
+
+               for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, ln, nbr))
+                       ospf6_gr_helper_exit(nbr, OSPF6_GR_HELPER_TOPO_CHG);
+       }
+
        for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on))
                ospf6_neighbor_delete(on);
 
index b5efca743e74a7fb7c33a8bca133fd24a7aa6419..ccdf8b1c8fc7d0424ef32f15483ef3906d5c4749 100644 (file)
@@ -218,6 +218,8 @@ extern void install_element_ospf6_clear_interface(void);
 
 extern int config_write_ospf6_debug_interface(struct vty *vty);
 extern void install_element_ospf6_debug_interface(void);
+extern int ospf6_interface_neighbor_count(struct ospf6_interface *oi);
+extern uint8_t dr_election(struct ospf6_interface *oi);
 
 DECLARE_HOOK(ospf6_interface_change,
             (struct ospf6_interface * oi, int state, int old_state),