]> git.proxmox.com Git - mirror_frr.git/blob - ospfd/ospf_gr.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / ospfd / ospf_gr.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
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.
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"
34 #include "ospfd/ospf_gr_clippy.c"
35
36 static void ospf_gr_nvm_delete(struct ospf *ospf);
37
38 /* Lookup self-originated Grace-LSA in the LSDB. */
39 static 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. */
55 static 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. */
88 static 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. */
138 static void ospf_gr_lsa_originate(struct ospf_interface *oi, bool maxage)
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
152 if (maxage)
153 lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
154
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
174 /* Flush all self-originated Grace-LSAs. */
175 static 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)) {
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
189 for (ALL_LIST_ELEMENTS_RO(area->oiflist, inode, oi))
190 ospf_gr_lsa_originate(oi, true);
191 }
192 }
193
194 /* Exit from the Graceful Restart mode. */
195 static 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;
204 THREAD_OFF(ospf->gr_info.t_grace_period);
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. */
252 static 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
271 static 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 */
316 void 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. */
340 static struct ospf_neighbor *
341 ospf_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. */
357 static struct ospf_neighbor *
358 ospf_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. */
374 static 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
390 static 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
445 static 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 */
475 void 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. */
498 static void ospf_gr_grace_period_expired(struct thread *thread)
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");
504 }
505
506 /*
507 * Returns the path of the file (non-volatile memory) that contains GR status
508 * information.
509 */
510 static 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 */
525 static 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);
534 inst_name = ospf_get_name(ospf);
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 */
572 static 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);
580 inst_name = ospf_get_name(ospf);
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 */
602 void 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);
613 inst_name = ospf_get_name(ospf);
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. */
664 static 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))
700 ospf_gr_lsa_originate(oi, false);
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
713 DEFPY(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
718 "Prepare to restart the OSPF process\n")
719 {
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
732 ospf_gr_prepare();
733
734 return CMD_SUCCESS;
735 }
736
737 DEFPY(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
755 DEFPY(no_graceful_restart, no_graceful_restart_cmd,
756 "no graceful-restart [grace-period (1-1800)]",
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
778 void 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 }