back to topotato report
topotato coverage report
Current view: top level - ospf6d - ospf6_gr_helper.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 46 510 9.0 %
Date: 2023-02-24 19:38:44 Functions: 8 36 22.2 %

          Line data    Source code
       1             : /*
       2             :  * OSPF6 Graceful Restart helper functions.
       3             :  *
       4             :  * Copyright (C) 2021-22 Vmware, Inc.
       5             :  * Rajesh Kumar Girada
       6             :  *
       7             :  * This file is part of GNU Zebra.
       8             :  *
       9             :  * GNU Zebra is free software; you can redistribute it and/or modify it
      10             :  * under the terms of the GNU General Public License as published by the
      11             :  * Free Software Foundation; either version 2, or (at your option) any
      12             :  * later version.
      13             :  *
      14             :  * GNU Zebra is distributed in the hope that it will be useful, but
      15             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      17             :  * General Public License for more details.
      18             :  *
      19             :  * You should have received a copy of the GNU General Public License along
      20             :  * with this program; see the file COPYING; if not, write to the Free Software
      21             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      22             :  */
      23             : 
      24             : #include <zebra.h>
      25             : 
      26             : #include "log.h"
      27             : #include "vty.h"
      28             : #include "command.h"
      29             : #include "prefix.h"
      30             : #include "stream.h"
      31             : #include "zclient.h"
      32             : #include "memory.h"
      33             : #include "table.h"
      34             : #include "lib/bfd.h"
      35             : #include "lib_errors.h"
      36             : #include "jhash.h"
      37             : 
      38             : #include "ospf6_proto.h"
      39             : #include "ospf6_lsa.h"
      40             : #include "ospf6_lsdb.h"
      41             : #include "ospf6_route.h"
      42             : #include "ospf6_message.h"
      43             : 
      44             : #include "ospf6_top.h"
      45             : #include "ospf6_area.h"
      46             : #include "ospf6_interface.h"
      47             : #include "ospf6_neighbor.h"
      48             : #include "ospf6_intra.h"
      49             : #include "ospf6d.h"
      50             : #include "ospf6_gr.h"
      51             : #include "lib/json.h"
      52             : #include "ospf6d/ospf6_gr_helper_clippy.c"
      53             : 
      54          48 : DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_GR_HELPER, "OSPF6 Graceful restart helper");
      55             : 
      56             : unsigned char conf_debug_ospf6_gr;
      57             : 
      58             : static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa,
      59             :                                      json_object *json, bool use_json);
      60             : 
      61             : struct ospf6_lsa_handler grace_lsa_handler = {.lh_type = OSPF6_LSTYPE_GRACE_LSA,
      62             :                                               .lh_name = "Grace",
      63             :                                               .lh_short_name = "GR",
      64             :                                               .lh_show =
      65             :                                                       ospf6_grace_lsa_show_info,
      66             :                                               .lh_get_prefix_str = NULL,
      67             :                                               .lh_debug = 0};
      68             : 
      69             : const char *ospf6_exit_reason_desc[] = {
      70             :         "Unknown reason",
      71             :         "Helper in progress",
      72             :         "Topology Change",
      73             :         "Grace timer expiry",
      74             :         "Successful graceful restart",
      75             : };
      76             : 
      77             : const char *ospf6_restart_reason_desc[] = {
      78             :         "Unknown restart",
      79             :         "Software restart",
      80             :         "Software reload/upgrade",
      81             :         "Switch to redundant control processor",
      82             : };
      83             : 
      84             : const char *ospf6_rejected_reason_desc[] = {
      85             :         "Unknown reason",
      86             :         "Helper support disabled",
      87             :         "Neighbour is not in FULL state",
      88             :         "Supports only planned restart but received for unplanned",
      89             :         "Topo change due to change in lsa rxmt list",
      90             :         "LSA age is more than Grace interval",
      91             : };
      92             : 
      93           0 : static unsigned int ospf6_enable_rtr_hash_key(const void *data)
      94             : {
      95           0 :         const struct advRtr *rtr = data;
      96             : 
      97           0 :         return jhash_1word(rtr->advRtrAddr, 0);
      98             : }
      99             : 
     100           0 : static bool ospf6_enable_rtr_hash_cmp(const void *d1, const void *d2)
     101             : {
     102           0 :         const struct advRtr *rtr1 = d1;
     103           0 :         const struct advRtr *rtr2 = d2;
     104             : 
     105           0 :         return (rtr1->advRtrAddr == rtr2->advRtrAddr);
     106             : }
     107             : 
     108           0 : static void *ospf6_enable_rtr_hash_alloc(void *p)
     109             : {
     110           0 :         struct advRtr *rid;
     111             : 
     112           0 :         rid = XCALLOC(MTYPE_OSPF6_GR_HELPER, sizeof(struct advRtr));
     113           0 :         rid->advRtrAddr = ((struct advRtr *)p)->advRtrAddr;
     114             : 
     115           0 :         return rid;
     116             : }
     117             : 
     118           0 : static void ospf6_disable_rtr_hash_free(void *rtr)
     119             : {
     120           0 :         XFREE(MTYPE_OSPF6_GR_HELPER, rtr);
     121           0 : }
     122             : 
     123          16 : static void ospf6_enable_rtr_hash_destroy(struct ospf6 *ospf6)
     124             : {
     125          16 :         if (ospf6->ospf6_helper_cfg.enable_rtr_list == NULL)
     126             :                 return;
     127             : 
     128          16 :         hash_clean(ospf6->ospf6_helper_cfg.enable_rtr_list,
     129             :                    ospf6_disable_rtr_hash_free);
     130          16 :         hash_free(ospf6->ospf6_helper_cfg.enable_rtr_list);
     131          16 :         ospf6->ospf6_helper_cfg.enable_rtr_list = NULL;
     132             : }
     133             : 
     134             : /*
     135             :  * Extracting tlv info from GRACE LSA.
     136             :  *
     137             :  * lsa
     138             :  *   ospf6 grace lsa
     139             :  *
     140             :  * Returns:
     141             :  * interval : grace interval.
     142             :  * reason   : Restarting reason.
     143             :  */
     144           0 : static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa,
     145             :                                           uint32_t *interval, uint8_t *reason)
     146             : {
     147           0 :         struct ospf6_lsa_header *lsah = NULL;
     148           0 :         struct tlv_header *tlvh = NULL;
     149           0 :         struct grace_tlv_graceperiod *gracePeriod;
     150           0 :         struct grace_tlv_restart_reason *grReason;
     151           0 :         uint16_t length = 0;
     152           0 :         int sum = 0;
     153             : 
     154           0 :         lsah = (struct ospf6_lsa_header *)lsa->header;
     155           0 :         if (ntohs(lsah->length) <= OSPF6_LSA_HEADER_SIZE) {
     156           0 :                 if (IS_DEBUG_OSPF6_GR)
     157           0 :                         zlog_debug("%s: undersized (%u B) lsa", __func__,
     158             :                                    ntohs(lsah->length));
     159           0 :                 return OSPF6_FAILURE;
     160             :         }
     161             : 
     162           0 :         length = ntohs(lsah->length) - OSPF6_LSA_HEADER_SIZE;
     163             : 
     164           0 :         for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
     165           0 :              tlvh = TLV_HDR_NEXT(tlvh)) {
     166             : 
     167             :                 /* Check TLV len against overall LSA */
     168           0 :                 if (sum + TLV_SIZE(tlvh) > length) {
     169           0 :                         if (IS_DEBUG_OSPF6_GR)
     170           0 :                                 zlog_debug(
     171             :                                         "%s: Malformed packet: Invalid TLV len:%d",
     172             :                                         __func__, TLV_SIZE(tlvh));
     173           0 :                         return OSPF6_FAILURE;
     174             :                 }
     175             : 
     176           0 :                 switch (ntohs(tlvh->type)) {
     177           0 :                 case GRACE_PERIOD_TYPE:
     178           0 :                         gracePeriod = (struct grace_tlv_graceperiod *)tlvh;
     179           0 :                         *interval = ntohl(gracePeriod->interval);
     180           0 :                         sum += TLV_SIZE(tlvh);
     181             : 
     182             :                         /* Check if grace interval is valid */
     183           0 :                         if (*interval > OSPF6_MAX_GRACE_INTERVAL
     184           0 :                             || *interval < OSPF6_MIN_GRACE_INTERVAL)
     185             :                                 return OSPF6_FAILURE;
     186             :                         break;
     187           0 :                 case RESTART_REASON_TYPE:
     188           0 :                         grReason = (struct grace_tlv_restart_reason *)tlvh;
     189           0 :                         *reason = grReason->reason;
     190           0 :                         sum += TLV_SIZE(tlvh);
     191             : 
     192           0 :                         if (*reason >= OSPF6_GR_INVALID_REASON_CODE)
     193             :                                 return OSPF6_FAILURE;
     194             :                         break;
     195           0 :                 default:
     196           0 :                         if (IS_DEBUG_OSPF6_GR)
     197           0 :                                 zlog_debug("%s, Ignoring unknown TLV type:%d",
     198             :                                            __func__, ntohs(tlvh->type));
     199             :                 }
     200             :         }
     201             : 
     202             :         return OSPF6_SUCCESS;
     203             : }
     204             : 
     205             : /*
     206             :  * Grace timer expiry handler.
     207             :  * HELPER aborts its role at grace timer expiry.
     208             :  *
     209             :  * thread
     210             :  *    thread pointer
     211             :  *
     212             :  * Returns:
     213             :  *    Nothing
     214             :  */
     215           0 : static void ospf6_handle_grace_timer_expiry(struct thread *thread)
     216             : {
     217           0 :         struct ospf6_neighbor *nbr = THREAD_ARG(thread);
     218             : 
     219           0 :         ospf6_gr_helper_exit(nbr, OSPF6_GR_HELPER_GRACE_TIMEOUT);
     220           0 : }
     221             : 
     222             : /*
     223             :  * API to check any change in the neighbor's
     224             :  * retransmission list.
     225             :  *
     226             :  * nbr
     227             :  *    ospf6 neighbor
     228             :  *
     229             :  * Returns:
     230             :  *    TRUE  - if any change in the lsa.
     231             :  *    FALSE - no change in the lsas.
     232             :  */
     233           0 : static bool ospf6_check_chg_in_rxmt_list(struct ospf6_neighbor *nbr)
     234             : {
     235           0 :         struct ospf6_lsa *lsa, *lsanext;
     236             : 
     237           0 :         for (ALL_LSDB(nbr->retrans_list, lsa, lsanext)) {
     238           0 :                 struct ospf6_lsa *lsa_in_db = NULL;
     239             : 
     240             :                 /* Fetching the same copy of LSA form LSDB to validate the
     241             :                  * topochange.
     242             :                  */
     243           0 :                 lsa_in_db =
     244           0 :                         ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
     245           0 :                                           lsa->header->adv_router, lsa->lsdb);
     246             : 
     247           0 :                 if (lsa_in_db && lsa_in_db->tobe_acknowledged) {
     248           0 :                         ospf6_lsa_unlock(lsa);
     249           0 :                         if (lsanext)
     250           0 :                                 ospf6_lsa_unlock(lsanext);
     251             : 
     252           0 :                         return OSPF6_TRUE;
     253             :                 }
     254             :         }
     255             : 
     256             :         return OSPF6_FALSE;
     257             : }
     258             : 
     259             : /*
     260             :  * Process Grace LSA.If it is eligible move to HELPER role.
     261             :  * Ref rfc3623 section 3.1 and rfc5187
     262             :  *
     263             :  * ospf
     264             :  *    Ospf6 pointer.
     265             :  *
     266             :  * lsa
     267             :  *    Grace LSA received from RESTARTER.
     268             :  *
     269             :  * restarter
     270             :  *    ospf6 neighbour which requests the router to act as
     271             :  *    HELPER.
     272             :  *
     273             :  * Returns:
     274             :  *    status.
     275             :  *    If supported as HELPER : OSPF_GR_HELPER_INPROGRESS
     276             :  *    If Not supported as HELPER : OSPF_GR_HELPER_NONE
     277             :  */
     278           0 : int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa,
     279             :                             struct ospf6_neighbor *restarter)
     280             : {
     281           0 :         uint8_t restart_reason = 0;
     282           0 :         uint32_t grace_interval = 0;
     283           0 :         uint32_t actual_grace_interval = 0;
     284           0 :         struct advRtr lookup;
     285           0 :         int ret;
     286             : 
     287             :         /* Extract the grace lsa packet fields */
     288           0 :         ret = ospf6_extract_grace_lsa_fields(lsa, &grace_interval,
     289             :                                              &restart_reason);
     290           0 :         if (ret != OSPF6_SUCCESS) {
     291           0 :                 if (IS_DEBUG_OSPF6_GR)
     292           0 :                         zlog_debug("%s, Wrong Grace LSA packet.", __func__);
     293           0 :                 return OSPF6_GR_NOT_HELPER;
     294             :         }
     295             : 
     296           0 :         if (IS_DEBUG_OSPF6_GR)
     297           0 :                 zlog_debug(
     298             :                         "%s, Grace LSA received from  %pI4, grace interval:%u, restart reason :%s",
     299             :                         __func__, &restarter->router_id, grace_interval,
     300             :                         ospf6_restart_reason_desc[restart_reason]);
     301             : 
     302             :         /* Verify Helper enabled globally */
     303           0 :         if (!ospf6->ospf6_helper_cfg.is_helper_supported) {
     304             :                 /* Verify Helper support is enabled for the
     305             :                  * current neighbour router-id.
     306             :                  */
     307           0 :                 lookup.advRtrAddr = restarter->router_id;
     308             : 
     309           0 :                 if (!hash_lookup(ospf6->ospf6_helper_cfg.enable_rtr_list,
     310             :                                  &lookup)) {
     311           0 :                         if (IS_DEBUG_OSPF6_GR)
     312           0 :                                 zlog_debug(
     313             :                                         "%s, HELPER support is disabled, So not a HELPER",
     314             :                                         __func__);
     315           0 :                         restarter->gr_helper_info.rejected_reason =
     316             :                                 OSPF6_HELPER_SUPPORT_DISABLED;
     317           0 :                         return OSPF6_GR_NOT_HELPER;
     318             :                 }
     319             :         }
     320             : 
     321             :         /* Check neighbour is in FULL state and
     322             :          * became a adjacency.
     323             :          */
     324           0 :         if (!IS_NBR_STATE_FULL(restarter)) {
     325           0 :                 if (IS_DEBUG_OSPF6_GR)
     326           0 :                         zlog_debug(
     327             :                                 "%s, This Neighbour %pI6 is not in FULL state.",
     328             :                                 __func__, &restarter->linklocal_addr);
     329           0 :                 restarter->gr_helper_info.rejected_reason =
     330             :                         OSPF6_HELPER_NOT_A_VALID_NEIGHBOUR;
     331           0 :                 return OSPF6_GR_NOT_HELPER;
     332             :         }
     333             : 
     334             :         /* Based on the restart reason from grace lsa
     335             :          * check the current router is supporting or not
     336             :          */
     337           0 :         if (ospf6->ospf6_helper_cfg.only_planned_restart
     338           0 :             && !OSPF6_GR_IS_PLANNED_RESTART(restart_reason)) {
     339           0 :                 if (IS_DEBUG_OSPF6_GR)
     340           0 :                         zlog_debug(
     341             :                                 "%s, Router supports only planned restarts but received the GRACE LSA due to an unplanned restart",
     342             :                                 __func__);
     343           0 :                 restarter->gr_helper_info.rejected_reason =
     344             :                         OSPF6_HELPER_PLANNED_ONLY_RESTART;
     345           0 :                 return OSPF6_GR_NOT_HELPER;
     346             :         }
     347             : 
     348             :         /* Check the retransmission list of this
     349             :          * neighbour, check any change in lsas.
     350             :          */
     351           0 :         if (ospf6->ospf6_helper_cfg.strict_lsa_check
     352           0 :             && restarter->retrans_list->count
     353           0 :             && ospf6_check_chg_in_rxmt_list(restarter)) {
     354           0 :                 if (IS_DEBUG_OSPF6_GR)
     355           0 :                         zlog_debug(
     356             :                                 "%s, Changed LSA in Rxmt list.So not Helper.",
     357             :                                 __func__);
     358           0 :                 restarter->gr_helper_info.rejected_reason =
     359             :                         OSPF6_HELPER_TOPO_CHANGE_RTXMT_LIST;
     360           0 :                 return OSPF6_GR_NOT_HELPER;
     361             :         }
     362             : 
     363             :         /* LSA age must be less than the grace period */
     364           0 :         if (ntohs(lsa->header->age) >= grace_interval) {
     365           0 :                 if (IS_DEBUG_OSPF6_GR)
     366           0 :                         zlog_debug(
     367             :                                 "%s, Grace LSA age(%d) is more than the grace interval(%d)",
     368             :                                 __func__, lsa->header->age, grace_interval);
     369           0 :                 restarter->gr_helper_info.rejected_reason =
     370             :                         OSPF6_HELPER_LSA_AGE_MORE;
     371           0 :                 return OSPF6_GR_NOT_HELPER;
     372             :         }
     373             : 
     374           0 :         if (ospf6->gr_info.restart_in_progress) {
     375           0 :                 if (IS_DEBUG_OSPF6_GR)
     376           0 :                         zlog_debug(
     377             :                                 "%s: router is in the process of graceful restart",
     378             :                                 __func__);
     379           0 :                 restarter->gr_helper_info.rejected_reason =
     380             :                         OSPF6_HELPER_RESTARTING;
     381           0 :                 return OSPF6_GR_NOT_HELPER;
     382             :         }
     383             : 
     384             :         /* check supported grace period configured
     385             :          * if configured, use this to start the grace
     386             :          * timer otherwise use the interval received
     387             :          * in grace LSA packet.
     388             :          */
     389           0 :         actual_grace_interval = grace_interval;
     390           0 :         if (grace_interval > ospf6->ospf6_helper_cfg.supported_grace_time) {
     391           0 :                 if (IS_DEBUG_OSPF6_GR)
     392           0 :                         zlog_debug(
     393             :                                 "%s, Received grace period %d is larger than supported grace %d",
     394             :                                 __func__, grace_interval,
     395             :                                 ospf6->ospf6_helper_cfg.supported_grace_time);
     396           0 :                 actual_grace_interval =
     397             :                         ospf6->ospf6_helper_cfg.supported_grace_time;
     398             :         }
     399             : 
     400           0 :         if (OSPF6_GR_IS_ACTIVE_HELPER(restarter)) {
     401           0 :                 THREAD_OFF(restarter->gr_helper_info.t_grace_timer);
     402             : 
     403           0 :                 if (ospf6->ospf6_helper_cfg.active_restarter_cnt > 0)
     404           0 :                         ospf6->ospf6_helper_cfg.active_restarter_cnt--;
     405             : 
     406           0 :                 if (IS_DEBUG_OSPF6_GR)
     407           0 :                         zlog_debug(
     408             :                                 "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
     409             :                                 __func__);
     410             :         } else {
     411           0 :                 if (IS_DEBUG_OSPF6_GR)
     412           0 :                         zlog_debug(
     413             :                                 "%s, This Router becomes a HELPER for the neighbour %pI6",
     414             :                                 __func__, &restarter->linklocal_addr);
     415             :         }
     416             : 
     417             :         /* Became a Helper to the RESTART neighbour.
     418             :          * change the helper status.
     419             :          */
     420           0 :         restarter->gr_helper_info.gr_helper_status = OSPF6_GR_ACTIVE_HELPER;
     421           0 :         restarter->gr_helper_info.recvd_grace_period = grace_interval;
     422           0 :         restarter->gr_helper_info.actual_grace_period = actual_grace_interval;
     423           0 :         restarter->gr_helper_info.gr_restart_reason = restart_reason;
     424           0 :         restarter->gr_helper_info.rejected_reason = OSPF6_HELPER_REJECTED_NONE;
     425             : 
     426             :         /* Increment the active restart nbr count */
     427           0 :         ospf6->ospf6_helper_cfg.active_restarter_cnt++;
     428             : 
     429           0 :         if (IS_DEBUG_OSPF6_GR)
     430           0 :                 zlog_debug("%s, Grace timer started.interval:%u", __func__,
     431             :                            actual_grace_interval);
     432             : 
     433             :         /* Start the grace timer */
     434           0 :         thread_add_timer(master, ospf6_handle_grace_timer_expiry, restarter,
     435             :                          actual_grace_interval,
     436             :                          &restarter->gr_helper_info.t_grace_timer);
     437             : 
     438           0 :         return OSPF6_GR_ACTIVE_HELPER;
     439             : }
     440             : 
     441             : /*
     442             :  * Api to exit from HELPER role to take all actions
     443             :  * required at exit.
     444             :  * Ref rfc3623 section 3. and rfc51872
     445             :  *
     446             :  * ospf6
     447             :  *    Ospf6 pointer.
     448             :  *
     449             :  * nbr
     450             :  *    Ospf6 neighbour for which it is acting as HELPER.
     451             :  *
     452             :  * reason
     453             :  *    The reason for exiting from HELPER.
     454             :  *
     455             :  * Returns:
     456             :  *    Nothing.
     457             :  */
     458          32 : void ospf6_gr_helper_exit(struct ospf6_neighbor *nbr,
     459             :                           enum ospf6_helper_exit_reason reason)
     460             : {
     461          32 :         struct ospf6_interface *oi = nbr->ospf6_if;
     462          32 :         struct ospf6 *ospf6;
     463             : 
     464          32 :         if (!oi)
     465             :                 return;
     466             : 
     467          32 :         ospf6 = oi->area->ospf6;
     468             : 
     469          32 :         if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr))
     470             :                 return;
     471             : 
     472           0 :         if (IS_DEBUG_OSPF6_GR)
     473           0 :                 zlog_debug("%s, Exiting from HELPER support to %pI6, due to %s",
     474             :                            __func__, &nbr->linklocal_addr,
     475             :                            ospf6_exit_reason_desc[reason]);
     476             : 
     477             :         /* Reset helper status*/
     478           0 :         nbr->gr_helper_info.gr_helper_status = OSPF6_GR_NOT_HELPER;
     479           0 :         nbr->gr_helper_info.helper_exit_reason = reason;
     480           0 :         nbr->gr_helper_info.actual_grace_period = 0;
     481           0 :         nbr->gr_helper_info.recvd_grace_period = 0;
     482           0 :         nbr->gr_helper_info.gr_restart_reason = 0;
     483           0 :         ospf6->ospf6_helper_cfg.last_exit_reason = reason;
     484             : 
     485             :         /* If the exit not triggered due to grace timer
     486             :          * expiry, stop the grace timer.
     487             :          */
     488           0 :         if (reason != OSPF6_GR_HELPER_GRACE_TIMEOUT)
     489           0 :                 THREAD_OFF(nbr->gr_helper_info.t_grace_timer);
     490             : 
     491           0 :         if (ospf6->ospf6_helper_cfg.active_restarter_cnt <= 0) {
     492           0 :                 zlog_err(
     493             :                         "OSPF6 GR-Helper: Number of active Restarters should be greater than zero.");
     494           0 :                 return;
     495             :         }
     496             :         /* Decrement active restarter count */
     497           0 :         ospf6->ospf6_helper_cfg.active_restarter_cnt--;
     498             : 
     499             :         /* check exit triggered due to successful completion
     500             :          * of graceful restart.
     501             :          */
     502           0 :         if (reason != OSPF6_GR_HELPER_COMPLETED) {
     503           0 :                 if (IS_DEBUG_OSPF6_GR)
     504           0 :                         zlog_debug("%s, Unsuccessful GR exit. RESTARTER : %pI6",
     505             :                                    __func__, &nbr->linklocal_addr);
     506             :         }
     507             : 
     508             :         /*Recalculate the DR for the network segment */
     509           0 :         dr_election(oi);
     510             : 
     511             :         /* Originate a router LSA */
     512           0 :         OSPF6_ROUTER_LSA_SCHEDULE(nbr->ospf6_if->area);
     513             : 
     514             :         /* Originate network lsa if it is an DR in the LAN */
     515           0 :         if (nbr->ospf6_if->state == OSPF6_INTERFACE_DR)
     516           0 :                 OSPF6_NETWORK_LSA_SCHEDULE(nbr->ospf6_if);
     517             : }
     518             : 
     519             : /*
     520             :  * Process max age Grace LSA.
     521             :  * It is a indication for successful completion of GR.
     522             :  * If router acting as HELPER, It exits from helper role.
     523             :  *
     524             :  * ospf6
     525             :  *    Ospf6 pointer.
     526             :  *
     527             :  * lsa
     528             :  *    Grace LSA received from RESTARTER.
     529             :  *
     530             :  * nbr
     531             :  *    ospf6 neighbour which request the router to act as
     532             :  *    HELPER.
     533             :  *
     534             :  * Returns:
     535             :  *    Nothing.
     536             :  */
     537           0 : void ospf6_process_maxage_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa,
     538             :                                     struct ospf6_neighbor *restarter)
     539             : {
     540           0 :         uint8_t restart_reason = 0;
     541           0 :         uint32_t grace_interval = 0;
     542           0 :         int ret;
     543             : 
     544             :         /* Extract the grace lsa packet fields */
     545           0 :         ret = ospf6_extract_grace_lsa_fields(lsa, &grace_interval,
     546             :                                              &restart_reason);
     547           0 :         if (ret != OSPF6_SUCCESS) {
     548           0 :                 if (IS_DEBUG_OSPF6_GR)
     549           0 :                         zlog_debug("%s, Wrong Grace LSA packet.", __func__);
     550           0 :                 return;
     551             :         }
     552             : 
     553           0 :         if (IS_DEBUG_OSPF6_GR)
     554           0 :                 zlog_debug("%s, GraceLSA received for neighbour %pI4.",
     555             :                            __func__, &restarter->router_id);
     556             : 
     557           0 :         ospf6_gr_helper_exit(restarter, OSPF6_GR_HELPER_COMPLETED);
     558             : }
     559             : 
     560             : /*
     561             :  * Actions to be taken  when topo change detected
     562             :  * HELPER will be exited upon a topo change.
     563             :  *
     564             :  * ospf6
     565             :  *    ospf6 pointer
     566             :  * lsa
     567             :  *    topo change occurred due to this lsa(type (1-5  and 7)
     568             :  *
     569             :  * Returns:
     570             :  *    Nothing
     571             :  */
     572         391 : void ospf6_helper_handle_topo_chg(struct ospf6 *ospf6, struct ospf6_lsa *lsa)
     573             : {
     574         391 :         struct listnode *i, *j, *k;
     575         391 :         struct ospf6_neighbor *nbr = NULL;
     576         391 :         struct ospf6_area *oa = NULL;
     577         391 :         struct ospf6_interface *oi = NULL;
     578             : 
     579         391 :         if (!ospf6->ospf6_helper_cfg.active_restarter_cnt)
     580             :                 return;
     581             : 
     582             :         /* Topo change not required to be handled if strict
     583             :          * LSA check is disabled for this router.
     584             :          */
     585           0 :         if (!ospf6->ospf6_helper_cfg.strict_lsa_check)
     586             :                 return;
     587             : 
     588           0 :         if (IS_DEBUG_OSPF6_GR)
     589           0 :                 zlog_debug("%s, Topo change detected due to lsa details : %s",
     590             :                            __func__, lsa->name);
     591             : 
     592           0 :         lsa->tobe_acknowledged = OSPF6_TRUE;
     593             : 
     594           0 :         for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
     595           0 :                 for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) {
     596             : 
     597             :                         /* Ref rfc3623 section 3.2.3.b and rfc5187
     598             :                          * If change due to external LSA and if the area is
     599             :                          * stub, then it is not a topo change. Since Type-5
     600             :                          * lsas will not be flooded in stub area.
     601             :                          */
     602           0 :                         if (IS_AREA_STUB(oi->area)
     603           0 :                             && ((lsa->header->type == OSPF6_LSTYPE_AS_EXTERNAL)
     604           0 :                                 || (lsa->header->type == OSPF6_LSTYPE_TYPE_7)
     605           0 :                                 || (lsa->header->type
     606             :                                     == OSPF6_LSTYPE_INTER_ROUTER))) {
     607           0 :                                 continue;
     608             :                         }
     609             : 
     610           0 :                         for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, nbr)) {
     611             : 
     612           0 :                                 ospf6_gr_helper_exit(nbr,
     613             :                                                      OSPF6_GR_HELPER_TOPO_CHG);
     614             :                         }
     615             :                 }
     616             : }
     617             : 
     618             : /* Configuration handlers */
     619             : /*
     620             :  * Disable/Enable HELPER support on router level.
     621             :  *
     622             :  * ospf6
     623             :  *    Ospf6 pointer.
     624             :  *
     625             :  * status
     626             :  *    TRUE/FALSE
     627             :  *
     628             :  * Returns:
     629             :  *    Nothing.
     630             :  */
     631           0 : static void ospf6_gr_helper_support_set(struct ospf6 *ospf6, bool support)
     632             : {
     633           0 :         struct ospf6_interface *oi;
     634           0 :         struct advRtr lookup;
     635           0 :         struct listnode *i, *j, *k;
     636           0 :         struct ospf6_neighbor *nbr = NULL;
     637           0 :         struct ospf6_area *oa = NULL;
     638             : 
     639           0 :         if (ospf6->ospf6_helper_cfg.is_helper_supported == support)
     640           0 :                 return;
     641             : 
     642           0 :         ospf6->ospf6_helper_cfg.is_helper_supported = support;
     643             : 
     644             :         /* If helper support disabled, cease HELPER role for all
     645             :          * supporting neighbors.
     646             :          */
     647           0 :         if (support == OSPF6_FALSE) {
     648           0 :                 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
     649           0 :                         for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) {
     650             : 
     651           0 :                                 for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k,
     652             :                                                           nbr)) {
     653             : 
     654           0 :                                         lookup.advRtrAddr = nbr->router_id;
     655             :                                         /* check if helper support enabled for
     656             :                                          * the corresponding  routerid.
     657             :                                          * If enabled,
     658             :                                          * dont exit from helper role.
     659             :                                          */
     660           0 :                                         if (hash_lookup(
     661             :                                                     ospf6->ospf6_helper_cfg
     662             :                                                             .enable_rtr_list,
     663             :                                                     &lookup))
     664           0 :                                                 continue;
     665             : 
     666           0 :                                         ospf6_gr_helper_exit(
     667             :                                                 nbr, OSPF6_GR_HELPER_TOPO_CHG);
     668             :                                 }
     669             :                         }
     670             :         }
     671             : }
     672             : 
     673             : /*
     674             :  * Api to enable/disable strict lsa check on the HELPER.
     675             :  *
     676             :  * ospf6
     677             :  *    Ospf6 pointer.
     678             :  *
     679             :  * enabled
     680             :  *    True - disable the lsa check.
     681             :  *    False - enable the strict lsa check.
     682             :  *
     683             :  * Returns:
     684             :  *    Nothing.
     685             :  */
     686           0 : static void ospf6_gr_helper_lsacheck_set(struct ospf6 *ospf6, bool enabled)
     687             : {
     688           0 :         if (ospf6->ospf6_helper_cfg.strict_lsa_check == enabled)
     689             :                 return;
     690             : 
     691           0 :         ospf6->ospf6_helper_cfg.strict_lsa_check = enabled;
     692             : }
     693             : 
     694             : /*
     695             :  * Api to set the supported restart reason.
     696             :  *
     697             :  * ospf6
     698             :  *    Ospf6 pointer.
     699             :  *
     700             :  * only_planned
     701             :  *    True: support only planned restart.
     702             :  *    False: support for planned/unplanned restarts.
     703             :  *
     704             :  * Returns:
     705             :  *    Nothing.
     706             :  */
     707             : 
     708             : static void
     709           0 : ospf6_gr_helper_set_supported_onlyPlanned_restart(struct ospf6 *ospf6,
     710             :                                                   bool only_planned)
     711             : {
     712           0 :         ospf6->ospf6_helper_cfg.only_planned_restart = only_planned;
     713             : }
     714             : 
     715             : /*
     716             :  * Api to set the supported grace interval in this router.
     717             :  *
     718             :  * ospf6
     719             :  *    Ospf6 pointer.
     720             :  *
     721             :  * interval
     722             :  *    The supported grace interval..
     723             :  *
     724             :  * Returns:
     725             :  *    Nothing.
     726             :  */
     727           0 : static void ospf6_gr_helper_supported_gracetime_set(struct ospf6 *ospf6,
     728             :                                                     uint32_t interval)
     729             : {
     730           0 :         ospf6->ospf6_helper_cfg.supported_grace_time = interval;
     731             : }
     732             : 
     733             : /* API to walk and print  all the Helper supported router ids */
     734           0 : static int ospf6_print_vty_helper_dis_rtr_walkcb(struct hash_bucket *bucket,
     735             :                                                  void *arg)
     736             : {
     737           0 :         struct advRtr *rtr = bucket->data;
     738           0 :         struct vty *vty = (struct vty *)arg;
     739           0 :         static unsigned int count;
     740             : 
     741           0 :         vty_out(vty, "%-6pI4,", &rtr->advRtrAddr);
     742           0 :         count++;
     743             : 
     744           0 :         if (count % 5 == 0)
     745           0 :                 vty_out(vty, "\n");
     746             : 
     747           0 :         return HASHWALK_CONTINUE;
     748             : }
     749             : 
     750             : /* API to walk and print  all the Helper supported router ids.*/
     751           0 : static int ospf6_print_json_helper_dis_rtr_walkcb(struct hash_bucket *bucket,
     752             :                                                   void *arg)
     753             : {
     754           0 :         struct advRtr *rtr = bucket->data;
     755           0 :         struct json_object *json_rid_array = (struct json_object *)arg;
     756           0 :         struct json_object *json_rid;
     757           0 :         char router_id[16];
     758             : 
     759           0 :         inet_ntop(AF_INET, &rtr->advRtrAddr, router_id, sizeof(router_id));
     760             : 
     761           0 :         json_rid = json_object_new_object();
     762             : 
     763           0 :         json_object_string_add(json_rid, "routerId", router_id);
     764           0 :         json_object_array_add(json_rid_array, json_rid);
     765             : 
     766           0 :         return HASHWALK_CONTINUE;
     767             : }
     768             : 
     769             : /*
     770             :  * Enable/Disable HELPER support on a specified advertisement
     771             :  * router.
     772             :  *
     773             :  * ospf6
     774             :  *    Ospf6 pointer.
     775             :  *
     776             :  * advRtr
     777             :  *    HELPER support for given Advertisement Router.
     778             :  *
     779             :  * support
     780             :  *    True - Enable Helper Support.
     781             :  *    False - Disable Helper Support.
     782             :  *
     783             :  * Returns:
     784             :  *    Nothing.
     785             :  */
     786           0 : static void ospf6_gr_helper_support_set_per_routerid(struct ospf6 *ospf6,
     787             :                                                      struct in_addr router_id,
     788             :                                                      bool support)
     789             : {
     790           0 :         struct advRtr temp;
     791           0 :         struct advRtr *rtr;
     792           0 :         struct listnode *i, *j, *k;
     793           0 :         struct ospf6_interface *oi;
     794           0 :         struct ospf6_neighbor *nbr;
     795           0 :         struct ospf6_area *oa;
     796             : 
     797           0 :         temp.advRtrAddr = router_id.s_addr;
     798             : 
     799           0 :         if (support == OSPF6_FALSE) {
     800             :                 /*Delete the routerid from the enable router hash table */
     801           0 :                 rtr = hash_lookup(ospf6->ospf6_helper_cfg.enable_rtr_list,
     802             :                                   &temp);
     803             : 
     804           0 :                 if (rtr) {
     805           0 :                         hash_release(ospf6->ospf6_helper_cfg.enable_rtr_list,
     806             :                                      rtr);
     807           0 :                         ospf6_disable_rtr_hash_free(rtr);
     808             :                 }
     809             : 
     810             :                 /* If helper support is enabled globally
     811             :                  * no action is required.
     812             :                  */
     813           0 :                 if (ospf6->ospf6_helper_cfg.is_helper_supported)
     814           0 :                         return;
     815             : 
     816             :                 /* Cease the HELPER role fore neighbours from the
     817             :                  * specified advertisement router.
     818             :                  */
     819           0 :                 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
     820           0 :                         for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) {
     821             : 
     822           0 :                                 for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k,
     823             :                                                           nbr)) {
     824             : 
     825           0 :                                         if (nbr->router_id != router_id.s_addr)
     826           0 :                                                 continue;
     827             : 
     828           0 :                                         if (OSPF6_GR_IS_ACTIVE_HELPER(nbr))
     829           0 :                                                 ospf6_gr_helper_exit(
     830             :                                                 nbr,
     831             :                                                 OSPF6_GR_HELPER_TOPO_CHG);
     832             :                                 }
     833             :                         }
     834             : 
     835             :         } else {
     836             :                 /* Add the routerid to the enable router hash table */
     837           0 :                 (void)hash_get(ospf6->ospf6_helper_cfg.enable_rtr_list, &temp,
     838             :                                ospf6_enable_rtr_hash_alloc);
     839             :         }
     840             : }
     841             : 
     842           0 : static void show_ospfv6_gr_helper_per_nbr(struct vty *vty, json_object *json,
     843             :                                           bool uj, struct ospf6_neighbor *nbr)
     844             : {
     845           0 :         if (!uj) {
     846           0 :                 vty_out(vty, "   Routerid : %pI4\n", &nbr->router_id);
     847           0 :                 vty_out(vty, "   Received Grace period : %d(in seconds).\n",
     848             :                         nbr->gr_helper_info.recvd_grace_period);
     849           0 :                 vty_out(vty, "   Actual Grace period : %d(in seconds)\n",
     850             :                         nbr->gr_helper_info.actual_grace_period);
     851           0 :                 vty_out(vty, "   Remaining GraceTime:%ld(in seconds).\n",
     852             :                         thread_timer_remain_second(
     853             :                                 nbr->gr_helper_info.t_grace_timer));
     854           0 :                 vty_out(vty, "   Graceful Restart reason: %s.\n\n",
     855             :                         ospf6_restart_reason_desc[nbr->gr_helper_info
     856           0 :                                                           .gr_restart_reason]);
     857             :         } else {
     858           0 :                 char nbrid[16];
     859           0 :                 json_object *json_neigh = NULL;
     860             : 
     861           0 :                 inet_ntop(AF_INET, &nbr->router_id, nbrid, sizeof(nbrid));
     862           0 :                 json_neigh = json_object_new_object();
     863           0 :                 json_object_string_add(json_neigh, "routerid", nbrid);
     864           0 :                 json_object_int_add(json_neigh, "recvdGraceInterval",
     865           0 :                                     nbr->gr_helper_info.recvd_grace_period);
     866           0 :                 json_object_int_add(json_neigh, "actualGraceInterval",
     867           0 :                         nbr->gr_helper_info.actual_grace_period);
     868           0 :                 json_object_int_add(json_neigh, "remainGracetime",
     869           0 :                         thread_timer_remain_second(
     870             :                                 nbr->gr_helper_info.t_grace_timer));
     871           0 :                 json_object_string_add(json_neigh, "restartReason",
     872             :                         ospf6_restart_reason_desc[
     873           0 :                                 nbr->gr_helper_info.gr_restart_reason]);
     874           0 :                 json_object_object_add(json, nbr->name, json_neigh);
     875             :         }
     876           0 : }
     877             : 
     878           0 : static void show_ospf6_gr_helper_details(struct vty *vty, struct ospf6 *ospf6,
     879             :                                         json_object *json, bool uj, bool detail)
     880             : {
     881           0 :         struct ospf6_interface *oi;
     882             : 
     883             :         /* Show Router ID. */
     884           0 :         if (uj) {
     885           0 :                 char router_id[16];
     886             : 
     887           0 :                 inet_ntop(AF_INET, &ospf6->router_id, router_id,
     888             :                           sizeof(router_id));
     889           0 :                 json_object_string_add(json, "routerId", router_id);
     890             :         } else
     891           0 :                 vty_out(vty,
     892             :                         " OSPFv3 Routing Process (0) with Router-ID %pI4\n",
     893             :                         &ospf6->router_id);
     894             : 
     895           0 :         if (!uj) {
     896             : 
     897           0 :                 if (ospf6->ospf6_helper_cfg.is_helper_supported)
     898           0 :                         vty_out(vty,
     899             :                                 " Graceful restart helper support enabled.\n");
     900             :                 else
     901           0 :                         vty_out(vty,
     902             :                                 " Graceful restart helper support disabled.\n");
     903             : 
     904           0 :                 if (ospf6->ospf6_helper_cfg.strict_lsa_check)
     905           0 :                         vty_out(vty, " Strict LSA check is enabled.\n");
     906             :                 else
     907           0 :                         vty_out(vty, " Strict LSA check is disabled.\n");
     908             : 
     909           0 :                 if (ospf6->ospf6_helper_cfg.only_planned_restart)
     910           0 :                         vty_out(vty,
     911             :                                 " Helper supported for planned restarts only.\n");
     912             :                 else
     913           0 :                         vty_out(vty,
     914             :                                 " Helper supported for Planned and Unplanned Restarts.\n");
     915             : 
     916           0 :                 vty_out(vty,
     917             :                         " Supported Graceful restart interval: %d(in seconds).\n",
     918             :                         ospf6->ospf6_helper_cfg.supported_grace_time);
     919             : 
     920           0 :                 if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf)) {
     921           0 :                         vty_out(vty, " Enable Router list:\n");
     922           0 :                         vty_out(vty, "   ");
     923           0 :                         hash_walk(ospf6->ospf6_helper_cfg.enable_rtr_list,
     924             :                                   ospf6_print_vty_helper_dis_rtr_walkcb, vty);
     925           0 :                         vty_out(vty, "\n\n");
     926             :                 }
     927             : 
     928           0 :                 if (ospf6->ospf6_helper_cfg.last_exit_reason
     929             :                     != OSPF6_GR_HELPER_EXIT_NONE) {
     930           0 :                         vty_out(vty, " Last Helper exit Reason :%s\n",
     931             :                                 ospf6_exit_reason_desc
     932             :                                         [ospf6->ospf6_helper_cfg
     933             :                                                  .last_exit_reason]);
     934             : 
     935           0 :                         if (ospf6->ospf6_helper_cfg.active_restarter_cnt)
     936           0 :                                 vty_out(vty,
     937             :                                         " Number of Active neighbours in graceful restart: %d\n",
     938             :                                         ospf6->ospf6_helper_cfg
     939             :                                                 .active_restarter_cnt);
     940             :                         else
     941           0 :                                 vty_out(vty, "\n");
     942             :                 }
     943             : 
     944             : 
     945             :         } else {
     946           0 :                 json_object_string_add(
     947             :                         json, "helperSupport",
     948           0 :                         (ospf6->ospf6_helper_cfg.is_helper_supported)
     949             :                                 ? "Enabled"
     950             :                                 : "Disabled");
     951           0 :                 json_object_string_add(
     952             :                         json, "strictLsaCheck",
     953           0 :                         (ospf6->ospf6_helper_cfg.strict_lsa_check)
     954             :                                 ? "Enabled"
     955             :                                 : "Disabled");
     956           0 :                 json_object_string_add(
     957             :                         json, "restartSupoort",
     958           0 :                         (ospf6->ospf6_helper_cfg.only_planned_restart)
     959             :                                 ? "Planned Restart only"
     960             :                                 : "Planned and Unplanned Restarts");
     961             : 
     962           0 :                 json_object_int_add(
     963             :                         json, "supportedGracePeriod",
     964           0 :                         ospf6->ospf6_helper_cfg.supported_grace_time);
     965             : 
     966           0 :                 if (ospf6->ospf6_helper_cfg.last_exit_reason !=
     967             :                     OSPF6_GR_HELPER_EXIT_NONE)
     968           0 :                         json_object_string_add(
     969             :                                 json, "lastExitReason",
     970             :                                 ospf6_exit_reason_desc
     971             :                                         [ospf6->ospf6_helper_cfg
     972             :                                                  .last_exit_reason]);
     973             : 
     974           0 :                 if (ospf6->ospf6_helper_cfg.active_restarter_cnt)
     975           0 :                         json_object_int_add(
     976             :                                 json, "activeRestarterCnt",
     977             :                                 ospf6->ospf6_helper_cfg.active_restarter_cnt);
     978             : 
     979           0 :                 if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6)) {
     980           0 :                         struct json_object *json_rid_array =
     981           0 :                                 json_object_new_array();
     982             : 
     983           0 :                         json_object_object_add(json, "enabledRouterIds",
     984             :                                                json_rid_array);
     985             : 
     986           0 :                         hash_walk(ospf6->ospf6_helper_cfg.enable_rtr_list,
     987             :                                   ospf6_print_json_helper_dis_rtr_walkcb,
     988             :                                   json_rid_array);
     989             :                 }
     990             :         }
     991             : 
     992           0 :         if (detail) {
     993           0 :                 int cnt = 1;
     994           0 :                 struct listnode *i, *j, *k;
     995           0 :                 struct ospf6_area *oa;
     996           0 :                 json_object *json_neighbors = NULL;
     997             : 
     998           0 :                 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
     999           0 :                         for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) {
    1000           0 :                                 struct ospf6_neighbor *nbr;
    1001             : 
    1002           0 :                                 if (uj) {
    1003           0 :                                         json_object_object_get_ex(
    1004             :                                                 json, "neighbors",
    1005             :                                                 &json_neighbors);
    1006           0 :                                         if (!json_neighbors) {
    1007           0 :                                                 json_neighbors =
    1008           0 :                                                 json_object_new_object();
    1009           0 :                                                 json_object_object_add(
    1010             :                                                         json, "neighbors",
    1011             :                                                         json_neighbors);
    1012             :                                         }
    1013             :                                 }
    1014             : 
    1015           0 :                                 for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k,
    1016             :                                                           nbr)) {
    1017             : 
    1018           0 :                                         if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr))
    1019           0 :                                                 continue;
    1020             : 
    1021           0 :                                         if (!uj)
    1022           0 :                                                 vty_out(vty,
    1023             :                                                         " Neighbour %d :\n",
    1024             :                                                         cnt++);
    1025             : 
    1026           0 :                                         show_ospfv6_gr_helper_per_nbr(
    1027             :                                                 vty, json_neighbors, uj, nbr);
    1028             : 
    1029             :                                 }
    1030             :                         }
    1031             :         }
    1032           0 : }
    1033             : 
    1034             : /* Graceful Restart HELPER  config Commands */
    1035           0 : DEFPY(ospf6_gr_helper_enable,
    1036             :       ospf6_gr_helper_enable_cmd,
    1037             :       "graceful-restart helper enable [A.B.C.D$rtr_id]",
    1038             :       "ospf6 graceful restart\n"
    1039             :       "ospf6 GR Helper\n"
    1040             :       "Enable Helper support\n"
    1041             :       "Advertisement Router-ID\n")
    1042             : {
    1043           0 :         VTY_DECLVAR_CONTEXT(ospf6, ospf6);
    1044             : 
    1045           0 :         if (rtr_id_str != NULL) {
    1046             : 
    1047           0 :                 ospf6_gr_helper_support_set_per_routerid(ospf6, rtr_id,
    1048             :                                                          OSPF6_TRUE);
    1049             : 
    1050           0 :                 return CMD_SUCCESS;
    1051             :         }
    1052             : 
    1053           0 :         ospf6_gr_helper_support_set(ospf6, OSPF6_TRUE);
    1054             : 
    1055           0 :         return CMD_SUCCESS;
    1056             : }
    1057             : 
    1058           0 : DEFPY(ospf6_gr_helper_disable,
    1059             :       ospf6_gr_helper_disable_cmd,
    1060             :       "no graceful-restart helper enable [A.B.C.D$rtr_id]",
    1061             :       NO_STR
    1062             :       "ospf6 graceful restart\n"
    1063             :       "ospf6 GR Helper\n"
    1064             :       "Enable Helper support\n"
    1065             :       "Advertisement Router-ID\n")
    1066             : {
    1067           0 :         VTY_DECLVAR_CONTEXT(ospf6, ospf6);
    1068             : 
    1069           0 :         if (rtr_id_str != NULL) {
    1070             : 
    1071           0 :                 ospf6_gr_helper_support_set_per_routerid(ospf6, rtr_id,
    1072             :                                                          OSPF6_FALSE);
    1073             : 
    1074           0 :                 return CMD_SUCCESS;
    1075             :         }
    1076             : 
    1077           0 :         ospf6_gr_helper_support_set(ospf6, OSPF6_FALSE);
    1078             : 
    1079           0 :         return CMD_SUCCESS;
    1080             : }
    1081             : 
    1082           0 : DEFPY(ospf6_gr_helper_disable_lsacheck,
    1083             :       ospf6_gr_helper_disable_lsacheck_cmd,
    1084             :       "graceful-restart helper lsa-check-disable",
    1085             :       "ospf6 graceful restart\n"
    1086             :       "ospf6 GR Helper\n"
    1087             :       "disable strict LSA check\n")
    1088             : {
    1089           0 :         VTY_DECLVAR_CONTEXT(ospf6, ospf6);
    1090             : 
    1091           0 :         ospf6_gr_helper_lsacheck_set(ospf6, OSPF6_FALSE);
    1092             :         return CMD_SUCCESS;
    1093             : }
    1094             : 
    1095           0 : DEFPY(no_ospf6_gr_helper_disable_lsacheck,
    1096             :       no_ospf6_gr_helper_disable_lsacheck_cmd,
    1097             :       "no graceful-restart helper lsa-check-disable",
    1098             :       NO_STR
    1099             :       "ospf6 graceful restart\n"
    1100             :       "ospf6 GR Helper\n"
    1101             :       "diasble strict LSA check\n")
    1102             : {
    1103           0 :         VTY_DECLVAR_CONTEXT(ospf6, ospf6);
    1104             : 
    1105           0 :         ospf6_gr_helper_lsacheck_set(ospf6, OSPF6_TRUE);
    1106             :         return CMD_SUCCESS;
    1107             : }
    1108             : 
    1109           0 : DEFPY(ospf6_gr_helper_planned_only,
    1110             :       ospf6_gr_helper_planned_only_cmd,
    1111             :       "graceful-restart helper planned-only",
    1112             :       "ospf6 graceful restart\n"
    1113             :       "ospf6 GR Helper\n"
    1114             :       "supported only planned restart\n")
    1115             : {
    1116           0 :         VTY_DECLVAR_CONTEXT(ospf6, ospf6);
    1117             : 
    1118           0 :         ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6, OSPF6_TRUE);
    1119             : 
    1120           0 :         return CMD_SUCCESS;
    1121             : }
    1122             : 
    1123           0 : DEFPY(no_ospf6_gr_helper_planned_only, no_ospf6_gr_helper_planned_only_cmd,
    1124             :       "no graceful-restart helper planned-only",
    1125             :       NO_STR
    1126             :       "ospf6 graceful restart\n"
    1127             :       "ospf6 GR Helper\n"
    1128             :       "supported only for planned restart\n")
    1129             : {
    1130           0 :         VTY_DECLVAR_CONTEXT(ospf6, ospf6);
    1131             : 
    1132           0 :         ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6, OSPF6_FALSE);
    1133             : 
    1134           0 :         return CMD_SUCCESS;
    1135             : }
    1136             : 
    1137           0 : DEFPY(ospf6_gr_helper_supported_grace_time,
    1138             :       ospf6_gr_helper_supported_grace_time_cmd,
    1139             :       "graceful-restart helper supported-grace-time (10-1800)$interval",
    1140             :       "ospf6 graceful restart\n"
    1141             :       "ospf6 GR Helper\n"
    1142             :       "supported grace timer\n"
    1143             :       "grace interval(in seconds)\n")
    1144             : {
    1145           0 :         VTY_DECLVAR_CONTEXT(ospf6, ospf6);
    1146             : 
    1147           0 :         ospf6_gr_helper_supported_gracetime_set(ospf6, interval);
    1148           0 :         return CMD_SUCCESS;
    1149             : }
    1150             : 
    1151           0 : DEFPY(no_ospf6_gr_helper_supported_grace_time,
    1152             :       no_ospf6_gr_helper_supported_grace_time_cmd,
    1153             :       "no graceful-restart helper supported-grace-time (10-1800)$interval",
    1154             :       NO_STR
    1155             :       "ospf6 graceful restart\n"
    1156             :       "ospf6 GR Helper\n"
    1157             :       "supported grace timer\n"
    1158             :       "grace interval(in seconds)\n")
    1159             : {
    1160           0 :         VTY_DECLVAR_CONTEXT(ospf6, ospf6);
    1161             : 
    1162           0 :         ospf6_gr_helper_supported_gracetime_set(ospf6,
    1163             :                                                 OSPF6_MAX_GRACE_INTERVAL);
    1164           0 :         return CMD_SUCCESS;
    1165             : }
    1166             : 
    1167             : /* Show commands */
    1168           0 : DEFPY(show_ipv6_ospf6_gr_helper,
    1169             :       show_ipv6_ospf6_gr_helper_cmd,
    1170             :       "show ipv6 ospf6 graceful-restart helper [detail] [json]",
    1171             :       SHOW_STR
    1172             :       "Ipv6 Information\n"
    1173             :       "OSPF6 information\n"
    1174             :       "ospf6 graceful restart\n"
    1175             :       "helper details in the router\n"
    1176             :       "detailed information\n" JSON_STR)
    1177             : {
    1178           0 :         int idx = 0;
    1179           0 :         bool uj = use_json(argc, argv);
    1180           0 :         struct ospf6 *ospf6 = NULL;
    1181           0 :         json_object *json = NULL;
    1182           0 :         bool detail = false;
    1183             : 
    1184           0 :         ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
    1185           0 :         if (ospf6 == NULL) {
    1186           0 :                 vty_out(vty, "OSPFv3 is not configured\n");
    1187           0 :                 return CMD_SUCCESS;
    1188             :         }
    1189             : 
    1190           0 :         if (argv_find(argv, argc, "detail", &idx))
    1191           0 :                 detail = true;
    1192             : 
    1193           0 :         if (uj)
    1194           0 :                 json = json_object_new_object();
    1195             : 
    1196           0 :         show_ospf6_gr_helper_details(vty, ospf6, json, uj, detail);
    1197             : 
    1198           0 :         if (uj)
    1199           0 :                 vty_json(vty, json);
    1200             : 
    1201             :         return CMD_SUCCESS;
    1202             : }
    1203             : 
    1204             : /* Debug commands */
    1205           0 : DEFPY(debug_ospf6_gr, debug_ospf6_gr_cmd,
    1206             :       "[no$no] debug ospf6 graceful-restart",
    1207             :       NO_STR DEBUG_STR OSPF6_STR "Graceful restart\n")
    1208             : {
    1209           0 :         if (!no)
    1210           0 :                 OSPF6_DEBUG_GR_ON();
    1211             :         else
    1212           0 :                 OSPF6_DEBUG_GR_OFF();
    1213             : 
    1214           0 :         return CMD_SUCCESS;
    1215             : }
    1216             : 
    1217             : /*
    1218             :  * Api to display the grace LSA information.
    1219             :  *
    1220             :  * vty
    1221             :  *    vty pointer.
    1222             :  * lsa
    1223             :  *    Grace LSA.
    1224             :  * json
    1225             :  *    json object
    1226             :  *
    1227             :  * Returns:
    1228             :  *    Nothing.
    1229             :  */
    1230           0 : static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa,
    1231             :                                      json_object *json, bool use_json)
    1232             : {
    1233           0 :         struct ospf6_lsa_header *lsah = NULL;
    1234           0 :         struct tlv_header *tlvh = NULL;
    1235           0 :         struct grace_tlv_graceperiod *gracePeriod;
    1236           0 :         struct grace_tlv_restart_reason *grReason;
    1237           0 :         uint16_t length = 0;
    1238           0 :         int sum = 0;
    1239             : 
    1240           0 :         lsah = (struct ospf6_lsa_header *)lsa->header;
    1241           0 :         if (ntohs(lsah->length) <= OSPF6_LSA_HEADER_SIZE) {
    1242           0 :                 if (IS_DEBUG_OSPF6_GR)
    1243           0 :                         zlog_debug("%s: undersized (%u B) lsa", __func__,
    1244             :                                    ntohs(lsah->length));
    1245           0 :                 return OSPF6_FAILURE;
    1246             :         }
    1247             : 
    1248           0 :         length = ntohs(lsah->length) - OSPF6_LSA_HEADER_SIZE;
    1249             : 
    1250           0 :         if (vty) {
    1251           0 :                 if (!use_json)
    1252           0 :                         vty_out(vty, "TLV info:\n");
    1253             :         } else {
    1254           0 :                 zlog_debug("  TLV info:");
    1255             :         }
    1256             : 
    1257           0 :         for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
    1258           0 :              tlvh = TLV_HDR_NEXT(tlvh)) {
    1259             : 
    1260             :                 /* Check TLV len */
    1261           0 :                 if (sum + TLV_SIZE(tlvh) > length) {
    1262           0 :                         if (vty)
    1263           0 :                                 vty_out(vty, "%% Invalid TLV length: %d\n",
    1264           0 :                                         TLV_SIZE(tlvh));
    1265           0 :                         else if (IS_DEBUG_OSPF6_GR)
    1266           0 :                                 zlog_debug("%% Invalid TLV length: %d",
    1267             :                                            TLV_SIZE(tlvh));
    1268           0 :                         return OSPF6_FAILURE;
    1269             :                 }
    1270             : 
    1271           0 :                 switch (ntohs(tlvh->type)) {
    1272           0 :                 case GRACE_PERIOD_TYPE:
    1273           0 :                         gracePeriod = (struct grace_tlv_graceperiod *)tlvh;
    1274           0 :                         sum += TLV_SIZE(tlvh);
    1275             : 
    1276           0 :                         if (vty) {
    1277           0 :                                 if (use_json)
    1278           0 :                                         json_object_int_add(
    1279             :                                                 json, "gracePeriod",
    1280           0 :                                                 ntohl(gracePeriod->interval));
    1281             :                                 else
    1282           0 :                                         vty_out(vty, "   Grace period:%d\n",
    1283             :                                                 ntohl(gracePeriod->interval));
    1284             :                         } else {
    1285           0 :                                 zlog_debug("    Grace period:%d",
    1286             :                                            ntohl(gracePeriod->interval));
    1287             :                         }
    1288             :                         break;
    1289           0 :                 case RESTART_REASON_TYPE:
    1290           0 :                         grReason = (struct grace_tlv_restart_reason *)tlvh;
    1291           0 :                         sum += TLV_SIZE(tlvh);
    1292           0 :                         if (vty) {
    1293           0 :                                 if (use_json)
    1294           0 :                                         json_object_string_add(
    1295             :                                                 json, "restartReason",
    1296             :                                                 ospf6_restart_reason_desc
    1297           0 :                                                         [grReason->reason]);
    1298             :                                 else
    1299           0 :                                         vty_out(vty, "   Restart reason:%s\n",
    1300             :                                                 ospf6_restart_reason_desc
    1301           0 :                                                         [grReason->reason]);
    1302             :                         } else {
    1303           0 :                                 zlog_debug("    Restart reason:%s",
    1304             :                                            ospf6_restart_reason_desc
    1305             :                                                    [grReason->reason]);
    1306             :                         }
    1307             :                         break;
    1308             :                 default:
    1309             :                         break;
    1310             :                 }
    1311             :         }
    1312             : 
    1313             :         return 0;
    1314             : }
    1315             : 
    1316          16 : void ospf6_gr_helper_config_init(void)
    1317             : {
    1318             : 
    1319          16 :         ospf6_install_lsa_handler(&grace_lsa_handler);
    1320             : 
    1321          16 :         install_element(OSPF6_NODE, &ospf6_gr_helper_enable_cmd);
    1322          16 :         install_element(OSPF6_NODE, &ospf6_gr_helper_disable_cmd);
    1323          16 :         install_element(OSPF6_NODE, &ospf6_gr_helper_disable_lsacheck_cmd);
    1324          16 :         install_element(OSPF6_NODE, &no_ospf6_gr_helper_disable_lsacheck_cmd);
    1325          16 :         install_element(OSPF6_NODE, &ospf6_gr_helper_planned_only_cmd);
    1326          16 :         install_element(OSPF6_NODE, &no_ospf6_gr_helper_planned_only_cmd);
    1327          16 :         install_element(OSPF6_NODE, &ospf6_gr_helper_supported_grace_time_cmd);
    1328          16 :         install_element(OSPF6_NODE,
    1329             :                         &no_ospf6_gr_helper_supported_grace_time_cmd);
    1330             : 
    1331          16 :         install_element(VIEW_NODE, &show_ipv6_ospf6_gr_helper_cmd);
    1332             : 
    1333          16 :         install_element(CONFIG_NODE, &debug_ospf6_gr_cmd);
    1334          16 :         install_element(ENABLE_NODE, &debug_ospf6_gr_cmd);
    1335          16 : }
    1336             : 
    1337             : 
    1338             : /*
    1339             :  * Initialize GR helper config data structure.
    1340             :  *
    1341             :  * ospf6
    1342             :  *    ospf6 pointer
    1343             :  *
    1344             :  * Returns:
    1345             :  *    Nothing
    1346             :  */
    1347          16 : void ospf6_gr_helper_init(struct ospf6 *ospf6)
    1348             : {
    1349          16 :         if (IS_DEBUG_OSPF6_GR)
    1350           0 :                 zlog_debug("%s, GR Helper init.", __func__);
    1351             : 
    1352          16 :         ospf6->ospf6_helper_cfg.is_helper_supported = OSPF6_FALSE;
    1353          16 :         ospf6->ospf6_helper_cfg.strict_lsa_check = OSPF6_TRUE;
    1354          16 :         ospf6->ospf6_helper_cfg.only_planned_restart = OSPF6_FALSE;
    1355          16 :         ospf6->ospf6_helper_cfg.supported_grace_time = OSPF6_MAX_GRACE_INTERVAL;
    1356          16 :         ospf6->ospf6_helper_cfg.last_exit_reason = OSPF6_GR_HELPER_EXIT_NONE;
    1357          16 :         ospf6->ospf6_helper_cfg.active_restarter_cnt = 0;
    1358             : 
    1359          16 :         ospf6->ospf6_helper_cfg.enable_rtr_list = hash_create(
    1360             :                 ospf6_enable_rtr_hash_key, ospf6_enable_rtr_hash_cmp,
    1361             :                 "Ospf6 enable router hash");
    1362          16 : }
    1363             : 
    1364             : /*
    1365             :  * De-initialize GR helper config data structure.
    1366             :  *
    1367             :  * ospf6
    1368             :  *    ospf6 pointer
    1369             :  *
    1370             :  * Returns:
    1371             :  *    Nothing
    1372             :  */
    1373          16 : void ospf6_gr_helper_deinit(struct ospf6 *ospf6)
    1374             : {
    1375             : 
    1376          16 :         if (IS_DEBUG_OSPF6_GR)
    1377           0 :                 zlog_debug("%s, GR helper deinit.", __func__);
    1378             : 
    1379          16 :         ospf6_enable_rtr_hash_destroy(ospf6);
    1380          16 : }
    1381             : 
    1382           0 : static int ospf6_cfg_write_helper_enable_rtr_walkcb(struct hash_bucket *backet,
    1383             :                                                     void *arg)
    1384             : {
    1385           0 :         struct advRtr *rtr = backet->data;
    1386           0 :         struct vty *vty = (struct vty *)arg;
    1387             : 
    1388           0 :         vty_out(vty, " graceful-restart helper enable %pI4\n", &rtr->advRtrAddr);
    1389           0 :         return HASHWALK_CONTINUE;
    1390             : }
    1391             : 
    1392           0 : int config_write_ospf6_gr_helper(struct vty *vty, struct ospf6 *ospf6)
    1393             : {
    1394           0 :         if (ospf6->ospf6_helper_cfg.is_helper_supported)
    1395           0 :                 vty_out(vty, " graceful-restart helper enable\n");
    1396             : 
    1397           0 :         if (!ospf6->ospf6_helper_cfg.strict_lsa_check)
    1398           0 :                 vty_out(vty, " graceful-restart helper lsa-check-disable\n");
    1399             : 
    1400           0 :         if (ospf6->ospf6_helper_cfg.only_planned_restart)
    1401           0 :                 vty_out(vty, " graceful-restart helper planned-only\n");
    1402             : 
    1403           0 :         if (ospf6->ospf6_helper_cfg.supported_grace_time
    1404             :             != OSPF6_MAX_GRACE_INTERVAL)
    1405           0 :                 vty_out(vty,
    1406             :                         " graceful-restart helper supported-grace-time %d\n",
    1407             :                         ospf6->ospf6_helper_cfg.supported_grace_time);
    1408             : 
    1409           0 :         if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6)) {
    1410           0 :                 hash_walk(ospf6->ospf6_helper_cfg.enable_rtr_list,
    1411             :                           ospf6_cfg_write_helper_enable_rtr_walkcb, vty);
    1412             :         }
    1413             : 
    1414           0 :         return 0;
    1415             : }
    1416             : 
    1417           0 : int config_write_ospf6_debug_gr_helper(struct vty *vty)
    1418             : {
    1419           0 :         if (IS_DEBUG_OSPF6_GR)
    1420           0 :                 vty_out(vty, "debug ospf6 graceful-restart\n");
    1421           0 :         return 0;
    1422             : }

Generated by: LCOV version v1.16-topotato