]> git.proxmox.com Git - mirror_frr.git/blame - ospf6d/ospf6_gr.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[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"
88b3d5e5 17#include "lib_errors.h"
71165098
RW
18
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"
88b3d5e5 29#include "ospf6d/ospf6_network.h"
71165098
RW
30#include "ospf6d/ospf6_flood.h"
31#include "ospf6d/ospf6_intra.h"
32#include "ospf6d/ospf6_spf.h"
33#include "ospf6d/ospf6_gr.h"
71165098 34#include "ospf6d/ospf6_gr_clippy.c"
71165098 35
88b3d5e5 36static void ospf6_gr_grace_period_expired(struct event *thread);
71165098
RW
37
38/* Originate and install Grace-LSA for a given interface. */
88b3d5e5
RW
39static int ospf6_gr_lsa_originate(struct ospf6_interface *oi,
40 enum ospf6_gr_restart_reason reason)
71165098 41{
88b3d5e5
RW
42 struct ospf6 *ospf6 = oi->area->ospf6;
43 struct ospf6_gr_info *gr_info = &ospf6->gr_info;
71165098
RW
44 struct ospf6_lsa_header *lsa_header;
45 struct ospf6_grace_lsa *grace_lsa;
46 struct ospf6_lsa *lsa;
88b3d5e5 47 uint16_t lsa_length;
71165098
RW
48 char buffer[OSPF6_MAX_LSASIZE];
49
50 if (IS_OSPF6_DEBUG_ORIGINATE(LINK))
d6f60d22 51 zlog_debug("Originate Grace-LSA for Interface %s",
71165098
RW
52 oi->interface->name);
53
54 /* prepare buffer */
55 memset(buffer, 0, sizeof(buffer));
56 lsa_header = (struct ospf6_lsa_header *)buffer;
57 grace_lsa =
58 (struct ospf6_grace_lsa *)((caddr_t)lsa_header
59 + sizeof(struct ospf6_lsa_header));
60
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);
65
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);
88b3d5e5 69 grace_lsa->tlv_reason.reason = reason;
71165098
RW
70
71 /* Fill LSA Header */
88b3d5e5 72 lsa_length = sizeof(*lsa_header) + sizeof(*grace_lsa);
71165098
RW
73 lsa_header->age = 0;
74 lsa_header->type = htons(OSPF6_LSTYPE_GRACE_LSA);
75 lsa_header->id = htonl(oi->interface->ifindex);
88b3d5e5 76 lsa_header->adv_router = ospf6->router_id;
71165098
RW
77 lsa_header->seqnum =
78 ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
79 lsa_header->adv_router, oi->lsdb);
88b3d5e5 80 lsa_header->length = htons(lsa_length);
71165098
RW
81
82 /* LSA checksum */
83 ospf6_lsa_checksum(lsa_header);
84
88b3d5e5
RW
85 if (reason == OSPF6_GR_UNKNOWN_RESTART) {
86 struct ospf6_header *oh;
87 uint32_t *uv32;
88 int n;
89 uint16_t length = OSPF6_HEADER_SIZE + 4 + lsa_length;
90 struct iovec iovector[2] = {};
91
92 /* Reserve space for OSPFv3 header. */
93 memmove(&buffer[OSPF6_HEADER_SIZE + 4], buffer, lsa_length);
94
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;
102 oh->reserved = 0;
103 oh->length = htons(length);
104
105 /* Fill LSA header. */
106 uv32 = (uint32_t *)&buffer[sizeof(*oh)];
107 *uv32 = htonl(1);
108
109 /* Send packet. */
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);
114 if (n != length)
115 flog_err(EC_LIB_DEVELOPMENT,
116 "%s: could not send entire message", __func__);
117 } else {
118 /* Create and install LSA. */
119 lsa = ospf6_lsa_create(lsa_header);
120 ospf6_lsa_originate_interface(lsa, oi);
121 }
71165098
RW
122
123 return 0;
124}
125
126/* Flush all self-originated Grace-LSAs. */
127static void ospf6_gr_flush_grace_lsas(struct ospf6 *ospf6)
128{
129 struct ospf6_area *area;
130 struct listnode *anode;
131
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;
136
137 if (IS_DEBUG_OSPF6_GR)
138 zlog_debug(
139 "GR: flushing self-originated Grace-LSAs [area %pI4]",
140 &area->area_id);
141
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,
146 oi->lsdb);
147 if (!lsa) {
148 zlog_warn(
149 "%s: Grace-LSA not found [interface %s] [area %pI4]",
150 __func__, oi->interface->name,
151 &area->area_id);
152 continue;
153 }
154
155 ospf6_lsa_purge(lsa);
156 }
157 }
158}
159
160/* Exit from the Graceful Restart mode. */
161static void ospf6_gr_restart_exit(struct ospf6 *ospf6, const char *reason)
162{
163 struct ospf6_area *area;
164 struct listnode *onode, *anode;
5eb2c602 165 struct ospf6_route *route;
71165098
RW
166
167 if (IS_DEBUG_OSPF6_GR)
168 zlog_debug("GR: exiting graceful restart: %s", reason);
169
170 ospf6->gr_info.restart_in_progress = false;
171 ospf6->gr_info.finishing_restart = true;
88b3d5e5
RW
172 XFREE(MTYPE_TMP, ospf6->gr_info.exit_reason);
173 ospf6->gr_info.exit_reason = XSTRDUP(MTYPE_TMP, reason);
e16d030c 174 EVENT_OFF(ospf6->gr_info.t_grace_period);
71165098 175
71165098
RW
176 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, onode, area)) {
177 struct ospf6_interface *oi;
178
179 /*
180 * 1) The router should reoriginate its router-LSAs for all
181 * attached areas in order to make sure they have the correct
182 * contents.
183 */
184 OSPF6_ROUTER_LSA_EXECUTE(area);
185
3d2533ed
RW
186 /*
187 * Force reorigination of intra-area-prefix-LSAs to handle
188 * areas without any full adjacency.
189 */
190 OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(area);
191
71165098 192 for (ALL_LIST_ELEMENTS_RO(area->if_list, anode, oi)) {
0c05ceae
RW
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);
199 }
200
5cbcc459
RW
201 /* Reoriginate Link-LSA. */
202 if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
203 OSPF6_LINK_LSA_EXECUTE(oi);
71165098
RW
204
205 /*
206 * 2) The router should reoriginate network-LSAs on all
207 * segments where it is the Designated Router.
208 */
209 if (oi->state == OSPF6_INTERFACE_DR)
210 OSPF6_NETWORK_LSA_EXECUTE(oi);
211 }
212 }
213
5eb2c602
RW
214 /*
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.
218 */
219 for (route = ospf6_route_head(ospf6->external_table); route;
220 route = ospf6_route_next(route))
221 ospf6_handle_external_lsa_origination(ospf6, route,
222 &route->prefix);
223
71165098
RW
224 /*
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
228 * necessary.
229 *
230 * 4) Any remnant entries in the system forwarding table that were
231 * installed before the restart, but that are no longer valid,
232 * should be removed.
233 */
234 ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_GR_FINISH);
235
236 /* 6) Any grace-LSAs that the router originated should be flushed. */
237 ospf6_gr_flush_grace_lsas(ospf6);
238}
239
88b3d5e5
RW
240/* Enter the Graceful Restart mode. */
241void ospf6_gr_restart_enter(struct ospf6 *ospf6,
2882096f
RW
242 enum ospf6_gr_restart_reason reason,
243 time_t timestamp)
88b3d5e5
RW
244{
245 unsigned long remaining_time;
246
247 ospf6->gr_info.restart_in_progress = true;
248 ospf6->gr_info.reason = reason;
249
250 /* Schedule grace period timeout. */
251 remaining_time = timestamp - time(NULL);
252 if (IS_DEBUG_OSPF6_GR)
253 zlog_debug(
254 "GR: remaining time until grace period expires: %lu(s)",
255 remaining_time);
256
257 event_add_timer(master, ospf6_gr_grace_period_expired, ospf6,
258 remaining_time, &ospf6->gr_info.t_grace_period);
259}
260
71165098
RW
261#define RTR_LSA_MISSING 0
262#define RTR_LSA_ADJ_FOUND 1
263#define RTR_LSA_ADJ_NOT_FOUND 2
264
265/* Check if a Router-LSA exists and if it contains a given link. */
266static int ospf6_router_lsa_contains_adj(struct ospf6_area *area,
267 in_addr_t adv_router,
268 in_addr_t neighbor_router_id)
269{
270 uint16_t type;
271 struct ospf6_lsa *lsa;
272 bool empty = true;
273
274 type = ntohs(OSPF6_LSTYPE_ROUTER);
275 for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, adv_router, lsa)) {
276 struct ospf6_router_lsa *router_lsa;
277 char *start, *end, *current;
278
279 empty = false;
280 router_lsa = (struct ospf6_router_lsa
281 *)((char *)lsa->header
282 + sizeof(struct ospf6_lsa_header));
283
284 /* Iterate over all interfaces in the Router-LSA. */
285 start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
286 end = (char *)lsa->header + ntohs(lsa->header->length);
287 for (current = start;
288 current + sizeof(struct ospf6_router_lsdesc) <= end;
289 current += sizeof(struct ospf6_router_lsdesc)) {
290 struct ospf6_router_lsdesc *lsdesc;
291
292 lsdesc = (struct ospf6_router_lsdesc *)current;
293 if (lsdesc->type != OSPF6_ROUTER_LSDESC_POINTTOPOINT)
294 continue;
295
296 if (lsdesc->neighbor_router_id == neighbor_router_id)
297 return RTR_LSA_ADJ_FOUND;
298 }
299 }
300
301 if (empty)
302 return RTR_LSA_MISSING;
303
304 return RTR_LSA_ADJ_NOT_FOUND;
305}
306
307static bool ospf6_gr_check_router_lsa_consistency(struct ospf6 *ospf6,
308 struct ospf6_area *area,
309 struct ospf6_lsa *lsa)
310{
311 if (lsa->header->adv_router == ospf6->router_id) {
312 struct ospf6_router_lsa *router_lsa;
313 char *start, *end, *current;
314
315 router_lsa = (struct ospf6_router_lsa
316 *)((char *)lsa->header
317 + sizeof(struct ospf6_lsa_header));
318
319 /* Iterate over all interfaces in the Router-LSA. */
320 start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
321 end = (char *)lsa->header + ntohs(lsa->header->length);
322 for (current = start;
323 current + sizeof(struct ospf6_router_lsdesc) <= end;
324 current += sizeof(struct ospf6_router_lsdesc)) {
325 struct ospf6_router_lsdesc *lsdesc;
326
327 lsdesc = (struct ospf6_router_lsdesc *)current;
328 if (lsdesc->type != OSPF6_ROUTER_LSDESC_POINTTOPOINT)
329 continue;
330
331 if (ospf6_router_lsa_contains_adj(
332 area, lsdesc->neighbor_router_id,
333 ospf6->router_id)
334 == RTR_LSA_ADJ_NOT_FOUND)
335 return false;
336 }
337 } else {
338 int adj1, adj2;
339
340 adj1 = ospf6_router_lsa_contains_adj(area, ospf6->router_id,
341 lsa->header->adv_router);
342 adj2 = ospf6_router_lsa_contains_adj(
343 area, lsa->header->adv_router, ospf6->router_id);
344 if ((adj1 == RTR_LSA_ADJ_FOUND && adj2 == RTR_LSA_ADJ_NOT_FOUND)
345 || (adj1 == RTR_LSA_ADJ_NOT_FOUND
346 && adj2 == RTR_LSA_ADJ_FOUND))
347 return false;
348 }
349
350 return true;
351}
352
353/*
354 * Check for LSAs that are inconsistent with the pre-restart LSAs, and abort the
355 * ongoing graceful restart when that's the case.
356 */
357void ospf6_gr_check_lsdb_consistency(struct ospf6 *ospf6,
358 struct ospf6_area *area)
359{
360 uint16_t type;
361 struct ospf6_lsa *lsa;
362
363 type = ntohs(OSPF6_LSTYPE_ROUTER);
364 for (ALL_LSDB_TYPED(area->lsdb, type, lsa)) {
365 if (!ospf6_gr_check_router_lsa_consistency(ospf6, area, lsa)) {
366 char reason[256];
367
368 snprintfrr(reason, sizeof(reason),
369 "detected inconsistent LSA %s [area %pI4]",
370 lsa->name, &area->area_id);
371 ospf6_gr_restart_exit(ospf6, reason);
372 return;
373 }
374 }
375}
376
377/* Check if there's a fully formed adjacency with the given neighbor ID. */
378static bool ospf6_gr_check_adj_id(struct ospf6_area *area,
379 in_addr_t neighbor_router_id)
380{
381 struct ospf6_neighbor *nbr;
382
383 nbr = ospf6_area_neighbor_lookup(area, neighbor_router_id);
384 if (!nbr || nbr->state < OSPF6_NEIGHBOR_FULL) {
385 if (IS_DEBUG_OSPF6_GR)
386 zlog_debug("GR: missing adjacency to router %pI4",
387 &neighbor_router_id);
388 return false;
389 }
390
391 return true;
392}
393
394static bool ospf6_gr_check_adjs_lsa_transit(struct ospf6_area *area,
395 in_addr_t neighbor_router_id,
396 uint32_t neighbor_interface_id)
397{
398 struct ospf6 *ospf6 = area->ospf6;
399
400 /* Check if we are the DR. */
401 if (neighbor_router_id == ospf6->router_id) {
402 struct ospf6_lsa *lsa;
403 char *start, *end, *current;
404 struct ospf6_network_lsa *network_lsa;
405 struct ospf6_network_lsdesc *lsdesc;
406
407 /* Lookup Network LSA corresponding to this interface. */
408 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_NETWORK),
409 neighbor_interface_id,
410 neighbor_router_id, area->lsdb);
411 if (!lsa)
412 return false;
413
414 /* Iterate over all routers present in the network. */
415 network_lsa = (struct ospf6_network_lsa
416 *)((char *)lsa->header
417 + sizeof(struct ospf6_lsa_header));
418 start = (char *)network_lsa + sizeof(struct ospf6_network_lsa);
419 end = (char *)lsa->header + ntohs(lsa->header->length);
420 for (current = start;
421 current + sizeof(struct ospf6_network_lsdesc) <= end;
422 current += sizeof(struct ospf6_network_lsdesc)) {
423 lsdesc = (struct ospf6_network_lsdesc *)current;
424
425 /* Skip self in the pseudonode. */
426 if (lsdesc->router_id == ospf6->router_id)
427 continue;
428
429 /*
430 * Check if there's a fully formed adjacency with this
431 * router.
432 */
433 if (!ospf6_gr_check_adj_id(area, lsdesc->router_id))
434 return false;
435 }
436 } else {
437 struct ospf6_neighbor *nbr;
438
439 /* Check if there's a fully formed adjacency with the DR. */
440 nbr = ospf6_area_neighbor_lookup(area, neighbor_router_id);
441 if (!nbr || nbr->state < OSPF6_NEIGHBOR_FULL) {
442 if (IS_DEBUG_OSPF6_GR)
443 zlog_debug(
444 "GR: missing adjacency to DR router %pI4",
445 &neighbor_router_id);
446 return false;
447 }
448 }
449
450 return true;
451}
452
453static bool ospf6_gr_check_adjs_lsa(struct ospf6_area *area,
454 struct ospf6_lsa *lsa)
455{
456 struct ospf6_router_lsa *router_lsa;
457 char *start, *end, *current;
458
459 router_lsa =
460 (struct ospf6_router_lsa *)((char *)lsa->header
461 + sizeof(struct ospf6_lsa_header));
462
463 /* Iterate over all interfaces in the Router-LSA. */
464 start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
465 end = (char *)lsa->header + ntohs(lsa->header->length);
466 for (current = start;
467 current + sizeof(struct ospf6_router_lsdesc) <= end;
468 current += sizeof(struct ospf6_router_lsdesc)) {
469 struct ospf6_router_lsdesc *lsdesc;
470
471 lsdesc = (struct ospf6_router_lsdesc *)current;
472 switch (lsdesc->type) {
473 case OSPF6_ROUTER_LSDESC_POINTTOPOINT:
474 if (!ospf6_gr_check_adj_id(area,
475 lsdesc->neighbor_router_id))
476 return false;
477 break;
478 case OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK:
479 if (!ospf6_gr_check_adjs_lsa_transit(
480 area, lsdesc->neighbor_router_id,
481 lsdesc->neighbor_interface_id))
482 return false;
483 break;
484 default:
485 break;
486 }
487 }
488
489 return true;
490}
491
492/*
493 * Check if all adjacencies prior to the restart were reestablished.
494 *
495 * This is done using pre-restart Router LSAs and pre-restart Network LSAs
496 * received from the helping neighbors.
497 */
498static bool ospf6_gr_check_adjs(struct ospf6 *ospf6)
499{
500 struct ospf6_area *area;
501 struct listnode *node;
502
503 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, area)) {
504 uint16_t type;
505 uint32_t router;
506 struct ospf6_lsa *lsa_self;
507 bool found = false;
508
509 type = ntohs(OSPF6_LSTYPE_ROUTER);
510 router = ospf6->router_id;
511 for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, router,
512 lsa_self)) {
513 found = true;
514 if (!ospf6_gr_check_adjs_lsa(area, lsa_self))
515 return false;
516 }
517 if (!found)
518 return false;
519 }
520
521 return true;
522}
523
524/* Handling of grace period expiry. */
e6685141 525static void ospf6_gr_grace_period_expired(struct event *thread)
71165098 526{
e16d030c 527 struct ospf6 *ospf6 = EVENT_ARG(thread);
71165098 528
71165098 529 ospf6_gr_restart_exit(ospf6, "grace period has expired");
71165098
RW
530}
531
0c05ceae
RW
532/* Send extra Grace-LSA out the interface (unplanned outages only). */
533void ospf6_gr_iface_send_grace_lsa(struct event *thread)
534{
535 struct ospf6_interface *oi = EVENT_ARG(thread);
536
537 ospf6_gr_lsa_originate(oi, oi->area->ospf6->gr_info.reason);
538
539 if (++oi->gr.hello_delay.elapsed_seconds < oi->gr.hello_delay.interval)
540 event_add_timer(master, ospf6_gr_iface_send_grace_lsa, oi, 1,
541 &oi->gr.hello_delay.t_grace_send);
542 else
543 event_add_event(master, ospf6_hello_send, oi, 0,
544 &oi->thread_send_hello);
545}
546
71165098
RW
547/*
548 * Record in non-volatile memory that the given OSPF instance is attempting to
549 * perform a graceful restart.
550 */
88b3d5e5 551static void ospf6_gr_nvm_update(struct ospf6 *ospf6, bool prepare)
71165098
RW
552{
553 const char *inst_name;
554 json_object *json;
555 json_object *json_instances;
556 json_object *json_instance;
557
558 inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
559
b275f44a 560 json = json_object_from_file((char *)OSPF6D_GR_STATE);
71165098
RW
561 if (json == NULL)
562 json = json_object_new_object();
563
564 json_object_object_get_ex(json, "instances", &json_instances);
565 if (!json_instances) {
566 json_instances = json_object_new_object();
567 json_object_object_add(json, "instances", json_instances);
568 }
569
570 json_object_object_get_ex(json_instances, inst_name, &json_instance);
571 if (!json_instance) {
572 json_instance = json_object_new_object();
573 json_object_object_add(json_instances, inst_name,
574 json_instance);
575 }
576
88b3d5e5
RW
577 json_object_int_add(json_instance, "gracePeriod",
578 ospf6->gr_info.grace_period);
579
71165098
RW
580 /*
581 * Record not only the grace period, but also a UNIX timestamp
582 * corresponding to the end of that period. That way, once ospf6d is
583 * restarted, it will be possible to take into account the time that
584 * passed while ospf6d wasn't running.
585 */
88b3d5e5
RW
586 if (prepare)
587 json_object_int_add(json_instance, "timestamp",
588 time(NULL) + ospf6->gr_info.grace_period);
71165098 589
b275f44a
RW
590 json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
591 JSON_C_TO_STRING_PRETTY);
71165098
RW
592 json_object_free(json);
593}
594
595/*
596 * Delete GR status information about the given OSPF instance from non-volatile
597 * memory.
598 */
88b3d5e5 599void ospf6_gr_nvm_delete(struct ospf6 *ospf6)
71165098
RW
600{
601 const char *inst_name;
602 json_object *json;
603 json_object *json_instances;
604
605 inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
606
b275f44a 607 json = json_object_from_file((char *)OSPF6D_GR_STATE);
71165098
RW
608 if (json == NULL)
609 json = json_object_new_object();
610
611 json_object_object_get_ex(json, "instances", &json_instances);
612 if (!json_instances) {
613 json_instances = json_object_new_object();
614 json_object_object_add(json, "instances", json_instances);
615 }
616
617 json_object_object_del(json_instances, inst_name);
618
b275f44a
RW
619 json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
620 JSON_C_TO_STRING_PRETTY);
71165098
RW
621 json_object_free(json);
622}
623
624/*
625 * Fetch from non-volatile memory whether the given OSPF instance is performing
626 * a graceful shutdown or not.
627 */
628void ospf6_gr_nvm_read(struct ospf6 *ospf6)
629{
630 const char *inst_name;
631 json_object *json;
632 json_object *json_instances;
633 json_object *json_instance;
634 json_object *json_timestamp;
88b3d5e5 635 json_object *json_grace_period;
71165098
RW
636 time_t timestamp = 0;
637
638 inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
639
b275f44a 640 json = json_object_from_file((char *)OSPF6D_GR_STATE);
71165098
RW
641 if (json == NULL)
642 json = json_object_new_object();
643
644 json_object_object_get_ex(json, "instances", &json_instances);
645 if (!json_instances) {
646 json_instances = json_object_new_object();
647 json_object_object_add(json, "instances", json_instances);
648 }
649
650 json_object_object_get_ex(json_instances, inst_name, &json_instance);
651 if (!json_instance) {
652 json_instance = json_object_new_object();
653 json_object_object_add(json_instances, inst_name,
654 json_instance);
655 }
656
88b3d5e5
RW
657 json_object_object_get_ex(json_instance, "gracePeriod",
658 &json_grace_period);
71165098
RW
659 json_object_object_get_ex(json_instance, "timestamp", &json_timestamp);
660 if (json_timestamp) {
661 time_t now;
71165098 662
88b3d5e5 663 /* Planned GR: check if the grace period has already expired. */
71165098
RW
664 now = time(NULL);
665 timestamp = json_object_get_int(json_timestamp);
666 if (now > timestamp) {
667 ospf6_gr_restart_exit(
668 ospf6, "grace period has expired already");
88b3d5e5
RW
669 } else
670 ospf6_gr_restart_enter(ospf6, OSPF6_GR_SW_RESTART,
671 timestamp);
672 } else if (json_grace_period) {
673 uint32_t grace_period;
674
675 /*
676 * Unplanned GR: the Grace-LSAs will be sent later as soon as
677 * the interfaces are operational.
678 */
679 grace_period = json_object_get_int(json_grace_period);
680 ospf6->gr_info.grace_period = grace_period;
681 ospf6_gr_restart_enter(ospf6, OSPF6_GR_UNKNOWN_RESTART,
682 time(NULL) +
683 ospf6->gr_info.grace_period);
71165098
RW
684 }
685
686 json_object_object_del(json_instances, inst_name);
687
b275f44a
RW
688 json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
689 JSON_C_TO_STRING_PRETTY);
71165098
RW
690 json_object_free(json);
691}
692
88b3d5e5
RW
693void ospf6_gr_unplanned_start_interface(struct ospf6_interface *oi)
694{
695 /*
696 * Can't check OSPF interface state as the OSPF instance might not be
697 * enabled yet.
698 */
699 if (!if_is_operative(oi->interface) || if_is_loopback(oi->interface))
700 return;
701
702 /* Send Grace-LSA. */
703 ospf6_gr_lsa_originate(oi, oi->area->ospf6->gr_info.reason);
0c05ceae
RW
704
705 /* Start GR hello-delay interval. */
706 oi->gr.hello_delay.elapsed_seconds = 0;
707 event_add_timer(master, ospf6_gr_iface_send_grace_lsa, oi, 1,
708 &oi->gr.hello_delay.t_grace_send);
88b3d5e5
RW
709}
710
71165098
RW
711/* Prepare to start a Graceful Restart. */
712static void ospf6_gr_prepare(void)
713{
714 struct ospf6 *ospf6;
715 struct ospf6_interface *oi;
716 struct listnode *onode, *anode, *inode;
717
718 for (ALL_LIST_ELEMENTS_RO(om6->ospf6, onode, ospf6)) {
719 struct ospf6_area *area;
720
721 if (!ospf6->gr_info.restart_support
722 || ospf6->gr_info.prepare_in_progress)
723 continue;
724
725 if (IS_DEBUG_OSPF6_GR)
726 zlog_debug(
727 "GR: preparing to perform a graceful restart [period %u second(s)] [vrf %s]",
728 ospf6->gr_info.grace_period,
729 ospf6_vrf_id_to_name(ospf6->vrf_id));
730
71165098
RW
731 /* Send a Grace-LSA to all neighbors. */
732 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, anode, area)) {
733 for (ALL_LIST_ELEMENTS_RO(area->if_list, inode, oi)) {
734 if (oi->state < OSPF6_INTERFACE_POINTTOPOINT)
735 continue;
88b3d5e5 736 ospf6_gr_lsa_originate(oi, OSPF6_GR_SW_RESTART);
71165098
RW
737 }
738 }
739
740 /* Record end of the grace period in non-volatile memory. */
88b3d5e5 741 ospf6_gr_nvm_update(ospf6, true);
71165098
RW
742
743 /*
744 * Mark that a Graceful Restart preparation is in progress, to
745 * prevent ospf6d from flushing its self-originated LSAs on
746 * exit.
747 */
748 ospf6->gr_info.prepare_in_progress = true;
749 }
750}
751
752static int ospf6_gr_neighbor_change(struct ospf6_neighbor *on, int next_state,
753 int prev_state)
754{
755 struct ospf6 *ospf6 = on->ospf6_if->area->ospf6;
756
757 if (next_state == OSPF6_NEIGHBOR_FULL
758 && ospf6->gr_info.restart_in_progress) {
759 if (ospf6_gr_check_adjs(ospf6)) {
760 ospf6_gr_restart_exit(
761 ospf6, "all adjacencies were reestablished");
762 } else {
763 if (IS_DEBUG_OSPF6_GR)
764 zlog_debug(
765 "GR: not all adjacencies were reestablished yet");
766 }
767 }
768
769 return 0;
770}
771
772int config_write_ospf6_gr(struct vty *vty, struct ospf6 *ospf6)
773{
774 if (!ospf6->gr_info.restart_support)
775 return 0;
776
777 if (ospf6->gr_info.grace_period == OSPF6_DFLT_GRACE_INTERVAL)
778 vty_out(vty, " graceful-restart\n");
779 else
780 vty_out(vty, " graceful-restart grace-period %u\n",
781 ospf6->gr_info.grace_period);
782
783 return 0;
784}
785
786DEFPY(ospf6_graceful_restart_prepare, ospf6_graceful_restart_prepare_cmd,
787 "graceful-restart prepare ipv6 ospf",
788 "Graceful Restart commands\n"
789 "Prepare upcoming graceful restart\n" IPV6_STR
4a3c92de 790 "Prepare to restart the OSPFv3 process\n")
71165098
RW
791{
792 ospf6_gr_prepare();
793
794 return CMD_SUCCESS;
795}
796
797DEFPY(ospf6_graceful_restart, ospf6_graceful_restart_cmd,
798 "graceful-restart [grace-period (1-1800)$grace_period]",
799 OSPF_GR_STR
800 "Maximum length of the 'grace period'\n"
801 "Maximum length of the 'grace period' in seconds\n")
802{
803 VTY_DECLVAR_INSTANCE_CONTEXT(ospf6, ospf6);
804
805 /* Check and get restart period if present. */
806 if (!grace_period_str)
807 grace_period = OSPF6_DFLT_GRACE_INTERVAL;
808
809 ospf6->gr_info.restart_support = true;
810 ospf6->gr_info.grace_period = grace_period;
811
88b3d5e5
RW
812 /* Freeze OSPF routes in the RIB. */
813 (void)ospf6_zebra_gr_enable(ospf6, ospf6->gr_info.grace_period);
814
815 /* Record that GR is enabled in non-volatile memory. */
816 ospf6_gr_nvm_update(ospf6, false);
817
71165098
RW
818 return CMD_SUCCESS;
819}
820
821DEFPY(ospf6_no_graceful_restart, ospf6_no_graceful_restart_cmd,
822 "no graceful-restart [period (1-1800)]",
823 NO_STR OSPF_GR_STR
824 "Maximum length of the 'grace period'\n"
825 "Maximum length of the 'grace period' in seconds\n")
826{
827 VTY_DECLVAR_INSTANCE_CONTEXT(ospf6, ospf6);
828
829 if (!ospf6->gr_info.restart_support)
830 return CMD_SUCCESS;
831
832 if (ospf6->gr_info.prepare_in_progress) {
833 vty_out(vty,
834 "%% Error: Graceful Restart preparation in progress\n");
835 return CMD_WARNING;
836 }
837
838 ospf6->gr_info.restart_support = false;
839 ospf6->gr_info.grace_period = OSPF6_DFLT_GRACE_INTERVAL;
88b3d5e5
RW
840 ospf6_gr_nvm_delete(ospf6);
841 ospf6_zebra_gr_disable(ospf6);
71165098
RW
842
843 return CMD_SUCCESS;
844}
845
846void ospf6_gr_init(void)
847{
848 hook_register(ospf6_neighbor_change, ospf6_gr_neighbor_change);
849
850 install_element(ENABLE_NODE, &ospf6_graceful_restart_prepare_cmd);
851 install_element(OSPF6_NODE, &ospf6_graceful_restart_cmd);
852 install_element(OSPF6_NODE, &ospf6_no_graceful_restart_cmd);
853}