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