]> git.proxmox.com Git - mirror_frr.git/blob - ospfd/ospf_gr_helper.c
ospfd: make reason string production safer
[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.", __PRETTY_FUNCTION__);
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.", __PRETTY_FUNCTION__);
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 length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
237
238 for (tlvh = TLV_HDR_TOP(lsah); sum < length;
239 tlvh = TLV_HDR_NEXT(tlvh)) {
240 switch (ntohs(tlvh->type)) {
241 case GRACE_PERIOD_TYPE:
242 grace_period = (struct grace_tlv_graceperiod *)tlvh;
243 *interval = ntohl(grace_period->interval);
244 sum += TLV_SIZE(tlvh);
245
246 /* Check if grace interval is valid */
247 if (*interval > OSPF_MAX_GRACE_INTERVAL
248 || *interval < OSPF_MIN_GRACE_INTERVAL)
249 return OSPF_GR_FAILURE;
250 break;
251 case RESTART_REASON_TYPE:
252 gr_reason = (struct grace_tlv_restart_reason *)tlvh;
253 *reason = gr_reason->reason;
254 sum += TLV_SIZE(tlvh);
255
256 if (*reason >= OSPF_GR_INVALID_REASON_CODE)
257 return OSPF_GR_FAILURE;
258 break;
259 case RESTARTER_IP_ADDR_TYPE:
260 restart_addr = (struct grace_tlv_restart_addr *)tlvh;
261 addr->s_addr = restart_addr->addr.s_addr;
262 sum += TLV_SIZE(tlvh);
263 break;
264 default:
265 if (IS_DEBUG_OSPF_GR_HELPER)
266 zlog_debug(
267 "%s, Malformed packet.Invalid TLV type:%d",
268 __PRETTY_FUNCTION__, ntohs(tlvh->type));
269 return OSPF_GR_FAILURE;
270 }
271 }
272
273 return OSPF_GR_SUCCESS;
274 }
275
276 /*
277 * Grace timer expiry handler.
278 * HELPER aborts its role at grace timer expiry.
279 *
280 * thread
281 * thread pointer
282 *
283 * Returns:
284 * Nothing
285 */
286 static int ospf_handle_grace_timer_expiry(struct thread *thread)
287 {
288 struct ospf_neighbor *nbr = THREAD_ARG(thread);
289
290 nbr->gr_helper_info.t_grace_timer = NULL;
291
292 ospf_gr_helper_exit(nbr, OSPF_GR_HELPER_GRACE_TIMEOUT);
293 return OSPF_GR_SUCCESS;
294 }
295
296 /*
297 * Process Grace LSA.If it is eligible move to HELPER role.
298 * Ref rfc3623 section 3.1
299 *
300 * ospf
301 * OSPF pointer.
302 *
303 * lsa
304 * Grace LSA received from RESTARTER.
305 *
306 * nbr
307 * ospf neighbour which requets the router to act as
308 * HELPER.
309 *
310 * Returns:
311 * status.
312 * If supported as HELPER : OSPF_GR_HELPER_INPROGRESS
313 * If Not supported as HELPER : OSPF_GR_HELPER_NONE
314 */
315 int ospf_process_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
316 struct ospf_neighbor *nbr)
317 {
318 struct in_addr restart_addr = {0};
319 uint8_t restart_reason = 0;
320 uint32_t grace_interval = 0;
321 uint32_t actual_grace_interval = 0;
322 struct advRtr lookup;
323 struct ospf_neighbor *restarter = NULL;
324 struct ospf_interface *oi = nbr->oi;
325 int ret;
326
327
328 /* Extract the grace lsa packet fields */
329 ret = ospf_extract_grace_lsa_fields(lsa, &grace_interval, &restart_addr,
330 &restart_reason);
331 if (ret != OSPF_GR_SUCCESS) {
332 if (IS_DEBUG_OSPF_GR_HELPER)
333 zlog_debug("%s, Wrong Grace LSA packet.",
334 __PRETTY_FUNCTION__);
335 return OSPF_GR_NOT_HELPER;
336 }
337
338 if (IS_DEBUG_OSPF_GR_HELPER)
339 zlog_debug(
340 "%s, Grace LSA received from %s, grace interval:%u, restartreason :%s",
341 __PRETTY_FUNCTION__, inet_ntoa(restart_addr),
342 grace_interval,
343 ospf_restart_reason2str(restart_reason));
344
345 /* Incase of broadcast links, if RESTARTER is DR_OTHER,
346 * grace LSA might be received from DR, so need to get
347 * actual neighbour info , here RESTARTER.
348 */
349 if (oi->type != OSPF_IFTYPE_POINTOPOINT) {
350 restarter = ospf_nbr_lookup_by_addr(oi->nbrs, &restart_addr);
351
352 if (!restarter) {
353 if (IS_DEBUG_OSPF_GR_HELPER)
354 zlog_debug(
355 "%s, Restarter is not a nbr(%s) for this router.",
356 __PRETTY_FUNCTION__,
357 inet_ntoa(restart_addr));
358 return OSPF_GR_NOT_HELPER;
359 }
360 } else
361 restarter = nbr;
362
363 /* Verify Helper enabled globally */
364 if (!ospf->is_helper_supported) {
365 /* Verify that Helper support is enabled for the
366 * current neighbour router-id.
367 */
368 lookup.advRtrAddr.s_addr = restarter->router_id.s_addr;
369
370 if (!hash_lookup(ospf->enable_rtr_list, &lookup)) {
371 if (IS_DEBUG_OSPF_GR_HELPER)
372 zlog_debug(
373 "%s, HELPER support is disabled, So not a HELPER",
374 __PRETTY_FUNCTION__);
375 restarter->gr_helper_info.rejected_reason =
376 OSPF_HELPER_SUPPORT_DISABLED;
377 return OSPF_GR_NOT_HELPER;
378 }
379 }
380
381
382 /* Check neighbour is in FULL state and
383 * became a adjacency.
384 */
385 if (!IS_NBR_STATE_FULL(restarter)) {
386 if (IS_DEBUG_OSPF_GR_HELPER)
387 zlog_debug(
388 "%s, This Neighbour %s is not in FULL state.",
389 __PRETTY_FUNCTION__, inet_ntoa(restarter->src));
390 restarter->gr_helper_info.rejected_reason =
391 OSPF_HELPER_NOT_A_VALID_NEIGHBOUR;
392 return OSPF_GR_NOT_HELPER;
393 }
394
395 /* Based on the restart reason from grace lsa
396 * check the current router is supporting or not
397 */
398 if (ospf->only_planned_restart
399 && !OSPF_GR_IS_PLANNED_RESTART(restart_reason)) {
400 if (IS_DEBUG_OSPF_GR_HELPER)
401 zlog_debug(
402 "%s, Router supports only planned restarts but received the GRACE LSA for an unplanned restart.",
403 __PRETTY_FUNCTION__);
404 restarter->gr_helper_info.rejected_reason =
405 OSPF_HELPER_PLANNED_ONLY_RESTART;
406 return OSPF_GR_NOT_HELPER;
407 }
408
409 /* Check the retranmission list of this
410 * neighbour, check any change in lsas.
411 */
412 if (ospf->strict_lsa_check && !ospf_ls_retransmit_isempty(restarter)
413 && ospf_check_change_in_rxmt_list(restarter)) {
414 if (IS_DEBUG_OSPF_GR_HELPER)
415 zlog_debug(
416 "%s, Changed LSA in Rxmt list. So not Helper.",
417 __PRETTY_FUNCTION__);
418 restarter->gr_helper_info.rejected_reason =
419 OSPF_HELPER_TOPO_CHANGE_RTXMT_LIST;
420 return OSPF_GR_NOT_HELPER;
421 }
422
423 /*LSA age must be less than the grace period */
424 if (ntohs(lsa->data->ls_age) >= grace_interval) {
425 if (IS_DEBUG_OSPF_GR_HELPER)
426 zlog_debug(
427 "%s, Grace LSA age(%d) is more than the graceinterval(%d)",
428 __PRETTY_FUNCTION__, lsa->data->ls_age,
429 grace_interval);
430 restarter->gr_helper_info.rejected_reason =
431 OSPF_HELPER_LSA_AGE_MORE;
432 return OSPF_GR_NOT_HELPER;
433 }
434
435 /* check supported grace period configured
436 * if configured, use this to start the grace
437 * timer otherwise use the interval received
438 * in grace LSA packet.
439 */
440 actual_grace_interval = grace_interval;
441 if (grace_interval > ospf->supported_grace_time) {
442 if (IS_DEBUG_OSPF_GR_HELPER)
443 zlog_debug(
444 "%s, Received grace period %d is larger than supported grace %d",
445 __PRETTY_FUNCTION__, grace_interval,
446 ospf->supported_grace_time);
447 actual_grace_interval = ospf->supported_grace_time;
448 }
449
450 if (OSPF_GR_IS_ACTIVE_HELPER(restarter)) {
451 if (restarter->gr_helper_info.t_grace_timer)
452 THREAD_OFF(restarter->gr_helper_info.t_grace_timer);
453
454 if (ospf->active_restarter_cnt > 0)
455 ospf->active_restarter_cnt--;
456
457 if (IS_DEBUG_OSPF_GR_HELPER)
458 zlog_debug(
459 "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
460 __PRETTY_FUNCTION__);
461 } else {
462 if (IS_DEBUG_OSPF_GR_HELPER)
463 zlog_debug(
464 "%s, This Router becomes a HELPER for the neighbour %s",
465 __PRETTY_FUNCTION__, inet_ntoa(restarter->src));
466 }
467
468 /* Became a Helper to the RESTART neighbour.
469 * Change the helper status.
470 */
471 restarter->gr_helper_info.gr_helper_status = OSPF_GR_ACTIVE_HELPER;
472 restarter->gr_helper_info.recvd_grace_period = grace_interval;
473 restarter->gr_helper_info.actual_grace_period = actual_grace_interval;
474 restarter->gr_helper_info.gr_restart_reason = restart_reason;
475 restarter->gr_helper_info.rejected_reason = OSPF_HELPER_REJECTED_NONE;
476
477 /* Incremnet the active restarer count */
478 ospf->active_restarter_cnt++;
479
480 if (IS_DEBUG_OSPF_GR_HELPER)
481 zlog_debug("%s, Grace timer started.interval:%d",
482 __PRETTY_FUNCTION__, actual_grace_interval);
483
484 /* Start the grace timer */
485 thread_add_timer(master, ospf_handle_grace_timer_expiry, restarter,
486 actual_grace_interval,
487 &restarter->gr_helper_info.t_grace_timer);
488
489 return OSPF_GR_ACTIVE_HELPER;
490 }
491
492 /*
493 * API to check any change in the neighbor's
494 * retransmission list.
495 *
496 * nbr
497 * ospf neighbor
498 *
499 * Returns:
500 * TRUE - if any change in the lsa.
501 * FALSE - no change in the lsas.
502 */
503 static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr)
504 {
505 struct route_node *rn;
506 struct ospf_lsa *lsa;
507 struct route_table *tbl;
508
509 tbl = nbr->ls_rxmt.type[OSPF_ROUTER_LSA].db;
510 LSDB_LOOP (tbl, rn, lsa)
511 if (lsa->to_be_acknowledged)
512 return OSPF_GR_TRUE;
513 tbl = nbr->ls_rxmt.type[OSPF_NETWORK_LSA].db;
514 LSDB_LOOP (tbl, rn, lsa)
515 if (lsa->to_be_acknowledged)
516 return OSPF_GR_TRUE;
517
518 tbl = nbr->ls_rxmt.type[OSPF_SUMMARY_LSA].db;
519 LSDB_LOOP (tbl, rn, lsa)
520 if (lsa->to_be_acknowledged)
521 return OSPF_GR_TRUE;
522
523 tbl = nbr->ls_rxmt.type[OSPF_ASBR_SUMMARY_LSA].db;
524 LSDB_LOOP (tbl, rn, lsa)
525 if (lsa->to_be_acknowledged)
526 return OSPF_GR_TRUE;
527
528 tbl = nbr->ls_rxmt.type[OSPF_AS_EXTERNAL_LSA].db;
529 LSDB_LOOP (tbl, rn, lsa)
530 if (lsa->to_be_acknowledged)
531 return OSPF_GR_TRUE;
532
533 tbl = nbr->ls_rxmt.type[OSPF_AS_NSSA_LSA].db;
534 LSDB_LOOP (tbl, rn, lsa)
535 if (lsa->to_be_acknowledged)
536 return OSPF_GR_TRUE;
537
538 return OSPF_GR_FALSE;
539 }
540
541 /*
542 * Actions to be taken when topo change detected
543 * HELPER will exit upon topo change.
544 *
545 * ospf
546 * ospf pointer
547 * lsa
548 * topo change occured due to this lsa type (1 to 5 and 7)
549 *
550 * Returns:
551 * Nothing
552 */
553 void ospf_helper_handle_topo_chg(struct ospf *ospf, struct ospf_lsa *lsa)
554 {
555 struct listnode *node;
556 struct ospf_interface *oi;
557
558 if (!ospf->active_restarter_cnt)
559 return;
560
561 /* Topo change not required to be hanlded if strict
562 * LSA check is disbaled for this router.
563 */
564 if (!ospf->strict_lsa_check)
565 return;
566
567 if (IS_DEBUG_OSPF_GR_HELPER)
568 zlog_debug(
569 "%s, Topo change detected due to lsa LSID:%s type:%d",
570 __PRETTY_FUNCTION__, inet_ntoa(lsa->data->id),
571 lsa->data->type);
572
573 lsa->to_be_acknowledged = OSPF_GR_TRUE;
574
575 for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
576 struct route_node *rn = NULL;
577
578 if (ospf_interface_neighbor_count(oi) == 0)
579 continue;
580
581 /* Ref rfc3623 section 3.2.3.b
582 * If change due to external LSA and if the area is
583 * stub, then it is not a topo change. Since Type-5
584 * lsas will not be flooded in stub area.
585 */
586 if ((oi->area->external_routing == OSPF_AREA_STUB)
587 && (lsa->data->type == OSPF_AS_EXTERNAL_LSA)) {
588 continue;
589 }
590
591 for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
592 struct ospf_neighbor *nbr = NULL;
593
594 if (!rn->info)
595 continue;
596
597 nbr = rn->info;
598
599 if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
600 ospf_gr_helper_exit(nbr,
601 OSPF_GR_HELPER_TOPO_CHG);
602 }
603 }
604 }
605
606 /*
607 * Api to exit from HELPER role to take all actions
608 * required at exit.
609 * Ref rfc3623 section 3.2
610 *
611 * ospf
612 * OSPF pointer.
613 *
614 * nbr
615 * OSPF neighbour for which it is acting as HELPER.
616 *
617 * reason
618 * The reason for exiting from HELPER.
619 *
620 * Returns:
621 * Nothing.
622 */
623 void ospf_gr_helper_exit(struct ospf_neighbor *nbr,
624 enum ospf_helper_exit_reason reason)
625 {
626 struct ospf_interface *oi = nbr->oi;
627 struct ospf *ospf = oi->ospf;
628
629 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
630 return;
631
632 if (IS_DEBUG_OSPF_GR_HELPER)
633 zlog_debug("%s, Exiting from HELPER support to %s, due to %s",
634 __PRETTY_FUNCTION__, inet_ntoa(nbr->src),
635 ospf_exit_reason2str(reason));
636
637 /* Reset helper status*/
638 nbr->gr_helper_info.gr_helper_status = OSPF_GR_NOT_HELPER;
639 nbr->gr_helper_info.helper_exit_reason = reason;
640 nbr->gr_helper_info.actual_grace_period = 0;
641 nbr->gr_helper_info.recvd_grace_period = 0;
642 nbr->gr_helper_info.gr_restart_reason = 0;
643 ospf->last_exit_reason = reason;
644
645 if (ospf->active_restarter_cnt <= 0) {
646 zlog_err(
647 "OSPF GR-Helper: active_restarter_cnt should be greater than zero here.");
648 return;
649 }
650 /* Decrement active Restarter count */
651 ospf->active_restarter_cnt--;
652
653 /* If the exit not triggered due to grace timer
654 * expairy , stop the grace timer.
655 */
656 if (reason != OSPF_GR_HELPER_GRACE_TIMEOUT)
657 THREAD_OFF(nbr->gr_helper_info.t_grace_timer);
658
659 /* check exit triggered due to successful completion
660 * of graceful restart.
661 * If no, bringdown the neighbour.
662 */
663 if (reason != OSPF_GR_HELPER_COMPLETED) {
664 if (IS_DEBUG_OSPF_GR_HELPER)
665 zlog_debug(
666 "%s, Failed GR exit, so bringing down the neighbour",
667 __PRETTY_FUNCTION__);
668 OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr);
669 }
670
671 /*Recalculate the DR for the network segment */
672 ospf_dr_election(oi);
673
674 /* Originate a router LSA */
675 ospf_router_lsa_update_area(oi->area);
676
677 /* Originate network lsa if it is an DR in the LAN */
678 if (oi->state == ISM_DR)
679 ospf_network_lsa_update(oi);
680 }
681
682 /*
683 * Process Maxage Grace LSA.
684 * It is a indication for successful completion of GR.
685 * If router acting as HELPER, It exits from helper role.
686 *
687 * ospf
688 * OSPF pointer.
689 *
690 * lsa
691 * Grace LSA received from RESTARTER.
692 *
693 * nbr
694 * ospf neighbour which requets the router to act as
695 * HELPER.
696 *
697 * Returns:
698 * Nothing.
699 */
700 void ospf_process_maxage_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
701 struct ospf_neighbor *nbr)
702 {
703 struct in_addr restartAddr = {0};
704 uint8_t restartReason = 0;
705 uint32_t graceInterval = 0;
706 struct ospf_neighbor *restarter = NULL;
707 struct ospf_interface *oi = nbr->oi;
708 int ret;
709
710 /* Extract the grace lsa packet fields */
711 ret = ospf_extract_grace_lsa_fields(lsa, &graceInterval, &restartAddr,
712 &restartReason);
713 if (ret != OSPF_GR_SUCCESS) {
714 if (IS_DEBUG_OSPF_GR_HELPER)
715 zlog_debug("%s, Wrong Grace LSA packet.",
716 __PRETTY_FUNCTION__);
717 return;
718 }
719
720 if (IS_DEBUG_OSPF_GR_HELPER)
721 zlog_debug("%s, GraceLSA received for neighbour %s.",
722 __PRETTY_FUNCTION__, inet_ntoa(restartAddr));
723
724 /* In case of broadcast links, if RESTARTER is DR_OTHER,
725 * grace LSA might be received from DR, so fetching the
726 * actual neighbour information using restarter address.
727 */
728 if (oi->type != OSPF_IFTYPE_POINTOPOINT) {
729 restarter = ospf_nbr_lookup_by_addr(oi->nbrs, &restartAddr);
730
731 if (!restarter) {
732 if (IS_DEBUG_OSPF_GR_HELPER)
733 zlog_debug(
734 "%s, Restarter is not a neighbour for this router.",
735 __PRETTY_FUNCTION__);
736 return;
737 }
738 } else {
739 restarter = nbr;
740 }
741
742 ospf_gr_helper_exit(restarter, OSPF_GR_HELPER_COMPLETED);
743 }
744
745 /* Configuration handlers */
746 /*
747 * Disable/Enable HELPER support on router level.
748 *
749 * ospf
750 * OSPFpointer.
751 *
752 * status
753 * TRUE/FALSE
754 *
755 * Returns:
756 * Nothing.
757 */
758 void ospf_gr_helper_support_set(struct ospf *ospf, bool support)
759 {
760 struct ospf_interface *oi;
761 struct listnode *node;
762 struct advRtr lookup;
763
764 if (ospf->is_helper_supported == support)
765 return;
766
767 ospf->is_helper_supported = support;
768
769 /* If helper support disabled, cease HELPER role for all
770 * supporting neighbors.
771 */
772 if (support == OSPF_GR_FALSE) {
773 for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
774 struct route_node *rn = NULL;
775
776 if (ospf_interface_neighbor_count(oi) == 0)
777 continue;
778
779 for (rn = route_top(oi->nbrs); rn;
780 rn = route_next(rn)) {
781 struct ospf_neighbor *nbr = NULL;
782
783 if (!rn->info)
784 continue;
785
786 nbr = rn->info;
787
788 lookup.advRtrAddr.s_addr =
789 nbr->router_id.s_addr;
790 /* check if helper support enabled for the
791 * correspodning routerid.If enabled, dont
792 * dont exit from helper role.
793 */
794 if (hash_lookup(ospf->enable_rtr_list, &lookup))
795 continue;
796
797 if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
798 ospf_gr_helper_exit(
799 nbr, OSPF_GR_HELPER_TOPO_CHG);
800 }
801 }
802 }
803 }
804
805 /*
806 * Enable/Disable HELPER support on a specified advertagement
807 * router.
808 *
809 * ospf
810 * OSPF pointer.
811 *
812 * advRtr
813 * HELPER support for given Advertisement Router.
814 *
815 * support
816 * True - Enable Helper Support.
817 * False - Disable Helper Support.
818 *
819 * Returns:
820 * Nothing.
821 */
822
823 void ospf_gr_helper_support_set_per_routerid(struct ospf *ospf,
824 struct in_addr *advrtr,
825 bool support)
826 {
827 struct advRtr temp;
828 struct advRtr *rtr;
829 struct ospf_interface *oi;
830 struct listnode *node;
831
832 temp.advRtrAddr.s_addr = advrtr->s_addr;
833
834 if (support == OSPF_GR_FALSE) {
835 /*Delete the routerid from the enable router hash table */
836 rtr = hash_lookup(ospf->enable_rtr_list, &temp);
837
838 if (rtr) {
839 hash_release(ospf->enable_rtr_list, rtr);
840 ospf_disable_rtr_hash_free(rtr);
841 }
842
843 /* If helper support is enabled globally
844 * no action is required.
845 */
846 if (ospf->is_helper_supported)
847 return;
848
849 /* Cease the HELPER role fore neighbours from the
850 * specified advertisement router.
851 */
852 for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
853 struct route_node *rn = NULL;
854
855 if (ospf_interface_neighbor_count(oi) == 0)
856 continue;
857
858 for (rn = route_top(oi->nbrs); rn;
859 rn = route_next(rn)) {
860 struct ospf_neighbor *nbr = NULL;
861
862 if (!rn->info)
863 continue;
864
865 nbr = rn->info;
866
867 if (nbr->router_id.s_addr != advrtr->s_addr)
868 continue;
869
870 if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
871 ospf_gr_helper_exit(
872 nbr, OSPF_GR_HELPER_TOPO_CHG);
873 }
874 }
875
876 } else {
877 /* Add the routerid to the enable router hash table */
878 hash_get(ospf->enable_rtr_list, &temp,
879 ospf_enable_rtr_hash_alloc);
880 }
881 }
882
883 /*
884 * Api to enable/disable strict lsa check on the HELPER.
885 *
886 * ospf
887 * OSPF pointer.
888 *
889 * enabled
890 * True - disable the lsa check.
891 * False - enable the strict lsa check.
892 *
893 * Returns:
894 * Nothing.
895 */
896 void ospf_gr_helper_lsa_check_set(struct ospf *ospf, bool enabled)
897 {
898 if (ospf->strict_lsa_check == enabled)
899 return;
900
901 ospf->strict_lsa_check = enabled;
902 }
903
904 /*
905 * Api to set the supported grace interval in this router.
906 *
907 * ospf
908 * OSPF pointer.
909 *
910 * interval
911 * The supported grace interval..
912 *
913 * Returns:
914 * Nothing.
915 */
916 void ospf_gr_helper_supported_gracetime_set(struct ospf *ospf,
917 uint32_t interval)
918 {
919 ospf->supported_grace_time = interval;
920 }
921
922 /*
923 * Api to set the supported restart reason.
924 *
925 * ospf
926 * OSPF pointer.
927 *
928 * planned_only
929 * True: support only planned restart.
930 * False: support for planned/unplanned restarts.
931 *
932 * Returns:
933 * Nothing.
934 */
935 void ospf_gr_helper_set_supported_planned_only_restart(struct ospf *ospf,
936 bool planned_only)
937 {
938 ospf->only_planned_restart = planned_only;
939 }
940
941 /*
942 * Api to display the grace LSA information.
943 *
944 * vty
945 * vty pointer.
946 * lsa
947 * Grace LSA.
948 * json
949 * json object
950 *
951 * Returns:
952 * Nothing.
953 */
954 static void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa)
955 {
956 struct lsa_header *lsah = NULL;
957 struct tlv_header *tlvh = NULL;
958 struct grace_tlv_graceperiod *gracePeriod;
959 struct grace_tlv_restart_reason *grReason;
960 struct grace_tlv_restart_addr *restartAddr;
961 uint16_t length = 0;
962 int sum = 0;
963
964 lsah = (struct lsa_header *)lsa->data;
965
966 length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
967
968 vty_out(vty, " TLV info:\n");
969
970 for (tlvh = TLV_HDR_TOP(lsah); sum < length;
971 tlvh = TLV_HDR_NEXT(tlvh)) {
972 switch (ntohs(tlvh->type)) {
973 case GRACE_PERIOD_TYPE:
974 gracePeriod = (struct grace_tlv_graceperiod *)tlvh;
975 sum += TLV_SIZE(tlvh);
976
977 vty_out(vty, " Grace period:%d\n",
978 ntohl(gracePeriod->interval));
979 break;
980 case RESTART_REASON_TYPE:
981 grReason = (struct grace_tlv_restart_reason *)tlvh;
982 sum += TLV_SIZE(tlvh);
983
984 vty_out(vty, " Restart reason:%s\n",
985 ospf_restart_reason2str(grReason->reason));
986 break;
987 case RESTARTER_IP_ADDR_TYPE:
988 restartAddr = (struct grace_tlv_restart_addr *)tlvh;
989 sum += TLV_SIZE(tlvh);
990
991 vty_out(vty, " Restarter address:%s\n",
992 inet_ntoa(restartAddr->addr));
993 break;
994 default:
995 break;
996 }
997 }
998 }