Coverage Report

Created: 2025-07-14 06:48

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