2 * OSPF Graceful Restart helper functions.
4 * Copyright (C) 2020-21 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
37 #include "ospfd/ospfd.h"
38 #include "ospfd/ospf_interface.h"
39 #include "ospfd/ospf_asbr.h"
40 #include "ospfd/ospf_lsa.h"
41 #include "ospfd/ospf_lsdb.h"
42 #include "ospfd/ospf_neighbor.h"
43 #include "ospfd/ospf_spf.h"
44 #include "ospfd/ospf_flood.h"
45 #include "ospfd/ospf_route.h"
46 #include "ospfd/ospf_zebra.h"
47 #include "ospfd/ospf_dump.h"
48 #include "ospfd/ospf_errors.h"
49 #include "ospfd/ospf_nsm.h"
50 #include "ospfd/ospf_ism.h"
51 #include "ospfd/ospf_gr.h"
53 static const char * const ospf_exit_reason_desc
[] = {
58 "Successful graceful restart",
61 static const char * const ospf_restart_reason_desc
[] = {
64 "Software reload/upgrade",
65 "Switch to redundant control processor",
68 static const char * const ospf_rejected_reason_desc
[] = {
70 "Helper support disabled",
71 "Neighbour is not in FULL state",
72 "Supports only planned restart but received unplanned",
73 "Topo change due to change in lsa rxmt list",
74 "LSA age is more than Grace interval",
75 "Router is in the process of graceful restart",
78 static void show_ospf_grace_lsa_info(struct vty
*vty
, struct json_object
*json
,
79 struct ospf_lsa
*lsa
);
80 static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor
*nbr
);
82 static unsigned int ospf_enable_rtr_hash_key(const void *data
)
84 const struct advRtr
*rtr
= data
;
86 return jhash_1word(rtr
->advRtrAddr
.s_addr
, 0);
89 static bool ospf_enable_rtr_hash_cmp(const void *d1
, const void *d2
)
91 const struct advRtr
*rtr1
= (struct advRtr
*)d1
;
92 const struct advRtr
*rtr2
= (struct advRtr
*)d2
;
94 return (rtr1
->advRtrAddr
.s_addr
== rtr2
->advRtrAddr
.s_addr
);
97 static void *ospf_enable_rtr_hash_alloc(void *p
)
101 rid
= XCALLOC(MTYPE_OSPF_GR_HELPER
, sizeof(struct advRtr
));
102 rid
->advRtrAddr
.s_addr
= ((struct in_addr
*)p
)->s_addr
;
107 static void ospf_disable_rtr_hash_free(void *rtr
)
109 XFREE(MTYPE_OSPF_GR_HELPER
, rtr
);
112 static void ospf_enable_rtr_hash_destroy(struct ospf
*ospf
)
114 if (ospf
->enable_rtr_list
== NULL
)
117 hash_clean(ospf
->enable_rtr_list
, ospf_disable_rtr_hash_free
);
118 hash_free(ospf
->enable_rtr_list
);
119 ospf
->enable_rtr_list
= NULL
;
123 * GR exit reason strings
125 const char *ospf_exit_reason2str(unsigned int reason
)
127 if (reason
< array_size(ospf_exit_reason_desc
))
128 return(ospf_exit_reason_desc
[reason
]);
130 return "Invalid reason";
134 * GR restart reason strings
136 const char *ospf_restart_reason2str(unsigned int reason
)
138 if (reason
< array_size(ospf_restart_reason_desc
))
139 return(ospf_restart_reason_desc
[reason
]);
141 return "Invalid reason";
145 * GR rejected reason strings
147 const char *ospf_rejected_reason2str(unsigned int reason
)
149 if (reason
< array_size(ospf_rejected_reason_desc
))
150 return(ospf_rejected_reason_desc
[reason
]);
152 return "Invalid reason";
156 * Initialize GR helper config data structures.
164 void ospf_gr_helper_instance_init(struct ospf
*ospf
)
166 if (IS_DEBUG_OSPF_GR
)
167 zlog_debug("%s, GR Helper init.", __func__
);
169 ospf
->is_helper_supported
= OSPF_GR_FALSE
;
170 ospf
->strict_lsa_check
= OSPF_GR_TRUE
;
171 ospf
->only_planned_restart
= OSPF_GR_FALSE
;
172 ospf
->supported_grace_time
= OSPF_MAX_GRACE_INTERVAL
;
173 ospf
->last_exit_reason
= OSPF_GR_HELPER_EXIT_NONE
;
174 ospf
->active_restarter_cnt
= 0;
176 ospf
->enable_rtr_list
=
177 hash_create(ospf_enable_rtr_hash_key
, ospf_enable_rtr_hash_cmp
,
178 "OSPF enable router hash");
182 * De-Initialize GR helper config data structures.
190 void ospf_gr_helper_instance_stop(struct ospf
*ospf
)
192 if (IS_DEBUG_OSPF_GR
)
193 zlog_debug("%s, GR helper deinit.", __func__
);
195 ospf_enable_rtr_hash_destroy(ospf
);
199 * Initialize GR helper config data structures.
204 void ospf_gr_helper_init(void)
208 if (IS_DEBUG_OSPF_GR
)
209 zlog_debug("%s, GR Helper init.", __func__
);
211 rc
= ospf_register_opaque_functab(
212 OSPF_OPAQUE_LINK_LSA
, OPAQUE_TYPE_GRACE_LSA
, NULL
, NULL
, NULL
,
213 NULL
, NULL
, NULL
, NULL
, show_ospf_grace_lsa_info
, NULL
, NULL
,
216 flog_warn(EC_OSPF_OPAQUE_REGISTRATION
,
217 "%s: Failed to register Grace LSA functions",
223 * De-Initialize GR helper config data structures.
228 void ospf_gr_helper_stop(void)
230 if (IS_DEBUG_OSPF_GR
)
231 zlog_debug("%s, GR helper deinit.", __func__
);
233 ospf_delete_opaque_functab(OSPF_OPAQUE_LINK_LSA
, OPAQUE_TYPE_GRACE_LSA
);
237 * Extracting tlv info from GRACE LSA.
243 * interval : grace interval.
244 * addr : RESTARTER address.
245 * reason : Restarting reason.
247 static int ospf_extract_grace_lsa_fields(struct ospf_lsa
*lsa
,
249 struct in_addr
*addr
, uint8_t *reason
)
251 struct lsa_header
*lsah
= NULL
;
252 struct tlv_header
*tlvh
= NULL
;
253 struct grace_tlv_graceperiod
*grace_period
;
254 struct grace_tlv_restart_reason
*gr_reason
;
255 struct grace_tlv_restart_addr
*restart_addr
;
259 lsah
= (struct lsa_header
*)lsa
->data
;
262 if (lsa
->size
<= OSPF_LSA_HEADER_SIZE
) {
263 if (IS_DEBUG_OSPF_GR
)
264 zlog_debug("%s: Malformed packet: Invalid LSA len:%d",
266 return OSPF_GR_FAILURE
;
269 length
= lsa
->size
- OSPF_LSA_HEADER_SIZE
;
271 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
&& tlvh
;
272 tlvh
= TLV_HDR_NEXT(tlvh
)) {
274 /* Check TLV len against overall LSA */
275 if (sum
+ TLV_SIZE(tlvh
) > length
) {
276 if (IS_DEBUG_OSPF_GR
)
277 zlog_debug("%s: Malformed packet: Invalid TLV len:%u",
278 __func__
, TLV_SIZE(tlvh
));
279 return OSPF_GR_FAILURE
;
282 switch (ntohs(tlvh
->type
)) {
283 case GRACE_PERIOD_TYPE
:
285 sizeof(struct grace_tlv_graceperiod
)) {
286 zlog_debug("%s: Malformed packet: Invalid grace TLV len:%u",
287 __func__
, TLV_SIZE(tlvh
));
288 return OSPF_GR_FAILURE
;
291 grace_period
= (struct grace_tlv_graceperiod
*)tlvh
;
292 *interval
= ntohl(grace_period
->interval
);
293 sum
+= TLV_SIZE(tlvh
);
295 /* Check if grace interval is valid */
296 if (*interval
> OSPF_MAX_GRACE_INTERVAL
297 || *interval
< OSPF_MIN_GRACE_INTERVAL
)
298 return OSPF_GR_FAILURE
;
300 case RESTART_REASON_TYPE
:
302 sizeof(struct grace_tlv_restart_reason
)) {
303 zlog_debug("%s: Malformed packet: Invalid reason TLV len:%u",
304 __func__
, TLV_SIZE(tlvh
));
305 return OSPF_GR_FAILURE
;
308 gr_reason
= (struct grace_tlv_restart_reason
*)tlvh
;
309 *reason
= gr_reason
->reason
;
310 sum
+= TLV_SIZE(tlvh
);
312 if (*reason
>= OSPF_GR_INVALID_REASON_CODE
)
313 return OSPF_GR_FAILURE
;
315 case RESTARTER_IP_ADDR_TYPE
:
317 sizeof(struct grace_tlv_restart_addr
)) {
318 zlog_debug("%s: Malformed packet: Invalid addr TLV len:%u",
319 __func__
, TLV_SIZE(tlvh
));
320 return OSPF_GR_FAILURE
;
323 restart_addr
= (struct grace_tlv_restart_addr
*)tlvh
;
324 addr
->s_addr
= restart_addr
->addr
.s_addr
;
325 sum
+= TLV_SIZE(tlvh
);
328 if (IS_DEBUG_OSPF_GR
)
330 "%s, Malformed packet.Invalid TLV type:%d",
331 __func__
, ntohs(tlvh
->type
));
332 return OSPF_GR_FAILURE
;
336 return OSPF_GR_SUCCESS
;
340 * Grace timer expiry handler.
341 * HELPER aborts its role at grace timer expiry.
349 static void ospf_handle_grace_timer_expiry(struct thread
*thread
)
351 struct ospf_neighbor
*nbr
= THREAD_ARG(thread
);
353 nbr
->gr_helper_info
.t_grace_timer
= NULL
;
355 ospf_gr_helper_exit(nbr
, OSPF_GR_HELPER_GRACE_TIMEOUT
);
359 * Process Grace LSA.If it is eligible move to HELPER role.
360 * Ref rfc3623 section 3.1
366 * Grace LSA received from RESTARTER.
369 * OSPF neighbour which requests the router to act as
374 * If supported as HELPER : OSPF_GR_HELPER_INPROGRESS
375 * If Not supported as HELPER : OSPF_GR_HELPER_NONE
377 int ospf_process_grace_lsa(struct ospf
*ospf
, struct ospf_lsa
*lsa
,
378 struct ospf_neighbor
*nbr
)
380 struct in_addr restart_addr
= {0};
381 uint8_t restart_reason
= 0;
382 uint32_t grace_interval
= 0;
383 uint32_t actual_grace_interval
= 0;
384 struct advRtr lookup
;
385 struct ospf_neighbor
*restarter
= NULL
;
386 struct ospf_interface
*oi
= nbr
->oi
;
390 /* Extract the grace lsa packet fields */
391 ret
= ospf_extract_grace_lsa_fields(lsa
, &grace_interval
, &restart_addr
,
393 if (ret
!= OSPF_GR_SUCCESS
) {
394 if (IS_DEBUG_OSPF_GR
)
395 zlog_debug("%s, Wrong Grace LSA packet.", __func__
);
396 return OSPF_GR_NOT_HELPER
;
399 if (IS_DEBUG_OSPF_GR
)
401 "%s, Grace LSA received from %pI4, grace interval:%u, restart reason:%s",
402 __func__
, &restart_addr
, grace_interval
,
403 ospf_restart_reason2str(restart_reason
));
405 /* In case of broadcast links, if RESTARTER is DR_OTHER,
406 * grace LSA might be received from DR, so need to get
407 * actual neighbour info , here RESTARTER.
409 if (oi
->type
!= OSPF_IFTYPE_POINTOPOINT
) {
410 restarter
= ospf_nbr_lookup_by_addr(oi
->nbrs
, &restart_addr
);
413 if (IS_DEBUG_OSPF_GR
)
415 "%s, Restarter is not a nbr(%pI4) for this router.",
416 __func__
, &restart_addr
);
417 return OSPF_GR_NOT_HELPER
;
422 /* Verify Helper enabled globally */
423 if (!ospf
->is_helper_supported
) {
424 /* Verify that Helper support is enabled for the
425 * current neighbour router-id.
427 lookup
.advRtrAddr
.s_addr
= restarter
->router_id
.s_addr
;
429 if (!hash_lookup(ospf
->enable_rtr_list
, &lookup
)) {
430 if (IS_DEBUG_OSPF_GR
)
432 "%s, HELPER support is disabled, So not a HELPER",
434 restarter
->gr_helper_info
.rejected_reason
=
435 OSPF_HELPER_SUPPORT_DISABLED
;
436 return OSPF_GR_NOT_HELPER
;
441 /* Check neighbour is in FULL state and
442 * became a adjacency.
444 if (!IS_NBR_STATE_FULL(restarter
)) {
445 if (IS_DEBUG_OSPF_GR
)
447 "%s, This Neighbour %pI4 is not in FULL state.",
448 __func__
, &restarter
->src
);
449 restarter
->gr_helper_info
.rejected_reason
=
450 OSPF_HELPER_NOT_A_VALID_NEIGHBOUR
;
451 return OSPF_GR_NOT_HELPER
;
454 /* Based on the restart reason from grace lsa
455 * check the current router is supporting or not
457 if (ospf
->only_planned_restart
458 && !OSPF_GR_IS_PLANNED_RESTART(restart_reason
)) {
459 if (IS_DEBUG_OSPF_GR
)
461 "%s, Router supports only planned restarts but received the GRACE LSA for an unplanned restart.",
463 restarter
->gr_helper_info
.rejected_reason
=
464 OSPF_HELPER_PLANNED_ONLY_RESTART
;
465 return OSPF_GR_NOT_HELPER
;
468 /* Check the retransmission list of this
469 * neighbour, check any change in lsas.
471 if (ospf
->strict_lsa_check
&& !ospf_ls_retransmit_isempty(restarter
)
472 && ospf_check_change_in_rxmt_list(restarter
)) {
473 if (IS_DEBUG_OSPF_GR
)
475 "%s, Changed LSA in Rxmt list. So not Helper.",
477 restarter
->gr_helper_info
.rejected_reason
=
478 OSPF_HELPER_TOPO_CHANGE_RTXMT_LIST
;
479 return OSPF_GR_NOT_HELPER
;
482 /*LSA age must be less than the grace period */
483 if (ntohs(lsa
->data
->ls_age
) >= grace_interval
) {
484 if (IS_DEBUG_OSPF_GR
)
486 "%s, Grace LSA age(%d) is more than the grace interval(%d)",
487 __func__
, lsa
->data
->ls_age
, grace_interval
);
488 restarter
->gr_helper_info
.rejected_reason
=
489 OSPF_HELPER_LSA_AGE_MORE
;
490 return OSPF_GR_NOT_HELPER
;
493 if (ospf
->gr_info
.restart_in_progress
) {
494 if (IS_DEBUG_OSPF_GR
)
496 "%s: router is in the process of graceful restart",
498 restarter
->gr_helper_info
.rejected_reason
=
499 OSPF_HELPER_RESTARTING
;
500 return OSPF_GR_NOT_HELPER
;
503 /* check supported grace period configured
504 * if configured, use this to start the grace
505 * timer otherwise use the interval received
506 * in grace LSA packet.
508 actual_grace_interval
= grace_interval
;
509 if (grace_interval
> ospf
->supported_grace_time
) {
510 if (IS_DEBUG_OSPF_GR
)
512 "%s, Received grace period %d is larger than supported grace %d",
513 __func__
, grace_interval
,
514 ospf
->supported_grace_time
);
515 actual_grace_interval
= ospf
->supported_grace_time
;
518 if (OSPF_GR_IS_ACTIVE_HELPER(restarter
)) {
519 if (restarter
->gr_helper_info
.t_grace_timer
)
520 THREAD_OFF(restarter
->gr_helper_info
.t_grace_timer
);
522 if (ospf
->active_restarter_cnt
> 0)
523 ospf
->active_restarter_cnt
--;
525 if (IS_DEBUG_OSPF_GR
)
527 "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
530 if (IS_DEBUG_OSPF_GR
)
532 "%s, This Router becomes a HELPER for the neighbour %pI4",
533 __func__
, &restarter
->src
);
536 /* Became a Helper to the RESTART neighbour.
537 * Change the helper status.
539 restarter
->gr_helper_info
.gr_helper_status
= OSPF_GR_ACTIVE_HELPER
;
540 restarter
->gr_helper_info
.recvd_grace_period
= grace_interval
;
541 restarter
->gr_helper_info
.actual_grace_period
= actual_grace_interval
;
542 restarter
->gr_helper_info
.gr_restart_reason
= restart_reason
;
543 restarter
->gr_helper_info
.rejected_reason
= OSPF_HELPER_REJECTED_NONE
;
545 /* Increment the active restarter count */
546 ospf
->active_restarter_cnt
++;
548 if (IS_DEBUG_OSPF_GR
)
549 zlog_debug("%s, Grace timer started.interval:%d", __func__
,
550 actual_grace_interval
);
552 /* Start the grace timer */
553 thread_add_timer(master
, ospf_handle_grace_timer_expiry
, restarter
,
554 actual_grace_interval
,
555 &restarter
->gr_helper_info
.t_grace_timer
);
557 return OSPF_GR_ACTIVE_HELPER
;
561 * API to check any change in the neighbor's
562 * retransmission list.
568 * TRUE - if any change in the lsa.
569 * FALSE - no change in the lsas.
571 static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor
*nbr
)
573 struct route_node
*rn
;
574 struct ospf_lsa
*lsa
;
575 struct route_table
*tbl
;
577 tbl
= nbr
->ls_rxmt
.type
[OSPF_ROUTER_LSA
].db
;
578 LSDB_LOOP (tbl
, rn
, lsa
)
579 if (lsa
->to_be_acknowledged
)
581 tbl
= nbr
->ls_rxmt
.type
[OSPF_NETWORK_LSA
].db
;
582 LSDB_LOOP (tbl
, rn
, lsa
)
583 if (lsa
->to_be_acknowledged
)
586 tbl
= nbr
->ls_rxmt
.type
[OSPF_SUMMARY_LSA
].db
;
587 LSDB_LOOP (tbl
, rn
, lsa
)
588 if (lsa
->to_be_acknowledged
)
591 tbl
= nbr
->ls_rxmt
.type
[OSPF_ASBR_SUMMARY_LSA
].db
;
592 LSDB_LOOP (tbl
, rn
, lsa
)
593 if (lsa
->to_be_acknowledged
)
596 tbl
= nbr
->ls_rxmt
.type
[OSPF_AS_EXTERNAL_LSA
].db
;
597 LSDB_LOOP (tbl
, rn
, lsa
)
598 if (lsa
->to_be_acknowledged
)
601 tbl
= nbr
->ls_rxmt
.type
[OSPF_AS_NSSA_LSA
].db
;
602 LSDB_LOOP (tbl
, rn
, lsa
)
603 if (lsa
->to_be_acknowledged
)
606 return OSPF_GR_FALSE
;
610 * Actions to be taken when topo change detected
611 * HELPER will exit upon topo change.
616 * topo change occurred due to this lsa type (1 to 5 and 7)
621 void ospf_helper_handle_topo_chg(struct ospf
*ospf
, struct ospf_lsa
*lsa
)
623 struct listnode
*node
;
624 struct ospf_interface
*oi
;
626 /* Topo change not required to be handled if strict
627 * LSA check is disabled for this router.
629 if (!ospf
->strict_lsa_check
)
632 if (IS_DEBUG_OSPF_GR
)
633 zlog_debug("%s: Topo change detected due to LSA[%s]", __func__
,
636 lsa
->to_be_acknowledged
= OSPF_GR_TRUE
;
638 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
639 struct route_node
*rn
= NULL
;
641 if (ospf_interface_neighbor_count(oi
) == 0)
644 /* Ref rfc3623 section 3.2.3.b
645 * If change due to external LSA and if the area is
646 * stub, then it is not a topo change. Since Type-5
647 * lsas will not be flooded in stub area.
649 if ((oi
->area
->external_routing
== OSPF_AREA_STUB
)
650 && (lsa
->data
->type
== OSPF_AS_EXTERNAL_LSA
)) {
654 for (rn
= route_top(oi
->nbrs
); rn
; rn
= route_next(rn
)) {
655 struct ospf_neighbor
*nbr
= NULL
;
662 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
663 ospf_gr_helper_exit(nbr
,
664 OSPF_GR_HELPER_TOPO_CHG
);
670 * Api to exit from HELPER role to take all actions
672 * Ref rfc3623 section 3.2
678 * OSPF neighbour for which it is acting as HELPER.
681 * The reason for exiting from HELPER.
686 void ospf_gr_helper_exit(struct ospf_neighbor
*nbr
,
687 enum ospf_helper_exit_reason reason
)
689 struct ospf_interface
*oi
= nbr
->oi
;
690 struct ospf
*ospf
= oi
->ospf
;
692 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr
))
695 if (IS_DEBUG_OSPF_GR
)
696 zlog_debug("%s, Exiting from HELPER support to %pI4, due to %s",
697 __func__
, &nbr
->src
, ospf_exit_reason2str(reason
));
699 /* Reset helper status*/
700 nbr
->gr_helper_info
.gr_helper_status
= OSPF_GR_NOT_HELPER
;
701 nbr
->gr_helper_info
.helper_exit_reason
= reason
;
702 nbr
->gr_helper_info
.actual_grace_period
= 0;
703 nbr
->gr_helper_info
.recvd_grace_period
= 0;
704 nbr
->gr_helper_info
.gr_restart_reason
= 0;
705 ospf
->last_exit_reason
= reason
;
707 if (ospf
->active_restarter_cnt
<= 0) {
709 "OSPF GR-Helper: active_restarter_cnt should be greater than zero here.");
712 /* Decrement active Restarter count */
713 ospf
->active_restarter_cnt
--;
715 /* If the exit not triggered due to grace timer
716 * expiry, stop the grace timer.
718 if (reason
!= OSPF_GR_HELPER_GRACE_TIMEOUT
)
719 THREAD_OFF(nbr
->gr_helper_info
.t_grace_timer
);
721 /* check exit triggered due to successful completion
722 * of graceful restart.
724 if (reason
!= OSPF_GR_HELPER_COMPLETED
) {
725 if (IS_DEBUG_OSPF_GR
)
726 zlog_debug("%s, Unsuccessful GR exit", __func__
);
729 /*Recalculate the DR for the network segment */
730 if (oi
->type
== OSPF_IFTYPE_BROADCAST
|| oi
->type
== OSPF_IFTYPE_NBMA
)
731 ospf_dr_election(oi
);
733 /* Originate a router LSA */
734 ospf_router_lsa_update_area(oi
->area
);
736 /* Originate network lsa if it is an DR in the LAN */
737 if (oi
->state
== ISM_DR
)
738 ospf_network_lsa_update(oi
);
742 * Process MaxAge Grace LSA.
743 * It is a indication for successful completion of GR.
744 * If router acting as HELPER, It exits from helper role.
750 * Grace LSA received from RESTARTER.
753 * OSPF neighbour which requests the router to act as
759 void ospf_process_maxage_grace_lsa(struct ospf
*ospf
, struct ospf_lsa
*lsa
,
760 struct ospf_neighbor
*nbr
)
762 struct in_addr restartAddr
= {0};
763 uint8_t restartReason
= 0;
764 uint32_t graceInterval
= 0;
765 struct ospf_neighbor
*restarter
= NULL
;
766 struct ospf_interface
*oi
= nbr
->oi
;
769 /* Extract the grace lsa packet fields */
770 ret
= ospf_extract_grace_lsa_fields(lsa
, &graceInterval
, &restartAddr
,
772 if (ret
!= OSPF_GR_SUCCESS
) {
773 if (IS_DEBUG_OSPF_GR
)
774 zlog_debug("%s, Wrong Grace LSA packet.", __func__
);
778 if (IS_DEBUG_OSPF_GR
)
779 zlog_debug("%s, GraceLSA received for neighbour %pI4", __func__
,
782 /* In case of broadcast links, if RESTARTER is DR_OTHER,
783 * grace LSA might be received from DR, so fetching the
784 * actual neighbour information using restarter address.
786 if (oi
->type
!= OSPF_IFTYPE_POINTOPOINT
) {
787 restarter
= ospf_nbr_lookup_by_addr(oi
->nbrs
, &restartAddr
);
790 if (IS_DEBUG_OSPF_GR
)
792 "%s, Restarter is not a neighbour for this router.",
800 ospf_gr_helper_exit(restarter
, OSPF_GR_HELPER_COMPLETED
);
803 /* Configuration handlers */
805 * Disable/Enable HELPER support on router level.
816 void ospf_gr_helper_support_set(struct ospf
*ospf
, bool support
)
818 struct ospf_interface
*oi
;
819 struct listnode
*node
;
820 struct advRtr lookup
;
822 if (ospf
->is_helper_supported
== support
)
825 ospf
->is_helper_supported
= support
;
827 /* If helper support disabled, cease HELPER role for all
828 * supporting neighbors.
830 if (support
== OSPF_GR_FALSE
) {
831 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
832 struct route_node
*rn
= NULL
;
834 if (ospf_interface_neighbor_count(oi
) == 0)
837 for (rn
= route_top(oi
->nbrs
); rn
;
838 rn
= route_next(rn
)) {
839 struct ospf_neighbor
*nbr
= NULL
;
846 lookup
.advRtrAddr
.s_addr
=
847 nbr
->router_id
.s_addr
;
848 /* check if helper support enabled for the
849 * corresponding routerid.If enabled, don't
850 * exit from helper role.
852 if (hash_lookup(ospf
->enable_rtr_list
, &lookup
))
855 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
857 nbr
, OSPF_GR_HELPER_TOPO_CHG
);
864 * Enable/Disable HELPER support on a specified advertagement
871 * HELPER support for given Advertisement Router.
874 * True - Enable Helper Support.
875 * False - Disable Helper Support.
881 void ospf_gr_helper_support_set_per_routerid(struct ospf
*ospf
,
882 struct in_addr
*advrtr
,
887 struct ospf_interface
*oi
;
888 struct listnode
*node
;
890 temp
.advRtrAddr
.s_addr
= advrtr
->s_addr
;
892 if (support
== OSPF_GR_FALSE
) {
893 /*Delete the routerid from the enable router hash table */
894 rtr
= hash_lookup(ospf
->enable_rtr_list
, &temp
);
897 hash_release(ospf
->enable_rtr_list
, rtr
);
898 ospf_disable_rtr_hash_free(rtr
);
901 /* If helper support is enabled globally
902 * no action is required.
904 if (ospf
->is_helper_supported
)
907 /* Cease the HELPER role fore neighbours from the
908 * specified advertisement router.
910 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
911 struct route_node
*rn
= NULL
;
913 if (ospf_interface_neighbor_count(oi
) == 0)
916 for (rn
= route_top(oi
->nbrs
); rn
;
917 rn
= route_next(rn
)) {
918 struct ospf_neighbor
*nbr
= NULL
;
925 if (nbr
->router_id
.s_addr
!= advrtr
->s_addr
)
928 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
930 nbr
, OSPF_GR_HELPER_TOPO_CHG
);
935 /* Add the routerid to the enable router hash table */
936 hash_get(ospf
->enable_rtr_list
, &temp
,
937 ospf_enable_rtr_hash_alloc
);
942 * Api to enable/disable strict lsa check on the HELPER.
948 * True - disable the lsa check.
949 * False - enable the strict lsa check.
954 void ospf_gr_helper_lsa_check_set(struct ospf
*ospf
, bool enabled
)
956 if (ospf
->strict_lsa_check
== enabled
)
959 ospf
->strict_lsa_check
= enabled
;
963 * Api to set the supported grace interval in this router.
969 * The supported grace interval..
974 void ospf_gr_helper_supported_gracetime_set(struct ospf
*ospf
,
977 ospf
->supported_grace_time
= interval
;
981 * Api to set the supported restart reason.
987 * True: support only planned restart.
988 * False: support for planned/unplanned restarts.
993 void ospf_gr_helper_set_supported_planned_only_restart(struct ospf
*ospf
,
996 ospf
->only_planned_restart
= planned_only
;
1000 * Api to display the grace LSA information.
1012 static void show_ospf_grace_lsa_info(struct vty
*vty
, struct json_object
*json
,
1013 struct ospf_lsa
*lsa
)
1015 struct lsa_header
*lsah
= NULL
;
1016 struct tlv_header
*tlvh
= NULL
;
1017 struct grace_tlv_graceperiod
*gracePeriod
;
1018 struct grace_tlv_restart_reason
*grReason
;
1019 struct grace_tlv_restart_addr
*restartAddr
;
1020 uint16_t length
= 0;
1026 lsah
= (struct lsa_header
*)lsa
->data
;
1028 if (lsa
->size
<= OSPF_LSA_HEADER_SIZE
) {
1030 vty_out(vty
, "%% Invalid LSA length: %d\n", length
);
1032 zlog_debug("%% Invalid LSA length: %d", length
);
1036 length
= lsa
->size
- OSPF_LSA_HEADER_SIZE
;
1039 vty_out(vty
, " TLV info:\n");
1041 zlog_debug(" TLV info:");
1043 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
&& tlvh
;
1044 tlvh
= TLV_HDR_NEXT(tlvh
)) {
1046 if (sum
+ TLV_SIZE(tlvh
) > length
) {
1048 vty_out(vty
, "%% Invalid TLV length: %u\n",
1051 zlog_debug("%% Invalid TLV length: %u",
1056 switch (ntohs(tlvh
->type
)) {
1057 case GRACE_PERIOD_TYPE
:
1059 < sizeof(struct grace_tlv_graceperiod
)) {
1062 "%% Invalid grace TLV length %u\n",
1066 "%% Invalid grace TLV length %u",
1071 gracePeriod
= (struct grace_tlv_graceperiod
*)tlvh
;
1072 sum
+= TLV_SIZE(tlvh
);
1075 vty_out(vty
, " Grace period:%d\n",
1076 ntohl(gracePeriod
->interval
));
1078 zlog_debug(" Grace period:%d",
1079 ntohl(gracePeriod
->interval
));
1081 case RESTART_REASON_TYPE
:
1083 < sizeof(struct grace_tlv_restart_reason
)) {
1086 "%% Invalid reason TLV length %u\n",
1090 "%% Invalid reason TLV length %u",
1095 grReason
= (struct grace_tlv_restart_reason
*)tlvh
;
1096 sum
+= TLV_SIZE(tlvh
);
1099 vty_out(vty
, " Restart reason:%s\n",
1100 ospf_restart_reason2str(
1103 zlog_debug(" Restart reason:%s",
1104 ospf_restart_reason2str(
1107 case RESTARTER_IP_ADDR_TYPE
:
1109 < sizeof(struct grace_tlv_restart_addr
)) {
1112 "%% Invalid addr TLV length %u\n",
1116 "%% Invalid addr TLV length %u",
1121 restartAddr
= (struct grace_tlv_restart_addr
*)tlvh
;
1122 sum
+= TLV_SIZE(tlvh
);
1125 vty_out(vty
, " Restarter address:%pI4\n",
1126 &restartAddr
->addr
);
1128 zlog_debug(" Restarter address:%pI4",
1129 &restartAddr
->addr
);
1133 vty_out(vty
, " Unknown TLV type %d\n",
1136 zlog_debug(" Unknown TLV type %d",