2 * This is an implementation of RFC 5187 Graceful Restart.
4 * Copyright 2021 NetDEF (c), All rights reserved.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31 #include "ospf6d/ospf6_lsa.h"
32 #include "ospf6d/ospf6_lsdb.h"
33 #include "ospf6d/ospf6_route.h"
34 #include "ospf6d/ospf6_area.h"
35 #include "ospf6d/ospf6_interface.h"
36 #include "ospf6d/ospf6d.h"
37 #include "ospf6d/ospf6_asbr.h"
38 #include "ospf6d/ospf6_zebra.h"
39 #include "ospf6d/ospf6_message.h"
40 #include "ospf6d/ospf6_neighbor.h"
41 #include "ospf6d/ospf6_flood.h"
42 #include "ospf6d/ospf6_intra.h"
43 #include "ospf6d/ospf6_spf.h"
44 #include "ospf6d/ospf6_gr.h"
45 #ifndef VTYSH_EXTRACT_PL
46 #include "ospf6d/ospf6_gr_clippy.c"
49 static void ospf6_gr_nvm_delete(struct ospf6
*ospf6
);
51 /* Originate and install Grace-LSA for a given interface. */
52 static int ospf6_gr_lsa_originate(struct ospf6_interface
*oi
)
54 struct ospf6_gr_info
*gr_info
= &oi
->area
->ospf6
->gr_info
;
55 struct ospf6_lsa_header
*lsa_header
;
56 struct ospf6_grace_lsa
*grace_lsa
;
57 struct ospf6_lsa
*lsa
;
58 char buffer
[OSPF6_MAX_LSASIZE
];
60 if (IS_OSPF6_DEBUG_ORIGINATE(LINK
))
61 zlog_debug("Originate Link-LSA for Interface %s",
65 memset(buffer
, 0, sizeof(buffer
));
66 lsa_header
= (struct ospf6_lsa_header
*)buffer
;
68 (struct ospf6_grace_lsa
*)((caddr_t
)lsa_header
69 + sizeof(struct ospf6_lsa_header
));
71 /* Put grace period. */
72 grace_lsa
->tlv_period
.header
.type
= htons(GRACE_PERIOD_TYPE
);
73 grace_lsa
->tlv_period
.header
.length
= htons(GRACE_PERIOD_LENGTH
);
74 grace_lsa
->tlv_period
.interval
= htonl(gr_info
->grace_period
);
76 /* Put restart reason. */
77 grace_lsa
->tlv_reason
.header
.type
= htons(RESTART_REASON_TYPE
);
78 grace_lsa
->tlv_reason
.header
.length
= htons(RESTART_REASON_LENGTH
);
79 if (gr_info
->restart_support
)
80 grace_lsa
->tlv_reason
.reason
= OSPF6_GR_SW_RESTART
;
82 grace_lsa
->tlv_reason
.reason
= OSPF6_GR_UNKNOWN_RESTART
;
86 lsa_header
->type
= htons(OSPF6_LSTYPE_GRACE_LSA
);
87 lsa_header
->id
= htonl(oi
->interface
->ifindex
);
88 lsa_header
->adv_router
= oi
->area
->ospf6
->router_id
;
90 ospf6_new_ls_seqnum(lsa_header
->type
, lsa_header
->id
,
91 lsa_header
->adv_router
, oi
->lsdb
);
92 lsa_header
->length
= htons(sizeof(*lsa_header
) + sizeof(*grace_lsa
));
95 ospf6_lsa_checksum(lsa_header
);
98 lsa
= ospf6_lsa_create(lsa_header
);
101 ospf6_lsa_originate_interface(lsa
, oi
);
106 /* Flush all self-originated Grace-LSAs. */
107 static void ospf6_gr_flush_grace_lsas(struct ospf6
*ospf6
)
109 struct ospf6_area
*area
;
110 struct listnode
*anode
;
112 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, anode
, area
)) {
113 struct ospf6_lsa
*lsa
;
114 struct ospf6_interface
*oi
;
115 struct listnode
*inode
;
117 if (IS_DEBUG_OSPF6_GR
)
119 "GR: flushing self-originated Grace-LSAs [area %pI4]",
122 for (ALL_LIST_ELEMENTS_RO(area
->if_list
, inode
, oi
)) {
123 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_GRACE_LSA
),
124 htonl(oi
->interface
->ifindex
),
125 oi
->area
->ospf6
->router_id
,
129 "%s: Grace-LSA not found [interface %s] [area %pI4]",
130 __func__
, oi
->interface
->name
,
135 ospf6_lsa_purge(lsa
);
140 /* Exit from the Graceful Restart mode. */
141 static void ospf6_gr_restart_exit(struct ospf6
*ospf6
, const char *reason
)
143 struct ospf6_area
*area
;
144 struct listnode
*onode
, *anode
;
146 if (IS_DEBUG_OSPF6_GR
)
147 zlog_debug("GR: exiting graceful restart: %s", reason
);
149 ospf6
->gr_info
.restart_in_progress
= false;
150 ospf6
->gr_info
.finishing_restart
= true;
151 THREAD_OFF(ospf6
->gr_info
.t_grace_period
);
153 /* Record in non-volatile memory that the restart is complete. */
154 ospf6_gr_nvm_delete(ospf6
);
156 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, onode
, area
)) {
157 struct ospf6_interface
*oi
;
160 * 1) The router should reoriginate its router-LSAs for all
161 * attached areas in order to make sure they have the correct
164 OSPF6_ROUTER_LSA_EXECUTE(area
);
166 for (ALL_LIST_ELEMENTS_RO(area
->if_list
, anode
, oi
)) {
167 OSPF6_LINK_LSA_EXECUTE(oi
);
170 * 2) The router should reoriginate network-LSAs on all
171 * segments where it is the Designated Router.
173 if (oi
->state
== OSPF6_INTERFACE_DR
)
174 OSPF6_NETWORK_LSA_EXECUTE(oi
);
179 * 3) The router reruns its OSPF routing calculations, this time
180 * installing the results into the system forwarding table, and
181 * originating summary-LSAs, Type-7 LSAs and AS-external-LSAs as
184 * 4) Any remnant entries in the system forwarding table that were
185 * installed before the restart, but that are no longer valid,
188 ospf6_spf_schedule(ospf6
, OSPF6_SPF_FLAGS_GR_FINISH
);
190 /* 6) Any grace-LSAs that the router originated should be flushed. */
191 ospf6_gr_flush_grace_lsas(ospf6
);
194 #define RTR_LSA_MISSING 0
195 #define RTR_LSA_ADJ_FOUND 1
196 #define RTR_LSA_ADJ_NOT_FOUND 2
198 /* Check if a Router-LSA exists and if it contains a given link. */
199 static int ospf6_router_lsa_contains_adj(struct ospf6_area
*area
,
200 in_addr_t adv_router
,
201 in_addr_t neighbor_router_id
)
204 struct ospf6_lsa
*lsa
;
207 type
= ntohs(OSPF6_LSTYPE_ROUTER
);
208 for (ALL_LSDB_TYPED_ADVRTR(area
->lsdb
, type
, adv_router
, lsa
)) {
209 struct ospf6_router_lsa
*router_lsa
;
210 char *start
, *end
, *current
;
213 router_lsa
= (struct ospf6_router_lsa
214 *)((char *)lsa
->header
215 + sizeof(struct ospf6_lsa_header
));
217 /* Iterate over all interfaces in the Router-LSA. */
218 start
= (char *)router_lsa
+ sizeof(struct ospf6_router_lsa
);
219 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
220 for (current
= start
;
221 current
+ sizeof(struct ospf6_router_lsdesc
) <= end
;
222 current
+= sizeof(struct ospf6_router_lsdesc
)) {
223 struct ospf6_router_lsdesc
*lsdesc
;
225 lsdesc
= (struct ospf6_router_lsdesc
*)current
;
226 if (lsdesc
->type
!= OSPF6_ROUTER_LSDESC_POINTTOPOINT
)
229 if (lsdesc
->neighbor_router_id
== neighbor_router_id
)
230 return RTR_LSA_ADJ_FOUND
;
235 return RTR_LSA_MISSING
;
237 return RTR_LSA_ADJ_NOT_FOUND
;
240 static bool ospf6_gr_check_router_lsa_consistency(struct ospf6
*ospf6
,
241 struct ospf6_area
*area
,
242 struct ospf6_lsa
*lsa
)
244 if (lsa
->header
->adv_router
== ospf6
->router_id
) {
245 struct ospf6_router_lsa
*router_lsa
;
246 char *start
, *end
, *current
;
248 router_lsa
= (struct ospf6_router_lsa
249 *)((char *)lsa
->header
250 + sizeof(struct ospf6_lsa_header
));
252 /* Iterate over all interfaces in the Router-LSA. */
253 start
= (char *)router_lsa
+ sizeof(struct ospf6_router_lsa
);
254 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
255 for (current
= start
;
256 current
+ sizeof(struct ospf6_router_lsdesc
) <= end
;
257 current
+= sizeof(struct ospf6_router_lsdesc
)) {
258 struct ospf6_router_lsdesc
*lsdesc
;
260 lsdesc
= (struct ospf6_router_lsdesc
*)current
;
261 if (lsdesc
->type
!= OSPF6_ROUTER_LSDESC_POINTTOPOINT
)
264 if (ospf6_router_lsa_contains_adj(
265 area
, lsdesc
->neighbor_router_id
,
267 == RTR_LSA_ADJ_NOT_FOUND
)
273 adj1
= ospf6_router_lsa_contains_adj(area
, ospf6
->router_id
,
274 lsa
->header
->adv_router
);
275 adj2
= ospf6_router_lsa_contains_adj(
276 area
, lsa
->header
->adv_router
, ospf6
->router_id
);
277 if ((adj1
== RTR_LSA_ADJ_FOUND
&& adj2
== RTR_LSA_ADJ_NOT_FOUND
)
278 || (adj1
== RTR_LSA_ADJ_NOT_FOUND
279 && adj2
== RTR_LSA_ADJ_FOUND
))
287 * Check for LSAs that are inconsistent with the pre-restart LSAs, and abort the
288 * ongoing graceful restart when that's the case.
290 void ospf6_gr_check_lsdb_consistency(struct ospf6
*ospf6
,
291 struct ospf6_area
*area
)
294 struct ospf6_lsa
*lsa
;
296 type
= ntohs(OSPF6_LSTYPE_ROUTER
);
297 for (ALL_LSDB_TYPED(area
->lsdb
, type
, lsa
)) {
298 if (!ospf6_gr_check_router_lsa_consistency(ospf6
, area
, lsa
)) {
301 snprintfrr(reason
, sizeof(reason
),
302 "detected inconsistent LSA %s [area %pI4]",
303 lsa
->name
, &area
->area_id
);
304 ospf6_gr_restart_exit(ospf6
, reason
);
310 /* Check if there's a fully formed adjacency with the given neighbor ID. */
311 static bool ospf6_gr_check_adj_id(struct ospf6_area
*area
,
312 in_addr_t neighbor_router_id
)
314 struct ospf6_neighbor
*nbr
;
316 nbr
= ospf6_area_neighbor_lookup(area
, neighbor_router_id
);
317 if (!nbr
|| nbr
->state
< OSPF6_NEIGHBOR_FULL
) {
318 if (IS_DEBUG_OSPF6_GR
)
319 zlog_debug("GR: missing adjacency to router %pI4",
320 &neighbor_router_id
);
327 static bool ospf6_gr_check_adjs_lsa_transit(struct ospf6_area
*area
,
328 in_addr_t neighbor_router_id
,
329 uint32_t neighbor_interface_id
)
331 struct ospf6
*ospf6
= area
->ospf6
;
333 /* Check if we are the DR. */
334 if (neighbor_router_id
== ospf6
->router_id
) {
335 struct ospf6_lsa
*lsa
;
336 char *start
, *end
, *current
;
337 struct ospf6_network_lsa
*network_lsa
;
338 struct ospf6_network_lsdesc
*lsdesc
;
340 /* Lookup Network LSA corresponding to this interface. */
341 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_NETWORK
),
342 neighbor_interface_id
,
343 neighbor_router_id
, area
->lsdb
);
347 /* Iterate over all routers present in the network. */
348 network_lsa
= (struct ospf6_network_lsa
349 *)((char *)lsa
->header
350 + sizeof(struct ospf6_lsa_header
));
351 start
= (char *)network_lsa
+ sizeof(struct ospf6_network_lsa
);
352 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
353 for (current
= start
;
354 current
+ sizeof(struct ospf6_network_lsdesc
) <= end
;
355 current
+= sizeof(struct ospf6_network_lsdesc
)) {
356 lsdesc
= (struct ospf6_network_lsdesc
*)current
;
358 /* Skip self in the pseudonode. */
359 if (lsdesc
->router_id
== ospf6
->router_id
)
363 * Check if there's a fully formed adjacency with this
366 if (!ospf6_gr_check_adj_id(area
, lsdesc
->router_id
))
370 struct ospf6_neighbor
*nbr
;
372 /* Check if there's a fully formed adjacency with the DR. */
373 nbr
= ospf6_area_neighbor_lookup(area
, neighbor_router_id
);
374 if (!nbr
|| nbr
->state
< OSPF6_NEIGHBOR_FULL
) {
375 if (IS_DEBUG_OSPF6_GR
)
377 "GR: missing adjacency to DR router %pI4",
378 &neighbor_router_id
);
386 static bool ospf6_gr_check_adjs_lsa(struct ospf6_area
*area
,
387 struct ospf6_lsa
*lsa
)
389 struct ospf6_router_lsa
*router_lsa
;
390 char *start
, *end
, *current
;
393 (struct ospf6_router_lsa
*)((char *)lsa
->header
394 + sizeof(struct ospf6_lsa_header
));
396 /* Iterate over all interfaces in the Router-LSA. */
397 start
= (char *)router_lsa
+ sizeof(struct ospf6_router_lsa
);
398 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
399 for (current
= start
;
400 current
+ sizeof(struct ospf6_router_lsdesc
) <= end
;
401 current
+= sizeof(struct ospf6_router_lsdesc
)) {
402 struct ospf6_router_lsdesc
*lsdesc
;
404 lsdesc
= (struct ospf6_router_lsdesc
*)current
;
405 switch (lsdesc
->type
) {
406 case OSPF6_ROUTER_LSDESC_POINTTOPOINT
:
407 if (!ospf6_gr_check_adj_id(area
,
408 lsdesc
->neighbor_router_id
))
411 case OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK
:
412 if (!ospf6_gr_check_adjs_lsa_transit(
413 area
, lsdesc
->neighbor_router_id
,
414 lsdesc
->neighbor_interface_id
))
426 * Check if all adjacencies prior to the restart were reestablished.
428 * This is done using pre-restart Router LSAs and pre-restart Network LSAs
429 * received from the helping neighbors.
431 static bool ospf6_gr_check_adjs(struct ospf6
*ospf6
)
433 struct ospf6_area
*area
;
434 struct listnode
*node
;
436 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, node
, area
)) {
439 struct ospf6_lsa
*lsa_self
;
442 type
= ntohs(OSPF6_LSTYPE_ROUTER
);
443 router
= ospf6
->router_id
;
444 for (ALL_LSDB_TYPED_ADVRTR(area
->lsdb
, type
, router
,
447 if (!ospf6_gr_check_adjs_lsa(area
, lsa_self
))
457 /* Handling of grace period expiry. */
458 static int ospf6_gr_grace_period_expired(struct thread
*thread
)
460 struct ospf6
*ospf6
= THREAD_ARG(thread
);
462 ospf6
->gr_info
.t_grace_period
= NULL
;
463 ospf6_gr_restart_exit(ospf6
, "grace period has expired");
469 * Record in non-volatile memory that the given OSPF instance is attempting to
470 * perform a graceful restart.
472 static void ospf6_gr_nvm_update(struct ospf6
*ospf6
)
474 const char *inst_name
;
476 json_object
*json_instances
;
477 json_object
*json_instance
;
479 inst_name
= ospf6
->name
? ospf6
->name
: VRF_DEFAULT_NAME
;
481 json
= json_object_from_file((char *)OSPF6D_GR_STATE
);
483 json
= json_object_new_object();
485 json_object_object_get_ex(json
, "instances", &json_instances
);
486 if (!json_instances
) {
487 json_instances
= json_object_new_object();
488 json_object_object_add(json
, "instances", json_instances
);
491 json_object_object_get_ex(json_instances
, inst_name
, &json_instance
);
492 if (!json_instance
) {
493 json_instance
= json_object_new_object();
494 json_object_object_add(json_instances
, inst_name
,
499 * Record not only the grace period, but also a UNIX timestamp
500 * corresponding to the end of that period. That way, once ospf6d is
501 * restarted, it will be possible to take into account the time that
502 * passed while ospf6d wasn't running.
504 json_object_int_add(json_instance
, "gracePeriod",
505 ospf6
->gr_info
.grace_period
);
506 json_object_int_add(json_instance
, "timestamp",
507 time(NULL
) + ospf6
->gr_info
.grace_period
);
509 json_object_to_file_ext((char *)OSPF6D_GR_STATE
, json
,
510 JSON_C_TO_STRING_PRETTY
);
511 json_object_free(json
);
515 * Delete GR status information about the given OSPF instance from non-volatile
518 static void ospf6_gr_nvm_delete(struct ospf6
*ospf6
)
520 const char *inst_name
;
522 json_object
*json_instances
;
524 inst_name
= ospf6
->name
? ospf6
->name
: VRF_DEFAULT_NAME
;
526 json
= json_object_from_file((char *)OSPF6D_GR_STATE
);
528 json
= json_object_new_object();
530 json_object_object_get_ex(json
, "instances", &json_instances
);
531 if (!json_instances
) {
532 json_instances
= json_object_new_object();
533 json_object_object_add(json
, "instances", json_instances
);
536 json_object_object_del(json_instances
, inst_name
);
538 json_object_to_file_ext((char *)OSPF6D_GR_STATE
, json
,
539 JSON_C_TO_STRING_PRETTY
);
540 json_object_free(json
);
544 * Fetch from non-volatile memory whether the given OSPF instance is performing
545 * a graceful shutdown or not.
547 void ospf6_gr_nvm_read(struct ospf6
*ospf6
)
549 const char *inst_name
;
551 json_object
*json_instances
;
552 json_object
*json_instance
;
553 json_object
*json_timestamp
;
554 time_t timestamp
= 0;
556 inst_name
= ospf6
->name
? ospf6
->name
: VRF_DEFAULT_NAME
;
558 json
= json_object_from_file((char *)OSPF6D_GR_STATE
);
560 json
= json_object_new_object();
562 json_object_object_get_ex(json
, "instances", &json_instances
);
563 if (!json_instances
) {
564 json_instances
= json_object_new_object();
565 json_object_object_add(json
, "instances", json_instances
);
568 json_object_object_get_ex(json_instances
, inst_name
, &json_instance
);
569 if (!json_instance
) {
570 json_instance
= json_object_new_object();
571 json_object_object_add(json_instances
, inst_name
,
575 json_object_object_get_ex(json_instance
, "timestamp", &json_timestamp
);
576 if (json_timestamp
) {
578 unsigned long remaining_time
;
580 /* Check if the grace period has already expired. */
582 timestamp
= json_object_get_int(json_timestamp
);
583 if (now
> timestamp
) {
584 ospf6_gr_restart_exit(
585 ospf6
, "grace period has expired already");
587 /* Schedule grace period timeout. */
588 ospf6
->gr_info
.restart_in_progress
= true;
589 remaining_time
= timestamp
- time(NULL
);
590 if (IS_DEBUG_OSPF6_GR
)
592 "GR: remaining time until grace period expires: %lu(s)",
594 thread_add_timer(master
, ospf6_gr_grace_period_expired
,
595 ospf6
, remaining_time
,
596 &ospf6
->gr_info
.t_grace_period
);
600 json_object_object_del(json_instances
, inst_name
);
602 json_object_to_file_ext((char *)OSPF6D_GR_STATE
, json
,
603 JSON_C_TO_STRING_PRETTY
);
604 json_object_free(json
);
607 /* Prepare to start a Graceful Restart. */
608 static void ospf6_gr_prepare(void)
611 struct ospf6_interface
*oi
;
612 struct listnode
*onode
, *anode
, *inode
;
614 for (ALL_LIST_ELEMENTS_RO(om6
->ospf6
, onode
, ospf6
)) {
615 struct ospf6_area
*area
;
617 if (!ospf6
->gr_info
.restart_support
618 || ospf6
->gr_info
.prepare_in_progress
)
621 if (IS_DEBUG_OSPF6_GR
)
623 "GR: preparing to perform a graceful restart [period %u second(s)] [vrf %s]",
624 ospf6
->gr_info
.grace_period
,
625 ospf6_vrf_id_to_name(ospf6
->vrf_id
));
627 /* Freeze OSPF routes in the RIB. */
628 if (ospf6_zebra_gr_enable(ospf6
, ospf6
->gr_info
.grace_period
)) {
630 "%s: failed to activate graceful restart: not connected to zebra",
635 /* Send a Grace-LSA to all neighbors. */
636 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, anode
, area
)) {
637 for (ALL_LIST_ELEMENTS_RO(area
->if_list
, inode
, oi
)) {
638 if (oi
->state
< OSPF6_INTERFACE_POINTTOPOINT
)
640 ospf6_gr_lsa_originate(oi
);
644 /* Record end of the grace period in non-volatile memory. */
645 ospf6_gr_nvm_update(ospf6
);
648 * Mark that a Graceful Restart preparation is in progress, to
649 * prevent ospf6d from flushing its self-originated LSAs on
652 ospf6
->gr_info
.prepare_in_progress
= true;
656 static int ospf6_gr_neighbor_change(struct ospf6_neighbor
*on
, int next_state
,
659 struct ospf6
*ospf6
= on
->ospf6_if
->area
->ospf6
;
661 if (next_state
== OSPF6_NEIGHBOR_FULL
662 && ospf6
->gr_info
.restart_in_progress
) {
663 if (ospf6_gr_check_adjs(ospf6
)) {
664 ospf6_gr_restart_exit(
665 ospf6
, "all adjacencies were reestablished");
667 if (IS_DEBUG_OSPF6_GR
)
669 "GR: not all adjacencies were reestablished yet");
676 int config_write_ospf6_gr(struct vty
*vty
, struct ospf6
*ospf6
)
678 if (!ospf6
->gr_info
.restart_support
)
681 if (ospf6
->gr_info
.grace_period
== OSPF6_DFLT_GRACE_INTERVAL
)
682 vty_out(vty
, " graceful-restart\n");
684 vty_out(vty
, " graceful-restart grace-period %u\n",
685 ospf6
->gr_info
.grace_period
);
690 DEFPY(ospf6_graceful_restart_prepare
, ospf6_graceful_restart_prepare_cmd
,
691 "graceful-restart prepare ipv6 ospf",
692 "Graceful Restart commands\n"
693 "Prepare upcoming graceful restart\n" IPV6_STR
694 "Prepare to restart the OSPFv3 process")
701 DEFPY(ospf6_graceful_restart
, ospf6_graceful_restart_cmd
,
702 "graceful-restart [grace-period (1-1800)$grace_period]",
704 "Maximum length of the 'grace period'\n"
705 "Maximum length of the 'grace period' in seconds\n")
707 VTY_DECLVAR_INSTANCE_CONTEXT(ospf6
, ospf6
);
709 /* Check and get restart period if present. */
710 if (!grace_period_str
)
711 grace_period
= OSPF6_DFLT_GRACE_INTERVAL
;
713 ospf6
->gr_info
.restart_support
= true;
714 ospf6
->gr_info
.grace_period
= grace_period
;
719 DEFPY(ospf6_no_graceful_restart
, ospf6_no_graceful_restart_cmd
,
720 "no graceful-restart [period (1-1800)]",
722 "Maximum length of the 'grace period'\n"
723 "Maximum length of the 'grace period' in seconds\n")
725 VTY_DECLVAR_INSTANCE_CONTEXT(ospf6
, ospf6
);
727 if (!ospf6
->gr_info
.restart_support
)
730 if (ospf6
->gr_info
.prepare_in_progress
) {
732 "%% Error: Graceful Restart preparation in progress\n");
736 ospf6
->gr_info
.restart_support
= false;
737 ospf6
->gr_info
.grace_period
= OSPF6_DFLT_GRACE_INTERVAL
;
742 void ospf6_gr_init(void)
744 hook_register(ospf6_neighbor_change
, ospf6_gr_neighbor_change
);
746 install_element(ENABLE_NODE
, &ospf6_graceful_restart_prepare_cmd
);
747 install_element(OSPF6_NODE
, &ospf6_graceful_restart_cmd
);
748 install_element(OSPF6_NODE
, &ospf6_no_graceful_restart_cmd
);