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
;
158 length
= ntohs(lsah
->length
) - OSPF6_LSA_HEADER_SIZE
;
160 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
&& tlvh
;
161 tlvh
= TLV_HDR_NEXT(tlvh
)) {
163 /* Check TLV len against overall LSA */
164 if (sum
+ TLV_SIZE(tlvh
) > length
) {
165 if (IS_DEBUG_OSPF6_GR
)
167 "%s: Malformed packet: Invalid TLV len:%d",
168 __func__
, TLV_SIZE(tlvh
));
169 return OSPF6_FAILURE
;
172 switch (ntohs(tlvh
->type
)) {
173 case GRACE_PERIOD_TYPE
:
174 gracePeriod
= (struct grace_tlv_graceperiod
*)tlvh
;
175 *interval
= ntohl(gracePeriod
->interval
);
176 sum
+= TLV_SIZE(tlvh
);
178 /* Check if grace interval is valid */
179 if (*interval
> OSPF6_MAX_GRACE_INTERVAL
180 || *interval
< OSPF6_MIN_GRACE_INTERVAL
)
181 return OSPF6_FAILURE
;
183 case RESTART_REASON_TYPE
:
184 grReason
= (struct grace_tlv_restart_reason
*)tlvh
;
185 *reason
= grReason
->reason
;
186 sum
+= TLV_SIZE(tlvh
);
188 if (*reason
>= OSPF6_GR_INVALID_REASON_CODE
)
189 return OSPF6_FAILURE
;
192 if (IS_DEBUG_OSPF6_GR
)
193 zlog_debug("%s, Ignoring unknown TLV type:%d",
194 __func__
, ntohs(tlvh
->type
));
198 return OSPF6_SUCCESS
;
202 * Grace timer expiry handler.
203 * HELPER aborts its role at grace timer expiry.
211 static int ospf6_handle_grace_timer_expiry(struct thread
*thread
)
213 struct ospf6_neighbor
*nbr
= THREAD_ARG(thread
);
215 ospf6_gr_helper_exit(nbr
, OSPF6_GR_HELPER_GRACE_TIMEOUT
);
216 return OSPF6_SUCCESS
;
220 * API to check any change in the neighbor's
221 * retransmission list.
227 * TRUE - if any change in the lsa.
228 * FALSE - no change in the lsas.
230 static bool ospf6_check_chg_in_rxmt_list(struct ospf6_neighbor
*nbr
)
232 struct ospf6_lsa
*lsa
, *lsanext
;
234 for (ALL_LSDB(nbr
->retrans_list
, lsa
, lsanext
)) {
235 struct ospf6_lsa
*lsa_in_db
= NULL
;
237 /* Fetching the same copy of LSA form LSDB to validate the
241 ospf6_lsdb_lookup(lsa
->header
->type
, lsa
->header
->id
,
242 lsa
->header
->adv_router
, lsa
->lsdb
);
244 if (lsa_in_db
&& lsa_in_db
->tobe_acknowledged
) {
245 ospf6_lsa_unlock(lsa
);
247 ospf6_lsa_unlock(lsanext
);
257 * Process Grace LSA.If it is eligible move to HELPER role.
258 * Ref rfc3623 section 3.1 and rfc5187
264 * Grace LSA received from RESTARTER.
267 * ospf6 neighbour which requests the router to act as
272 * If supported as HELPER : OSPF_GR_HELPER_INPROGRESS
273 * If Not supported as HELPER : OSPF_GR_HELPER_NONE
275 int ospf6_process_grace_lsa(struct ospf6
*ospf6
, struct ospf6_lsa
*lsa
,
276 struct ospf6_neighbor
*restarter
)
278 uint8_t restart_reason
= 0;
279 uint32_t grace_interval
= 0;
280 uint32_t actual_grace_interval
= 0;
281 struct advRtr lookup
;
284 /* Extract the grace lsa packet fields */
285 ret
= ospf6_extract_grace_lsa_fields(lsa
, &grace_interval
,
287 if (ret
!= OSPF6_SUCCESS
) {
288 if (IS_DEBUG_OSPF6_GR
)
289 zlog_debug("%s, Wrong Grace LSA packet.", __func__
);
290 return OSPF6_GR_NOT_HELPER
;
293 if (IS_DEBUG_OSPF6_GR
)
295 "%s, Grace LSA received from %pI4, grace interval:%u, restart reason :%s",
296 __func__
, &restarter
->router_id
, grace_interval
,
297 ospf6_restart_reason_desc
[restart_reason
]);
299 /* Verify Helper enabled globally */
300 if (!ospf6
->ospf6_helper_cfg
.is_helper_supported
) {
301 /* Verify Helper support is enabled for the
302 * current neighbour router-id.
304 lookup
.advRtrAddr
= restarter
->router_id
;
306 if (!hash_lookup(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
308 if (IS_DEBUG_OSPF6_GR
)
310 "%s, HELPER support is disabled, So not a HELPER",
312 restarter
->gr_helper_info
.rejected_reason
=
313 OSPF6_HELPER_SUPPORT_DISABLED
;
314 return OSPF6_GR_NOT_HELPER
;
318 /* Check neighbour is in FULL state and
319 * became a adjacency.
321 if (!IS_NBR_STATE_FULL(restarter
)) {
322 if (IS_DEBUG_OSPF6_GR
)
324 "%s, This Neighbour %pI6 is not in FULL state.",
325 __func__
, &restarter
->linklocal_addr
);
326 restarter
->gr_helper_info
.rejected_reason
=
327 OSPF6_HELPER_NOT_A_VALID_NEIGHBOUR
;
328 return OSPF6_GR_NOT_HELPER
;
331 /* Based on the restart reason from grace lsa
332 * check the current router is supporting or not
334 if (ospf6
->ospf6_helper_cfg
.only_planned_restart
335 && !OSPF6_GR_IS_PLANNED_RESTART(restart_reason
)) {
336 if (IS_DEBUG_OSPF6_GR
)
338 "%s, Router supports only planned restarts but received the GRACE LSA due a unplanned restart",
340 restarter
->gr_helper_info
.rejected_reason
=
341 OSPF6_HELPER_PLANNED_ONLY_RESTART
;
342 return OSPF6_GR_NOT_HELPER
;
345 /* Check the retransmission list of this
346 * neighbour, check any change in lsas.
348 if (ospf6
->ospf6_helper_cfg
.strict_lsa_check
349 && restarter
->retrans_list
->count
350 && ospf6_check_chg_in_rxmt_list(restarter
)) {
351 if (IS_DEBUG_OSPF6_GR
)
353 "%s, Changed LSA in Rxmt list.So not Helper.",
355 restarter
->gr_helper_info
.rejected_reason
=
356 OSPF6_HELPER_TOPO_CHANGE_RTXMT_LIST
;
357 return OSPF6_GR_NOT_HELPER
;
360 /* LSA age must be less than the grace period */
361 if (ntohs(lsa
->header
->age
) >= grace_interval
) {
362 if (IS_DEBUG_OSPF6_GR
)
364 "%s, Grace LSA age(%d) is more than the grace interval(%d)",
365 __func__
, lsa
->header
->age
, grace_interval
);
366 restarter
->gr_helper_info
.rejected_reason
=
367 OSPF6_HELPER_LSA_AGE_MORE
;
368 return OSPF6_GR_NOT_HELPER
;
371 if (ospf6
->gr_info
.restart_in_progress
) {
372 if (IS_DEBUG_OSPF6_GR
)
374 "%s: router is in the process of graceful restart",
376 restarter
->gr_helper_info
.rejected_reason
=
377 OSPF6_HELPER_RESTARTING
;
378 return OSPF6_GR_NOT_HELPER
;
381 /* check supported grace period configured
382 * if configured, use this to start the grace
383 * timer otherwise use the interval received
384 * in grace LSA packet.
386 actual_grace_interval
= grace_interval
;
387 if (grace_interval
> ospf6
->ospf6_helper_cfg
.supported_grace_time
) {
388 if (IS_DEBUG_OSPF6_GR
)
390 "%s, Received grace period %d is larger than supported grace %d",
391 __func__
, grace_interval
,
392 ospf6
->ospf6_helper_cfg
.supported_grace_time
);
393 actual_grace_interval
=
394 ospf6
->ospf6_helper_cfg
.supported_grace_time
;
397 if (OSPF6_GR_IS_ACTIVE_HELPER(restarter
)) {
398 if (restarter
->gr_helper_info
.t_grace_timer
)
399 THREAD_OFF(restarter
->gr_helper_info
.t_grace_timer
);
401 if (ospf6
->ospf6_helper_cfg
.active_restarter_cnt
> 0)
402 ospf6
->ospf6_helper_cfg
.active_restarter_cnt
--;
404 if (IS_DEBUG_OSPF6_GR
)
406 "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
409 if (IS_DEBUG_OSPF6_GR
)
411 "%s, This Router becomes a HELPER for the neighbour %pI6",
412 __func__
, &restarter
->linklocal_addr
);
415 /* Became a Helper to the RESTART neighbour.
416 * change the helper status.
418 restarter
->gr_helper_info
.gr_helper_status
= OSPF6_GR_ACTIVE_HELPER
;
419 restarter
->gr_helper_info
.recvd_grace_period
= grace_interval
;
420 restarter
->gr_helper_info
.actual_grace_period
= actual_grace_interval
;
421 restarter
->gr_helper_info
.gr_restart_reason
= restart_reason
;
422 restarter
->gr_helper_info
.rejected_reason
= OSPF6_HELPER_REJECTED_NONE
;
424 /* Increment the active restart nbr count */
425 ospf6
->ospf6_helper_cfg
.active_restarter_cnt
++;
427 if (IS_DEBUG_OSPF6_GR
)
428 zlog_debug("%s, Grace timer started.interval:%u", __func__
,
429 actual_grace_interval
);
431 /* Start the grace timer */
432 thread_add_timer(master
, ospf6_handle_grace_timer_expiry
, restarter
,
433 actual_grace_interval
,
434 &restarter
->gr_helper_info
.t_grace_timer
);
436 return OSPF6_GR_ACTIVE_HELPER
;
440 * Api to exit from HELPER role to take all actions
442 * Ref rfc3623 section 3. and rfc51872
448 * Ospf6 neighbour for which it is acting as HELPER.
451 * The reason for exiting from HELPER.
456 void ospf6_gr_helper_exit(struct ospf6_neighbor
*nbr
,
457 enum ospf6_helper_exit_reason reason
)
459 struct ospf6_interface
*oi
= nbr
->ospf6_if
;
465 ospf6
= oi
->area
->ospf6
;
467 if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr
))
470 if (IS_DEBUG_OSPF6_GR
)
471 zlog_debug("%s, Exiting from HELPER support to %pI6, due to %s",
472 __func__
, &nbr
->linklocal_addr
,
473 ospf6_exit_reason_desc
[reason
]);
475 /* Reset helper status*/
476 nbr
->gr_helper_info
.gr_helper_status
= OSPF6_GR_NOT_HELPER
;
477 nbr
->gr_helper_info
.helper_exit_reason
= reason
;
478 nbr
->gr_helper_info
.actual_grace_period
= 0;
479 nbr
->gr_helper_info
.recvd_grace_period
= 0;
480 nbr
->gr_helper_info
.gr_restart_reason
= 0;
481 ospf6
->ospf6_helper_cfg
.last_exit_reason
= reason
;
483 /* If the exit not triggered due to grace timer
484 * expiry, stop the grace timer.
486 if (reason
!= OSPF6_GR_HELPER_GRACE_TIMEOUT
)
487 THREAD_OFF(nbr
->gr_helper_info
.t_grace_timer
);
489 if (ospf6
->ospf6_helper_cfg
.active_restarter_cnt
<= 0) {
491 "OSPF6 GR-Helper: Number of active Restarters should be greater than zero.");
494 /* Decrement active restarter count */
495 ospf6
->ospf6_helper_cfg
.active_restarter_cnt
--;
497 /* check exit triggered due to successful completion
498 * of graceful restart.
500 if (reason
!= OSPF6_GR_HELPER_COMPLETED
) {
501 if (IS_DEBUG_OSPF6_GR
)
502 zlog_debug("%s, Unsuccessful GR exit. RESTARTER : %pI6",
503 __func__
, &nbr
->linklocal_addr
);
506 /*Recalculate the DR for the network segment */
509 /* Originate a router LSA */
510 OSPF6_ROUTER_LSA_SCHEDULE(nbr
->ospf6_if
->area
);
512 /* Originate network lsa if it is an DR in the LAN */
513 if (nbr
->ospf6_if
->state
== OSPF6_INTERFACE_DR
)
514 OSPF6_NETWORK_LSA_SCHEDULE(nbr
->ospf6_if
);
518 * Process max age Grace LSA.
519 * It is a indication for successful completion of GR.
520 * If router acting as HELPER, It exits from helper role.
526 * Grace LSA received from RESTARTER.
529 * ospf6 neighbour which request the router to act as
535 void ospf6_process_maxage_grace_lsa(struct ospf6
*ospf6
, struct ospf6_lsa
*lsa
,
536 struct ospf6_neighbor
*restarter
)
538 uint8_t restart_reason
= 0;
539 uint32_t grace_interval
= 0;
542 /* Extract the grace lsa packet fields */
543 ret
= ospf6_extract_grace_lsa_fields(lsa
, &grace_interval
,
545 if (ret
!= OSPF6_SUCCESS
) {
546 if (IS_DEBUG_OSPF6_GR
)
547 zlog_debug("%s, Wrong Grace LSA packet.", __func__
);
551 if (IS_DEBUG_OSPF6_GR
)
552 zlog_debug("%s, GraceLSA received for neighbour %pI4.",
553 __func__
, &restarter
->router_id
);
555 ospf6_gr_helper_exit(restarter
, OSPF6_GR_HELPER_COMPLETED
);
559 * Actions to be taken when topo change detected
560 * HELPER will be exited upon a topo change.
565 * topo change occurred due to this lsa(type (1-5 and 7)
570 void ospf6_helper_handle_topo_chg(struct ospf6
*ospf6
, struct ospf6_lsa
*lsa
)
572 struct listnode
*i
, *j
, *k
;
573 struct ospf6_neighbor
*nbr
= NULL
;
574 struct ospf6_area
*oa
= NULL
;
575 struct ospf6_interface
*oi
= NULL
;
577 if (!ospf6
->ospf6_helper_cfg
.active_restarter_cnt
)
580 /* Topo change not required to be handled if strict
581 * LSA check is disabled for this router.
583 if (!ospf6
->ospf6_helper_cfg
.strict_lsa_check
)
586 if (IS_DEBUG_OSPF6_GR
)
587 zlog_debug("%s, Topo change detected due to lsa details : %s",
588 __func__
, lsa
->name
);
590 lsa
->tobe_acknowledged
= OSPF6_TRUE
;
592 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, i
, oa
))
593 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, j
, oi
)) {
595 /* Ref rfc3623 section 3.2.3.b and rfc5187
596 * If change due to external LSA and if the area is
597 * stub, then it is not a topo change. Since Type-5
598 * lsas will not be flooded in stub area.
600 if (IS_AREA_STUB(oi
->area
)
601 && ((lsa
->header
->type
== OSPF6_LSTYPE_AS_EXTERNAL
)
602 || (lsa
->header
->type
== OSPF6_LSTYPE_TYPE_7
)
603 || (lsa
->header
->type
604 == OSPF6_LSTYPE_INTER_ROUTER
))) {
608 for (ALL_LIST_ELEMENTS_RO(oi
->neighbor_list
, k
, nbr
)) {
610 ospf6_gr_helper_exit(nbr
,
611 OSPF6_GR_HELPER_TOPO_CHG
);
616 /* Configuration handlers */
618 * Disable/Enable HELPER support on router level.
629 static void ospf6_gr_helper_support_set(struct ospf6
*ospf6
, bool support
)
631 struct ospf6_interface
*oi
;
632 struct advRtr lookup
;
633 struct listnode
*i
, *j
, *k
;
634 struct ospf6_neighbor
*nbr
= NULL
;
635 struct ospf6_area
*oa
= NULL
;
637 if (ospf6
->ospf6_helper_cfg
.is_helper_supported
== support
)
640 ospf6
->ospf6_helper_cfg
.is_helper_supported
= support
;
642 /* If helper support disabled, cease HELPER role for all
643 * supporting neighbors.
645 if (support
== OSPF6_FALSE
) {
646 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, i
, oa
))
647 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, j
, oi
)) {
649 for (ALL_LIST_ELEMENTS_RO(oi
->neighbor_list
, k
,
652 lookup
.advRtrAddr
= nbr
->router_id
;
653 /* check if helper support enabled for
654 * the corresponding routerid.
656 * dont exit from helper role.
659 ospf6
->ospf6_helper_cfg
664 ospf6_gr_helper_exit(
665 nbr
, OSPF6_GR_HELPER_TOPO_CHG
);
672 * Api to enable/disable strict lsa check on the HELPER.
678 * True - disable the lsa check.
679 * False - enable the strict lsa check.
684 static void ospf6_gr_helper_lsacheck_set(struct ospf6
*ospf6
, bool enabled
)
686 if (ospf6
->ospf6_helper_cfg
.strict_lsa_check
== enabled
)
689 ospf6
->ospf6_helper_cfg
.strict_lsa_check
= enabled
;
693 * Api to set the supported restart reason.
699 * True: support only planned restart.
700 * False: support for planned/unplanned restarts.
707 ospf6_gr_helper_set_supported_onlyPlanned_restart(struct ospf6
*ospf6
,
710 ospf6
->ospf6_helper_cfg
.only_planned_restart
= only_planned
;
714 * Api to set the supported grace interval in this router.
720 * The supported grace interval..
725 static void ospf6_gr_helper_supported_gracetime_set(struct ospf6
*ospf6
,
728 ospf6
->ospf6_helper_cfg
.supported_grace_time
= interval
;
731 /* API to walk and print all the Helper supported router ids */
732 static int ospf6_print_vty_helper_dis_rtr_walkcb(struct hash_bucket
*bucket
,
735 struct advRtr
*rtr
= bucket
->data
;
736 struct vty
*vty
= (struct vty
*)arg
;
737 static unsigned int count
;
739 vty_out(vty
, "%-6pI4,", &rtr
->advRtrAddr
);
745 return HASHWALK_CONTINUE
;
748 /* API to walk and print all the Helper supported router ids.*/
749 static int ospf6_print_json_helper_dis_rtr_walkcb(struct hash_bucket
*bucket
,
752 struct advRtr
*rtr
= bucket
->data
;
753 struct json_object
*json_rid_array
= (struct json_object
*)arg
;
754 struct json_object
*json_rid
;
757 inet_ntop(AF_INET
, &rtr
->advRtrAddr
, router_id
, sizeof(router_id
));
759 json_rid
= json_object_new_object();
761 json_object_string_add(json_rid
, "routerId", router_id
);
762 json_object_array_add(json_rid_array
, json_rid
);
764 return HASHWALK_CONTINUE
;
768 * Enable/Disable HELPER support on a specified advertisement
775 * HELPER support for given Advertisement Router.
778 * True - Enable Helper Support.
779 * False - Disable Helper Support.
784 static void ospf6_gr_helper_support_set_per_routerid(struct ospf6
*ospf6
,
785 struct in_addr router_id
,
790 struct listnode
*i
, *j
, *k
;
791 struct ospf6_interface
*oi
;
792 struct ospf6_neighbor
*nbr
;
793 struct ospf6_area
*oa
;
795 temp
.advRtrAddr
= router_id
.s_addr
;
797 if (support
== OSPF6_FALSE
) {
798 /*Delete the routerid from the enable router hash table */
799 rtr
= hash_lookup(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
803 hash_release(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
805 ospf6_disable_rtr_hash_free(rtr
);
808 /* If helper support is enabled globally
809 * no action is required.
811 if (ospf6
->ospf6_helper_cfg
.is_helper_supported
)
814 /* Cease the HELPER role fore neighbours from the
815 * specified advertisement router.
817 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, i
, oa
))
818 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, j
, oi
)) {
820 for (ALL_LIST_ELEMENTS_RO(oi
->neighbor_list
, k
,
823 if (nbr
->router_id
!= router_id
.s_addr
)
826 if (OSPF6_GR_IS_ACTIVE_HELPER(nbr
))
827 ospf6_gr_helper_exit(
829 OSPF6_GR_HELPER_TOPO_CHG
);
834 /* Add the routerid to the enable router hash table */
835 hash_get(ospf6
->ospf6_helper_cfg
.enable_rtr_list
, &temp
,
836 ospf6_enable_rtr_hash_alloc
);
840 static void show_ospfv6_gr_helper_per_nbr(struct vty
*vty
, json_object
*json
,
841 bool uj
, struct ospf6_neighbor
*nbr
)
844 vty_out(vty
, " Routerid : %pI4\n", &nbr
->router_id
);
845 vty_out(vty
, " Received Grace period : %d(in seconds).\n",
846 nbr
->gr_helper_info
.recvd_grace_period
);
847 vty_out(vty
, " Actual Grace period : %d(in seconds)\n",
848 nbr
->gr_helper_info
.actual_grace_period
);
849 vty_out(vty
, " Remaining GraceTime:%ld(in seconds).\n",
850 thread_timer_remain_second(
851 nbr
->gr_helper_info
.t_grace_timer
));
852 vty_out(vty
, " Graceful Restart reason: %s.\n\n",
853 ospf6_restart_reason_desc
[nbr
->gr_helper_info
854 .gr_restart_reason
]);
857 json_object
*json_neigh
= NULL
;
859 inet_ntop(AF_INET
, &nbr
->router_id
, nbrid
, sizeof(nbrid
));
860 json_neigh
= json_object_new_object();
861 json_object_string_add(json_neigh
, "routerid", nbrid
);
862 json_object_int_add(json_neigh
, "recvdGraceInterval",
863 nbr
->gr_helper_info
.recvd_grace_period
);
864 json_object_int_add(json_neigh
, "actualGraceInterval",
865 nbr
->gr_helper_info
.actual_grace_period
);
866 json_object_int_add(json_neigh
, "remainGracetime",
867 thread_timer_remain_second(
868 nbr
->gr_helper_info
.t_grace_timer
));
869 json_object_string_add(json_neigh
, "restartReason",
870 ospf6_restart_reason_desc
[
871 nbr
->gr_helper_info
.gr_restart_reason
]);
872 json_object_object_add(json
, nbr
->name
, json_neigh
);
876 static void show_ospf6_gr_helper_details(struct vty
*vty
, struct ospf6
*ospf6
,
877 json_object
*json
, bool uj
, bool detail
)
879 struct ospf6_interface
*oi
;
881 /* Show Router ID. */
885 inet_ntop(AF_INET
, &ospf6
->router_id
, router_id
,
887 json_object_string_add(json
, "routerId", router_id
);
890 " OSPFv3 Routing Process (0) with Router-ID %pI4\n",
895 if (ospf6
->ospf6_helper_cfg
.is_helper_supported
)
897 " Graceful restart helper support enabled.\n");
900 " Graceful restart helper support disabled.\n");
902 if (ospf6
->ospf6_helper_cfg
.strict_lsa_check
)
903 vty_out(vty
, " Strict LSA check is enabled.\n");
905 vty_out(vty
, " Strict LSA check is disabled.\n");
907 if (ospf6
->ospf6_helper_cfg
.only_planned_restart
)
909 " Helper supported for planned restarts only.\n");
912 " Helper supported for Planned and Unplanned Restarts.\n");
915 " Supported Graceful restart interval: %d(in seconds).\n",
916 ospf6
->ospf6_helper_cfg
.supported_grace_time
);
918 if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf
)) {
919 vty_out(vty
, " Enable Router list:\n");
921 hash_walk(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
922 ospf6_print_vty_helper_dis_rtr_walkcb
, vty
);
923 vty_out(vty
, "\n\n");
926 if (ospf6
->ospf6_helper_cfg
.last_exit_reason
927 != OSPF6_GR_HELPER_EXIT_NONE
) {
928 vty_out(vty
, " Last Helper exit Reason :%s\n",
929 ospf6_exit_reason_desc
930 [ospf6
->ospf6_helper_cfg
933 if (ospf6
->ospf6_helper_cfg
.active_restarter_cnt
)
935 " Number of Active neighbours in graceful restart: %d\n",
936 ospf6
->ospf6_helper_cfg
937 .active_restarter_cnt
);
944 json_object_string_add(
945 json
, "helperSupport",
946 (ospf6
->ospf6_helper_cfg
.is_helper_supported
)
949 json_object_string_add(
950 json
, "strictLsaCheck",
951 (ospf6
->ospf6_helper_cfg
.strict_lsa_check
)
954 json_object_string_add(
955 json
, "restartSupoort",
956 (ospf6
->ospf6_helper_cfg
.only_planned_restart
)
957 ? "Planned Restart only"
958 : "Planned and Unplanned Restarts");
961 json
, "supportedGracePeriod",
962 ospf6
->ospf6_helper_cfg
.supported_grace_time
);
964 #if CONFDATE > 20230131
965 CPP_NOTICE("Remove JSON object commands with keys starting with capital")
967 if (ospf6
->ospf6_helper_cfg
.last_exit_reason
!=
968 OSPF6_GR_HELPER_EXIT_NONE
) {
969 json_object_string_add(
970 json
, "LastExitReason",
971 ospf6_exit_reason_desc
972 [ospf6
->ospf6_helper_cfg
974 json_object_string_add(
975 json
, "lastExitReason",
976 ospf6_exit_reason_desc
977 [ospf6
->ospf6_helper_cfg
981 if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6
)) {
982 struct json_object
*json_rid_array
=
983 json_object_new_array();
985 json_object_object_add(json
, "enabledRouterIds",
988 hash_walk(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
989 ospf6_print_json_helper_dis_rtr_walkcb
,
996 struct listnode
*i
, *j
, *k
;
997 struct ospf6_area
*oa
;
998 json_object
*json_neighbors
= NULL
;
1000 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, i
, oa
))
1001 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, j
, oi
)) {
1002 struct ospf6_neighbor
*nbr
;
1005 json_object_object_get_ex(
1008 json_object_object_get_ex(
1011 if (!json_neighbors
) {
1013 json_object_new_object();
1014 json_object_object_add(
1017 json_object_object_add(
1023 for (ALL_LIST_ELEMENTS_RO(oi
->neighbor_list
, k
,
1026 if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr
))
1031 " Neighbour %d :\n",
1034 show_ospfv6_gr_helper_per_nbr(
1035 vty
, json_neighbors
, uj
, nbr
);
1042 /* Graceful Restart HELPER config Commands */
1043 DEFPY(ospf6_gr_helper_enable
,
1044 ospf6_gr_helper_enable_cmd
,
1045 "graceful-restart helper enable [A.B.C.D$rtr_id]",
1046 "ospf6 graceful restart\n"
1048 "Enable Helper support\n"
1049 "Advertisement Router-ID\n")
1051 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1053 if (rtr_id_str
!= NULL
) {
1055 ospf6_gr_helper_support_set_per_routerid(ospf6
, rtr_id
,
1061 ospf6_gr_helper_support_set(ospf6
, OSPF6_TRUE
);
1066 DEFPY(ospf6_gr_helper_disable
,
1067 ospf6_gr_helper_disable_cmd
,
1068 "no graceful-restart helper enable [A.B.C.D$rtr_id]",
1070 "ospf6 graceful restart\n"
1072 "Enable Helper support\n"
1073 "Advertisement Router-ID\n")
1075 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1077 if (rtr_id_str
!= NULL
) {
1079 ospf6_gr_helper_support_set_per_routerid(ospf6
, rtr_id
,
1085 ospf6_gr_helper_support_set(ospf6
, OSPF6_FALSE
);
1090 DEFPY(ospf6_gr_helper_disable_lsacheck
,
1091 ospf6_gr_helper_disable_lsacheck_cmd
,
1092 "graceful-restart helper lsa-check-disable",
1093 "ospf6 graceful restart\n"
1095 "disable strict LSA check\n")
1097 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1099 ospf6_gr_helper_lsacheck_set(ospf6
, OSPF6_FALSE
);
1103 DEFPY(no_ospf6_gr_helper_disable_lsacheck
,
1104 no_ospf6_gr_helper_disable_lsacheck_cmd
,
1105 "no graceful-restart helper lsa-check-disable",
1107 "ospf6 graceful restart\n"
1109 "diasble strict LSA check\n")
1111 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1113 ospf6_gr_helper_lsacheck_set(ospf6
, OSPF6_TRUE
);
1117 DEFPY(ospf6_gr_helper_planned_only
,
1118 ospf6_gr_helper_planned_only_cmd
,
1119 "graceful-restart helper planned-only",
1120 "ospf6 graceful restart\n"
1122 "supported only planned restart\n")
1124 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1126 ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6
, OSPF6_TRUE
);
1131 DEFPY(no_ospf6_gr_helper_planned_only
, no_ospf6_gr_helper_planned_only_cmd
,
1132 "no graceful-restart helper planned-only",
1134 "ospf6 graceful restart\n"
1136 "supported only for planned restart\n")
1138 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1140 ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6
, OSPF6_FALSE
);
1145 DEFPY(ospf6_gr_helper_supported_grace_time
,
1146 ospf6_gr_helper_supported_grace_time_cmd
,
1147 "graceful-restart helper supported-grace-time (10-1800)$interval",
1148 "ospf6 graceful restart\n"
1150 "supported grace timer\n"
1151 "grace interval(in seconds)\n")
1153 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1155 ospf6_gr_helper_supported_gracetime_set(ospf6
, interval
);
1159 DEFPY(no_ospf6_gr_helper_supported_grace_time
,
1160 no_ospf6_gr_helper_supported_grace_time_cmd
,
1161 "no graceful-restart helper supported-grace-time (10-1800)$interval",
1163 "ospf6 graceful restart\n"
1165 "supported grace timer\n"
1166 "grace interval(in seconds)\n")
1168 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1170 ospf6_gr_helper_supported_gracetime_set(ospf6
,
1171 OSPF6_MAX_GRACE_INTERVAL
);
1176 DEFPY(show_ipv6_ospf6_gr_helper
,
1177 show_ipv6_ospf6_gr_helper_cmd
,
1178 "show ipv6 ospf6 graceful-restart helper [detail] [json]",
1180 "Ipv6 Information\n"
1181 "OSPF6 information\n"
1182 "ospf6 graceful restart\n"
1183 "helper details in the router\n"
1184 "detailed information\n" JSON_STR
)
1187 bool uj
= use_json(argc
, argv
);
1188 struct ospf6
*ospf6
= NULL
;
1189 json_object
*json
= NULL
;
1190 bool detail
= false;
1192 ospf6
= ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME
);
1193 if (ospf6
== NULL
) {
1194 vty_out(vty
, "OSPFv3 is not configured\n");
1198 if (argv_find(argv
, argc
, "detail", &idx
))
1202 json
= json_object_new_object();
1204 show_ospf6_gr_helper_details(vty
, ospf6
, json
, uj
, detail
);
1207 vty_json(vty
, json
);
1212 /* Debug commands */
1213 DEFPY(debug_ospf6_gr
, debug_ospf6_gr_cmd
,
1214 "[no$no] debug ospf6 graceful-restart",
1215 NO_STR DEBUG_STR OSPF6_STR
"Graceful restart\n")
1218 OSPF6_DEBUG_GR_ON();
1220 OSPF6_DEBUG_GR_OFF();
1226 * Api to display the grace LSA information.
1238 static int ospf6_grace_lsa_show_info(struct vty
*vty
, struct ospf6_lsa
*lsa
,
1239 json_object
*json
, bool use_json
)
1241 struct ospf6_lsa_header
*lsah
= NULL
;
1242 struct tlv_header
*tlvh
= NULL
;
1243 struct grace_tlv_graceperiod
*gracePeriod
;
1244 struct grace_tlv_restart_reason
*grReason
;
1245 uint16_t length
= 0;
1248 lsah
= (struct ospf6_lsa_header
*)lsa
->header
;
1250 length
= ntohs(lsah
->length
) - OSPF6_LSA_HEADER_SIZE
;
1254 vty_out(vty
, "TLV info:\n");
1256 zlog_debug(" TLV info:");
1259 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
&& tlvh
;
1260 tlvh
= TLV_HDR_NEXT(tlvh
)) {
1263 if (sum
+ TLV_SIZE(tlvh
) > length
) {
1265 vty_out(vty
, "%% Invalid TLV length: %d\n",
1267 else if (IS_DEBUG_OSPF6_GR
)
1268 zlog_debug("%% Invalid TLV length: %d",
1270 return OSPF6_FAILURE
;
1273 switch (ntohs(tlvh
->type
)) {
1274 case GRACE_PERIOD_TYPE
:
1275 gracePeriod
= (struct grace_tlv_graceperiod
*)tlvh
;
1276 sum
+= TLV_SIZE(tlvh
);
1280 json_object_int_add(
1281 json
, "gracePeriod",
1282 ntohl(gracePeriod
->interval
));
1284 vty_out(vty
, " Grace period:%d\n",
1285 ntohl(gracePeriod
->interval
));
1287 zlog_debug(" Grace period:%d",
1288 ntohl(gracePeriod
->interval
));
1291 case RESTART_REASON_TYPE
:
1292 grReason
= (struct grace_tlv_restart_reason
*)tlvh
;
1293 sum
+= TLV_SIZE(tlvh
);
1296 json_object_string_add(
1297 json
, "restartReason",
1298 ospf6_restart_reason_desc
1299 [grReason
->reason
]);
1301 vty_out(vty
, " Restart reason:%s\n",
1302 ospf6_restart_reason_desc
1303 [grReason
->reason
]);
1305 zlog_debug(" Restart reason:%s",
1306 ospf6_restart_reason_desc
1307 [grReason
->reason
]);
1318 void ospf6_gr_helper_config_init(void)
1321 ospf6_install_lsa_handler(&grace_lsa_handler
);
1323 install_element(OSPF6_NODE
, &ospf6_gr_helper_enable_cmd
);
1324 install_element(OSPF6_NODE
, &ospf6_gr_helper_disable_cmd
);
1325 install_element(OSPF6_NODE
, &ospf6_gr_helper_disable_lsacheck_cmd
);
1326 install_element(OSPF6_NODE
, &no_ospf6_gr_helper_disable_lsacheck_cmd
);
1327 install_element(OSPF6_NODE
, &ospf6_gr_helper_planned_only_cmd
);
1328 install_element(OSPF6_NODE
, &no_ospf6_gr_helper_planned_only_cmd
);
1329 install_element(OSPF6_NODE
, &ospf6_gr_helper_supported_grace_time_cmd
);
1330 install_element(OSPF6_NODE
,
1331 &no_ospf6_gr_helper_supported_grace_time_cmd
);
1333 install_element(VIEW_NODE
, &show_ipv6_ospf6_gr_helper_cmd
);
1335 install_element(CONFIG_NODE
, &debug_ospf6_gr_cmd
);
1336 install_element(ENABLE_NODE
, &debug_ospf6_gr_cmd
);
1341 * Initialize GR helper config data structure.
1349 void ospf6_gr_helper_init(struct ospf6
*ospf6
)
1351 if (IS_DEBUG_OSPF6_GR
)
1352 zlog_debug("%s, GR Helper init.", __func__
);
1354 ospf6
->ospf6_helper_cfg
.is_helper_supported
= OSPF6_FALSE
;
1355 ospf6
->ospf6_helper_cfg
.strict_lsa_check
= OSPF6_TRUE
;
1356 ospf6
->ospf6_helper_cfg
.only_planned_restart
= OSPF6_FALSE
;
1357 ospf6
->ospf6_helper_cfg
.supported_grace_time
= OSPF6_MAX_GRACE_INTERVAL
;
1358 ospf6
->ospf6_helper_cfg
.last_exit_reason
= OSPF6_GR_HELPER_EXIT_NONE
;
1359 ospf6
->ospf6_helper_cfg
.active_restarter_cnt
= 0;
1361 ospf6
->ospf6_helper_cfg
.enable_rtr_list
= hash_create(
1362 ospf6_enable_rtr_hash_key
, ospf6_enable_rtr_hash_cmp
,
1363 "Ospf6 enable router hash");
1367 * De-initialize GR helper config data structure.
1375 void ospf6_gr_helper_deinit(struct ospf6
*ospf6
)
1378 if (IS_DEBUG_OSPF6_GR
)
1379 zlog_debug("%s, GR helper deinit.", __func__
);
1381 ospf6_enable_rtr_hash_destroy(ospf6
);
1384 static int ospf6_cfg_write_helper_enable_rtr_walkcb(struct hash_bucket
*backet
,
1387 struct advRtr
*rtr
= backet
->data
;
1388 struct vty
*vty
= (struct vty
*)arg
;
1390 vty_out(vty
, " graceful-restart helper enable %pI4\n", &rtr
->advRtrAddr
);
1391 return HASHWALK_CONTINUE
;
1394 int config_write_ospf6_gr_helper(struct vty
*vty
, struct ospf6
*ospf6
)
1396 if (ospf6
->ospf6_helper_cfg
.is_helper_supported
)
1397 vty_out(vty
, " graceful-restart helper enable\n");
1399 if (!ospf6
->ospf6_helper_cfg
.strict_lsa_check
)
1400 vty_out(vty
, " graceful-restart helper lsa-check-disable\n");
1402 if (ospf6
->ospf6_helper_cfg
.only_planned_restart
)
1403 vty_out(vty
, " graceful-restart helper planned-only\n");
1405 if (ospf6
->ospf6_helper_cfg
.supported_grace_time
1406 != OSPF6_MAX_GRACE_INTERVAL
)
1408 " graceful-restart helper supported-grace-time %d\n",
1409 ospf6
->ospf6_helper_cfg
.supported_grace_time
);
1411 if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6
)) {
1412 hash_walk(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
1413 ospf6_cfg_write_helper_enable_rtr_walkcb
, vty
);
1419 int config_write_ospf6_debug_gr_helper(struct vty
*vty
)
1421 if (IS_DEBUG_OSPF6_GR
)
1422 vty_out(vty
, "debug ospf6 graceful-restart\n");