2 * OSPF6 Graceful Restart helper functions.
4 * Copyright (C) 2021-22 Vmware, Inc.
7 * This file is part of GNU Zebra.
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
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.
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
35 #include "lib_errors.h"
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"
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"
52 #ifndef VTYSH_EXTRACT_PL
53 #include "ospf6d/ospf6_gr_helper_clippy.c"
56 DEFINE_MTYPE_STATIC(OSPF6D
, OSPF6_GR_HELPER
, "OSPF6 Graceful restart helper");
58 unsigned char conf_debug_ospf6_gr
;
60 static int ospf6_grace_lsa_show_info(struct vty
*vty
, struct ospf6_lsa
*lsa
,
61 json_object
*json
, bool use_json
);
63 struct ospf6_lsa_handler grace_lsa_handler
= {.lh_type
= OSPF6_LSTYPE_GRACE_LSA
,
65 .lh_short_name
= "GR",
67 ospf6_grace_lsa_show_info
,
68 .lh_get_prefix_str
= NULL
,
71 const char *ospf6_exit_reason_desc
[] = {
76 "Successful graceful restart",
79 const char *ospf6_restart_reason_desc
[] = {
82 "Software reload/upgrade",
83 "Switch to redundant control processor",
86 const char *ospf6_rejected_reason_desc
[] = {
88 "Helper support disabled",
89 "Neighbour is not in FULL state",
90 "Supports only planned restart but received for unplanned",
91 "Topo change due to change in lsa rxmt list",
92 "LSA age is more than Grace interval",
95 static unsigned int ospf6_enable_rtr_hash_key(const void *data
)
97 const struct advRtr
*rtr
= data
;
99 return jhash_1word(rtr
->advRtrAddr
, 0);
102 static bool ospf6_enable_rtr_hash_cmp(const void *d1
, const void *d2
)
104 const struct advRtr
*rtr1
= d1
;
105 const struct advRtr
*rtr2
= d2
;
107 return (rtr1
->advRtrAddr
== rtr2
->advRtrAddr
);
110 static void *ospf6_enable_rtr_hash_alloc(void *p
)
114 rid
= XCALLOC(MTYPE_OSPF6_GR_HELPER
, sizeof(struct advRtr
));
115 rid
->advRtrAddr
= ((struct advRtr
*)p
)->advRtrAddr
;
120 static void ospf6_disable_rtr_hash_free(void *rtr
)
122 XFREE(MTYPE_OSPF6_GR_HELPER
, rtr
);
125 static void ospf6_enable_rtr_hash_destroy(struct ospf6
*ospf6
)
127 if (ospf6
->ospf6_helper_cfg
.enable_rtr_list
== NULL
)
130 hash_clean(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
131 ospf6_disable_rtr_hash_free
);
132 hash_free(ospf6
->ospf6_helper_cfg
.enable_rtr_list
);
133 ospf6
->ospf6_helper_cfg
.enable_rtr_list
= NULL
;
137 * Extracting tlv info from GRACE LSA.
143 * interval : grace interval.
144 * reason : Restarting reason.
146 static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa
*lsa
,
147 uint32_t *interval
, uint8_t *reason
)
149 struct ospf6_lsa_header
*lsah
= NULL
;
150 struct tlv_header
*tlvh
= NULL
;
151 struct grace_tlv_graceperiod
*gracePeriod
;
152 struct grace_tlv_restart_reason
*grReason
;
156 lsah
= (struct ospf6_lsa_header
*)lsa
->header
;
157 if (ntohs(lsah
->length
) <= OSPF6_LSA_HEADER_SIZE
) {
158 if (IS_DEBUG_OSPF6_GR
)
159 zlog_debug("%s: undersized (%u B) lsa", __func__
,
160 ntohs(lsah
->length
));
161 return OSPF6_FAILURE
;
164 length
= ntohs(lsah
->length
) - OSPF6_LSA_HEADER_SIZE
;
166 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
&& tlvh
;
167 tlvh
= TLV_HDR_NEXT(tlvh
)) {
169 /* Check TLV len against overall LSA */
170 if (sum
+ TLV_SIZE(tlvh
) > length
) {
171 if (IS_DEBUG_OSPF6_GR
)
173 "%s: Malformed packet: Invalid TLV len:%d",
174 __func__
, TLV_SIZE(tlvh
));
175 return OSPF6_FAILURE
;
178 switch (ntohs(tlvh
->type
)) {
179 case GRACE_PERIOD_TYPE
:
180 gracePeriod
= (struct grace_tlv_graceperiod
*)tlvh
;
181 *interval
= ntohl(gracePeriod
->interval
);
182 sum
+= TLV_SIZE(tlvh
);
184 /* Check if grace interval is valid */
185 if (*interval
> OSPF6_MAX_GRACE_INTERVAL
186 || *interval
< OSPF6_MIN_GRACE_INTERVAL
)
187 return OSPF6_FAILURE
;
189 case RESTART_REASON_TYPE
:
190 grReason
= (struct grace_tlv_restart_reason
*)tlvh
;
191 *reason
= grReason
->reason
;
192 sum
+= TLV_SIZE(tlvh
);
194 if (*reason
>= OSPF6_GR_INVALID_REASON_CODE
)
195 return OSPF6_FAILURE
;
198 if (IS_DEBUG_OSPF6_GR
)
199 zlog_debug("%s, Ignoring unknown TLV type:%d",
200 __func__
, ntohs(tlvh
->type
));
204 return OSPF6_SUCCESS
;
208 * Grace timer expiry handler.
209 * HELPER aborts its role at grace timer expiry.
217 static void ospf6_handle_grace_timer_expiry(struct thread
*thread
)
219 struct ospf6_neighbor
*nbr
= THREAD_ARG(thread
);
221 ospf6_gr_helper_exit(nbr
, OSPF6_GR_HELPER_GRACE_TIMEOUT
);
225 * API to check any change in the neighbor's
226 * retransmission list.
232 * TRUE - if any change in the lsa.
233 * FALSE - no change in the lsas.
235 static bool ospf6_check_chg_in_rxmt_list(struct ospf6_neighbor
*nbr
)
237 struct ospf6_lsa
*lsa
, *lsanext
;
239 for (ALL_LSDB(nbr
->retrans_list
, lsa
, lsanext
)) {
240 struct ospf6_lsa
*lsa_in_db
= NULL
;
242 /* Fetching the same copy of LSA form LSDB to validate the
246 ospf6_lsdb_lookup(lsa
->header
->type
, lsa
->header
->id
,
247 lsa
->header
->adv_router
, lsa
->lsdb
);
249 if (lsa_in_db
&& lsa_in_db
->tobe_acknowledged
) {
250 ospf6_lsa_unlock(lsa
);
252 ospf6_lsa_unlock(lsanext
);
262 * Process Grace LSA.If it is eligible move to HELPER role.
263 * Ref rfc3623 section 3.1 and rfc5187
269 * Grace LSA received from RESTARTER.
272 * ospf6 neighbour which requests the router to act as
277 * If supported as HELPER : OSPF_GR_HELPER_INPROGRESS
278 * If Not supported as HELPER : OSPF_GR_HELPER_NONE
280 int ospf6_process_grace_lsa(struct ospf6
*ospf6
, struct ospf6_lsa
*lsa
,
281 struct ospf6_neighbor
*restarter
)
283 uint8_t restart_reason
= 0;
284 uint32_t grace_interval
= 0;
285 uint32_t actual_grace_interval
= 0;
286 struct advRtr lookup
;
289 /* Extract the grace lsa packet fields */
290 ret
= ospf6_extract_grace_lsa_fields(lsa
, &grace_interval
,
292 if (ret
!= OSPF6_SUCCESS
) {
293 if (IS_DEBUG_OSPF6_GR
)
294 zlog_debug("%s, Wrong Grace LSA packet.", __func__
);
295 return OSPF6_GR_NOT_HELPER
;
298 if (IS_DEBUG_OSPF6_GR
)
300 "%s, Grace LSA received from %pI4, grace interval:%u, restart reason :%s",
301 __func__
, &restarter
->router_id
, grace_interval
,
302 ospf6_restart_reason_desc
[restart_reason
]);
304 /* Verify Helper enabled globally */
305 if (!ospf6
->ospf6_helper_cfg
.is_helper_supported
) {
306 /* Verify Helper support is enabled for the
307 * current neighbour router-id.
309 lookup
.advRtrAddr
= restarter
->router_id
;
311 if (!hash_lookup(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
313 if (IS_DEBUG_OSPF6_GR
)
315 "%s, HELPER support is disabled, So not a HELPER",
317 restarter
->gr_helper_info
.rejected_reason
=
318 OSPF6_HELPER_SUPPORT_DISABLED
;
319 return OSPF6_GR_NOT_HELPER
;
323 /* Check neighbour is in FULL state and
324 * became a adjacency.
326 if (!IS_NBR_STATE_FULL(restarter
)) {
327 if (IS_DEBUG_OSPF6_GR
)
329 "%s, This Neighbour %pI6 is not in FULL state.",
330 __func__
, &restarter
->linklocal_addr
);
331 restarter
->gr_helper_info
.rejected_reason
=
332 OSPF6_HELPER_NOT_A_VALID_NEIGHBOUR
;
333 return OSPF6_GR_NOT_HELPER
;
336 /* Based on the restart reason from grace lsa
337 * check the current router is supporting or not
339 if (ospf6
->ospf6_helper_cfg
.only_planned_restart
340 && !OSPF6_GR_IS_PLANNED_RESTART(restart_reason
)) {
341 if (IS_DEBUG_OSPF6_GR
)
343 "%s, Router supports only planned restarts but received the GRACE LSA due to an unplanned restart",
345 restarter
->gr_helper_info
.rejected_reason
=
346 OSPF6_HELPER_PLANNED_ONLY_RESTART
;
347 return OSPF6_GR_NOT_HELPER
;
350 /* Check the retransmission list of this
351 * neighbour, check any change in lsas.
353 if (ospf6
->ospf6_helper_cfg
.strict_lsa_check
354 && restarter
->retrans_list
->count
355 && ospf6_check_chg_in_rxmt_list(restarter
)) {
356 if (IS_DEBUG_OSPF6_GR
)
358 "%s, Changed LSA in Rxmt list.So not Helper.",
360 restarter
->gr_helper_info
.rejected_reason
=
361 OSPF6_HELPER_TOPO_CHANGE_RTXMT_LIST
;
362 return OSPF6_GR_NOT_HELPER
;
365 /* LSA age must be less than the grace period */
366 if (ntohs(lsa
->header
->age
) >= grace_interval
) {
367 if (IS_DEBUG_OSPF6_GR
)
369 "%s, Grace LSA age(%d) is more than the grace interval(%d)",
370 __func__
, lsa
->header
->age
, grace_interval
);
371 restarter
->gr_helper_info
.rejected_reason
=
372 OSPF6_HELPER_LSA_AGE_MORE
;
373 return OSPF6_GR_NOT_HELPER
;
376 if (ospf6
->gr_info
.restart_in_progress
) {
377 if (IS_DEBUG_OSPF6_GR
)
379 "%s: router is in the process of graceful restart",
381 restarter
->gr_helper_info
.rejected_reason
=
382 OSPF6_HELPER_RESTARTING
;
383 return OSPF6_GR_NOT_HELPER
;
386 /* check supported grace period configured
387 * if configured, use this to start the grace
388 * timer otherwise use the interval received
389 * in grace LSA packet.
391 actual_grace_interval
= grace_interval
;
392 if (grace_interval
> ospf6
->ospf6_helper_cfg
.supported_grace_time
) {
393 if (IS_DEBUG_OSPF6_GR
)
395 "%s, Received grace period %d is larger than supported grace %d",
396 __func__
, grace_interval
,
397 ospf6
->ospf6_helper_cfg
.supported_grace_time
);
398 actual_grace_interval
=
399 ospf6
->ospf6_helper_cfg
.supported_grace_time
;
402 if (OSPF6_GR_IS_ACTIVE_HELPER(restarter
)) {
403 THREAD_OFF(restarter
->gr_helper_info
.t_grace_timer
);
405 if (ospf6
->ospf6_helper_cfg
.active_restarter_cnt
> 0)
406 ospf6
->ospf6_helper_cfg
.active_restarter_cnt
--;
408 if (IS_DEBUG_OSPF6_GR
)
410 "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
413 if (IS_DEBUG_OSPF6_GR
)
415 "%s, This Router becomes a HELPER for the neighbour %pI6",
416 __func__
, &restarter
->linklocal_addr
);
419 /* Became a Helper to the RESTART neighbour.
420 * change the helper status.
422 restarter
->gr_helper_info
.gr_helper_status
= OSPF6_GR_ACTIVE_HELPER
;
423 restarter
->gr_helper_info
.recvd_grace_period
= grace_interval
;
424 restarter
->gr_helper_info
.actual_grace_period
= actual_grace_interval
;
425 restarter
->gr_helper_info
.gr_restart_reason
= restart_reason
;
426 restarter
->gr_helper_info
.rejected_reason
= OSPF6_HELPER_REJECTED_NONE
;
428 /* Increment the active restart nbr count */
429 ospf6
->ospf6_helper_cfg
.active_restarter_cnt
++;
431 if (IS_DEBUG_OSPF6_GR
)
432 zlog_debug("%s, Grace timer started.interval:%u", __func__
,
433 actual_grace_interval
);
435 /* Start the grace timer */
436 thread_add_timer(master
, ospf6_handle_grace_timer_expiry
, restarter
,
437 actual_grace_interval
,
438 &restarter
->gr_helper_info
.t_grace_timer
);
440 return OSPF6_GR_ACTIVE_HELPER
;
444 * Api to exit from HELPER role to take all actions
446 * Ref rfc3623 section 3. and rfc51872
452 * Ospf6 neighbour for which it is acting as HELPER.
455 * The reason for exiting from HELPER.
460 void ospf6_gr_helper_exit(struct ospf6_neighbor
*nbr
,
461 enum ospf6_helper_exit_reason reason
)
463 struct ospf6_interface
*oi
= nbr
->ospf6_if
;
469 ospf6
= oi
->area
->ospf6
;
471 if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr
))
474 if (IS_DEBUG_OSPF6_GR
)
475 zlog_debug("%s, Exiting from HELPER support to %pI6, due to %s",
476 __func__
, &nbr
->linklocal_addr
,
477 ospf6_exit_reason_desc
[reason
]);
479 /* Reset helper status*/
480 nbr
->gr_helper_info
.gr_helper_status
= OSPF6_GR_NOT_HELPER
;
481 nbr
->gr_helper_info
.helper_exit_reason
= reason
;
482 nbr
->gr_helper_info
.actual_grace_period
= 0;
483 nbr
->gr_helper_info
.recvd_grace_period
= 0;
484 nbr
->gr_helper_info
.gr_restart_reason
= 0;
485 ospf6
->ospf6_helper_cfg
.last_exit_reason
= reason
;
487 /* If the exit not triggered due to grace timer
488 * expiry, stop the grace timer.
490 if (reason
!= OSPF6_GR_HELPER_GRACE_TIMEOUT
)
491 THREAD_OFF(nbr
->gr_helper_info
.t_grace_timer
);
493 if (ospf6
->ospf6_helper_cfg
.active_restarter_cnt
<= 0) {
495 "OSPF6 GR-Helper: Number of active Restarters should be greater than zero.");
498 /* Decrement active restarter count */
499 ospf6
->ospf6_helper_cfg
.active_restarter_cnt
--;
501 /* check exit triggered due to successful completion
502 * of graceful restart.
504 if (reason
!= OSPF6_GR_HELPER_COMPLETED
) {
505 if (IS_DEBUG_OSPF6_GR
)
506 zlog_debug("%s, Unsuccessful GR exit. RESTARTER : %pI6",
507 __func__
, &nbr
->linklocal_addr
);
510 /*Recalculate the DR for the network segment */
513 /* Originate a router LSA */
514 OSPF6_ROUTER_LSA_SCHEDULE(nbr
->ospf6_if
->area
);
516 /* Originate network lsa if it is an DR in the LAN */
517 if (nbr
->ospf6_if
->state
== OSPF6_INTERFACE_DR
)
518 OSPF6_NETWORK_LSA_SCHEDULE(nbr
->ospf6_if
);
522 * Process max age Grace LSA.
523 * It is a indication for successful completion of GR.
524 * If router acting as HELPER, It exits from helper role.
530 * Grace LSA received from RESTARTER.
533 * ospf6 neighbour which request the router to act as
539 void ospf6_process_maxage_grace_lsa(struct ospf6
*ospf6
, struct ospf6_lsa
*lsa
,
540 struct ospf6_neighbor
*restarter
)
542 uint8_t restart_reason
= 0;
543 uint32_t grace_interval
= 0;
546 /* Extract the grace lsa packet fields */
547 ret
= ospf6_extract_grace_lsa_fields(lsa
, &grace_interval
,
549 if (ret
!= OSPF6_SUCCESS
) {
550 if (IS_DEBUG_OSPF6_GR
)
551 zlog_debug("%s, Wrong Grace LSA packet.", __func__
);
555 if (IS_DEBUG_OSPF6_GR
)
556 zlog_debug("%s, GraceLSA received for neighbour %pI4.",
557 __func__
, &restarter
->router_id
);
559 ospf6_gr_helper_exit(restarter
, OSPF6_GR_HELPER_COMPLETED
);
563 * Actions to be taken when topo change detected
564 * HELPER will be exited upon a topo change.
569 * topo change occurred due to this lsa(type (1-5 and 7)
574 void ospf6_helper_handle_topo_chg(struct ospf6
*ospf6
, struct ospf6_lsa
*lsa
)
576 struct listnode
*i
, *j
, *k
;
577 struct ospf6_neighbor
*nbr
= NULL
;
578 struct ospf6_area
*oa
= NULL
;
579 struct ospf6_interface
*oi
= NULL
;
581 if (!ospf6
->ospf6_helper_cfg
.active_restarter_cnt
)
584 /* Topo change not required to be handled if strict
585 * LSA check is disabled for this router.
587 if (!ospf6
->ospf6_helper_cfg
.strict_lsa_check
)
590 if (IS_DEBUG_OSPF6_GR
)
591 zlog_debug("%s, Topo change detected due to lsa details : %s",
592 __func__
, lsa
->name
);
594 lsa
->tobe_acknowledged
= OSPF6_TRUE
;
596 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, i
, oa
))
597 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, j
, oi
)) {
599 /* Ref rfc3623 section 3.2.3.b and rfc5187
600 * If change due to external LSA and if the area is
601 * stub, then it is not a topo change. Since Type-5
602 * lsas will not be flooded in stub area.
604 if (IS_AREA_STUB(oi
->area
)
605 && ((lsa
->header
->type
== OSPF6_LSTYPE_AS_EXTERNAL
)
606 || (lsa
->header
->type
== OSPF6_LSTYPE_TYPE_7
)
607 || (lsa
->header
->type
608 == OSPF6_LSTYPE_INTER_ROUTER
))) {
612 for (ALL_LIST_ELEMENTS_RO(oi
->neighbor_list
, k
, nbr
)) {
614 ospf6_gr_helper_exit(nbr
,
615 OSPF6_GR_HELPER_TOPO_CHG
);
620 /* Configuration handlers */
622 * Disable/Enable HELPER support on router level.
633 static void ospf6_gr_helper_support_set(struct ospf6
*ospf6
, bool support
)
635 struct ospf6_interface
*oi
;
636 struct advRtr lookup
;
637 struct listnode
*i
, *j
, *k
;
638 struct ospf6_neighbor
*nbr
= NULL
;
639 struct ospf6_area
*oa
= NULL
;
641 if (ospf6
->ospf6_helper_cfg
.is_helper_supported
== support
)
644 ospf6
->ospf6_helper_cfg
.is_helper_supported
= support
;
646 /* If helper support disabled, cease HELPER role for all
647 * supporting neighbors.
649 if (support
== OSPF6_FALSE
) {
650 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, i
, oa
))
651 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, j
, oi
)) {
653 for (ALL_LIST_ELEMENTS_RO(oi
->neighbor_list
, k
,
656 lookup
.advRtrAddr
= nbr
->router_id
;
657 /* check if helper support enabled for
658 * the corresponding routerid.
660 * dont exit from helper role.
663 ospf6
->ospf6_helper_cfg
668 ospf6_gr_helper_exit(
669 nbr
, OSPF6_GR_HELPER_TOPO_CHG
);
676 * Api to enable/disable strict lsa check on the HELPER.
682 * True - disable the lsa check.
683 * False - enable the strict lsa check.
688 static void ospf6_gr_helper_lsacheck_set(struct ospf6
*ospf6
, bool enabled
)
690 if (ospf6
->ospf6_helper_cfg
.strict_lsa_check
== enabled
)
693 ospf6
->ospf6_helper_cfg
.strict_lsa_check
= enabled
;
697 * Api to set the supported restart reason.
703 * True: support only planned restart.
704 * False: support for planned/unplanned restarts.
711 ospf6_gr_helper_set_supported_onlyPlanned_restart(struct ospf6
*ospf6
,
714 ospf6
->ospf6_helper_cfg
.only_planned_restart
= only_planned
;
718 * Api to set the supported grace interval in this router.
724 * The supported grace interval..
729 static void ospf6_gr_helper_supported_gracetime_set(struct ospf6
*ospf6
,
732 ospf6
->ospf6_helper_cfg
.supported_grace_time
= interval
;
735 /* API to walk and print all the Helper supported router ids */
736 static int ospf6_print_vty_helper_dis_rtr_walkcb(struct hash_bucket
*bucket
,
739 struct advRtr
*rtr
= bucket
->data
;
740 struct vty
*vty
= (struct vty
*)arg
;
741 static unsigned int count
;
743 vty_out(vty
, "%-6pI4,", &rtr
->advRtrAddr
);
749 return HASHWALK_CONTINUE
;
752 /* API to walk and print all the Helper supported router ids.*/
753 static int ospf6_print_json_helper_dis_rtr_walkcb(struct hash_bucket
*bucket
,
756 struct advRtr
*rtr
= bucket
->data
;
757 struct json_object
*json_rid_array
= (struct json_object
*)arg
;
758 struct json_object
*json_rid
;
761 inet_ntop(AF_INET
, &rtr
->advRtrAddr
, router_id
, sizeof(router_id
));
763 json_rid
= json_object_new_object();
765 json_object_string_add(json_rid
, "routerId", router_id
);
766 json_object_array_add(json_rid_array
, json_rid
);
768 return HASHWALK_CONTINUE
;
772 * Enable/Disable HELPER support on a specified advertisement
779 * HELPER support for given Advertisement Router.
782 * True - Enable Helper Support.
783 * False - Disable Helper Support.
788 static void ospf6_gr_helper_support_set_per_routerid(struct ospf6
*ospf6
,
789 struct in_addr router_id
,
794 struct listnode
*i
, *j
, *k
;
795 struct ospf6_interface
*oi
;
796 struct ospf6_neighbor
*nbr
;
797 struct ospf6_area
*oa
;
799 temp
.advRtrAddr
= router_id
.s_addr
;
801 if (support
== OSPF6_FALSE
) {
802 /*Delete the routerid from the enable router hash table */
803 rtr
= hash_lookup(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
807 hash_release(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
809 ospf6_disable_rtr_hash_free(rtr
);
812 /* If helper support is enabled globally
813 * no action is required.
815 if (ospf6
->ospf6_helper_cfg
.is_helper_supported
)
818 /* Cease the HELPER role fore neighbours from the
819 * specified advertisement router.
821 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, i
, oa
))
822 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, j
, oi
)) {
824 for (ALL_LIST_ELEMENTS_RO(oi
->neighbor_list
, k
,
827 if (nbr
->router_id
!= router_id
.s_addr
)
830 if (OSPF6_GR_IS_ACTIVE_HELPER(nbr
))
831 ospf6_gr_helper_exit(
833 OSPF6_GR_HELPER_TOPO_CHG
);
838 /* Add the routerid to the enable router hash table */
839 (void)hash_get(ospf6
->ospf6_helper_cfg
.enable_rtr_list
, &temp
,
840 ospf6_enable_rtr_hash_alloc
);
844 static void show_ospfv6_gr_helper_per_nbr(struct vty
*vty
, json_object
*json
,
845 bool uj
, struct ospf6_neighbor
*nbr
)
848 vty_out(vty
, " Routerid : %pI4\n", &nbr
->router_id
);
849 vty_out(vty
, " Received Grace period : %d(in seconds).\n",
850 nbr
->gr_helper_info
.recvd_grace_period
);
851 vty_out(vty
, " Actual Grace period : %d(in seconds)\n",
852 nbr
->gr_helper_info
.actual_grace_period
);
853 vty_out(vty
, " Remaining GraceTime:%ld(in seconds).\n",
854 thread_timer_remain_second(
855 nbr
->gr_helper_info
.t_grace_timer
));
856 vty_out(vty
, " Graceful Restart reason: %s.\n\n",
857 ospf6_restart_reason_desc
[nbr
->gr_helper_info
858 .gr_restart_reason
]);
861 json_object
*json_neigh
= NULL
;
863 inet_ntop(AF_INET
, &nbr
->router_id
, nbrid
, sizeof(nbrid
));
864 json_neigh
= json_object_new_object();
865 json_object_string_add(json_neigh
, "routerid", nbrid
);
866 json_object_int_add(json_neigh
, "recvdGraceInterval",
867 nbr
->gr_helper_info
.recvd_grace_period
);
868 json_object_int_add(json_neigh
, "actualGraceInterval",
869 nbr
->gr_helper_info
.actual_grace_period
);
870 json_object_int_add(json_neigh
, "remainGracetime",
871 thread_timer_remain_second(
872 nbr
->gr_helper_info
.t_grace_timer
));
873 json_object_string_add(json_neigh
, "restartReason",
874 ospf6_restart_reason_desc
[
875 nbr
->gr_helper_info
.gr_restart_reason
]);
876 json_object_object_add(json
, nbr
->name
, json_neigh
);
880 static void show_ospf6_gr_helper_details(struct vty
*vty
, struct ospf6
*ospf6
,
881 json_object
*json
, bool uj
, bool detail
)
883 struct ospf6_interface
*oi
;
885 /* Show Router ID. */
889 inet_ntop(AF_INET
, &ospf6
->router_id
, router_id
,
891 json_object_string_add(json
, "routerId", router_id
);
894 " OSPFv3 Routing Process (0) with Router-ID %pI4\n",
899 if (ospf6
->ospf6_helper_cfg
.is_helper_supported
)
901 " Graceful restart helper support enabled.\n");
904 " Graceful restart helper support disabled.\n");
906 if (ospf6
->ospf6_helper_cfg
.strict_lsa_check
)
907 vty_out(vty
, " Strict LSA check is enabled.\n");
909 vty_out(vty
, " Strict LSA check is disabled.\n");
911 if (ospf6
->ospf6_helper_cfg
.only_planned_restart
)
913 " Helper supported for planned restarts only.\n");
916 " Helper supported for Planned and Unplanned Restarts.\n");
919 " Supported Graceful restart interval: %d(in seconds).\n",
920 ospf6
->ospf6_helper_cfg
.supported_grace_time
);
922 if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf
)) {
923 vty_out(vty
, " Enable Router list:\n");
925 hash_walk(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
926 ospf6_print_vty_helper_dis_rtr_walkcb
, vty
);
927 vty_out(vty
, "\n\n");
930 if (ospf6
->ospf6_helper_cfg
.last_exit_reason
931 != OSPF6_GR_HELPER_EXIT_NONE
) {
932 vty_out(vty
, " Last Helper exit Reason :%s\n",
933 ospf6_exit_reason_desc
934 [ospf6
->ospf6_helper_cfg
937 if (ospf6
->ospf6_helper_cfg
.active_restarter_cnt
)
939 " Number of Active neighbours in graceful restart: %d\n",
940 ospf6
->ospf6_helper_cfg
941 .active_restarter_cnt
);
948 json_object_string_add(
949 json
, "helperSupport",
950 (ospf6
->ospf6_helper_cfg
.is_helper_supported
)
953 json_object_string_add(
954 json
, "strictLsaCheck",
955 (ospf6
->ospf6_helper_cfg
.strict_lsa_check
)
958 json_object_string_add(
959 json
, "restartSupoort",
960 (ospf6
->ospf6_helper_cfg
.only_planned_restart
)
961 ? "Planned Restart only"
962 : "Planned and Unplanned Restarts");
965 json
, "supportedGracePeriod",
966 ospf6
->ospf6_helper_cfg
.supported_grace_time
);
968 #if CONFDATE > 20230131
969 CPP_NOTICE("Remove JSON object commands with keys starting with capital")
971 if (ospf6
->ospf6_helper_cfg
.last_exit_reason
!=
972 OSPF6_GR_HELPER_EXIT_NONE
) {
973 json_object_string_add(
974 json
, "LastExitReason",
975 ospf6_exit_reason_desc
976 [ospf6
->ospf6_helper_cfg
978 json_object_string_add(
979 json
, "lastExitReason",
980 ospf6_exit_reason_desc
981 [ospf6
->ospf6_helper_cfg
985 if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6
)) {
986 struct json_object
*json_rid_array
=
987 json_object_new_array();
989 json_object_object_add(json
, "enabledRouterIds",
992 hash_walk(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
993 ospf6_print_json_helper_dis_rtr_walkcb
,
1000 struct listnode
*i
, *j
, *k
;
1001 struct ospf6_area
*oa
;
1002 json_object
*json_neighbors
= NULL
;
1004 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, i
, oa
))
1005 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, j
, oi
)) {
1006 struct ospf6_neighbor
*nbr
;
1009 json_object_object_get_ex(
1012 json_object_object_get_ex(
1015 if (!json_neighbors
) {
1017 json_object_new_object();
1018 json_object_object_add(
1021 json_object_object_add(
1027 for (ALL_LIST_ELEMENTS_RO(oi
->neighbor_list
, k
,
1030 if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr
))
1035 " Neighbour %d :\n",
1038 show_ospfv6_gr_helper_per_nbr(
1039 vty
, json_neighbors
, uj
, nbr
);
1046 /* Graceful Restart HELPER config Commands */
1047 DEFPY(ospf6_gr_helper_enable
,
1048 ospf6_gr_helper_enable_cmd
,
1049 "graceful-restart helper enable [A.B.C.D$rtr_id]",
1050 "ospf6 graceful restart\n"
1052 "Enable Helper support\n"
1053 "Advertisement Router-ID\n")
1055 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1057 if (rtr_id_str
!= NULL
) {
1059 ospf6_gr_helper_support_set_per_routerid(ospf6
, rtr_id
,
1065 ospf6_gr_helper_support_set(ospf6
, OSPF6_TRUE
);
1070 DEFPY(ospf6_gr_helper_disable
,
1071 ospf6_gr_helper_disable_cmd
,
1072 "no graceful-restart helper enable [A.B.C.D$rtr_id]",
1074 "ospf6 graceful restart\n"
1076 "Enable Helper support\n"
1077 "Advertisement Router-ID\n")
1079 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1081 if (rtr_id_str
!= NULL
) {
1083 ospf6_gr_helper_support_set_per_routerid(ospf6
, rtr_id
,
1089 ospf6_gr_helper_support_set(ospf6
, OSPF6_FALSE
);
1094 DEFPY(ospf6_gr_helper_disable_lsacheck
,
1095 ospf6_gr_helper_disable_lsacheck_cmd
,
1096 "graceful-restart helper lsa-check-disable",
1097 "ospf6 graceful restart\n"
1099 "disable strict LSA check\n")
1101 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1103 ospf6_gr_helper_lsacheck_set(ospf6
, OSPF6_FALSE
);
1107 DEFPY(no_ospf6_gr_helper_disable_lsacheck
,
1108 no_ospf6_gr_helper_disable_lsacheck_cmd
,
1109 "no graceful-restart helper lsa-check-disable",
1111 "ospf6 graceful restart\n"
1113 "diasble strict LSA check\n")
1115 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1117 ospf6_gr_helper_lsacheck_set(ospf6
, OSPF6_TRUE
);
1121 DEFPY(ospf6_gr_helper_planned_only
,
1122 ospf6_gr_helper_planned_only_cmd
,
1123 "graceful-restart helper planned-only",
1124 "ospf6 graceful restart\n"
1126 "supported only planned restart\n")
1128 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1130 ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6
, OSPF6_TRUE
);
1135 DEFPY(no_ospf6_gr_helper_planned_only
, no_ospf6_gr_helper_planned_only_cmd
,
1136 "no graceful-restart helper planned-only",
1138 "ospf6 graceful restart\n"
1140 "supported only for planned restart\n")
1142 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1144 ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6
, OSPF6_FALSE
);
1149 DEFPY(ospf6_gr_helper_supported_grace_time
,
1150 ospf6_gr_helper_supported_grace_time_cmd
,
1151 "graceful-restart helper supported-grace-time (10-1800)$interval",
1152 "ospf6 graceful restart\n"
1154 "supported grace timer\n"
1155 "grace interval(in seconds)\n")
1157 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1159 ospf6_gr_helper_supported_gracetime_set(ospf6
, interval
);
1163 DEFPY(no_ospf6_gr_helper_supported_grace_time
,
1164 no_ospf6_gr_helper_supported_grace_time_cmd
,
1165 "no graceful-restart helper supported-grace-time (10-1800)$interval",
1167 "ospf6 graceful restart\n"
1169 "supported grace timer\n"
1170 "grace interval(in seconds)\n")
1172 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1174 ospf6_gr_helper_supported_gracetime_set(ospf6
,
1175 OSPF6_MAX_GRACE_INTERVAL
);
1180 DEFPY(show_ipv6_ospf6_gr_helper
,
1181 show_ipv6_ospf6_gr_helper_cmd
,
1182 "show ipv6 ospf6 graceful-restart helper [detail] [json]",
1184 "Ipv6 Information\n"
1185 "OSPF6 information\n"
1186 "ospf6 graceful restart\n"
1187 "helper details in the router\n"
1188 "detailed information\n" JSON_STR
)
1191 bool uj
= use_json(argc
, argv
);
1192 struct ospf6
*ospf6
= NULL
;
1193 json_object
*json
= NULL
;
1194 bool detail
= false;
1196 ospf6
= ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME
);
1197 if (ospf6
== NULL
) {
1198 vty_out(vty
, "OSPFv3 is not configured\n");
1202 if (argv_find(argv
, argc
, "detail", &idx
))
1206 json
= json_object_new_object();
1208 show_ospf6_gr_helper_details(vty
, ospf6
, json
, uj
, detail
);
1211 vty_json(vty
, json
);
1216 /* Debug commands */
1217 DEFPY(debug_ospf6_gr
, debug_ospf6_gr_cmd
,
1218 "[no$no] debug ospf6 graceful-restart",
1219 NO_STR DEBUG_STR OSPF6_STR
"Graceful restart\n")
1222 OSPF6_DEBUG_GR_ON();
1224 OSPF6_DEBUG_GR_OFF();
1230 * Api to display the grace LSA information.
1242 static int ospf6_grace_lsa_show_info(struct vty
*vty
, struct ospf6_lsa
*lsa
,
1243 json_object
*json
, bool use_json
)
1245 struct ospf6_lsa_header
*lsah
= NULL
;
1246 struct tlv_header
*tlvh
= NULL
;
1247 struct grace_tlv_graceperiod
*gracePeriod
;
1248 struct grace_tlv_restart_reason
*grReason
;
1249 uint16_t length
= 0;
1252 lsah
= (struct ospf6_lsa_header
*)lsa
->header
;
1253 if (ntohs(lsah
->length
) <= OSPF6_LSA_HEADER_SIZE
) {
1254 if (IS_DEBUG_OSPF6_GR
)
1255 zlog_debug("%s: undersized (%u B) lsa", __func__
,
1256 ntohs(lsah
->length
));
1257 return OSPF6_FAILURE
;
1260 length
= ntohs(lsah
->length
) - OSPF6_LSA_HEADER_SIZE
;
1264 vty_out(vty
, "TLV info:\n");
1266 zlog_debug(" TLV info:");
1269 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
&& tlvh
;
1270 tlvh
= TLV_HDR_NEXT(tlvh
)) {
1273 if (sum
+ TLV_SIZE(tlvh
) > length
) {
1275 vty_out(vty
, "%% Invalid TLV length: %d\n",
1277 else if (IS_DEBUG_OSPF6_GR
)
1278 zlog_debug("%% Invalid TLV length: %d",
1280 return OSPF6_FAILURE
;
1283 switch (ntohs(tlvh
->type
)) {
1284 case GRACE_PERIOD_TYPE
:
1285 gracePeriod
= (struct grace_tlv_graceperiod
*)tlvh
;
1286 sum
+= TLV_SIZE(tlvh
);
1290 json_object_int_add(
1291 json
, "gracePeriod",
1292 ntohl(gracePeriod
->interval
));
1294 vty_out(vty
, " Grace period:%d\n",
1295 ntohl(gracePeriod
->interval
));
1297 zlog_debug(" Grace period:%d",
1298 ntohl(gracePeriod
->interval
));
1301 case RESTART_REASON_TYPE
:
1302 grReason
= (struct grace_tlv_restart_reason
*)tlvh
;
1303 sum
+= TLV_SIZE(tlvh
);
1306 json_object_string_add(
1307 json
, "restartReason",
1308 ospf6_restart_reason_desc
1309 [grReason
->reason
]);
1311 vty_out(vty
, " Restart reason:%s\n",
1312 ospf6_restart_reason_desc
1313 [grReason
->reason
]);
1315 zlog_debug(" Restart reason:%s",
1316 ospf6_restart_reason_desc
1317 [grReason
->reason
]);
1328 void ospf6_gr_helper_config_init(void)
1331 ospf6_install_lsa_handler(&grace_lsa_handler
);
1333 install_element(OSPF6_NODE
, &ospf6_gr_helper_enable_cmd
);
1334 install_element(OSPF6_NODE
, &ospf6_gr_helper_disable_cmd
);
1335 install_element(OSPF6_NODE
, &ospf6_gr_helper_disable_lsacheck_cmd
);
1336 install_element(OSPF6_NODE
, &no_ospf6_gr_helper_disable_lsacheck_cmd
);
1337 install_element(OSPF6_NODE
, &ospf6_gr_helper_planned_only_cmd
);
1338 install_element(OSPF6_NODE
, &no_ospf6_gr_helper_planned_only_cmd
);
1339 install_element(OSPF6_NODE
, &ospf6_gr_helper_supported_grace_time_cmd
);
1340 install_element(OSPF6_NODE
,
1341 &no_ospf6_gr_helper_supported_grace_time_cmd
);
1343 install_element(VIEW_NODE
, &show_ipv6_ospf6_gr_helper_cmd
);
1345 install_element(CONFIG_NODE
, &debug_ospf6_gr_cmd
);
1346 install_element(ENABLE_NODE
, &debug_ospf6_gr_cmd
);
1351 * Initialize GR helper config data structure.
1359 void ospf6_gr_helper_init(struct ospf6
*ospf6
)
1361 if (IS_DEBUG_OSPF6_GR
)
1362 zlog_debug("%s, GR Helper init.", __func__
);
1364 ospf6
->ospf6_helper_cfg
.is_helper_supported
= OSPF6_FALSE
;
1365 ospf6
->ospf6_helper_cfg
.strict_lsa_check
= OSPF6_TRUE
;
1366 ospf6
->ospf6_helper_cfg
.only_planned_restart
= OSPF6_FALSE
;
1367 ospf6
->ospf6_helper_cfg
.supported_grace_time
= OSPF6_MAX_GRACE_INTERVAL
;
1368 ospf6
->ospf6_helper_cfg
.last_exit_reason
= OSPF6_GR_HELPER_EXIT_NONE
;
1369 ospf6
->ospf6_helper_cfg
.active_restarter_cnt
= 0;
1371 ospf6
->ospf6_helper_cfg
.enable_rtr_list
= hash_create(
1372 ospf6_enable_rtr_hash_key
, ospf6_enable_rtr_hash_cmp
,
1373 "Ospf6 enable router hash");
1377 * De-initialize GR helper config data structure.
1385 void ospf6_gr_helper_deinit(struct ospf6
*ospf6
)
1388 if (IS_DEBUG_OSPF6_GR
)
1389 zlog_debug("%s, GR helper deinit.", __func__
);
1391 ospf6_enable_rtr_hash_destroy(ospf6
);
1394 static int ospf6_cfg_write_helper_enable_rtr_walkcb(struct hash_bucket
*backet
,
1397 struct advRtr
*rtr
= backet
->data
;
1398 struct vty
*vty
= (struct vty
*)arg
;
1400 vty_out(vty
, " graceful-restart helper enable %pI4\n", &rtr
->advRtrAddr
);
1401 return HASHWALK_CONTINUE
;
1404 int config_write_ospf6_gr_helper(struct vty
*vty
, struct ospf6
*ospf6
)
1406 if (ospf6
->ospf6_helper_cfg
.is_helper_supported
)
1407 vty_out(vty
, " graceful-restart helper enable\n");
1409 if (!ospf6
->ospf6_helper_cfg
.strict_lsa_check
)
1410 vty_out(vty
, " graceful-restart helper lsa-check-disable\n");
1412 if (ospf6
->ospf6_helper_cfg
.only_planned_restart
)
1413 vty_out(vty
, " graceful-restart helper planned-only\n");
1415 if (ospf6
->ospf6_helper_cfg
.supported_grace_time
1416 != OSPF6_MAX_GRACE_INTERVAL
)
1418 " graceful-restart helper supported-grace-time %d\n",
1419 ospf6
->ospf6_helper_cfg
.supported_grace_time
);
1421 if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6
)) {
1422 hash_walk(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
1423 ospf6_cfg_write_helper_enable_rtr_walkcb
, vty
);
1429 int config_write_ospf6_debug_gr_helper(struct vty
*vty
)
1431 if (IS_DEBUG_OSPF6_GR
)
1432 vty_out(vty
, "debug ospf6 graceful-restart\n");