Coverage Report

Created: 2025-08-03 06:36

/src/frr/ospfd/ospf_gr_helper.c
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * OSPF Graceful Restart helper functions.
4
 *
5
 * Copyright (C) 2020-21 Vmware, Inc.
6
 * Rajesh Kumar Girada
7
 */
8
9
#include <zebra.h>
10
11
#include "frrevent.h"
12
#include "memory.h"
13
#include "linklist.h"
14
#include "prefix.h"
15
#include "if.h"
16
#include "table.h"
17
#include "vty.h"
18
#include "filter.h"
19
#include "log.h"
20
#include "jhash.h"
21
22
#include "ospfd/ospfd.h"
23
#include "ospfd/ospf_interface.h"
24
#include "ospfd/ospf_asbr.h"
25
#include "ospfd/ospf_lsa.h"
26
#include "ospfd/ospf_lsdb.h"
27
#include "ospfd/ospf_neighbor.h"
28
#include "ospfd/ospf_spf.h"
29
#include "ospfd/ospf_flood.h"
30
#include "ospfd/ospf_route.h"
31
#include "ospfd/ospf_zebra.h"
32
#include "ospfd/ospf_dump.h"
33
#include "ospfd/ospf_errors.h"
34
#include "ospfd/ospf_nsm.h"
35
#include "ospfd/ospf_ism.h"
36
#include "ospfd/ospf_gr.h"
37
38
static const char * const ospf_exit_reason_desc[] = {
39
  "Unknown reason",
40
  "Helper in progress",
41
  "Topology Change",
42
  "Grace timer expiry",
43
  "Successful graceful restart",
44
};
45
46
static const char * const ospf_restart_reason_desc[] = {
47
  "Unknown restart",
48
  "Software restart",
49
  "Software reload/upgrade",
50
  "Switch to redundant control processor",
51
};
52
53
static const char * const ospf_rejected_reason_desc[] = {
54
  "Unknown reason",
55
  "Helper support disabled",
56
  "Neighbour is not in FULL state",
57
  "Supports only planned restart but received unplanned",
58
  "Topo change due to change in lsa rxmt list",
59
  "LSA age is more than Grace interval",
60
  "Router is in the process of graceful restart",
61
};
62
63
static void show_ospf_grace_lsa_info(struct vty *vty, struct json_object *json,
64
             struct ospf_lsa *lsa);
65
static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr);
66
67
static unsigned int ospf_enable_rtr_hash_key(const void *data)
68
0
{
69
0
  const struct advRtr *rtr = data;
70
71
0
  return jhash_1word(rtr->advRtrAddr.s_addr, 0);
72
0
}
73
74
static bool ospf_enable_rtr_hash_cmp(const void *d1, const void *d2)
75
0
{
76
0
  const struct advRtr *rtr1 = (struct advRtr *)d1;
77
0
  const struct advRtr *rtr2 = (struct advRtr *)d2;
78
79
0
  return (rtr1->advRtrAddr.s_addr == rtr2->advRtrAddr.s_addr);
80
0
}
81
82
static void *ospf_enable_rtr_hash_alloc(void *p)
83
0
{
84
0
  struct advRtr *rid;
85
86
0
  rid = XCALLOC(MTYPE_OSPF_GR_HELPER, sizeof(struct advRtr));
87
0
  rid->advRtrAddr.s_addr = ((struct in_addr *)p)->s_addr;
88
89
0
  return rid;
90
0
}
91
92
static void ospf_disable_rtr_hash_free(void *rtr)
93
0
{
94
0
  XFREE(MTYPE_OSPF_GR_HELPER, rtr);
95
0
}
96
97
static void ospf_enable_rtr_hash_destroy(struct ospf *ospf)
98
0
{
99
0
  if (ospf->enable_rtr_list == NULL)
100
0
    return;
101
102
0
  hash_clean_and_free(&ospf->enable_rtr_list, ospf_disable_rtr_hash_free);
103
0
}
104
105
/*
106
 * GR exit reason strings
107
 */
108
const char *ospf_exit_reason2str(unsigned int reason)
109
0
{
110
0
  if (reason < array_size(ospf_exit_reason_desc))
111
0
    return(ospf_exit_reason_desc[reason]);
112
0
  else
113
0
    return "Invalid reason";
114
0
}
115
116
/*
117
 * GR restart reason strings
118
 */
119
const char *ospf_restart_reason2str(unsigned int reason)
120
0
{
121
0
  if (reason < array_size(ospf_restart_reason_desc))
122
0
    return(ospf_restart_reason_desc[reason]);
123
0
  else
124
0
    return "Invalid reason";
125
0
}
126
127
/*
128
 * GR rejected reason strings
129
 */
130
const char *ospf_rejected_reason2str(unsigned int reason)
131
0
{
132
0
  if (reason < array_size(ospf_rejected_reason_desc))
133
0
    return(ospf_rejected_reason_desc[reason]);
134
0
  else
135
0
    return "Invalid reason";
136
0
}
137
138
/*
139
 * Initialize GR helper config data structures.
140
 *
141
 * OSPF
142
 *    OSPF pointer
143
 *
144
 * Returns:
145
 *    Nothing
146
 */
