]>
Commit | Line | Data |
---|---|---|
eb5d44eb | 1 | /* |
d62a17ae | 2 | * IS-IS Rout(e)ing protocol - isis_adjacency.c |
eb5d44eb | 3 | * handling of IS-IS adjacencies |
4 | * | |
5 | * Copyright (C) 2001,2002 Sampo Saaristo | |
d62a17ae | 6 | * Tampere University of Technology |
eb5d44eb | 7 | * Institute of Communications Engineering |
8 | * | |
d62a17ae | 9 | * This program is free software; you can redistribute it and/or modify it |
10 | * under the terms of the GNU General Public Licenseas published by the Free | |
11 | * Software Foundation; either version 2 of the License, or (at your option) | |
eb5d44eb | 12 | * any later version. |
13 | * | |
d62a17ae | 14 | * This program is distributed in the hope that it will be useful,but WITHOUT |
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
eb5d44eb | 17 | * more details. |
896014f4 DL |
18 | * |
19 | * You should have received a copy of the GNU General Public License along | |
20 | * with this program; see the file COPYING; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
eb5d44eb | 22 | */ |
23 | ||
eb5d44eb | 24 | #include <zebra.h> |
eb5d44eb | 25 | |
26 | #include "log.h" | |
27 | #include "memory.h" | |
28 | #include "hash.h" | |
29 | #include "vty.h" | |
30 | #include "linklist.h" | |
31 | #include "thread.h" | |
32 | #include "if.h" | |
33 | #include "stream.h" | |
34 | ||
eb5d44eb | 35 | #include "isisd/isis_constants.h" |
36 | #include "isisd/isis_common.h" | |
3f045a08 | 37 | #include "isisd/isis_flags.h" |
eb5d44eb | 38 | #include "isisd/isisd.h" |
39 | #include "isisd/isis_circuit.h" | |
40 | #include "isisd/isis_adjacency.h" | |
41 | #include "isisd/isis_misc.h" | |
42 | #include "isisd/isis_dr.h" | |
43 | #include "isisd/isis_dynhn.h" | |
44 | #include "isisd/isis_pdu.h" | |
3f045a08 JB |
45 | #include "isisd/isis_lsp.h" |
46 | #include "isisd/isis_spf.h" | |
47 | #include "isisd/isis_events.h" | |
206f4aae | 48 | #include "isisd/isis_mt.h" |
42fe2621 | 49 | #include "isisd/isis_tlvs.h" |
8e6fb83b | 50 | #include "isisd/fabricd.h" |
2a1c520e | 51 | #include "isisd/isis_nb.h" |
eb5d44eb | 52 | |
eb5d44eb | 53 | extern struct isis *isis; |
54 | ||
d7c0a89a | 55 | static struct isis_adjacency *adj_alloc(const uint8_t *id) |
eb5d44eb | 56 | { |
d62a17ae | 57 | struct isis_adjacency *adj; |
eb5d44eb | 58 | |
d62a17ae | 59 | adj = XCALLOC(MTYPE_ISIS_ADJACENCY, sizeof(struct isis_adjacency)); |
60 | memcpy(adj->sysid, id, ISIS_SYS_ID_LEN); | |
f390d2c7 | 61 | |
d62a17ae | 62 | return adj; |
eb5d44eb | 63 | } |
64 | ||
d7c0a89a | 65 | struct isis_adjacency *isis_new_adj(const uint8_t *id, const uint8_t *snpa, |
d62a17ae | 66 | int level, struct isis_circuit *circuit) |
eb5d44eb | 67 | { |
d62a17ae | 68 | struct isis_adjacency *adj; |
69 | int i; | |
70 | ||
71 | adj = adj_alloc(id); /* P2P kludge */ | |
72 | ||
d62a17ae | 73 | if (snpa) { |
74 | memcpy(adj->snpa, snpa, ETH_ALEN); | |
75 | } else { | |
76 | memset(adj->snpa, ' ', ETH_ALEN); | |
eb5d44eb | 77 | } |
eb5d44eb | 78 | |
d62a17ae | 79 | adj->circuit = circuit; |
80 | adj->level = level; | |
81 | adj->flaps = 0; | |
82 | adj->last_flap = time(NULL); | |
42fe2621 | 83 | adj->threeway_state = ISIS_THREEWAY_DOWN; |
d62a17ae | 84 | if (circuit->circ_type == CIRCUIT_T_BROADCAST) { |
85 | listnode_add(circuit->u.bc.adjdb[level - 1], adj); | |
86 | adj->dischanges[level - 1] = 0; | |
87 | for (i = 0; i < DIS_RECORDS; | |
88 | i++) /* clear N DIS state change records */ | |
89 | { | |
90 | adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis = | |
91 | ISIS_UNKNOWN_DIS; | |
92 | adj->dis_record[(i * ISIS_LEVELS) + level - 1] | |
93 | .last_dis_change = time(NULL); | |
94 | } | |
95 | } | |
96 | ||
97 | return adj; | |
eb5d44eb | 98 | } |
99 | ||
d7c0a89a | 100 | struct isis_adjacency *isis_adj_lookup(const uint8_t *sysid, struct list *adjdb) |
eb5d44eb | 101 | { |
d62a17ae | 102 | struct isis_adjacency *adj; |
103 | struct listnode *node; | |
eb5d44eb | 104 | |
d62a17ae | 105 | for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) |
106 | if (memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN) == 0) | |
107 | return adj; | |
f390d2c7 | 108 | |
d62a17ae | 109 | return NULL; |
eb5d44eb | 110 | } |
111 | ||
d7c0a89a | 112 | struct isis_adjacency *isis_adj_lookup_snpa(const uint8_t *ssnpa, |
d62a17ae | 113 | struct list *adjdb) |
eb5d44eb | 114 | { |
d62a17ae | 115 | struct listnode *node; |
116 | struct isis_adjacency *adj; | |
eb5d44eb | 117 | |
d62a17ae | 118 | for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) |
119 | if (memcmp(adj->snpa, ssnpa, ETH_ALEN) == 0) | |
120 | return adj; | |
f390d2c7 | 121 | |
d62a17ae | 122 | return NULL; |
eb5d44eb | 123 | } |
124 | ||
a5b5e946 CF |
125 | DEFINE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj)) |
126 | ||
d62a17ae | 127 | void isis_delete_adj(void *arg) |
eb5d44eb | 128 | { |
d62a17ae | 129 | struct isis_adjacency *adj = arg; |
3f045a08 | 130 | |
d62a17ae | 131 | if (!adj) |
132 | return; | |
f390d2c7 | 133 | |
d62a17ae | 134 | THREAD_TIMER_OFF(adj->t_expire); |
a5b5e946 CF |
135 | if (adj->adj_state != ISIS_ADJ_DOWN) { |
136 | adj->adj_state = ISIS_ADJ_DOWN; | |
137 | hook_call(isis_adj_state_change_hook, adj); | |
138 | } | |
3f045a08 | 139 | |
d62a17ae | 140 | /* remove from SPF trees */ |
141 | spftree_area_adj_del(adj->circuit->area, adj); | |
13fb40ac | 142 | |
0a22ddfb QY |
143 | XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses); |
144 | XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses); | |
145 | XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses); | |
3f045a08 | 146 | |
d62a17ae | 147 | adj_mt_finish(adj); |
d8fba7d9 | 148 | |
d62a17ae | 149 | XFREE(MTYPE_ISIS_ADJACENCY, adj); |
150 | return; | |
eb5d44eb | 151 | } |
152 | ||
d62a17ae | 153 | static const char *adj_state2string(int state) |
3f045a08 JB |
154 | { |
155 | ||
d62a17ae | 156 | switch (state) { |
157 | case ISIS_ADJ_INITIALIZING: | |
158 | return "Initializing"; | |
159 | case ISIS_ADJ_UP: | |
160 | return "Up"; | |
161 | case ISIS_ADJ_DOWN: | |
162 | return "Down"; | |
163 | default: | |
164 | return "Unknown"; | |
165 | } | |
166 | ||
167 | return NULL; /* not reached */ | |
3f045a08 JB |
168 | } |
169 | ||
42fe2621 CF |
170 | void isis_adj_process_threeway(struct isis_adjacency *adj, |
171 | struct isis_threeway_adj *tw_adj, | |
172 | enum isis_adj_usage adj_usage) | |
173 | { | |
174 | enum isis_threeway_state next_tw_state = ISIS_THREEWAY_DOWN; | |
175 | ||
58e5d748 | 176 | if (tw_adj && !adj->circuit->disable_threeway_adj) { |
42fe2621 CF |
177 | if (tw_adj->state == ISIS_THREEWAY_DOWN) { |
178 | next_tw_state = ISIS_THREEWAY_INITIALIZING; | |
179 | } else if (tw_adj->state == ISIS_THREEWAY_INITIALIZING) { | |
180 | next_tw_state = ISIS_THREEWAY_UP; | |
181 | } else if (tw_adj->state == ISIS_THREEWAY_UP) { | |
182 | if (adj->threeway_state == ISIS_THREEWAY_DOWN) | |
183 | next_tw_state = ISIS_THREEWAY_DOWN; | |
184 | else | |
185 | next_tw_state = ISIS_THREEWAY_UP; | |
186 | } | |
187 | } else { | |
188 | next_tw_state = ISIS_THREEWAY_UP; | |
189 | } | |
190 | ||
191 | if (next_tw_state != adj->threeway_state) { | |
192 | if (isis->debugs & DEBUG_ADJ_PACKETS) { | |
193 | zlog_info("ISIS-Adj (%s): Threeway state change %s to %s", | |
194 | adj->circuit->area->area_tag, | |
195 | isis_threeway_state_name(adj->threeway_state), | |
196 | isis_threeway_state_name(next_tw_state)); | |
197 | } | |
198 | } | |
199 | ||
8e6fb83b CF |
200 | if (next_tw_state != ISIS_THREEWAY_DOWN) |
201 | fabricd_initial_sync_hello(adj->circuit); | |
202 | ||
42fe2621 CF |
203 | if (next_tw_state == ISIS_THREEWAY_DOWN) { |
204 | isis_adj_state_change(adj, ISIS_ADJ_DOWN, "Neighbor restarted"); | |
205 | return; | |
206 | } | |
207 | ||
208 | if (next_tw_state == ISIS_THREEWAY_UP) { | |
209 | if (adj->adj_state != ISIS_ADJ_UP) { | |
210 | isis_adj_state_change(adj, ISIS_ADJ_UP, NULL); | |
211 | adj->adj_usage = adj_usage; | |
212 | } | |
213 | } | |
214 | ||
5346acec CF |
215 | if (adj->threeway_state != next_tw_state) { |
216 | send_hello_sched(adj->circuit, 0, TRIGGERED_IIH_DELAY); | |
217 | } | |
218 | ||
42fe2621 CF |
219 | adj->threeway_state = next_tw_state; |
220 | } | |
221 | ||
d62a17ae | 222 | void isis_adj_state_change(struct isis_adjacency *adj, |
223 | enum isis_adj_state new_state, const char *reason) | |
eb5d44eb | 224 | { |
5346acec CF |
225 | enum isis_adj_state old_state = adj->adj_state; |
226 | struct isis_circuit *circuit = adj->circuit; | |
d62a17ae | 227 | bool del; |
228 | ||
d62a17ae | 229 | adj->adj_state = new_state; |
5346acec CF |
230 | if (new_state != old_state) { |
231 | send_hello_sched(circuit, adj->level, TRIGGERED_IIH_DELAY); | |
232 | } | |
d62a17ae | 233 | |
234 | if (isis->debugs & DEBUG_ADJ_PACKETS) { | |
235 | zlog_debug("ISIS-Adj (%s): Adjacency state change %d->%d: %s", | |
236 | circuit->area->area_tag, old_state, new_state, | |
237 | reason ? reason : "unspecified"); | |
238 | } | |
239 | ||
240 | if (circuit->area->log_adj_changes) { | |
241 | const char *adj_name; | |
242 | struct isis_dynhn *dyn; | |
243 | ||
244 | dyn = dynhn_find_by_id(adj->sysid); | |
245 | if (dyn) | |
af8ac8f9 | 246 | adj_name = dyn->hostname; |
d62a17ae | 247 | else |
248 | adj_name = sysid_print(adj->sysid); | |
249 | ||
250 | zlog_info( | |
251 | "%%ADJCHANGE: Adjacency to %s (%s) changed from %s to %s, %s", | |
252 | adj_name, adj->circuit->interface->name, | |
253 | adj_state2string(old_state), | |
254 | adj_state2string(new_state), | |
255 | reason ? reason : "unspecified"); | |
256 | } | |
257 | ||
c32496ee | 258 | circuit->adj_state_changes++; |
de983bb8 EDP |
259 | #ifndef FABRICD |
260 | /* send northbound notification */ | |
261 | isis_notif_adj_state_change(adj, new_state, reason); | |
262 | #endif /* ifndef FABRICD */ | |
263 | ||
d62a17ae | 264 | if (circuit->circ_type == CIRCUIT_T_BROADCAST) { |
265 | del = false; | |
5346acec | 266 | for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) { |
d62a17ae | 267 | if ((adj->level & level) == 0) |
268 | continue; | |
269 | if (new_state == ISIS_ADJ_UP) { | |
270 | circuit->upadjcount[level - 1]++; | |
a5b5e946 | 271 | hook_call(isis_adj_state_change_hook, adj); |
d62a17ae | 272 | /* update counter & timers for debugging |
273 | * purposes */ | |
274 | adj->last_flap = time(NULL); | |
275 | adj->flaps++; | |
276 | } else if (new_state == ISIS_ADJ_DOWN) { | |
277 | listnode_delete(circuit->u.bc.adjdb[level - 1], | |
278 | adj); | |
58e16237 | 279 | |
d62a17ae | 280 | circuit->upadjcount[level - 1]--; |
58e16237 | 281 | if (circuit->upadjcount[level - 1] == 0) |
9b39405f | 282 | isis_tx_queue_clean(circuit->tx_queue); |
58e16237 | 283 | |
a5b5e946 | 284 | hook_call(isis_adj_state_change_hook, adj); |
d62a17ae | 285 | del = true; |
286 | } | |
287 | ||
288 | if (circuit->u.bc.lan_neighs[level - 1]) { | |
289 | list_delete_all_node( | |
290 | circuit->u.bc.lan_neighs[level - 1]); | |
291 | isis_adj_build_neigh_list( | |
292 | circuit->u.bc.adjdb[level - 1], | |
293 | circuit->u.bc.lan_neighs[level - 1]); | |
294 | } | |
295 | ||
296 | /* On adjacency state change send new pseudo LSP if we | |
297 | * are the DR */ | |
298 | if (circuit->u.bc.is_dr[level - 1]) | |
299 | lsp_regenerate_schedule_pseudo(circuit, level); | |
300 | } | |
301 | ||
302 | if (del) | |
303 | isis_delete_adj(adj); | |
304 | ||
d62a17ae | 305 | } else if (circuit->circ_type == CIRCUIT_T_P2P) { |
306 | del = false; | |
5346acec | 307 | for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) { |
d62a17ae | 308 | if ((adj->level & level) == 0) |
309 | continue; | |
310 | if (new_state == ISIS_ADJ_UP) { | |
311 | circuit->upadjcount[level - 1]++; | |
a5b5e946 | 312 | hook_call(isis_adj_state_change_hook, adj); |
d62a17ae | 313 | |
d62a17ae | 314 | /* update counter & timers for debugging |
315 | * purposes */ | |
316 | adj->last_flap = time(NULL); | |
317 | adj->flaps++; | |
318 | ||
8e6fb83b CF |
319 | if (level == IS_LEVEL_1) { |
320 | thread_add_timer(master, send_l1_csnp, | |
321 | circuit, 0, | |
322 | &circuit->t_send_csnp[0]); | |
323 | } else { | |
324 | thread_add_timer(master, send_l2_csnp, | |
325 | circuit, 0, | |
326 | &circuit->t_send_csnp[1]); | |
327 | } | |
d62a17ae | 328 | } else if (new_state == ISIS_ADJ_DOWN) { |
329 | if (adj->circuit->u.p2p.neighbor == adj) | |
330 | adj->circuit->u.p2p.neighbor = NULL; | |
331 | circuit->upadjcount[level - 1]--; | |
58e16237 | 332 | if (circuit->upadjcount[level - 1] == 0) |
9b39405f | 333 | isis_tx_queue_clean(circuit->tx_queue); |
58e16237 | 334 | |
a5b5e946 | 335 | hook_call(isis_adj_state_change_hook, adj); |
d62a17ae | 336 | del = true; |
337 | } | |
338 | } | |
339 | ||
340 | if (del) | |
341 | isis_delete_adj(adj); | |
d62a17ae | 342 | } |
eb5d44eb | 343 | } |
344 | ||
345 | ||
d62a17ae | 346 | void isis_adj_print(struct isis_adjacency *adj) |
eb5d44eb | 347 | { |
d62a17ae | 348 | struct isis_dynhn *dyn; |
d62a17ae | 349 | |
350 | if (!adj) | |
351 | return; | |
352 | dyn = dynhn_find_by_id(adj->sysid); | |
353 | if (dyn) | |
af8ac8f9 | 354 | zlog_debug("%s", dyn->hostname); |
d62a17ae | 355 | |
356 | zlog_debug("SystemId %20s SNPA %s, level %d\nHolding Time %d", | |
357 | sysid_print(adj->sysid), snpa_print(adj->snpa), adj->level, | |
358 | adj->hold_time); | |
0c1bd758 | 359 | if (adj->ipv4_address_count) { |
d62a17ae | 360 | zlog_debug("IPv4 Address(es):"); |
0c1bd758 CF |
361 | for (unsigned int i = 0; i < adj->ipv4_address_count; i++) |
362 | zlog_debug("%s", inet_ntoa(adj->ipv4_addresses[i])); | |
d62a17ae | 363 | } |
364 | ||
0c1bd758 | 365 | if (adj->ipv6_address_count) { |
d62a17ae | 366 | zlog_debug("IPv6 Address(es):"); |
0c1bd758 CF |
367 | for (unsigned int i = 0; i < adj->ipv6_address_count; i++) { |
368 | char buf[INET6_ADDRSTRLEN]; | |
369 | inet_ntop(AF_INET6, &adj->ipv6_addresses[i], buf, | |
370 | sizeof(buf)); | |
371 | zlog_debug("%s", buf); | |
d62a17ae | 372 | } |
f390d2c7 | 373 | } |
d62a17ae | 374 | zlog_debug("Speaks: %s", nlpid2string(&adj->nlpids)); |
eb5d44eb | 375 | |
d62a17ae | 376 | return; |
eb5d44eb | 377 | } |
378 | ||
2a1c520e RW |
379 | const char *isis_adj_yang_state(enum isis_adj_state state) |
380 | { | |
381 | switch (state) { | |
382 | case ISIS_ADJ_DOWN: | |
383 | return "down"; | |
384 | case ISIS_ADJ_UP: | |
385 | return "up"; | |
386 | case ISIS_ADJ_INITIALIZING: | |
387 | return "init"; | |
388 | default: | |
389 | return "failed"; | |
390 | } | |
391 | } | |
392 | ||
d62a17ae | 393 | int isis_adj_expire(struct thread *thread) |
eb5d44eb | 394 | { |
d62a17ae | 395 | struct isis_adjacency *adj; |
eb5d44eb | 396 | |
d62a17ae | 397 | /* |
398 | * Get the adjacency | |
399 | */ | |
400 | adj = THREAD_ARG(thread); | |
401 | assert(adj); | |
402 | adj->t_expire = NULL; | |
eb5d44eb | 403 | |
d62a17ae | 404 | /* trigger the adj expire event */ |
405 | isis_adj_state_change(adj, ISIS_ADJ_DOWN, "holding time expired"); | |
eb5d44eb | 406 | |
d62a17ae | 407 | return 0; |
eb5d44eb | 408 | } |
409 | ||
eb5d44eb | 410 | /* |
3f045a08 | 411 | * show isis neighbor [detail] |
eb5d44eb | 412 | */ |
d62a17ae | 413 | void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty, |
414 | char detail) | |
eb5d44eb | 415 | { |
d62a17ae | 416 | time_t now; |
417 | struct isis_dynhn *dyn; | |
418 | int level; | |
d62a17ae | 419 | |
420 | dyn = dynhn_find_by_id(adj->sysid); | |
421 | if (dyn) | |
af8ac8f9 | 422 | vty_out(vty, " %-20s", dyn->hostname); |
d62a17ae | 423 | else |
424 | vty_out(vty, " %-20s", sysid_print(adj->sysid)); | |
425 | ||
426 | if (detail == ISIS_UI_LEVEL_BRIEF) { | |
427 | if (adj->circuit) | |
428 | vty_out(vty, "%-12s", adj->circuit->interface->name); | |
429 | else | |
430 | vty_out(vty, "NULL circuit!"); | |
431 | vty_out(vty, "%-3u", adj->level); /* level */ | |
432 | vty_out(vty, "%-13s", adj_state2string(adj->adj_state)); | |
433 | now = time(NULL); | |
434 | if (adj->last_upd) | |
435 | vty_out(vty, "%-9llu", | |
436 | (unsigned long long)adj->last_upd | |
437 | + adj->hold_time - now); | |
438 | else | |
439 | vty_out(vty, "- "); | |
440 | vty_out(vty, "%-10s", snpa_print(adj->snpa)); | |
441 | vty_out(vty, "\n"); | |
f390d2c7 | 442 | } |
d62a17ae | 443 | |
444 | if (detail == ISIS_UI_LEVEL_DETAIL) { | |
445 | level = adj->level; | |
446 | vty_out(vty, "\n"); | |
447 | if (adj->circuit) | |
448 | vty_out(vty, " Interface: %s", | |
449 | adj->circuit->interface->name); | |
450 | else | |
451 | vty_out(vty, " Interface: NULL circuit"); | |
452 | vty_out(vty, ", Level: %u", adj->level); /* level */ | |
453 | vty_out(vty, ", State: %s", adj_state2string(adj->adj_state)); | |
454 | now = time(NULL); | |
455 | if (adj->last_upd) | |
456 | vty_out(vty, ", Expires in %s", | |
457 | time2string(adj->last_upd + adj->hold_time | |
458 | - now)); | |
459 | else | |
460 | vty_out(vty, ", Expires in %s", | |
461 | time2string(adj->hold_time)); | |
462 | vty_out(vty, "\n"); | |
463 | vty_out(vty, " Adjacency flaps: %u", adj->flaps); | |
464 | vty_out(vty, ", Last: %s ago", | |
465 | time2string(now - adj->last_flap)); | |
466 | vty_out(vty, "\n"); | |
467 | vty_out(vty, " Circuit type: %s", | |
468 | circuit_t2string(adj->circuit_t)); | |
469 | vty_out(vty, ", Speaks: %s", nlpid2string(&adj->nlpids)); | |
470 | vty_out(vty, "\n"); | |
471 | if (adj->mt_count != 1 | |
472 | || adj->mt_set[0] != ISIS_MT_IPV4_UNICAST) { | |
473 | vty_out(vty, " Topologies:\n"); | |
474 | for (unsigned int i = 0; i < adj->mt_count; i++) | |
475 | vty_out(vty, " %s\n", | |
476 | isis_mtid2str(adj->mt_set[i])); | |
477 | } | |
478 | vty_out(vty, " SNPA: %s", snpa_print(adj->snpa)); | |
479 | if (adj->circuit | |
480 | && (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) { | |
481 | dyn = dynhn_find_by_id(adj->lanid); | |
482 | if (dyn) | |
af8ac8f9 | 483 | vty_out(vty, ", LAN id: %s.%02x", dyn->hostname, |
d62a17ae | 484 | adj->lanid[ISIS_SYS_ID_LEN]); |
485 | else | |
486 | vty_out(vty, ", LAN id: %s.%02x", | |
487 | sysid_print(adj->lanid), | |
488 | adj->lanid[ISIS_SYS_ID_LEN]); | |
489 | ||
490 | vty_out(vty, "\n"); | |
491 | vty_out(vty, " LAN Priority: %u", | |
492 | adj->prio[adj->level - 1]); | |
493 | ||
494 | vty_out(vty, ", %s, DIS flaps: %u, Last: %s ago", | |
495 | isis_disflag2string( | |
496 | adj->dis_record[ISIS_LEVELS + level - 1] | |
497 | .dis), | |
498 | adj->dischanges[level - 1], | |
9d303b37 DL |
499 | time2string(now - (adj->dis_record[ISIS_LEVELS |
500 | + level - 1] | |
501 | .last_dis_change))); | |
d62a17ae | 502 | } |
503 | vty_out(vty, "\n"); | |
504 | ||
0c1bd758 | 505 | if (adj->area_address_count) { |
d62a17ae | 506 | vty_out(vty, " Area Address(es):\n"); |
0c1bd758 CF |
507 | for (unsigned int i = 0; i < adj->area_address_count; |
508 | i++) { | |
d62a17ae | 509 | vty_out(vty, " %s\n", |
996c9314 LB |
510 | isonet_print(adj->area_addresses[i] |
511 | .area_addr, | |
512 | adj->area_addresses[i] | |
513 | .addr_len)); | |
0c1bd758 | 514 | } |
d62a17ae | 515 | } |
0c1bd758 | 516 | if (adj->ipv4_address_count) { |
d62a17ae | 517 | vty_out(vty, " IPv4 Address(es):\n"); |
0c1bd758 CF |
518 | for (unsigned int i = 0; i < adj->ipv4_address_count; |
519 | i++) | |
520 | vty_out(vty, " %s\n", | |
996c9314 | 521 | inet_ntoa(adj->ipv4_addresses[i])); |
d62a17ae | 522 | } |
0c1bd758 | 523 | if (adj->ipv6_address_count) { |
d62a17ae | 524 | vty_out(vty, " IPv6 Address(es):\n"); |
0c1bd758 CF |
525 | for (unsigned int i = 0; i < adj->ipv6_address_count; |
526 | i++) { | |
527 | char buf[INET6_ADDRSTRLEN]; | |
528 | inet_ntop(AF_INET6, &adj->ipv6_addresses[i], | |
529 | buf, sizeof(buf)); | |
530 | vty_out(vty, " %s\n", buf); | |
d62a17ae | 531 | } |
532 | } | |
533 | vty_out(vty, "\n"); | |
f390d2c7 | 534 | } |
d62a17ae | 535 | return; |
eb5d44eb | 536 | } |
537 | ||
d62a17ae | 538 | void isis_adj_build_neigh_list(struct list *adjdb, struct list *list) |
eb5d44eb | 539 | { |
d62a17ae | 540 | struct isis_adjacency *adj; |
541 | struct listnode *node; | |
542 | ||
543 | if (!list) { | |
544 | zlog_warn("isis_adj_build_neigh_list(): NULL list"); | |
545 | return; | |
f390d2c7 | 546 | } |
547 | ||
d62a17ae | 548 | for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) { |
549 | if (!adj) { | |
550 | zlog_warn("isis_adj_build_neigh_list(): NULL adj"); | |
551 | return; | |
552 | } | |
553 | ||
554 | if ((adj->adj_state == ISIS_ADJ_UP | |
555 | || adj->adj_state == ISIS_ADJ_INITIALIZING)) | |
556 | listnode_add(list, adj->snpa); | |
557 | } | |
558 | return; | |
eb5d44eb | 559 | } |
560 | ||
d62a17ae | 561 | void isis_adj_build_up_list(struct list *adjdb, struct list *list) |
eb5d44eb | 562 | { |
d62a17ae | 563 | struct isis_adjacency *adj; |
564 | struct listnode *node; | |
565 | ||
566 | if (adjdb == NULL) { | |
567 | zlog_warn("isis_adj_build_up_list(): adjacency DB is empty"); | |
568 | return; | |
569 | } | |
570 | ||
571 | if (!list) { | |
572 | zlog_warn("isis_adj_build_up_list(): NULL list"); | |
573 | return; | |
f390d2c7 | 574 | } |
575 | ||
d62a17ae | 576 | for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) { |
577 | if (!adj) { | |
578 | zlog_warn("isis_adj_build_up_list(): NULL adj"); | |
579 | return; | |
580 | } | |
f390d2c7 | 581 | |
d62a17ae | 582 | if (adj->adj_state == ISIS_ADJ_UP) |
583 | listnode_add(list, adj); | |
584 | } | |
585 | ||
586 | return; | |
eb5d44eb | 587 | } |
d8fba7d9 | 588 | |
d62a17ae | 589 | int isis_adj_usage2levels(enum isis_adj_usage usage) |
d8fba7d9 | 590 | { |
d62a17ae | 591 | switch (usage) { |
592 | case ISIS_ADJ_LEVEL1: | |
593 | return IS_LEVEL_1; | |
594 | case ISIS_ADJ_LEVEL2: | |
595 | return IS_LEVEL_2; | |
596 | case ISIS_ADJ_LEVEL1AND2: | |
597 | return IS_LEVEL_1 | IS_LEVEL_2; | |
598 | default: | |
599 | break; | |
600 | } | |
601 | return 0; | |
d8fba7d9 | 602 | } |