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