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.", __PRETTY_FUNCTION__
);
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.", __PRETTY_FUNCTION__
);
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
;
236 length
= ntohs(lsah
->length
);
239 if (length
<= OSPF_LSA_HEADER_SIZE
) {
240 if (IS_DEBUG_OSPF_GR_HELPER
)
241 zlog_debug("%s: Malformed packet: Invalid LSA len:%d",
243 return OSPF_GR_FAILURE
;
246 length
-= OSPF_LSA_HEADER_SIZE
;
248 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
;
249 tlvh
= TLV_HDR_NEXT(tlvh
)) {
251 /* Check TLV len against overall LSA */
252 if (sum
+ TLV_SIZE(tlvh
) > length
) {
253 if (IS_DEBUG_OSPF_GR_HELPER
)
254 zlog_debug("%s: Malformed packet: Invalid TLV len:%u",
255 __func__
, TLV_SIZE(tlvh
));
256 return OSPF_GR_FAILURE
;
259 switch (ntohs(tlvh
->type
)) {
260 case GRACE_PERIOD_TYPE
:
262 sizeof(struct grace_tlv_graceperiod
)) {
263 zlog_debug("%s: Malformed packet: Invalid grace TLV len:%u",
264 __func__
, TLV_SIZE(tlvh
));
265 return OSPF_GR_FAILURE
;
268 grace_period
= (struct grace_tlv_graceperiod
*)tlvh
;
269 *interval
= ntohl(grace_period
->interval
);
270 sum
+= TLV_SIZE(tlvh
);
272 /* Check if grace interval is valid */
273 if (*interval
> OSPF_MAX_GRACE_INTERVAL
274 || *interval
< OSPF_MIN_GRACE_INTERVAL
)
275 return OSPF_GR_FAILURE
;
277 case RESTART_REASON_TYPE
:
279 sizeof(struct grace_tlv_restart_reason
)) {
280 zlog_debug("%s: Malformed packet: Invalid reason TLV len:%u",
281 __func__
, TLV_SIZE(tlvh
));
282 return OSPF_GR_FAILURE
;
285 gr_reason
= (struct grace_tlv_restart_reason
*)tlvh
;
286 *reason
= gr_reason
->reason
;
287 sum
+= TLV_SIZE(tlvh
);
289 if (*reason
>= OSPF_GR_INVALID_REASON_CODE
)
290 return OSPF_GR_FAILURE
;
292 case RESTARTER_IP_ADDR_TYPE
:
294 sizeof(struct grace_tlv_restart_addr
)) {
295 zlog_debug("%s: Malformed packet: Invalid addr TLV len:%u",
296 __func__
, TLV_SIZE(tlvh
));
297 return OSPF_GR_FAILURE
;
300 restart_addr
= (struct grace_tlv_restart_addr
*)tlvh
;
301 addr
->s_addr
= restart_addr
->addr
.s_addr
;
302 sum
+= TLV_SIZE(tlvh
);
305 if (IS_DEBUG_OSPF_GR_HELPER
)
307 "%s, Malformed packet.Invalid TLV type:%d",
308 __PRETTY_FUNCTION__
, ntohs(tlvh
->type
));
309 return OSPF_GR_FAILURE
;
313 return OSPF_GR_SUCCESS
;
317 * Grace timer expiry handler.
318 * HELPER aborts its role at grace timer expiry.
326 static int ospf_handle_grace_timer_expiry(struct thread
*thread
)
328 struct ospf_neighbor
*nbr
= THREAD_ARG(thread
);
330 nbr
->gr_helper_info
.t_grace_timer
= NULL
;
332 ospf_gr_helper_exit(nbr
, OSPF_GR_HELPER_GRACE_TIMEOUT
);
333 return OSPF_GR_SUCCESS
;
337 * Process Grace LSA.If it is eligible move to HELPER role.
338 * Ref rfc3623 section 3.1
344 * Grace LSA received from RESTARTER.
347 * ospf neighbour which requets the router to act as
352 * If supported as HELPER : OSPF_GR_HELPER_INPROGRESS
353 * If Not supported as HELPER : OSPF_GR_HELPER_NONE
355 int ospf_process_grace_lsa(struct ospf
*ospf
, struct ospf_lsa
*lsa
,
356 struct ospf_neighbor
*nbr
)
358 struct in_addr restart_addr
= {0};
359 uint8_t restart_reason
= 0;
360 uint32_t grace_interval
= 0;
361 uint32_t actual_grace_interval
= 0;
362 struct advRtr lookup
;
363 struct ospf_neighbor
*restarter
= NULL
;
364 struct ospf_interface
*oi
= nbr
->oi
;
368 /* Extract the grace lsa packet fields */
369 ret
= ospf_extract_grace_lsa_fields(lsa
, &grace_interval
, &restart_addr
,
371 if (ret
!= OSPF_GR_SUCCESS
) {
372 if (IS_DEBUG_OSPF_GR_HELPER
)
373 zlog_debug("%s, Wrong Grace LSA packet.",
374 __PRETTY_FUNCTION__
);
375 return OSPF_GR_NOT_HELPER
;
378 if (IS_DEBUG_OSPF_GR_HELPER
)
380 "%s, Grace LSA received from %pI4, grace interval:%u, restartreason :%s",
381 __PRETTY_FUNCTION__
, &restart_addr
,
383 ospf_restart_reason2str(restart_reason
));
385 /* Incase of broadcast links, if RESTARTER is DR_OTHER,
386 * grace LSA might be received from DR, so need to get
387 * actual neighbour info , here RESTARTER.
389 if (oi
->type
!= OSPF_IFTYPE_POINTOPOINT
) {
390 restarter
= ospf_nbr_lookup_by_addr(oi
->nbrs
, &restart_addr
);
393 if (IS_DEBUG_OSPF_GR_HELPER
)
395 "%s, Restarter is not a nbr(%pI4) for this router.",
398 return OSPF_GR_NOT_HELPER
;
403 /* Verify Helper enabled globally */
404 if (!ospf
->is_helper_supported
) {
405 /* Verify that Helper support is enabled for the
406 * current neighbour router-id.
408 lookup
.advRtrAddr
.s_addr
= restarter
->router_id
.s_addr
;
410 if (!hash_lookup(ospf
->enable_rtr_list
, &lookup
)) {
411 if (IS_DEBUG_OSPF_GR_HELPER
)
413 "%s, HELPER support is disabled, So not a HELPER",
414 __PRETTY_FUNCTION__
);
415 restarter
->gr_helper_info
.rejected_reason
=
416 OSPF_HELPER_SUPPORT_DISABLED
;
417 return OSPF_GR_NOT_HELPER
;
422 /* Check neighbour is in FULL state and
423 * became a adjacency.
425 if (!IS_NBR_STATE_FULL(restarter
)) {
426 if (IS_DEBUG_OSPF_GR_HELPER
)
428 "%s, This Neighbour %pI4 is not in FULL state.",
429 __PRETTY_FUNCTION__
, &restarter
->src
);
430 restarter
->gr_helper_info
.rejected_reason
=
431 OSPF_HELPER_NOT_A_VALID_NEIGHBOUR
;
432 return OSPF_GR_NOT_HELPER
;
435 /* Based on the restart reason from grace lsa
436 * check the current router is supporting or not
438 if (ospf
->only_planned_restart
439 && !OSPF_GR_IS_PLANNED_RESTART(restart_reason
)) {
440 if (IS_DEBUG_OSPF_GR_HELPER
)
442 "%s, Router supports only planned restarts but received the GRACE LSA for an unplanned restart.",
443 __PRETTY_FUNCTION__
);
444 restarter
->gr_helper_info
.rejected_reason
=
445 OSPF_HELPER_PLANNED_ONLY_RESTART
;
446 return OSPF_GR_NOT_HELPER
;
449 /* Check the retranmission list of this
450 * neighbour, check any change in lsas.
452 if (ospf
->strict_lsa_check
&& !ospf_ls_retransmit_isempty(restarter
)
453 && ospf_check_change_in_rxmt_list(restarter
)) {
454 if (IS_DEBUG_OSPF_GR_HELPER
)
456 "%s, Changed LSA in Rxmt list. So not Helper.",
457 __PRETTY_FUNCTION__
);
458 restarter
->gr_helper_info
.rejected_reason
=
459 OSPF_HELPER_TOPO_CHANGE_RTXMT_LIST
;
460 return OSPF_GR_NOT_HELPER
;
463 /*LSA age must be less than the grace period */
464 if (ntohs(lsa
->data
->ls_age
) >= grace_interval
) {
465 if (IS_DEBUG_OSPF_GR_HELPER
)
467 "%s, Grace LSA age(%d) is more than the graceinterval(%d)",
468 __PRETTY_FUNCTION__
, lsa
->data
->ls_age
,
470 restarter
->gr_helper_info
.rejected_reason
=
471 OSPF_HELPER_LSA_AGE_MORE
;
472 return OSPF_GR_NOT_HELPER
;
475 /* check supported grace period configured
476 * if configured, use this to start the grace
477 * timer otherwise use the interval received
478 * in grace LSA packet.
480 actual_grace_interval
= grace_interval
;
481 if (grace_interval
> ospf
->supported_grace_time
) {
482 if (IS_DEBUG_OSPF_GR_HELPER
)
484 "%s, Received grace period %d is larger than supported grace %d",
485 __PRETTY_FUNCTION__
, grace_interval
,
486 ospf
->supported_grace_time
);
487 actual_grace_interval
= ospf
->supported_grace_time
;
490 if (OSPF_GR_IS_ACTIVE_HELPER(restarter
)) {
491 if (restarter
->gr_helper_info
.t_grace_timer
)
492 THREAD_OFF(restarter
->gr_helper_info
.t_grace_timer
);
494 if (ospf
->active_restarter_cnt
> 0)
495 ospf
->active_restarter_cnt
--;
497 if (IS_DEBUG_OSPF_GR_HELPER
)
499 "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
500 __PRETTY_FUNCTION__
);
502 if (IS_DEBUG_OSPF_GR_HELPER
)
504 "%s, This Router becomes a HELPER for the neighbour %pI4",
505 __PRETTY_FUNCTION__
, &restarter
->src
);
508 /* Became a Helper to the RESTART neighbour.
509 * Change the helper status.
511 restarter
->gr_helper_info
.gr_helper_status
= OSPF_GR_ACTIVE_HELPER
;
512 restarter
->gr_helper_info
.recvd_grace_period
= grace_interval
;
513 restarter
->gr_helper_info
.actual_grace_period
= actual_grace_interval
;
514 restarter
->gr_helper_info
.gr_restart_reason
= restart_reason
;
515 restarter
->gr_helper_info
.rejected_reason
= OSPF_HELPER_REJECTED_NONE
;
517 /* Incremnet the active restarer count */
518 ospf
->active_restarter_cnt
++;
520 if (IS_DEBUG_OSPF_GR_HELPER
)
521 zlog_debug("%s, Grace timer started.interval:%d",
522 __PRETTY_FUNCTION__
, actual_grace_interval
);
524 /* Start the grace timer */
525 thread_add_timer(master
, ospf_handle_grace_timer_expiry
, restarter
,
526 actual_grace_interval
,
527 &restarter
->gr_helper_info
.t_grace_timer
);
529 return OSPF_GR_ACTIVE_HELPER
;
533 * API to check any change in the neighbor's
534 * retransmission list.
540 * TRUE - if any change in the lsa.
541 * FALSE - no change in the lsas.
543 static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor
*nbr
)
545 struct route_node
*rn
;
546 struct ospf_lsa
*lsa
;
547 struct route_table
*tbl
;
549 tbl
= nbr
->ls_rxmt
.type
[OSPF_ROUTER_LSA
].db
;
550 LSDB_LOOP (tbl
, rn
, lsa
)
551 if (lsa
->to_be_acknowledged
)
553 tbl
= nbr
->ls_rxmt
.type
[OSPF_NETWORK_LSA
].db
;
554 LSDB_LOOP (tbl
, rn
, lsa
)
555 if (lsa
->to_be_acknowledged
)
558 tbl
= nbr
->ls_rxmt
.type
[OSPF_SUMMARY_LSA
].db
;
559 LSDB_LOOP (tbl
, rn
, lsa
)
560 if (lsa
->to_be_acknowledged
)
563 tbl
= nbr
->ls_rxmt
.type
[OSPF_ASBR_SUMMARY_LSA
].db
;
564 LSDB_LOOP (tbl
, rn
, lsa
)
565 if (lsa
->to_be_acknowledged
)
568 tbl
= nbr
->ls_rxmt
.type
[OSPF_AS_EXTERNAL_LSA
].db
;
569 LSDB_LOOP (tbl
, rn
, lsa
)
570 if (lsa
->to_be_acknowledged
)
573 tbl
= nbr
->ls_rxmt
.type
[OSPF_AS_NSSA_LSA
].db
;
574 LSDB_LOOP (tbl
, rn
, lsa
)
575 if (lsa
->to_be_acknowledged
)
578 return OSPF_GR_FALSE
;
582 * Actions to be taken when topo change detected
583 * HELPER will exit upon topo change.
588 * topo change occured due to this lsa type (1 to 5 and 7)
593 void ospf_helper_handle_topo_chg(struct ospf
*ospf
, struct ospf_lsa
*lsa
)
595 struct listnode
*node
;
596 struct ospf_interface
*oi
;
598 if (!ospf
->active_restarter_cnt
)
601 /* Topo change not required to be handled if strict
602 * LSA check is disbaled for this router.
604 if (!ospf
->strict_lsa_check
)
607 if (IS_DEBUG_OSPF_GR_HELPER
)
609 "%s, Topo change detected due to lsa LSID:%pI4 type:%d",
610 __PRETTY_FUNCTION__
, &lsa
->data
->id
,
613 lsa
->to_be_acknowledged
= OSPF_GR_TRUE
;
615 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
616 struct route_node
*rn
= NULL
;
618 if (ospf_interface_neighbor_count(oi
) == 0)
621 /* Ref rfc3623 section 3.2.3.b
622 * If change due to external LSA and if the area is
623 * stub, then it is not a topo change. Since Type-5
624 * lsas will not be flooded in stub area.
626 if ((oi
->area
->external_routing
== OSPF_AREA_STUB
)
627 && (lsa
->data
->type
== OSPF_AS_EXTERNAL_LSA
)) {
631 for (rn
= route_top(oi
->nbrs
); rn
; rn
= route_next(rn
)) {
632 struct ospf_neighbor
*nbr
= NULL
;
639 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
640 ospf_gr_helper_exit(nbr
,
641 OSPF_GR_HELPER_TOPO_CHG
);
647 * Api to exit from HELPER role to take all actions
649 * Ref rfc3623 section 3.2
655 * OSPF neighbour for which it is acting as HELPER.
658 * The reason for exiting from HELPER.
663 void ospf_gr_helper_exit(struct ospf_neighbor
*nbr
,
664 enum ospf_helper_exit_reason reason
)
666 struct ospf_interface
*oi
= nbr
->oi
;
667 struct ospf
*ospf
= oi
->ospf
;
669 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr
))
672 if (IS_DEBUG_OSPF_GR_HELPER
)
673 zlog_debug("%s, Exiting from HELPER support to %pI4, due to %s",
674 __PRETTY_FUNCTION__
, &nbr
->src
,
675 ospf_exit_reason2str(reason
));
677 /* Reset helper status*/
678 nbr
->gr_helper_info
.gr_helper_status
= OSPF_GR_NOT_HELPER
;
679 nbr
->gr_helper_info
.helper_exit_reason
= reason
;
680 nbr
->gr_helper_info
.actual_grace_period
= 0;
681 nbr
->gr_helper_info
.recvd_grace_period
= 0;
682 nbr
->gr_helper_info
.gr_restart_reason
= 0;
683 ospf
->last_exit_reason
= reason
;
685 if (ospf
->active_restarter_cnt
<= 0) {
687 "OSPF GR-Helper: active_restarter_cnt should be greater than zero here.");
690 /* Decrement active Restarter count */
691 ospf
->active_restarter_cnt
--;
693 /* If the exit not triggered due to grace timer
694 * expairy , stop the grace timer.
696 if (reason
!= OSPF_GR_HELPER_GRACE_TIMEOUT
)
697 THREAD_OFF(nbr
->gr_helper_info
.t_grace_timer
);
699 /* check exit triggered due to successful completion
700 * of graceful restart.
701 * If no, bringdown the neighbour.
703 if (reason
!= OSPF_GR_HELPER_COMPLETED
) {
704 if (IS_DEBUG_OSPF_GR_HELPER
)
706 "%s, Failed GR exit, so bringing down the neighbour",
707 __PRETTY_FUNCTION__
);
708 OSPF_NSM_EVENT_EXECUTE(nbr
, NSM_KillNbr
);
711 /*Recalculate the DR for the network segment */
712 ospf_dr_election(oi
);
714 /* Originate a router LSA */
715 ospf_router_lsa_update_area(oi
->area
);
717 /* Originate network lsa if it is an DR in the LAN */
718 if (oi
->state
== ISM_DR
)
719 ospf_network_lsa_update(oi
);
723 * Process Maxage Grace LSA.
724 * It is a indication for successful completion of GR.
725 * If router acting as HELPER, It exits from helper role.
731 * Grace LSA received from RESTARTER.
734 * ospf neighbour which requets the router to act as
740 void ospf_process_maxage_grace_lsa(struct ospf
*ospf
, struct ospf_lsa
*lsa
,
741 struct ospf_neighbor
*nbr
)
743 struct in_addr restartAddr
= {0};
744 uint8_t restartReason
= 0;
745 uint32_t graceInterval
= 0;
746 struct ospf_neighbor
*restarter
= NULL
;
747 struct ospf_interface
*oi
= nbr
->oi
;
750 /* Extract the grace lsa packet fields */
751 ret
= ospf_extract_grace_lsa_fields(lsa
, &graceInterval
, &restartAddr
,
753 if (ret
!= OSPF_GR_SUCCESS
) {
754 if (IS_DEBUG_OSPF_GR_HELPER
)
755 zlog_debug("%s, Wrong Grace LSA packet.",
756 __PRETTY_FUNCTION__
);
760 if (IS_DEBUG_OSPF_GR_HELPER
)
761 zlog_debug("%s, GraceLSA received for neighbour %pI4",
762 __PRETTY_FUNCTION__
, &restartAddr
);
764 /* In case of broadcast links, if RESTARTER is DR_OTHER,
765 * grace LSA might be received from DR, so fetching the
766 * actual neighbour information using restarter address.
768 if (oi
->type
!= OSPF_IFTYPE_POINTOPOINT
) {
769 restarter
= ospf_nbr_lookup_by_addr(oi
->nbrs
, &restartAddr
);
772 if (IS_DEBUG_OSPF_GR_HELPER
)
774 "%s, Restarter is not a neighbour for this router.",
775 __PRETTY_FUNCTION__
);
782 ospf_gr_helper_exit(restarter
, OSPF_GR_HELPER_COMPLETED
);
785 /* Configuration handlers */
787 * Disable/Enable HELPER support on router level.
798 void ospf_gr_helper_support_set(struct ospf
*ospf
, bool support
)
800 struct ospf_interface
*oi
;
801 struct listnode
*node
;
802 struct advRtr lookup
;
804 if (ospf
->is_helper_supported
== support
)
807 ospf
->is_helper_supported
= support
;
809 /* If helper support disabled, cease HELPER role for all
810 * supporting neighbors.
812 if (support
== OSPF_GR_FALSE
) {
813 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
814 struct route_node
*rn
= NULL
;
816 if (ospf_interface_neighbor_count(oi
) == 0)
819 for (rn
= route_top(oi
->nbrs
); rn
;
820 rn
= route_next(rn
)) {
821 struct ospf_neighbor
*nbr
= NULL
;
828 lookup
.advRtrAddr
.s_addr
=
829 nbr
->router_id
.s_addr
;
830 /* check if helper support enabled for the
831 * correspodning routerid.If enabled, dont
832 * dont exit from helper role.
834 if (hash_lookup(ospf
->enable_rtr_list
, &lookup
))
837 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
839 nbr
, OSPF_GR_HELPER_TOPO_CHG
);
846 * Enable/Disable HELPER support on a specified advertagement
853 * HELPER support for given Advertisement Router.
856 * True - Enable Helper Support.
857 * False - Disable Helper Support.
863 void ospf_gr_helper_support_set_per_routerid(struct ospf
*ospf
,
864 struct in_addr
*advrtr
,
869 struct ospf_interface
*oi
;
870 struct listnode
*node
;
872 temp
.advRtrAddr
.s_addr
= advrtr
->s_addr
;
874 if (support
== OSPF_GR_FALSE
) {
875 /*Delete the routerid from the enable router hash table */
876 rtr
= hash_lookup(ospf
->enable_rtr_list
, &temp
);
879 hash_release(ospf
->enable_rtr_list
, rtr
);
880 ospf_disable_rtr_hash_free(rtr
);
883 /* If helper support is enabled globally
884 * no action is required.
886 if (ospf
->is_helper_supported
)
889 /* Cease the HELPER role fore neighbours from the
890 * specified advertisement router.
892 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
893 struct route_node
*rn
= NULL
;
895 if (ospf_interface_neighbor_count(oi
) == 0)
898 for (rn
= route_top(oi
->nbrs
); rn
;
899 rn
= route_next(rn
)) {
900 struct ospf_neighbor
*nbr
= NULL
;
907 if (nbr
->router_id
.s_addr
!= advrtr
->s_addr
)
910 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
912 nbr
, OSPF_GR_HELPER_TOPO_CHG
);
917 /* Add the routerid to the enable router hash table */
918 hash_get(ospf
->enable_rtr_list
, &temp
,
919 ospf_enable_rtr_hash_alloc
);
924 * Api to enable/disable strict lsa check on the HELPER.
930 * True - disable the lsa check.
931 * False - enable the strict lsa check.
936 void ospf_gr_helper_lsa_check_set(struct ospf
*ospf
, bool enabled
)
938 if (ospf
->strict_lsa_check
== enabled
)
941 ospf
->strict_lsa_check
= enabled
;
945 * Api to set the supported grace interval in this router.
951 * The supported grace interval..
956 void ospf_gr_helper_supported_gracetime_set(struct ospf
*ospf
,
959 ospf
->supported_grace_time
= interval
;
963 * Api to set the supported restart reason.
969 * True: support only planned restart.
970 * False: support for planned/unplanned restarts.
975 void ospf_gr_helper_set_supported_planned_only_restart(struct ospf
*ospf
,
978 ospf
->only_planned_restart
= planned_only
;
982 * Api to display the grace LSA information.
994 static void show_ospf_grace_lsa_info(struct vty
*vty
, struct ospf_lsa
*lsa
)
996 struct lsa_header
*lsah
= NULL
;
997 struct tlv_header
*tlvh
= NULL
;
998 struct grace_tlv_graceperiod
*gracePeriod
;
999 struct grace_tlv_restart_reason
*grReason
;
1000 struct grace_tlv_restart_addr
*restartAddr
;
1001 uint16_t length
= 0;
1004 lsah
= (struct lsa_header
*)lsa
->data
;
1006 length
= ntohs(lsah
->length
);
1008 if (length
<= OSPF_LSA_HEADER_SIZE
) {
1009 vty_out(vty
, "%% Invalid LSA length: %d\n", length
);
1013 length
-= OSPF_LSA_HEADER_SIZE
;
1015 vty_out(vty
, " TLV info:\n");
1017 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
;
1018 tlvh
= TLV_HDR_NEXT(tlvh
)) {
1020 if (sum
+ TLV_SIZE(tlvh
) > length
) {
1021 vty_out(vty
, "%% Invalid TLV length: %u\n",
1026 switch (ntohs(tlvh
->type
)) {
1027 case GRACE_PERIOD_TYPE
:
1028 if (TLV_SIZE(tlvh
) <
1029 sizeof(struct grace_tlv_graceperiod
)) {
1031 "%% Invalid grace TLV length %u\n",
1036 gracePeriod
= (struct grace_tlv_graceperiod
*)tlvh
;
1037 sum
+= TLV_SIZE(tlvh
);
1039 vty_out(vty
, " Grace period:%d\n",
1040 ntohl(gracePeriod
->interval
));
1042 case RESTART_REASON_TYPE
:
1043 if (TLV_SIZE(tlvh
) <
1044 sizeof(struct grace_tlv_restart_reason
)) {
1046 "%% Invalid reason TLV length %u\n",
1051 grReason
= (struct grace_tlv_restart_reason
*)tlvh
;
1052 sum
+= TLV_SIZE(tlvh
);
1054 vty_out(vty
, " Restart reason:%s\n",
1055 ospf_restart_reason2str(grReason
->reason
));
1057 case RESTARTER_IP_ADDR_TYPE
:
1058 if (TLV_SIZE(tlvh
) <
1059 sizeof(struct grace_tlv_restart_addr
)) {
1061 "%% Invalid addr TLV length %u\n",
1066 restartAddr
= (struct grace_tlv_restart_addr
*)tlvh
;
1067 sum
+= TLV_SIZE(tlvh
);
1069 vty_out(vty
, " Restarter address:%pI4\n",
1070 &restartAddr
->addr
);
1073 vty_out(vty
, " Unknown TLV type %d\n",