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