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