Line data Source code
1 : /*
2 : * OSPF6 Graceful Restart helper functions.
3 : *
4 : * Copyright (C) 2021-22 Vmware, Inc.
5 : * Rajesh Kumar Girada
6 : *
7 : * This file is part of GNU Zebra.
8 : *
9 : * GNU Zebra is free software; you can redistribute it and/or modify it
10 : * under the terms of the GNU General Public License as published by the
11 : * Free Software Foundation; either version 2, or (at your option) any
12 : * later version.
13 : *
14 : * GNU Zebra is distributed in the hope that it will be useful, but
15 : * WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 : * General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License along
20 : * with this program; see the file COPYING; if not, write to the Free Software
21 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 : */
23 :
24 : #include <zebra.h>
25 :
26 : #include "log.h"
27 : #include "vty.h"
28 : #include "command.h"
29 : #include "prefix.h"
30 : #include "stream.h"
31 : #include "zclient.h"
32 : #include "memory.h"
33 : #include "table.h"
34 : #include "lib/bfd.h"
35 : #include "lib_errors.h"
36 : #include "jhash.h"
37 :
38 : #include "ospf6_proto.h"
39 : #include "ospf6_lsa.h"
40 : #include "ospf6_lsdb.h"
41 : #include "ospf6_route.h"
42 : #include "ospf6_message.h"
43 :
44 : #include "ospf6_top.h"
45 : #include "ospf6_area.h"
46 : #include "ospf6_interface.h"
47 : #include "ospf6_neighbor.h"
48 : #include "ospf6_intra.h"
49 : #include "ospf6d.h"
50 : #include "ospf6_gr.h"
51 : #include "lib/json.h"
52 : #include "ospf6d/ospf6_gr_helper_clippy.c"
53 :
54 48 : DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_GR_HELPER, "OSPF6 Graceful restart helper");
55 :
56 : unsigned char conf_debug_ospf6_gr;
57 :
58 : static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa,
59 : json_object *json, bool use_json);
60 :
61 : struct ospf6_lsa_handler grace_lsa_handler = {.lh_type = OSPF6_LSTYPE_GRACE_LSA,
62 : .lh_name = "Grace",
63 : .lh_short_name = "GR",
64 : .lh_show =
65 : ospf6_grace_lsa_show_info,
66 : .lh_get_prefix_str = NULL,
67 : .lh_debug = 0};
68 :
69 : const char *ospf6_exit_reason_desc[] = {
70 : "Unknown reason",
71 : "Helper in progress",
72 : "Topology Change",
73 : "Grace timer expiry",
74 : "Successful graceful restart",
75 : };
76 :
77 : const char *ospf6_restart_reason_desc[] = {
78 : "Unknown restart",
79 : "Software restart",
80 : "Software reload/upgrade",
81 : "Switch to redundant control processor",
82 : };
83 :
84 : const char *ospf6_rejected_reason_desc[] = {
85 : "Unknown reason",
86 : "Helper support disabled",
87 : "Neighbour is not in FULL state",
88 : "Supports only planned restart but received for unplanned",
89 : "Topo change due to change in lsa rxmt list",
90 : "LSA age is more than Grace interval",
91 : };
92 :
93 0 : static unsigned int ospf6_enable_rtr_hash_key(const void *data)
94 : {
95 0 : const struct advRtr *rtr = data;
96 :
97 0 : return jhash_1word(rtr->advRtrAddr, 0);
98 : }
99 :
100 0 : static bool ospf6_enable_rtr_hash_cmp(const void *d1, const void *d2)
101 : {
102 0 : const struct advRtr *rtr1 = d1;
103 0 : const struct advRtr *rtr2 = d2;
104 :
105 0 : return (rtr1->advRtrAddr == rtr2->advRtrAddr);
106 : }
107 :
108 0 : static void *ospf6_enable_rtr_hash_alloc(void *p)
109 : {
110 0 : struct advRtr *rid;
111 :
112 0 : rid = XCALLOC(MTYPE_OSPF6_GR_HELPER, sizeof(struct advRtr));
113 0 : rid->advRtrAddr = ((struct advRtr *)p)->advRtrAddr;
114 :
115 0 : return rid;
116 : }
117 :
118 0 : static void ospf6_disable_rtr_hash_free(void *rtr)
119 : {
120 0 : XFREE(MTYPE_OSPF6_GR_HELPER, rtr);
121 0 : }
122 :
123 16 : static void ospf6_enable_rtr_hash_destroy(struct ospf6 *ospf6)
124 : {
125 16 : if (ospf6->ospf6_helper_cfg.enable_rtr_list == NULL)
126 : return;
127 :
128 16 : hash_clean(ospf6->ospf6_helper_cfg.enable_rtr_list,
129 : ospf6_disable_rtr_hash_free);
130 16 : hash_free(ospf6->ospf6_helper_cfg.enable_rtr_list);
131 16 : ospf6->ospf6_helper_cfg.enable_rtr_list = NULL;
132 : }
133 :
134 : /*
135 : * Extracting tlv info from GRACE LSA.
136 : *
137 : * lsa
138 : * ospf6 grace lsa
139 : *
140 : * Returns:
141 : * interval : grace interval.
142 : * reason : Restarting reason.
143 : */
144 0 : static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa,
145 : uint32_t *interval, uint8_t *reason)
146 : {
147 0 : struct ospf6_lsa_header *lsah = NULL;
148 0 : struct tlv_header *tlvh = NULL;
149 0 : struct grace_tlv_graceperiod *gracePeriod;
150 0 : struct grace_tlv_restart_reason *grReason;
151 0 : uint16_t length = 0;
152 0 : int sum = 0;
153 :
154 0 : lsah = (struct ospf6_lsa_header *)lsa->header;
155 0 : if (ntohs(lsah->length) <= OSPF6_LSA_HEADER_SIZE) {
156 0 : if (IS_DEBUG_OSPF6_GR)
157 0 : zlog_debug("%s: undersized (%u B) lsa", __func__,
158 : ntohs(lsah->length));
159 0 : return OSPF6_FAILURE;
160 : }
161 :
162 0 : length = ntohs(lsah->length) - OSPF6_LSA_HEADER_SIZE;
163 :
164 0 : for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
165 0 : tlvh = TLV_HDR_NEXT(tlvh)) {
166 :
167 : /* Check TLV len against overall LSA */
168 0 : if (sum + TLV_SIZE(tlvh) > length) {
169 0 : if (IS_DEBUG_OSPF6_GR)
170 0 : zlog_debug(
171 : "%s: Malformed packet: Invalid TLV len:%d",
172 : __func__, TLV_SIZE(tlvh));
173 0 : return OSPF6_FAILURE;
174 : }
175 :
176 0 : switch (ntohs(tlvh->type)) {
177 0 : case GRACE_PERIOD_TYPE:
178 0 : gracePeriod = (struct grace_tlv_graceperiod *)tlvh;
179 0 : *interval = ntohl(gracePeriod->interval);
180 0 : sum += TLV_SIZE(tlvh);
181 :
182 : /* Check if grace interval is valid */
183 0 : if (*interval > OSPF6_MAX_GRACE_INTERVAL
184 0 : || *interval < OSPF6_MIN_GRACE_INTERVAL)
185 : return OSPF6_FAILURE;
186 : break;
187 0 : case RESTART_REASON_TYPE:
188 0 : grReason = (struct grace_tlv_restart_reason *)tlvh;
189 0 : *reason = grReason->reason;
190 0 : sum += TLV_SIZE(tlvh);
191 :
192 0 : if (*reason >= OSPF6_GR_INVALID_REASON_CODE)
193 : return OSPF6_FAILURE;
194 : break;
195 0 : default:
196 0 : if (IS_DEBUG_OSPF6_GR)
197 0 : zlog_debug("%s, Ignoring unknown TLV type:%d",
198 : __func__, ntohs(tlvh->type));
199 : }
200 : }
201 :
202 : return OSPF6_SUCCESS;
203 : }
204 :
205 : /*
206 : * Grace timer expiry handler.
207 : * HELPER aborts its role at grace timer expiry.
208 : *
209 : * thread
210 : * thread pointer
211 : *
212 : * Returns:
213 : * Nothing
214 : */
215 0 : static void ospf6_handle_grace_timer_expiry(struct thread *thread)
216 : {
217 0 : struct ospf6_neighbor *nbr = THREAD_ARG(thread);
218 :
219 0 : ospf6_gr_helper_exit(nbr, OSPF6_GR_HELPER_GRACE_TIMEOUT);
220 0 : }
221 :
222 : /*
223 : * API to check any change in the neighbor's
224 : * retransmission list.
225 : *
226 : * nbr
227 : * ospf6 neighbor
228 : *
229 : * Returns:
230 : * TRUE - if any change in the lsa.
231 : * FALSE - no change in the lsas.
232 : */
233 0 : static bool ospf6_check_chg_in_rxmt_list(struct ospf6_neighbor *nbr)
234 : {
235 0 : struct ospf6_lsa *lsa, *lsanext;
236 :
237 0 : for (ALL_LSDB(nbr->retrans_list, lsa, lsanext)) {
238 0 : struct ospf6_lsa *lsa_in_db = NULL;
239 :
240 : /* Fetching the same copy of LSA form LSDB to validate the
241 : * topochange.
242 : */
243 0 : lsa_in_db =
244 0 : ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
245 0 : lsa->header->adv_router, lsa->lsdb);
246 :
247 0 : if (lsa_in_db && lsa_in_db->tobe_acknowledged) {
248 0 : ospf6_lsa_unlock(lsa);
249 0 : if (lsanext)
250 0 : ospf6_lsa_unlock(lsanext);
251 :
252 0 : return OSPF6_TRUE;
253 : }
254 : }
255 :
256 : return OSPF6_FALSE;
257 : }
258 :
259 : /*
260 : * Process Grace LSA.If it is eligible move to HELPER role.
261 : * Ref rfc3623 section 3.1 and rfc5187
262 : *
263 : * ospf
264 : * Ospf6 pointer.
265 : *
266 : * lsa
267 : * Grace LSA received from RESTARTER.
268 : *
269 : * restarter
270 : * ospf6 neighbour which requests the router to act as
271 : * HELPER.
272 : *
273 : * Returns:
274 : * status.
275 : * If supported as HELPER : OSPF_GR_HELPER_INPROGRESS
276 : * If Not supported as HELPER : OSPF_GR_HELPER_NONE
277 : */
278 0 : int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa,
279 : struct ospf6_neighbor *restarter)
280 : {
281 0 : uint8_t restart_reason = 0;
282 0 : uint32_t grace_interval = 0;
283 0 : uint32_t actual_grace_interval = 0;
284 0 : struct advRtr lookup;
285 0 : int ret;
286 :
287 : /* Extract the grace lsa packet fields */
288 0 : ret = ospf6_extract_grace_lsa_fields(lsa, &grace_interval,
289 : &restart_reason);
290 0 : if (ret != OSPF6_SUCCESS) {
291 0 : if (IS_DEBUG_OSPF6_GR)
292 0 : zlog_debug("%s, Wrong Grace LSA packet.", __func__);
293 0 : return OSPF6_GR_NOT_HELPER;
294 : }
295 :
296 0 : if (IS_DEBUG_OSPF6_GR)
297 0 : zlog_debug(
298 : "%s, Grace LSA received from %pI4, grace interval:%u, restart reason :%s",
299 : __func__, &restarter->router_id, grace_interval,
300 : ospf6_restart_reason_desc[restart_reason]);
301 :
302 : /* Verify Helper enabled globally */
303 0 : if (!ospf6->ospf6_helper_cfg.is_helper_supported) {
304 : /* Verify Helper support is enabled for the
305 : * current neighbour router-id.
306 : */
307 0 : lookup.advRtrAddr = restarter->router_id;
308 :
309 0 : if (!hash_lookup(ospf6->ospf6_helper_cfg.enable_rtr_list,
310 : &lookup)) {
311 0 : if (IS_DEBUG_OSPF6_GR)
312 0 : zlog_debug(
313 : "%s, HELPER support is disabled, So not a HELPER",
314 : __func__);
315 0 : restarter->gr_helper_info.rejected_reason =
316 : OSPF6_HELPER_SUPPORT_DISABLED;
317 0 : return OSPF6_GR_NOT_HELPER;
318 : }
319 : }
320 :
321 : /* Check neighbour is in FULL state and
322 : * became a adjacency.
323 : */
324 0 : if (!IS_NBR_STATE_FULL(restarter)) {
325 0 : if (IS_DEBUG_OSPF6_GR)
326 0 : zlog_debug(
327 : "%s, This Neighbour %pI6 is not in FULL state.",
328 : __func__, &restarter->linklocal_addr);
329 0 : restarter->gr_helper_info.rejected_reason =
330 : OSPF6_HELPER_NOT_A_VALID_NEIGHBOUR;
331 0 : return OSPF6_GR_NOT_HELPER;
332 : }
333 :
334 : /* Based on the restart reason from grace lsa
335 : * check the current router is supporting or not
336 : */
337 0 : if (ospf6->ospf6_helper_cfg.only_planned_restart
338 0 : && !OSPF6_GR_IS_PLANNED_RESTART(restart_reason)) {
339 0 : if (IS_DEBUG_OSPF6_GR)
340 0 : zlog_debug(
341 : "%s, Router supports only planned restarts but received the GRACE LSA due to an unplanned restart",
342 : __func__);
343 0 : restarter->gr_helper_info.rejected_reason =
344 : OSPF6_HELPER_PLANNED_ONLY_RESTART;
345 0 : return OSPF6_GR_NOT_HELPER;
346 : }
347 :
348 : /* Check the retransmission list of this
349 : * neighbour, check any change in lsas.
350 : */
351 0 : if (ospf6->ospf6_helper_cfg.strict_lsa_check
352 0 : && restarter->retrans_list->count
353 0 : && ospf6_check_chg_in_rxmt_list(restarter)) {
354 0 : if (IS_DEBUG_OSPF6_GR)
355 0 : zlog_debug(
356 : "%s, Changed LSA in Rxmt list.So not Helper.",
357 : __func__);
358 0 : restarter->gr_helper_info.rejected_reason =
359 : OSPF6_HELPER_TOPO_CHANGE_RTXMT_LIST;
360 0 : return OSPF6_GR_NOT_HELPER;
361 : }
362 :
363 : /* LSA age must be less than the grace period */
364 0 : if (ntohs(lsa->header->age) >= grace_interval) {
365 0 : if (IS_DEBUG_OSPF6_GR)
366 0 : zlog_debug(
367 : "%s, Grace LSA age(%d) is more than the grace interval(%d)",
368 : __func__, lsa->header->age, grace_interval);
369 0 : restarter->gr_helper_info.rejected_reason =
370 : OSPF6_HELPER_LSA_AGE_MORE;
371 0 : return OSPF6_GR_NOT_HELPER;
372 : }
373 :
374 0 : if (ospf6->gr_info.restart_in_progress) {
375 0 : if (IS_DEBUG_OSPF6_GR)
376 0 : zlog_debug(
377 : "%s: router is in the process of graceful restart",
378 : __func__);
379 0 : restarter->gr_helper_info.rejected_reason =
380 : OSPF6_HELPER_RESTARTING;
381 0 : return OSPF6_GR_NOT_HELPER;
382 : }
383 :
384 : /* check supported grace period configured
385 : * if configured, use this to start the grace
386 : * timer otherwise use the interval received
387 : * in grace LSA packet.
388 : */
389 0 : actual_grace_interval = grace_interval;
390 0 : if (grace_interval > ospf6->ospf6_helper_cfg.supported_grace_time) {
391 0 : if (IS_DEBUG_OSPF6_GR)
392 0 : zlog_debug(
393 : "%s, Received grace period %d is larger than supported grace %d",
394 : __func__, grace_interval,
395 : ospf6->ospf6_helper_cfg.supported_grace_time);
396 0 : actual_grace_interval =
397 : ospf6->ospf6_helper_cfg.supported_grace_time;
398 : }
399 :
400 0 : if (OSPF6_GR_IS_ACTIVE_HELPER(restarter)) {
401 0 : THREAD_OFF(restarter->gr_helper_info.t_grace_timer);
402 :
403 0 : if (ospf6->ospf6_helper_cfg.active_restarter_cnt > 0)
404 0 : ospf6->ospf6_helper_cfg.active_restarter_cnt--;
405 :
406 0 : if (IS_DEBUG_OSPF6_GR)
407 0 : zlog_debug(
408 : "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
409 : __func__);
410 : } else {
411 0 : if (IS_DEBUG_OSPF6_GR)
412 0 : zlog_debug(
413 : "%s, This Router becomes a HELPER for the neighbour %pI6",
414 : __func__, &restarter->linklocal_addr);
415 : }
416 :
417 : /* Became a Helper to the RESTART neighbour.
418 : * change the helper status.
419 : */
420 0 : restarter->gr_helper_info.gr_helper_status = OSPF6_GR_ACTIVE_HELPER;
421 0 : restarter->gr_helper_info.recvd_grace_period = grace_interval;
422 0 : restarter->gr_helper_info.actual_grace_period = actual_grace_interval;
423 0 : restarter->gr_helper_info.gr_restart_reason = restart_reason;
424 0 : restarter->gr_helper_info.rejected_reason = OSPF6_HELPER_REJECTED_NONE;
425 :
426 : /* Increment the active restart nbr count */
427 0 : ospf6->ospf6_helper_cfg.active_restarter_cnt++;
428 :
429 0 : if (IS_DEBUG_OSPF6_GR)
430 0 : zlog_debug("%s, Grace timer started.interval:%u", __func__,
431 : actual_grace_interval);
432 :
433 : /* Start the grace timer */
434 0 : thread_add_timer(master, ospf6_handle_grace_timer_expiry, restarter,
435 : actual_grace_interval,
436 : &restarter->gr_helper_info.t_grace_timer);
437 :
438 0 : return OSPF6_GR_ACTIVE_HELPER;
439 : }
440 :
441 : /*
442 : * Api to exit from HELPER role to take all actions
443 : * required at exit.
444 : * Ref rfc3623 section 3. and rfc51872
445 : *
446 : * ospf6
447 : * Ospf6 pointer.
448 : *
449 : * nbr
450 : * Ospf6 neighbour for which it is acting as HELPER.
451 : *
452 : * reason
453 : * The reason for exiting from HELPER.
454 : *
455 : * Returns:
456 : * Nothing.
457 : */
458 32 : void ospf6_gr_helper_exit(struct ospf6_neighbor *nbr,
459 : enum ospf6_helper_exit_reason reason)
460 : {
461 32 : struct ospf6_interface *oi = nbr->ospf6_if;
462 32 : struct ospf6 *ospf6;
463 :
464 32 : if (!oi)
465 : return;
466 :
467 32 : ospf6 = oi->area->ospf6;
468 :
469 32 : if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr))
470 : return;
471 :
472 0 : if (IS_DEBUG_OSPF6_GR)
473 0 : zlog_debug("%s, Exiting from HELPER support to %pI6, due to %s",
474 : __func__, &nbr->linklocal_addr,
475 : ospf6_exit_reason_desc[reason]);
476 :
477 : /* Reset helper status*/
478 0 : nbr->gr_helper_info.gr_helper_status = OSPF6_GR_NOT_HELPER;
479 0 : nbr->gr_helper_info.helper_exit_reason = reason;
480 0 : nbr->gr_helper_info.actual_grace_period = 0;
481 0 : nbr->gr_helper_info.recvd_grace_period = 0;
482 0 : nbr->gr_helper_info.gr_restart_reason = 0;
483 0 : ospf6->ospf6_helper_cfg.last_exit_reason = reason;
484 :
485 : /* If the exit not triggered due to grace timer
486 : * expiry, stop the grace timer.
487 : */
488 0 : if (reason != OSPF6_GR_HELPER_GRACE_TIMEOUT)
489 0 : THREAD_OFF(nbr->gr_helper_info.t_grace_timer);
490 :
491 0 : if (ospf6->ospf6_helper_cfg.active_restarter_cnt <= 0) {
492 0 : zlog_err(
493 : "OSPF6 GR-Helper: Number of active Restarters should be greater than zero.");
494 0 : return;
495 : }
496 : /* Decrement active restarter count */
497 0 : ospf6->ospf6_helper_cfg.active_restarter_cnt--;
498 :
499 : /* check exit triggered due to successful completion
500 : * of graceful restart.
501 : */
502 0 : if (reason != OSPF6_GR_HELPER_COMPLETED) {
503 0 : if (IS_DEBUG_OSPF6_GR)
504 0 : zlog_debug("%s, Unsuccessful GR exit. RESTARTER : %pI6",
505 : __func__, &nbr->linklocal_addr);
506 : }
507 :
508 : /*Recalculate the DR for the network segment */
509 0 : dr_election(oi);
510 :
511 : /* Originate a router LSA */
512 0 : OSPF6_ROUTER_LSA_SCHEDULE(nbr->ospf6_if->area);
513 :
514 : /* Originate network lsa if it is an DR in the LAN */
515 0 : if (nbr->ospf6_if->state == OSPF6_INTERFACE_DR)
516 0 : OSPF6_NETWORK_LSA_SCHEDULE(nbr->ospf6_if);
517 : }
518 :
519 : /*
520 : * Process max age Grace LSA.
521 : * It is a indication for successful completion of GR.
522 : * If router acting as HELPER, It exits from helper role.
523 : *
524 : * ospf6
525 : * Ospf6 pointer.
526 : *
527 : * lsa
528 : * Grace LSA received from RESTARTER.
529 : *
530 : * nbr
531 : * ospf6 neighbour which request the router to act as
532 : * HELPER.
533 : *
534 : * Returns:
535 : * Nothing.
536 : */
537 0 : void ospf6_process_maxage_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa,
538 : struct ospf6_neighbor *restarter)
539 : {
540 0 : uint8_t restart_reason = 0;
541 0 : uint32_t grace_interval = 0;
542 0 : int ret;
543 :
544 : /* Extract the grace lsa packet fields */
545 0 : ret = ospf6_extract_grace_lsa_fields(lsa, &grace_interval,
546 : &restart_reason);
547 0 : if (ret != OSPF6_SUCCESS) {
548 0 : if (IS_DEBUG_OSPF6_GR)
549 0 : zlog_debug("%s, Wrong Grace LSA packet.", __func__);
550 0 : return;
551 : }
552 :
553 0 : if (IS_DEBUG_OSPF6_GR)
554 0 : zlog_debug("%s, GraceLSA received for neighbour %pI4.",
555 : __func__, &restarter->router_id);
556 :
557 0 : ospf6_gr_helper_exit(restarter, OSPF6_GR_HELPER_COMPLETED);
558 : }
559 :
560 : /*
561 : * Actions to be taken when topo change detected
562 : * HELPER will be exited upon a topo change.
563 : *
564 : * ospf6
565 : * ospf6 pointer
566 : * lsa
567 : * topo change occurred due to this lsa(type (1-5 and 7)
568 : *
569 : * Returns:
570 : * Nothing
571 : */
572 392 : void ospf6_helper_handle_topo_chg(struct ospf6 *ospf6, struct ospf6_lsa *lsa)
573 : {
574 392 : struct listnode *i, *j, *k;
575 392 : struct ospf6_neighbor *nbr = NULL;
576 392 : struct ospf6_area *oa = NULL;
577 392 : struct ospf6_interface *oi = NULL;
578 :
579 392 : if (!ospf6->ospf6_helper_cfg.active_restarter_cnt)
580 : return;
581 :
582 : /* Topo change not required to be handled if strict
583 : * LSA check is disabled for this router.
584 : */
585 0 : if (!ospf6->ospf6_helper_cfg.strict_lsa_check)
586 : return;
587 :
588 0 : if (IS_DEBUG_OSPF6_GR)
589 0 : zlog_debug("%s, Topo change detected due to lsa details : %s",
590 : __func__, lsa->name);
591 :
592 0 : lsa->tobe_acknowledged = OSPF6_TRUE;
593 :
594 0 : for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
595 0 : for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) {
596 :
597 : /* Ref rfc3623 section 3.2.3.b and rfc5187
598 : * If change due to external LSA and if the area is
599 : * stub, then it is not a topo change. Since Type-5
600 : * lsas will not be flooded in stub area.
601 : */
602 0 : if (IS_AREA_STUB(oi->area)
603 0 : && ((lsa->header->type == OSPF6_LSTYPE_AS_EXTERNAL)
604 0 : || (lsa->header->type == OSPF6_LSTYPE_TYPE_7)
605 0 : || (lsa->header->type
606 : == OSPF6_LSTYPE_INTER_ROUTER))) {
607 0 : continue;
608 : }
609 :
610 0 : for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, nbr)) {
611 :
612 0 : ospf6_gr_helper_exit(nbr,
613 : OSPF6_GR_HELPER_TOPO_CHG);
614 : }
615 : }
616 : }
617 :
618 : /* Configuration handlers */
619 : /*
620 : * Disable/Enable HELPER support on router level.
621 : *
622 : * ospf6
623 : * Ospf6 pointer.
624 : *
625 : * status
626 : * TRUE/FALSE
627 : *
628 : * Returns:
629 : * Nothing.
630 : */
631 0 : static void ospf6_gr_helper_support_set(struct ospf6 *ospf6, bool support)
632 : {
633 0 : struct ospf6_interface *oi;
634 0 : struct advRtr lookup;
635 0 : struct listnode *i, *j, *k;
636 0 : struct ospf6_neighbor *nbr = NULL;
637 0 : struct ospf6_area *oa = NULL;
638 :
639 0 : if (ospf6->ospf6_helper_cfg.is_helper_supported == support)
640 0 : return;
641 :
642 0 : ospf6->ospf6_helper_cfg.is_helper_supported = support;
643 :
644 : /* If helper support disabled, cease HELPER role for all
645 : * supporting neighbors.
646 : */
647 0 : if (support == OSPF6_FALSE) {
648 0 : for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
649 0 : for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) {
650 :
651 0 : for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k,
652 : nbr)) {
653 :
654 0 : lookup.advRtrAddr = nbr->router_id;
655 : /* check if helper support enabled for
656 : * the corresponding routerid.
657 : * If enabled,
658 : * dont exit from helper role.
659 : */
660 0 : if (hash_lookup(
661 : ospf6->ospf6_helper_cfg
662 : .enable_rtr_list,
663 : &lookup))
664 0 : continue;
665 :
666 0 : ospf6_gr_helper_exit(
667 : nbr, OSPF6_GR_HELPER_TOPO_CHG);
668 : }
669 : }
670 : }
671 : }
672 :
673 : /*
674 : * Api to enable/disable strict lsa check on the HELPER.
675 : *
676 : * ospf6
677 : * Ospf6 pointer.
678 : *
679 : * enabled
680 : * True - disable the lsa check.
681 : * False - enable the strict lsa check.
682 : *
683 : * Returns:
684 : * Nothing.
685 : */
686 0 : static void ospf6_gr_helper_lsacheck_set(struct ospf6 *ospf6, bool enabled)
687 : {
688 0 : if (ospf6->ospf6_helper_cfg.strict_lsa_check == enabled)
689 : return;
690 :
691 0 : ospf6->ospf6_helper_cfg.strict_lsa_check = enabled;
692 : }
693 :
694 : /*
695 : * Api to set the supported restart reason.
696 : *
697 : * ospf6
698 : * Ospf6 pointer.
699 : *
700 : * only_planned
701 : * True: support only planned restart.
702 : * False: support for planned/unplanned restarts.
703 : *
704 : * Returns:
705 : * Nothing.
706 : */
707 :
708 : static void
709 0 : ospf6_gr_helper_set_supported_onlyPlanned_restart(struct ospf6 *ospf6,
710 : bool only_planned)
711 : {
712 0 : ospf6->ospf6_helper_cfg.only_planned_restart = only_planned;
713 : }
714 :
715 : /*
716 : * Api to set the supported grace interval in this router.
717 : *
718 : * ospf6
719 : * Ospf6 pointer.
720 : *
721 : * interval
722 : * The supported grace interval..
723 : *
724 : * Returns:
725 : * Nothing.
726 : */
727 0 : static void ospf6_gr_helper_supported_gracetime_set(struct ospf6 *ospf6,
728 : uint32_t interval)
729 : {
730 0 : ospf6->ospf6_helper_cfg.supported_grace_time = interval;
731 : }
732 :
733 : /* API to walk and print all the Helper supported router ids */
734 0 : static int ospf6_print_vty_helper_dis_rtr_walkcb(struct hash_bucket *bucket,
735 : void *arg)
736 : {
737 0 : struct advRtr *rtr = bucket->data;
738 0 : struct vty *vty = (struct vty *)arg;
739 0 : static unsigned int count;
740 :
741 0 : vty_out(vty, "%-6pI4,", &rtr->advRtrAddr);
742 0 : count++;
743 :
744 0 : if (count % 5 == 0)
745 0 : vty_out(vty, "\n");
746 :
747 0 : return HASHWALK_CONTINUE;
748 : }
749 :
750 : /* API to walk and print all the Helper supported router ids.*/
751 0 : static int ospf6_print_json_helper_dis_rtr_walkcb(struct hash_bucket *bucket,
752 : void *arg)
753 : {
754 0 : struct advRtr *rtr = bucket->data;
755 0 : struct json_object *json_rid_array = (struct json_object *)arg;
756 0 : struct json_object *json_rid;
757 0 : char router_id[16];
758 :
759 0 : inet_ntop(AF_INET, &rtr->advRtrAddr, router_id, sizeof(router_id));
760 :
761 0 : json_rid = json_object_new_object();
762 :
763 0 : json_object_string_add(json_rid, "routerId", router_id);
764 0 : json_object_array_add(json_rid_array, json_rid);
765 :
766 0 : return HASHWALK_CONTINUE;
767 : }
768 :
769 : /*
770 : * Enable/Disable HELPER support on a specified advertisement
771 : * router.
772 : *
773 : * ospf6
774 : * Ospf6 pointer.
775 : *
776 : * advRtr
777 : * HELPER support for given Advertisement Router.
778 : *
779 : * support
780 : * True - Enable Helper Support.
781 : * False - Disable Helper Support.
782 : *
783 : * Returns:
784 : * Nothing.
785 : */
786 0 : static void ospf6_gr_helper_support_set_per_routerid(struct ospf6 *ospf6,
787 : struct in_addr router_id,
788 : bool support)
789 : {
790 0 : struct advRtr temp;
791 0 : struct advRtr *rtr;
792 0 : struct listnode *i, *j, *k;
793 0 : struct ospf6_interface *oi;
794 0 : struct ospf6_neighbor *nbr;
795 0 : struct ospf6_area *oa;
796 :
797 0 : temp.advRtrAddr = router_id.s_addr;
798 :
799 0 : if (support == OSPF6_FALSE) {
800 : /*Delete the routerid from the enable router hash table */
801 0 : rtr = hash_lookup(ospf6->ospf6_helper_cfg.enable_rtr_list,
802 : &temp);
803 :
804 0 : if (rtr) {
805 0 : hash_release(ospf6->ospf6_helper_cfg.enable_rtr_list,
806 : rtr);
807 0 : ospf6_disable_rtr_hash_free(rtr);
808 : }
809 :
810 : /* If helper support is enabled globally
811 : * no action is required.
812 : */
813 0 : if (ospf6->ospf6_helper_cfg.is_helper_supported)
814 0 : return;
815 :
816 : /* Cease the HELPER role fore neighbours from the
817 : * specified advertisement router.
818 : */
819 0 : for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
820 0 : for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) {
821 :
822 0 : for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k,
823 : nbr)) {
824 :
825 0 : if (nbr->router_id != router_id.s_addr)
826 0 : continue;
827 :
828 0 : if (OSPF6_GR_IS_ACTIVE_HELPER(nbr))
829 0 : ospf6_gr_helper_exit(
830 : nbr,
831 : OSPF6_GR_HELPER_TOPO_CHG);
832 : }
833 : }
834 :
835 : } else {
836 : /* Add the routerid to the enable router hash table */
837 0 : (void)hash_get(ospf6->ospf6_helper_cfg.enable_rtr_list, &temp,
838 : ospf6_enable_rtr_hash_alloc);
839 : }
840 : }
841 :
842 0 : static void show_ospfv6_gr_helper_per_nbr(struct vty *vty, json_object *json,
843 : bool uj, struct ospf6_neighbor *nbr)
844 : {
845 0 : if (!uj) {
846 0 : vty_out(vty, " Routerid : %pI4\n", &nbr->router_id);
847 0 : vty_out(vty, " Received Grace period : %d(in seconds).\n",
848 : nbr->gr_helper_info.recvd_grace_period);
849 0 : vty_out(vty, " Actual Grace period : %d(in seconds)\n",
850 : nbr->gr_helper_info.actual_grace_period);
851 0 : vty_out(vty, " Remaining GraceTime:%ld(in seconds).\n",
852 : thread_timer_remain_second(
853 : nbr->gr_helper_info.t_grace_timer));
854 0 : vty_out(vty, " Graceful Restart reason: %s.\n\n",
855 : ospf6_restart_reason_desc[nbr->gr_helper_info
856 0 : .gr_restart_reason]);
857 : } else {
858 0 : char nbrid[16];
859 0 : json_object *json_neigh = NULL;
860 :
861 0 : inet_ntop(AF_INET, &nbr->router_id, nbrid, sizeof(nbrid));
862 0 : json_neigh = json_object_new_object();
863 0 : json_object_string_add(json_neigh, "routerid", nbrid);
864 0 : json_object_int_add(json_neigh, "recvdGraceInterval",
865 0 : nbr->gr_helper_info.recvd_grace_period);
866 0 : json_object_int_add(json_neigh, "actualGraceInterval",
867 0 : nbr->gr_helper_info.actual_grace_period);
868 0 : json_object_int_add(json_neigh, "remainGracetime",
869 0 : thread_timer_remain_second(
870 : nbr->gr_helper_info.t_grace_timer));
871 0 : json_object_string_add(json_neigh, "restartReason",
872 : ospf6_restart_reason_desc[
873 0 : nbr->gr_helper_info.gr_restart_reason]);
874 0 : json_object_object_add(json, nbr->name, json_neigh);
875 : }
876 0 : }
877 :
878 0 : static void show_ospf6_gr_helper_details(struct vty *vty, struct ospf6 *ospf6,
879 : json_object *json, bool uj, bool detail)
880 : {
881 0 : struct ospf6_interface *oi;
882 :
883 : /* Show Router ID. */
884 0 : if (uj) {
885 0 : char router_id[16];
886 :
887 0 : inet_ntop(AF_INET, &ospf6->router_id, router_id,
888 : sizeof(router_id));
889 0 : json_object_string_add(json, "routerId", router_id);
890 : } else
891 0 : vty_out(vty,
892 : " OSPFv3 Routing Process (0) with Router-ID %pI4\n",
893 : &ospf6->router_id);
894 :
895 0 : if (!uj) {
896 :
897 0 : if (ospf6->ospf6_helper_cfg.is_helper_supported)
898 0 : vty_out(vty,
899 : " Graceful restart helper support enabled.\n");
900 : else
901 0 : vty_out(vty,
902 : " Graceful restart helper support disabled.\n");
903 :
904 0 : if (ospf6->ospf6_helper_cfg.strict_lsa_check)
905 0 : vty_out(vty, " Strict LSA check is enabled.\n");
906 : else
907 0 : vty_out(vty, " Strict LSA check is disabled.\n");
908 :
909 0 : if (ospf6->ospf6_helper_cfg.only_planned_restart)
910 0 : vty_out(vty,
911 : " Helper supported for planned restarts only.\n");
912 : else
913 0 : vty_out(vty,
914 : " Helper supported for Planned and Unplanned Restarts.\n");
915 :
916 0 : vty_out(vty,
917 : " Supported Graceful restart interval: %d(in seconds).\n",
918 : ospf6->ospf6_helper_cfg.supported_grace_time);
919 :
920 0 : if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf)) {
921 0 : vty_out(vty, " Enable Router list:\n");
922 0 : vty_out(vty, " ");
923 0 : hash_walk(ospf6->ospf6_helper_cfg.enable_rtr_list,
924 : ospf6_print_vty_helper_dis_rtr_walkcb, vty);
925 0 : vty_out(vty, "\n\n");
926 : }
927 :
928 0 : if (ospf6->ospf6_helper_cfg.last_exit_reason
929 : != OSPF6_GR_HELPER_EXIT_NONE) {
930 0 : vty_out(vty, " Last Helper exit Reason :%s\n",
931 : ospf6_exit_reason_desc
932 : [ospf6->ospf6_helper_cfg
933 : .last_exit_reason]);
934 :
935 0 : if (ospf6->ospf6_helper_cfg.active_restarter_cnt)
936 0 : vty_out(vty,
937 : " Number of Active neighbours in graceful restart: %d\n",
938 : ospf6->ospf6_helper_cfg
939 : .active_restarter_cnt);
940 : else
941 0 : vty_out(vty, "\n");
942 : }
943 :
944 :
945 : } else {
946 0 : json_object_string_add(
947 : json, "helperSupport",
948 0 : (ospf6->ospf6_helper_cfg.is_helper_supported)
949 : ? "Enabled"
950 : : "Disabled");
951 0 : json_object_string_add(
952 : json, "strictLsaCheck",
953 0 : (ospf6->ospf6_helper_cfg.strict_lsa_check)
954 : ? "Enabled"
955 : : "Disabled");
956 0 : json_object_string_add(
957 : json, "restartSupoort",
958 0 : (ospf6->ospf6_helper_cfg.only_planned_restart)
959 : ? "Planned Restart only"
960 : : "Planned and Unplanned Restarts");
961 :
962 0 : json_object_int_add(
963 : json, "supportedGracePeriod",
964 0 : ospf6->ospf6_helper_cfg.supported_grace_time);
965 :
966 0 : if (ospf6->ospf6_helper_cfg.last_exit_reason !=
967 : OSPF6_GR_HELPER_EXIT_NONE)
968 0 : json_object_string_add(
969 : json, "lastExitReason",
970 : ospf6_exit_reason_desc
971 : [ospf6->ospf6_helper_cfg
972 : .last_exit_reason]);
973 :
974 0 : if (ospf6->ospf6_helper_cfg.active_restarter_cnt)
975 0 : json_object_int_add(
976 : json, "activeRestarterCnt",
977 : ospf6->ospf6_helper_cfg.active_restarter_cnt);
978 :
979 0 : if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6)) {
980 0 : struct json_object *json_rid_array =
981 0 : json_object_new_array();
982 :
983 0 : json_object_object_add(json, "enabledRouterIds",
984 : json_rid_array);
985 :
986 0 : hash_walk(ospf6->ospf6_helper_cfg.enable_rtr_list,
987 : ospf6_print_json_helper_dis_rtr_walkcb,
988 : json_rid_array);
989 : }
990 : }
991 :
992 0 : if (detail) {
993 0 : int cnt = 1;
994 0 : struct listnode *i, *j, *k;
995 0 : struct ospf6_area *oa;
996 0 : json_object *json_neighbors = NULL;
997 :
998 0 : for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
999 0 : for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) {
1000 0 : struct ospf6_neighbor *nbr;
1001 :
1002 0 : if (uj) {
1003 0 : json_object_object_get_ex(
1004 : json, "neighbors",
1005 : &json_neighbors);
1006 0 : if (!json_neighbors) {
1007 0 : json_neighbors =
1008 0 : json_object_new_object();
1009 0 : json_object_object_add(
1010 : json, "neighbors",
1011 : json_neighbors);
1012 : }
1013 : }
1014 :
1015 0 : for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k,
1016 : nbr)) {
1017 :
1018 0 : if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr))
1019 0 : continue;
1020 :
1021 0 : if (!uj)
1022 0 : vty_out(vty,
1023 : " Neighbour %d :\n",
1024 : cnt++);
1025 :
1026 0 : show_ospfv6_gr_helper_per_nbr(
1027 : vty, json_neighbors, uj, nbr);
1028 :
1029 : }
1030 : }
1031 : }
1032 0 : }
1033 :
1034 : /* Graceful Restart HELPER config Commands */
1035 0 : DEFPY(ospf6_gr_helper_enable,
1036 : ospf6_gr_helper_enable_cmd,
1037 : "graceful-restart helper enable [A.B.C.D$rtr_id]",
1038 : "ospf6 graceful restart\n"
1039 : "ospf6 GR Helper\n"
1040 : "Enable Helper support\n"
1041 : "Advertisement Router-ID\n")
1042 : {
1043 0 : VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1044 :
1045 0 : if (rtr_id_str != NULL) {
1046 :
1047 0 : ospf6_gr_helper_support_set_per_routerid(ospf6, rtr_id,
1048 : OSPF6_TRUE);
1049 :
1050 0 : return CMD_SUCCESS;
1051 : }
1052 :
1053 0 : ospf6_gr_helper_support_set(ospf6, OSPF6_TRUE);
1054 :
1055 0 : return CMD_SUCCESS;
1056 : }
1057 :
1058 0 : DEFPY(ospf6_gr_helper_disable,
1059 : ospf6_gr_helper_disable_cmd,
1060 : "no graceful-restart helper enable [A.B.C.D$rtr_id]",
1061 : NO_STR
1062 : "ospf6 graceful restart\n"
1063 : "ospf6 GR Helper\n"
1064 : "Enable Helper support\n"
1065 : "Advertisement Router-ID\n")
1066 : {
1067 0 : VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1068 :
1069 0 : if (rtr_id_str != NULL) {
1070 :
1071 0 : ospf6_gr_helper_support_set_per_routerid(ospf6, rtr_id,
1072 : OSPF6_FALSE);
1073 :
1074 0 : return CMD_SUCCESS;
1075 : }
1076 :
1077 0 : ospf6_gr_helper_support_set(ospf6, OSPF6_FALSE);
1078 :
1079 0 : return CMD_SUCCESS;
1080 : }
1081 :
1082 0 : DEFPY(ospf6_gr_helper_disable_lsacheck,
1083 : ospf6_gr_helper_disable_lsacheck_cmd,
1084 : "graceful-restart helper lsa-check-disable",
1085 : "ospf6 graceful restart\n"
1086 : "ospf6 GR Helper\n"
1087 : "disable strict LSA check\n")
1088 : {
1089 0 : VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1090 :
1091 0 : ospf6_gr_helper_lsacheck_set(ospf6, OSPF6_FALSE);
1092 : return CMD_SUCCESS;
1093 : }
1094 :
1095 0 : DEFPY(no_ospf6_gr_helper_disable_lsacheck,
1096 : no_ospf6_gr_helper_disable_lsacheck_cmd,
1097 : "no graceful-restart helper lsa-check-disable",
1098 : NO_STR
1099 : "ospf6 graceful restart\n"
1100 : "ospf6 GR Helper\n"
1101 : "diasble strict LSA check\n")
1102 : {
1103 0 : VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1104 :
1105 0 : ospf6_gr_helper_lsacheck_set(ospf6, OSPF6_TRUE);
1106 : return CMD_SUCCESS;
1107 : }
1108 :
1109 0 : DEFPY(ospf6_gr_helper_planned_only,
1110 : ospf6_gr_helper_planned_only_cmd,
1111 : "graceful-restart helper planned-only",
1112 : "ospf6 graceful restart\n"
1113 : "ospf6 GR Helper\n"
1114 : "supported only planned restart\n")
1115 : {
1116 0 : VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1117 :
1118 0 : ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6, OSPF6_TRUE);
1119 :
1120 0 : return CMD_SUCCESS;
1121 : }
1122 :
1123 0 : DEFPY(no_ospf6_gr_helper_planned_only, no_ospf6_gr_helper_planned_only_cmd,
1124 : "no graceful-restart helper planned-only",
1125 : NO_STR
1126 : "ospf6 graceful restart\n"
1127 : "ospf6 GR Helper\n"
1128 : "supported only for planned restart\n")
1129 : {
1130 0 : VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1131 :
1132 0 : ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6, OSPF6_FALSE);
1133 :
1134 0 : return CMD_SUCCESS;
1135 : }
1136 :
1137 0 : DEFPY(ospf6_gr_helper_supported_grace_time,
1138 : ospf6_gr_helper_supported_grace_time_cmd,
1139 : "graceful-restart helper supported-grace-time (10-1800)$interval",
1140 : "ospf6 graceful restart\n"
1141 : "ospf6 GR Helper\n"
1142 : "supported grace timer\n"
1143 : "grace interval(in seconds)\n")
1144 : {
1145 0 : VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1146 :
1147 0 : ospf6_gr_helper_supported_gracetime_set(ospf6, interval);
1148 0 : return CMD_SUCCESS;
1149 : }
1150 :
1151 0 : DEFPY(no_ospf6_gr_helper_supported_grace_time,
1152 : no_ospf6_gr_helper_supported_grace_time_cmd,
1153 : "no graceful-restart helper supported-grace-time (10-1800)$interval",
1154 : NO_STR
1155 : "ospf6 graceful restart\n"
1156 : "ospf6 GR Helper\n"
1157 : "supported grace timer\n"
1158 : "grace interval(in seconds)\n")
1159 : {
1160 0 : VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1161 :
1162 0 : ospf6_gr_helper_supported_gracetime_set(ospf6,
1163 : OSPF6_MAX_GRACE_INTERVAL);
1164 0 : return CMD_SUCCESS;
1165 : }
1166 :
1167 : /* Show commands */
1168 0 : DEFPY(show_ipv6_ospf6_gr_helper,
1169 : show_ipv6_ospf6_gr_helper_cmd,
1170 : "show ipv6 ospf6 graceful-restart helper [detail] [json]",
1171 : SHOW_STR
1172 : "Ipv6 Information\n"
1173 : "OSPF6 information\n"
1174 : "ospf6 graceful restart\n"
1175 : "helper details in the router\n"
1176 : "detailed information\n" JSON_STR)
1177 : {
1178 0 : int idx = 0;
1179 0 : bool uj = use_json(argc, argv);
1180 0 : struct ospf6 *ospf6 = NULL;
1181 0 : json_object *json = NULL;
1182 0 : bool detail = false;
1183 :
1184 0 : ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
1185 0 : if (ospf6 == NULL) {
1186 0 : vty_out(vty, "OSPFv3 is not configured\n");
1187 0 : return CMD_SUCCESS;
1188 : }
1189 :
1190 0 : if (argv_find(argv, argc, "detail", &idx))
1191 0 : detail = true;
1192 :
1193 0 : if (uj)
1194 0 : json = json_object_new_object();
1195 :
1196 0 : show_ospf6_gr_helper_details(vty, ospf6, json, uj, detail);
1197 :
1198 0 : if (uj)
1199 0 : vty_json(vty, json);
1200 :
1201 : return CMD_SUCCESS;
1202 : }
1203 :
1204 : /* Debug commands */
1205 0 : DEFPY(debug_ospf6_gr, debug_ospf6_gr_cmd,
1206 : "[no$no] debug ospf6 graceful-restart",
1207 : NO_STR DEBUG_STR OSPF6_STR "Graceful restart\n")
1208 : {
1209 0 : if (!no)
1210 0 : OSPF6_DEBUG_GR_ON();
1211 : else
1212 0 : OSPF6_DEBUG_GR_OFF();
1213 :
1214 0 : return CMD_SUCCESS;
1215 : }
1216 :
1217 : /*
1218 : * Api to display the grace LSA information.
1219 : *
1220 : * vty
1221 : * vty pointer.
1222 : * lsa
1223 : * Grace LSA.
1224 : * json
1225 : * json object
1226 : *
1227 : * Returns:
1228 : * Nothing.
1229 : */
1230 0 : static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa,
1231 : json_object *json, bool use_json)
1232 : {
1233 0 : struct ospf6_lsa_header *lsah = NULL;
1234 0 : struct tlv_header *tlvh = NULL;
1235 0 : struct grace_tlv_graceperiod *gracePeriod;
1236 0 : struct grace_tlv_restart_reason *grReason;
1237 0 : uint16_t length = 0;
1238 0 : int sum = 0;
1239 :
1240 0 : lsah = (struct ospf6_lsa_header *)lsa->header;
1241 0 : if (ntohs(lsah->length) <= OSPF6_LSA_HEADER_SIZE) {
1242 0 : if (IS_DEBUG_OSPF6_GR)
1243 0 : zlog_debug("%s: undersized (%u B) lsa", __func__,
1244 : ntohs(lsah->length));
1245 0 : return OSPF6_FAILURE;
1246 : }
1247 :
1248 0 : length = ntohs(lsah->length) - OSPF6_LSA_HEADER_SIZE;
1249 :
1250 0 : if (vty) {
1251 0 : if (!use_json)
1252 0 : vty_out(vty, "TLV info:\n");
1253 : } else {
1254 0 : zlog_debug(" TLV info:");
1255 : }
1256 :
1257 0 : for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
1258 0 : tlvh = TLV_HDR_NEXT(tlvh)) {
1259 :
1260 : /* Check TLV len */
1261 0 : if (sum + TLV_SIZE(tlvh) > length) {
1262 0 : if (vty)
1263 0 : vty_out(vty, "%% Invalid TLV length: %d\n",
1264 0 : TLV_SIZE(tlvh));
1265 0 : else if (IS_DEBUG_OSPF6_GR)
1266 0 : zlog_debug("%% Invalid TLV length: %d",
1267 : TLV_SIZE(tlvh));
1268 0 : return OSPF6_FAILURE;
1269 : }
1270 :
1271 0 : switch (ntohs(tlvh->type)) {
1272 0 : case GRACE_PERIOD_TYPE:
1273 0 : gracePeriod = (struct grace_tlv_graceperiod *)tlvh;
1274 0 : sum += TLV_SIZE(tlvh);
1275 :
1276 0 : if (vty) {
1277 0 : if (use_json)
1278 0 : json_object_int_add(
1279 : json, "gracePeriod",
1280 0 : ntohl(gracePeriod->interval));
1281 : else
1282 0 : vty_out(vty, " Grace period:%d\n",
1283 : ntohl(gracePeriod->interval));
1284 : } else {
1285 0 : zlog_debug(" Grace period:%d",
1286 : ntohl(gracePeriod->interval));
1287 : }
1288 : break;
1289 0 : case RESTART_REASON_TYPE:
1290 0 : grReason = (struct grace_tlv_restart_reason *)tlvh;
1291 0 : sum += TLV_SIZE(tlvh);
1292 0 : if (vty) {
1293 0 : if (use_json)
1294 0 : json_object_string_add(
1295 : json, "restartReason",
1296 : ospf6_restart_reason_desc
1297 0 : [grReason->reason]);
1298 : else
1299 0 : vty_out(vty, " Restart reason:%s\n",
1300 : ospf6_restart_reason_desc
1301 0 : [grReason->reason]);
1302 : } else {
1303 0 : zlog_debug(" Restart reason:%s",
1304 : ospf6_restart_reason_desc
1305 : [grReason->reason]);
1306 : }
1307 : break;
1308 : default:
1309 : break;
1310 : }
1311 : }
1312 :
1313 : return 0;
1314 : }
1315 :
1316 16 : void ospf6_gr_helper_config_init(void)
1317 : {
1318 :
1319 16 : ospf6_install_lsa_handler(&grace_lsa_handler);
1320 :
1321 16 : install_element(OSPF6_NODE, &ospf6_gr_helper_enable_cmd);
1322 16 : install_element(OSPF6_NODE, &ospf6_gr_helper_disable_cmd);
1323 16 : install_element(OSPF6_NODE, &ospf6_gr_helper_disable_lsacheck_cmd);
1324 16 : install_element(OSPF6_NODE, &no_ospf6_gr_helper_disable_lsacheck_cmd);
1325 16 : install_element(OSPF6_NODE, &ospf6_gr_helper_planned_only_cmd);
1326 16 : install_element(OSPF6_NODE, &no_ospf6_gr_helper_planned_only_cmd);
1327 16 : install_element(OSPF6_NODE, &ospf6_gr_helper_supported_grace_time_cmd);
1328 16 : install_element(OSPF6_NODE,
1329 : &no_ospf6_gr_helper_supported_grace_time_cmd);
1330 :
1331 16 : install_element(VIEW_NODE, &show_ipv6_ospf6_gr_helper_cmd);
1332 :
1333 16 : install_element(CONFIG_NODE, &debug_ospf6_gr_cmd);
1334 16 : install_element(ENABLE_NODE, &debug_ospf6_gr_cmd);
1335 16 : }
1336 :
1337 :
1338 : /*
1339 : * Initialize GR helper config data structure.
1340 : *
1341 : * ospf6
1342 : * ospf6 pointer
1343 : *
1344 : * Returns:
1345 : * Nothing
1346 : */
1347 16 : void ospf6_gr_helper_init(struct ospf6 *ospf6)
1348 : {
1349 16 : if (IS_DEBUG_OSPF6_GR)
1350 0 : zlog_debug("%s, GR Helper init.", __func__);
1351 :
1352 16 : ospf6->ospf6_helper_cfg.is_helper_supported = OSPF6_FALSE;
1353 16 : ospf6->ospf6_helper_cfg.strict_lsa_check = OSPF6_TRUE;
1354 16 : ospf6->ospf6_helper_cfg.only_planned_restart = OSPF6_FALSE;
1355 16 : ospf6->ospf6_helper_cfg.supported_grace_time = OSPF6_MAX_GRACE_INTERVAL;
1356 16 : ospf6->ospf6_helper_cfg.last_exit_reason = OSPF6_GR_HELPER_EXIT_NONE;
1357 16 : ospf6->ospf6_helper_cfg.active_restarter_cnt = 0;
1358 :
1359 16 : ospf6->ospf6_helper_cfg.enable_rtr_list = hash_create(
1360 : ospf6_enable_rtr_hash_key, ospf6_enable_rtr_hash_cmp,
1361 : "Ospf6 enable router hash");
1362 16 : }
1363 :
1364 : /*
1365 : * De-initialize GR helper config data structure.
1366 : *
1367 : * ospf6
1368 : * ospf6 pointer
1369 : *
1370 : * Returns:
1371 : * Nothing
1372 : */
1373 16 : void ospf6_gr_helper_deinit(struct ospf6 *ospf6)
1374 : {
1375 :
1376 16 : if (IS_DEBUG_OSPF6_GR)
1377 0 : zlog_debug("%s, GR helper deinit.", __func__);
1378 :
1379 16 : ospf6_enable_rtr_hash_destroy(ospf6);
1380 16 : }
1381 :
1382 0 : static int ospf6_cfg_write_helper_enable_rtr_walkcb(struct hash_bucket *backet,
1383 : void *arg)
1384 : {
1385 0 : struct advRtr *rtr = backet->data;
1386 0 : struct vty *vty = (struct vty *)arg;
1387 :
1388 0 : vty_out(vty, " graceful-restart helper enable %pI4\n", &rtr->advRtrAddr);
1389 0 : return HASHWALK_CONTINUE;
1390 : }
1391 :
1392 0 : int config_write_ospf6_gr_helper(struct vty *vty, struct ospf6 *ospf6)
1393 : {
1394 0 : if (ospf6->ospf6_helper_cfg.is_helper_supported)
1395 0 : vty_out(vty, " graceful-restart helper enable\n");
1396 :
1397 0 : if (!ospf6->ospf6_helper_cfg.strict_lsa_check)
1398 0 : vty_out(vty, " graceful-restart helper lsa-check-disable\n");
1399 :
1400 0 : if (ospf6->ospf6_helper_cfg.only_planned_restart)
1401 0 : vty_out(vty, " graceful-restart helper planned-only\n");
1402 :
1403 0 : if (ospf6->ospf6_helper_cfg.supported_grace_time
1404 : != OSPF6_MAX_GRACE_INTERVAL)
1405 0 : vty_out(vty,
1406 : " graceful-restart helper supported-grace-time %d\n",
1407 : ospf6->ospf6_helper_cfg.supported_grace_time);
1408 :
1409 0 : if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6)) {
1410 0 : hash_walk(ospf6->ospf6_helper_cfg.enable_rtr_list,
1411 : ospf6_cfg_write_helper_enable_rtr_walkcb, vty);
1412 : }
1413 :
1414 0 : return 0;
1415 : }
1416 :
1417 0 : int config_write_ospf6_debug_gr_helper(struct vty *vty)
1418 : {
1419 0 : if (IS_DEBUG_OSPF6_GR)
1420 0 : vty_out(vty, "debug ospf6 graceful-restart\n");
1421 0 : return 0;
1422 : }
|