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(ospf
->enable_rtr_list
, ospf_disable_rtr_hash_free
);
103 hash_free(ospf
->enable_rtr_list
);
104 ospf
->enable_rtr_list
= NULL
;
108 * GR exit reason strings
110 const char *ospf_exit_reason2str(unsigned int reason
)
112 if (reason
< array_size(ospf_exit_reason_desc
))
113 return(ospf_exit_reason_desc
[reason
]);
115 return "Invalid reason";
119 * GR restart reason strings
121 const char *ospf_restart_reason2str(unsigned int reason
)
123 if (reason
< array_size(ospf_restart_reason_desc
))
124 return(ospf_restart_reason_desc
[reason
]);
126 return "Invalid reason";
130 * GR rejected reason strings
132 const char *ospf_rejected_reason2str(unsigned int reason
)
134 if (reason
< array_size(ospf_rejected_reason_desc
))
135 return(ospf_rejected_reason_desc
[reason
]);
137 return "Invalid reason";
141 * Initialize GR helper config data structures.
149 void ospf_gr_helper_instance_init(struct ospf
*ospf
)
151 if (IS_DEBUG_OSPF_GR
)
152 zlog_debug("%s, GR Helper init.", __func__
);
154 ospf
->is_helper_supported
= OSPF_GR_FALSE
;
155 ospf
->strict_lsa_check
= OSPF_GR_TRUE
;
156 ospf
->only_planned_restart
= OSPF_GR_FALSE
;
157 ospf
->supported_grace_time
= OSPF_MAX_GRACE_INTERVAL
;
158 ospf
->last_exit_reason
= OSPF_GR_HELPER_EXIT_NONE
;
159 ospf
->active_restarter_cnt
= 0;
161 ospf
->enable_rtr_list
=
162 hash_create(ospf_enable_rtr_hash_key
, ospf_enable_rtr_hash_cmp
,
163 "OSPF enable router hash");
167 * De-Initialize GR helper config data structures.
175 void ospf_gr_helper_instance_stop(struct ospf
*ospf
)
177 if (IS_DEBUG_OSPF_GR
)
178 zlog_debug("%s, GR helper deinit.", __func__
);
180 ospf_enable_rtr_hash_destroy(ospf
);
184 * Initialize GR helper config data structures.
189 void ospf_gr_helper_init(void)
193 if (IS_DEBUG_OSPF_GR
)
194 zlog_debug("%s, GR Helper init.", __func__
);
196 rc
= ospf_register_opaque_functab(
197 OSPF_OPAQUE_LINK_LSA
, OPAQUE_TYPE_GRACE_LSA
, NULL
, NULL
, NULL
,
198 NULL
, NULL
, NULL
, NULL
, show_ospf_grace_lsa_info
, NULL
, NULL
,
201 flog_warn(EC_OSPF_OPAQUE_REGISTRATION
,
202 "%s: Failed to register Grace LSA functions",
208 * De-Initialize GR helper config data structures.
213 void ospf_gr_helper_stop(void)
215 if (IS_DEBUG_OSPF_GR
)
216 zlog_debug("%s, GR helper deinit.", __func__
);
218 ospf_delete_opaque_functab(OSPF_OPAQUE_LINK_LSA
, OPAQUE_TYPE_GRACE_LSA
);
222 * Extracting tlv info from GRACE LSA.
228 * interval : grace interval.
229 * addr : RESTARTER address.
230 * reason : Restarting reason.
232 static int ospf_extract_grace_lsa_fields(struct ospf_lsa
*lsa
,
234 struct in_addr
*addr
, uint8_t *reason
)
236 struct lsa_header
*lsah
= NULL
;
237 struct tlv_header
*tlvh
= NULL
;
238 struct grace_tlv_graceperiod
*grace_period
;
239 struct grace_tlv_restart_reason
*gr_reason
;
240 struct grace_tlv_restart_addr
*restart_addr
;
244 lsah
= (struct lsa_header
*)lsa
->data
;
247 if (lsa
->size
<= OSPF_LSA_HEADER_SIZE
) {
248 if (IS_DEBUG_OSPF_GR
)
249 zlog_debug("%s: Malformed packet: Invalid LSA len:%d",
251 return OSPF_GR_FAILURE
;
254 length
= lsa
->size
- OSPF_LSA_HEADER_SIZE
;
256 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
&& tlvh
;
257 tlvh
= TLV_HDR_NEXT(tlvh
)) {
259 /* Check TLV len against overall LSA */
260 if (sum
+ TLV_SIZE(tlvh
) > length
) {
261 if (IS_DEBUG_OSPF_GR
)
262 zlog_debug("%s: Malformed packet: Invalid TLV len:%u",
263 __func__
, TLV_SIZE(tlvh
));
264 return OSPF_GR_FAILURE
;
267 switch (ntohs(tlvh
->type
)) {
268 case GRACE_PERIOD_TYPE
:
270 sizeof(struct grace_tlv_graceperiod
)) {
271 zlog_debug("%s: Malformed packet: Invalid grace TLV len:%u",
272 __func__
, TLV_SIZE(tlvh
));
273 return OSPF_GR_FAILURE
;
276 grace_period
= (struct grace_tlv_graceperiod
*)tlvh
;
277 *interval
= ntohl(grace_period
->interval
);
278 sum
+= TLV_SIZE(tlvh
);
280 /* Check if grace interval is valid */
281 if (*interval
> OSPF_MAX_GRACE_INTERVAL
282 || *interval
< OSPF_MIN_GRACE_INTERVAL
)
283 return OSPF_GR_FAILURE
;
285 case RESTART_REASON_TYPE
:
287 sizeof(struct grace_tlv_restart_reason
)) {
288 zlog_debug("%s: Malformed packet: Invalid reason TLV len:%u",
289 __func__
, TLV_SIZE(tlvh
));
290 return OSPF_GR_FAILURE
;
293 gr_reason
= (struct grace_tlv_restart_reason
*)tlvh
;
294 *reason
= gr_reason
->reason
;
295 sum
+= TLV_SIZE(tlvh
);
297 if (*reason
>= OSPF_GR_INVALID_REASON_CODE
)
298 return OSPF_GR_FAILURE
;
300 case RESTARTER_IP_ADDR_TYPE
:
302 sizeof(struct grace_tlv_restart_addr
)) {
303 zlog_debug("%s: Malformed packet: Invalid addr TLV len:%u",
304 __func__
, TLV_SIZE(tlvh
));
305 return OSPF_GR_FAILURE
;
308 restart_addr
= (struct grace_tlv_restart_addr
*)tlvh
;
309 addr
->s_addr
= restart_addr
->addr
.s_addr
;
310 sum
+= TLV_SIZE(tlvh
);
313 if (IS_DEBUG_OSPF_GR
)
315 "%s, Malformed packet.Invalid TLV type:%d",
316 __func__
, ntohs(tlvh
->type
));
317 return OSPF_GR_FAILURE
;
321 return OSPF_GR_SUCCESS
;
325 * Grace timer expiry handler.
326 * HELPER aborts its role at grace timer expiry.
334 static void ospf_handle_grace_timer_expiry(struct thread
*thread
)
336 struct ospf_neighbor
*nbr
= THREAD_ARG(thread
);
338 nbr
->gr_helper_info
.t_grace_timer
= NULL
;
340 ospf_gr_helper_exit(nbr
, OSPF_GR_HELPER_GRACE_TIMEOUT
);
344 * Process Grace LSA.If it is eligible move to HELPER role.
345 * Ref rfc3623 section 3.1
351 * Grace LSA received from RESTARTER.
354 * OSPF neighbour which requests the router to act as
359 * If supported as HELPER : OSPF_GR_HELPER_INPROGRESS
360 * If Not supported as HELPER : OSPF_GR_HELPER_NONE
362 int ospf_process_grace_lsa(struct ospf
*ospf
, struct ospf_lsa
*lsa
,
363 struct ospf_neighbor
*nbr
)
365 struct in_addr restart_addr
= {0};
366 uint8_t restart_reason
= 0;
367 uint32_t grace_interval
= 0;
368 uint32_t actual_grace_interval
= 0;
369 struct advRtr lookup
;
370 struct ospf_neighbor
*restarter
= NULL
;
371 struct ospf_interface
*oi
= nbr
->oi
;
375 /* Extract the grace lsa packet fields */
376 ret
= ospf_extract_grace_lsa_fields(lsa
, &grace_interval
, &restart_addr
,
378 if (ret
!= OSPF_GR_SUCCESS
) {
379 if (IS_DEBUG_OSPF_GR
)
380 zlog_debug("%s, Wrong Grace LSA packet.", __func__
);
381 return OSPF_GR_NOT_HELPER
;
384 if (IS_DEBUG_OSPF_GR
)
386 "%s, Grace LSA received from %pI4, grace interval:%u, restart reason:%s",
387 __func__
, &restart_addr
, grace_interval
,
388 ospf_restart_reason2str(restart_reason
));
390 /* In case of broadcast links, if RESTARTER is DR_OTHER,
391 * grace LSA might be received from DR, so need to get
392 * actual neighbour info , here RESTARTER.
394 if (oi
->type
!= OSPF_IFTYPE_POINTOPOINT
) {
395 restarter
= ospf_nbr_lookup_by_addr(oi
->nbrs
, &restart_addr
);
398 if (IS_DEBUG_OSPF_GR
)
400 "%s, Restarter is not a nbr(%pI4) for this router.",
401 __func__
, &restart_addr
);
402 return OSPF_GR_NOT_HELPER
;
407 /* Verify Helper enabled globally */
408 if (!ospf
->is_helper_supported
) {
409 /* Verify that Helper support is enabled for the
410 * current neighbour router-id.
412 lookup
.advRtrAddr
.s_addr
= restarter
->router_id
.s_addr
;
414 if (!hash_lookup(ospf
->enable_rtr_list
, &lookup
)) {
415 if (IS_DEBUG_OSPF_GR
)
417 "%s, HELPER support is disabled, So not a HELPER",
419 restarter
->gr_helper_info
.rejected_reason
=
420 OSPF_HELPER_SUPPORT_DISABLED
;
421 return OSPF_GR_NOT_HELPER
;
426 /* Check neighbour is in FULL state and
427 * became a adjacency.
429 if (!IS_NBR_STATE_FULL(restarter
)) {
430 if (IS_DEBUG_OSPF_GR
)
432 "%s, This Neighbour %pI4 is not in FULL state.",
433 __func__
, &restarter
->src
);
434 restarter
->gr_helper_info
.rejected_reason
=
435 OSPF_HELPER_NOT_A_VALID_NEIGHBOUR
;
436 return OSPF_GR_NOT_HELPER
;
439 /* Based on the restart reason from grace lsa
440 * check the current router is supporting or not
442 if (ospf
->only_planned_restart
443 && !OSPF_GR_IS_PLANNED_RESTART(restart_reason
)) {
444 if (IS_DEBUG_OSPF_GR
)
446 "%s, Router supports only planned restarts but received the GRACE LSA for an unplanned restart.",
448 restarter
->gr_helper_info
.rejected_reason
=
449 OSPF_HELPER_PLANNED_ONLY_RESTART
;
450 return OSPF_GR_NOT_HELPER
;
453 /* Check the retransmission list of this
454 * neighbour, check any change in lsas.
456 if (ospf
->strict_lsa_check
&& !ospf_ls_retransmit_isempty(restarter
)
457 && ospf_check_change_in_rxmt_list(restarter
)) {
458 if (IS_DEBUG_OSPF_GR
)
460 "%s, Changed LSA in Rxmt list. So not Helper.",
462 restarter
->gr_helper_info
.rejected_reason
=
463 OSPF_HELPER_TOPO_CHANGE_RTXMT_LIST
;
464 return OSPF_GR_NOT_HELPER
;
467 /*LSA age must be less than the grace period */
468 if (ntohs(lsa
->data
->ls_age
) >= grace_interval
) {
469 if (IS_DEBUG_OSPF_GR
)
471 "%s, Grace LSA age(%d) is more than the grace interval(%d)",
472 __func__
, lsa
->data
->ls_age
, grace_interval
);
473 restarter
->gr_helper_info
.rejected_reason
=
474 OSPF_HELPER_LSA_AGE_MORE
;
475 return OSPF_GR_NOT_HELPER
;
478 if (ospf
->gr_info
.restart_in_progress
) {
479 if (IS_DEBUG_OSPF_GR
)
481 "%s: router is in the process of graceful restart",
483 restarter
->gr_helper_info
.rejected_reason
=
484 OSPF_HELPER_RESTARTING
;
485 return OSPF_GR_NOT_HELPER
;
488 /* check supported grace period configured
489 * if configured, use this to start the grace
490 * timer otherwise use the interval received
491 * in grace LSA packet.
493 actual_grace_interval
= grace_interval
;
494 if (grace_interval
> ospf
->supported_grace_time
) {
495 if (IS_DEBUG_OSPF_GR
)
497 "%s, Received grace period %d is larger than supported grace %d",
498 __func__
, grace_interval
,
499 ospf
->supported_grace_time
);
500 actual_grace_interval
= ospf
->supported_grace_time
;
503 if (OSPF_GR_IS_ACTIVE_HELPER(restarter
)) {
504 if (restarter
->gr_helper_info
.t_grace_timer
)
505 THREAD_OFF(restarter
->gr_helper_info
.t_grace_timer
);
507 if (ospf
->active_restarter_cnt
> 0)
508 ospf
->active_restarter_cnt
--;
510 if (IS_DEBUG_OSPF_GR
)
512 "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
515 if (IS_DEBUG_OSPF_GR
)
517 "%s, This Router becomes a HELPER for the neighbour %pI4",
518 __func__
, &restarter
->src
);
521 /* Became a Helper to the RESTART neighbour.
522 * Change the helper status.
524 restarter
->gr_helper_info
.gr_helper_status
= OSPF_GR_ACTIVE_HELPER
;
525 restarter
->gr_helper_info
.recvd_grace_period
= grace_interval
;
526 restarter
->gr_helper_info
.actual_grace_period
= actual_grace_interval
;
527 restarter
->gr_helper_info
.gr_restart_reason
= restart_reason
;
528 restarter
->gr_helper_info
.rejected_reason
= OSPF_HELPER_REJECTED_NONE
;
530 /* Increment the active restarter count */
531 ospf
->active_restarter_cnt
++;
533 if (IS_DEBUG_OSPF_GR
)
534 zlog_debug("%s, Grace timer started.interval:%d", __func__
,
535 actual_grace_interval
);
537 /* Start the grace timer */
538 thread_add_timer(master
, ospf_handle_grace_timer_expiry
, restarter
,
539 actual_grace_interval
,
540 &restarter
->gr_helper_info
.t_grace_timer
);
542 return OSPF_GR_ACTIVE_HELPER
;
546 * API to check any change in the neighbor's
547 * retransmission list.
553 * TRUE - if any change in the lsa.
554 * FALSE - no change in the lsas.
556 static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor
*nbr
)
558 struct route_node
*rn
;
559 struct ospf_lsa
*lsa
;
560 struct route_table
*tbl
;
562 tbl
= nbr
->ls_rxmt
.type
[OSPF_ROUTER_LSA
].db
;
563 LSDB_LOOP (tbl
, rn
, lsa
)
564 if (lsa
->to_be_acknowledged
)
566 tbl
= nbr
->ls_rxmt
.type
[OSPF_NETWORK_LSA
].db
;
567 LSDB_LOOP (tbl
, rn
, lsa
)
568 if (lsa
->to_be_acknowledged
)
571 tbl
= nbr
->ls_rxmt
.type
[OSPF_SUMMARY_LSA
].db
;
572 LSDB_LOOP (tbl
, rn
, lsa
)
573 if (lsa
->to_be_acknowledged
)
576 tbl
= nbr
->ls_rxmt
.type
[OSPF_ASBR_SUMMARY_LSA
].db
;
577 LSDB_LOOP (tbl
, rn
, lsa
)
578 if (lsa
->to_be_acknowledged
)
581 tbl
= nbr
->ls_rxmt
.type
[OSPF_AS_EXTERNAL_LSA
].db
;
582 LSDB_LOOP (tbl
, rn
, lsa
)
583 if (lsa
->to_be_acknowledged
)
586 tbl
= nbr
->ls_rxmt
.type
[OSPF_AS_NSSA_LSA
].db
;
587 LSDB_LOOP (tbl
, rn
, lsa
)
588 if (lsa
->to_be_acknowledged
)
591 return OSPF_GR_FALSE
;
595 * Actions to be taken when topo change detected
596 * HELPER will exit upon topo change.
601 * topo change occurred due to this lsa type (1 to 5 and 7)
606 void ospf_helper_handle_topo_chg(struct ospf
*ospf
, struct ospf_lsa
*lsa
)
608 struct listnode
*node
;
609 struct ospf_interface
*oi
;
611 /* Topo change not required to be handled if strict
612 * LSA check is disabled for this router.
614 if (!ospf
->strict_lsa_check
)
617 if (IS_DEBUG_OSPF_GR
)
618 zlog_debug("%s: Topo change detected due to LSA[%s]", __func__
,
621 lsa
->to_be_acknowledged
= OSPF_GR_TRUE
;
623 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
624 struct route_node
*rn
= NULL
;
626 if (ospf_interface_neighbor_count(oi
) == 0)
629 /* Ref rfc3623 section 3.2.3.b
630 * If change due to external LSA and if the area is
631 * stub, then it is not a topo change. Since Type-5
632 * lsas will not be flooded in stub area.
634 if ((oi
->area
->external_routing
== OSPF_AREA_STUB
)
635 && (lsa
->data
->type
== OSPF_AS_EXTERNAL_LSA
)) {
639 for (rn
= route_top(oi
->nbrs
); rn
; rn
= route_next(rn
)) {
640 struct ospf_neighbor
*nbr
= NULL
;
647 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
648 ospf_gr_helper_exit(nbr
,
649 OSPF_GR_HELPER_TOPO_CHG
);
655 * Api to exit from HELPER role to take all actions
657 * Ref rfc3623 section 3.2
663 * OSPF neighbour for which it is acting as HELPER.
666 * The reason for exiting from HELPER.
671 void ospf_gr_helper_exit(struct ospf_neighbor
*nbr
,
672 enum ospf_helper_exit_reason reason
)
674 struct ospf_interface
*oi
= nbr
->oi
;
675 struct ospf
*ospf
= oi
->ospf
;
677 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr
))
680 if (IS_DEBUG_OSPF_GR
)
681 zlog_debug("%s, Exiting from HELPER support to %pI4, due to %s",
682 __func__
, &nbr
->src
, ospf_exit_reason2str(reason
));
684 /* Reset helper status*/
685 nbr
->gr_helper_info
.gr_helper_status
= OSPF_GR_NOT_HELPER
;
686 nbr
->gr_helper_info
.helper_exit_reason
= reason
;
687 nbr
->gr_helper_info
.actual_grace_period
= 0;
688 nbr
->gr_helper_info
.recvd_grace_period
= 0;
689 nbr
->gr_helper_info
.gr_restart_reason
= 0;
690 ospf
->last_exit_reason
= reason
;
692 if (ospf
->active_restarter_cnt
<= 0) {
694 "OSPF GR-Helper: active_restarter_cnt should be greater than zero here.");
697 /* Decrement active Restarter count */
698 ospf
->active_restarter_cnt
--;
700 /* If the exit not triggered due to grace timer
701 * expiry, stop the grace timer.
703 if (reason
!= OSPF_GR_HELPER_GRACE_TIMEOUT
)
704 THREAD_OFF(nbr
->gr_helper_info
.t_grace_timer
);
706 /* check exit triggered due to successful completion
707 * of graceful restart.
709 if (reason
!= OSPF_GR_HELPER_COMPLETED
) {
710 if (IS_DEBUG_OSPF_GR
)
711 zlog_debug("%s, Unsuccessful GR exit", __func__
);
714 /*Recalculate the DR for the network segment */
715 if (oi
->type
== OSPF_IFTYPE_BROADCAST
|| oi
->type
== OSPF_IFTYPE_NBMA
)
716 ospf_dr_election(oi
);
718 /* Originate a router LSA */
719 ospf_router_lsa_update_area(oi
->area
);
721 /* Originate network lsa if it is an DR in the LAN */
722 if (oi
->state
== ISM_DR
)
723 ospf_network_lsa_update(oi
);
727 * Process MaxAge Grace LSA.
728 * It is a indication for successful completion of GR.
729 * If router acting as HELPER, It exits from helper role.
735 * Grace LSA received from RESTARTER.
738 * OSPF neighbour which requests the router to act as
744 void ospf_process_maxage_grace_lsa(struct ospf
*ospf
, struct ospf_lsa
*lsa
,
745 struct ospf_neighbor
*nbr
)
747 struct in_addr restartAddr
= {0};
748 uint8_t restartReason
= 0;
749 uint32_t graceInterval
= 0;
750 struct ospf_neighbor
*restarter
= NULL
;
751 struct ospf_interface
*oi
= nbr
->oi
;
754 /* Extract the grace lsa packet fields */
755 ret
= ospf_extract_grace_lsa_fields(lsa
, &graceInterval
, &restartAddr
,
757 if (ret
!= OSPF_GR_SUCCESS
) {
758 if (IS_DEBUG_OSPF_GR
)
759 zlog_debug("%s, Wrong Grace LSA packet.", __func__
);
763 if (IS_DEBUG_OSPF_GR
)
764 zlog_debug("%s, GraceLSA received for neighbour %pI4", __func__
,
767 /* In case of broadcast links, if RESTARTER is DR_OTHER,
768 * grace LSA might be received from DR, so fetching the
769 * actual neighbour information using restarter address.
771 if (oi
->type
!= OSPF_IFTYPE_POINTOPOINT
) {
772 restarter
= ospf_nbr_lookup_by_addr(oi
->nbrs
, &restartAddr
);
775 if (IS_DEBUG_OSPF_GR
)
777 "%s, Restarter is not a neighbour for this router.",
785 ospf_gr_helper_exit(restarter
, OSPF_GR_HELPER_COMPLETED
);
788 /* Configuration handlers */
790 * Disable/Enable HELPER support on router level.
801 void ospf_gr_helper_support_set(struct ospf
*ospf
, bool support
)
803 struct ospf_interface
*oi
;
804 struct listnode
*node
;
805 struct advRtr lookup
;
807 if (ospf
->is_helper_supported
== support
)
810 ospf
->is_helper_supported
= support
;
812 /* If helper support disabled, cease HELPER role for all
813 * supporting neighbors.
815 if (support
== OSPF_GR_FALSE
) {
816 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
817 struct route_node
*rn
= NULL
;
819 if (ospf_interface_neighbor_count(oi
) == 0)
822 for (rn
= route_top(oi
->nbrs
); rn
;
823 rn
= route_next(rn
)) {
824 struct ospf_neighbor
*nbr
= NULL
;
831 lookup
.advRtrAddr
.s_addr
=
832 nbr
->router_id
.s_addr
;
833 /* check if helper support enabled for the
834 * corresponding routerid.If enabled, don't
835 * exit from helper role.
837 if (hash_lookup(ospf
->enable_rtr_list
, &lookup
))
840 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
842 nbr
, OSPF_GR_HELPER_TOPO_CHG
);
849 * Enable/Disable HELPER support on a specified advertagement
856 * HELPER support for given Advertisement Router.
859 * True - Enable Helper Support.
860 * False - Disable Helper Support.
866 void ospf_gr_helper_support_set_per_routerid(struct ospf
*ospf
,
867 struct in_addr
*advrtr
,
872 struct ospf_interface
*oi
;
873 struct listnode
*node
;
875 temp
.advRtrAddr
.s_addr
= advrtr
->s_addr
;
877 if (support
== OSPF_GR_FALSE
) {
878 /*Delete the routerid from the enable router hash table */
879 rtr
= hash_lookup(ospf
->enable_rtr_list
, &temp
);
882 hash_release(ospf
->enable_rtr_list
, rtr
);
883 ospf_disable_rtr_hash_free(rtr
);
886 /* If helper support is enabled globally
887 * no action is required.
889 if (ospf
->is_helper_supported
)
892 /* Cease the HELPER role fore neighbours from the
893 * specified advertisement router.
895 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
896 struct route_node
*rn
= NULL
;
898 if (ospf_interface_neighbor_count(oi
) == 0)
901 for (rn
= route_top(oi
->nbrs
); rn
;
902 rn
= route_next(rn
)) {
903 struct ospf_neighbor
*nbr
= NULL
;
910 if (nbr
->router_id
.s_addr
!= advrtr
->s_addr
)
913 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
915 nbr
, OSPF_GR_HELPER_TOPO_CHG
);
920 /* Add the routerid to the enable router hash table */
921 (void)hash_get(ospf
->enable_rtr_list
, &temp
,
922 ospf_enable_rtr_hash_alloc
);
927 * Api to enable/disable strict lsa check on the HELPER.
933 * True - disable the lsa check.
934 * False - enable the strict lsa check.
939 void ospf_gr_helper_lsa_check_set(struct ospf
*ospf
, bool enabled
)
941 if (ospf
->strict_lsa_check
== enabled
)
944 ospf
->strict_lsa_check
= enabled
;
948 * Api to set the supported grace interval in this router.
954 * The supported grace interval..
959 void ospf_gr_helper_supported_gracetime_set(struct ospf
*ospf
,
962 ospf
->supported_grace_time
= interval
;
966 * Api to set the supported restart reason.
972 * True: support only planned restart.
973 * False: support for planned/unplanned restarts.
978 void ospf_gr_helper_set_supported_planned_only_restart(struct ospf
*ospf
,
981 ospf
->only_planned_restart
= planned_only
;
985 * Api to display the grace LSA information.
997 static void show_ospf_grace_lsa_info(struct vty
*vty
, struct json_object
*json
,
998 struct ospf_lsa
*lsa
)
1000 struct lsa_header
*lsah
= NULL
;
1001 struct tlv_header
*tlvh
= NULL
;
1002 struct grace_tlv_graceperiod
*gracePeriod
;
1003 struct grace_tlv_restart_reason
*grReason
;
1004 struct grace_tlv_restart_addr
*restartAddr
;
1005 uint16_t length
= 0;
1011 lsah
= (struct lsa_header
*)lsa
->data
;
1013 if (lsa
->size
<= OSPF_LSA_HEADER_SIZE
) {
1015 vty_out(vty
, "%% Invalid LSA length: %d\n", length
);
1017 zlog_debug("%% Invalid LSA length: %d", length
);
1021 length
= lsa
->size
- OSPF_LSA_HEADER_SIZE
;
1024 vty_out(vty
, " TLV info:\n");
1026 zlog_debug(" TLV info:");
1028 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
&& tlvh
;
1029 tlvh
= TLV_HDR_NEXT(tlvh
)) {
1031 if (sum
+ TLV_SIZE(tlvh
) > length
) {
1033 vty_out(vty
, "%% Invalid TLV length: %u\n",
1036 zlog_debug("%% Invalid TLV length: %u",
1041 switch (ntohs(tlvh
->type
)) {
1042 case GRACE_PERIOD_TYPE
:
1044 < sizeof(struct grace_tlv_graceperiod
)) {
1047 "%% Invalid grace TLV length %u\n",
1051 "%% Invalid grace TLV length %u",
1056 gracePeriod
= (struct grace_tlv_graceperiod
*)tlvh
;
1057 sum
+= TLV_SIZE(tlvh
);
1060 vty_out(vty
, " Grace period:%d\n",
1061 ntohl(gracePeriod
->interval
));
1063 zlog_debug(" Grace period:%d",
1064 ntohl(gracePeriod
->interval
));
1066 case RESTART_REASON_TYPE
:
1068 < sizeof(struct grace_tlv_restart_reason
)) {
1071 "%% Invalid reason TLV length %u\n",
1075 "%% Invalid reason TLV length %u",
1080 grReason
= (struct grace_tlv_restart_reason
*)tlvh
;
1081 sum
+= TLV_SIZE(tlvh
);
1084 vty_out(vty
, " Restart reason:%s\n",
1085 ospf_restart_reason2str(
1088 zlog_debug(" Restart reason:%s",
1089 ospf_restart_reason2str(
1092 case RESTARTER_IP_ADDR_TYPE
:
1094 < sizeof(struct grace_tlv_restart_addr
)) {
1097 "%% Invalid addr TLV length %u\n",
1101 "%% Invalid addr TLV length %u",
1106 restartAddr
= (struct grace_tlv_restart_addr
*)tlvh
;
1107 sum
+= TLV_SIZE(tlvh
);
1110 vty_out(vty
, " Restarter address:%pI4\n",
1111 &restartAddr
->addr
);
1113 zlog_debug(" Restarter address:%pI4",
1114 &restartAddr
->addr
);
1118 vty_out(vty
, " Unknown TLV type %d\n",
1121 zlog_debug(" Unknown TLV type %d",