Line data Source code
1 : /*
2 : * This is an implementation of RFC 5187 Graceful Restart.
3 : *
4 : * Copyright 2021 NetDEF (c), All rights reserved.
5 : *
6 : * This program is free software; you can redistribute it and/or modify it
7 : * under the terms of the GNU General Public License as published by the Free
8 : * Software Foundation; either version 2 of the License, or (at your option)
9 : * any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful, but WITHOUT
12 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 : * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 : * more details.
15 : *
16 : * You should have received a copy of the GNU General Public License along
17 : * with this program; see the file COPYING; if not, write to the Free Software
18 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 : */
20 :
21 : #include <zebra.h>
22 :
23 : #include "memory.h"
24 : #include "command.h"
25 : #include "table.h"
26 : #include "vty.h"
27 : #include "log.h"
28 : #include "hook.h"
29 : #include "printfrr.h"
30 :
31 : #include "ospf6d/ospf6_lsa.h"
32 : #include "ospf6d/ospf6_lsdb.h"
33 : #include "ospf6d/ospf6_route.h"
34 : #include "ospf6d/ospf6_area.h"
35 : #include "ospf6d/ospf6_interface.h"
36 : #include "ospf6d/ospf6d.h"
37 : #include "ospf6d/ospf6_asbr.h"
38 : #include "ospf6d/ospf6_zebra.h"
39 : #include "ospf6d/ospf6_message.h"
40 : #include "ospf6d/ospf6_neighbor.h"
41 : #include "ospf6d/ospf6_flood.h"
42 : #include "ospf6d/ospf6_intra.h"
43 : #include "ospf6d/ospf6_spf.h"
44 : #include "ospf6d/ospf6_gr.h"
45 : #include "ospf6d/ospf6_gr_clippy.c"
46 :
47 : static void ospf6_gr_nvm_delete(struct ospf6 *ospf6);
48 :
49 : /* Originate and install Grace-LSA for a given interface. */
50 0 : static int ospf6_gr_lsa_originate(struct ospf6_interface *oi)
51 : {
52 0 : struct ospf6_gr_info *gr_info = &oi->area->ospf6->gr_info;
53 0 : struct ospf6_lsa_header *lsa_header;
54 0 : struct ospf6_grace_lsa *grace_lsa;
55 0 : struct ospf6_lsa *lsa;
56 0 : char buffer[OSPF6_MAX_LSASIZE];
57 :
58 0 : if (IS_OSPF6_DEBUG_ORIGINATE(LINK))
59 0 : zlog_debug("Originate Grace-LSA for Interface %pOI", oi);
60 :
61 : /* prepare buffer */
62 0 : memset(buffer, 0, sizeof(buffer));
63 0 : lsa_header = (struct ospf6_lsa_header *)buffer;
64 0 : grace_lsa =
65 : (struct ospf6_grace_lsa *)((caddr_t)lsa_header
66 : + sizeof(struct ospf6_lsa_header));
67 :
68 : /* Put grace period. */
69 0 : grace_lsa->tlv_period.header.type = htons(GRACE_PERIOD_TYPE);
70 0 : grace_lsa->tlv_period.header.length = htons(GRACE_PERIOD_LENGTH);
71 0 : grace_lsa->tlv_period.interval = htonl(gr_info->grace_period);
72 :
73 : /* Put restart reason. */
74 0 : grace_lsa->tlv_reason.header.type = htons(RESTART_REASON_TYPE);
75 0 : grace_lsa->tlv_reason.header.length = htons(RESTART_REASON_LENGTH);
76 0 : if (gr_info->restart_support)
77 0 : grace_lsa->tlv_reason.reason = OSPF6_GR_SW_RESTART;
78 : else
79 : grace_lsa->tlv_reason.reason = OSPF6_GR_UNKNOWN_RESTART;
80 :
81 : /* Fill LSA Header */
82 0 : lsa_header->age = 0;
83 0 : lsa_header->type = htons(OSPF6_LSTYPE_GRACE_LSA);
84 0 : lsa_header->id = htonl(oi->interface->ifindex);
85 0 : lsa_header->adv_router = oi->area->ospf6->router_id;
86 0 : lsa_header->seqnum =
87 0 : ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
88 : lsa_header->adv_router, oi->lsdb);
89 0 : lsa_header->length = htons(sizeof(*lsa_header) + sizeof(*grace_lsa));
90 :
91 : /* LSA checksum */
92 0 : ospf6_lsa_checksum(lsa_header);
93 :
94 : /* create LSA */
95 0 : lsa = ospf6_lsa_create(lsa_header);
96 :
97 : /* Originate */
98 0 : ospf6_lsa_originate_interface(lsa, oi);
99 :
100 0 : return 0;
101 : }
102 :
103 : /* Flush all self-originated Grace-LSAs. */
104 0 : static void ospf6_gr_flush_grace_lsas(struct ospf6 *ospf6)
105 : {
106 0 : struct ospf6_area *area;
107 0 : struct listnode *anode;
108 :
109 0 : for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, anode, area)) {
110 0 : struct ospf6_lsa *lsa;
111 0 : struct ospf6_interface *oi;
112 0 : struct listnode *inode;
113 :
114 0 : if (IS_DEBUG_OSPF6_GR)
115 0 : zlog_debug(
116 : "GR: flushing self-originated Grace-LSAs [area %pI4]",
117 : &area->area_id);
118 :
119 0 : for (ALL_LIST_ELEMENTS_RO(area->if_list, inode, oi)) {
120 0 : lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_GRACE_LSA),
121 0 : htonl(oi->interface->ifindex),
122 0 : oi->area->ospf6->router_id,
123 : oi->lsdb);
124 0 : if (!lsa) {
125 0 : zlog_warn(
126 : "%s: Grace-LSA not found [interface %pOI] [area %pI4]",
127 : __func__, oi, &area->area_id);
128 0 : continue;
129 : }
130 :
131 0 : ospf6_lsa_purge(lsa);
132 : }
133 : }
134 0 : }
135 :
136 : /* Exit from the Graceful Restart mode. */
137 0 : static void ospf6_gr_restart_exit(struct ospf6 *ospf6, const char *reason)
138 : {
139 0 : struct ospf6_area *area;
140 0 : struct listnode *onode, *anode;
141 :
142 0 : if (IS_DEBUG_OSPF6_GR)
143 0 : zlog_debug("GR: exiting graceful restart: %s", reason);
144 :
145 0 : ospf6->gr_info.restart_in_progress = false;
146 0 : ospf6->gr_info.finishing_restart = true;
147 0 : THREAD_OFF(ospf6->gr_info.t_grace_period);
148 :
149 : /* Record in non-volatile memory that the restart is complete. */
150 0 : ospf6_gr_nvm_delete(ospf6);
151 :
152 0 : for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, onode, area)) {
153 0 : struct ospf6_interface *oi;
154 :
155 : /*
156 : * 1) The router should reoriginate its router-LSAs for all
157 : * attached areas in order to make sure they have the correct
158 : * contents.
159 : */
160 0 : OSPF6_ROUTER_LSA_EXECUTE(area);
161 :
162 0 : for (ALL_LIST_ELEMENTS_RO(area->if_list, anode, oi)) {
163 0 : OSPF6_LINK_LSA_EXECUTE(oi);
164 :
165 : /*
166 : * 2) The router should reoriginate network-LSAs on all
167 : * segments where it is the Designated Router.
168 : */
169 0 : if (oi->state == OSPF6_INTERFACE_DR)
170 0 : OSPF6_NETWORK_LSA_EXECUTE(oi);
171 : }
172 : }
173 :
174 : /*
175 : * 3) The router reruns its OSPF routing calculations, this time
176 : * installing the results into the system forwarding table, and
177 : * originating summary-LSAs, Type-7 LSAs and AS-external-LSAs as
178 : * necessary.
179 : *
180 : * 4) Any remnant entries in the system forwarding table that were
181 : * installed before the restart, but that are no longer valid,
182 : * should be removed.
183 : */
184 0 : ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_GR_FINISH);
185 :
186 : /* 6) Any grace-LSAs that the router originated should be flushed. */
187 0 : ospf6_gr_flush_grace_lsas(ospf6);
188 0 : }
189 :
190 : #define RTR_LSA_MISSING 0
191 : #define RTR_LSA_ADJ_FOUND 1
192 : #define RTR_LSA_ADJ_NOT_FOUND 2
193 :
194 : /* Check if a Router-LSA exists and if it contains a given link. */
195 0 : static int ospf6_router_lsa_contains_adj(struct ospf6_area *area,
196 : in_addr_t adv_router,
197 : in_addr_t neighbor_router_id)
198 : {
199 0 : uint16_t type;
200 0 : struct ospf6_lsa *lsa;
201 0 : bool empty = true;
202 :
203 0 : type = ntohs(OSPF6_LSTYPE_ROUTER);
204 0 : for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, adv_router, lsa)) {
205 0 : struct ospf6_router_lsa *router_lsa;
206 0 : char *start, *end, *current;
207 :
208 0 : empty = false;
209 0 : router_lsa = (struct ospf6_router_lsa
210 0 : *)((char *)lsa->header
211 : + sizeof(struct ospf6_lsa_header));
212 :
213 : /* Iterate over all interfaces in the Router-LSA. */
214 0 : start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
215 0 : end = (char *)lsa->header + ntohs(lsa->header->length);
216 0 : for (current = start;
217 0 : current + sizeof(struct ospf6_router_lsdesc) <= end;
218 : current += sizeof(struct ospf6_router_lsdesc)) {
219 0 : struct ospf6_router_lsdesc *lsdesc;
220 :
221 0 : lsdesc = (struct ospf6_router_lsdesc *)current;
222 0 : if (lsdesc->type != OSPF6_ROUTER_LSDESC_POINTTOPOINT)
223 0 : continue;
224 :
225 0 : if (lsdesc->neighbor_router_id == neighbor_router_id)
226 : return RTR_LSA_ADJ_FOUND;
227 : }
228 : }
229 :
230 0 : if (empty)
231 0 : return RTR_LSA_MISSING;
232 :
233 : return RTR_LSA_ADJ_NOT_FOUND;
234 : }
235 :
236 0 : static bool ospf6_gr_check_router_lsa_consistency(struct ospf6 *ospf6,
237 : struct ospf6_area *area,
238 : struct ospf6_lsa *lsa)
239 : {
240 0 : if (lsa->header->adv_router == ospf6->router_id) {
241 0 : struct ospf6_router_lsa *router_lsa;
242 0 : char *start, *end, *current;
243 :
244 0 : router_lsa = (struct ospf6_router_lsa
245 : *)((char *)lsa->header
246 : + sizeof(struct ospf6_lsa_header));
247 :
248 : /* Iterate over all interfaces in the Router-LSA. */
249 0 : start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
250 0 : end = (char *)lsa->header + ntohs(lsa->header->length);
251 0 : for (current = start;
252 0 : current + sizeof(struct ospf6_router_lsdesc) <= end;
253 : current += sizeof(struct ospf6_router_lsdesc)) {
254 0 : struct ospf6_router_lsdesc *lsdesc;
255 :
256 0 : lsdesc = (struct ospf6_router_lsdesc *)current;
257 0 : if (lsdesc->type != OSPF6_ROUTER_LSDESC_POINTTOPOINT)
258 0 : continue;
259 :
260 0 : if (ospf6_router_lsa_contains_adj(
261 : area, lsdesc->neighbor_router_id,
262 : ospf6->router_id)
263 : == RTR_LSA_ADJ_NOT_FOUND)
264 : return false;
265 : }
266 : } else {
267 0 : int adj1, adj2;
268 :
269 0 : adj1 = ospf6_router_lsa_contains_adj(area, ospf6->router_id,
270 : lsa->header->adv_router);
271 0 : adj2 = ospf6_router_lsa_contains_adj(
272 0 : area, lsa->header->adv_router, ospf6->router_id);
273 0 : if ((adj1 == RTR_LSA_ADJ_FOUND && adj2 == RTR_LSA_ADJ_NOT_FOUND)
274 0 : || (adj1 == RTR_LSA_ADJ_NOT_FOUND
275 0 : && adj2 == RTR_LSA_ADJ_FOUND))
276 : return false;
277 : }
278 :
279 : return true;
280 : }
281 :
282 : /*
283 : * Check for LSAs that are inconsistent with the pre-restart LSAs, and abort the
284 : * ongoing graceful restart when that's the case.
285 : */
286 0 : void ospf6_gr_check_lsdb_consistency(struct ospf6 *ospf6,
287 : struct ospf6_area *area)
288 : {
289 0 : uint16_t type;
290 0 : struct ospf6_lsa *lsa;
291 :
292 0 : type = ntohs(OSPF6_LSTYPE_ROUTER);
293 0 : for (ALL_LSDB_TYPED(area->lsdb, type, lsa)) {
294 0 : if (!ospf6_gr_check_router_lsa_consistency(ospf6, area, lsa)) {
295 0 : char reason[256];
296 :
297 0 : snprintfrr(reason, sizeof(reason),
298 : "detected inconsistent LSA %s [area %pI4]",
299 0 : lsa->name, &area->area_id);
300 0 : ospf6_gr_restart_exit(ospf6, reason);
301 0 : return;
302 : }
303 : }
304 : }
305 :
306 : /* Check if there's a fully formed adjacency with the given neighbor ID. */
307 0 : static bool ospf6_gr_check_adj_id(struct ospf6_area *area,
308 : in_addr_t neighbor_router_id)
309 : {
310 0 : struct ospf6_neighbor *nbr;
311 :
312 0 : nbr = ospf6_area_neighbor_lookup(area, neighbor_router_id);
313 0 : if (!nbr || nbr->state < OSPF6_NEIGHBOR_FULL) {
314 0 : if (IS_DEBUG_OSPF6_GR)
315 0 : zlog_debug("GR: missing adjacency to router %pI4",
316 : &neighbor_router_id);
317 0 : return false;
318 : }
319 :
320 : return true;
321 : }
322 :
323 0 : static bool ospf6_gr_check_adjs_lsa_transit(struct ospf6_area *area,
324 : in_addr_t neighbor_router_id,
325 : uint32_t neighbor_interface_id)
326 : {
327 0 : struct ospf6 *ospf6 = area->ospf6;
328 :
329 : /* Check if we are the DR. */
330 0 : if (neighbor_router_id == ospf6->router_id) {
331 0 : struct ospf6_lsa *lsa;
332 0 : char *start, *end, *current;
333 0 : struct ospf6_network_lsa *network_lsa;
334 0 : struct ospf6_network_lsdesc *lsdesc;
335 :
336 : /* Lookup Network LSA corresponding to this interface. */
337 0 : lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_NETWORK),
338 : neighbor_interface_id,
339 : neighbor_router_id, area->lsdb);
340 0 : if (!lsa)
341 : return false;
342 :
343 : /* Iterate over all routers present in the network. */
344 0 : network_lsa = (struct ospf6_network_lsa
345 0 : *)((char *)lsa->header
346 : + sizeof(struct ospf6_lsa_header));
347 0 : start = (char *)network_lsa + sizeof(struct ospf6_network_lsa);
348 0 : end = (char *)lsa->header + ntohs(lsa->header->length);
349 0 : for (current = start;
350 0 : current + sizeof(struct ospf6_network_lsdesc) <= end;
351 : current += sizeof(struct ospf6_network_lsdesc)) {
352 0 : lsdesc = (struct ospf6_network_lsdesc *)current;
353 :
354 : /* Skip self in the pseudonode. */
355 0 : if (lsdesc->router_id == ospf6->router_id)
356 0 : continue;
357 :
358 : /*
359 : * Check if there's a fully formed adjacency with this
360 : * router.
361 : */
362 0 : if (!ospf6_gr_check_adj_id(area, lsdesc->router_id))
363 : return false;
364 : }
365 : } else {
366 0 : struct ospf6_neighbor *nbr;
367 :
368 : /* Check if there's a fully formed adjacency with the DR. */
369 0 : nbr = ospf6_area_neighbor_lookup(area, neighbor_router_id);
370 0 : if (!nbr || nbr->state < OSPF6_NEIGHBOR_FULL) {
371 0 : if (IS_DEBUG_OSPF6_GR)
372 0 : zlog_debug(
373 : "GR: missing adjacency to DR router %pI4",
374 : &neighbor_router_id);
375 0 : return false;
376 : }
377 : }
378 :
379 : return true;
380 : }
381 :
382 0 : static bool ospf6_gr_check_adjs_lsa(struct ospf6_area *area,
383 : struct ospf6_lsa *lsa)
384 : {
385 0 : struct ospf6_router_lsa *router_lsa;
386 0 : char *start, *end, *current;
387 :
388 0 : router_lsa =
389 0 : (struct ospf6_router_lsa *)((char *)lsa->header
390 : + sizeof(struct ospf6_lsa_header));
391 :
392 : /* Iterate over all interfaces in the Router-LSA. */
393 0 : start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
394 0 : end = (char *)lsa->header + ntohs(lsa->header->length);
395 0 : for (current = start;
396 0 : current + sizeof(struct ospf6_router_lsdesc) <= end;
397 : current += sizeof(struct ospf6_router_lsdesc)) {
398 0 : struct ospf6_router_lsdesc *lsdesc;
399 :
400 0 : lsdesc = (struct ospf6_router_lsdesc *)current;
401 0 : switch (lsdesc->type) {
402 0 : case OSPF6_ROUTER_LSDESC_POINTTOPOINT:
403 0 : if (!ospf6_gr_check_adj_id(area,
404 : lsdesc->neighbor_router_id))
405 : return false;
406 : break;
407 0 : case OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK:
408 0 : if (!ospf6_gr_check_adjs_lsa_transit(
409 : area, lsdesc->neighbor_router_id,
410 : lsdesc->neighbor_interface_id))
411 : return false;
412 : break;
413 : default:
414 : break;
415 : }
416 : }
417 :
418 : return true;
419 : }
420 :
421 : /*
422 : * Check if all adjacencies prior to the restart were reestablished.
423 : *
424 : * This is done using pre-restart Router LSAs and pre-restart Network LSAs
425 : * received from the helping neighbors.
426 : */
427 0 : static bool ospf6_gr_check_adjs(struct ospf6 *ospf6)
428 : {
429 0 : struct ospf6_area *area;
430 0 : struct listnode *node;
431 :
432 0 : for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, area)) {
433 0 : uint16_t type;
434 0 : uint32_t router;
435 0 : struct ospf6_lsa *lsa_self;
436 0 : bool found = false;
437 :
438 0 : type = ntohs(OSPF6_LSTYPE_ROUTER);
439 0 : router = ospf6->router_id;
440 0 : for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, router,
441 : lsa_self)) {
442 0 : found = true;
443 0 : if (!ospf6_gr_check_adjs_lsa(area, lsa_self))
444 0 : return false;
445 : }
446 0 : if (!found)
447 : return false;
448 : }
449 :
450 : return true;
451 : }
452 :
453 : /* Handling of grace period expiry. */
454 0 : static void ospf6_gr_grace_period_expired(struct thread *thread)
455 : {
456 0 : struct ospf6 *ospf6 = THREAD_ARG(thread);
457 :
458 0 : ospf6_gr_restart_exit(ospf6, "grace period has expired");
459 0 : }
460 :
461 : /*
462 : * Record in non-volatile memory that the given OSPF instance is attempting to
463 : * perform a graceful restart.
464 : */
465 0 : static void ospf6_gr_nvm_update(struct ospf6 *ospf6)
466 : {
467 0 : const char *inst_name;
468 0 : json_object *json;
469 0 : json_object *json_instances;
470 0 : json_object *json_instance;
471 :
472 0 : inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
473 :
474 0 : json = json_object_from_file((char *)OSPF6D_GR_STATE);
475 0 : if (json == NULL)
476 0 : json = json_object_new_object();
477 :
478 0 : json_object_object_get_ex(json, "instances", &json_instances);
479 0 : if (!json_instances) {
480 0 : json_instances = json_object_new_object();
481 0 : json_object_object_add(json, "instances", json_instances);
482 : }
483 :
484 0 : json_object_object_get_ex(json_instances, inst_name, &json_instance);
485 0 : if (!json_instance) {
486 0 : json_instance = json_object_new_object();
487 0 : json_object_object_add(json_instances, inst_name,
488 : json_instance);
489 : }
490 :
491 : /*
492 : * Record not only the grace period, but also a UNIX timestamp
493 : * corresponding to the end of that period. That way, once ospf6d is
494 : * restarted, it will be possible to take into account the time that
495 : * passed while ospf6d wasn't running.
496 : */
497 0 : json_object_int_add(json_instance, "gracePeriod",
498 0 : ospf6->gr_info.grace_period);
499 0 : json_object_int_add(json_instance, "timestamp",
500 0 : time(NULL) + ospf6->gr_info.grace_period);
501 :
502 0 : json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
503 : JSON_C_TO_STRING_PRETTY);
504 0 : json_object_free(json);
505 0 : }
506 :
507 : /*
508 : * Delete GR status information about the given OSPF instance from non-volatile
509 : * memory.
510 : */
511 0 : static void ospf6_gr_nvm_delete(struct ospf6 *ospf6)
512 : {
513 0 : const char *inst_name;
514 0 : json_object *json;
515 0 : json_object *json_instances;
516 :
517 0 : inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
518 :
519 0 : json = json_object_from_file((char *)OSPF6D_GR_STATE);
520 0 : if (json == NULL)
521 0 : json = json_object_new_object();
522 :
523 0 : json_object_object_get_ex(json, "instances", &json_instances);
524 0 : if (!json_instances) {
525 0 : json_instances = json_object_new_object();
526 0 : json_object_object_add(json, "instances", json_instances);
527 : }
528 :
529 0 : json_object_object_del(json_instances, inst_name);
530 :
531 0 : json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
532 : JSON_C_TO_STRING_PRETTY);
533 0 : json_object_free(json);
534 0 : }
535 :
536 : /*
537 : * Fetch from non-volatile memory whether the given OSPF instance is performing
538 : * a graceful shutdown or not.
539 : */
540 4 : void ospf6_gr_nvm_read(struct ospf6 *ospf6)
541 : {
542 4 : const char *inst_name;
543 4 : json_object *json;
544 4 : json_object *json_instances;
545 4 : json_object *json_instance;
546 4 : json_object *json_timestamp;
547 4 : time_t timestamp = 0;
548 :
549 4 : inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
550 :
551 4 : json = json_object_from_file((char *)OSPF6D_GR_STATE);
552 4 : if (json == NULL)
553 4 : json = json_object_new_object();
554 :
555 4 : json_object_object_get_ex(json, "instances", &json_instances);
556 4 : if (!json_instances) {
557 4 : json_instances = json_object_new_object();
558 4 : json_object_object_add(json, "instances", json_instances);
559 : }
560 :
561 4 : json_object_object_get_ex(json_instances, inst_name, &json_instance);
562 4 : if (!json_instance) {
563 4 : json_instance = json_object_new_object();
564 4 : json_object_object_add(json_instances, inst_name,
565 : json_instance);
566 : }
567 :
568 4 : json_object_object_get_ex(json_instance, "timestamp", &json_timestamp);
569 4 : if (json_timestamp) {
570 0 : time_t now;
571 0 : unsigned long remaining_time;
572 :
573 : /* Check if the grace period has already expired. */
574 0 : now = time(NULL);
575 0 : timestamp = json_object_get_int(json_timestamp);
576 0 : if (now > timestamp) {
577 0 : ospf6_gr_restart_exit(
578 : ospf6, "grace period has expired already");
579 : } else {
580 : /* Schedule grace period timeout. */
581 0 : ospf6->gr_info.restart_in_progress = true;
582 0 : remaining_time = timestamp - time(NULL);
583 0 : if (IS_DEBUG_OSPF6_GR)
584 0 : zlog_debug(
585 : "GR: remaining time until grace period expires: %lu(s)",
586 : remaining_time);
587 0 : thread_add_timer(master, ospf6_gr_grace_period_expired,
588 : ospf6, remaining_time,
589 : &ospf6->gr_info.t_grace_period);
590 : }
591 : }
592 :
593 4 : json_object_object_del(json_instances, inst_name);
594 :
595 4 : json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
596 : JSON_C_TO_STRING_PRETTY);
597 4 : json_object_free(json);
598 4 : }
599 :
600 : /* Prepare to start a Graceful Restart. */
601 0 : static void ospf6_gr_prepare(void)
602 : {
603 0 : struct ospf6 *ospf6;
604 0 : struct ospf6_interface *oi;
605 0 : struct listnode *onode, *anode, *inode;
606 :
607 0 : for (ALL_LIST_ELEMENTS_RO(om6->ospf6, onode, ospf6)) {
608 0 : struct ospf6_area *area;
609 :
610 0 : if (!ospf6->gr_info.restart_support
611 0 : || ospf6->gr_info.prepare_in_progress)
612 0 : continue;
613 :
614 0 : if (IS_DEBUG_OSPF6_GR)
615 0 : zlog_debug(
616 : "GR: preparing to perform a graceful restart [period %u second(s)] [vrf %s]",
617 : ospf6->gr_info.grace_period,
618 : ospf6_vrf_id_to_name(ospf6->vrf_id));
619 :
620 : /* Freeze OSPF routes in the RIB. */
621 0 : if (ospf6_zebra_gr_enable(ospf6, ospf6->gr_info.grace_period)) {
622 0 : zlog_warn(
623 : "%s: failed to activate graceful restart: not connected to zebra",
624 : __func__);
625 0 : continue;
626 : }
627 :
628 : /* Send a Grace-LSA to all neighbors. */
629 0 : for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, anode, area)) {
630 0 : for (ALL_LIST_ELEMENTS_RO(area->if_list, inode, oi)) {
631 0 : if (oi->state < OSPF6_INTERFACE_POINTTOPOINT)
632 0 : continue;
633 0 : ospf6_gr_lsa_originate(oi);
634 : }
635 : }
636 :
637 : /* Record end of the grace period in non-volatile memory. */
638 0 : ospf6_gr_nvm_update(ospf6);
639 :
640 : /*
641 : * Mark that a Graceful Restart preparation is in progress, to
642 : * prevent ospf6d from flushing its self-originated LSAs on
643 : * exit.
644 : */
645 0 : ospf6->gr_info.prepare_in_progress = true;
646 : }
647 0 : }
648 :
649 45 : static int ospf6_gr_neighbor_change(struct ospf6_neighbor *on, int next_state,
650 : int prev_state)
651 : {
652 45 : struct ospf6 *ospf6 = on->ospf6_if->area->ospf6;
653 :
654 45 : if (next_state == OSPF6_NEIGHBOR_FULL
655 8 : && ospf6->gr_info.restart_in_progress) {
656 0 : if (ospf6_gr_check_adjs(ospf6)) {
657 0 : ospf6_gr_restart_exit(
658 : ospf6, "all adjacencies were reestablished");
659 : } else {
660 0 : if (IS_DEBUG_OSPF6_GR)
661 0 : zlog_debug(
662 : "GR: not all adjacencies were reestablished yet");
663 : }
664 : }
665 :
666 45 : return 0;
667 : }
668 :
669 0 : int config_write_ospf6_gr(struct vty *vty, struct ospf6 *ospf6)
670 : {
671 0 : if (!ospf6->gr_info.restart_support)
672 : return 0;
673 :
674 0 : if (ospf6->gr_info.grace_period == OSPF6_DFLT_GRACE_INTERVAL)
675 0 : vty_out(vty, " graceful-restart\n");
676 : else
677 0 : vty_out(vty, " graceful-restart grace-period %u\n",
678 : ospf6->gr_info.grace_period);
679 :
680 : return 0;
681 : }
682 :
683 0 : DEFPY(ospf6_graceful_restart_prepare, ospf6_graceful_restart_prepare_cmd,
684 : "graceful-restart prepare ipv6 ospf",
685 : "Graceful Restart commands\n"
686 : "Prepare upcoming graceful restart\n" IPV6_STR
687 : "Prepare to restart the OSPFv3 process\n")
688 : {
689 0 : ospf6_gr_prepare();
690 :
691 0 : return CMD_SUCCESS;
692 : }
693 :
694 0 : DEFPY(ospf6_graceful_restart, ospf6_graceful_restart_cmd,
695 : "graceful-restart [grace-period (1-1800)$grace_period]",
696 : OSPF_GR_STR
697 : "Maximum length of the 'grace period'\n"
698 : "Maximum length of the 'grace period' in seconds\n")
699 : {
700 0 : VTY_DECLVAR_INSTANCE_CONTEXT(ospf6, ospf6);
701 :
702 : /* Check and get restart period if present. */
703 0 : if (!grace_period_str)
704 0 : grace_period = OSPF6_DFLT_GRACE_INTERVAL;
705 :
706 0 : ospf6->gr_info.restart_support = true;
707 0 : ospf6->gr_info.grace_period = grace_period;
708 :
709 0 : return CMD_SUCCESS;
710 : }
711 :
712 0 : DEFPY(ospf6_no_graceful_restart, ospf6_no_graceful_restart_cmd,
713 : "no graceful-restart [period (1-1800)]",
714 : NO_STR OSPF_GR_STR
715 : "Maximum length of the 'grace period'\n"
716 : "Maximum length of the 'grace period' in seconds\n")
717 : {
718 0 : VTY_DECLVAR_INSTANCE_CONTEXT(ospf6, ospf6);
719 :
720 0 : if (!ospf6->gr_info.restart_support)
721 : return CMD_SUCCESS;
722 :
723 0 : if (ospf6->gr_info.prepare_in_progress) {
724 0 : vty_out(vty,
725 : "%% Error: Graceful Restart preparation in progress\n");
726 0 : return CMD_WARNING;
727 : }
728 :
729 0 : ospf6->gr_info.restart_support = false;
730 0 : ospf6->gr_info.grace_period = OSPF6_DFLT_GRACE_INTERVAL;
731 :
732 0 : return CMD_SUCCESS;
733 : }
734 :
735 4 : void ospf6_gr_init(void)
736 : {
737 4 : hook_register(ospf6_neighbor_change, ospf6_gr_neighbor_change);
738 :
739 4 : install_element(ENABLE_NODE, &ospf6_graceful_restart_prepare_cmd);
740 4 : install_element(OSPF6_NODE, &ospf6_graceful_restart_cmd);
741 4 : install_element(OSPF6_NODE, &ospf6_no_graceful_restart_cmd);
742 4 : }
|