]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_gr.c
Merge pull request #10566 from whichbug/master
[mirror_frr.git] / ospf6d / ospf6_gr.c
1 /*
2 * This is an implementation of RFC 5187 Graceful Restart.
3 *
4 * Copyright 2021 NetDEF (c), All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #include "memory.h"
24 #include "command.h"
25 #include "table.h"
26 #include "vty.h"
27 #include "log.h"
28 #include "hook.h"
29 #include "printfrr.h"
30
31 #include "ospf6d/ospf6_lsa.h"
32 #include "ospf6d/ospf6_lsdb.h"
33 #include "ospf6d/ospf6_route.h"
34 #include "ospf6d/ospf6_area.h"
35 #include "ospf6d/ospf6_interface.h"
36 #include "ospf6d/ospf6d.h"
37 #include "ospf6d/ospf6_asbr.h"
38 #include "ospf6d/ospf6_zebra.h"
39 #include "ospf6d/ospf6_message.h"
40 #include "ospf6d/ospf6_neighbor.h"
41 #include "ospf6d/ospf6_flood.h"
42 #include "ospf6d/ospf6_intra.h"
43 #include "ospf6d/ospf6_spf.h"
44 #include "ospf6d/ospf6_gr.h"
45 #ifndef VTYSH_EXTRACT_PL
46 #include "ospf6d/ospf6_gr_clippy.c"
47 #endif
48
49 static void ospf6_gr_nvm_delete(struct ospf6 *ospf6);
50
51 /* Originate and install Grace-LSA for a given interface. */
52 static int ospf6_gr_lsa_originate(struct ospf6_interface *oi)
53 {
54 struct ospf6_gr_info *gr_info = &oi->area->ospf6->gr_info;
55 struct ospf6_lsa_header *lsa_header;
56 struct ospf6_grace_lsa *grace_lsa;
57 struct ospf6_lsa *lsa;
58 char buffer[OSPF6_MAX_LSASIZE];
59
60 if (IS_OSPF6_DEBUG_ORIGINATE(LINK))
61 zlog_debug("Originate Grace-LSA for Interface %s",
62 oi->interface->name);
63
64 /* prepare buffer */
65 memset(buffer, 0, sizeof(buffer));
66 lsa_header = (struct ospf6_lsa_header *)buffer;
67 grace_lsa =
68 (struct ospf6_grace_lsa *)((caddr_t)lsa_header
69 + sizeof(struct ospf6_lsa_header));
70
71 /* Put grace period. */
72 grace_lsa->tlv_period.header.type = htons(GRACE_PERIOD_TYPE);
73 grace_lsa->tlv_period.header.length = htons(GRACE_PERIOD_LENGTH);
74 grace_lsa->tlv_period.interval = htonl(gr_info->grace_period);
75
76 /* Put restart reason. */
77 grace_lsa->tlv_reason.header.type = htons(RESTART_REASON_TYPE);
78 grace_lsa->tlv_reason.header.length = htons(RESTART_REASON_LENGTH);
79 if (gr_info->restart_support)
80 grace_lsa->tlv_reason.reason = OSPF6_GR_SW_RESTART;
81 else
82 grace_lsa->tlv_reason.reason = OSPF6_GR_UNKNOWN_RESTART;
83
84 /* Fill LSA Header */
85 lsa_header->age = 0;
86 lsa_header->type = htons(OSPF6_LSTYPE_GRACE_LSA);
87 lsa_header->id = htonl(oi->interface->ifindex);
88 lsa_header->adv_router = oi->area->ospf6->router_id;
89 lsa_header->seqnum =
90 ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
91 lsa_header->adv_router, oi->lsdb);
92 lsa_header->length = htons(sizeof(*lsa_header) + sizeof(*grace_lsa));
93
94 /* LSA checksum */
95 ospf6_lsa_checksum(lsa_header);
96
97 /* create LSA */
98 lsa = ospf6_lsa_create(lsa_header);
99
100 /* Originate */
101 ospf6_lsa_originate_interface(lsa, oi);
102
103 return 0;
104 }
105
106 /* Flush all self-originated Grace-LSAs. */
107 static void ospf6_gr_flush_grace_lsas(struct ospf6 *ospf6)
108 {
109 struct ospf6_area *area;
110 struct listnode *anode;
111
112 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, anode, area)) {
113 struct ospf6_lsa *lsa;
114 struct ospf6_interface *oi;
115 struct listnode *inode;
116
117 if (IS_DEBUG_OSPF6_GR)
118 zlog_debug(
119 "GR: flushing self-originated Grace-LSAs [area %pI4]",
120 &area->area_id);
121
122 for (ALL_LIST_ELEMENTS_RO(area->if_list, inode, oi)) {
123 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_GRACE_LSA),
124 htonl(oi->interface->ifindex),
125 oi->area->ospf6->router_id,
126 oi->lsdb);
127 if (!lsa) {
128 zlog_warn(
129 "%s: Grace-LSA not found [interface %s] [area %pI4]",
130 __func__, oi->interface->name,
131 &area->area_id);
132 continue;
133 }
134
135 ospf6_lsa_purge(lsa);
136 }
137 }
138 }
139
140 /* Exit from the Graceful Restart mode. */
141 static void ospf6_gr_restart_exit(struct ospf6 *ospf6, const char *reason)
142 {
143 struct ospf6_area *area;
144 struct listnode *onode, *anode;
145
146 if (IS_DEBUG_OSPF6_GR)
147 zlog_debug("GR: exiting graceful restart: %s", reason);
148
149 ospf6->gr_info.restart_in_progress = false;
150 ospf6->gr_info.finishing_restart = true;
151 THREAD_OFF(ospf6->gr_info.t_grace_period);
152
153 /* Record in non-volatile memory that the restart is complete. */
154 ospf6_gr_nvm_delete(ospf6);
155
156 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, onode, area)) {
157 struct ospf6_interface *oi;
158
159 /*
160 * 1) The router should reoriginate its router-LSAs for all
161 * attached areas in order to make sure they have the correct
162 * contents.
163 */
164 OSPF6_ROUTER_LSA_EXECUTE(area);
165
166 for (ALL_LIST_ELEMENTS_RO(area->if_list, anode, oi)) {
167 OSPF6_LINK_LSA_EXECUTE(oi);
168
169 /*
170 * 2) The router should reoriginate network-LSAs on all
171 * segments where it is the Designated Router.
172 */
173 if (oi->state == OSPF6_INTERFACE_DR)
174 OSPF6_NETWORK_LSA_EXECUTE(oi);
175 }
176 }
177
178 /*
179 * 3) The router reruns its OSPF routing calculations, this time
180 * installing the results into the system forwarding table, and
181 * originating summary-LSAs, Type-7 LSAs and AS-external-LSAs as
182 * necessary.
183 *
184 * 4) Any remnant entries in the system forwarding table that were
185 * installed before the restart, but that are no longer valid,
186 * should be removed.
187 */
188 ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_GR_FINISH);
189
190 /* 6) Any grace-LSAs that the router originated should be flushed. */
191 ospf6_gr_flush_grace_lsas(ospf6);
192 }
193
194 #define RTR_LSA_MISSING 0
195 #define RTR_LSA_ADJ_FOUND 1
196 #define RTR_LSA_ADJ_NOT_FOUND 2
197
198 /* Check if a Router-LSA exists and if it contains a given link. */
199 static int ospf6_router_lsa_contains_adj(struct ospf6_area *area,
200 in_addr_t adv_router,
201 in_addr_t neighbor_router_id)
202 {
203 uint16_t type;
204 struct ospf6_lsa *lsa;
205 bool empty = true;
206
207 type = ntohs(OSPF6_LSTYPE_ROUTER);
208 for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, adv_router, lsa)) {
209 struct ospf6_router_lsa *router_lsa;
210 char *start, *end, *current;
211
212 empty = false;
213 router_lsa = (struct ospf6_router_lsa
214 *)((char *)lsa->header
215 + sizeof(struct ospf6_lsa_header));
216
217 /* Iterate over all interfaces in the Router-LSA. */
218 start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
219 end = (char *)lsa->header + ntohs(lsa->header->length);
220 for (current = start;
221 current + sizeof(struct ospf6_router_lsdesc) <= end;
222 current += sizeof(struct ospf6_router_lsdesc)) {
223 struct ospf6_router_lsdesc *lsdesc;
224
225 lsdesc = (struct ospf6_router_lsdesc *)current;
226 if (lsdesc->type != OSPF6_ROUTER_LSDESC_POINTTOPOINT)
227 continue;
228
229 if (lsdesc->neighbor_router_id == neighbor_router_id)
230 return RTR_LSA_ADJ_FOUND;
231 }
232 }
233
234 if (empty)
235 return RTR_LSA_MISSING;
236
237 return RTR_LSA_ADJ_NOT_FOUND;
238 }
239
240 static bool ospf6_gr_check_router_lsa_consistency(struct ospf6 *ospf6,
241 struct ospf6_area *area,
242 struct ospf6_lsa *lsa)
243 {
244 if (lsa->header->adv_router == ospf6->router_id) {
245 struct ospf6_router_lsa *router_lsa;
246 char *start, *end, *current;
247
248 router_lsa = (struct ospf6_router_lsa
249 *)((char *)lsa->header
250 + sizeof(struct ospf6_lsa_header));
251
252 /* Iterate over all interfaces in the Router-LSA. */
253 start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
254 end = (char *)lsa->header + ntohs(lsa->header->length);
255 for (current = start;
256 current + sizeof(struct ospf6_router_lsdesc) <= end;
257 current += sizeof(struct ospf6_router_lsdesc)) {
258 struct ospf6_router_lsdesc *lsdesc;
259
260 lsdesc = (struct ospf6_router_lsdesc *)current;
261 if (lsdesc->type != OSPF6_ROUTER_LSDESC_POINTTOPOINT)
262 continue;
263
264 if (ospf6_router_lsa_contains_adj(
265 area, lsdesc->neighbor_router_id,
266 ospf6->router_id)
267 == RTR_LSA_ADJ_NOT_FOUND)
268 return false;
269 }
270 } else {
271 int adj1, adj2;
272
273 adj1 = ospf6_router_lsa_contains_adj(area, ospf6->router_id,
274 lsa->header->adv_router);
275 adj2 = ospf6_router_lsa_contains_adj(
276 area, lsa->header->adv_router, ospf6->router_id);
277 if ((adj1 == RTR_LSA_ADJ_FOUND && adj2 == RTR_LSA_ADJ_NOT_FOUND)
278 || (adj1 == RTR_LSA_ADJ_NOT_FOUND
279 && adj2 == RTR_LSA_ADJ_FOUND))
280 return false;
281 }
282
283 return true;
284 }
285
286 /*
287 * Check for LSAs that are inconsistent with the pre-restart LSAs, and abort the
288 * ongoing graceful restart when that's the case.
289 */
290 void ospf6_gr_check_lsdb_consistency(struct ospf6 *ospf6,
291 struct ospf6_area *area)
292 {
293 uint16_t type;
294 struct ospf6_lsa *lsa;
295
296 type = ntohs(OSPF6_LSTYPE_ROUTER);
297 for (ALL_LSDB_TYPED(area->lsdb, type, lsa)) {
298 if (!ospf6_gr_check_router_lsa_consistency(ospf6, area, lsa)) {
299 char reason[256];
300
301 snprintfrr(reason, sizeof(reason),
302 "detected inconsistent LSA %s [area %pI4]",
303 lsa->name, &area->area_id);
304 ospf6_gr_restart_exit(ospf6, reason);
305 return;
306 }
307 }
308 }
309
310 /* Check if there's a fully formed adjacency with the given neighbor ID. */
311 static bool ospf6_gr_check_adj_id(struct ospf6_area *area,
312 in_addr_t neighbor_router_id)
313 {
314 struct ospf6_neighbor *nbr;
315
316 nbr = ospf6_area_neighbor_lookup(area, neighbor_router_id);
317 if (!nbr || nbr->state < OSPF6_NEIGHBOR_FULL) {
318 if (IS_DEBUG_OSPF6_GR)
319 zlog_debug("GR: missing adjacency to router %pI4",
320 &neighbor_router_id);
321 return false;
322 }
323
324 return true;
325 }
326
327 static bool ospf6_gr_check_adjs_lsa_transit(struct ospf6_area *area,
328 in_addr_t neighbor_router_id,
329 uint32_t neighbor_interface_id)
330 {
331 struct ospf6 *ospf6 = area->ospf6;
332
333 /* Check if we are the DR. */
334 if (neighbor_router_id == ospf6->router_id) {
335 struct ospf6_lsa *lsa;
336 char *start, *end, *current;
337 struct ospf6_network_lsa *network_lsa;
338 struct ospf6_network_lsdesc *lsdesc;
339
340 /* Lookup Network LSA corresponding to this interface. */
341 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_NETWORK),
342 neighbor_interface_id,
343 neighbor_router_id, area->lsdb);
344 if (!lsa)
345 return false;
346
347 /* Iterate over all routers present in the network. */
348 network_lsa = (struct ospf6_network_lsa
349 *)((char *)lsa->header
350 + sizeof(struct ospf6_lsa_header));
351 start = (char *)network_lsa + sizeof(struct ospf6_network_lsa);
352 end = (char *)lsa->header + ntohs(lsa->header->length);
353 for (current = start;
354 current + sizeof(struct ospf6_network_lsdesc) <= end;
355 current += sizeof(struct ospf6_network_lsdesc)) {
356 lsdesc = (struct ospf6_network_lsdesc *)current;
357
358 /* Skip self in the pseudonode. */
359 if (lsdesc->router_id == ospf6->router_id)
360 continue;
361
362 /*
363 * Check if there's a fully formed adjacency with this
364 * router.
365 */
366 if (!ospf6_gr_check_adj_id(area, lsdesc->router_id))
367 return false;
368 }
369 } else {
370 struct ospf6_neighbor *nbr;
371
372 /* Check if there's a fully formed adjacency with the DR. */
373 nbr = ospf6_area_neighbor_lookup(area, neighbor_router_id);
374 if (!nbr || nbr->state < OSPF6_NEIGHBOR_FULL) {
375 if (IS_DEBUG_OSPF6_GR)
376 zlog_debug(
377 "GR: missing adjacency to DR router %pI4",
378 &neighbor_router_id);
379 return false;
380 }
381 }
382
383 return true;
384 }
385
386 static bool ospf6_gr_check_adjs_lsa(struct ospf6_area *area,
387 struct ospf6_lsa *lsa)
388 {
389 struct ospf6_router_lsa *router_lsa;
390 char *start, *end, *current;
391
392 router_lsa =
393 (struct ospf6_router_lsa *)((char *)lsa->header
394 + sizeof(struct ospf6_lsa_header));
395
396 /* Iterate over all interfaces in the Router-LSA. */
397 start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
398 end = (char *)lsa->header + ntohs(lsa->header->length);
399 for (current = start;
400 current + sizeof(struct ospf6_router_lsdesc) <= end;
401 current += sizeof(struct ospf6_router_lsdesc)) {
402 struct ospf6_router_lsdesc *lsdesc;
403
404 lsdesc = (struct ospf6_router_lsdesc *)current;
405 switch (lsdesc->type) {
406 case OSPF6_ROUTER_LSDESC_POINTTOPOINT:
407 if (!ospf6_gr_check_adj_id(area,
408 lsdesc->neighbor_router_id))
409 return false;
410 break;
411 case OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK:
412 if (!ospf6_gr_check_adjs_lsa_transit(
413 area, lsdesc->neighbor_router_id,
414 lsdesc->neighbor_interface_id))
415 return false;
416 break;
417 default:
418 break;
419 }
420 }
421
422 return true;
423 }
424
425 /*
426 * Check if all adjacencies prior to the restart were reestablished.
427 *
428 * This is done using pre-restart Router LSAs and pre-restart Network LSAs
429 * received from the helping neighbors.
430 */
431 static bool ospf6_gr_check_adjs(struct ospf6 *ospf6)
432 {
433 struct ospf6_area *area;
434 struct listnode *node;
435
436 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, area)) {
437 uint16_t type;
438 uint32_t router;
439 struct ospf6_lsa *lsa_self;
440 bool found = false;
441
442 type = ntohs(OSPF6_LSTYPE_ROUTER);
443 router = ospf6->router_id;
444 for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, router,
445 lsa_self)) {
446 found = true;
447 if (!ospf6_gr_check_adjs_lsa(area, lsa_self))
448 return false;
449 }
450 if (!found)
451 return false;
452 }
453
454 return true;
455 }
456
457 /* Handling of grace period expiry. */
458 static void ospf6_gr_grace_period_expired(struct thread *thread)
459 {
460 struct ospf6 *ospf6 = THREAD_ARG(thread);
461
462 ospf6->gr_info.t_grace_period = NULL;
463 ospf6_gr_restart_exit(ospf6, "grace period has expired");
464 }
465
466 /*
467 * Record in non-volatile memory that the given OSPF instance is attempting to
468 * perform a graceful restart.
469 */
470 static void ospf6_gr_nvm_update(struct ospf6 *ospf6)
471 {
472 const char *inst_name;
473 json_object *json;
474 json_object *json_instances;
475 json_object *json_instance;
476
477 inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
478
479 json = json_object_from_file((char *)OSPF6D_GR_STATE);
480 if (json == NULL)
481 json = json_object_new_object();
482
483 json_object_object_get_ex(json, "instances", &json_instances);
484 if (!json_instances) {
485 json_instances = json_object_new_object();
486 json_object_object_add(json, "instances", json_instances);
487 }
488
489 json_object_object_get_ex(json_instances, inst_name, &json_instance);
490 if (!json_instance) {
491 json_instance = json_object_new_object();
492 json_object_object_add(json_instances, inst_name,
493 json_instance);
494 }
495
496 /*
497 * Record not only the grace period, but also a UNIX timestamp
498 * corresponding to the end of that period. That way, once ospf6d is
499 * restarted, it will be possible to take into account the time that
500 * passed while ospf6d wasn't running.
501 */
502 json_object_int_add(json_instance, "gracePeriod",
503 ospf6->gr_info.grace_period);
504 json_object_int_add(json_instance, "timestamp",
505 time(NULL) + ospf6->gr_info.grace_period);
506
507 json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
508 JSON_C_TO_STRING_PRETTY);
509 json_object_free(json);
510 }
511
512 /*
513 * Delete GR status information about the given OSPF instance from non-volatile
514 * memory.
515 */
516 static void ospf6_gr_nvm_delete(struct ospf6 *ospf6)
517 {
518 const char *inst_name;
519 json_object *json;
520 json_object *json_instances;
521
522 inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
523
524 json = json_object_from_file((char *)OSPF6D_GR_STATE);
525 if (json == NULL)
526 json = json_object_new_object();
527
528 json_object_object_get_ex(json, "instances", &json_instances);
529 if (!json_instances) {
530 json_instances = json_object_new_object();
531 json_object_object_add(json, "instances", json_instances);
532 }
533
534 json_object_object_del(json_instances, inst_name);
535
536 json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
537 JSON_C_TO_STRING_PRETTY);
538 json_object_free(json);
539 }
540
541 /*
542 * Fetch from non-volatile memory whether the given OSPF instance is performing
543 * a graceful shutdown or not.
544 */
545 void ospf6_gr_nvm_read(struct ospf6 *ospf6)
546 {
547 const char *inst_name;
548 json_object *json;
549 json_object *json_instances;
550 json_object *json_instance;
551 json_object *json_timestamp;
552 time_t timestamp = 0;
553
554 inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
555
556 json = json_object_from_file((char *)OSPF6D_GR_STATE);
557 if (json == NULL)
558 json = json_object_new_object();
559
560 json_object_object_get_ex(json, "instances", &json_instances);
561 if (!json_instances) {
562 json_instances = json_object_new_object();
563 json_object_object_add(json, "instances", json_instances);
564 }
565
566 json_object_object_get_ex(json_instances, inst_name, &json_instance);
567 if (!json_instance) {
568 json_instance = json_object_new_object();
569 json_object_object_add(json_instances, inst_name,
570 json_instance);
571 }
572
573 json_object_object_get_ex(json_instance, "timestamp", &json_timestamp);
574 if (json_timestamp) {
575 time_t now;
576 unsigned long remaining_time;
577
578 /* Check if the grace period has already expired. */
579 now = time(NULL);
580 timestamp = json_object_get_int(json_timestamp);
581 if (now > timestamp) {
582 ospf6_gr_restart_exit(
583 ospf6, "grace period has expired already");
584 } else {
585 /* Schedule grace period timeout. */
586 ospf6->gr_info.restart_in_progress = true;
587 remaining_time = timestamp - time(NULL);
588 if (IS_DEBUG_OSPF6_GR)
589 zlog_debug(
590 "GR: remaining time until grace period expires: %lu(s)",
591 remaining_time);
592 thread_add_timer(master, ospf6_gr_grace_period_expired,
593 ospf6, remaining_time,
594 &ospf6->gr_info.t_grace_period);
595 }
596 }
597
598 json_object_object_del(json_instances, inst_name);
599
600 json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
601 JSON_C_TO_STRING_PRETTY);
602 json_object_free(json);
603 }
604
605 /* Prepare to start a Graceful Restart. */
606 static void ospf6_gr_prepare(void)
607 {
608 struct ospf6 *ospf6;
609 struct ospf6_interface *oi;
610 struct listnode *onode, *anode, *inode;
611
612 for (ALL_LIST_ELEMENTS_RO(om6->ospf6, onode, ospf6)) {
613 struct ospf6_area *area;
614
615 if (!ospf6->gr_info.restart_support
616 || ospf6->gr_info.prepare_in_progress)
617 continue;
618
619 if (IS_DEBUG_OSPF6_GR)
620 zlog_debug(
621 "GR: preparing to perform a graceful restart [period %u second(s)] [vrf %s]",
622 ospf6->gr_info.grace_period,
623 ospf6_vrf_id_to_name(ospf6->vrf_id));
624
625 /* Freeze OSPF routes in the RIB. */
626 if (ospf6_zebra_gr_enable(ospf6, ospf6->gr_info.grace_period)) {
627 zlog_warn(
628 "%s: failed to activate graceful restart: not connected to zebra",
629 __func__);
630 continue;
631 }
632
633 /* Send a Grace-LSA to all neighbors. */
634 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, anode, area)) {
635 for (ALL_LIST_ELEMENTS_RO(area->if_list, inode, oi)) {
636 if (oi->state < OSPF6_INTERFACE_POINTTOPOINT)
637 continue;
638 ospf6_gr_lsa_originate(oi);
639 }
640 }
641
642 /* Record end of the grace period in non-volatile memory. */
643 ospf6_gr_nvm_update(ospf6);
644
645 /*
646 * Mark that a Graceful Restart preparation is in progress, to
647 * prevent ospf6d from flushing its self-originated LSAs on
648 * exit.
649 */
650 ospf6->gr_info.prepare_in_progress = true;
651 }
652 }
653
654 static int ospf6_gr_neighbor_change(struct ospf6_neighbor *on, int next_state,
655 int prev_state)
656 {
657 struct ospf6 *ospf6 = on->ospf6_if->area->ospf6;
658
659 if (next_state == OSPF6_NEIGHBOR_FULL
660 && ospf6->gr_info.restart_in_progress) {
661 if (ospf6_gr_check_adjs(ospf6)) {
662 ospf6_gr_restart_exit(
663 ospf6, "all adjacencies were reestablished");
664 } else {
665 if (IS_DEBUG_OSPF6_GR)
666 zlog_debug(
667 "GR: not all adjacencies were reestablished yet");
668 }
669 }
670
671 return 0;
672 }
673
674 int config_write_ospf6_gr(struct vty *vty, struct ospf6 *ospf6)
675 {
676 if (!ospf6->gr_info.restart_support)
677 return 0;
678
679 if (ospf6->gr_info.grace_period == OSPF6_DFLT_GRACE_INTERVAL)
680 vty_out(vty, " graceful-restart\n");
681 else
682 vty_out(vty, " graceful-restart grace-period %u\n",
683 ospf6->gr_info.grace_period);
684
685 return 0;
686 }
687
688 DEFPY(ospf6_graceful_restart_prepare, ospf6_graceful_restart_prepare_cmd,
689 "graceful-restart prepare ipv6 ospf",
690 "Graceful Restart commands\n"
691 "Prepare upcoming graceful restart\n" IPV6_STR
692 "Prepare to restart the OSPFv3 process")
693 {
694 ospf6_gr_prepare();
695
696 return CMD_SUCCESS;
697 }
698
699 DEFPY(ospf6_graceful_restart, ospf6_graceful_restart_cmd,
700 "graceful-restart [grace-period (1-1800)$grace_period]",
701 OSPF_GR_STR
702 "Maximum length of the 'grace period'\n"
703 "Maximum length of the 'grace period' in seconds\n")
704 {
705 VTY_DECLVAR_INSTANCE_CONTEXT(ospf6, ospf6);
706
707 /* Check and get restart period if present. */
708 if (!grace_period_str)
709 grace_period = OSPF6_DFLT_GRACE_INTERVAL;
710
711 ospf6->gr_info.restart_support = true;
712 ospf6->gr_info.grace_period = grace_period;
713
714 return CMD_SUCCESS;
715 }
716
717 DEFPY(ospf6_no_graceful_restart, ospf6_no_graceful_restart_cmd,
718 "no graceful-restart [period (1-1800)]",
719 NO_STR OSPF_GR_STR
720 "Maximum length of the 'grace period'\n"
721 "Maximum length of the 'grace period' in seconds\n")
722 {
723 VTY_DECLVAR_INSTANCE_CONTEXT(ospf6, ospf6);
724
725 if (!ospf6->gr_info.restart_support)
726 return CMD_SUCCESS;
727
728 if (ospf6->gr_info.prepare_in_progress) {
729 vty_out(vty,
730 "%% Error: Graceful Restart preparation in progress\n");
731 return CMD_WARNING;
732 }
733
734 ospf6->gr_info.restart_support = false;
735 ospf6->gr_info.grace_period = OSPF6_DFLT_GRACE_INTERVAL;
736
737 return CMD_SUCCESS;
738 }
739
740 void ospf6_gr_init(void)
741 {
742 hook_register(ospf6_neighbor_change, ospf6_gr_neighbor_change);
743
744 install_element(ENABLE_NODE, &ospf6_graceful_restart_prepare_cmd);
745 install_element(OSPF6_NODE, &ospf6_graceful_restart_cmd);
746 install_element(OSPF6_NODE, &ospf6_no_graceful_restart_cmd);
747 }