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 #include "ospf6d/ospf6_gr_helper_clippy.c"
54 DEFINE_MTYPE_STATIC(OSPF6D
, OSPF6_GR_HELPER
, "OSPF6 Graceful restart helper");
56 unsigned char conf_debug_ospf6_gr
;
58 static int ospf6_grace_lsa_show_info(struct vty
*vty
, struct ospf6_lsa
*lsa
,
59 json_object
*json
, bool use_json
);
61 struct ospf6_lsa_handler grace_lsa_handler
= {.lh_type
= OSPF6_LSTYPE_GRACE_LSA
,
63 .lh_short_name
= "GR",
65 ospf6_grace_lsa_show_info
,
66 .lh_get_prefix_str
= NULL
,
69 const char *ospf6_exit_reason_desc
[] = {
74 "Successful graceful restart",
77 const char *ospf6_restart_reason_desc
[] = {
80 "Software reload/upgrade",
81 "Switch to redundant control processor",
84 const char *ospf6_rejected_reason_desc
[] = {
86 "Helper support disabled",
87 "Neighbour is not in FULL state",
88 "Supports only planned restart but received for unplanned",
89 "Topo change due to change in lsa rxmt list",
90 "LSA age is more than Grace interval",
93 static unsigned int ospf6_enable_rtr_hash_key(const void *data
)
95 const struct advRtr
*rtr
= data
;
97 return jhash_1word(rtr
->advRtrAddr
, 0);
100 static bool ospf6_enable_rtr_hash_cmp(const void *d1
, const void *d2
)
102 const struct advRtr
*rtr1
= d1
;
103 const struct advRtr
*rtr2
= d2
;
105 return (rtr1
->advRtrAddr
== rtr2
->advRtrAddr
);
108 static void *ospf6_enable_rtr_hash_alloc(void *p
)
112 rid
= XCALLOC(MTYPE_OSPF6_GR_HELPER
, sizeof(struct advRtr
));
113 rid
->advRtrAddr
= ((struct advRtr
*)p
)->advRtrAddr
;
118 static void ospf6_disable_rtr_hash_free(void *rtr
)
120 XFREE(MTYPE_OSPF6_GR_HELPER
, rtr
);
123 static void ospf6_enable_rtr_hash_destroy(struct ospf6
*ospf6
)
125 if (ospf6
->ospf6_helper_cfg
.enable_rtr_list
== NULL
)
128 hash_clean(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
129 ospf6_disable_rtr_hash_free
);
130 hash_free(ospf6
->ospf6_helper_cfg
.enable_rtr_list
);
131 ospf6
->ospf6_helper_cfg
.enable_rtr_list
= NULL
;
135 * Extracting tlv info from GRACE LSA.
141 * interval : grace interval.
142 * reason : Restarting reason.
144 static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa
*lsa
,
145 uint32_t *interval
, uint8_t *reason
)
147 struct ospf6_lsa_header
*lsah
= NULL
;
148 struct tlv_header
*tlvh
= NULL
;
149 struct grace_tlv_graceperiod
*gracePeriod
;
150 struct grace_tlv_restart_reason
*grReason
;
154 lsah
= (struct ospf6_lsa_header
*)lsa
->header
;
155 if (ntohs(lsah
->length
) <= OSPF6_LSA_HEADER_SIZE
) {
156 if (IS_DEBUG_OSPF6_GR
)
157 zlog_debug("%s: undersized (%u B) lsa", __func__
,
158 ntohs(lsah
->length
));
159 return OSPF6_FAILURE
;
162 length
= ntohs(lsah
->length
) - OSPF6_LSA_HEADER_SIZE
;
164 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
&& tlvh
;
165 tlvh
= TLV_HDR_NEXT(tlvh
)) {
167 /* Check TLV len against overall LSA */
168 if (sum
+ TLV_SIZE(tlvh
) > length
) {
169 if (IS_DEBUG_OSPF6_GR
)
171 "%s: Malformed packet: Invalid TLV len:%d",
172 __func__
, TLV_SIZE(tlvh
));
173 return OSPF6_FAILURE
;
176 switch (ntohs(tlvh
->type
)) {
177 case GRACE_PERIOD_TYPE
:
178 gracePeriod
= (struct grace_tlv_graceperiod
*)tlvh
;
179 *interval
= ntohl(gracePeriod
->interval
);
180 sum
+= TLV_SIZE(tlvh
);
182 /* Check if grace interval is valid */
183 if (*interval
> OSPF6_MAX_GRACE_INTERVAL
184 || *interval
< OSPF6_MIN_GRACE_INTERVAL
)
185 return OSPF6_FAILURE
;
187 case RESTART_REASON_TYPE
:
188 grReason
= (struct grace_tlv_restart_reason
*)tlvh
;
189 *reason
= grReason
->reason
;
190 sum
+= TLV_SIZE(tlvh
);
192 if (*reason
>= OSPF6_GR_INVALID_REASON_CODE
)
193 return OSPF6_FAILURE
;
196 if (IS_DEBUG_OSPF6_GR
)
197 zlog_debug("%s, Ignoring unknown TLV type:%d",
198 __func__
, ntohs(tlvh
->type
));
202 return OSPF6_SUCCESS
;
206 * Grace timer expiry handler.
207 * HELPER aborts its role at grace timer expiry.
215 static void ospf6_handle_grace_timer_expiry(struct thread
*thread
)
217 struct ospf6_neighbor
*nbr
= THREAD_ARG(thread
);
219 ospf6_gr_helper_exit(nbr
, OSPF6_GR_HELPER_GRACE_TIMEOUT
);
223 * API to check any change in the neighbor's
224 * retransmission list.
230 * TRUE - if any change in the lsa.
231 * FALSE - no change in the lsas.
233 static bool ospf6_check_chg_in_rxmt_list(struct ospf6_neighbor
*nbr
)
235 struct ospf6_lsa
*lsa
, *lsanext
;
237 for (ALL_LSDB(nbr
->retrans_list
, lsa
, lsanext
)) {
238 struct ospf6_lsa
*lsa_in_db
= NULL
;
240 /* Fetching the same copy of LSA form LSDB to validate the
244 ospf6_lsdb_lookup(lsa
->header
->type
, lsa
->header
->id
,
245 lsa
->header
->adv_router
, lsa
->lsdb
);
247 if (lsa_in_db
&& lsa_in_db
->tobe_acknowledged
) {
248 ospf6_lsa_unlock(lsa
);
250 ospf6_lsa_unlock(lsanext
);
260 * Process Grace LSA.If it is eligible move to HELPER role.
261 * Ref rfc3623 section 3.1 and rfc5187
267 * Grace LSA received from RESTARTER.
270 * ospf6 neighbour which requests the router to act as
275 * If supported as HELPER : OSPF_GR_HELPER_INPROGRESS
276 * If Not supported as HELPER : OSPF_GR_HELPER_NONE
278 int ospf6_process_grace_lsa(struct ospf6
*ospf6
, struct ospf6_lsa
*lsa
,
279 struct ospf6_neighbor
*restarter
)
281 uint8_t restart_reason
= 0;
282 uint32_t grace_interval
= 0;
283 uint32_t actual_grace_interval
= 0;
284 struct advRtr lookup
;
287 /* Extract the grace lsa packet fields */
288 ret
= ospf6_extract_grace_lsa_fields(lsa
, &grace_interval
,
290 if (ret
!= OSPF6_SUCCESS
) {
291 if (IS_DEBUG_OSPF6_GR
)
292 zlog_debug("%s, Wrong Grace LSA packet.", __func__
);
293 return OSPF6_GR_NOT_HELPER
;
296 if (IS_DEBUG_OSPF6_GR
)
298 "%s, Grace LSA received from %pI4, grace interval:%u, restart reason :%s",
299 __func__
, &restarter
->router_id
, grace_interval
,
300 ospf6_restart_reason_desc
[restart_reason
]);
302 /* Verify Helper enabled globally */
303 if (!ospf6
->ospf6_helper_cfg
.is_helper_supported
) {
304 /* Verify Helper support is enabled for the
305 * current neighbour router-id.
307 lookup
.advRtrAddr
= restarter
->router_id
;
309 if (!hash_lookup(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
311 if (IS_DEBUG_OSPF6_GR
)
313 "%s, HELPER support is disabled, So not a HELPER",
315 restarter
->gr_helper_info
.rejected_reason
=
316 OSPF6_HELPER_SUPPORT_DISABLED
;
317 return OSPF6_GR_NOT_HELPER
;
321 /* Check neighbour is in FULL state and
322 * became a adjacency.
324 if (!IS_NBR_STATE_FULL(restarter
)) {
325 if (IS_DEBUG_OSPF6_GR
)
327 "%s, This Neighbour %pI6 is not in FULL state.",
328 __func__
, &restarter
->linklocal_addr
);
329 restarter
->gr_helper_info
.rejected_reason
=
330 OSPF6_HELPER_NOT_A_VALID_NEIGHBOUR
;
331 return OSPF6_GR_NOT_HELPER
;
334 /* Based on the restart reason from grace lsa
335 * check the current router is supporting or not
337 if (ospf6
->ospf6_helper_cfg
.only_planned_restart
338 && !OSPF6_GR_IS_PLANNED_RESTART(restart_reason
)) {
339 if (IS_DEBUG_OSPF6_GR
)
341 "%s, Router supports only planned restarts but received the GRACE LSA due to an unplanned restart",
343 restarter
->gr_helper_info
.rejected_reason
=
344 OSPF6_HELPER_PLANNED_ONLY_RESTART
;
345 return OSPF6_GR_NOT_HELPER
;
348 /* Check the retransmission list of this
349 * neighbour, check any change in lsas.
351 if (ospf6
->ospf6_helper_cfg
.strict_lsa_check
352 && restarter
->retrans_list
->count
353 && ospf6_check_chg_in_rxmt_list(restarter
)) {
354 if (IS_DEBUG_OSPF6_GR
)
356 "%s, Changed LSA in Rxmt list.So not Helper.",
358 restarter
->gr_helper_info
.rejected_reason
=
359 OSPF6_HELPER_TOPO_CHANGE_RTXMT_LIST
;
360 return OSPF6_GR_NOT_HELPER
;
363 /* LSA age must be less than the grace period */
364 if (ntohs(lsa
->header
->age
) >= grace_interval
) {
365 if (IS_DEBUG_OSPF6_GR
)
367 "%s, Grace LSA age(%d) is more than the grace interval(%d)",
368 __func__
, lsa
->header
->age
, grace_interval
);
369 restarter
->gr_helper_info
.rejected_reason
=
370 OSPF6_HELPER_LSA_AGE_MORE
;
371 return OSPF6_GR_NOT_HELPER
;
374 if (ospf6
->gr_info
.restart_in_progress
) {
375 if (IS_DEBUG_OSPF6_GR
)
377 "%s: router is in the process of graceful restart",
379 restarter
->gr_helper_info
.rejected_reason
=
380 OSPF6_HELPER_RESTARTING
;
381 return OSPF6_GR_NOT_HELPER
;
384 /* check supported grace period configured
385 * if configured, use this to start the grace
386 * timer otherwise use the interval received
387 * in grace LSA packet.
389 actual_grace_interval
= grace_interval
;
390 if (grace_interval
> ospf6
->ospf6_helper_cfg
.supported_grace_time
) {
391 if (IS_DEBUG_OSPF6_GR
)
393 "%s, Received grace period %d is larger than supported grace %d",
394 __func__
, grace_interval
,
395 ospf6
->ospf6_helper_cfg
.supported_grace_time
);
396 actual_grace_interval
=
397 ospf6
->ospf6_helper_cfg
.supported_grace_time
;
400 if (OSPF6_GR_IS_ACTIVE_HELPER(restarter
)) {
401 THREAD_OFF(restarter
->gr_helper_info
.t_grace_timer
);
403 if (ospf6
->ospf6_helper_cfg
.active_restarter_cnt
> 0)
404 ospf6
->ospf6_helper_cfg
.active_restarter_cnt
--;
406 if (IS_DEBUG_OSPF6_GR
)
408 "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
411 if (IS_DEBUG_OSPF6_GR
)
413 "%s, This Router becomes a HELPER for the neighbour %pI6",
414 __func__
, &restarter
->linklocal_addr
);
417 /* Became a Helper to the RESTART neighbour.
418 * change the helper status.
420 restarter
->gr_helper_info
.gr_helper_status
= OSPF6_GR_ACTIVE_HELPER
;
421 restarter
->gr_helper_info
.recvd_grace_period
= grace_interval
;
422 restarter
->gr_helper_info
.actual_grace_period
= actual_grace_interval
;
423 restarter
->gr_helper_info
.gr_restart_reason
= restart_reason
;
424 restarter
->gr_helper_info
.rejected_reason
= OSPF6_HELPER_REJECTED_NONE
;
426 /* Increment the active restart nbr count */
427 ospf6
->ospf6_helper_cfg
.active_restarter_cnt
++;
429 if (IS_DEBUG_OSPF6_GR
)
430 zlog_debug("%s, Grace timer started.interval:%u", __func__
,
431 actual_grace_interval
);
433 /* Start the grace timer */
434 thread_add_timer(master
, ospf6_handle_grace_timer_expiry
, restarter
,
435 actual_grace_interval
,
436 &restarter
->gr_helper_info
.t_grace_timer
);
438 return OSPF6_GR_ACTIVE_HELPER
;
442 * Api to exit from HELPER role to take all actions
444 * Ref rfc3623 section 3. and rfc51872
450 * Ospf6 neighbour for which it is acting as HELPER.
453 * The reason for exiting from HELPER.
458 void ospf6_gr_helper_exit(struct ospf6_neighbor
*nbr
,
459 enum ospf6_helper_exit_reason reason
)
461 struct ospf6_interface
*oi
= nbr
->ospf6_if
;
467 ospf6
= oi
->area
->ospf6
;
469 if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr
))
472 if (IS_DEBUG_OSPF6_GR
)
473 zlog_debug("%s, Exiting from HELPER support to %pI6, due to %s",
474 __func__
, &nbr
->linklocal_addr
,
475 ospf6_exit_reason_desc
[reason
]);
477 /* Reset helper status*/
478 nbr
->gr_helper_info
.gr_helper_status
= OSPF6_GR_NOT_HELPER
;
479 nbr
->gr_helper_info
.helper_exit_reason
= reason
;
480 nbr
->gr_helper_info
.actual_grace_period
= 0;
481 nbr
->gr_helper_info
.recvd_grace_period
= 0;
482 nbr
->gr_helper_info
.gr_restart_reason
= 0;
483 ospf6
->ospf6_helper_cfg
.last_exit_reason
= reason
;
485 /* If the exit not triggered due to grace timer
486 * expiry, stop the grace timer.
488 if (reason
!= OSPF6_GR_HELPER_GRACE_TIMEOUT
)
489 THREAD_OFF(nbr
->gr_helper_info
.t_grace_timer
);
491 if (ospf6
->ospf6_helper_cfg
.active_restarter_cnt
<= 0) {
493 "OSPF6 GR-Helper: Number of active Restarters should be greater than zero.");
496 /* Decrement active restarter count */
497 ospf6
->ospf6_helper_cfg
.active_restarter_cnt
--;
499 /* check exit triggered due to successful completion
500 * of graceful restart.
502 if (reason
!= OSPF6_GR_HELPER_COMPLETED
) {
503 if (IS_DEBUG_OSPF6_GR
)
504 zlog_debug("%s, Unsuccessful GR exit. RESTARTER : %pI6",
505 __func__
, &nbr
->linklocal_addr
);
508 /*Recalculate the DR for the network segment */
511 /* Originate a router LSA */
512 OSPF6_ROUTER_LSA_SCHEDULE(nbr
->ospf6_if
->area
);
514 /* Originate network lsa if it is an DR in the LAN */
515 if (nbr
->ospf6_if
->state
== OSPF6_INTERFACE_DR
)
516 OSPF6_NETWORK_LSA_SCHEDULE(nbr
->ospf6_if
);
520 * Process max age Grace LSA.
521 * It is a indication for successful completion of GR.
522 * If router acting as HELPER, It exits from helper role.
528 * Grace LSA received from RESTARTER.
531 * ospf6 neighbour which request the router to act as
537 void ospf6_process_maxage_grace_lsa(struct ospf6
*ospf6
, struct ospf6_lsa
*lsa
,
538 struct ospf6_neighbor
*restarter
)
540 uint8_t restart_reason
= 0;
541 uint32_t grace_interval
= 0;
544 /* Extract the grace lsa packet fields */
545 ret
= ospf6_extract_grace_lsa_fields(lsa
, &grace_interval
,
547 if (ret
!= OSPF6_SUCCESS
) {
548 if (IS_DEBUG_OSPF6_GR
)
549 zlog_debug("%s, Wrong Grace LSA packet.", __func__
);
553 if (IS_DEBUG_OSPF6_GR
)
554 zlog_debug("%s, GraceLSA received for neighbour %pI4.",
555 __func__
, &restarter
->router_id
);
557 ospf6_gr_helper_exit(restarter
, OSPF6_GR_HELPER_COMPLETED
);
561 * Actions to be taken when topo change detected
562 * HELPER will be exited upon a topo change.
567 * topo change occurred due to this lsa(type (1-5 and 7)
572 void ospf6_helper_handle_topo_chg(struct ospf6
*ospf6
, struct ospf6_lsa
*lsa
)
574 struct listnode
*i
, *j
, *k
;
575 struct ospf6_neighbor
*nbr
= NULL
;
576 struct ospf6_area
*oa
= NULL
;
577 struct ospf6_interface
*oi
= NULL
;
579 if (!ospf6
->ospf6_helper_cfg
.active_restarter_cnt
)
582 /* Topo change not required to be handled if strict
583 * LSA check is disabled for this router.
585 if (!ospf6
->ospf6_helper_cfg
.strict_lsa_check
)
588 if (IS_DEBUG_OSPF6_GR
)
589 zlog_debug("%s, Topo change detected due to lsa details : %s",
590 __func__
, lsa
->name
);
592 lsa
->tobe_acknowledged
= OSPF6_TRUE
;
594 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, i
, oa
))
595 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, j
, oi
)) {
597 /* Ref rfc3623 section 3.2.3.b and rfc5187
598 * If change due to external LSA and if the area is
599 * stub, then it is not a topo change. Since Type-5
600 * lsas will not be flooded in stub area.
602 if (IS_AREA_STUB(oi
->area
)
603 && ((lsa
->header
->type
== OSPF6_LSTYPE_AS_EXTERNAL
)
604 || (lsa
->header
->type
== OSPF6_LSTYPE_TYPE_7
)
605 || (lsa
->header
->type
606 == OSPF6_LSTYPE_INTER_ROUTER
))) {
610 for (ALL_LIST_ELEMENTS_RO(oi
->neighbor_list
, k
, nbr
)) {
612 ospf6_gr_helper_exit(nbr
,
613 OSPF6_GR_HELPER_TOPO_CHG
);
618 /* Configuration handlers */
620 * Disable/Enable HELPER support on router level.
631 static void ospf6_gr_helper_support_set(struct ospf6
*ospf6
, bool support
)
633 struct ospf6_interface
*oi
;
634 struct advRtr lookup
;
635 struct listnode
*i
, *j
, *k
;
636 struct ospf6_neighbor
*nbr
= NULL
;
637 struct ospf6_area
*oa
= NULL
;
639 if (ospf6
->ospf6_helper_cfg
.is_helper_supported
== support
)
642 ospf6
->ospf6_helper_cfg
.is_helper_supported
= support
;
644 /* If helper support disabled, cease HELPER role for all
645 * supporting neighbors.
647 if (support
== OSPF6_FALSE
) {
648 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, i
, oa
))
649 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, j
, oi
)) {
651 for (ALL_LIST_ELEMENTS_RO(oi
->neighbor_list
, k
,
654 lookup
.advRtrAddr
= nbr
->router_id
;
655 /* check if helper support enabled for
656 * the corresponding routerid.
658 * dont exit from helper role.
661 ospf6
->ospf6_helper_cfg
666 ospf6_gr_helper_exit(
667 nbr
, OSPF6_GR_HELPER_TOPO_CHG
);
674 * Api to enable/disable strict lsa check on the HELPER.
680 * True - disable the lsa check.
681 * False - enable the strict lsa check.
686 static void ospf6_gr_helper_lsacheck_set(struct ospf6
*ospf6
, bool enabled
)
688 if (ospf6
->ospf6_helper_cfg
.strict_lsa_check
== enabled
)
691 ospf6
->ospf6_helper_cfg
.strict_lsa_check
= enabled
;
695 * Api to set the supported restart reason.
701 * True: support only planned restart.
702 * False: support for planned/unplanned restarts.
709 ospf6_gr_helper_set_supported_onlyPlanned_restart(struct ospf6
*ospf6
,
712 ospf6
->ospf6_helper_cfg
.only_planned_restart
= only_planned
;
716 * Api to set the supported grace interval in this router.
722 * The supported grace interval..
727 static void ospf6_gr_helper_supported_gracetime_set(struct ospf6
*ospf6
,
730 ospf6
->ospf6_helper_cfg
.supported_grace_time
= interval
;
733 /* API to walk and print all the Helper supported router ids */
734 static int ospf6_print_vty_helper_dis_rtr_walkcb(struct hash_bucket
*bucket
,
737 struct advRtr
*rtr
= bucket
->data
;
738 struct vty
*vty
= (struct vty
*)arg
;
739 static unsigned int count
;
741 vty_out(vty
, "%-6pI4,", &rtr
->advRtrAddr
);
747 return HASHWALK_CONTINUE
;
750 /* API to walk and print all the Helper supported router ids.*/
751 static int ospf6_print_json_helper_dis_rtr_walkcb(struct hash_bucket
*bucket
,
754 struct advRtr
*rtr
= bucket
->data
;
755 struct json_object
*json_rid_array
= (struct json_object
*)arg
;
756 struct json_object
*json_rid
;
759 inet_ntop(AF_INET
, &rtr
->advRtrAddr
, router_id
, sizeof(router_id
));
761 json_rid
= json_object_new_object();
763 json_object_string_add(json_rid
, "routerId", router_id
);
764 json_object_array_add(json_rid_array
, json_rid
);
766 return HASHWALK_CONTINUE
;
770 * Enable/Disable HELPER support on a specified advertisement
777 * HELPER support for given Advertisement Router.
780 * True - Enable Helper Support.
781 * False - Disable Helper Support.
786 static void ospf6_gr_helper_support_set_per_routerid(struct ospf6
*ospf6
,
787 struct in_addr router_id
,
792 struct listnode
*i
, *j
, *k
;
793 struct ospf6_interface
*oi
;
794 struct ospf6_neighbor
*nbr
;
795 struct ospf6_area
*oa
;
797 temp
.advRtrAddr
= router_id
.s_addr
;
799 if (support
== OSPF6_FALSE
) {
800 /*Delete the routerid from the enable router hash table */
801 rtr
= hash_lookup(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
805 hash_release(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
807 ospf6_disable_rtr_hash_free(rtr
);
810 /* If helper support is enabled globally
811 * no action is required.
813 if (ospf6
->ospf6_helper_cfg
.is_helper_supported
)
816 /* Cease the HELPER role fore neighbours from the
817 * specified advertisement router.
819 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, i
, oa
))
820 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, j
, oi
)) {
822 for (ALL_LIST_ELEMENTS_RO(oi
->neighbor_list
, k
,
825 if (nbr
->router_id
!= router_id
.s_addr
)
828 if (OSPF6_GR_IS_ACTIVE_HELPER(nbr
))
829 ospf6_gr_helper_exit(
831 OSPF6_GR_HELPER_TOPO_CHG
);
836 /* Add the routerid to the enable router hash table */
837 (void)hash_get(ospf6
->ospf6_helper_cfg
.enable_rtr_list
, &temp
,
838 ospf6_enable_rtr_hash_alloc
);
842 static void show_ospfv6_gr_helper_per_nbr(struct vty
*vty
, json_object
*json
,
843 bool uj
, struct ospf6_neighbor
*nbr
)
846 vty_out(vty
, " Routerid : %pI4\n", &nbr
->router_id
);
847 vty_out(vty
, " Received Grace period : %d(in seconds).\n",
848 nbr
->gr_helper_info
.recvd_grace_period
);
849 vty_out(vty
, " Actual Grace period : %d(in seconds)\n",
850 nbr
->gr_helper_info
.actual_grace_period
);
851 vty_out(vty
, " Remaining GraceTime:%ld(in seconds).\n",
852 thread_timer_remain_second(
853 nbr
->gr_helper_info
.t_grace_timer
));
854 vty_out(vty
, " Graceful Restart reason: %s.\n\n",
855 ospf6_restart_reason_desc
[nbr
->gr_helper_info
856 .gr_restart_reason
]);
859 json_object
*json_neigh
= NULL
;
861 inet_ntop(AF_INET
, &nbr
->router_id
, nbrid
, sizeof(nbrid
));
862 json_neigh
= json_object_new_object();
863 json_object_string_add(json_neigh
, "routerid", nbrid
);
864 json_object_int_add(json_neigh
, "recvdGraceInterval",
865 nbr
->gr_helper_info
.recvd_grace_period
);
866 json_object_int_add(json_neigh
, "actualGraceInterval",
867 nbr
->gr_helper_info
.actual_grace_period
);
868 json_object_int_add(json_neigh
, "remainGracetime",
869 thread_timer_remain_second(
870 nbr
->gr_helper_info
.t_grace_timer
));
871 json_object_string_add(json_neigh
, "restartReason",
872 ospf6_restart_reason_desc
[
873 nbr
->gr_helper_info
.gr_restart_reason
]);
874 json_object_object_add(json
, nbr
->name
, json_neigh
);
878 static void show_ospf6_gr_helper_details(struct vty
*vty
, struct ospf6
*ospf6
,
879 json_object
*json
, bool uj
, bool detail
)
881 struct ospf6_interface
*oi
;
883 /* Show Router ID. */
887 inet_ntop(AF_INET
, &ospf6
->router_id
, router_id
,
889 json_object_string_add(json
, "routerId", router_id
);
892 " OSPFv3 Routing Process (0) with Router-ID %pI4\n",
897 if (ospf6
->ospf6_helper_cfg
.is_helper_supported
)
899 " Graceful restart helper support enabled.\n");
902 " Graceful restart helper support disabled.\n");
904 if (ospf6
->ospf6_helper_cfg
.strict_lsa_check
)
905 vty_out(vty
, " Strict LSA check is enabled.\n");
907 vty_out(vty
, " Strict LSA check is disabled.\n");
909 if (ospf6
->ospf6_helper_cfg
.only_planned_restart
)
911 " Helper supported for planned restarts only.\n");
914 " Helper supported for Planned and Unplanned Restarts.\n");
917 " Supported Graceful restart interval: %d(in seconds).\n",
918 ospf6
->ospf6_helper_cfg
.supported_grace_time
);
920 if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf
)) {
921 vty_out(vty
, " Enable Router list:\n");
923 hash_walk(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
924 ospf6_print_vty_helper_dis_rtr_walkcb
, vty
);
925 vty_out(vty
, "\n\n");
928 if (ospf6
->ospf6_helper_cfg
.last_exit_reason
929 != OSPF6_GR_HELPER_EXIT_NONE
) {
930 vty_out(vty
, " Last Helper exit Reason :%s\n",
931 ospf6_exit_reason_desc
932 [ospf6
->ospf6_helper_cfg
935 if (ospf6
->ospf6_helper_cfg
.active_restarter_cnt
)
937 " Number of Active neighbours in graceful restart: %d\n",
938 ospf6
->ospf6_helper_cfg
939 .active_restarter_cnt
);
946 json_object_string_add(
947 json
, "helperSupport",
948 (ospf6
->ospf6_helper_cfg
.is_helper_supported
)
951 json_object_string_add(
952 json
, "strictLsaCheck",
953 (ospf6
->ospf6_helper_cfg
.strict_lsa_check
)
956 json_object_string_add(
957 json
, "restartSupoort",
958 (ospf6
->ospf6_helper_cfg
.only_planned_restart
)
959 ? "Planned Restart only"
960 : "Planned and Unplanned Restarts");
963 json
, "supportedGracePeriod",
964 ospf6
->ospf6_helper_cfg
.supported_grace_time
);
966 #if CONFDATE > 20230131
967 CPP_NOTICE("Remove JSON object commands with keys starting with capital")
969 if (ospf6
->ospf6_helper_cfg
.last_exit_reason
!=
970 OSPF6_GR_HELPER_EXIT_NONE
) {
971 json_object_string_add(
972 json
, "LastExitReason",
973 ospf6_exit_reason_desc
974 [ospf6
->ospf6_helper_cfg
976 json_object_string_add(
977 json
, "lastExitReason",
978 ospf6_exit_reason_desc
979 [ospf6
->ospf6_helper_cfg
983 if (ospf6
->ospf6_helper_cfg
.active_restarter_cnt
)
985 json
, "activeRestarterCnt",
986 ospf6
->ospf6_helper_cfg
.active_restarter_cnt
);
988 if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6
)) {
989 struct json_object
*json_rid_array
=
990 json_object_new_array();
992 json_object_object_add(json
, "enabledRouterIds",
995 hash_walk(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
996 ospf6_print_json_helper_dis_rtr_walkcb
,
1003 struct listnode
*i
, *j
, *k
;
1004 struct ospf6_area
*oa
;
1005 json_object
*json_neighbors
= NULL
;
1007 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, i
, oa
))
1008 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, j
, oi
)) {
1009 struct ospf6_neighbor
*nbr
;
1012 json_object_object_get_ex(
1015 json_object_object_get_ex(
1018 if (!json_neighbors
) {
1020 json_object_new_object();
1021 json_object_object_add(
1024 json_object_object_add(
1030 for (ALL_LIST_ELEMENTS_RO(oi
->neighbor_list
, k
,
1033 if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr
))
1038 " Neighbour %d :\n",
1041 show_ospfv6_gr_helper_per_nbr(
1042 vty
, json_neighbors
, uj
, nbr
);
1049 /* Graceful Restart HELPER config Commands */
1050 DEFPY(ospf6_gr_helper_enable
,
1051 ospf6_gr_helper_enable_cmd
,
1052 "graceful-restart helper enable [A.B.C.D$rtr_id]",
1053 "ospf6 graceful restart\n"
1055 "Enable Helper support\n"
1056 "Advertisement Router-ID\n")
1058 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1060 if (rtr_id_str
!= NULL
) {
1062 ospf6_gr_helper_support_set_per_routerid(ospf6
, rtr_id
,
1068 ospf6_gr_helper_support_set(ospf6
, OSPF6_TRUE
);
1073 DEFPY(ospf6_gr_helper_disable
,
1074 ospf6_gr_helper_disable_cmd
,
1075 "no graceful-restart helper enable [A.B.C.D$rtr_id]",
1077 "ospf6 graceful restart\n"
1079 "Enable Helper support\n"
1080 "Advertisement Router-ID\n")
1082 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1084 if (rtr_id_str
!= NULL
) {
1086 ospf6_gr_helper_support_set_per_routerid(ospf6
, rtr_id
,
1092 ospf6_gr_helper_support_set(ospf6
, OSPF6_FALSE
);
1097 DEFPY(ospf6_gr_helper_disable_lsacheck
,
1098 ospf6_gr_helper_disable_lsacheck_cmd
,
1099 "graceful-restart helper lsa-check-disable",
1100 "ospf6 graceful restart\n"
1102 "disable strict LSA check\n")
1104 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1106 ospf6_gr_helper_lsacheck_set(ospf6
, OSPF6_FALSE
);
1110 DEFPY(no_ospf6_gr_helper_disable_lsacheck
,
1111 no_ospf6_gr_helper_disable_lsacheck_cmd
,
1112 "no graceful-restart helper lsa-check-disable",
1114 "ospf6 graceful restart\n"
1116 "diasble strict LSA check\n")
1118 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1120 ospf6_gr_helper_lsacheck_set(ospf6
, OSPF6_TRUE
);
1124 DEFPY(ospf6_gr_helper_planned_only
,
1125 ospf6_gr_helper_planned_only_cmd
,
1126 "graceful-restart helper planned-only",
1127 "ospf6 graceful restart\n"
1129 "supported only planned restart\n")
1131 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1133 ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6
, OSPF6_TRUE
);
1138 DEFPY(no_ospf6_gr_helper_planned_only
, no_ospf6_gr_helper_planned_only_cmd
,
1139 "no graceful-restart helper planned-only",
1141 "ospf6 graceful restart\n"
1143 "supported only for planned restart\n")
1145 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1147 ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6
, OSPF6_FALSE
);
1152 DEFPY(ospf6_gr_helper_supported_grace_time
,
1153 ospf6_gr_helper_supported_grace_time_cmd
,
1154 "graceful-restart helper supported-grace-time (10-1800)$interval",
1155 "ospf6 graceful restart\n"
1157 "supported grace timer\n"
1158 "grace interval(in seconds)\n")
1160 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1162 ospf6_gr_helper_supported_gracetime_set(ospf6
, interval
);
1166 DEFPY(no_ospf6_gr_helper_supported_grace_time
,
1167 no_ospf6_gr_helper_supported_grace_time_cmd
,
1168 "no graceful-restart helper supported-grace-time (10-1800)$interval",
1170 "ospf6 graceful restart\n"
1172 "supported grace timer\n"
1173 "grace interval(in seconds)\n")
1175 VTY_DECLVAR_CONTEXT(ospf6
, ospf6
);
1177 ospf6_gr_helper_supported_gracetime_set(ospf6
,
1178 OSPF6_MAX_GRACE_INTERVAL
);
1183 DEFPY(show_ipv6_ospf6_gr_helper
,
1184 show_ipv6_ospf6_gr_helper_cmd
,
1185 "show ipv6 ospf6 graceful-restart helper [detail] [json]",
1187 "Ipv6 Information\n"
1188 "OSPF6 information\n"
1189 "ospf6 graceful restart\n"
1190 "helper details in the router\n"
1191 "detailed information\n" JSON_STR
)
1194 bool uj
= use_json(argc
, argv
);
1195 struct ospf6
*ospf6
= NULL
;
1196 json_object
*json
= NULL
;
1197 bool detail
= false;
1199 ospf6
= ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME
);
1200 if (ospf6
== NULL
) {
1201 vty_out(vty
, "OSPFv3 is not configured\n");
1205 if (argv_find(argv
, argc
, "detail", &idx
))
1209 json
= json_object_new_object();
1211 show_ospf6_gr_helper_details(vty
, ospf6
, json
, uj
, detail
);
1214 vty_json(vty
, json
);
1219 /* Debug commands */
1220 DEFPY(debug_ospf6_gr
, debug_ospf6_gr_cmd
,
1221 "[no$no] debug ospf6 graceful-restart",
1222 NO_STR DEBUG_STR OSPF6_STR
"Graceful restart\n")
1225 OSPF6_DEBUG_GR_ON();
1227 OSPF6_DEBUG_GR_OFF();
1233 * Api to display the grace LSA information.
1245 static int ospf6_grace_lsa_show_info(struct vty
*vty
, struct ospf6_lsa
*lsa
,
1246 json_object
*json
, bool use_json
)
1248 struct ospf6_lsa_header
*lsah
= NULL
;
1249 struct tlv_header
*tlvh
= NULL
;
1250 struct grace_tlv_graceperiod
*gracePeriod
;
1251 struct grace_tlv_restart_reason
*grReason
;
1252 uint16_t length
= 0;
1255 lsah
= (struct ospf6_lsa_header
*)lsa
->header
;
1256 if (ntohs(lsah
->length
) <= OSPF6_LSA_HEADER_SIZE
) {
1257 if (IS_DEBUG_OSPF6_GR
)
1258 zlog_debug("%s: undersized (%u B) lsa", __func__
,
1259 ntohs(lsah
->length
));
1260 return OSPF6_FAILURE
;
1263 length
= ntohs(lsah
->length
) - OSPF6_LSA_HEADER_SIZE
;
1267 vty_out(vty
, "TLV info:\n");
1269 zlog_debug(" TLV info:");
1272 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
&& tlvh
;
1273 tlvh
= TLV_HDR_NEXT(tlvh
)) {
1276 if (sum
+ TLV_SIZE(tlvh
) > length
) {
1278 vty_out(vty
, "%% Invalid TLV length: %d\n",
1280 else if (IS_DEBUG_OSPF6_GR
)
1281 zlog_debug("%% Invalid TLV length: %d",
1283 return OSPF6_FAILURE
;
1286 switch (ntohs(tlvh
->type
)) {
1287 case GRACE_PERIOD_TYPE
:
1288 gracePeriod
= (struct grace_tlv_graceperiod
*)tlvh
;
1289 sum
+= TLV_SIZE(tlvh
);
1293 json_object_int_add(
1294 json
, "gracePeriod",
1295 ntohl(gracePeriod
->interval
));
1297 vty_out(vty
, " Grace period:%d\n",
1298 ntohl(gracePeriod
->interval
));
1300 zlog_debug(" Grace period:%d",
1301 ntohl(gracePeriod
->interval
));
1304 case RESTART_REASON_TYPE
:
1305 grReason
= (struct grace_tlv_restart_reason
*)tlvh
;
1306 sum
+= TLV_SIZE(tlvh
);
1309 json_object_string_add(
1310 json
, "restartReason",
1311 ospf6_restart_reason_desc
1312 [grReason
->reason
]);
1314 vty_out(vty
, " Restart reason:%s\n",
1315 ospf6_restart_reason_desc
1316 [grReason
->reason
]);
1318 zlog_debug(" Restart reason:%s",
1319 ospf6_restart_reason_desc
1320 [grReason
->reason
]);
1331 void ospf6_gr_helper_config_init(void)
1334 ospf6_install_lsa_handler(&grace_lsa_handler
);
1336 install_element(OSPF6_NODE
, &ospf6_gr_helper_enable_cmd
);
1337 install_element(OSPF6_NODE
, &ospf6_gr_helper_disable_cmd
);
1338 install_element(OSPF6_NODE
, &ospf6_gr_helper_disable_lsacheck_cmd
);
1339 install_element(OSPF6_NODE
, &no_ospf6_gr_helper_disable_lsacheck_cmd
);
1340 install_element(OSPF6_NODE
, &ospf6_gr_helper_planned_only_cmd
);
1341 install_element(OSPF6_NODE
, &no_ospf6_gr_helper_planned_only_cmd
);
1342 install_element(OSPF6_NODE
, &ospf6_gr_helper_supported_grace_time_cmd
);
1343 install_element(OSPF6_NODE
,
1344 &no_ospf6_gr_helper_supported_grace_time_cmd
);
1346 install_element(VIEW_NODE
, &show_ipv6_ospf6_gr_helper_cmd
);
1348 install_element(CONFIG_NODE
, &debug_ospf6_gr_cmd
);
1349 install_element(ENABLE_NODE
, &debug_ospf6_gr_cmd
);
1354 * Initialize GR helper config data structure.
1362 void ospf6_gr_helper_init(struct ospf6
*ospf6
)
1364 if (IS_DEBUG_OSPF6_GR
)
1365 zlog_debug("%s, GR Helper init.", __func__
);
1367 ospf6
->ospf6_helper_cfg
.is_helper_supported
= OSPF6_FALSE
;
1368 ospf6
->ospf6_helper_cfg
.strict_lsa_check
= OSPF6_TRUE
;
1369 ospf6
->ospf6_helper_cfg
.only_planned_restart
= OSPF6_FALSE
;
1370 ospf6
->ospf6_helper_cfg
.supported_grace_time
= OSPF6_MAX_GRACE_INTERVAL
;
1371 ospf6
->ospf6_helper_cfg
.last_exit_reason
= OSPF6_GR_HELPER_EXIT_NONE
;
1372 ospf6
->ospf6_helper_cfg
.active_restarter_cnt
= 0;
1374 ospf6
->ospf6_helper_cfg
.enable_rtr_list
= hash_create(
1375 ospf6_enable_rtr_hash_key
, ospf6_enable_rtr_hash_cmp
,
1376 "Ospf6 enable router hash");
1380 * De-initialize GR helper config data structure.
1388 void ospf6_gr_helper_deinit(struct ospf6
*ospf6
)
1391 if (IS_DEBUG_OSPF6_GR
)
1392 zlog_debug("%s, GR helper deinit.", __func__
);
1394 ospf6_enable_rtr_hash_destroy(ospf6
);
1397 static int ospf6_cfg_write_helper_enable_rtr_walkcb(struct hash_bucket
*backet
,
1400 struct advRtr
*rtr
= backet
->data
;
1401 struct vty
*vty
= (struct vty
*)arg
;
1403 vty_out(vty
, " graceful-restart helper enable %pI4\n", &rtr
->advRtrAddr
);
1404 return HASHWALK_CONTINUE
;
1407 int config_write_ospf6_gr_helper(struct vty
*vty
, struct ospf6
*ospf6
)
1409 if (ospf6
->ospf6_helper_cfg
.is_helper_supported
)
1410 vty_out(vty
, " graceful-restart helper enable\n");
1412 if (!ospf6
->ospf6_helper_cfg
.strict_lsa_check
)
1413 vty_out(vty
, " graceful-restart helper lsa-check-disable\n");
1415 if (ospf6
->ospf6_helper_cfg
.only_planned_restart
)
1416 vty_out(vty
, " graceful-restart helper planned-only\n");
1418 if (ospf6
->ospf6_helper_cfg
.supported_grace_time
1419 != OSPF6_MAX_GRACE_INTERVAL
)
1421 " graceful-restart helper supported-grace-time %d\n",
1422 ospf6
->ospf6_helper_cfg
.supported_grace_time
);
1424 if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6
)) {
1425 hash_walk(ospf6
->ospf6_helper_cfg
.enable_rtr_list
,
1426 ospf6_cfg_write_helper_enable_rtr_walkcb
, vty
);
1432 int config_write_ospf6_debug_gr_helper(struct vty
*vty
)
1434 if (IS_DEBUG_OSPF6_GR
)
1435 vty_out(vty
, "debug ospf6 graceful-restart\n");