Coverage Report

Created: 2025-10-23 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/ospfd/ospf_gr_helper.c
Line
Count
Source
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
1.35k
{
234
1.35k
  struct lsa_header *lsah = NULL;
235
1.35k
  struct tlv_header *tlvh = NULL;
236
1.35k
  struct grace_tlv_graceperiod *grace_period;
237
1.35k
  struct grace_tlv_restart_reason *gr_reason;
238
1.35k
  struct grace_tlv_restart_addr *restart_addr;
239
1.35k
  uint16_t length = 0;
240
1.35k
  int sum = 0;
241
242
1.35k
  lsah = (struct lsa_header *)lsa->data;
243
244
  /* Check LSA len */
245
1.35k
  if (lsa->size <= OSPF_LSA_HEADER_SIZE) {
246
192
    if (IS_DEBUG_OSPF_GR)
247
0
      zlog_debug("%s: Malformed packet: Invalid LSA len:%d",
248
192
           __func__, length);
249
192
    return OSPF_GR_FAILURE;
250
192
  }
251
252
1.15k
  length = lsa->size - OSPF_LSA_HEADER_SIZE;
253
254
1.56k
  for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
255
1.54k
       tlvh = TLV_HDR_NEXT(tlvh)) {
256
257
    /* Check TLV len against overall LSA */
258
1.54k
    if (sum + TLV_SIZE(tlvh) > length) {
259
387
      if (IS_DEBUG_OSPF_GR)
260
0
        zlog_debug("%s: Malformed packet: Invalid TLV len:%u",
261
387
             __func__, TLV_SIZE(tlvh));
262
387
      return OSPF_GR_FAILURE;
263
387
    }
264
265
1.16k
    switch (ntohs(tlvh->type)) {
266
160
    case GRACE_PERIOD_TYPE:
267
160
      if (TLV_SIZE(tlvh) <
268
160
          sizeof(struct grace_tlv_graceperiod)) {
269
66
        zlog_debug("%s: Malformed packet: Invalid grace TLV len:%u",
270
66
             __func__, TLV_SIZE(tlvh));
271
66
        return OSPF_GR_FAILURE;
272
66
      }
273
274
94
      grace_period = (struct grace_tlv_graceperiod *)tlvh;
275
94
      *interval = ntohl(grace_period->interval);
276
94
      sum += TLV_SIZE(tlvh);
277
278
      /* Check if grace interval is valid */
279
94
      if (*interval > OSPF_MAX_GRACE_INTERVAL
280
40
          || *interval < OSPF_MIN_GRACE_INTERVAL)
281
56
        return OSPF_GR_FAILURE;
282
38
      break;
283
684
    case RESTART_REASON_TYPE:
284
684
      if (TLV_SIZE(tlvh) <
285
684
          sizeof(struct grace_tlv_restart_reason)) {
286
142
        zlog_debug("%s: Malformed packet: Invalid reason TLV len:%u",
287
142
             __func__, TLV_SIZE(tlvh));
288
142
        return OSPF_GR_FAILURE;
289
142
      }
290
291
542
      gr_reason = (struct grace_tlv_restart_reason *)tlvh;
292
542
      *reason = gr_reason->reason;
293
542
      sum += TLV_SIZE(tlvh);
294
295
542
      if (*reason >= OSPF_GR_INVALID_REASON_CODE)
296
223
        return OSPF_GR_FAILURE;
297
319
      break;
298
319
    case RESTARTER_IP_ADDR_TYPE:
299
108
      if (TLV_SIZE(tlvh) <
300
108
          sizeof(struct grace_tlv_restart_addr)) {
301
58
        zlog_debug("%s: Malformed packet: Invalid addr TLV len:%u",
302
58
             __func__, TLV_SIZE(tlvh));
303
58
        return OSPF_GR_FAILURE;
304
58
      }
305
306
50
      restart_addr = (struct grace_tlv_restart_addr *)tlvh;
307
50
      addr->s_addr = restart_addr->addr.s_addr;
308
50
      sum += TLV_SIZE(tlvh);
309
50
      break;
310
209
    default:
311
209
      if (IS_DEBUG_OSPF_GR)
312
0
        zlog_debug(
313
209
          "%s, Malformed packet.Invalid TLV type:%d",
314
209
          __func__, ntohs(tlvh->type));
315
209
      return OSPF_GR_FAILURE;
316
1.16k
    }
317
1.16k
  }
318
319
18
  return OSPF_GR_SUCCESS;
320
1.15k
}
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
1.35k
{
363
1.35k
  struct in_addr restart_addr = {0};
364
1.35k
  uint8_t restart_reason = 0;
365
1.35k
  uint32_t grace_interval = 0;
366
1.35k
  uint32_t actual_grace_interval = 0;
367
1.35k
  struct advRtr lookup;
368
1.35k
  struct ospf_neighbor *restarter = NULL;
369
1.35k
  struct ospf_interface *oi = nbr->oi;
370
1.35k
  int ret;
371
372
373
  /* Extract the grace lsa packet fields */
374
1.35k
  ret = ospf_extract_grace_lsa_fields(lsa, &grace_interval, &restart_addr,
375
1.35k
              &restart_reason);
376
1.35k
  if (ret != OSPF_GR_SUCCESS) {
377
1.33k
    if (IS_DEBUG_OSPF_GR)
378
0
      zlog_debug("%s, Wrong Grace LSA packet.", __func__);
379
1.33k
    return OSPF_GR_NOT_HELPER;
380
1.33k
  }
381
382
18
  if (IS_DEBUG_OSPF_GR)
383
0
    zlog_debug(
384
18
      "%s, Grace LSA received from %pI4, grace interval:%u, restart reason:%s",
385
18
      __func__, &restart_addr, grace_interval,
386
18
      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
18
  if (oi->type != OSPF_IFTYPE_POINTOPOINT) {
393
18
    restarter = ospf_nbr_lookup_by_addr(oi->nbrs, &restart_addr);
394
395
18
    if (!restarter) {
396
18
      if (IS_DEBUG_OSPF_GR)
397
0
        zlog_debug(
398
18
          "%s, Restarter is not a nbr(%pI4) for this router.",
399
18
          __func__, &restart_addr);
400
18
      return OSPF_GR_NOT_HELPER;
401
18
    }
402
18
  } 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
}