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