147
void ospf_gr_helper_instance_init(struct ospf *ospf)
148
1
{
149
1
  if (IS_DEBUG_OSPF_GR)
150
0
    zlog_debug("%s, GR Helper init.", __func__);
151
152
1
  ospf->is_helper_supported = OSPF_GR_FALSE;
153
1
  ospf->strict_lsa_check = OSPF_GR_TRUE;
154
1
  ospf->only_planned_restart = OSPF_GR_FALSE;
155
1
  ospf->supported_grace_time = OSPF_MAX_GRACE_INTERVAL;
156
1
  ospf->last_exit_reason = OSPF_GR_HELPER_EXIT_NONE;
157
1
  ospf->active_restarter_cnt = 0;
158
159
1
  ospf->enable_rtr_list =
160
1
    hash_create(ospf_enable_rtr_hash_key, ospf_enable_rtr_hash_cmp,
161
1
          "OSPF enable router hash");
162
1
}
163
164
/*
165
 * De-Initialize GR helper config data structures.
166
 *
167
 * OSPF
168
 *    OSPF pointer
169
 *
170
 * Returns:
171
 *    Nothing
172
 */
173
void ospf_gr_helper_instance_stop(struct ospf *ospf)
174
0
{
175
0
  if (IS_DEBUG_OSPF_GR)
176
0
    zlog_debug("%s, GR helper deinit.", __func__);
177
178
0
  ospf_enable_rtr_hash_destroy(ospf);
179
0
}
180
181
/*
182
 * Initialize GR helper config data structures.
183
 *
184
 * Returns:
185
 *    Nothing
186
 */
187
void ospf_gr_helper_init(void)
188
0
{
189
0
  int rc;
190
191
0
  if (IS_DEBUG_OSPF_GR)
192
0
    zlog_debug("%s, GR Helper init.", __func__);
193
194
0
  rc = ospf_register_opaque_functab(
195
0
    OSPF_OPAQUE_LINK_LSA, OPAQUE_TYPE_GRACE_LSA, NULL, NULL, NULL,
196
0
    NULL, NULL, NULL, NULL, show_ospf_grace_lsa_info, NULL, NULL,
197
0
    NULL, NULL);
198
0
  if (rc != 0) {
199
0
    flog_warn(EC_OSPF_OPAQUE_REGISTRATION,
200
0
        "%s: Failed to register Grace LSA functions",
201
0
        __func__);
202
0
  }
203
0
}
204
205
/*
206
 * De-Initialize GR helper config data structures.
207
 *
208
 * Returns:
209
 *    Nothing
210
 */
211
void ospf_gr_helper_stop(void)
212
0
{
213
0
  if (IS_DEBUG_OSPF_GR)
214
0
    zlog_debug("%s, GR helper deinit.", __func__);
215
216
0
  ospf_delete_opaque_functab(OSPF_OPAQUE_LINK_LSA, OPAQUE_TYPE_GRACE_LSA);
217
0
}
218
219
/*
220
 * Extracting tlv info from GRACE LSA.
221
 *
222
 * lsa
223
 *   ospf grace lsa
224
 *
225
 * Returns:
226
 * interval : grace interval.
227
 * addr     : RESTARTER address.
228
 * reason   : Restarting reason.
229
 */
230
static int ospf_extract_grace_lsa_fields(struct ospf_lsa *lsa,
231
           uint32_t *interval,
232
           struct in_addr *addr, uint8_t *reason)
233
369
{
234
369
  struct lsa_header *lsah = NULL;
235
369
  struct tlv_header *tlvh = NULL;
236
369
  struct grace_tlv_graceperiod *grace_period;
237
369
  struct grace_tlv_restart_reason *gr_reason;
238
369
  struct grace_tlv_restart_addr *restart_addr;
239
369
  uint16_t length = 0;
240
369
  int sum = 0;
241
242
369
  lsah = (struct lsa_header *)lsa->data;
243
244
  /* Check LSA len */
245
369
  if (lsa->size <= OSPF_LSA_HEADER_SIZE) {
246
8
    if (IS_DEBUG_OSPF_GR)
247
0
      zlog_debug("%s: Malformed packet: Invalid LSA len:%d",
248
8
           __func__, length);
249
8
    return OSPF_GR_FAILURE;
250
8
  }
251
252
361
  length = lsa->size - OSPF_LSA_HEADER_SIZE;
253
254
503
  for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
255
502
       tlvh = TLV_HDR_NEXT(tlvh)) {
256
257
    /* Check TLV len against overall LSA */
258
502
    if (sum + TLV_SIZE(tlvh) > length) {
259
144
      if (IS_DEBUG_OSPF_GR)
260
0
        zlog_debug("%s: Malformed packet: Invalid TLV len:%u",
261
144
             __func__, TLV_SIZE(tlvh));
262
144
      return OSPF_GR_FAILURE;
263
144
    }
264
265
358
    switch (ntohs(tlvh->type)) {
266
49
    case GRACE_PERIOD_TYPE:
267
49
      if (TLV_SIZE(tlvh) <
268
49
          sizeof(struct grace_tlv_graceperiod)) {
269
38
        zlog_debug("%s: Malformed packet: Invalid grace TLV len:%u",
270
38
             __func__, TLV_SIZE(tlvh));
271
38
        return OSPF_GR_FAILURE;
272
38
      }
273
274
11
      grace_period = (struct grace_tlv_graceperiod *)tlvh;
275
11
      *interval = ntohl(grace_period->interval);
276
11
      sum += TLV_SIZE(tlvh);
277
278
      /* Check if grace interval is valid */
279
11
      if (*interval > OSPF_MAX_GRACE_INTERVAL
280
11
          || *interval < OSPF_MIN_GRACE_INTERVAL)
281
11
        return OSPF_GR_FAILURE;
282
0
      break;
283
221
    case RESTART_REASON_TYPE:
284
221
      if (TLV_SIZE(tlvh) <
285
221
          sizeof(struct grace_tlv_restart_reason)) {
286
121
        zlog_debug("%s: Malformed packet: Invalid reason TLV len:%u",
287
121
             __func__, TLV_SIZE(tlvh));
288
121
        return OSPF_GR_FAILURE;
289
121
      }
290
291
100
      gr_reason = (struct grace_tlv_restart_reason *)tlvh;
292
100
      *reason = gr_reason->reason;
293
100
      sum += TLV_SIZE(tlvh);
294
295
100
      if (*reason >= OSPF_GR_INVALID_REASON_CODE)
296
3
        return OSPF_GR_FAILURE;
297
97
      break;
298
97
    case RESTARTER_IP_ADDR_TYPE:
299
87
      if (TLV_SIZE(tlvh) <
300
87
          sizeof(struct grace_tlv_restart_addr)) {
301
42
        zlog_debug("%s: Malformed packet: Invalid addr TLV len:%u",
302
42
             __func__, TLV_SIZE(tlvh));
303
42
        return OSPF_GR_FAILURE;
304
42
      }
305
306
45
      restart_addr = (struct grace_tlv_restart_addr *)tlvh;
307
45
      addr->s_addr = restart_addr->addr.s_addr;
308
45
      sum += TLV_SIZE(tlvh);
309
45
      break;
310
1
    default:
311
1
      if (IS_DEBUG_OSPF_GR)
312
0
        zlog_debug(
313
1
          "%s, Malformed packet.Invalid TLV type:%d",
314
1
          __func__, ntohs(tlvh->type));
315
1
      return OSPF_GR_FAILURE;
316
358
    }
317
358
  }
