]> git.proxmox.com Git - mirror_frr.git/blob - ospfd/ospf_gr_helper.c
*: Convert thread_add_XXX functions to event_add_XXX
[mirror_frr.git] / ospfd / ospf_gr_helper.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * OSPF Graceful Restart helper functions.
4 *
5 * Copyright (C) 2020-21 Vmware, Inc.
6 * Rajesh Kumar Girada
7 */
8
9 #include <zebra.h>
10
11 #include "event.h"
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"
36 #include "ospfd/ospf_gr.h"
37
38 static const char * const ospf_exit_reason_desc[] = {
39 "Unknown reason",
40 "Helper in progress",
41 "Topology Change",
42 "Grace timer expiry",
43 "Successful graceful restart",
44 };
45
46 static const char * const ospf_restart_reason_desc[] = {
47 "Unknown restart",
48 "Software restart",
49 "Software reload/upgrade",
50 "Switch to redundant control processor",
51 };
52
53 static const char * const ospf_rejected_reason_desc[] = {
54 "Unknown reason",
55 "Helper support disabled",
56 "Neighbour is not in FULL state",
57 "Supports only planned restart but received unplanned",
58 "Topo change due to change in lsa rxmt list",
59 "LSA age is more than Grace interval",
60 "Router is in the process of graceful restart",
61 };
62
63 static void show_ospf_grace_lsa_info(struct vty *vty, struct json_object *json,
64 struct ospf_lsa *lsa);
65 static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr);
66
67 static 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
74 static 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
82 static 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
92 static void ospf_disable_rtr_hash_free(void *rtr)
93 {
94 XFREE(MTYPE_OSPF_GR_HELPER, rtr);
95 }
96
97 static void ospf_enable_rtr_hash_destroy(struct ospf *ospf)
98 {
99 if (ospf->enable_rtr_list == NULL)
100 return;
101
102 hash_clean_and_free(&ospf->enable_rtr_list, ospf_disable_rtr_hash_free);
103 }
104
105 /*
106 * GR exit reason strings
107 */
108 const 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 */
119 const 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 */
130 const 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
138 /*
139 * Initialize GR helper config data structures.
140 *
141 * OSPF
142 * OSPF pointer
143 *
144 * Returns:
145 * Nothing
146 */
147 void ospf_gr_helper_instance_init(struct ospf *ospf)
148 {
149 if (IS_DEBUG_OSPF_GR)
150 zlog_debug("%s, GR Helper init.", __func__);
151
152 ospf->is_helper_supported = OSPF_GR_FALSE;
153 ospf->strict_lsa_check = OSPF_GR_TRUE;
154 ospf->only_planned_restart = OSPF_GR_FALSE;
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");
162 }
163
164 /*
165 * De-Initialize GR helper config data structures.
166 *
167 * OSPF
168 * OSPF pointer
169 *
170 * Returns:
171 * Nothing
172 */
173 void ospf_gr_helper_instance_stop(struct ospf *ospf)
174 {
175 if (IS_DEBUG_OSPF_GR)
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 */
187 void ospf_gr_helper_init(void)
188 {
189 int rc;
190
191 if (IS_DEBUG_OSPF_GR)
192 zlog_debug("%s, GR Helper init.", __func__);
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 }
203 }
204
205 /*
206 * De-Initialize GR helper config data structures.
207 *
208 * Returns:
209 * Nothing
210 */
211 void ospf_gr_helper_stop(void)
212 {
213 if (IS_DEBUG_OSPF_GR)
214 zlog_debug("%s, GR helper deinit.", __func__);
215
216 ospf_delete_opaque_functab(OSPF_OPAQUE_LINK_LSA, OPAQUE_TYPE_GRACE_LSA);
217 }
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 */
230 static 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
244 /* Check LSA len */
245 if (lsa->size <= OSPF_LSA_HEADER_SIZE) {
246 if (IS_DEBUG_OSPF_GR)
247 zlog_debug("%s: Malformed packet: Invalid LSA len:%d",
248 __func__, length);
249 return OSPF_GR_FAILURE;
250 }
251
252 length = lsa->size - OSPF_LSA_HEADER_SIZE;
253
254 for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
255 tlvh = TLV_HDR_NEXT(tlvh)) {
256
257 /* Check TLV len against overall LSA */
258 if (sum + TLV_SIZE(tlvh) > length) {
259 if (IS_DEBUG_OSPF_GR)
260 zlog_debug("%s: Malformed packet: Invalid TLV len:%u",
261 __func__, TLV_SIZE(tlvh));
262 return OSPF_GR_FAILURE;
263 }
264
265 switch (ntohs(tlvh->type)) {
266 case GRACE_PERIOD_TYPE:
267 if (TLV_SIZE(tlvh) <
268 sizeof(struct grace_tlv_graceperiod)) {
269 zlog_debug("%s: Malformed packet: Invalid grace TLV len:%u",
270 __func__, TLV_SIZE(tlvh));
271 return OSPF_GR_FAILURE;
272 }
273
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:
284 if (TLV_SIZE(tlvh) <
285 sizeof(struct grace_tlv_restart_reason)) {
286 zlog_debug("%s: Malformed packet: Invalid reason TLV len:%u",
287 __func__, TLV_SIZE(tlvh));
288 return OSPF_GR_FAILURE;
289 }
290
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:
299 if (TLV_SIZE(tlvh) <
300 sizeof(struct grace_tlv_restart_addr)) {
301 zlog_debug("%s: Malformed packet: Invalid addr TLV len:%u",
302 __func__, TLV_SIZE(tlvh));
303 return OSPF_GR_FAILURE;
304 }
305
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:
311 if (IS_DEBUG_OSPF_GR)
312 zlog_debug(
313 "%s, Malformed packet.Invalid TLV type:%d",
314 __func__, ntohs(tlvh->type));
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 */
332 static void ospf_handle_grace_timer_expiry(struct event *thread)
333 {
334 struct ospf_neighbor *nbr = THREAD_ARG(thread);
335
336 nbr->gr_helper_info.t_grace_timer = NULL;
337
338 ospf_gr_helper_exit(nbr, OSPF_GR_HELPER_GRACE_TIMEOUT);
339 }
340
341 /*
342 * Process Grace LSA.If it is eligible move to HELPER role.
343 * Ref rfc3623 section 3.1
344 *
345 * ospf
346 * OSPF pointer.
347 *
348 * lsa
349 * Grace LSA received from RESTARTER.
350 *
351 * nbr
352 * OSPF neighbour which requests the router to act as
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 */
360 int 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) {
377 if (IS_DEBUG_OSPF_GR)
378 zlog_debug("%s, Wrong Grace LSA packet.", __func__);
379 return OSPF_GR_NOT_HELPER;
380 }
381
382 if (IS_DEBUG_OSPF_GR)
383 zlog_debug(
384 "%s, Grace LSA received from %pI4, grace interval:%u, restart reason:%s",
385 __func__, &restart_addr, grace_interval,
386 ospf_restart_reason2str(restart_reason));
387
388 /* In case of broadcast links, if RESTARTER is DR_OTHER,
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) {
396 if (IS_DEBUG_OSPF_GR)
397 zlog_debug(
398 "%s, Restarter is not a nbr(%pI4) for this router.",
399 __func__, &restart_addr);
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)) {
413 if (IS_DEBUG_OSPF_GR)
414 zlog_debug(
415 "%s, HELPER support is disabled, So not a HELPER",
416 __func__);
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)) {
428 if (IS_DEBUG_OSPF_GR)
429 zlog_debug(
430 "%s, This Neighbour %pI4 is not in FULL state.",
431 __func__, &restarter->src);
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)) {
442 if (IS_DEBUG_OSPF_GR)
443 zlog_debug(
444 "%s, Router supports only planned restarts but received the GRACE LSA for an unplanned restart.",
445 __func__);
446 restarter->gr_helper_info.rejected_reason =
447 OSPF_HELPER_PLANNED_ONLY_RESTART;
448 return OSPF_GR_NOT_HELPER;
449 }
450
451 /* Check the retransmission list of this
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)) {
456 if (IS_DEBUG_OSPF_GR)
457 zlog_debug(
458 "%s, Changed LSA in Rxmt list. So not Helper.",
459 __func__);
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) {
467 if (IS_DEBUG_OSPF_GR)
468 zlog_debug(
469 "%s, Grace LSA age(%d) is more than the grace interval(%d)",
470 __func__, lsa->data->ls_age, grace_interval);
471 restarter->gr_helper_info.rejected_reason =
472 OSPF_HELPER_LSA_AGE_MORE;
473 return OSPF_GR_NOT_HELPER;
474 }
475
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
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) {
493 if (IS_DEBUG_OSPF_GR)
494 zlog_debug(
495 "%s, Received grace period %d is larger than supported grace %d",
496 __func__, grace_interval,
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)
503 THREAD_OFF(restarter->gr_helper_info.t_grace_timer);
504
505 if (ospf->active_restarter_cnt > 0)
506 ospf->active_restarter_cnt--;
507
508 if (IS_DEBUG_OSPF_GR)
509 zlog_debug(
510 "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
511 __func__);
512 } else {
513 if (IS_DEBUG_OSPF_GR)
514 zlog_debug(
515 "%s, This Router becomes a HELPER for the neighbour %pI4",
516 __func__, &restarter->src);
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
528 /* Increment the active restarter count */
529 ospf->active_restarter_cnt++;
530
531 if (IS_DEBUG_OSPF_GR)
532 zlog_debug("%s, Grace timer started.interval:%d", __func__,
533 actual_grace_interval);
534
535 /* Start the grace timer */
536 event_add_timer(master, ospf_handle_grace_timer_expiry, restarter,
537 actual_grace_interval,
538 &restarter->gr_helper_info.t_grace_timer);
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
548 * OSPF neighbor
549 *
550 * Returns:
551 * TRUE - if any change in the lsa.
552 * FALSE - no change in the lsas.
553 */
554 static 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
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
599 * topo change occurred due to this lsa type (1 to 5 and 7)
600 *
601 * Returns:
602 * Nothing
603 */
604 void ospf_helper_handle_topo_chg(struct ospf *ospf, struct ospf_lsa *lsa)
605 {
606 struct listnode *node;
607 struct ospf_interface *oi;
608
609 /* Topo change not required to be handled if strict
610 * LSA check is disabled for this router.
611 */
612 if (!ospf->strict_lsa_check)
613 return;
614
615 if (IS_DEBUG_OSPF_GR)
616 zlog_debug("%s: Topo change detected due to LSA[%s]", __func__,
617 dump_lsa_key(lsa));
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
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
658 * OSPF pointer.
659 *
660 * nbr
661 * OSPF neighbour for which it is acting as HELPER.
662 *
663 * reason
664 * The reason for exiting from HELPER.
665 *
666 * Returns:
667 * Nothing.
668 */
669 void ospf_gr_helper_exit(struct ospf_neighbor *nbr,
670 enum ospf_helper_exit_reason reason)
671 {
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
678 if (IS_DEBUG_OSPF_GR)
679 zlog_debug("%s, Exiting from HELPER support to %pI4, due to %s",
680 __func__, &nbr->src, ospf_exit_reason2str(reason));
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
699 * expiry, stop the grace timer.
700 */
701 if (reason != OSPF_GR_HELPER_GRACE_TIMEOUT)
702 THREAD_OFF(nbr->gr_helper_info.t_grace_timer);
703
704 /* check exit triggered due to successful completion
705 * of graceful restart.
706 */
707 if (reason != OSPF_GR_HELPER_COMPLETED) {
708 if (IS_DEBUG_OSPF_GR)
709 zlog_debug("%s, Unsuccessful GR exit", __func__);
710 }
711
712 /*Recalculate the DR for the network segment */
713 if (oi->type == OSPF_IFTYPE_BROADCAST || oi->type == OSPF_IFTYPE_NBMA)
714 ospf_dr_election(oi);
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);
722 }
723
724 /*
725 * Process MaxAge Grace LSA.
726 * It is a indication for successful completion of GR.
727 * If router acting as HELPER, It exits from helper role.
728 *
729 * ospf
730 * OSPF pointer.
731 *
732 * lsa
733 * Grace LSA received from RESTARTER.
734 *
735 * nbr
736 * OSPF neighbour which requests the router to act as
737 * HELPER.
738 *
739 * Returns:
740 * Nothing.
741 */
742 void ospf_process_maxage_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
743 struct ospf_neighbor *nbr)
744 {
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) {
756 if (IS_DEBUG_OSPF_GR)
757 zlog_debug("%s, Wrong Grace LSA packet.", __func__);
758 return;
759 }
760
761 if (IS_DEBUG_OSPF_GR)
762 zlog_debug("%s, GraceLSA received for neighbour %pI4", __func__,
763 &restartAddr);
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) {
773 if (IS_DEBUG_OSPF_GR)
774 zlog_debug(
775 "%s, Restarter is not a neighbour for this router.",
776 __func__);
777 return;
778 }
779 } else {
780 restarter = nbr;
781 }
782
783 ospf_gr_helper_exit(restarter, OSPF_GR_HELPER_COMPLETED);
784 }
785
786 /* Configuration handlers */
787 /*
788 * Disable/Enable HELPER support on router level.
789 *
790 * ospf
791 * OSPF pointer.
792 *
793 * status
794 * TRUE/FALSE
795 *
796 * Returns:
797 * Nothing.
798 */
799 void 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
832 * corresponding routerid.If enabled, don't
833 * exit from helper role.
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
864 void 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 */
919 (void)hash_get(ospf->enable_rtr_list, &temp,
920 ospf_enable_rtr_hash_alloc);
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 */
937 void 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 */
957 void 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 */
976 void ospf_gr_helper_set_supported_planned_only_restart(struct ospf *ospf,
977 bool planned_only)
978 {
979 ospf->only_planned_restart = planned_only;
980 }
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 */
995 static void show_ospf_grace_lsa_info(struct vty *vty, struct json_object *json,
996 struct ospf_lsa *lsa)
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
1006 if (json)
1007 return;
1008
1009 lsah = (struct lsa_header *)lsa->data;
1010
1011 if (lsa->size <= OSPF_LSA_HEADER_SIZE) {
1012 if (vty)
1013 vty_out(vty, "%% Invalid LSA length: %d\n", length);
1014 else
1015 zlog_debug("%% Invalid LSA length: %d", length);
1016 return;
1017 }
1018
1019 length = lsa->size - OSPF_LSA_HEADER_SIZE;
1020
1021 if (vty)
1022 vty_out(vty, " TLV info:\n");
1023 else
1024 zlog_debug(" TLV info:");
1025
1026 for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
1027 tlvh = TLV_HDR_NEXT(tlvh)) {
1028 /* Check TLV len */
1029 if (sum + TLV_SIZE(tlvh) > length) {
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));
1036 return;
1037 }
1038
1039 switch (ntohs(tlvh->type)) {
1040 case GRACE_PERIOD_TYPE:
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));
1051 return;
1052 }
1053
1054 gracePeriod = (struct grace_tlv_graceperiod *)tlvh;
1055 sum += TLV_SIZE(tlvh);
1056
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));
1063 break;
1064 case RESTART_REASON_TYPE:
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));
1075 return;
1076 }
1077
1078 grReason = (struct grace_tlv_restart_reason *)tlvh;
1079 sum += TLV_SIZE(tlvh);
1080
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));
1089 break;
1090 case RESTARTER_IP_ADDR_TYPE:
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));
1101 return;
1102 }
1103
1104 restartAddr = (struct grace_tlv_restart_addr *)tlvh;
1105 sum += TLV_SIZE(tlvh);
1106
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);
1113 break;
1114 default:
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));
1121
1122 break;
1123 }
1124 }
1125 }