1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * OSPF6 Graceful Restart helper functions.
5 * Copyright (C) 2021-22 Vmware, Inc.
20 #include "lib_errors.h"
23 #include "ospf6_proto.h"
24 #include "ospf6_lsa.h"
25 #include "ospf6_lsdb.h"
26 #include "ospf6_route.h"
27 #include "ospf6_message.h"
29 #include "ospf6_top.h"
30 #include "ospf6_area.h"
31 #include "ospf6_interface.h"
32 #include "ospf6_neighbor.h"
33 #include "ospf6_intra.h"
37 #include "ospf6d/ospf6_gr_helper_clippy.c"
39 DEFINE_MTYPE_STATIC(OSPF6D
, OSPF6_GR_HELPER
, "OSPF6 Graceful restart helper");
41 unsigned char conf_debug_ospf6_gr
;
43 static int ospf6_grace_lsa_show_info(struct vty
*vty
, struct ospf6_lsa
*lsa
,
44 json_object
*json
, bool use_json
);
46 struct ospf6_lsa_handler grace_lsa_handler
= {.lh_type
= OSPF6_LSTYPE_GRACE_LSA
,
48 .lh_short_name
= "GR",
50 ospf6_grace_lsa_show_info
,
51 .lh_get_prefix_str
= NULL
,
54 const char *ospf6_exit_reason_desc
[] = {
59 "Successful graceful restart",
62 const char *ospf6_restart_reason_desc
[] = {
65 "Software reload/upgrade",
66 "Switch to redundant control processor",
69 const char *ospf6_rejected_reason_desc
[] = {
71 "Helper support disabled",
72 "Neighbour is not in FULL state",
73 "Supports only planned restart but received for unplanned",
74 "Topo change due to change in lsa rxmt list",
75 "LSA age is more than Grace interval",
78 static unsigned int ospf6_enable_rtr_hash_key(const void *data
)
80 const struct advRtr
*rtr
= data
;
82 return jhash_1word(rtr
->advRtrAddr
, 0);
85 static bool ospf6_enable_rtr_hash_cmp(const void *d1
, const void *d2
)
87 const struct advRtr
*rtr1
= d1
;
88 const struct advRtr
*rtr2
= d2
;
90 return (rtr1
->advRtrAddr
== rtr2
->advRtrAddr
);
93 static void *ospf6_enable_rtr_hash_alloc(void *p
)
97 rid
= XCALLOC(MTYPE_OSPF6_GR_HELPER
, sizeof(struct advRtr
));
98 rid
->advRtrAddr
= ((struct advRtr
*)p
)->advRtrAddr
;
103 static void ospf6_disable_rtr_hash_free(void *rtr
)
105 XFREE(MTYPE_OSPF6_GR_HELPER
, rtr
);
108 static void ospf6_enable_rtr_hash_destroy(struct ospf6
*ospf6
)
110 if (ospf6
->ospf6_helper_cfg
.enable_rtr_list
== NULL
)
113 hash_clean_and_free(&ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
114 ospf6_disable_rtr_hash_free
);
118 * Extracting tlv info from GRACE LSA.
124 * interval : grace interval.
125 * reason : Restarting reason.
127 static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa
*lsa
,
128 uint32_t *interval
, uint8_t *reason
)
130 struct ospf6_lsa_header
*lsah
= NULL
;
131 struct tlv_header
*tlvh
= NULL
;
132 struct grace_tlv_graceperiod
*gracePeriod
;
133 struct grace_tlv_restart_reason
*grReason
;
137 lsah
= (struct ospf6_lsa_header
*)lsa
->header
;
138 if (ntohs(lsah
->length
) <= OSPF6_LSA_HEADER_SIZE
) {
139 if (IS_DEBUG_OSPF6_GR
)
140 zlog_debug("%s: undersized (%u B) lsa", __func__
,
141 ntohs(lsah
->length
));
142 return OSPF6_FAILURE
;
145 length
= ntohs(lsah
->length
) - OSPF6_LSA_HEADER_SIZE
;
147 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
&& tlvh
;
148 tlvh
= TLV_HDR_NEXT(tlvh
)) {
150 /* Check TLV len against overall LSA */
151 if (sum
+ TLV_SIZE(tlvh
) > length
) {
152 if (IS_DEBUG_OSPF6_GR
)
154 "%s: Malformed packet: Invalid TLV len:%d",
155 __func__
, TLV_SIZE(tlvh
));
156 return OSPF6_FAILURE
;
159 switch (ntohs(tlvh
->type
)) {
160 case GRACE_PERIOD_TYPE
:
161 gracePeriod
= (struct grace_tlv_graceperiod
*)tlvh
;
162 *interval
= ntohl(gracePeriod
->interval
);
163 sum
+= TLV_SIZE(tlvh
);
165 /* Check if grace interval is valid */
166 if (*interval
> OSPF6_MAX_GRACE_INTERVAL
167 || *interval
< OSPF6_MIN_GRACE_INTERVAL
)
168 return OSPF6_FAILURE
;
170 case RESTART_REASON_TYPE
:
171 grReason
= (struct grace_tlv_restart_reason
*)tlvh
;
172 *reason
= grReason
->reason
;
173 sum
+= TLV_SIZE(tlvh
);
175 if (*reason
>= OSPF6_GR_INVALID_REASON_CODE
)
176 return OSPF6_FAILURE
;
179 if (IS_DEBUG_OSPF6_GR
)
180 zlog_debug("%s, Ignoring unknown TLV type:%d",
181 __func__
, ntohs(tlvh
->type
));
185 return OSPF6_SUCCESS
;
189 * Grace timer expiry handler.
190 * HELPER aborts its role at grace timer expiry.
198 static void ospf6_handle_grace_timer_expiry(struct event
*thread
)
200 struct ospf6_neighbor
*nbr
= EVENT_ARG(thread
);
202 ospf6_gr_helper_exit(nbr
, OSPF6_GR_HELPER_GRACE_TIMEOUT
);
206 * API to check any change in the neighbor's
207 * retransmission list.
213 * TRUE - if any change in the lsa.
214 * FALSE - no change in the lsas.
216 static bool ospf6_check_chg_in_rxmt_list(struct ospf6_neighbor
*nbr
)
218 struct ospf6_lsa
*lsa
, *lsanext
;
220 for (ALL_LSDB(nbr
->retrans_list
, lsa
, lsanext
)) {
221 struct ospf6_lsa
*lsa_in_db
= NULL
;
223 /* Fetching the same copy of LSA form LSDB to validate the
227 ospf6_lsdb_lookup(lsa
->header
->type
, lsa
->header
->id
,
228 lsa
->header
->adv_router
, lsa
->lsdb
);
230 if (lsa_in_db
&& lsa_in_db
->tobe_acknowledged
) {
231 ospf6_lsa_unlock(lsa
);
233 ospf6_lsa_unlock(lsanext
);
243 * Process Grace LSA.If it is eligible move to HELPER role.
244 * Ref rfc3623 section 3.1 and rfc5187
250 * Grace LSA received from RESTARTER.
253 * ospf6 neighbour which requests the router to act as
258 * If supported as HELPER : OSPF_GR_HELPER_INPROGRESS
259 * If Not supported as HELPER : OSPF_GR_HELPER_NONE
261 int ospf6_process_grace_lsa(struct ospf6
*ospf6
, struct ospf6_lsa
*lsa
,
262 struct ospf6_neighbor
*restarter
)
264 uint8_t restart_reason
= 0;
265 uint32_t grace_interval
= 0;
266 uint32_t actual_grace_interval
= 0;
267 struct advRtr lookup
;
270 /* Extract the grace lsa packet fields */
271 ret
= ospf6_extract_grace_lsa_fields(lsa
, &grace_interval
,
273 if (ret
!= OSPF6_SUCCESS
) {
274 if (IS_DEBUG_OSPF6_GR
)
275 zlog_debug("%s, Wrong Grace LSA packet.", __func__
);
276 return OSPF6_GR_NOT_HELPER
;
279 if (IS_DEBUG_OSPF6_GR
)
281 "%s, Grace LSA received from %s(%pI4), grace interval:%u, restart reason:%s",
282 __func__
, restarter
->name
, &restarter
->router_id
,
284 ospf6_restart_reason_desc
[restart_reason
]);
286 /* Verify Helper enabled globally */
287 if (!ospf6
->ospf6_helper_cfg
.is_helper_supported
) {
288 /* Verify Helper support is enabled for the
289 * current neighbour router-id.
291 lookup
.advRtrAddr
= restarter
->router_id
;
293 if (!hash_lookup(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
295 if (IS_DEBUG_OSPF6_GR
)
297 "%s, HELPER support is disabled, So not a HELPER",
299 restarter
->gr_helper_info
.rejected_reason
=
300 OSPF6_HELPER_SUPPORT_DISABLED
;
301 return OSPF6_GR_NOT_HELPER
;
305 /* Check neighbour is in FULL state and
306 * became a adjacency.
308 if (!IS_NBR_STATE_FULL(restarter
)) {
309 if (IS_DEBUG_OSPF6_GR
)
311 "%s, This Neighbour %pI6 is not in FULL state.",
312 __func__
, &restarter
->linklocal_addr
);
313 restarter
->gr_helper_info
.rejected_reason
=
314 OSPF6_HELPER_NOT_A_VALID_NEIGHBOUR
;
315 return OSPF6_GR_NOT_HELPER
;
318 /* Based on the restart reason from grace lsa
319 * check the current router is supporting or not
321 if (ospf6
->ospf6_helper_cfg
.only_planned_restart
322 && !OSPF6_GR_IS_PLANNED_RESTART(restart_reason
)) {
323 if (IS_DEBUG_OSPF6_GR
)
325 "%s, Router supports only planned restarts but received the GRACE LSA due to an unplanned restart",
327 restarter
->gr_helper_info
.rejected_reason
=
328 OSPF6_HELPER_PLANNED_ONLY_RESTART
;
329 return OSPF6_GR_NOT_HELPER
;
332 /* Check the retransmission list of this
333 * neighbour, check any change in lsas.
335 if (ospf6
->ospf6_helper_cfg
.strict_lsa_check
336 && restarter
->retrans_list
->count
337 && ospf6_check_chg_in_rxmt_list(restarter
)) {
338 if (IS_DEBUG_OSPF6_GR
)
340 "%s, Changed LSA in Rxmt list.So not Helper.",
342 restarter
->gr_helper_info
.rejected_reason
=
343 OSPF6_HELPER_TOPO_CHANGE_RTXMT_LIST
;
344 return OSPF6_GR_NOT_HELPER
;
347 /* LSA age must be less than the grace period */
348 if (ntohs(lsa
->header
->age
) >= grace_interval
) {
349 if (IS_DEBUG_OSPF6_GR
)
351 "%s, Grace LSA age(%d) is more than the grace interval(%d)",
352 __func__
, lsa
->header
->age
, grace_interval
);
353 restarter
->gr_helper_info
.rejected_reason
=
354 OSPF6_HELPER_LSA_AGE_MORE
;
355 return OSPF6_GR_NOT_HELPER
;
358 if (ospf6
->gr_info
.restart_in_progress
) {
359 if (IS_DEBUG_OSPF6_GR
)
361 "%s: router is in the process of graceful restart",
363 restarter
->gr_helper_info
.rejected_reason
=
364 OSPF6_HELPER_RESTARTING
;
365 return OSPF6_GR_NOT_HELPER
;
368 /* check supported grace period configured
369 * if configured, use this to start the grace
370 * timer otherwise use the interval received
371 * in grace LSA packet.
373 actual_grace_interval
= grace_interval
;
374 if (grace_interval
> ospf6
->ospf6_helper_cfg
.supported_grace_time
) {
375 if (IS_DEBUG_OSPF6_GR
)
377 "%s, Received grace period %d is larger than supported grace %d",
378 __func__
, grace_interval
,
379 ospf6
->ospf6_helper_cfg
.supported_grace_time
);
380 actual_grace_interval
=
381 ospf6
->ospf6_helper_cfg
.supported_grace_time
;
384 if (OSPF6_GR_IS_ACTIVE_HELPER(restarter
)) {
385 EVENT_OFF(restarter
->gr_helper_info
.t_grace_timer
);
387 if (ospf6
->ospf6_helper_cfg
.active_restarter_cnt
> 0)
388 ospf6
->ospf6_helper_cfg
.active_restarter_cnt
--;
390 if (IS_DEBUG_OSPF6_GR
)
392 "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
395 if (IS_DEBUG_OSPF6_GR
)
397 "%s, This Router becomes a HELPER for the neighbour %pI6",
398 __func__
, &restarter
->linklocal_addr
);
401 /* Became a Helper to the RESTART neighbour.
402 * change the helper status.
404 restarter
->gr_helper_info
.gr_helper_status
= OSPF6_GR_ACTIVE_HELPER
;
405 restarter
->gr_helper_info
.recvd_grace_period
= grace_interval
;
406 restarter
->gr_helper_info
.actual_grace_period
= actual_grace_interval
;
407 restarter
->gr_helper_info
.gr_restart_reason
= restart_reason
;
408 restarter
->gr_helper_info
.rejected_reason
= OSPF6_HELPER_REJECTED_NONE
;
410 /* Increment the active restart nbr count */
411 ospf6
->ospf6_helper_cfg
.active_restarter_cnt
++;
413 if (IS_DEBUG_OSPF6_GR
)
414 zlog_debug("%s, Grace timer started.interval:%u", __func__
,
415 actual_grace_interval
);
417 /* Start the grace timer */
418 event_add_timer(master
, ospf6_handle_grace_timer_expiry
, restarter
,
419 actual_grace_interval
,
420 &restarter
->gr_helper_info
.t_grace_timer
);
422 return OSPF6_GR_ACTIVE_HELPER
;
426 * Api to exit from HELPER role to take all actions
428 * Ref rfc3623 section 3. and rfc51872
434 * Ospf6 neighbour for which it is acting as HELPER.
437 * The reason for exiting from HELPER.
442 void ospf6_gr_helper_exit(struct ospf6_neighbor
*nbr
,
443 enum ospf6_helper_exit_reason reason
)
445 struct ospf6_interface
*oi
= nbr
->ospf6_if
;
451 ospf6
= oi
->area
->ospf6
;
453 if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr
))
456 if (IS_DEBUG_OSPF6_GR
)
457 zlog_debug("%s, Exiting from HELPER support to %pI6, due to %s",
458 __func__
, &nbr
->linklocal_addr
,
459 ospf6_exit_reason_desc
[reason
]);
461 /* Reset helper status*/
462 nbr
->gr_helper_info
.gr_helper_status
= OSPF6_GR_NOT_HELPER
;
463 nbr
->gr_helper_info
.helper_exit_reason
= reason
;
464 nbr
->gr_helper_info
.actual_grace_period
= 0;
465 nbr
->gr_helper_info
.recvd_grace_period
= 0;
466 nbr
->gr_helper_info
.gr_restart_reason
= 0;
467 ospf6
->ospf6_helper_cfg
.last_exit_reason
= reason
;
469 /* If the exit not triggered due to grace timer
470 * expiry, stop the grace timer.
472 if (reason
!= OSPF6_GR_HELPER_GRACE_TIMEOUT
)
473 EVENT_OFF(nbr
->gr_helper_info
.t_grace_timer
);
475 if (ospf6
->ospf6_helper_cfg
.active_restarter_cnt
<= 0) {
477 "OSPF6 GR-Helper: Number of active Restarters should be greater than zero.");
480 /* Decrement active restarter count */
481 ospf6
->ospf6_helper_cfg
.active_restarter_cnt
--;
483 /* check exit triggered due to successful completion
484 * of graceful restart.
486 if (reason
!= OSPF6_GR_HELPER_COMPLETED
) {
487 if (IS_DEBUG_OSPF6_GR
)
488 zlog_debug("%s, Unsuccessful GR exit. RESTARTER : %pI6",
489 __func__
, &nbr
->linklocal_addr
);
492 /*Recalculate the DR for the network segment */
495 /* Originate a router LSA */
496 OSPF6_ROUTER_LSA_SCHEDULE(nbr
->ospf6_if
->area
);
498 /* Originate network lsa if it is an DR in the LAN */
499 if (nbr
->ospf6_if
->state
== OSPF6_INTERFACE_DR
)
500 OSPF6_NETWORK_LSA_SCHEDULE(nbr
->ospf6_if
);
504 * Process max age Grace LSA.
505 * It is a indication for successful completion of GR.
506 * If router acting as HELPER, It exits from helper role.
512 * Grace LSA received from RESTARTER.
515 * ospf6 neighbour which request the router to act as
521 void ospf6_process_maxage_grace_lsa(struct ospf6
*ospf6
, struct ospf6_lsa
*lsa
,
522 struct ospf6_neighbor
*restarter
)
524 uint8_t restart_reason
= 0;
525 uint32_t grace_interval
= 0;
528 /* Extract the grace lsa packet fields */
529 ret
= ospf6_extract_grace_lsa_fields(lsa
, &grace_interval
,
531 if (ret
!= OSPF6_SUCCESS
) {
532 if (IS_DEBUG_OSPF6_GR
)
533 zlog_debug("%s, Wrong Grace LSA packet.", __func__
);
537 if (IS_DEBUG_OSPF6_GR
)
538 zlog_debug("%s, GraceLSA received for neighbour %pI4.",
539 __func__
, &restarter
->router_id
);
541 ospf6_gr_helper_exit(restarter
, OSPF6_GR_HELPER_COMPLETED
);
545 * Actions to be taken when topo change detected
546 * HELPER will be exited upon a topo change.
551 * topo change occurred due to this lsa(type (1-5 and 7)
556 void ospf6_helper_handle_topo_chg(struct ospf6
*ospf6
, struct ospf6_lsa
*lsa
)
558 struct listnode
*i
, *j
, *k
;
559 struct ospf6_neighbor
*nbr
= NULL
;
560 struct ospf6_area
*oa
= NULL
;
561 struct ospf6_interface
*oi
= NULL
;
563 if (!ospf6
->ospf6_helper_cfg
.active_restarter_cnt
)
566 /* Topo change not required to be handled if strict
567 * LSA check is disabled for this router.
569 if (!ospf6
->ospf6_helper_cfg
.strict_lsa_check
)
572 if (IS_DEBUG_OSPF6_GR
)
573 zlog_debug("%s, Topo change detected due to lsa details : %s",
574 __func__
, lsa
->name
);
576 lsa
->tobe_acknowledged
= OSPF6_TRUE
;
578 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, i
, oa
))
579 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, j
, oi
)) {
581 /* Ref rfc3623 section 3.2.3.b and rfc5187
582 * If change due to external LSA and if the area is
583 * stub, then it is not a topo change. Since Type-5
584 * lsas will not be flooded in stub area.
586 if (IS_AREA_STUB(oi
->area
)
587 && ((lsa
->header
->type
== OSPF6_LSTYPE_AS_EXTERNAL
)
588 || (lsa
->header
->type
== OSPF6_LSTYPE_TYPE_7
)
589 || (lsa
->header
->type
590 == OSPF6_LSTYPE_INTER_ROUTER
))) {
594 for (ALL_LIST_ELEMENTS_RO(oi
->neighbor_list
, k
, nbr
)) {
596 ospf6_gr_helper_exit(nbr
,
597 OSPF6_GR_HELPER_TOPO_CHG
);
602 /* Configuration handlers */
604 * Disable/Enable HELPER support on router level.
615 static void ospf6_gr_helper_support_set(struct ospf6
*ospf6
, bool support
)
617 struct ospf6_interface
*oi
;
618 struct advRtr lookup
;
619 struct listnode
*i
, *j
, *k
;
620 struct ospf6_neighbor
*nbr
= NULL
;
621 struct ospf6_area
*oa
= NULL
;
623 if (ospf6
->ospf6_helper_cfg
.is_helper_supported
== support
)
626 ospf6
->ospf6_helper_cfg
.is_helper_supported
= support
;
628 /* If helper support disabled, cease HELPER role for all
629 * supporting neighbors.
631 if (support
== OSPF6_FALSE
) {
632 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, i
, oa
))
633 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, j
, oi
)) {
635 for (ALL_LIST_ELEMENTS_RO(oi
->neighbor_list
, k
,
638 lookup
.advRtrAddr
= nbr
->router_id
;
639 /* check if helper support enabled for
640 * the corresponding routerid.
642 * dont exit from helper role.
645 ospf6
->ospf6_helper_cfg
650 ospf6_gr_helper_exit(
651 nbr
, OSPF6_GR_HELPER_TOPO_CHG
);
658 * Api to enable/disable strict lsa check on the HELPER.
664 * True - disable the lsa check.
665 * False - enable the strict lsa check.
670 static void ospf6_gr_helper_lsacheck_set(struct ospf6
*ospf6
, bool enabled
)
672 if (ospf6
->ospf6_helper_cfg
.strict_lsa_check
== enabled
)
675 ospf6
->ospf6_helper_cfg
.strict_lsa_check
= enabled
;
679 * Api to set the supported restart reason.
685 * True: support only planned restart.
686 * False: support for planned/unplanned restarts.
693 ospf6_gr_helper_set_supported_onlyPlanned_restart(struct ospf6
*ospf6
,
696 ospf6
->ospf6_helper_cfg
.only_planned_restart
= only_planned
;
700 * Api to set the supported grace interval in this router.
706 * The supported grace interval..
711 static void ospf6_gr_helper_supported_gracetime_set(struct ospf6
*ospf6
,
714 ospf6
->ospf6_helper_cfg
.supported_grace_time
= interval
;
717 /* API to walk and print all the Helper supported router ids */
718 static int ospf6_print_vty_helper_dis_rtr_walkcb(struct hash_bucket
*bucket
,
721 struct advRtr
*rtr
= bucket
->data
;
722 struct vty
*vty
= (struct vty
*)arg
;
723 static unsigned int count
;
725 vty_out(vty
, "%-6pI4,", &rtr
->advRtrAddr
);
731 return HASHWALK_CONTINUE
;
734 /* API to walk and print all the Helper supported router ids.*/
735 static int ospf6_print_json_helper_dis_rtr_walkcb(struct hash_bucket
*bucket
,
738 struct advRtr
*rtr
= bucket
->data
;
739 struct json_object
*json_rid_array
= (struct json_object
*)arg
;
740 struct json_object
*json_rid
;
743 inet_ntop(AF_INET
, &rtr
->advRtrAddr
, router_id
, sizeof(router_id
));
745 json_rid
= json_object_new_object();
747 json_object_string_add(json_rid
, "routerId", router_id
);
748 json_object_array_add(json_rid_array
, json_rid
);
750 return HASHWALK_CONTINUE
;
754 * Enable/Disable HELPER support on a specified advertisement
761 * HELPER support for given Advertisement Router.
764 * True - Enable Helper Support.
765 * False - Disable Helper Support.
770 static void ospf6_gr_helper_support_set_per_routerid(struct ospf6
*ospf6
,
771 struct in_addr router_id
,
776 struct listnode
*i
, *j
, *k
;
777 struct ospf6_interface
*oi
;
778 struct ospf6_neighbor
*nbr
;
779 struct ospf6_area
*oa
;
781 temp
.advRtrAddr
= router_id
.s_addr
;
783 if (support
== OSPF6_FALSE
) {
784 /*Delete the routerid from the enable router hash table */
785 rtr
= hash_lookup(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
789 hash_release(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
791 ospf6_disable_rtr_hash_free(rtr
);
794 /* If helper support is enabled globally
795 * no action is required.
797 if (ospf6
->ospf6_helper_cfg
.is_helper_supported
)
800 /* Cease the HELPER role fore neighbours from the
801 * specified advertisement router.
803 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, i
, oa
))
804 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, j
, oi
)) {
806 for (ALL_LIST_ELEMENTS_RO(oi
->neighbor_list
, k
,
809 if (nbr
->router_id
!= router_id
.s_addr
)
812 if (OSPF6_GR_IS_ACTIVE_HELPER(nbr
))
813 ospf6_gr_helper_exit(
815 OSPF6_GR_HELPER_TOPO_CHG
);
820 /* Add the routerid to the enable router hash table */
821 (void)hash_get(ospf6
->ospf6_helper_cfg
.enable_rtr_list
, &temp
,
822 ospf6_enable_rtr_hash_alloc
);
826 static void show_ospfv6_gr_helper_per_nbr(struct vty
*vty
, json_object
*json
,
827 bool uj
, struct ospf6_neighbor
*nbr
)
830 vty_out(vty
, " Routerid : %pI4\n", &nbr
->router_id
);
831 vty_out(vty
, " Received Grace period : %d(in seconds).\n",
832 nbr
->gr_helper_info
.recvd_grace_period
);
833 vty_out(vty
, " Actual Grace period : %d(in seconds)\n",
834 nbr
->gr_helper_info
.actual_grace_period
);
835 vty_out(vty
, " Remaining GraceTime:%ld(in seconds).\n",
836 event_timer_remain_second(
837 nbr
->gr_helper_info
.t_grace_timer
));
838 vty_out(vty
, " Graceful Restart reason: %s.\n\n",
839 ospf6_restart_reason_desc
[nbr
->gr_helper_info
840 .gr_restart_reason
]);
843 json_object
*json_neigh
= NULL
;
845 inet_ntop(AF_INET
, &nbr
->router_id
, nbrid
, sizeof(nbrid
));
846 json_neigh
= json_object_new_object();
847 json_object_string_add(json_neigh
, "routerid", nbrid
);
848 json_object_int_add(json_neigh
, "recvdGraceInterval",
849 nbr
->gr_helper_info
.recvd_grace_period
);
850 json_object_int_add(json_neigh
, "actualGraceInterval",
851 nbr
->gr_helper_info
.actual_grace_period
);
852 json_object_int_add(json_neigh
, "remainGracetime",
853 event_timer_remain_second(
854 nbr
->gr_helper_info
.t_grace_timer
));
855 json_object_string_add(json_neigh
, "restartReason",
856 ospf6_restart_reason_desc
[
857 nbr
->gr_helper_info
.gr_restart_reason
]);
858 json_object_object_add(json
, nbr
->name
, json_neigh
);
862 static void show_ospf6_gr_helper_details(struct vty
*vty
, struct ospf6
*ospf6
,
863 json_object
*json
, bool uj
, bool detail
)
865 struct ospf6_interface
*oi
;
867 /* Show Router ID. */
871 inet_ntop(AF_INET
, &ospf6
->router_id
, router_id
,
873 json_object_string_add(json
, "routerId", router_id
);
876 " OSPFv3 Routing Process (0) with Router-ID %pI4\n",
881 if (ospf6
->ospf6_helper_cfg
.is_helper_supported
)
883 " Graceful restart helper support enabled.\n");
886 " Graceful restart helper support disabled.\n");
888 if (ospf6
->ospf6_helper_cfg
.strict_lsa_check
)
889 vty_out(vty
, " Strict LSA check is enabled.\n");
891 vty_out(vty
, " Strict LSA check is disabled.\n");
893 if (ospf6
->ospf6_helper_cfg
.only_planned_restart
)
895 " Helper supported for planned restarts only.\n");
898 " Helper supported for Planned and Unplanned Restarts.\n");
901 " Supported Graceful restart interval: %d(in seconds).\n",
902 ospf6
->ospf6_helper_cfg
.supported_grace_time
);
904 if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf
)) {
905 vty_out(vty
, " Enable Router list:\n");
907 hash_walk(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
908 ospf6_print_vty_helper_dis_rtr_walkcb
, vty
);
909 vty_out(vty
, "\n\n");
912 if (ospf6
->ospf6_helper_cfg
.last_exit_reason
913 != OSPF6_GR_HELPER_EXIT_NONE
) {
914 vty_out(vty
, " Last Helper exit Reason :%s\n",
915 ospf6_exit_reason_desc
916 [ospf6
->ospf6_helper_cfg
919 if (ospf6
->ospf6_helper_cfg
.active_restarter_cnt
)
921 " Number of Active neighbours in graceful restart: %d\n",
922 ospf6
->ospf6_helper_cfg
923 .active_restarter_cnt
);
930 json_object_string_add(
931 json
, "helperSupport",
932 (ospf6
->ospf6_helper_cfg
.is_helper_supported
)
935 json_object_string_add(
936 json
, "strictLsaCheck",
937 (ospf6
->ospf6_helper_cfg
.strict_lsa_check
)
941 #if CONFDATE > 20240401
942 CPP_NOTICE("Remove deprecated json key: restartSupoort")
944 json_object_string_add(
945 json
, "restartSupoort",
946 (ospf6
->ospf6_helper_cfg
.only_planned_restart
)
947 ? "Planned Restart only"
948 : "Planned and Unplanned Restarts");
950 json_object_string_add(
951 json
, "restartSupport",
952 (ospf6
->ospf6_helper_cfg
.only_planned_restart
)
953 ? "Planned Restart only"
954 : "Planned and Unplanned Restarts");
957 json
, "supportedGracePeriod",
958 ospf6
->ospf6_helper_cfg
.supported_grace_time
);
960 if (ospf6
->ospf6_helper_cfg
.last_exit_reason
!=
961 OSPF6_GR_HELPER_EXIT_NONE
)
962 json_object_string_add(
963 json
, "lastExitReason",
964 ospf6_exit_reason_desc
965 [ospf6
->ospf6_helper_cfg
968 if (ospf6
->ospf6_helper_cfg
.active_restarter_cnt
)
970 json
, "activeRestarterCnt",
971 ospf6
->ospf6_helper_cfg
.active_restarter_cnt
);
973 if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6
)) {
974 struct json_object
*json_rid_array
=
975 json_object_new_array();
977 json_object_object_add(json
, "enabledRouterIds",
980 hash_walk(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
981 ospf6_print_json_helper_dis_rtr_walkcb
,
988 struct listnode
*i
, *j
, *k
;
989 struct ospf6_area
*oa
;
990 json_object
*json_neighbors
= NULL
;
992 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, i
, oa
))
993 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, j
, oi
)) {
994 struct ospf6_neighbor
*nbr
;
997 json_object_object_get_ex(
1000 if (!json_neighbors
) {
1002 json_object_new_object();
1003 json_object_object_add(
1009 for (ALL_LIST_ELEMENTS_RO(oi
->neighbor_list
, k
,
1012 if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr
))
1017 " Neighbour %d :\n",
1020 show_ospfv6_gr_helper_per_nbr(
1021 vty
, json_neighbors
, uj
, nbr
);
1028 /* Graceful Restart HELPER config Commands */
1029 DEFPY(ospf6_gr_helper_enable
,
1030 ospf6_gr_helper_enable_cmd
,
1031 "graceful-restart helper enable [A.B.C.D$rtr_id]",
1032 "ospf6 graceful restart\n"
1034 "Enable Helper support\n"
1035 "Advertisement Router-ID\n")
1037 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1039 if (rtr_id_str
!= NULL
) {
1041 ospf6_gr_helper_support_set_per_routerid(ospf6
, rtr_id
,
1047 ospf6_gr_helper_support_set(ospf6
, OSPF6_TRUE
);
1052 DEFPY(ospf6_gr_helper_disable
,
1053 ospf6_gr_helper_disable_cmd
,
1054 "no graceful-restart helper enable [A.B.C.D$rtr_id]",
1056 "ospf6 graceful restart\n"
1058 "Enable Helper support\n"
1059 "Advertisement Router-ID\n")
1061 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1063 if (rtr_id_str
!= NULL
) {
1065 ospf6_gr_helper_support_set_per_routerid(ospf6
, rtr_id
,
1071 ospf6_gr_helper_support_set(ospf6
, OSPF6_FALSE
);
1076 DEFPY(ospf6_gr_helper_disable_lsacheck
,
1077 ospf6_gr_helper_disable_lsacheck_cmd
,
1078 "graceful-restart helper lsa-check-disable",
1079 "ospf6 graceful restart\n"
1081 "disable strict LSA check\n")
1083 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1085 ospf6_gr_helper_lsacheck_set(ospf6
, OSPF6_FALSE
);
1089 DEFPY(no_ospf6_gr_helper_disable_lsacheck
,
1090 no_ospf6_gr_helper_disable_lsacheck_cmd
,
1091 "no graceful-restart helper lsa-check-disable",
1093 "ospf6 graceful restart\n"
1095 "diasble strict LSA check\n")
1097 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1099 ospf6_gr_helper_lsacheck_set(ospf6
, OSPF6_TRUE
);
1103 DEFPY(ospf6_gr_helper_planned_only
,
1104 ospf6_gr_helper_planned_only_cmd
,
1105 "graceful-restart helper planned-only",
1106 "ospf6 graceful restart\n"
1108 "supported only planned restart\n")
1110 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1112 ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6
, OSPF6_TRUE
);
1117 DEFPY(no_ospf6_gr_helper_planned_only
, no_ospf6_gr_helper_planned_only_cmd
,
1118 "no graceful-restart helper planned-only",
1120 "ospf6 graceful restart\n"
1122 "supported only for planned restart\n")
1124 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1126 ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6
, OSPF6_FALSE
);
1131 DEFPY(ospf6_gr_helper_supported_grace_time
,
1132 ospf6_gr_helper_supported_grace_time_cmd
,
1133 "graceful-restart helper supported-grace-time (10-1800)$interval",
1134 "ospf6 graceful restart\n"
1136 "supported grace timer\n"
1137 "grace interval(in seconds)\n")
1139 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1141 ospf6_gr_helper_supported_gracetime_set(ospf6
, interval
);
1145 DEFPY(no_ospf6_gr_helper_supported_grace_time
,
1146 no_ospf6_gr_helper_supported_grace_time_cmd
,
1147 "no graceful-restart helper supported-grace-time (10-1800)$interval",
1149 "ospf6 graceful restart\n"
1151 "supported grace timer\n"
1152 "grace interval(in seconds)\n")
1154 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1156 ospf6_gr_helper_supported_gracetime_set(ospf6
,
1157 OSPF6_MAX_GRACE_INTERVAL
);
1162 DEFPY(show_ipv6_ospf6_gr_helper
,
1163 show_ipv6_ospf6_gr_helper_cmd
,
1164 "show ipv6 ospf6 graceful-restart helper [detail] [json]",
1166 "Ipv6 Information\n"
1167 "OSPF6 information\n"
1168 "ospf6 graceful restart\n"
1169 "helper details in the router\n"
1170 "detailed information\n" JSON_STR
)
1173 bool uj
= use_json(argc
, argv
);
1174 struct ospf6
*ospf6
= NULL
;
1175 json_object
*json
= NULL
;
1176 bool detail
= false;
1178 ospf6
= ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME
);
1179 if (ospf6
== NULL
) {
1180 vty_out(vty
, "OSPFv3 is not configured\n");
1184 if (argv_find(argv
, argc
, "detail", &idx
))
1188 json
= json_object_new_object();
1190 show_ospf6_gr_helper_details(vty
, ospf6
, json
, uj
, detail
);
1193 vty_json(vty
, json
);
1198 /* Debug commands */
1199 DEFPY(debug_ospf6_gr
, debug_ospf6_gr_cmd
,
1200 "[no$no] debug ospf6 graceful-restart",
1201 NO_STR DEBUG_STR OSPF6_STR
"Graceful restart\n")
1204 OSPF6_DEBUG_GR_ON();
1206 OSPF6_DEBUG_GR_OFF();
1212 * Api to display the grace LSA information.
1224 static int ospf6_grace_lsa_show_info(struct vty
*vty
, struct ospf6_lsa
*lsa
,
1225 json_object
*json
, bool use_json
)
1227 struct ospf6_lsa_header
*lsah
= NULL
;
1228 struct tlv_header
*tlvh
= NULL
;
1229 struct grace_tlv_graceperiod
*gracePeriod
;
1230 struct grace_tlv_restart_reason
*grReason
;
1231 uint16_t length
= 0;
1234 lsah
= (struct ospf6_lsa_header
*)lsa
->header
;
1235 if (ntohs(lsah
->length
) <= OSPF6_LSA_HEADER_SIZE
) {
1236 if (IS_DEBUG_OSPF6_GR
)
1237 zlog_debug("%s: undersized (%u B) lsa", __func__
,
1238 ntohs(lsah
->length
));
1239 return OSPF6_FAILURE
;
1242 length
= ntohs(lsah
->length
) - OSPF6_LSA_HEADER_SIZE
;
1246 vty_out(vty
, "TLV info:\n");
1248 zlog_debug(" TLV info:");
1251 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
&& tlvh
;
1252 tlvh
= TLV_HDR_NEXT(tlvh
)) {
1255 if (sum
+ TLV_SIZE(tlvh
) > length
) {
1257 vty_out(vty
, "%% Invalid TLV length: %d\n",
1259 else if (IS_DEBUG_OSPF6_GR
)
1260 zlog_debug("%% Invalid TLV length: %d",
1262 return OSPF6_FAILURE
;
1265 switch (ntohs(tlvh
->type
)) {
1266 case GRACE_PERIOD_TYPE
:
1267 gracePeriod
= (struct grace_tlv_graceperiod
*)tlvh
;
1268 sum
+= TLV_SIZE(tlvh
);
1272 json_object_int_add(
1273 json
, "gracePeriod",
1274 ntohl(gracePeriod
->interval
));
1276 vty_out(vty
, " Grace period:%d\n",
1277 ntohl(gracePeriod
->interval
));
1279 zlog_debug(" Grace period:%d",
1280 ntohl(gracePeriod
->interval
));
1283 case RESTART_REASON_TYPE
:
1284 grReason
= (struct grace_tlv_restart_reason
*)tlvh
;
1285 sum
+= TLV_SIZE(tlvh
);
1288 json_object_string_add(
1289 json
, "restartReason",
1290 ospf6_restart_reason_desc
1291 [grReason
->reason
]);
1293 vty_out(vty
, " Restart reason:%s\n",
1294 ospf6_restart_reason_desc
1295 [grReason
->reason
]);
1297 zlog_debug(" Restart reason:%s",
1298 ospf6_restart_reason_desc
1299 [grReason
->reason
]);
1310 void ospf6_gr_helper_config_init(void)
1313 ospf6_install_lsa_handler(&grace_lsa_handler
);
1315 install_element(OSPF6_NODE
, &ospf6_gr_helper_enable_cmd
);
1316 install_element(OSPF6_NODE
, &ospf6_gr_helper_disable_cmd
);
1317 install_element(OSPF6_NODE
, &ospf6_gr_helper_disable_lsacheck_cmd
);
1318 install_element(OSPF6_NODE
, &no_ospf6_gr_helper_disable_lsacheck_cmd
);
1319 install_element(OSPF6_NODE
, &ospf6_gr_helper_planned_only_cmd
);
1320 install_element(OSPF6_NODE
, &no_ospf6_gr_helper_planned_only_cmd
);
1321 install_element(OSPF6_NODE
, &ospf6_gr_helper_supported_grace_time_cmd
);
1322 install_element(OSPF6_NODE
,
1323 &no_ospf6_gr_helper_supported_grace_time_cmd
);
1325 install_element(VIEW_NODE
, &show_ipv6_ospf6_gr_helper_cmd
);
1327 install_element(CONFIG_NODE
, &debug_ospf6_gr_cmd
);
1328 install_element(ENABLE_NODE
, &debug_ospf6_gr_cmd
);
1333 * Initialize GR helper config data structure.
1341 void ospf6_gr_helper_init(struct ospf6
*ospf6
)
1343 if (IS_DEBUG_OSPF6_GR
)
1344 zlog_debug("%s, GR Helper init.", __func__
);
1346 ospf6
->ospf6_helper_cfg
.is_helper_supported
= OSPF6_FALSE
;
1347 ospf6
->ospf6_helper_cfg
.strict_lsa_check
= OSPF6_TRUE
;
1348 ospf6
->ospf6_helper_cfg
.only_planned_restart
= OSPF6_FALSE
;
1349 ospf6
->ospf6_helper_cfg
.supported_grace_time
= OSPF6_MAX_GRACE_INTERVAL
;
1350 ospf6
->ospf6_helper_cfg
.last_exit_reason
= OSPF6_GR_HELPER_EXIT_NONE
;
1351 ospf6
->ospf6_helper_cfg
.active_restarter_cnt
= 0;
1353 ospf6
->ospf6_helper_cfg
.enable_rtr_list
= hash_create(
1354 ospf6_enable_rtr_hash_key
, ospf6_enable_rtr_hash_cmp
,
1355 "Ospf6 enable router hash");
1359 * De-initialize GR helper config data structure.
1367 void ospf6_gr_helper_deinit(struct ospf6
*ospf6
)
1370 if (IS_DEBUG_OSPF6_GR
)
1371 zlog_debug("%s, GR helper deinit.", __func__
);
1373 ospf6_enable_rtr_hash_destroy(ospf6
);
1376 static int ospf6_cfg_write_helper_enable_rtr_walkcb(struct hash_bucket
*backet
,
1379 struct advRtr
*rtr
= backet
->data
;
1380 struct vty
*vty
= (struct vty
*)arg
;
1382 vty_out(vty
, " graceful-restart helper enable %pI4\n", &rtr
->advRtrAddr
);
1383 return HASHWALK_CONTINUE
;
1386 int config_write_ospf6_gr_helper(struct vty
*vty
, struct ospf6
*ospf6
)
1388 if (ospf6
->ospf6_helper_cfg
.is_helper_supported
)
1389 vty_out(vty
, " graceful-restart helper enable\n");
1391 if (!ospf6
->ospf6_helper_cfg
.strict_lsa_check
)
1392 vty_out(vty
, " graceful-restart helper lsa-check-disable\n");
1394 if (ospf6
->ospf6_helper_cfg
.only_planned_restart
)
1395 vty_out(vty
, " graceful-restart helper planned-only\n");
1397 if (ospf6
->ospf6_helper_cfg
.supported_grace_time
1398 != OSPF6_MAX_GRACE_INTERVAL
)
1400 " graceful-restart helper supported-grace-time %d\n",
1401 ospf6
->ospf6_helper_cfg
.supported_grace_time
);
1403 if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6
)) {
1404 hash_walk(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
1405 ospf6_cfg_write_helper_enable_rtr_walkcb
, vty
);
1411 int config_write_ospf6_debug_gr_helper(struct vty
*vty
)
1413 if (IS_DEBUG_OSPF6_GR
)
1414 vty_out(vty
, "debug ospf6 graceful-restart\n");