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 int 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
);
356 return OSPF_GR_SUCCESS
;
360 * Process Grace LSA.If it is eligible move to HELPER role.
361 * Ref rfc3623 section 3.1
367 * Grace LSA received from RESTARTER.
370 * OSPF neighbour which requests the router to act as
375 * If supported as HELPER : OSPF_GR_HELPER_INPROGRESS
376 * If Not supported as HELPER : OSPF_GR_HELPER_NONE
378 int ospf_process_grace_lsa(struct ospf
*ospf
, struct ospf_lsa
*lsa
,
379 struct ospf_neighbor
*nbr
)
381 struct in_addr restart_addr
= {0};
382 uint8_t restart_reason
= 0;
383 uint32_t grace_interval
= 0;
384 uint32_t actual_grace_interval
= 0;
385 struct advRtr lookup
;
386 struct ospf_neighbor
*restarter
= NULL
;
387 struct ospf_interface
*oi
= nbr
->oi
;
391 /* Extract the grace lsa packet fields */
392 ret
= ospf_extract_grace_lsa_fields(lsa
, &grace_interval
, &restart_addr
,
394 if (ret
!= OSPF_GR_SUCCESS
) {
395 if (IS_DEBUG_OSPF_GR
)
396 zlog_debug("%s, Wrong Grace LSA packet.", __func__
);
397 return OSPF_GR_NOT_HELPER
;
400 if (IS_DEBUG_OSPF_GR
)
402 "%s, Grace LSA received from %pI4, grace interval:%u, restart reason:%s",
403 __func__
, &restart_addr
, grace_interval
,
404 ospf_restart_reason2str(restart_reason
));
406 /* In case of broadcast links, if RESTARTER is DR_OTHER,
407 * grace LSA might be received from DR, so need to get
408 * actual neighbour info , here RESTARTER.
410 if (oi
->type
!= OSPF_IFTYPE_POINTOPOINT
) {
411 restarter
= ospf_nbr_lookup_by_addr(oi
->nbrs
, &restart_addr
);
414 if (IS_DEBUG_OSPF_GR
)
416 "%s, Restarter is not a nbr(%pI4) for this router.",
417 __func__
, &restart_addr
);
418 return OSPF_GR_NOT_HELPER
;
423 /* Verify Helper enabled globally */
424 if (!ospf
->is_helper_supported
) {
425 /* Verify that Helper support is enabled for the
426 * current neighbour router-id.
428 lookup
.advRtrAddr
.s_addr
= restarter
->router_id
.s_addr
;
430 if (!hash_lookup(ospf
->enable_rtr_list
, &lookup
)) {
431 if (IS_DEBUG_OSPF_GR
)
433 "%s, HELPER support is disabled, So not a HELPER",
435 restarter
->gr_helper_info
.rejected_reason
=
436 OSPF_HELPER_SUPPORT_DISABLED
;
437 return OSPF_GR_NOT_HELPER
;
442 /* Check neighbour is in FULL state and
443 * became a adjacency.
445 if (!IS_NBR_STATE_FULL(restarter
)) {
446 if (IS_DEBUG_OSPF_GR
)
448 "%s, This Neighbour %pI4 is not in FULL state.",
449 __func__
, &restarter
->src
);
450 restarter
->gr_helper_info
.rejected_reason
=
451 OSPF_HELPER_NOT_A_VALID_NEIGHBOUR
;
452 return OSPF_GR_NOT_HELPER
;
455 /* Based on the restart reason from grace lsa
456 * check the current router is supporting or not
458 if (ospf
->only_planned_restart
459 && !OSPF_GR_IS_PLANNED_RESTART(restart_reason
)) {
460 if (IS_DEBUG_OSPF_GR
)
462 "%s, Router supports only planned restarts but received the GRACE LSA for an unplanned restart.",
464 restarter
->gr_helper_info
.rejected_reason
=
465 OSPF_HELPER_PLANNED_ONLY_RESTART
;
466 return OSPF_GR_NOT_HELPER
;
469 /* Check the retransmission list of this
470 * neighbour, check any change in lsas.
472 if (ospf
->strict_lsa_check
&& !ospf_ls_retransmit_isempty(restarter
)
473 && ospf_check_change_in_rxmt_list(restarter
)) {
474 if (IS_DEBUG_OSPF_GR
)
476 "%s, Changed LSA in Rxmt list. So not Helper.",
478 restarter
->gr_helper_info
.rejected_reason
=
479 OSPF_HELPER_TOPO_CHANGE_RTXMT_LIST
;
480 return OSPF_GR_NOT_HELPER
;
483 /*LSA age must be less than the grace period */
484 if (ntohs(lsa
->data
->ls_age
) >= grace_interval
) {
485 if (IS_DEBUG_OSPF_GR
)
487 "%s, Grace LSA age(%d) is more than the grace interval(%d)",
488 __func__
, lsa
->data
->ls_age
, grace_interval
);
489 restarter
->gr_helper_info
.rejected_reason
=
490 OSPF_HELPER_LSA_AGE_MORE
;
491 return OSPF_GR_NOT_HELPER
;
494 if (ospf
->gr_info
.restart_in_progress
) {
495 if (IS_DEBUG_OSPF_GR
)
497 "%s: router is in the process of graceful restart",
499 restarter
->gr_helper_info
.rejected_reason
=
500 OSPF_HELPER_RESTARTING
;
501 return OSPF_GR_NOT_HELPER
;
504 /* check supported grace period configured
505 * if configured, use this to start the grace
506 * timer otherwise use the interval received
507 * in grace LSA packet.
509 actual_grace_interval
= grace_interval
;
510 if (grace_interval
> ospf
->supported_grace_time
) {
511 if (IS_DEBUG_OSPF_GR
)
513 "%s, Received grace period %d is larger than supported grace %d",
514 __func__
, grace_interval
,
515 ospf
->supported_grace_time
);
516 actual_grace_interval
= ospf
->supported_grace_time
;
519 if (OSPF_GR_IS_ACTIVE_HELPER(restarter
)) {
520 if (restarter
->gr_helper_info
.t_grace_timer
)
521 THREAD_OFF(restarter
->gr_helper_info
.t_grace_timer
);
523 if (ospf
->active_restarter_cnt
> 0)
524 ospf
->active_restarter_cnt
--;
526 if (IS_DEBUG_OSPF_GR
)
528 "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
531 if (IS_DEBUG_OSPF_GR
)
533 "%s, This Router becomes a HELPER for the neighbour %pI4",
534 __func__
, &restarter
->src
);
537 /* Became a Helper to the RESTART neighbour.
538 * Change the helper status.
540 restarter
->gr_helper_info
.gr_helper_status
= OSPF_GR_ACTIVE_HELPER
;
541 restarter
->gr_helper_info
.recvd_grace_period
= grace_interval
;
542 restarter
->gr_helper_info
.actual_grace_period
= actual_grace_interval
;
543 restarter
->gr_helper_info
.gr_restart_reason
= restart_reason
;
544 restarter
->gr_helper_info
.rejected_reason
= OSPF_HELPER_REJECTED_NONE
;
546 /* Increment the active restarter count */
547 ospf
->active_restarter_cnt
++;
549 if (IS_DEBUG_OSPF_GR
)
550 zlog_debug("%s, Grace timer started.interval:%d", __func__
,
551 actual_grace_interval
);
553 /* Start the grace timer */
554 thread_add_timer(master
, ospf_handle_grace_timer_expiry
, restarter
,
555 actual_grace_interval
,
556 &restarter
->gr_helper_info
.t_grace_timer
);
558 return OSPF_GR_ACTIVE_HELPER
;
562 * API to check any change in the neighbor's
563 * retransmission list.
569 * TRUE - if any change in the lsa.
570 * FALSE - no change in the lsas.
572 static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor
*nbr
)
574 struct route_node
*rn
;
575 struct ospf_lsa
*lsa
;
576 struct route_table
*tbl
;
578 tbl
= nbr
->ls_rxmt
.type
[OSPF_ROUTER_LSA
].db
;
579 LSDB_LOOP (tbl
, rn
, lsa
)
580 if (lsa
->to_be_acknowledged
)
582 tbl
= nbr
->ls_rxmt
.type
[OSPF_NETWORK_LSA
].db
;
583 LSDB_LOOP (tbl
, rn
, lsa
)
584 if (lsa
->to_be_acknowledged
)
587 tbl
= nbr
->ls_rxmt
.type
[OSPF_SUMMARY_LSA
].db
;
588 LSDB_LOOP (tbl
, rn
, lsa
)
589 if (lsa
->to_be_acknowledged
)
592 tbl
= nbr
->ls_rxmt
.type
[OSPF_ASBR_SUMMARY_LSA
].db
;
593 LSDB_LOOP (tbl
, rn
, lsa
)
594 if (lsa
->to_be_acknowledged
)
597 tbl
= nbr
->ls_rxmt
.type
[OSPF_AS_EXTERNAL_LSA
].db
;
598 LSDB_LOOP (tbl
, rn
, lsa
)
599 if (lsa
->to_be_acknowledged
)
602 tbl
= nbr
->ls_rxmt
.type
[OSPF_AS_NSSA_LSA
].db
;
603 LSDB_LOOP (tbl
, rn
, lsa
)
604 if (lsa
->to_be_acknowledged
)
607 return OSPF_GR_FALSE
;
611 * Actions to be taken when topo change detected
612 * HELPER will exit upon topo change.
617 * topo change occurred due to this lsa type (1 to 5 and 7)
622 void ospf_helper_handle_topo_chg(struct ospf
*ospf
, struct ospf_lsa
*lsa
)
624 struct listnode
*node
;
625 struct ospf_interface
*oi
;
627 /* Topo change not required to be handled if strict
628 * LSA check is disabled for this router.
630 if (!ospf
->strict_lsa_check
)
633 if (IS_DEBUG_OSPF_GR
)
634 zlog_debug("%s: Topo change detected due to LSA[%s]", __func__
,
637 lsa
->to_be_acknowledged
= OSPF_GR_TRUE
;
639 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
640 struct route_node
*rn
= NULL
;
642 if (ospf_interface_neighbor_count(oi
) == 0)
645 /* Ref rfc3623 section 3.2.3.b
646 * If change due to external LSA and if the area is
647 * stub, then it is not a topo change. Since Type-5
648 * lsas will not be flooded in stub area.
650 if ((oi
->area
->external_routing
== OSPF_AREA_STUB
)
651 && (lsa
->data
->type
== OSPF_AS_EXTERNAL_LSA
)) {
655 for (rn
= route_top(oi
->nbrs
); rn
; rn
= route_next(rn
)) {
656 struct ospf_neighbor
*nbr
= NULL
;
663 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
664 ospf_gr_helper_exit(nbr
,
665 OSPF_GR_HELPER_TOPO_CHG
);
671 * Api to exit from HELPER role to take all actions
673 * Ref rfc3623 section 3.2
679 * OSPF neighbour for which it is acting as HELPER.
682 * The reason for exiting from HELPER.
687 void ospf_gr_helper_exit(struct ospf_neighbor
*nbr
,
688 enum ospf_helper_exit_reason reason
)
690 struct ospf_interface
*oi
= nbr
->oi
;
691 struct ospf
*ospf
= oi
->ospf
;
693 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr
))
696 if (IS_DEBUG_OSPF_GR
)
697 zlog_debug("%s, Exiting from HELPER support to %pI4, due to %s",
698 __func__
, &nbr
->src
, ospf_exit_reason2str(reason
));
700 /* Reset helper status*/
701 nbr
->gr_helper_info
.gr_helper_status
= OSPF_GR_NOT_HELPER
;
702 nbr
->gr_helper_info
.helper_exit_reason
= reason
;
703 nbr
->gr_helper_info
.actual_grace_period
= 0;
704 nbr
->gr_helper_info
.recvd_grace_period
= 0;
705 nbr
->gr_helper_info
.gr_restart_reason
= 0;
706 ospf
->last_exit_reason
= reason
;
708 if (ospf
->active_restarter_cnt
<= 0) {
710 "OSPF GR-Helper: active_restarter_cnt should be greater than zero here.");
713 /* Decrement active Restarter count */
714 ospf
->active_restarter_cnt
--;
716 /* If the exit not triggered due to grace timer
717 * expiry, stop the grace timer.
719 if (reason
!= OSPF_GR_HELPER_GRACE_TIMEOUT
)
720 THREAD_OFF(nbr
->gr_helper_info
.t_grace_timer
);
722 /* check exit triggered due to successful completion
723 * of graceful restart.
725 if (reason
!= OSPF_GR_HELPER_COMPLETED
) {
726 if (IS_DEBUG_OSPF_GR
)
727 zlog_debug("%s, Unsuccessful GR exit", __func__
);
730 /*Recalculate the DR for the network segment */
731 if (oi
->type
== OSPF_IFTYPE_BROADCAST
|| oi
->type
== OSPF_IFTYPE_NBMA
)
732 ospf_dr_election(oi
);
734 /* Originate a router LSA */
735 ospf_router_lsa_update_area(oi
->area
);
737 /* Originate network lsa if it is an DR in the LAN */
738 if (oi
->state
== ISM_DR
)
739 ospf_network_lsa_update(oi
);
743 * Process MaxAge Grace LSA.
744 * It is a indication for successful completion of GR.
745 * If router acting as HELPER, It exits from helper role.
751 * Grace LSA received from RESTARTER.
754 * OSPF neighbour which requests the router to act as
760 void ospf_process_maxage_grace_lsa(struct ospf
*ospf
, struct ospf_lsa
*lsa
,
761 struct ospf_neighbor
*nbr
)
763 struct in_addr restartAddr
= {0};
764 uint8_t restartReason
= 0;
765 uint32_t graceInterval
= 0;
766 struct ospf_neighbor
*restarter
= NULL
;
767 struct ospf_interface
*oi
= nbr
->oi
;
770 /* Extract the grace lsa packet fields */
771 ret
= ospf_extract_grace_lsa_fields(lsa
, &graceInterval
, &restartAddr
,
773 if (ret
!= OSPF_GR_SUCCESS
) {
774 if (IS_DEBUG_OSPF_GR
)
775 zlog_debug("%s, Wrong Grace LSA packet.", __func__
);
779 if (IS_DEBUG_OSPF_GR
)
780 zlog_debug("%s, GraceLSA received for neighbour %pI4", __func__
,
783 /* In case of broadcast links, if RESTARTER is DR_OTHER,
784 * grace LSA might be received from DR, so fetching the
785 * actual neighbour information using restarter address.
787 if (oi
->type
!= OSPF_IFTYPE_POINTOPOINT
) {
788 restarter
= ospf_nbr_lookup_by_addr(oi
->nbrs
, &restartAddr
);
791 if (IS_DEBUG_OSPF_GR
)
793 "%s, Restarter is not a neighbour for this router.",
801 ospf_gr_helper_exit(restarter
, OSPF_GR_HELPER_COMPLETED
);
804 /* Configuration handlers */
806 * Disable/Enable HELPER support on router level.
817 void ospf_gr_helper_support_set(struct ospf
*ospf
, bool support
)
819 struct ospf_interface
*oi
;
820 struct listnode
*node
;
821 struct advRtr lookup
;
823 if (ospf
->is_helper_supported
== support
)
826 ospf
->is_helper_supported
= support
;
828 /* If helper support disabled, cease HELPER role for all
829 * supporting neighbors.
831 if (support
== OSPF_GR_FALSE
) {
832 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
833 struct route_node
*rn
= NULL
;
835 if (ospf_interface_neighbor_count(oi
) == 0)
838 for (rn
= route_top(oi
->nbrs
); rn
;
839 rn
= route_next(rn
)) {
840 struct ospf_neighbor
*nbr
= NULL
;
847 lookup
.advRtrAddr
.s_addr
=
848 nbr
->router_id
.s_addr
;
849 /* check if helper support enabled for the
850 * corresponding routerid.If enabled, dont
851 * dont exit from helper role.
853 if (hash_lookup(ospf
->enable_rtr_list
, &lookup
))
856 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
858 nbr
, OSPF_GR_HELPER_TOPO_CHG
);
865 * Enable/Disable HELPER support on a specified advertagement
872 * HELPER support for given Advertisement Router.
875 * True - Enable Helper Support.
876 * False - Disable Helper Support.
882 void ospf_gr_helper_support_set_per_routerid(struct ospf
*ospf
,
883 struct in_addr
*advrtr
,
888 struct ospf_interface
*oi
;
889 struct listnode
*node
;
891 temp
.advRtrAddr
.s_addr
= advrtr
->s_addr
;
893 if (support
== OSPF_GR_FALSE
) {
894 /*Delete the routerid from the enable router hash table */
895 rtr
= hash_lookup(ospf
->enable_rtr_list
, &temp
);
898 hash_release(ospf
->enable_rtr_list
, rtr
);
899 ospf_disable_rtr_hash_free(rtr
);
902 /* If helper support is enabled globally
903 * no action is required.
905 if (ospf
->is_helper_supported
)
908 /* Cease the HELPER role fore neighbours from the
909 * specified advertisement router.
911 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
912 struct route_node
*rn
= NULL
;
914 if (ospf_interface_neighbor_count(oi
) == 0)
917 for (rn
= route_top(oi
->nbrs
); rn
;
918 rn
= route_next(rn
)) {
919 struct ospf_neighbor
*nbr
= NULL
;
926 if (nbr
->router_id
.s_addr
!= advrtr
->s_addr
)
929 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
931 nbr
, OSPF_GR_HELPER_TOPO_CHG
);
936 /* Add the routerid to the enable router hash table */
937 hash_get(ospf
->enable_rtr_list
, &temp
,
938 ospf_enable_rtr_hash_alloc
);
943 * Api to enable/disable strict lsa check on the HELPER.
949 * True - disable the lsa check.
950 * False - enable the strict lsa check.
955 void ospf_gr_helper_lsa_check_set(struct ospf
*ospf
, bool enabled
)
957 if (ospf
->strict_lsa_check
== enabled
)
960 ospf
->strict_lsa_check
= enabled
;
964 * Api to set the supported grace interval in this router.
970 * The supported grace interval..
975 void ospf_gr_helper_supported_gracetime_set(struct ospf
*ospf
,
978 ospf
->supported_grace_time
= interval
;
982 * Api to set the supported restart reason.
988 * True: support only planned restart.
989 * False: support for planned/unplanned restarts.
994 void ospf_gr_helper_set_supported_planned_only_restart(struct ospf
*ospf
,
997 ospf
->only_planned_restart
= planned_only
;
1001 * Api to display the grace LSA information.
1013 static void show_ospf_grace_lsa_info(struct vty
*vty
, struct json_object
*json
,
1014 struct ospf_lsa
*lsa
)
1016 struct lsa_header
*lsah
= NULL
;
1017 struct tlv_header
*tlvh
= NULL
;
1018 struct grace_tlv_graceperiod
*gracePeriod
;
1019 struct grace_tlv_restart_reason
*grReason
;
1020 struct grace_tlv_restart_addr
*restartAddr
;
1021 uint16_t length
= 0;
1027 lsah
= (struct lsa_header
*)lsa
->data
;
1029 if (lsa
->size
<= OSPF_LSA_HEADER_SIZE
) {
1031 vty_out(vty
, "%% Invalid LSA length: %d\n", length
);
1033 zlog_debug("%% Invalid LSA length: %d", length
);
1037 length
= lsa
->size
- OSPF_LSA_HEADER_SIZE
;
1040 vty_out(vty
, " TLV info:\n");
1042 zlog_debug(" TLV info:");
1044 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
&& tlvh
;
1045 tlvh
= TLV_HDR_NEXT(tlvh
)) {
1047 if (sum
+ TLV_SIZE(tlvh
) > length
) {
1049 vty_out(vty
, "%% Invalid TLV length: %u\n",
1052 zlog_debug("%% Invalid TLV length: %u",
1057 switch (ntohs(tlvh
->type
)) {
1058 case GRACE_PERIOD_TYPE
:
1060 < sizeof(struct grace_tlv_graceperiod
)) {
1063 "%% Invalid grace TLV length %u\n",
1067 "%% Invalid grace TLV length %u",
1072 gracePeriod
= (struct grace_tlv_graceperiod
*)tlvh
;
1073 sum
+= TLV_SIZE(tlvh
);
1076 vty_out(vty
, " Grace period:%d\n",
1077 ntohl(gracePeriod
->interval
));
1079 zlog_debug(" Grace period:%d",
1080 ntohl(gracePeriod
->interval
));
1082 case RESTART_REASON_TYPE
:
1084 < sizeof(struct grace_tlv_restart_reason
)) {
1087 "%% Invalid reason TLV length %u\n",
1091 "%% Invalid reason TLV length %u",
1096 grReason
= (struct grace_tlv_restart_reason
*)tlvh
;
1097 sum
+= TLV_SIZE(tlvh
);
1100 vty_out(vty
, " Restart reason:%s\n",
1101 ospf_restart_reason2str(
1104 zlog_debug(" Restart reason:%s",
1105 ospf_restart_reason2str(
1108 case RESTARTER_IP_ADDR_TYPE
:
1110 < sizeof(struct grace_tlv_restart_addr
)) {
1113 "%% Invalid addr TLV length %u\n",
1117 "%% Invalid addr TLV length %u",
1122 restartAddr
= (struct grace_tlv_restart_addr
*)tlvh
;
1123 sum
+= TLV_SIZE(tlvh
);
1126 vty_out(vty
, " Restarter address:%pI4\n",
1127 &restartAddr
->addr
);
1129 zlog_debug(" Restarter address:%pI4",
1130 &restartAddr
->addr
);
1134 vty_out(vty
, " Unknown TLV type %d\n",
1137 zlog_debug(" Unknown TLV type %d",