back to topotato report
topotato coverage report
Current view: top level - ospfd - ospf_gr.c (source / functions) Hit Total Coverage
Test: test_ospf_topo1.py::OSPFTopo1Test Lines: 38 360 10.6 %
Date: 2023-02-24 18:38:32 Functions: 3 25 12.0 %

          Line data    Source code
       1             : /*
       2             :  * This is an implementation of RFC 3623 Graceful OSPF Restart.
       3             :  *
       4             :  * Copyright 2021 NetDEF (c), All rights reserved.
       5             :  * Copyright 2020 6WIND (c), All rights reserved.
       6             :  *
       7             :  * This program is free software; you can redistribute it and/or modify it
       8             :  * under the terms of the GNU General Public License as published by the Free
       9             :  * Software Foundation; either version 2 of the License, or (at your option)
      10             :  * any later version.
      11             :  *
      12             :  * This program is distributed in the hope that it will be useful, but WITHOUT
      13             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14             :  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
      15             :  * more details.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License along
      18             :  * with this program; see the file COPYING; if not, write to the Free Software
      19             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      20             :  */
      21             : 
      22             : #include <zebra.h>
      23             : 
      24             : #include "memory.h"
      25             : #include "command.h"
      26             : #include "table.h"
      27             : #include "vty.h"
      28             : #include "log.h"
      29             : #include "printfrr.h"
      30             : 
      31             : #include "ospfd/ospfd.h"
      32             : #include "ospfd/ospf_abr.h"
      33             : #include "ospfd/ospf_flood.h"
      34             : #include "ospfd/ospf_ism.h"
      35             : #include "ospfd/ospf_interface.h"
      36             : #include "ospfd/ospf_asbr.h"
      37             : #include "ospfd/ospf_lsa.h"
      38             : #include "ospfd/ospf_route.h"
      39             : #include "ospfd/ospf_zebra.h"
      40             : #include "ospfd/ospf_lsdb.h"
      41             : #include "ospfd/ospf_neighbor.h"
      42             : #include "ospfd/ospf_opaque.h"
      43             : #include "ospfd/ospf_nsm.h"
      44             : #include "ospfd/ospf_gr.h"
      45             : #include "ospfd/ospf_errors.h"
      46             : #include "ospfd/ospf_dump.h"
      47             : #include "ospfd/ospf_gr_clippy.c"
      48             : 
      49             : static void ospf_gr_nvm_delete(struct ospf *ospf);
      50             : 
      51             : /* Lookup self-originated Grace-LSA in the LSDB. */
      52           0 : static struct ospf_lsa *ospf_gr_lsa_lookup(struct ospf *ospf,
      53             :                                            struct ospf_area *area)
      54             : {
      55           0 :         struct ospf_lsa *lsa;
      56           0 :         struct in_addr lsa_id;
      57           0 :         uint32_t lsa_id_host_byte_order;
      58             : 
      59           0 :         lsa_id_host_byte_order = SET_OPAQUE_LSID(OPAQUE_TYPE_GRACE_LSA, 0);
      60           0 :         lsa_id.s_addr = htonl(lsa_id_host_byte_order);
      61           0 :         lsa = ospf_lsa_lookup(ospf, area, OSPF_OPAQUE_LINK_LSA, lsa_id,
      62             :                               ospf->router_id);
      63             : 
      64           0 :         return lsa;
      65             : }
      66             : 
      67             : /* Fill in fields of the Grace-LSA that is being originated. */
      68           0 : static void ospf_gr_lsa_body_set(struct ospf_gr_info *gr_info,
      69             :                                  struct ospf_interface *oi, struct stream *s)
      70             : {
      71           0 :         struct grace_tlv_graceperiod tlv_period = {};
      72           0 :         struct grace_tlv_restart_reason tlv_reason = {};
      73           0 :         struct grace_tlv_restart_addr tlv_address = {};
      74             : 
      75             :         /* Put grace period. */
      76           0 :         tlv_period.header.type = htons(GRACE_PERIOD_TYPE);
      77           0 :         tlv_period.header.length = htons(GRACE_PERIOD_LENGTH);
      78           0 :         tlv_period.interval = htonl(gr_info->grace_period);
      79           0 :         stream_put(s, &tlv_period, sizeof(tlv_period));
      80             : 
      81             :         /* Put restart reason. */
      82           0 :         tlv_reason.header.type = htons(RESTART_REASON_TYPE);
      83           0 :         tlv_reason.header.length = htons(RESTART_REASON_LENGTH);
      84           0 :         if (gr_info->restart_support)
      85           0 :                 tlv_reason.reason = OSPF_GR_SW_RESTART;
      86             :         else
      87           0 :                 tlv_reason.reason = OSPF_GR_UNKNOWN_RESTART;
      88           0 :         stream_put(s, &tlv_reason, sizeof(tlv_reason));
      89             : 
      90             :         /* Put IP address. */
      91           0 :         if (oi->type == OSPF_IFTYPE_BROADCAST || oi->type == OSPF_IFTYPE_NBMA
      92           0 :             || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) {
      93           0 :                 tlv_address.header.type = htons(RESTARTER_IP_ADDR_TYPE);
      94           0 :                 tlv_address.header.length = htons(RESTARTER_IP_ADDR_LEN);
      95           0 :                 tlv_address.addr = oi->address->u.prefix4;
      96           0 :                 stream_put(s, &tlv_address, sizeof(tlv_address));
      97             :         }
      98           0 : }
      99             : 
     100             : /* Generate Grace-LSA for a given interface. */
     101           0 : static struct ospf_lsa *ospf_gr_lsa_new(struct ospf_interface *oi)
     102             : {
     103           0 :         struct stream *s;
     104           0 :         struct lsa_header *lsah;
     105           0 :         struct ospf_lsa *new;
     106           0 :         uint8_t options, lsa_type;
     107           0 :         struct in_addr lsa_id;
     108           0 :         uint32_t lsa_id_host_byte_order;
     109           0 :         uint16_t length;
     110             : 
     111             :         /* Create a stream for LSA. */
     112           0 :         s = stream_new(OSPF_MAX_LSA_SIZE);
     113             : 
     114           0 :         lsah = (struct lsa_header *)STREAM_DATA(s);
     115             : 
     116           0 :         options = LSA_OPTIONS_GET(oi->area);
     117           0 :         options |= LSA_OPTIONS_NSSA_GET(oi->area);
     118           0 :         options |= OSPF_OPTION_O;
     119             : 
     120           0 :         lsa_type = OSPF_OPAQUE_LINK_LSA;
     121           0 :         lsa_id_host_byte_order = SET_OPAQUE_LSID(OPAQUE_TYPE_GRACE_LSA, 0);
     122           0 :         lsa_id.s_addr = htonl(lsa_id_host_byte_order);
     123             : 
     124             :         /* Set opaque-LSA header fields. */
     125           0 :         lsa_header_set(s, options, lsa_type, lsa_id, oi->ospf->router_id);
     126             : 
     127             :         /* Set opaque-LSA body fields. */
     128           0 :         ospf_gr_lsa_body_set(&oi->ospf->gr_info, oi, s);
     129             : 
     130             :         /* Set length. */
     131           0 :         length = stream_get_endp(s);
     132           0 :         lsah->length = htons(length);
     133             : 
     134             :         /* Now, create an OSPF LSA instance. */
     135           0 :         new = ospf_lsa_new_and_data(length);
     136             : 
     137           0 :         if (IS_DEBUG_OSPF_GR)
     138           0 :                 zlog_debug("LSA[Type%d:%pI4]: Create an Opaque-LSA/GR instance",
     139             :                            lsa_type, &lsa_id);
     140             : 
     141           0 :         new->area = oi->area;
     142           0 :         new->oi = oi;
     143           0 :         SET_FLAG(new->flags, OSPF_LSA_SELF);
     144           0 :         memcpy(new->data, lsah, length);
     145           0 :         stream_free(s);
     146             : 
     147           0 :         return new;
     148             : }
     149             : 
     150             : /* Originate and install Grace-LSA for a given interface. */
     151           0 : static void ospf_gr_lsa_originate(struct ospf_interface *oi, bool maxage)
     152             : {
     153           0 :         struct ospf_lsa *lsa, *old;
     154             : 
     155           0 :         if (ospf_interface_neighbor_count(oi) == 0)
     156           0 :                 return;
     157             : 
     158             :         /* Create new Grace-LSA. */
     159           0 :         lsa = ospf_gr_lsa_new(oi);
     160           0 :         if (!lsa) {
     161           0 :                 zlog_warn("%s: ospf_gr_lsa_new() failed", __func__);
     162           0 :                 return;
     163             :         }
     164             : 
     165           0 :         if (maxage)
     166           0 :                 lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
     167             : 
     168             :         /* Find the old LSA and increase the seqno. */
     169           0 :         old = ospf_gr_lsa_lookup(oi->ospf, oi->area);
     170           0 :         if (old)
     171           0 :                 lsa->data->ls_seqnum = lsa_seqnum_increment(old);
     172             : 
     173             :         /* Install this LSA into LSDB. */
     174           0 :         if (ospf_lsa_install(oi->ospf, oi, lsa) == NULL) {
     175           0 :                 zlog_warn("%s: ospf_lsa_install() failed", __func__);
     176           0 :                 ospf_lsa_unlock(&lsa);
     177           0 :                 return;
     178             :         }
     179             : 
     180             :         /* Update new LSA origination count. */
     181           0 :         oi->ospf->lsa_originate_count++;
     182             : 
     183             :         /* Flood the LSA through out the interface */
     184           0 :         ospf_flood_through_interface(oi, NULL, lsa);
     185             : }
     186             : 
     187             : /* Flush all self-originated Grace-LSAs. */
     188           0 : static void ospf_gr_flush_grace_lsas(struct ospf *ospf)
     189             : {
     190           0 :         struct ospf_area *area;
     191           0 :         struct listnode *anode;
     192             : 
     193           0 :         for (ALL_LIST_ELEMENTS_RO(ospf->areas, anode, area)) {
     194           0 :                 struct ospf_interface *oi;
     195           0 :                 struct listnode *inode;
     196             : 
     197           0 :                 if (IS_DEBUG_OSPF_GR)
     198           0 :                         zlog_debug(
     199             :                                 "GR: flushing self-originated Grace-LSAs [area %pI4]",
     200             :                                 &area->area_id);
     201             : 
     202           0 :                 for (ALL_LIST_ELEMENTS_RO(area->oiflist, inode, oi))
     203           0 :                         ospf_gr_lsa_originate(oi, true);
     204             :         }
     205           0 : }
     206             : 
     207             : /* Exit from the Graceful Restart mode. */
     208           0 : static void ospf_gr_restart_exit(struct ospf *ospf, const char *reason)
     209             : {
     210           0 :         struct ospf_area *area;
     211           0 :         struct listnode *onode, *anode;
     212             : 
     213           0 :         if (IS_DEBUG_OSPF_GR)
     214           0 :                 zlog_debug("GR: exiting graceful restart: %s", reason);
     215             : 
     216           0 :         ospf->gr_info.restart_in_progress = false;
     217           0 :         THREAD_OFF(ospf->gr_info.t_grace_period);
     218             : 
     219             :         /* Record in non-volatile memory that the restart is complete. */
     220           0 :         ospf_gr_nvm_delete(ospf);
     221             : 
     222           0 :         for (ALL_LIST_ELEMENTS_RO(ospf->areas, onode, area)) {
     223           0 :                 struct ospf_interface *oi;
     224             : 
     225             :                 /*
     226             :                  * 1) The router should reoriginate its router-LSAs for all
     227             :                  *    attached areas in order to make sure they have the correct
     228             :                  *    contents.
     229             :                  */
     230           0 :                 ospf_router_lsa_update_area(area);
     231             : 
     232             :                 /*
     233             :                  * 2) The router should reoriginate network-LSAs on all segments
     234             :                  *    where it is the Designated Router.
     235             :                  */
     236           0 :                 for (ALL_LIST_ELEMENTS_RO(area->oiflist, anode, oi))
     237           0 :                         if (oi->state == ISM_DR)
     238           0 :                                 ospf_network_lsa_update(oi);
     239             :         }
     240             : 
     241             :         /*
     242             :          * 5) Any received self-originated LSAs that are no longer valid should
     243             :          *    be flushed.
     244             :          */
     245           0 :         ospf_schedule_abr_task(ospf);
     246             : 
     247             :         /*
     248             :          * 3) The router reruns its OSPF routing calculations, this time
     249             :          *    installing the results into the system forwarding table, and
     250             :          *    originating summary-LSAs, Type-7 LSAs and AS-external-LSAs as
     251             :          *    necessary.
     252             :          *
     253             :          * 4) Any remnant entries in the system forwarding table that were
     254             :          *    installed before the restart, but that are no longer valid,
     255             :          *    should be removed.
     256             :          */
     257           0 :         ospf->gr_info.finishing_restart = true;
     258           0 :         ospf_spf_calculate_schedule(ospf, SPF_FLAG_GR_FINISH);
     259             : 
     260             :         /* 6) Any grace-LSAs that the router originated should be flushed. */
     261           0 :         ospf_gr_flush_grace_lsas(ospf);
     262           0 : }
     263             : 
     264             : /* Check if a Router-LSA contains a given link. */
     265           0 : static bool ospf_router_lsa_contains_adj(struct ospf_lsa *lsa,
     266             :                                          struct in_addr *id)
     267             : {
     268           0 :         struct router_lsa *rl;
     269             : 
     270           0 :         rl = (struct router_lsa *)lsa->data;
     271           0 :         for (int i = 0; i < ntohs(rl->links); i++) {
     272           0 :                 struct in_addr *link_id = &rl->link[i].link_id;
     273             : 
     274           0 :                 if (rl->link[i].type != LSA_LINK_TYPE_POINTOPOINT)
     275           0 :                         continue;
     276             : 
     277           0 :                 if (IPV4_ADDR_SAME(id, link_id))
     278             :                         return true;
     279             :         }
     280             : 
     281             :         return false;
     282             : }
     283             : 
     284           0 : static bool ospf_gr_check_router_lsa_consistency(struct ospf *ospf,
     285             :                                                  struct ospf_area *area,
     286             :                                                  struct ospf_lsa *lsa)
     287             : {
     288           0 :         if (CHECK_FLAG(lsa->flags, OSPF_LSA_SELF)) {
     289           0 :                 struct ospf_lsa *lsa_self = lsa;
     290           0 :                 struct router_lsa *rl = (struct router_lsa *)lsa->data;
     291             : 
     292           0 :                 for (int i = 0; i < ntohs(rl->links); i++) {
     293           0 :                         struct in_addr *link_id = &rl->link[i].link_id;
     294           0 :                         struct ospf_lsa *lsa_adj;
     295             : 
     296           0 :                         if (rl->link[i].type != LSA_LINK_TYPE_POINTOPOINT)
     297           0 :                                 continue;
     298             : 
     299           0 :                         lsa_adj = ospf_lsa_lookup_by_id(area, OSPF_ROUTER_LSA,
     300             :                                                         *link_id);
     301           0 :                         if (!lsa_adj)
     302           0 :                                 continue;
     303             : 
     304           0 :                         if (!ospf_router_lsa_contains_adj(lsa_adj,
     305           0 :                                                           &lsa_self->data->id))
     306             :                                 return false;
     307             :                 }
     308             :         } else {
     309           0 :                 struct ospf_lsa *lsa_self;
     310             : 
     311           0 :                 lsa_self = ospf_lsa_lookup_by_id(area, OSPF_ROUTER_LSA,
     312             :                                                  ospf->router_id);
     313           0 :                 if (!lsa_self
     314           0 :                     || !CHECK_FLAG(lsa_self->flags, OSPF_LSA_RECEIVED))
     315             :                         return true;
     316             : 
     317           0 :                 if (ospf_router_lsa_contains_adj(lsa, &ospf->router_id)
     318           0 :                     != ospf_router_lsa_contains_adj(lsa_self, &lsa->data->id))
     319             :                         return false;
     320             :         }
     321             : 
     322             :         return true;
     323             : }
     324             : 
     325             : /*
     326             :  * Check for LSAs that are inconsistent with the pre-restart LSAs, and abort the
     327             :  * ongoing graceful restart when that's the case.
     328             :  */
     329           0 : void ospf_gr_check_lsdb_consistency(struct ospf *ospf, struct ospf_area *area)
     330             : {
     331           0 :         struct route_node *rn;
     332           0 :         struct ospf_lsa *lsa;
     333             : 
     334           0 :         for (rn = route_top(ROUTER_LSDB(area)); rn; rn = route_next(rn)) {
     335           0 :                 lsa = rn->info;
     336           0 :                 if (!lsa)
     337           0 :                         continue;
     338             : 
     339           0 :                 if (!ospf_gr_check_router_lsa_consistency(ospf, area, lsa)) {
     340           0 :                         char reason[256];
     341             : 
     342           0 :                         snprintfrr(reason, sizeof(reason),
     343             :                                    "detected inconsistent LSA[%s] [area %pI4]",
     344             :                                    dump_lsa_key(lsa), &area->area_id);
     345           0 :                         ospf_gr_restart_exit(ospf, reason);
     346           0 :                         route_unlock_node(rn);
     347           0 :                         return;
     348             :                 }
     349             :         }
     350             : }
     351             : 
     352             : /* Lookup neighbor by address in a given OSPF area. */
     353             : static struct ospf_neighbor *
     354           0 : ospf_area_nbr_lookup_by_addr(struct ospf_area *area, struct in_addr *addr)
     355             : {
     356           0 :         struct ospf_interface *oi;
     357           0 :         struct ospf_neighbor *nbr;
     358           0 :         struct listnode *node;
     359             : 
     360           0 :         for (ALL_LIST_ELEMENTS_RO(area->oiflist, node, oi)) {
     361           0 :                 nbr = ospf_nbr_lookup_by_addr(oi->nbrs, addr);
     362           0 :                 if (nbr)
     363           0 :                         return nbr;
     364             :         }
     365             : 
     366             :         return NULL;
     367             : }
     368             : 
     369             : /* Lookup neighbor by Router ID in a given OSPF area. */
     370             : static struct ospf_neighbor *
     371           0 : ospf_area_nbr_lookup_by_routerid(struct ospf_area *area, struct in_addr *id)
     372             : {
     373           0 :         struct ospf_interface *oi;
     374           0 :         struct ospf_neighbor *nbr;
     375           0 :         struct listnode *node;
     376             : 
     377           0 :         for (ALL_LIST_ELEMENTS_RO(area->oiflist, node, oi)) {
     378           0 :                 nbr = ospf_nbr_lookup_by_routerid(oi->nbrs, id);
     379           0 :                 if (nbr)
     380           0 :                         return nbr;
     381             :         }
     382             : 
     383             :         return NULL;
     384             : }
     385             : 
     386             : /* Check if there's a fully formed adjacency with the given neighbor ID. */
     387           0 : static bool ospf_gr_check_adj_id(struct ospf_area *area,
     388             :                                  struct in_addr *nbr_id)
     389             : {
     390           0 :         struct ospf_neighbor *nbr;
     391             : 
     392           0 :         nbr = ospf_area_nbr_lookup_by_routerid(area, nbr_id);
     393           0 :         if (!nbr || nbr->state < NSM_Full) {
     394           0 :                 if (IS_DEBUG_OSPF_GR)
     395           0 :                         zlog_debug("GR: missing adjacency to router %pI4",
     396             :                                    nbr_id);
     397           0 :                 return false;
     398             :         }
     399             : 
     400             :         return true;
     401             : }
     402             : 
     403           0 : static bool ospf_gr_check_adjs_lsa_transit(struct ospf_area *area,
     404             :                                            struct in_addr *link_id)
     405             : {
     406           0 :         struct ospf *ospf = area->ospf;
     407           0 :         struct ospf_interface *oi;
     408             : 
     409             :         /*
     410             :          * Check if the transit network refers to a local interface (in which
     411             :          * case it must be a DR for that network).
     412             :          */
     413           0 :         oi = ospf_if_lookup_by_local_addr(ospf, NULL, *link_id);
     414           0 :         if (oi) {
     415           0 :                 struct ospf_lsa *lsa;
     416           0 :                 struct network_lsa *nlsa;
     417           0 :                 size_t cnt;
     418             : 
     419             :                 /* Lookup Network LSA corresponding to this interface. */
     420           0 :                 lsa = ospf_lsa_lookup_by_id(area, OSPF_NETWORK_LSA, *link_id);
     421           0 :                 if (!lsa)
     422             :                         return false;
     423             : 
     424             :                 /* Iterate over all routers present in the network. */
     425           0 :                 nlsa = (struct network_lsa *)lsa->data;
     426           0 :                 cnt = (lsa->size - (OSPF_LSA_HEADER_SIZE + 4)) / 4;
     427           0 :                 for (size_t i = 0; i < cnt; i++) {
     428           0 :                         struct in_addr *nbr_id = &nlsa->routers[i];
     429             : 
     430             :                         /* Skip self in the pseudonode. */
     431           0 :                         if (IPV4_ADDR_SAME(nbr_id, &ospf->router_id))
     432           0 :                                 continue;
     433             : 
     434             :                         /*
     435             :                          * Check if there's a fully formed adjacency with this
     436             :                          * router.
     437             :                          */
     438           0 :                         if (!ospf_gr_check_adj_id(area, nbr_id))
     439             :                                 return false;
     440             :                 }
     441             :         } else {
     442           0 :                 struct ospf_neighbor *nbr;
     443             : 
     444             :                 /* Check if there's a fully formed adjacency with the DR. */
     445           0 :                 nbr = ospf_area_nbr_lookup_by_addr(area, link_id);
     446           0 :                 if (!nbr || nbr->state < NSM_Full) {
     447           0 :                         if (IS_DEBUG_OSPF_GR)
     448           0 :                                 zlog_debug(
     449             :                                         "GR: missing adjacency to DR router %pI4",
     450             :                                         link_id);
     451           0 :                         return false;
     452             :                 }
     453             :         }
     454             : 
     455             :         return true;
     456             : }
     457             : 
     458           0 : static bool ospf_gr_check_adjs_lsa(struct ospf_area *area, struct ospf_lsa *lsa)
     459             : {
     460           0 :         struct router_lsa *rl = (struct router_lsa *)lsa->data;
     461             : 
     462           0 :         for (int i = 0; i < ntohs(rl->links); i++) {
     463           0 :                 struct in_addr *link_id = &rl->link[i].link_id;
     464             : 
     465           0 :                 switch (rl->link[i].type) {
     466           0 :                 case LSA_LINK_TYPE_POINTOPOINT:
     467           0 :                         if (!ospf_gr_check_adj_id(area, link_id))
     468             :                                 return false;
     469             :                         break;
     470           0 :                 case LSA_LINK_TYPE_TRANSIT:
     471           0 :                         if (!ospf_gr_check_adjs_lsa_transit(area, link_id))
     472             :                                 return false;
     473             :                         break;
     474             :                 default:
     475             :                         break;
     476             :                 }
     477             :         }
     478             : 
     479             :         return true;
     480             : }
     481             : 
     482             : /*
     483             :  * Check if all adjacencies prior to the restart were reestablished.
     484             :  *
     485             :  * This is done using pre-restart Router LSAs and pre-restart Network LSAs
     486             :  * received from the helping neighbors.
     487             :  */
     488           0 : void ospf_gr_check_adjs(struct ospf *ospf)
     489             : {
     490           0 :         struct ospf_area *area;
     491           0 :         struct listnode *node;
     492             : 
     493           0 :         for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) {
     494           0 :                 struct ospf_lsa *lsa_self;
     495             : 
     496           0 :                 lsa_self = ospf_lsa_lookup_by_id(area, OSPF_ROUTER_LSA,
     497             :                                                  ospf->router_id);
     498           0 :                 if (!lsa_self || !ospf_gr_check_adjs_lsa(area, lsa_self)) {
     499           0 :                         if (IS_DEBUG_OSPF_GR)
     500           0 :                                 zlog_debug(
     501             :                                         "GR: not all adjacencies were reestablished yet [area %pI4]",
     502             :                                         &area->area_id);
     503           0 :                         return;
     504             :                 }
     505             :         }
     506             : 
     507           0 :         ospf_gr_restart_exit(ospf, "all adjacencies were reestablished");
     508             : }
     509             : 
     510             : /* Handling of grace period expiry. */
     511           0 : static void ospf_gr_grace_period_expired(struct thread *thread)
     512             : {
     513           0 :         struct ospf *ospf = THREAD_ARG(thread);
     514             : 
     515           0 :         ospf->gr_info.t_grace_period = NULL;
     516           0 :         ospf_gr_restart_exit(ospf, "grace period has expired");
     517           0 : }
     518             : 
     519             : /*
     520             :  * Returns the path of the file (non-volatile memory) that contains GR status
     521             :  * information.
     522             :  */
     523           4 : static char *ospf_gr_nvm_filepath(struct ospf *ospf)
     524             : {
     525           4 :         static char filepath[MAXPATHLEN];
     526           4 :         char instance[16] = "";
     527             : 
     528           4 :         if (ospf->instance)
     529           0 :                 snprintf(instance, sizeof(instance), "-%d", ospf->instance);
     530           4 :         snprintf(filepath, sizeof(filepath), OSPFD_GR_STATE, instance);
     531           4 :         return filepath;
     532             : }
     533             : 
     534             : /*
     535             :  * Record in non-volatile memory that the given OSPF instance is attempting to
     536             :  * perform a graceful restart.
     537             :  */
     538           0 : static void ospf_gr_nvm_update(struct ospf *ospf)
     539             : {
     540           0 :         char *filepath;
     541           0 :         const char *inst_name;
     542           0 :         json_object *json;
     543           0 :         json_object *json_instances;
     544           0 :         json_object *json_instance;
     545             : 
     546           0 :         filepath = ospf_gr_nvm_filepath(ospf);
     547           0 :         inst_name = ospf_get_name(ospf);
     548             : 
     549           0 :         json = json_object_from_file(filepath);
     550           0 :         if (json == NULL)
     551           0 :                 json = json_object_new_object();
     552             : 
     553           0 :         json_object_object_get_ex(json, "instances", &json_instances);
     554           0 :         if (!json_instances) {
     555           0 :                 json_instances = json_object_new_object();
     556           0 :                 json_object_object_add(json, "instances", json_instances);
     557             :         }
     558             : 
     559           0 :         json_object_object_get_ex(json_instances, inst_name, &json_instance);
     560           0 :         if (!json_instance) {
     561           0 :                 json_instance = json_object_new_object();
     562           0 :                 json_object_object_add(json_instances, inst_name,
     563             :                                        json_instance);
     564             :         }
     565             : 
     566             :         /*
     567             :          * Record not only the grace period, but also a UNIX timestamp
     568             :          * corresponding to the end of that period. That way, once ospfd is
     569             :          * restarted, it will be possible to take into account the time that
     570             :          * passed while ospfd wasn't running.
     571             :          */
     572           0 :         json_object_int_add(json_instance, "gracePeriod",
     573           0 :                             ospf->gr_info.grace_period);
     574           0 :         json_object_int_add(json_instance, "timestamp",
     575           0 :                             time(NULL) + ospf->gr_info.grace_period);
     576             : 
     577           0 :         json_object_to_file_ext(filepath, json, JSON_C_TO_STRING_PRETTY);
     578           0 :         json_object_free(json);
     579           0 : }
     580             : 
     581             : /*
     582             :  * Delete GR status information about the given OSPF instance from non-volatile
     583             :  * memory.
     584             :  */
     585           0 : static void ospf_gr_nvm_delete(struct ospf *ospf)
     586             : {
     587           0 :         char *filepath;
     588           0 :         const char *inst_name;
     589           0 :         json_object *json;
     590           0 :         json_object *json_instances;
     591             : 
     592           0 :         filepath = ospf_gr_nvm_filepath(ospf);
     593           0 :         inst_name = ospf_get_name(ospf);
     594             : 
     595           0 :         json = json_object_from_file(filepath);
     596           0 :         if (json == NULL)
     597           0 :                 json = json_object_new_object();
     598             : 
     599           0 :         json_object_object_get_ex(json, "instances", &json_instances);
     600           0 :         if (!json_instances) {
     601           0 :                 json_instances = json_object_new_object();
     602           0 :                 json_object_object_add(json, "instances", json_instances);
     603             :         }
     604             : 
     605           0 :         json_object_object_del(json_instances, inst_name);
     606             : 
     607           0 :         json_object_to_file_ext(filepath, json, JSON_C_TO_STRING_PRETTY);
     608           0 :         json_object_free(json);
     609           0 : }
     610             : 
     611             : /*
     612             :  * Fetch from non-volatile memory whether the given OSPF instance is performing
     613             :  * a graceful shutdown or not.
     614             :  */
     615           4 : void ospf_gr_nvm_read(struct ospf *ospf)
     616             : {
     617           4 :         char *filepath;
     618           4 :         const char *inst_name;
     619           4 :         json_object *json;
     620           4 :         json_object *json_instances;
     621           4 :         json_object *json_instance;
     622           4 :         json_object *json_timestamp;
     623           4 :         time_t timestamp = 0;
     624             : 
     625           4 :         filepath = ospf_gr_nvm_filepath(ospf);
     626           4 :         inst_name = ospf_get_name(ospf);
     627             : 
     628           4 :         json = json_object_from_file(filepath);
     629           4 :         if (json == NULL)
     630           4 :                 json = json_object_new_object();
     631             : 
     632           4 :         json_object_object_get_ex(json, "instances", &json_instances);
     633           4 :         if (!json_instances) {
     634           4 :                 json_instances = json_object_new_object();
     635           4 :                 json_object_object_add(json, "instances", json_instances);
     636             :         }
     637             : 
     638           4 :         json_object_object_get_ex(json_instances, inst_name, &json_instance);
     639           4 :         if (!json_instance) {
     640           4 :                 json_instance = json_object_new_object();
     641           4 :                 json_object_object_add(json_instances, inst_name,
     642             :                                        json_instance);
     643             :         }
     644             : 
     645           4 :         json_object_object_get_ex(json_instance, "timestamp", &json_timestamp);
     646           4 :         if (json_timestamp) {
     647           0 :                 time_t now;
     648           0 :                 unsigned long remaining_time;
     649             : 
     650             :                 /* Check if the grace period has already expired. */
     651           0 :                 now = time(NULL);
     652           0 :                 timestamp = json_object_get_int(json_timestamp);
     653           0 :                 if (now > timestamp) {
     654           0 :                         ospf_gr_restart_exit(
     655             :                                 ospf, "grace period has expired already");
     656             :                 } else {
     657             :                         /* Schedule grace period timeout. */
     658           0 :                         ospf->gr_info.restart_in_progress = true;
     659           0 :                         remaining_time = timestamp - time(NULL);
     660           0 :                         if (IS_DEBUG_OSPF_GR)
     661           0 :                                 zlog_debug(
     662             :                                         "GR: remaining time until grace period expires: %lu(s)",
     663             :                                         remaining_time);
     664           0 :                         thread_add_timer(master, ospf_gr_grace_period_expired,
     665             :                                          ospf, remaining_time,
     666             :                                          &ospf->gr_info.t_grace_period);
     667             :                 }
     668             :         }
     669             : 
     670           4 :         json_object_object_del(json_instances, inst_name);
     671             : 
     672           4 :         json_object_to_file_ext(filepath, json, JSON_C_TO_STRING_PRETTY);
     673           4 :         json_object_free(json);
     674           4 : }
     675             : 
     676             : /* Prepare to start a Graceful Restart. */
     677           0 : static void ospf_gr_prepare(void)
     678             : {
     679           0 :         struct ospf *ospf;
     680           0 :         struct ospf_interface *oi;
     681           0 :         struct listnode *onode;
     682             : 
     683           0 :         for (ALL_LIST_ELEMENTS_RO(om->ospf, onode, ospf)) {
     684           0 :                 struct listnode *inode;
     685             : 
     686           0 :                 if (!ospf->gr_info.restart_support
     687           0 :                     || ospf->gr_info.prepare_in_progress)
     688           0 :                         continue;
     689             : 
     690           0 :                 if (IS_DEBUG_OSPF_GR)
     691           0 :                         zlog_debug(
     692             :                                 "GR: preparing to perform a graceful restart [period %u second(s)] [vrf %s]",
     693             :                                 ospf->gr_info.grace_period,
     694             :                                 ospf_vrf_id_to_name(ospf->vrf_id));
     695             : 
     696           0 :                 if (!CHECK_FLAG(ospf->config, OSPF_OPAQUE_CAPABLE)) {
     697           0 :                         zlog_warn(
     698             :                                 "%s: failed to activate graceful restart: opaque capability not enabled",
     699             :                                 __func__);
     700           0 :                         continue;
     701             :                 }
     702             : 
     703             :                 /* Freeze OSPF routes in the RIB. */
     704           0 :                 if (ospf_zebra_gr_enable(ospf, ospf->gr_info.grace_period)) {
     705           0 :                         zlog_warn(
     706             :                                 "%s: failed to activate graceful restart: not connected to zebra",
     707             :                                 __func__);
     708           0 :                         continue;
     709             :                 }
     710             : 
     711             :                 /* Send a Grace-LSA to all neighbors. */
     712           0 :                 for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, inode, oi))
     713           0 :                         ospf_gr_lsa_originate(oi, false);
     714             : 
     715             :                 /* Record end of the grace period in non-volatile memory. */
     716           0 :                 ospf_gr_nvm_update(ospf);
     717             : 
     718             :                 /*
     719             :                  * Mark that a Graceful Restart preparation is in progress, to
     720             :                  * prevent ospfd from flushing its self-originated LSAs on exit.
     721             :                  */
     722           0 :                 ospf->gr_info.prepare_in_progress = true;
     723             :         }
     724           0 : }
     725             : 
     726           0 : DEFPY(graceful_restart_prepare, graceful_restart_prepare_cmd,
     727             :       "graceful-restart prepare ip ospf",
     728             :       "Graceful Restart commands\n"
     729             :       "Prepare upcoming graceful restart\n"
     730             :       IP_STR
     731             :       "Prepare to restart the OSPF process\n")
     732             : {
     733           0 :         struct ospf *ospf;
     734           0 :         struct listnode *node;
     735             : 
     736           0 :         for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
     737           0 :                 if (!CHECK_FLAG(ospf->config, OSPF_OPAQUE_CAPABLE)) {
     738           0 :                         vty_out(vty,
     739             :                                 "%% Can't start graceful restart: opaque capability not enabled (VRF %s)\n\n",
     740             :                                 ospf_get_name(ospf));
     741           0 :                         return CMD_WARNING;
     742             :                 }
     743             :         }
     744             : 
     745           0 :         ospf_gr_prepare();
     746             : 
     747           0 :         return CMD_SUCCESS;
     748             : }
     749             : 
     750           0 : DEFPY(graceful_restart, graceful_restart_cmd,
     751             :       "graceful-restart [grace-period (1-1800)$grace_period]",
     752             :       OSPF_GR_STR
     753             :       "Maximum length of the 'grace period'\n"
     754             :       "Maximum length of the 'grace period' in seconds\n")
     755             : {
     756           0 :         VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
     757             : 
     758             :         /* Check and get restart period if present. */
     759           0 :         if (!grace_period_str)
     760           0 :                 grace_period = OSPF_DFLT_GRACE_INTERVAL;
     761             : 
     762           0 :         ospf->gr_info.restart_support = true;
     763           0 :         ospf->gr_info.grace_period = grace_period;
     764             : 
     765           0 :         return CMD_SUCCESS;
     766             : }
     767             : 
     768           0 : DEFPY(no_graceful_restart, no_graceful_restart_cmd,
     769             :       "no graceful-restart [grace-period (1-1800)]",
     770             :       NO_STR OSPF_GR_STR
     771             :       "Maximum length of the 'grace period'\n"
     772             :       "Maximum length of the 'grace period' in seconds\n")
     773             : {
     774           0 :         VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
     775             : 
     776           0 :         if (!ospf->gr_info.restart_support)
     777             :                 return CMD_SUCCESS;
     778             : 
     779           0 :         if (ospf->gr_info.prepare_in_progress) {
     780           0 :                 vty_out(vty,
     781             :                         "%% Error: Graceful Restart preparation in progress\n");
     782           0 :                 return CMD_WARNING;
     783             :         }
     784             : 
     785           0 :         ospf->gr_info.restart_support = false;
     786           0 :         ospf->gr_info.grace_period = OSPF_DFLT_GRACE_INTERVAL;
     787             : 
     788           0 :         return CMD_SUCCESS;
     789             : }
     790             : 
     791           4 : void ospf_gr_init(void)
     792             : {
     793           4 :         install_element(ENABLE_NODE, &graceful_restart_prepare_cmd);
     794           4 :         install_element(OSPF_NODE, &graceful_restart_cmd);
     795           4 :         install_element(OSPF_NODE, &no_graceful_restart_cmd);
     796           4 : }

Generated by: LCOV version v1.16-topotato