1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * This is an implementation of RFC 5187 Graceful Restart.
5 * Copyright 2021 NetDEF (c), All rights reserved.
18 #include "ospf6d/ospf6_lsa.h"
19 #include "ospf6d/ospf6_lsdb.h"
20 #include "ospf6d/ospf6_route.h"
21 #include "ospf6d/ospf6_area.h"
22 #include "ospf6d/ospf6_interface.h"
23 #include "ospf6d/ospf6d.h"
24 #include "ospf6d/ospf6_asbr.h"
25 #include "ospf6d/ospf6_zebra.h"
26 #include "ospf6d/ospf6_message.h"
27 #include "ospf6d/ospf6_neighbor.h"
28 #include "ospf6d/ospf6_flood.h"
29 #include "ospf6d/ospf6_intra.h"
30 #include "ospf6d/ospf6_spf.h"
31 #include "ospf6d/ospf6_gr.h"
32 #include "ospf6d/ospf6_gr_clippy.c"
34 static void ospf6_gr_nvm_delete(struct ospf6
*ospf6
);
36 /* Originate and install Grace-LSA for a given interface. */
37 static int ospf6_gr_lsa_originate(struct ospf6_interface
*oi
)
39 struct ospf6_gr_info
*gr_info
= &oi
->area
->ospf6
->gr_info
;
40 struct ospf6_lsa_header
*lsa_header
;
41 struct ospf6_grace_lsa
*grace_lsa
;
42 struct ospf6_lsa
*lsa
;
43 char buffer
[OSPF6_MAX_LSASIZE
];
45 if (IS_OSPF6_DEBUG_ORIGINATE(LINK
))
46 zlog_debug("Originate Grace-LSA for Interface %s",
50 memset(buffer
, 0, sizeof(buffer
));
51 lsa_header
= (struct ospf6_lsa_header
*)buffer
;
53 (struct ospf6_grace_lsa
*)((caddr_t
)lsa_header
54 + sizeof(struct ospf6_lsa_header
));
56 /* Put grace period. */
57 grace_lsa
->tlv_period
.header
.type
= htons(GRACE_PERIOD_TYPE
);
58 grace_lsa
->tlv_period
.header
.length
= htons(GRACE_PERIOD_LENGTH
);
59 grace_lsa
->tlv_period
.interval
= htonl(gr_info
->grace_period
);
61 /* Put restart reason. */
62 grace_lsa
->tlv_reason
.header
.type
= htons(RESTART_REASON_TYPE
);
63 grace_lsa
->tlv_reason
.header
.length
= htons(RESTART_REASON_LENGTH
);
64 if (gr_info
->restart_support
)
65 grace_lsa
->tlv_reason
.reason
= OSPF6_GR_SW_RESTART
;
67 grace_lsa
->tlv_reason
.reason
= OSPF6_GR_UNKNOWN_RESTART
;
71 lsa_header
->type
= htons(OSPF6_LSTYPE_GRACE_LSA
);
72 lsa_header
->id
= htonl(oi
->interface
->ifindex
);
73 lsa_header
->adv_router
= oi
->area
->ospf6
->router_id
;
75 ospf6_new_ls_seqnum(lsa_header
->type
, lsa_header
->id
,
76 lsa_header
->adv_router
, oi
->lsdb
);
77 lsa_header
->length
= htons(sizeof(*lsa_header
) + sizeof(*grace_lsa
));
80 ospf6_lsa_checksum(lsa_header
);
83 lsa
= ospf6_lsa_create(lsa_header
);
86 ospf6_lsa_originate_interface(lsa
, oi
);
91 /* Flush all self-originated Grace-LSAs. */
92 static void ospf6_gr_flush_grace_lsas(struct ospf6
*ospf6
)
94 struct ospf6_area
*area
;
95 struct listnode
*anode
;
97 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, anode
, area
)) {
98 struct ospf6_lsa
*lsa
;
99 struct ospf6_interface
*oi
;
100 struct listnode
*inode
;
102 if (IS_DEBUG_OSPF6_GR
)
104 "GR: flushing self-originated Grace-LSAs [area %pI4]",
107 for (ALL_LIST_ELEMENTS_RO(area
->if_list
, inode
, oi
)) {
108 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_GRACE_LSA
),
109 htonl(oi
->interface
->ifindex
),
110 oi
->area
->ospf6
->router_id
,
114 "%s: Grace-LSA not found [interface %s] [area %pI4]",
115 __func__
, oi
->interface
->name
,
120 ospf6_lsa_purge(lsa
);
125 /* Exit from the Graceful Restart mode. */
126 static void ospf6_gr_restart_exit(struct ospf6
*ospf6
, const char *reason
)
128 struct ospf6_area
*area
;
129 struct listnode
*onode
, *anode
;
130 struct ospf6_route
*route
;
132 if (IS_DEBUG_OSPF6_GR
)
133 zlog_debug("GR: exiting graceful restart: %s", reason
);
135 ospf6
->gr_info
.restart_in_progress
= false;
136 ospf6
->gr_info
.finishing_restart
= true;
137 EVENT_OFF(ospf6
->gr_info
.t_grace_period
);
139 /* Record in non-volatile memory that the restart is complete. */
140 ospf6_gr_nvm_delete(ospf6
);
142 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, onode
, area
)) {
143 struct ospf6_interface
*oi
;
146 * 1) The router should reoriginate its router-LSAs for all
147 * attached areas in order to make sure they have the correct
150 OSPF6_ROUTER_LSA_EXECUTE(area
);
153 * Force reorigination of intra-area-prefix-LSAs to handle
154 * areas without any full adjacency.
156 OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(area
);
158 for (ALL_LIST_ELEMENTS_RO(area
->if_list
, anode
, oi
)) {
159 /* Reoriginate Link-LSA. */
160 if (oi
->type
!= OSPF_IFTYPE_VIRTUALLINK
)
161 OSPF6_LINK_LSA_EXECUTE(oi
);
164 * 2) The router should reoriginate network-LSAs on all
165 * segments where it is the Designated Router.
167 if (oi
->state
== OSPF6_INTERFACE_DR
)
168 OSPF6_NETWORK_LSA_EXECUTE(oi
);
173 * While all self-originated NSSA and AS-external LSAs were already
174 * learned from the helping neighbors, we need to reoriginate them in
175 * order to ensure they will be refreshed periodically.
177 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
178 route
= ospf6_route_next(route
))
179 ospf6_handle_external_lsa_origination(ospf6
, route
,
183 * 3) The router reruns its OSPF routing calculations, this time
184 * installing the results into the system forwarding table, and
185 * originating summary-LSAs, Type-7 LSAs and AS-external-LSAs as
188 * 4) Any remnant entries in the system forwarding table that were
189 * installed before the restart, but that are no longer valid,
192 ospf6_spf_schedule(ospf6
, OSPF6_SPF_FLAGS_GR_FINISH
);
194 /* 6) Any grace-LSAs that the router originated should be flushed. */
195 ospf6_gr_flush_grace_lsas(ospf6
);
198 #define RTR_LSA_MISSING 0
199 #define RTR_LSA_ADJ_FOUND 1
200 #define RTR_LSA_ADJ_NOT_FOUND 2
202 /* Check if a Router-LSA exists and if it contains a given link. */
203 static int ospf6_router_lsa_contains_adj(struct ospf6_area
*area
,
204 in_addr_t adv_router
,
205 in_addr_t neighbor_router_id
)
208 struct ospf6_lsa
*lsa
;
211 type
= ntohs(OSPF6_LSTYPE_ROUTER
);
212 for (ALL_LSDB_TYPED_ADVRTR(area
->lsdb
, type
, adv_router
, lsa
)) {
213 struct ospf6_router_lsa
*router_lsa
;
214 char *start
, *end
, *current
;
217 router_lsa
= (struct ospf6_router_lsa
218 *)((char *)lsa
->header
219 + sizeof(struct ospf6_lsa_header
));
221 /* Iterate over all interfaces in the Router-LSA. */
222 start
= (char *)router_lsa
+ sizeof(struct ospf6_router_lsa
);
223 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
224 for (current
= start
;
225 current
+ sizeof(struct ospf6_router_lsdesc
) <= end
;
226 current
+= sizeof(struct ospf6_router_lsdesc
)) {
227 struct ospf6_router_lsdesc
*lsdesc
;
229 lsdesc
= (struct ospf6_router_lsdesc
*)current
;
230 if (lsdesc
->type
!= OSPF6_ROUTER_LSDESC_POINTTOPOINT
)
233 if (lsdesc
->neighbor_router_id
== neighbor_router_id
)
234 return RTR_LSA_ADJ_FOUND
;
239 return RTR_LSA_MISSING
;
241 return RTR_LSA_ADJ_NOT_FOUND
;
244 static bool ospf6_gr_check_router_lsa_consistency(struct ospf6
*ospf6
,
245 struct ospf6_area
*area
,
246 struct ospf6_lsa
*lsa
)
248 if (lsa
->header
->adv_router
== ospf6
->router_id
) {
249 struct ospf6_router_lsa
*router_lsa
;
250 char *start
, *end
, *current
;
252 router_lsa
= (struct ospf6_router_lsa
253 *)((char *)lsa
->header
254 + sizeof(struct ospf6_lsa_header
));
256 /* Iterate over all interfaces in the Router-LSA. */
257 start
= (char *)router_lsa
+ sizeof(struct ospf6_router_lsa
);
258 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
259 for (current
= start
;
260 current
+ sizeof(struct ospf6_router_lsdesc
) <= end
;
261 current
+= sizeof(struct ospf6_router_lsdesc
)) {
262 struct ospf6_router_lsdesc
*lsdesc
;
264 lsdesc
= (struct ospf6_router_lsdesc
*)current
;
265 if (lsdesc
->type
!= OSPF6_ROUTER_LSDESC_POINTTOPOINT
)
268 if (ospf6_router_lsa_contains_adj(
269 area
, lsdesc
->neighbor_router_id
,
271 == RTR_LSA_ADJ_NOT_FOUND
)
277 adj1
= ospf6_router_lsa_contains_adj(area
, ospf6
->router_id
,
278 lsa
->header
->adv_router
);
279 adj2
= ospf6_router_lsa_contains_adj(
280 area
, lsa
->header
->adv_router
, ospf6
->router_id
);
281 if ((adj1
== RTR_LSA_ADJ_FOUND
&& adj2
== RTR_LSA_ADJ_NOT_FOUND
)
282 || (adj1
== RTR_LSA_ADJ_NOT_FOUND
283 && adj2
== RTR_LSA_ADJ_FOUND
))
291 * Check for LSAs that are inconsistent with the pre-restart LSAs, and abort the
292 * ongoing graceful restart when that's the case.
294 void ospf6_gr_check_lsdb_consistency(struct ospf6
*ospf6
,
295 struct ospf6_area
*area
)
298 struct ospf6_lsa
*lsa
;
300 type
= ntohs(OSPF6_LSTYPE_ROUTER
);
301 for (ALL_LSDB_TYPED(area
->lsdb
, type
, lsa
)) {
302 if (!ospf6_gr_check_router_lsa_consistency(ospf6
, area
, lsa
)) {
305 snprintfrr(reason
, sizeof(reason
),
306 "detected inconsistent LSA %s [area %pI4]",
307 lsa
->name
, &area
->area_id
);
308 ospf6_gr_restart_exit(ospf6
, reason
);
314 /* Check if there's a fully formed adjacency with the given neighbor ID. */
315 static bool ospf6_gr_check_adj_id(struct ospf6_area
*area
,
316 in_addr_t neighbor_router_id
)
318 struct ospf6_neighbor
*nbr
;
320 nbr
= ospf6_area_neighbor_lookup(area
, neighbor_router_id
);
321 if (!nbr
|| nbr
->state
< OSPF6_NEIGHBOR_FULL
) {
322 if (IS_DEBUG_OSPF6_GR
)
323 zlog_debug("GR: missing adjacency to router %pI4",
324 &neighbor_router_id
);
331 static bool ospf6_gr_check_adjs_lsa_transit(struct ospf6_area
*area
,
332 in_addr_t neighbor_router_id
,
333 uint32_t neighbor_interface_id
)
335 struct ospf6
*ospf6
= area
->ospf6
;
337 /* Check if we are the DR. */
338 if (neighbor_router_id
== ospf6
->router_id
) {
339 struct ospf6_lsa
*lsa
;
340 char *start
, *end
, *current
;
341 struct ospf6_network_lsa
*network_lsa
;
342 struct ospf6_network_lsdesc
*lsdesc
;
344 /* Lookup Network LSA corresponding to this interface. */
345 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_NETWORK
),
346 neighbor_interface_id
,
347 neighbor_router_id
, area
->lsdb
);
351 /* Iterate over all routers present in the network. */
352 network_lsa
= (struct ospf6_network_lsa
353 *)((char *)lsa
->header
354 + sizeof(struct ospf6_lsa_header
));
355 start
= (char *)network_lsa
+ sizeof(struct ospf6_network_lsa
);
356 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
357 for (current
= start
;
358 current
+ sizeof(struct ospf6_network_lsdesc
) <= end
;
359 current
+= sizeof(struct ospf6_network_lsdesc
)) {
360 lsdesc
= (struct ospf6_network_lsdesc
*)current
;
362 /* Skip self in the pseudonode. */
363 if (lsdesc
->router_id
== ospf6
->router_id
)
367 * Check if there's a fully formed adjacency with this
370 if (!ospf6_gr_check_adj_id(area
, lsdesc
->router_id
))
374 struct ospf6_neighbor
*nbr
;
376 /* Check if there's a fully formed adjacency with the DR. */
377 nbr
= ospf6_area_neighbor_lookup(area
, neighbor_router_id
);
378 if (!nbr
|| nbr
->state
< OSPF6_NEIGHBOR_FULL
) {
379 if (IS_DEBUG_OSPF6_GR
)
381 "GR: missing adjacency to DR router %pI4",
382 &neighbor_router_id
);
390 static bool ospf6_gr_check_adjs_lsa(struct ospf6_area
*area
,
391 struct ospf6_lsa
*lsa
)
393 struct ospf6_router_lsa
*router_lsa
;
394 char *start
, *end
, *current
;
397 (struct ospf6_router_lsa
*)((char *)lsa
->header
398 + sizeof(struct ospf6_lsa_header
));
400 /* Iterate over all interfaces in the Router-LSA. */
401 start
= (char *)router_lsa
+ sizeof(struct ospf6_router_lsa
);
402 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
403 for (current
= start
;
404 current
+ sizeof(struct ospf6_router_lsdesc
) <= end
;
405 current
+= sizeof(struct ospf6_router_lsdesc
)) {
406 struct ospf6_router_lsdesc
*lsdesc
;
408 lsdesc
= (struct ospf6_router_lsdesc
*)current
;
409 switch (lsdesc
->type
) {
410 case OSPF6_ROUTER_LSDESC_POINTTOPOINT
:
411 if (!ospf6_gr_check_adj_id(area
,
412 lsdesc
->neighbor_router_id
))
415 case OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK
:
416 if (!ospf6_gr_check_adjs_lsa_transit(
417 area
, lsdesc
->neighbor_router_id
,
418 lsdesc
->neighbor_interface_id
))
430 * Check if all adjacencies prior to the restart were reestablished.
432 * This is done using pre-restart Router LSAs and pre-restart Network LSAs
433 * received from the helping neighbors.
435 static bool ospf6_gr_check_adjs(struct ospf6
*ospf6
)
437 struct ospf6_area
*area
;
438 struct listnode
*node
;
440 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, node
, area
)) {
443 struct ospf6_lsa
*lsa_self
;
446 type
= ntohs(OSPF6_LSTYPE_ROUTER
);
447 router
= ospf6
->router_id
;
448 for (ALL_LSDB_TYPED_ADVRTR(area
->lsdb
, type
, router
,
451 if (!ospf6_gr_check_adjs_lsa(area
, lsa_self
))
461 /* Handling of grace period expiry. */
462 static void ospf6_gr_grace_period_expired(struct event
*thread
)
464 struct ospf6
*ospf6
= EVENT_ARG(thread
);
466 ospf6_gr_restart_exit(ospf6
, "grace period has expired");
470 * Record in non-volatile memory that the given OSPF instance is attempting to
471 * perform a graceful restart.
473 static void ospf6_gr_nvm_update(struct ospf6
*ospf6
)
475 const char *inst_name
;
477 json_object
*json_instances
;
478 json_object
*json_instance
;
480 inst_name
= ospf6
->name
? ospf6
->name
: VRF_DEFAULT_NAME
;
482 json
= json_object_from_file((char *)OSPF6D_GR_STATE
);
484 json
= json_object_new_object();
486 json_object_object_get_ex(json
, "instances", &json_instances
);
487 if (!json_instances
) {
488 json_instances
= json_object_new_object();
489 json_object_object_add(json
, "instances", json_instances
);
492 json_object_object_get_ex(json_instances
, inst_name
, &json_instance
);
493 if (!json_instance
) {
494 json_instance
= json_object_new_object();
495 json_object_object_add(json_instances
, inst_name
,
500 * Record not only the grace period, but also a UNIX timestamp
501 * corresponding to the end of that period. That way, once ospf6d is
502 * restarted, it will be possible to take into account the time that
503 * passed while ospf6d wasn't running.
505 json_object_int_add(json_instance
, "gracePeriod",
506 ospf6
->gr_info
.grace_period
);
507 json_object_int_add(json_instance
, "timestamp",
508 time(NULL
) + ospf6
->gr_info
.grace_period
);
510 json_object_to_file_ext((char *)OSPF6D_GR_STATE
, json
,
511 JSON_C_TO_STRING_PRETTY
);
512 json_object_free(json
);
516 * Delete GR status information about the given OSPF instance from non-volatile
519 static void ospf6_gr_nvm_delete(struct ospf6
*ospf6
)
521 const char *inst_name
;
523 json_object
*json_instances
;
525 inst_name
= ospf6
->name
? ospf6
->name
: VRF_DEFAULT_NAME
;
527 json
= json_object_from_file((char *)OSPF6D_GR_STATE
);
529 json
= json_object_new_object();
531 json_object_object_get_ex(json
, "instances", &json_instances
);
532 if (!json_instances
) {
533 json_instances
= json_object_new_object();
534 json_object_object_add(json
, "instances", json_instances
);
537 json_object_object_del(json_instances
, inst_name
);
539 json_object_to_file_ext((char *)OSPF6D_GR_STATE
, json
,
540 JSON_C_TO_STRING_PRETTY
);
541 json_object_free(json
);
545 * Fetch from non-volatile memory whether the given OSPF instance is performing
546 * a graceful shutdown or not.
548 void ospf6_gr_nvm_read(struct ospf6
*ospf6
)
550 const char *inst_name
;
552 json_object
*json_instances
;
553 json_object
*json_instance
;
554 json_object
*json_timestamp
;
555 time_t timestamp
= 0;
557 inst_name
= ospf6
->name
? ospf6
->name
: VRF_DEFAULT_NAME
;
559 json
= json_object_from_file((char *)OSPF6D_GR_STATE
);
561 json
= json_object_new_object();
563 json_object_object_get_ex(json
, "instances", &json_instances
);
564 if (!json_instances
) {
565 json_instances
= json_object_new_object();
566 json_object_object_add(json
, "instances", json_instances
);
569 json_object_object_get_ex(json_instances
, inst_name
, &json_instance
);
570 if (!json_instance
) {
571 json_instance
= json_object_new_object();
572 json_object_object_add(json_instances
, inst_name
,
576 json_object_object_get_ex(json_instance
, "timestamp", &json_timestamp
);
577 if (json_timestamp
) {
579 unsigned long remaining_time
;
581 /* Check if the grace period has already expired. */
583 timestamp
= json_object_get_int(json_timestamp
);
584 if (now
> timestamp
) {
585 ospf6_gr_restart_exit(
586 ospf6
, "grace period has expired already");
588 /* Schedule grace period timeout. */
589 ospf6
->gr_info
.restart_in_progress
= true;
590 remaining_time
= timestamp
- time(NULL
);
591 if (IS_DEBUG_OSPF6_GR
)
593 "GR: remaining time until grace period expires: %lu(s)",
595 event_add_timer(master
, ospf6_gr_grace_period_expired
,
596 ospf6
, remaining_time
,
597 &ospf6
->gr_info
.t_grace_period
);
601 json_object_object_del(json_instances
, inst_name
);
603 json_object_to_file_ext((char *)OSPF6D_GR_STATE
, json
,
604 JSON_C_TO_STRING_PRETTY
);
605 json_object_free(json
);
608 /* Prepare to start a Graceful Restart. */
609 static void ospf6_gr_prepare(void)
612 struct ospf6_interface
*oi
;
613 struct listnode
*onode
, *anode
, *inode
;
615 for (ALL_LIST_ELEMENTS_RO(om6
->ospf6
, onode
, ospf6
)) {
616 struct ospf6_area
*area
;
618 if (!ospf6
->gr_info
.restart_support
619 || ospf6
->gr_info
.prepare_in_progress
)
622 if (IS_DEBUG_OSPF6_GR
)
624 "GR: preparing to perform a graceful restart [period %u second(s)] [vrf %s]",
625 ospf6
->gr_info
.grace_period
,
626 ospf6_vrf_id_to_name(ospf6
->vrf_id
));
628 /* Freeze OSPF routes in the RIB. */
629 if (ospf6_zebra_gr_enable(ospf6
, ospf6
->gr_info
.grace_period
)) {
631 "%s: failed to activate graceful restart: not connected to zebra",
636 /* Send a Grace-LSA to all neighbors. */
637 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, anode
, area
)) {
638 for (ALL_LIST_ELEMENTS_RO(area
->if_list
, inode
, oi
)) {
639 if (oi
->state
< OSPF6_INTERFACE_POINTTOPOINT
)
641 ospf6_gr_lsa_originate(oi
);
645 /* Record end of the grace period in non-volatile memory. */
646 ospf6_gr_nvm_update(ospf6
);
649 * Mark that a Graceful Restart preparation is in progress, to
650 * prevent ospf6d from flushing its self-originated LSAs on
653 ospf6
->gr_info
.prepare_in_progress
= true;
657 static int ospf6_gr_neighbor_change(struct ospf6_neighbor
*on
, int next_state
,
660 struct ospf6
*ospf6
= on
->ospf6_if
->area
->ospf6
;
662 if (next_state
== OSPF6_NEIGHBOR_FULL
663 && ospf6
->gr_info
.restart_in_progress
) {
664 if (ospf6_gr_check_adjs(ospf6
)) {
665 ospf6_gr_restart_exit(
666 ospf6
, "all adjacencies were reestablished");
668 if (IS_DEBUG_OSPF6_GR
)
670 "GR: not all adjacencies were reestablished yet");
677 int config_write_ospf6_gr(struct vty
*vty
, struct ospf6
*ospf6
)
679 if (!ospf6
->gr_info
.restart_support
)
682 if (ospf6
->gr_info
.grace_period
== OSPF6_DFLT_GRACE_INTERVAL
)
683 vty_out(vty
, " graceful-restart\n");
685 vty_out(vty
, " graceful-restart grace-period %u\n",
686 ospf6
->gr_info
.grace_period
);
691 DEFPY(ospf6_graceful_restart_prepare
, ospf6_graceful_restart_prepare_cmd
,
692 "graceful-restart prepare ipv6 ospf",
693 "Graceful Restart commands\n"
694 "Prepare upcoming graceful restart\n" IPV6_STR
695 "Prepare to restart the OSPFv3 process\n")
702 DEFPY(ospf6_graceful_restart
, ospf6_graceful_restart_cmd
,
703 "graceful-restart [grace-period (1-1800)$grace_period]",
705 "Maximum length of the 'grace period'\n"
706 "Maximum length of the 'grace period' in seconds\n")
708 VTY_DECLVAR_INSTANCE_CONTEXT(ospf6
, ospf6
);
710 /* Check and get restart period if present. */
711 if (!grace_period_str
)
712 grace_period
= OSPF6_DFLT_GRACE_INTERVAL
;
714 ospf6
->gr_info
.restart_support
= true;
715 ospf6
->gr_info
.grace_period
= grace_period
;
720 DEFPY(ospf6_no_graceful_restart
, ospf6_no_graceful_restart_cmd
,
721 "no graceful-restart [period (1-1800)]",
723 "Maximum length of the 'grace period'\n"
724 "Maximum length of the 'grace period' in seconds\n")
726 VTY_DECLVAR_INSTANCE_CONTEXT(ospf6
, ospf6
);
728 if (!ospf6
->gr_info
.restart_support
)
731 if (ospf6
->gr_info
.prepare_in_progress
) {
733 "%% Error: Graceful Restart preparation in progress\n");
737 ospf6
->gr_info
.restart_support
= false;
738 ospf6
->gr_info
.grace_period
= OSPF6_DFLT_GRACE_INTERVAL
;
743 void ospf6_gr_init(void)
745 hook_register(ospf6_neighbor_change
, ospf6_gr_neighbor_change
);
747 install_element(ENABLE_NODE
, &ospf6_graceful_restart_prepare_cmd
);
748 install_element(OSPF6_NODE
, &ospf6_graceful_restart_cmd
);
749 install_element(OSPF6_NODE
, &ospf6_no_graceful_restart_cmd
);