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