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