]> git.proxmox.com Git - mirror_frr.git/blob - ospfd/ospf_gr_helper.c
ospfd: GR helper config commands
[mirror_frr.git] / ospfd / ospf_gr_helper.c
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"
51 #include "ospfd/ospf_gr_helper.h"
52
53 const char *ospf_exit_reason_desc[] = {
54 "Unknown reason",
55 "Helper inprogress",
56 "Topology Change",
57 "Grace timer expairy",
58 "Successful graceful restart",
59 };
60
61 const char *ospf_restart_reason_desc[] = {
62 "Unknown restart",
63 "Software restart",
64 "Software reload/upgrade",
65 "Switch to redundant control processor",
66 };
67
68 const char *ospf_rejected_reason_desc[] = {
69 "Unknown reason",
70 "Helper support disabled",
71 "Neighbour is not in FULL state",
72 "Supports only planned restart but received for unplanned",
73 "Topo change due to change in lsa rxmt list",
74 "LSA age is more than Grace interval",
75 };
76
77 static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr);
78
79 static unsigned int ospf_enable_rtr_hash_key(const void *data)
80 {
81 const struct advRtr *rtr = data;
82
83 return jhash_1word(rtr->advRtrAddr.s_addr, 0);
84 }
85
86 static bool ospf_enable_rtr_hash_cmp(const void *d1, const void *d2)
87 {
88 const struct advRtr *rtr1 = (struct advRtr *)d1;
89 const struct advRtr *rtr2 = (struct advRtr *)d2;
90
91 return (rtr1->advRtrAddr.s_addr == rtr2->advRtrAddr.s_addr);
92 }
93
94 static void *ospf_enable_rtr_hash_alloc(void *p)
95 {
96 struct advRtr *rid;
97
98 rid = XCALLOC(MTYPE_OSPF_GR_HELPER, sizeof(struct advRtr));
99 rid->advRtrAddr.s_addr = ((struct in_addr *)p)->s_addr;
100
101 return rid;
102 }
103
104 static void ospf_disable_rtr_hash_free(void *rtr)
105 {
106 XFREE(MTYPE_OSPF_GR_HELPER, rtr);
107 }
108
109 static void ospf_enable_rtr_hash_destroy(struct ospf *ospf)
110 {
111 if (ospf->enable_rtr_list == NULL)
112 return;
113
114 hash_clean(ospf->enable_rtr_list, ospf_disable_rtr_hash_free);
115 hash_free(ospf->enable_rtr_list);
116 ospf->enable_rtr_list = NULL;
117 }
118
119 /*
120 * Initialize GR helper config data structures.
121 *
122 * OSPF
123 * OSPF pointer
124 *
125 * Returns:
126 * Nothing
127 */
128 void ospf_gr_helper_init(struct ospf *ospf)
129 {
130 if (IS_DEBUG_OSPF_GR_HELPER)
131 zlog_debug("%s, GR Helper init.", __PRETTY_FUNCTION__);
132
133 ospf->is_helper_supported = OSPF_GR_FALSE;
134 ospf->strict_lsa_check = OSPF_GR_TRUE;
135 ospf->only_planned_restart = OSPF_GR_FALSE;
136 ospf->supported_grace_time = OSPF_MAX_GRACE_INTERVAL;
137 ospf->last_exit_reason = OSPF_GR_HELPER_EXIT_NONE;
138 ospf->active_restarter_cnt = 0;
139
140 ospf->enable_rtr_list =
141 hash_create(ospf_enable_rtr_hash_key, ospf_enable_rtr_hash_cmp,
142 "OSPF enable router hash");
143 }
144
145 /*
146 * De-Initialize GR helper config data structures.
147 *
148 * OSPF
149 * OSPF pointer
150 *
151 * Returns:
152 * Nothing
153 */
154 void ospf_gr_helper_stop(struct ospf *ospf)
155 {
156
157 if (IS_DEBUG_OSPF_GR_HELPER)
158 zlog_debug("%s, GR helper deinit.", __PRETTY_FUNCTION__);
159
160 ospf_enable_rtr_hash_destroy(ospf);
161 }
162
163 /*
164 * Extracting tlv info from GRACE LSA.
165 *
166 * lsa
167 * ospf grace lsa
168 *
169 * Returns:
170 * interval : grace interval.
171 * addr : RESTARTER address.
172 * reason : Restarting reason.
173 */
174 static int ospf_extract_grace_lsa_fields(struct ospf_lsa *lsa,
175 uint32_t *interval,
176 struct in_addr *addr, uint8_t *reason)
177 {
178 struct lsa_header *lsah = NULL;
179 struct tlv_header *tlvh = NULL;
180 struct grace_tlv_graceperiod *grace_period;
181 struct grace_tlv_restart_reason *gr_reason;
182 struct grace_tlv_restart_addr *restart_addr;
183 uint16_t length = 0;
184 int sum = 0;
185
186 lsah = (struct lsa_header *)lsa->data;
187
188 length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
189
190 for (tlvh = TLV_HDR_TOP(lsah); sum < length;
191 tlvh = TLV_HDR_NEXT(tlvh)) {
192 switch (ntohs(tlvh->type)) {
193 case GRACE_PERIOD_TYPE:
194 grace_period = (struct grace_tlv_graceperiod *)tlvh;
195 *interval = ntohl(grace_period->interval);
196 sum += TLV_SIZE(tlvh);
197
198 /* Check if grace interval is valid */
199 if (*interval > OSPF_MAX_GRACE_INTERVAL
200 || *interval < OSPF_MIN_GRACE_INTERVAL)
201 return OSPF_GR_FAILURE;
202 break;
203 case RESTART_REASON_TYPE:
204 gr_reason = (struct grace_tlv_restart_reason *)tlvh;
205 *reason = gr_reason->reason;
206 sum += TLV_SIZE(tlvh);
207
208 if (*reason >= OSPF_GR_INVALID_REASON_CODE)
209 return OSPF_GR_FAILURE;
210 break;
211 case RESTARTER_IP_ADDR_TYPE:
212 restart_addr = (struct grace_tlv_restart_addr *)tlvh;
213 addr->s_addr = restart_addr->addr.s_addr;
214 sum += TLV_SIZE(tlvh);
215 break;
216 default:
217 if (IS_DEBUG_OSPF_GR_HELPER)
218 zlog_debug(
219 "%s, Malformed packet.Invalid TLV type:%d",
220 __PRETTY_FUNCTION__, ntohs(tlvh->type));
221 return OSPF_GR_FAILURE;
222 }
223 }
224
225 return OSPF_GR_SUCCESS;
226 }
227
228 /*
229 * Grace timer expiry handler.
230 * HELPER aborts its role at grace timer expiry.
231 *
232 * thread
233 * thread pointer
234 *
235 * Returns:
236 * Nothing
237 */
238 static int ospf_handle_grace_timer_expiry(struct thread *thread)
239 {
240 struct ospf_neighbor *nbr = THREAD_ARG(thread);
241
242 nbr->gr_helper_info.t_grace_timer = NULL;
243
244 ospf_gr_helper_exit(nbr, OSPF_GR_HELPER_GRACE_TIMEOUT);
245 return OSPF_GR_SUCCESS;
246 }
247
248 /*
249 * Process Grace LSA.If it is eligible move to HELPER role.
250 * Ref rfc3623 section 3.1
251 *
252 * ospf
253 * OSPF pointer.
254 *
255 * lsa
256 * Grace LSA received from RESTARTER.
257 *
258 * nbr
259 * ospf neighbour which requets the router to act as
260 * HELPER.
261 *
262 * Returns:
263 * status.
264 * If supported as HELPER : OSPF_GR_HELPER_INPROGRESS
265 * If Not supported as HELPER : OSPF_GR_HELPER_NONE
266 */
267 int ospf_process_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
268 struct ospf_neighbor *nbr)
269 {
270 struct in_addr restart_addr = {0};
271 uint8_t restart_reason = 0;
272 uint32_t grace_interval = 0;
273 uint32_t actual_grace_interval = 0;
274 struct advRtr lookup;
275 struct ospf_neighbor *restarter = NULL;
276 struct ospf_interface *oi = nbr->oi;
277 int ret;
278
279
280 /* Extract the grace lsa packet fields */
281 ret = ospf_extract_grace_lsa_fields(lsa, &grace_interval, &restart_addr,
282 &restart_reason);
283 if (ret != OSPF_GR_SUCCESS) {
284 if (IS_DEBUG_OSPF_GR_HELPER)
285 zlog_debug("%s, Wrong Grace LSA packet.",
286 __PRETTY_FUNCTION__);
287 return OSPF_GR_NOT_HELPER;
288 }
289
290 if (IS_DEBUG_OSPF_GR_HELPER)
291 zlog_debug(
292 "%s, Grace LSA received from %s, grace interval:%u, restartreason :%s",
293 __PRETTY_FUNCTION__, inet_ntoa(restart_addr),
294 grace_interval, ospf_restart_reason_desc[restart_reason]);
295
296 /* Incase of broadcast links, if RESTARTER is DR_OTHER,
297 * grace LSA might be received from DR, so need to get
298 * actual neighbour info , here RESTARTER.
299 */
300 if (oi->type != OSPF_IFTYPE_POINTOPOINT) {
301 restarter = ospf_nbr_lookup_by_addr(oi->nbrs, &restart_addr);
302
303 if (!restarter) {
304 if (IS_DEBUG_OSPF_GR_HELPER)
305 zlog_debug(
306 "%s, Restarter is not a nbr(%s) for this router.",
307 __PRETTY_FUNCTION__,
308 inet_ntoa(restart_addr));
309 return OSPF_GR_NOT_HELPER;
310 }
311 } else
312 restarter = nbr;
313
314 /* Verify Helper enabled globally */
315 if (!ospf->is_helper_supported) {
316 /* Verify that Helper support is enabled for the
317 * current neighbour router-id.
318 */
319 lookup.advRtrAddr.s_addr = restarter->router_id.s_addr;
320
321 if (!hash_lookup(ospf->enable_rtr_list, &lookup)) {
322 if (IS_DEBUG_OSPF_GR_HELPER)
323 zlog_debug(
324 "%s, HELPER support is disabled, So not a HELPER",
325 __PRETTY_FUNCTION__);
326 restarter->gr_helper_info.rejected_reason =
327 OSPF_HELPER_SUPPORT_DISABLED;
328 return OSPF_GR_NOT_HELPER;
329 }
330 }
331
332
333 /* Check neighbour is in FULL state and
334 * became a adjacency.
335 */
336 if (!IS_NBR_STATE_FULL(restarter)) {
337 if (IS_DEBUG_OSPF_GR_HELPER)
338 zlog_debug(
339 "%s, This Neighbour %s is not in FULL state.",
340 __PRETTY_FUNCTION__, inet_ntoa(restarter->src));
341 restarter->gr_helper_info.rejected_reason =
342 OSPF_HELPER_NOT_A_VALID_NEIGHBOUR;
343 return OSPF_GR_NOT_HELPER;
344 }
345
346 /* Based on the restart reason from grace lsa
347 * check the current router is supporting or not
348 */
349 if (ospf->only_planned_restart
350 && !OSPF_GR_IS_PLANNED_RESTART(restart_reason)) {
351 if (IS_DEBUG_OSPF_GR_HELPER)
352 zlog_debug(
353 "%s, Router supports only planned restarts but received the GRACE LSA for an unplanned restart.",
354 __PRETTY_FUNCTION__);
355 restarter->gr_helper_info.rejected_reason =
356 OSPF_HELPER_PLANNED_ONLY_RESTART;
357 return OSPF_GR_NOT_HELPER;
358 }
359
360 /* Check the retranmission list of this
361 * neighbour, check any change in lsas.
362 */
363 if (ospf->strict_lsa_check && !ospf_ls_retransmit_isempty(restarter)
364 && ospf_check_change_in_rxmt_list(restarter)) {
365 if (IS_DEBUG_OSPF_GR_HELPER)
366 zlog_debug(
367 "%s, Changed LSA in Rxmt list. So not Helper.",
368 __PRETTY_FUNCTION__);
369 restarter->gr_helper_info.rejected_reason =
370 OSPF_HELPER_TOPO_CHANGE_RTXMT_LIST;
371 return OSPF_GR_NOT_HELPER;
372 }
373
374 /*LSA age must be less than the grace period */
375 if (ntohs(lsa->data->ls_age) >= grace_interval) {
376 if (IS_DEBUG_OSPF_GR_HELPER)
377 zlog_debug(
378 "%s, Grace LSA age(%d) is more than the graceinterval(%d)",
379 __PRETTY_FUNCTION__, lsa->data->ls_age,
380 grace_interval);
381 restarter->gr_helper_info.rejected_reason =
382 OSPF_HELPER_LSA_AGE_MORE;
383 return OSPF_GR_NOT_HELPER;
384 }
385
386 /* check supported grace period configured
387 * if configured, use this to start the grace
388 * timer otherwise use the interval received
389 * in grace LSA packet.
390 */
391 actual_grace_interval = grace_interval;
392 if (grace_interval > ospf->supported_grace_time) {
393 if (IS_DEBUG_OSPF_GR_HELPER)
394 zlog_debug(
395 "%s, Received grace period %d is larger than supported grace %d",
396 __PRETTY_FUNCTION__, grace_interval,
397 ospf->supported_grace_time);
398 actual_grace_interval = ospf->supported_grace_time;
399 }
400
401 if (OSPF_GR_IS_ACTIVE_HELPER(restarter)) {
402 if (restarter->gr_helper_info.t_grace_timer)
403 THREAD_OFF(restarter->gr_helper_info.t_grace_timer);
404
405 if (ospf->active_restarter_cnt > 0)
406 ospf->active_restarter_cnt--;
407
408 if (IS_DEBUG_OSPF_GR_HELPER)
409 zlog_debug(
410 "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
411 __PRETTY_FUNCTION__);
412 } else {
413 if (IS_DEBUG_OSPF_GR_HELPER)
414 zlog_debug(
415 "%s, This Router becomes a HELPER for the neighbour %s",
416 __PRETTY_FUNCTION__, inet_ntoa(restarter->src));
417 }
418
419 /* Became a Helper to the RESTART neighbour.
420 * Change the helper status.
421 */
422 restarter->gr_helper_info.gr_helper_status = OSPF_GR_ACTIVE_HELPER;
423 restarter->gr_helper_info.recvd_grace_period = grace_interval;
424 restarter->gr_helper_info.actual_grace_period = actual_grace_interval;
425 restarter->gr_helper_info.gr_restart_reason = restart_reason;
426 restarter->gr_helper_info.rejected_reason = OSPF_HELPER_REJECTED_NONE;
427
428 /* Incremnet the active restarer count */
429 ospf->active_restarter_cnt++;
430
431 if (IS_DEBUG_OSPF_GR_HELPER)
432 zlog_debug("%s, Grace timer started.interval:%d",
433 __PRETTY_FUNCTION__, actual_grace_interval);
434
435 /* Start the grace timer */
436 thread_add_timer(master, ospf_handle_grace_timer_expiry, restarter,
437 actual_grace_interval,
438 &restarter->gr_helper_info.t_grace_timer);
439
440 return OSPF_GR_ACTIVE_HELPER;
441 }
442
443 /*
444 * API to check any change in the neighbor's
445 * retransmission list.
446 *
447 * nbr
448 * ospf neighbor
449 *
450 * Returns:
451 * TRUE - if any change in the lsa.
452 * FALSE - no change in the lsas.
453 */
454 static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr)
455 {
456 struct route_node *rn;
457 struct ospf_lsa *lsa;
458 struct route_table *tbl;
459
460 tbl = nbr->ls_rxmt.type[OSPF_ROUTER_LSA].db;
461 LSDB_LOOP (tbl, rn, lsa)
462 if (lsa->to_be_acknowledged)
463 return OSPF_GR_TRUE;
464 tbl = nbr->ls_rxmt.type[OSPF_NETWORK_LSA].db;
465 LSDB_LOOP (tbl, rn, lsa)
466 if (lsa->to_be_acknowledged)
467 return OSPF_GR_TRUE;
468
469 tbl = nbr->ls_rxmt.type[OSPF_SUMMARY_LSA].db;
470 LSDB_LOOP (tbl, rn, lsa)
471 if (lsa->to_be_acknowledged)
472 return OSPF_GR_TRUE;
473
474 tbl = nbr->ls_rxmt.type[OSPF_ASBR_SUMMARY_LSA].db;
475 LSDB_LOOP (tbl, rn, lsa)
476 if (lsa->to_be_acknowledged)
477 return OSPF_GR_TRUE;
478
479 tbl = nbr->ls_rxmt.type[OSPF_AS_EXTERNAL_LSA].db;
480 LSDB_LOOP (tbl, rn, lsa)
481 if (lsa->to_be_acknowledged)
482 return OSPF_GR_TRUE;
483
484 tbl = nbr->ls_rxmt.type[OSPF_AS_NSSA_LSA].db;
485 LSDB_LOOP (tbl, rn, lsa)
486 if (lsa->to_be_acknowledged)
487 return OSPF_GR_TRUE;
488
489 return OSPF_GR_FALSE;
490 }
491
492 /*
493 * Actions to be taken when topo change detected
494 * HELPER will exit upon topo change.
495 *
496 * ospf
497 * ospf pointer
498 * lsa
499 * topo change occured due to this lsa type (1 to 5 and 7)
500 *
501 * Returns:
502 * Nothing
503 */
504 void ospf_helper_handle_topo_chg(struct ospf *ospf, struct ospf_lsa *lsa)
505 {
506 struct listnode *node;
507 struct ospf_interface *oi;
508
509 if (!ospf->active_restarter_cnt)
510 return;
511
512 /* Topo change not required to be hanlded if strict
513 * LSA check is disbaled for this router.
514 */
515 if (!ospf->strict_lsa_check)
516 return;
517
518 if (IS_DEBUG_OSPF_GR_HELPER)
519 zlog_debug(
520 "%s, Topo change detected due to lsa LSID:%s type:%d",
521 __PRETTY_FUNCTION__, inet_ntoa(lsa->data->id),
522 lsa->data->type);
523
524 lsa->to_be_acknowledged = OSPF_GR_TRUE;
525
526 for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
527 struct route_node *rn = NULL;
528
529 if (ospf_interface_neighbor_count(oi) == 0)
530 continue;
531
532 /* Ref rfc3623 section 3.2.3.b
533 * If change due to external LSA and if the area is
534 * stub, then it is not a topo change. Since Type-5
535 * lsas will not be flooded in stub area.
536 */
537 if ((oi->area->external_routing == OSPF_AREA_STUB)
538 && (lsa->data->type == OSPF_AS_EXTERNAL_LSA)) {
539 continue;
540 }
541
542 for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
543 struct ospf_neighbor *nbr = NULL;
544
545 if (!rn->info)
546 continue;
547
548 nbr = rn->info;
549
550 if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
551 ospf_gr_helper_exit(nbr,
552 OSPF_GR_HELPER_TOPO_CHG);
553 }
554 }
555 }
556
557 /*
558 * Api to exit from HELPER role to take all actions
559 * required at exit.
560 * Ref rfc3623 section 3.2
561 *
562 * ospf
563 * OSPF pointer.
564 *
565 * nbr
566 * OSPF neighbour for which it is acting as HELPER.
567 *
568 * reason
569 * The reason for exiting from HELPER.
570 *
571 * Returns:
572 * Nothing.
573 */
574 void ospf_gr_helper_exit(struct ospf_neighbor *nbr,
575 enum ospf_helper_exit_reason reason)
576 {
577 struct ospf_interface *oi = nbr->oi;
578 struct ospf *ospf = oi->ospf;
579
580 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
581 return;
582
583 if (IS_DEBUG_OSPF_GR_HELPER)
584 zlog_debug("%s, Exiting from HELPER support to %s, due to %s",
585 __PRETTY_FUNCTION__, inet_ntoa(nbr->src),
586 ospf_exit_reason_desc[reason]);
587
588 /* Reset helper status*/
589 nbr->gr_helper_info.gr_helper_status = OSPF_GR_NOT_HELPER;
590 nbr->gr_helper_info.helper_exit_reason = reason;
591 nbr->gr_helper_info.actual_grace_period = 0;
592 nbr->gr_helper_info.recvd_grace_period = 0;
593 nbr->gr_helper_info.gr_restart_reason = 0;
594 ospf->last_exit_reason = reason;
595
596 if (ospf->active_restarter_cnt <= 0) {
597 zlog_err(
598 "OSPF GR-Helper: active_restarter_cnt should be greater than zero here.");
599 return;
600 }
601 /* Decrement active Restarter count */
602 ospf->active_restarter_cnt--;
603
604 /* If the exit not triggered due to grace timer
605 * expairy , stop the grace timer.
606 */
607 if (reason != OSPF_GR_HELPER_GRACE_TIMEOUT)
608 THREAD_OFF(nbr->gr_helper_info.t_grace_timer);
609
610 /* check exit triggered due to successful completion
611 * of graceful restart.
612 * If no, bringdown the neighbour.
613 */
614 if (reason != OSPF_GR_HELPER_COMPLETED) {
615 if (IS_DEBUG_OSPF_GR_HELPER)
616 zlog_debug(
617 "%s, Failed GR exit, so bringing down the neighbour",
618 __PRETTY_FUNCTION__);
619 OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr);
620 }
621
622 /*Recalculate the DR for the network segment */
623 ospf_dr_election(oi);
624
625 /* Originate a router LSA */
626 ospf_router_lsa_update_area(oi->area);
627
628 /* Originate network lsa if it is an DR in the LAN */
629 if (oi->state == ISM_DR)
630 ospf_network_lsa_update(oi);
631 }
632
633 /*
634 * Process Maxage Grace LSA.
635 * It is a indication for successful completion of GR.
636 * If router acting as HELPER, It exits from helper role.
637 *
638 * ospf
639 * OSPF pointer.
640 *
641 * lsa
642 * Grace LSA received from RESTARTER.
643 *
644 * nbr
645 * ospf neighbour which requets the router to act as
646 * HELPER.
647 *
648 * Returns:
649 * Nothing.
650 */
651 void ospf_process_maxage_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
652 struct ospf_neighbor *nbr)
653 {
654 struct in_addr restartAddr = {0};
655 uint8_t restartReason = 0;
656 uint32_t graceInterval = 0;
657 struct ospf_neighbor *restarter = NULL;
658 struct ospf_interface *oi = nbr->oi;
659 int ret;
660
661 /* Extract the grace lsa packet fields */
662 ret = ospf_extract_grace_lsa_fields(lsa, &graceInterval, &restartAddr,
663 &restartReason);
664 if (ret != OSPF_GR_SUCCESS) {
665 if (IS_DEBUG_OSPF_GR_HELPER)
666 zlog_debug("%s, Wrong Grace LSA packet.",
667 __PRETTY_FUNCTION__);
668 return;
669 }
670
671 if (IS_DEBUG_OSPF_GR_HELPER)
672 zlog_debug("%s, GraceLSA received for neighbour %s.",
673 __PRETTY_FUNCTION__, inet_ntoa(restartAddr));
674
675 /* In case of broadcast links, if RESTARTER is DR_OTHER,
676 * grace LSA might be received from DR, so fetching the
677 * actual neighbour information using restarter address.
678 */
679 if (oi->type != OSPF_IFTYPE_POINTOPOINT) {
680 restarter = ospf_nbr_lookup_by_addr(oi->nbrs, &restartAddr);
681
682 if (!restarter) {
683 if (IS_DEBUG_OSPF_GR_HELPER)
684 zlog_debug(
685 "%s, Restarter is not a neighbour for this router.",
686 __PRETTY_FUNCTION__);
687 return;
688 }
689 } else {
690 restarter = nbr;
691 }
692
693 ospf_gr_helper_exit(restarter, OSPF_GR_HELPER_COMPLETED);
694 }
695
696 /* Configuration handlers */
697 /*
698 * Disable/Enable HELPER support on router level.
699 *
700 * ospf
701 * OSPFpointer.
702 *
703 * status
704 * TRUE/FALSE
705 *
706 * Returns:
707 * Nothing.
708 */
709 void ospf_gr_helper_support_set(struct ospf *ospf, bool support)
710 {
711 struct ospf_interface *oi;
712 struct listnode *node;
713 struct advRtr lookup;
714
715 if (ospf->is_helper_supported == support)
716 return;
717
718 ospf->is_helper_supported = support;
719
720 /* If helper support disabled, cease HELPER role for all
721 * supporting neighbors.
722 */
723 if (support == OSPF_GR_FALSE) {
724 for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
725 struct route_node *rn = NULL;
726
727 if (ospf_interface_neighbor_count(oi) == 0)
728 continue;
729
730 for (rn = route_top(oi->nbrs); rn;
731 rn = route_next(rn)) {
732 struct ospf_neighbor *nbr = NULL;
733
734 if (!rn->info)
735 continue;
736
737 nbr = rn->info;
738
739 lookup.advRtrAddr.s_addr =
740 nbr->router_id.s_addr;
741 /* check if helper support enabled for the
742 * correspodning routerid.If enabled, dont
743 * dont exit from helper role.
744 */
745 if (hash_lookup(ospf->enable_rtr_list, &lookup))
746 continue;
747
748 if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
749 ospf_gr_helper_exit(
750 nbr, OSPF_GR_HELPER_TOPO_CHG);
751 }
752 }
753 }
754 }
755
756 /*
757 * Enable/Disable HELPER support on a specified advertagement
758 * router.
759 *
760 * ospf
761 * OSPF pointer.
762 *
763 * advRtr
764 * HELPER support for given Advertisement Router.
765 *
766 * support
767 * True - Enable Helper Support.
768 * False - Disable Helper Support.
769 *
770 * Returns:
771 * Nothing.
772 */
773
774 void ospf_gr_helper_support_set_per_routerid(struct ospf *ospf,
775 struct in_addr *advrtr,
776 bool support)
777 {
778 struct advRtr temp;
779 struct advRtr *rtr;
780 struct ospf_interface *oi;
781 struct listnode *node;
782
783 temp.advRtrAddr.s_addr = advrtr->s_addr;
784
785 if (support == OSPF_GR_FALSE) {
786 /*Delete the routerid from the enable router hash table */
787 rtr = hash_lookup(ospf->enable_rtr_list, &temp);
788
789 if (rtr) {
790 hash_release(ospf->enable_rtr_list, rtr);
791 ospf_disable_rtr_hash_free(rtr);
792 }
793
794 /* If helper support is enabled globally
795 * no action is required.
796 */
797 if (ospf->is_helper_supported)
798 return;
799
800 /* Cease the HELPER role fore neighbours from the
801 * specified advertisement router.
802 */
803 for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
804 struct route_node *rn = NULL;
805
806 if (ospf_interface_neighbor_count(oi) == 0)
807 continue;
808
809 for (rn = route_top(oi->nbrs); rn;
810 rn = route_next(rn)) {
811 struct ospf_neighbor *nbr = NULL;
812
813 if (!rn->info)
814 continue;
815
816 nbr = rn->info;
817
818 if (nbr->router_id.s_addr != advrtr->s_addr)
819 continue;
820
821 if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
822 ospf_gr_helper_exit(
823 nbr, OSPF_GR_HELPER_TOPO_CHG);
824 }
825 }
826
827 } else {
828 /* Add the routerid to the enable router hash table */
829 hash_get(ospf->enable_rtr_list, &temp,
830 ospf_enable_rtr_hash_alloc);
831 }
832 }
833
834 /*
835 * Api to enable/disable strict lsa check on the HELPER.
836 *
837 * ospf
838 * OSPF pointer.
839 *
840 * enabled
841 * True - disable the lsa check.
842 * False - enable the strict lsa check.
843 *
844 * Returns:
845 * Nothing.
846 */
847 void ospf_gr_helper_lsa_check_set(struct ospf *ospf, bool enabled)
848 {
849 if (ospf->strict_lsa_check == enabled)
850 return;
851
852 ospf->strict_lsa_check = enabled;
853 }
854
855 /*
856 * Api to set the supported grace interval in this router.
857 *
858 * ospf
859 * OSPF pointer.
860 *
861 * interval
862 * The supported grace interval..
863 *
864 * Returns:
865 * Nothing.
866 */
867 void ospf_gr_helper_supported_gracetime_set(struct ospf *ospf,
868 uint32_t interval)
869 {
870 ospf->supported_grace_time = interval;
871 }
872
873 /*
874 * Api to set the supported restart reason.
875 *
876 * ospf
877 * OSPF pointer.
878 *
879 * planned_only
880 * True: support only planned restart.
881 * False: support for planned/unplanned restarts.
882 *
883 * Returns:
884 * Nothing.
885 */
886 void ospf_gr_helper_set_supported_planned_only_restart(struct ospf *ospf,
887 bool planned_only)
888 {
889 ospf->only_planned_restart = planned_only;
890 }