318
319
1
  return OSPF_GR_SUCCESS;
320
361
}
321
322
/*
323
 * Grace timer expiry handler.
324
 * HELPER aborts its role at grace timer expiry.
325
 *
326
 * thread
327
 *    thread pointer
328
 *
329
 * Returns:
330
 *    Nothing
331
 */
332
static void ospf_handle_grace_timer_expiry(struct event *thread)
333
0
{
334
0
  struct ospf_neighbor *nbr = EVENT_ARG(thread);
335
0
336
0
  nbr->gr_helper_info.t_grace_timer = NULL;
337
0
338
0
  ospf_gr_helper_exit(nbr, OSPF_GR_HELPER_GRACE_TIMEOUT);
339
0
}
340
341
/*
342
 * Process Grace LSA.If it is eligible move to HELPER role.
343
 * Ref rfc3623 section 3.1
344
 *
345
 * ospf
346
 *    OSPF pointer.
347
 *
348
 * lsa
349
 *    Grace LSA received from RESTARTER.
350
 *
351
 * nbr
352
 *    OSPF neighbour which requests the router to act as
353
 *    HELPER.
354
 *
355
 * Returns:
356
 *    status.
357
 *    If supported as HELPER : OSPF_GR_HELPER_INPROGRESS
358
 *    If Not supported as HELPER : OSPF_GR_HELPER_NONE
359
 */
360
int ospf_process_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
361
         struct ospf_neighbor *nbr)
