]> git.proxmox.com Git - mirror_frr.git/blame - ospfd/ospf_gr_helper.c
Merge pull request #10447 from ton31337/fix/json_with_whitespaces
[mirror_frr.git] / ospfd / ospf_gr_helper.c
CommitLineData
06bc3110 1/*
2 * OSPF Graceful Restart helper functions.
3 *
4 * Copyright (C) 2020-21 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 "thread.h"
27#include "memory.h"
28#include "linklist.h"
29#include "prefix.h"
30#include "if.h"
31#include "table.h"
32#include "vty.h"
33#include "filter.h"
34#include "log.h"
35#include "jhash.h"
36
37#include "ospfd/ospfd.h"
38#include "ospfd/ospf_interface.h"
39#include "ospfd/ospf_asbr.h"
40#include "ospfd/ospf_lsa.h"
41#include "ospfd/ospf_lsdb.h"
42#include "ospfd/ospf_neighbor.h"
43#include "ospfd/ospf_spf.h"
44#include "ospfd/ospf_flood.h"
45#include "ospfd/ospf_route.h"
46#include "ospfd/ospf_zebra.h"
47#include "ospfd/ospf_dump.h"
48#include "ospfd/ospf_errors.h"
49#include "ospfd/ospf_nsm.h"
50#include "ospfd/ospf_ism.h"
cd52c44c 51#include "ospfd/ospf_gr.h"
06bc3110 52
d05d5280 53static const char * const ospf_exit_reason_desc[] = {
ad686992 54 "Unknown reason",
98cb53f9 55 "Helper in progress",
ad686992 56 "Topology Change",
d05d5280 57 "Grace timer expiry",
ad686992 58 "Successful graceful restart",
59};
60
d05d5280 61static const char * const ospf_restart_reason_desc[] = {
ad686992 62 "Unknown restart",
63 "Software restart",
64 "Software reload/upgrade",
65 "Switch to redundant control processor",
66};
67
d05d5280 68static const char * const ospf_rejected_reason_desc[] = {
ad686992 69 "Unknown reason",
70 "Helper support disabled",
71 "Neighbour is not in FULL state",
d05d5280 72 "Supports only planned restart but received unplanned",
ad686992 73 "Topo change due to change in lsa rxmt list",
74 "LSA age is more than Grace interval",
10514170 75 "Router is in the process of graceful restart",
ad686992 76};
77
3e63092b
RW
78static void show_ospf_grace_lsa_info(struct vty *vty, struct json_object *json,
79 struct ospf_lsa *lsa);
ad686992 80static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr);
06bc3110 81
82static unsigned int ospf_enable_rtr_hash_key(const void *data)
83{
84 const struct advRtr *rtr = data;
85
86 return jhash_1word(rtr->advRtrAddr.s_addr, 0);
87}
88
89static bool ospf_enable_rtr_hash_cmp(const void *d1, const void *d2)
90{
91 const struct advRtr *rtr1 = (struct advRtr *)d1;
92 const struct advRtr *rtr2 = (struct advRtr *)d2;
93
94 return (rtr1->advRtrAddr.s_addr == rtr2->advRtrAddr.s_addr);
95}
96
97static void *ospf_enable_rtr_hash_alloc(void *p)
98{
99 struct advRtr *rid;
100
101 rid = XCALLOC(MTYPE_OSPF_GR_HELPER, sizeof(struct advRtr));
102 rid->advRtrAddr.s_addr = ((struct in_addr *)p)->s_addr;
103
104 return rid;
105}
106
107static void ospf_disable_rtr_hash_free(void *rtr)
108{
109 XFREE(MTYPE_OSPF_GR_HELPER, rtr);
110}
111
112static void ospf_enable_rtr_hash_destroy(struct ospf *ospf)
113{
114 if (ospf->enable_rtr_list == NULL)
115 return;
116
117 hash_clean(ospf->enable_rtr_list, ospf_disable_rtr_hash_free);
118 hash_free(ospf->enable_rtr_list);
119 ospf->enable_rtr_list = NULL;
120}
121
d05d5280
MS
122/*
123 * GR exit reason strings
124 */
125const char *ospf_exit_reason2str(unsigned int reason)
126{
127 if (reason < array_size(ospf_exit_reason_desc))
128 return(ospf_exit_reason_desc[reason]);
129 else
130 return "Invalid reason";
131}
132
133/*
134 * GR restart reason strings
135 */
136const char *ospf_restart_reason2str(unsigned int reason)
137{
138 if (reason < array_size(ospf_restart_reason_desc))
139 return(ospf_restart_reason_desc[reason]);
140 else
141 return "Invalid reason";
142}
143
144/*
145 * GR rejected reason strings
146 */
147const char *ospf_rejected_reason2str(unsigned int reason)
148{
149 if (reason < array_size(ospf_rejected_reason_desc))
150 return(ospf_rejected_reason_desc[reason]);
151 else
152 return "Invalid reason";
153}
154
06bc3110 155/*
156 * Initialize GR helper config data structures.
157 *
158 * OSPF
159 * OSPF pointer
160 *
161 * Returns:
162 * Nothing
163 */
51f8588e 164void ospf_gr_helper_instance_init(struct ospf *ospf)
06bc3110 165{
3f87e1d8 166 if (IS_DEBUG_OSPF_GR)
a4544597 167 zlog_debug("%s, GR Helper init.", __func__);
06bc3110 168
ad686992 169 ospf->is_helper_supported = OSPF_GR_FALSE;
170 ospf->strict_lsa_check = OSPF_GR_TRUE;
171 ospf->only_planned_restart = OSPF_GR_FALSE;
06bc3110 172 ospf->supported_grace_time = OSPF_MAX_GRACE_INTERVAL;
173 ospf->last_exit_reason = OSPF_GR_HELPER_EXIT_NONE;
174 ospf->active_restarter_cnt = 0;
175
176 ospf->enable_rtr_list =
177 hash_create(ospf_enable_rtr_hash_key, ospf_enable_rtr_hash_cmp,
178 "OSPF enable router hash");
51f8588e
RW
179}
180
181/*
182 * De-Initialize GR helper config data structures.
183 *
184 * OSPF
185 * OSPF pointer
186 *
187 * Returns:
188 * Nothing
189 */
190void ospf_gr_helper_instance_stop(struct ospf *ospf)
191{
3f87e1d8 192 if (IS_DEBUG_OSPF_GR)
51f8588e
RW
193 zlog_debug("%s, GR helper deinit.", __func__);
194
195 ospf_enable_rtr_hash_destroy(ospf);
196}
197
198/*
199 * Initialize GR helper config data structures.
200 *
201 * Returns:
202 * Nothing
203 */
204void ospf_gr_helper_init(void)
205{
206 int rc;
207
3f87e1d8 208 if (IS_DEBUG_OSPF_GR)
51f8588e 209 zlog_debug("%s, GR Helper init.", __func__);
abd5b8c7 210
211 rc = ospf_register_opaque_functab(
212 OSPF_OPAQUE_LINK_LSA, OPAQUE_TYPE_GRACE_LSA, NULL, NULL, NULL,
213 NULL, NULL, NULL, NULL, show_ospf_grace_lsa_info, NULL, NULL,
214 NULL, NULL);
215 if (rc != 0) {
216 flog_warn(EC_OSPF_OPAQUE_REGISTRATION,
217 "%s: Failed to register Grace LSA functions",
218 __func__);
219 }
06bc3110 220}
221
222/*
223 * De-Initialize GR helper config data structures.
224 *
06bc3110 225 * Returns:
226 * Nothing
227 */
51f8588e 228void ospf_gr_helper_stop(void)
06bc3110 229{
3f87e1d8 230 if (IS_DEBUG_OSPF_GR)
a4544597 231 zlog_debug("%s, GR helper deinit.", __func__);
06bc3110 232
abd5b8c7 233 ospf_delete_opaque_functab(OSPF_OPAQUE_LINK_LSA, OPAQUE_TYPE_GRACE_LSA);
06bc3110 234}
ad686992 235
236/*
237 * Extracting tlv info from GRACE LSA.
238 *
239 * lsa
240 * ospf grace lsa
241 *
242 * Returns:
243 * interval : grace interval.
244 * addr : RESTARTER address.
245 * reason : Restarting reason.
246 */
247static int ospf_extract_grace_lsa_fields(struct ospf_lsa *lsa,
248 uint32_t *interval,
249 struct in_addr *addr, uint8_t *reason)
250{
251 struct lsa_header *lsah = NULL;
252 struct tlv_header *tlvh = NULL;
253 struct grace_tlv_graceperiod *grace_period;
254 struct grace_tlv_restart_reason *gr_reason;
255 struct grace_tlv_restart_addr *restart_addr;
256 uint16_t length = 0;
257 int sum = 0;
258
259 lsah = (struct lsa_header *)lsa->data;
260
d8193748 261 /* Check LSA len */
8db278b5 262 if (lsa->size <= OSPF_LSA_HEADER_SIZE) {
3f87e1d8 263 if (IS_DEBUG_OSPF_GR)
d8193748
MS
264 zlog_debug("%s: Malformed packet: Invalid LSA len:%d",
265 __func__, length);
266 return OSPF_GR_FAILURE;
267 }
268
8db278b5 269 length = lsa->size - OSPF_LSA_HEADER_SIZE;
ad686992 270
8db278b5 271 for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
ad686992 272 tlvh = TLV_HDR_NEXT(tlvh)) {
d8193748
MS
273
274 /* Check TLV len against overall LSA */
275 if (sum + TLV_SIZE(tlvh) > length) {
3f87e1d8 276 if (IS_DEBUG_OSPF_GR)
72327cf3 277 zlog_debug("%s: Malformed packet: Invalid TLV len:%u",
d8193748
MS
278 __func__, TLV_SIZE(tlvh));
279 return OSPF_GR_FAILURE;
280 }
281
ad686992 282 switch (ntohs(tlvh->type)) {
283 case GRACE_PERIOD_TYPE:
d8193748
MS
284 if (TLV_SIZE(tlvh) <
285 sizeof(struct grace_tlv_graceperiod)) {
72327cf3 286 zlog_debug("%s: Malformed packet: Invalid grace TLV len:%u",
d8193748
MS
287 __func__, TLV_SIZE(tlvh));
288 return OSPF_GR_FAILURE;
289 }
290
ad686992 291 grace_period = (struct grace_tlv_graceperiod *)tlvh;
292 *interval = ntohl(grace_period->interval);
293 sum += TLV_SIZE(tlvh);
294
295 /* Check if grace interval is valid */
296 if (*interval > OSPF_MAX_GRACE_INTERVAL
297 || *interval < OSPF_MIN_GRACE_INTERVAL)
298 return OSPF_GR_FAILURE;
299 break;
300 case RESTART_REASON_TYPE:
d8193748
MS
301 if (TLV_SIZE(tlvh) <
302 sizeof(struct grace_tlv_restart_reason)) {
72327cf3 303 zlog_debug("%s: Malformed packet: Invalid reason TLV len:%u",
d8193748
MS
304 __func__, TLV_SIZE(tlvh));
305 return OSPF_GR_FAILURE;
306 }
307
ad686992 308 gr_reason = (struct grace_tlv_restart_reason *)tlvh;
309 *reason = gr_reason->reason;
310 sum += TLV_SIZE(tlvh);
311
312 if (*reason >= OSPF_GR_INVALID_REASON_CODE)
313 return OSPF_GR_FAILURE;
314 break;
315 case RESTARTER_IP_ADDR_TYPE:
d8193748
MS
316 if (TLV_SIZE(tlvh) <
317 sizeof(struct grace_tlv_restart_addr)) {
72327cf3 318 zlog_debug("%s: Malformed packet: Invalid addr TLV len:%u",
d8193748
MS
319 __func__, TLV_SIZE(tlvh));
320 return OSPF_GR_FAILURE;
321 }
322
ad686992 323 restart_addr = (struct grace_tlv_restart_addr *)tlvh;
324 addr->s_addr = restart_addr->addr.s_addr;
325 sum += TLV_SIZE(tlvh);
326 break;
327 default:
3f87e1d8 328 if (IS_DEBUG_OSPF_GR)
ad686992 329 zlog_debug(
330 "%s, Malformed packet.Invalid TLV type:%d",
a4544597 331 __func__, ntohs(tlvh->type));
ad686992 332 return OSPF_GR_FAILURE;
333 }
334 }
335
336 return OSPF_GR_SUCCESS;
337}
338
339/*
340 * Grace timer expiry handler.
341 * HELPER aborts its role at grace timer expiry.
342 *
343 * thread
344 * thread pointer
345 *
346 * Returns:
347 * Nothing
348 */
cc9f21da 349static void ospf_handle_grace_timer_expiry(struct thread *thread)
ad686992 350{
351 struct ospf_neighbor *nbr = THREAD_ARG(thread);
352
353 nbr->gr_helper_info.t_grace_timer = NULL;
354
355 ospf_gr_helper_exit(nbr, OSPF_GR_HELPER_GRACE_TIMEOUT);
ad686992 356}
357
358/*
359 * Process Grace LSA.If it is eligible move to HELPER role.
360 * Ref rfc3623 section 3.1
361 *
362 * ospf
07b33add 363 * OSPF pointer.
ad686992 364 *
365 * lsa
366 * Grace LSA received from RESTARTER.
367 *
368 * nbr
98cb53f9 369 * OSPF neighbour which requests the router to act as
ad686992 370 * HELPER.
371 *
372 * Returns:
373 * status.
374 * If supported as HELPER : OSPF_GR_HELPER_INPROGRESS
375 * If Not supported as HELPER : OSPF_GR_HELPER_NONE
376 */
377int ospf_process_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
378 struct ospf_neighbor *nbr)
379{
380 struct in_addr restart_addr = {0};
381 uint8_t restart_reason = 0;
382 uint32_t grace_interval = 0;
383 uint32_t actual_grace_interval = 0;
384 struct advRtr lookup;
385 struct ospf_neighbor *restarter = NULL;
386 struct ospf_interface *oi = nbr->oi;
387 int ret;
388
389
390 /* Extract the grace lsa packet fields */
391 ret = ospf_extract_grace_lsa_fields(lsa, &grace_interval, &restart_addr,
392 &restart_reason);
393 if (ret != OSPF_GR_SUCCESS) {
3f87e1d8 394 if (IS_DEBUG_OSPF_GR)
a4544597 395 zlog_debug("%s, Wrong Grace LSA packet.", __func__);
ad686992 396 return OSPF_GR_NOT_HELPER;
397 }
398
3f87e1d8 399 if (IS_DEBUG_OSPF_GR)
ad686992 400 zlog_debug(
98cb53f9 401 "%s, Grace LSA received from %pI4, grace interval:%u, restart reason:%s",
a4544597 402 __func__, &restart_addr, grace_interval,
d05d5280 403 ospf_restart_reason2str(restart_reason));
ad686992 404
98cb53f9 405 /* In case of broadcast links, if RESTARTER is DR_OTHER,
ad686992 406 * grace LSA might be received from DR, so need to get
407 * actual neighbour info , here RESTARTER.
408 */
409 if (oi->type != OSPF_IFTYPE_POINTOPOINT) {
410 restarter = ospf_nbr_lookup_by_addr(oi->nbrs, &restart_addr);
411
412 if (!restarter) {
3f87e1d8 413 if (IS_DEBUG_OSPF_GR)
ad686992 414 zlog_debug(
96b663a3 415 "%s, Restarter is not a nbr(%pI4) for this router.",
a4544597 416 __func__, &restart_addr);
ad686992 417 return OSPF_GR_NOT_HELPER;
418 }
419 } else
420 restarter = nbr;
421
422 /* Verify Helper enabled globally */
423 if (!ospf->is_helper_supported) {
424 /* Verify that Helper support is enabled for the
425 * current neighbour router-id.
426 */
427 lookup.advRtrAddr.s_addr = restarter->router_id.s_addr;
428
429 if (!hash_lookup(ospf->enable_rtr_list, &lookup)) {
3f87e1d8 430 if (IS_DEBUG_OSPF_GR)
ad686992 431 zlog_debug(
432 "%s, HELPER support is disabled, So not a HELPER",
a4544597 433 __func__);
ad686992 434 restarter->gr_helper_info.rejected_reason =
435 OSPF_HELPER_SUPPORT_DISABLED;
436 return OSPF_GR_NOT_HELPER;
437 }
438 }
439
440
441 /* Check neighbour is in FULL state and
442 * became a adjacency.
443 */
444 if (!IS_NBR_STATE_FULL(restarter)) {
3f87e1d8 445 if (IS_DEBUG_OSPF_GR)
ad686992 446 zlog_debug(
96b663a3 447 "%s, This Neighbour %pI4 is not in FULL state.",
a4544597 448 __func__, &restarter->src);
ad686992 449 restarter->gr_helper_info.rejected_reason =
450 OSPF_HELPER_NOT_A_VALID_NEIGHBOUR;
451 return OSPF_GR_NOT_HELPER;
452 }
453
454 /* Based on the restart reason from grace lsa
455 * check the current router is supporting or not
456 */
457 if (ospf->only_planned_restart
458 && !OSPF_GR_IS_PLANNED_RESTART(restart_reason)) {
3f87e1d8 459 if (IS_DEBUG_OSPF_GR)
ad686992 460 zlog_debug(
461 "%s, Router supports only planned restarts but received the GRACE LSA for an unplanned restart.",
a4544597 462 __func__);
ad686992 463 restarter->gr_helper_info.rejected_reason =
464 OSPF_HELPER_PLANNED_ONLY_RESTART;
465 return OSPF_GR_NOT_HELPER;
466 }
467
98cb53f9 468 /* Check the retransmission list of this
ad686992 469 * neighbour, check any change in lsas.
470 */
471 if (ospf->strict_lsa_check && !ospf_ls_retransmit_isempty(restarter)
472 && ospf_check_change_in_rxmt_list(restarter)) {
3f87e1d8 473 if (IS_DEBUG_OSPF_GR)
ad686992 474 zlog_debug(
475 "%s, Changed LSA in Rxmt list. So not Helper.",
a4544597 476 __func__);
ad686992 477 restarter->gr_helper_info.rejected_reason =
478 OSPF_HELPER_TOPO_CHANGE_RTXMT_LIST;
479 return OSPF_GR_NOT_HELPER;
480 }
481
482 /*LSA age must be less than the grace period */
483 if (ntohs(lsa->data->ls_age) >= grace_interval) {
3f87e1d8 484 if (IS_DEBUG_OSPF_GR)
ad686992 485 zlog_debug(
98cb53f9 486 "%s, Grace LSA age(%d) is more than the grace interval(%d)",
a4544597 487 __func__, lsa->data->ls_age, grace_interval);
ad686992 488 restarter->gr_helper_info.rejected_reason =
489 OSPF_HELPER_LSA_AGE_MORE;
490 return OSPF_GR_NOT_HELPER;
491 }
492
10514170
RW
493 if (ospf->gr_info.restart_in_progress) {
494 if (IS_DEBUG_OSPF_GR)
495 zlog_debug(
496 "%s: router is in the process of graceful restart",
497 __func__);
498 restarter->gr_helper_info.rejected_reason =
499 OSPF_HELPER_RESTARTING;
500 return OSPF_GR_NOT_HELPER;
501 }
502
ad686992 503 /* check supported grace period configured
504 * if configured, use this to start the grace
505 * timer otherwise use the interval received
506 * in grace LSA packet.
507 */
508 actual_grace_interval = grace_interval;
509 if (grace_interval > ospf->supported_grace_time) {
3f87e1d8 510 if (IS_DEBUG_OSPF_GR)
ad686992 511 zlog_debug(
512 "%s, Received grace period %d is larger than supported grace %d",
a4544597 513 __func__, grace_interval,
ad686992 514 ospf->supported_grace_time);
515 actual_grace_interval = ospf->supported_grace_time;
516 }
517
518 if (OSPF_GR_IS_ACTIVE_HELPER(restarter)) {
519 if (restarter->gr_helper_info.t_grace_timer)
520 THREAD_OFF(restarter->gr_helper_info.t_grace_timer);
521
522 if (ospf->active_restarter_cnt > 0)
523 ospf->active_restarter_cnt--;
524
3f87e1d8 525 if (IS_DEBUG_OSPF_GR)
ad686992 526 zlog_debug(
527 "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
a4544597 528 __func__);
ad686992 529 } else {
3f87e1d8 530 if (IS_DEBUG_OSPF_GR)
ad686992 531 zlog_debug(
96b663a3 532 "%s, This Router becomes a HELPER for the neighbour %pI4",
a4544597 533 __func__, &restarter->src);
ad686992 534 }
535
536 /* Became a Helper to the RESTART neighbour.
537 * Change the helper status.
538 */
539 restarter->gr_helper_info.gr_helper_status = OSPF_GR_ACTIVE_HELPER;
540 restarter->gr_helper_info.recvd_grace_period = grace_interval;
541 restarter->gr_helper_info.actual_grace_period = actual_grace_interval;
542 restarter->gr_helper_info.gr_restart_reason = restart_reason;
543 restarter->gr_helper_info.rejected_reason = OSPF_HELPER_REJECTED_NONE;
544
98cb53f9 545 /* Increment the active restarter count */
ad686992 546 ospf->active_restarter_cnt++;
547
3f87e1d8 548 if (IS_DEBUG_OSPF_GR)
a4544597
DS
549 zlog_debug("%s, Grace timer started.interval:%d", __func__,
550 actual_grace_interval);
ad686992 551
552 /* Start the grace timer */
553 thread_add_timer(master, ospf_handle_grace_timer_expiry, restarter,
554 actual_grace_interval,
555 &restarter->gr_helper_info.t_grace_timer);
556
557 return OSPF_GR_ACTIVE_HELPER;
558}
559
560/*
561 * API to check any change in the neighbor's
562 * retransmission list.
563 *
564 * nbr
98cb53f9 565 * OSPF neighbor
ad686992 566 *
567 * Returns:
568 * TRUE - if any change in the lsa.
569 * FALSE - no change in the lsas.
570 */
571static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr)
572{
573 struct route_node *rn;
574 struct ospf_lsa *lsa;
575 struct route_table *tbl;
576
577 tbl = nbr->ls_rxmt.type[OSPF_ROUTER_LSA].db;
578 LSDB_LOOP (tbl, rn, lsa)
579 if (lsa->to_be_acknowledged)
580 return OSPF_GR_TRUE;
581 tbl = nbr->ls_rxmt.type[OSPF_NETWORK_LSA].db;
582 LSDB_LOOP (tbl, rn, lsa)
583 if (lsa->to_be_acknowledged)
584 return OSPF_GR_TRUE;
585
586 tbl = nbr->ls_rxmt.type[OSPF_SUMMARY_LSA].db;
587 LSDB_LOOP (tbl, rn, lsa)
588 if (lsa->to_be_acknowledged)
589 return OSPF_GR_TRUE;
590
591 tbl = nbr->ls_rxmt.type[OSPF_ASBR_SUMMARY_LSA].db;
592 LSDB_LOOP (tbl, rn, lsa)
593 if (lsa->to_be_acknowledged)
594 return OSPF_GR_TRUE;
595
596 tbl = nbr->ls_rxmt.type[OSPF_AS_EXTERNAL_LSA].db;
597 LSDB_LOOP (tbl, rn, lsa)
598 if (lsa->to_be_acknowledged)
599 return OSPF_GR_TRUE;
600
601 tbl = nbr->ls_rxmt.type[OSPF_AS_NSSA_LSA].db;
602 LSDB_LOOP (tbl, rn, lsa)
603 if (lsa->to_be_acknowledged)
604 return OSPF_GR_TRUE;
605
606 return OSPF_GR_FALSE;
607}
608
df074ec3 609/*
610 * Actions to be taken when topo change detected
611 * HELPER will exit upon topo change.
612 *
613 * ospf
614 * ospf pointer
615 * lsa
98cb53f9 616 * topo change occurred due to this lsa type (1 to 5 and 7)
df074ec3 617 *
618 * Returns:
619 * Nothing
620 */
621void ospf_helper_handle_topo_chg(struct ospf *ospf, struct ospf_lsa *lsa)
622{
623 struct listnode *node;
624 struct ospf_interface *oi;
625
d8193748 626 /* Topo change not required to be handled if strict
98cb53f9 627 * LSA check is disabled for this router.
df074ec3 628 */
629 if (!ospf->strict_lsa_check)
630 return;
631
3f87e1d8 632 if (IS_DEBUG_OSPF_GR)
e9505bc6
RW
633 zlog_debug("%s: Topo change detected due to LSA[%s]", __func__,
634 dump_lsa_key(lsa));
df074ec3 635
636 lsa->to_be_acknowledged = OSPF_GR_TRUE;
637
638 for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
639 struct route_node *rn = NULL;
640
641 if (ospf_interface_neighbor_count(oi) == 0)
642 continue;
643
644 /* Ref rfc3623 section 3.2.3.b
645 * If change due to external LSA and if the area is
646 * stub, then it is not a topo change. Since Type-5
647 * lsas will not be flooded in stub area.
648 */
649 if ((oi->area->external_routing == OSPF_AREA_STUB)
650 && (lsa->data->type == OSPF_AS_EXTERNAL_LSA)) {
651 continue;
652 }
653
654 for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
655 struct ospf_neighbor *nbr = NULL;
656
657 if (!rn->info)
658 continue;
659
660 nbr = rn->info;
661
662 if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
663 ospf_gr_helper_exit(nbr,
664 OSPF_GR_HELPER_TOPO_CHG);
665 }
666 }
667}
668
ad686992 669/*
670 * Api to exit from HELPER role to take all actions
671 * required at exit.
672 * Ref rfc3623 section 3.2
673 *
674 * ospf
07b33add 675 * OSPF pointer.
ad686992 676 *
677 * nbr
07b33add 678 * OSPF neighbour for which it is acting as HELPER.
ad686992 679 *
680 * reason
681 * The reason for exiting from HELPER.
682 *
683 * Returns:
684 * Nothing.
685 */
686void ospf_gr_helper_exit(struct ospf_neighbor *nbr,
687 enum ospf_helper_exit_reason reason)
688{
df074ec3 689 struct ospf_interface *oi = nbr->oi;
690 struct ospf *ospf = oi->ospf;
691
692 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
693 return;
694
3f87e1d8 695 if (IS_DEBUG_OSPF_GR)
96b663a3 696 zlog_debug("%s, Exiting from HELPER support to %pI4, due to %s",
a4544597 697 __func__, &nbr->src, ospf_exit_reason2str(reason));
df074ec3 698
699 /* Reset helper status*/
700 nbr->gr_helper_info.gr_helper_status = OSPF_GR_NOT_HELPER;
701 nbr->gr_helper_info.helper_exit_reason = reason;
702 nbr->gr_helper_info.actual_grace_period = 0;
703 nbr->gr_helper_info.recvd_grace_period = 0;
704 nbr->gr_helper_info.gr_restart_reason = 0;
705 ospf->last_exit_reason = reason;
706
707 if (ospf->active_restarter_cnt <= 0) {
708 zlog_err(
709 "OSPF GR-Helper: active_restarter_cnt should be greater than zero here.");
710 return;
711 }
712 /* Decrement active Restarter count */
713 ospf->active_restarter_cnt--;
714
715 /* If the exit not triggered due to grace timer
98cb53f9 716 * expiry, stop the grace timer.
df074ec3 717 */
718 if (reason != OSPF_GR_HELPER_GRACE_TIMEOUT)
719 THREAD_OFF(nbr->gr_helper_info.t_grace_timer);
720
721 /* check exit triggered due to successful completion
722 * of graceful restart.
df074ec3 723 */
724 if (reason != OSPF_GR_HELPER_COMPLETED) {
3f87e1d8 725 if (IS_DEBUG_OSPF_GR)
89eb4727 726 zlog_debug("%s, Unsuccessful GR exit", __func__);
df074ec3 727 }
728
729 /*Recalculate the DR for the network segment */
802a5739
RW
730 if (oi->type == OSPF_IFTYPE_BROADCAST || oi->type == OSPF_IFTYPE_NBMA)
731 ospf_dr_election(oi);
df074ec3 732
733 /* Originate a router LSA */
734 ospf_router_lsa_update_area(oi->area);
735
736 /* Originate network lsa if it is an DR in the LAN */
737 if (oi->state == ISM_DR)
738 ospf_network_lsa_update(oi);
ad686992 739}
740
741/*
98cb53f9 742 * Process MaxAge Grace LSA.
df074ec3 743 * It is a indication for successful completion of GR.
ad686992 744 * If router acting as HELPER, It exits from helper role.
745 *
746 * ospf
07b33add 747 * OSPF pointer.
ad686992 748 *
749 * lsa
750 * Grace LSA received from RESTARTER.
751 *
752 * nbr
98cb53f9 753 * OSPF neighbour which requests the router to act as
ad686992 754 * HELPER.
755 *
756 * Returns:
757 * Nothing.
758 */
759void ospf_process_maxage_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
760 struct ospf_neighbor *nbr)
761{
df074ec3 762 struct in_addr restartAddr = {0};
763 uint8_t restartReason = 0;
764 uint32_t graceInterval = 0;
765 struct ospf_neighbor *restarter = NULL;
766 struct ospf_interface *oi = nbr->oi;
767 int ret;
768
769 /* Extract the grace lsa packet fields */
770 ret = ospf_extract_grace_lsa_fields(lsa, &graceInterval, &restartAddr,
771 &restartReason);
772 if (ret != OSPF_GR_SUCCESS) {
3f87e1d8 773 if (IS_DEBUG_OSPF_GR)
a4544597 774 zlog_debug("%s, Wrong Grace LSA packet.", __func__);
df074ec3 775 return;
776 }
777
3f87e1d8 778 if (IS_DEBUG_OSPF_GR)
a4544597
DS
779 zlog_debug("%s, GraceLSA received for neighbour %pI4", __func__,
780 &restartAddr);
df074ec3 781
782 /* In case of broadcast links, if RESTARTER is DR_OTHER,
783 * grace LSA might be received from DR, so fetching the
784 * actual neighbour information using restarter address.
785 */
786 if (oi->type != OSPF_IFTYPE_POINTOPOINT) {
787 restarter = ospf_nbr_lookup_by_addr(oi->nbrs, &restartAddr);
788
789 if (!restarter) {
3f87e1d8 790 if (IS_DEBUG_OSPF_GR)
df074ec3 791 zlog_debug(
792 "%s, Restarter is not a neighbour for this router.",
a4544597 793 __func__);
df074ec3 794 return;
795 }
796 } else {
797 restarter = nbr;
798 }
799
800 ospf_gr_helper_exit(restarter, OSPF_GR_HELPER_COMPLETED);
ad686992 801}
07b33add 802
803/* Configuration handlers */
804/*
805 * Disable/Enable HELPER support on router level.
806 *
807 * ospf
98cb53f9 808 * OSPF pointer.
07b33add 809 *
810 * status
811 * TRUE/FALSE
812 *
813 * Returns:
814 * Nothing.
815 */
816void ospf_gr_helper_support_set(struct ospf *ospf, bool support)
817{
818 struct ospf_interface *oi;
819 struct listnode *node;
820 struct advRtr lookup;
821
822 if (ospf->is_helper_supported == support)
823 return;
824
825 ospf->is_helper_supported = support;
826
827 /* If helper support disabled, cease HELPER role for all
828 * supporting neighbors.
829 */
830 if (support == OSPF_GR_FALSE) {
831 for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
832 struct route_node *rn = NULL;
833
834 if (ospf_interface_neighbor_count(oi) == 0)
835 continue;
836
837 for (rn = route_top(oi->nbrs); rn;
838 rn = route_next(rn)) {
839 struct ospf_neighbor *nbr = NULL;
840
841 if (!rn->info)
842 continue;
843
844 nbr = rn->info;
845
846 lookup.advRtrAddr.s_addr =
847 nbr->router_id.s_addr;
848 /* check if helper support enabled for the
1461559c
DS
849 * corresponding routerid.If enabled, don't
850 * exit from helper role.
07b33add 851 */
852 if (hash_lookup(ospf->enable_rtr_list, &lookup))
853 continue;
854
855 if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
856 ospf_gr_helper_exit(
857 nbr, OSPF_GR_HELPER_TOPO_CHG);
858 }
859 }
860 }
861}
862
863/*
864 * Enable/Disable HELPER support on a specified advertagement
865 * router.
866 *
867 * ospf
868 * OSPF pointer.
869 *
870 * advRtr
871 * HELPER support for given Advertisement Router.
872 *
873 * support
874 * True - Enable Helper Support.
875 * False - Disable Helper Support.
876 *
877 * Returns:
878 * Nothing.
879 */
880
881void ospf_gr_helper_support_set_per_routerid(struct ospf *ospf,
882 struct in_addr *advrtr,
883 bool support)
884{
885 struct advRtr temp;
886 struct advRtr *rtr;
887 struct ospf_interface *oi;
888 struct listnode *node;
889
890 temp.advRtrAddr.s_addr = advrtr->s_addr;
891
892 if (support == OSPF_GR_FALSE) {
893 /*Delete the routerid from the enable router hash table */
894 rtr = hash_lookup(ospf->enable_rtr_list, &temp);
895
896 if (rtr) {
897 hash_release(ospf->enable_rtr_list, rtr);
898 ospf_disable_rtr_hash_free(rtr);
899 }
900
901 /* If helper support is enabled globally
902 * no action is required.
903 */
904 if (ospf->is_helper_supported)
905 return;
906
907 /* Cease the HELPER role fore neighbours from the
908 * specified advertisement router.
909 */
910 for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
911 struct route_node *rn = NULL;
912
913 if (ospf_interface_neighbor_count(oi) == 0)
914 continue;
915
916 for (rn = route_top(oi->nbrs); rn;
917 rn = route_next(rn)) {
918 struct ospf_neighbor *nbr = NULL;
919
920 if (!rn->info)
921 continue;
922
923 nbr = rn->info;
924
925 if (nbr->router_id.s_addr != advrtr->s_addr)
926 continue;
927
928 if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
929 ospf_gr_helper_exit(
930 nbr, OSPF_GR_HELPER_TOPO_CHG);
931 }
932 }
933
934 } else {
935 /* Add the routerid to the enable router hash table */
936 hash_get(ospf->enable_rtr_list, &temp,
937 ospf_enable_rtr_hash_alloc);
938 }
939}
940
941/*
942 * Api to enable/disable strict lsa check on the HELPER.
943 *
944 * ospf
945 * OSPF pointer.
946 *
947 * enabled
948 * True - disable the lsa check.
949 * False - enable the strict lsa check.
950 *
951 * Returns:
952 * Nothing.
953 */
954void ospf_gr_helper_lsa_check_set(struct ospf *ospf, bool enabled)
955{
956 if (ospf->strict_lsa_check == enabled)
957 return;
958
959 ospf->strict_lsa_check = enabled;
960}
961
962/*
963 * Api to set the supported grace interval in this router.
964 *
965 * ospf
966 * OSPF pointer.
967 *
968 * interval
969 * The supported grace interval..
970 *
971 * Returns:
972 * Nothing.
973 */
974void ospf_gr_helper_supported_gracetime_set(struct ospf *ospf,
975 uint32_t interval)
976{
977 ospf->supported_grace_time = interval;
978}
979
980/*
981 * Api to set the supported restart reason.
982 *
983 * ospf
984 * OSPF pointer.
985 *
986 * planned_only
987 * True: support only planned restart.
988 * False: support for planned/unplanned restarts.
989 *
990 * Returns:
991 * Nothing.
992 */
993void ospf_gr_helper_set_supported_planned_only_restart(struct ospf *ospf,
994 bool planned_only)
995{
996 ospf->only_planned_restart = planned_only;
997}
abd5b8c7 998
999/*
1000 * Api to display the grace LSA information.
1001 *
1002 * vty
1003 * vty pointer.
1004 * lsa
1005 * Grace LSA.
1006 * json
1007 * json object
1008 *
1009 * Returns:
1010 * Nothing.
1011 */
3e63092b
RW
1012static void show_ospf_grace_lsa_info(struct vty *vty, struct json_object *json,
1013 struct ospf_lsa *lsa)
abd5b8c7 1014{
1015 struct lsa_header *lsah = NULL;
1016 struct tlv_header *tlvh = NULL;
1017 struct grace_tlv_graceperiod *gracePeriod;
1018 struct grace_tlv_restart_reason *grReason;
1019 struct grace_tlv_restart_addr *restartAddr;
1020 uint16_t length = 0;
1021 int sum = 0;
1022
3e63092b
RW
1023 if (json)
1024 return;
1025
abd5b8c7 1026 lsah = (struct lsa_header *)lsa->data;
1027
8db278b5 1028 if (lsa->size <= OSPF_LSA_HEADER_SIZE) {
f5f27b58
RW
1029 if (vty)
1030 vty_out(vty, "%% Invalid LSA length: %d\n", length);
1031 else
1032 zlog_debug("%% Invalid LSA length: %d", length);
d8193748
MS
1033 return;
1034 }
1035
8db278b5 1036 length = lsa->size - OSPF_LSA_HEADER_SIZE;
abd5b8c7 1037
f5f27b58
RW
1038 if (vty)
1039 vty_out(vty, " TLV info:\n");
1040 else
1041 zlog_debug(" TLV info:");
abd5b8c7 1042
8db278b5 1043 for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
abd5b8c7 1044 tlvh = TLV_HDR_NEXT(tlvh)) {
d8193748
MS
1045 /* Check TLV len */
1046 if (sum + TLV_SIZE(tlvh) > length) {
f5f27b58
RW
1047 if (vty)
1048 vty_out(vty, "%% Invalid TLV length: %u\n",
1049 TLV_SIZE(tlvh));
1050 else
1051 zlog_debug("%% Invalid TLV length: %u",
1052 TLV_SIZE(tlvh));
d8193748
MS
1053 return;
1054 }
1055
abd5b8c7 1056 switch (ntohs(tlvh->type)) {
1057 case GRACE_PERIOD_TYPE:
f5f27b58
RW
1058 if (TLV_SIZE(tlvh)
1059 < sizeof(struct grace_tlv_graceperiod)) {
1060 if (vty)
1061 vty_out(vty,
1062 "%% Invalid grace TLV length %u\n",
1063 TLV_SIZE(tlvh));
1064 else
1065 zlog_debug(
1066 "%% Invalid grace TLV length %u",
1067 TLV_SIZE(tlvh));
d8193748
MS
1068 return;
1069 }
1070
abd5b8c7 1071 gracePeriod = (struct grace_tlv_graceperiod *)tlvh;
1072 sum += TLV_SIZE(tlvh);
1073
f5f27b58
RW
1074 if (vty)
1075 vty_out(vty, " Grace period:%d\n",
1076 ntohl(gracePeriod->interval));
1077 else
1078 zlog_debug(" Grace period:%d",
1079 ntohl(gracePeriod->interval));
abd5b8c7 1080 break;
1081 case RESTART_REASON_TYPE:
f5f27b58
RW
1082 if (TLV_SIZE(tlvh)
1083 < sizeof(struct grace_tlv_restart_reason)) {
1084 if (vty)
1085 vty_out(vty,
1086 "%% Invalid reason TLV length %u\n",
1087 TLV_SIZE(tlvh));
1088 else
1089 zlog_debug(
1090 "%% Invalid reason TLV length %u",
1091 TLV_SIZE(tlvh));
d8193748
MS
1092 return;
1093 }
1094
abd5b8c7 1095 grReason = (struct grace_tlv_restart_reason *)tlvh;
1096 sum += TLV_SIZE(tlvh);
1097
f5f27b58
RW
1098 if (vty)
1099 vty_out(vty, " Restart reason:%s\n",
1100 ospf_restart_reason2str(
1101 grReason->reason));
1102 else
1103 zlog_debug(" Restart reason:%s",
1104 ospf_restart_reason2str(
1105 grReason->reason));
abd5b8c7 1106 break;
1107 case RESTARTER_IP_ADDR_TYPE:
f5f27b58
RW
1108 if (TLV_SIZE(tlvh)
1109 < sizeof(struct grace_tlv_restart_addr)) {
1110 if (vty)
1111 vty_out(vty,
1112 "%% Invalid addr TLV length %u\n",
1113 TLV_SIZE(tlvh));
1114 else
1115 zlog_debug(
1116 "%% Invalid addr TLV length %u",
1117 TLV_SIZE(tlvh));
d8193748
MS
1118 return;
1119 }
1120
abd5b8c7 1121 restartAddr = (struct grace_tlv_restart_addr *)tlvh;
1122 sum += TLV_SIZE(tlvh);
1123
f5f27b58
RW
1124 if (vty)
1125 vty_out(vty, " Restarter address:%pI4\n",
1126 &restartAddr->addr);
1127 else
1128 zlog_debug(" Restarter address:%pI4",
1129 &restartAddr->addr);
abd5b8c7 1130 break;
1131 default:
f5f27b58
RW
1132 if (vty)
1133 vty_out(vty, " Unknown TLV type %d\n",
1134 ntohs(tlvh->type));
1135 else
1136 zlog_debug(" Unknown TLV type %d",
1137 ntohs(tlvh->type));
d8193748 1138
abd5b8c7 1139 break;
1140 }
1141 }
1142}