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