362
369
{
363
369
  struct in_addr restart_addr = {0};
364
369
  uint8_t restart_reason = 0;
365
369
  uint32_t grace_interval = 0;
366
369
  uint32_t actual_grace_interval = 0;
367
369
  struct advRtr lookup;
368
369
  struct ospf_neighbor *restarter = NULL;
369
369
  struct ospf_interface *oi = nbr->oi;
370
369
  int ret;
371
372
373
  /* Extract the grace lsa packet fields */
374
369
  ret = ospf_extract_grace_lsa_fields(lsa, &grace_interval, &restart_addr,
375
369
              &restart_reason);
376
369
  if (ret != OSPF_GR_SUCCESS) {
377
368
    if (IS_DEBUG_OSPF_GR)
378
0
      zlog_debug("%s, Wrong Grace LSA packet.", __func__);
379
368
    return OSPF_GR_NOT_HELPER;
380
368
  }
381
382
1
  if (IS_DEBUG_OSPF_GR)
383
0
    zlog_debug(
384
1
      "%s, Grace LSA received from %pI4, grace interval:%u, restart reason:%s",
385
1
      __func__, &restart_addr, grace_interval,
386
1
      ospf_restart_reason2str(restart_reason));
387
388
  /* In case of broadcast links, if RESTARTER is DR_OTHER,
389
   * grace LSA might be received from DR, so need to get
390
   * actual neighbour info , here RESTARTER.
391
   */
392
1
  if (oi->type != OSPF_IFTYPE_POINTOPOINT) {
393
1
    restarter = ospf_nbr_lookup_by_addr(oi->nbrs, &restart_addr);
394
395
1
    if (!restarter) {
396
1
      if (IS_DEBUG_OSPF_GR)
397
0
        zlog_debug(
398
1
          "%s, Restarter is not a nbr(%pI4) for this router.",
399
1
          __func__, &restart_addr);
400
1
      return OSPF_GR_NOT_HELPER;
401
1
    }
402
1
  } else
403
0
    restarter = nbr;
404
405
  /* Verify Helper enabled globally */
406
0
  if (!ospf->is_helper_supported) {
407
    /* Verify that Helper support is enabled for the
408
     * current neighbour router-id.
409
     */
410
0
    lookup.advRtrAddr.s_addr = restarter->router_id.s_addr;
411
412
0
    if (!hash_lookup(ospf->enable_rtr_list, &lookup)) {
413
0
      if (IS_DEBUG_OSPF_GR)
414
0
        zlog_debug(
415
0
          "%s, HELPER support is disabled, So not a HELPER",
416
0
          __func__);
417
0
      restarter->gr_helper_info.rejected_reason =
418
0
        OSPF_HELPER_SUPPORT_DISABLED;
419
0
      return OSPF_GR_NOT_HELPER;
420
0
    }
421
0
  }
422
423
424
  /* Check neighbour is in FULL state and
425
   * became a adjacency.
426
   */
427
0
  if (!IS_NBR_STATE_FULL(restarter)) {
428
0
    if (IS_DEBUG_OSPF_GR)
429
0
      zlog_debug(
430
0
        "%s, This Neighbour %pI4 is not in FULL state.",
431
0
        __func__, &restarter->src);
432
0
    restarter->gr_helper_info.rejected_reason =
433
0
      OSPF_HELPER_NOT_A_VALID_NEIGHBOUR;
434
0
    return OSPF_GR_NOT_HELPER;
435
0
  }
436
437
  /* Based on the restart reason from grace lsa
438
   * check the current router is supporting or not
439
   */
440
0
  if (ospf->only_planned_restart
441
0
      && !OSPF_GR_IS_PLANNED_RESTART(restart_reason)) {
442
0
    if (IS_DEBUG_OSPF_GR)
443
0
      zlog_debug(
444
0
        "%s, Router supports only planned restarts but received the GRACE LSA for an unplanned restart.",
445
0
        __func__);
446
0
    restarter->gr_helper_info.rejected_reason =
447
0
      OSPF_HELPER_PLANNED_ONLY_RESTART;
448
0
    return OSPF_GR_NOT_HELPER;
449
0
  }
450
451
  /* Check the retransmission list of this
452
   * neighbour, check any change in lsas.
453
   */
454
0
  if (ospf->strict_lsa_check && !ospf_ls_retransmit_isempty(restarter)
455
0
      && ospf_check_change_in_rxmt_list(restarter)) {
456
0
    if (IS_DEBUG_OSPF_GR)
457
0
      zlog_debug(
458
0
        "%s, Changed LSA in Rxmt list. So not Helper.",
459
0
        __func__);
460
0
    restarter->gr_helper_info.rejected_reason =
461
0
      OSPF_HELPER_TOPO_CHANGE_RTXMT_LIST;
462
0
    return OSPF_GR_NOT_HELPER;
463
0
  }
464
465
  /*LSA age must be less than the grace period */
466
0
  if (ntohs(lsa->data->ls_age) >= grace_interval) {
467
0
    if (IS_DEBUG_OSPF_GR)
468
0
      zlog_debug(
469
0
        "%s, Grace LSA age(%d) is more than the grace interval(%d)",
470
0
        __func__, lsa->data->ls_age, grace_interval);
471
0
    restarter->gr_helper_info.rejected_reason =
472
0
      OSPF_HELPER_LSA_AGE_MORE;
473
0
    return OSPF_GR_NOT_HELPER;
474
0
  }
475
476
0
  if (ospf->gr_info.restart_in_progress) {
477
0
    if (IS_DEBUG_OSPF_GR)
478
0
      zlog_debug(
479
0
        "%s: router is in the process of graceful restart",
480
0
        __func__);
481
0
    restarter->gr_helper_info.rejected_reason =
482
0
      OSPF_HELPER_RESTARTING;
483
0
    return OSPF_GR_NOT_HELPER;
484
0
  }
485
486
  /* check supported grace period configured
487
   * if configured, use this to start the grace
488
   * timer otherwise use the interval received
489
   * in grace LSA packet.
490
   */
491
0
  actual_grace_interval = grace_interval;
492
0
  if (grace_interval > ospf->supported_grace_time) {
493
0
    if (IS_DEBUG_OSPF_GR)
494
0
      zlog_debug(
495
0
        "%s, Received grace period %d is larger than supported grace %d",
496
0
        __func__, grace_interval,
497
0
        ospf->supported_grace_time);
498
0
    actual_grace_interval = ospf->supported_grace_time;
499
0
  }
500
501
0
  if (OSPF_GR_IS_ACTIVE_HELPER(restarter)) {
502
0
    if (restarter->gr_helper_info.t_grace_timer)
503
0
      EVENT_OFF(restarter->gr_helper_info.t_grace_timer);
504
505
0
    if (ospf->active_restarter_cnt > 0)
506
0
      ospf->active_restarter_cnt--;
507
508
0
    if (IS_DEBUG_OSPF_GR)
509
0
      zlog_debug(
510
0
        "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
511
0
        __func__);
512
0
  } else {
513
0
    if (IS_DEBUG_OSPF_GR)
514
0
      zlog_debug(
515
0
        "%s, This Router becomes a HELPER for the neighbour %pI4",
516
0
        __func__, &restarter->src);
517
0
  }
518
519
  /* Became a Helper to the RESTART neighbour.
520
   * Change the helper status.
521
   */
522
0
  restarter->gr_helper_info.gr_helper_status = OSPF_GR_ACTIVE_HELPER;
523
0
  restarter->gr_helper_info.recvd_grace_period = grace_interval;
524
0
  restarter->gr_helper_info.actual_grace_period = actual_grace_interval;
525
0
  restarter->gr_helper_info.gr_restart_reason = restart_reason;
526
0
  restarter->gr_helper_info.rejected_reason = OSPF_HELPER_REJECTED_NONE;
527
528
  /* Increment the active restarter count */
529
0
  ospf->active_restarter_cnt++;
530
531
0
  if (IS_DEBUG_OSPF_GR)
532
0
    zlog_debug("%s, Grace timer started.interval:%d", __func__,
533
0
         actual_grace_interval);
534
535
  /* Start the grace timer */
536
0
  event_add_timer(master, ospf_handle_grace_timer_expiry, restarter,
537
0
      actual_grace_interval,
538
0
      &restarter->gr_helper_info.t_grace_timer);
539
540
0
  return OSPF_GR_ACTIVE_HELPER;
541
0
}
542
543
/*
544
 * API to check any change in the neighbor's
545
 * retransmission list.
546
 *
547
 * nbr
548
 *    OSPF neighbor
549
 *
550
 * Returns:
551
 *    TRUE  - if any change in the lsa.
552
 *    FALSE - no change in the lsas.
553
 */
