]> git.proxmox.com Git - mirror_frr.git/blame - ospf6d/ospf6_gr.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / ospf6d / ospf6_gr.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
71165098
RW
2/*
3 * This is an implementation of RFC 5187 Graceful Restart.
4 *
5 * Copyright 2021 NetDEF (c), All rights reserved.
71165098
RW
6 */
7
8#include <zebra.h>
9
10#include "memory.h"
11#include "command.h"
12#include "table.h"
13#include "vty.h"
14#include "log.h"
15#include "hook.h"
16#include "printfrr.h"
17
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"
71165098 32#include "ospf6d/ospf6_gr_clippy.c"
71165098
RW
33
34static void ospf6_gr_nvm_delete(struct ospf6 *ospf6);
35
36/* Originate and install Grace-LSA for a given interface. */
37static int ospf6_gr_lsa_originate(struct ospf6_interface *oi)
38{
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];
44
45 if (IS_OSPF6_DEBUG_ORIGINATE(LINK))
d6f60d22 46 zlog_debug("Originate Grace-LSA for Interface %s",
71165098
RW
47 oi->interface->name);
48
49 /* prepare buffer */
50 memset(buffer, 0, sizeof(buffer));
51 lsa_header = (struct ospf6_lsa_header *)buffer;
52 grace_lsa =
53 (struct ospf6_grace_lsa *)((caddr_t)lsa_header
54 + sizeof(struct ospf6_lsa_header));
55
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);
60
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;
66 else
67 grace_lsa->tlv_reason.reason = OSPF6_GR_UNKNOWN_RESTART;
68
69 /* Fill LSA Header */
70 lsa_header->age = 0;
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;
74 lsa_header->seqnum =
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));
78
79 /* LSA checksum */
80 ospf6_lsa_checksum(lsa_header);
81
82 /* create LSA */
83 lsa = ospf6_lsa_create(lsa_header);
84
85 /* Originate */
86 ospf6_lsa_originate_interface(lsa, oi);
87
88 return 0;
89}
90
91/* Flush all self-originated Grace-LSAs. */
92static void ospf6_gr_flush_grace_lsas(struct ospf6 *ospf6)
93{
94 struct ospf6_area *area;
95 struct listnode *anode;
96
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;
101
102 if (IS_DEBUG_OSPF6_GR)
103 zlog_debug(
104 "GR: flushing self-originated Grace-LSAs [area %pI4]",
105 &area->area_id);
106
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,
111 oi->lsdb);
112 if (!lsa) {
113 zlog_warn(
114 "%s: Grace-LSA not found [interface %s] [area %pI4]",
115 __func__, oi->interface->name,
116 &area->area_id);
117 continue;
118 }
119
120 ospf6_lsa_purge(lsa);
121 }
122 }
123}
124
125/* Exit from the Graceful Restart mode. */
126static void ospf6_gr_restart_exit(struct ospf6 *ospf6, const char *reason)
127{
128 struct ospf6_area *area;
129 struct listnode *onode, *anode;
130
131 if (IS_DEBUG_OSPF6_GR)
132 zlog_debug("GR: exiting graceful restart: %s", reason);
133
134 ospf6->gr_info.restart_in_progress = false;
135 ospf6->gr_info.finishing_restart = true;
136 THREAD_OFF(ospf6->gr_info.t_grace_period);
137
138 /* Record in non-volatile memory that the restart is complete. */
139 ospf6_gr_nvm_delete(ospf6);
140
141 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, onode, area)) {
142 struct ospf6_interface *oi;
143
144 /*
145 * 1) The router should reoriginate its router-LSAs for all
146 * attached areas in order to make sure they have the correct
147 * contents.
148 */
149 OSPF6_ROUTER_LSA_EXECUTE(area);
150
151 for (ALL_LIST_ELEMENTS_RO(area->if_list, anode, oi)) {
152 OSPF6_LINK_LSA_EXECUTE(oi);
153
154 /*
155 * 2) The router should reoriginate network-LSAs on all
156 * segments where it is the Designated Router.
157 */
158 if (oi->state == OSPF6_INTERFACE_DR)
159 OSPF6_NETWORK_LSA_EXECUTE(oi);
160 }
161 }
162
163 /*
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
167 * necessary.
168 *
169 * 4) Any remnant entries in the system forwarding table that were
170 * installed before the restart, but that are no longer valid,
171 * should be removed.
172 */
173 ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_GR_FINISH);
174
175 /* 6) Any grace-LSAs that the router originated should be flushed. */
176 ospf6_gr_flush_grace_lsas(ospf6);
177}
178
179#define RTR_LSA_MISSING 0
180#define RTR_LSA_ADJ_FOUND 1
181#define RTR_LSA_ADJ_NOT_FOUND 2
182
183/* Check if a Router-LSA exists and if it contains a given link. */
184static int ospf6_router_lsa_contains_adj(struct ospf6_area *area,
185 in_addr_t adv_router,
186 in_addr_t neighbor_router_id)
187{
188 uint16_t type;
189 struct ospf6_lsa *lsa;
190 bool empty = true;
191
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;
196
197 empty = false;
198 router_lsa = (struct ospf6_router_lsa
199 *)((char *)lsa->header
200 + sizeof(struct ospf6_lsa_header));
201
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;
209
210 lsdesc = (struct ospf6_router_lsdesc *)current;
211 if (lsdesc->type != OSPF6_ROUTER_LSDESC_POINTTOPOINT)
212 continue;
213
214 if (lsdesc->neighbor_router_id == neighbor_router_id)
215 return RTR_LSA_ADJ_FOUND;
216 }
217 }
218
219 if (empty)
220 return RTR_LSA_MISSING;
221
222 return RTR_LSA_ADJ_NOT_FOUND;
223}
224
225static bool ospf6_gr_check_router_lsa_consistency(struct ospf6 *ospf6,
226 struct ospf6_area *area,
227 struct ospf6_lsa *lsa)
228{
229 if (lsa->header->adv_router == ospf6->router_id) {
230 struct ospf6_router_lsa *router_lsa;
231 char *start, *end, *current;
232
233 router_lsa = (struct ospf6_router_lsa
234 *)((char *)lsa->header
235 + sizeof(struct ospf6_lsa_header));
236
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;
244
245 lsdesc = (struct ospf6_router_lsdesc *)current;
246 if (lsdesc->type != OSPF6_ROUTER_LSDESC_POINTTOPOINT)
247 continue;
248
249 if (ospf6_router_lsa_contains_adj(
250 area, lsdesc->neighbor_router_id,
251 ospf6->router_id)
252 == RTR_LSA_ADJ_NOT_FOUND)
253 return false;
254 }
255 } else {
256 int adj1, adj2;
257
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))
265 return false;
266 }
267
268 return true;
269}
270
271/*
272 * Check for LSAs that are inconsistent with the pre-restart LSAs, and abort the
273 * ongoing graceful restart when that's the case.
274 */
275void ospf6_gr_check_lsdb_consistency(struct ospf6 *ospf6,
276 struct ospf6_area *area)
277{
278 uint16_t type;
279 struct ospf6_lsa *lsa;
280
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)) {
284 char reason[256];
285
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);
290 return;
291 }
292 }
293}
294
295/* Check if there's a fully formed adjacency with the given neighbor ID. */
296static bool ospf6_gr_check_adj_id(struct ospf6_area *area,
297 in_addr_t neighbor_router_id)
298{
299 struct ospf6_neighbor *nbr;
300
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);
306 return false;
307 }
308
309 return true;
310}
311
312static bool ospf6_gr_check_adjs_lsa_transit(struct ospf6_area *area,
313 in_addr_t neighbor_router_id,
314 uint32_t neighbor_interface_id)
315{
316 struct ospf6 *ospf6 = area->ospf6;
317
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;
324
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);
329 if (!lsa)
330 return false;
331
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;
342
343 /* Skip self in the pseudonode. */
344 if (lsdesc->router_id == ospf6->router_id)
345 continue;
346
347 /*
348 * Check if there's a fully formed adjacency with this
349 * router.
350 */
351 if (!ospf6_gr_check_adj_id(area, lsdesc->router_id))
352 return false;
353 }
354 } else {
355 struct ospf6_neighbor *nbr;
356
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)
361 zlog_debug(
362 "GR: missing adjacency to DR router %pI4",
363 &neighbor_router_id);
364 return false;
365 }
366 }
367
368 return true;
369}
370
371static bool ospf6_gr_check_adjs_lsa(struct ospf6_area *area,
372 struct ospf6_lsa *lsa)
373{
374 struct ospf6_router_lsa *router_lsa;
375 char *start, *end, *current;
376
377 router_lsa =
378 (struct ospf6_router_lsa *)((char *)lsa->header
379 + sizeof(struct ospf6_lsa_header));
380
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;
388
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))
394 return false;
395 break;
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))
400 return false;
401 break;
402 default:
403 break;
404 }
405 }
406
407 return true;
408}
409
410/*
411 * Check if all adjacencies prior to the restart were reestablished.
412 *
413 * This is done using pre-restart Router LSAs and pre-restart Network LSAs
414 * received from the helping neighbors.
415 */
416static bool ospf6_gr_check_adjs(struct ospf6 *ospf6)
417{
418 struct ospf6_area *area;
419 struct listnode *node;
420
421 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, area)) {
422 uint16_t type;
423 uint32_t router;
424 struct ospf6_lsa *lsa_self;
425 bool found = false;
426
427 type = ntohs(OSPF6_LSTYPE_ROUTER);
428 router = ospf6->router_id;
429 for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, router,
430 lsa_self)) {
431 found = true;
432 if (!ospf6_gr_check_adjs_lsa(area, lsa_self))
433 return false;
434 }
435 if (!found)
436 return false;
437 }
438
439 return true;
440}
441
442/* Handling of grace period expiry. */
cc9f21da 443static void ospf6_gr_grace_period_expired(struct thread *thread)
71165098
RW
444{
445 struct ospf6 *ospf6 = THREAD_ARG(thread);
446
71165098 447 ospf6_gr_restart_exit(ospf6, "grace period has expired");
71165098
RW
448}
449
450/*
451 * Record in non-volatile memory that the given OSPF instance is attempting to
452 * perform a graceful restart.
453 */
454static void ospf6_gr_nvm_update(struct ospf6 *ospf6)
455{
456 const char *inst_name;
457 json_object *json;
458 json_object *json_instances;
459 json_object *json_instance;
460
461 inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
462
b275f44a 463 json = json_object_from_file((char *)OSPF6D_GR_STATE);
71165098
RW
464 if (json == NULL)
465 json = json_object_new_object();
466
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);
471 }
472
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,
477 json_instance);
478 }
479
480 /*
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.
485 */
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);
490
b275f44a
RW
491 json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
492 JSON_C_TO_STRING_PRETTY);
71165098
RW
493 json_object_free(json);
494}
495
496/*
497 * Delete GR status information about the given OSPF instance from non-volatile
498 * memory.
499 */
500static void ospf6_gr_nvm_delete(struct ospf6 *ospf6)
501{
502 const char *inst_name;
503 json_object *json;
504 json_object *json_instances;
505
506 inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
507
b275f44a 508 json = json_object_from_file((char *)OSPF6D_GR_STATE);
71165098
RW
509 if (json == NULL)
510 json = json_object_new_object();
511
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);
516 }
517
518 json_object_object_del(json_instances, inst_name);
519
b275f44a
RW
520 json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
521 JSON_C_TO_STRING_PRETTY);
71165098
RW
522 json_object_free(json);
523}
524
525/*
526 * Fetch from non-volatile memory whether the given OSPF instance is performing
527 * a graceful shutdown or not.
528 */
529void ospf6_gr_nvm_read(struct ospf6 *ospf6)
530{
531 const char *inst_name;
532 json_object *json;
533 json_object *json_instances;
534 json_object *json_instance;
535 json_object *json_timestamp;
536 time_t timestamp = 0;
537
538 inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
539
b275f44a 540 json = json_object_from_file((char *)OSPF6D_GR_STATE);
71165098
RW
541 if (json == NULL)
542 json = json_object_new_object();
543
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);
548 }
549
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,
554 json_instance);
555 }
556
557 json_object_object_get_ex(json_instance, "timestamp", &json_timestamp);
558 if (json_timestamp) {
559 time_t now;
560 unsigned long remaining_time;
561
562 /* Check if the grace period has already expired. */
563 now = time(NULL);
564 timestamp = json_object_get_int(json_timestamp);
565 if (now > timestamp) {
566 ospf6_gr_restart_exit(
567 ospf6, "grace period has expired already");
568 } else {
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)
573 zlog_debug(
574 "GR: remaining time until grace period expires: %lu(s)",
575 remaining_time);
576 thread_add_timer(master, ospf6_gr_grace_period_expired,
577 ospf6, remaining_time,
578 &ospf6->gr_info.t_grace_period);
579 }
580 }
581
582 json_object_object_del(json_instances, inst_name);
583
b275f44a
RW
584 json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
585 JSON_C_TO_STRING_PRETTY);
71165098
RW
586 json_object_free(json);
587}
588
589/* Prepare to start a Graceful Restart. */
590static void ospf6_gr_prepare(void)
591{
592 struct ospf6 *ospf6;
593 struct ospf6_interface *oi;
594 struct listnode *onode, *anode, *inode;
595
596 for (ALL_LIST_ELEMENTS_RO(om6->ospf6, onode, ospf6)) {
597 struct ospf6_area *area;
598
599 if (!ospf6->gr_info.restart_support
600 || ospf6->gr_info.prepare_in_progress)
601 continue;
602
603 if (IS_DEBUG_OSPF6_GR)
604 zlog_debug(
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));
608
609 /* Freeze OSPF routes in the RIB. */
610 if (ospf6_zebra_gr_enable(ospf6, ospf6->gr_info.grace_period)) {
611 zlog_warn(
612 "%s: failed to activate graceful restart: not connected to zebra",
613 __func__);
614 continue;
615 }
616
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)
621 continue;
622 ospf6_gr_lsa_originate(oi);
623 }
624 }
625
626 /* Record end of the grace period in non-volatile memory. */
627 ospf6_gr_nvm_update(ospf6);
628
629 /*
630 * Mark that a Graceful Restart preparation is in progress, to
631 * prevent ospf6d from flushing its self-originated LSAs on
632 * exit.
633 */
634 ospf6->gr_info.prepare_in_progress = true;
635 }
636}
637
638static int ospf6_gr_neighbor_change(struct ospf6_neighbor *on, int next_state,
639 int prev_state)
640{
641 struct ospf6 *ospf6 = on->ospf6_if->area->ospf6;
642
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");
648 } else {
649 if (IS_DEBUG_OSPF6_GR)
650 zlog_debug(
651 "GR: not all adjacencies were reestablished yet");
652 }
653 }
654
655 return 0;
656}
657
658int config_write_ospf6_gr(struct vty *vty, struct ospf6 *ospf6)
659{
660 if (!ospf6->gr_info.restart_support)
661 return 0;
662
663 if (ospf6->gr_info.grace_period == OSPF6_DFLT_GRACE_INTERVAL)
664 vty_out(vty, " graceful-restart\n");
665 else
666 vty_out(vty, " graceful-restart grace-period %u\n",
667 ospf6->gr_info.grace_period);
668
669 return 0;
670}
671
672DEFPY(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
4a3c92de 676 "Prepare to restart the OSPFv3 process\n")
71165098
RW
677{
678 ospf6_gr_prepare();
679
680 return CMD_SUCCESS;
681}
682
683DEFPY(ospf6_graceful_restart, ospf6_graceful_restart_cmd,
684 "graceful-restart [grace-period (1-1800)$grace_period]",
685 OSPF_GR_STR
686 "Maximum length of the 'grace period'\n"
687 "Maximum length of the 'grace period' in seconds\n")
688{
689 VTY_DECLVAR_INSTANCE_CONTEXT(ospf6, ospf6);
690
691 /* Check and get restart period if present. */
692 if (!grace_period_str)
693 grace_period = OSPF6_DFLT_GRACE_INTERVAL;
694
695 ospf6->gr_info.restart_support = true;
696 ospf6->gr_info.grace_period = grace_period;
697
698 return CMD_SUCCESS;
699}
700
701DEFPY(ospf6_no_graceful_restart, ospf6_no_graceful_restart_cmd,
702 "no graceful-restart [period (1-1800)]",
703 NO_STR OSPF_GR_STR
704 "Maximum length of the 'grace period'\n"
705 "Maximum length of the 'grace period' in seconds\n")
706{
707 VTY_DECLVAR_INSTANCE_CONTEXT(ospf6, ospf6);
708
709 if (!ospf6->gr_info.restart_support)
710 return CMD_SUCCESS;
711
712 if (ospf6->gr_info.prepare_in_progress) {
713 vty_out(vty,
714 "%% Error: Graceful Restart preparation in progress\n");
715 return CMD_WARNING;
716 }
717
718 ospf6->gr_info.restart_support = false;
719 ospf6->gr_info.grace_period = OSPF6_DFLT_GRACE_INTERVAL;
720
721 return CMD_SUCCESS;
722}
723
724void ospf6_gr_init(void)
725{
726 hook_register(ospf6_neighbor_change, ospf6_gr_neighbor_change);
727
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);
731}