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