554
static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr)
555
0
{
556
0
  struct route_node *rn;
557
0
  struct ospf_lsa *lsa;
558
0
  struct route_table *tbl;
559
560
0
  tbl = nbr->ls_rxmt.type[OSPF_ROUTER_LSA].db;
561
0
  LSDB_LOOP (tbl, rn, lsa)
562
0
    if (lsa->to_be_acknowledged)
563
0
      return OSPF_GR_TRUE;
564
0
  tbl = nbr->ls_rxmt.type[OSPF_NETWORK_LSA].db;
565
0
  LSDB_LOOP (tbl, rn, lsa)
566
0
    if (lsa->to_be_acknowledged)
567
0
      return OSPF_GR_TRUE;
568
569
0
  tbl = nbr->ls_rxmt.type[OSPF_SUMMARY_LSA].db;
570
0
  LSDB_LOOP (tbl, rn, lsa)
571
0
    if (lsa->to_be_acknowledged)
572
0
      return OSPF_GR_TRUE;
573
574
0
  tbl = nbr->ls_rxmt.type[OSPF_ASBR_SUMMARY_LSA].db;
575
0
  LSDB_LOOP (tbl, rn, lsa)
576
0
    if (lsa->to_be_acknowledged)
577
0
      return OSPF_GR_TRUE;
578
579
0
  tbl = nbr->ls_rxmt.type[OSPF_AS_EXTERNAL_LSA].db;
580
0
  LSDB_LOOP (tbl, rn, lsa)
581
0
    if (lsa->to_be_acknowledged)
582
0
      return OSPF_GR_TRUE;
583
584
0
  tbl = nbr->ls_rxmt.type[OSPF_AS_NSSA_LSA].db;
585
0
  LSDB_LOOP (tbl, rn, lsa)
586
0
    if (lsa->to_be_acknowledged)
587
0
      return OSPF_GR_TRUE;
588
589
0
  return OSPF_GR_FALSE;
590
0
}
591
592
/*
593
 * Actions to be taken  when topo change detected
594
 * HELPER will exit upon topo change.
595
 *
596
 * ospf
597
 *    ospf pointer
598
 * lsa
599
 *    topo change occurred due to this lsa type (1 to 5 and 7)
600
 *
601
 * Returns:
602
 *    Nothing
603
 */
604
void ospf_helper_handle_topo_chg(struct ospf *ospf, struct ospf_lsa *lsa)
605
0
{
606
0
  struct listnode *node;
607
0
  struct ospf_interface *oi;
608
609
  /* Topo change not required to be handled if strict
610
   * LSA check is disabled for this router.
611
   */
612
0
  if (!ospf->strict_lsa_check)
613
0
    return;
614
615
0
  if (IS_DEBUG_OSPF_GR)
616
0
    zlog_debug("%s: Topo change detected due to LSA[%s]", __func__,
617
0
         dump_lsa_key(lsa));
618
619
0
  lsa->to_be_acknowledged = OSPF_GR_TRUE;
620
621
0
  for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
622
0
    struct route_node *rn = NULL;
623
624
0
    if (ospf_interface_neighbor_count(oi) == 0)
625
0
      continue;
626
627
    /* Ref rfc3623 section 3.2.3.b
628
     * If change due to external LSA and if the area is
629
     * stub, then it is not a topo change. Since Type-5
630
     * lsas will not be flooded in stub area.
631
     */
632
0
    if ((oi->area->external_routing == OSPF_AREA_STUB)
633
0
        && (lsa->data->type == OSPF_AS_EXTERNAL_LSA)) {
634
0
      continue;
635
0
    }
636
637
0
    for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
638
0
      struct ospf_neighbor *nbr = NULL;
639
640
0
      if (!rn->info)
641
0
        continue;
642
643
0
      nbr = rn->info;
644
645
0
      if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
646
0
        ospf_gr_helper_exit(nbr,
647
0
                OSPF_GR_HELPER_TOPO_CHG);
648
0
    }
649
0
  }
650
0
}
651
652
/*
653
 * Api to exit from HELPER role to take all actions
654
 * required at exit.
655
 * Ref rfc3623 section 3.2
656
 *
657
 * ospf
658
 *    OSPF pointer.
659
 *
660
 * nbr
661
 *    OSPF neighbour for which it is acting as HELPER.
662
 *
663
 * reason
664
 *    The reason for exiting from HELPER.
665
 *
666
 * Returns:
667
 *    Nothing.
668
 */
669
void ospf_gr_helper_exit(struct ospf_neighbor *nbr,
670
       enum ospf_helper_exit_reason reason)
