]> git.proxmox.com Git - mirror_frr.git/blob - ospfd/ospf_gr.c
ospfd: use ospf_get_name() wherever possible
[mirror_frr.git] / ospfd / ospf_gr.c
1 /*
2 * This is an implementation of RFC 3623 Graceful OSPF Restart.
3 *
4 * Copyright 2021 NetDEF (c), All rights reserved.
5 * Copyright 2020 6WIND (c), All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include <zebra.h>
23
24 #include "memory.h"
25 #include "command.h"
26 #include "table.h"
27 #include "vty.h"
28 #include "log.h"
29 #include "printfrr.h"
30
31 #include "ospfd/ospfd.h"
32 #include "ospfd/ospf_abr.h"
33 #include "ospfd/ospf_flood.h"
34 #include "ospfd/ospf_ism.h"
35 #include "ospfd/ospf_interface.h"
36 #include "ospfd/ospf_asbr.h"
37 #include "ospfd/ospf_lsa.h"
38 #include "ospfd/ospf_route.h"
39 #include "ospfd/ospf_zebra.h"
40 #include "ospfd/ospf_lsdb.h"
41 #include "ospfd/ospf_neighbor.h"
42 #include "ospfd/ospf_opaque.h"
43 #include "ospfd/ospf_nsm.h"
44 #include "ospfd/ospf_gr.h"
45 #include "ospfd/ospf_errors.h"
46 #include "ospfd/ospf_dump.h"
47 #ifndef VTYSH_EXTRACT_PL
48 #include "ospfd/ospf_gr_clippy.c"
49 #endif
50
51 static void ospf_gr_nvm_delete(struct ospf *ospf);
52
53 /* Lookup self-originated Grace-LSA in the LSDB. */
54 static struct ospf_lsa *ospf_gr_lsa_lookup(struct ospf *ospf,
55 struct ospf_area *area)
56 {
57 struct ospf_lsa *lsa;
58 struct in_addr lsa_id;
59 uint32_t lsa_id_host_byte_order;
60
61 lsa_id_host_byte_order = SET_OPAQUE_LSID(OPAQUE_TYPE_GRACE_LSA, 0);
62 lsa_id.s_addr = htonl(lsa_id_host_byte_order);
63 lsa = ospf_lsa_lookup(ospf, area, OSPF_OPAQUE_LINK_LSA, lsa_id,
64 ospf->router_id);
65
66 return lsa;
67 }
68
69 /* Fill in fields of the Grace-LSA that is being originated. */
70 static void ospf_gr_lsa_body_set(struct ospf_gr_info *gr_info,
71 struct ospf_interface *oi, struct stream *s)
72 {
73 struct grace_tlv_graceperiod tlv_period = {};
74 struct grace_tlv_restart_reason tlv_reason = {};
75 struct grace_tlv_restart_addr tlv_address = {};
76
77 /* Put grace period. */
78 tlv_period.header.type = htons(GRACE_PERIOD_TYPE);
79 tlv_period.header.length = htons(GRACE_PERIOD_LENGTH);
80 tlv_period.interval = htonl(gr_info->grace_period);
81 stream_put(s, &tlv_period, sizeof(tlv_period));
82
83 /* Put restart reason. */
84 tlv_reason.header.type = htons(RESTART_REASON_TYPE);
85 tlv_reason.header.length = htons(RESTART_REASON_LENGTH);
86 if (gr_info->restart_support)
87 tlv_reason.reason = OSPF_GR_SW_RESTART;
88 else
89 tlv_reason.reason = OSPF_GR_UNKNOWN_RESTART;
90 stream_put(s, &tlv_reason, sizeof(tlv_reason));
91
92 /* Put IP address. */
93 if (oi->type == OSPF_IFTYPE_BROADCAST || oi->type == OSPF_IFTYPE_NBMA
94 || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) {
95 tlv_address.header.type = htons(RESTARTER_IP_ADDR_TYPE);
96 tlv_address.header.length = htons(RESTARTER_IP_ADDR_LEN);
97 tlv_address.addr = oi->address->u.prefix4;
98 stream_put(s, &tlv_address, sizeof(tlv_address));
99 }
100 }
101
102 /* Generate Grace-LSA for a given interface. */
103 static struct ospf_lsa *ospf_gr_lsa_new(struct ospf_interface *oi)
104 {
105 struct stream *s;
106 struct lsa_header *lsah;
107 struct ospf_lsa *new;
108 uint8_t options, lsa_type;
109 struct in_addr lsa_id;
110 uint32_t lsa_id_host_byte_order;
111 uint16_t length;
112
113 /* Create a stream for LSA. */
114 s = stream_new(OSPF_MAX_LSA_SIZE);
115
116 lsah = (struct lsa_header *)STREAM_DATA(s);
117
118 options = LSA_OPTIONS_GET(oi->area);
119 options |= LSA_OPTIONS_NSSA_GET(oi->area);
120 options |= OSPF_OPTION_O;
121
122 lsa_type = OSPF_OPAQUE_LINK_LSA;
123 lsa_id_host_byte_order = SET_OPAQUE_LSID(OPAQUE_TYPE_GRACE_LSA, 0);
124 lsa_id.s_addr = htonl(lsa_id_host_byte_order);
125
126 /* Set opaque-LSA header fields. */
127 lsa_header_set(s, options, lsa_type, lsa_id, oi->ospf->router_id);
128
129 /* Set opaque-LSA body fields. */
130 ospf_gr_lsa_body_set(&oi->ospf->gr_info, oi, s);
131
132 /* Set length. */
133 length = stream_get_endp(s);
134 lsah->length = htons(length);
135
136 /* Now, create an OSPF LSA instance. */
137 new = ospf_lsa_new_and_data(length);
138
139 if (IS_DEBUG_OSPF_GR)
140 zlog_debug("LSA[Type%d:%pI4]: Create an Opaque-LSA/GR instance",
141 lsa_type, &lsa_id);
142
143 new->area = oi->area;
144 new->oi = oi;
145 SET_FLAG(new->flags, OSPF_LSA_SELF);
146 memcpy(new->data, lsah, length);
147 stream_free(s);
148
149 return new;
150 }
151
152 /* Originate and install Grace-LSA for a given interface. */
153 static void ospf_gr_lsa_originate(struct ospf_interface *oi)
154 {
155 struct ospf_lsa *lsa, *old;
156
157 if (ospf_interface_neighbor_count(oi) == 0)
158 return;
159
160 /* Create new Grace-LSA. */
161 lsa = ospf_gr_lsa_new(oi);
162 if (!lsa) {
163 zlog_warn("%s: ospf_gr_lsa_new() failed", __func__);
164 return;
165 }
166
167 /* Find the old LSA and increase the seqno. */
168 old = ospf_gr_lsa_lookup(oi->ospf, oi->area);
169 if (old)
170 lsa->data->ls_seqnum = lsa_seqnum_increment(old);
171
172 /* Install this LSA into LSDB. */
173 if (ospf_lsa_install(oi->ospf, oi, lsa) == NULL) {
174 zlog_warn("%s: ospf_lsa_install() failed", __func__);
175 ospf_lsa_unlock(&lsa);
176 return;
177 }
178
179 /* Update new LSA origination count. */
180 oi->ospf->lsa_originate_count++;
181
182 /* Flood the LSA through out the interface */
183 ospf_flood_through_interface(oi, NULL, lsa);
184 }
185
186 /* Flush a given self-originated Grace-LSA. */
187 static struct ospf_lsa *ospf_gr_flush_grace_lsa(struct ospf_interface *oi,
188 struct ospf_lsa *old)
189 {
190 struct ospf_lsa *lsa;
191
192 if (ospf_interface_neighbor_count(oi) == 0)
193 return NULL;
194
195 if (IS_DEBUG_OSPF_GR)
196 zlog_debug(
197 "GR: flushing self-originated Grace-LSAs [interface %s]",
198 oi->ifp->name);
199
200 lsa = ospf_lsa_dup(old);
201 lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
202 lsa->data->ls_seqnum = lsa_seqnum_increment(lsa);
203
204 /* Install updated LSA into LSDB. */
205 if (ospf_lsa_install(oi->ospf, oi, lsa) == NULL) {
206 zlog_warn("%s: ospf_lsa_install() failed", __func__);
207 ospf_lsa_unlock(&lsa);
208 return NULL;
209 }
210
211 /* Flood the LSA through out the interface */
212 ospf_flood_through_interface(oi, NULL, lsa);
213
214 return lsa;
215 }
216
217 /* Flush all self-originated Grace-LSAs. */
218 static void ospf_gr_flush_grace_lsas(struct ospf *ospf)
219 {
220 struct ospf_area *area;
221 struct listnode *anode;
222
223 for (ALL_LIST_ELEMENTS_RO(ospf->areas, anode, area)) {
224 struct ospf_lsa *lsa;
225 struct ospf_interface *oi;
226 struct listnode *inode;
227
228 if (IS_DEBUG_OSPF_GR)
229 zlog_debug(
230 "GR: flushing self-originated Grace-LSAs [area %pI4]",
231 &area->area_id);
232
233 lsa = ospf_gr_lsa_lookup(ospf, area);
234 if (!lsa) {
235 zlog_warn("%s: Grace-LSA not found [area %pI4]",
236 __func__, &area->area_id);
237 continue;
238 }
239
240 for (ALL_LIST_ELEMENTS_RO(area->oiflist, inode, oi))
241 ospf_gr_flush_grace_lsa(oi, lsa);
242 }
243 }
244
245 /* Exit from the Graceful Restart mode. */
246 static void ospf_gr_restart_exit(struct ospf *ospf, const char *reason)
247 {
248 struct ospf_area *area;
249 struct listnode *onode, *anode;
250
251 if (IS_DEBUG_OSPF_GR)
252 zlog_debug("GR: exiting graceful restart: %s", reason);
253
254 ospf->gr_info.restart_in_progress = false;
255 OSPF_TIMER_OFF(ospf->gr_info.t_grace_period);
256
257 /* Record in non-volatile memory that the restart is complete. */
258 ospf_gr_nvm_delete(ospf);
259
260 for (ALL_LIST_ELEMENTS_RO(ospf->areas, onode, area)) {
261 struct ospf_interface *oi;
262
263 /*
264 * 1) The router should reoriginate its router-LSAs for all
265 * attached areas in order to make sure they have the correct
266 * contents.
267 */
268 ospf_router_lsa_update_area(area);
269
270 /*
271 * 2) The router should reoriginate network-LSAs on all segments
272 * where it is the Designated Router.
273 */
274 for (ALL_LIST_ELEMENTS_RO(area->oiflist, anode, oi))
275 if (oi->state == ISM_DR)
276 ospf_network_lsa_update(oi);
277 }
278
279 /*
280 * 5) Any received self-originated LSAs that are no longer valid should
281 * be flushed.
282 */
283 ospf_schedule_abr_task(ospf);
284
285 /*
286 * 3) The router reruns its OSPF routing calculations, this time
287 * installing the results into the system forwarding table, and
288 * originating summary-LSAs, Type-7 LSAs and AS-external-LSAs as
289 * necessary.
290 *
291 * 4) Any remnant entries in the system forwarding table that were
292 * installed before the restart, but that are no longer valid,
293 * should be removed.
294 */
295 ospf->gr_info.finishing_restart = true;
296 ospf_spf_calculate_schedule(ospf, SPF_FLAG_GR_FINISH);
297
298 /* 6) Any grace-LSAs that the router originated should be flushed. */
299 ospf_gr_flush_grace_lsas(ospf);
300 }
301
302 /* Check if a Router-LSA contains a given link. */
303 static bool ospf_router_lsa_contains_adj(struct ospf_lsa *lsa,
304 struct in_addr *id)
305 {
306 struct router_lsa *rl;
307
308 rl = (struct router_lsa *)lsa->data;
309 for (int i = 0; i < ntohs(rl->links); i++) {
310 struct in_addr *link_id = &rl->link[i].link_id;
311
312 if (rl->link[i].type != LSA_LINK_TYPE_POINTOPOINT)
313 continue;
314
315 if (IPV4_ADDR_SAME(id, link_id))
316 return true;
317 }
318
319 return false;
320 }
321
322 static bool ospf_gr_check_router_lsa_consistency(struct ospf *ospf,
323 struct ospf_area *area,
324 struct ospf_lsa *lsa)
325 {
326 if (CHECK_FLAG(lsa->flags, OSPF_LSA_SELF)) {
327 struct ospf_lsa *lsa_self = lsa;
328 struct router_lsa *rl = (struct router_lsa *)lsa->data;
329
330 for (int i = 0; i < ntohs(rl->links); i++) {
331 struct in_addr *link_id = &rl->link[i].link_id;
332 struct ospf_lsa *lsa_adj;
333
334 if (rl->link[i].type != LSA_LINK_TYPE_POINTOPOINT)
335 continue;
336
337 lsa_adj = ospf_lsa_lookup_by_id(area, OSPF_ROUTER_LSA,
338 *link_id);
339 if (!lsa_adj)
340 continue;
341
342 if (!ospf_router_lsa_contains_adj(lsa_adj,
343 &lsa_self->data->id))
344 return false;
345 }
346 } else {
347 struct ospf_lsa *lsa_self;
348
349 lsa_self = ospf_lsa_lookup_by_id(area, OSPF_ROUTER_LSA,
350 ospf->router_id);
351 if (!lsa_self
352 || !CHECK_FLAG(lsa_self->flags, OSPF_LSA_RECEIVED))
353 return true;
354
355 if (ospf_router_lsa_contains_adj(lsa, &ospf->router_id)
356 != ospf_router_lsa_contains_adj(lsa_self, &lsa->data->id))
357 return false;
358 }
359
360 return true;
361 }
362
363 /*
364 * Check for LSAs that are inconsistent with the pre-restart LSAs, and abort the
365 * ongoing graceful restart when that's the case.
366 */
367 void ospf_gr_check_lsdb_consistency(struct ospf *ospf, struct ospf_area *area)
368 {
369 struct route_node *rn;
370 struct ospf_lsa *lsa;
371
372 for (rn = route_top(ROUTER_LSDB(area)); rn; rn = route_next(rn)) {
373 lsa = rn->info;
374 if (!lsa)
375 continue;
376
377 if (!ospf_gr_check_router_lsa_consistency(ospf, area, lsa)) {
378 char reason[256];
379
380 snprintfrr(reason, sizeof(reason),
381 "detected inconsistent LSA[%s] [area %pI4]",
382 dump_lsa_key(lsa), &area->area_id);
383 ospf_gr_restart_exit(ospf, reason);
384 route_unlock_node(rn);
385 return;
386 }
387 }
388 }
389
390 /* Lookup neighbor by address in a given OSPF area. */
391 static struct ospf_neighbor *
392 ospf_area_nbr_lookup_by_addr(struct ospf_area *area, struct in_addr *addr)
393 {
394 struct ospf_interface *oi;
395 struct ospf_neighbor *nbr;
396 struct listnode *node;
397
398 for (ALL_LIST_ELEMENTS_RO(area->oiflist, node, oi)) {
399 nbr = ospf_nbr_lookup_by_addr(oi->nbrs, addr);
400 if (nbr)
401 return nbr;
402 }
403
404 return NULL;
405 }
406
407 /* Lookup neighbor by Router ID in a given OSPF area. */
408 static struct ospf_neighbor *
409 ospf_area_nbr_lookup_by_routerid(struct ospf_area *area, struct in_addr *id)
410 {
411 struct ospf_interface *oi;
412 struct ospf_neighbor *nbr;
413 struct listnode *node;
414
415 for (ALL_LIST_ELEMENTS_RO(area->oiflist, node, oi)) {
416 nbr = ospf_nbr_lookup_by_routerid(oi->nbrs, id);
417 if (nbr)
418 return nbr;
419 }
420
421 return NULL;
422 }
423
424 /* Check if there's a fully formed adjacency with the given neighbor ID. */
425 static bool ospf_gr_check_adj_id(struct ospf_area *area,
426 struct in_addr *nbr_id)
427 {
428 struct ospf_neighbor *nbr;
429
430 nbr = ospf_area_nbr_lookup_by_routerid(area, nbr_id);
431 if (!nbr || nbr->state < NSM_Full) {
432 if (IS_DEBUG_OSPF_GR)
433 zlog_debug("GR: missing adjacency to router %pI4",
434 nbr_id);
435 return false;
436 }
437
438 return true;
439 }
440
441 static bool ospf_gr_check_adjs_lsa_transit(struct ospf_area *area,
442 struct in_addr *link_id)
443 {
444 struct ospf *ospf = area->ospf;
445 struct ospf_interface *oi;
446
447 /*
448 * Check if the transit network refers to a local interface (in which
449 * case it must be a DR for that network).
450 */
451 oi = ospf_if_lookup_by_local_addr(ospf, NULL, *link_id);
452 if (oi) {
453 struct ospf_lsa *lsa;
454 struct network_lsa *nlsa;
455 size_t cnt;
456
457 /* Lookup Network LSA corresponding to this interface. */
458 lsa = ospf_lsa_lookup_by_id(area, OSPF_NETWORK_LSA, *link_id);
459 if (!lsa)
460 return false;
461
462 /* Iterate over all routers present in the network. */
463 nlsa = (struct network_lsa *)lsa->data;
464 cnt = (lsa->size - (OSPF_LSA_HEADER_SIZE + 4)) / 4;
465 for (size_t i = 0; i < cnt; i++) {
466 struct in_addr *nbr_id = &nlsa->routers[i];
467
468 /* Skip self in the pseudonode. */
469 if (IPV4_ADDR_SAME(nbr_id, &ospf->router_id))
470 continue;
471
472 /*
473 * Check if there's a fully formed adjacency with this
474 * router.
475 */
476 if (!ospf_gr_check_adj_id(area, nbr_id))
477 return false;
478 }
479 } else {
480 struct ospf_neighbor *nbr;
481
482 /* Check if there's a fully formed adjacency with the DR. */
483 nbr = ospf_area_nbr_lookup_by_addr(area, link_id);
484 if (!nbr || nbr->state < NSM_Full) {
485 if (IS_DEBUG_OSPF_GR)
486 zlog_debug(
487 "GR: missing adjacency to DR router %pI4",
488 link_id);
489 return false;
490 }
491 }
492
493 return true;
494 }
495
496 static bool ospf_gr_check_adjs_lsa(struct ospf_area *area, struct ospf_lsa *lsa)
497 {
498 struct router_lsa *rl = (struct router_lsa *)lsa->data;
499
500 for (int i = 0; i < ntohs(rl->links); i++) {
501 struct in_addr *link_id = &rl->link[i].link_id;
502
503 switch (rl->link[i].type) {
504 case LSA_LINK_TYPE_POINTOPOINT:
505 if (!ospf_gr_check_adj_id(area, link_id))
506 return false;
507 break;
508 case LSA_LINK_TYPE_TRANSIT:
509 if (!ospf_gr_check_adjs_lsa_transit(area, link_id))
510 return false;
511 break;
512 default:
513 break;
514 }
515 }
516
517 return true;
518 }
519
520 /*
521 * Check if all adjacencies prior to the restart were reestablished.
522 *
523 * This is done using pre-restart Router LSAs and pre-restart Network LSAs
524 * received from the helping neighbors.
525 */
526 void ospf_gr_check_adjs(struct ospf *ospf)
527 {
528 struct ospf_area *area;
529 struct listnode *node;
530
531 for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) {
532 struct ospf_lsa *lsa_self;
533
534 lsa_self = ospf_lsa_lookup_by_id(area, OSPF_ROUTER_LSA,
535 ospf->router_id);
536 if (!lsa_self || !ospf_gr_check_adjs_lsa(area, lsa_self)) {
537 if (IS_DEBUG_OSPF_GR)
538 zlog_debug(
539 "GR: not all adjacencies were reestablished yet [area %pI4]",
540 &area->area_id);
541 return;
542 }
543 }
544
545 ospf_gr_restart_exit(ospf, "all adjacencies were reestablished");
546 }
547
548 /* Handling of grace period expiry. */
549 static int ospf_gr_grace_period_expired(struct thread *thread)
550 {
551 struct ospf *ospf = THREAD_ARG(thread);
552
553 ospf->gr_info.t_grace_period = NULL;
554 ospf_gr_restart_exit(ospf, "grace period has expired");
555
556 return 0;
557 }
558
559 /*
560 * Returns the path of the file (non-volatile memory) that contains GR status
561 * information.
562 */
563 static char *ospf_gr_nvm_filepath(struct ospf *ospf)
564 {
565 static char filepath[MAXPATHLEN];
566 char instance[16] = "";
567
568 if (ospf->instance)
569 snprintf(instance, sizeof(instance), "-%d", ospf->instance);
570 snprintf(filepath, sizeof(filepath), OSPFD_GR_STATE, instance);
571 return filepath;
572 }
573
574 /*
575 * Record in non-volatile memory that the given OSPF instance is attempting to
576 * perform a graceful restart.
577 */
578 static void ospf_gr_nvm_update(struct ospf *ospf)
579 {
580 char *filepath;
581 const char *inst_name;
582 json_object *json;
583 json_object *json_instances;
584 json_object *json_instance;
585
586 filepath = ospf_gr_nvm_filepath(ospf);
587 inst_name = ospf_get_name(ospf);
588
589 json = json_object_from_file(filepath);
590 if (json == NULL)
591 json = json_object_new_object();
592
593 json_object_object_get_ex(json, "instances", &json_instances);
594 if (!json_instances) {
595 json_instances = json_object_new_object();
596 json_object_object_add(json, "instances", json_instances);
597 }
598
599 json_object_object_get_ex(json_instances, inst_name, &json_instance);
600 if (!json_instance) {
601 json_instance = json_object_new_object();
602 json_object_object_add(json_instances, inst_name,
603 json_instance);
604 }
605
606 /*
607 * Record not only the grace period, but also a UNIX timestamp
608 * corresponding to the end of that period. That way, once ospfd is
609 * restarted, it will be possible to take into account the time that
610 * passed while ospfd wasn't running.
611 */
612 json_object_int_add(json_instance, "gracePeriod",
613 ospf->gr_info.grace_period);
614 json_object_int_add(json_instance, "timestamp",
615 time(NULL) + ospf->gr_info.grace_period);
616
617 json_object_to_file_ext(filepath, json, JSON_C_TO_STRING_PRETTY);
618 json_object_free(json);
619 }
620
621 /*
622 * Delete GR status information about the given OSPF instance from non-volatile
623 * memory.
624 */
625 static void ospf_gr_nvm_delete(struct ospf *ospf)
626 {
627 char *filepath;
628 const char *inst_name;
629 json_object *json;
630 json_object *json_instances;
631
632 filepath = ospf_gr_nvm_filepath(ospf);
633 inst_name = ospf_get_name(ospf);
634
635 json = json_object_from_file(filepath);
636 if (json == NULL)
637 json = json_object_new_object();
638
639 json_object_object_get_ex(json, "instances", &json_instances);
640 if (!json_instances) {
641 json_instances = json_object_new_object();
642 json_object_object_add(json, "instances", json_instances);
643 }
644
645 json_object_object_del(json_instances, inst_name);
646
647 json_object_to_file_ext(filepath, json, JSON_C_TO_STRING_PRETTY);
648 json_object_free(json);
649 }
650
651 /*
652 * Fetch from non-volatile memory whether the given OSPF instance is performing
653 * a graceful shutdown or not.
654 */
655 void ospf_gr_nvm_read(struct ospf *ospf)
656 {
657 char *filepath;
658 const char *inst_name;
659 json_object *json;
660 json_object *json_instances;
661 json_object *json_instance;
662 json_object *json_timestamp;
663 time_t timestamp = 0;
664
665 filepath = ospf_gr_nvm_filepath(ospf);
666 inst_name = ospf_get_name(ospf);
667
668 json = json_object_from_file(filepath);
669 if (json == NULL)
670 json = json_object_new_object();
671
672 json_object_object_get_ex(json, "instances", &json_instances);
673 if (!json_instances) {
674 json_instances = json_object_new_object();
675 json_object_object_add(json, "instances", json_instances);
676 }
677
678 json_object_object_get_ex(json_instances, inst_name, &json_instance);
679 if (!json_instance) {
680 json_instance = json_object_new_object();
681 json_object_object_add(json_instances, inst_name,
682 json_instance);
683 }
684
685 json_object_object_get_ex(json_instance, "timestamp", &json_timestamp);
686 if (json_timestamp) {
687 time_t now;
688 unsigned long remaining_time;
689
690 /* Check if the grace period has already expired. */
691 now = time(NULL);
692 timestamp = json_object_get_int(json_timestamp);
693 if (now > timestamp) {
694 ospf_gr_restart_exit(
695 ospf, "grace period has expired already");
696 } else {
697 /* Schedule grace period timeout. */
698 ospf->gr_info.restart_in_progress = true;
699 remaining_time = timestamp - time(NULL);
700 if (IS_DEBUG_OSPF_GR)
701 zlog_debug(
702 "GR: remaining time until grace period expires: %lu(s)",
703 remaining_time);
704 thread_add_timer(master, ospf_gr_grace_period_expired,
705 ospf, remaining_time,
706 &ospf->gr_info.t_grace_period);
707 }
708 }
709
710 json_object_object_del(json_instances, inst_name);
711
712 json_object_to_file_ext(filepath, json, JSON_C_TO_STRING_PRETTY);
713 json_object_free(json);
714 }
715
716 /* Prepare to start a Graceful Restart. */
717 static void ospf_gr_prepare(void)
718 {
719 struct ospf *ospf;
720 struct ospf_interface *oi;
721 struct listnode *onode;
722
723 for (ALL_LIST_ELEMENTS_RO(om->ospf, onode, ospf)) {
724 struct listnode *inode;
725
726 if (!ospf->gr_info.restart_support
727 || ospf->gr_info.prepare_in_progress)
728 continue;
729
730 if (IS_DEBUG_OSPF_GR)
731 zlog_debug(
732 "GR: preparing to perform a graceful restart [period %u second(s)] [vrf %s]",
733 ospf->gr_info.grace_period,
734 ospf_vrf_id_to_name(ospf->vrf_id));
735
736 if (!CHECK_FLAG(ospf->config, OSPF_OPAQUE_CAPABLE)) {
737 zlog_warn(
738 "%s: failed to activate graceful restart: opaque capability not enabled",
739 __func__);
740 continue;
741 }
742
743 /* Freeze OSPF routes in the RIB. */
744 if (ospf_zebra_gr_enable(ospf, ospf->gr_info.grace_period)) {
745 zlog_warn(
746 "%s: failed to activate graceful restart: not connected to zebra",
747 __func__);
748 continue;
749 }
750
751 /* Send a Grace-LSA to all neighbors. */
752 for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, inode, oi))
753 ospf_gr_lsa_originate(oi);
754
755 /* Record end of the grace period in non-volatile memory. */
756 ospf_gr_nvm_update(ospf);
757
758 /*
759 * Mark that a Graceful Restart preparation is in progress, to
760 * prevent ospfd from flushing its self-originated LSAs on exit.
761 */
762 ospf->gr_info.prepare_in_progress = true;
763 }
764 }
765
766 DEFPY(graceful_restart_prepare, graceful_restart_prepare_cmd,
767 "graceful-restart prepare ip ospf",
768 "Graceful Restart commands\n"
769 "Prepare upcoming graceful restart\n"
770 IP_STR
771 "Prepare to restart the OSPF process")
772 {
773 ospf_gr_prepare();
774
775 return CMD_SUCCESS;
776 }
777
778 DEFPY(graceful_restart, graceful_restart_cmd,
779 "graceful-restart [grace-period (1-1800)$grace_period]",
780 OSPF_GR_STR
781 "Maximum length of the 'grace period'\n"
782 "Maximum length of the 'grace period' in seconds\n")
783 {
784 VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
785
786 /* Check and get restart period if present. */
787 if (!grace_period_str)
788 grace_period = OSPF_DFLT_GRACE_INTERVAL;
789
790 ospf->gr_info.restart_support = true;
791 ospf->gr_info.grace_period = grace_period;
792
793 return CMD_SUCCESS;
794 }
795
796 DEFPY(no_graceful_restart, no_graceful_restart_cmd,
797 "no graceful-restart [period (1-1800)]",
798 NO_STR 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(ospf, ospf);
803
804 if (!ospf->gr_info.restart_support)
805 return CMD_SUCCESS;
806
807 if (ospf->gr_info.prepare_in_progress) {
808 vty_out(vty,
809 "%% Error: Graceful Restart preparation in progress\n");
810 return CMD_WARNING;
811 }
812
813 ospf->gr_info.restart_support = false;
814 ospf->gr_info.grace_period = OSPF_DFLT_GRACE_INTERVAL;
815
816 return CMD_SUCCESS;
817 }
818
819 void ospf_gr_init(void)
820 {
821 install_element(ENABLE_NODE, &graceful_restart_prepare_cmd);
822 install_element(OSPF_NODE, &graceful_restart_cmd);
823 install_element(OSPF_NODE, &no_graceful_restart_cmd);
824 }