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