back to topotato report
topotato coverage report
Current view: top level - ospf6d - ospf6_gr.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 36 324 11.1 %
Date: 2023-02-24 14:41:08 Functions: 3 20 15.0 %

          Line data    Source code
       1             : /*
       2             :  * This is an implementation of RFC 5187 Graceful Restart.
       3             :  *
       4             :  * Copyright 2021 NetDEF (c), All rights reserved.
       5             :  *
       6             :  * This program is free software; you can redistribute it and/or modify it
       7             :  * under the terms of the GNU General Public License as published by the Free
       8             :  * Software Foundation; either version 2 of the License, or (at your option)
       9             :  * any later version.
      10             :  *
      11             :  * This program is distributed in the hope that it will be useful, but WITHOUT
      12             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13             :  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
      14             :  * more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License along
      17             :  * with this program; see the file COPYING; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : #include <zebra.h>
      22             : 
      23             : #include "memory.h"
      24             : #include "command.h"
      25             : #include "table.h"
      26             : #include "vty.h"
      27             : #include "log.h"
      28             : #include "hook.h"
      29             : #include "printfrr.h"
      30             : 
      31             : #include "ospf6d/ospf6_lsa.h"
      32             : #include "ospf6d/ospf6_lsdb.h"
      33             : #include "ospf6d/ospf6_route.h"
      34             : #include "ospf6d/ospf6_area.h"
      35             : #include "ospf6d/ospf6_interface.h"
      36             : #include "ospf6d/ospf6d.h"
      37             : #include "ospf6d/ospf6_asbr.h"
      38             : #include "ospf6d/ospf6_zebra.h"
      39             : #include "ospf6d/ospf6_message.h"
      40             : #include "ospf6d/ospf6_neighbor.h"
      41             : #include "ospf6d/ospf6_flood.h"
      42             : #include "ospf6d/ospf6_intra.h"
      43             : #include "ospf6d/ospf6_spf.h"
      44             : #include "ospf6d/ospf6_gr.h"
      45             : #include "ospf6d/ospf6_gr_clippy.c"
      46             : 
      47             : static void ospf6_gr_nvm_delete(struct ospf6 *ospf6);
      48             : 
      49             : /* Originate and install Grace-LSA for a given interface. */
      50           0 : static int ospf6_gr_lsa_originate(struct ospf6_interface *oi)
      51             : {
      52           0 :         struct ospf6_gr_info *gr_info = &oi->area->ospf6->gr_info;
      53           0 :         struct ospf6_lsa_header *lsa_header;
      54           0 :         struct ospf6_grace_lsa *grace_lsa;
      55           0 :         struct ospf6_lsa *lsa;
      56           0 :         char buffer[OSPF6_MAX_LSASIZE];
      57             : 
      58           0 :         if (IS_OSPF6_DEBUG_ORIGINATE(LINK))
      59           0 :                 zlog_debug("Originate Grace-LSA for Interface %pOI", oi);
      60             : 
      61             :         /* prepare buffer */
      62           0 :         memset(buffer, 0, sizeof(buffer));
      63           0 :         lsa_header = (struct ospf6_lsa_header *)buffer;
      64           0 :         grace_lsa =
      65             :                 (struct ospf6_grace_lsa *)((caddr_t)lsa_header
      66             :                                            + sizeof(struct ospf6_lsa_header));
      67             : 
      68             :         /* Put grace period. */
      69           0 :         grace_lsa->tlv_period.header.type = htons(GRACE_PERIOD_TYPE);
      70           0 :         grace_lsa->tlv_period.header.length = htons(GRACE_PERIOD_LENGTH);
      71           0 :         grace_lsa->tlv_period.interval = htonl(gr_info->grace_period);
      72             : 
      73             :         /* Put restart reason. */
      74           0 :         grace_lsa->tlv_reason.header.type = htons(RESTART_REASON_TYPE);
      75           0 :         grace_lsa->tlv_reason.header.length = htons(RESTART_REASON_LENGTH);
      76           0 :         if (gr_info->restart_support)
      77           0 :                 grace_lsa->tlv_reason.reason = OSPF6_GR_SW_RESTART;
      78             :         else
      79             :                 grace_lsa->tlv_reason.reason = OSPF6_GR_UNKNOWN_RESTART;
      80             : 
      81             :         /* Fill LSA Header */
      82           0 :         lsa_header->age = 0;
      83           0 :         lsa_header->type = htons(OSPF6_LSTYPE_GRACE_LSA);
      84           0 :         lsa_header->id = htonl(oi->interface->ifindex);
      85           0 :         lsa_header->adv_router = oi->area->ospf6->router_id;
      86           0 :         lsa_header->seqnum =
      87           0 :                 ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
      88             :                                     lsa_header->adv_router, oi->lsdb);
      89           0 :         lsa_header->length = htons(sizeof(*lsa_header) + sizeof(*grace_lsa));
      90             : 
      91             :         /* LSA checksum */
      92           0 :         ospf6_lsa_checksum(lsa_header);
      93             : 
      94             :         /* create LSA */
      95           0 :         lsa = ospf6_lsa_create(lsa_header);
      96             : 
      97             :         /* Originate */
      98           0 :         ospf6_lsa_originate_interface(lsa, oi);
      99             : 
     100           0 :         return 0;
     101             : }
     102             : 
     103             : /* Flush all self-originated Grace-LSAs. */
     104           0 : static void ospf6_gr_flush_grace_lsas(struct ospf6 *ospf6)
     105             : {
     106           0 :         struct ospf6_area *area;
     107           0 :         struct listnode *anode;
     108             : 
     109           0 :         for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, anode, area)) {
     110           0 :                 struct ospf6_lsa *lsa;
     111           0 :                 struct ospf6_interface *oi;
     112           0 :                 struct listnode *inode;
     113             : 
     114           0 :                 if (IS_DEBUG_OSPF6_GR)
     115           0 :                         zlog_debug(
     116             :                                 "GR: flushing self-originated Grace-LSAs [area %pI4]",
     117             :                                 &area->area_id);
     118             : 
     119           0 :                 for (ALL_LIST_ELEMENTS_RO(area->if_list, inode, oi)) {
     120           0 :                         lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_GRACE_LSA),
     121           0 :                                                 htonl(oi->interface->ifindex),
     122           0 :                                                 oi->area->ospf6->router_id,
     123             :                                                 oi->lsdb);
     124           0 :                         if (!lsa) {
     125           0 :                                 zlog_warn(
     126             :                                         "%s: Grace-LSA not found [interface %pOI] [area %pI4]",
     127             :                                         __func__, oi, &area->area_id);
     128           0 :                                 continue;
     129             :                         }
     130             : 
     131           0 :                         ospf6_lsa_purge(lsa);
     132             :                 }
     133             :         }
     134           0 : }
     135             : 
     136             : /* Exit from the Graceful Restart mode. */
     137           0 : static void ospf6_gr_restart_exit(struct ospf6 *ospf6, const char *reason)
     138             : {
     139           0 :         struct ospf6_area *area;
     140           0 :         struct listnode *onode, *anode;
     141             : 
     142           0 :         if (IS_DEBUG_OSPF6_GR)
     143           0 :                 zlog_debug("GR: exiting graceful restart: %s", reason);
     144             : 
     145           0 :         ospf6->gr_info.restart_in_progress = false;
     146           0 :         ospf6->gr_info.finishing_restart = true;
     147           0 :         THREAD_OFF(ospf6->gr_info.t_grace_period);
     148             : 
     149             :         /* Record in non-volatile memory that the restart is complete. */
     150           0 :         ospf6_gr_nvm_delete(ospf6);
     151             : 
     152           0 :         for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, onode, area)) {
     153           0 :                 struct ospf6_interface *oi;
     154             : 
     155             :                 /*
     156             :                  * 1) The router should reoriginate its router-LSAs for all
     157             :                  *    attached areas in order to make sure they have the correct
     158             :                  *    contents.
     159             :                  */
     160           0 :                 OSPF6_ROUTER_LSA_EXECUTE(area);
     161             : 
     162           0 :                 for (ALL_LIST_ELEMENTS_RO(area->if_list, anode, oi)) {
     163           0 :                         OSPF6_LINK_LSA_EXECUTE(oi);
     164             : 
     165             :                         /*
     166             :                          * 2) The router should reoriginate network-LSAs on all
     167             :                          * segments where it is the Designated Router.
     168             :                          */
     169           0 :                         if (oi->state == OSPF6_INTERFACE_DR)
     170           0 :                                 OSPF6_NETWORK_LSA_EXECUTE(oi);
     171             :                 }
     172             :         }
     173             : 
     174             :         /*
     175             :          * 3) The router reruns its OSPF routing calculations, this time
     176             :          *    installing the results into the system forwarding table, and
     177             :          *    originating summary-LSAs, Type-7 LSAs and AS-external-LSAs as
     178             :          *    necessary.
     179             :          *
     180             :          * 4) Any remnant entries in the system forwarding table that were
     181             :          *    installed before the restart, but that are no longer valid,
     182             :          *    should be removed.
     183             :          */
     184           0 :         ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_GR_FINISH);
     185             : 
     186             :         /* 6) Any grace-LSAs that the router originated should be flushed. */
     187           0 :         ospf6_gr_flush_grace_lsas(ospf6);
     188           0 : }
     189             : 
     190             : #define RTR_LSA_MISSING 0
     191             : #define RTR_LSA_ADJ_FOUND 1
     192             : #define RTR_LSA_ADJ_NOT_FOUND 2
     193             : 
     194             : /* Check if a Router-LSA exists and if it contains a given link. */
     195           0 : static int ospf6_router_lsa_contains_adj(struct ospf6_area *area,
     196             :                                          in_addr_t adv_router,
     197             :                                          in_addr_t neighbor_router_id)
     198             : {
     199           0 :         uint16_t type;
     200           0 :         struct ospf6_lsa *lsa;
     201           0 :         bool empty = true;
     202             : 
     203           0 :         type = ntohs(OSPF6_LSTYPE_ROUTER);
     204           0 :         for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, adv_router, lsa)) {
     205           0 :                 struct ospf6_router_lsa *router_lsa;
     206           0 :                 char *start, *end, *current;
     207             : 
     208           0 :                 empty = false;
     209           0 :                 router_lsa = (struct ospf6_router_lsa
     210           0 :                                       *)((char *)lsa->header
     211             :                                          + sizeof(struct ospf6_lsa_header));
     212             : 
     213             :                 /* Iterate over all interfaces in the Router-LSA. */
     214           0 :                 start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
     215           0 :                 end = (char *)lsa->header + ntohs(lsa->header->length);
     216           0 :                 for (current = start;
     217           0 :                      current + sizeof(struct ospf6_router_lsdesc) <= end;
     218             :                      current += sizeof(struct ospf6_router_lsdesc)) {
     219           0 :                         struct ospf6_router_lsdesc *lsdesc;
     220             : 
     221           0 :                         lsdesc = (struct ospf6_router_lsdesc *)current;
     222           0 :                         if (lsdesc->type != OSPF6_ROUTER_LSDESC_POINTTOPOINT)
     223           0 :                                 continue;
     224             : 
     225           0 :                         if (lsdesc->neighbor_router_id == neighbor_router_id)
     226             :                                 return RTR_LSA_ADJ_FOUND;
     227             :                 }
     228             :         }
     229             : 
     230           0 :         if (empty)
     231           0 :                 return RTR_LSA_MISSING;
     232             : 
     233             :         return RTR_LSA_ADJ_NOT_FOUND;
     234             : }
     235             : 
     236           0 : static bool ospf6_gr_check_router_lsa_consistency(struct ospf6 *ospf6,
     237             :                                                   struct ospf6_area *area,
     238             :                                                   struct ospf6_lsa *lsa)
     239             : {
     240           0 :         if (lsa->header->adv_router == ospf6->router_id) {
     241           0 :                 struct ospf6_router_lsa *router_lsa;
     242           0 :                 char *start, *end, *current;
     243             : 
     244           0 :                 router_lsa = (struct ospf6_router_lsa
     245             :                                       *)((char *)lsa->header
     246             :                                          + sizeof(struct ospf6_lsa_header));
     247             : 
     248             :                 /* Iterate over all interfaces in the Router-LSA. */
     249           0 :                 start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
     250           0 :                 end = (char *)lsa->header + ntohs(lsa->header->length);
     251           0 :                 for (current = start;
     252           0 :                      current + sizeof(struct ospf6_router_lsdesc) <= end;
     253             :                      current += sizeof(struct ospf6_router_lsdesc)) {
     254           0 :                         struct ospf6_router_lsdesc *lsdesc;
     255             : 
     256           0 :                         lsdesc = (struct ospf6_router_lsdesc *)current;
     257           0 :                         if (lsdesc->type != OSPF6_ROUTER_LSDESC_POINTTOPOINT)
     258           0 :                                 continue;
     259             : 
     260           0 :                         if (ospf6_router_lsa_contains_adj(
     261             :                                     area, lsdesc->neighbor_router_id,
     262             :                                     ospf6->router_id)
     263             :                             == RTR_LSA_ADJ_NOT_FOUND)
     264             :                                 return false;
     265             :                 }
     266             :         } else {
     267           0 :                 int adj1, adj2;
     268             : 
     269           0 :                 adj1 = ospf6_router_lsa_contains_adj(area, ospf6->router_id,
     270             :                                                      lsa->header->adv_router);
     271           0 :                 adj2 = ospf6_router_lsa_contains_adj(
     272           0 :                         area, lsa->header->adv_router, ospf6->router_id);
     273           0 :                 if ((adj1 == RTR_LSA_ADJ_FOUND && adj2 == RTR_LSA_ADJ_NOT_FOUND)
     274           0 :                     || (adj1 == RTR_LSA_ADJ_NOT_FOUND
     275           0 :                         && adj2 == RTR_LSA_ADJ_FOUND))
     276             :                         return false;
     277             :         }
     278             : 
     279             :         return true;
     280             : }
     281             : 
     282             : /*
     283             :  * Check for LSAs that are inconsistent with the pre-restart LSAs, and abort the
     284             :  * ongoing graceful restart when that's the case.
     285             :  */
     286           0 : void ospf6_gr_check_lsdb_consistency(struct ospf6 *ospf6,
     287             :                                      struct ospf6_area *area)
     288             : {
     289           0 :         uint16_t type;
     290           0 :         struct ospf6_lsa *lsa;
     291             : 
     292           0 :         type = ntohs(OSPF6_LSTYPE_ROUTER);
     293           0 :         for (ALL_LSDB_TYPED(area->lsdb, type, lsa)) {
     294           0 :                 if (!ospf6_gr_check_router_lsa_consistency(ospf6, area, lsa)) {
     295           0 :                         char reason[256];
     296             : 
     297           0 :                         snprintfrr(reason, sizeof(reason),
     298             :                                    "detected inconsistent LSA %s [area %pI4]",
     299           0 :                                    lsa->name, &area->area_id);
     300           0 :                         ospf6_gr_restart_exit(ospf6, reason);
     301           0 :                         return;
     302             :                 }
     303             :         }
     304             : }
     305             : 
     306             : /* Check if there's a fully formed adjacency with the given neighbor ID. */
     307           0 : static bool ospf6_gr_check_adj_id(struct ospf6_area *area,
     308             :                                   in_addr_t neighbor_router_id)
     309             : {
     310           0 :         struct ospf6_neighbor *nbr;
     311             : 
     312           0 :         nbr = ospf6_area_neighbor_lookup(area, neighbor_router_id);
     313           0 :         if (!nbr || nbr->state < OSPF6_NEIGHBOR_FULL) {
     314           0 :                 if (IS_DEBUG_OSPF6_GR)
     315           0 :                         zlog_debug("GR: missing adjacency to router %pI4",
     316             :                                    &neighbor_router_id);
     317           0 :                 return false;
     318             :         }
     319             : 
     320             :         return true;
     321             : }
     322             : 
     323           0 : static bool ospf6_gr_check_adjs_lsa_transit(struct ospf6_area *area,
     324             :                                             in_addr_t neighbor_router_id,
     325             :                                             uint32_t neighbor_interface_id)
     326             : {
     327           0 :         struct ospf6 *ospf6 = area->ospf6;
     328             : 
     329             :         /* Check if we are the DR. */
     330           0 :         if (neighbor_router_id == ospf6->router_id) {
     331           0 :                 struct ospf6_lsa *lsa;
     332           0 :                 char *start, *end, *current;
     333           0 :                 struct ospf6_network_lsa *network_lsa;
     334           0 :                 struct ospf6_network_lsdesc *lsdesc;
     335             : 
     336             :                 /* Lookup Network LSA corresponding to this interface. */
     337           0 :                 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_NETWORK),
     338             :                                         neighbor_interface_id,
     339             :                                         neighbor_router_id, area->lsdb);
     340           0 :                 if (!lsa)
     341             :                         return false;
     342             : 
     343             :                 /* Iterate over all routers present in the network. */
     344           0 :                 network_lsa = (struct ospf6_network_lsa
     345           0 :                                        *)((char *)lsa->header
     346             :                                           + sizeof(struct ospf6_lsa_header));
     347           0 :                 start = (char *)network_lsa + sizeof(struct ospf6_network_lsa);
     348           0 :                 end = (char *)lsa->header + ntohs(lsa->header->length);
     349           0 :                 for (current = start;
     350           0 :                      current + sizeof(struct ospf6_network_lsdesc) <= end;
     351             :                      current += sizeof(struct ospf6_network_lsdesc)) {
     352           0 :                         lsdesc = (struct ospf6_network_lsdesc *)current;
     353             : 
     354             :                         /* Skip self in the pseudonode. */
     355           0 :                         if (lsdesc->router_id == ospf6->router_id)
     356           0 :                                 continue;
     357             : 
     358             :                         /*
     359             :                          * Check if there's a fully formed adjacency with this
     360             :                          * router.
     361             :                          */
     362           0 :                         if (!ospf6_gr_check_adj_id(area, lsdesc->router_id))
     363             :                                 return false;
     364             :                 }
     365             :         } else {
     366           0 :                 struct ospf6_neighbor *nbr;
     367             : 
     368             :                 /* Check if there's a fully formed adjacency with the DR. */
     369           0 :                 nbr = ospf6_area_neighbor_lookup(area, neighbor_router_id);
     370           0 :                 if (!nbr || nbr->state < OSPF6_NEIGHBOR_FULL) {
     371           0 :                         if (IS_DEBUG_OSPF6_GR)
     372           0 :                                 zlog_debug(
     373             :                                         "GR: missing adjacency to DR router %pI4",
     374             :                                         &neighbor_router_id);
     375           0 :                         return false;
     376             :                 }
     377             :         }
     378             : 
     379             :         return true;
     380             : }
     381             : 
     382           0 : static bool ospf6_gr_check_adjs_lsa(struct ospf6_area *area,
     383             :                                     struct ospf6_lsa *lsa)
     384             : {
     385           0 :         struct ospf6_router_lsa *router_lsa;
     386           0 :         char *start, *end, *current;
     387             : 
     388           0 :         router_lsa =
     389           0 :                 (struct ospf6_router_lsa *)((char *)lsa->header
     390             :                                             + sizeof(struct ospf6_lsa_header));
     391             : 
     392             :         /* Iterate over all interfaces in the Router-LSA. */
     393           0 :         start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
     394           0 :         end = (char *)lsa->header + ntohs(lsa->header->length);
     395           0 :         for (current = start;
     396           0 :              current + sizeof(struct ospf6_router_lsdesc) <= end;
     397             :              current += sizeof(struct ospf6_router_lsdesc)) {
     398           0 :                 struct ospf6_router_lsdesc *lsdesc;
     399             : 
     400           0 :                 lsdesc = (struct ospf6_router_lsdesc *)current;
     401           0 :                 switch (lsdesc->type) {
     402           0 :                 case OSPF6_ROUTER_LSDESC_POINTTOPOINT:
     403           0 :                         if (!ospf6_gr_check_adj_id(area,
     404             :                                                    lsdesc->neighbor_router_id))
     405             :                                 return false;
     406             :                         break;
     407           0 :                 case OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK:
     408           0 :                         if (!ospf6_gr_check_adjs_lsa_transit(
     409             :                                     area, lsdesc->neighbor_router_id,
     410             :                                     lsdesc->neighbor_interface_id))
     411             :                                 return false;
     412             :                         break;
     413             :                 default:
     414             :                         break;
     415             :                 }
     416             :         }
     417             : 
     418             :         return true;
     419             : }
     420             : 
     421             : /*
     422             :  * Check if all adjacencies prior to the restart were reestablished.
     423             :  *
     424             :  * This is done using pre-restart Router LSAs and pre-restart Network LSAs
     425             :  * received from the helping neighbors.
     426             :  */
     427           0 : static bool ospf6_gr_check_adjs(struct ospf6 *ospf6)
     428             : {
     429           0 :         struct ospf6_area *area;
     430           0 :         struct listnode *node;
     431             : 
     432           0 :         for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, area)) {
     433           0 :                 uint16_t type;
     434           0 :                 uint32_t router;
     435           0 :                 struct ospf6_lsa *lsa_self;
     436           0 :                 bool found = false;
     437             : 
     438           0 :                 type = ntohs(OSPF6_LSTYPE_ROUTER);
     439           0 :                 router = ospf6->router_id;
     440           0 :                 for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, router,
     441             :                                            lsa_self)) {
     442           0 :                         found = true;
     443           0 :                         if (!ospf6_gr_check_adjs_lsa(area, lsa_self))
     444           0 :                                 return false;
     445             :                 }
     446           0 :                 if (!found)
     447             :                         return false;
     448             :         }
     449             : 
     450             :         return true;
     451             : }
     452             : 
     453             : /* Handling of grace period expiry. */
     454           0 : static void ospf6_gr_grace_period_expired(struct thread *thread)
     455             : {
     456           0 :         struct ospf6 *ospf6 = THREAD_ARG(thread);
     457             : 
     458           0 :         ospf6_gr_restart_exit(ospf6, "grace period has expired");
     459           0 : }
     460             : 
     461             : /*
     462             :  * Record in non-volatile memory that the given OSPF instance is attempting to
     463             :  * perform a graceful restart.
     464             :  */
     465           0 : static void ospf6_gr_nvm_update(struct ospf6 *ospf6)
     466             : {
     467           0 :         const char *inst_name;
     468           0 :         json_object *json;
     469           0 :         json_object *json_instances;
     470           0 :         json_object *json_instance;
     471             : 
     472           0 :         inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
     473             : 
     474           0 :         json = json_object_from_file((char *)OSPF6D_GR_STATE);
     475           0 :         if (json == NULL)
     476           0 :                 json = json_object_new_object();
     477             : 
     478           0 :         json_object_object_get_ex(json, "instances", &json_instances);
     479           0 :         if (!json_instances) {
     480           0 :                 json_instances = json_object_new_object();
     481           0 :                 json_object_object_add(json, "instances", json_instances);
     482             :         }
     483             : 
     484           0 :         json_object_object_get_ex(json_instances, inst_name, &json_instance);
     485           0 :         if (!json_instance) {
     486           0 :                 json_instance = json_object_new_object();
     487           0 :                 json_object_object_add(json_instances, inst_name,
     488             :                                        json_instance);
     489             :         }
     490             : 
     491             :         /*
     492             :          * Record not only the grace period, but also a UNIX timestamp
     493             :          * corresponding to the end of that period. That way, once ospf6d is
     494             :          * restarted, it will be possible to take into account the time that
     495             :          * passed while ospf6d wasn't running.
     496             :          */
     497           0 :         json_object_int_add(json_instance, "gracePeriod",
     498           0 :                             ospf6->gr_info.grace_period);
     499           0 :         json_object_int_add(json_instance, "timestamp",
     500           0 :                             time(NULL) + ospf6->gr_info.grace_period);
     501             : 
     502           0 :         json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
     503             :                                 JSON_C_TO_STRING_PRETTY);
     504           0 :         json_object_free(json);
     505           0 : }
     506             : 
     507             : /*
     508             :  * Delete GR status information about the given OSPF instance from non-volatile
     509             :  * memory.
     510             :  */
     511           0 : static void ospf6_gr_nvm_delete(struct ospf6 *ospf6)
     512             : {
     513           0 :         const char *inst_name;
     514           0 :         json_object *json;
     515           0 :         json_object *json_instances;
     516             : 
     517           0 :         inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
     518             : 
     519           0 :         json = json_object_from_file((char *)OSPF6D_GR_STATE);
     520           0 :         if (json == NULL)
     521           0 :                 json = json_object_new_object();
     522             : 
     523           0 :         json_object_object_get_ex(json, "instances", &json_instances);
     524           0 :         if (!json_instances) {
     525           0 :                 json_instances = json_object_new_object();
     526           0 :                 json_object_object_add(json, "instances", json_instances);
     527             :         }
     528             : 
     529           0 :         json_object_object_del(json_instances, inst_name);
     530             : 
     531           0 :         json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
     532             :                                 JSON_C_TO_STRING_PRETTY);
     533           0 :         json_object_free(json);
     534           0 : }
     535             : 
     536             : /*
     537             :  * Fetch from non-volatile memory whether the given OSPF instance is performing
     538             :  * a graceful shutdown or not.
     539             :  */
     540          16 : void ospf6_gr_nvm_read(struct ospf6 *ospf6)
     541             : {
     542          16 :         const char *inst_name;
     543          16 :         json_object *json;
     544          16 :         json_object *json_instances;
     545          16 :         json_object *json_instance;
     546          16 :         json_object *json_timestamp;
     547          16 :         time_t timestamp = 0;
     548             : 
     549          16 :         inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
     550             : 
     551          16 :         json = json_object_from_file((char *)OSPF6D_GR_STATE);
     552          16 :         if (json == NULL)
     553          16 :                 json = json_object_new_object();
     554             : 
     555          16 :         json_object_object_get_ex(json, "instances", &json_instances);
     556          16 :         if (!json_instances) {
     557          16 :                 json_instances = json_object_new_object();
     558          16 :                 json_object_object_add(json, "instances", json_instances);
     559             :         }
     560             : 
     561          16 :         json_object_object_get_ex(json_instances, inst_name, &json_instance);
     562          16 :         if (!json_instance) {
     563          16 :                 json_instance = json_object_new_object();
     564          16 :                 json_object_object_add(json_instances, inst_name,
     565             :                                        json_instance);
     566             :         }
     567             : 
     568          16 :         json_object_object_get_ex(json_instance, "timestamp", &json_timestamp);
     569          16 :         if (json_timestamp) {
     570           0 :                 time_t now;
     571           0 :                 unsigned long remaining_time;
     572             : 
     573             :                 /* Check if the grace period has already expired. */
     574           0 :                 now = time(NULL);
     575           0 :                 timestamp = json_object_get_int(json_timestamp);
     576           0 :                 if (now > timestamp) {
     577           0 :                         ospf6_gr_restart_exit(
     578             :                                 ospf6, "grace period has expired already");
     579             :                 } else {
     580             :                         /* Schedule grace period timeout. */
     581           0 :                         ospf6->gr_info.restart_in_progress = true;
     582           0 :                         remaining_time = timestamp - time(NULL);
     583           0 :                         if (IS_DEBUG_OSPF6_GR)
     584           0 :                                 zlog_debug(
     585             :                                         "GR: remaining time until grace period expires: %lu(s)",
     586             :                                         remaining_time);
     587           0 :                         thread_add_timer(master, ospf6_gr_grace_period_expired,
     588             :                                          ospf6, remaining_time,
     589             :                                          &ospf6->gr_info.t_grace_period);
     590             :                 }
     591             :         }
     592             : 
     593          16 :         json_object_object_del(json_instances, inst_name);
     594             : 
     595          16 :         json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
     596             :                                 JSON_C_TO_STRING_PRETTY);
     597          16 :         json_object_free(json);
     598          16 : }
     599             : 
     600             : /* Prepare to start a Graceful Restart. */
     601           0 : static void ospf6_gr_prepare(void)
     602             : {
     603           0 :         struct ospf6 *ospf6;
     604           0 :         struct ospf6_interface *oi;
     605           0 :         struct listnode *onode, *anode, *inode;
     606             : 
     607           0 :         for (ALL_LIST_ELEMENTS_RO(om6->ospf6, onode, ospf6)) {
     608           0 :                 struct ospf6_area *area;
     609             : 
     610           0 :                 if (!ospf6->gr_info.restart_support
     611           0 :                     || ospf6->gr_info.prepare_in_progress)
     612           0 :                         continue;
     613             : 
     614           0 :                 if (IS_DEBUG_OSPF6_GR)
     615           0 :                         zlog_debug(
     616             :                                 "GR: preparing to perform a graceful restart [period %u second(s)] [vrf %s]",
     617             :                                 ospf6->gr_info.grace_period,
     618             :                                 ospf6_vrf_id_to_name(ospf6->vrf_id));
     619             : 
     620             :                 /* Freeze OSPF routes in the RIB. */
     621           0 :                 if (ospf6_zebra_gr_enable(ospf6, ospf6->gr_info.grace_period)) {
     622           0 :                         zlog_warn(
     623             :                                 "%s: failed to activate graceful restart: not connected to zebra",
     624             :                                 __func__);
     625           0 :                         continue;
     626             :                 }
     627             : 
     628             :                 /* Send a Grace-LSA to all neighbors. */
     629           0 :                 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, anode, area)) {
     630           0 :                         for (ALL_LIST_ELEMENTS_RO(area->if_list, inode, oi)) {
     631           0 :                                 if (oi->state < OSPF6_INTERFACE_POINTTOPOINT)
     632           0 :                                         continue;
     633           0 :                                 ospf6_gr_lsa_originate(oi);
     634             :                         }
     635             :                 }
     636             : 
     637             :                 /* Record end of the grace period in non-volatile memory. */
     638           0 :                 ospf6_gr_nvm_update(ospf6);
     639             : 
     640             :                 /*
     641             :                  * Mark that a Graceful Restart preparation is in progress, to
     642             :                  * prevent ospf6d from flushing its self-originated LSAs on
     643             :                  * exit.
     644             :                  */
     645           0 :                 ospf6->gr_info.prepare_in_progress = true;
     646             :         }
     647           0 : }
     648             : 
     649         182 : static int ospf6_gr_neighbor_change(struct ospf6_neighbor *on, int next_state,
     650             :                                     int prev_state)
     651             : {
     652         182 :         struct ospf6 *ospf6 = on->ospf6_if->area->ospf6;
     653             : 
     654         182 :         if (next_state == OSPF6_NEIGHBOR_FULL
     655          34 :             && ospf6->gr_info.restart_in_progress) {
     656           0 :                 if (ospf6_gr_check_adjs(ospf6)) {
     657           0 :                         ospf6_gr_restart_exit(
     658             :                                 ospf6, "all adjacencies were reestablished");
     659             :                 } else {
     660           0 :                         if (IS_DEBUG_OSPF6_GR)
     661           0 :                                 zlog_debug(
     662             :                                         "GR: not all adjacencies were reestablished yet");
     663             :                 }
     664             :         }
     665             : 
     666         182 :         return 0;
     667             : }
     668             : 
     669           0 : int config_write_ospf6_gr(struct vty *vty, struct ospf6 *ospf6)
     670             : {
     671           0 :         if (!ospf6->gr_info.restart_support)
     672             :                 return 0;
     673             : 
     674           0 :         if (ospf6->gr_info.grace_period == OSPF6_DFLT_GRACE_INTERVAL)
     675           0 :                 vty_out(vty, " graceful-restart\n");
     676             :         else
     677           0 :                 vty_out(vty, " graceful-restart grace-period %u\n",
     678             :                         ospf6->gr_info.grace_period);
     679             : 
     680             :         return 0;
     681             : }
     682             : 
     683           0 : DEFPY(ospf6_graceful_restart_prepare, ospf6_graceful_restart_prepare_cmd,
     684             :       "graceful-restart prepare ipv6 ospf",
     685             :       "Graceful Restart commands\n"
     686             :       "Prepare upcoming graceful restart\n" IPV6_STR
     687             :       "Prepare to restart the OSPFv3 process\n")
     688             : {
     689           0 :         ospf6_gr_prepare();
     690             : 
     691           0 :         return CMD_SUCCESS;
     692             : }
     693             : 
     694           0 : DEFPY(ospf6_graceful_restart, ospf6_graceful_restart_cmd,
     695             :       "graceful-restart [grace-period (1-1800)$grace_period]",
     696             :       OSPF_GR_STR
     697             :       "Maximum length of the 'grace period'\n"
     698             :       "Maximum length of the 'grace period' in seconds\n")
     699             : {
     700           0 :         VTY_DECLVAR_INSTANCE_CONTEXT(ospf6, ospf6);
     701             : 
     702             :         /* Check and get restart period if present. */
     703           0 :         if (!grace_period_str)
     704           0 :                 grace_period = OSPF6_DFLT_GRACE_INTERVAL;
     705             : 
     706           0 :         ospf6->gr_info.restart_support = true;
     707           0 :         ospf6->gr_info.grace_period = grace_period;
     708             : 
     709           0 :         return CMD_SUCCESS;
     710             : }
     711             : 
     712           0 : DEFPY(ospf6_no_graceful_restart, ospf6_no_graceful_restart_cmd,
     713             :       "no graceful-restart [period (1-1800)]",
     714             :       NO_STR OSPF_GR_STR
     715             :       "Maximum length of the 'grace period'\n"
     716             :       "Maximum length of the 'grace period' in seconds\n")
     717             : {
     718           0 :         VTY_DECLVAR_INSTANCE_CONTEXT(ospf6, ospf6);
     719             : 
     720           0 :         if (!ospf6->gr_info.restart_support)
     721             :                 return CMD_SUCCESS;
     722             : 
     723           0 :         if (ospf6->gr_info.prepare_in_progress) {
     724           0 :                 vty_out(vty,
     725             :                         "%% Error: Graceful Restart preparation in progress\n");
     726           0 :                 return CMD_WARNING;
     727             :         }
     728             : 
     729           0 :         ospf6->gr_info.restart_support = false;
     730           0 :         ospf6->gr_info.grace_period = OSPF6_DFLT_GRACE_INTERVAL;
     731             : 
     732           0 :         return CMD_SUCCESS;
     733             : }
     734             : 
     735          16 : void ospf6_gr_init(void)
     736             : {
     737          16 :         hook_register(ospf6_neighbor_change, ospf6_gr_neighbor_change);
     738             : 
     739          16 :         install_element(ENABLE_NODE, &ospf6_graceful_restart_prepare_cmd);
     740          16 :         install_element(OSPF6_NODE, &ospf6_graceful_restart_cmd);
     741          16 :         install_element(OSPF6_NODE, &ospf6_no_graceful_restart_cmd);
     742          16 : }

Generated by: LCOV version v1.16-topotato