Line data Source code
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 0 : static unsigned int ospf_enable_rtr_hash_key(const void *data)
83 : {
84 0 : const struct advRtr *rtr = data;
85 :
86 0 : return jhash_1word(rtr->advRtrAddr.s_addr, 0);
87 : }
88 :
89 0 : static bool ospf_enable_rtr_hash_cmp(const void *d1, const void *d2)
90 : {
91 0 : const struct advRtr *rtr1 = (struct advRtr *)d1;
92 0 : const struct advRtr *rtr2 = (struct advRtr *)d2;
93 :
94 0 : return (rtr1->advRtrAddr.s_addr == rtr2->advRtrAddr.s_addr);
95 : }
96 :
97 0 : static void *ospf_enable_rtr_hash_alloc(void *p)
98 : {
99 0 : struct advRtr *rid;
100 :
101 0 : rid = XCALLOC(MTYPE_OSPF_GR_HELPER, sizeof(struct advRtr));
102 0 : rid->advRtrAddr.s_addr = ((struct in_addr *)p)->s_addr;
103 :
104 0 : return rid;
105 : }
106 :
107 0 : static void ospf_disable_rtr_hash_free(void *rtr)
108 : {
109 0 : XFREE(MTYPE_OSPF_GR_HELPER, rtr);
110 0 : }
111 :
112 4 : static void ospf_enable_rtr_hash_destroy(struct ospf *ospf)
113 : {
114 4 : if (ospf->enable_rtr_list == NULL)
115 : return;
116 :
117 4 : hash_clean(ospf->enable_rtr_list, ospf_disable_rtr_hash_free);
118 4 : hash_free(ospf->enable_rtr_list);
119 4 : ospf->enable_rtr_list = NULL;
120 : }
121 :
122 : /*
123 : * GR exit reason strings
124 : */
125 0 : const char *ospf_exit_reason2str(unsigned int reason)
126 : {
127 0 : if (reason < array_size(ospf_exit_reason_desc))
128 0 : return(ospf_exit_reason_desc[reason]);
129 : else
130 : return "Invalid reason";
131 : }
132 :
133 : /*
134 : * GR restart reason strings
135 : */
136 0 : const char *ospf_restart_reason2str(unsigned int reason)
137 : {
138 0 : if (reason < array_size(ospf_restart_reason_desc))
139 0 : return(ospf_restart_reason_desc[reason]);
140 : else
141 : return "Invalid reason";
142 : }
143 :
144 : /*
145 : * GR rejected reason strings
146 : */
147 0 : const char *ospf_rejected_reason2str(unsigned int reason)
148 : {
149 0 : if (reason < array_size(ospf_rejected_reason_desc))
150 0 : 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 4 : void ospf_gr_helper_instance_init(struct ospf *ospf)
165 : {
166 4 : if (IS_DEBUG_OSPF_GR)
167 0 : zlog_debug("%s, GR Helper init.", __func__);
168 :
169 4 : ospf->is_helper_supported = OSPF_GR_FALSE;
170 4 : ospf->strict_lsa_check = OSPF_GR_TRUE;
171 4 : ospf->only_planned_restart = OSPF_GR_FALSE;
172 4 : ospf->supported_grace_time = OSPF_MAX_GRACE_INTERVAL;
173 4 : ospf->last_exit_reason = OSPF_GR_HELPER_EXIT_NONE;
174 4 : ospf->active_restarter_cnt = 0;
175 :
176 8 : ospf->enable_rtr_list =
177 4 : hash_create(ospf_enable_rtr_hash_key, ospf_enable_rtr_hash_cmp,
178 : "OSPF enable router hash");
179 4 : }
180 :
181 : /*
182 : * De-Initialize GR helper config data structures.
183 : *
184 : * OSPF
185 : * OSPF pointer
186 : *
187 : * Returns:
188 : * Nothing
189 : */
190 4 : void ospf_gr_helper_instance_stop(struct ospf *ospf)
191 : {
192 4 : if (IS_DEBUG_OSPF_GR)
193 0 : zlog_debug("%s, GR helper deinit.", __func__);
194 :
195 4 : ospf_enable_rtr_hash_destroy(ospf);
196 4 : }
197 :
198 : /*
199 : * Initialize GR helper config data structures.
200 : *
201 : * Returns:
202 : * Nothing
203 : */
204 4 : void ospf_gr_helper_init(void)
205 : {
206 4 : int rc;
207 :
208 4 : if (IS_DEBUG_OSPF_GR)
209 0 : zlog_debug("%s, GR Helper init.", __func__);
210 :
211 4 : 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 4 : if (rc != 0) {
216 0 : flog_warn(EC_OSPF_OPAQUE_REGISTRATION,
217 : "%s: Failed to register Grace LSA functions",
218 : __func__);
219 : }
220 4 : }
221 :
222 : /*
223 : * De-Initialize GR helper config data structures.
224 : *
225 : * Returns:
226 : * Nothing
227 : */
228 0 : void ospf_gr_helper_stop(void)
229 : {
230 0 : if (IS_DEBUG_OSPF_GR)
231 0 : zlog_debug("%s, GR helper deinit.", __func__);
232 :
233 0 : ospf_delete_opaque_functab(OSPF_OPAQUE_LINK_LSA, OPAQUE_TYPE_GRACE_LSA);
234 0 : }
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 0 : 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 0 : struct lsa_header *lsah = NULL;
252 0 : struct tlv_header *tlvh = NULL;
253 0 : struct grace_tlv_graceperiod *grace_period;
254 0 : struct grace_tlv_restart_reason *gr_reason;
255 0 : struct grace_tlv_restart_addr *restart_addr;
256 0 : uint16_t length = 0;
257 0 : int sum = 0;
258 :
259 0 : lsah = (struct lsa_header *)lsa->data;
260 :
261 : /* Check LSA len */
262 0 : if (lsa->size <= OSPF_LSA_HEADER_SIZE) {
263 0 : if (IS_DEBUG_OSPF_GR)
264 0 : zlog_debug("%s: Malformed packet: Invalid LSA len:%d",
265 : __func__, length);
266 0 : return OSPF_GR_FAILURE;
267 : }
268 :
269 0 : length = lsa->size - OSPF_LSA_HEADER_SIZE;
270 :
271 0 : for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
272 0 : tlvh = TLV_HDR_NEXT(tlvh)) {
273 :
274 : /* Check TLV len against overall LSA */
275 0 : if (sum + TLV_SIZE(tlvh) > length) {
276 0 : if (IS_DEBUG_OSPF_GR)
277 0 : zlog_debug("%s: Malformed packet: Invalid TLV len:%u",
278 : __func__, TLV_SIZE(tlvh));
279 0 : return OSPF_GR_FAILURE;
280 : }
281 :
282 0 : switch (ntohs(tlvh->type)) {
283 0 : case GRACE_PERIOD_TYPE:
284 0 : if (TLV_SIZE(tlvh) <
285 : sizeof(struct grace_tlv_graceperiod)) {
286 0 : zlog_debug("%s: Malformed packet: Invalid grace TLV len:%u",
287 : __func__, TLV_SIZE(tlvh));
288 0 : return OSPF_GR_FAILURE;
289 : }
290 :
291 0 : grace_period = (struct grace_tlv_graceperiod *)tlvh;
292 0 : *interval = ntohl(grace_period->interval);
293 0 : sum += TLV_SIZE(tlvh);
294 :
295 : /* Check if grace interval is valid */
296 0 : if (*interval > OSPF_MAX_GRACE_INTERVAL
297 0 : || *interval < OSPF_MIN_GRACE_INTERVAL)
298 : return OSPF_GR_FAILURE;
299 : break;
300 0 : case RESTART_REASON_TYPE:
301 0 : if (TLV_SIZE(tlvh) <
302 : sizeof(struct grace_tlv_restart_reason)) {
303 0 : zlog_debug("%s: Malformed packet: Invalid reason TLV len:%u",
304 : __func__, TLV_SIZE(tlvh));
305 0 : return OSPF_GR_FAILURE;
306 : }
307 :
308 0 : gr_reason = (struct grace_tlv_restart_reason *)tlvh;
309 0 : *reason = gr_reason->reason;
310 0 : sum += TLV_SIZE(tlvh);
311 :
312 0 : if (*reason >= OSPF_GR_INVALID_REASON_CODE)
313 : return OSPF_GR_FAILURE;
314 : break;
315 0 : case RESTARTER_IP_ADDR_TYPE:
316 0 : if (TLV_SIZE(tlvh) <
317 : sizeof(struct grace_tlv_restart_addr)) {
318 0 : zlog_debug("%s: Malformed packet: Invalid addr TLV len:%u",
319 : __func__, TLV_SIZE(tlvh));
320 0 : return OSPF_GR_FAILURE;
321 : }
322 :
323 0 : restart_addr = (struct grace_tlv_restart_addr *)tlvh;
324 0 : addr->s_addr = restart_addr->addr.s_addr;
325 0 : sum += TLV_SIZE(tlvh);
326 0 : break;
327 0 : default:
328 0 : if (IS_DEBUG_OSPF_GR)
329 0 : 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 0 : static void ospf_handle_grace_timer_expiry(struct thread *thread)
350 : {
351 0 : struct ospf_neighbor *nbr = THREAD_ARG(thread);
352 :
353 0 : nbr->gr_helper_info.t_grace_timer = NULL;
354 :
355 0 : ospf_gr_helper_exit(nbr, OSPF_GR_HELPER_GRACE_TIMEOUT);
356 0 : }
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 0 : int ospf_process_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
378 : struct ospf_neighbor *nbr)
379 : {
380 0 : struct in_addr restart_addr = {0};
381 0 : uint8_t restart_reason = 0;
382 0 : uint32_t grace_interval = 0;
383 0 : uint32_t actual_grace_interval = 0;
384 0 : struct advRtr lookup;
385 0 : struct ospf_neighbor *restarter = NULL;
386 0 : struct ospf_interface *oi = nbr->oi;
387 0 : int ret;
388 :
389 :
390 : /* Extract the grace lsa packet fields */
391 0 : ret = ospf_extract_grace_lsa_fields(lsa, &grace_interval, &restart_addr,
392 : &restart_reason);
393 0 : if (ret != OSPF_GR_SUCCESS) {
394 0 : if (IS_DEBUG_OSPF_GR)
395 0 : zlog_debug("%s, Wrong Grace LSA packet.", __func__);
396 0 : return OSPF_GR_NOT_HELPER;
397 : }
398 :
399 0 : if (IS_DEBUG_OSPF_GR)
400 0 : 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 0 : if (oi->type != OSPF_IFTYPE_POINTOPOINT) {
410 0 : restarter = ospf_nbr_lookup_by_addr(oi->nbrs, &restart_addr);
411 :
412 0 : if (!restarter) {
413 0 : if (IS_DEBUG_OSPF_GR)
414 0 : zlog_debug(
415 : "%s, Restarter is not a nbr(%pI4) for this router.",
416 : __func__, &restart_addr);
417 0 : return OSPF_GR_NOT_HELPER;
418 : }
419 : } else
420 : restarter = nbr;
421 :
422 : /* Verify Helper enabled globally */
423 0 : if (!ospf->is_helper_supported) {
424 : /* Verify that Helper support is enabled for the
425 : * current neighbour router-id.
426 : */
427 0 : lookup.advRtrAddr.s_addr = restarter->router_id.s_addr;
428 :
429 0 : if (!hash_lookup(ospf->enable_rtr_list, &lookup)) {
430 0 : if (IS_DEBUG_OSPF_GR)
431 0 : zlog_debug(
432 : "%s, HELPER support is disabled, So not a HELPER",
433 : __func__);
434 0 : restarter->gr_helper_info.rejected_reason =
435 : OSPF_HELPER_SUPPORT_DISABLED;
436 0 : return OSPF_GR_NOT_HELPER;
437 : }
438 : }
439 :
440 :
441 : /* Check neighbour is in FULL state and
442 : * became a adjacency.
443 : */
444 0 : if (!IS_NBR_STATE_FULL(restarter)) {
445 0 : if (IS_DEBUG_OSPF_GR)
446 0 : zlog_debug(
447 : "%s, This Neighbour %pI4 is not in FULL state.",
448 : __func__, &restarter->src);
449 0 : restarter->gr_helper_info.rejected_reason =
450 : OSPF_HELPER_NOT_A_VALID_NEIGHBOUR;
451 0 : 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 0 : if (ospf->only_planned_restart
458 0 : && !OSPF_GR_IS_PLANNED_RESTART(restart_reason)) {
459 0 : if (IS_DEBUG_OSPF_GR)
460 0 : zlog_debug(
461 : "%s, Router supports only planned restarts but received the GRACE LSA for an unplanned restart.",
462 : __func__);
463 0 : restarter->gr_helper_info.rejected_reason =
464 : OSPF_HELPER_PLANNED_ONLY_RESTART;
465 0 : return OSPF_GR_NOT_HELPER;
466 : }
467 :
468 : /* Check the retransmission list of this
469 : * neighbour, check any change in lsas.
470 : */
471 0 : if (ospf->strict_lsa_check && !ospf_ls_retransmit_isempty(restarter)
472 0 : && ospf_check_change_in_rxmt_list(restarter)) {
473 0 : if (IS_DEBUG_OSPF_GR)
474 0 : zlog_debug(
475 : "%s, Changed LSA in Rxmt list. So not Helper.",
476 : __func__);
477 0 : restarter->gr_helper_info.rejected_reason =
478 : OSPF_HELPER_TOPO_CHANGE_RTXMT_LIST;
479 0 : return OSPF_GR_NOT_HELPER;
480 : }
481 :
482 : /*LSA age must be less than the grace period */
483 0 : if (ntohs(lsa->data->ls_age) >= grace_interval) {
484 0 : if (IS_DEBUG_OSPF_GR)
485 0 : zlog_debug(
486 : "%s, Grace LSA age(%d) is more than the grace interval(%d)",
487 : __func__, lsa->data->ls_age, grace_interval);
488 0 : restarter->gr_helper_info.rejected_reason =
489 : OSPF_HELPER_LSA_AGE_MORE;
490 0 : return OSPF_GR_NOT_HELPER;
491 : }
492 :
493 0 : if (ospf->gr_info.restart_in_progress) {
494 0 : if (IS_DEBUG_OSPF_GR)
495 0 : zlog_debug(
496 : "%s: router is in the process of graceful restart",
497 : __func__);
498 0 : restarter->gr_helper_info.rejected_reason =
499 : OSPF_HELPER_RESTARTING;
500 0 : 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 0 : actual_grace_interval = grace_interval;
509 0 : if (grace_interval > ospf->supported_grace_time) {
510 0 : if (IS_DEBUG_OSPF_GR)
511 0 : zlog_debug(
512 : "%s, Received grace period %d is larger than supported grace %d",
513 : __func__, grace_interval,
514 : ospf->supported_grace_time);
515 0 : actual_grace_interval = ospf->supported_grace_time;
516 : }
517 :
518 0 : if (OSPF_GR_IS_ACTIVE_HELPER(restarter)) {
519 0 : if (restarter->gr_helper_info.t_grace_timer)
520 0 : THREAD_OFF(restarter->gr_helper_info.t_grace_timer);
521 :
522 0 : if (ospf->active_restarter_cnt > 0)
523 0 : ospf->active_restarter_cnt--;
524 :
525 0 : if (IS_DEBUG_OSPF_GR)
526 0 : zlog_debug(
527 : "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer",
528 : __func__);
529 : } else {
530 0 : if (IS_DEBUG_OSPF_GR)
531 0 : 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 0 : restarter->gr_helper_info.gr_helper_status = OSPF_GR_ACTIVE_HELPER;
540 0 : restarter->gr_helper_info.recvd_grace_period = grace_interval;
541 0 : restarter->gr_helper_info.actual_grace_period = actual_grace_interval;
542 0 : restarter->gr_helper_info.gr_restart_reason = restart_reason;
543 0 : restarter->gr_helper_info.rejected_reason = OSPF_HELPER_REJECTED_NONE;
544 :
545 : /* Increment the active restarter count */
546 0 : ospf->active_restarter_cnt++;
547 :
548 0 : if (IS_DEBUG_OSPF_GR)
549 0 : zlog_debug("%s, Grace timer started.interval:%d", __func__,
550 : actual_grace_interval);
551 :
552 : /* Start the grace timer */
553 0 : thread_add_timer(master, ospf_handle_grace_timer_expiry, restarter,
554 : actual_grace_interval,
555 : &restarter->gr_helper_info.t_grace_timer);
556 :
557 0 : 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 0 : static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr)
572 : {
573 0 : struct route_node *rn;
574 0 : struct ospf_lsa *lsa;
575 0 : struct route_table *tbl;
576 :
577 0 : tbl = nbr->ls_rxmt.type[OSPF_ROUTER_LSA].db;
578 0 : LSDB_LOOP (tbl, rn, lsa)
579 0 : if (lsa->to_be_acknowledged)
580 : return OSPF_GR_TRUE;
581 0 : tbl = nbr->ls_rxmt.type[OSPF_NETWORK_LSA].db;
582 0 : LSDB_LOOP (tbl, rn, lsa)
583 0 : if (lsa->to_be_acknowledged)
584 : return OSPF_GR_TRUE;
585 :
586 0 : tbl = nbr->ls_rxmt.type[OSPF_SUMMARY_LSA].db;
587 0 : LSDB_LOOP (tbl, rn, lsa)
588 0 : if (lsa->to_be_acknowledged)
589 : return OSPF_GR_TRUE;
590 :
591 0 : tbl = nbr->ls_rxmt.type[OSPF_ASBR_SUMMARY_LSA].db;
592 0 : LSDB_LOOP (tbl, rn, lsa)
593 0 : if (lsa->to_be_acknowledged)
594 : return OSPF_GR_TRUE;
595 :
596 0 : tbl = nbr->ls_rxmt.type[OSPF_AS_EXTERNAL_LSA].db;
597 0 : LSDB_LOOP (tbl, rn, lsa)
598 0 : if (lsa->to_be_acknowledged)
599 : return OSPF_GR_TRUE;
600 :
601 0 : tbl = nbr->ls_rxmt.type[OSPF_AS_NSSA_LSA].db;
602 0 : LSDB_LOOP (tbl, rn, lsa)
603 0 : 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 0 : void ospf_helper_handle_topo_chg(struct ospf *ospf, struct ospf_lsa *lsa)
622 : {
623 0 : struct listnode *node;
624 0 : 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 0 : if (!ospf->strict_lsa_check)
630 : return;
631 :
632 0 : if (IS_DEBUG_OSPF_GR)
633 0 : zlog_debug("%s: Topo change detected due to LSA[%s]", __func__,
634 : dump_lsa_key(lsa));
635 :
636 0 : lsa->to_be_acknowledged = OSPF_GR_TRUE;
637 :
638 0 : for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
639 0 : struct route_node *rn = NULL;
640 :
641 0 : if (ospf_interface_neighbor_count(oi) == 0)
642 0 : 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 0 : if ((oi->area->external_routing == OSPF_AREA_STUB)
650 0 : && (lsa->data->type == OSPF_AS_EXTERNAL_LSA)) {
651 0 : continue;
652 : }
653 :
654 0 : for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
655 0 : struct ospf_neighbor *nbr = NULL;
656 :
657 0 : if (!rn->info)
658 0 : continue;
659 :
660 0 : nbr = rn->info;
661 :
662 0 : if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
663 0 : 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 0 : void ospf_gr_helper_exit(struct ospf_neighbor *nbr,
687 : enum ospf_helper_exit_reason reason)
688 : {
689 0 : struct ospf_interface *oi = nbr->oi;
690 0 : struct ospf *ospf = oi->ospf;
691 :
692 0 : if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
693 : return;
694 :
695 0 : if (IS_DEBUG_OSPF_GR)
696 0 : 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 0 : nbr->gr_helper_info.gr_helper_status = OSPF_GR_NOT_HELPER;
701 0 : nbr->gr_helper_info.helper_exit_reason = reason;
702 0 : nbr->gr_helper_info.actual_grace_period = 0;
703 0 : nbr->gr_helper_info.recvd_grace_period = 0;
704 0 : nbr->gr_helper_info.gr_restart_reason = 0;
705 0 : ospf->last_exit_reason = reason;
706 :
707 0 : if (ospf->active_restarter_cnt <= 0) {
708 0 : zlog_err(
709 : "OSPF GR-Helper: active_restarter_cnt should be greater than zero here.");
710 0 : return;
711 : }
712 : /* Decrement active Restarter count */
713 0 : ospf->active_restarter_cnt--;
714 :
715 : /* If the exit not triggered due to grace timer
716 : * expiry, stop the grace timer.
717 : */
718 0 : if (reason != OSPF_GR_HELPER_GRACE_TIMEOUT)
719 0 : THREAD_OFF(nbr->gr_helper_info.t_grace_timer);
720 :
721 : /* check exit triggered due to successful completion
722 : * of graceful restart.
723 : */
724 0 : if (reason != OSPF_GR_HELPER_COMPLETED) {
725 0 : if (IS_DEBUG_OSPF_GR)
726 0 : zlog_debug("%s, Unsuccessful GR exit", __func__);
727 : }
728 :
729 : /*Recalculate the DR for the network segment */
730 0 : if (oi->type == OSPF_IFTYPE_BROADCAST || oi->type == OSPF_IFTYPE_NBMA)
731 0 : ospf_dr_election(oi);
732 :
733 : /* Originate a router LSA */
734 0 : ospf_router_lsa_update_area(oi->area);
735 :
736 : /* Originate network lsa if it is an DR in the LAN */
737 0 : if (oi->state == ISM_DR)
738 0 : 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 0 : void ospf_process_maxage_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
760 : struct ospf_neighbor *nbr)
761 : {
762 0 : struct in_addr restartAddr = {0};
763 0 : uint8_t restartReason = 0;
764 0 : uint32_t graceInterval = 0;
765 0 : struct ospf_neighbor *restarter = NULL;
766 0 : struct ospf_interface *oi = nbr->oi;
767 0 : int ret;
768 :
769 : /* Extract the grace lsa packet fields */
770 0 : ret = ospf_extract_grace_lsa_fields(lsa, &graceInterval, &restartAddr,
771 : &restartReason);
772 0 : if (ret != OSPF_GR_SUCCESS) {
773 0 : if (IS_DEBUG_OSPF_GR)
774 0 : zlog_debug("%s, Wrong Grace LSA packet.", __func__);
775 0 : return;
776 : }
777 :
778 0 : if (IS_DEBUG_OSPF_GR)
779 0 : 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 0 : if (oi->type != OSPF_IFTYPE_POINTOPOINT) {
787 0 : restarter = ospf_nbr_lookup_by_addr(oi->nbrs, &restartAddr);
788 :
789 0 : if (!restarter) {
790 0 : if (IS_DEBUG_OSPF_GR)
791 0 : zlog_debug(
792 : "%s, Restarter is not a neighbour for this router.",
793 : __func__);
794 0 : return;
795 : }
796 : } else {
797 : restarter = nbr;
798 : }
799 :
800 0 : 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 0 : void ospf_gr_helper_support_set(struct ospf *ospf, bool support)
817 : {
818 0 : struct ospf_interface *oi;
819 0 : struct listnode *node;
820 0 : struct advRtr lookup;
821 :
822 0 : if (ospf->is_helper_supported == support)
823 0 : return;
824 :
825 0 : ospf->is_helper_supported = support;
826 :
827 : /* If helper support disabled, cease HELPER role for all
828 : * supporting neighbors.
829 : */
830 0 : if (support == OSPF_GR_FALSE) {
831 0 : for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
832 0 : struct route_node *rn = NULL;
833 :
834 0 : if (ospf_interface_neighbor_count(oi) == 0)
835 0 : continue;
836 :
837 0 : for (rn = route_top(oi->nbrs); rn;
838 0 : rn = route_next(rn)) {
839 0 : struct ospf_neighbor *nbr = NULL;
840 :
841 0 : if (!rn->info)
842 0 : continue;
843 :
844 0 : nbr = rn->info;
845 :
846 0 : lookup.advRtrAddr.s_addr =
847 0 : 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 0 : if (hash_lookup(ospf->enable_rtr_list, &lookup))
853 0 : continue;
854 :
855 0 : if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
856 0 : 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 0 : void ospf_gr_helper_support_set_per_routerid(struct ospf *ospf,
882 : struct in_addr *advrtr,
883 : bool support)
884 : {
885 0 : struct advRtr temp;
886 0 : struct advRtr *rtr;
887 0 : struct ospf_interface *oi;
888 0 : struct listnode *node;
889 :
890 0 : temp.advRtrAddr.s_addr = advrtr->s_addr;
891 :
892 0 : if (support == OSPF_GR_FALSE) {
893 : /*Delete the routerid from the enable router hash table */
894 0 : rtr = hash_lookup(ospf->enable_rtr_list, &temp);
895 :
896 0 : if (rtr) {
897 0 : hash_release(ospf->enable_rtr_list, rtr);
898 0 : ospf_disable_rtr_hash_free(rtr);
899 : }
900 :
901 : /* If helper support is enabled globally
902 : * no action is required.
903 : */
904 0 : if (ospf->is_helper_supported)
905 0 : return;
906 :
907 : /* Cease the HELPER role fore neighbours from the
908 : * specified advertisement router.
909 : */
910 0 : for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
911 0 : struct route_node *rn = NULL;
912 :
913 0 : if (ospf_interface_neighbor_count(oi) == 0)
914 0 : continue;
915 :
916 0 : for (rn = route_top(oi->nbrs); rn;
917 0 : rn = route_next(rn)) {
918 0 : struct ospf_neighbor *nbr = NULL;
919 :
920 0 : if (!rn->info)
921 0 : continue;
922 :
923 0 : nbr = rn->info;
924 :
925 0 : if (nbr->router_id.s_addr != advrtr->s_addr)
926 0 : continue;
927 :
928 0 : if (OSPF_GR_IS_ACTIVE_HELPER(nbr))
929 0 : 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 0 : (void)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 0 : void ospf_gr_helper_lsa_check_set(struct ospf *ospf, bool enabled)
955 : {
956 0 : if (ospf->strict_lsa_check == enabled)
957 : return;
958 :
959 0 : 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 0 : void ospf_gr_helper_supported_gracetime_set(struct ospf *ospf,
975 : uint32_t interval)
976 : {
977 0 : ospf->supported_grace_time = interval;
978 0 : }
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 0 : void ospf_gr_helper_set_supported_planned_only_restart(struct ospf *ospf,
994 : bool planned_only)
995 : {
996 0 : ospf->only_planned_restart = planned_only;
997 0 : }
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 0 : static void show_ospf_grace_lsa_info(struct vty *vty, struct json_object *json,
1013 : struct ospf_lsa *lsa)
1014 : {
1015 0 : struct lsa_header *lsah = NULL;
1016 0 : struct tlv_header *tlvh = NULL;
1017 0 : struct grace_tlv_graceperiod *gracePeriod;
1018 0 : struct grace_tlv_restart_reason *grReason;
1019 0 : struct grace_tlv_restart_addr *restartAddr;
1020 0 : uint16_t length = 0;
1021 0 : int sum = 0;
1022 :
1023 0 : if (json)
1024 : return;
1025 :
1026 0 : lsah = (struct lsa_header *)lsa->data;
1027 :
1028 0 : if (lsa->size <= OSPF_LSA_HEADER_SIZE) {
1029 0 : if (vty)
1030 0 : vty_out(vty, "%% Invalid LSA length: %d\n", length);
1031 : else
1032 0 : zlog_debug("%% Invalid LSA length: %d", length);
1033 0 : return;
1034 : }
1035 :
1036 0 : length = lsa->size - OSPF_LSA_HEADER_SIZE;
1037 :
1038 0 : if (vty)
1039 0 : vty_out(vty, " TLV info:\n");
1040 : else
1041 0 : zlog_debug(" TLV info:");
1042 :
1043 0 : for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
1044 0 : tlvh = TLV_HDR_NEXT(tlvh)) {
1045 : /* Check TLV len */
1046 0 : if (sum + TLV_SIZE(tlvh) > length) {
1047 0 : if (vty)
1048 0 : vty_out(vty, "%% Invalid TLV length: %u\n",
1049 0 : TLV_SIZE(tlvh));
1050 : else
1051 0 : zlog_debug("%% Invalid TLV length: %u",
1052 : TLV_SIZE(tlvh));
1053 0 : return;
1054 : }
1055 :
1056 0 : switch (ntohs(tlvh->type)) {
1057 0 : case GRACE_PERIOD_TYPE:
1058 0 : if (TLV_SIZE(tlvh)
1059 : < sizeof(struct grace_tlv_graceperiod)) {
1060 0 : if (vty)
1061 0 : vty_out(vty,
1062 : "%% Invalid grace TLV length %u\n",
1063 0 : TLV_SIZE(tlvh));
1064 : else
1065 0 : zlog_debug(
1066 : "%% Invalid grace TLV length %u",
1067 : TLV_SIZE(tlvh));
1068 0 : return;
1069 : }
1070 :
1071 0 : gracePeriod = (struct grace_tlv_graceperiod *)tlvh;
1072 0 : sum += TLV_SIZE(tlvh);
1073 :
1074 0 : if (vty)
1075 0 : vty_out(vty, " Grace period:%d\n",
1076 : ntohl(gracePeriod->interval));
1077 : else
1078 0 : zlog_debug(" Grace period:%d",
1079 : ntohl(gracePeriod->interval));
1080 : break;
1081 0 : case RESTART_REASON_TYPE:
1082 0 : if (TLV_SIZE(tlvh)
1083 : < sizeof(struct grace_tlv_restart_reason)) {
1084 0 : if (vty)
1085 0 : vty_out(vty,
1086 : "%% Invalid reason TLV length %u\n",
1087 0 : TLV_SIZE(tlvh));
1088 : else
1089 0 : zlog_debug(
1090 : "%% Invalid reason TLV length %u",
1091 : TLV_SIZE(tlvh));
1092 0 : return;
1093 : }
1094 :
1095 0 : grReason = (struct grace_tlv_restart_reason *)tlvh;
1096 0 : sum += TLV_SIZE(tlvh);
1097 :
1098 0 : if (vty)
1099 0 : vty_out(vty, " Restart reason:%s\n",
1100 : ospf_restart_reason2str(
1101 0 : grReason->reason));
1102 : else
1103 0 : zlog_debug(" Restart reason:%s",
1104 : ospf_restart_reason2str(
1105 : grReason->reason));
1106 : break;
1107 0 : case RESTARTER_IP_ADDR_TYPE:
1108 0 : if (TLV_SIZE(tlvh)
1109 : < sizeof(struct grace_tlv_restart_addr)) {
1110 0 : if (vty)
1111 0 : vty_out(vty,
1112 : "%% Invalid addr TLV length %u\n",
1113 0 : TLV_SIZE(tlvh));
1114 : else
1115 0 : zlog_debug(
1116 : "%% Invalid addr TLV length %u",
1117 : TLV_SIZE(tlvh));
1118 0 : return;
1119 : }
1120 :
1121 0 : restartAddr = (struct grace_tlv_restart_addr *)tlvh;
1122 0 : sum += TLV_SIZE(tlvh);
1123 :
1124 0 : if (vty)
1125 0 : vty_out(vty, " Restarter address:%pI4\n",
1126 : &restartAddr->addr);
1127 : else
1128 0 : zlog_debug(" Restarter address:%pI4",
1129 : &restartAddr->addr);
1130 : break;
1131 0 : default:
1132 0 : if (vty)
1133 0 : vty_out(vty, " Unknown TLV type %d\n",
1134 0 : ntohs(tlvh->type));
1135 : else
1136 0 : zlog_debug(" Unknown TLV type %d",
1137 : ntohs(tlvh->type));
1138 :
1139 : break;
1140 : }
1141 : }
1142 : }
|