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