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 ospf_lsa
*lsa
);
79 static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor
*nbr
);
81 static unsigned int ospf_enable_rtr_hash_key(const void *data
)
83 const struct advRtr
*rtr
= data
;
85 return jhash_1word(rtr
->advRtrAddr
.s_addr
, 0);
88 static bool ospf_enable_rtr_hash_cmp(const void *d1
, const void *d2
)
90 const struct advRtr
*rtr1
= (struct advRtr
*)d1
;
91 const struct advRtr
*rtr2
= (struct advRtr
*)d2
;
93 return (rtr1
->advRtrAddr
.s_addr
== rtr2
->advRtrAddr
.s_addr
);
96 static void *ospf_enable_rtr_hash_alloc(void *p
)
100 rid
= XCALLOC(MTYPE_OSPF_GR_HELPER
, sizeof(struct advRtr
));
101 rid
->advRtrAddr
.s_addr
= ((struct in_addr
*)p
)->s_addr
;
106 static void ospf_disable_rtr_hash_free(void *rtr
)
108 XFREE(MTYPE_OSPF_GR_HELPER
, rtr
);
111 static void ospf_enable_rtr_hash_destroy(struct ospf
*ospf
)
113 if (ospf
->enable_rtr_list
== NULL
)
116 hash_clean(ospf
->enable_rtr_list
, ospf_disable_rtr_hash_free
);
117 hash_free(ospf
->enable_rtr_list
);
118 ospf
->enable_rtr_list
= NULL
;
122 * GR exit reason strings
124 const char *ospf_exit_reason2str(unsigned int reason
)
126 if (reason
< array_size(ospf_exit_reason_desc
))
127 return(ospf_exit_reason_desc
[reason
]);
129 return "Invalid reason";
133 * GR restart reason strings
135 const char *ospf_restart_reason2str(unsigned int reason
)
137 if (reason
< array_size(ospf_restart_reason_desc
))
138 return(ospf_restart_reason_desc
[reason
]);
140 return "Invalid reason";
144 * GR rejected reason strings
146 const char *ospf_rejected_reason2str(unsigned int reason
)
148 if (reason
< array_size(ospf_rejected_reason_desc
))
149 return(ospf_rejected_reason_desc
[reason
]);
151 return "Invalid reason";
155 * Initialize GR helper config data structures.
163 void ospf_gr_helper_instance_init(struct ospf
*ospf
)
165 if (IS_DEBUG_OSPF_GR
)
166 zlog_debug("%s, GR Helper init.", __func__
);
168 ospf
->is_helper_supported
= OSPF_GR_FALSE
;
169 ospf
->strict_lsa_check
= OSPF_GR_TRUE
;
170 ospf
->only_planned_restart
= OSPF_GR_FALSE
;
171 ospf
->supported_grace_time
= OSPF_MAX_GRACE_INTERVAL
;
172 ospf
->last_exit_reason
= OSPF_GR_HELPER_EXIT_NONE
;
173 ospf
->active_restarter_cnt
= 0;
175 ospf
->enable_rtr_list
=
176 hash_create(ospf_enable_rtr_hash_key
, ospf_enable_rtr_hash_cmp
,
177 "OSPF enable router hash");
181 * De-Initialize GR helper config data structures.
189 void ospf_gr_helper_instance_stop(struct ospf
*ospf
)
191 if (IS_DEBUG_OSPF_GR
)
192 zlog_debug("%s, GR helper deinit.", __func__
);
194 ospf_enable_rtr_hash_destroy(ospf
);
198 * Initialize GR helper config data structures.
203 void ospf_gr_helper_init(void)
207 if (IS_DEBUG_OSPF_GR
)
208 zlog_debug("%s, GR Helper init.", __func__
);
210 rc
= ospf_register_opaque_functab(
211 OSPF_OPAQUE_LINK_LSA
, OPAQUE_TYPE_GRACE_LSA
, NULL
, NULL
, NULL
,
212 NULL
, NULL
, NULL
, NULL
, show_ospf_grace_lsa_info
, NULL
, NULL
,
215 flog_warn(EC_OSPF_OPAQUE_REGISTRATION
,
216 "%s: Failed to register Grace LSA functions",
222 * De-Initialize GR helper config data structures.
227 void ospf_gr_helper_stop(void)
229 if (IS_DEBUG_OSPF_GR
)
230 zlog_debug("%s, GR helper deinit.", __func__
);
232 ospf_delete_opaque_functab(OSPF_OPAQUE_LINK_LSA
, OPAQUE_TYPE_GRACE_LSA
);
236 * Extracting tlv info from GRACE LSA.
242 * interval : grace interval.
243 * addr : RESTARTER address.
244 * reason : Restarting reason.
246 static int ospf_extract_grace_lsa_fields(struct ospf_lsa
*lsa
,
248 struct in_addr
*addr
, uint8_t *reason
)
250 struct lsa_header
*lsah
= NULL
;
251 struct tlv_header
*tlvh
= NULL
;
252 struct grace_tlv_graceperiod
*grace_period
;
253 struct grace_tlv_restart_reason
*gr_reason
;
254 struct grace_tlv_restart_addr
*restart_addr
;
258 lsah
= (struct lsa_header
*)lsa
->data
;
261 if (lsa
->size
<= OSPF_LSA_HEADER_SIZE
) {
262 if (IS_DEBUG_OSPF_GR
)
263 zlog_debug("%s: Malformed packet: Invalid LSA len:%d",
265 return OSPF_GR_FAILURE
;
268 length
= lsa
->size
- OSPF_LSA_HEADER_SIZE
;
270 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
&& tlvh
;
271 tlvh
= TLV_HDR_NEXT(tlvh
)) {
273 /* Check TLV len against overall LSA */
274 if (sum
+ TLV_SIZE(tlvh
) > length
) {
275 if (IS_DEBUG_OSPF_GR
)
276 zlog_debug("%s: Malformed packet: Invalid TLV len:%u",
277 __func__
, TLV_SIZE(tlvh
));
278 return OSPF_GR_FAILURE
;
281 switch (ntohs(tlvh
->type
)) {
282 case GRACE_PERIOD_TYPE
:
284 sizeof(struct grace_tlv_graceperiod
)) {
285 zlog_debug("%s: Malformed packet: Invalid grace TLV len:%u",
286 __func__
, TLV_SIZE(tlvh
));
287 return OSPF_GR_FAILURE
;
290 grace_period
= (struct grace_tlv_graceperiod
*)tlvh
;
291 *interval
= ntohl(grace_period
->interval
);
292 sum
+= TLV_SIZE(tlvh
);
294 /* Check if grace interval is valid */
295 if (*interval
> OSPF_MAX_GRACE_INTERVAL
296 || *interval
< OSPF_MIN_GRACE_INTERVAL
)
297 return OSPF_GR_FAILURE
;
299 case RESTART_REASON_TYPE
:
301 sizeof(struct grace_tlv_restart_reason
)) {
302 zlog_debug("%s: Malformed packet: Invalid reason TLV len:%u",
303 __func__
, TLV_SIZE(tlvh
));
304 return OSPF_GR_FAILURE
;
307 gr_reason
= (struct grace_tlv_restart_reason
*)tlvh
;
308 *reason
= gr_reason
->reason
;
309 sum
+= TLV_SIZE(tlvh
);
311 if (*reason
>= OSPF_GR_INVALID_REASON_CODE
)
312 return OSPF_GR_FAILURE
;
314 case RESTARTER_IP_ADDR_TYPE
:
316 sizeof(struct grace_tlv_restart_addr
)) {
317 zlog_debug("%s: Malformed packet: Invalid addr TLV len:%u",
318 __func__
, TLV_SIZE(tlvh
));
319 return OSPF_GR_FAILURE
;
322 restart_addr
= (struct grace_tlv_restart_addr
*)tlvh
;
323 addr
->s_addr
= restart_addr
->addr
.s_addr
;
324 sum
+= TLV_SIZE(tlvh
);
327 if (IS_DEBUG_OSPF_GR
)
329 "%s, Malformed packet.Invalid TLV type:%d",
330 __func__
, ntohs(tlvh
->type
));
331 return OSPF_GR_FAILURE
;
335 return OSPF_GR_SUCCESS
;
339 * Grace timer expiry handler.
340 * HELPER aborts its role at grace timer expiry.
348 static int ospf_handle_grace_timer_expiry(struct thread
*thread
)
350 struct ospf_neighbor
*nbr
= THREAD_ARG(thread
);
352 nbr
->gr_helper_info
.t_grace_timer
= NULL
;
354 ospf_gr_helper_exit(nbr
, OSPF_GR_HELPER_GRACE_TIMEOUT
);
355 return OSPF_GR_SUCCESS
;
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 if (!ospf
->active_restarter_cnt
)
629 /* Topo change not required to be handled if strict
630 * LSA check is disabled for this router.
632 if (!ospf
->strict_lsa_check
)
635 if (IS_DEBUG_OSPF_GR
)
636 zlog_debug("%s: Topo change detected due to LSA[%s]", __func__
,
639 lsa
->to_be_acknowledged
= OSPF_GR_TRUE
;
641 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
642 struct route_node
*rn
= NULL
;
644 if (ospf_interface_neighbor_count(oi
) == 0)
647 /* Ref rfc3623 section 3.2.3.b
648 * If change due to external LSA and if the area is
649 * stub, then it is not a topo change. Since Type-5
650 * lsas will not be flooded in stub area.
652 if ((oi
->area
->external_routing
== OSPF_AREA_STUB
)
653 && (lsa
->data
->type
== OSPF_AS_EXTERNAL_LSA
)) {
657 for (rn
= route_top(oi
->nbrs
); rn
; rn
= route_next(rn
)) {
658 struct ospf_neighbor
*nbr
= NULL
;
665 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
666 ospf_gr_helper_exit(nbr
,
667 OSPF_GR_HELPER_TOPO_CHG
);
673 * Api to exit from HELPER role to take all actions
675 * Ref rfc3623 section 3.2
681 * OSPF neighbour for which it is acting as HELPER.
684 * The reason for exiting from HELPER.
689 void ospf_gr_helper_exit(struct ospf_neighbor
*nbr
,
690 enum ospf_helper_exit_reason reason
)
692 struct ospf_interface
*oi
= nbr
->oi
;
693 struct ospf
*ospf
= oi
->ospf
;
695 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr
))
698 if (IS_DEBUG_OSPF_GR
)
699 zlog_debug("%s, Exiting from HELPER support to %pI4, due to %s",
700 __func__
, &nbr
->src
, ospf_exit_reason2str(reason
));
702 /* Reset helper status*/
703 nbr
->gr_helper_info
.gr_helper_status
= OSPF_GR_NOT_HELPER
;
704 nbr
->gr_helper_info
.helper_exit_reason
= reason
;
705 nbr
->gr_helper_info
.actual_grace_period
= 0;
706 nbr
->gr_helper_info
.recvd_grace_period
= 0;
707 nbr
->gr_helper_info
.gr_restart_reason
= 0;
708 ospf
->last_exit_reason
= reason
;
710 if (ospf
->active_restarter_cnt
<= 0) {
712 "OSPF GR-Helper: active_restarter_cnt should be greater than zero here.");
715 /* Decrement active Restarter count */
716 ospf
->active_restarter_cnt
--;
718 /* If the exit not triggered due to grace timer
719 * expiry, stop the grace timer.
721 if (reason
!= OSPF_GR_HELPER_GRACE_TIMEOUT
)
722 THREAD_OFF(nbr
->gr_helper_info
.t_grace_timer
);
724 /* check exit triggered due to successful completion
725 * of graceful restart.
726 * If no, bring down the neighbour.
728 if (reason
!= OSPF_GR_HELPER_COMPLETED
) {
729 if (IS_DEBUG_OSPF_GR
)
731 "%s, Failed GR exit, so bringing down the neighbour",
733 OSPF_NSM_EVENT_SCHEDULE(nbr
, NSM_KillNbr
);
736 /*Recalculate the DR for the network segment */
737 if (oi
->type
== OSPF_IFTYPE_BROADCAST
|| oi
->type
== OSPF_IFTYPE_NBMA
)
738 ospf_dr_election(oi
);
740 /* Originate a router LSA */
741 ospf_router_lsa_update_area(oi
->area
);
743 /* Originate network lsa if it is an DR in the LAN */
744 if (oi
->state
== ISM_DR
)
745 ospf_network_lsa_update(oi
);
749 * Process MaxAge Grace LSA.
750 * It is a indication for successful completion of GR.
751 * If router acting as HELPER, It exits from helper role.
757 * Grace LSA received from RESTARTER.
760 * OSPF neighbour which requests the router to act as
766 void ospf_process_maxage_grace_lsa(struct ospf
*ospf
, struct ospf_lsa
*lsa
,
767 struct ospf_neighbor
*nbr
)
769 struct in_addr restartAddr
= {0};
770 uint8_t restartReason
= 0;
771 uint32_t graceInterval
= 0;
772 struct ospf_neighbor
*restarter
= NULL
;
773 struct ospf_interface
*oi
= nbr
->oi
;
776 /* Extract the grace lsa packet fields */
777 ret
= ospf_extract_grace_lsa_fields(lsa
, &graceInterval
, &restartAddr
,
779 if (ret
!= OSPF_GR_SUCCESS
) {
780 if (IS_DEBUG_OSPF_GR
)
781 zlog_debug("%s, Wrong Grace LSA packet.", __func__
);
785 if (IS_DEBUG_OSPF_GR
)
786 zlog_debug("%s, GraceLSA received for neighbour %pI4", __func__
,
789 /* In case of broadcast links, if RESTARTER is DR_OTHER,
790 * grace LSA might be received from DR, so fetching the
791 * actual neighbour information using restarter address.
793 if (oi
->type
!= OSPF_IFTYPE_POINTOPOINT
) {
794 restarter
= ospf_nbr_lookup_by_addr(oi
->nbrs
, &restartAddr
);
797 if (IS_DEBUG_OSPF_GR
)
799 "%s, Restarter is not a neighbour for this router.",
807 ospf_gr_helper_exit(restarter
, OSPF_GR_HELPER_COMPLETED
);
810 /* Configuration handlers */
812 * Disable/Enable HELPER support on router level.
823 void ospf_gr_helper_support_set(struct ospf
*ospf
, bool support
)
825 struct ospf_interface
*oi
;
826 struct listnode
*node
;
827 struct advRtr lookup
;
829 if (ospf
->is_helper_supported
== support
)
832 ospf
->is_helper_supported
= support
;
834 /* If helper support disabled, cease HELPER role for all
835 * supporting neighbors.
837 if (support
== OSPF_GR_FALSE
) {
838 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
839 struct route_node
*rn
= NULL
;
841 if (ospf_interface_neighbor_count(oi
) == 0)
844 for (rn
= route_top(oi
->nbrs
); rn
;
845 rn
= route_next(rn
)) {
846 struct ospf_neighbor
*nbr
= NULL
;
853 lookup
.advRtrAddr
.s_addr
=
854 nbr
->router_id
.s_addr
;
855 /* check if helper support enabled for the
856 * corresponding routerid.If enabled, dont
857 * dont exit from helper role.
859 if (hash_lookup(ospf
->enable_rtr_list
, &lookup
))
862 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
864 nbr
, OSPF_GR_HELPER_TOPO_CHG
);
871 * Enable/Disable HELPER support on a specified advertagement
878 * HELPER support for given Advertisement Router.
881 * True - Enable Helper Support.
882 * False - Disable Helper Support.
888 void ospf_gr_helper_support_set_per_routerid(struct ospf
*ospf
,
889 struct in_addr
*advrtr
,
894 struct ospf_interface
*oi
;
895 struct listnode
*node
;
897 temp
.advRtrAddr
.s_addr
= advrtr
->s_addr
;
899 if (support
== OSPF_GR_FALSE
) {
900 /*Delete the routerid from the enable router hash table */
901 rtr
= hash_lookup(ospf
->enable_rtr_list
, &temp
);
904 hash_release(ospf
->enable_rtr_list
, rtr
);
905 ospf_disable_rtr_hash_free(rtr
);
908 /* If helper support is enabled globally
909 * no action is required.
911 if (ospf
->is_helper_supported
)
914 /* Cease the HELPER role fore neighbours from the
915 * specified advertisement router.
917 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, node
, oi
)) {
918 struct route_node
*rn
= NULL
;
920 if (ospf_interface_neighbor_count(oi
) == 0)
923 for (rn
= route_top(oi
->nbrs
); rn
;
924 rn
= route_next(rn
)) {
925 struct ospf_neighbor
*nbr
= NULL
;
932 if (nbr
->router_id
.s_addr
!= advrtr
->s_addr
)
935 if (OSPF_GR_IS_ACTIVE_HELPER(nbr
))
937 nbr
, OSPF_GR_HELPER_TOPO_CHG
);
942 /* Add the routerid to the enable router hash table */
943 hash_get(ospf
->enable_rtr_list
, &temp
,
944 ospf_enable_rtr_hash_alloc
);
949 * Api to enable/disable strict lsa check on the HELPER.
955 * True - disable the lsa check.
956 * False - enable the strict lsa check.
961 void ospf_gr_helper_lsa_check_set(struct ospf
*ospf
, bool enabled
)
963 if (ospf
->strict_lsa_check
== enabled
)
966 ospf
->strict_lsa_check
= enabled
;
970 * Api to set the supported grace interval in this router.
976 * The supported grace interval..
981 void ospf_gr_helper_supported_gracetime_set(struct ospf
*ospf
,
984 ospf
->supported_grace_time
= interval
;
988 * Api to set the supported restart reason.
994 * True: support only planned restart.
995 * False: support for planned/unplanned restarts.
1000 void ospf_gr_helper_set_supported_planned_only_restart(struct ospf
*ospf
,
1003 ospf
->only_planned_restart
= planned_only
;
1007 * Api to display the grace LSA information.
1019 static void show_ospf_grace_lsa_info(struct vty
*vty
, struct ospf_lsa
*lsa
)
1021 struct lsa_header
*lsah
= NULL
;
1022 struct tlv_header
*tlvh
= NULL
;
1023 struct grace_tlv_graceperiod
*gracePeriod
;
1024 struct grace_tlv_restart_reason
*grReason
;
1025 struct grace_tlv_restart_addr
*restartAddr
;
1026 uint16_t length
= 0;
1029 lsah
= (struct lsa_header
*)lsa
->data
;
1031 if (lsa
->size
<= OSPF_LSA_HEADER_SIZE
) {
1033 vty_out(vty
, "%% Invalid LSA length: %d\n", length
);
1035 zlog_debug("%% Invalid LSA length: %d", length
);
1039 length
= lsa
->size
- OSPF_LSA_HEADER_SIZE
;
1042 vty_out(vty
, " TLV info:\n");
1044 zlog_debug(" TLV info:");
1046 for (tlvh
= TLV_HDR_TOP(lsah
); sum
< length
&& tlvh
;
1047 tlvh
= TLV_HDR_NEXT(tlvh
)) {
1049 if (sum
+ TLV_SIZE(tlvh
) > length
) {
1051 vty_out(vty
, "%% Invalid TLV length: %u\n",
1054 zlog_debug("%% Invalid TLV length: %u",
1059 switch (ntohs(tlvh
->type
)) {
1060 case GRACE_PERIOD_TYPE
:
1062 < sizeof(struct grace_tlv_graceperiod
)) {
1065 "%% Invalid grace TLV length %u\n",
1069 "%% Invalid grace TLV length %u",
1074 gracePeriod
= (struct grace_tlv_graceperiod
*)tlvh
;
1075 sum
+= TLV_SIZE(tlvh
);
1078 vty_out(vty
, " Grace period:%d\n",
1079 ntohl(gracePeriod
->interval
));
1081 zlog_debug(" Grace period:%d",
1082 ntohl(gracePeriod
->interval
));
1084 case RESTART_REASON_TYPE
:
1086 < sizeof(struct grace_tlv_restart_reason
)) {
1089 "%% Invalid reason TLV length %u\n",
1093 "%% Invalid reason TLV length %u",
1098 grReason
= (struct grace_tlv_restart_reason
*)tlvh
;
1099 sum
+= TLV_SIZE(tlvh
);
1102 vty_out(vty
, " Restart reason:%s\n",
1103 ospf_restart_reason2str(
1106 zlog_debug(" Restart reason:%s",
1107 ospf_restart_reason2str(
1110 case RESTARTER_IP_ADDR_TYPE
:
1112 < sizeof(struct grace_tlv_restart_addr
)) {
1115 "%% Invalid addr TLV length %u\n",
1119 "%% Invalid addr TLV length %u",
1124 restartAddr
= (struct grace_tlv_restart_addr
*)tlvh
;
1125 sum
+= TLV_SIZE(tlvh
);
1128 vty_out(vty
, " Restarter address:%pI4\n",
1129 &restartAddr
->addr
);
1131 zlog_debug(" Restarter address:%pI4",
1132 &restartAddr
->addr
);
1136 vty_out(vty
, " Unknown TLV type %d\n",
1139 zlog_debug(" Unknown TLV type %d",