1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * OSPF Graceful Restart helper functions.
5 * Copyright (C) 2020-21 Vmware, Inc.
22 #include "ospfd/ospfd.h"
23 #include "ospfd/ospf_interface.h"
24 #include "ospfd/ospf_asbr.h"
25 #include "ospfd/ospf_lsa.h"
26 #include "ospfd/ospf_lsdb.h"
27 #include "ospfd/ospf_neighbor.h"
28 #include "ospfd/ospf_spf.h"
29 #include "ospfd/ospf_flood.h"
30 #include "ospfd/ospf_route.h"
31 #include "ospfd/ospf_zebra.h"
32 #include "ospfd/ospf_dump.h"
33 #include "ospfd/ospf_errors.h"
34 #include "ospfd/ospf_nsm.h"
35 #include "ospfd/ospf_ism.h"
36 #include "ospfd/ospf_gr.h"
38 static const char * const ospf_exit_reason_desc
[] = {
43 "Successful graceful restart",
46 static const char * const ospf_restart_reason_desc
[] = {
49 "Software reload/upgrade",
50 "Switch to redundant control processor",
53 static const char * const ospf_rejected_reason_desc
[] = {
55 "Helper support disabled",
56 "Neighbour is not in FULL state",
57 "Supports only planned restart but received unplanned",
58 "Topo change due to change in lsa rxmt list",
59 "LSA age is more than Grace interval",
60 "Router is in the process of graceful restart",
63 static void show_ospf_grace_lsa_info(struct vty
*vty
, struct json_object
*json
,
64 struct ospf_lsa
*lsa
);
65 static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor
*nbr
);
67 static unsigned int ospf_enable_rtr_hash_key(const void *data
)
69 const struct advRtr
*rtr
= data
;
71 return jhash_1word(rtr
->advRtrAddr
.s_addr
, 0);
74 static bool ospf_enable_rtr_hash_cmp(const void *d1
, const void *d2
)
76 const struct advRtr
*rtr1
= (struct advRtr
*)d1
;
77 const struct advRtr
*rtr2
= (struct advRtr
*)d2
;
79 return (rtr1
->advRtrAddr
.s_addr
== rtr2
->advRtrAddr
.s_addr
);
82 static void *ospf_enable_rtr_hash_alloc(void *p
)
86 rid
= XCALLOC(MTYPE_OSPF_GR_HELPER
, sizeof(struct advRtr
));
87 rid
->advRtrAddr
.s_addr
= ((struct in_addr
*)p
)->s_addr
;
92 static void ospf_disable_rtr_hash_free(void *rtr
)
94 XFREE(MTYPE_OSPF_GR_HELPER
, rtr
);
97 static void ospf_enable_rtr_hash_destroy(struct ospf
*ospf
)
99 if (ospf
->enable_rtr_list
== NULL
)
102 hash_clean_and_free(&ospf
->enable_rtr_list
, ospf_disable_rtr_hash_free
);
106 * GR exit reason strings
108 const char *ospf_exit_reason2str(unsigned int reason
)
110 if (reason
< array_size(ospf_exit_reason_desc
))
111 return(ospf_exit_reason_desc
[reason
]);
113 return "Invalid reason";
117 * GR restart reason strings
119 const char *ospf_restart_reason2str(unsigned int reason
)
121 if (reason
< array_size(ospf_restart_reason_desc
))
122 return(ospf_restart_reason_desc
[reason
]);
124 return "Invalid reason";
128 * GR rejected reason strings
130 const char *ospf_rejected_reason2str(unsigned int reason
)
132 if (reason
< array_size(ospf_rejected_reason_desc
))
133 return(ospf_rejected_reason_desc
[reason
]);
135 return "Invalid reason";
139 * Initialize GR helper config data structures.
147 void ospf_gr_helper_instance_init(struct ospf
*ospf
)
149 if (IS_DEBUG_OSPF_GR
)
150 zlog_debug("%s, GR Helper init.", __func__
);
152 ospf
->is_helper_supported
= OSPF_GR_FALSE
;
153 ospf
->strict_lsa_check
= OSPF_GR_TRUE
;
154 ospf
->only_planned_restart
= OSPF_GR_FALSE
;
155 ospf
->supported_grace_time
= OSPF_MAX_GRACE_INTERVAL
;
156 ospf
->last_exit_reason
= OSPF_GR_HELPER_EXIT_NONE
;
157 ospf
->active_restarter_cnt
= 0;
159 ospf
->enable_rtr_list
=
160 hash_create(ospf_enable_rtr_hash_key
, ospf_enable_rtr_hash_cmp
,
161 "OSPF enable router hash");
165 * De-Initialize GR helper config data structures.
173 void ospf_gr_helper_instance_stop(struct ospf
*ospf
)
175 if (IS_DEBUG_OSPF_GR
)
176 zlog_debug("%s, GR helper deinit.", __func__
);
178 ospf_enable_rtr_hash_destroy(ospf
);
182 * Initialize GR helper config data structures.
187 void ospf_gr_helper_init(void)
191 if (IS_DEBUG_OSPF_GR
)
192 zlog_debug("%s, GR Helper init.", __func__
);
194 rc
= ospf_register_opaque_functab(
195 OSPF_OPAQUE_LINK_LSA
, OPAQUE_TYPE_GRACE_LSA
, NULL
, NULL
, NULL
,
196 NULL
, NULL
, NULL
, NULL
, show_ospf_grace_lsa_info
, NULL
, NULL
,
199 flog_warn(EC_OSPF_OPAQUE_REGISTRATION
,
200 "%s: Failed to register Grace LSA functions",
206 * De-Initialize GR helper config data structures.
211 void ospf_gr_helper_stop(void)
213 if (IS_DEBUG_OSPF_GR
)
214 zlog_debug("%s, GR helper deinit.", __func__
);
216 ospf_delete_opaque_functab(OSPF_OPAQUE_LINK_LSA
, OPAQUE_TYPE_GRACE_LSA
);
220 * Extracting tlv info from GRACE LSA.
226 * interval : grace interval.
227 * addr : RESTARTER address.
228 * reason : Restarting reason.
230 static int ospf_extract_grace_lsa_fields(struct ospf_lsa
*lsa
,
232 struct in_addr
*addr
, uint8_t *reason
)
234 struct lsa_header
*lsah
= NULL
;
235 struct tlv_header
*tlvh
= NULL
;
236 struct grace_tlv_graceperiod
*grace_period
;
237 struct grace_tlv_restart_reason
*gr_reason
;
238 struct grace_tlv_restart_addr
*restart_addr
;
242 lsah
= (struct lsa_header
*)lsa
->data
;
245 if (lsa
->size
<= OSPF_LSA_HEADER_SIZE
) {
246 if (IS_DEBUG_OSPF_GR
)
247 zlog_debug("%s: Malformed packet: Invalid LSA len:%d",
249 return OSPF_GR_FAILURE
;
252 length
= lsa
->size
- OSPF_LSA_HEADER_SIZE
;
254 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
&& tlvh
;
255 tlvh
= TLV_HDR_NEXT(tlvh
)) {
257 /* Check TLV len against overall LSA */
258 if (sum
+ TLV_SIZE(tlvh
) > length
) {
259 if (IS_DEBUG_OSPF_GR
)
260 zlog_debug("%s: Malformed packet: Invalid TLV len:%u",
261 __func__
, TLV_SIZE(tlvh
));
262 return OSPF_GR_FAILURE
;
265 switch (ntohs(tlvh
->type
)) {
266 case GRACE_PERIOD_TYPE
:
268 sizeof(struct grace_tlv_graceperiod
)) {
269 zlog_debug("%s: Malformed packet: Invalid grace TLV len:%u",
270 __func__
, TLV_SIZE(tlvh
));
271 return OSPF_GR_FAILURE
;
274 grace_period
= (struct grace_tlv_graceperiod
*)tlvh
;
275 *interval
= ntohl(grace_period
->interval
);
276 sum
+= TLV_SIZE(tlvh
);
278 /* Check if grace interval is valid */
279 if (*interval
> OSPF_MAX_GRACE_INTERVAL
280 || *interval
< OSPF_MIN_GRACE_INTERVAL
)
281 return OSPF_GR_FAILURE
;
283 case RESTART_REASON_TYPE
:
285 sizeof(struct grace_tlv_restart_reason
)) {
286 zlog_debug("%s: Malformed packet: Invalid reason TLV len:%u",
287 __func__
, TLV_SIZE(tlvh
));
288 return OSPF_GR_FAILURE
;
291 gr_reason
= (struct grace_tlv_restart_reason
*)tlvh
;
292 *reason
= gr_reason
->reason
;
293 sum
+= TLV_SIZE(tlvh
);
295 if (*reason
>= OSPF_GR_INVALID_REASON_CODE
)
296 return OSPF_GR_FAILURE
;
298 case RESTARTER_IP_ADDR_TYPE
:
300 sizeof(struct grace_tlv_restart_addr
)) {
301 zlog_debug("%s: Malformed packet: Invalid addr TLV len:%u",
302 __func__
, TLV_SIZE(tlvh
));
303 return OSPF_GR_FAILURE
;
306 restart_addr
= (struct grace_tlv_restart_addr
*)tlvh
;
307 addr
->s_addr
= restart_addr
->addr
.s_addr
;
308 sum
+= TLV_SIZE(tlvh
);
311 if (IS_DEBUG_OSPF_GR
)
313 "%s, Malformed packet.Invalid TLV type:%d",
314 __func__
, ntohs(tlvh
->type
));
315 return OSPF_GR_FAILURE
;
319 return OSPF_GR_SUCCESS
;
323 * Grace timer expiry handler.
324 * HELPER aborts its role at grace timer expiry.
332 static void ospf_handle_grace_timer_expiry(struct event
*thread
)
334 struct ospf_neighbor
*nbr
= THREAD_ARG(thread
);
336 nbr
->gr_helper_info
.t_grace_timer
= NULL
;
338 ospf_gr_helper_exit(nbr
, OSPF_GR_HELPER_GRACE_TIMEOUT
);
342 * Process Grace LSA.If it is eligible move to HELPER role.
343 * Ref rfc3623 section 3.1
349 * Grace LSA received from RESTARTER.
352 * OSPF neighbour which requests the router to act as
357 * If supported as HELPER : OSPF_GR_HELPER_INPROGRESS
358 * If Not supported as HELPER : OSPF_GR_HELPER_NONE
360 int ospf_process_grace_lsa(struct ospf
*ospf
, struct ospf_lsa
*lsa
,
361 struct ospf_neighbor
*nbr
)
363 struct in_addr restart_addr
= {0};
364 uint8_t restart_reason
= 0;
365 uint32_t grace_interval
= 0;
366 uint32_t actual_grace_interval
= 0;
367 struct advRtr lookup
;
368 struct ospf_neighbor
*restarter
= NULL
;
369 struct ospf_interface
*oi
= nbr
->oi
;
373 /* Extract the grace lsa packet fields */
374 ret
= ospf_extract_grace_lsa_fields(lsa
, &grace_interval
, &restart_addr
,
376 if (ret
!= OSPF_GR_SUCCESS
) {
377 if (IS_DEBUG_OSPF_GR
)
378 zlog_debug("%s, Wrong Grace LSA packet.", __func__
);
379 return OSPF_GR_NOT_HELPER
;
382 if (IS_DEBUG_OSPF_GR
)
384 "%s, Grace LSA received from %pI4, grace interval:%u, restart reason:%s",
385 __func__
, &restart_addr
, grace_interval
,
386 ospf_restart_reason2str(restart_reason
));
388 /* In case of broadcast links, if RESTARTER is DR_OTHER,
389 * grace LSA might be received from DR, so need to get
390 * actual neighbour info , here RESTARTER.
392 if (oi
->type
!= OSPF_IFTYPE_POINTOPOINT
) {
393 restarter
= ospf_nbr_lookup_by_addr(oi
->nbrs
, &restart_addr
);
396 if (IS_DEBUG_OSPF_GR
)
398 "%s, Restarter is not a nbr(%pI4) for this router.",
399 __func__
, &restart_addr
);
400 return OSPF_GR_NOT_HELPER
;
405 /* Verify Helper enabled globally */
406 if (!ospf
->is_helper_supported
) {
407 /* Verify that Helper support is enabled for the
408 * current neighbour router-id.
410 lookup
.advRtrAddr
.s_addr
= restarter
->router_id
.s_addr
;
412 if (!hash_lookup(ospf
->enable_rtr_list
, &lookup
)) {
413 if (IS_DEBUG_OSPF_GR
)
415 "%s, HELPER support is disabled, So not a HELPER",
417 restarter
->gr_helper_info
.rejected_reason
=
418 OSPF_HELPER_SUPPORT_DISABLED
;
419 return OSPF_GR_NOT_HELPER
;
424 /* Check neighbour is in FULL state and
425 * became a adjacency.
427 if (!IS_NBR_STATE_FULL(restarter
)) {
428 if (IS_DEBUG_OSPF_GR
)
430 "%s, This Neighbour %pI4 is not in FULL state.",
431 __func__
, &restarter
->src
);
432 restarter
->gr_helper_info
.rejected_reason
=
433 OSPF_HELPER_NOT_A_VALID_NEIGHBOUR
;
434 return OSPF_GR_NOT_HELPER
;
437 /* Based on the restart reason from grace lsa
438 * check the current router is supporting or not
440 if (ospf
->only_planned_restart
441 && !OSPF_GR_IS_PLANNED_RESTART(restart_reason
)) {
442 if (IS_DEBUG_OSPF_GR
)
444 "%s, Router supports only planned restarts but received the GRACE LSA for an unplanned restart.",
446 restarter
->gr_helper_info
.rejected_reason
=
447 OSPF_HELPER_PLANNED_ONLY_RESTART
;
448 return OSPF_GR_NOT_HELPER
;
451 /* Check the retransmission list of this
452 * neighbour, check any change in lsas.
454 if (ospf
->strict_lsa_check
&& !ospf_ls_retransmit_isempty(restarter
)
455 && ospf_check_change_in_rxmt_list(restarter
)) {
456 if (IS_DEBUG_OSPF_GR
)
458 "%s, Changed LSA in Rxmt list. So not Helper.",
460 restarter
->gr_helper_info
.rejected_reason
=
461 OSPF_HELPER_TOPO_CHANGE_RTXMT_LIST
;
462 return OSPF_GR_NOT_HELPER
;
465 /*LSA age must be less than the grace period */
466 if (ntohs(lsa
->data
->ls_age
) >= grace_interval
) {
467 if (IS_DEBUG_OSPF_GR
)
469 "%s, Grace LSA age(%d) is more than the grace interval(%d)",
470 __func__
, lsa
->data
->ls_age
, grace_interval
);
471 restarter
->gr_helper_info
.rejected_reason
=
472 OSPF_HELPER_LSA_AGE_MORE
;
473 return OSPF_GR_NOT_HELPER
;
476 if (ospf
->gr_info
.restart_in_progress
) {
477 if (IS_DEBUG_OSPF_GR
)
479 "%s: router is in the process of graceful restart",
481 restarter
->gr_helper_info
.rejected_reason
=
482 OSPF_HELPER_RESTARTING
;
483 return OSPF_GR_NOT_HELPER
;
486 /* check supported grace period configured
487 * if configured, use this to start the grace
488 * timer otherwise use the interval received
489 * in grace LSA packet.
491 actual_grace_interval
= grace_interval
;
492 if (grace_interval
> ospf
->supported_grace_time
) {
493 if (IS_DEBUG_OSPF_GR
)
495 "%s, Received grace period %d is larger than supported grace %d",
496 __func__
, grace_interval
,
497 ospf
->supported_grace_time
);
498 actual_grace_interval
= ospf
->supported_grace_time
;
501 if (OSPF_GR_IS_ACTIVE_HELPER(restarter
)) {
502 if (restarter
->gr_helper_info
.t_grace_timer
)
503 THREAD_OFF(restarter
->gr_helper_info
.t_grace_timer
);
505 if (ospf
->active_restarter_cnt
> 0)
506 ospf
->active_restarter_cnt
--;
508 if (IS_DEBUG_OSPF_GR
)
510 "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
513 if (IS_DEBUG_OSPF_GR
)
515 "%s, This Router becomes a HELPER for the neighbour %pI4",
516 __func__
, &restarter
->src
);
519 /* Became a Helper to the RESTART neighbour.
520 * Change the helper status.
522 restarter
->gr_helper_info
.gr_helper_status
= OSPF_GR_ACTIVE_HELPER
;
523 restarter
->gr_helper_info
.recvd_grace_period
= grace_interval
;
524 restarter
->gr_helper_info
.actual_grace_period
= actual_grace_interval
;
525 restarter
->gr_helper_info
.gr_restart_reason
= restart_reason
;
526 restarter
->gr_helper_info
.rejected_reason
= OSPF_HELPER_REJECTED_NONE
;
528 /* Increment the active restarter count */
529 ospf
->active_restarter_cnt
++;
531 if (IS_DEBUG_OSPF_GR
)
532 zlog_debug("%s, Grace timer started.interval:%d", __func__
,
533 actual_grace_interval
);
535 /* Start the grace timer */
536 event_add_timer(master
, ospf_handle_grace_timer_expiry
, restarter
,
537 actual_grace_interval
,
538 &restarter
->gr_helper_info
.t_grace_timer
);
540 return OSPF_GR_ACTIVE_HELPER
;
544 * API to check any change in the neighbor's
545 * retransmission list.
551 * TRUE - if any change in the lsa.
552 * FALSE - no change in the lsas.
554 static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor
*nbr
)
556 struct route_node
*rn
;
557 struct ospf_lsa
*lsa
;
558 struct route_table
*tbl
;
560 tbl
= nbr
->ls_rxmt
.type
[OSPF_ROUTER_LSA
].db
;
561 LSDB_LOOP (tbl
, rn
, lsa
)
562 if (lsa
->to_be_acknowledged
)
564 tbl
= nbr
->ls_rxmt
.type
[OSPF_NETWORK_LSA
].db
;
565 LSDB_LOOP (tbl
, rn
, lsa
)
566 if (lsa
->to_be_acknowledged
)
569 tbl
= nbr
->ls_rxmt
.type
[OSPF_SUMMARY_LSA
].db
;
570 LSDB_LOOP (tbl
, rn
, lsa
)
571 if (lsa
->to_be_acknowledged
)
574 tbl
= nbr
->ls_rxmt
.type
[OSPF_ASBR_SUMMARY_LSA
].db
;
575 LSDB_LOOP (tbl
, rn
, lsa
)
576 if (lsa
->to_be_acknowledged
)
579 tbl
= nbr
->ls_rxmt
.type
[OSPF_AS_EXTERNAL_LSA
].db
;
580 LSDB_LOOP (tbl
, rn
, lsa
)
581 if (lsa
->to_be_acknowledged
)
584 tbl
= nbr
->ls_rxmt
.type
[OSPF_AS_NSSA_LSA
].db
;
585 LSDB_LOOP (tbl
, rn
, lsa
)
586 if (lsa
->to_be_acknowledged
)
589 return OSPF_GR_FALSE
;
593 * Actions to be taken when topo change detected
594 * HELPER will exit upon topo change.
599 * topo change occurred due to this lsa type (1 to 5 and 7)
604 void ospf_helper_handle_topo_chg(struct ospf
*ospf
, struct ospf_lsa
*lsa
)
606 struct listnode
*node
;
607 struct ospf_interface
*oi
;
609 /* Topo change not required to be handled if strict
610 * LSA check is disabled for this router.
612 if (!ospf
->strict_lsa_check
)
615 if (IS_DEBUG_OSPF_GR
)
616 zlog_debug("%s: Topo change detected due to LSA[%s]", __func__
,
619 lsa
->to_be_acknowledged
= OSPF_GR_TRUE
;
621 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
622 struct route_node
*rn
= NULL
;
624 if (ospf_interface_neighbor_count(oi
) == 0)
627 /* Ref rfc3623 section 3.2.3.b
628 * If change due to external LSA and if the area is
629 * stub, then it is not a topo change. Since Type-5
630 * lsas will not be flooded in stub area.
632 if ((oi
->area
->external_routing
== OSPF_AREA_STUB
)
633 && (lsa
->data
->type
== OSPF_AS_EXTERNAL_LSA
)) {
637 for (rn
= route_top(oi
->nbrs
); rn
; rn
= route_next(rn
)) {
638 struct ospf_neighbor
*nbr
= NULL
;
645 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
646 ospf_gr_helper_exit(nbr
,
647 OSPF_GR_HELPER_TOPO_CHG
);
653 * Api to exit from HELPER role to take all actions
655 * Ref rfc3623 section 3.2
661 * OSPF neighbour for which it is acting as HELPER.
664 * The reason for exiting from HELPER.
669 void ospf_gr_helper_exit(struct ospf_neighbor
*nbr
,
670 enum ospf_helper_exit_reason reason
)
672 struct ospf_interface
*oi
= nbr
->oi
;
673 struct ospf
*ospf
= oi
->ospf
;
675 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr
))
678 if (IS_DEBUG_OSPF_GR
)
679 zlog_debug("%s, Exiting from HELPER support to %pI4, due to %s",
680 __func__
, &nbr
->src
, ospf_exit_reason2str(reason
));
682 /* Reset helper status*/
683 nbr
->gr_helper_info
.gr_helper_status
= OSPF_GR_NOT_HELPER
;
684 nbr
->gr_helper_info
.helper_exit_reason
= reason
;
685 nbr
->gr_helper_info
.actual_grace_period
= 0;
686 nbr
->gr_helper_info
.recvd_grace_period
= 0;
687 nbr
->gr_helper_info
.gr_restart_reason
= 0;
688 ospf
->last_exit_reason
= reason
;
690 if (ospf
->active_restarter_cnt
<= 0) {
692 "OSPF GR-Helper: active_restarter_cnt should be greater than zero here.");
695 /* Decrement active Restarter count */
696 ospf
->active_restarter_cnt
--;
698 /* If the exit not triggered due to grace timer
699 * expiry, stop the grace timer.
701 if (reason
!= OSPF_GR_HELPER_GRACE_TIMEOUT
)
702 THREAD_OFF(nbr
->gr_helper_info
.t_grace_timer
);
704 /* check exit triggered due to successful completion
705 * of graceful restart.
707 if (reason
!= OSPF_GR_HELPER_COMPLETED
) {
708 if (IS_DEBUG_OSPF_GR
)
709 zlog_debug("%s, Unsuccessful GR exit", __func__
);
712 /*Recalculate the DR for the network segment */
713 if (oi
->type
== OSPF_IFTYPE_BROADCAST
|| oi
->type
== OSPF_IFTYPE_NBMA
)
714 ospf_dr_election(oi
);
716 /* Originate a router LSA */
717 ospf_router_lsa_update_area(oi
->area
);
719 /* Originate network lsa if it is an DR in the LAN */
720 if (oi
->state
== ISM_DR
)
721 ospf_network_lsa_update(oi
);
725 * Process MaxAge Grace LSA.
726 * It is a indication for successful completion of GR.
727 * If router acting as HELPER, It exits from helper role.
733 * Grace LSA received from RESTARTER.
736 * OSPF neighbour which requests the router to act as
742 void ospf_process_maxage_grace_lsa(struct ospf
*ospf
, struct ospf_lsa
*lsa
,
743 struct ospf_neighbor
*nbr
)
745 struct in_addr restartAddr
= {0};
746 uint8_t restartReason
= 0;
747 uint32_t graceInterval
= 0;
748 struct ospf_neighbor
*restarter
= NULL
;
749 struct ospf_interface
*oi
= nbr
->oi
;
752 /* Extract the grace lsa packet fields */
753 ret
= ospf_extract_grace_lsa_fields(lsa
, &graceInterval
, &restartAddr
,
755 if (ret
!= OSPF_GR_SUCCESS
) {
756 if (IS_DEBUG_OSPF_GR
)
757 zlog_debug("%s, Wrong Grace LSA packet.", __func__
);
761 if (IS_DEBUG_OSPF_GR
)
762 zlog_debug("%s, GraceLSA received for neighbour %pI4", __func__
,
765 /* In case of broadcast links, if RESTARTER is DR_OTHER,
766 * grace LSA might be received from DR, so fetching the
767 * actual neighbour information using restarter address.
769 if (oi
->type
!= OSPF_IFTYPE_POINTOPOINT
) {
770 restarter
= ospf_nbr_lookup_by_addr(oi
->nbrs
, &restartAddr
);
773 if (IS_DEBUG_OSPF_GR
)
775 "%s, Restarter is not a neighbour for this router.",
783 ospf_gr_helper_exit(restarter
, OSPF_GR_HELPER_COMPLETED
);
786 /* Configuration handlers */
788 * Disable/Enable HELPER support on router level.
799 void ospf_gr_helper_support_set(struct ospf
*ospf
, bool support
)
801 struct ospf_interface
*oi
;
802 struct listnode
*node
;
803 struct advRtr lookup
;
805 if (ospf
->is_helper_supported
== support
)
808 ospf
->is_helper_supported
= support
;
810 /* If helper support disabled, cease HELPER role for all
811 * supporting neighbors.
813 if (support
== OSPF_GR_FALSE
) {
814 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
815 struct route_node
*rn
= NULL
;
817 if (ospf_interface_neighbor_count(oi
) == 0)
820 for (rn
= route_top(oi
->nbrs
); rn
;
821 rn
= route_next(rn
)) {
822 struct ospf_neighbor
*nbr
= NULL
;
829 lookup
.advRtrAddr
.s_addr
=
830 nbr
->router_id
.s_addr
;
831 /* check if helper support enabled for the
832 * corresponding routerid.If enabled, don't
833 * exit from helper role.
835 if (hash_lookup(ospf
->enable_rtr_list
, &lookup
))
838 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
840 nbr
, OSPF_GR_HELPER_TOPO_CHG
);
847 * Enable/Disable HELPER support on a specified advertagement
854 * HELPER support for given Advertisement Router.
857 * True - Enable Helper Support.
858 * False - Disable Helper Support.
864 void ospf_gr_helper_support_set_per_routerid(struct ospf
*ospf
,
865 struct in_addr
*advrtr
,
870 struct ospf_interface
*oi
;
871 struct listnode
*node
;
873 temp
.advRtrAddr
.s_addr
= advrtr
->s_addr
;
875 if (support
== OSPF_GR_FALSE
) {
876 /*Delete the routerid from the enable router hash table */
877 rtr
= hash_lookup(ospf
->enable_rtr_list
, &temp
);
880 hash_release(ospf
->enable_rtr_list
, rtr
);
881 ospf_disable_rtr_hash_free(rtr
);
884 /* If helper support is enabled globally
885 * no action is required.
887 if (ospf
->is_helper_supported
)
890 /* Cease the HELPER role fore neighbours from the
891 * specified advertisement router.
893 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
894 struct route_node
*rn
= NULL
;
896 if (ospf_interface_neighbor_count(oi
) == 0)
899 for (rn
= route_top(oi
->nbrs
); rn
;
900 rn
= route_next(rn
)) {
901 struct ospf_neighbor
*nbr
= NULL
;
908 if (nbr
->router_id
.s_addr
!= advrtr
->s_addr
)
911 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
913 nbr
, OSPF_GR_HELPER_TOPO_CHG
);
918 /* Add the routerid to the enable router hash table */
919 (void)hash_get(ospf
->enable_rtr_list
, &temp
,
920 ospf_enable_rtr_hash_alloc
);
925 * Api to enable/disable strict lsa check on the HELPER.
931 * True - disable the lsa check.
932 * False - enable the strict lsa check.
937 void ospf_gr_helper_lsa_check_set(struct ospf
*ospf
, bool enabled
)
939 if (ospf
->strict_lsa_check
== enabled
)
942 ospf
->strict_lsa_check
= enabled
;
946 * Api to set the supported grace interval in this router.
952 * The supported grace interval..
957 void ospf_gr_helper_supported_gracetime_set(struct ospf
*ospf
,
960 ospf
->supported_grace_time
= interval
;
964 * Api to set the supported restart reason.
970 * True: support only planned restart.
971 * False: support for planned/unplanned restarts.
976 void ospf_gr_helper_set_supported_planned_only_restart(struct ospf
*ospf
,
979 ospf
->only_planned_restart
= planned_only
;
983 * Api to display the grace LSA information.
995 static void show_ospf_grace_lsa_info(struct vty
*vty
, struct json_object
*json
,
996 struct ospf_lsa
*lsa
)
998 struct lsa_header
*lsah
= NULL
;
999 struct tlv_header
*tlvh
= NULL
;
1000 struct grace_tlv_graceperiod
*gracePeriod
;
1001 struct grace_tlv_restart_reason
*grReason
;
1002 struct grace_tlv_restart_addr
*restartAddr
;
1003 uint16_t length
= 0;
1009 lsah
= (struct lsa_header
*)lsa
->data
;
1011 if (lsa
->size
<= OSPF_LSA_HEADER_SIZE
) {
1013 vty_out(vty
, "%% Invalid LSA length: %d\n", length
);
1015 zlog_debug("%% Invalid LSA length: %d", length
);
1019 length
= lsa
->size
- OSPF_LSA_HEADER_SIZE
;
1022 vty_out(vty
, " TLV info:\n");
1024 zlog_debug(" TLV info:");
1026 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
&& tlvh
;
1027 tlvh
= TLV_HDR_NEXT(tlvh
)) {
1029 if (sum
+ TLV_SIZE(tlvh
) > length
) {
1031 vty_out(vty
, "%% Invalid TLV length: %u\n",
1034 zlog_debug("%% Invalid TLV length: %u",
1039 switch (ntohs(tlvh
->type
)) {
1040 case GRACE_PERIOD_TYPE
:
1042 < sizeof(struct grace_tlv_graceperiod
)) {
1045 "%% Invalid grace TLV length %u\n",
1049 "%% Invalid grace TLV length %u",
1054 gracePeriod
= (struct grace_tlv_graceperiod
*)tlvh
;
1055 sum
+= TLV_SIZE(tlvh
);
1058 vty_out(vty
, " Grace period:%d\n",
1059 ntohl(gracePeriod
->interval
));
1061 zlog_debug(" Grace period:%d",
1062 ntohl(gracePeriod
->interval
));
1064 case RESTART_REASON_TYPE
:
1066 < sizeof(struct grace_tlv_restart_reason
)) {
1069 "%% Invalid reason TLV length %u\n",
1073 "%% Invalid reason TLV length %u",
1078 grReason
= (struct grace_tlv_restart_reason
*)tlvh
;
1079 sum
+= TLV_SIZE(tlvh
);
1082 vty_out(vty
, " Restart reason:%s\n",
1083 ospf_restart_reason2str(
1086 zlog_debug(" Restart reason:%s",
1087 ospf_restart_reason2str(
1090 case RESTARTER_IP_ADDR_TYPE
:
1092 < sizeof(struct grace_tlv_restart_addr
)) {
1095 "%% Invalid addr TLV length %u\n",
1099 "%% Invalid addr TLV length %u",
1104 restartAddr
= (struct grace_tlv_restart_addr
*)tlvh
;
1105 sum
+= TLV_SIZE(tlvh
);
1108 vty_out(vty
, " Restarter address:%pI4\n",
1109 &restartAddr
->addr
);
1111 zlog_debug(" Restarter address:%pI4",
1112 &restartAddr
->addr
);
1116 vty_out(vty
, " Unknown TLV type %d\n",
1119 zlog_debug(" Unknown TLV type %d",