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