]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* |
508e53e2 | 2 | * Copyright (C) 2003 Yasuhiro Ohara |
718e3744 | 3 | * |
4 | * This file is part of GNU Zebra. | |
5 | * | |
6 | * GNU Zebra is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation; either version 2, or (at your option) any | |
9 | * later version. | |
10 | * | |
11 | * GNU Zebra is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * General Public License for more details. | |
15 | * | |
896014f4 DL |
16 | * You should have received a copy of the GNU General Public License along |
17 | * with this program; see the file COPYING; if not, write to the Free Software | |
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
718e3744 | 19 | */ |
20 | ||
718e3744 | 21 | #include <zebra.h> |
22 | ||
23 | #include "log.h" | |
508e53e2 | 24 | #include "memory.h" |
718e3744 | 25 | #include "thread.h" |
26 | #include "linklist.h" | |
27 | #include "vty.h" | |
28 | #include "command.h" | |
d06cc416 | 29 | #include "lib/bfd.h" |
718e3744 | 30 | |
508e53e2 | 31 | #include "ospf6_proto.h" |
718e3744 | 32 | #include "ospf6_lsa.h" |
508e53e2 | 33 | #include "ospf6_lsdb.h" |
718e3744 | 34 | #include "ospf6_message.h" |
508e53e2 | 35 | #include "ospf6_top.h" |
36 | #include "ospf6_area.h" | |
37 | #include "ospf6_interface.h" | |
718e3744 | 38 | #include "ospf6_neighbor.h" |
508e53e2 | 39 | #include "ospf6_intra.h" |
3b4cd3a9 | 40 | #include "ospf6_flood.h" |
049207c3 | 41 | #include "ospf6d.h" |
7f342629 | 42 | #include "ospf6_bfd.h" |
4dfd8aff DW |
43 | #include "ospf6_abr.h" |
44 | #include "ospf6_asbr.h" | |
45 | #include "ospf6_lsa.h" | |
46 | #include "ospf6_spf.h" | |
47 | #include "ospf6_zebra.h" | |
0d1753a7 | 48 | #include "ospf6_gr.h" |
6a5bb300 | 49 | #include "lib/json.h" |
718e3744 | 50 | |
30043e4c DL |
51 | DEFINE_MTYPE(OSPF6D, OSPF6_NEIGHBOR, "OSPF6 neighbor"); |
52 | ||
3012671f | 53 | DEFINE_HOOK(ospf6_neighbor_change, |
d62a17ae | 54 | (struct ospf6_neighbor * on, int state, int next_state), |
8451921b | 55 | (on, state, next_state)); |
3012671f | 56 | |
508e53e2 | 57 | unsigned char conf_debug_ospf6_neighbor = 0; |
58 | ||
2b64873d | 59 | const char *const ospf6_neighbor_state_str[] = { |
d62a17ae | 60 | "None", "Down", "Attempt", "Init", "Twoway", |
61 | "ExStart", "ExChange", "Loading", "Full", NULL}; | |
718e3744 | 62 | |
2b64873d DL |
63 | const char *const ospf6_neighbor_event_str[] = { |
64 | "NoEvent", "HelloReceived", "2-WayReceived", "NegotiationDone", | |
65 | "ExchangeDone", "LoadingDone", "AdjOK?", "SeqNumberMismatch", | |
66 | "BadLSReq", "1-WayReceived", "InactivityTimer", | |
67 | }; | |
68 | ||
d62a17ae | 69 | int ospf6_neighbor_cmp(void *va, void *vb) |
718e3744 | 70 | { |
d62a17ae | 71 | struct ospf6_neighbor *ona = (struct ospf6_neighbor *)va; |
72 | struct ospf6_neighbor *onb = (struct ospf6_neighbor *)vb; | |
27fa3398 DS |
73 | |
74 | if (ona->router_id == onb->router_id) | |
75 | return 0; | |
76 | ||
77 | return (ntohl(ona->router_id) < ntohl(onb->router_id)) ? -1 : 1; | |
718e3744 | 78 | } |
79 | ||
d7c0a89a | 80 | struct ospf6_neighbor *ospf6_neighbor_lookup(uint32_t router_id, |
d62a17ae | 81 | struct ospf6_interface *oi) |
718e3744 | 82 | { |
d62a17ae | 83 | struct listnode *n; |
84 | struct ospf6_neighbor *on; | |
85 | ||
86 | for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, n, on)) | |
87 | if (on->router_id == router_id) | |
88 | return on; | |
89 | ||
90 | return (struct ospf6_neighbor *)NULL; | |
718e3744 | 91 | } |
92 | ||
71165098 RW |
93 | struct ospf6_neighbor *ospf6_area_neighbor_lookup(struct ospf6_area *area, |
94 | uint32_t router_id) | |
95 | { | |
96 | struct ospf6_interface *oi; | |
97 | struct ospf6_neighbor *nbr; | |
98 | struct listnode *node; | |
99 | ||
100 | for (ALL_LIST_ELEMENTS_RO(area->if_list, node, oi)) { | |
101 | nbr = ospf6_neighbor_lookup(router_id, oi); | |
102 | if (nbr) | |
103 | return nbr; | |
104 | } | |
105 | ||
106 | return NULL; | |
107 | } | |
108 | ||
508e53e2 | 109 | /* create ospf6_neighbor */ |
d7c0a89a | 110 | struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id, |
d62a17ae | 111 | struct ospf6_interface *oi) |
718e3744 | 112 | { |
d62a17ae | 113 | struct ospf6_neighbor *on; |
114 | char buf[16]; | |
115 | ||
aa406bbc | 116 | on = XCALLOC(MTYPE_OSPF6_NEIGHBOR, sizeof(struct ospf6_neighbor)); |
d62a17ae | 117 | inet_ntop(AF_INET, &router_id, buf, sizeof(buf)); |
118 | snprintf(on->name, sizeof(on->name), "%s%%%s", buf, | |
119 | oi->interface->name); | |
120 | on->ospf6_if = oi; | |
121 | on->state = OSPF6_NEIGHBOR_DOWN; | |
122 | on->state_change = 0; | |
123 | monotime(&on->last_changed); | |
124 | on->router_id = router_id; | |
125 | ||
126 | on->summary_list = ospf6_lsdb_create(on); | |
127 | on->request_list = ospf6_lsdb_create(on); | |
128 | on->retrans_list = ospf6_lsdb_create(on); | |
129 | ||
130 | on->dbdesc_list = ospf6_lsdb_create(on); | |
131 | on->lsupdate_list = ospf6_lsdb_create(on); | |
132 | on->lsack_list = ospf6_lsdb_create(on); | |
133 | ||
134 | listnode_add_sort(oi->neighbor_list, on); | |
135 | ||
136 | ospf6_bfd_info_nbr_create(oi, on); | |
137 | return on; | |
718e3744 | 138 | } |
139 | ||
d62a17ae | 140 | void ospf6_neighbor_delete(struct ospf6_neighbor *on) |
718e3744 | 141 | { |
2e37407f | 142 | struct ospf6_lsa *lsa, *lsanext; |
3b4cd3a9 | 143 | |
d62a17ae | 144 | ospf6_lsdb_remove_all(on->summary_list); |
145 | ospf6_lsdb_remove_all(on->request_list); | |
2e37407f | 146 | for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { |
d62a17ae | 147 | ospf6_decrement_retrans_count(lsa); |
148 | ospf6_lsdb_remove(lsa, on->retrans_list); | |
149 | } | |
718e3744 | 150 | |
d62a17ae | 151 | ospf6_lsdb_remove_all(on->dbdesc_list); |
152 | ospf6_lsdb_remove_all(on->lsupdate_list); | |
153 | ospf6_lsdb_remove_all(on->lsack_list); | |
508e53e2 | 154 | |
d62a17ae | 155 | ospf6_lsdb_delete(on->summary_list); |
156 | ospf6_lsdb_delete(on->request_list); | |
157 | ospf6_lsdb_delete(on->retrans_list); | |
718e3744 | 158 | |
d62a17ae | 159 | ospf6_lsdb_delete(on->dbdesc_list); |
160 | ospf6_lsdb_delete(on->lsupdate_list); | |
161 | ospf6_lsdb_delete(on->lsack_list); | |
508e53e2 | 162 | |
d62a17ae | 163 | THREAD_OFF(on->inactivity_timer); |
508e53e2 | 164 | |
bc09f3e6 YR |
165 | THREAD_OFF(on->last_dbdesc_release_timer); |
166 | ||
d62a17ae | 167 | THREAD_OFF(on->thread_send_dbdesc); |
168 | THREAD_OFF(on->thread_send_lsreq); | |
169 | THREAD_OFF(on->thread_send_lsupdate); | |
170 | THREAD_OFF(on->thread_send_lsack); | |
0d1753a7 | 171 | THREAD_OFF(on->gr_helper_info.t_grace_timer); |
508e53e2 | 172 | |
d06cc416 | 173 | bfd_sess_free(&on->bfd_session); |
d62a17ae | 174 | XFREE(MTYPE_OSPF6_NEIGHBOR, on); |
718e3744 | 175 | } |
176 | ||
d7c0a89a | 177 | static void ospf6_neighbor_state_change(uint8_t next_state, |
d62a17ae | 178 | struct ospf6_neighbor *on, int event) |
718e3744 | 179 | { |
d7c0a89a | 180 | uint8_t prev_state; |
d62a17ae | 181 | |
182 | prev_state = on->state; | |
183 | on->state = next_state; | |
184 | ||
185 | if (prev_state == next_state) | |
186 | return; | |
187 | ||
188 | on->state_change++; | |
189 | monotime(&on->last_changed); | |
190 | ||
191 | /* log */ | |
192 | if (IS_OSPF6_DEBUG_NEIGHBOR(STATE)) { | |
193 | zlog_debug("Neighbor state change %s: [%s]->[%s] (%s)", | |
194 | on->name, ospf6_neighbor_state_str[prev_state], | |
195 | ospf6_neighbor_state_str[next_state], | |
196 | ospf6_neighbor_event_string(event)); | |
197 | } | |
198 | ||
199 | /* Optionally notify about adjacency changes */ | |
200 | if (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags, | |
201 | OSPF6_LOG_ADJACENCY_CHANGES) | |
202 | && (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags, | |
203 | OSPF6_LOG_ADJACENCY_DETAIL) | |
204 | || (next_state == OSPF6_NEIGHBOR_FULL) | |
205 | || (next_state < prev_state))) | |
206 | zlog_notice("AdjChg: Nbr %s: %s -> %s (%s)", on->name, | |
207 | ospf6_neighbor_state_str[prev_state], | |
208 | ospf6_neighbor_state_str[next_state], | |
209 | ospf6_neighbor_event_string(event)); | |
210 | ||
211 | if (prev_state == OSPF6_NEIGHBOR_FULL | |
212 | || next_state == OSPF6_NEIGHBOR_FULL) { | |
0d1753a7 | 213 | if (!OSPF6_GR_IS_ACTIVE_HELPER(on)) { |
214 | OSPF6_ROUTER_LSA_SCHEDULE(on->ospf6_if->area); | |
215 | if (on->ospf6_if->state == OSPF6_INTERFACE_DR) { | |
216 | OSPF6_NETWORK_LSA_SCHEDULE(on->ospf6_if); | |
217 | OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT( | |
218 | on->ospf6_if); | |
219 | } | |
d62a17ae | 220 | } |
690df177 CS |
221 | if (next_state == OSPF6_NEIGHBOR_FULL) |
222 | on->ospf6_if->area->intra_prefix_originate = 1; | |
223 | ||
0d1753a7 | 224 | if (!OSPF6_GR_IS_ACTIVE_HELPER(on)) |
225 | OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB( | |
226 | on->ospf6_if->area); | |
76249532 | 227 | |
0d1753a7 | 228 | if ((prev_state == OSPF6_NEIGHBOR_LOADING |
229 | || prev_state == OSPF6_NEIGHBOR_EXCHANGE) | |
230 | && next_state == OSPF6_NEIGHBOR_FULL) { | |
76249532 | 231 | OSPF6_AS_EXTERN_LSA_SCHEDULE(on->ospf6_if); |
d6927cf3 | 232 | on->ospf6_if->area->full_nbrs++; |
76249532 | 233 | } |
d6927cf3 CS |
234 | |
235 | if (prev_state == OSPF6_NEIGHBOR_FULL) | |
236 | on->ospf6_if->area->full_nbrs--; | |
d62a17ae | 237 | } |
238 | ||
239 | if ((prev_state == OSPF6_NEIGHBOR_EXCHANGE | |
240 | || prev_state == OSPF6_NEIGHBOR_LOADING) | |
241 | && (next_state != OSPF6_NEIGHBOR_EXCHANGE | |
242 | && next_state != OSPF6_NEIGHBOR_LOADING)) | |
243 | ospf6_maxage_remove(on->ospf6_if->area->ospf6); | |
244 | ||
245 | hook_call(ospf6_neighbor_change, on, next_state, prev_state); | |
246 | ospf6_bfd_trigger_event(on, prev_state, next_state); | |
718e3744 | 247 | } |
248 | ||
508e53e2 | 249 | /* RFC2328 section 10.4 */ |
d62a17ae | 250 | static int need_adjacency(struct ospf6_neighbor *on) |
718e3744 | 251 | { |
d62a17ae | 252 | if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT |
253 | || on->ospf6_if->state == OSPF6_INTERFACE_DR | |
254 | || on->ospf6_if->state == OSPF6_INTERFACE_BDR) | |
255 | return 1; | |
718e3744 | 256 | |
d62a17ae | 257 | if (on->ospf6_if->drouter == on->router_id |
258 | || on->ospf6_if->bdrouter == on->router_id) | |
259 | return 1; | |
508e53e2 | 260 | |
d62a17ae | 261 | return 0; |
718e3744 | 262 | } |
263 | ||
d62a17ae | 264 | int hello_received(struct thread *thread) |
718e3744 | 265 | { |
d62a17ae | 266 | struct ospf6_neighbor *on; |
718e3744 | 267 | |
d62a17ae | 268 | on = (struct ospf6_neighbor *)THREAD_ARG(thread); |
269 | assert(on); | |
718e3744 | 270 | |
d62a17ae | 271 | if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) |
272 | zlog_debug("Neighbor Event %s: *HelloReceived*", on->name); | |
508e53e2 | 273 | |
d62a17ae | 274 | /* reset Inactivity Timer */ |
275 | THREAD_OFF(on->inactivity_timer); | |
d62a17ae | 276 | thread_add_timer(master, inactivity_timer, on, |
277 | on->ospf6_if->dead_interval, &on->inactivity_timer); | |
508e53e2 | 278 | |
d62a17ae | 279 | if (on->state <= OSPF6_NEIGHBOR_DOWN) |
280 | ospf6_neighbor_state_change(OSPF6_NEIGHBOR_INIT, on, | |
281 | OSPF6_NEIGHBOR_EVENT_HELLO_RCVD); | |
508e53e2 | 282 | |
d62a17ae | 283 | return 0; |
718e3744 | 284 | } |
285 | ||
d62a17ae | 286 | int twoway_received(struct thread *thread) |
718e3744 | 287 | { |
d62a17ae | 288 | struct ospf6_neighbor *on; |
508e53e2 | 289 | |
d62a17ae | 290 | on = (struct ospf6_neighbor *)THREAD_ARG(thread); |
291 | assert(on); | |
508e53e2 | 292 | |
d62a17ae | 293 | if (on->state > OSPF6_NEIGHBOR_INIT) |
294 | return 0; | |
508e53e2 | 295 | |
d62a17ae | 296 | if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) |
297 | zlog_debug("Neighbor Event %s: *2Way-Received*", on->name); | |
508e53e2 | 298 | |
d62a17ae | 299 | thread_add_event(master, neighbor_change, on->ospf6_if, 0, NULL); |
508e53e2 | 300 | |
d62a17ae | 301 | if (!need_adjacency(on)) { |
302 | ospf6_neighbor_state_change(OSPF6_NEIGHBOR_TWOWAY, on, | |
303 | OSPF6_NEIGHBOR_EVENT_TWOWAY_RCVD); | |
304 | return 0; | |
305 | } | |
718e3744 | 306 | |
d62a17ae | 307 | ospf6_neighbor_state_change(OSPF6_NEIGHBOR_EXSTART, on, |
308 | OSPF6_NEIGHBOR_EVENT_TWOWAY_RCVD); | |
309 | SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT); | |
310 | SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT); | |
311 | SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT); | |
508e53e2 | 312 | |
d62a17ae | 313 | THREAD_OFF(on->thread_send_dbdesc); |
d62a17ae | 314 | thread_add_event(master, ospf6_dbdesc_send, on, 0, |
315 | &on->thread_send_dbdesc); | |
508e53e2 | 316 | |
d62a17ae | 317 | return 0; |
718e3744 | 318 | } |
319 | ||
d62a17ae | 320 | int negotiation_done(struct thread *thread) |
718e3744 | 321 | { |
d62a17ae | 322 | struct ospf6_neighbor *on; |
2e37407f | 323 | struct ospf6_lsa *lsa, *lsanext; |
d62a17ae | 324 | |
325 | on = (struct ospf6_neighbor *)THREAD_ARG(thread); | |
326 | assert(on); | |
327 | ||
328 | if (on->state != OSPF6_NEIGHBOR_EXSTART) | |
329 | return 0; | |
330 | ||
331 | if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) | |
332 | zlog_debug("Neighbor Event %s: *NegotiationDone*", on->name); | |
333 | ||
334 | /* clear ls-list */ | |
335 | ospf6_lsdb_remove_all(on->summary_list); | |
336 | ospf6_lsdb_remove_all(on->request_list); | |
2e37407f | 337 | for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { |
d62a17ae | 338 | ospf6_decrement_retrans_count(lsa); |
339 | ospf6_lsdb_remove(lsa, on->retrans_list); | |
340 | } | |
341 | ||
342 | /* Interface scoped LSAs */ | |
2e37407f | 343 | for (ALL_LSDB(on->ospf6_if->lsdb, lsa, lsanext)) { |
d62a17ae | 344 | if (OSPF6_LSA_IS_MAXAGE(lsa)) { |
345 | ospf6_increment_retrans_count(lsa); | |
346 | ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list); | |
347 | } else | |
348 | ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->summary_list); | |
349 | } | |
350 | ||
351 | /* Area scoped LSAs */ | |
2e37407f | 352 | for (ALL_LSDB(on->ospf6_if->area->lsdb, lsa, lsanext)) { |
d62a17ae | 353 | if (OSPF6_LSA_IS_MAXAGE(lsa)) { |
354 | ospf6_increment_retrans_count(lsa); | |
355 | ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list); | |
356 | } else | |
357 | ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->summary_list); | |
358 | } | |
359 | ||
360 | /* AS scoped LSAs */ | |
2e37407f | 361 | for (ALL_LSDB(on->ospf6_if->area->ospf6->lsdb, lsa, lsanext)) { |
d62a17ae | 362 | if (OSPF6_LSA_IS_MAXAGE(lsa)) { |
363 | ospf6_increment_retrans_count(lsa); | |
364 | ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list); | |
365 | } else | |
366 | ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->summary_list); | |
367 | } | |
368 | ||
369 | UNSET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT); | |
370 | ospf6_neighbor_state_change(OSPF6_NEIGHBOR_EXCHANGE, on, | |
371 | OSPF6_NEIGHBOR_EVENT_NEGOTIATION_DONE); | |
372 | ||
373 | return 0; | |
718e3744 | 374 | } |
375 | ||
bc09f3e6 YR |
376 | static int ospf6_neighbor_last_dbdesc_release(struct thread *thread) |
377 | { | |
378 | struct ospf6_neighbor *on = THREAD_ARG(thread); | |
379 | ||
380 | assert(on); | |
381 | memset(&on->dbdesc_last, 0, sizeof(struct ospf6_dbdesc)); | |
382 | ||
383 | return 0; | |
384 | } | |
385 | ||
d62a17ae | 386 | int exchange_done(struct thread *thread) |
718e3744 | 387 | { |
d62a17ae | 388 | struct ospf6_neighbor *on; |
718e3744 | 389 | |
d62a17ae | 390 | on = (struct ospf6_neighbor *)THREAD_ARG(thread); |
391 | assert(on); | |
508e53e2 | 392 | |
d62a17ae | 393 | if (on->state != OSPF6_NEIGHBOR_EXCHANGE) |
394 | return 0; | |
508e53e2 | 395 | |
d62a17ae | 396 | if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) |
397 | zlog_debug("Neighbor Event %s: *ExchangeDone*", on->name); | |
508e53e2 | 398 | |
d62a17ae | 399 | THREAD_OFF(on->thread_send_dbdesc); |
400 | ospf6_lsdb_remove_all(on->dbdesc_list); | |
508e53e2 | 401 | |
bc09f3e6 YR |
402 | /* RFC 2328 (10.8): Release the last dbdesc after dead_interval */ |
403 | if (!CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT)) { | |
404 | THREAD_OFF(on->last_dbdesc_release_timer); | |
405 | thread_add_timer(master, ospf6_neighbor_last_dbdesc_release, on, | |
406 | on->ospf6_if->dead_interval, | |
407 | &on->last_dbdesc_release_timer); | |
408 | } | |
508e53e2 | 409 | |
d62a17ae | 410 | if (on->request_list->count == 0) |
411 | ospf6_neighbor_state_change(OSPF6_NEIGHBOR_FULL, on, | |
412 | OSPF6_NEIGHBOR_EVENT_EXCHANGE_DONE); | |
413 | else { | |
414 | ospf6_neighbor_state_change(OSPF6_NEIGHBOR_LOADING, on, | |
415 | OSPF6_NEIGHBOR_EVENT_EXCHANGE_DONE); | |
eb82e9ee | 416 | |
d62a17ae | 417 | thread_add_event(master, ospf6_lsreq_send, on, 0, |
418 | &on->thread_send_lsreq); | |
419 | } | |
508e53e2 | 420 | |
d62a17ae | 421 | return 0; |
508e53e2 | 422 | } |
423 | ||
eb82e9ee | 424 | /* Check loading state. */ |
d62a17ae | 425 | void ospf6_check_nbr_loading(struct ospf6_neighbor *on) |
eb82e9ee DD |
426 | { |
427 | ||
d62a17ae | 428 | /* RFC2328 Section 10.9: When the neighbor responds to these requests |
429 | with the proper Link State Update packet(s), the Link state request | |
430 | list is truncated and a new Link State Request packet is sent. | |
431 | */ | |
432 | if ((on->state == OSPF6_NEIGHBOR_LOADING) | |
433 | || (on->state == OSPF6_NEIGHBOR_EXCHANGE)) { | |
434 | if (on->request_list->count == 0) | |
435 | thread_add_event(master, loading_done, on, 0, NULL); | |
436 | else if (on->last_ls_req == NULL) { | |
437 | if (on->thread_send_lsreq != NULL) | |
438 | THREAD_OFF(on->thread_send_lsreq); | |
d62a17ae | 439 | thread_add_event(master, ospf6_lsreq_send, on, 0, |
440 | &on->thread_send_lsreq); | |
441 | } | |
eb82e9ee | 442 | } |
eb82e9ee DD |
443 | } |
444 | ||
d62a17ae | 445 | int loading_done(struct thread *thread) |
508e53e2 | 446 | { |
d62a17ae | 447 | struct ospf6_neighbor *on; |
508e53e2 | 448 | |
d62a17ae | 449 | on = (struct ospf6_neighbor *)THREAD_ARG(thread); |
450 | assert(on); | |
508e53e2 | 451 | |
d62a17ae | 452 | if (on->state != OSPF6_NEIGHBOR_LOADING) |
453 | return 0; | |
508e53e2 | 454 | |
d62a17ae | 455 | if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) |
456 | zlog_debug("Neighbor Event %s: *LoadingDone*", on->name); | |
508e53e2 | 457 | |
d62a17ae | 458 | assert(on->request_list->count == 0); |
508e53e2 | 459 | |
d62a17ae | 460 | ospf6_neighbor_state_change(OSPF6_NEIGHBOR_FULL, on, |
461 | OSPF6_NEIGHBOR_EVENT_LOADING_DONE); | |
508e53e2 | 462 | |
d62a17ae | 463 | return 0; |
508e53e2 | 464 | } |
465 | ||
d62a17ae | 466 | int adj_ok(struct thread *thread) |
508e53e2 | 467 | { |
d62a17ae | 468 | struct ospf6_neighbor *on; |
2e37407f | 469 | struct ospf6_lsa *lsa, *lsanext; |
d62a17ae | 470 | |
471 | on = (struct ospf6_neighbor *)THREAD_ARG(thread); | |
472 | assert(on); | |
473 | ||
474 | if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) | |
475 | zlog_debug("Neighbor Event %s: *AdjOK?*", on->name); | |
476 | ||
477 | if (on->state == OSPF6_NEIGHBOR_TWOWAY && need_adjacency(on)) { | |
478 | ospf6_neighbor_state_change(OSPF6_NEIGHBOR_EXSTART, on, | |
479 | OSPF6_NEIGHBOR_EVENT_ADJ_OK); | |
480 | SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT); | |
481 | SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT); | |
482 | SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT); | |
483 | ||
484 | THREAD_OFF(on->thread_send_dbdesc); | |
485 | on->thread_send_dbdesc = NULL; | |
486 | thread_add_event(master, ospf6_dbdesc_send, on, 0, | |
487 | &on->thread_send_dbdesc); | |
488 | ||
489 | } else if (on->state >= OSPF6_NEIGHBOR_EXSTART && !need_adjacency(on)) { | |
490 | ospf6_neighbor_state_change(OSPF6_NEIGHBOR_TWOWAY, on, | |
491 | OSPF6_NEIGHBOR_EVENT_ADJ_OK); | |
492 | ospf6_lsdb_remove_all(on->summary_list); | |
493 | ospf6_lsdb_remove_all(on->request_list); | |
2e37407f | 494 | for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { |
d62a17ae | 495 | ospf6_decrement_retrans_count(lsa); |
496 | ospf6_lsdb_remove(lsa, on->retrans_list); | |
497 | } | |
498 | } | |
499 | ||
500 | return 0; | |
508e53e2 | 501 | } |
718e3744 | 502 | |
d62a17ae | 503 | int seqnumber_mismatch(struct thread *thread) |
508e53e2 | 504 | { |
d62a17ae | 505 | struct ospf6_neighbor *on; |
2e37407f | 506 | struct ospf6_lsa *lsa, *lsanext; |
718e3744 | 507 | |
d62a17ae | 508 | on = (struct ospf6_neighbor *)THREAD_ARG(thread); |
509 | assert(on); | |
718e3744 | 510 | |
d62a17ae | 511 | if (on->state < OSPF6_NEIGHBOR_EXCHANGE) |
512 | return 0; | |
718e3744 | 513 | |
d62a17ae | 514 | if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) |
515 | zlog_debug("Neighbor Event %s: *SeqNumberMismatch*", on->name); | |
718e3744 | 516 | |
d62a17ae | 517 | ospf6_neighbor_state_change(OSPF6_NEIGHBOR_EXSTART, on, |
518 | OSPF6_NEIGHBOR_EVENT_SEQNUMBER_MISMATCH); | |
519 | SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT); | |
520 | SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT); | |
521 | SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT); | |
718e3744 | 522 | |
d62a17ae | 523 | ospf6_lsdb_remove_all(on->summary_list); |
524 | ospf6_lsdb_remove_all(on->request_list); | |
2e37407f | 525 | for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { |
d62a17ae | 526 | ospf6_decrement_retrans_count(lsa); |
527 | ospf6_lsdb_remove(lsa, on->retrans_list); | |
528 | } | |
508e53e2 | 529 | |
d62a17ae | 530 | THREAD_OFF(on->thread_send_dbdesc); |
531 | on->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */ | |
931b1b8c | 532 | |
d62a17ae | 533 | on->thread_send_dbdesc = NULL; |
534 | thread_add_event(master, ospf6_dbdesc_send, on, 0, | |
535 | &on->thread_send_dbdesc); | |
508e53e2 | 536 | |
d62a17ae | 537 | return 0; |
718e3744 | 538 | } |
539 | ||
d62a17ae | 540 | int bad_lsreq(struct thread *thread) |
718e3744 | 541 | { |
d62a17ae | 542 | struct ospf6_neighbor *on; |
2e37407f | 543 | struct ospf6_lsa *lsa, *lsanext; |
508e53e2 | 544 | |
d62a17ae | 545 | on = (struct ospf6_neighbor *)THREAD_ARG(thread); |
546 | assert(on); | |
508e53e2 | 547 | |
d62a17ae | 548 | if (on->state < OSPF6_NEIGHBOR_EXCHANGE) |
549 | return 0; | |
718e3744 | 550 | |
d62a17ae | 551 | if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) |
552 | zlog_debug("Neighbor Event %s: *BadLSReq*", on->name); | |
718e3744 | 553 | |
d62a17ae | 554 | ospf6_neighbor_state_change(OSPF6_NEIGHBOR_EXSTART, on, |
555 | OSPF6_NEIGHBOR_EVENT_BAD_LSREQ); | |
556 | SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT); | |
557 | SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT); | |
558 | SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT); | |
718e3744 | 559 | |
d62a17ae | 560 | ospf6_lsdb_remove_all(on->summary_list); |
561 | ospf6_lsdb_remove_all(on->request_list); | |
2e37407f | 562 | for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { |
d62a17ae | 563 | ospf6_decrement_retrans_count(lsa); |
564 | ospf6_lsdb_remove(lsa, on->retrans_list); | |
565 | } | |
718e3744 | 566 | |
d62a17ae | 567 | THREAD_OFF(on->thread_send_dbdesc); |
568 | on->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */ | |
931b1b8c | 569 | |
d62a17ae | 570 | on->thread_send_dbdesc = NULL; |
571 | thread_add_event(master, ospf6_dbdesc_send, on, 0, | |
572 | &on->thread_send_dbdesc); | |
508e53e2 | 573 | |
d62a17ae | 574 | return 0; |
718e3744 | 575 | } |
576 | ||
d62a17ae | 577 | int oneway_received(struct thread *thread) |
718e3744 | 578 | { |
d62a17ae | 579 | struct ospf6_neighbor *on; |
2e37407f | 580 | struct ospf6_lsa *lsa, *lsanext; |
718e3744 | 581 | |
d62a17ae | 582 | on = (struct ospf6_neighbor *)THREAD_ARG(thread); |
583 | assert(on); | |
508e53e2 | 584 | |
d62a17ae | 585 | if (on->state < OSPF6_NEIGHBOR_TWOWAY) |
586 | return 0; | |
508e53e2 | 587 | |
d62a17ae | 588 | if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) |
589 | zlog_debug("Neighbor Event %s: *1Way-Received*", on->name); | |
508e53e2 | 590 | |
d62a17ae | 591 | ospf6_neighbor_state_change(OSPF6_NEIGHBOR_INIT, on, |
592 | OSPF6_NEIGHBOR_EVENT_ONEWAY_RCVD); | |
593 | thread_add_event(master, neighbor_change, on->ospf6_if, 0, NULL); | |
508e53e2 | 594 | |
d62a17ae | 595 | ospf6_lsdb_remove_all(on->summary_list); |
596 | ospf6_lsdb_remove_all(on->request_list); | |
2e37407f | 597 | for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { |
d62a17ae | 598 | ospf6_decrement_retrans_count(lsa); |
599 | ospf6_lsdb_remove(lsa, on->retrans_list); | |
600 | } | |
508e53e2 | 601 | |
d62a17ae | 602 | THREAD_OFF(on->thread_send_dbdesc); |
603 | THREAD_OFF(on->thread_send_lsreq); | |
604 | THREAD_OFF(on->thread_send_lsupdate); | |
605 | THREAD_OFF(on->thread_send_lsack); | |
508e53e2 | 606 | |
d62a17ae | 607 | return 0; |
508e53e2 | 608 | } |
609 | ||
d62a17ae | 610 | int inactivity_timer(struct thread *thread) |
508e53e2 | 611 | { |
d62a17ae | 612 | struct ospf6_neighbor *on; |
508e53e2 | 613 | |
d62a17ae | 614 | on = (struct ospf6_neighbor *)THREAD_ARG(thread); |
615 | assert(on); | |
508e53e2 | 616 | |
d62a17ae | 617 | if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) |
618 | zlog_debug("Neighbor Event %s: *InactivityTimer*", on->name); | |
508e53e2 | 619 | |
d62a17ae | 620 | on->drouter = on->prev_drouter = 0; |
621 | on->bdrouter = on->prev_bdrouter = 0; | |
508e53e2 | 622 | |
0d1753a7 | 623 | if (!OSPF6_GR_IS_ACTIVE_HELPER(on)) { |
624 | on->drouter = on->prev_drouter = 0; | |
625 | on->bdrouter = on->prev_bdrouter = 0; | |
626 | ||
627 | ospf6_neighbor_state_change( | |
628 | OSPF6_NEIGHBOR_DOWN, on, | |
629 | OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER); | |
630 | thread_add_event(master, neighbor_change, on->ospf6_if, 0, | |
631 | NULL); | |
632 | ||
633 | listnode_delete(on->ospf6_if->neighbor_list, on); | |
634 | ospf6_neighbor_delete(on); | |
508e53e2 | 635 | |
0d1753a7 | 636 | } else { |
0fc3e113 | 637 | if (IS_DEBUG_OSPF6_GR) |
0d1753a7 | 638 | zlog_debug( |
639 | "%s, Acting as HELPER for this neighbour, So restart the dead timer.", | |
640 | __PRETTY_FUNCTION__); | |
641 | ||
642 | thread_add_timer(master, inactivity_timer, on, | |
643 | on->ospf6_if->dead_interval, | |
644 | &on->inactivity_timer); | |
645 | } | |
508e53e2 | 646 | |
d62a17ae | 647 | return 0; |
718e3744 | 648 | } |
649 | ||
508e53e2 | 650 | |
718e3744 | 651 | /* vty functions */ |
652 | /* show neighbor structure */ | |
6a5bb300 | 653 | static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on, |
654 | json_object *json_array, bool use_json) | |
718e3744 | 655 | { |
d62a17ae | 656 | char router_id[16]; |
68bfcc05 | 657 | char duration[64]; |
d62a17ae | 658 | struct timeval res; |
659 | char nstate[16]; | |
68bfcc05 | 660 | char deadtime[64]; |
d62a17ae | 661 | long h, m, s; |
6a5bb300 | 662 | json_object *json_route; |
d62a17ae | 663 | |
664 | /* Router-ID (Name) */ | |
665 | inet_ntop(AF_INET, &on->router_id, router_id, sizeof(router_id)); | |
508e53e2 | 666 | #ifdef HAVE_GETNAMEINFO |
d62a17ae | 667 | { |
668 | } | |
508e53e2 | 669 | #endif /*HAVE_GETNAMEINFO*/ |
670 | ||
d62a17ae | 671 | /* Dead time */ |
672 | h = m = s = 0; | |
673 | if (on->inactivity_timer) { | |
674 | s = monotime_until(&on->inactivity_timer->u.sands, NULL) | |
675 | / 1000000LL; | |
676 | h = s / 3600; | |
677 | s -= h * 3600; | |
678 | m = s / 60; | |
679 | s -= m * 60; | |
680 | } | |
681 | snprintf(deadtime, sizeof(deadtime), "%02ld:%02ld:%02ld", h, m, s); | |
682 | ||
683 | /* Neighbor State */ | |
e5973353 | 684 | if (on->ospf6_if->type == OSPF_IFTYPE_POINTOPOINT) |
d62a17ae | 685 | snprintf(nstate, sizeof(nstate), "PointToPoint"); |
686 | else { | |
687 | if (on->router_id == on->drouter) | |
688 | snprintf(nstate, sizeof(nstate), "DR"); | |
689 | else if (on->router_id == on->bdrouter) | |
690 | snprintf(nstate, sizeof(nstate), "BDR"); | |
691 | else | |
692 | snprintf(nstate, sizeof(nstate), "DROther"); | |
693 | } | |
694 | ||
695 | /* Duration */ | |
696 | monotime_since(&on->last_changed, &res); | |
697 | timerstring(&res, duration, sizeof(duration)); | |
698 | ||
699 | /* | |
700 | vty_out (vty, "%-15s %3d %11s %6s/%-12s %11s %s[%s]\n", | |
6a5bb300 | 701 | "Neighbor ID", "Pri", "DeadTime", "State", "IfState", |
702 | "Duration", "I/F", "State"); | |
d62a17ae | 703 | */ |
6a5bb300 | 704 | if (use_json) { |
705 | json_route = json_object_new_object(); | |
706 | ||
707 | json_object_string_add(json_route, "neighborId", router_id); | |
708 | json_object_int_add(json_route, "priority", on->priority); | |
709 | json_object_string_add(json_route, "deadTime", deadtime); | |
710 | json_object_string_add(json_route, "state", | |
711 | ospf6_neighbor_state_str[on->state]); | |
712 | json_object_string_add(json_route, "ifState", nstate); | |
713 | json_object_string_add(json_route, "duration", duration); | |
714 | json_object_string_add(json_route, "interfaceName", | |
715 | on->ospf6_if->interface->name); | |
716 | json_object_string_add( | |
717 | json_route, "interfaceState", | |
718 | ospf6_interface_state_str[on->ospf6_if->state]); | |
719 | ||
720 | json_object_array_add(json_array, json_route); | |
721 | } else | |
722 | vty_out(vty, "%-15s %3d %11s %8s/%-12s %11s %s[%s]\n", | |
723 | router_id, on->priority, deadtime, | |
724 | ospf6_neighbor_state_str[on->state], nstate, duration, | |
725 | on->ospf6_if->interface->name, | |
726 | ospf6_interface_state_str[on->ospf6_if->state]); | |
508e53e2 | 727 | } |
728 | ||
d62a17ae | 729 | static void ospf6_neighbor_show_drchoice(struct vty *vty, |
6a5bb300 | 730 | struct ospf6_neighbor *on, |
731 | json_object *json_array, bool use_json) | |
508e53e2 | 732 | { |
d62a17ae | 733 | char router_id[16]; |
734 | char drouter[16], bdrouter[16]; | |
68bfcc05 | 735 | char duration[64]; |
d62a17ae | 736 | struct timeval now, res; |
6a5bb300 | 737 | json_object *json_route; |
d62a17ae | 738 | |
739 | /* | |
740 | vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]\n", | |
741 | "RouterID", "State", "Duration", "DR", "BDR", "I/F", | |
742 | "State"); | |
743 | */ | |
744 | ||
745 | inet_ntop(AF_INET, &on->router_id, router_id, sizeof(router_id)); | |
746 | inet_ntop(AF_INET, &on->drouter, drouter, sizeof(drouter)); | |
747 | inet_ntop(AF_INET, &on->bdrouter, bdrouter, sizeof(bdrouter)); | |
748 | ||
749 | monotime(&now); | |
750 | timersub(&now, &on->last_changed, &res); | |
751 | timerstring(&res, duration, sizeof(duration)); | |
752 | ||
6a5bb300 | 753 | if (use_json) { |
754 | json_route = json_object_new_object(); | |
755 | json_object_string_add(json_route, "routerId", router_id); | |
756 | json_object_string_add(json_route, "state", | |
757 | ospf6_neighbor_state_str[on->state]); | |
758 | json_object_string_add(json_route, "duration", duration); | |
759 | json_object_string_add(json_route, "dRouter", drouter); | |
760 | json_object_string_add(json_route, "bdRouter", bdrouter); | |
761 | json_object_string_add(json_route, "interfaceName", | |
762 | on->ospf6_if->interface->name); | |
763 | json_object_string_add( | |
764 | json_route, "interfaceState", | |
765 | ospf6_interface_state_str[on->ospf6_if->state]); | |
766 | ||
767 | json_object_array_add(json_array, json_route); | |
768 | } else | |
769 | vty_out(vty, "%-15s %8s/%-11s %-15s %-15s %s[%s]\n", router_id, | |
770 | ospf6_neighbor_state_str[on->state], duration, drouter, | |
771 | bdrouter, on->ospf6_if->interface->name, | |
772 | ospf6_interface_state_str[on->ospf6_if->state]); | |
718e3744 | 773 | } |
774 | ||
d62a17ae | 775 | static void ospf6_neighbor_show_detail(struct vty *vty, |
6a5bb300 | 776 | struct ospf6_neighbor *on, |
777 | json_object *json, bool use_json) | |
718e3744 | 778 | { |
d62a17ae | 779 | char drouter[16], bdrouter[16]; |
780 | char linklocal_addr[64], duration[32]; | |
781 | struct timeval now, res; | |
2e37407f | 782 | struct ospf6_lsa *lsa, *lsanext; |
6a5bb300 | 783 | json_object *json_neighbor; |
784 | json_object *json_array; | |
785 | char db_desc_str[20]; | |
d62a17ae | 786 | |
787 | inet_ntop(AF_INET6, &on->linklocal_addr, linklocal_addr, | |
788 | sizeof(linklocal_addr)); | |
789 | inet_ntop(AF_INET, &on->drouter, drouter, sizeof(drouter)); | |
790 | inet_ntop(AF_INET, &on->bdrouter, bdrouter, sizeof(bdrouter)); | |
791 | ||
792 | monotime(&now); | |
793 | timersub(&now, &on->last_changed, &res); | |
794 | timerstring(&res, duration, sizeof(duration)); | |
795 | ||
6a5bb300 | 796 | if (use_json) { |
797 | json_neighbor = json_object_new_object(); | |
798 | json_object_string_add(json_neighbor, "area", | |
799 | on->ospf6_if->area->name); | |
800 | json_object_string_add(json_neighbor, "interface", | |
801 | on->ospf6_if->interface->name); | |
802 | json_object_int_add(json_neighbor, "interfaceIndex", | |
803 | on->ospf6_if->interface->ifindex); | |
804 | json_object_int_add(json_neighbor, "neighborInterfaceIndex", | |
805 | on->ifindex); | |
806 | json_object_string_add(json_neighbor, "linkLocalAddress", | |
807 | linklocal_addr); | |
808 | json_object_string_add(json_neighbor, "neighborState", | |
809 | ospf6_neighbor_state_str[on->state]); | |
810 | json_object_string_add(json_neighbor, "neighborStateDuration", | |
811 | duration); | |
812 | json_object_string_add(json_neighbor, "neighborDRouter", | |
813 | drouter); | |
814 | json_object_string_add(json_neighbor, "neighborBdRouter", | |
815 | bdrouter); | |
816 | snprintf(db_desc_str, sizeof(db_desc_str), "%s%s%s", | |
817 | (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT) | |
818 | ? "Initial " | |
819 | : ""), | |
820 | (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT) | |
821 | ? "More" | |
822 | : ""), | |
823 | (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT) | |
824 | ? "Master" | |
825 | : "Slave")); | |
826 | json_object_string_add(json_neighbor, "dbDescStatus", | |
827 | db_desc_str); | |
828 | ||
829 | json_object_int_add(json_neighbor, "dbDescSeqNumber", | |
830 | (unsigned long)ntohl(on->dbdesc_seqnum)); | |
831 | ||
832 | json_array = json_object_new_array(); | |
833 | json_object_int_add(json_neighbor, "summaryListCount", | |
834 | on->summary_list->count); | |
835 | for (ALL_LSDB(on->summary_list, lsa, lsanext)) | |
836 | json_object_array_add( | |
837 | json_array, json_object_new_string(lsa->name)); | |
838 | json_object_object_add(json_neighbor, "summaryListLsa", | |
839 | json_array); | |
840 | ||
841 | json_array = json_object_new_array(); | |
842 | json_object_int_add(json_neighbor, "requestListCount", | |
843 | on->request_list->count); | |
844 | for (ALL_LSDB(on->request_list, lsa, lsanext)) | |
845 | json_object_array_add( | |
846 | json_array, json_object_new_string(lsa->name)); | |
847 | json_object_object_add(json_neighbor, "requestListLsa", | |
848 | json_array); | |
849 | ||
850 | json_array = json_object_new_array(); | |
851 | json_object_int_add(json_neighbor, "reTransListCount", | |
852 | on->retrans_list->count); | |
853 | for (ALL_LSDB(on->retrans_list, lsa, lsanext)) | |
854 | json_object_array_add( | |
855 | json_array, json_object_new_string(lsa->name)); | |
856 | json_object_object_add(json_neighbor, "reTransListLsa", | |
857 | json_array); | |
858 | ||
859 | ||
860 | timerclear(&res); | |
861 | if (on->thread_send_dbdesc) | |
862 | timersub(&on->thread_send_dbdesc->u.sands, &now, &res); | |
863 | timerstring(&res, duration, sizeof(duration)); | |
864 | json_object_int_add(json_neighbor, "pendingLsaDbDescCount", | |
865 | on->dbdesc_list->count); | |
866 | json_object_string_add(json_neighbor, "pendingLsaDbDescTime", | |
867 | duration); | |
868 | json_object_string_add(json_neighbor, "dbDescSendThread", | |
869 | (on->thread_send_dbdesc ? "on" : "off")); | |
870 | json_array = json_object_new_array(); | |
871 | for (ALL_LSDB(on->dbdesc_list, lsa, lsanext)) | |
872 | json_object_array_add( | |
873 | json_array, json_object_new_string(lsa->name)); | |
874 | json_object_object_add(json_neighbor, "pendingLsaDbDesc", | |
875 | json_array); | |
876 | ||
877 | timerclear(&res); | |
878 | if (on->thread_send_lsreq) | |
879 | timersub(&on->thread_send_lsreq->u.sands, &now, &res); | |
880 | timerstring(&res, duration, sizeof(duration)); | |
881 | json_object_int_add(json_neighbor, "pendingLsaLsReqCount", | |
882 | on->request_list->count); | |
883 | json_object_string_add(json_neighbor, "pendingLsaLsReqTime", | |
884 | duration); | |
885 | json_object_string_add(json_neighbor, "lsReqSendThread", | |
886 | (on->thread_send_lsreq ? "on" : "off")); | |
887 | json_array = json_object_new_array(); | |
888 | for (ALL_LSDB(on->request_list, lsa, lsanext)) | |
889 | json_object_array_add( | |
890 | json_array, json_object_new_string(lsa->name)); | |
891 | json_object_object_add(json_neighbor, "pendingLsaLsReq", | |
892 | json_array); | |
893 | ||
894 | ||
895 | timerclear(&res); | |
896 | if (on->thread_send_lsupdate) | |
897 | timersub(&on->thread_send_lsupdate->u.sands, &now, | |
898 | &res); | |
899 | timerstring(&res, duration, sizeof(duration)); | |
900 | json_object_int_add(json_neighbor, "pendingLsaLsUpdateCount", | |
901 | on->lsupdate_list->count); | |
902 | json_object_string_add(json_neighbor, "pendingLsaLsUpdateTime", | |
903 | duration); | |
904 | json_object_string_add( | |
905 | json_neighbor, "lsUpdateSendThread", | |
906 | (on->thread_send_lsupdate ? "on" : "off")); | |
907 | json_array = json_object_new_array(); | |
908 | for (ALL_LSDB(on->lsupdate_list, lsa, lsanext)) | |
909 | json_object_array_add( | |
910 | json_array, json_object_new_string(lsa->name)); | |
911 | json_object_object_add(json_neighbor, "pendingLsaLsUpdate", | |
912 | json_array); | |
913 | ||
914 | timerclear(&res); | |
915 | if (on->thread_send_lsack) | |
916 | timersub(&on->thread_send_lsack->u.sands, &now, &res); | |
917 | timerstring(&res, duration, sizeof(duration)); | |
918 | json_object_int_add(json_neighbor, "pendingLsaLsAckCount", | |
919 | on->lsack_list->count); | |
920 | json_object_string_add(json_neighbor, "pendingLsaLsAckTime", | |
921 | duration); | |
922 | json_object_string_add(json_neighbor, "lsAckSendThread", | |
923 | (on->thread_send_lsack ? "on" : "off")); | |
924 | json_array = json_object_new_array(); | |
925 | for (ALL_LSDB(on->lsack_list, lsa, lsanext)) | |
926 | json_object_array_add( | |
927 | json_array, json_object_new_string(lsa->name)); | |
928 | json_object_object_add(json_neighbor, "pendingLsaLsAck", | |
929 | json_array); | |
930 | ||
d06cc416 | 931 | bfd_sess_show(vty, json_neighbor, on->bfd_session); |
6a5bb300 | 932 | |
933 | json_object_object_add(json, on->name, json_neighbor); | |
934 | ||
935 | ||
936 | } else { | |
937 | vty_out(vty, " Neighbor %s\n", on->name); | |
938 | vty_out(vty, " Area %s via interface %s (ifindex %d)\n", | |
939 | on->ospf6_if->area->name, on->ospf6_if->interface->name, | |
940 | on->ospf6_if->interface->ifindex); | |
941 | vty_out(vty, " His IfIndex: %d Link-local address: %s\n", | |
942 | on->ifindex, linklocal_addr); | |
943 | vty_out(vty, " State %s for a duration of %s\n", | |
944 | ospf6_neighbor_state_str[on->state], duration); | |
945 | vty_out(vty, " His choice of DR/BDR %s/%s, Priority %d\n", | |
946 | drouter, bdrouter, on->priority); | |
947 | vty_out(vty, " DbDesc status: %s%s%s SeqNum: %#lx\n", | |
948 | (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT) | |
949 | ? "Initial " | |
950 | : ""), | |
951 | (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT) | |
952 | ? "More " | |
953 | : ""), | |
954 | (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT) | |
955 | ? "Master" | |
956 | : "Slave"), | |
957 | (unsigned long)ntohl(on->dbdesc_seqnum)); | |
958 | ||
959 | vty_out(vty, " Summary-List: %d LSAs\n", | |
960 | on->summary_list->count); | |
961 | for (ALL_LSDB(on->summary_list, lsa, lsanext)) | |
962 | vty_out(vty, " %s\n", lsa->name); | |
963 | ||
964 | vty_out(vty, " Request-List: %d LSAs\n", | |
965 | on->request_list->count); | |
966 | for (ALL_LSDB(on->request_list, lsa, lsanext)) | |
967 | vty_out(vty, " %s\n", lsa->name); | |
968 | ||
969 | vty_out(vty, " Retrans-List: %d LSAs\n", | |
970 | on->retrans_list->count); | |
971 | for (ALL_LSDB(on->retrans_list, lsa, lsanext)) | |
972 | vty_out(vty, " %s\n", lsa->name); | |
973 | ||
974 | timerclear(&res); | |
975 | if (on->thread_send_dbdesc) | |
976 | timersub(&on->thread_send_dbdesc->u.sands, &now, &res); | |
977 | timerstring(&res, duration, sizeof(duration)); | |
978 | vty_out(vty, | |
979 | " %d Pending LSAs for DbDesc in Time %s [thread %s]\n", | |
980 | on->dbdesc_list->count, duration, | |
981 | (on->thread_send_dbdesc ? "on" : "off")); | |
982 | for (ALL_LSDB(on->dbdesc_list, lsa, lsanext)) | |
983 | vty_out(vty, " %s\n", lsa->name); | |
984 | ||
985 | timerclear(&res); | |
986 | if (on->thread_send_lsreq) | |
987 | timersub(&on->thread_send_lsreq->u.sands, &now, &res); | |
988 | timerstring(&res, duration, sizeof(duration)); | |
989 | vty_out(vty, | |
990 | " %d Pending LSAs for LSReq in Time %s [thread %s]\n", | |
991 | on->request_list->count, duration, | |
992 | (on->thread_send_lsreq ? "on" : "off")); | |
993 | for (ALL_LSDB(on->request_list, lsa, lsanext)) | |
994 | vty_out(vty, " %s\n", lsa->name); | |
995 | ||
996 | timerclear(&res); | |
997 | if (on->thread_send_lsupdate) | |
998 | timersub(&on->thread_send_lsupdate->u.sands, &now, | |
999 | &res); | |
1000 | timerstring(&res, duration, sizeof(duration)); | |
1001 | vty_out(vty, | |
1002 | " %d Pending LSAs for LSUpdate in Time %s [thread %s]\n", | |
1003 | on->lsupdate_list->count, duration, | |
1004 | (on->thread_send_lsupdate ? "on" : "off")); | |
1005 | for (ALL_LSDB(on->lsupdate_list, lsa, lsanext)) | |
1006 | vty_out(vty, " %s\n", lsa->name); | |
1007 | ||
1008 | timerclear(&res); | |
1009 | if (on->thread_send_lsack) | |
1010 | timersub(&on->thread_send_lsack->u.sands, &now, &res); | |
1011 | timerstring(&res, duration, sizeof(duration)); | |
1012 | vty_out(vty, | |
1013 | " %d Pending LSAs for LSAck in Time %s [thread %s]\n", | |
1014 | on->lsack_list->count, duration, | |
1015 | (on->thread_send_lsack ? "on" : "off")); | |
1016 | for (ALL_LSDB(on->lsack_list, lsa, lsanext)) | |
1017 | vty_out(vty, " %s\n", lsa->name); | |
1018 | ||
d06cc416 | 1019 | bfd_sess_show(vty, NULL, on->bfd_session); |
6a5bb300 | 1020 | } |
718e3744 | 1021 | } |
1022 | ||
ee3e6d7f IR |
1023 | static void ospf6_neighbor_show_detail_common(struct vty *vty, |
1024 | struct ospf6 *ospf6, bool uj, | |
1025 | bool detail, bool drchoice) | |
718e3744 | 1026 | { |
d62a17ae | 1027 | struct ospf6_neighbor *on; |
1028 | struct ospf6_interface *oi; | |
1029 | struct ospf6_area *oa; | |
1030 | struct listnode *i, *j, *k; | |
6a5bb300 | 1031 | json_object *json = NULL; |
1032 | json_object *json_array = NULL; | |
6a5bb300 | 1033 | void (*showfunc)(struct vty *, struct ospf6_neighbor *, |
1034 | json_object *json, bool use_json); | |
d62a17ae | 1035 | |
ee3e6d7f IR |
1036 | if (detail) |
1037 | showfunc = ospf6_neighbor_show_detail; | |
1038 | else if (drchoice) | |
1039 | showfunc = ospf6_neighbor_show_drchoice; | |
1040 | else | |
1041 | showfunc = ospf6_neighbor_show; | |
d62a17ae | 1042 | |
6a5bb300 | 1043 | if (uj) { |
1044 | json = json_object_new_object(); | |
1045 | json_array = json_object_new_array(); | |
1046 | } else { | |
1047 | if (showfunc == ospf6_neighbor_show) | |
1048 | vty_out(vty, "%-15s %3s %11s %8s/%-12s %11s %s[%s]\n", | |
1049 | "Neighbor ID", "Pri", "DeadTime", "State", | |
1050 | "IfState", "Duration", "I/F", "State"); | |
1051 | else if (showfunc == ospf6_neighbor_show_drchoice) | |
1052 | vty_out(vty, "%-15s %8s/%-11s %-15s %-15s %s[%s]\n", | |
1053 | "RouterID", "State", "Duration", "DR", "BDR", | |
1054 | "I/F", "State"); | |
1055 | } | |
d62a17ae | 1056 | |
1057 | for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) | |
1058 | for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) | |
6a5bb300 | 1059 | for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, on)) { |
1060 | if (showfunc == ospf6_neighbor_show_detail) | |
1061 | (*showfunc)(vty, on, json, uj); | |
1062 | else | |
1063 | (*showfunc)(vty, on, json_array, uj); | |
1064 | } | |
1065 | ||
1066 | if (uj) { | |
1067 | if (showfunc != ospf6_neighbor_show_detail) | |
1068 | json_object_object_add(json, "neighbors", json_array); | |
1069 | else | |
1070 | json_object_free(json_array); | |
1071 | vty_out(vty, "%s\n", | |
1072 | json_object_to_json_string_ext( | |
1073 | json, JSON_C_TO_STRING_PRETTY)); | |
1074 | json_object_free(json); | |
1075 | } | |
718e3744 | 1076 | } |
1077 | ||
d48ef099 | 1078 | DEFUN(show_ipv6_ospf6_neighbor, show_ipv6_ospf6_neighbor_cmd, |
1079 | "show ipv6 ospf6 [vrf <NAME|all>] neighbor [<detail|drchoice>] [json]", | |
1080 | SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR | |
1081 | "All VRFs\n" | |
1082 | "Neighbor list\n" | |
1083 | "Display details\n" | |
1084 | "Display DR choices\n" JSON_STR) | |
1085 | { | |
d48ef099 | 1086 | struct ospf6 *ospf6; |
1087 | struct listnode *node; | |
1088 | const char *vrf_name = NULL; | |
1089 | bool all_vrf = false; | |
1090 | int idx_vrf = 0; | |
ee3e6d7f IR |
1091 | int idx_type = 4; |
1092 | bool uj = use_json(argc, argv); | |
1093 | bool detail = false; | |
1094 | bool drchoice = false; | |
d48ef099 | 1095 | |
d48ef099 | 1096 | OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); |
ee3e6d7f IR |
1097 | |
1098 | if (argv_find(argv, argc, "detail", &idx_type)) | |
1099 | detail = true; | |
1100 | else if (argv_find(argv, argc, "drchoice", &idx_type)) | |
1101 | drchoice = true; | |
d48ef099 | 1102 | |
1103 | for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) { | |
1104 | if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) { | |
ee3e6d7f IR |
1105 | ospf6_neighbor_show_detail_common(vty, ospf6, uj, |
1106 | detail, drchoice); | |
d48ef099 | 1107 | if (!all_vrf) |
1108 | break; | |
1109 | } | |
1110 | } | |
718e3744 | 1111 | |
d48ef099 | 1112 | return CMD_SUCCESS; |
1113 | } | |
1114 | ||
1115 | static int ospf6_neighbor_show_common(struct vty *vty, int argc, | |
1116 | struct cmd_token **argv, | |
1117 | struct ospf6 *ospf6, int idx_ipv4) | |
718e3744 | 1118 | { |
d62a17ae | 1119 | struct ospf6_neighbor *on; |
1120 | struct ospf6_interface *oi; | |
1121 | struct ospf6_area *oa; | |
1122 | struct listnode *i, *j, *k; | |
6a5bb300 | 1123 | void (*showfunc)(struct vty *, struct ospf6_neighbor *, |
1124 | json_object *json, bool use_json); | |
d7c0a89a | 1125 | uint32_t router_id; |
6a5bb300 | 1126 | json_object *json = NULL; |
1127 | bool uj = use_json(argc, argv); | |
d62a17ae | 1128 | |
d62a17ae | 1129 | showfunc = ospf6_neighbor_show_detail; |
6a5bb300 | 1130 | if (uj) |
1131 | json = json_object_new_object(); | |
d62a17ae | 1132 | |
1133 | if ((inet_pton(AF_INET, argv[idx_ipv4]->arg, &router_id)) != 1) { | |
1134 | vty_out(vty, "Router-ID is not parsable: %s\n", | |
1135 | argv[idx_ipv4]->arg); | |
1136 | return CMD_SUCCESS; | |
1137 | } | |
1138 | ||
1139 | for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) | |
1140 | for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) | |
786b76d0 YR |
1141 | for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, on)) { |
1142 | if (router_id == on->router_id) | |
1143 | (*showfunc)(vty, on, json, uj); | |
1144 | } | |
d62a17ae | 1145 | |
6a5bb300 | 1146 | if (uj) { |
1147 | vty_out(vty, "%s\n", | |
1148 | json_object_to_json_string_ext( | |
1149 | json, JSON_C_TO_STRING_PRETTY)); | |
1150 | json_object_free(json); | |
1151 | } | |
d48ef099 | 1152 | |
1153 | return CMD_SUCCESS; | |
1154 | } | |
1155 | ||
1156 | DEFUN(show_ipv6_ospf6_neighbor_one, show_ipv6_ospf6_neighbor_one_cmd, | |
1157 | "show ipv6 ospf6 [vrf <NAME|all>] neighbor A.B.C.D [json]", | |
1158 | SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR | |
1159 | "All VRFs\n" | |
1160 | "Neighbor list\n" | |
1161 | "Specify Router-ID as IPv4 address notation\n" JSON_STR) | |
1162 | { | |
1163 | int idx_ipv4 = 4; | |
1164 | struct ospf6 *ospf6; | |
1165 | struct listnode *node; | |
1166 | const char *vrf_name = NULL; | |
1167 | bool all_vrf = false; | |
1168 | int idx_vrf = 0; | |
1169 | ||
d48ef099 | 1170 | OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); |
1171 | if (idx_vrf > 0) | |
1172 | idx_ipv4 += 2; | |
1173 | ||
1174 | for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) { | |
1175 | if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) { | |
1176 | ospf6_neighbor_show_common(vty, argc, argv, ospf6, | |
1177 | idx_ipv4); | |
1178 | ||
1179 | if (!all_vrf) | |
1180 | break; | |
1181 | } | |
1182 | } | |
1183 | ||
d62a17ae | 1184 | return CMD_SUCCESS; |
718e3744 | 1185 | } |
1186 | ||
d62a17ae | 1187 | void ospf6_neighbor_init(void) |
718e3744 | 1188 | { |
d62a17ae | 1189 | install_element(VIEW_NODE, &show_ipv6_ospf6_neighbor_cmd); |
1190 | install_element(VIEW_NODE, &show_ipv6_ospf6_neighbor_one_cmd); | |
508e53e2 | 1191 | } |
1192 | ||
1193 | DEFUN (debug_ospf6_neighbor, | |
1194 | debug_ospf6_neighbor_cmd, | |
6de69f83 | 1195 | "debug ospf6 neighbor [<state|event>]", |
508e53e2 | 1196 | DEBUG_STR |
1197 | OSPF6_STR | |
1198 | "Debug OSPFv3 Neighbor\n" | |
1d68dbfe DW |
1199 | "Debug OSPFv3 Neighbor State Change\n" |
1200 | "Debug OSPFv3 Neighbor Event\n") | |
508e53e2 | 1201 | { |
d62a17ae | 1202 | int idx_type = 3; |
1203 | unsigned char level = 0; | |
1204 | ||
1205 | if (argc == 4) { | |
1206 | if (!strncmp(argv[idx_type]->arg, "s", 1)) | |
1207 | level = OSPF6_DEBUG_NEIGHBOR_STATE; | |
1208 | else if (!strncmp(argv[idx_type]->arg, "e", 1)) | |
1209 | level = OSPF6_DEBUG_NEIGHBOR_EVENT; | |
1210 | } else | |
1211 | level = OSPF6_DEBUG_NEIGHBOR_STATE | OSPF6_DEBUG_NEIGHBOR_EVENT; | |
1212 | ||
1213 | OSPF6_DEBUG_NEIGHBOR_ON(level); | |
1214 | return CMD_SUCCESS; | |
718e3744 | 1215 | } |
1216 | ||
508e53e2 | 1217 | |
1218 | DEFUN (no_debug_ospf6_neighbor, | |
1219 | no_debug_ospf6_neighbor_cmd, | |
6de69f83 | 1220 | "no debug ospf6 neighbor [<state|event>]", |
508e53e2 | 1221 | NO_STR |
1222 | DEBUG_STR | |
1223 | OSPF6_STR | |
1224 | "Debug OSPFv3 Neighbor\n" | |
1d68dbfe DW |
1225 | "Debug OSPFv3 Neighbor State Change\n" |
1226 | "Debug OSPFv3 Neighbor Event\n") | |
508e53e2 | 1227 | { |
d62a17ae | 1228 | int idx_type = 4; |
1229 | unsigned char level = 0; | |
1230 | ||
1231 | if (argc == 5) { | |
1232 | if (!strncmp(argv[idx_type]->arg, "s", 1)) | |
1233 | level = OSPF6_DEBUG_NEIGHBOR_STATE; | |
1234 | if (!strncmp(argv[idx_type]->arg, "e", 1)) | |
1235 | level = OSPF6_DEBUG_NEIGHBOR_EVENT; | |
1236 | } else | |
1237 | level = OSPF6_DEBUG_NEIGHBOR_STATE | OSPF6_DEBUG_NEIGHBOR_EVENT; | |
1238 | ||
1239 | OSPF6_DEBUG_NEIGHBOR_OFF(level); | |
1240 | return CMD_SUCCESS; | |
508e53e2 | 1241 | } |
1242 | ||
508e53e2 | 1243 | |
4dfd8aff DW |
1244 | DEFUN (no_debug_ospf6, |
1245 | no_debug_ospf6_cmd, | |
1246 | "no debug ospf6", | |
1247 | NO_STR | |
1248 | DEBUG_STR | |
1249 | OSPF6_STR) | |
1250 | { | |
d7c0a89a | 1251 | unsigned int i; |
d62a17ae | 1252 | struct ospf6_lsa_handler *handler = NULL; |
1253 | ||
1254 | OSPF6_DEBUG_ABR_OFF(); | |
1255 | OSPF6_DEBUG_ASBR_OFF(); | |
1256 | OSPF6_DEBUG_BROUTER_OFF(); | |
1257 | OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_OFF(); | |
1258 | OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_OFF(); | |
1259 | OSPF6_DEBUG_FLOODING_OFF(); | |
1260 | OSPF6_DEBUG_INTERFACE_OFF(); | |
1261 | ||
1262 | for (i = 0; i < vector_active(ospf6_lsa_handler_vector); i++) { | |
1263 | handler = vector_slot(ospf6_lsa_handler_vector, i); | |
1264 | ||
1265 | if (handler != NULL) { | |
01db90cd | 1266 | UNSET_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG); |
d62a17ae | 1267 | } |
1268 | } | |
1269 | ||
1270 | for (i = 0; i < 6; i++) | |
1271 | OSPF6_DEBUG_MESSAGE_OFF(i, | |
1272 | OSPF6_DEBUG_NEIGHBOR_STATE | |
1273 | | OSPF6_DEBUG_NEIGHBOR_EVENT); | |
1274 | ||
1275 | OSPF6_DEBUG_NEIGHBOR_OFF(OSPF6_DEBUG_NEIGHBOR_STATE | |
1276 | | OSPF6_DEBUG_NEIGHBOR_EVENT); | |
1277 | OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_TABLE); | |
1278 | OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_INTRA); | |
1279 | OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_INTER); | |
1280 | OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_MEMORY); | |
1281 | OSPF6_DEBUG_SPF_OFF(OSPF6_DEBUG_SPF_PROCESS); | |
1282 | OSPF6_DEBUG_SPF_OFF(OSPF6_DEBUG_SPF_TIME); | |
1283 | OSPF6_DEBUG_SPF_OFF(OSPF6_DEBUG_SPF_DATABASE); | |
1284 | OSPF6_DEBUG_ZEBRA_OFF(OSPF6_DEBUG_ZEBRA_SEND | OSPF6_DEBUG_ZEBRA_RECV); | |
1285 | ||
1286 | return CMD_SUCCESS; | |
4dfd8aff DW |
1287 | } |
1288 | ||
d62a17ae | 1289 | int config_write_ospf6_debug_neighbor(struct vty *vty) |
508e53e2 | 1290 | { |
d62a17ae | 1291 | if (IS_OSPF6_DEBUG_NEIGHBOR(STATE) && IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) |
1292 | vty_out(vty, "debug ospf6 neighbor\n"); | |
1293 | else if (IS_OSPF6_DEBUG_NEIGHBOR(STATE)) | |
1294 | vty_out(vty, "debug ospf6 neighbor state\n"); | |
1295 | else if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) | |
1296 | vty_out(vty, "debug ospf6 neighbor event\n"); | |
1297 | return 0; | |
508e53e2 | 1298 | } |
1299 | ||
d62a17ae | 1300 | void install_element_ospf6_debug_neighbor(void) |
508e53e2 | 1301 | { |
d62a17ae | 1302 | install_element(ENABLE_NODE, &debug_ospf6_neighbor_cmd); |
1303 | install_element(ENABLE_NODE, &no_debug_ospf6_neighbor_cmd); | |
1304 | install_element(ENABLE_NODE, &no_debug_ospf6_cmd); | |
1305 | install_element(CONFIG_NODE, &debug_ospf6_neighbor_cmd); | |
1306 | install_element(CONFIG_NODE, &no_debug_ospf6_neighbor_cmd); | |
1307 | install_element(CONFIG_NODE, &no_debug_ospf6_cmd); | |
508e53e2 | 1308 | } |