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.
17 #include "lib_errors.h"
19 #include "ospf6d/ospf6_lsa.h"
20 #include "ospf6d/ospf6_lsdb.h"
21 #include "ospf6d/ospf6_route.h"
22 #include "ospf6d/ospf6_area.h"
23 #include "ospf6d/ospf6_interface.h"
24 #include "ospf6d/ospf6d.h"
25 #include "ospf6d/ospf6_asbr.h"
26 #include "ospf6d/ospf6_zebra.h"
27 #include "ospf6d/ospf6_message.h"
28 #include "ospf6d/ospf6_neighbor.h"
29 #include "ospf6d/ospf6_network.h"
30 #include "ospf6d/ospf6_flood.h"
31 #include "ospf6d/ospf6_intra.h"
32 #include "ospf6d/ospf6_spf.h"
33 #include "ospf6d/ospf6_gr.h"
34 #include "ospf6d/ospf6_gr_clippy.c"
36 static void ospf6_gr_grace_period_expired(struct event
*thread
);
38 /* Originate and install Grace-LSA for a given interface. */
39 static int ospf6_gr_lsa_originate(struct ospf6_interface
*oi
,
40 enum ospf6_gr_restart_reason reason
)
42 struct ospf6
*ospf6
= oi
->area
->ospf6
;
43 struct ospf6_gr_info
*gr_info
= &ospf6
->gr_info
;
44 struct ospf6_lsa_header
*lsa_header
;
45 struct ospf6_grace_lsa
*grace_lsa
;
46 struct ospf6_lsa
*lsa
;
48 char buffer
[OSPF6_MAX_LSASIZE
];
50 if (IS_OSPF6_DEBUG_ORIGINATE(LINK
))
51 zlog_debug("Originate Grace-LSA for Interface %s",
55 memset(buffer
, 0, sizeof(buffer
));
56 lsa_header
= (struct ospf6_lsa_header
*)buffer
;
58 (struct ospf6_grace_lsa
*)((caddr_t
)lsa_header
59 + sizeof(struct ospf6_lsa_header
));
61 /* Put grace period. */
62 grace_lsa
->tlv_period
.header
.type
= htons(GRACE_PERIOD_TYPE
);
63 grace_lsa
->tlv_period
.header
.length
= htons(GRACE_PERIOD_LENGTH
);
64 grace_lsa
->tlv_period
.interval
= htonl(gr_info
->grace_period
);
66 /* Put restart reason. */
67 grace_lsa
->tlv_reason
.header
.type
= htons(RESTART_REASON_TYPE
);
68 grace_lsa
->tlv_reason
.header
.length
= htons(RESTART_REASON_LENGTH
);
69 grace_lsa
->tlv_reason
.reason
= reason
;
72 lsa_length
= sizeof(*lsa_header
) + sizeof(*grace_lsa
);
74 lsa_header
->type
= htons(OSPF6_LSTYPE_GRACE_LSA
);
75 lsa_header
->id
= htonl(oi
->interface
->ifindex
);
76 lsa_header
->adv_router
= ospf6
->router_id
;
78 ospf6_new_ls_seqnum(lsa_header
->type
, lsa_header
->id
,
79 lsa_header
->adv_router
, oi
->lsdb
);
80 lsa_header
->length
= htons(lsa_length
);
83 ospf6_lsa_checksum(lsa_header
);
85 if (reason
== OSPF6_GR_UNKNOWN_RESTART
) {
86 struct ospf6_header
*oh
;
89 uint16_t length
= OSPF6_HEADER_SIZE
+ 4 + lsa_length
;
90 struct iovec iovector
[2] = {};
92 /* Reserve space for OSPFv3 header. */
93 memmove(&buffer
[OSPF6_HEADER_SIZE
+ 4], buffer
, lsa_length
);
95 /* Fill in the OSPFv3 header. */
96 oh
= (struct ospf6_header
*)buffer
;
97 oh
->version
= OSPFV3_VERSION
;
98 oh
->type
= OSPF6_MESSAGE_TYPE_LSUPDATE
;
99 oh
->router_id
= oi
->area
->ospf6
->router_id
;
100 oh
->area_id
= oi
->area
->area_id
;
101 oh
->instance_id
= oi
->instance_id
;
103 oh
->length
= htons(length
);
105 /* Fill LSA header. */
106 uv32
= (uint32_t *)&buffer
[sizeof(*oh
)];
110 iovector
[0].iov_base
= lsa_header
;
111 iovector
[0].iov_len
= length
;
112 n
= ospf6_sendmsg(oi
->linklocal_addr
, &allspfrouters6
,
113 oi
->interface
->ifindex
, iovector
, ospf6
->fd
);
115 flog_err(EC_LIB_DEVELOPMENT
,
116 "%s: could not send entire message", __func__
);
118 /* Create and install LSA. */
119 lsa
= ospf6_lsa_create(lsa_header
);
120 ospf6_lsa_originate_interface(lsa
, oi
);
126 /* Flush all self-originated Grace-LSAs. */
127 static void ospf6_gr_flush_grace_lsas(struct ospf6
*ospf6
)
129 struct ospf6_area
*area
;
130 struct listnode
*anode
;
132 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, anode
, area
)) {
133 struct ospf6_lsa
*lsa
;
134 struct ospf6_interface
*oi
;
135 struct listnode
*inode
;
137 if (IS_DEBUG_OSPF6_GR
)
139 "GR: flushing self-originated Grace-LSAs [area %pI4]",
142 for (ALL_LIST_ELEMENTS_RO(area
->if_list
, inode
, oi
)) {
143 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_GRACE_LSA
),
144 htonl(oi
->interface
->ifindex
),
145 oi
->area
->ospf6
->router_id
,
149 "%s: Grace-LSA not found [interface %s] [area %pI4]",
150 __func__
, oi
->interface
->name
,
155 ospf6_lsa_purge(lsa
);
160 /* Exit from the Graceful Restart mode. */
161 static void ospf6_gr_restart_exit(struct ospf6
*ospf6
, const char *reason
)
163 struct ospf6_area
*area
;
164 struct listnode
*onode
, *anode
;
165 struct ospf6_route
*route
;
167 if (IS_DEBUG_OSPF6_GR
)
168 zlog_debug("GR: exiting graceful restart: %s", reason
);
170 ospf6
->gr_info
.restart_in_progress
= false;
171 ospf6
->gr_info
.finishing_restart
= true;
172 XFREE(MTYPE_TMP
, ospf6
->gr_info
.exit_reason
);
173 ospf6
->gr_info
.exit_reason
= XSTRDUP(MTYPE_TMP
, reason
);
174 EVENT_OFF(ospf6
->gr_info
.t_grace_period
);
176 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, onode
, area
)) {
177 struct ospf6_interface
*oi
;
180 * 1) The router should reoriginate its router-LSAs for all
181 * attached areas in order to make sure they have the correct
184 OSPF6_ROUTER_LSA_EXECUTE(area
);
187 * Force reorigination of intra-area-prefix-LSAs to handle
188 * areas without any full adjacency.
190 OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(area
);
192 for (ALL_LIST_ELEMENTS_RO(area
->if_list
, anode
, oi
)) {
193 /* Disable hello delay. */
194 if (oi
->gr
.hello_delay
.t_grace_send
) {
195 oi
->gr
.hello_delay
.elapsed_seconds
= 0;
196 EVENT_OFF(oi
->gr
.hello_delay
.t_grace_send
);
197 event_add_event(master
, ospf6_hello_send
, oi
, 0,
198 &oi
->thread_send_hello
);
201 /* Reoriginate Link-LSA. */
202 if (oi
->type
!= OSPF_IFTYPE_VIRTUALLINK
)
203 OSPF6_LINK_LSA_EXECUTE(oi
);
206 * 2) The router should reoriginate network-LSAs on all
207 * segments where it is the Designated Router.
209 if (oi
->state
== OSPF6_INTERFACE_DR
)
210 OSPF6_NETWORK_LSA_EXECUTE(oi
);
215 * While all self-originated NSSA and AS-external LSAs were already
216 * learned from the helping neighbors, we need to reoriginate them in
217 * order to ensure they will be refreshed periodically.
219 for (route
= ospf6_route_head(ospf6
->external_table
); route
;
220 route
= ospf6_route_next(route
))
221 ospf6_handle_external_lsa_origination(ospf6
, route
,
225 * 3) The router reruns its OSPF routing calculations, this time
226 * installing the results into the system forwarding table, and
227 * originating summary-LSAs, Type-7 LSAs and AS-external-LSAs as
230 * 4) Any remnant entries in the system forwarding table that were
231 * installed before the restart, but that are no longer valid,
234 ospf6_spf_schedule(ospf6
, OSPF6_SPF_FLAGS_GR_FINISH
);
236 /* 6) Any grace-LSAs that the router originated should be flushed. */
237 ospf6_gr_flush_grace_lsas(ospf6
);
240 /* Enter the Graceful Restart mode. */
241 void ospf6_gr_restart_enter(struct ospf6
*ospf6
,
242 enum ospf6_gr_restart_reason reason
, int timestamp
)
244 unsigned long remaining_time
;
246 ospf6
->gr_info
.restart_in_progress
= true;
247 ospf6
->gr_info
.reason
= reason
;
249 /* Schedule grace period timeout. */
250 remaining_time
= timestamp
- time(NULL
);
251 if (IS_DEBUG_OSPF6_GR
)
253 "GR: remaining time until grace period expires: %lu(s)",
256 event_add_timer(master
, ospf6_gr_grace_period_expired
, ospf6
,
257 remaining_time
, &ospf6
->gr_info
.t_grace_period
);
260 #define RTR_LSA_MISSING 0
261 #define RTR_LSA_ADJ_FOUND 1
262 #define RTR_LSA_ADJ_NOT_FOUND 2
264 /* Check if a Router-LSA exists and if it contains a given link. */
265 static int ospf6_router_lsa_contains_adj(struct ospf6_area
*area
,
266 in_addr_t adv_router
,
267 in_addr_t neighbor_router_id
)
270 struct ospf6_lsa
*lsa
;
273 type
= ntohs(OSPF6_LSTYPE_ROUTER
);
274 for (ALL_LSDB_TYPED_ADVRTR(area
->lsdb
, type
, adv_router
, lsa
)) {
275 struct ospf6_router_lsa
*router_lsa
;
276 char *start
, *end
, *current
;
279 router_lsa
= (struct ospf6_router_lsa
280 *)((char *)lsa
->header
281 + sizeof(struct ospf6_lsa_header
));
283 /* Iterate over all interfaces in the Router-LSA. */
284 start
= (char *)router_lsa
+ sizeof(struct ospf6_router_lsa
);
285 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
286 for (current
= start
;
287 current
+ sizeof(struct ospf6_router_lsdesc
) <= end
;
288 current
+= sizeof(struct ospf6_router_lsdesc
)) {
289 struct ospf6_router_lsdesc
*lsdesc
;
291 lsdesc
= (struct ospf6_router_lsdesc
*)current
;
292 if (lsdesc
->type
!= OSPF6_ROUTER_LSDESC_POINTTOPOINT
)
295 if (lsdesc
->neighbor_router_id
== neighbor_router_id
)
296 return RTR_LSA_ADJ_FOUND
;
301 return RTR_LSA_MISSING
;
303 return RTR_LSA_ADJ_NOT_FOUND
;
306 static bool ospf6_gr_check_router_lsa_consistency(struct ospf6
*ospf6
,
307 struct ospf6_area
*area
,
308 struct ospf6_lsa
*lsa
)
310 if (lsa
->header
->adv_router
== ospf6
->router_id
) {
311 struct ospf6_router_lsa
*router_lsa
;
312 char *start
, *end
, *current
;
314 router_lsa
= (struct ospf6_router_lsa
315 *)((char *)lsa
->header
316 + sizeof(struct ospf6_lsa_header
));
318 /* Iterate over all interfaces in the Router-LSA. */
319 start
= (char *)router_lsa
+ sizeof(struct ospf6_router_lsa
);
320 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
321 for (current
= start
;
322 current
+ sizeof(struct ospf6_router_lsdesc
) <= end
;
323 current
+= sizeof(struct ospf6_router_lsdesc
)) {
324 struct ospf6_router_lsdesc
*lsdesc
;
326 lsdesc
= (struct ospf6_router_lsdesc
*)current
;
327 if (lsdesc
->type
!= OSPF6_ROUTER_LSDESC_POINTTOPOINT
)
330 if (ospf6_router_lsa_contains_adj(
331 area
, lsdesc
->neighbor_router_id
,
333 == RTR_LSA_ADJ_NOT_FOUND
)
339 adj1
= ospf6_router_lsa_contains_adj(area
, ospf6
->router_id
,
340 lsa
->header
->adv_router
);
341 adj2
= ospf6_router_lsa_contains_adj(
342 area
, lsa
->header
->adv_router
, ospf6
->router_id
);
343 if ((adj1
== RTR_LSA_ADJ_FOUND
&& adj2
== RTR_LSA_ADJ_NOT_FOUND
)
344 || (adj1
== RTR_LSA_ADJ_NOT_FOUND
345 && adj2
== RTR_LSA_ADJ_FOUND
))
353 * Check for LSAs that are inconsistent with the pre-restart LSAs, and abort the
354 * ongoing graceful restart when that's the case.
356 void ospf6_gr_check_lsdb_consistency(struct ospf6
*ospf6
,
357 struct ospf6_area
*area
)
360 struct ospf6_lsa
*lsa
;
362 type
= ntohs(OSPF6_LSTYPE_ROUTER
);
363 for (ALL_LSDB_TYPED(area
->lsdb
, type
, lsa
)) {
364 if (!ospf6_gr_check_router_lsa_consistency(ospf6
, area
, lsa
)) {
367 snprintfrr(reason
, sizeof(reason
),
368 "detected inconsistent LSA %s [area %pI4]",
369 lsa
->name
, &area
->area_id
);
370 ospf6_gr_restart_exit(ospf6
, reason
);
376 /* Check if there's a fully formed adjacency with the given neighbor ID. */
377 static bool ospf6_gr_check_adj_id(struct ospf6_area
*area
,
378 in_addr_t neighbor_router_id
)
380 struct ospf6_neighbor
*nbr
;
382 nbr
= ospf6_area_neighbor_lookup(area
, neighbor_router_id
);
383 if (!nbr
|| nbr
->state
< OSPF6_NEIGHBOR_FULL
) {
384 if (IS_DEBUG_OSPF6_GR
)
385 zlog_debug("GR: missing adjacency to router %pI4",
386 &neighbor_router_id
);
393 static bool ospf6_gr_check_adjs_lsa_transit(struct ospf6_area
*area
,
394 in_addr_t neighbor_router_id
,
395 uint32_t neighbor_interface_id
)
397 struct ospf6
*ospf6
= area
->ospf6
;
399 /* Check if we are the DR. */
400 if (neighbor_router_id
== ospf6
->router_id
) {
401 struct ospf6_lsa
*lsa
;
402 char *start
, *end
, *current
;
403 struct ospf6_network_lsa
*network_lsa
;
404 struct ospf6_network_lsdesc
*lsdesc
;
406 /* Lookup Network LSA corresponding to this interface. */
407 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_NETWORK
),
408 neighbor_interface_id
,
409 neighbor_router_id
, area
->lsdb
);
413 /* Iterate over all routers present in the network. */
414 network_lsa
= (struct ospf6_network_lsa
415 *)((char *)lsa
->header
416 + sizeof(struct ospf6_lsa_header
));
417 start
= (char *)network_lsa
+ sizeof(struct ospf6_network_lsa
);
418 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
419 for (current
= start
;
420 current
+ sizeof(struct ospf6_network_lsdesc
) <= end
;
421 current
+= sizeof(struct ospf6_network_lsdesc
)) {
422 lsdesc
= (struct ospf6_network_lsdesc
*)current
;
424 /* Skip self in the pseudonode. */
425 if (lsdesc
->router_id
== ospf6
->router_id
)
429 * Check if there's a fully formed adjacency with this
432 if (!ospf6_gr_check_adj_id(area
, lsdesc
->router_id
))
436 struct ospf6_neighbor
*nbr
;
438 /* Check if there's a fully formed adjacency with the DR. */
439 nbr
= ospf6_area_neighbor_lookup(area
, neighbor_router_id
);
440 if (!nbr
|| nbr
->state
< OSPF6_NEIGHBOR_FULL
) {
441 if (IS_DEBUG_OSPF6_GR
)
443 "GR: missing adjacency to DR router %pI4",
444 &neighbor_router_id
);
452 static bool ospf6_gr_check_adjs_lsa(struct ospf6_area
*area
,
453 struct ospf6_lsa
*lsa
)
455 struct ospf6_router_lsa
*router_lsa
;
456 char *start
, *end
, *current
;
459 (struct ospf6_router_lsa
*)((char *)lsa
->header
460 + sizeof(struct ospf6_lsa_header
));
462 /* Iterate over all interfaces in the Router-LSA. */
463 start
= (char *)router_lsa
+ sizeof(struct ospf6_router_lsa
);
464 end
= (char *)lsa
->header
+ ntohs(lsa
->header
->length
);
465 for (current
= start
;
466 current
+ sizeof(struct ospf6_router_lsdesc
) <= end
;
467 current
+= sizeof(struct ospf6_router_lsdesc
)) {
468 struct ospf6_router_lsdesc
*lsdesc
;
470 lsdesc
= (struct ospf6_router_lsdesc
*)current
;
471 switch (lsdesc
->type
) {
472 case OSPF6_ROUTER_LSDESC_POINTTOPOINT
:
473 if (!ospf6_gr_check_adj_id(area
,
474 lsdesc
->neighbor_router_id
))
477 case OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK
:
478 if (!ospf6_gr_check_adjs_lsa_transit(
479 area
, lsdesc
->neighbor_router_id
,
480 lsdesc
->neighbor_interface_id
))
492 * Check if all adjacencies prior to the restart were reestablished.
494 * This is done using pre-restart Router LSAs and pre-restart Network LSAs
495 * received from the helping neighbors.
497 static bool ospf6_gr_check_adjs(struct ospf6
*ospf6
)
499 struct ospf6_area
*area
;
500 struct listnode
*node
;
502 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, node
, area
)) {
505 struct ospf6_lsa
*lsa_self
;
508 type
= ntohs(OSPF6_LSTYPE_ROUTER
);
509 router
= ospf6
->router_id
;
510 for (ALL_LSDB_TYPED_ADVRTR(area
->lsdb
, type
, router
,
513 if (!ospf6_gr_check_adjs_lsa(area
, lsa_self
))
523 /* Handling of grace period expiry. */
524 static void ospf6_gr_grace_period_expired(struct event
*thread
)
526 struct ospf6
*ospf6
= EVENT_ARG(thread
);
528 ospf6_gr_restart_exit(ospf6
, "grace period has expired");
531 /* Send extra Grace-LSA out the interface (unplanned outages only). */
532 void ospf6_gr_iface_send_grace_lsa(struct event
*thread
)
534 struct ospf6_interface
*oi
= EVENT_ARG(thread
);
536 ospf6_gr_lsa_originate(oi
, oi
->area
->ospf6
->gr_info
.reason
);
538 if (++oi
->gr
.hello_delay
.elapsed_seconds
< oi
->gr
.hello_delay
.interval
)
539 event_add_timer(master
, ospf6_gr_iface_send_grace_lsa
, oi
, 1,
540 &oi
->gr
.hello_delay
.t_grace_send
);
542 event_add_event(master
, ospf6_hello_send
, oi
, 0,
543 &oi
->thread_send_hello
);
547 * Record in non-volatile memory that the given OSPF instance is attempting to
548 * perform a graceful restart.
550 static void ospf6_gr_nvm_update(struct ospf6
*ospf6
, bool prepare
)
552 const char *inst_name
;
554 json_object
*json_instances
;
555 json_object
*json_instance
;
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_int_add(json_instance
, "gracePeriod",
577 ospf6
->gr_info
.grace_period
);
580 * Record not only the grace period, but also a UNIX timestamp
581 * corresponding to the end of that period. That way, once ospf6d is
582 * restarted, it will be possible to take into account the time that
583 * passed while ospf6d wasn't running.
586 json_object_int_add(json_instance
, "timestamp",
587 time(NULL
) + ospf6
->gr_info
.grace_period
);
589 json_object_to_file_ext((char *)OSPF6D_GR_STATE
, json
,
590 JSON_C_TO_STRING_PRETTY
);
591 json_object_free(json
);
595 * Delete GR status information about the given OSPF instance from non-volatile
598 void ospf6_gr_nvm_delete(struct ospf6
*ospf6
)
600 const char *inst_name
;
602 json_object
*json_instances
;
604 inst_name
= ospf6
->name
? ospf6
->name
: VRF_DEFAULT_NAME
;
606 json
= json_object_from_file((char *)OSPF6D_GR_STATE
);
608 json
= json_object_new_object();
610 json_object_object_get_ex(json
, "instances", &json_instances
);
611 if (!json_instances
) {
612 json_instances
= json_object_new_object();
613 json_object_object_add(json
, "instances", json_instances
);
616 json_object_object_del(json_instances
, inst_name
);
618 json_object_to_file_ext((char *)OSPF6D_GR_STATE
, json
,
619 JSON_C_TO_STRING_PRETTY
);
620 json_object_free(json
);
624 * Fetch from non-volatile memory whether the given OSPF instance is performing
625 * a graceful shutdown or not.
627 void ospf6_gr_nvm_read(struct ospf6
*ospf6
)
629 const char *inst_name
;
631 json_object
*json_instances
;
632 json_object
*json_instance
;
633 json_object
*json_timestamp
;
634 json_object
*json_grace_period
;
635 time_t timestamp
= 0;
637 inst_name
= ospf6
->name
? ospf6
->name
: VRF_DEFAULT_NAME
;
639 json
= json_object_from_file((char *)OSPF6D_GR_STATE
);
641 json
= json_object_new_object();
643 json_object_object_get_ex(json
, "instances", &json_instances
);
644 if (!json_instances
) {
645 json_instances
= json_object_new_object();
646 json_object_object_add(json
, "instances", json_instances
);
649 json_object_object_get_ex(json_instances
, inst_name
, &json_instance
);
650 if (!json_instance
) {
651 json_instance
= json_object_new_object();
652 json_object_object_add(json_instances
, inst_name
,
656 json_object_object_get_ex(json_instance
, "gracePeriod",
658 json_object_object_get_ex(json_instance
, "timestamp", &json_timestamp
);
659 if (json_timestamp
) {
662 /* Planned GR: check if the grace period has already expired. */
664 timestamp
= json_object_get_int(json_timestamp
);
665 if (now
> timestamp
) {
666 ospf6_gr_restart_exit(
667 ospf6
, "grace period has expired already");
669 ospf6_gr_restart_enter(ospf6
, OSPF6_GR_SW_RESTART
,
671 } else if (json_grace_period
) {
672 uint32_t grace_period
;
675 * Unplanned GR: the Grace-LSAs will be sent later as soon as
676 * the interfaces are operational.
678 grace_period
= json_object_get_int(json_grace_period
);
679 ospf6
->gr_info
.grace_period
= grace_period
;
680 ospf6_gr_restart_enter(ospf6
, OSPF6_GR_UNKNOWN_RESTART
,
682 ospf6
->gr_info
.grace_period
);
685 json_object_object_del(json_instances
, inst_name
);
687 json_object_to_file_ext((char *)OSPF6D_GR_STATE
, json
,
688 JSON_C_TO_STRING_PRETTY
);
689 json_object_free(json
);
692 void ospf6_gr_unplanned_start_interface(struct ospf6_interface
*oi
)
695 * Can't check OSPF interface state as the OSPF instance might not be
698 if (!if_is_operative(oi
->interface
) || if_is_loopback(oi
->interface
))
701 /* Send Grace-LSA. */
702 ospf6_gr_lsa_originate(oi
, oi
->area
->ospf6
->gr_info
.reason
);
704 /* Start GR hello-delay interval. */
705 oi
->gr
.hello_delay
.elapsed_seconds
= 0;
706 event_add_timer(master
, ospf6_gr_iface_send_grace_lsa
, oi
, 1,
707 &oi
->gr
.hello_delay
.t_grace_send
);
710 /* Prepare to start a Graceful Restart. */
711 static void ospf6_gr_prepare(void)
714 struct ospf6_interface
*oi
;
715 struct listnode
*onode
, *anode
, *inode
;
717 for (ALL_LIST_ELEMENTS_RO(om6
->ospf6
, onode
, ospf6
)) {
718 struct ospf6_area
*area
;
720 if (!ospf6
->gr_info
.restart_support
721 || ospf6
->gr_info
.prepare_in_progress
)
724 if (IS_DEBUG_OSPF6_GR
)
726 "GR: preparing to perform a graceful restart [period %u second(s)] [vrf %s]",
727 ospf6
->gr_info
.grace_period
,
728 ospf6_vrf_id_to_name(ospf6
->vrf_id
));
730 /* Send a Grace-LSA to all neighbors. */
731 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, anode
, area
)) {
732 for (ALL_LIST_ELEMENTS_RO(area
->if_list
, inode
, oi
)) {
733 if (oi
->state
< OSPF6_INTERFACE_POINTTOPOINT
)
735 ospf6_gr_lsa_originate(oi
, OSPF6_GR_SW_RESTART
);
739 /* Record end of the grace period in non-volatile memory. */
740 ospf6_gr_nvm_update(ospf6
, true);
743 * Mark that a Graceful Restart preparation is in progress, to
744 * prevent ospf6d from flushing its self-originated LSAs on
747 ospf6
->gr_info
.prepare_in_progress
= true;
751 static int ospf6_gr_neighbor_change(struct ospf6_neighbor
*on
, int next_state
,
754 struct ospf6
*ospf6
= on
->ospf6_if
->area
->ospf6
;
756 if (next_state
== OSPF6_NEIGHBOR_FULL
757 && ospf6
->gr_info
.restart_in_progress
) {
758 if (ospf6_gr_check_adjs(ospf6
)) {
759 ospf6_gr_restart_exit(
760 ospf6
, "all adjacencies were reestablished");
762 if (IS_DEBUG_OSPF6_GR
)
764 "GR: not all adjacencies were reestablished yet");
771 int config_write_ospf6_gr(struct vty
*vty
, struct ospf6
*ospf6
)
773 if (!ospf6
->gr_info
.restart_support
)
776 if (ospf6
->gr_info
.grace_period
== OSPF6_DFLT_GRACE_INTERVAL
)
777 vty_out(vty
, " graceful-restart\n");
779 vty_out(vty
, " graceful-restart grace-period %u\n",
780 ospf6
->gr_info
.grace_period
);
785 DEFPY(ospf6_graceful_restart_prepare
, ospf6_graceful_restart_prepare_cmd
,
786 "graceful-restart prepare ipv6 ospf",
787 "Graceful Restart commands\n"
788 "Prepare upcoming graceful restart\n" IPV6_STR
789 "Prepare to restart the OSPFv3 process\n")
796 DEFPY(ospf6_graceful_restart
, ospf6_graceful_restart_cmd
,
797 "graceful-restart [grace-period (1-1800)$grace_period]",
799 "Maximum length of the 'grace period'\n"
800 "Maximum length of the 'grace period' in seconds\n")
802 VTY_DECLVAR_INSTANCE_CONTEXT(ospf6
, ospf6
);
804 /* Check and get restart period if present. */
805 if (!grace_period_str
)
806 grace_period
= OSPF6_DFLT_GRACE_INTERVAL
;
808 ospf6
->gr_info
.restart_support
= true;
809 ospf6
->gr_info
.grace_period
= grace_period
;
811 /* Freeze OSPF routes in the RIB. */
812 (void)ospf6_zebra_gr_enable(ospf6
, ospf6
->gr_info
.grace_period
);
814 /* Record that GR is enabled in non-volatile memory. */
815 ospf6_gr_nvm_update(ospf6
, false);
820 DEFPY(ospf6_no_graceful_restart
, ospf6_no_graceful_restart_cmd
,
821 "no graceful-restart [period (1-1800)]",
823 "Maximum length of the 'grace period'\n"
824 "Maximum length of the 'grace period' in seconds\n")
826 VTY_DECLVAR_INSTANCE_CONTEXT(ospf6
, ospf6
);
828 if (!ospf6
->gr_info
.restart_support
)
831 if (ospf6
->gr_info
.prepare_in_progress
) {
833 "%% Error: Graceful Restart preparation in progress\n");
837 ospf6
->gr_info
.restart_support
= false;
838 ospf6
->gr_info
.grace_period
= OSPF6_DFLT_GRACE_INTERVAL
;
839 ospf6_gr_nvm_delete(ospf6
);
840 ospf6_zebra_gr_disable(ospf6
);
845 void ospf6_gr_init(void)
847 hook_register(ospf6_neighbor_change
, ospf6_gr_neighbor_change
);
849 install_element(ENABLE_NODE
, &ospf6_graceful_restart_prepare_cmd
);
850 install_element(OSPF6_NODE
, &ospf6_graceful_restart_cmd
);
851 install_element(OSPF6_NODE
, &ospf6_no_graceful_restart_cmd
);