summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRenato Westphal <renato@opensourcerouting.org>2021-08-19 15:01:34 -0300
committerGitHub <noreply@github.com>2021-08-19 15:01:34 -0300
commitf70b917249b783c47ef8e8c0575374a6207a2baa (patch)
treefe0ea3b9e5d877f629d7fabe88de2f7545e67626
parent2cb694ba131b5e543ce16d77f452c6296c978c13 (diff)
parent0fc3e113231829c3412f5009be2b4c790b444bd3 (diff)
Merge pull request #8935 from rgirada/ospfv3_gr_helper
ospf6d: Support for ospfv3 graceful restart helper functionality
-rw-r--r--doc/user/ospf6d.rst46
-rw-r--r--ospf6d/ospf6_flood.c61
-rw-r--r--ospf6d/ospf6_gr.h161
-rw-r--r--ospf6d/ospf6_gr_helper.c1375
-rw-r--r--ospf6d/ospf6_interface.c32
-rw-r--r--ospf6d/ospf6_interface.h2
-rw-r--r--ospf6d/ospf6_lsa.h14
-rw-r--r--ospf6d/ospf6_message.c56
-rw-r--r--ospf6d/ospf6_neighbor.c50
-rw-r--r--ospf6d/ospf6_neighbor.h35
-rw-r--r--ospf6d/ospf6_top.c5
-rw-r--r--ospf6d/ospf6_top.h41
-rw-r--r--ospf6d/ospf6d.c3
-rw-r--r--ospf6d/ospf6d.h6
-rw-r--r--ospf6d/subdir.am4
15 files changed, 1869 insertions, 22 deletions
diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst
index 55ab493873..c090f3496a 100644
--- a/doc/user/ospf6d.rst
+++ b/doc/user/ospf6d.rst
@@ -258,6 +258,39 @@ Redistribute routes to OSPF6
argument injects the default route regardless of it being present in the
router. Metric values and route-map can also be specified optionally.
+Graceful Restart Helper
+=======================
+
+.. clicmd:: graceful-restart helper-only [A.B.C.D]
+
+
+ Configure Graceful Restart (RFC 5187) helper support.
+ By default, helper support is disabled for all neighbours.
+ This config enables/disables helper support on this router
+ for all neighbours.
+ To enable/disable helper support for a specific
+ neighbour, the router-id (A.B.C.D) has to be specified.
+
+.. clicmd:: graceful-restart helper strict-lsa-checking
+
+
+ If 'strict-lsa-checking' is configured then the helper will
+ abort the Graceful Restart when a LSA change occurs which
+ affects the restarting router.
+ By default 'strict-lsa-checking' is enabled"
+
+.. clicmd:: graceful-restart helper supported-grace-time (10-1800)
+
+
+ Supports as HELPER for configured grace period.
+
+.. clicmd:: graceful-restart helper planned-only
+
+
+ It helps to support as HELPER only for planned
+ restarts. By default, it supports both planned and
+ unplanned outages.
+
.. _showing-ospf6-information:
Showing OSPF6 information
@@ -351,6 +384,19 @@ Showing OSPF6 information
JSON object, with each router having "cost", "isLeafNode" and "children" as
arguments.
+.. clicmd:: show ipv6 ospf6 graceful-restart helper [detail] [json]
+
+ This command shows the graceful-restart helper details including helper
+ configuration parameters.
+
+Debugging OSPF6
+===============
+
+.. clicmd:: debug ospf6 graceful-restart
+
+ This command enables/disables debug information for ospf6 graceful restart
+ helper functionality.
+
.. _ospf6-debugging:
diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c
index 5a4dd72b66..f13ed3e3bb 100644
--- a/ospf6d/ospf6_flood.c
+++ b/ospf6d/ospf6_flood.c
@@ -41,6 +41,7 @@
#include "ospf6_flood.h"
#include "ospf6_nssa.h"
+#include "ospf6_gr.h"
unsigned char conf_debug_ospf6_flooding;
@@ -323,6 +324,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) {
@@ -1016,6 +1033,50 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
!= from->ospf6_if->area->ospf6->router_id)
ospf6_flood(from, new);
+ /* Received Grace-LSA */
+ if (IS_GRACE_LSA(new)) {
+ struct ospf6 *ospf6;
+
+ ospf6 = ospf6_get_by_lsdb(new);
+
+ assert(ospf6);
+
+ if (OSPF6_LSA_IS_MAXAGE(new)) {
+
+ if (IS_DEBUG_OSPF6_GR)
+ zlog_debug(
+ "%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)
+ zlog_debug(
+ "%s, GraceLSA doesn't exist in lsdb, so discarding GraceLSA",
+ __func__);
+ return;
+ }
+ } else {
+
+ if (IS_DEBUG_OSPF6_GR)
+ 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)
+ zlog_debug(
+ "%s, Not moving to HELPER role, So dicarding GraceLSA",
+ __func__);
+ return;
+ }
+ }
+ }
+
/* (d), installing lsdb, which may cause routing
table calculation (replacing database copy) */
ospf6_install_lsa(new);
diff --git a/ospf6d/ospf6_gr.h b/ospf6d/ospf6_gr.h
new file mode 100644
index 0000000000..378b7193cd
--- /dev/null
+++ b/ospf6d/ospf6_gr.h
@@ -0,0 +1,161 @@
+/*
+ * OSPF6 Graceful Retsart helper functions.
+ *
+ * Copyright (C) 2021-22 Vmware, Inc.
+ * Rajesh Kumar Girada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef OSPF6_GR_H
+#define OSPF6_GR_H
+
+#define OSPF6_GR_NOT_HELPER 0
+#define OSPF6_GR_ACTIVE_HELPER 1
+
+#define OSPF6_GR_HELPER_NO_LSACHECK 0
+#define OSPF6_GR_HELPER_LSACHECK 1
+
+#define OSPF6_MAX_GRACE_INTERVAL 1800
+#define OSPF6_MIN_GRACE_INTERVAL 1
+
+/* Debug option */
+extern unsigned char conf_debug_ospf6_gr;
+
+#define OSPF6_DEBUG_GR 0x01
+
+#define OSPF6_DEBUG_GR_ON() (conf_debug_ospf6_gr |= OSPF6_DEBUG_GR)
+
+#define OSPF6_DEBUG_GR_OFF() (conf_debug_ospf6_gr &= ~OSPF6_DEBUG_GR)
+
+#define IS_DEBUG_OSPF6_GR conf_debug_ospf6_gr
+
+
+enum ospf6_helper_exit_reason {
+ OSPF6_GR_HELPER_EXIT_NONE = 0,
+ OSPF6_GR_HELPER_INPROGRESS,
+ OSPF6_GR_HELPER_TOPO_CHG,
+ OSPF6_GR_HELPER_GRACE_TIMEOUT,
+ OSPF6_GR_HELPER_COMPLETED
+};
+
+enum ospf6_gr_restart_reason {
+ OSPF6_GR_UNKNOWN_RESTART = 0,
+ OSPF6_GR_SW_RESTART = 1,
+ OSPF6_GR_SW_UPGRADE = 2,
+ OSPF6_GR_SWITCH_REDUNDANT_CARD = 3,
+ OSPF6_GR_INVALID_REASON_CODE = 4
+};
+
+enum ospf6_gr_helper_rejected_reason {
+ OSPF6_HELPER_REJECTED_NONE,
+ OSPF6_HELPER_SUPPORT_DISABLED,
+ OSPF6_HELPER_NOT_A_VALID_NEIGHBOUR,
+ OSPF6_HELPER_PLANNED_ONLY_RESTART,
+ OSPF6_HELPER_TOPO_CHANGE_RTXMT_LIST,
+ OSPF6_HELPER_LSA_AGE_MORE
+};
+
+#ifdef roundup
+#define ROUNDUP(val, gran) roundup(val, gran)
+#else /* roundup */
+#define ROUNDUP(val, gran) (((val)-1 | (gran)-1) + 1)
+#endif /* roundup */
+
+/*
+ * Generic TLV (type, length, value) macros
+ */
+struct tlv_header {
+ uint16_t type; /* Type of Value */
+ uint16_t length; /* Length of Value portion only, in bytes */
+};
+
+#define TLV_HDR_SIZE (sizeof(struct tlv_header))
+
+#define TLV_BODY_SIZE(tlvh) (ROUNDUP(ntohs((tlvh)->length), sizeof(uint32_t)))
+
+#define TLV_SIZE(tlvh) (TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh))
+
+#define TLV_HDR_TOP(lsah) \
+ (struct tlv_header *)((char *)(lsah) + OSPF6_LSA_HEADER_SIZE)
+
+#define TLV_HDR_NEXT(tlvh) \
+ (struct tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh))
+
+/* Ref RFC5187 appendix-A */
+/* Grace period TLV */
+#define GRACE_PERIOD_TYPE 1
+#define GRACE_PERIOD_LENGTH 4
+struct grace_tlv_graceperiod {
+ struct tlv_header header;
+ uint32_t interval;
+};
+#define GRACE_PERIOD_TLV_SIZE sizeof(struct grace_tlv_graceperiod)
+
+/* Restart reason TLV */
+#define RESTART_REASON_TYPE 2
+#define RESTART_REASON_LENGTH 1
+struct grace_tlv_restart_reason {
+ struct tlv_header header;
+ uint8_t reason;
+ uint8_t reserved[3];
+};
+#define GRACE_RESTART_REASON_TLV_SIZE sizeof(struct grace_tlv_restart_reason)
+
+#define OSPF6_GRACE_LSA_MIN_SIZE \
+ GRACE_PERIOD_TLV_SIZE + GRACE_RESTART_REASON_TLV_SIZE
+
+struct advRtr {
+ in_addr_t advRtrAddr;
+};
+
+#define OSPF6_HELPER_ENABLE_RTR_COUNT(ospf) \
+ (ospf6->ospf6_helper_cfg.enable_rtr_list->count)
+
+/* Check , it is a planned restart */
+#define OSPF6_GR_IS_PLANNED_RESTART(reason) \
+ ((reason == OSPF6_GR_SW_RESTART) || (reason == OSPF6_GR_SW_UPGRADE))
+
+/* Check the router is HELPER for current neighbour */
+#define OSPF6_GR_IS_ACTIVE_HELPER(N) \
+ ((N)->gr_helper_info.gr_helper_status == OSPF6_GR_ACTIVE_HELPER)
+
+/* Check the LSA is GRACE LSA */
+#define IS_GRACE_LSA(lsa) (ntohs(lsa->header->type) == OSPF6_LSTYPE_GRACE_LSA)
+
+/* Check neighbour is in FULL state */
+#define IS_NBR_STATE_FULL(nbr) (nbr->state == OSPF6_NEIGHBOR_FULL)
+
+extern const char *ospf6_exit_reason_desc[];
+extern const char *ospf6_restart_reason_desc[];
+extern const char *ospf6_rejected_reason_desc[];
+
+extern void ospf6_gr_helper_config_init(void);
+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);
+extern int config_write_ospf6_gr_helper(struct vty *vty, struct ospf6 *ospf6);
+extern int config_write_ospf6_debug_gr_helper(struct vty *vty);
+#endif /* OSPF6_GR_H */
diff --git a/ospf6d/ospf6_gr_helper.c b/ospf6d/ospf6_gr_helper.c
new file mode 100644
index 0000000000..07e479efcb
--- /dev/null
+++ b/ospf6d/ospf6_gr_helper.c
@@ -0,0 +1,1375 @@
+/*
+ * OSPF6 Graceful Restart helper functions.
+ *
+ * Copyright (C) 2021-22 Vmware, Inc.
+ * Rajesh Kumar Girada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "vty.h"
+#include "command.h"
+#include "prefix.h"
+#include "stream.h"
+#include "zclient.h"
+#include "memory.h"
+#include "table.h"
+#include "lib/bfd.h"
+#include "lib_errors.h"
+#include "jhash.h"
+
+#include "ospf6_proto.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+#include "ospf6_route.h"
+#include "ospf6_message.h"
+
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_interface.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_intra.h"
+#include "ospf6d.h"
+#include "ospf6_gr.h"
+#include "lib/json.h"
+#ifndef VTYSH_EXTRACT_PL
+#include "ospf6d/ospf6_gr_helper_clippy.c"
+#endif
+
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_GR_HELPER, "OSPF6 Graceful restart helper");
+
+unsigned char conf_debug_ospf6_gr;
+
+static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa,
+ json_object *json, bool use_json);
+
+struct ospf6_lsa_handler grace_lsa_handler = {.lh_type = OSPF6_LSTYPE_GRACE_LSA,
+ .lh_name = "Grace",
+ .lh_short_name = "GR",
+ .lh_show =
+ ospf6_grace_lsa_show_info,
+ .lh_get_prefix_str = NULL,
+ .lh_debug = 0};
+
+const char *ospf6_exit_reason_desc[] = {
+ "Unknown reason",
+ "Helper in progress",
+ "Topology Change",
+ "Grace timer expiry",
+ "Successful graceful restart",
+};
+
+const char *ospf6_restart_reason_desc[] = {
+ "Unknown restart",
+ "Software restart",
+ "Software reload/upgrade",
+ "Switch to redundant control processor",
+};
+
+const char *ospf6_rejected_reason_desc[] = {
+ "Unknown reason",
+ "Helper support disabled",
+ "Neighbour is not in FULL state",
+ "Supports only planned restart but received for unplanned",
+ "Topo change due to change in lsa rxmt list",
+ "LSA age is more than Grace interval",
+};
+
+static unsigned int ospf6_enable_rtr_hash_key(const void *data)
+{
+ const struct advRtr *rtr = data;
+
+ return jhash_1word(rtr->advRtrAddr, 0);
+}
+
+static bool ospf6_enable_rtr_hash_cmp(const void *d1, const void *d2)
+{
+ const struct advRtr *rtr1 = d1;
+ const struct advRtr *rtr2 = d2;
+
+ return (rtr1->advRtrAddr == rtr2->advRtrAddr);
+}
+
+static void *ospf6_enable_rtr_hash_alloc(void *p)
+{
+ struct advRtr *rid;
+
+ rid = XCALLOC(MTYPE_OSPF6_GR_HELPER, sizeof(struct advRtr));
+ rid->advRtrAddr = ((struct advRtr *)p)->advRtrAddr;
+
+ return rid;
+}
+
+static void ospf6_disable_rtr_hash_free(void *rtr)
+{
+ XFREE(MTYPE_OSPF6_GR_HELPER, rtr);
+}
+
+static void ospf6_enable_rtr_hash_destroy(struct ospf6 *ospf6)
+{
+ if (ospf6->ospf6_helper_cfg.enable_rtr_list == NULL)
+ return;
+
+ hash_clean(ospf6->ospf6_helper_cfg.enable_rtr_list,
+ ospf6_disable_rtr_hash_free);
+ hash_free(ospf6->ospf6_helper_cfg.enable_rtr_list);
+ ospf6->ospf6_helper_cfg.enable_rtr_list = NULL;
+}
+
+/*
+ * Extracting tlv info from GRACE LSA.
+ *
+ * lsa
+ * ospf6 grace lsa
+ *
+ * Returns:
+ * interval : grace interval.
+ * reason : Restarting reason.
+ */
+static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa,
+ uint32_t *interval, uint8_t *reason)
+{
+ struct ospf6_lsa_header *lsah = NULL;
+ struct tlv_header *tlvh = NULL;
+ struct grace_tlv_graceperiod *gracePeriod;
+ struct grace_tlv_restart_reason *grReason;
+ uint16_t length = 0;
+ int sum = 0;
+
+ lsah = (struct ospf6_lsa_header *)lsa->header;
+
+ length = ntohs(lsah->length) - OSPF6_LSA_HEADER_SIZE;
+
+ for (tlvh = TLV_HDR_TOP(lsah); sum < length;
+ tlvh = TLV_HDR_NEXT(tlvh)) {
+ switch (ntohs(tlvh->type)) {
+ case GRACE_PERIOD_TYPE:
+ gracePeriod = (struct grace_tlv_graceperiod *)tlvh;
+ *interval = ntohl(gracePeriod->interval);
+ sum += TLV_SIZE(tlvh);
+
+ /* Check if grace interval is valid */
+ if (*interval > OSPF6_MAX_GRACE_INTERVAL
+ || *interval < OSPF6_MIN_GRACE_INTERVAL)
+ return OSPF6_FAILURE;
+ break;
+ case RESTART_REASON_TYPE:
+ grReason = (struct grace_tlv_restart_reason *)tlvh;
+ *reason = grReason->reason;
+ sum += TLV_SIZE(tlvh);
+
+ if (*reason >= OSPF6_GR_INVALID_REASON_CODE)
+ return OSPF6_FAILURE;
+ break;
+ default:
+ if (IS_DEBUG_OSPF6_GR)
+ zlog_debug("%s, Ignoring unknown TLV type:%d",
+ __func__, ntohs(tlvh->type));
+ }
+ }
+
+ return OSPF6_SUCCESS;
+}
+
+/*
+ * Grace timer expiry handler.
+ * HELPER aborts its role at grace timer expiry.
+ *
+ * thread
+ * thread pointer
+ *
+ * Returns:
+ * Nothing
+ */
+static int ospf6_handle_grace_timer_expiry(struct thread *thread)
+{
+ struct ospf6_neighbor *nbr = THREAD_ARG(thread);
+
+ nbr->gr_helper_info.t_grace_timer = NULL;
+
+ ospf6_gr_helper_exit(nbr, OSPF6_GR_HELPER_GRACE_TIMEOUT);
+ return OSPF6_SUCCESS;
+}
+
+/*
+ * API to check any change in the neighbor's
+ * retransmission list.
+ *
+ * nbr
+ * ospf6 neighbor
+ *
+ * Returns:
+ * TRUE - if any change in the lsa.
+ * FALSE - no change in the lsas.
+ */
+static bool ospf6_check_chg_in_rxmt_list(struct ospf6_neighbor *nbr)
+{
+ struct ospf6_lsa *lsa, *lsanext;
+
+ for (ALL_LSDB(nbr->retrans_list, lsa, lsanext)) {
+ struct ospf6_lsa *lsa_in_db = NULL;
+
+ /* Fetching the same copy of LSA form LSDB to validate the
+ * topochange.
+ */
+ lsa_in_db =
+ ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
+ lsa->header->adv_router, lsa->lsdb);
+
+ if (lsa_in_db && lsa_in_db->tobe_acknowledged)
+ return OSPF6_TRUE;
+ }
+
+ return OSPF6_FALSE;
+}
+
+/*
+ * Process Grace LSA.If it is eligible move to HELPER role.
+ * Ref rfc3623 section 3.1 and rfc5187
+ *
+ * ospf
+ * Ospf6 pointer.
+ *
+ * lsa
+ * Grace LSA received from RESTARTER.
+ *
+ * restarter
+ * ospf6 neighbour which requests the router to act as
+ * HELPER.
+ *
+ * Returns:
+ * status.
+ * If supported as HELPER : OSPF_GR_HELPER_INPROGRESS
+ * If Not supported as HELPER : OSPF_GR_HELPER_NONE
+ */
+int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa,
+ struct ospf6_neighbor *restarter)
+{
+ uint8_t restart_reason = 0;
+ uint32_t grace_interval = 0;
+ uint32_t actual_grace_interval = 0;
+ struct advRtr lookup;
+ 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)
+ zlog_debug("%s, Wrong Grace LSA packet.", __func__);
+ return OSPF6_GR_NOT_HELPER;
+ }
+
+ if (IS_DEBUG_OSPF6_GR)
+ zlog_debug(
+ "%s, Grace LSA received from %pI4, grace interval:%u, restart reason :%s",
+ __func__, &restarter->router_id, grace_interval,
+ ospf6_restart_reason_desc[restart_reason]);
+
+ /* Verify Helper enabled globally */
+ if (!ospf6->ospf6_helper_cfg.is_helper_supported) {
+ /* Verify Helper support is enabled for the
+ * current neighbour router-id.
+ */
+ lookup.advRtrAddr = restarter->router_id;
+
+ if (!hash_lookup(ospf6->ospf6_helper_cfg.enable_rtr_list,
+ &lookup)) {
+ if (IS_DEBUG_OSPF6_GR)
+ zlog_debug(
+ "%s, HELPER support is disabled, So not a HELPER",
+ __func__);
+ restarter->gr_helper_info.rejected_reason =
+ OSPF6_HELPER_SUPPORT_DISABLED;
+ return OSPF6_GR_NOT_HELPER;
+ }
+ }
+
+ /* Check neighbour is in FULL state and
+ * became a adjacency.
+ */
+ if (!IS_NBR_STATE_FULL(restarter)) {
+ if (IS_DEBUG_OSPF6_GR)
+ zlog_debug(
+ "%s, This Neighbour %pI6 is not in FULL state.",
+ __func__, &restarter->linklocal_addr);
+ restarter->gr_helper_info.rejected_reason =
+ OSPF6_HELPER_NOT_A_VALID_NEIGHBOUR;
+ return OSPF6_GR_NOT_HELPER;
+ }
+
+ /* Based on the restart reason from grace lsa
+ * check the current router is supporting or not
+ */
+ if (ospf6->ospf6_helper_cfg.only_planned_restart
+ && !OSPF6_GR_IS_PLANNED_RESTART(restart_reason)) {
+ if (IS_DEBUG_OSPF6_GR)
+ zlog_debug(
+ "%s, Router supports only planned restarts but received the GRACE LSA due a unplanned restart",
+ __func__);
+ restarter->gr_helper_info.rejected_reason =
+ OSPF6_HELPER_PLANNED_ONLY_RESTART;
+ return OSPF6_GR_NOT_HELPER;
+ }
+
+ /* Check the retransmission list of this
+ * neighbour, check any change in lsas.
+ */
+ if (ospf6->ospf6_helper_cfg.strict_lsa_check
+ && restarter->retrans_list->count
+ && ospf6_check_chg_in_rxmt_list(restarter)) {
+ if (IS_DEBUG_OSPF6_GR)
+ zlog_debug(
+ "%s, Changed LSA in Rxmt list.So not Helper.",
+ __func__);
+ restarter->gr_helper_info.rejected_reason =
+ OSPF6_HELPER_TOPO_CHANGE_RTXMT_LIST;
+ return OSPF6_GR_NOT_HELPER;
+ }
+
+ /* LSA age must be less than the grace period */
+ if (ntohs(lsa->header->age) >= grace_interval) {
+ if (IS_DEBUG_OSPF6_GR)
+ zlog_debug(
+ "%s, Grace LSA age(%d) is more than the grace interval(%d)",
+ __func__, lsa->header->age, grace_interval);
+ restarter->gr_helper_info.rejected_reason =
+ OSPF6_HELPER_LSA_AGE_MORE;
+ return OSPF6_GR_NOT_HELPER;
+ }
+
+ /* check supported grace period configured
+ * if configured, use this to start the grace
+ * timer otherwise use the interval received
+ * in grace LSA packet.
+ */
+ actual_grace_interval = grace_interval;
+ if (grace_interval > ospf6->ospf6_helper_cfg.supported_grace_time) {
+ if (IS_DEBUG_OSPF6_GR)
+ zlog_debug(
+ "%s, Received grace period %d is larger than supported grace %d",
+ __func__, grace_interval,
+ ospf6->ospf6_helper_cfg.supported_grace_time);
+ actual_grace_interval =
+ ospf6->ospf6_helper_cfg.supported_grace_time;
+ }
+
+ if (OSPF6_GR_IS_ACTIVE_HELPER(restarter)) {
+ if (restarter->gr_helper_info.t_grace_timer)
+ THREAD_OFF(restarter->gr_helper_info.t_grace_timer);
+
+ if (ospf6->ospf6_helper_cfg.active_restarter_cnt > 0)
+ ospf6->ospf6_helper_cfg.active_restarter_cnt--;
+
+ if (IS_DEBUG_OSPF6_GR)
+ zlog_debug(
+ "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
+ __func__);
+ } else {
+ if (IS_DEBUG_OSPF6_GR)
+ zlog_debug(
+ "%s, This Router becomes a HELPER for the neighbour %pI6",
+ __func__, &restarter->linklocal_addr);
+ }
+
+ /* Became a Helper to the RESTART neighbour.
+ * change the helper status.
+ */
+ restarter->gr_helper_info.gr_helper_status = OSPF6_GR_ACTIVE_HELPER;
+ restarter->gr_helper_info.recvd_grace_period = grace_interval;
+ restarter->gr_helper_info.actual_grace_period = actual_grace_interval;
+ restarter->gr_helper_info.gr_restart_reason = restart_reason;
+ restarter->gr_helper_info.rejected_reason = OSPF6_HELPER_REJECTED_NONE;
+
+ /* Increment the active restart nbr count */
+ ospf6->ospf6_helper_cfg.active_restarter_cnt++;
+
+ if (IS_DEBUG_OSPF6_GR)
+ zlog_debug("%s, Grace timer started.interval:%u", __func__,
+ actual_grace_interval);
+
+ /* Start the grace timer */
+ thread_add_timer(master, ospf6_handle_grace_timer_expiry, restarter,
+ actual_grace_interval,
+ &restarter->gr_helper_info.t_grace_timer);
+
+ 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)
+ 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
+ * expiry, 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)
+ 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 max age Grace LSA.
+ * It is a indication for successful 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 request 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)
+ zlog_debug("%s, Wrong Grace LSA packet.", __func__);
+ return;
+ }
+
+ if (IS_DEBUG_OSPF6_GR)
+ 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 occurred 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 handled if strict
+ * LSA check is disabled for this router.
+ */
+ if (!ospf6->ospf6_helper_cfg.strict_lsa_check)
+ return;
+
+ if (IS_DEBUG_OSPF6_GR)
+ 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);
+ }
+ }
+}
+
+/* Configuration handlers */
+/*
+ * Disable/Enable HELPER support on router level.
+ *
+ * ospf6
+ * Ospf6 pointer.
+ *
+ * status
+ * TRUE/FALSE
+ *
+ * Returns:
+ * Nothing.
+ */
+static void ospf6_gr_helper_support_set(struct ospf6 *ospf6, bool support)
+{
+ struct ospf6_interface *oi;
+ struct advRtr lookup;
+ struct listnode *i, *j, *k;
+ struct ospf6_neighbor *nbr = NULL;
+ struct ospf6_area *oa = NULL;
+
+ if (ospf6->ospf6_helper_cfg.is_helper_supported == support)
+ return;
+
+ ospf6->ospf6_helper_cfg.is_helper_supported = support;
+
+ /* If helper support disabled, cease HELPER role for all
+ * supporting neighbors.
+ */
+ if (support == OSPF6_FALSE) {
+ for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
+ for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) {
+
+ for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k,
+ nbr)) {
+
+ lookup.advRtrAddr = nbr->router_id;
+ /* check if helper support enabled for
+ * the corresponding routerid.
+ * If enabled,
+ * dont exit from helper role.
+ */
+ if (hash_lookup(
+ ospf6->ospf6_helper_cfg
+ .enable_rtr_list,
+ &lookup))
+ continue;
+
+ ospf6_gr_helper_exit(
+ nbr, OSPF6_GR_HELPER_TOPO_CHG);
+ }
+ }
+ }
+}
+
+/*
+ * Api to enable/disable strict lsa check on the HELPER.
+ *
+ * ospf6
+ * Ospf6 pointer.
+ *
+ * enabled
+ * True - disable the lsa check.
+ * False - enable the strict lsa check.
+ *
+ * Returns:
+ * Nothing.
+ */
+static void ospf6_gr_helper_lsacheck_set(struct ospf6 *ospf6, bool enabled)
+{
+ if (ospf6->ospf6_helper_cfg.strict_lsa_check == enabled)
+ return;
+
+ ospf6->ospf6_helper_cfg.strict_lsa_check = enabled;
+}
+
+/*
+ * Api to set the supported restart reason.
+ *
+ * ospf6
+ * Ospf6 pointer.
+ *
+ * only_planned
+ * True: support only planned restart.
+ * False: support for planned/unplanned restarts.
+ *
+ * Returns:
+ * Nothing.
+ */
+
+static void
+ospf6_gr_helper_set_supported_onlyPlanned_restart(struct ospf6 *ospf6,
+ bool only_planned)
+{
+ ospf6->ospf6_helper_cfg.only_planned_restart = only_planned;
+}
+
+/*
+ * Api to set the supported grace interval in this router.
+ *
+ * ospf6
+ * Ospf6 pointer.
+ *
+ * interval
+ * The supported grace interval..
+ *
+ * Returns:
+ * Nothing.
+ */
+static void ospf6_gr_helper_supported_gracetime_set(struct ospf6 *ospf6,
+ uint32_t interval)
+{
+ ospf6->ospf6_helper_cfg.supported_grace_time = interval;
+}
+
+/* API to walk and print all the Helper supported router ids */
+static int ospf6_print_vty_helper_dis_rtr_walkcb(struct hash_bucket *bucket,
+ void *arg)
+{
+ struct advRtr *rtr = bucket->data;
+ struct vty *vty = (struct vty *)arg;
+ static unsigned int count;
+
+ vty_out(vty, "%-6pI4,", &rtr->advRtrAddr);
+ count++;
+
+ if (count % 5 == 0)
+ vty_out(vty, "\n");
+
+ return HASHWALK_CONTINUE;
+}
+
+/* API to walk and print all the Helper supported router ids.*/
+static int ospf6_print_json_helper_dis_rtr_walkcb(struct hash_bucket *bucket,
+ void *arg)
+{
+ struct advRtr *rtr = bucket->data;
+ struct json_object *json_rid_array = (struct json_object *)arg;
+ struct json_object *json_rid;
+ char router_id[16];
+
+ inet_ntop(AF_INET, &rtr->advRtrAddr, router_id, sizeof(router_id));
+
+ json_rid = json_object_new_object();
+
+ json_object_string_add(json_rid, "routerId", router_id);
+ json_object_array_add(json_rid_array, json_rid);
+
+ return HASHWALK_CONTINUE;
+}
+
+/*
+ * Enable/Disable HELPER support on a specified advertisement
+ * router.
+ *
+ * ospf6
+ * Ospf6 pointer.
+ *
+ * advRtr
+ * HELPER support for given Advertisement Router.
+ *
+ * support
+ * True - Enable Helper Support.
+ * False - Disable Helper Support.
+ *
+ * Returns:
+ * Nothing.
+ */
+static void ospf6_gr_helper_support_set_per_routerid(struct ospf6 *ospf6,
+ struct in_addr router_id,
+ bool support)
+{
+ struct advRtr temp;
+ struct advRtr *rtr;
+ struct listnode *i, *j, *k;
+ struct ospf6_interface *oi;
+ struct ospf6_neighbor *nbr;
+ struct ospf6_area *oa;
+
+ temp.advRtrAddr = router_id.s_addr;
+
+ if (support == OSPF6_FALSE) {
+ /*Delete the routerid from the enable router hash table */
+ rtr = hash_lookup(ospf6->ospf6_helper_cfg.enable_rtr_list,
+ &temp);
+
+ if (rtr) {
+ hash_release(ospf6->ospf6_helper_cfg.enable_rtr_list,
+ rtr);
+ ospf6_disable_rtr_hash_free(rtr);
+ }
+
+ /* If helper support is enabled globally
+ * no action is required.
+ */
+ if (ospf6->ospf6_helper_cfg.is_helper_supported)
+ return;
+
+ /* Cease the HELPER role fore neighbours from the
+ * specified advertisement router.
+ */
+ for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
+ for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) {
+
+ for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k,
+ nbr)) {
+
+ if (nbr->router_id != router_id.s_addr)
+ continue;
+
+ if (OSPF6_GR_IS_ACTIVE_HELPER(nbr))
+ ospf6_gr_helper_exit(
+ nbr,
+ OSPF6_GR_HELPER_TOPO_CHG);
+ }
+ }
+
+ } else {
+ /* Add the routerid to the enable router hash table */
+ hash_get(ospf6->ospf6_helper_cfg.enable_rtr_list, &temp,
+ ospf6_enable_rtr_hash_alloc);
+ }
+}
+
+static void show_ospfv6_gr_helper_per_nbr(struct vty *vty, json_object *json,
+ bool uj, struct ospf6_neighbor *nbr)
+{
+ if (!uj) {
+ vty_out(vty, " Routerid : %pI4\n", &nbr->router_id);
+ vty_out(vty, " Received Grace period : %d(in seconds).\n",
+ nbr->gr_helper_info.recvd_grace_period);
+ vty_out(vty, " Actual Grace period : %d(in seconds)\n",
+ nbr->gr_helper_info.actual_grace_period);
+ vty_out(vty, " Remaining GraceTime:%ld(in seconds).\n",
+ thread_timer_remain_second(
+ nbr->gr_helper_info.t_grace_timer));
+ vty_out(vty, " Graceful Restart reason: %s.\n\n",
+ ospf6_restart_reason_desc[nbr->gr_helper_info
+ .gr_restart_reason]);
+ } else {
+ char nbrid[16];
+ json_object *json_neigh = NULL;
+
+ inet_ntop(AF_INET, &nbr->router_id, nbrid, sizeof(nbrid));
+ json_neigh = json_object_new_object();
+ json_object_string_add(json_neigh, "routerid", nbrid);
+ json_object_int_add(json_neigh, "recvdGraceInterval",
+ nbr->gr_helper_info.recvd_grace_period);
+ json_object_int_add(json_neigh, "actualGraceInterval",
+ nbr->gr_helper_info.actual_grace_period);
+ json_object_int_add(json_neigh, "remainGracetime",
+ thread_timer_remain_second(
+ nbr->gr_helper_info.t_grace_timer));
+ json_object_string_add(json_neigh, "restartReason",
+ ospf6_restart_reason_desc[
+ nbr->gr_helper_info.gr_restart_reason]);
+ json_object_object_add(json, nbr->name, json_neigh);
+ }
+}
+
+static int show_ospf6_gr_helper_details(struct vty *vty, struct ospf6 *ospf6,
+ json_object *json, bool uj, bool detail)
+{
+ struct ospf6_interface *oi;
+
+ /* Show Router ID. */
+ if (uj) {
+ char router_id[16];
+
+ inet_ntop(AF_INET, &ospf6->router_id, router_id,
+ sizeof(router_id));
+ json_object_string_add(json, "routerId", router_id);
+ } else
+ vty_out(vty,
+ " OSPFv3 Routing Process (0) with Router-ID %pI4\n",
+ &ospf6->router_id);
+
+ if (!uj) {
+
+ if (ospf6->ospf6_helper_cfg.is_helper_supported)
+ vty_out(vty,
+ " Graceful restart helper support enabled.\n");
+ else
+ vty_out(vty,
+ " Graceful restart helper support disabled.\n");
+
+ if (ospf6->ospf6_helper_cfg.strict_lsa_check)
+ vty_out(vty, " Strict LSA check is enabled.\n");
+ else
+ vty_out(vty, " Strict LSA check is disabled.\n");
+
+ if (ospf6->ospf6_helper_cfg.only_planned_restart)
+ vty_out(vty,
+ " Helper supported for planned restarts only.\n");
+ else
+ vty_out(vty,
+ " Helper supported for Planned and Unplanned Restarts.\n");
+
+ vty_out(vty,
+ " Supported Graceful restart interval: %d(in seconds).\n",
+ ospf6->ospf6_helper_cfg.supported_grace_time);
+
+ if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf)) {
+ vty_out(vty, " Enable Router list:\n");
+ vty_out(vty, " ");
+ hash_walk(ospf6->ospf6_helper_cfg.enable_rtr_list,
+ ospf6_print_vty_helper_dis_rtr_walkcb, vty);
+ vty_out(vty, "\n\n");
+ }
+
+ if (ospf6->ospf6_helper_cfg.last_exit_reason
+ != OSPF6_GR_HELPER_EXIT_NONE) {
+ vty_out(vty, " Last Helper exit Reason :%s\n",
+ ospf6_exit_reason_desc
+ [ospf6->ospf6_helper_cfg
+ .last_exit_reason]);
+
+ if (ospf6->ospf6_helper_cfg.active_restarter_cnt)
+ vty_out(vty,
+ " Number of Active neighbours in graceful restart: %d\n",
+ ospf6->ospf6_helper_cfg
+ .active_restarter_cnt);
+ else
+ vty_out(vty, "\n");
+ }
+
+
+ } else {
+ json_object_string_add(
+ json, "helperSupport",
+ (ospf6->ospf6_helper_cfg.is_helper_supported)
+ ? "Enabled"
+ : "Disabled");
+ json_object_string_add(
+ json, "strictLsaCheck",
+ (ospf6->ospf6_helper_cfg.strict_lsa_check)
+ ? "Enabled"
+ : "Disabled");
+ json_object_string_add(
+ json, "restartSupoort",
+ (ospf6->ospf6_helper_cfg.only_planned_restart)
+ ? "Planned Restart only"
+ : "Planned and Unplanned Restarts");
+
+ json_object_int_add(
+ json, "supportedGracePeriod",
+ ospf6->ospf6_helper_cfg.supported_grace_time);
+
+ if (ospf6->ospf6_helper_cfg.last_exit_reason
+ != OSPF6_GR_HELPER_EXIT_NONE)
+ json_object_string_add(
+ json, "LastExitReason",
+ ospf6_exit_reason_desc
+ [ospf6->ospf6_helper_cfg
+ .last_exit_reason]);
+
+ if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6)) {
+ struct json_object *json_rid_array =
+ json_object_new_array();
+
+ json_object_object_add(json, "enabledRouterIds",
+ json_rid_array);
+
+ hash_walk(ospf6->ospf6_helper_cfg.enable_rtr_list,
+ ospf6_print_json_helper_dis_rtr_walkcb,
+ json_rid_array);
+ }
+ }
+
+ if (detail) {
+ int cnt = 1;
+ struct listnode *i, *j, *k;
+ struct ospf6_area *oa;
+ json_object *json_neighbors = NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
+ for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) {
+ struct ospf6_neighbor *nbr;
+
+ if (uj) {
+ json_object_object_get_ex(
+ json, "Neighbors",
+ &json_neighbors);
+ if (!json_neighbors) {
+ json_neighbors =
+ json_object_new_object();
+ json_object_object_add(
+ json, "Neighbors",
+ json_neighbors);
+ }
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k,
+ nbr)) {
+
+ if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr))
+ continue;
+
+ if (!uj)
+ vty_out(vty,
+ " Neighbour %d :\n",
+ cnt++);
+
+ show_ospfv6_gr_helper_per_nbr(
+ vty, json_neighbors, uj, nbr);
+
+ }
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+/* Graceful Restart HELPER config Commands */
+DEFPY(ospf6_gr_helper_enable,
+ ospf6_gr_helper_enable_cmd,
+ "graceful-restart helper-only [A.B.C.D$rtr_id]",
+ "ospf6 graceful restart\n"
+ "Enable Helper support\n"
+ "Advertisement RouterId\n")
+{
+ VTY_DECLVAR_CONTEXT(ospf6, ospf6);
+
+ if (rtr_id_str != NULL) {
+
+ ospf6_gr_helper_support_set_per_routerid(ospf6, rtr_id,
+ OSPF6_TRUE);
+
+ return CMD_SUCCESS;
+ }
+
+ ospf6_gr_helper_support_set(ospf6, OSPF6_TRUE);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(ospf6_gr_helper_disable,
+ ospf6_gr_helper_disable_cmd,
+ "no graceful-restart helper-only [A.B.C.D$rtr_id]",
+ NO_STR
+ "ospf6 graceful restart\n"
+ "Disable Helper support\n"
+ "Advertisement RouterId\n")
+{
+ VTY_DECLVAR_CONTEXT(ospf6, ospf6);
+
+ if (rtr_id_str != NULL) {
+
+ ospf6_gr_helper_support_set_per_routerid(ospf6, rtr_id,
+ OSPF6_FALSE);
+
+ return CMD_SUCCESS;
+ }
+
+ ospf6_gr_helper_support_set(ospf6, OSPF6_FALSE);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(ospf6_gr_helper_disable_lsacheck,
+ ospf6_gr_helper_disable_lsacheck_cmd,
+ "graceful-restart helper lsa-check-disable",
+ "ospf6 graceful restart\n"
+ "ospf6 GR Helper\n"
+ "disable strict LSA check\n")
+{
+ VTY_DECLVAR_CONTEXT(ospf6, ospf6);
+
+ ospf6_gr_helper_lsacheck_set(ospf6, OSPF6_FALSE);
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_ospf6_gr_helper_disable_lsacheck,
+ no_ospf6_gr_helper_disable_lsacheck_cmd,
+ "no graceful-restart helper lsa-check-disable",
+ NO_STR
+ "ospf6 graceful restart\n"
+ "ospf6 GR Helper\n"
+ "diasble strict LSA check\n")
+{
+ VTY_DECLVAR_CONTEXT(ospf6, ospf6);
+
+ ospf6_gr_helper_lsacheck_set(ospf6, OSPF6_TRUE);
+ return CMD_SUCCESS;
+}
+
+DEFPY(ospf6_gr_helper_planned_only,
+ ospf6_gr_helper_planned_only_cmd,
+ "graceful-restart helper planned-only",
+ "ospf6 graceful restart\n"
+ "ospf6 GR Helper\n"
+ "supported only planned restart\n")
+{
+ VTY_DECLVAR_CONTEXT(ospf6, ospf6);
+
+ ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6, OSPF6_TRUE);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_ospf6_gr_helper_planned_only, no_ospf6_gr_helper_planned_only_cmd,
+ "no graceful-restart helper planned-only",
+ NO_STR
+ "ospf6 graceful restart\n"
+ "ospf6 GR Helper\n"
+ "supported only for planned restart\n")
+{
+ VTY_DECLVAR_CONTEXT(ospf6, ospf6);
+
+ ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6, OSPF6_FALSE);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(ospf6_gr_helper_supported_grace_time,
+ ospf6_gr_helper_supported_grace_time_cmd,
+ "graceful-restart helper supported-grace-time (10-1800)$interval",
+ "ospf6 graceful restart\n"
+ "ospf6 GR Helper\n"
+ "supported grace timer\n"
+ "grace interval(in seconds)\n")
+{
+ VTY_DECLVAR_CONTEXT(ospf6, ospf6);
+
+ ospf6_gr_helper_supported_gracetime_set(ospf6, interval);
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_ospf6_gr_helper_supported_grace_time,
+ no_ospf6_gr_helper_supported_grace_time_cmd,
+ "no graceful-restart helper supported-grace-time (10-1800)$interval",
+ NO_STR
+ "ospf6 graceful restart\n"
+ "ospf6 GR Helper\n"
+ "supported grace timer\n"
+ "grace interval(in seconds)\n")
+{
+ VTY_DECLVAR_CONTEXT(ospf6, ospf6);
+
+ ospf6_gr_helper_supported_gracetime_set(ospf6,
+ OSPF6_MAX_GRACE_INTERVAL);
+ return CMD_SUCCESS;
+}
+
+/* Show commands */
+DEFPY(show_ipv6_ospf6_gr_helper,
+ show_ipv6_ospf6_gr_helper_cmd,
+ "show ipv6 ospf6 graceful-restart helper [detail] [json]",
+ SHOW_STR
+ "Ipv6 Information\n"
+ "OSPF6 information\n"
+ "ospf6 graceful restart\n"
+ "helper details in the router\n"
+ "detailed information\n" JSON_STR)
+{
+ int idx = 0;
+ bool uj = use_json(argc, argv);
+ struct ospf6 *ospf6 = NULL;
+ json_object *json = NULL;
+ bool detail = false;
+
+ ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
+ OSPF6_CMD_CHECK_RUNNING();
+
+ if (argv_find(argv, argc, "detail", &idx))
+ detail = true;
+
+ if (uj)
+ json = json_object_new_object();
+
+ show_ospf6_gr_helper_details(vty, ospf6, json, uj, detail);
+
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/* Debug commands */
+DEFPY(debug_ospf6_gr, debug_ospf6_gr_cmd,
+ "[no$no] debug ospf6 graceful-restart",
+ NO_STR DEBUG_STR OSPF6_STR "Graceful restart\n")
+{
+ if (!no)
+ OSPF6_DEBUG_GR_ON();
+ else
+ OSPF6_DEBUG_GR_OFF();
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Api to display the grace LSA information.
+ *
+ * vty
+ * vty pointer.
+ * lsa
+ * Grace LSA.
+ * json
+ * json object
+ *
+ * Returns:
+ * Nothing.
+ */
+static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa,
+ json_object *json, bool use_json)
+{
+ struct ospf6_lsa_header *lsah = NULL;
+ struct tlv_header *tlvh = NULL;
+ struct grace_tlv_graceperiod *gracePeriod;
+ struct grace_tlv_restart_reason *grReason;
+ uint16_t length = 0;
+ int sum = 0;
+
+ lsah = (struct ospf6_lsa_header *)lsa->header;
+
+ length = ntohs(lsah->length) - OSPF6_LSA_HEADER_SIZE;
+
+ if (vty) {
+ if (!use_json)
+ vty_out(vty, "TLV info:\n");
+ } else {
+ zlog_debug(" TLV info:");
+ }
+
+ for (tlvh = TLV_HDR_TOP(lsah); sum < length;
+ tlvh = TLV_HDR_NEXT(tlvh)) {
+ switch (ntohs(tlvh->type)) {
+ case GRACE_PERIOD_TYPE:
+ gracePeriod = (struct grace_tlv_graceperiod *)tlvh;
+ sum += TLV_SIZE(tlvh);
+
+ if (vty) {
+ if (use_json)
+ json_object_int_add(
+ json, "gracePeriod",
+ ntohl(gracePeriod->interval));
+ else
+ vty_out(vty, " Grace period:%d\n",
+ ntohl(gracePeriod->interval));
+ } else {
+ zlog_debug(" Grace period:%d",
+ ntohl(gracePeriod->interval));
+ }
+ break;
+ case RESTART_REASON_TYPE:
+ grReason = (struct grace_tlv_restart_reason *)tlvh;
+ sum += TLV_SIZE(tlvh);
+ if (vty) {
+ if (use_json)
+ json_object_string_add(
+ json, "restartReason",
+ ospf6_restart_reason_desc
+ [grReason->reason]);
+ else
+ vty_out(vty, " Restart reason:%s\n",
+ ospf6_restart_reason_desc
+ [grReason->reason]);
+ } else {
+ zlog_debug(" Restart reason:%s",
+ ospf6_restart_reason_desc
+ [grReason->reason]);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+void ospf6_gr_helper_config_init(void)
+{
+
+ ospf6_install_lsa_handler(&grace_lsa_handler);
+
+ install_element(OSPF6_NODE, &ospf6_gr_helper_enable_cmd);
+ install_element(OSPF6_NODE, &ospf6_gr_helper_disable_cmd);
+ install_element(OSPF6_NODE, &ospf6_gr_helper_disable_lsacheck_cmd);
+ install_element(OSPF6_NODE, &no_ospf6_gr_helper_disable_lsacheck_cmd);
+ install_element(OSPF6_NODE, &ospf6_gr_helper_planned_only_cmd);
+ install_element(OSPF6_NODE, &no_ospf6_gr_helper_planned_only_cmd);
+ install_element(OSPF6_NODE, &ospf6_gr_helper_supported_grace_time_cmd);
+ install_element(OSPF6_NODE,
+ &no_ospf6_gr_helper_supported_grace_time_cmd);
+
+ install_element(VIEW_NODE, &show_ipv6_ospf6_gr_helper_cmd);
+
+ install_element(CONFIG_NODE, &debug_ospf6_gr_cmd);
+ install_element(ENABLE_NODE, &debug_ospf6_gr_cmd);
+}
+
+
+/*
+ * Initialize GR helper config data structure.
+ *
+ * ospf6
+ * ospf6 pointer
+ *
+ * Returns:
+ * Nothing
+ */
+void ospf6_gr_helper_init(struct ospf6 *ospf6)
+{
+ if (IS_DEBUG_OSPF6_GR)
+ zlog_debug("%s, GR Helper init.", __func__);
+
+ ospf6->ospf6_helper_cfg.is_helper_supported = OSPF6_FALSE;
+ ospf6->ospf6_helper_cfg.strict_lsa_check = OSPF6_TRUE;
+ ospf6->ospf6_helper_cfg.only_planned_restart = OSPF6_FALSE;
+ ospf6->ospf6_helper_cfg.supported_grace_time = OSPF6_MAX_GRACE_INTERVAL;
+ ospf6->ospf6_helper_cfg.last_exit_reason = OSPF6_GR_HELPER_EXIT_NONE;
+ ospf6->ospf6_helper_cfg.active_restarter_cnt = 0;
+
+ ospf6->ospf6_helper_cfg.enable_rtr_list = hash_create(
+ ospf6_enable_rtr_hash_key, ospf6_enable_rtr_hash_cmp,
+ "Ospf6 enable router hash");
+}
+
+/*
+ * De-initialize GR helper config data structure.
+ *
+ * ospf6
+ * ospf6 pointer
+ *
+ * Returns:
+ * Nothing
+ */
+void ospf6_gr_helper_deinit(struct ospf6 *ospf6)
+{
+
+ if (IS_DEBUG_OSPF6_GR)
+ zlog_debug("%s, GR helper deinit.", __func__);
+
+ ospf6_enable_rtr_hash_destroy(ospf6);
+}
+
+static int ospf6_cfg_write_helper_enable_rtr_walkcb(struct hash_bucket *backet,
+ void *arg)
+{
+ struct advRtr *rtr = backet->data;
+ struct vty *vty = (struct vty *)arg;
+
+ vty_out(vty, " graceful-restart helper-only %pI4\n", &rtr->advRtrAddr);
+ return HASHWALK_CONTINUE;
+}
+
+int config_write_ospf6_gr_helper(struct vty *vty, struct ospf6 *ospf6)
+{
+ if (ospf6->ospf6_helper_cfg.is_helper_supported)
+ vty_out(vty, " graceful-restart helper-only\n");
+
+ if (!ospf6->ospf6_helper_cfg.strict_lsa_check)
+ vty_out(vty, " graceful-restart helper lsa-check-disable\n");
+
+ if (ospf6->ospf6_helper_cfg.only_planned_restart)
+ vty_out(vty, " graceful-restart helper planned-only\n");
+
+ if (ospf6->ospf6_helper_cfg.supported_grace_time
+ != OSPF6_MAX_GRACE_INTERVAL)
+ vty_out(vty,
+ " graceful-restart helper supported-grace-time %d\n",
+ ospf6->ospf6_helper_cfg.supported_grace_time);
+
+ if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6)) {
+ hash_walk(ospf6->ospf6_helper_cfg.enable_rtr_list,
+ ospf6_cfg_write_helper_enable_rtr_walkcb, vty);
+ }
+
+ return 0;
+}
+
+int config_write_ospf6_debug_gr_helper(struct vty *vty)
+{
+ if (IS_DEBUG_OSPF6_GR)
+ vty_out(vty, "debug ospf6 gr helper\n");
+ return 0;
+}
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index a169b9c60e..bbb474ba1a 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -44,9 +44,10 @@
#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);
diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h
index b5efca743e..ccdf8b1c8f 100644
--- a/ospf6d/ospf6_interface.h
+++ b/ospf6d/ospf6_interface.h
@@ -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),
diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h
index 4c95ee69bd..a8ed9132dd 100644
--- a/ospf6d/ospf6_lsa.h
+++ b/ospf6d/ospf6_lsa.h
@@ -70,7 +70,8 @@
#define OSPF6_LSTYPE_TYPE_7 0x2007
#define OSPF6_LSTYPE_LINK 0x0008
#define OSPF6_LSTYPE_INTRA_PREFIX 0x2009
-#define OSPF6_LSTYPE_SIZE 0x000a
+#define OSPF6_LSTYPE_GRACE_LSA 0x000b
+#define OSPF6_LSTYPE_SIZE 0x000c
/* Masks for LS Type : RFC 2740 A.4.2.1 "LS type" */
#define OSPF6_LSTYPE_UBIT_MASK 0x8000
@@ -146,6 +147,9 @@ struct ospf6_lsa {
/* lsa instance */
struct ospf6_lsa_header *header;
+
+ /*For topo chg detection in HELPER role*/
+ bool tobe_acknowledged;
};
#define OSPF6_LSA_HEADERONLY 0x01
@@ -210,6 +214,14 @@ extern vector ospf6_lsa_handler_vector;
continue; \
}
+#define CHECK_LSA_TOPO_CHG_ELIGIBLE(type) \
+ ((type == OSPF6_LSTYPE_ROUTER) \
+ || (type == OSPF6_LSTYPE_NETWORK) \
+ || (type == OSPF6_LSTYPE_INTER_PREFIX) \
+ || (type == OSPF6_LSTYPE_INTER_ROUTER) \
+ || (type == OSPF6_LSTYPE_AS_EXTERNAL) \
+ || (type == OSPF6_LSTYPE_TYPE_7) \
+ || (type == OSPF6_LSTYPE_INTRA_PREFIX))
/* Function Prototypes */
extern const char *ospf6_lstype_name(uint16_t type);
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index 549f5668b9..cd73e3d406 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -46,7 +46,7 @@
#include "ospf6_flood.h"
#include "ospf6d.h"
-
+#include "ospf6_gr.h"
#include <netinet/ip6.h>
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_MESSAGE, "OSPF6 message");
@@ -84,7 +84,9 @@ const uint16_t ospf6_lsa_minlen[OSPF6_LSTYPE_SIZE] = {
/* 0x2006 */ 0,
/* 0x2007 */ OSPF6_AS_EXTERNAL_LSA_MIN_SIZE,
/* 0x0008 */ OSPF6_LINK_LSA_MIN_SIZE,
- /* 0x2009 */ OSPF6_INTRA_PREFIX_LSA_MIN_SIZE};
+ /* 0x2009 */ OSPF6_INTRA_PREFIX_LSA_MIN_SIZE,
+ /* 0x200a */ 0,
+ /* 0x000b */ OSPF6_GRACE_LSA_MIN_SIZE};
/* print functions */
@@ -512,8 +514,44 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst,
thread_execute(master, hello_received, on, 0);
if (twoway)
thread_execute(master, twoway_received, on, 0);
- else
- thread_execute(master, oneway_received, on, 0);
+ else {
+ if (IS_DEBUG_OSPF6_GR)
+ zlog_debug(
+ "%s, Received oneway hello from RESTARTER so ignore here.",
+ __PRETTY_FUNCTION__);
+
+ if (!OSPF6_GR_IS_ACTIVE_HELPER(on)) {
+ /* If the router is DR_OTHER, RESTARTER will not wait
+ * until it receives the hello from it if it receives
+ * from DR and BDR.
+ * So, helper might receives ONE_WAY hello from
+ * RESTARTER. So not allowing to change the state if it
+ * receives one_way hellow when it acts as HELPER for
+ * that specific neighbor.
+ */
+ thread_execute(master, oneway_received, on, 0);
+ }
+ }
+
+ if (OSPF6_GR_IS_ACTIVE_HELPER(on)) {
+ /* As per the GR Conformance Test Case 7.2. Section 3
+ * "Also, if X was the Designated Router on network segment S
+ * when the helping relationship began, Y maintains X as the
+ * Designated Router until the helping relationship is
+ * terminated."
+ * When it is a helper for this neighbor, It should not trigger
+ * the ISM Events. Also Intentionally not setting the priority
+ * and other fields so that when the neighbor exits the Grace
+ * period, it can handle if there is any change before GR and
+ * after GR.
+ */
+ if (IS_DEBUG_OSPF6_GR)
+ zlog_debug(
+ "%s, Neighbor is under GR Restart, hence ignoring the ISM Events",
+ __PRETTY_FUNCTION__);
+
+ return;
+ }
/* Schedule interface events */
if (backupseen)
@@ -1260,7 +1298,15 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah,
lsalen - OSPF6_LSA_HEADER_SIZE
- OSPF6_INTRA_PREFIX_LSA_MIN_SIZE,
ntohs(intra_prefix_lsa->prefix_num) /* 16 bits */
- );
+ );
+ case OSPF6_LSTYPE_GRACE_LSA:
+ if (lsalen < OSPF6_LSA_HEADER_SIZE + GRACE_PERIOD_TLV_SIZE
+ + GRACE_RESTART_REASON_TLV_SIZE) {
+ if (IS_DEBUG_OSPF6_GR)
+ zlog_debug("%s: Undersized GraceLSA.",
+ __func__);
+ return MSG_NG;
+ }
}
/* No additional validation is possible for unknown LSA types, which are
themselves valid in OPSFv3, hence the default decision is to accept.
diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c
index 8cf05183e1..4ea615f32b 100644
--- a/ospf6d/ospf6_neighbor.c
+++ b/ospf6d/ospf6_neighbor.c
@@ -45,6 +45,7 @@
#include "ospf6_lsa.h"
#include "ospf6_spf.h"
#include "ospf6_zebra.h"
+#include "ospf6_gr.h"
#include "lib/json.h"
DEFINE_MTYPE(OSPF6D, OSPF6_NEIGHBOR, "OSPF6 neighbor");
@@ -151,6 +152,7 @@ void ospf6_neighbor_delete(struct ospf6_neighbor *on)
THREAD_OFF(on->thread_send_lsreq);
THREAD_OFF(on->thread_send_lsupdate);
THREAD_OFF(on->thread_send_lsack);
+ THREAD_OFF(on->gr_helper_info.t_grace_timer);
bfd_sess_free(&on->bfd_session);
XFREE(MTYPE_OSPF6_NEIGHBOR, on);
@@ -192,19 +194,24 @@ static void ospf6_neighbor_state_change(uint8_t next_state,
if (prev_state == OSPF6_NEIGHBOR_FULL
|| next_state == OSPF6_NEIGHBOR_FULL) {
- OSPF6_ROUTER_LSA_SCHEDULE(on->ospf6_if->area);
- if (on->ospf6_if->state == OSPF6_INTERFACE_DR) {
- OSPF6_NETWORK_LSA_SCHEDULE(on->ospf6_if);
- OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT(on->ospf6_if);
+ if (!OSPF6_GR_IS_ACTIVE_HELPER(on)) {
+ OSPF6_ROUTER_LSA_SCHEDULE(on->ospf6_if->area);
+ if (on->ospf6_if->state == OSPF6_INTERFACE_DR) {
+ OSPF6_NETWORK_LSA_SCHEDULE(on->ospf6_if);
+ OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT(
+ on->ospf6_if);
+ }
}
if (next_state == OSPF6_NEIGHBOR_FULL)
on->ospf6_if->area->intra_prefix_originate = 1;
- OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(on->ospf6_if->area);
+ if (!OSPF6_GR_IS_ACTIVE_HELPER(on))
+ OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(
+ on->ospf6_if->area);
- if ((prev_state == OSPF6_NEIGHBOR_LOADING ||
- prev_state == OSPF6_NEIGHBOR_EXCHANGE) &&
- next_state == OSPF6_NEIGHBOR_FULL) {
+ if ((prev_state == OSPF6_NEIGHBOR_LOADING
+ || prev_state == OSPF6_NEIGHBOR_EXCHANGE)
+ && next_state == OSPF6_NEIGHBOR_FULL) {
OSPF6_AS_EXTERN_LSA_SCHEDULE(on->ospf6_if);
on->ospf6_if->area->full_nbrs++;
}
@@ -601,12 +608,29 @@ int inactivity_timer(struct thread *thread)
on->drouter = on->prev_drouter = 0;
on->bdrouter = on->prev_bdrouter = 0;
- ospf6_neighbor_state_change(OSPF6_NEIGHBOR_DOWN, on,
- OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER);
- thread_add_event(master, neighbor_change, on->ospf6_if, 0, NULL);
+ if (!OSPF6_GR_IS_ACTIVE_HELPER(on)) {
+ on->drouter = on->prev_drouter = 0;
+ on->bdrouter = on->prev_bdrouter = 0;
+
+ ospf6_neighbor_state_change(
+ OSPF6_NEIGHBOR_DOWN, on,
+ OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER);
+ thread_add_event(master, neighbor_change, on->ospf6_if, 0,
+ NULL);
+
+ listnode_delete(on->ospf6_if->neighbor_list, on);
+ ospf6_neighbor_delete(on);
- listnode_delete(on->ospf6_if->neighbor_list, on);
- ospf6_neighbor_delete(on);
+ } else {
+ if (IS_DEBUG_OSPF6_GR)
+ zlog_debug(
+ "%s, Acting as HELPER for this neighbour, So restart the dead timer.",
+ __PRETTY_FUNCTION__);
+
+ thread_add_timer(master, inactivity_timer, on,
+ on->ospf6_if->dead_interval,
+ &on->inactivity_timer);
+ }
return 0;
}
diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h
index 729b1d2e85..a229897226 100644
--- a/ospf6d/ospf6_neighbor.h
+++ b/ospf6d/ospf6_neighbor.h
@@ -32,6 +32,38 @@ extern unsigned char conf_debug_ospf6_neighbor;
#define IS_OSPF6_DEBUG_NEIGHBOR(level) \
(conf_debug_ospf6_neighbor & OSPF6_DEBUG_NEIGHBOR_##level)
+struct ospf6_helper_info {
+
+ /* Grace interval received from
+ * Restarting Router.
+ */
+ uint32_t recvd_grace_period;
+
+ /* Grace interval used for grace
+ * gracetimer.
+ */
+ uint32_t actual_grace_period;
+
+ /* Grace timer,This Router acts as
+ * helper until this timer until
+ * this timer expires.
+ */
+ struct thread *t_grace_timer;
+
+ /* Helper status */
+ uint32_t gr_helper_status;
+
+ /* Helper exit reason*/
+ uint32_t helper_exit_reason;
+
+ /* Planned/Unplanned restart*/
+ uint32_t gr_restart_reason;
+
+
+ /* Helper rejected reason */
+ uint32_t rejected_reason;
+};
+
/* Neighbor structure */
struct ospf6_neighbor {
/* Neighbor Router ID String */
@@ -104,6 +136,9 @@ struct ospf6_neighbor {
/* BFD information */
struct bfd_session_params *bfd_session;
+
+ /* ospf6 graceful restart HELPER info */
+ struct ospf6_helper_info gr_helper_info;
};
/* Neighbor state */
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index 6105e2c24b..fc181a6d18 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -51,6 +51,7 @@
#include "ospf6_intra.h"
#include "ospf6_spf.h"
#include "ospf6d.h"
+#include "ospf6_gr.h"
#include "lib/json.h"
#include "ospf6_nssa.h"
@@ -440,6 +441,7 @@ static struct ospf6 *ospf6_create(const char *name)
o->oi_write_q = list_new();
+ ospf6_gr_helper_init(o);
QOBJ_REG(o, ospf6);
/* Make ospf protocol socket. */
@@ -485,6 +487,7 @@ void ospf6_delete(struct ospf6 *o)
QOBJ_UNREG(o);
+ ospf6_gr_helper_deinit(o);
ospf6_flush_self_originated_lsas_now(o);
ospf6_disable(o);
ospf6_del(o);
@@ -2233,7 +2236,7 @@ static int config_write_ospf6(struct vty *vty)
ospf6_distance_config_write(vty, ospf6);
ospf6_distribute_config_write(vty, ospf6);
ospf6_asbr_summary_config_write(vty, ospf6);
-
+ config_write_ospf6_gr_helper(vty, ospf6);
vty_out(vty, "!\n");
}
return 0;
diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h
index fe02cd3f84..58ecf08495 100644
--- a/ospf6d/ospf6_top.h
+++ b/ospf6d/ospf6_top.h
@@ -60,6 +60,43 @@ struct ospf6_redist {
#define ROUTEMAP(R) (R->route_map.map)
};
+struct ospf6_gr_helper {
+ /* Gracefull restart Helper supported configs*/
+ /* Supported grace interval*/
+ uint32_t supported_grace_time;
+
+ /* Helper support
+ * Supported : True
+ * Not Supported : False.
+ */
+ bool is_helper_supported;
+
+ /* Support for strict LSA check.
+ * if it is set,Helper aborted
+ * upon a TOPO change.
+ */
+ bool strict_lsa_check;
+
+ /* Support as HELPER only for
+ * planned restarts.
+ */
+ bool only_planned_restart;
+
+ /* This list contains the advertisement
+ * routerids for which Helper support is
+ * enabled.
+ */
+ struct hash *enable_rtr_list;
+
+ /* HELPER for number of active
+ * RESTARTERs.
+ */
+ int active_restarter_cnt;
+
+ /* last HELPER exit reason */
+ uint32_t last_exit_reason;
+};
+
/* OSPFv3 top level data structure */
struct ospf6 {
/* The relevant vrf_id */
@@ -154,6 +191,10 @@ struct ospf6 {
* to support ECMP.
*/
uint16_t max_multipath;
+
+ /*ospf6 Graceful restart helper info */
+ struct ospf6_gr_helper ospf6_helper_cfg;
+
/* Count of NSSA areas */
uint8_t anyNSSA;
struct thread *t_abr_task; /* ABR task timer. */
diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c
index fb6ac4402a..5dfd986e2a 100644
--- a/ospf6d/ospf6d.c
+++ b/ospf6d/ospf6d.c
@@ -45,6 +45,7 @@
#include "ospf6_flood.h"
#include "ospf6d.h"
#include "ospf6_bfd.h"
+#include "ospf6_gr.h"
#include "lib/json.h"
#include "ospf6_nssa.h"
@@ -96,6 +97,7 @@ static int config_write_ospf6_debug(struct vty *vty)
config_write_ospf6_debug_abr(vty);
config_write_ospf6_debug_flood(vty);
config_write_ospf6_debug_nssa(vty);
+ config_write_ospf6_debug_gr_helper(vty);
return 0;
}
@@ -1402,6 +1404,7 @@ void ospf6_init(struct thread_master *master)
ospf6_intra_init();
ospf6_asbr_init();
ospf6_abr_init();
+ ospf6_gr_helper_config_init();
/* initialize hooks for modifying filter rules */
prefix_list_add_hook(ospf6_plist_add);
diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h
index 5afece9b0a..d5170be7cc 100644
--- a/ospf6d/ospf6d.h
+++ b/ospf6d/ospf6d.h
@@ -108,6 +108,12 @@ extern struct thread_master *master;
vrf_name = VRF_DEFAULT_NAME; \
}
+#define OSPF6_FALSE false
+#define OSPF6_TRUE true
+#define OSPF6_SUCCESS 1
+#define OSPF6_FAILURE 0
+#define OSPF6_INVALID -1
+
extern struct zebra_privs_t ospf6d_privs;
/* Function Prototypes */
diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am
index 78fb26b00e..ac99e90b26 100644
--- a/ospf6d/subdir.am
+++ b/ospf6d/subdir.am
@@ -12,6 +12,7 @@ vtysh_scan += \
ospf6d/ospf6_area.c \
ospf6d/ospf6_bfd.c \
ospf6d/ospf6_flood.c \
+ ospf6d/ospf6_gr_helper.c \
ospf6d/ospf6_interface.c \
ospf6d/ospf6_intra.c \
ospf6d/ospf6_lsa.c \
@@ -39,6 +40,7 @@ ospf6d_libospf6_a_SOURCES = \
ospf6d/ospf6_routemap_nb_config.c \
ospf6d/ospf6_bfd.c \
ospf6d/ospf6_flood.c \
+ ospf6d/ospf6_gr_helper.c \
ospf6d/ospf6_interface.c \
ospf6d/ospf6_intra.c \
ospf6d/ospf6_lsa.c \
@@ -61,6 +63,7 @@ noinst_HEADERS += \
ospf6d/ospf6_asbr.h \
ospf6d/ospf6_bfd.h \
ospf6d/ospf6_flood.h \
+ ospf6d/ospf6_gr.h \
ospf6d/ospf6_interface.h \
ospf6d/ospf6_intra.h \
ospf6d/ospf6_lsa.h \
@@ -91,6 +94,7 @@ clippy_scan += \
ospf6d/ospf6_top.c \
ospf6d/ospf6_asbr.c \
ospf6d/ospf6_lsa.c \
+ ospf6d/ospf6_gr_helper.c \
# end
nodist_ospf6d_ospf6d_SOURCES = \