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_helper.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",
77 static void show_ospf_grace_lsa_info(struct vty
*vty
, struct ospf_lsa
*lsa
);
78 static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor
*nbr
);
80 static unsigned int ospf_enable_rtr_hash_key(const void *data
)
82 const struct advRtr
*rtr
= data
;
84 return jhash_1word(rtr
->advRtrAddr
.s_addr
, 0);
87 static bool ospf_enable_rtr_hash_cmp(const void *d1
, const void *d2
)
89 const struct advRtr
*rtr1
= (struct advRtr
*)d1
;
90 const struct advRtr
*rtr2
= (struct advRtr
*)d2
;
92 return (rtr1
->advRtrAddr
.s_addr
== rtr2
->advRtrAddr
.s_addr
);
95 static void *ospf_enable_rtr_hash_alloc(void *p
)
99 rid
= XCALLOC(MTYPE_OSPF_GR_HELPER
, sizeof(struct advRtr
));
100 rid
->advRtrAddr
.s_addr
= ((struct in_addr
*)p
)->s_addr
;
105 static void ospf_disable_rtr_hash_free(void *rtr
)
107 XFREE(MTYPE_OSPF_GR_HELPER
, rtr
);
110 static void ospf_enable_rtr_hash_destroy(struct ospf
*ospf
)
112 if (ospf
->enable_rtr_list
== NULL
)
115 hash_clean(ospf
->enable_rtr_list
, ospf_disable_rtr_hash_free
);
116 hash_free(ospf
->enable_rtr_list
);
117 ospf
->enable_rtr_list
= NULL
;
121 * GR exit reason strings
123 const char *ospf_exit_reason2str(unsigned int reason
)
125 if (reason
< array_size(ospf_exit_reason_desc
))
126 return(ospf_exit_reason_desc
[reason
]);
128 return "Invalid reason";
132 * GR restart reason strings
134 const char *ospf_restart_reason2str(unsigned int reason
)
136 if (reason
< array_size(ospf_restart_reason_desc
))
137 return(ospf_restart_reason_desc
[reason
]);
139 return "Invalid reason";
143 * GR rejected reason strings
145 const char *ospf_rejected_reason2str(unsigned int reason
)
147 if (reason
< array_size(ospf_rejected_reason_desc
))
148 return(ospf_rejected_reason_desc
[reason
]);
150 return "Invalid reason";
154 * Initialize GR helper config data structures.
162 void ospf_gr_helper_init(struct ospf
*ospf
)
166 if (IS_DEBUG_OSPF_GR_HELPER
)
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");
180 rc
= ospf_register_opaque_functab(
181 OSPF_OPAQUE_LINK_LSA
, OPAQUE_TYPE_GRACE_LSA
, NULL
, NULL
, NULL
,
182 NULL
, NULL
, NULL
, NULL
, show_ospf_grace_lsa_info
, NULL
, NULL
,
185 flog_warn(EC_OSPF_OPAQUE_REGISTRATION
,
186 "%s: Failed to register Grace LSA functions",
192 * De-Initialize GR helper config data structures.
200 void ospf_gr_helper_stop(struct ospf
*ospf
)
203 if (IS_DEBUG_OSPF_GR_HELPER
)
204 zlog_debug("%s, GR helper deinit.", __func__
);
206 ospf_enable_rtr_hash_destroy(ospf
);
208 ospf_delete_opaque_functab(OSPF_OPAQUE_LINK_LSA
, OPAQUE_TYPE_GRACE_LSA
);
212 * Extracting tlv info from GRACE LSA.
218 * interval : grace interval.
219 * addr : RESTARTER address.
220 * reason : Restarting reason.
222 static int ospf_extract_grace_lsa_fields(struct ospf_lsa
*lsa
,
224 struct in_addr
*addr
, uint8_t *reason
)
226 struct lsa_header
*lsah
= NULL
;
227 struct tlv_header
*tlvh
= NULL
;
228 struct grace_tlv_graceperiod
*grace_period
;
229 struct grace_tlv_restart_reason
*gr_reason
;
230 struct grace_tlv_restart_addr
*restart_addr
;
234 lsah
= (struct lsa_header
*)lsa
->data
;
237 if (lsa
->size
<= OSPF_LSA_HEADER_SIZE
) {
238 if (IS_DEBUG_OSPF_GR_HELPER
)
239 zlog_debug("%s: Malformed packet: Invalid LSA len:%d",
241 return OSPF_GR_FAILURE
;
244 length
= lsa
->size
- OSPF_LSA_HEADER_SIZE
;
246 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
&& tlvh
;
247 tlvh
= TLV_HDR_NEXT(tlvh
)) {
249 /* Check TLV len against overall LSA */
250 if (sum
+ TLV_SIZE(tlvh
) > length
) {
251 if (IS_DEBUG_OSPF_GR_HELPER
)
252 zlog_debug("%s: Malformed packet: Invalid TLV len:%u",
253 __func__
, TLV_SIZE(tlvh
));
254 return OSPF_GR_FAILURE
;
257 switch (ntohs(tlvh
->type
)) {
258 case GRACE_PERIOD_TYPE
:
260 sizeof(struct grace_tlv_graceperiod
)) {
261 zlog_debug("%s: Malformed packet: Invalid grace TLV len:%u",
262 __func__
, TLV_SIZE(tlvh
));
263 return OSPF_GR_FAILURE
;
266 grace_period
= (struct grace_tlv_graceperiod
*)tlvh
;
267 *interval
= ntohl(grace_period
->interval
);
268 sum
+= TLV_SIZE(tlvh
);
270 /* Check if grace interval is valid */
271 if (*interval
> OSPF_MAX_GRACE_INTERVAL
272 || *interval
< OSPF_MIN_GRACE_INTERVAL
)
273 return OSPF_GR_FAILURE
;
275 case RESTART_REASON_TYPE
:
277 sizeof(struct grace_tlv_restart_reason
)) {
278 zlog_debug("%s: Malformed packet: Invalid reason TLV len:%u",
279 __func__
, TLV_SIZE(tlvh
));
280 return OSPF_GR_FAILURE
;
283 gr_reason
= (struct grace_tlv_restart_reason
*)tlvh
;
284 *reason
= gr_reason
->reason
;
285 sum
+= TLV_SIZE(tlvh
);
287 if (*reason
>= OSPF_GR_INVALID_REASON_CODE
)
288 return OSPF_GR_FAILURE
;
290 case RESTARTER_IP_ADDR_TYPE
:
292 sizeof(struct grace_tlv_restart_addr
)) {
293 zlog_debug("%s: Malformed packet: Invalid addr TLV len:%u",
294 __func__
, TLV_SIZE(tlvh
));
295 return OSPF_GR_FAILURE
;
298 restart_addr
= (struct grace_tlv_restart_addr
*)tlvh
;
299 addr
->s_addr
= restart_addr
->addr
.s_addr
;
300 sum
+= TLV_SIZE(tlvh
);
303 if (IS_DEBUG_OSPF_GR_HELPER
)
305 "%s, Malformed packet.Invalid TLV type:%d",
306 __func__
, ntohs(tlvh
->type
));
307 return OSPF_GR_FAILURE
;
311 return OSPF_GR_SUCCESS
;
315 * Grace timer expiry handler.
316 * HELPER aborts its role at grace timer expiry.
324 static int ospf_handle_grace_timer_expiry(struct thread
*thread
)
326 struct ospf_neighbor
*nbr
= THREAD_ARG(thread
);
328 nbr
->gr_helper_info
.t_grace_timer
= NULL
;
330 ospf_gr_helper_exit(nbr
, OSPF_GR_HELPER_GRACE_TIMEOUT
);
331 return OSPF_GR_SUCCESS
;
335 * Process Grace LSA.If it is eligible move to HELPER role.
336 * Ref rfc3623 section 3.1
342 * Grace LSA received from RESTARTER.
345 * ospf neighbour which requets the router to act as
350 * If supported as HELPER : OSPF_GR_HELPER_INPROGRESS
351 * If Not supported as HELPER : OSPF_GR_HELPER_NONE
353 int ospf_process_grace_lsa(struct ospf
*ospf
, struct ospf_lsa
*lsa
,
354 struct ospf_neighbor
*nbr
)
356 struct in_addr restart_addr
= {0};
357 uint8_t restart_reason
= 0;
358 uint32_t grace_interval
= 0;
359 uint32_t actual_grace_interval
= 0;
360 struct advRtr lookup
;
361 struct ospf_neighbor
*restarter
= NULL
;
362 struct ospf_interface
*oi
= nbr
->oi
;
366 /* Extract the grace lsa packet fields */
367 ret
= ospf_extract_grace_lsa_fields(lsa
, &grace_interval
, &restart_addr
,
369 if (ret
!= OSPF_GR_SUCCESS
) {
370 if (IS_DEBUG_OSPF_GR_HELPER
)
371 zlog_debug("%s, Wrong Grace LSA packet.", __func__
);
372 return OSPF_GR_NOT_HELPER
;
375 if (IS_DEBUG_OSPF_GR_HELPER
)
377 "%s, Grace LSA received from %pI4, grace interval:%u, restartreason :%s",
378 __func__
, &restart_addr
, grace_interval
,
379 ospf_restart_reason2str(restart_reason
));
381 /* Incase of broadcast links, if RESTARTER is DR_OTHER,
382 * grace LSA might be received from DR, so need to get
383 * actual neighbour info , here RESTARTER.
385 if (oi
->type
!= OSPF_IFTYPE_POINTOPOINT
) {
386 restarter
= ospf_nbr_lookup_by_addr(oi
->nbrs
, &restart_addr
);
389 if (IS_DEBUG_OSPF_GR_HELPER
)
391 "%s, Restarter is not a nbr(%pI4) for this router.",
392 __func__
, &restart_addr
);
393 return OSPF_GR_NOT_HELPER
;
398 /* Verify Helper enabled globally */
399 if (!ospf
->is_helper_supported
) {
400 /* Verify that Helper support is enabled for the
401 * current neighbour router-id.
403 lookup
.advRtrAddr
.s_addr
= restarter
->router_id
.s_addr
;
405 if (!hash_lookup(ospf
->enable_rtr_list
, &lookup
)) {
406 if (IS_DEBUG_OSPF_GR_HELPER
)
408 "%s, HELPER support is disabled, So not a HELPER",
410 restarter
->gr_helper_info
.rejected_reason
=
411 OSPF_HELPER_SUPPORT_DISABLED
;
412 return OSPF_GR_NOT_HELPER
;
417 /* Check neighbour is in FULL state and
418 * became a adjacency.
420 if (!IS_NBR_STATE_FULL(restarter
)) {
421 if (IS_DEBUG_OSPF_GR_HELPER
)
423 "%s, This Neighbour %pI4 is not in FULL state.",
424 __func__
, &restarter
->src
);
425 restarter
->gr_helper_info
.rejected_reason
=
426 OSPF_HELPER_NOT_A_VALID_NEIGHBOUR
;
427 return OSPF_GR_NOT_HELPER
;
430 /* Based on the restart reason from grace lsa
431 * check the current router is supporting or not
433 if (ospf
->only_planned_restart
434 && !OSPF_GR_IS_PLANNED_RESTART(restart_reason
)) {
435 if (IS_DEBUG_OSPF_GR_HELPER
)
437 "%s, Router supports only planned restarts but received the GRACE LSA for an unplanned restart.",
439 restarter
->gr_helper_info
.rejected_reason
=
440 OSPF_HELPER_PLANNED_ONLY_RESTART
;
441 return OSPF_GR_NOT_HELPER
;
444 /* Check the retranmission list of this
445 * neighbour, check any change in lsas.
447 if (ospf
->strict_lsa_check
&& !ospf_ls_retransmit_isempty(restarter
)
448 && ospf_check_change_in_rxmt_list(restarter
)) {
449 if (IS_DEBUG_OSPF_GR_HELPER
)
451 "%s, Changed LSA in Rxmt list. So not Helper.",
453 restarter
->gr_helper_info
.rejected_reason
=
454 OSPF_HELPER_TOPO_CHANGE_RTXMT_LIST
;
455 return OSPF_GR_NOT_HELPER
;
458 /*LSA age must be less than the grace period */
459 if (ntohs(lsa
->data
->ls_age
) >= grace_interval
) {
460 if (IS_DEBUG_OSPF_GR_HELPER
)
462 "%s, Grace LSA age(%d) is more than the graceinterval(%d)",
463 __func__
, lsa
->data
->ls_age
, grace_interval
);
464 restarter
->gr_helper_info
.rejected_reason
=
465 OSPF_HELPER_LSA_AGE_MORE
;
466 return OSPF_GR_NOT_HELPER
;
469 /* check supported grace period configured
470 * if configured, use this to start the grace
471 * timer otherwise use the interval received
472 * in grace LSA packet.
474 actual_grace_interval
= grace_interval
;
475 if (grace_interval
> ospf
->supported_grace_time
) {
476 if (IS_DEBUG_OSPF_GR_HELPER
)
478 "%s, Received grace period %d is larger than supported grace %d",
479 __func__
, grace_interval
,
480 ospf
->supported_grace_time
);
481 actual_grace_interval
= ospf
->supported_grace_time
;
484 if (OSPF_GR_IS_ACTIVE_HELPER(restarter
)) {
485 if (restarter
->gr_helper_info
.t_grace_timer
)
486 THREAD_OFF(restarter
->gr_helper_info
.t_grace_timer
);
488 if (ospf
->active_restarter_cnt
> 0)
489 ospf
->active_restarter_cnt
--;
491 if (IS_DEBUG_OSPF_GR_HELPER
)
493 "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
496 if (IS_DEBUG_OSPF_GR_HELPER
)
498 "%s, This Router becomes a HELPER for the neighbour %pI4",
499 __func__
, &restarter
->src
);
502 /* Became a Helper to the RESTART neighbour.
503 * Change the helper status.
505 restarter
->gr_helper_info
.gr_helper_status
= OSPF_GR_ACTIVE_HELPER
;
506 restarter
->gr_helper_info
.recvd_grace_period
= grace_interval
;
507 restarter
->gr_helper_info
.actual_grace_period
= actual_grace_interval
;
508 restarter
->gr_helper_info
.gr_restart_reason
= restart_reason
;
509 restarter
->gr_helper_info
.rejected_reason
= OSPF_HELPER_REJECTED_NONE
;
511 /* Incremnet the active restarer count */
512 ospf
->active_restarter_cnt
++;
514 if (IS_DEBUG_OSPF_GR_HELPER
)
515 zlog_debug("%s, Grace timer started.interval:%d", __func__
,
516 actual_grace_interval
);
518 /* Start the grace timer */
519 thread_add_timer(master
, ospf_handle_grace_timer_expiry
, restarter
,
520 actual_grace_interval
,
521 &restarter
->gr_helper_info
.t_grace_timer
);
523 return OSPF_GR_ACTIVE_HELPER
;
527 * API to check any change in the neighbor's
528 * retransmission list.
534 * TRUE - if any change in the lsa.
535 * FALSE - no change in the lsas.
537 static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor
*nbr
)
539 struct route_node
*rn
;
540 struct ospf_lsa
*lsa
;
541 struct route_table
*tbl
;
543 tbl
= nbr
->ls_rxmt
.type
[OSPF_ROUTER_LSA
].db
;
544 LSDB_LOOP (tbl
, rn
, lsa
)
545 if (lsa
->to_be_acknowledged
)
547 tbl
= nbr
->ls_rxmt
.type
[OSPF_NETWORK_LSA
].db
;
548 LSDB_LOOP (tbl
, rn
, lsa
)
549 if (lsa
->to_be_acknowledged
)
552 tbl
= nbr
->ls_rxmt
.type
[OSPF_SUMMARY_LSA
].db
;
553 LSDB_LOOP (tbl
, rn
, lsa
)
554 if (lsa
->to_be_acknowledged
)
557 tbl
= nbr
->ls_rxmt
.type
[OSPF_ASBR_SUMMARY_LSA
].db
;
558 LSDB_LOOP (tbl
, rn
, lsa
)
559 if (lsa
->to_be_acknowledged
)
562 tbl
= nbr
->ls_rxmt
.type
[OSPF_AS_EXTERNAL_LSA
].db
;
563 LSDB_LOOP (tbl
, rn
, lsa
)
564 if (lsa
->to_be_acknowledged
)
567 tbl
= nbr
->ls_rxmt
.type
[OSPF_AS_NSSA_LSA
].db
;
568 LSDB_LOOP (tbl
, rn
, lsa
)
569 if (lsa
->to_be_acknowledged
)
572 return OSPF_GR_FALSE
;
576 * Actions to be taken when topo change detected
577 * HELPER will exit upon topo change.
582 * topo change occured due to this lsa type (1 to 5 and 7)
587 void ospf_helper_handle_topo_chg(struct ospf
*ospf
, struct ospf_lsa
*lsa
)
589 struct listnode
*node
;
590 struct ospf_interface
*oi
;
592 if (!ospf
->active_restarter_cnt
)
595 /* Topo change not required to be handled if strict
596 * LSA check is disbaled for this router.
598 if (!ospf
->strict_lsa_check
)
601 if (IS_DEBUG_OSPF_GR_HELPER
)
603 "%s, Topo change detected due to lsa LSID:%pI4 type:%d",
604 __func__
, &lsa
->data
->id
, lsa
->data
->type
);
606 lsa
->to_be_acknowledged
= OSPF_GR_TRUE
;
608 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
609 struct route_node
*rn
= NULL
;
611 if (ospf_interface_neighbor_count(oi
) == 0)
614 /* Ref rfc3623 section 3.2.3.b
615 * If change due to external LSA and if the area is
616 * stub, then it is not a topo change. Since Type-5
617 * lsas will not be flooded in stub area.
619 if ((oi
->area
->external_routing
== OSPF_AREA_STUB
)
620 && (lsa
->data
->type
== OSPF_AS_EXTERNAL_LSA
)) {
624 for (rn
= route_top(oi
->nbrs
); rn
; rn
= route_next(rn
)) {
625 struct ospf_neighbor
*nbr
= NULL
;
632 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
633 ospf_gr_helper_exit(nbr
,
634 OSPF_GR_HELPER_TOPO_CHG
);
640 * Api to exit from HELPER role to take all actions
642 * Ref rfc3623 section 3.2
648 * OSPF neighbour for which it is acting as HELPER.
651 * The reason for exiting from HELPER.
656 void ospf_gr_helper_exit(struct ospf_neighbor
*nbr
,
657 enum ospf_helper_exit_reason reason
)
659 struct ospf_interface
*oi
= nbr
->oi
;
660 struct ospf
*ospf
= oi
->ospf
;
662 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr
))
665 if (IS_DEBUG_OSPF_GR_HELPER
)
666 zlog_debug("%s, Exiting from HELPER support to %pI4, due to %s",
667 __func__
, &nbr
->src
, ospf_exit_reason2str(reason
));
669 /* Reset helper status*/
670 nbr
->gr_helper_info
.gr_helper_status
= OSPF_GR_NOT_HELPER
;
671 nbr
->gr_helper_info
.helper_exit_reason
= reason
;
672 nbr
->gr_helper_info
.actual_grace_period
= 0;
673 nbr
->gr_helper_info
.recvd_grace_period
= 0;
674 nbr
->gr_helper_info
.gr_restart_reason
= 0;
675 ospf
->last_exit_reason
= reason
;
677 if (ospf
->active_restarter_cnt
<= 0) {
679 "OSPF GR-Helper: active_restarter_cnt should be greater than zero here.");
682 /* Decrement active Restarter count */
683 ospf
->active_restarter_cnt
--;
685 /* If the exit not triggered due to grace timer
686 * expairy , stop the grace timer.
688 if (reason
!= OSPF_GR_HELPER_GRACE_TIMEOUT
)
689 THREAD_OFF(nbr
->gr_helper_info
.t_grace_timer
);
691 /* check exit triggered due to successful completion
692 * of graceful restart.
693 * If no, bringdown the neighbour.
695 if (reason
!= OSPF_GR_HELPER_COMPLETED
) {
696 if (IS_DEBUG_OSPF_GR_HELPER
)
698 "%s, Failed GR exit, so bringing down the neighbour",
700 OSPF_NSM_EVENT_EXECUTE(nbr
, NSM_KillNbr
);
703 /*Recalculate the DR for the network segment */
704 ospf_dr_election(oi
);
706 /* Originate a router LSA */
707 ospf_router_lsa_update_area(oi
->area
);
709 /* Originate network lsa if it is an DR in the LAN */
710 if (oi
->state
== ISM_DR
)
711 ospf_network_lsa_update(oi
);
715 * Process Maxage Grace LSA.
716 * It is a indication for successful completion of GR.
717 * If router acting as HELPER, It exits from helper role.
723 * Grace LSA received from RESTARTER.
726 * ospf neighbour which requets the router to act as
732 void ospf_process_maxage_grace_lsa(struct ospf
*ospf
, struct ospf_lsa
*lsa
,
733 struct ospf_neighbor
*nbr
)
735 struct in_addr restartAddr
= {0};
736 uint8_t restartReason
= 0;
737 uint32_t graceInterval
= 0;
738 struct ospf_neighbor
*restarter
= NULL
;
739 struct ospf_interface
*oi
= nbr
->oi
;
742 /* Extract the grace lsa packet fields */
743 ret
= ospf_extract_grace_lsa_fields(lsa
, &graceInterval
, &restartAddr
,
745 if (ret
!= OSPF_GR_SUCCESS
) {
746 if (IS_DEBUG_OSPF_GR_HELPER
)
747 zlog_debug("%s, Wrong Grace LSA packet.", __func__
);
751 if (IS_DEBUG_OSPF_GR_HELPER
)
752 zlog_debug("%s, GraceLSA received for neighbour %pI4", __func__
,
755 /* In case of broadcast links, if RESTARTER is DR_OTHER,
756 * grace LSA might be received from DR, so fetching the
757 * actual neighbour information using restarter address.
759 if (oi
->type
!= OSPF_IFTYPE_POINTOPOINT
) {
760 restarter
= ospf_nbr_lookup_by_addr(oi
->nbrs
, &restartAddr
);
763 if (IS_DEBUG_OSPF_GR_HELPER
)
765 "%s, Restarter is not a neighbour for this router.",
773 ospf_gr_helper_exit(restarter
, OSPF_GR_HELPER_COMPLETED
);
776 /* Configuration handlers */
778 * Disable/Enable HELPER support on router level.
789 void ospf_gr_helper_support_set(struct ospf
*ospf
, bool support
)
791 struct ospf_interface
*oi
;
792 struct listnode
*node
;
793 struct advRtr lookup
;
795 if (ospf
->is_helper_supported
== support
)
798 ospf
->is_helper_supported
= support
;
800 /* If helper support disabled, cease HELPER role for all
801 * supporting neighbors.
803 if (support
== OSPF_GR_FALSE
) {
804 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
805 struct route_node
*rn
= NULL
;
807 if (ospf_interface_neighbor_count(oi
) == 0)
810 for (rn
= route_top(oi
->nbrs
); rn
;
811 rn
= route_next(rn
)) {
812 struct ospf_neighbor
*nbr
= NULL
;
819 lookup
.advRtrAddr
.s_addr
=
820 nbr
->router_id
.s_addr
;
821 /* check if helper support enabled for the
822 * correspodning routerid.If enabled, dont
823 * dont exit from helper role.
825 if (hash_lookup(ospf
->enable_rtr_list
, &lookup
))
828 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
830 nbr
, OSPF_GR_HELPER_TOPO_CHG
);
837 * Enable/Disable HELPER support on a specified advertagement
844 * HELPER support for given Advertisement Router.
847 * True - Enable Helper Support.
848 * False - Disable Helper Support.
854 void ospf_gr_helper_support_set_per_routerid(struct ospf
*ospf
,
855 struct in_addr
*advrtr
,
860 struct ospf_interface
*oi
;
861 struct listnode
*node
;
863 temp
.advRtrAddr
.s_addr
= advrtr
->s_addr
;
865 if (support
== OSPF_GR_FALSE
) {
866 /*Delete the routerid from the enable router hash table */
867 rtr
= hash_lookup(ospf
->enable_rtr_list
, &temp
);
870 hash_release(ospf
->enable_rtr_list
, rtr
);
871 ospf_disable_rtr_hash_free(rtr
);
874 /* If helper support is enabled globally
875 * no action is required.
877 if (ospf
->is_helper_supported
)
880 /* Cease the HELPER role fore neighbours from the
881 * specified advertisement router.
883 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
884 struct route_node
*rn
= NULL
;
886 if (ospf_interface_neighbor_count(oi
) == 0)
889 for (rn
= route_top(oi
->nbrs
); rn
;
890 rn
= route_next(rn
)) {
891 struct ospf_neighbor
*nbr
= NULL
;
898 if (nbr
->router_id
.s_addr
!= advrtr
->s_addr
)
901 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
903 nbr
, OSPF_GR_HELPER_TOPO_CHG
);
908 /* Add the routerid to the enable router hash table */
909 hash_get(ospf
->enable_rtr_list
, &temp
,
910 ospf_enable_rtr_hash_alloc
);
915 * Api to enable/disable strict lsa check on the HELPER.
921 * True - disable the lsa check.
922 * False - enable the strict lsa check.
927 void ospf_gr_helper_lsa_check_set(struct ospf
*ospf
, bool enabled
)
929 if (ospf
->strict_lsa_check
== enabled
)
932 ospf
->strict_lsa_check
= enabled
;
936 * Api to set the supported grace interval in this router.
942 * The supported grace interval..
947 void ospf_gr_helper_supported_gracetime_set(struct ospf
*ospf
,
950 ospf
->supported_grace_time
= interval
;
954 * Api to set the supported restart reason.
960 * True: support only planned restart.
961 * False: support for planned/unplanned restarts.
966 void ospf_gr_helper_set_supported_planned_only_restart(struct ospf
*ospf
,
969 ospf
->only_planned_restart
= planned_only
;
973 * Api to display the grace LSA information.
985 static void show_ospf_grace_lsa_info(struct vty
*vty
, struct ospf_lsa
*lsa
)
987 struct lsa_header
*lsah
= NULL
;
988 struct tlv_header
*tlvh
= NULL
;
989 struct grace_tlv_graceperiod
*gracePeriod
;
990 struct grace_tlv_restart_reason
*grReason
;
991 struct grace_tlv_restart_addr
*restartAddr
;
995 lsah
= (struct lsa_header
*)lsa
->data
;
997 if (lsa
->size
<= OSPF_LSA_HEADER_SIZE
) {
998 vty_out(vty
, "%% Invalid LSA length: %d\n", length
);
1002 length
= lsa
->size
- OSPF_LSA_HEADER_SIZE
;
1004 vty_out(vty
, " TLV info:\n");
1006 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
&& tlvh
;
1007 tlvh
= TLV_HDR_NEXT(tlvh
)) {
1009 if (sum
+ TLV_SIZE(tlvh
) > length
) {
1010 vty_out(vty
, "%% Invalid TLV length: %u\n",
1015 switch (ntohs(tlvh
->type
)) {
1016 case GRACE_PERIOD_TYPE
:
1017 if (TLV_SIZE(tlvh
) <
1018 sizeof(struct grace_tlv_graceperiod
)) {
1020 "%% Invalid grace TLV length %u\n",
1025 gracePeriod
= (struct grace_tlv_graceperiod
*)tlvh
;
1026 sum
+= TLV_SIZE(tlvh
);
1028 vty_out(vty
, " Grace period:%d\n",
1029 ntohl(gracePeriod
->interval
));
1031 case RESTART_REASON_TYPE
:
1032 if (TLV_SIZE(tlvh
) <
1033 sizeof(struct grace_tlv_restart_reason
)) {
1035 "%% Invalid reason TLV length %u\n",
1040 grReason
= (struct grace_tlv_restart_reason
*)tlvh
;
1041 sum
+= TLV_SIZE(tlvh
);
1043 vty_out(vty
, " Restart reason:%s\n",
1044 ospf_restart_reason2str(grReason
->reason
));
1046 case RESTARTER_IP_ADDR_TYPE
:
1047 if (TLV_SIZE(tlvh
) <
1048 sizeof(struct grace_tlv_restart_addr
)) {
1050 "%% Invalid addr TLV length %u\n",
1055 restartAddr
= (struct grace_tlv_restart_addr
*)tlvh
;
1056 sum
+= TLV_SIZE(tlvh
);
1058 vty_out(vty
, " Restarter address:%pI4\n",
1059 &restartAddr
->addr
);
1062 vty_out(vty
, " Unknown TLV type %d\n",