]>
Commit | Line | Data |
---|---|---|
59790f52 | 1 | /* |
0d1753a7 | 2 | * OSPF6 Graceful Restart helper functions. |
59790f52 | 3 | * |
4 | * Copyright (C) 2021-22 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 "log.h" | |
27 | #include "vty.h" | |
28 | #include "command.h" | |
29 | #include "prefix.h" | |
30 | #include "stream.h" | |
31 | #include "zclient.h" | |
32 | #include "memory.h" | |
33 | #include "table.h" | |
34 | #include "lib/bfd.h" | |
35 | #include "lib_errors.h" | |
36 | #include "jhash.h" | |
37 | ||
38 | #include "ospf6_proto.h" | |
39 | #include "ospf6_lsa.h" | |
40 | #include "ospf6_lsdb.h" | |
41 | #include "ospf6_route.h" | |
42 | #include "ospf6_message.h" | |
43 | ||
44 | #include "ospf6_top.h" | |
45 | #include "ospf6_area.h" | |
46 | #include "ospf6_interface.h" | |
47 | #include "ospf6_neighbor.h" | |
48 | #include "ospf6_intra.h" | |
49 | #include "ospf6d.h" | |
0d1753a7 | 50 | #include "ospf6_gr.h" |
59790f52 | 51 | #include "lib/json.h" |
59790f52 | 52 | #include "ospf6d/ospf6_gr_helper_clippy.c" |
59790f52 | 53 | |
54 | DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_GR_HELPER, "OSPF6 Graceful restart helper"); | |
55 | ||
0d1753a7 | 56 | unsigned char conf_debug_ospf6_gr; |
06943666 | 57 | |
0fc3e113 | 58 | static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa, |
59 | json_object *json, bool use_json); | |
60 | ||
61 | struct ospf6_lsa_handler grace_lsa_handler = {.lh_type = OSPF6_LSTYPE_GRACE_LSA, | |
62 | .lh_name = "Grace", | |
63 | .lh_short_name = "GR", | |
64 | .lh_show = | |
65 | ospf6_grace_lsa_show_info, | |
66 | .lh_get_prefix_str = NULL, | |
67 | .lh_debug = 0}; | |
68 | ||
59790f52 | 69 | const char *ospf6_exit_reason_desc[] = { |
0fc3e113 | 70 | "Unknown reason", |
71 | "Helper in progress", | |
72 | "Topology Change", | |
73 | "Grace timer expiry", | |
74 | "Successful graceful restart", | |
59790f52 | 75 | }; |
76 | ||
77 | const char *ospf6_restart_reason_desc[] = { | |
78 | "Unknown restart", | |
79 | "Software restart", | |
80 | "Software reload/upgrade", | |
81 | "Switch to redundant control processor", | |
82 | }; | |
83 | ||
84 | const char *ospf6_rejected_reason_desc[] = { | |
85 | "Unknown reason", | |
86 | "Helper support disabled", | |
87 | "Neighbour is not in FULL state", | |
88 | "Supports only planned restart but received for unplanned", | |
89 | "Topo change due to change in lsa rxmt list", | |
90 | "LSA age is more than Grace interval", | |
91 | }; | |
92 | ||
93 | static unsigned int ospf6_enable_rtr_hash_key(const void *data) | |
94 | { | |
95 | const struct advRtr *rtr = data; | |
96 | ||
97 | return jhash_1word(rtr->advRtrAddr, 0); | |
98 | } | |
99 | ||
100 | static bool ospf6_enable_rtr_hash_cmp(const void *d1, const void *d2) | |
101 | { | |
102 | const struct advRtr *rtr1 = d1; | |
103 | const struct advRtr *rtr2 = d2; | |
104 | ||
105 | return (rtr1->advRtrAddr == rtr2->advRtrAddr); | |
106 | } | |
107 | ||
108 | static void *ospf6_enable_rtr_hash_alloc(void *p) | |
109 | { | |
110 | struct advRtr *rid; | |
111 | ||
112 | rid = XCALLOC(MTYPE_OSPF6_GR_HELPER, sizeof(struct advRtr)); | |
113 | rid->advRtrAddr = ((struct advRtr *)p)->advRtrAddr; | |
114 | ||
115 | return rid; | |
116 | } | |
117 | ||
118 | static void ospf6_disable_rtr_hash_free(void *rtr) | |
119 | { | |
120 | XFREE(MTYPE_OSPF6_GR_HELPER, rtr); | |
121 | } | |
122 | ||
123 | static void ospf6_enable_rtr_hash_destroy(struct ospf6 *ospf6) | |
124 | { | |
125 | if (ospf6->ospf6_helper_cfg.enable_rtr_list == NULL) | |
126 | return; | |
127 | ||
128 | hash_clean(ospf6->ospf6_helper_cfg.enable_rtr_list, | |
129 | ospf6_disable_rtr_hash_free); | |
130 | hash_free(ospf6->ospf6_helper_cfg.enable_rtr_list); | |
131 | ospf6->ospf6_helper_cfg.enable_rtr_list = NULL; | |
132 | } | |
133 | ||
0d1753a7 | 134 | /* |
135 | * Extracting tlv info from GRACE LSA. | |
136 | * | |
137 | * lsa | |
138 | * ospf6 grace lsa | |
139 | * | |
140 | * Returns: | |
141 | * interval : grace interval. | |
142 | * reason : Restarting reason. | |
143 | */ | |
144 | static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa, | |
145 | uint32_t *interval, uint8_t *reason) | |
146 | { | |
147 | struct ospf6_lsa_header *lsah = NULL; | |
148 | struct tlv_header *tlvh = NULL; | |
149 | struct grace_tlv_graceperiod *gracePeriod; | |
150 | struct grace_tlv_restart_reason *grReason; | |
151 | uint16_t length = 0; | |
152 | int sum = 0; | |
153 | ||
154 | lsah = (struct ospf6_lsa_header *)lsa->header; | |
905b12b2 | 155 | if (ntohs(lsah->length) <= OSPF6_LSA_HEADER_SIZE) { |
156 | if (IS_DEBUG_OSPF6_GR) | |
157 | zlog_debug("%s: undersized (%u B) lsa", __func__, | |
158 | ntohs(lsah->length)); | |
159 | return OSPF6_FAILURE; | |
160 | } | |
0d1753a7 | 161 | |
162 | length = ntohs(lsah->length) - OSPF6_LSA_HEADER_SIZE; | |
163 | ||
6d1a5a1c | 164 | for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh; |
0d1753a7 | 165 | tlvh = TLV_HDR_NEXT(tlvh)) { |
6d1a5a1c | 166 | |
167 | /* Check TLV len against overall LSA */ | |
168 | if (sum + TLV_SIZE(tlvh) > length) { | |
169 | if (IS_DEBUG_OSPF6_GR) | |
170 | zlog_debug( | |
171 | "%s: Malformed packet: Invalid TLV len:%d", | |
172 | __func__, TLV_SIZE(tlvh)); | |
173 | return OSPF6_FAILURE; | |
174 | } | |
175 | ||
0d1753a7 | 176 | switch (ntohs(tlvh->type)) { |
177 | case GRACE_PERIOD_TYPE: | |
178 | gracePeriod = (struct grace_tlv_graceperiod *)tlvh; | |
179 | *interval = ntohl(gracePeriod->interval); | |
180 | sum += TLV_SIZE(tlvh); | |
181 | ||
182 | /* Check if grace interval is valid */ | |
183 | if (*interval > OSPF6_MAX_GRACE_INTERVAL | |
184 | || *interval < OSPF6_MIN_GRACE_INTERVAL) | |
185 | return OSPF6_FAILURE; | |
186 | break; | |
187 | case RESTART_REASON_TYPE: | |
188 | grReason = (struct grace_tlv_restart_reason *)tlvh; | |
189 | *reason = grReason->reason; | |
190 | sum += TLV_SIZE(tlvh); | |
191 | ||
192 | if (*reason >= OSPF6_GR_INVALID_REASON_CODE) | |
193 | return OSPF6_FAILURE; | |
194 | break; | |
195 | default: | |
0fc3e113 | 196 | if (IS_DEBUG_OSPF6_GR) |
197 | zlog_debug("%s, Ignoring unknown TLV type:%d", | |
198 | __func__, ntohs(tlvh->type)); | |
0d1753a7 | 199 | } |
200 | } | |
201 | ||
202 | return OSPF6_SUCCESS; | |
203 | } | |
204 | ||
205 | /* | |
206 | * Grace timer expiry handler. | |
207 | * HELPER aborts its role at grace timer expiry. | |
208 | * | |
209 | * thread | |
210 | * thread pointer | |
211 | * | |
212 | * Returns: | |
213 | * Nothing | |
214 | */ | |
cc9f21da | 215 | static void ospf6_handle_grace_timer_expiry(struct thread *thread) |
0d1753a7 | 216 | { |
217 | struct ospf6_neighbor *nbr = THREAD_ARG(thread); | |
218 | ||
9a06f23d | 219 | ospf6_gr_helper_exit(nbr, OSPF6_GR_HELPER_GRACE_TIMEOUT); |
0d1753a7 | 220 | } |
221 | ||
222 | /* | |
223 | * API to check any change in the neighbor's | |
224 | * retransmission list. | |
225 | * | |
226 | * nbr | |
227 | * ospf6 neighbor | |
228 | * | |
229 | * Returns: | |
230 | * TRUE - if any change in the lsa. | |
231 | * FALSE - no change in the lsas. | |
232 | */ | |
233 | static bool ospf6_check_chg_in_rxmt_list(struct ospf6_neighbor *nbr) | |
234 | { | |
235 | struct ospf6_lsa *lsa, *lsanext; | |
236 | ||
237 | for (ALL_LSDB(nbr->retrans_list, lsa, lsanext)) { | |
238 | struct ospf6_lsa *lsa_in_db = NULL; | |
239 | ||
240 | /* Fetching the same copy of LSA form LSDB to validate the | |
241 | * topochange. | |
242 | */ | |
243 | lsa_in_db = | |
244 | ospf6_lsdb_lookup(lsa->header->type, lsa->header->id, | |
245 | lsa->header->adv_router, lsa->lsdb); | |
246 | ||
37692712 | 247 | if (lsa_in_db && lsa_in_db->tobe_acknowledged) { |
248 | ospf6_lsa_unlock(lsa); | |
249 | if (lsanext) | |
250 | ospf6_lsa_unlock(lsanext); | |
251 | ||
0d1753a7 | 252 | return OSPF6_TRUE; |
37692712 | 253 | } |
0d1753a7 | 254 | } |
255 | ||
256 | return OSPF6_FALSE; | |
257 | } | |
258 | ||
259 | /* | |
260 | * Process Grace LSA.If it is eligible move to HELPER role. | |
261 | * Ref rfc3623 section 3.1 and rfc5187 | |
262 | * | |
263 | * ospf | |
264 | * Ospf6 pointer. | |
265 | * | |
266 | * lsa | |
267 | * Grace LSA received from RESTARTER. | |
268 | * | |
269 | * restarter | |
270 | * ospf6 neighbour which requests the router to act as | |
271 | * HELPER. | |
272 | * | |
273 | * Returns: | |
274 | * status. | |
275 | * If supported as HELPER : OSPF_GR_HELPER_INPROGRESS | |
276 | * If Not supported as HELPER : OSPF_GR_HELPER_NONE | |
277 | */ | |
278 | int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, | |
279 | struct ospf6_neighbor *restarter) | |
280 | { | |
281 | uint8_t restart_reason = 0; | |
282 | uint32_t grace_interval = 0; | |
283 | uint32_t actual_grace_interval = 0; | |
284 | struct advRtr lookup; | |
285 | int ret; | |
286 | ||
287 | /* Extract the grace lsa packet fields */ | |
288 | ret = ospf6_extract_grace_lsa_fields(lsa, &grace_interval, | |
289 | &restart_reason); | |
290 | if (ret != OSPF6_SUCCESS) { | |
0fc3e113 | 291 | if (IS_DEBUG_OSPF6_GR) |
292 | zlog_debug("%s, Wrong Grace LSA packet.", __func__); | |
0d1753a7 | 293 | return OSPF6_GR_NOT_HELPER; |
294 | } | |
295 | ||
0fc3e113 | 296 | if (IS_DEBUG_OSPF6_GR) |
0d1753a7 | 297 | zlog_debug( |
298 | "%s, Grace LSA received from %pI4, grace interval:%u, restart reason :%s", | |
0fc3e113 | 299 | __func__, &restarter->router_id, grace_interval, |
0d1753a7 | 300 | ospf6_restart_reason_desc[restart_reason]); |
301 | ||
302 | /* Verify Helper enabled globally */ | |
303 | if (!ospf6->ospf6_helper_cfg.is_helper_supported) { | |
304 | /* Verify Helper support is enabled for the | |
305 | * current neighbour router-id. | |
306 | */ | |
307 | lookup.advRtrAddr = restarter->router_id; | |
308 | ||
309 | if (!hash_lookup(ospf6->ospf6_helper_cfg.enable_rtr_list, | |
310 | &lookup)) { | |
0fc3e113 | 311 | if (IS_DEBUG_OSPF6_GR) |
0d1753a7 | 312 | zlog_debug( |
313 | "%s, HELPER support is disabled, So not a HELPER", | |
314 | __func__); | |
315 | restarter->gr_helper_info.rejected_reason = | |
316 | OSPF6_HELPER_SUPPORT_DISABLED; | |
317 | return OSPF6_GR_NOT_HELPER; | |
318 | } | |
319 | } | |
320 | ||
321 | /* Check neighbour is in FULL state and | |
322 | * became a adjacency. | |
323 | */ | |
324 | if (!IS_NBR_STATE_FULL(restarter)) { | |
0fc3e113 | 325 | if (IS_DEBUG_OSPF6_GR) |
0d1753a7 | 326 | zlog_debug( |
327 | "%s, This Neighbour %pI6 is not in FULL state.", | |
328 | __func__, &restarter->linklocal_addr); | |
329 | restarter->gr_helper_info.rejected_reason = | |
330 | OSPF6_HELPER_NOT_A_VALID_NEIGHBOUR; | |
331 | return OSPF6_GR_NOT_HELPER; | |
332 | } | |
333 | ||
334 | /* Based on the restart reason from grace lsa | |
335 | * check the current router is supporting or not | |
336 | */ | |
337 | if (ospf6->ospf6_helper_cfg.only_planned_restart | |
338 | && !OSPF6_GR_IS_PLANNED_RESTART(restart_reason)) { | |
0fc3e113 | 339 | if (IS_DEBUG_OSPF6_GR) |
0d1753a7 | 340 | zlog_debug( |
abc14fa0 | 341 | "%s, Router supports only planned restarts but received the GRACE LSA due to an unplanned restart", |
0d1753a7 | 342 | __func__); |
343 | restarter->gr_helper_info.rejected_reason = | |
344 | OSPF6_HELPER_PLANNED_ONLY_RESTART; | |
345 | return OSPF6_GR_NOT_HELPER; | |
346 | } | |
347 | ||
348 | /* Check the retransmission list of this | |
349 | * neighbour, check any change in lsas. | |
350 | */ | |
351 | if (ospf6->ospf6_helper_cfg.strict_lsa_check | |
352 | && restarter->retrans_list->count | |
353 | && ospf6_check_chg_in_rxmt_list(restarter)) { | |
0fc3e113 | 354 | if (IS_DEBUG_OSPF6_GR) |
0d1753a7 | 355 | zlog_debug( |
356 | "%s, Changed LSA in Rxmt list.So not Helper.", | |
357 | __func__); | |
358 | restarter->gr_helper_info.rejected_reason = | |
359 | OSPF6_HELPER_TOPO_CHANGE_RTXMT_LIST; | |
360 | return OSPF6_GR_NOT_HELPER; | |
361 | } | |
362 | ||
0fc3e113 | 363 | /* LSA age must be less than the grace period */ |
0d1753a7 | 364 | if (ntohs(lsa->header->age) >= grace_interval) { |
0fc3e113 | 365 | if (IS_DEBUG_OSPF6_GR) |
0d1753a7 | 366 | zlog_debug( |
367 | "%s, Grace LSA age(%d) is more than the grace interval(%d)", | |
0fc3e113 | 368 | __func__, lsa->header->age, grace_interval); |
0d1753a7 | 369 | restarter->gr_helper_info.rejected_reason = |
370 | OSPF6_HELPER_LSA_AGE_MORE; | |
371 | return OSPF6_GR_NOT_HELPER; | |
372 | } | |
373 | ||
71165098 RW |
374 | if (ospf6->gr_info.restart_in_progress) { |
375 | if (IS_DEBUG_OSPF6_GR) | |
376 | zlog_debug( | |
377 | "%s: router is in the process of graceful restart", | |
378 | __func__); | |
379 | restarter->gr_helper_info.rejected_reason = | |
380 | OSPF6_HELPER_RESTARTING; | |
381 | return OSPF6_GR_NOT_HELPER; | |
382 | } | |
383 | ||
0d1753a7 | 384 | /* check supported grace period configured |
385 | * if configured, use this to start the grace | |
386 | * timer otherwise use the interval received | |
387 | * in grace LSA packet. | |
388 | */ | |
389 | actual_grace_interval = grace_interval; | |
390 | if (grace_interval > ospf6->ospf6_helper_cfg.supported_grace_time) { | |
0fc3e113 | 391 | if (IS_DEBUG_OSPF6_GR) |
0d1753a7 | 392 | zlog_debug( |
393 | "%s, Received grace period %d is larger than supported grace %d", | |
394 | __func__, grace_interval, | |
395 | ospf6->ospf6_helper_cfg.supported_grace_time); | |
396 | actual_grace_interval = | |
397 | ospf6->ospf6_helper_cfg.supported_grace_time; | |
398 | } | |
399 | ||
400 | if (OSPF6_GR_IS_ACTIVE_HELPER(restarter)) { | |
c905f04c | 401 | THREAD_OFF(restarter->gr_helper_info.t_grace_timer); |
0d1753a7 | 402 | |
403 | if (ospf6->ospf6_helper_cfg.active_restarter_cnt > 0) | |
404 | ospf6->ospf6_helper_cfg.active_restarter_cnt--; | |
405 | ||
0fc3e113 | 406 | if (IS_DEBUG_OSPF6_GR) |
0d1753a7 | 407 | zlog_debug( |
408 | "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer", | |
409 | __func__); | |
410 | } else { | |
0fc3e113 | 411 | if (IS_DEBUG_OSPF6_GR) |
0d1753a7 | 412 | zlog_debug( |
413 | "%s, This Router becomes a HELPER for the neighbour %pI6", | |
414 | __func__, &restarter->linklocal_addr); | |
415 | } | |
416 | ||
417 | /* Became a Helper to the RESTART neighbour. | |
418 | * change the helper status. | |
419 | */ | |
420 | restarter->gr_helper_info.gr_helper_status = OSPF6_GR_ACTIVE_HELPER; | |
421 | restarter->gr_helper_info.recvd_grace_period = grace_interval; | |
422 | restarter->gr_helper_info.actual_grace_period = actual_grace_interval; | |
423 | restarter->gr_helper_info.gr_restart_reason = restart_reason; | |
424 | restarter->gr_helper_info.rejected_reason = OSPF6_HELPER_REJECTED_NONE; | |
425 | ||
426 | /* Increment the active restart nbr count */ | |
427 | ospf6->ospf6_helper_cfg.active_restarter_cnt++; | |
428 | ||
0fc3e113 | 429 | if (IS_DEBUG_OSPF6_GR) |
430 | zlog_debug("%s, Grace timer started.interval:%u", __func__, | |
431 | actual_grace_interval); | |
0d1753a7 | 432 | |
433 | /* Start the grace timer */ | |
434 | thread_add_timer(master, ospf6_handle_grace_timer_expiry, restarter, | |
435 | actual_grace_interval, | |
436 | &restarter->gr_helper_info.t_grace_timer); | |
437 | ||
438 | return OSPF6_GR_ACTIVE_HELPER; | |
439 | } | |
440 | ||
9a06f23d | 441 | /* |
442 | * Api to exit from HELPER role to take all actions | |
443 | * required at exit. | |
444 | * Ref rfc3623 section 3. and rfc51872 | |
445 | * | |
446 | * ospf6 | |
447 | * Ospf6 pointer. | |
448 | * | |
449 | * nbr | |
450 | * Ospf6 neighbour for which it is acting as HELPER. | |
451 | * | |
452 | * reason | |
453 | * The reason for exiting from HELPER. | |
454 | * | |
455 | * Returns: | |
456 | * Nothing. | |
457 | */ | |
458 | void ospf6_gr_helper_exit(struct ospf6_neighbor *nbr, | |
459 | enum ospf6_helper_exit_reason reason) | |
460 | { | |
461 | struct ospf6_interface *oi = nbr->ospf6_if; | |
462 | struct ospf6 *ospf6; | |
463 | ||
464 | if (!oi) | |
465 | return; | |
466 | ||
467 | ospf6 = oi->area->ospf6; | |
468 | ||
469 | if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr)) | |
470 | return; | |
471 | ||
0fc3e113 | 472 | if (IS_DEBUG_OSPF6_GR) |
9a06f23d | 473 | zlog_debug("%s, Exiting from HELPER support to %pI6, due to %s", |
474 | __func__, &nbr->linklocal_addr, | |
475 | ospf6_exit_reason_desc[reason]); | |
476 | ||
477 | /* Reset helper status*/ | |
478 | nbr->gr_helper_info.gr_helper_status = OSPF6_GR_NOT_HELPER; | |
479 | nbr->gr_helper_info.helper_exit_reason = reason; | |
480 | nbr->gr_helper_info.actual_grace_period = 0; | |
481 | nbr->gr_helper_info.recvd_grace_period = 0; | |
482 | nbr->gr_helper_info.gr_restart_reason = 0; | |
483 | ospf6->ospf6_helper_cfg.last_exit_reason = reason; | |
484 | ||
485 | /* If the exit not triggered due to grace timer | |
0fc3e113 | 486 | * expiry, stop the grace timer. |
9a06f23d | 487 | */ |
488 | if (reason != OSPF6_GR_HELPER_GRACE_TIMEOUT) | |
489 | THREAD_OFF(nbr->gr_helper_info.t_grace_timer); | |
490 | ||
491 | if (ospf6->ospf6_helper_cfg.active_restarter_cnt <= 0) { | |
492 | zlog_err( | |
493 | "OSPF6 GR-Helper: Number of active Restarters should be greater than zero."); | |
494 | return; | |
495 | } | |
0fc3e113 | 496 | /* Decrement active restarter count */ |
9a06f23d | 497 | ospf6->ospf6_helper_cfg.active_restarter_cnt--; |
498 | ||
499 | /* check exit triggered due to successful completion | |
500 | * of graceful restart. | |
501 | */ | |
502 | if (reason != OSPF6_GR_HELPER_COMPLETED) { | |
0fc3e113 | 503 | if (IS_DEBUG_OSPF6_GR) |
9a06f23d | 504 | zlog_debug("%s, Unsuccessful GR exit. RESTARTER : %pI6", |
505 | __func__, &nbr->linklocal_addr); | |
506 | } | |
507 | ||
508 | /*Recalculate the DR for the network segment */ | |
509 | dr_election(oi); | |
510 | ||
511 | /* Originate a router LSA */ | |
512 | OSPF6_ROUTER_LSA_SCHEDULE(nbr->ospf6_if->area); | |
513 | ||
514 | /* Originate network lsa if it is an DR in the LAN */ | |
515 | if (nbr->ospf6_if->state == OSPF6_INTERFACE_DR) | |
516 | OSPF6_NETWORK_LSA_SCHEDULE(nbr->ospf6_if); | |
517 | } | |
518 | ||
519 | /* | |
0fc3e113 | 520 | * Process max age Grace LSA. |
521 | * It is a indication for successful completion of GR. | |
9a06f23d | 522 | * If router acting as HELPER, It exits from helper role. |
523 | * | |
524 | * ospf6 | |
525 | * Ospf6 pointer. | |
526 | * | |
527 | * lsa | |
528 | * Grace LSA received from RESTARTER. | |
529 | * | |
530 | * nbr | |
0fc3e113 | 531 | * ospf6 neighbour which request the router to act as |
9a06f23d | 532 | * HELPER. |
533 | * | |
534 | * Returns: | |
535 | * Nothing. | |
536 | */ | |
537 | void ospf6_process_maxage_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, | |
538 | struct ospf6_neighbor *restarter) | |
539 | { | |
540 | uint8_t restart_reason = 0; | |
541 | uint32_t grace_interval = 0; | |
542 | int ret; | |
543 | ||
544 | /* Extract the grace lsa packet fields */ | |
545 | ret = ospf6_extract_grace_lsa_fields(lsa, &grace_interval, | |
546 | &restart_reason); | |
547 | if (ret != OSPF6_SUCCESS) { | |
0fc3e113 | 548 | if (IS_DEBUG_OSPF6_GR) |
549 | zlog_debug("%s, Wrong Grace LSA packet.", __func__); | |
9a06f23d | 550 | return; |
551 | } | |
552 | ||
0fc3e113 | 553 | if (IS_DEBUG_OSPF6_GR) |
9a06f23d | 554 | zlog_debug("%s, GraceLSA received for neighbour %pI4.", |
555 | __func__, &restarter->router_id); | |
556 | ||
557 | ospf6_gr_helper_exit(restarter, OSPF6_GR_HELPER_COMPLETED); | |
558 | } | |
559 | ||
560 | /* | |
561 | * Actions to be taken when topo change detected | |
562 | * HELPER will be exited upon a topo change. | |
563 | * | |
564 | * ospf6 | |
565 | * ospf6 pointer | |
566 | * lsa | |
0fc3e113 | 567 | * topo change occurred due to this lsa(type (1-5 and 7) |
9a06f23d | 568 | * |
569 | * Returns: | |
570 | * Nothing | |
571 | */ | |
572 | void ospf6_helper_handle_topo_chg(struct ospf6 *ospf6, struct ospf6_lsa *lsa) | |
573 | { | |
574 | struct listnode *i, *j, *k; | |
575 | struct ospf6_neighbor *nbr = NULL; | |
576 | struct ospf6_area *oa = NULL; | |
577 | struct ospf6_interface *oi = NULL; | |
578 | ||
579 | if (!ospf6->ospf6_helper_cfg.active_restarter_cnt) | |
580 | return; | |
581 | ||
0fc3e113 | 582 | /* Topo change not required to be handled if strict |
583 | * LSA check is disabled for this router. | |
9a06f23d | 584 | */ |
585 | if (!ospf6->ospf6_helper_cfg.strict_lsa_check) | |
586 | return; | |
587 | ||
0fc3e113 | 588 | if (IS_DEBUG_OSPF6_GR) |
589 | zlog_debug("%s, Topo change detected due to lsa details : %s", | |
590 | __func__, lsa->name); | |
9a06f23d | 591 | |
592 | lsa->tobe_acknowledged = OSPF6_TRUE; | |
593 | ||
594 | for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) | |
595 | for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { | |
596 | ||
597 | /* Ref rfc3623 section 3.2.3.b and rfc5187 | |
598 | * If change due to external LSA and if the area is | |
599 | * stub, then it is not a topo change. Since Type-5 | |
600 | * lsas will not be flooded in stub area. | |
601 | */ | |
602 | if (IS_AREA_STUB(oi->area) | |
603 | && ((lsa->header->type == OSPF6_LSTYPE_AS_EXTERNAL) | |
604 | || (lsa->header->type == OSPF6_LSTYPE_TYPE_7) | |
605 | || (lsa->header->type | |
606 | == OSPF6_LSTYPE_INTER_ROUTER))) { | |
607 | continue; | |
608 | } | |
609 | ||
610 | for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, nbr)) { | |
611 | ||
612 | ospf6_gr_helper_exit(nbr, | |
613 | OSPF6_GR_HELPER_TOPO_CHG); | |
614 | } | |
615 | } | |
616 | } | |
617 | ||
0fc3e113 | 618 | /* Configuration handlers */ |
619 | /* | |
620 | * Disable/Enable HELPER support on router level. | |
621 | * | |
622 | * ospf6 | |
623 | * Ospf6 pointer. | |
624 | * | |
625 | * status | |
626 | * TRUE/FALSE | |
627 | * | |
628 | * Returns: | |
629 | * Nothing. | |
630 | */ | |
631 | static void ospf6_gr_helper_support_set(struct ospf6 *ospf6, bool support) | |
632 | { | |
633 | struct ospf6_interface *oi; | |
634 | struct advRtr lookup; | |
635 | struct listnode *i, *j, *k; | |
636 | struct ospf6_neighbor *nbr = NULL; | |
637 | struct ospf6_area *oa = NULL; | |
638 | ||
639 | if (ospf6->ospf6_helper_cfg.is_helper_supported == support) | |
640 | return; | |
641 | ||
642 | ospf6->ospf6_helper_cfg.is_helper_supported = support; | |
643 | ||
644 | /* If helper support disabled, cease HELPER role for all | |
645 | * supporting neighbors. | |
646 | */ | |
647 | if (support == OSPF6_FALSE) { | |
648 | for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) | |
649 | for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { | |
650 | ||
651 | for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, | |
652 | nbr)) { | |
653 | ||
654 | lookup.advRtrAddr = nbr->router_id; | |
655 | /* check if helper support enabled for | |
656 | * the corresponding routerid. | |
657 | * If enabled, | |
658 | * dont exit from helper role. | |
659 | */ | |
660 | if (hash_lookup( | |
661 | ospf6->ospf6_helper_cfg | |
662 | .enable_rtr_list, | |
663 | &lookup)) | |
664 | continue; | |
665 | ||
666 | ospf6_gr_helper_exit( | |
667 | nbr, OSPF6_GR_HELPER_TOPO_CHG); | |
668 | } | |
669 | } | |
670 | } | |
671 | } | |
672 | ||
673 | /* | |
674 | * Api to enable/disable strict lsa check on the HELPER. | |
675 | * | |
676 | * ospf6 | |
677 | * Ospf6 pointer. | |
678 | * | |
679 | * enabled | |
680 | * True - disable the lsa check. | |
681 | * False - enable the strict lsa check. | |
682 | * | |
683 | * Returns: | |
684 | * Nothing. | |
685 | */ | |
686 | static void ospf6_gr_helper_lsacheck_set(struct ospf6 *ospf6, bool enabled) | |
687 | { | |
688 | if (ospf6->ospf6_helper_cfg.strict_lsa_check == enabled) | |
689 | return; | |
690 | ||
691 | ospf6->ospf6_helper_cfg.strict_lsa_check = enabled; | |
692 | } | |
693 | ||
694 | /* | |
695 | * Api to set the supported restart reason. | |
696 | * | |
697 | * ospf6 | |
698 | * Ospf6 pointer. | |
699 | * | |
700 | * only_planned | |
701 | * True: support only planned restart. | |
702 | * False: support for planned/unplanned restarts. | |
703 | * | |
704 | * Returns: | |
705 | * Nothing. | |
706 | */ | |
707 | ||
708 | static void | |
709 | ospf6_gr_helper_set_supported_onlyPlanned_restart(struct ospf6 *ospf6, | |
710 | bool only_planned) | |
711 | { | |
712 | ospf6->ospf6_helper_cfg.only_planned_restart = only_planned; | |
713 | } | |
714 | ||
715 | /* | |
716 | * Api to set the supported grace interval in this router. | |
717 | * | |
718 | * ospf6 | |
719 | * Ospf6 pointer. | |
720 | * | |
721 | * interval | |
722 | * The supported grace interval.. | |
723 | * | |
724 | * Returns: | |
725 | * Nothing. | |
726 | */ | |
727 | static void ospf6_gr_helper_supported_gracetime_set(struct ospf6 *ospf6, | |
728 | uint32_t interval) | |
729 | { | |
730 | ospf6->ospf6_helper_cfg.supported_grace_time = interval; | |
731 | } | |
732 | ||
733 | /* API to walk and print all the Helper supported router ids */ | |
734 | static int ospf6_print_vty_helper_dis_rtr_walkcb(struct hash_bucket *bucket, | |
735 | void *arg) | |
736 | { | |
737 | struct advRtr *rtr = bucket->data; | |
738 | struct vty *vty = (struct vty *)arg; | |
739 | static unsigned int count; | |
740 | ||
741 | vty_out(vty, "%-6pI4,", &rtr->advRtrAddr); | |
742 | count++; | |
743 | ||
744 | if (count % 5 == 0) | |
745 | vty_out(vty, "\n"); | |
746 | ||
747 | return HASHWALK_CONTINUE; | |
748 | } | |
749 | ||
750 | /* API to walk and print all the Helper supported router ids.*/ | |
751 | static int ospf6_print_json_helper_dis_rtr_walkcb(struct hash_bucket *bucket, | |
752 | void *arg) | |
753 | { | |
754 | struct advRtr *rtr = bucket->data; | |
755 | struct json_object *json_rid_array = (struct json_object *)arg; | |
756 | struct json_object *json_rid; | |
757 | char router_id[16]; | |
758 | ||
759 | inet_ntop(AF_INET, &rtr->advRtrAddr, router_id, sizeof(router_id)); | |
760 | ||
761 | json_rid = json_object_new_object(); | |
762 | ||
763 | json_object_string_add(json_rid, "routerId", router_id); | |
764 | json_object_array_add(json_rid_array, json_rid); | |
765 | ||
766 | return HASHWALK_CONTINUE; | |
767 | } | |
768 | ||
769 | /* | |
770 | * Enable/Disable HELPER support on a specified advertisement | |
771 | * router. | |
772 | * | |
773 | * ospf6 | |
774 | * Ospf6 pointer. | |
775 | * | |
776 | * advRtr | |
777 | * HELPER support for given Advertisement Router. | |
778 | * | |
779 | * support | |
780 | * True - Enable Helper Support. | |
781 | * False - Disable Helper Support. | |
782 | * | |
783 | * Returns: | |
784 | * Nothing. | |
785 | */ | |
786 | static void ospf6_gr_helper_support_set_per_routerid(struct ospf6 *ospf6, | |
787 | struct in_addr router_id, | |
788 | bool support) | |
789 | { | |
790 | struct advRtr temp; | |
791 | struct advRtr *rtr; | |
792 | struct listnode *i, *j, *k; | |
793 | struct ospf6_interface *oi; | |
794 | struct ospf6_neighbor *nbr; | |
795 | struct ospf6_area *oa; | |
796 | ||
797 | temp.advRtrAddr = router_id.s_addr; | |
798 | ||
799 | if (support == OSPF6_FALSE) { | |
800 | /*Delete the routerid from the enable router hash table */ | |
801 | rtr = hash_lookup(ospf6->ospf6_helper_cfg.enable_rtr_list, | |
802 | &temp); | |
803 | ||
804 | if (rtr) { | |
805 | hash_release(ospf6->ospf6_helper_cfg.enable_rtr_list, | |
806 | rtr); | |
807 | ospf6_disable_rtr_hash_free(rtr); | |
808 | } | |
809 | ||
810 | /* If helper support is enabled globally | |
811 | * no action is required. | |
812 | */ | |
813 | if (ospf6->ospf6_helper_cfg.is_helper_supported) | |
814 | return; | |
815 | ||
816 | /* Cease the HELPER role fore neighbours from the | |
817 | * specified advertisement router. | |
818 | */ | |
819 | for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) | |
820 | for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { | |
821 | ||
822 | for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, | |
823 | nbr)) { | |
824 | ||
825 | if (nbr->router_id != router_id.s_addr) | |
826 | continue; | |
827 | ||
828 | if (OSPF6_GR_IS_ACTIVE_HELPER(nbr)) | |
829 | ospf6_gr_helper_exit( | |
830 | nbr, | |
831 | OSPF6_GR_HELPER_TOPO_CHG); | |
832 | } | |
833 | } | |
834 | ||
835 | } else { | |
836 | /* Add the routerid to the enable router hash table */ | |
8e3aae66 | 837 | (void)hash_get(ospf6->ospf6_helper_cfg.enable_rtr_list, &temp, |
838 | ospf6_enable_rtr_hash_alloc); | |
0fc3e113 | 839 | } |
840 | } | |
841 | ||
842 | static void show_ospfv6_gr_helper_per_nbr(struct vty *vty, json_object *json, | |
843 | bool uj, struct ospf6_neighbor *nbr) | |
844 | { | |
845 | if (!uj) { | |
846 | vty_out(vty, " Routerid : %pI4\n", &nbr->router_id); | |
847 | vty_out(vty, " Received Grace period : %d(in seconds).\n", | |
848 | nbr->gr_helper_info.recvd_grace_period); | |
849 | vty_out(vty, " Actual Grace period : %d(in seconds)\n", | |
850 | nbr->gr_helper_info.actual_grace_period); | |
851 | vty_out(vty, " Remaining GraceTime:%ld(in seconds).\n", | |
852 | thread_timer_remain_second( | |
853 | nbr->gr_helper_info.t_grace_timer)); | |
854 | vty_out(vty, " Graceful Restart reason: %s.\n\n", | |
855 | ospf6_restart_reason_desc[nbr->gr_helper_info | |
856 | .gr_restart_reason]); | |
857 | } else { | |
858 | char nbrid[16]; | |
859 | json_object *json_neigh = NULL; | |
860 | ||
861 | inet_ntop(AF_INET, &nbr->router_id, nbrid, sizeof(nbrid)); | |
862 | json_neigh = json_object_new_object(); | |
863 | json_object_string_add(json_neigh, "routerid", nbrid); | |
864 | json_object_int_add(json_neigh, "recvdGraceInterval", | |
865 | nbr->gr_helper_info.recvd_grace_period); | |
866 | json_object_int_add(json_neigh, "actualGraceInterval", | |
867 | nbr->gr_helper_info.actual_grace_period); | |
868 | json_object_int_add(json_neigh, "remainGracetime", | |
869 | thread_timer_remain_second( | |
870 | nbr->gr_helper_info.t_grace_timer)); | |
871 | json_object_string_add(json_neigh, "restartReason", | |
872 | ospf6_restart_reason_desc[ | |
873 | nbr->gr_helper_info.gr_restart_reason]); | |
874 | json_object_object_add(json, nbr->name, json_neigh); | |
875 | } | |
876 | } | |
877 | ||
4d97dde2 | 878 | static void show_ospf6_gr_helper_details(struct vty *vty, struct ospf6 *ospf6, |
0fc3e113 | 879 | json_object *json, bool uj, bool detail) |
880 | { | |
881 | struct ospf6_interface *oi; | |
882 | ||
883 | /* Show Router ID. */ | |
884 | if (uj) { | |
885 | char router_id[16]; | |
886 | ||
887 | inet_ntop(AF_INET, &ospf6->router_id, router_id, | |
888 | sizeof(router_id)); | |
889 | json_object_string_add(json, "routerId", router_id); | |
890 | } else | |
891 | vty_out(vty, | |
892 | " OSPFv3 Routing Process (0) with Router-ID %pI4\n", | |
893 | &ospf6->router_id); | |
894 | ||
895 | if (!uj) { | |
896 | ||
897 | if (ospf6->ospf6_helper_cfg.is_helper_supported) | |
898 | vty_out(vty, | |
899 | " Graceful restart helper support enabled.\n"); | |
900 | else | |
901 | vty_out(vty, | |
902 | " Graceful restart helper support disabled.\n"); | |
903 | ||
904 | if (ospf6->ospf6_helper_cfg.strict_lsa_check) | |
905 | vty_out(vty, " Strict LSA check is enabled.\n"); | |
906 | else | |
907 | vty_out(vty, " Strict LSA check is disabled.\n"); | |
908 | ||
909 | if (ospf6->ospf6_helper_cfg.only_planned_restart) | |
910 | vty_out(vty, | |
911 | " Helper supported for planned restarts only.\n"); | |
912 | else | |
913 | vty_out(vty, | |
914 | " Helper supported for Planned and Unplanned Restarts.\n"); | |
915 | ||
916 | vty_out(vty, | |
917 | " Supported Graceful restart interval: %d(in seconds).\n", | |
918 | ospf6->ospf6_helper_cfg.supported_grace_time); | |
919 | ||
920 | if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf)) { | |
921 | vty_out(vty, " Enable Router list:\n"); | |
922 | vty_out(vty, " "); | |
923 | hash_walk(ospf6->ospf6_helper_cfg.enable_rtr_list, | |
924 | ospf6_print_vty_helper_dis_rtr_walkcb, vty); | |
925 | vty_out(vty, "\n\n"); | |
926 | } | |
927 | ||
928 | if (ospf6->ospf6_helper_cfg.last_exit_reason | |
929 | != OSPF6_GR_HELPER_EXIT_NONE) { | |
930 | vty_out(vty, " Last Helper exit Reason :%s\n", | |
931 | ospf6_exit_reason_desc | |
932 | [ospf6->ospf6_helper_cfg | |
933 | .last_exit_reason]); | |
934 | ||
935 | if (ospf6->ospf6_helper_cfg.active_restarter_cnt) | |
936 | vty_out(vty, | |
937 | " Number of Active neighbours in graceful restart: %d\n", | |
938 | ospf6->ospf6_helper_cfg | |
939 | .active_restarter_cnt); | |
940 | else | |
941 | vty_out(vty, "\n"); | |
942 | } | |
943 | ||
944 | ||
945 | } else { | |
946 | json_object_string_add( | |
947 | json, "helperSupport", | |
948 | (ospf6->ospf6_helper_cfg.is_helper_supported) | |
949 | ? "Enabled" | |
950 | : "Disabled"); | |
951 | json_object_string_add( | |
952 | json, "strictLsaCheck", | |
953 | (ospf6->ospf6_helper_cfg.strict_lsa_check) | |
954 | ? "Enabled" | |
955 | : "Disabled"); | |
956 | json_object_string_add( | |
957 | json, "restartSupoort", | |
958 | (ospf6->ospf6_helper_cfg.only_planned_restart) | |
959 | ? "Planned Restart only" | |
960 | : "Planned and Unplanned Restarts"); | |
961 | ||
962 | json_object_int_add( | |
963 | json, "supportedGracePeriod", | |
964 | ospf6->ospf6_helper_cfg.supported_grace_time); | |
965 | ||
77a2f8e5 | 966 | if (ospf6->ospf6_helper_cfg.last_exit_reason != |
1ce23106 | 967 | OSPF6_GR_HELPER_EXIT_NONE) |
77a2f8e5 DA |
968 | json_object_string_add( |
969 | json, "lastExitReason", | |
970 | ospf6_exit_reason_desc | |
971 | [ospf6->ospf6_helper_cfg | |
972 | .last_exit_reason]); | |
0fc3e113 | 973 | |
239ccb07 | 974 | if (ospf6->ospf6_helper_cfg.active_restarter_cnt) |
975 | json_object_int_add( | |
976 | json, "activeRestarterCnt", | |
977 | ospf6->ospf6_helper_cfg.active_restarter_cnt); | |
978 | ||
0fc3e113 | 979 | if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6)) { |
980 | struct json_object *json_rid_array = | |
981 | json_object_new_array(); | |
982 | ||
983 | json_object_object_add(json, "enabledRouterIds", | |
984 | json_rid_array); | |
985 | ||
986 | hash_walk(ospf6->ospf6_helper_cfg.enable_rtr_list, | |
987 | ospf6_print_json_helper_dis_rtr_walkcb, | |
988 | json_rid_array); | |
989 | } | |
990 | } | |
991 | ||
992 | if (detail) { | |
993 | int cnt = 1; | |
994 | struct listnode *i, *j, *k; | |
995 | struct ospf6_area *oa; | |
996 | json_object *json_neighbors = NULL; | |
997 | ||
998 | for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) | |
999 | for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { | |
1000 | struct ospf6_neighbor *nbr; | |
1001 | ||
1002 | if (uj) { | |
77a2f8e5 DA |
1003 | json_object_object_get_ex( |
1004 | json, "neighbors", | |
1005 | &json_neighbors); | |
0fc3e113 | 1006 | if (!json_neighbors) { |
1007 | json_neighbors = | |
1008 | json_object_new_object(); | |
77a2f8e5 DA |
1009 | json_object_object_add( |
1010 | json, "neighbors", | |
1011 | json_neighbors); | |
0fc3e113 | 1012 | } |
1013 | } | |
1014 | ||
1015 | for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, | |
1016 | nbr)) { | |
1017 | ||
1018 | if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr)) | |
1019 | continue; | |
1020 | ||
1021 | if (!uj) | |
1022 | vty_out(vty, | |
1023 | " Neighbour %d :\n", | |
1024 | cnt++); | |
1025 | ||
1026 | show_ospfv6_gr_helper_per_nbr( | |
1027 | vty, json_neighbors, uj, nbr); | |
1028 | ||
1029 | } | |
1030 | } | |
1031 | } | |
0fc3e113 | 1032 | } |
1033 | ||
1034 | /* Graceful Restart HELPER config Commands */ | |
1035 | DEFPY(ospf6_gr_helper_enable, | |
1036 | ospf6_gr_helper_enable_cmd, | |
6b513b4c | 1037 | "graceful-restart helper enable [A.B.C.D$rtr_id]", |
0fc3e113 | 1038 | "ospf6 graceful restart\n" |
6b513b4c | 1039 | "ospf6 GR Helper\n" |
0fc3e113 | 1040 | "Enable Helper support\n" |
6b513b4c | 1041 | "Advertisement Router-ID\n") |
0fc3e113 | 1042 | { |
1043 | VTY_DECLVAR_CONTEXT(ospf6, ospf6); | |
1044 | ||
1045 | if (rtr_id_str != NULL) { | |
1046 | ||
1047 | ospf6_gr_helper_support_set_per_routerid(ospf6, rtr_id, | |
1048 | OSPF6_TRUE); | |
1049 | ||
1050 | return CMD_SUCCESS; | |
1051 | } | |
1052 | ||
1053 | ospf6_gr_helper_support_set(ospf6, OSPF6_TRUE); | |
1054 | ||
1055 | return CMD_SUCCESS; | |
1056 | } | |
1057 | ||
1058 | DEFPY(ospf6_gr_helper_disable, | |
1059 | ospf6_gr_helper_disable_cmd, | |
6b513b4c | 1060 | "no graceful-restart helper enable [A.B.C.D$rtr_id]", |
0fc3e113 | 1061 | NO_STR |
1062 | "ospf6 graceful restart\n" | |
6b513b4c RW |
1063 | "ospf6 GR Helper\n" |
1064 | "Enable Helper support\n" | |
1065 | "Advertisement Router-ID\n") | |
0fc3e113 | 1066 | { |
1067 | VTY_DECLVAR_CONTEXT(ospf6, ospf6); | |
1068 | ||
1069 | if (rtr_id_str != NULL) { | |
1070 | ||
1071 | ospf6_gr_helper_support_set_per_routerid(ospf6, rtr_id, | |
1072 | OSPF6_FALSE); | |
1073 | ||
1074 | return CMD_SUCCESS; | |
1075 | } | |
1076 | ||
1077 | ospf6_gr_helper_support_set(ospf6, OSPF6_FALSE); | |
1078 | ||
1079 | return CMD_SUCCESS; | |
1080 | } | |
1081 | ||
1082 | DEFPY(ospf6_gr_helper_disable_lsacheck, | |
1083 | ospf6_gr_helper_disable_lsacheck_cmd, | |
1084 | "graceful-restart helper lsa-check-disable", | |
1085 | "ospf6 graceful restart\n" | |
1086 | "ospf6 GR Helper\n" | |
1087 | "disable strict LSA check\n") | |
1088 | { | |
1089 | VTY_DECLVAR_CONTEXT(ospf6, ospf6); | |
1090 | ||
1091 | ospf6_gr_helper_lsacheck_set(ospf6, OSPF6_FALSE); | |
1092 | return CMD_SUCCESS; | |
1093 | } | |
1094 | ||
1095 | DEFPY(no_ospf6_gr_helper_disable_lsacheck, | |
1096 | no_ospf6_gr_helper_disable_lsacheck_cmd, | |
1097 | "no graceful-restart helper lsa-check-disable", | |
1098 | NO_STR | |
1099 | "ospf6 graceful restart\n" | |
1100 | "ospf6 GR Helper\n" | |
1101 | "diasble strict LSA check\n") | |
1102 | { | |
1103 | VTY_DECLVAR_CONTEXT(ospf6, ospf6); | |
1104 | ||
1105 | ospf6_gr_helper_lsacheck_set(ospf6, OSPF6_TRUE); | |
1106 | return CMD_SUCCESS; | |
1107 | } | |
1108 | ||
1109 | DEFPY(ospf6_gr_helper_planned_only, | |
1110 | ospf6_gr_helper_planned_only_cmd, | |
1111 | "graceful-restart helper planned-only", | |
1112 | "ospf6 graceful restart\n" | |
1113 | "ospf6 GR Helper\n" | |
1114 | "supported only planned restart\n") | |
1115 | { | |
1116 | VTY_DECLVAR_CONTEXT(ospf6, ospf6); | |
1117 | ||
1118 | ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6, OSPF6_TRUE); | |
1119 | ||
1120 | return CMD_SUCCESS; | |
1121 | } | |
1122 | ||
1123 | DEFPY(no_ospf6_gr_helper_planned_only, no_ospf6_gr_helper_planned_only_cmd, | |
1124 | "no graceful-restart helper planned-only", | |
1125 | NO_STR | |
1126 | "ospf6 graceful restart\n" | |
1127 | "ospf6 GR Helper\n" | |
1128 | "supported only for planned restart\n") | |
1129 | { | |
1130 | VTY_DECLVAR_CONTEXT(ospf6, ospf6); | |
1131 | ||
1132 | ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6, OSPF6_FALSE); | |
1133 | ||
1134 | return CMD_SUCCESS; | |
1135 | } | |
1136 | ||
1137 | DEFPY(ospf6_gr_helper_supported_grace_time, | |
1138 | ospf6_gr_helper_supported_grace_time_cmd, | |
1139 | "graceful-restart helper supported-grace-time (10-1800)$interval", | |
1140 | "ospf6 graceful restart\n" | |
1141 | "ospf6 GR Helper\n" | |
1142 | "supported grace timer\n" | |
1143 | "grace interval(in seconds)\n") | |
1144 | { | |
1145 | VTY_DECLVAR_CONTEXT(ospf6, ospf6); | |
1146 | ||
1147 | ospf6_gr_helper_supported_gracetime_set(ospf6, interval); | |
1148 | return CMD_SUCCESS; | |
1149 | } | |
1150 | ||
1151 | DEFPY(no_ospf6_gr_helper_supported_grace_time, | |
1152 | no_ospf6_gr_helper_supported_grace_time_cmd, | |
1153 | "no graceful-restart helper supported-grace-time (10-1800)$interval", | |
1154 | NO_STR | |
1155 | "ospf6 graceful restart\n" | |
1156 | "ospf6 GR Helper\n" | |
1157 | "supported grace timer\n" | |
1158 | "grace interval(in seconds)\n") | |
1159 | { | |
1160 | VTY_DECLVAR_CONTEXT(ospf6, ospf6); | |
1161 | ||
1162 | ospf6_gr_helper_supported_gracetime_set(ospf6, | |
1163 | OSPF6_MAX_GRACE_INTERVAL); | |
1164 | return CMD_SUCCESS; | |
1165 | } | |
1166 | ||
1167 | /* Show commands */ | |
1168 | DEFPY(show_ipv6_ospf6_gr_helper, | |
1169 | show_ipv6_ospf6_gr_helper_cmd, | |
1170 | "show ipv6 ospf6 graceful-restart helper [detail] [json]", | |
1171 | SHOW_STR | |
1172 | "Ipv6 Information\n" | |
1173 | "OSPF6 information\n" | |
1174 | "ospf6 graceful restart\n" | |
1175 | "helper details in the router\n" | |
1176 | "detailed information\n" JSON_STR) | |
1177 | { | |
1178 | int idx = 0; | |
1179 | bool uj = use_json(argc, argv); | |
1180 | struct ospf6 *ospf6 = NULL; | |
1181 | json_object *json = NULL; | |
1182 | bool detail = false; | |
1183 | ||
1184 | ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME); | |
390dce12 IR |
1185 | if (ospf6 == NULL) { |
1186 | vty_out(vty, "OSPFv3 is not configured\n"); | |
1187 | return CMD_SUCCESS; | |
1188 | } | |
0fc3e113 | 1189 | |
1190 | if (argv_find(argv, argc, "detail", &idx)) | |
1191 | detail = true; | |
1192 | ||
1193 | if (uj) | |
1194 | json = json_object_new_object(); | |
1195 | ||
1196 | show_ospf6_gr_helper_details(vty, ospf6, json, uj, detail); | |
1197 | ||
c48349e3 | 1198 | if (uj) |
5a6c232b | 1199 | vty_json(vty, json); |
0fc3e113 | 1200 | |
1201 | return CMD_SUCCESS; | |
1202 | } | |
1203 | ||
06943666 | 1204 | /* Debug commands */ |
0fc3e113 | 1205 | DEFPY(debug_ospf6_gr, debug_ospf6_gr_cmd, |
06943666 | 1206 | "[no$no] debug ospf6 graceful-restart", |
0fc3e113 | 1207 | NO_STR DEBUG_STR OSPF6_STR "Graceful restart\n") |
06943666 | 1208 | { |
1209 | if (!no) | |
0fc3e113 | 1210 | OSPF6_DEBUG_GR_ON(); |
06943666 | 1211 | else |
0fc3e113 | 1212 | OSPF6_DEBUG_GR_OFF(); |
06943666 | 1213 | |
1214 | return CMD_SUCCESS; | |
1215 | } | |
1216 | ||
0fc3e113 | 1217 | /* |
1218 | * Api to display the grace LSA information. | |
1219 | * | |
1220 | * vty | |
1221 | * vty pointer. | |
1222 | * lsa | |
1223 | * Grace LSA. | |
1224 | * json | |
1225 | * json object | |
1226 | * | |
1227 | * Returns: | |
1228 | * Nothing. | |
1229 | */ | |
1230 | static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa, | |
1231 | json_object *json, bool use_json) | |
1232 | { | |
1233 | struct ospf6_lsa_header *lsah = NULL; | |
1234 | struct tlv_header *tlvh = NULL; | |
1235 | struct grace_tlv_graceperiod *gracePeriod; | |
1236 | struct grace_tlv_restart_reason *grReason; | |
1237 | uint16_t length = 0; | |
1238 | int sum = 0; | |
1239 | ||
1240 | lsah = (struct ospf6_lsa_header *)lsa->header; | |
905b12b2 | 1241 | if (ntohs(lsah->length) <= OSPF6_LSA_HEADER_SIZE) { |
1242 | if (IS_DEBUG_OSPF6_GR) | |
1243 | zlog_debug("%s: undersized (%u B) lsa", __func__, | |
1244 | ntohs(lsah->length)); | |
1245 | return OSPF6_FAILURE; | |
1246 | } | |
0fc3e113 | 1247 | |
1248 | length = ntohs(lsah->length) - OSPF6_LSA_HEADER_SIZE; | |
1249 | ||
1250 | if (vty) { | |
1251 | if (!use_json) | |
1252 | vty_out(vty, "TLV info:\n"); | |
1253 | } else { | |
1254 | zlog_debug(" TLV info:"); | |
1255 | } | |
1256 | ||
6d1a5a1c | 1257 | for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh; |
0fc3e113 | 1258 | tlvh = TLV_HDR_NEXT(tlvh)) { |
6d1a5a1c | 1259 | |
1260 | /* Check TLV len */ | |
1261 | if (sum + TLV_SIZE(tlvh) > length) { | |
1262 | if (vty) | |
1263 | vty_out(vty, "%% Invalid TLV length: %d\n", | |
1264 | TLV_SIZE(tlvh)); | |
1265 | else if (IS_DEBUG_OSPF6_GR) | |
1266 | zlog_debug("%% Invalid TLV length: %d", | |
1267 | TLV_SIZE(tlvh)); | |
1268 | return OSPF6_FAILURE; | |
1269 | } | |
1270 | ||
0fc3e113 | 1271 | switch (ntohs(tlvh->type)) { |
1272 | case GRACE_PERIOD_TYPE: | |
1273 | gracePeriod = (struct grace_tlv_graceperiod *)tlvh; | |
1274 | sum += TLV_SIZE(tlvh); | |
1275 | ||
1276 | if (vty) { | |
1277 | if (use_json) | |
1278 | json_object_int_add( | |
1279 | json, "gracePeriod", | |
1280 | ntohl(gracePeriod->interval)); | |
1281 | else | |
1282 | vty_out(vty, " Grace period:%d\n", | |
1283 | ntohl(gracePeriod->interval)); | |
1284 | } else { | |
1285 | zlog_debug(" Grace period:%d", | |
1286 | ntohl(gracePeriod->interval)); | |
1287 | } | |
1288 | break; | |
1289 | case RESTART_REASON_TYPE: | |
1290 | grReason = (struct grace_tlv_restart_reason *)tlvh; | |
1291 | sum += TLV_SIZE(tlvh); | |
1292 | if (vty) { | |
1293 | if (use_json) | |
1294 | json_object_string_add( | |
1295 | json, "restartReason", | |
1296 | ospf6_restart_reason_desc | |
1297 | [grReason->reason]); | |
1298 | else | |
1299 | vty_out(vty, " Restart reason:%s\n", | |
1300 | ospf6_restart_reason_desc | |
1301 | [grReason->reason]); | |
1302 | } else { | |
1303 | zlog_debug(" Restart reason:%s", | |
1304 | ospf6_restart_reason_desc | |
1305 | [grReason->reason]); | |
1306 | } | |
1307 | break; | |
1308 | default: | |
1309 | break; | |
1310 | } | |
1311 | } | |
1312 | ||
1313 | return 0; | |
1314 | } | |
1315 | ||
1316 | void ospf6_gr_helper_config_init(void) | |
1317 | { | |
1318 | ||
1319 | ospf6_install_lsa_handler(&grace_lsa_handler); | |
1320 | ||
1321 | install_element(OSPF6_NODE, &ospf6_gr_helper_enable_cmd); | |
1322 | install_element(OSPF6_NODE, &ospf6_gr_helper_disable_cmd); | |
1323 | install_element(OSPF6_NODE, &ospf6_gr_helper_disable_lsacheck_cmd); | |
1324 | install_element(OSPF6_NODE, &no_ospf6_gr_helper_disable_lsacheck_cmd); | |
1325 | install_element(OSPF6_NODE, &ospf6_gr_helper_planned_only_cmd); | |
1326 | install_element(OSPF6_NODE, &no_ospf6_gr_helper_planned_only_cmd); | |
1327 | install_element(OSPF6_NODE, &ospf6_gr_helper_supported_grace_time_cmd); | |
1328 | install_element(OSPF6_NODE, | |
1329 | &no_ospf6_gr_helper_supported_grace_time_cmd); | |
1330 | ||
1331 | install_element(VIEW_NODE, &show_ipv6_ospf6_gr_helper_cmd); | |
1332 | ||
1333 | install_element(CONFIG_NODE, &debug_ospf6_gr_cmd); | |
1334 | install_element(ENABLE_NODE, &debug_ospf6_gr_cmd); | |
1335 | } | |
1336 | ||
1337 | ||
59790f52 | 1338 | /* |
0d1753a7 | 1339 | * Initialize GR helper config data structure. |
59790f52 | 1340 | * |
1341 | * ospf6 | |
1342 | * ospf6 pointer | |
1343 | * | |
1344 | * Returns: | |
1345 | * Nothing | |
1346 | */ | |
1347 | void ospf6_gr_helper_init(struct ospf6 *ospf6) | |
1348 | { | |
0fc3e113 | 1349 | if (IS_DEBUG_OSPF6_GR) |
0d1753a7 | 1350 | zlog_debug("%s, GR Helper init.", __func__); |
06943666 | 1351 | |
59790f52 | 1352 | ospf6->ospf6_helper_cfg.is_helper_supported = OSPF6_FALSE; |
1353 | ospf6->ospf6_helper_cfg.strict_lsa_check = OSPF6_TRUE; | |
1354 | ospf6->ospf6_helper_cfg.only_planned_restart = OSPF6_FALSE; | |
1355 | ospf6->ospf6_helper_cfg.supported_grace_time = OSPF6_MAX_GRACE_INTERVAL; | |
1356 | ospf6->ospf6_helper_cfg.last_exit_reason = OSPF6_GR_HELPER_EXIT_NONE; | |
1357 | ospf6->ospf6_helper_cfg.active_restarter_cnt = 0; | |
1358 | ||
1359 | ospf6->ospf6_helper_cfg.enable_rtr_list = hash_create( | |
1360 | ospf6_enable_rtr_hash_key, ospf6_enable_rtr_hash_cmp, | |
1361 | "Ospf6 enable router hash"); | |
1362 | } | |
1363 | ||
1364 | /* | |
0fc3e113 | 1365 | * De-initialize GR helper config data structure. |
59790f52 | 1366 | * |
1367 | * ospf6 | |
1368 | * ospf6 pointer | |
1369 | * | |
1370 | * Returns: | |
1371 | * Nothing | |
1372 | */ | |
1373 | void ospf6_gr_helper_deinit(struct ospf6 *ospf6) | |
1374 | { | |
06943666 | 1375 | |
0fc3e113 | 1376 | if (IS_DEBUG_OSPF6_GR) |
0d1753a7 | 1377 | zlog_debug("%s, GR helper deinit.", __func__); |
06943666 | 1378 | |
59790f52 | 1379 | ospf6_enable_rtr_hash_destroy(ospf6); |
1380 | } | |
0fc3e113 | 1381 | |
1382 | static int ospf6_cfg_write_helper_enable_rtr_walkcb(struct hash_bucket *backet, | |
1383 | void *arg) | |
1384 | { | |
1385 | struct advRtr *rtr = backet->data; | |
1386 | struct vty *vty = (struct vty *)arg; | |
1387 | ||
6b513b4c | 1388 | vty_out(vty, " graceful-restart helper enable %pI4\n", &rtr->advRtrAddr); |
0fc3e113 | 1389 | return HASHWALK_CONTINUE; |
1390 | } | |
1391 | ||
1392 | int config_write_ospf6_gr_helper(struct vty *vty, struct ospf6 *ospf6) | |
1393 | { | |
1394 | if (ospf6->ospf6_helper_cfg.is_helper_supported) | |
6b513b4c | 1395 | vty_out(vty, " graceful-restart helper enable\n"); |
0fc3e113 | 1396 | |
1397 | if (!ospf6->ospf6_helper_cfg.strict_lsa_check) | |
1398 | vty_out(vty, " graceful-restart helper lsa-check-disable\n"); | |
1399 | ||
1400 | if (ospf6->ospf6_helper_cfg.only_planned_restart) | |
1401 | vty_out(vty, " graceful-restart helper planned-only\n"); | |
1402 | ||
1403 | if (ospf6->ospf6_helper_cfg.supported_grace_time | |
1404 | != OSPF6_MAX_GRACE_INTERVAL) | |
1405 | vty_out(vty, | |
1406 | " graceful-restart helper supported-grace-time %d\n", | |
1407 | ospf6->ospf6_helper_cfg.supported_grace_time); | |
1408 | ||
1409 | if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6)) { | |
1410 | hash_walk(ospf6->ospf6_helper_cfg.enable_rtr_list, | |
1411 | ospf6_cfg_write_helper_enable_rtr_walkcb, vty); | |
1412 | } | |
1413 | ||
1414 | return 0; | |
1415 | } | |
1416 | ||
1417 | int config_write_ospf6_debug_gr_helper(struct vty *vty) | |
1418 | { | |
1419 | if (IS_DEBUG_OSPF6_GR) | |
3ebc5e4b | 1420 | vty_out(vty, "debug ospf6 graceful-restart\n"); |
0fc3e113 | 1421 | return 0; |
1422 | } |