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 #include "ospf6d/ospf6_gr_clippy.c"
47 static void ospf6_gr_nvm_delete(struct ospf6
*ospf6
);
49 /* Originate and install Grace-LSA for a given interface. */
50 static int ospf6_gr_lsa_originate(struct ospf6_interface
*oi
)
52 struct ospf6_gr_info
*gr_info
= &oi
->area
->ospf6
->gr_info
;
53 struct ospf6_lsa_header
*lsa_header
;
54 struct ospf6_grace_lsa
*grace_lsa
;
55 struct ospf6_lsa
*lsa
;
56 char buffer
[OSPF6_MAX_LSASIZE
];
58 if (IS_OSPF6_DEBUG_ORIGINATE(LINK
))
59 zlog_debug("Originate Grace-LSA for Interface %s",
63 memset(buffer
, 0, sizeof(buffer
));
64 lsa_header
= (struct ospf6_lsa_header
*)buffer
;
66 (struct ospf6_grace_lsa
*)((caddr_t
)lsa_header
67 + sizeof(struct ospf6_lsa_header
));
69 /* Put grace period. */
70 grace_lsa
->tlv_period
.header
.type
= htons(GRACE_PERIOD_TYPE
);
71 grace_lsa
->tlv_period
.header
.length
= htons(GRACE_PERIOD_LENGTH
);
72 grace_lsa
->tlv_period
.interval
= htonl(gr_info
->grace_period
);
74 /* Put restart reason. */
75 grace_lsa
->tlv_reason
.header
.type
= htons(RESTART_REASON_TYPE
);
76 grace_lsa
->tlv_reason
.header
.length
= htons(RESTART_REASON_LENGTH
);
77 if (gr_info
->restart_support
)
78 grace_lsa
->tlv_reason
.reason
= OSPF6_GR_SW_RESTART
;
80 grace_lsa
->tlv_reason
.reason
= OSPF6_GR_UNKNOWN_RESTART
;
84 lsa_header
->type
= htons(OSPF6_LSTYPE_GRACE_LSA
);
85 lsa_header
->id
= htonl(oi
->interface
->ifindex
);
86 lsa_header
->adv_router
= oi
->area
->ospf6
->router_id
;
88 ospf6_new_ls_seqnum(lsa_header
->type
, lsa_header
->id
,
89 lsa_header
->adv_router
, oi
->lsdb
);
90 lsa_header
->length
= htons(sizeof(*lsa_header
) + sizeof(*grace_lsa
));
93 ospf6_lsa_checksum(lsa_header
);
96 lsa
= ospf6_lsa_create(lsa_header
);
99 ospf6_lsa_originate_interface(lsa
, oi
);
104 /* Flush all self-originated Grace-LSAs. */
105 static void ospf6_gr_flush_grace_lsas(struct ospf6
*ospf6
)
107 struct ospf6_area
*area
;
108 struct listnode
*anode
;
110 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, anode
, area
)) {
111 struct ospf6_lsa
*lsa
;
112 struct ospf6_interface
*oi
;
113 struct listnode
*inode
;
115 if (IS_DEBUG_OSPF6_GR
)
117 "GR: flushing self-originated Grace-LSAs [area %pI4]",
120 for (ALL_LIST_ELEMENTS_RO(area
->if_list
, inode
, oi
)) {
121 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_GRACE_LSA
),
122 htonl(oi
->interface
->ifindex
),
123 oi
->area
->ospf6
->router_id
,
127 "%s: Grace-LSA not found [interface %s] [area %pI4]",
128 __func__
, oi
->interface
->name
,
133 ospf6_lsa_purge(lsa
);
138 /* Exit from the Graceful Restart mode. */
139 static void ospf6_gr_restart_exit(struct ospf6
*ospf6
, const char *reason
)
141 struct ospf6_area
*area
;
142 struct listnode
*onode
, *anode
;
144 if (IS_DEBUG_OSPF6_GR
)
145 zlog_debug("GR: exiting graceful restart: %s", reason
);
147 ospf6
->gr_info
.restart_in_progress
= false;
148 ospf6
->gr_info
.finishing_restart
= true;
149 THREAD_OFF(ospf6
->gr_info
.t_grace_period
);
151 /* Record in non-volatile memory that the restart is complete. */
152 ospf6_gr_nvm_delete(ospf6
);
154 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, onode
, area
)) {
155 struct ospf6_interface
*oi
;
158 * 1) The router should reoriginate its router-LSAs for all
159 * attached areas in order to make sure they have the correct
162 OSPF6_ROUTER_LSA_EXECUTE(area
);
164 for (ALL_LIST_ELEMENTS_RO(area
->if_list
, anode
, oi
)) {
165 OSPF6_LINK_LSA_EXECUTE(oi
);
168 * 2) The router should reoriginate network-LSAs on all
169 * segments where it is the Designated Router.
171 if (oi
->state
== OSPF6_INTERFACE_DR
)
172 OSPF6_NETWORK_LSA_EXECUTE(oi
);
177 * 3) The router reruns its OSPF routing calculations, this time
178 * installing the results into the system forwarding table, and
179 * originating summary-LSAs, Type-7 LSAs and AS-external-LSAs as
182 * 4) Any remnant entries in the system forwarding table that were
183 * installed before the restart, but that are no longer valid,
186 ospf6_spf_schedule(ospf6
, OSPF6_SPF_FLAGS_GR_FINISH
);
188 /* 6) Any grace-LSAs that the router originated should be flushed. */
189 ospf6_gr_flush_grace_lsas(ospf6
);
192 #define RTR_LSA_MISSING 0
193 #define RTR_LSA_ADJ_FOUND 1
194 #define RTR_LSA_ADJ_NOT_FOUND 2
196 /* Check if a Router-LSA exists and if it contains a given link. */
197 static int ospf6_router_lsa_contains_adj(struct ospf6_area
*area
,
198 in_addr_t adv_router
,
199 in_addr_t neighbor_router_id
)
202 struct ospf6_lsa
*lsa
;
205 type
= ntohs(OSPF6_LSTYPE_ROUTER
);
206 for (ALL_LSDB_TYPED_ADVRTR(area
->lsdb
, type
, adv_router
, lsa
)) {
207 struct ospf6_router_lsa
*router_lsa
;
208 char *start
, *end
, *current
;
211 router_lsa
= (struct ospf6_router_lsa
212 *)((char *)lsa
->header
213 + sizeof(struct ospf6_lsa_header
));
215 /* Iterate over all interfaces in the Router-LSA. */
216 start
= (char *)router_lsa
+ sizeof(struct ospf6_router_lsa
);
217 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
218 for (current
= start
;
219 current
+ sizeof(struct ospf6_router_lsdesc
) <= end
;
220 current
+= sizeof(struct ospf6_router_lsdesc
)) {
221 struct ospf6_router_lsdesc
*lsdesc
;
223 lsdesc
= (struct ospf6_router_lsdesc
*)current
;
224 if (lsdesc
->type
!= OSPF6_ROUTER_LSDESC_POINTTOPOINT
)
227 if (lsdesc
->neighbor_router_id
== neighbor_router_id
)
228 return RTR_LSA_ADJ_FOUND
;
233 return RTR_LSA_MISSING
;
235 return RTR_LSA_ADJ_NOT_FOUND
;
238 static bool ospf6_gr_check_router_lsa_consistency(struct ospf6
*ospf6
,
239 struct ospf6_area
*area
,
240 struct ospf6_lsa
*lsa
)
242 if (lsa
->header
->adv_router
== ospf6
->router_id
) {
243 struct ospf6_router_lsa
*router_lsa
;
244 char *start
, *end
, *current
;
246 router_lsa
= (struct ospf6_router_lsa
247 *)((char *)lsa
->header
248 + sizeof(struct ospf6_lsa_header
));
250 /* Iterate over all interfaces in the Router-LSA. */
251 start
= (char *)router_lsa
+ sizeof(struct ospf6_router_lsa
);
252 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
253 for (current
= start
;
254 current
+ sizeof(struct ospf6_router_lsdesc
) <= end
;
255 current
+= sizeof(struct ospf6_router_lsdesc
)) {
256 struct ospf6_router_lsdesc
*lsdesc
;
258 lsdesc
= (struct ospf6_router_lsdesc
*)current
;
259 if (lsdesc
->type
!= OSPF6_ROUTER_LSDESC_POINTTOPOINT
)
262 if (ospf6_router_lsa_contains_adj(
263 area
, lsdesc
->neighbor_router_id
,
265 == RTR_LSA_ADJ_NOT_FOUND
)
271 adj1
= ospf6_router_lsa_contains_adj(area
, ospf6
->router_id
,
272 lsa
->header
->adv_router
);
273 adj2
= ospf6_router_lsa_contains_adj(
274 area
, lsa
->header
->adv_router
, ospf6
->router_id
);
275 if ((adj1
== RTR_LSA_ADJ_FOUND
&& adj2
== RTR_LSA_ADJ_NOT_FOUND
)
276 || (adj1
== RTR_LSA_ADJ_NOT_FOUND
277 && adj2
== RTR_LSA_ADJ_FOUND
))
285 * Check for LSAs that are inconsistent with the pre-restart LSAs, and abort the
286 * ongoing graceful restart when that's the case.
288 void ospf6_gr_check_lsdb_consistency(struct ospf6
*ospf6
,
289 struct ospf6_area
*area
)
292 struct ospf6_lsa
*lsa
;
294 type
= ntohs(OSPF6_LSTYPE_ROUTER
);
295 for (ALL_LSDB_TYPED(area
->lsdb
, type
, lsa
)) {
296 if (!ospf6_gr_check_router_lsa_consistency(ospf6
, area
, lsa
)) {
299 snprintfrr(reason
, sizeof(reason
),
300 "detected inconsistent LSA %s [area %pI4]",
301 lsa
->name
, &area
->area_id
);
302 ospf6_gr_restart_exit(ospf6
, reason
);
308 /* Check if there's a fully formed adjacency with the given neighbor ID. */
309 static bool ospf6_gr_check_adj_id(struct ospf6_area
*area
,
310 in_addr_t neighbor_router_id
)
312 struct ospf6_neighbor
*nbr
;
314 nbr
= ospf6_area_neighbor_lookup(area
, neighbor_router_id
);
315 if (!nbr
|| nbr
->state
< OSPF6_NEIGHBOR_FULL
) {
316 if (IS_DEBUG_OSPF6_GR
)
317 zlog_debug("GR: missing adjacency to router %pI4",
318 &neighbor_router_id
);
325 static bool ospf6_gr_check_adjs_lsa_transit(struct ospf6_area
*area
,
326 in_addr_t neighbor_router_id
,
327 uint32_t neighbor_interface_id
)
329 struct ospf6
*ospf6
= area
->ospf6
;
331 /* Check if we are the DR. */
332 if (neighbor_router_id
== ospf6
->router_id
) {
333 struct ospf6_lsa
*lsa
;
334 char *start
, *end
, *current
;
335 struct ospf6_network_lsa
*network_lsa
;
336 struct ospf6_network_lsdesc
*lsdesc
;
338 /* Lookup Network LSA corresponding to this interface. */
339 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_NETWORK
),
340 neighbor_interface_id
,
341 neighbor_router_id
, area
->lsdb
);
345 /* Iterate over all routers present in the network. */
346 network_lsa
= (struct ospf6_network_lsa
347 *)((char *)lsa
->header
348 + sizeof(struct ospf6_lsa_header
));
349 start
= (char *)network_lsa
+ sizeof(struct ospf6_network_lsa
);
350 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
351 for (current
= start
;
352 current
+ sizeof(struct ospf6_network_lsdesc
) <= end
;
353 current
+= sizeof(struct ospf6_network_lsdesc
)) {
354 lsdesc
= (struct ospf6_network_lsdesc
*)current
;
356 /* Skip self in the pseudonode. */
357 if (lsdesc
->router_id
== ospf6
->router_id
)
361 * Check if there's a fully formed adjacency with this
364 if (!ospf6_gr_check_adj_id(area
, lsdesc
->router_id
))
368 struct ospf6_neighbor
*nbr
;
370 /* Check if there's a fully formed adjacency with the DR. */
371 nbr
= ospf6_area_neighbor_lookup(area
, neighbor_router_id
);
372 if (!nbr
|| nbr
->state
< OSPF6_NEIGHBOR_FULL
) {
373 if (IS_DEBUG_OSPF6_GR
)
375 "GR: missing adjacency to DR router %pI4",
376 &neighbor_router_id
);
384 static bool ospf6_gr_check_adjs_lsa(struct ospf6_area
*area
,
385 struct ospf6_lsa
*lsa
)
387 struct ospf6_router_lsa
*router_lsa
;
388 char *start
, *end
, *current
;
391 (struct ospf6_router_lsa
*)((char *)lsa
->header
392 + sizeof(struct ospf6_lsa_header
));
394 /* Iterate over all interfaces in the Router-LSA. */
395 start
= (char *)router_lsa
+ sizeof(struct ospf6_router_lsa
);
396 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
397 for (current
= start
;
398 current
+ sizeof(struct ospf6_router_lsdesc
) <= end
;
399 current
+= sizeof(struct ospf6_router_lsdesc
)) {
400 struct ospf6_router_lsdesc
*lsdesc
;
402 lsdesc
= (struct ospf6_router_lsdesc
*)current
;
403 switch (lsdesc
->type
) {
404 case OSPF6_ROUTER_LSDESC_POINTTOPOINT
:
405 if (!ospf6_gr_check_adj_id(area
,
406 lsdesc
->neighbor_router_id
))
409 case OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK
:
410 if (!ospf6_gr_check_adjs_lsa_transit(
411 area
, lsdesc
->neighbor_router_id
,
412 lsdesc
->neighbor_interface_id
))
424 * Check if all adjacencies prior to the restart were reestablished.
426 * This is done using pre-restart Router LSAs and pre-restart Network LSAs
427 * received from the helping neighbors.
429 static bool ospf6_gr_check_adjs(struct ospf6
*ospf6
)
431 struct ospf6_area
*area
;
432 struct listnode
*node
;
434 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, node
, area
)) {
437 struct ospf6_lsa
*lsa_self
;
440 type
= ntohs(OSPF6_LSTYPE_ROUTER
);
441 router
= ospf6
->router_id
;
442 for (ALL_LSDB_TYPED_ADVRTR(area
->lsdb
, type
, router
,
445 if (!ospf6_gr_check_adjs_lsa(area
, lsa_self
))
455 /* Handling of grace period expiry. */
456 static void ospf6_gr_grace_period_expired(struct thread
*thread
)
458 struct ospf6
*ospf6
= THREAD_ARG(thread
);
460 ospf6_gr_restart_exit(ospf6
, "grace period has expired");
464 * Record in non-volatile memory that the given OSPF instance is attempting to
465 * perform a graceful restart.
467 static void ospf6_gr_nvm_update(struct ospf6
*ospf6
)
469 const char *inst_name
;
471 json_object
*json_instances
;
472 json_object
*json_instance
;
474 inst_name
= ospf6
->name
? ospf6
->name
: VRF_DEFAULT_NAME
;
476 json
= json_object_from_file((char *)OSPF6D_GR_STATE
);
478 json
= json_object_new_object();
480 json_object_object_get_ex(json
, "instances", &json_instances
);
481 if (!json_instances
) {
482 json_instances
= json_object_new_object();
483 json_object_object_add(json
, "instances", json_instances
);
486 json_object_object_get_ex(json_instances
, inst_name
, &json_instance
);
487 if (!json_instance
) {
488 json_instance
= json_object_new_object();
489 json_object_object_add(json_instances
, inst_name
,
494 * Record not only the grace period, but also a UNIX timestamp
495 * corresponding to the end of that period. That way, once ospf6d is
496 * restarted, it will be possible to take into account the time that
497 * passed while ospf6d wasn't running.
499 json_object_int_add(json_instance
, "gracePeriod",
500 ospf6
->gr_info
.grace_period
);
501 json_object_int_add(json_instance
, "timestamp",
502 time(NULL
) + ospf6
->gr_info
.grace_period
);
504 json_object_to_file_ext((char *)OSPF6D_GR_STATE
, json
,
505 JSON_C_TO_STRING_PRETTY
);
506 json_object_free(json
);
510 * Delete GR status information about the given OSPF instance from non-volatile
513 static void ospf6_gr_nvm_delete(struct ospf6
*ospf6
)
515 const char *inst_name
;
517 json_object
*json_instances
;
519 inst_name
= ospf6
->name
? ospf6
->name
: VRF_DEFAULT_NAME
;
521 json
= json_object_from_file((char *)OSPF6D_GR_STATE
);
523 json
= json_object_new_object();
525 json_object_object_get_ex(json
, "instances", &json_instances
);
526 if (!json_instances
) {
527 json_instances
= json_object_new_object();
528 json_object_object_add(json
, "instances", json_instances
);
531 json_object_object_del(json_instances
, inst_name
);
533 json_object_to_file_ext((char *)OSPF6D_GR_STATE
, json
,
534 JSON_C_TO_STRING_PRETTY
);
535 json_object_free(json
);
539 * Fetch from non-volatile memory whether the given OSPF instance is performing
540 * a graceful shutdown or not.
542 void ospf6_gr_nvm_read(struct ospf6
*ospf6
)
544 const char *inst_name
;
546 json_object
*json_instances
;
547 json_object
*json_instance
;
548 json_object
*json_timestamp
;
549 time_t timestamp
= 0;
551 inst_name
= ospf6
->name
? ospf6
->name
: VRF_DEFAULT_NAME
;
553 json
= json_object_from_file((char *)OSPF6D_GR_STATE
);
555 json
= json_object_new_object();
557 json_object_object_get_ex(json
, "instances", &json_instances
);
558 if (!json_instances
) {
559 json_instances
= json_object_new_object();
560 json_object_object_add(json
, "instances", json_instances
);
563 json_object_object_get_ex(json_instances
, inst_name
, &json_instance
);
564 if (!json_instance
) {
565 json_instance
= json_object_new_object();
566 json_object_object_add(json_instances
, inst_name
,
570 json_object_object_get_ex(json_instance
, "timestamp", &json_timestamp
);
571 if (json_timestamp
) {
573 unsigned long remaining_time
;
575 /* Check if the grace period has already expired. */
577 timestamp
= json_object_get_int(json_timestamp
);
578 if (now
> timestamp
) {
579 ospf6_gr_restart_exit(
580 ospf6
, "grace period has expired already");
582 /* Schedule grace period timeout. */
583 ospf6
->gr_info
.restart_in_progress
= true;
584 remaining_time
= timestamp
- time(NULL
);
585 if (IS_DEBUG_OSPF6_GR
)
587 "GR: remaining time until grace period expires: %lu(s)",
589 thread_add_timer(master
, ospf6_gr_grace_period_expired
,
590 ospf6
, remaining_time
,
591 &ospf6
->gr_info
.t_grace_period
);
595 json_object_object_del(json_instances
, inst_name
);
597 json_object_to_file_ext((char *)OSPF6D_GR_STATE
, json
,
598 JSON_C_TO_STRING_PRETTY
);
599 json_object_free(json
);
602 /* Prepare to start a Graceful Restart. */
603 static void ospf6_gr_prepare(void)
606 struct ospf6_interface
*oi
;
607 struct listnode
*onode
, *anode
, *inode
;
609 for (ALL_LIST_ELEMENTS_RO(om6
->ospf6
, onode
, ospf6
)) {
610 struct ospf6_area
*area
;
612 if (!ospf6
->gr_info
.restart_support
613 || ospf6
->gr_info
.prepare_in_progress
)
616 if (IS_DEBUG_OSPF6_GR
)
618 "GR: preparing to perform a graceful restart [period %u second(s)] [vrf %s]",
619 ospf6
->gr_info
.grace_period
,
620 ospf6_vrf_id_to_name(ospf6
->vrf_id
));
622 /* Freeze OSPF routes in the RIB. */
623 if (ospf6_zebra_gr_enable(ospf6
, ospf6
->gr_info
.grace_period
)) {
625 "%s: failed to activate graceful restart: not connected to zebra",
630 /* Send a Grace-LSA to all neighbors. */
631 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, anode
, area
)) {
632 for (ALL_LIST_ELEMENTS_RO(area
->if_list
, inode
, oi
)) {
633 if (oi
->state
< OSPF6_INTERFACE_POINTTOPOINT
)
635 ospf6_gr_lsa_originate(oi
);
639 /* Record end of the grace period in non-volatile memory. */
640 ospf6_gr_nvm_update(ospf6
);
643 * Mark that a Graceful Restart preparation is in progress, to
644 * prevent ospf6d from flushing its self-originated LSAs on
647 ospf6
->gr_info
.prepare_in_progress
= true;
651 static int ospf6_gr_neighbor_change(struct ospf6_neighbor
*on
, int next_state
,
654 struct ospf6
*ospf6
= on
->ospf6_if
->area
->ospf6
;
656 if (next_state
== OSPF6_NEIGHBOR_FULL
657 && ospf6
->gr_info
.restart_in_progress
) {
658 if (ospf6_gr_check_adjs(ospf6
)) {
659 ospf6_gr_restart_exit(
660 ospf6
, "all adjacencies were reestablished");
662 if (IS_DEBUG_OSPF6_GR
)
664 "GR: not all adjacencies were reestablished yet");
671 int config_write_ospf6_gr(struct vty
*vty
, struct ospf6
*ospf6
)
673 if (!ospf6
->gr_info
.restart_support
)
676 if (ospf6
->gr_info
.grace_period
== OSPF6_DFLT_GRACE_INTERVAL
)
677 vty_out(vty
, " graceful-restart\n");
679 vty_out(vty
, " graceful-restart grace-period %u\n",
680 ospf6
->gr_info
.grace_period
);
685 DEFPY(ospf6_graceful_restart_prepare
, ospf6_graceful_restart_prepare_cmd
,
686 "graceful-restart prepare ipv6 ospf",
687 "Graceful Restart commands\n"
688 "Prepare upcoming graceful restart\n" IPV6_STR
689 "Prepare to restart the OSPFv3 process\n")
696 DEFPY(ospf6_graceful_restart
, ospf6_graceful_restart_cmd
,
697 "graceful-restart [grace-period (1-1800)$grace_period]",
699 "Maximum length of the 'grace period'\n"
700 "Maximum length of the 'grace period' in seconds\n")
702 VTY_DECLVAR_INSTANCE_CONTEXT(ospf6
, ospf6
);
704 /* Check and get restart period if present. */
705 if (!grace_period_str
)
706 grace_period
= OSPF6_DFLT_GRACE_INTERVAL
;
708 ospf6
->gr_info
.restart_support
= true;
709 ospf6
->gr_info
.grace_period
= grace_period
;
714 DEFPY(ospf6_no_graceful_restart
, ospf6_no_graceful_restart_cmd
,
715 "no graceful-restart [period (1-1800)]",
717 "Maximum length of the 'grace period'\n"
718 "Maximum length of the 'grace period' in seconds\n")
720 VTY_DECLVAR_INSTANCE_CONTEXT(ospf6
, ospf6
);
722 if (!ospf6
->gr_info
.restart_support
)
725 if (ospf6
->gr_info
.prepare_in_progress
) {
727 "%% Error: Graceful Restart preparation in progress\n");
731 ospf6
->gr_info
.restart_support
= false;
732 ospf6
->gr_info
.grace_period
= OSPF6_DFLT_GRACE_INTERVAL
;
737 void ospf6_gr_init(void)
739 hook_register(ospf6_neighbor_change
, ospf6_gr_neighbor_change
);
741 install_element(ENABLE_NODE
, &ospf6_graceful_restart_prepare_cmd
);
742 install_element(OSPF6_NODE
, &ospf6_graceful_restart_cmd
);
743 install_element(OSPF6_NODE
, &ospf6_no_graceful_restart_cmd
);