]> git.proxmox.com Git - mirror_frr.git/blame - ospf6d/ospf6_gr.c
Merge pull request #13310 from opensourcerouting/feature/bgpd_node_target_extended_co...
[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;
5eb2c602 130 struct ospf6_route *route;
71165098
RW
131
132 if (IS_DEBUG_OSPF6_GR)
133 zlog_debug("GR: exiting graceful restart: %s", reason);
134
135 ospf6->gr_info.restart_in_progress = false;
136 ospf6->gr_info.finishing_restart = true;
e16d030c 137 EVENT_OFF(ospf6->gr_info.t_grace_period);
71165098
RW
138
139 /* Record in non-volatile memory that the restart is complete. */
140 ospf6_gr_nvm_delete(ospf6);
141
142 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, onode, area)) {
143 struct ospf6_interface *oi;
144
145 /*
146 * 1) The router should reoriginate its router-LSAs for all
147 * attached areas in order to make sure they have the correct
148 * contents.
149 */
150 OSPF6_ROUTER_LSA_EXECUTE(area);
151
3d2533ed
RW
152 /*
153 * Force reorigination of intra-area-prefix-LSAs to handle
154 * areas without any full adjacency.
155 */
156 OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(area);
157
71165098 158 for (ALL_LIST_ELEMENTS_RO(area->if_list, anode, oi)) {
5cbcc459
RW
159 /* Reoriginate Link-LSA. */
160 if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
161 OSPF6_LINK_LSA_EXECUTE(oi);
71165098
RW
162
163 /*
164 * 2) The router should reoriginate network-LSAs on all
165 * segments where it is the Designated Router.
166 */
167 if (oi->state == OSPF6_INTERFACE_DR)
168 OSPF6_NETWORK_LSA_EXECUTE(oi);
169 }
170 }
171
5eb2c602
RW
172 /*
173 * While all self-originated NSSA and AS-external LSAs were already
174 * learned from the helping neighbors, we need to reoriginate them in
175 * order to ensure they will be refreshed periodically.
176 */
177 for (route = ospf6_route_head(ospf6->external_table); route;
178 route = ospf6_route_next(route))
179 ospf6_handle_external_lsa_origination(ospf6, route,
180 &route->prefix);
181
71165098
RW
182 /*
183 * 3) The router reruns its OSPF routing calculations, this time
184 * installing the results into the system forwarding table, and
185 * originating summary-LSAs, Type-7 LSAs and AS-external-LSAs as
186 * necessary.
187 *
188 * 4) Any remnant entries in the system forwarding table that were
189 * installed before the restart, but that are no longer valid,
190 * should be removed.
191 */
192 ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_GR_FINISH);
193
194 /* 6) Any grace-LSAs that the router originated should be flushed. */
195 ospf6_gr_flush_grace_lsas(ospf6);
196}
197
198#define RTR_LSA_MISSING 0
199#define RTR_LSA_ADJ_FOUND 1
200#define RTR_LSA_ADJ_NOT_FOUND 2
201
202/* Check if a Router-LSA exists and if it contains a given link. */
203static int ospf6_router_lsa_contains_adj(struct ospf6_area *area,
204 in_addr_t adv_router,
205 in_addr_t neighbor_router_id)
206{
207 uint16_t type;
208 struct ospf6_lsa *lsa;
209 bool empty = true;
210
211 type = ntohs(OSPF6_LSTYPE_ROUTER);
212 for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, adv_router, lsa)) {
213 struct ospf6_router_lsa *router_lsa;
214 char *start, *end, *current;
215
216 empty = false;
217 router_lsa = (struct ospf6_router_lsa
218 *)((char *)lsa->header
219 + sizeof(struct ospf6_lsa_header));
220
221 /* Iterate over all interfaces in the Router-LSA. */
222 start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
223 end = (char *)lsa->header + ntohs(lsa->header->length);
224 for (current = start;
225 current + sizeof(struct ospf6_router_lsdesc) <= end;
226 current += sizeof(struct ospf6_router_lsdesc)) {
227 struct ospf6_router_lsdesc *lsdesc;
228
229 lsdesc = (struct ospf6_router_lsdesc *)current;
230 if (lsdesc->type != OSPF6_ROUTER_LSDESC_POINTTOPOINT)
231 continue;
232
233 if (lsdesc->neighbor_router_id == neighbor_router_id)
234 return RTR_LSA_ADJ_FOUND;
235 }
236 }
237
238 if (empty)
239 return RTR_LSA_MISSING;
240
241 return RTR_LSA_ADJ_NOT_FOUND;
242}
243
244static bool ospf6_gr_check_router_lsa_consistency(struct ospf6 *ospf6,
245 struct ospf6_area *area,
246 struct ospf6_lsa *lsa)
247{
248 if (lsa->header->adv_router == ospf6->router_id) {
249 struct ospf6_router_lsa *router_lsa;
250 char *start, *end, *current;
251
252 router_lsa = (struct ospf6_router_lsa
253 *)((char *)lsa->header
254 + sizeof(struct ospf6_lsa_header));
255
256 /* Iterate over all interfaces in the Router-LSA. */
257 start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
258 end = (char *)lsa->header + ntohs(lsa->header->length);
259 for (current = start;
260 current + sizeof(struct ospf6_router_lsdesc) <= end;
261 current += sizeof(struct ospf6_router_lsdesc)) {
262 struct ospf6_router_lsdesc *lsdesc;
263
264 lsdesc = (struct ospf6_router_lsdesc *)current;
265 if (lsdesc->type != OSPF6_ROUTER_LSDESC_POINTTOPOINT)
266 continue;
267
268 if (ospf6_router_lsa_contains_adj(
269 area, lsdesc->neighbor_router_id,
270 ospf6->router_id)
271 == RTR_LSA_ADJ_NOT_FOUND)
272 return false;
273 }
274 } else {
275 int adj1, adj2;
276
277 adj1 = ospf6_router_lsa_contains_adj(area, ospf6->router_id,
278 lsa->header->adv_router);
279 adj2 = ospf6_router_lsa_contains_adj(
280 area, lsa->header->adv_router, ospf6->router_id);
281 if ((adj1 == RTR_LSA_ADJ_FOUND && adj2 == RTR_LSA_ADJ_NOT_FOUND)
282 || (adj1 == RTR_LSA_ADJ_NOT_FOUND
283 && adj2 == RTR_LSA_ADJ_FOUND))
284 return false;
285 }
286
287 return true;
288}
289
290/*
291 * Check for LSAs that are inconsistent with the pre-restart LSAs, and abort the
292 * ongoing graceful restart when that's the case.
293 */
294void ospf6_gr_check_lsdb_consistency(struct ospf6 *ospf6,
295 struct ospf6_area *area)
296{
297 uint16_t type;
298 struct ospf6_lsa *lsa;
299
300 type = ntohs(OSPF6_LSTYPE_ROUTER);
301 for (ALL_LSDB_TYPED(area->lsdb, type, lsa)) {
302 if (!ospf6_gr_check_router_lsa_consistency(ospf6, area, lsa)) {
303 char reason[256];
304
305 snprintfrr(reason, sizeof(reason),
306 "detected inconsistent LSA %s [area %pI4]",
307 lsa->name, &area->area_id);
308 ospf6_gr_restart_exit(ospf6, reason);
309 return;
310 }
311 }
312}
313
314/* Check if there's a fully formed adjacency with the given neighbor ID. */
315static bool ospf6_gr_check_adj_id(struct ospf6_area *area,
316 in_addr_t neighbor_router_id)
317{
318 struct ospf6_neighbor *nbr;
319
320 nbr = ospf6_area_neighbor_lookup(area, neighbor_router_id);
321 if (!nbr || nbr->state < OSPF6_NEIGHBOR_FULL) {
322 if (IS_DEBUG_OSPF6_GR)
323 zlog_debug("GR: missing adjacency to router %pI4",
324 &neighbor_router_id);
325 return false;
326 }
327
328 return true;
329}
330
331static bool ospf6_gr_check_adjs_lsa_transit(struct ospf6_area *area,
332 in_addr_t neighbor_router_id,
333 uint32_t neighbor_interface_id)
334{
335 struct ospf6 *ospf6 = area->ospf6;
336
337 /* Check if we are the DR. */
338 if (neighbor_router_id == ospf6->router_id) {
339 struct ospf6_lsa *lsa;
340 char *start, *end, *current;
341 struct ospf6_network_lsa *network_lsa;
342 struct ospf6_network_lsdesc *lsdesc;
343
344 /* Lookup Network LSA corresponding to this interface. */
345 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_NETWORK),
346 neighbor_interface_id,
347 neighbor_router_id, area->lsdb);
348 if (!lsa)
349 return false;
350
351 /* Iterate over all routers present in the network. */
352 network_lsa = (struct ospf6_network_lsa
353 *)((char *)lsa->header
354 + sizeof(struct ospf6_lsa_header));
355 start = (char *)network_lsa + sizeof(struct ospf6_network_lsa);
356 end = (char *)lsa->header + ntohs(lsa->header->length);
357 for (current = start;
358 current + sizeof(struct ospf6_network_lsdesc) <= end;
359 current += sizeof(struct ospf6_network_lsdesc)) {
360 lsdesc = (struct ospf6_network_lsdesc *)current;
361
362 /* Skip self in the pseudonode. */
363 if (lsdesc->router_id == ospf6->router_id)
364 continue;
365
366 /*
367 * Check if there's a fully formed adjacency with this
368 * router.
369 */
370 if (!ospf6_gr_check_adj_id(area, lsdesc->router_id))
371 return false;
372 }
373 } else {
374 struct ospf6_neighbor *nbr;
375
376 /* Check if there's a fully formed adjacency with the DR. */
377 nbr = ospf6_area_neighbor_lookup(area, neighbor_router_id);
378 if (!nbr || nbr->state < OSPF6_NEIGHBOR_FULL) {
379 if (IS_DEBUG_OSPF6_GR)
380 zlog_debug(
381 "GR: missing adjacency to DR router %pI4",
382 &neighbor_router_id);
383 return false;
384 }
385 }
386
387 return true;
388}
389
390static bool ospf6_gr_check_adjs_lsa(struct ospf6_area *area,
391 struct ospf6_lsa *lsa)
392{
393 struct ospf6_router_lsa *router_lsa;
394 char *start, *end, *current;
395
396 router_lsa =
397 (struct ospf6_router_lsa *)((char *)lsa->header
398 + sizeof(struct ospf6_lsa_header));
399
400 /* Iterate over all interfaces in the Router-LSA. */
401 start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
402 end = (char *)lsa->header + ntohs(lsa->header->length);
403 for (current = start;
404 current + sizeof(struct ospf6_router_lsdesc) <= end;
405 current += sizeof(struct ospf6_router_lsdesc)) {
406 struct ospf6_router_lsdesc *lsdesc;
407
408 lsdesc = (struct ospf6_router_lsdesc *)current;
409 switch (lsdesc->type) {
410 case OSPF6_ROUTER_LSDESC_POINTTOPOINT:
411 if (!ospf6_gr_check_adj_id(area,
412 lsdesc->neighbor_router_id))
413 return false;
414 break;
415 case OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK:
416 if (!ospf6_gr_check_adjs_lsa_transit(
417 area, lsdesc->neighbor_router_id,
418 lsdesc->neighbor_interface_id))
419 return false;
420 break;
421 default:
422 break;
423 }
424 }
425
426 return true;
427}
428
429/*
430 * Check if all adjacencies prior to the restart were reestablished.
431 *
432 * This is done using pre-restart Router LSAs and pre-restart Network LSAs
433 * received from the helping neighbors.
434 */
435static bool ospf6_gr_check_adjs(struct ospf6 *ospf6)
436{
437 struct ospf6_area *area;
438 struct listnode *node;
439
440 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, area)) {
441 uint16_t type;
442 uint32_t router;
443 struct ospf6_lsa *lsa_self;
444 bool found = false;
445
446 type = ntohs(OSPF6_LSTYPE_ROUTER);
447 router = ospf6->router_id;
448 for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, router,
449 lsa_self)) {
450 found = true;
451 if (!ospf6_gr_check_adjs_lsa(area, lsa_self))
452 return false;
453 }
454 if (!found)
455 return false;
456 }
457
458 return true;
459}
460
461/* Handling of grace period expiry. */
e6685141 462static void ospf6_gr_grace_period_expired(struct event *thread)
71165098 463{
e16d030c 464 struct ospf6 *ospf6 = EVENT_ARG(thread);
71165098 465
71165098 466 ospf6_gr_restart_exit(ospf6, "grace period has expired");
71165098
RW
467}
468
469/*
470 * Record in non-volatile memory that the given OSPF instance is attempting to
471 * perform a graceful restart.
472 */
473static void ospf6_gr_nvm_update(struct ospf6 *ospf6)
474{
475 const char *inst_name;
476 json_object *json;
477 json_object *json_instances;
478 json_object *json_instance;
479
480 inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
481
b275f44a 482 json = json_object_from_file((char *)OSPF6D_GR_STATE);
71165098
RW
483 if (json == NULL)
484 json = json_object_new_object();
485
486 json_object_object_get_ex(json, "instances", &json_instances);
487 if (!json_instances) {
488 json_instances = json_object_new_object();
489 json_object_object_add(json, "instances", json_instances);
490 }
491
492 json_object_object_get_ex(json_instances, inst_name, &json_instance);
493 if (!json_instance) {
494 json_instance = json_object_new_object();
495 json_object_object_add(json_instances, inst_name,
496 json_instance);
497 }
498
499 /*
500 * Record not only the grace period, but also a UNIX timestamp
501 * corresponding to the end of that period. That way, once ospf6d is
502 * restarted, it will be possible to take into account the time that
503 * passed while ospf6d wasn't running.
504 */
505 json_object_int_add(json_instance, "gracePeriod",
506 ospf6->gr_info.grace_period);
507 json_object_int_add(json_instance, "timestamp",
508 time(NULL) + ospf6->gr_info.grace_period);
509
b275f44a
RW
510 json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
511 JSON_C_TO_STRING_PRETTY);
71165098
RW
512 json_object_free(json);
513}
514
515/*
516 * Delete GR status information about the given OSPF instance from non-volatile
517 * memory.
518 */
519static void ospf6_gr_nvm_delete(struct ospf6 *ospf6)
520{
521 const char *inst_name;
522 json_object *json;
523 json_object *json_instances;
524
525 inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
526
b275f44a 527 json = json_object_from_file((char *)OSPF6D_GR_STATE);
71165098
RW
528 if (json == NULL)
529 json = json_object_new_object();
530
531 json_object_object_get_ex(json, "instances", &json_instances);
532 if (!json_instances) {
533 json_instances = json_object_new_object();
534 json_object_object_add(json, "instances", json_instances);
535 }
536
537 json_object_object_del(json_instances, inst_name);
538
b275f44a
RW
539 json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
540 JSON_C_TO_STRING_PRETTY);
71165098
RW
541 json_object_free(json);
542}
543
544/*
545 * Fetch from non-volatile memory whether the given OSPF instance is performing
546 * a graceful shutdown or not.
547 */
548void ospf6_gr_nvm_read(struct ospf6 *ospf6)
549{
550 const char *inst_name;
551 json_object *json;
552 json_object *json_instances;
553 json_object *json_instance;
554 json_object *json_timestamp;
555 time_t timestamp = 0;
556
557 inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
558
b275f44a 559 json = json_object_from_file((char *)OSPF6D_GR_STATE);
71165098
RW
560 if (json == NULL)
561 json = json_object_new_object();
562
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);
567 }
568
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,
573 json_instance);
574 }
575
576 json_object_object_get_ex(json_instance, "timestamp", &json_timestamp);
577 if (json_timestamp) {
578 time_t now;
579 unsigned long remaining_time;
580
581 /* Check if the grace period has already expired. */
582 now = time(NULL);
583 timestamp = json_object_get_int(json_timestamp);
584 if (now > timestamp) {
585 ospf6_gr_restart_exit(
586 ospf6, "grace period has expired already");
587 } else {
588 /* Schedule grace period timeout. */
589 ospf6->gr_info.restart_in_progress = true;
590 remaining_time = timestamp - time(NULL);
591 if (IS_DEBUG_OSPF6_GR)
592 zlog_debug(
593 "GR: remaining time until grace period expires: %lu(s)",
594 remaining_time);
907a2395
DS
595 event_add_timer(master, ospf6_gr_grace_period_expired,
596 ospf6, remaining_time,
597 &ospf6->gr_info.t_grace_period);
71165098
RW
598 }
599 }
600
601 json_object_object_del(json_instances, inst_name);
602
b275f44a
RW
603 json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
604 JSON_C_TO_STRING_PRETTY);
71165098
RW
605 json_object_free(json);
606}
607
608/* Prepare to start a Graceful Restart. */
609static void ospf6_gr_prepare(void)
610{
611 struct ospf6 *ospf6;
612 struct ospf6_interface *oi;
613 struct listnode *onode, *anode, *inode;
614
615 for (ALL_LIST_ELEMENTS_RO(om6->ospf6, onode, ospf6)) {
616 struct ospf6_area *area;
617
618 if (!ospf6->gr_info.restart_support
619 || ospf6->gr_info.prepare_in_progress)
620 continue;
621
622 if (IS_DEBUG_OSPF6_GR)
623 zlog_debug(
624 "GR: preparing to perform a graceful restart [period %u second(s)] [vrf %s]",
625 ospf6->gr_info.grace_period,
626 ospf6_vrf_id_to_name(ospf6->vrf_id));
627
628 /* Freeze OSPF routes in the RIB. */
629 if (ospf6_zebra_gr_enable(ospf6, ospf6->gr_info.grace_period)) {
630 zlog_warn(
631 "%s: failed to activate graceful restart: not connected to zebra",
632 __func__);
633 continue;
634 }
635
636 /* Send a Grace-LSA to all neighbors. */
637 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, anode, area)) {
638 for (ALL_LIST_ELEMENTS_RO(area->if_list, inode, oi)) {
639 if (oi->state < OSPF6_INTERFACE_POINTTOPOINT)
640 continue;
641 ospf6_gr_lsa_originate(oi);
642 }
643 }
644
645 /* Record end of the grace period in non-volatile memory. */
646 ospf6_gr_nvm_update(ospf6);
647
648 /*
649 * Mark that a Graceful Restart preparation is in progress, to
650 * prevent ospf6d from flushing its self-originated LSAs on
651 * exit.
652 */
653 ospf6->gr_info.prepare_in_progress = true;
654 }
655}
656
657static int ospf6_gr_neighbor_change(struct ospf6_neighbor *on, int next_state,
658 int prev_state)
659{
660 struct ospf6 *ospf6 = on->ospf6_if->area->ospf6;
661
662 if (next_state == OSPF6_NEIGHBOR_FULL
663 && ospf6->gr_info.restart_in_progress) {
664 if (ospf6_gr_check_adjs(ospf6)) {
665 ospf6_gr_restart_exit(
666 ospf6, "all adjacencies were reestablished");
667 } else {
668 if (IS_DEBUG_OSPF6_GR)
669 zlog_debug(
670 "GR: not all adjacencies were reestablished yet");
671 }
672 }
673
674 return 0;
675}
676
677int config_write_ospf6_gr(struct vty *vty, struct ospf6 *ospf6)
678{
679 if (!ospf6->gr_info.restart_support)
680 return 0;
681
682 if (ospf6->gr_info.grace_period == OSPF6_DFLT_GRACE_INTERVAL)
683 vty_out(vty, " graceful-restart\n");
684 else
685 vty_out(vty, " graceful-restart grace-period %u\n",
686 ospf6->gr_info.grace_period);
687
688 return 0;
689}
690
691DEFPY(ospf6_graceful_restart_prepare, ospf6_graceful_restart_prepare_cmd,
692 "graceful-restart prepare ipv6 ospf",
693 "Graceful Restart commands\n"
694 "Prepare upcoming graceful restart\n" IPV6_STR
4a3c92de 695 "Prepare to restart the OSPFv3 process\n")
71165098
RW
696{
697 ospf6_gr_prepare();
698
699 return CMD_SUCCESS;
700}
701
702DEFPY(ospf6_graceful_restart, ospf6_graceful_restart_cmd,
703 "graceful-restart [grace-period (1-1800)$grace_period]",
704 OSPF_GR_STR
705 "Maximum length of the 'grace period'\n"
706 "Maximum length of the 'grace period' in seconds\n")
707{
708 VTY_DECLVAR_INSTANCE_CONTEXT(ospf6, ospf6);
709
710 /* Check and get restart period if present. */
711 if (!grace_period_str)
712 grace_period = OSPF6_DFLT_GRACE_INTERVAL;
713
714 ospf6->gr_info.restart_support = true;
715 ospf6->gr_info.grace_period = grace_period;
716
717 return CMD_SUCCESS;
718}
719
720DEFPY(ospf6_no_graceful_restart, ospf6_no_graceful_restart_cmd,
721 "no graceful-restart [period (1-1800)]",
722 NO_STR OSPF_GR_STR
723 "Maximum length of the 'grace period'\n"
724 "Maximum length of the 'grace period' in seconds\n")
725{
726 VTY_DECLVAR_INSTANCE_CONTEXT(ospf6, ospf6);
727
728 if (!ospf6->gr_info.restart_support)
729 return CMD_SUCCESS;
730
731 if (ospf6->gr_info.prepare_in_progress) {
732 vty_out(vty,
733 "%% Error: Graceful Restart preparation in progress\n");
734 return CMD_WARNING;
735 }
736
737 ospf6->gr_info.restart_support = false;
738 ospf6->gr_info.grace_period = OSPF6_DFLT_GRACE_INTERVAL;
739
740 return CMD_SUCCESS;
741}
742
743void ospf6_gr_init(void)
744{
745 hook_register(ospf6_neighbor_change, ospf6_gr_neighbor_change);
746
747 install_element(ENABLE_NODE, &ospf6_graceful_restart_prepare_cmd);
748 install_element(OSPF6_NODE, &ospf6_graceful_restart_cmd);
749 install_element(OSPF6_NODE, &ospf6_no_graceful_restart_cmd);
750}