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