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