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
;
131 if (IS_DEBUG_OSPF6_GR
)
132 zlog_debug("GR: exiting graceful restart: %s", reason
);
134 ospf6
->gr_info
.restart_in_progress
= false;
135 ospf6
->gr_info
.finishing_restart
= true;
136 THREAD_OFF(ospf6
->gr_info
.t_grace_period
);
138 /* Record in non-volatile memory that the restart is complete. */
139 ospf6_gr_nvm_delete(ospf6
);
141 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, onode
, area
)) {
142 struct ospf6_interface
*oi
;
145 * 1) The router should reoriginate its router-LSAs for all
146 * attached areas in order to make sure they have the correct
149 OSPF6_ROUTER_LSA_EXECUTE(area
);
151 for (ALL_LIST_ELEMENTS_RO(area
->if_list
, anode
, oi
)) {
152 OSPF6_LINK_LSA_EXECUTE(oi
);
155 * 2) The router should reoriginate network-LSAs on all
156 * segments where it is the Designated Router.
158 if (oi
->state
== OSPF6_INTERFACE_DR
)
159 OSPF6_NETWORK_LSA_EXECUTE(oi
);
164 * 3) The router reruns its OSPF routing calculations, this time
165 * installing the results into the system forwarding table, and
166 * originating summary-LSAs, Type-7 LSAs and AS-external-LSAs as
169 * 4) Any remnant entries in the system forwarding table that were
170 * installed before the restart, but that are no longer valid,
173 ospf6_spf_schedule(ospf6
, OSPF6_SPF_FLAGS_GR_FINISH
);
175 /* 6) Any grace-LSAs that the router originated should be flushed. */
176 ospf6_gr_flush_grace_lsas(ospf6
);
179 #define RTR_LSA_MISSING 0
180 #define RTR_LSA_ADJ_FOUND 1
181 #define RTR_LSA_ADJ_NOT_FOUND 2
183 /* Check if a Router-LSA exists and if it contains a given link. */
184 static int ospf6_router_lsa_contains_adj(struct ospf6_area
*area
,
185 in_addr_t adv_router
,
186 in_addr_t neighbor_router_id
)
189 struct ospf6_lsa
*lsa
;
192 type
= ntohs(OSPF6_LSTYPE_ROUTER
);
193 for (ALL_LSDB_TYPED_ADVRTR(area
->lsdb
, type
, adv_router
, lsa
)) {
194 struct ospf6_router_lsa
*router_lsa
;
195 char *start
, *end
, *current
;
198 router_lsa
= (struct ospf6_router_lsa
199 *)((char *)lsa
->header
200 + sizeof(struct ospf6_lsa_header
));
202 /* Iterate over all interfaces in the Router-LSA. */
203 start
= (char *)router_lsa
+ sizeof(struct ospf6_router_lsa
);
204 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
205 for (current
= start
;
206 current
+ sizeof(struct ospf6_router_lsdesc
) <= end
;
207 current
+= sizeof(struct ospf6_router_lsdesc
)) {
208 struct ospf6_router_lsdesc
*lsdesc
;
210 lsdesc
= (struct ospf6_router_lsdesc
*)current
;
211 if (lsdesc
->type
!= OSPF6_ROUTER_LSDESC_POINTTOPOINT
)
214 if (lsdesc
->neighbor_router_id
== neighbor_router_id
)
215 return RTR_LSA_ADJ_FOUND
;
220 return RTR_LSA_MISSING
;
222 return RTR_LSA_ADJ_NOT_FOUND
;
225 static bool ospf6_gr_check_router_lsa_consistency(struct ospf6
*ospf6
,
226 struct ospf6_area
*area
,
227 struct ospf6_lsa
*lsa
)
229 if (lsa
->header
->adv_router
== ospf6
->router_id
) {
230 struct ospf6_router_lsa
*router_lsa
;
231 char *start
, *end
, *current
;
233 router_lsa
= (struct ospf6_router_lsa
234 *)((char *)lsa
->header
235 + sizeof(struct ospf6_lsa_header
));
237 /* Iterate over all interfaces in the Router-LSA. */
238 start
= (char *)router_lsa
+ sizeof(struct ospf6_router_lsa
);
239 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
240 for (current
= start
;
241 current
+ sizeof(struct ospf6_router_lsdesc
) <= end
;
242 current
+= sizeof(struct ospf6_router_lsdesc
)) {
243 struct ospf6_router_lsdesc
*lsdesc
;
245 lsdesc
= (struct ospf6_router_lsdesc
*)current
;
246 if (lsdesc
->type
!= OSPF6_ROUTER_LSDESC_POINTTOPOINT
)
249 if (ospf6_router_lsa_contains_adj(
250 area
, lsdesc
->neighbor_router_id
,
252 == RTR_LSA_ADJ_NOT_FOUND
)
258 adj1
= ospf6_router_lsa_contains_adj(area
, ospf6
->router_id
,
259 lsa
->header
->adv_router
);
260 adj2
= ospf6_router_lsa_contains_adj(
261 area
, lsa
->header
->adv_router
, ospf6
->router_id
);
262 if ((adj1
== RTR_LSA_ADJ_FOUND
&& adj2
== RTR_LSA_ADJ_NOT_FOUND
)
263 || (adj1
== RTR_LSA_ADJ_NOT_FOUND
264 && adj2
== RTR_LSA_ADJ_FOUND
))
272 * Check for LSAs that are inconsistent with the pre-restart LSAs, and abort the
273 * ongoing graceful restart when that's the case.
275 void ospf6_gr_check_lsdb_consistency(struct ospf6
*ospf6
,
276 struct ospf6_area
*area
)
279 struct ospf6_lsa
*lsa
;
281 type
= ntohs(OSPF6_LSTYPE_ROUTER
);
282 for (ALL_LSDB_TYPED(area
->lsdb
, type
, lsa
)) {
283 if (!ospf6_gr_check_router_lsa_consistency(ospf6
, area
, lsa
)) {
286 snprintfrr(reason
, sizeof(reason
),
287 "detected inconsistent LSA %s [area %pI4]",
288 lsa
->name
, &area
->area_id
);
289 ospf6_gr_restart_exit(ospf6
, reason
);
295 /* Check if there's a fully formed adjacency with the given neighbor ID. */
296 static bool ospf6_gr_check_adj_id(struct ospf6_area
*area
,
297 in_addr_t neighbor_router_id
)
299 struct ospf6_neighbor
*nbr
;
301 nbr
= ospf6_area_neighbor_lookup(area
, neighbor_router_id
);
302 if (!nbr
|| nbr
->state
< OSPF6_NEIGHBOR_FULL
) {
303 if (IS_DEBUG_OSPF6_GR
)
304 zlog_debug("GR: missing adjacency to router %pI4",
305 &neighbor_router_id
);
312 static bool ospf6_gr_check_adjs_lsa_transit(struct ospf6_area
*area
,
313 in_addr_t neighbor_router_id
,
314 uint32_t neighbor_interface_id
)
316 struct ospf6
*ospf6
= area
->ospf6
;
318 /* Check if we are the DR. */
319 if (neighbor_router_id
== ospf6
->router_id
) {
320 struct ospf6_lsa
*lsa
;
321 char *start
, *end
, *current
;
322 struct ospf6_network_lsa
*network_lsa
;
323 struct ospf6_network_lsdesc
*lsdesc
;
325 /* Lookup Network LSA corresponding to this interface. */
326 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_NETWORK
),
327 neighbor_interface_id
,
328 neighbor_router_id
, area
->lsdb
);
332 /* Iterate over all routers present in the network. */
333 network_lsa
= (struct ospf6_network_lsa
334 *)((char *)lsa
->header
335 + sizeof(struct ospf6_lsa_header
));
336 start
= (char *)network_lsa
+ sizeof(struct ospf6_network_lsa
);
337 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
338 for (current
= start
;
339 current
+ sizeof(struct ospf6_network_lsdesc
) <= end
;
340 current
+= sizeof(struct ospf6_network_lsdesc
)) {
341 lsdesc
= (struct ospf6_network_lsdesc
*)current
;
343 /* Skip self in the pseudonode. */
344 if (lsdesc
->router_id
== ospf6
->router_id
)
348 * Check if there's a fully formed adjacency with this
351 if (!ospf6_gr_check_adj_id(area
, lsdesc
->router_id
))
355 struct ospf6_neighbor
*nbr
;
357 /* Check if there's a fully formed adjacency with the DR. */
358 nbr
= ospf6_area_neighbor_lookup(area
, neighbor_router_id
);
359 if (!nbr
|| nbr
->state
< OSPF6_NEIGHBOR_FULL
) {
360 if (IS_DEBUG_OSPF6_GR
)
362 "GR: missing adjacency to DR router %pI4",
363 &neighbor_router_id
);
371 static bool ospf6_gr_check_adjs_lsa(struct ospf6_area
*area
,
372 struct ospf6_lsa
*lsa
)
374 struct ospf6_router_lsa
*router_lsa
;
375 char *start
, *end
, *current
;
378 (struct ospf6_router_lsa
*)((char *)lsa
->header
379 + sizeof(struct ospf6_lsa_header
));
381 /* Iterate over all interfaces in the Router-LSA. */
382 start
= (char *)router_lsa
+ sizeof(struct ospf6_router_lsa
);
383 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
384 for (current
= start
;
385 current
+ sizeof(struct ospf6_router_lsdesc
) <= end
;
386 current
+= sizeof(struct ospf6_router_lsdesc
)) {
387 struct ospf6_router_lsdesc
*lsdesc
;
389 lsdesc
= (struct ospf6_router_lsdesc
*)current
;
390 switch (lsdesc
->type
) {
391 case OSPF6_ROUTER_LSDESC_POINTTOPOINT
:
392 if (!ospf6_gr_check_adj_id(area
,
393 lsdesc
->neighbor_router_id
))
396 case OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK
:
397 if (!ospf6_gr_check_adjs_lsa_transit(
398 area
, lsdesc
->neighbor_router_id
,
399 lsdesc
->neighbor_interface_id
))
411 * Check if all adjacencies prior to the restart were reestablished.
413 * This is done using pre-restart Router LSAs and pre-restart Network LSAs
414 * received from the helping neighbors.
416 static bool ospf6_gr_check_adjs(struct ospf6
*ospf6
)
418 struct ospf6_area
*area
;
419 struct listnode
*node
;
421 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, node
, area
)) {
424 struct ospf6_lsa
*lsa_self
;
427 type
= ntohs(OSPF6_LSTYPE_ROUTER
);
428 router
= ospf6
->router_id
;
429 for (ALL_LSDB_TYPED_ADVRTR(area
->lsdb
, type
, router
,
432 if (!ospf6_gr_check_adjs_lsa(area
, lsa_self
))
442 /* Handling of grace period expiry. */
443 static void ospf6_gr_grace_period_expired(struct thread
*thread
)
445 struct ospf6
*ospf6
= THREAD_ARG(thread
);
447 ospf6_gr_restart_exit(ospf6
, "grace period has expired");
451 * Record in non-volatile memory that the given OSPF instance is attempting to
452 * perform a graceful restart.
454 static void ospf6_gr_nvm_update(struct ospf6
*ospf6
)
456 const char *inst_name
;
458 json_object
*json_instances
;
459 json_object
*json_instance
;
461 inst_name
= ospf6
->name
? ospf6
->name
: VRF_DEFAULT_NAME
;
463 json
= json_object_from_file((char *)OSPF6D_GR_STATE
);
465 json
= json_object_new_object();
467 json_object_object_get_ex(json
, "instances", &json_instances
);
468 if (!json_instances
) {
469 json_instances
= json_object_new_object();
470 json_object_object_add(json
, "instances", json_instances
);
473 json_object_object_get_ex(json_instances
, inst_name
, &json_instance
);
474 if (!json_instance
) {
475 json_instance
= json_object_new_object();
476 json_object_object_add(json_instances
, inst_name
,
481 * Record not only the grace period, but also a UNIX timestamp
482 * corresponding to the end of that period. That way, once ospf6d is
483 * restarted, it will be possible to take into account the time that
484 * passed while ospf6d wasn't running.
486 json_object_int_add(json_instance
, "gracePeriod",
487 ospf6
->gr_info
.grace_period
);
488 json_object_int_add(json_instance
, "timestamp",
489 time(NULL
) + ospf6
->gr_info
.grace_period
);
491 json_object_to_file_ext((char *)OSPF6D_GR_STATE
, json
,
492 JSON_C_TO_STRING_PRETTY
);
493 json_object_free(json
);
497 * Delete GR status information about the given OSPF instance from non-volatile
500 static void ospf6_gr_nvm_delete(struct ospf6
*ospf6
)
502 const char *inst_name
;
504 json_object
*json_instances
;
506 inst_name
= ospf6
->name
? ospf6
->name
: VRF_DEFAULT_NAME
;
508 json
= json_object_from_file((char *)OSPF6D_GR_STATE
);
510 json
= json_object_new_object();
512 json_object_object_get_ex(json
, "instances", &json_instances
);
513 if (!json_instances
) {
514 json_instances
= json_object_new_object();
515 json_object_object_add(json
, "instances", json_instances
);
518 json_object_object_del(json_instances
, inst_name
);
520 json_object_to_file_ext((char *)OSPF6D_GR_STATE
, json
,
521 JSON_C_TO_STRING_PRETTY
);
522 json_object_free(json
);
526 * Fetch from non-volatile memory whether the given OSPF instance is performing
527 * a graceful shutdown or not.
529 void ospf6_gr_nvm_read(struct ospf6
*ospf6
)
531 const char *inst_name
;
533 json_object
*json_instances
;
534 json_object
*json_instance
;
535 json_object
*json_timestamp
;
536 time_t timestamp
= 0;
538 inst_name
= ospf6
->name
? ospf6
->name
: VRF_DEFAULT_NAME
;
540 json
= json_object_from_file((char *)OSPF6D_GR_STATE
);
542 json
= json_object_new_object();
544 json_object_object_get_ex(json
, "instances", &json_instances
);
545 if (!json_instances
) {
546 json_instances
= json_object_new_object();
547 json_object_object_add(json
, "instances", json_instances
);
550 json_object_object_get_ex(json_instances
, inst_name
, &json_instance
);
551 if (!json_instance
) {
552 json_instance
= json_object_new_object();
553 json_object_object_add(json_instances
, inst_name
,
557 json_object_object_get_ex(json_instance
, "timestamp", &json_timestamp
);
558 if (json_timestamp
) {
560 unsigned long remaining_time
;
562 /* Check if the grace period has already expired. */
564 timestamp
= json_object_get_int(json_timestamp
);
565 if (now
> timestamp
) {
566 ospf6_gr_restart_exit(
567 ospf6
, "grace period has expired already");
569 /* Schedule grace period timeout. */
570 ospf6
->gr_info
.restart_in_progress
= true;
571 remaining_time
= timestamp
- time(NULL
);
572 if (IS_DEBUG_OSPF6_GR
)
574 "GR: remaining time until grace period expires: %lu(s)",
576 thread_add_timer(master
, ospf6_gr_grace_period_expired
,
577 ospf6
, remaining_time
,
578 &ospf6
->gr_info
.t_grace_period
);
582 json_object_object_del(json_instances
, inst_name
);
584 json_object_to_file_ext((char *)OSPF6D_GR_STATE
, json
,
585 JSON_C_TO_STRING_PRETTY
);
586 json_object_free(json
);
589 /* Prepare to start a Graceful Restart. */
590 static void ospf6_gr_prepare(void)
593 struct ospf6_interface
*oi
;
594 struct listnode
*onode
, *anode
, *inode
;
596 for (ALL_LIST_ELEMENTS_RO(om6
->ospf6
, onode
, ospf6
)) {
597 struct ospf6_area
*area
;
599 if (!ospf6
->gr_info
.restart_support
600 || ospf6
->gr_info
.prepare_in_progress
)
603 if (IS_DEBUG_OSPF6_GR
)
605 "GR: preparing to perform a graceful restart [period %u second(s)] [vrf %s]",
606 ospf6
->gr_info
.grace_period
,
607 ospf6_vrf_id_to_name(ospf6
->vrf_id
));
609 /* Freeze OSPF routes in the RIB. */
610 if (ospf6_zebra_gr_enable(ospf6
, ospf6
->gr_info
.grace_period
)) {
612 "%s: failed to activate graceful restart: not connected to zebra",
617 /* Send a Grace-LSA to all neighbors. */
618 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, anode
, area
)) {
619 for (ALL_LIST_ELEMENTS_RO(area
->if_list
, inode
, oi
)) {
620 if (oi
->state
< OSPF6_INTERFACE_POINTTOPOINT
)
622 ospf6_gr_lsa_originate(oi
);
626 /* Record end of the grace period in non-volatile memory. */
627 ospf6_gr_nvm_update(ospf6
);
630 * Mark that a Graceful Restart preparation is in progress, to
631 * prevent ospf6d from flushing its self-originated LSAs on
634 ospf6
->gr_info
.prepare_in_progress
= true;
638 static int ospf6_gr_neighbor_change(struct ospf6_neighbor
*on
, int next_state
,
641 struct ospf6
*ospf6
= on
->ospf6_if
->area
->ospf6
;
643 if (next_state
== OSPF6_NEIGHBOR_FULL
644 && ospf6
->gr_info
.restart_in_progress
) {
645 if (ospf6_gr_check_adjs(ospf6
)) {
646 ospf6_gr_restart_exit(
647 ospf6
, "all adjacencies were reestablished");
649 if (IS_DEBUG_OSPF6_GR
)
651 "GR: not all adjacencies were reestablished yet");
658 int config_write_ospf6_gr(struct vty
*vty
, struct ospf6
*ospf6
)
660 if (!ospf6
->gr_info
.restart_support
)
663 if (ospf6
->gr_info
.grace_period
== OSPF6_DFLT_GRACE_INTERVAL
)
664 vty_out(vty
, " graceful-restart\n");
666 vty_out(vty
, " graceful-restart grace-period %u\n",
667 ospf6
->gr_info
.grace_period
);
672 DEFPY(ospf6_graceful_restart_prepare
, ospf6_graceful_restart_prepare_cmd
,
673 "graceful-restart prepare ipv6 ospf",
674 "Graceful Restart commands\n"
675 "Prepare upcoming graceful restart\n" IPV6_STR
676 "Prepare to restart the OSPFv3 process\n")
683 DEFPY(ospf6_graceful_restart
, ospf6_graceful_restart_cmd
,
684 "graceful-restart [grace-period (1-1800)$grace_period]",
686 "Maximum length of the 'grace period'\n"
687 "Maximum length of the 'grace period' in seconds\n")
689 VTY_DECLVAR_INSTANCE_CONTEXT(ospf6
, ospf6
);
691 /* Check and get restart period if present. */
692 if (!grace_period_str
)
693 grace_period
= OSPF6_DFLT_GRACE_INTERVAL
;
695 ospf6
->gr_info
.restart_support
= true;
696 ospf6
->gr_info
.grace_period
= grace_period
;
701 DEFPY(ospf6_no_graceful_restart
, ospf6_no_graceful_restart_cmd
,
702 "no graceful-restart [period (1-1800)]",
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 if (!ospf6
->gr_info
.restart_support
)
712 if (ospf6
->gr_info
.prepare_in_progress
) {
714 "%% Error: Graceful Restart preparation in progress\n");
718 ospf6
->gr_info
.restart_support
= false;
719 ospf6
->gr_info
.grace_period
= OSPF6_DFLT_GRACE_INTERVAL
;
724 void ospf6_gr_init(void)
726 hook_register(ospf6_neighbor_change
, ospf6_gr_neighbor_change
);
728 install_element(ENABLE_NODE
, &ospf6_graceful_restart_prepare_cmd
);
729 install_element(OSPF6_NODE
, &ospf6_graceful_restart_cmd
);
730 install_element(OSPF6_NODE
, &ospf6_no_graceful_restart_cmd
);