2 * This is an implementation of RFC 3623 Graceful OSPF Restart.
4 * Copyright 2021 NetDEF (c), All rights reserved.
5 * Copyright 2020 6WIND (c), All rights reserved.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31 #include "ospfd/ospfd.h"
32 #include "ospfd/ospf_abr.h"
33 #include "ospfd/ospf_flood.h"
34 #include "ospfd/ospf_ism.h"
35 #include "ospfd/ospf_interface.h"
36 #include "ospfd/ospf_asbr.h"
37 #include "ospfd/ospf_lsa.h"
38 #include "ospfd/ospf_route.h"
39 #include "ospfd/ospf_zebra.h"
40 #include "ospfd/ospf_lsdb.h"
41 #include "ospfd/ospf_neighbor.h"
42 #include "ospfd/ospf_opaque.h"
43 #include "ospfd/ospf_nsm.h"
44 #include "ospfd/ospf_gr.h"
45 #include "ospfd/ospf_errors.h"
46 #include "ospfd/ospf_dump.h"
47 #ifndef VTYSH_EXTRACT_PL
48 #include "ospfd/ospf_gr_clippy.c"
51 static void ospf_gr_nvm_delete(struct ospf
*ospf
);
53 /* Lookup self-originated Grace-LSA in the LSDB. */
54 static struct ospf_lsa
*ospf_gr_lsa_lookup(struct ospf
*ospf
,
55 struct ospf_area
*area
)
58 struct in_addr lsa_id
;
59 uint32_t lsa_id_host_byte_order
;
61 lsa_id_host_byte_order
= SET_OPAQUE_LSID(OPAQUE_TYPE_GRACE_LSA
, 0);
62 lsa_id
.s_addr
= htonl(lsa_id_host_byte_order
);
63 lsa
= ospf_lsa_lookup(ospf
, area
, OSPF_OPAQUE_LINK_LSA
, lsa_id
,
69 /* Fill in fields of the Grace-LSA that is being originated. */
70 static void ospf_gr_lsa_body_set(struct ospf_gr_info
*gr_info
,
71 struct ospf_interface
*oi
, struct stream
*s
)
73 struct grace_tlv_graceperiod tlv_period
= {};
74 struct grace_tlv_restart_reason tlv_reason
= {};
75 struct grace_tlv_restart_addr tlv_address
= {};
77 /* Put grace period. */
78 tlv_period
.header
.type
= htons(GRACE_PERIOD_TYPE
);
79 tlv_period
.header
.length
= htons(GRACE_PERIOD_LENGTH
);
80 tlv_period
.interval
= htonl(gr_info
->grace_period
);
81 stream_put(s
, &tlv_period
, sizeof(tlv_period
));
83 /* Put restart reason. */
84 tlv_reason
.header
.type
= htons(RESTART_REASON_TYPE
);
85 tlv_reason
.header
.length
= htons(RESTART_REASON_LENGTH
);
86 if (gr_info
->restart_support
)
87 tlv_reason
.reason
= OSPF_GR_SW_RESTART
;
89 tlv_reason
.reason
= OSPF_GR_UNKNOWN_RESTART
;
90 stream_put(s
, &tlv_reason
, sizeof(tlv_reason
));
93 if (oi
->type
== OSPF_IFTYPE_BROADCAST
|| oi
->type
== OSPF_IFTYPE_NBMA
94 || oi
->type
== OSPF_IFTYPE_POINTOMULTIPOINT
) {
95 tlv_address
.header
.type
= htons(RESTARTER_IP_ADDR_TYPE
);
96 tlv_address
.header
.length
= htons(RESTARTER_IP_ADDR_LEN
);
97 tlv_address
.addr
= oi
->address
->u
.prefix4
;
98 stream_put(s
, &tlv_address
, sizeof(tlv_address
));
102 /* Generate Grace-LSA for a given interface. */
103 static struct ospf_lsa
*ospf_gr_lsa_new(struct ospf_interface
*oi
)
106 struct lsa_header
*lsah
;
107 struct ospf_lsa
*new;
108 uint8_t options
, lsa_type
;
109 struct in_addr lsa_id
;
110 uint32_t lsa_id_host_byte_order
;
113 /* Create a stream for LSA. */
114 s
= stream_new(OSPF_MAX_LSA_SIZE
);
116 lsah
= (struct lsa_header
*)STREAM_DATA(s
);
118 options
= LSA_OPTIONS_GET(oi
->area
);
119 options
|= LSA_OPTIONS_NSSA_GET(oi
->area
);
120 options
|= OSPF_OPTION_O
;
122 lsa_type
= OSPF_OPAQUE_LINK_LSA
;
123 lsa_id_host_byte_order
= SET_OPAQUE_LSID(OPAQUE_TYPE_GRACE_LSA
, 0);
124 lsa_id
.s_addr
= htonl(lsa_id_host_byte_order
);
126 /* Set opaque-LSA header fields. */
127 lsa_header_set(s
, options
, lsa_type
, lsa_id
, oi
->ospf
->router_id
);
129 /* Set opaque-LSA body fields. */
130 ospf_gr_lsa_body_set(&oi
->ospf
->gr_info
, oi
, s
);
133 length
= stream_get_endp(s
);
134 lsah
->length
= htons(length
);
136 /* Now, create an OSPF LSA instance. */
137 new = ospf_lsa_new_and_data(length
);
139 if (IS_DEBUG_OSPF_GR
)
140 zlog_debug("LSA[Type%d:%pI4]: Create an Opaque-LSA/GR instance",
143 new->area
= oi
->area
;
145 SET_FLAG(new->flags
, OSPF_LSA_SELF
);
146 memcpy(new->data
, lsah
, length
);
152 /* Originate and install Grace-LSA for a given interface. */
153 static void ospf_gr_lsa_originate(struct ospf_interface
*oi
)
155 struct ospf_lsa
*lsa
, *old
;
157 if (ospf_interface_neighbor_count(oi
) == 0)
160 /* Create new Grace-LSA. */
161 lsa
= ospf_gr_lsa_new(oi
);
163 zlog_warn("%s: ospf_gr_lsa_new() failed", __func__
);
167 /* Find the old LSA and increase the seqno. */
168 old
= ospf_gr_lsa_lookup(oi
->ospf
, oi
->area
);
170 lsa
->data
->ls_seqnum
= lsa_seqnum_increment(old
);
172 /* Install this LSA into LSDB. */
173 if (ospf_lsa_install(oi
->ospf
, oi
, lsa
) == NULL
) {
174 zlog_warn("%s: ospf_lsa_install() failed", __func__
);
175 ospf_lsa_unlock(&lsa
);
179 /* Update new LSA origination count. */
180 oi
->ospf
->lsa_originate_count
++;
182 /* Flood the LSA through out the interface */
183 ospf_flood_through_interface(oi
, NULL
, lsa
);
186 /* Flush a given self-originated Grace-LSA. */
187 static struct ospf_lsa
*ospf_gr_flush_grace_lsa(struct ospf_interface
*oi
,
188 struct ospf_lsa
*old
)
190 struct ospf_lsa
*lsa
;
192 if (ospf_interface_neighbor_count(oi
) == 0)
195 if (IS_DEBUG_OSPF_GR
)
197 "GR: flushing self-originated Grace-LSAs [interface %s]",
200 lsa
= ospf_lsa_dup(old
);
201 lsa
->data
->ls_age
= htons(OSPF_LSA_MAXAGE
);
202 lsa
->data
->ls_seqnum
= lsa_seqnum_increment(lsa
);
204 /* Install updated LSA into LSDB. */
205 if (ospf_lsa_install(oi
->ospf
, oi
, lsa
) == NULL
) {
206 zlog_warn("%s: ospf_lsa_install() failed", __func__
);
207 ospf_lsa_unlock(&lsa
);
211 /* Flood the LSA through out the interface */
212 ospf_flood_through_interface(oi
, NULL
, lsa
);
217 /* Flush all self-originated Grace-LSAs. */
218 static void ospf_gr_flush_grace_lsas(struct ospf
*ospf
)
220 struct ospf_area
*area
;
221 struct listnode
*anode
;
223 for (ALL_LIST_ELEMENTS_RO(ospf
->areas
, anode
, area
)) {
224 struct ospf_lsa
*lsa
;
225 struct ospf_interface
*oi
;
226 struct listnode
*inode
;
228 if (IS_DEBUG_OSPF_GR
)
230 "GR: flushing self-originated Grace-LSAs [area %pI4]",
233 lsa
= ospf_gr_lsa_lookup(ospf
, area
);
235 zlog_warn("%s: Grace-LSA not found [area %pI4]",
236 __func__
, &area
->area_id
);
240 for (ALL_LIST_ELEMENTS_RO(area
->oiflist
, inode
, oi
))
241 ospf_gr_flush_grace_lsa(oi
, lsa
);
245 /* Exit from the Graceful Restart mode. */
246 static void ospf_gr_restart_exit(struct ospf
*ospf
, const char *reason
)
248 struct ospf_area
*area
;
249 struct listnode
*onode
, *anode
;
251 if (IS_DEBUG_OSPF_GR
)
252 zlog_debug("GR: exiting graceful restart: %s", reason
);
254 ospf
->gr_info
.restart_in_progress
= false;
255 OSPF_TIMER_OFF(ospf
->gr_info
.t_grace_period
);
257 /* Record in non-volatile memory that the restart is complete. */
258 ospf_gr_nvm_delete(ospf
);
260 for (ALL_LIST_ELEMENTS_RO(ospf
->areas
, onode
, area
)) {
261 struct ospf_interface
*oi
;
264 * 1) The router should reoriginate its router-LSAs for all
265 * attached areas in order to make sure they have the correct
268 ospf_router_lsa_update_area(area
);
271 * 2) The router should reoriginate network-LSAs on all segments
272 * where it is the Designated Router.
274 for (ALL_LIST_ELEMENTS_RO(area
->oiflist
, anode
, oi
))
275 if (oi
->state
== ISM_DR
)
276 ospf_network_lsa_update(oi
);
280 * 5) Any received self-originated LSAs that are no longer valid should
283 ospf_schedule_abr_task(ospf
);
286 * 3) The router reruns its OSPF routing calculations, this time
287 * installing the results into the system forwarding table, and
288 * originating summary-LSAs, Type-7 LSAs and AS-external-LSAs as
291 * 4) Any remnant entries in the system forwarding table that were
292 * installed before the restart, but that are no longer valid,
295 ospf
->gr_info
.finishing_restart
= true;
296 ospf_spf_calculate_schedule(ospf
, SPF_FLAG_GR_FINISH
);
298 /* 6) Any grace-LSAs that the router originated should be flushed. */
299 ospf_gr_flush_grace_lsas(ospf
);
302 /* Check if a Router-LSA contains a given link. */
303 static bool ospf_router_lsa_contains_adj(struct ospf_lsa
*lsa
,
306 struct router_lsa
*rl
;
308 rl
= (struct router_lsa
*)lsa
->data
;
309 for (int i
= 0; i
< ntohs(rl
->links
); i
++) {
310 struct in_addr
*link_id
= &rl
->link
[i
].link_id
;
312 if (rl
->link
[i
].type
!= LSA_LINK_TYPE_POINTOPOINT
)
315 if (IPV4_ADDR_SAME(id
, link_id
))
322 static bool ospf_gr_check_router_lsa_consistency(struct ospf
*ospf
,
323 struct ospf_area
*area
,
324 struct ospf_lsa
*lsa
)
326 if (CHECK_FLAG(lsa
->flags
, OSPF_LSA_SELF
)) {
327 struct ospf_lsa
*lsa_self
= lsa
;
328 struct router_lsa
*rl
= (struct router_lsa
*)lsa
->data
;
330 for (int i
= 0; i
< ntohs(rl
->links
); i
++) {
331 struct in_addr
*link_id
= &rl
->link
[i
].link_id
;
332 struct ospf_lsa
*lsa_adj
;
334 if (rl
->link
[i
].type
!= LSA_LINK_TYPE_POINTOPOINT
)
337 lsa_adj
= ospf_lsa_lookup_by_id(area
, OSPF_ROUTER_LSA
,
342 if (!ospf_router_lsa_contains_adj(lsa_adj
,
343 &lsa_self
->data
->id
))
347 struct ospf_lsa
*lsa_self
;
349 lsa_self
= ospf_lsa_lookup_by_id(area
, OSPF_ROUTER_LSA
,
352 || !CHECK_FLAG(lsa_self
->flags
, OSPF_LSA_RECEIVED
))
355 if (ospf_router_lsa_contains_adj(lsa
, &ospf
->router_id
)
356 != ospf_router_lsa_contains_adj(lsa_self
, &lsa
->data
->id
))
364 * Check for LSAs that are inconsistent with the pre-restart LSAs, and abort the
365 * ongoing graceful restart when that's the case.
367 void ospf_gr_check_lsdb_consistency(struct ospf
*ospf
, struct ospf_area
*area
)
369 struct route_node
*rn
;
370 struct ospf_lsa
*lsa
;
372 for (rn
= route_top(ROUTER_LSDB(area
)); rn
; rn
= route_next(rn
)) {
377 if (!ospf_gr_check_router_lsa_consistency(ospf
, area
, lsa
)) {
380 snprintfrr(reason
, sizeof(reason
),
381 "detected inconsistent LSA[%s] [area %pI4]",
382 dump_lsa_key(lsa
), &area
->area_id
);
383 ospf_gr_restart_exit(ospf
, reason
);
384 route_unlock_node(rn
);
390 /* Lookup neighbor by address in a given OSPF area. */
391 static struct ospf_neighbor
*
392 ospf_area_nbr_lookup_by_addr(struct ospf_area
*area
, struct in_addr
*addr
)
394 struct ospf_interface
*oi
;
395 struct ospf_neighbor
*nbr
;
396 struct listnode
*node
;
398 for (ALL_LIST_ELEMENTS_RO(area
->oiflist
, node
, oi
)) {
399 nbr
= ospf_nbr_lookup_by_addr(oi
->nbrs
, addr
);
407 /* Lookup neighbor by Router ID in a given OSPF area. */
408 static struct ospf_neighbor
*
409 ospf_area_nbr_lookup_by_routerid(struct ospf_area
*area
, struct in_addr
*id
)
411 struct ospf_interface
*oi
;
412 struct ospf_neighbor
*nbr
;
413 struct listnode
*node
;
415 for (ALL_LIST_ELEMENTS_RO(area
->oiflist
, node
, oi
)) {
416 nbr
= ospf_nbr_lookup_by_routerid(oi
->nbrs
, id
);
424 /* Check if there's a fully formed adjacency with the given neighbor ID. */
425 static bool ospf_gr_check_adj_id(struct ospf_area
*area
,
426 struct in_addr
*nbr_id
)
428 struct ospf_neighbor
*nbr
;
430 nbr
= ospf_area_nbr_lookup_by_routerid(area
, nbr_id
);
431 if (!nbr
|| nbr
->state
< NSM_Full
) {
432 if (IS_DEBUG_OSPF_GR
)
433 zlog_debug("GR: missing adjacency to router %pI4",
441 static bool ospf_gr_check_adjs_lsa_transit(struct ospf_area
*area
,
442 struct in_addr
*link_id
)
444 struct ospf
*ospf
= area
->ospf
;
445 struct ospf_interface
*oi
;
448 * Check if the transit network refers to a local interface (in which
449 * case it must be a DR for that network).
451 oi
= ospf_if_lookup_by_local_addr(ospf
, NULL
, *link_id
);
453 struct ospf_lsa
*lsa
;
454 struct network_lsa
*nlsa
;
457 /* Lookup Network LSA corresponding to this interface. */
458 lsa
= ospf_lsa_lookup_by_id(area
, OSPF_NETWORK_LSA
, *link_id
);
462 /* Iterate over all routers present in the network. */
463 nlsa
= (struct network_lsa
*)lsa
->data
;
464 cnt
= (lsa
->size
- (OSPF_LSA_HEADER_SIZE
+ 4)) / 4;
465 for (size_t i
= 0; i
< cnt
; i
++) {
466 struct in_addr
*nbr_id
= &nlsa
->routers
[i
];
468 /* Skip self in the pseudonode. */
469 if (IPV4_ADDR_SAME(nbr_id
, &ospf
->router_id
))
473 * Check if there's a fully formed adjacency with this
476 if (!ospf_gr_check_adj_id(area
, nbr_id
))
480 struct ospf_neighbor
*nbr
;
482 /* Check if there's a fully formed adjacency with the DR. */
483 nbr
= ospf_area_nbr_lookup_by_addr(area
, link_id
);
484 if (!nbr
|| nbr
->state
< NSM_Full
) {
485 if (IS_DEBUG_OSPF_GR
)
487 "GR: missing adjacency to DR router %pI4",
496 static bool ospf_gr_check_adjs_lsa(struct ospf_area
*area
, struct ospf_lsa
*lsa
)
498 struct router_lsa
*rl
= (struct router_lsa
*)lsa
->data
;
500 for (int i
= 0; i
< ntohs(rl
->links
); i
++) {
501 struct in_addr
*link_id
= &rl
->link
[i
].link_id
;
503 switch (rl
->link
[i
].type
) {
504 case LSA_LINK_TYPE_POINTOPOINT
:
505 if (!ospf_gr_check_adj_id(area
, link_id
))
508 case LSA_LINK_TYPE_TRANSIT
:
509 if (!ospf_gr_check_adjs_lsa_transit(area
, link_id
))
521 * Check if all adjacencies prior to the restart were reestablished.
523 * This is done using pre-restart Router LSAs and pre-restart Network LSAs
524 * received from the helping neighbors.
526 void ospf_gr_check_adjs(struct ospf
*ospf
)
528 struct ospf_area
*area
;
529 struct listnode
*node
;
531 for (ALL_LIST_ELEMENTS_RO(ospf
->areas
, node
, area
)) {
532 struct ospf_lsa
*lsa_self
;
534 lsa_self
= ospf_lsa_lookup_by_id(area
, OSPF_ROUTER_LSA
,
536 if (!lsa_self
|| !ospf_gr_check_adjs_lsa(area
, lsa_self
)) {
537 if (IS_DEBUG_OSPF_GR
)
539 "GR: not all adjacencies were reestablished yet [area %pI4]",
545 ospf_gr_restart_exit(ospf
, "all adjacencies were reestablished");
548 /* Handling of grace period expiry. */
549 static int ospf_gr_grace_period_expired(struct thread
*thread
)
551 struct ospf
*ospf
= THREAD_ARG(thread
);
553 ospf
->gr_info
.t_grace_period
= NULL
;
554 ospf_gr_restart_exit(ospf
, "grace period has expired");
560 * Returns the path of the file (non-volatile memory) that contains GR status
563 static char *ospf_gr_nvm_filepath(struct ospf
*ospf
)
565 static char filepath
[MAXPATHLEN
];
566 char instance
[16] = "";
569 snprintf(instance
, sizeof(instance
), "-%d", ospf
->instance
);
570 snprintf(filepath
, sizeof(filepath
), OSPFD_GR_STATE
, instance
);
575 * Record in non-volatile memory that the given OSPF instance is attempting to
576 * perform a graceful restart.
578 static void ospf_gr_nvm_update(struct ospf
*ospf
)
581 const char *inst_name
;
583 json_object
*json_instances
;
584 json_object
*json_instance
;
586 filepath
= ospf_gr_nvm_filepath(ospf
);
587 inst_name
= ospf
->name
? ospf
->name
: VRF_DEFAULT_NAME
;
589 json
= json_object_from_file(filepath
);
591 json
= json_object_new_object();
593 json_object_object_get_ex(json
, "instances", &json_instances
);
594 if (!json_instances
) {
595 json_instances
= json_object_new_object();
596 json_object_object_add(json
, "instances", json_instances
);
599 json_object_object_get_ex(json_instances
, inst_name
, &json_instance
);
600 if (!json_instance
) {
601 json_instance
= json_object_new_object();
602 json_object_object_add(json_instances
, inst_name
,
607 * Record not only the grace period, but also a UNIX timestamp
608 * corresponding to the end of that period. That way, once ospfd is
609 * restarted, it will be possible to take into account the time that
610 * passed while ospfd wasn't running.
612 json_object_int_add(json_instance
, "gracePeriod",
613 ospf
->gr_info
.grace_period
);
614 json_object_int_add(json_instance
, "timestamp",
615 time(NULL
) + ospf
->gr_info
.grace_period
);
617 json_object_to_file_ext(filepath
, json
, JSON_C_TO_STRING_PRETTY
);
618 json_object_free(json
);
622 * Delete GR status information about the given OSPF instance from non-volatile
625 static void ospf_gr_nvm_delete(struct ospf
*ospf
)
628 const char *inst_name
;
630 json_object
*json_instances
;
632 filepath
= ospf_gr_nvm_filepath(ospf
);
633 inst_name
= ospf
->name
? ospf
->name
: VRF_DEFAULT_NAME
;
635 json
= json_object_from_file(filepath
);
637 json
= json_object_new_object();
639 json_object_object_get_ex(json
, "instances", &json_instances
);
640 if (!json_instances
) {
641 json_instances
= json_object_new_object();
642 json_object_object_add(json
, "instances", json_instances
);
645 json_object_object_del(json_instances
, inst_name
);
647 json_object_to_file_ext(filepath
, json
, JSON_C_TO_STRING_PRETTY
);
648 json_object_free(json
);
652 * Fetch from non-volatile memory whether the given OSPF instance is performing
653 * a graceful shutdown or not.
655 void ospf_gr_nvm_read(struct ospf
*ospf
)
658 const char *inst_name
;
660 json_object
*json_instances
;
661 json_object
*json_instance
;
662 json_object
*json_timestamp
;
663 time_t timestamp
= 0;
665 filepath
= ospf_gr_nvm_filepath(ospf
);
666 inst_name
= ospf
->name
? ospf
->name
: VRF_DEFAULT_NAME
;
668 json
= json_object_from_file(filepath
);
670 json
= json_object_new_object();
672 json_object_object_get_ex(json
, "instances", &json_instances
);
673 if (!json_instances
) {
674 json_instances
= json_object_new_object();
675 json_object_object_add(json
, "instances", json_instances
);
678 json_object_object_get_ex(json_instances
, inst_name
, &json_instance
);
679 if (!json_instance
) {
680 json_instance
= json_object_new_object();
681 json_object_object_add(json_instances
, inst_name
,
685 json_object_object_get_ex(json_instance
, "timestamp", &json_timestamp
);
686 if (json_timestamp
) {
688 unsigned long remaining_time
;
690 /* Check if the grace period has already expired. */
692 timestamp
= json_object_get_int(json_timestamp
);
693 if (now
> timestamp
) {
694 ospf_gr_restart_exit(
695 ospf
, "grace period has expired already");
697 /* Schedule grace period timeout. */
698 ospf
->gr_info
.restart_in_progress
= true;
699 remaining_time
= timestamp
- time(NULL
);
700 if (IS_DEBUG_OSPF_GR
)
702 "GR: remaining time until grace period expires: %lu(s)",
704 thread_add_timer(master
, ospf_gr_grace_period_expired
,
705 ospf
, remaining_time
,
706 &ospf
->gr_info
.t_grace_period
);
710 json_object_object_del(json_instances
, inst_name
);
712 json_object_to_file_ext(filepath
, json
, JSON_C_TO_STRING_PRETTY
);
713 json_object_free(json
);
716 /* Prepare to start a Graceful Restart. */
717 static void ospf_gr_prepare(void)
720 struct ospf_interface
*oi
;
721 struct listnode
*onode
;
723 for (ALL_LIST_ELEMENTS_RO(om
->ospf
, onode
, ospf
)) {
724 struct listnode
*inode
;
726 if (!ospf
->gr_info
.restart_support
727 || ospf
->gr_info
.prepare_in_progress
)
730 if (IS_DEBUG_OSPF_GR
)
732 "GR: preparing to perform a graceful restart [period %u second(s)] [vrf %s]",
733 ospf
->gr_info
.grace_period
,
734 ospf_vrf_id_to_name(ospf
->vrf_id
));
736 if (!CHECK_FLAG(ospf
->config
, OSPF_OPAQUE_CAPABLE
)) {
738 "%s: failed to activate graceful restart: opaque capability not enabled",
743 /* Freeze OSPF routes in the RIB. */
744 if (ospf_zebra_gr_enable(ospf
, ospf
->gr_info
.grace_period
)) {
746 "%s: failed to activate graceful restart: not connected to zebra",
751 /* Send a Grace-LSA to all neighbors. */
752 for (ALL_LIST_ELEMENTS_RO(ospf
->oiflist
, inode
, oi
))
753 ospf_gr_lsa_originate(oi
);
755 /* Record end of the grace period in non-volatile memory. */
756 ospf_gr_nvm_update(ospf
);
759 * Mark that a Graceful Restart preparation is in progress, to
760 * prevent ospfd from flushing its self-originated LSAs on exit.
762 ospf
->gr_info
.prepare_in_progress
= true;
766 DEFPY(graceful_restart_prepare
, graceful_restart_prepare_cmd
,
767 "graceful-restart prepare ip ospf",
768 "Graceful Restart commands\n"
769 "Prepare upcoming graceful restart\n"
771 "Prepare to restart the OSPF process")
778 DEFPY(graceful_restart
, graceful_restart_cmd
,
779 "graceful-restart [grace-period (1-1800)$grace_period]",
781 "Maximum length of the 'grace period'\n"
782 "Maximum length of the 'grace period' in seconds\n")
784 VTY_DECLVAR_INSTANCE_CONTEXT(ospf
, ospf
);
786 /* Check and get restart period if present. */
787 if (!grace_period_str
)
788 grace_period
= OSPF_DFLT_GRACE_INTERVAL
;
790 ospf
->gr_info
.restart_support
= true;
791 ospf
->gr_info
.grace_period
= grace_period
;
796 DEFPY(no_graceful_restart
, no_graceful_restart_cmd
,
797 "no graceful-restart [period (1-1800)]",
799 "Maximum length of the 'grace period'\n"
800 "Maximum length of the 'grace period' in seconds\n")
802 VTY_DECLVAR_INSTANCE_CONTEXT(ospf
, ospf
);
804 if (!ospf
->gr_info
.restart_support
)
807 if (ospf
->gr_info
.prepare_in_progress
) {
809 "%% Error: Graceful Restart preparation in progress\n");
813 ospf
->gr_info
.restart_support
= false;
814 ospf
->gr_info
.grace_period
= OSPF_DFLT_GRACE_INTERVAL
;
819 void ospf_gr_init(void)
821 install_element(ENABLE_NODE
, &graceful_restart_prepare_cmd
);
822 install_element(OSPF_NODE
, &graceful_restart_cmd
);
823 install_element(OSPF_NODE
, &no_graceful_restart_cmd
);