671
0
{
672
0
  struct ospf_interface *oi = nbr->oi;
673
0
  struct ospf *ospf = oi->ospf;
674
675
0
  if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
676
0
    return;
677
678
0
  if (IS_DEBUG_OSPF_GR)
679
0
    zlog_debug("%s, Exiting from HELPER support to %pI4, due to %s",
680
0
         __func__, &nbr->src, ospf_exit_reason2str(reason));
681
682
  /* Reset helper status*/
683
0
  nbr->gr_helper_info.gr_helper_status = OSPF_GR_NOT_HELPER;
684
0
  nbr->gr_helper_info.helper_exit_reason = reason;
685
0
  nbr->gr_helper_info.actual_grace_period = 0;
686
0
  nbr->gr_helper_info.recvd_grace_period = 0;
687
0
  nbr->gr_helper_info.gr_restart_reason = 0;
688
0
  ospf->last_exit_reason = reason;
689
690
0
  if (ospf->active_restarter_cnt <= 0) {
691
0
    zlog_err(
692
0
      "OSPF GR-Helper: active_restarter_cnt should be greater than zero here.");
693
0
    return;
694
0
  }
695
  /* Decrement active Restarter count */
696
0
  ospf->active_restarter_cnt--;
697
698
  /* If the exit not triggered due to grace timer
699
   * expiry, stop the grace timer.
700
   */
701
0
  if (reason != OSPF_GR_HELPER_GRACE_TIMEOUT)
702
0
    EVENT_OFF(nbr->gr_helper_info.t_grace_timer);
703
704
  /* check exit triggered due to successful completion
705
   * of graceful restart.
706
   */
707
0
  if (reason != OSPF_GR_HELPER_COMPLETED) {
708
0
    if (IS_DEBUG_OSPF_GR)
709
0
      zlog_debug("%s, Unsuccessful GR exit", __func__);
710
0
  }
711
712
  /*Recalculate the DR for the network segment */
713
0
  if (oi->type == OSPF_IFTYPE_BROADCAST || oi->type == OSPF_IFTYPE_NBMA)
714
0
    ospf_dr_election(oi);
715
716
  /* Originate a router LSA */
717
0
  ospf_router_lsa_update_area(oi->area);
718
719
  /* Originate network lsa if it is an DR in the LAN */
720
0
  if (oi->state == ISM_DR)
721
0
    ospf_network_lsa_update(oi);
722
0
}
723
724
/*
725
 * Process MaxAge Grace LSA.
726
 * It is a indication for successful completion of GR.
727
 * If router acting as HELPER, It exits from helper role.
728
 *
729
 * ospf
730
 *    OSPF pointer.
731
 *
732
 * lsa
733
 *    Grace LSA received from RESTARTER.
734
 *
735
 * nbr
736
 *    OSPF neighbour which requests the router to act as
737
 *    HELPER.
738
 *
739
 * Returns:
740
 *    Nothing.
741
 */
742
void ospf_process_maxage_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
743
           struct ospf_neighbor *nbr)
744
0
{
745
0
  struct in_addr restartAddr = {0};
746
0
  uint8_t restartReason = 0;
747
0
  uint32_t graceInterval = 0;
748
0
  struct ospf_neighbor *restarter = NULL;
749
0
  struct ospf_interface *oi = nbr->oi;
750
0
  int ret;
751
752
  /* Extract the grace lsa packet fields */
753
0
  ret = ospf_extract_grace_lsa_fields(lsa, &graceInterval, &restartAddr,
754
0
              &restartReason);
755
0
  if (ret != OSPF_GR_SUCCESS) {
756
0
    if (IS_DEBUG_OSPF_GR)
757
0
      zlog_debug("%s, Wrong Grace LSA packet.", __func__);
758
0
    return;
759
0
  }
760
761
0
  if (IS_DEBUG_OSPF_GR)
762
0
    zlog_debug("%s, GraceLSA received for neighbour %pI4", __func__,
763
0
         &restartAddr);
764
765
  /* In case of broadcast links, if RESTARTER is DR_OTHER,
766
   * grace LSA might be received from DR, so fetching the
767
   * actual neighbour information using restarter address.
768
   */
769
0
  if (oi->type != OSPF_IFTYPE_POINTOPOINT) {
770
0
    restarter = ospf_nbr_lookup_by_addr(oi->nbrs, &restartAddr);
771
772
0
    if (!restarter) {
773
0
      if (IS_DEBUG_OSPF_GR)
774
0
        zlog_debug(
775
0
          "%s, Restarter is not a neighbour for this router.",
776
0
          __func__);
777
0
      return;
778
0
    }
779
0
  } else {
780
0
    restarter = nbr;
781
0
  }
782
783
0
  ospf_gr_helper_exit(restarter, OSPF_GR_HELPER_COMPLETED);
784
0
}
785
786
/* Configuration handlers */
787
/*
788
 * Disable/Enable HELPER support on router level.
789
 *
790
 * ospf
791
 *    OSPF pointer.
792
 *
793
 * status
794
 *    TRUE/FALSE
795
 *
796
 * Returns:
797
 *    Nothing.
798
 */
