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