]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_gr_helper.c
Merge pull request #12329 from opensourcerouting/feature/graceful-shutdown_per_peer
[mirror_frr.git] / ospf6d / ospf6_gr_helper.c
1 /*
2 * OSPF6 Graceful Restart helper functions.
3 *
4 * Copyright (C) 2021-22 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 "log.h"
27 #include "vty.h"
28 #include "command.h"
29 #include "prefix.h"
30 #include "stream.h"
31 #include "zclient.h"
32 #include "memory.h"
33 #include "table.h"
34 #include "lib/bfd.h"
35 #include "lib_errors.h"
36 #include "jhash.h"
37
38 #include "ospf6_proto.h"
39 #include "ospf6_lsa.h"
40 #include "ospf6_lsdb.h"
41 #include "ospf6_route.h"
42 #include "ospf6_message.h"
43
44 #include "ospf6_top.h"
45 #include "ospf6_area.h"
46 #include "ospf6_interface.h"
47 #include "ospf6_neighbor.h"
48 #include "ospf6_intra.h"
49 #include "ospf6d.h"
50 #include "ospf6_gr.h"
51 #include "lib/json.h"
52 #include "ospf6d/ospf6_gr_helper_clippy.c"
53
54 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_GR_HELPER, "OSPF6 Graceful restart helper");
55
56 unsigned char conf_debug_ospf6_gr;
57
58 static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa,
59 json_object *json, bool use_json);
60
61 struct ospf6_lsa_handler grace_lsa_handler = {.lh_type = OSPF6_LSTYPE_GRACE_LSA,
62 .lh_name = "Grace",
63 .lh_short_name = "GR",
64 .lh_show =
65 ospf6_grace_lsa_show_info,
66 .lh_get_prefix_str = NULL,
67 .lh_debug = 0};
68
69 const char *ospf6_exit_reason_desc[] = {
70 "Unknown reason",
71 "Helper in progress",
72 "Topology Change",
73 "Grace timer expiry",
74 "Successful graceful restart",
75 };
76
77 const char *ospf6_restart_reason_desc[] = {
78 "Unknown restart",
79 "Software restart",
80 "Software reload/upgrade",
81 "Switch to redundant control processor",
82 };
83
84 const char *ospf6_rejected_reason_desc[] = {
85 "Unknown reason",
86 "Helper support disabled",
87 "Neighbour is not in FULL state",
88 "Supports only planned restart but received for unplanned",
89 "Topo change due to change in lsa rxmt list",
90 "LSA age is more than Grace interval",
91 };
92
93 static unsigned int ospf6_enable_rtr_hash_key(const void *data)
94 {
95 const struct advRtr *rtr = data;
96
97 return jhash_1word(rtr->advRtrAddr, 0);
98 }
99
100 static bool ospf6_enable_rtr_hash_cmp(const void *d1, const void *d2)
101 {
102 const struct advRtr *rtr1 = d1;
103 const struct advRtr *rtr2 = d2;
104
105 return (rtr1->advRtrAddr == rtr2->advRtrAddr);
106 }
107
108 static void *ospf6_enable_rtr_hash_alloc(void *p)
109 {
110 struct advRtr *rid;
111
112 rid = XCALLOC(MTYPE_OSPF6_GR_HELPER, sizeof(struct advRtr));
113 rid->advRtrAddr = ((struct advRtr *)p)->advRtrAddr;
114
115 return rid;
116 }
117
118 static void ospf6_disable_rtr_hash_free(void *rtr)
119 {
120 XFREE(MTYPE_OSPF6_GR_HELPER, rtr);
121 }
122
123 static void ospf6_enable_rtr_hash_destroy(struct ospf6 *ospf6)
124 {
125 if (ospf6->ospf6_helper_cfg.enable_rtr_list == NULL)
126 return;
127
128 hash_clean(ospf6->ospf6_helper_cfg.enable_rtr_list,
129 ospf6_disable_rtr_hash_free);
130 hash_free(ospf6->ospf6_helper_cfg.enable_rtr_list);
131 ospf6->ospf6_helper_cfg.enable_rtr_list = NULL;
132 }
133
134 /*
135 * Extracting tlv info from GRACE LSA.
136 *
137 * lsa
138 * ospf6 grace lsa
139 *
140 * Returns:
141 * interval : grace interval.
142 * reason : Restarting reason.
143 */
144 static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa,
145 uint32_t *interval, uint8_t *reason)
146 {
147 struct ospf6_lsa_header *lsah = NULL;
148 struct tlv_header *tlvh = NULL;
149 struct grace_tlv_graceperiod *gracePeriod;
150 struct grace_tlv_restart_reason *grReason;
151 uint16_t length = 0;
152 int sum = 0;
153
154 lsah = (struct ospf6_lsa_header *)lsa->header;
155 if (ntohs(lsah->length) <= OSPF6_LSA_HEADER_SIZE) {
156 if (IS_DEBUG_OSPF6_GR)
157 zlog_debug("%s: undersized (%u B) lsa", __func__,
158 ntohs(lsah->length));
159 return OSPF6_FAILURE;
160 }
161
162 length = ntohs(lsah->length) - OSPF6_LSA_HEADER_SIZE;
163
164 for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
165 tlvh = TLV_HDR_NEXT(tlvh)) {
166
167 /* Check TLV len against overall LSA */
168 if (sum + TLV_SIZE(tlvh) > length) {
169 if (IS_DEBUG_OSPF6_GR)
170 zlog_debug(
171 "%s: Malformed packet: Invalid TLV len:%d",
172 __func__, TLV_SIZE(tlvh));
173 return OSPF6_FAILURE;
174 }
175
176 switch (ntohs(tlvh->type)) {
177 case GRACE_PERIOD_TYPE:
178 gracePeriod = (struct grace_tlv_graceperiod *)tlvh;
179 *interval = ntohl(gracePeriod->interval);
180 sum += TLV_SIZE(tlvh);
181
182 /* Check if grace interval is valid */
183 if (*interval > OSPF6_MAX_GRACE_INTERVAL
184 || *interval < OSPF6_MIN_GRACE_INTERVAL)
185 return OSPF6_FAILURE;
186 break;
187 case RESTART_REASON_TYPE:
188 grReason = (struct grace_tlv_restart_reason *)tlvh;
189 *reason = grReason->reason;
190 sum += TLV_SIZE(tlvh);
191
192 if (*reason >= OSPF6_GR_INVALID_REASON_CODE)
193 return OSPF6_FAILURE;
194 break;
195 default:
196 if (IS_DEBUG_OSPF6_GR)
197 zlog_debug("%s, Ignoring unknown TLV type:%d",
198 __func__, ntohs(tlvh->type));
199 }
200 }
201
202 return OSPF6_SUCCESS;
203 }
204
205 /*
206 * Grace timer expiry handler.
207 * HELPER aborts its role at grace timer expiry.
208 *
209 * thread
210 * thread pointer
211 *
212 * Returns:
213 * Nothing
214 */
215 static void ospf6_handle_grace_timer_expiry(struct thread *thread)
216 {
217 struct ospf6_neighbor *nbr = THREAD_ARG(thread);
218
219 ospf6_gr_helper_exit(nbr, OSPF6_GR_HELPER_GRACE_TIMEOUT);
220 }
221
222 /*
223 * API to check any change in the neighbor's
224 * retransmission list.
225 *
226 * nbr
227 * ospf6 neighbor
228 *
229 * Returns:
230 * TRUE - if any change in the lsa.
231 * FALSE - no change in the lsas.
232 */
233 static bool ospf6_check_chg_in_rxmt_list(struct ospf6_neighbor *nbr)
234 {
235 struct ospf6_lsa *lsa, *lsanext;
236
237 for (ALL_LSDB(nbr->retrans_list, lsa, lsanext)) {
238 struct ospf6_lsa *lsa_in_db = NULL;
239
240 /* Fetching the same copy of LSA form LSDB to validate the
241 * topochange.
242 */
243 lsa_in_db =
244 ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
245 lsa->header->adv_router, lsa->lsdb);
246
247 if (lsa_in_db && lsa_in_db->tobe_acknowledged) {
248 ospf6_lsa_unlock(lsa);
249 if (lsanext)
250 ospf6_lsa_unlock(lsanext);
251
252 return OSPF6_TRUE;
253 }
254 }
255
256 return OSPF6_FALSE;
257 }
258
259 /*
260 * Process Grace LSA.If it is eligible move to HELPER role.
261 * Ref rfc3623 section 3.1 and rfc5187
262 *
263 * ospf
264 * Ospf6 pointer.
265 *
266 * lsa
267 * Grace LSA received from RESTARTER.
268 *
269 * restarter
270 * ospf6 neighbour which requests the router to act as
271 * HELPER.
272 *
273 * Returns:
274 * status.
275 * If supported as HELPER : OSPF_GR_HELPER_INPROGRESS
276 * If Not supported as HELPER : OSPF_GR_HELPER_NONE
277 */
278 int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa,
279 struct ospf6_neighbor *restarter)
280 {
281 uint8_t restart_reason = 0;
282 uint32_t grace_interval = 0;
283 uint32_t actual_grace_interval = 0;
284 struct advRtr lookup;
285 int ret;
286
287 /* Extract the grace lsa packet fields */
288 ret = ospf6_extract_grace_lsa_fields(lsa, &grace_interval,
289 &restart_reason);
290 if (ret != OSPF6_SUCCESS) {
291 if (IS_DEBUG_OSPF6_GR)
292 zlog_debug("%s, Wrong Grace LSA packet.", __func__);
293 return OSPF6_GR_NOT_HELPER;
294 }
295
296 if (IS_DEBUG_OSPF6_GR)
297 zlog_debug(
298 "%s, Grace LSA received from %pI4, grace interval:%u, restart reason :%s",
299 __func__, &restarter->router_id, grace_interval,
300 ospf6_restart_reason_desc[restart_reason]);
301
302 /* Verify Helper enabled globally */
303 if (!ospf6->ospf6_helper_cfg.is_helper_supported) {
304 /* Verify Helper support is enabled for the
305 * current neighbour router-id.
306 */
307 lookup.advRtrAddr = restarter->router_id;
308
309 if (!hash_lookup(ospf6->ospf6_helper_cfg.enable_rtr_list,
310 &lookup)) {
311 if (IS_DEBUG_OSPF6_GR)
312 zlog_debug(
313 "%s, HELPER support is disabled, So not a HELPER",
314 __func__);
315 restarter->gr_helper_info.rejected_reason =
316 OSPF6_HELPER_SUPPORT_DISABLED;
317 return OSPF6_GR_NOT_HELPER;
318 }
319 }
320
321 /* Check neighbour is in FULL state and
322 * became a adjacency.
323 */
324 if (!IS_NBR_STATE_FULL(restarter)) {
325 if (IS_DEBUG_OSPF6_GR)
326 zlog_debug(
327 "%s, This Neighbour %pI6 is not in FULL state.",
328 __func__, &restarter->linklocal_addr);
329 restarter->gr_helper_info.rejected_reason =
330 OSPF6_HELPER_NOT_A_VALID_NEIGHBOUR;
331 return OSPF6_GR_NOT_HELPER;
332 }
333
334 /* Based on the restart reason from grace lsa
335 * check the current router is supporting or not
336 */
337 if (ospf6->ospf6_helper_cfg.only_planned_restart
338 && !OSPF6_GR_IS_PLANNED_RESTART(restart_reason)) {
339 if (IS_DEBUG_OSPF6_GR)
340 zlog_debug(
341 "%s, Router supports only planned restarts but received the GRACE LSA due to an unplanned restart",
342 __func__);
343 restarter->gr_helper_info.rejected_reason =
344 OSPF6_HELPER_PLANNED_ONLY_RESTART;
345 return OSPF6_GR_NOT_HELPER;
346 }
347
348 /* Check the retransmission list of this
349 * neighbour, check any change in lsas.
350 */
351 if (ospf6->ospf6_helper_cfg.strict_lsa_check
352 && restarter->retrans_list->count
353 && ospf6_check_chg_in_rxmt_list(restarter)) {
354 if (IS_DEBUG_OSPF6_GR)
355 zlog_debug(
356 "%s, Changed LSA in Rxmt list.So not Helper.",
357 __func__);
358 restarter->gr_helper_info.rejected_reason =
359 OSPF6_HELPER_TOPO_CHANGE_RTXMT_LIST;
360 return OSPF6_GR_NOT_HELPER;
361 }
362
363 /* LSA age must be less than the grace period */
364 if (ntohs(lsa->header->age) >= grace_interval) {
365 if (IS_DEBUG_OSPF6_GR)
366 zlog_debug(
367 "%s, Grace LSA age(%d) is more than the grace interval(%d)",
368 __func__, lsa->header->age, grace_interval);
369 restarter->gr_helper_info.rejected_reason =
370 OSPF6_HELPER_LSA_AGE_MORE;
371 return OSPF6_GR_NOT_HELPER;
372 }
373
374 if (ospf6->gr_info.restart_in_progress) {
375 if (IS_DEBUG_OSPF6_GR)
376 zlog_debug(
377 "%s: router is in the process of graceful restart",
378 __func__);
379 restarter->gr_helper_info.rejected_reason =
380 OSPF6_HELPER_RESTARTING;
381 return OSPF6_GR_NOT_HELPER;
382 }
383
384 /* check supported grace period configured
385 * if configured, use this to start the grace
386 * timer otherwise use the interval received
387 * in grace LSA packet.
388 */
389 actual_grace_interval = grace_interval;
390 if (grace_interval > ospf6->ospf6_helper_cfg.supported_grace_time) {
391 if (IS_DEBUG_OSPF6_GR)
392 zlog_debug(
393 "%s, Received grace period %d is larger than supported grace %d",
394 __func__, grace_interval,
395 ospf6->ospf6_helper_cfg.supported_grace_time);
396 actual_grace_interval =
397 ospf6->ospf6_helper_cfg.supported_grace_time;
398 }
399
400 if (OSPF6_GR_IS_ACTIVE_HELPER(restarter)) {
401 THREAD_OFF(restarter->gr_helper_info.t_grace_timer);
402
403 if (ospf6->ospf6_helper_cfg.active_restarter_cnt > 0)
404 ospf6->ospf6_helper_cfg.active_restarter_cnt--;
405
406 if (IS_DEBUG_OSPF6_GR)
407 zlog_debug(
408 "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
409 __func__);
410 } else {
411 if (IS_DEBUG_OSPF6_GR)
412 zlog_debug(
413 "%s, This Router becomes a HELPER for the neighbour %pI6",
414 __func__, &restarter->linklocal_addr);
415 }
416
417 /* Became a Helper to the RESTART neighbour.
418 * change the helper status.
419 */
420 restarter->gr_helper_info.gr_helper_status = OSPF6_GR_ACTIVE_HELPER;
421 restarter->gr_helper_info.recvd_grace_period = grace_interval;
422 restarter->gr_helper_info.actual_grace_period = actual_grace_interval;
423 restarter->gr_helper_info.gr_restart_reason = restart_reason;
424 restarter->gr_helper_info.rejected_reason = OSPF6_HELPER_REJECTED_NONE;
425
426 /* Increment the active restart nbr count */
427 ospf6->ospf6_helper_cfg.active_restarter_cnt++;
428
429 if (IS_DEBUG_OSPF6_GR)
430 zlog_debug("%s, Grace timer started.interval:%u", __func__,
431 actual_grace_interval);
432
433 /* Start the grace timer */
434 thread_add_timer(master, ospf6_handle_grace_timer_expiry, restarter,
435 actual_grace_interval,
436 &restarter->gr_helper_info.t_grace_timer);
437
438 return OSPF6_GR_ACTIVE_HELPER;
439 }
440
441 /*
442 * Api to exit from HELPER role to take all actions
443 * required at exit.
444 * Ref rfc3623 section 3. and rfc51872
445 *
446 * ospf6
447 * Ospf6 pointer.
448 *
449 * nbr
450 * Ospf6 neighbour for which it is acting as HELPER.
451 *
452 * reason
453 * The reason for exiting from HELPER.
454 *
455 * Returns:
456 * Nothing.
457 */
458 void ospf6_gr_helper_exit(struct ospf6_neighbor *nbr,
459 enum ospf6_helper_exit_reason reason)
460 {
461 struct ospf6_interface *oi = nbr->ospf6_if;
462 struct ospf6 *ospf6;
463
464 if (!oi)
465 return;
466
467 ospf6 = oi->area->ospf6;
468
469 if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr))
470 return;
471
472 if (IS_DEBUG_OSPF6_GR)
473 zlog_debug("%s, Exiting from HELPER support to %pI6, due to %s",
474 __func__, &nbr->linklocal_addr,
475 ospf6_exit_reason_desc[reason]);
476
477 /* Reset helper status*/
478 nbr->gr_helper_info.gr_helper_status = OSPF6_GR_NOT_HELPER;
479 nbr->gr_helper_info.helper_exit_reason = reason;
480 nbr->gr_helper_info.actual_grace_period = 0;
481 nbr->gr_helper_info.recvd_grace_period = 0;
482 nbr->gr_helper_info.gr_restart_reason = 0;
483 ospf6->ospf6_helper_cfg.last_exit_reason = reason;
484
485 /* If the exit not triggered due to grace timer
486 * expiry, stop the grace timer.
487 */
488 if (reason != OSPF6_GR_HELPER_GRACE_TIMEOUT)
489 THREAD_OFF(nbr->gr_helper_info.t_grace_timer);
490
491 if (ospf6->ospf6_helper_cfg.active_restarter_cnt <= 0) {
492 zlog_err(
493 "OSPF6 GR-Helper: Number of active Restarters should be greater than zero.");
494 return;
495 }
496 /* Decrement active restarter count */
497 ospf6->ospf6_helper_cfg.active_restarter_cnt--;
498
499 /* check exit triggered due to successful completion
500 * of graceful restart.
501 */
502 if (reason != OSPF6_GR_HELPER_COMPLETED) {
503 if (IS_DEBUG_OSPF6_GR)
504 zlog_debug("%s, Unsuccessful GR exit. RESTARTER : %pI6",
505 __func__, &nbr->linklocal_addr);
506 }
507
508 /*Recalculate the DR for the network segment */
509 dr_election(oi);
510
511 /* Originate a router LSA */
512 OSPF6_ROUTER_LSA_SCHEDULE(nbr->ospf6_if->area);
513
514 /* Originate network lsa if it is an DR in the LAN */
515 if (nbr->ospf6_if->state == OSPF6_INTERFACE_DR)
516 OSPF6_NETWORK_LSA_SCHEDULE(nbr->ospf6_if);
517 }
518
519 /*
520 * Process max age Grace LSA.
521 * It is a indication for successful completion of GR.
522 * If router acting as HELPER, It exits from helper role.
523 *
524 * ospf6
525 * Ospf6 pointer.
526 *
527 * lsa
528 * Grace LSA received from RESTARTER.
529 *
530 * nbr
531 * ospf6 neighbour which request the router to act as
532 * HELPER.
533 *
534 * Returns:
535 * Nothing.
536 */
537 void ospf6_process_maxage_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa,
538 struct ospf6_neighbor *restarter)
539 {
540 uint8_t restart_reason = 0;
541 uint32_t grace_interval = 0;
542 int ret;
543
544 /* Extract the grace lsa packet fields */
545 ret = ospf6_extract_grace_lsa_fields(lsa, &grace_interval,
546 &restart_reason);
547 if (ret != OSPF6_SUCCESS) {
548 if (IS_DEBUG_OSPF6_GR)
549 zlog_debug("%s, Wrong Grace LSA packet.", __func__);
550 return;
551 }
552
553 if (IS_DEBUG_OSPF6_GR)
554 zlog_debug("%s, GraceLSA received for neighbour %pI4.",
555 __func__, &restarter->router_id);
556
557 ospf6_gr_helper_exit(restarter, OSPF6_GR_HELPER_COMPLETED);
558 }
559
560 /*
561 * Actions to be taken when topo change detected
562 * HELPER will be exited upon a topo change.
563 *
564 * ospf6
565 * ospf6 pointer
566 * lsa
567 * topo change occurred due to this lsa(type (1-5 and 7)
568 *
569 * Returns:
570 * Nothing
571 */
572 void ospf6_helper_handle_topo_chg(struct ospf6 *ospf6, struct ospf6_lsa *lsa)
573 {
574 struct listnode *i, *j, *k;
575 struct ospf6_neighbor *nbr = NULL;
576 struct ospf6_area *oa = NULL;
577 struct ospf6_interface *oi = NULL;
578
579 if (!ospf6->ospf6_helper_cfg.active_restarter_cnt)
580 return;
581
582 /* Topo change not required to be handled if strict
583 * LSA check is disabled for this router.
584 */
585 if (!ospf6->ospf6_helper_cfg.strict_lsa_check)
586 return;
587
588 if (IS_DEBUG_OSPF6_GR)
589 zlog_debug("%s, Topo change detected due to lsa details : %s",
590 __func__, lsa->name);
591
592 lsa->tobe_acknowledged = OSPF6_TRUE;
593
594 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
595 for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) {
596
597 /* Ref rfc3623 section 3.2.3.b and rfc5187
598 * If change due to external LSA and if the area is
599 * stub, then it is not a topo change. Since Type-5
600 * lsas will not be flooded in stub area.
601 */
602 if (IS_AREA_STUB(oi->area)
603 && ((lsa->header->type == OSPF6_LSTYPE_AS_EXTERNAL)
604 || (lsa->header->type == OSPF6_LSTYPE_TYPE_7)
605 || (lsa->header->type
606 == OSPF6_LSTYPE_INTER_ROUTER))) {
607 continue;
608 }
609
610 for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, nbr)) {
611
612 ospf6_gr_helper_exit(nbr,
613 OSPF6_GR_HELPER_TOPO_CHG);
614 }
615 }
616 }
617
618 /* Configuration handlers */
619 /*
620 * Disable/Enable HELPER support on router level.
621 *
622 * ospf6
623 * Ospf6 pointer.
624 *
625 * status
626 * TRUE/FALSE
627 *
628 * Returns:
629 * Nothing.
630 */
631 static void ospf6_gr_helper_support_set(struct ospf6 *ospf6, bool support)
632 {
633 struct ospf6_interface *oi;
634 struct advRtr lookup;
635 struct listnode *i, *j, *k;
636 struct ospf6_neighbor *nbr = NULL;
637 struct ospf6_area *oa = NULL;
638
639 if (ospf6->ospf6_helper_cfg.is_helper_supported == support)
640 return;
641
642 ospf6->ospf6_helper_cfg.is_helper_supported = support;
643
644 /* If helper support disabled, cease HELPER role for all
645 * supporting neighbors.
646 */
647 if (support == OSPF6_FALSE) {
648 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
649 for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) {
650
651 for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k,
652 nbr)) {
653
654 lookup.advRtrAddr = nbr->router_id;
655 /* check if helper support enabled for
656 * the corresponding routerid.
657 * If enabled,
658 * dont exit from helper role.
659 */
660 if (hash_lookup(
661 ospf6->ospf6_helper_cfg
662 .enable_rtr_list,
663 &lookup))
664 continue;
665
666 ospf6_gr_helper_exit(
667 nbr, OSPF6_GR_HELPER_TOPO_CHG);
668 }
669 }
670 }
671 }
672
673 /*
674 * Api to enable/disable strict lsa check on the HELPER.
675 *
676 * ospf6
677 * Ospf6 pointer.
678 *
679 * enabled
680 * True - disable the lsa check.
681 * False - enable the strict lsa check.
682 *
683 * Returns:
684 * Nothing.
685 */
686 static void ospf6_gr_helper_lsacheck_set(struct ospf6 *ospf6, bool enabled)
687 {
688 if (ospf6->ospf6_helper_cfg.strict_lsa_check == enabled)
689 return;
690
691 ospf6->ospf6_helper_cfg.strict_lsa_check = enabled;
692 }
693
694 /*
695 * Api to set the supported restart reason.
696 *
697 * ospf6
698 * Ospf6 pointer.
699 *
700 * only_planned
701 * True: support only planned restart.
702 * False: support for planned/unplanned restarts.
703 *
704 * Returns:
705 * Nothing.
706 */
707
708 static void
709 ospf6_gr_helper_set_supported_onlyPlanned_restart(struct ospf6 *ospf6,
710 bool only_planned)
711 {
712 ospf6->ospf6_helper_cfg.only_planned_restart = only_planned;
713 }
714
715 /*
716 * Api to set the supported grace interval in this router.
717 *
718 * ospf6
719 * Ospf6 pointer.
720 *
721 * interval
722 * The supported grace interval..
723 *
724 * Returns:
725 * Nothing.
726 */
727 static void ospf6_gr_helper_supported_gracetime_set(struct ospf6 *ospf6,
728 uint32_t interval)
729 {
730 ospf6->ospf6_helper_cfg.supported_grace_time = interval;
731 }
732
733 /* API to walk and print all the Helper supported router ids */
734 static int ospf6_print_vty_helper_dis_rtr_walkcb(struct hash_bucket *bucket,
735 void *arg)
736 {
737 struct advRtr *rtr = bucket->data;
738 struct vty *vty = (struct vty *)arg;
739 static unsigned int count;
740
741 vty_out(vty, "%-6pI4,", &rtr->advRtrAddr);
742 count++;
743
744 if (count % 5 == 0)
745 vty_out(vty, "\n");
746
747 return HASHWALK_CONTINUE;
748 }
749
750 /* API to walk and print all the Helper supported router ids.*/
751 static int ospf6_print_json_helper_dis_rtr_walkcb(struct hash_bucket *bucket,
752 void *arg)
753 {
754 struct advRtr *rtr = bucket->data;
755 struct json_object *json_rid_array = (struct json_object *)arg;
756 struct json_object *json_rid;
757 char router_id[16];
758
759 inet_ntop(AF_INET, &rtr->advRtrAddr, router_id, sizeof(router_id));
760
761 json_rid = json_object_new_object();
762
763 json_object_string_add(json_rid, "routerId", router_id);
764 json_object_array_add(json_rid_array, json_rid);
765
766 return HASHWALK_CONTINUE;
767 }
768
769 /*
770 * Enable/Disable HELPER support on a specified advertisement
771 * router.
772 *
773 * ospf6
774 * Ospf6 pointer.
775 *
776 * advRtr
777 * HELPER support for given Advertisement Router.
778 *
779 * support
780 * True - Enable Helper Support.
781 * False - Disable Helper Support.
782 *
783 * Returns:
784 * Nothing.
785 */
786 static void ospf6_gr_helper_support_set_per_routerid(struct ospf6 *ospf6,
787 struct in_addr router_id,
788 bool support)
789 {
790 struct advRtr temp;
791 struct advRtr *rtr;
792 struct listnode *i, *j, *k;
793 struct ospf6_interface *oi;
794 struct ospf6_neighbor *nbr;
795 struct ospf6_area *oa;
796
797 temp.advRtrAddr = router_id.s_addr;
798
799 if (support == OSPF6_FALSE) {
800 /*Delete the routerid from the enable router hash table */
801 rtr = hash_lookup(ospf6->ospf6_helper_cfg.enable_rtr_list,
802 &temp);
803
804 if (rtr) {
805 hash_release(ospf6->ospf6_helper_cfg.enable_rtr_list,
806 rtr);
807 ospf6_disable_rtr_hash_free(rtr);
808 }
809
810 /* If helper support is enabled globally
811 * no action is required.
812 */
813 if (ospf6->ospf6_helper_cfg.is_helper_supported)
814 return;
815
816 /* Cease the HELPER role fore neighbours from the
817 * specified advertisement router.
818 */
819 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
820 for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) {
821
822 for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k,
823 nbr)) {
824
825 if (nbr->router_id != router_id.s_addr)
826 continue;
827
828 if (OSPF6_GR_IS_ACTIVE_HELPER(nbr))
829 ospf6_gr_helper_exit(
830 nbr,
831 OSPF6_GR_HELPER_TOPO_CHG);
832 }
833 }
834
835 } else {
836 /* Add the routerid to the enable router hash table */
837 (void)hash_get(ospf6->ospf6_helper_cfg.enable_rtr_list, &temp,
838 ospf6_enable_rtr_hash_alloc);
839 }
840 }
841
842 static void show_ospfv6_gr_helper_per_nbr(struct vty *vty, json_object *json,
843 bool uj, struct ospf6_neighbor *nbr)
844 {
845 if (!uj) {
846 vty_out(vty, " Routerid : %pI4\n", &nbr->router_id);
847 vty_out(vty, " Received Grace period : %d(in seconds).\n",
848 nbr->gr_helper_info.recvd_grace_period);
849 vty_out(vty, " Actual Grace period : %d(in seconds)\n",
850 nbr->gr_helper_info.actual_grace_period);
851 vty_out(vty, " Remaining GraceTime:%ld(in seconds).\n",
852 thread_timer_remain_second(
853 nbr->gr_helper_info.t_grace_timer));
854 vty_out(vty, " Graceful Restart reason: %s.\n\n",
855 ospf6_restart_reason_desc[nbr->gr_helper_info
856 .gr_restart_reason]);
857 } else {
858 char nbrid[16];
859 json_object *json_neigh = NULL;
860
861 inet_ntop(AF_INET, &nbr->router_id, nbrid, sizeof(nbrid));
862 json_neigh = json_object_new_object();
863 json_object_string_add(json_neigh, "routerid", nbrid);
864 json_object_int_add(json_neigh, "recvdGraceInterval",
865 nbr->gr_helper_info.recvd_grace_period);
866 json_object_int_add(json_neigh, "actualGraceInterval",
867 nbr->gr_helper_info.actual_grace_period);
868 json_object_int_add(json_neigh, "remainGracetime",
869 thread_timer_remain_second(
870 nbr->gr_helper_info.t_grace_timer));
871 json_object_string_add(json_neigh, "restartReason",
872 ospf6_restart_reason_desc[
873 nbr->gr_helper_info.gr_restart_reason]);
874 json_object_object_add(json, nbr->name, json_neigh);
875 }
876 }
877
878 static void show_ospf6_gr_helper_details(struct vty *vty, struct ospf6 *ospf6,
879 json_object *json, bool uj, bool detail)
880 {
881 struct ospf6_interface *oi;
882
883 /* Show Router ID. */
884 if (uj) {
885 char router_id[16];
886
887 inet_ntop(AF_INET, &ospf6->router_id, router_id,
888 sizeof(router_id));
889 json_object_string_add(json, "routerId", router_id);
890 } else
891 vty_out(vty,
892 " OSPFv3 Routing Process (0) with Router-ID %pI4\n",
893 &ospf6->router_id);
894
895 if (!uj) {
896
897 if (ospf6->ospf6_helper_cfg.is_helper_supported)
898 vty_out(vty,
899 " Graceful restart helper support enabled.\n");
900 else
901 vty_out(vty,
902 " Graceful restart helper support disabled.\n");
903
904 if (ospf6->ospf6_helper_cfg.strict_lsa_check)
905 vty_out(vty, " Strict LSA check is enabled.\n");
906 else
907 vty_out(vty, " Strict LSA check is disabled.\n");
908
909 if (ospf6->ospf6_helper_cfg.only_planned_restart)
910 vty_out(vty,
911 " Helper supported for planned restarts only.\n");
912 else
913 vty_out(vty,
914 " Helper supported for Planned and Unplanned Restarts.\n");
915
916 vty_out(vty,
917 " Supported Graceful restart interval: %d(in seconds).\n",
918 ospf6->ospf6_helper_cfg.supported_grace_time);
919
920 if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf)) {
921 vty_out(vty, " Enable Router list:\n");
922 vty_out(vty, " ");
923 hash_walk(ospf6->ospf6_helper_cfg.enable_rtr_list,
924 ospf6_print_vty_helper_dis_rtr_walkcb, vty);
925 vty_out(vty, "\n\n");
926 }
927
928 if (ospf6->ospf6_helper_cfg.last_exit_reason
929 != OSPF6_GR_HELPER_EXIT_NONE) {
930 vty_out(vty, " Last Helper exit Reason :%s\n",
931 ospf6_exit_reason_desc
932 [ospf6->ospf6_helper_cfg
933 .last_exit_reason]);
934
935 if (ospf6->ospf6_helper_cfg.active_restarter_cnt)
936 vty_out(vty,
937 " Number of Active neighbours in graceful restart: %d\n",
938 ospf6->ospf6_helper_cfg
939 .active_restarter_cnt);
940 else
941 vty_out(vty, "\n");
942 }
943
944
945 } else {
946 json_object_string_add(
947 json, "helperSupport",
948 (ospf6->ospf6_helper_cfg.is_helper_supported)
949 ? "Enabled"
950 : "Disabled");
951 json_object_string_add(
952 json, "strictLsaCheck",
953 (ospf6->ospf6_helper_cfg.strict_lsa_check)
954 ? "Enabled"
955 : "Disabled");
956 json_object_string_add(
957 json, "restartSupoort",
958 (ospf6->ospf6_helper_cfg.only_planned_restart)
959 ? "Planned Restart only"
960 : "Planned and Unplanned Restarts");
961
962 json_object_int_add(
963 json, "supportedGracePeriod",
964 ospf6->ospf6_helper_cfg.supported_grace_time);
965
966 #if CONFDATE > 20230131
967 CPP_NOTICE("Remove JSON object commands with keys starting with capital")
968 #endif
969 if (ospf6->ospf6_helper_cfg.last_exit_reason !=
970 OSPF6_GR_HELPER_EXIT_NONE) {
971 json_object_string_add(
972 json, "LastExitReason",
973 ospf6_exit_reason_desc
974 [ospf6->ospf6_helper_cfg
975 .last_exit_reason]);
976 json_object_string_add(
977 json, "lastExitReason",
978 ospf6_exit_reason_desc
979 [ospf6->ospf6_helper_cfg
980 .last_exit_reason]);
981 }
982
983 if (ospf6->ospf6_helper_cfg.active_restarter_cnt)
984 json_object_int_add(
985 json, "activeRestarterCnt",
986 ospf6->ospf6_helper_cfg.active_restarter_cnt);
987
988 if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6)) {
989 struct json_object *json_rid_array =
990 json_object_new_array();
991
992 json_object_object_add(json, "enabledRouterIds",
993 json_rid_array);
994
995 hash_walk(ospf6->ospf6_helper_cfg.enable_rtr_list,
996 ospf6_print_json_helper_dis_rtr_walkcb,
997 json_rid_array);
998 }
999 }
1000
1001 if (detail) {
1002 int cnt = 1;
1003 struct listnode *i, *j, *k;
1004 struct ospf6_area *oa;
1005 json_object *json_neighbors = NULL;
1006
1007 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
1008 for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) {
1009 struct ospf6_neighbor *nbr;
1010
1011 if (uj) {
1012 json_object_object_get_ex(
1013 json, "Neighbors",
1014 &json_neighbors);
1015 json_object_object_get_ex(
1016 json, "neighbors",
1017 &json_neighbors);
1018 if (!json_neighbors) {
1019 json_neighbors =
1020 json_object_new_object();
1021 json_object_object_add(
1022 json, "Neighbors",
1023 json_neighbors);
1024 json_object_object_add(
1025 json, "neighbors",
1026 json_neighbors);
1027 }
1028 }
1029
1030 for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k,
1031 nbr)) {
1032
1033 if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr))
1034 continue;
1035
1036 if (!uj)
1037 vty_out(vty,
1038 " Neighbour %d :\n",
1039 cnt++);
1040
1041 show_ospfv6_gr_helper_per_nbr(
1042 vty, json_neighbors, uj, nbr);
1043
1044 }
1045 }
1046 }
1047 }
1048
1049 /* Graceful Restart HELPER config Commands */
1050 DEFPY(ospf6_gr_helper_enable,
1051 ospf6_gr_helper_enable_cmd,
1052 "graceful-restart helper enable [A.B.C.D$rtr_id]",
1053 "ospf6 graceful restart\n"
1054 "ospf6 GR Helper\n"
1055 "Enable Helper support\n"
1056 "Advertisement Router-ID\n")
1057 {
1058 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1059
1060 if (rtr_id_str != NULL) {
1061
1062 ospf6_gr_helper_support_set_per_routerid(ospf6, rtr_id,
1063 OSPF6_TRUE);
1064
1065 return CMD_SUCCESS;
1066 }
1067
1068 ospf6_gr_helper_support_set(ospf6, OSPF6_TRUE);
1069
1070 return CMD_SUCCESS;
1071 }
1072
1073 DEFPY(ospf6_gr_helper_disable,
1074 ospf6_gr_helper_disable_cmd,
1075 "no graceful-restart helper enable [A.B.C.D$rtr_id]",
1076 NO_STR
1077 "ospf6 graceful restart\n"
1078 "ospf6 GR Helper\n"
1079 "Enable Helper support\n"
1080 "Advertisement Router-ID\n")
1081 {
1082 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1083
1084 if (rtr_id_str != NULL) {
1085
1086 ospf6_gr_helper_support_set_per_routerid(ospf6, rtr_id,
1087 OSPF6_FALSE);
1088
1089 return CMD_SUCCESS;
1090 }
1091
1092 ospf6_gr_helper_support_set(ospf6, OSPF6_FALSE);
1093
1094 return CMD_SUCCESS;
1095 }
1096
1097 DEFPY(ospf6_gr_helper_disable_lsacheck,
1098 ospf6_gr_helper_disable_lsacheck_cmd,
1099 "graceful-restart helper lsa-check-disable",
1100 "ospf6 graceful restart\n"
1101 "ospf6 GR Helper\n"
1102 "disable strict LSA check\n")
1103 {
1104 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1105
1106 ospf6_gr_helper_lsacheck_set(ospf6, OSPF6_FALSE);
1107 return CMD_SUCCESS;
1108 }
1109
1110 DEFPY(no_ospf6_gr_helper_disable_lsacheck,
1111 no_ospf6_gr_helper_disable_lsacheck_cmd,
1112 "no graceful-restart helper lsa-check-disable",
1113 NO_STR
1114 "ospf6 graceful restart\n"
1115 "ospf6 GR Helper\n"
1116 "diasble strict LSA check\n")
1117 {
1118 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1119
1120 ospf6_gr_helper_lsacheck_set(ospf6, OSPF6_TRUE);
1121 return CMD_SUCCESS;
1122 }
1123
1124 DEFPY(ospf6_gr_helper_planned_only,
1125 ospf6_gr_helper_planned_only_cmd,
1126 "graceful-restart helper planned-only",
1127 "ospf6 graceful restart\n"
1128 "ospf6 GR Helper\n"
1129 "supported only planned restart\n")
1130 {
1131 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1132
1133 ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6, OSPF6_TRUE);
1134
1135 return CMD_SUCCESS;
1136 }
1137
1138 DEFPY(no_ospf6_gr_helper_planned_only, no_ospf6_gr_helper_planned_only_cmd,
1139 "no graceful-restart helper planned-only",
1140 NO_STR
1141 "ospf6 graceful restart\n"
1142 "ospf6 GR Helper\n"
1143 "supported only for planned restart\n")
1144 {
1145 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1146
1147 ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6, OSPF6_FALSE);
1148
1149 return CMD_SUCCESS;
1150 }
1151
1152 DEFPY(ospf6_gr_helper_supported_grace_time,
1153 ospf6_gr_helper_supported_grace_time_cmd,
1154 "graceful-restart helper supported-grace-time (10-1800)$interval",
1155 "ospf6 graceful restart\n"
1156 "ospf6 GR Helper\n"
1157 "supported grace timer\n"
1158 "grace interval(in seconds)\n")
1159 {
1160 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1161
1162 ospf6_gr_helper_supported_gracetime_set(ospf6, interval);
1163 return CMD_SUCCESS;
1164 }
1165
1166 DEFPY(no_ospf6_gr_helper_supported_grace_time,
1167 no_ospf6_gr_helper_supported_grace_time_cmd,
1168 "no graceful-restart helper supported-grace-time (10-1800)$interval",
1169 NO_STR
1170 "ospf6 graceful restart\n"
1171 "ospf6 GR Helper\n"
1172 "supported grace timer\n"
1173 "grace interval(in seconds)\n")
1174 {
1175 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1176
1177 ospf6_gr_helper_supported_gracetime_set(ospf6,
1178 OSPF6_MAX_GRACE_INTERVAL);
1179 return CMD_SUCCESS;
1180 }
1181
1182 /* Show commands */
1183 DEFPY(show_ipv6_ospf6_gr_helper,
1184 show_ipv6_ospf6_gr_helper_cmd,
1185 "show ipv6 ospf6 graceful-restart helper [detail] [json]",
1186 SHOW_STR
1187 "Ipv6 Information\n"
1188 "OSPF6 information\n"
1189 "ospf6 graceful restart\n"
1190 "helper details in the router\n"
1191 "detailed information\n" JSON_STR)
1192 {
1193 int idx = 0;
1194 bool uj = use_json(argc, argv);
1195 struct ospf6 *ospf6 = NULL;
1196 json_object *json = NULL;
1197 bool detail = false;
1198
1199 ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
1200 if (ospf6 == NULL) {
1201 vty_out(vty, "OSPFv3 is not configured\n");
1202 return CMD_SUCCESS;
1203 }
1204
1205 if (argv_find(argv, argc, "detail", &idx))
1206 detail = true;
1207
1208 if (uj)
1209 json = json_object_new_object();
1210
1211 show_ospf6_gr_helper_details(vty, ospf6, json, uj, detail);
1212
1213 if (uj)
1214 vty_json(vty, json);
1215
1216 return CMD_SUCCESS;
1217 }
1218
1219 /* Debug commands */
1220 DEFPY(debug_ospf6_gr, debug_ospf6_gr_cmd,
1221 "[no$no] debug ospf6 graceful-restart",
1222 NO_STR DEBUG_STR OSPF6_STR "Graceful restart\n")
1223 {
1224 if (!no)
1225 OSPF6_DEBUG_GR_ON();
1226 else
1227 OSPF6_DEBUG_GR_OFF();
1228
1229 return CMD_SUCCESS;
1230 }
1231
1232 /*
1233 * Api to display the grace LSA information.
1234 *
1235 * vty
1236 * vty pointer.
1237 * lsa
1238 * Grace LSA.
1239 * json
1240 * json object
1241 *
1242 * Returns:
1243 * Nothing.
1244 */
1245 static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa,
1246 json_object *json, bool use_json)
1247 {
1248 struct ospf6_lsa_header *lsah = NULL;
1249 struct tlv_header *tlvh = NULL;
1250 struct grace_tlv_graceperiod *gracePeriod;
1251 struct grace_tlv_restart_reason *grReason;
1252 uint16_t length = 0;
1253 int sum = 0;
1254
1255 lsah = (struct ospf6_lsa_header *)lsa->header;
1256 if (ntohs(lsah->length) <= OSPF6_LSA_HEADER_SIZE) {
1257 if (IS_DEBUG_OSPF6_GR)
1258 zlog_debug("%s: undersized (%u B) lsa", __func__,
1259 ntohs(lsah->length));
1260 return OSPF6_FAILURE;
1261 }
1262
1263 length = ntohs(lsah->length) - OSPF6_LSA_HEADER_SIZE;
1264
1265 if (vty) {
1266 if (!use_json)
1267 vty_out(vty, "TLV info:\n");
1268 } else {
1269 zlog_debug(" TLV info:");
1270 }
1271
1272 for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
1273 tlvh = TLV_HDR_NEXT(tlvh)) {
1274
1275 /* Check TLV len */
1276 if (sum + TLV_SIZE(tlvh) > length) {
1277 if (vty)
1278 vty_out(vty, "%% Invalid TLV length: %d\n",
1279 TLV_SIZE(tlvh));
1280 else if (IS_DEBUG_OSPF6_GR)
1281 zlog_debug("%% Invalid TLV length: %d",
1282 TLV_SIZE(tlvh));
1283 return OSPF6_FAILURE;
1284 }
1285
1286 switch (ntohs(tlvh->type)) {
1287 case GRACE_PERIOD_TYPE:
1288 gracePeriod = (struct grace_tlv_graceperiod *)tlvh;
1289 sum += TLV_SIZE(tlvh);
1290
1291 if (vty) {
1292 if (use_json)
1293 json_object_int_add(
1294 json, "gracePeriod",
1295 ntohl(gracePeriod->interval));
1296 else
1297 vty_out(vty, " Grace period:%d\n",
1298 ntohl(gracePeriod->interval));
1299 } else {
1300 zlog_debug(" Grace period:%d",
1301 ntohl(gracePeriod->interval));
1302 }
1303 break;
1304 case RESTART_REASON_TYPE:
1305 grReason = (struct grace_tlv_restart_reason *)tlvh;
1306 sum += TLV_SIZE(tlvh);
1307 if (vty) {
1308 if (use_json)
1309 json_object_string_add(
1310 json, "restartReason",
1311 ospf6_restart_reason_desc
1312 [grReason->reason]);
1313 else
1314 vty_out(vty, " Restart reason:%s\n",
1315 ospf6_restart_reason_desc
1316 [grReason->reason]);
1317 } else {
1318 zlog_debug(" Restart reason:%s",
1319 ospf6_restart_reason_desc
1320 [grReason->reason]);
1321 }
1322 break;
1323 default:
1324 break;
1325 }
1326 }
1327
1328 return 0;
1329 }
1330
1331 void ospf6_gr_helper_config_init(void)
1332 {
1333
1334 ospf6_install_lsa_handler(&grace_lsa_handler);
1335
1336 install_element(OSPF6_NODE, &ospf6_gr_helper_enable_cmd);
1337 install_element(OSPF6_NODE, &ospf6_gr_helper_disable_cmd);
1338 install_element(OSPF6_NODE, &ospf6_gr_helper_disable_lsacheck_cmd);
1339 install_element(OSPF6_NODE, &no_ospf6_gr_helper_disable_lsacheck_cmd);
1340 install_element(OSPF6_NODE, &ospf6_gr_helper_planned_only_cmd);
1341 install_element(OSPF6_NODE, &no_ospf6_gr_helper_planned_only_cmd);
1342 install_element(OSPF6_NODE, &ospf6_gr_helper_supported_grace_time_cmd);
1343 install_element(OSPF6_NODE,
1344 &no_ospf6_gr_helper_supported_grace_time_cmd);
1345
1346 install_element(VIEW_NODE, &show_ipv6_ospf6_gr_helper_cmd);
1347
1348 install_element(CONFIG_NODE, &debug_ospf6_gr_cmd);
1349 install_element(ENABLE_NODE, &debug_ospf6_gr_cmd);
1350 }
1351
1352
1353 /*
1354 * Initialize GR helper config data structure.
1355 *
1356 * ospf6
1357 * ospf6 pointer
1358 *
1359 * Returns:
1360 * Nothing
1361 */
1362 void ospf6_gr_helper_init(struct ospf6 *ospf6)
1363 {
1364 if (IS_DEBUG_OSPF6_GR)
1365 zlog_debug("%s, GR Helper init.", __func__);
1366
1367 ospf6->ospf6_helper_cfg.is_helper_supported = OSPF6_FALSE;
1368 ospf6->ospf6_helper_cfg.strict_lsa_check = OSPF6_TRUE;
1369 ospf6->ospf6_helper_cfg.only_planned_restart = OSPF6_FALSE;
1370 ospf6->ospf6_helper_cfg.supported_grace_time = OSPF6_MAX_GRACE_INTERVAL;
1371 ospf6->ospf6_helper_cfg.last_exit_reason = OSPF6_GR_HELPER_EXIT_NONE;
1372 ospf6->ospf6_helper_cfg.active_restarter_cnt = 0;
1373
1374 ospf6->ospf6_helper_cfg.enable_rtr_list = hash_create(
1375 ospf6_enable_rtr_hash_key, ospf6_enable_rtr_hash_cmp,
1376 "Ospf6 enable router hash");
1377 }
1378
1379 /*
1380 * De-initialize GR helper config data structure.
1381 *
1382 * ospf6
1383 * ospf6 pointer
1384 *
1385 * Returns:
1386 * Nothing
1387 */
1388 void ospf6_gr_helper_deinit(struct ospf6 *ospf6)
1389 {
1390
1391 if (IS_DEBUG_OSPF6_GR)
1392 zlog_debug("%s, GR helper deinit.", __func__);
1393
1394 ospf6_enable_rtr_hash_destroy(ospf6);
1395 }
1396
1397 static int ospf6_cfg_write_helper_enable_rtr_walkcb(struct hash_bucket *backet,
1398 void *arg)
1399 {
1400 struct advRtr *rtr = backet->data;
1401 struct vty *vty = (struct vty *)arg;
1402
1403 vty_out(vty, " graceful-restart helper enable %pI4\n", &rtr->advRtrAddr);
1404 return HASHWALK_CONTINUE;
1405 }
1406
1407 int config_write_ospf6_gr_helper(struct vty *vty, struct ospf6 *ospf6)
1408 {
1409 if (ospf6->ospf6_helper_cfg.is_helper_supported)
1410 vty_out(vty, " graceful-restart helper enable\n");
1411
1412 if (!ospf6->ospf6_helper_cfg.strict_lsa_check)
1413 vty_out(vty, " graceful-restart helper lsa-check-disable\n");
1414
1415 if (ospf6->ospf6_helper_cfg.only_planned_restart)
1416 vty_out(vty, " graceful-restart helper planned-only\n");
1417
1418 if (ospf6->ospf6_helper_cfg.supported_grace_time
1419 != OSPF6_MAX_GRACE_INTERVAL)
1420 vty_out(vty,
1421 " graceful-restart helper supported-grace-time %d\n",
1422 ospf6->ospf6_helper_cfg.supported_grace_time);
1423
1424 if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6)) {
1425 hash_walk(ospf6->ospf6_helper_cfg.enable_rtr_list,
1426 ospf6_cfg_write_helper_enable_rtr_walkcb, vty);
1427 }
1428
1429 return 0;
1430 }
1431
1432 int config_write_ospf6_debug_gr_helper(struct vty *vty)
1433 {
1434 if (IS_DEBUG_OSPF6_GR)
1435 vty_out(vty, "debug ospf6 graceful-restart\n");
1436 return 0;
1437 }