799
void ospf_gr_helper_support_set(struct ospf *ospf, bool support)
800
0
{
801
0
  struct ospf_interface *oi;
802
0
  struct listnode *node;
803
0
  struct advRtr lookup;
804
805
0
  if (ospf->is_helper_supported == support)
806
0
    return;
807
808
0
  ospf->is_helper_supported = support;
809
810
  /* If helper support disabled, cease HELPER role for all
811
   * supporting neighbors.
812
   */
813
0
  if (support == OSPF_GR_FALSE) {
814
0
    for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
815
0
      struct route_node *rn = NULL;
816
817
0
      if (ospf_interface_neighbor_count(oi) == 0)
818
0
        continue;
819
820
0
      for (rn = route_top(oi->nbrs); rn;
821
0
           rn = route_next(rn)) {
822
0
        struct ospf_neighbor *nbr = NULL;
823
824
0
        if (!rn->info)
825
0
          continue;
826
827
0
        nbr = rn->info;
828
829
0
        lookup.advRtrAddr.s_addr =
830
0
          nbr->router_id.s_addr;
831
        /* check if helper support enabled for the
832
         * corresponding routerid.If enabled, don't
833
         * exit from helper role.
834
         */
835
0
        if (hash_lookup(ospf->enable_rtr_list, &lookup))
836
0
          continue;
837
838
0
        if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
839
0
          ospf_gr_helper_exit(
840
0
            nbr, OSPF_GR_HELPER_TOPO_CHG);
841
0
      }
842
0
    }
843
0
  }
844
0
}
845
846
/*
847
 * Enable/Disable HELPER support on a specified advertagement
848
 * router.
849
 *
850
 * ospf
851
 *    OSPF pointer.
852
 *
853
 * advRtr
854
 *    HELPER support for given Advertisement Router.
855
 *
856
 * support
857
 *    True - Enable Helper Support.
858
 *    False - Disable Helper Support.
859
 *
860
 * Returns:
861
 *    Nothing.
862
 */
863
864
void ospf_gr_helper_support_set_per_routerid(struct ospf *ospf,
865
               struct in_addr *advrtr,
866
               bool support)
867
0
{
868
0
  struct advRtr temp;
869
0
  struct advRtr *rtr;
870
0
  struct ospf_interface *oi;
871
0
  struct listnode *node;
872
873
0
  temp.advRtrAddr.s_addr = advrtr->s_addr;
874
875
0
  if (support == OSPF_GR_FALSE) {
876
    /*Delete the routerid from the enable router hash table */
877
0
    rtr = hash_lookup(ospf->enable_rtr_list, &temp);
878
879
0
    if (rtr) {
880
0
      hash_release(ospf->enable_rtr_list, rtr);
881
0
      ospf_disable_rtr_hash_free(rtr);
882
0
    }
883
884
    /* If helper support is enabled globally
885
     * no action is required.
886
     */
887
0
    if (ospf->is_helper_supported)
888
0
      return;
889
890
    /* Cease the HELPER role fore neighbours from the
891
     * specified advertisement router.
892
     */
893
0
    for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
894
0
      struct route_node *rn = NULL;
895
896
0
      if (ospf_interface_neighbor_count(oi) == 0)
897
0
        continue;
898
899
0
      for (rn = route_top(oi->nbrs); rn;
900
0
           rn = route_next(rn)) {
901
0
        struct ospf_neighbor *nbr = NULL;
902
903
0
        if (!rn->info)
904
0
          continue;
905
906
0
        nbr = rn->info;
907
908
0
        if (nbr->router_id.s_addr != advrtr->s_addr)
909
0
          continue;
910
911
0
        if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
912
0
          ospf_gr_helper_exit(
913
0
            nbr, OSPF_GR_HELPER_TOPO_CHG);
914
0
      }
915
0
    }
916
917
0
  } else {
918
    /* Add the routerid to the enable router hash table */
919
0
    (void)hash_get(ospf->enable_rtr_list, &temp,
920
0
             ospf_enable_rtr_hash_alloc);
921
0
  }
922
0
}
923
924
/*
925
 * Api to enable/disable strict lsa check on the HELPER.
926
 *
927
 * ospf
928
 *    OSPF pointer.
929
 *
930
 * enabled
931
 *    True - disable the lsa check.
932
 *    False - enable the strict lsa check.
933
 *
934
 * Returns:
935
 *    Nothing.
936
 */
937
void ospf_gr_helper_lsa_check_set(struct ospf *ospf, bool enabled)
938
0
{
939
0
  if (ospf->strict_lsa_check == enabled)
940
0
    return;
941
942
0
  ospf->strict_lsa_check = enabled;
943
0
}
944
945
/*
946
 * Api to set the supported grace interval in this router.
947
 *
948
 * ospf
949
 *    OSPF pointer.
950
 *
951
 * interval
952
 *    The supported grace interval..
953
 *
954
 * Returns:
955
 *    Nothing.
956
 */
957
void ospf_gr_helper_supported_gracetime_set(struct ospf *ospf,
958
              uint32_t interval)
959
0
{
960
0
  ospf->supported_grace_time = interval;
961
0
}
962
963
/*
964
 * Api to set the supported restart reason.
965
 *
966
 * ospf
967
 *    OSPF pointer.
968
 *
969
 * planned_only
970
 *    True: support only planned restart.
971
 *    False: support for planned/unplanned restarts.
972
 *
973
 * Returns:
974
 *    Nothing.
975
 */
976
void ospf_gr_helper_set_supported_planned_only_restart(struct ospf *ospf,
977
                  bool planned_only)
978
0
{
979
0
  ospf->only_planned_restart = planned_only;
980
0
}
981
982
/*
983
 * Api to display the grace LSA information.
984
 *
985
 * vty
986
 *    vty pointer.
987
 * lsa
988
 *    Grace LSA.
989
 * json
990
 *    json object
991
 *
992
 * Returns:
993
 *    Nothing.
994
 */
