From 6539d9ef457b6894220415c42c2b8aeded34c188 Mon Sep 17 00:00:00 2001 From: rgirada Date: Fri, 25 Jun 2021 00:59:50 -0700 Subject: [PATCH 1/7] ospf6d: documentation for ospf6 GR helper functionality Description: Documentation for ospf6 graceful restart Helper functionality. Ref RFC : 5187. Signed-off-by: Rajesh Girada --- doc/user/ospf6d.rst | 46 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index 948527d774..e4f9a67b80 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -319,6 +319,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 @@ -412,6 +445,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. + Sample configuration ==================== From 91c169f7d78e71417431c4297da008145da98d9d Mon Sep 17 00:00:00 2001 From: rgirada Date: Fri, 25 Jun 2021 02:49:47 -0700 Subject: [PATCH 2/7] ospf6d: Datastructure modification for GR helper functionality. Description: Adding GR helper specific datastructures. Signed-off-by: Rajesh Girada --- ospf6d/ospf6_lsa.h | 14 +++++++++++++- ospf6d/ospf6_neighbor.h | 35 +++++++++++++++++++++++++++++++++++ ospf6d/ospf6_top.h | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 1 deletion(-) 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_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.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. */ From 59790f521a843d46b0640592c34bdc0731d7f8db Mon Sep 17 00:00:00 2001 From: rgirada Date: Mon, 28 Jun 2021 00:04:54 -0700 Subject: [PATCH 3/7] ospf6d: Init/De-init gr helper functionality Description: Graceful restart helper functionality initialisation and deinit apis. Signed-off-by: Rajesh Girada --- ospf6d/ospf6_gr_helper.c | 155 +++++++++++++++++++++++++++++++++++++++ ospf6d/ospf6_gr_helper.h | 137 ++++++++++++++++++++++++++++++++++ ospf6d/ospf6_top.c | 4 +- ospf6d/ospf6d.h | 6 ++ ospf6d/subdir.am | 4 + 5 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 ospf6d/ospf6_gr_helper.c create mode 100644 ospf6d/ospf6_gr_helper.h diff --git a/ospf6d/ospf6_gr_helper.c b/ospf6d/ospf6_gr_helper.c new file mode 100644 index 0000000000..0108423cee --- /dev/null +++ b/ospf6d/ospf6_gr_helper.c @@ -0,0 +1,155 @@ +/* + * 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 + */ + +#include + +#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_helper.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"); + +const char *ospf6_exit_reason_desc[] = { + "Unknown reason", "Helper inprogress", "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; +} + +/* + * Initilise GR helper config datastructer. + * + * ospf6 + * ospf6 pointer + * + * Returns: + * Nothing + */ +void ospf6_gr_helper_init(struct ospf6 *ospf6) +{ + 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-Initilise GR helper config datastructer. + * + * ospf6 + * ospf6 pointer + * + * Returns: + * Nothing + */ +void ospf6_gr_helper_deinit(struct ospf6 *ospf6) +{ + ospf6_enable_rtr_hash_destroy(ospf6); +} diff --git a/ospf6d/ospf6_gr_helper.h b/ospf6d/ospf6_gr_helper.h new file mode 100644 index 0000000000..f5d49d4c06 --- /dev/null +++ b/ospf6d/ospf6_gr_helper.h @@ -0,0 +1,137 @@ +/* + * 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_HELPER_H +#define OSPF6_GR_HELPER_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 + +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 appendex-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.enableRtrList->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)->grHelperInfo.grHelper_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_init(struct ospf6 *ospf6); +extern void ospf6_gr_helper_deinit(struct ospf6 *ospf6); +#endif /* OSPF6_GR_HELPER_H */ diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 6105e2c24b..e445e8703c 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_helper.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,6 @@ 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); - vty_out(vty, "!\n"); } return 0; 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..608d3d1a29 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_helper.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 = \ From 0694366601e1be40c2a5ef903a280fabe5c2b170 Mon Sep 17 00:00:00 2001 From: rgirada Date: Mon, 28 Jun 2021 01:56:09 -0700 Subject: [PATCH 4/7] ospf6d: debug command support for helper support. Description: Adding debug support for helper functionality. Signed-off-by: Rajesh Girada --- ospf6d/ospf6_gr_helper.c | 25 +++++++++++++++++++++++++ ospf6d/ospf6_gr_helper.h | 14 ++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/ospf6d/ospf6_gr_helper.c b/ospf6d/ospf6_gr_helper.c index 0108423cee..a7a1b7cbab 100644 --- a/ospf6d/ospf6_gr_helper.c +++ b/ospf6d/ospf6_gr_helper.c @@ -55,6 +55,8 @@ DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_GR_HELPER, "OSPF6 Graceful restart helper"); +unsigned char conf_debug_ospf6_gr = 0; + const char *ospf6_exit_reason_desc[] = { "Unknown reason", "Helper inprogress", "Topology Change", "Grace timer expiry", "Successful graceful restart", @@ -117,6 +119,22 @@ static void ospf6_enable_rtr_hash_destroy(struct ospf6 *ospf6) ospf6->ospf6_helper_cfg.enable_rtr_list = NULL; } +/* 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_HELPER_ON(); + else + OSPF6_DEBUG_GR_HELPER_OFF(); + + return CMD_SUCCESS; +} + /* * Initilise GR helper config datastructer. * @@ -128,6 +146,9 @@ static void ospf6_enable_rtr_hash_destroy(struct ospf6 *ospf6) */ void ospf6_gr_helper_init(struct ospf6 *ospf6) { + if (IS_DEBUG_OSPF6_GR_HELPER) + zlog_debug("%s, GR Helper init.", __PRETTY_FUNCTION__); + 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; @@ -151,5 +172,9 @@ void ospf6_gr_helper_init(struct ospf6 *ospf6) */ void ospf6_gr_helper_deinit(struct ospf6 *ospf6) { + + if (IS_DEBUG_OSPF6_GR_HELPER) + zlog_debug("%s, GR helper deinit.", __PRETTY_FUNCTION__); + ospf6_enable_rtr_hash_destroy(ospf6); } diff --git a/ospf6d/ospf6_gr_helper.h b/ospf6d/ospf6_gr_helper.h index f5d49d4c06..f09ffa1bc9 100644 --- a/ospf6d/ospf6_gr_helper.h +++ b/ospf6d/ospf6_gr_helper.h @@ -33,6 +33,20 @@ #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_HELPER 0x01 + +#define OSPF6_DEBUG_GR_HELPER_ON() \ + (conf_debug_ospf6_gr |= OSPF6_DEBUG_GR_HELPER) + +#define OSPF6_DEBUG_GR_HELPER_OFF() \ + (conf_debug_ospf6_gr &= ~OSPF6_DEBUG_GR_HELPER) + +#define IS_DEBUG_OSPF6_GR_HELPER conf_debug_ospf6_gr + + enum ospf6_helper_exit_reason { OSPF6_GR_HELPER_EXIT_NONE = 0, OSPF6_GR_HELPER_INPROGRESS, From 0d1753a7db0c8fa3839918ec8eccb207ba1d2594 Mon Sep 17 00:00:00 2001 From: rgirada Date: Mon, 28 Jun 2021 04:55:27 -0700 Subject: [PATCH 5/7] ospf6d: Helper functionality changes Description: 1. changes to process GRACE LSA packet. 2. Validation changes to enter Helper role. 3. Helper functionality during graceful restart. Signed-off-by: Rajesh Girada --- ospf6d/ospf6_flood.c | 25 ++ ospf6d/{ospf6_gr_helper.h => ospf6_gr.h} | 10 +- ospf6d/ospf6_gr_helper.c | 296 ++++++++++++++++++++++- ospf6d/ospf6_message.c | 56 ++++- ospf6d/ospf6_neighbor.c | 50 +++- ospf6d/ospf6_top.c | 2 +- ospf6d/subdir.am | 2 +- 7 files changed, 411 insertions(+), 30 deletions(-) rename ospf6d/{ospf6_gr_helper.h => ospf6_gr.h} (94%) diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index 3d52597161..77c2ad1628 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; @@ -999,6 +1000,30 @@ 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 (IS_DEBUG_OSPF6_GR_HELPER) + zlog_debug( + "%s, Received a GraceLSA from router %d", + __PRETTY_FUNCTION__, + 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", + __PRETTY_FUNCTION__); + return; + } + } + /* (d), installing lsdb, which may cause routing table calculation (replacing database copy) */ ospf6_install_lsa(new); diff --git a/ospf6d/ospf6_gr_helper.h b/ospf6d/ospf6_gr.h similarity index 94% rename from ospf6d/ospf6_gr_helper.h rename to ospf6d/ospf6_gr.h index f09ffa1bc9..6336363688 100644 --- a/ospf6d/ospf6_gr_helper.h +++ b/ospf6d/ospf6_gr.h @@ -21,8 +21,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef OSPF6_GR_HELPER_H -#define OSPF6_GR_HELPER_H +#ifndef OSPF6_GR_H +#define OSPF6_GR_H #define OSPF6_GR_NOT_HELPER 0 #define OSPF6_GR_ACTIVE_HELPER 1 @@ -134,7 +134,7 @@ struct advRtr { /* Check the router is HELPER for current neighbour */ #define OSPF6_GR_IS_ACTIVE_HELPER(N) \ - ((N)->grHelperInfo.grHelper_status == OSPF6_GR_ACTIVE_HELPER) + ((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) @@ -148,4 +148,6 @@ 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); -#endif /* OSPF6_GR_HELPER_H */ +extern int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, + struct ospf6_neighbor *nbr); +#endif /* OSPF6_GR_H */ diff --git a/ospf6d/ospf6_gr_helper.c b/ospf6d/ospf6_gr_helper.c index a7a1b7cbab..d035171154 100644 --- a/ospf6d/ospf6_gr_helper.c +++ b/ospf6d/ospf6_gr_helper.c @@ -1,5 +1,5 @@ /* - * OSPF6 Graceful Retsart helper functions. + * OSPF6 Graceful Restart helper functions. * * Copyright (C) 2021-22 Vmware, Inc. * Rajesh Kumar Girada @@ -47,7 +47,7 @@ #include "ospf6_neighbor.h" #include "ospf6_intra.h" #include "ospf6d.h" -#include "ospf6_gr_helper.h" +#include "ospf6_gr.h" #include "lib/json.h" #ifndef VTYSH_EXTRACT_PL #include "ospf6d/ospf6_gr_helper_clippy.c" @@ -55,7 +55,7 @@ DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_GR_HELPER, "OSPF6 Graceful restart helper"); -unsigned char conf_debug_ospf6_gr = 0; +unsigned char conf_debug_ospf6_gr; const char *ospf6_exit_reason_desc[] = { "Unknown reason", "Helper inprogress", "Topology Change", @@ -119,6 +119,290 @@ static void ospf6_enable_rtr_hash_destroy(struct ospf6 *ospf6) 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_HELPER) + 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_HELPER) + zlog_debug("%s, Wrong Grace LSA packet.", + __func__); + return OSPF6_GR_NOT_HELPER; + } + + if (IS_DEBUG_OSPF6_GR_HELPER) + 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_HELPER) + 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_HELPER) + 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_HELPER) + 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_HELPER) + 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_HELPER) + 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_HELPER) + 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_HELPER) + 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_HELPER) + 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_HELPER) + 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; +} + /* Debug commands */ DEFPY(debug_ospf6_gr, debug_ospf6_gr_cmd, @@ -136,7 +420,7 @@ DEFPY(debug_ospf6_gr, } /* - * Initilise GR helper config datastructer. + * Initialize GR helper config data structure. * * ospf6 * ospf6 pointer @@ -147,7 +431,7 @@ DEFPY(debug_ospf6_gr, void ospf6_gr_helper_init(struct ospf6 *ospf6) { if (IS_DEBUG_OSPF6_GR_HELPER) - zlog_debug("%s, GR Helper init.", __PRETTY_FUNCTION__); + 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; @@ -174,7 +458,7 @@ void ospf6_gr_helper_deinit(struct ospf6 *ospf6) { if (IS_DEBUG_OSPF6_GR_HELPER) - zlog_debug("%s, GR helper deinit.", __PRETTY_FUNCTION__); + zlog_debug("%s, GR helper deinit.", __func__); ospf6_enable_rtr_hash_destroy(ospf6); } diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 549f5668b9..a80ec4430f 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 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_HELPER) + 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_HELPER) + 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_HELPER) + 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..331b75f803 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; - listnode_delete(on->ospf6_if->neighbor_list, on); - ospf6_neighbor_delete(on); + 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); + + } else { + if (IS_DEBUG_OSPF6_GR_HELPER) + 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_top.c b/ospf6d/ospf6_top.c index e445e8703c..37361de689 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -51,7 +51,7 @@ #include "ospf6_intra.h" #include "ospf6_spf.h" #include "ospf6d.h" -#include "ospf6_gr_helper.h" +#include "ospf6_gr.h" #include "lib/json.h" #include "ospf6_nssa.h" diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am index 608d3d1a29..ac99e90b26 100644 --- a/ospf6d/subdir.am +++ b/ospf6d/subdir.am @@ -63,7 +63,7 @@ noinst_HEADERS += \ ospf6d/ospf6_asbr.h \ ospf6d/ospf6_bfd.h \ ospf6d/ospf6_flood.h \ - ospf6d/ospf6_gr_helper.h \ + ospf6d/ospf6_gr.h \ ospf6d/ospf6_interface.h \ ospf6d/ospf6_intra.h \ ospf6d/ospf6_lsa.h \ From 9a06f23d0bd7b0e712ce747c31b22842a8baf15f Mon Sep 17 00:00:00 2001 From: rgirada Date: Thu, 1 Jul 2021 04:55:44 -0700 Subject: [PATCH 6/7] ospf6d: GR helper exit scenarios 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 --- ospf6d/ospf6_flood.c | 56 +++++++++--- ospf6d/ospf6_gr.h | 7 ++ ospf6d/ospf6_gr_helper.c | 181 ++++++++++++++++++++++++++++++++++++++- ospf6d/ospf6_interface.c | 32 ++++++- ospf6d/ospf6_interface.h | 2 + 5 files changed, 265 insertions(+), 13 deletions(-) diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index 77c2ad1628..458b81f2ea 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -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; + } } } diff --git a/ospf6d/ospf6_gr.h b/ospf6d/ospf6_gr.h index 6336363688..49fc86a4e2 100644 --- a/ospf6d/ospf6_gr.h +++ b/ospf6d/ospf6_gr.h @@ -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 */ diff --git a/ospf6d/ospf6_gr_helper.c b/ospf6d/ospf6_gr_helper.c index d035171154..60c62a9341 100644 --- a/ospf6d/ospf6_gr_helper.c +++ b/ospf6d/ospf6_gr_helper.c @@ -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, 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), From 0fc3e113231829c3412f5009be2b4c790b444bd3 Mon Sep 17 00:00:00 2001 From: rgirada Date: Thu, 1 Jul 2021 07:09:38 -0700 Subject: [PATCH 7/7] ospf6d: GR helper configurations Description: Adding the following cli commands to enable/disable GR helper functionality. 1. [no] graceful-restart helper-only [A.B.C.D] 2. [no] graceful-restart helper lsa-check-disable 3. [no] graceful-restart helper planned-only 4. [no] graceful-restart helper supported-grace-time (10-1800) show commands: show ipv6 ospf6 graceful-restart helper [detail] [json] Signed-off-by: Rajesh Girada --- ospf6d/ospf6_flood.c | 8 +- ospf6d/ospf6_gr.h | 17 +- ospf6d/ospf6_gr_helper.c | 848 ++++++++++++++++++++++++++++++++++++--- ospf6d/ospf6_message.c | 6 +- ospf6d/ospf6_neighbor.c | 2 +- ospf6d/ospf6_top.c | 1 + ospf6d/ospf6d.c | 3 + 7 files changed, 811 insertions(+), 74 deletions(-) diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index 458b81f2ea..87c43c4657 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -1026,7 +1026,7 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from, if (OSPF6_LSA_IS_MAXAGE(new)) { - if (IS_DEBUG_OSPF6_GR_HELPER) + if (IS_DEBUG_OSPF6_GR) zlog_debug( "%s, Received a maxage GraceLSA from router %pI4", __func__, @@ -1035,7 +1035,7 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from, ospf6_process_maxage_grace_lsa( ospf6, new, from); } else { - if (IS_DEBUG_OSPF6_GR_HELPER) + if (IS_DEBUG_OSPF6_GR) zlog_debug( "%s, GraceLSA doesn't exist in lsdb, so discarding GraceLSA", __func__); @@ -1043,7 +1043,7 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from, } } else { - if (IS_DEBUG_OSPF6_GR_HELPER) + if (IS_DEBUG_OSPF6_GR) zlog_debug( "%s, Received a GraceLSA from router %pI4", __func__, @@ -1051,7 +1051,7 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from, if (ospf6_process_grace_lsa(ospf6, new, from) == OSPF6_GR_NOT_HELPER) { - if (IS_DEBUG_OSPF6_GR_HELPER) + if (IS_DEBUG_OSPF6_GR) zlog_debug( "%s, Not moving to HELPER role, So dicarding GraceLSA", __func__); diff --git a/ospf6d/ospf6_gr.h b/ospf6d/ospf6_gr.h index 49fc86a4e2..378b7193cd 100644 --- a/ospf6d/ospf6_gr.h +++ b/ospf6d/ospf6_gr.h @@ -36,15 +36,13 @@ /* Debug option */ extern unsigned char conf_debug_ospf6_gr; -#define OSPF6_DEBUG_GR_HELPER 0x01 +#define OSPF6_DEBUG_GR 0x01 -#define OSPF6_DEBUG_GR_HELPER_ON() \ - (conf_debug_ospf6_gr |= OSPF6_DEBUG_GR_HELPER) +#define OSPF6_DEBUG_GR_ON() (conf_debug_ospf6_gr |= OSPF6_DEBUG_GR) -#define OSPF6_DEBUG_GR_HELPER_OFF() \ - (conf_debug_ospf6_gr &= ~OSPF6_DEBUG_GR_HELPER) +#define OSPF6_DEBUG_GR_OFF() (conf_debug_ospf6_gr &= ~OSPF6_DEBUG_GR) -#define IS_DEBUG_OSPF6_GR_HELPER conf_debug_ospf6_gr +#define IS_DEBUG_OSPF6_GR conf_debug_ospf6_gr enum ospf6_helper_exit_reason { @@ -98,7 +96,7 @@ struct tlv_header { #define TLV_HDR_NEXT(tlvh) \ (struct tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh)) -/* Ref RFC5187 appendex-A */ +/* Ref RFC5187 appendix-A */ /* Grace period TLV */ #define GRACE_PERIOD_TYPE 1 #define GRACE_PERIOD_LENGTH 4 @@ -126,7 +124,7 @@ struct advRtr { }; #define OSPF6_HELPER_ENABLE_RTR_COUNT(ospf) \ - (ospf6->ospf6_helper_cfg.enableRtrList->count) + (ospf6->ospf6_helper_cfg.enable_rtr_list->count) /* Check , it is a planned restart */ #define OSPF6_GR_IS_PLANNED_RESTART(reason) \ @@ -146,6 +144,7 @@ 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, @@ -157,4 +156,6 @@ extern void ospf6_process_maxage_grace_lsa(struct ospf6 *ospf, 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 index 60c62a9341..07e479efcb 100644 --- a/ospf6d/ospf6_gr_helper.c +++ b/ospf6d/ospf6_gr_helper.c @@ -57,9 +57,23 @@ 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 inprogress", "Topology Change", - "Grace timer expiry", "Successful graceful restart", + "Unknown reason", + "Helper in progress", + "Topology Change", + "Grace timer expiry", + "Successful graceful restart", }; const char *ospf6_restart_reason_desc[] = { @@ -165,10 +179,9 @@ static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa, return OSPF6_FAILURE; break; default: - if (IS_DEBUG_OSPF6_GR_HELPER) - zlog_debug( - "%s, Ignoring unknown TLV type:%d", - __func__, ntohs(tlvh->type)); + if (IS_DEBUG_OSPF6_GR) + zlog_debug("%s, Ignoring unknown TLV type:%d", + __func__, ntohs(tlvh->type)); } } @@ -259,17 +272,15 @@ int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, 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__); + if (IS_DEBUG_OSPF6_GR) + zlog_debug("%s, Wrong Grace LSA packet.", __func__); return OSPF6_GR_NOT_HELPER; } - if (IS_DEBUG_OSPF6_GR_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, + __func__, &restarter->router_id, grace_interval, ospf6_restart_reason_desc[restart_reason]); /* Verify Helper enabled globally */ @@ -281,7 +292,7 @@ int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, if (!hash_lookup(ospf6->ospf6_helper_cfg.enable_rtr_list, &lookup)) { - if (IS_DEBUG_OSPF6_GR_HELPER) + if (IS_DEBUG_OSPF6_GR) zlog_debug( "%s, HELPER support is disabled, So not a HELPER", __func__); @@ -295,7 +306,7 @@ int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, * became a adjacency. */ if (!IS_NBR_STATE_FULL(restarter)) { - if (IS_DEBUG_OSPF6_GR_HELPER) + if (IS_DEBUG_OSPF6_GR) zlog_debug( "%s, This Neighbour %pI6 is not in FULL state.", __func__, &restarter->linklocal_addr); @@ -309,7 +320,7 @@ int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, */ if (ospf6->ospf6_helper_cfg.only_planned_restart && !OSPF6_GR_IS_PLANNED_RESTART(restart_reason)) { - if (IS_DEBUG_OSPF6_GR_HELPER) + if (IS_DEBUG_OSPF6_GR) zlog_debug( "%s, Router supports only planned restarts but received the GRACE LSA due a unplanned restart", __func__); @@ -324,7 +335,7 @@ int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, if (ospf6->ospf6_helper_cfg.strict_lsa_check && restarter->retrans_list->count && ospf6_check_chg_in_rxmt_list(restarter)) { - if (IS_DEBUG_OSPF6_GR_HELPER) + if (IS_DEBUG_OSPF6_GR) zlog_debug( "%s, Changed LSA in Rxmt list.So not Helper.", __func__); @@ -333,13 +344,12 @@ int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, return OSPF6_GR_NOT_HELPER; } - /*LSA age must be less than the grace period */ + /* LSA age must be less than the grace period */ if (ntohs(lsa->header->age) >= grace_interval) { - if (IS_DEBUG_OSPF6_GR_HELPER) + 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); + __func__, lsa->header->age, grace_interval); restarter->gr_helper_info.rejected_reason = OSPF6_HELPER_LSA_AGE_MORE; return OSPF6_GR_NOT_HELPER; @@ -352,7 +362,7 @@ int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, */ actual_grace_interval = grace_interval; if (grace_interval > ospf6->ospf6_helper_cfg.supported_grace_time) { - if (IS_DEBUG_OSPF6_GR_HELPER) + if (IS_DEBUG_OSPF6_GR) zlog_debug( "%s, Received grace period %d is larger than supported grace %d", __func__, grace_interval, @@ -368,12 +378,12 @@ int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, if (ospf6->ospf6_helper_cfg.active_restarter_cnt > 0) ospf6->ospf6_helper_cfg.active_restarter_cnt--; - if (IS_DEBUG_OSPF6_GR_HELPER) + 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_HELPER) + if (IS_DEBUG_OSPF6_GR) zlog_debug( "%s, This Router becomes a HELPER for the neighbour %pI6", __func__, &restarter->linklocal_addr); @@ -391,9 +401,9 @@ int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, /* Increment the active restart nbr count */ ospf6->ospf6_helper_cfg.active_restarter_cnt++; - if (IS_DEBUG_OSPF6_GR_HELPER) - zlog_debug("%s, Grace timer started.interval:%u", - __func__, actual_grace_interval); + 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, @@ -434,7 +444,7 @@ void ospf6_gr_helper_exit(struct ospf6_neighbor *nbr, if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr)) return; - if (IS_DEBUG_OSPF6_GR_HELPER) + 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]); @@ -448,7 +458,7 @@ void ospf6_gr_helper_exit(struct ospf6_neighbor *nbr, ospf6->ospf6_helper_cfg.last_exit_reason = reason; /* If the exit not triggered due to grace timer - * expairy , stop the grace timer. + * expiry, stop the grace timer. */ if (reason != OSPF6_GR_HELPER_GRACE_TIMEOUT) THREAD_OFF(nbr->gr_helper_info.t_grace_timer); @@ -458,14 +468,14 @@ void ospf6_gr_helper_exit(struct ospf6_neighbor *nbr, "OSPF6 GR-Helper: Number of active Restarters should be greater than zero."); return; } - /* Decrement active Restarter count */ + /* 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) + if (IS_DEBUG_OSPF6_GR) zlog_debug("%s, Unsuccessful GR exit. RESTARTER : %pI6", __func__, &nbr->linklocal_addr); } @@ -482,8 +492,8 @@ void ospf6_gr_helper_exit(struct ospf6_neighbor *nbr, } /* - * Process Maxage Grace LSA. - * It is a indication for successfull completion of GR. + * 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 @@ -493,7 +503,7 @@ void ospf6_gr_helper_exit(struct ospf6_neighbor *nbr, * Grace LSA received from RESTARTER. * * nbr - * ospf6 neighbour which requets the router to act as + * ospf6 neighbour which request the router to act as * HELPER. * * Returns: @@ -510,13 +520,12 @@ void ospf6_process_maxage_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, 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__); + if (IS_DEBUG_OSPF6_GR) + zlog_debug("%s, Wrong Grace LSA packet.", __func__); return; } - if (IS_DEBUG_OSPF6_GR_HELPER) + if (IS_DEBUG_OSPF6_GR) zlog_debug("%s, GraceLSA received for neighbour %pI4.", __func__, &restarter->router_id); @@ -530,7 +539,7 @@ void ospf6_process_maxage_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, * ospf6 * ospf6 pointer * lsa - * topo change occured due to this lsa(type (1-5 and 7) + * topo change occurred due to this lsa(type (1-5 and 7) * * Returns: * Nothing @@ -545,16 +554,15 @@ void ospf6_helper_handle_topo_chg(struct ospf6 *ospf6, struct ospf6_lsa *lsa) 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. + /* 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_HELPER) - zlog_debug( - "%s, Topo change detected due to lsa details : %s", - __func__, lsa->name); + if (IS_DEBUG_OSPF6_GR) + zlog_debug("%s, Topo change detected due to lsa details : %s", + __func__, lsa->name); lsa->tobe_acknowledged = OSPF6_TRUE; @@ -582,22 +590,704 @@ void ospf6_helper_handle_topo_chg(struct ospf6 *ospf6, struct ospf6_lsa *lsa) } } -/* 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") +/* 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) { - if (!no) - OSPF6_DEBUG_GR_HELPER_ON(); - else - OSPF6_DEBUG_GR_HELPER_OFF(); + 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. * @@ -609,7 +1299,7 @@ DEFPY(debug_ospf6_gr, */ void ospf6_gr_helper_init(struct ospf6 *ospf6) { - if (IS_DEBUG_OSPF6_GR_HELPER) + if (IS_DEBUG_OSPF6_GR) zlog_debug("%s, GR Helper init.", __func__); ospf6->ospf6_helper_cfg.is_helper_supported = OSPF6_FALSE; @@ -625,7 +1315,7 @@ void ospf6_gr_helper_init(struct ospf6 *ospf6) } /* - * De-Initilise GR helper config datastructer. + * De-initialize GR helper config data structure. * * ospf6 * ospf6 pointer @@ -636,8 +1326,50 @@ void ospf6_gr_helper_init(struct ospf6 *ospf6) void ospf6_gr_helper_deinit(struct ospf6 *ospf6) { - if (IS_DEBUG_OSPF6_GR_HELPER) + 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_message.c b/ospf6d/ospf6_message.c index a80ec4430f..cd73e3d406 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -515,7 +515,7 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, if (twoway) thread_execute(master, twoway_received, on, 0); else { - if (IS_DEBUG_OSPF6_GR_HELPER) + if (IS_DEBUG_OSPF6_GR) zlog_debug( "%s, Received oneway hello from RESTARTER so ignore here.", __PRETTY_FUNCTION__); @@ -545,7 +545,7 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, * period, it can handle if there is any change before GR and * after GR. */ - if (IS_DEBUG_OSPF6_GR_HELPER) + if (IS_DEBUG_OSPF6_GR) zlog_debug( "%s, Neighbor is under GR Restart, hence ignoring the ISM Events", __PRETTY_FUNCTION__); @@ -1302,7 +1302,7 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah, 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_HELPER) + if (IS_DEBUG_OSPF6_GR) zlog_debug("%s: Undersized GraceLSA.", __func__); return MSG_NG; diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index 331b75f803..4ea615f32b 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -622,7 +622,7 @@ int inactivity_timer(struct thread *thread) ospf6_neighbor_delete(on); } else { - if (IS_DEBUG_OSPF6_GR_HELPER) + if (IS_DEBUG_OSPF6_GR) zlog_debug( "%s, Acting as HELPER for this neighbour, So restart the dead timer.", __PRETTY_FUNCTION__); diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 37361de689..fc181a6d18 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -2236,6 +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/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);