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