995
static void show_ospf_grace_lsa_info(struct vty *vty, struct json_object *json,
996
             struct ospf_lsa *lsa)
997
0
{
998
0
  struct lsa_header *lsah = NULL;
999
0
  struct tlv_header *tlvh = NULL;
1000
0
  struct grace_tlv_graceperiod *gracePeriod;
1001
0
  struct grace_tlv_restart_reason *grReason;
1002
0
  struct grace_tlv_restart_addr *restartAddr;
1003
0
  uint16_t length = 0;
1004
0
  int sum = 0;
1005
1006
0
  if (json)
1007
0
    return;
1008
1009
0
  lsah = (struct lsa_header *)lsa->data;
1010
1011
0
  if (lsa->size <= OSPF_LSA_HEADER_SIZE) {
1012
0
    if (vty)
1013
0
      vty_out(vty, "%% Invalid LSA length: %d\n", length);
1014
0
    else
1015
0
      zlog_debug("%% Invalid LSA length: %d", length);
1016
0
    return;
1017
0
  }
1018
1019
0
  length = lsa->size - OSPF_LSA_HEADER_SIZE;
1020
1021
0
  if (vty)
1022
0
    vty_out(vty, "  TLV info:\n");
1023
0
  else
1024
0
    zlog_debug("  TLV info:");
1025
1026
0
  for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
1027
0
       tlvh = TLV_HDR_NEXT(tlvh)) {
1028
    /* Check TLV len */
1029
0
    if (sum + TLV_SIZE(tlvh) > length) {
1030
0
      if (vty)
1031
0
        vty_out(vty, "%% Invalid TLV length: %u\n",
1032
0
          TLV_SIZE(tlvh));
1033
0
      else
1034
0
        zlog_debug("%% Invalid TLV length: %u",
1035
0
             TLV_SIZE(tlvh));
1036
0
      return;
1037
0
    }
1038
1039
0
    switch (ntohs(tlvh->type)) {
1040
0
    case GRACE_PERIOD_TYPE:
1041
0
      if (TLV_SIZE(tlvh)
1042
0
          < sizeof(struct grace_tlv_graceperiod)) {
1043
0
        if (vty)
1044
0
          vty_out(vty,
1045
0
            "%% Invalid grace TLV length %u\n",
1046
0
            TLV_SIZE(tlvh));
1047
0
        else
1048
0
          zlog_debug(
1049
0
            "%% Invalid grace TLV length %u",
1050
0
            TLV_SIZE(tlvh));
1051
0
        return;
1052
0
      }
1053
1054
0
      gracePeriod = (struct grace_tlv_graceperiod *)tlvh;
1055
0
      sum += TLV_SIZE(tlvh);
1056
1057
0
      if (vty)
1058
0
        vty_out(vty, "   Grace period:%d\n",
1059
0
          ntohl(gracePeriod->interval));
1060
0
      else
1061
0
        zlog_debug("   Grace period:%d",
1062
0
             ntohl(gracePeriod->interval));
1063
0
      break;
1064
0
    case RESTART_REASON_TYPE:
1065
0
      if (TLV_SIZE(tlvh)
1066
0
          < sizeof(struct grace_tlv_restart_reason)) {
1067
0
        if (vty)
1068
0
          vty_out(vty,
1069
0
            "%% Invalid reason TLV length %u\n",
1070
0
            TLV_SIZE(tlvh));
1071
0
        else
1072
0
          zlog_debug(
1073
0
            "%% Invalid reason TLV length %u",
1074
0
            TLV_SIZE(tlvh));
1075
0
        return;
1076
0
      }
1077
1078
0
      grReason = (struct grace_tlv_restart_reason *)tlvh;
1079
0
      sum += TLV_SIZE(tlvh);
1080
1081
0
      if (vty)
1082
0
        vty_out(vty, "   Restart reason:%s\n",
1083
0
          ospf_restart_reason2str(
1084
0
            grReason->reason));
1085
0
      else
1086
0
        zlog_debug("   Restart reason:%s",
1087
0
             ospf_restart_reason2str(
1088
0
               grReason->reason));
1089
0
      break;
1090
0
    case RESTARTER_IP_ADDR_TYPE:
1091
0
      if (TLV_SIZE(tlvh)
1092
0
          < sizeof(struct grace_tlv_restart_addr)) {
1093
0
        if (vty)
1094
0
          vty_out(vty,
1095
0
            "%% Invalid addr TLV length %u\n",
1096
0
            TLV_SIZE(tlvh));
1097
0
        else
1098
0
          zlog_debug(
1099
0
            "%% Invalid addr TLV length %u",
1100
0
            TLV_SIZE(tlvh));
1101
0
        return;
1102
0
      }
1103
1104
0
      restartAddr = (struct grace_tlv_restart_addr *)tlvh;
1105
0
      sum += TLV_SIZE(tlvh);
1106
1107
0
      if (vty)
1108
0
        vty_out(vty, "   Restarter address:%pI4\n",
1109
0
          &restartAddr->addr);
1110
0
      else
1111
0
        zlog_debug("   Restarter address:%pI4",
1112
0
             &restartAddr->addr);
1113
0
      break;
1114
0
    default:
1115
0
      if (vty)
1116
0
        vty_out(vty, "   Unknown TLV type %d\n",
1117
0
          ntohs(tlvh->type));
1118
0
      else
1119
0
        zlog_debug("   Unknown TLV type %d",
1120
0
             ntohs(tlvh->type));
1121
1122
0
      break;
1123
0
    }
1124
0
  }
1125
0
}