]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_adjacency.c
Merge pull request #8015 from mjstapp/fix_topo_gen_support
[mirror_frr.git] / isisd / isis_adjacency.c
CommitLineData
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 45#include "isisd/isis_lsp.h"
3f045a08 46#include "isisd/isis_events.h"
206f4aae 47#include "isisd/isis_mt.h"
42fe2621 48#include "isisd/isis_tlvs.h"
8e6fb83b 49#include "isisd/fabricd.h"
2a1c520e 50#include "isisd/isis_nb.h"
eb5d44eb 51
d7c0a89a 52static struct isis_adjacency *adj_alloc(const uint8_t *id)
eb5d44eb 53{
d62a17ae 54 struct isis_adjacency *adj;
eb5d44eb 55
d62a17ae 56 adj = XCALLOC(MTYPE_ISIS_ADJACENCY, sizeof(struct isis_adjacency));
57 memcpy(adj->sysid, id, ISIS_SYS_ID_LEN);
f390d2c7 58
d62a17ae 59 return adj;
eb5d44eb 60}
61
d7c0a89a 62struct isis_adjacency *isis_new_adj(const uint8_t *id, const uint8_t *snpa,
d62a17ae 63 int level, struct isis_circuit *circuit)
eb5d44eb 64{
d62a17ae 65 struct isis_adjacency *adj;
66 int i;
67
68 adj = adj_alloc(id); /* P2P kludge */
69
d62a17ae 70 if (snpa) {
71 memcpy(adj->snpa, snpa, ETH_ALEN);
72 } else {
73 memset(adj->snpa, ' ', ETH_ALEN);
eb5d44eb 74 }
eb5d44eb 75
d62a17ae 76 adj->circuit = circuit;
77 adj->level = level;
78 adj->flaps = 0;
79 adj->last_flap = time(NULL);
42fe2621 80 adj->threeway_state = ISIS_THREEWAY_DOWN;
d62a17ae 81 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
82 listnode_add(circuit->u.bc.adjdb[level - 1], adj);
83 adj->dischanges[level - 1] = 0;
84 for (i = 0; i < DIS_RECORDS;
85 i++) /* clear N DIS state change records */
86 {
87 adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis =
88 ISIS_UNKNOWN_DIS;
89 adj->dis_record[(i * ISIS_LEVELS) + level - 1]
90 .last_dis_change = time(NULL);
91 }
92 }
26f6acaf 93 adj->adj_sids = list_new();
75eddbc3 94 listnode_add(circuit->area->adjacency_list, adj);
d62a17ae 95
96 return adj;
eb5d44eb 97}
98
d7c0a89a 99struct isis_adjacency *isis_adj_lookup(const uint8_t *sysid, struct list *adjdb)
eb5d44eb 100{
d62a17ae 101 struct isis_adjacency *adj;
102 struct listnode *node;
eb5d44eb 103
d62a17ae 104 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj))
105 if (memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN) == 0)
106 return adj;
f390d2c7 107
d62a17ae 108 return NULL;
eb5d44eb 109}
110
d7c0a89a 111struct isis_adjacency *isis_adj_lookup_snpa(const uint8_t *ssnpa,
d62a17ae 112 struct list *adjdb)
eb5d44eb 113{
d62a17ae 114 struct listnode *node;
115 struct isis_adjacency *adj;
eb5d44eb 116
d62a17ae 117 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj))
118 if (memcmp(adj->snpa, ssnpa, ETH_ALEN) == 0)
119 return adj;
f390d2c7 120
d62a17ae 121 return NULL;
eb5d44eb 122}
123
75eddbc3
RW
124struct isis_adjacency *isis_adj_find(const struct isis_area *area, int level,
125 const uint8_t *sysid)
26f6acaf 126{
75eddbc3 127 struct isis_adjacency *adj;
26f6acaf
RW
128 struct listnode *node;
129
75eddbc3
RW
130 for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) {
131 if (!(adj->level & level))
132 continue;
133
134 if (!memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN))
135 return adj;
26f6acaf
RW
136 }
137
75eddbc3 138 return NULL;
26f6acaf
RW
139}
140
a5b5e946
CF
141DEFINE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj))
142
d62a17ae 143void isis_delete_adj(void *arg)
eb5d44eb 144{
d62a17ae 145 struct isis_adjacency *adj = arg;
3f045a08 146
d62a17ae 147 if (!adj)
148 return;
f390d2c7 149
50478845 150 thread_cancel(&adj->t_expire);
690497fb 151 if (adj->adj_state != ISIS_ADJ_DOWN)
a5b5e946 152 adj->adj_state = ISIS_ADJ_DOWN;
3f045a08 153
690497fb
G
154 hook_call(isis_adj_state_change_hook, adj);
155
0a22ddfb
QY
156 XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses);
157 XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses);
158 XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses);
3f045a08 159
d62a17ae 160 adj_mt_finish(adj);
26f6acaf 161 list_delete(&adj->adj_sids);
d8fba7d9 162
75eddbc3 163 listnode_delete(adj->circuit->area->adjacency_list, adj);
d62a17ae 164 XFREE(MTYPE_ISIS_ADJACENCY, adj);
165 return;
eb5d44eb 166}
167
d62a17ae 168static const char *adj_state2string(int state)
3f045a08
JB
169{
170
d62a17ae 171 switch (state) {
172 case ISIS_ADJ_INITIALIZING:
173 return "Initializing";
174 case ISIS_ADJ_UP:
175 return "Up";
176 case ISIS_ADJ_DOWN:
177 return "Down";
178 default:
179 return "Unknown";
180 }
181
182 return NULL; /* not reached */
3f045a08
JB
183}
184
7145d5bb
EDP
185static const char *adj_level2string(int level)
186{
187 switch (level) {
188 case IS_LEVEL_1:
189 return "level-1";
190 case IS_LEVEL_2:
191 return "level-2";
192 case IS_LEVEL_1_AND_2:
193 return "level-1-2";
194 default:
195 return "unknown";
196 }
197
198 return NULL; /* not reached */
199}
200
42fe2621
CF
201void isis_adj_process_threeway(struct isis_adjacency *adj,
202 struct isis_threeway_adj *tw_adj,
203 enum isis_adj_usage adj_usage)
204{
205 enum isis_threeway_state next_tw_state = ISIS_THREEWAY_DOWN;
206
58e5d748 207 if (tw_adj && !adj->circuit->disable_threeway_adj) {
42fe2621
CF
208 if (tw_adj->state == ISIS_THREEWAY_DOWN) {
209 next_tw_state = ISIS_THREEWAY_INITIALIZING;
210 } else if (tw_adj->state == ISIS_THREEWAY_INITIALIZING) {
211 next_tw_state = ISIS_THREEWAY_UP;
212 } else if (tw_adj->state == ISIS_THREEWAY_UP) {
213 if (adj->threeway_state == ISIS_THREEWAY_DOWN)
214 next_tw_state = ISIS_THREEWAY_DOWN;
215 else
216 next_tw_state = ISIS_THREEWAY_UP;
217 }
218 } else {
219 next_tw_state = ISIS_THREEWAY_UP;
220 }
221
222 if (next_tw_state != adj->threeway_state) {
e740f9c1 223 if (IS_DEBUG_ADJ_PACKETS) {
42fe2621
CF
224 zlog_info("ISIS-Adj (%s): Threeway state change %s to %s",
225 adj->circuit->area->area_tag,
226 isis_threeway_state_name(adj->threeway_state),
227 isis_threeway_state_name(next_tw_state));
228 }
229 }
230
8e6fb83b
CF
231 if (next_tw_state != ISIS_THREEWAY_DOWN)
232 fabricd_initial_sync_hello(adj->circuit);
233
42fe2621 234 if (next_tw_state == ISIS_THREEWAY_DOWN) {
16167b31
DS
235 isis_adj_state_change(&adj, ISIS_ADJ_DOWN,
236 "Neighbor restarted");
42fe2621
CF
237 return;
238 }
239
240 if (next_tw_state == ISIS_THREEWAY_UP) {
241 if (adj->adj_state != ISIS_ADJ_UP) {
16167b31 242 isis_adj_state_change(&adj, ISIS_ADJ_UP, NULL);
42fe2621
CF
243 adj->adj_usage = adj_usage;
244 }
245 }
246
5346acec
CF
247 if (adj->threeway_state != next_tw_state) {
248 send_hello_sched(adj->circuit, 0, TRIGGERED_IIH_DELAY);
249 }
250
42fe2621
CF
251 adj->threeway_state = next_tw_state;
252}
7145d5bb
EDP
253void isis_log_adj_change(struct isis_adjacency *adj,
254 enum isis_adj_state old_state,
255 enum isis_adj_state new_state, const char *reason)
256{
257 const char *adj_name;
258 struct isis_dynhn *dyn;
259
260 dyn = dynhn_find_by_id(adj->sysid);
261 if (dyn)
262 adj_name = dyn->hostname;
263 else
264 adj_name = sysid_print(adj->sysid);
265
266 zlog_info(
267 "%%ADJCHANGE: Adjacency to %s (%s) for %s changed from %s to %s, %s",
268 adj_name, adj->circuit->interface->name,
269 adj_level2string(adj->level), adj_state2string(old_state),
270 adj_state2string(new_state), reason ? reason : "unspecified");
271}
16167b31 272void isis_adj_state_change(struct isis_adjacency **padj,
d62a17ae 273 enum isis_adj_state new_state, const char *reason)
eb5d44eb 274{
16167b31 275 struct isis_adjacency *adj = *padj;
5346acec
CF
276 enum isis_adj_state old_state = adj->adj_state;
277 struct isis_circuit *circuit = adj->circuit;
16167b31 278 bool del = false;
d62a17ae 279
8cea0065
EDP
280 if (new_state == old_state)
281 return;
282
d62a17ae 283 adj->adj_state = new_state;
8cea0065 284 send_hello_sched(circuit, adj->level, TRIGGERED_IIH_DELAY);
d62a17ae 285
e740f9c1 286 if (IS_DEBUG_ADJ_PACKETS) {
d62a17ae 287 zlog_debug("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
288 circuit->area->area_tag, old_state, new_state,
289 reason ? reason : "unspecified");
290 }
291
7145d5bb
EDP
292 if (circuit->area->log_adj_changes)
293 isis_log_adj_change(adj, old_state, new_state, reason);
d62a17ae 294
c32496ee 295 circuit->adj_state_changes++;
de983bb8
EDP
296#ifndef FABRICD
297 /* send northbound notification */
298 isis_notif_adj_state_change(adj, new_state, reason);
299#endif /* ifndef FABRICD */
300
d62a17ae 301 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
5346acec 302 for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
d62a17ae 303 if ((adj->level & level) == 0)
304 continue;
305 if (new_state == ISIS_ADJ_UP) {
306 circuit->upadjcount[level - 1]++;
d62a17ae 307 /* update counter & timers for debugging
308 * purposes */
309 adj->last_flap = time(NULL);
310 adj->flaps++;
8cea0065 311 } else if (old_state == ISIS_ADJ_UP) {
d62a17ae 312 listnode_delete(circuit->u.bc.adjdb[level - 1],
313 adj);
58e16237 314
d62a17ae 315 circuit->upadjcount[level - 1]--;
58e16237 316 if (circuit->upadjcount[level - 1] == 0)
9b39405f 317 isis_tx_queue_clean(circuit->tx_queue);
58e16237 318
8cea0065
EDP
319 if (new_state == ISIS_ADJ_DOWN)
320 del = true;
d62a17ae 321 }
322
323 if (circuit->u.bc.lan_neighs[level - 1]) {
324 list_delete_all_node(
325 circuit->u.bc.lan_neighs[level - 1]);
326 isis_adj_build_neigh_list(
327 circuit->u.bc.adjdb[level - 1],
328 circuit->u.bc.lan_neighs[level - 1]);
329 }
330
331 /* On adjacency state change send new pseudo LSP if we
332 * are the DR */
333 if (circuit->u.bc.is_dr[level - 1])
334 lsp_regenerate_schedule_pseudo(circuit, level);
335 }
336
d62a17ae 337 } else if (circuit->circ_type == CIRCUIT_T_P2P) {
5346acec 338 for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
d62a17ae 339 if ((adj->level & level) == 0)
340 continue;
341 if (new_state == ISIS_ADJ_UP) {
342 circuit->upadjcount[level - 1]++;
d62a17ae 343
d62a17ae 344 /* update counter & timers for debugging
345 * purposes */
346 adj->last_flap = time(NULL);
347 adj->flaps++;
348
8e6fb83b
CF
349 if (level == IS_LEVEL_1) {
350 thread_add_timer(master, send_l1_csnp,
351 circuit, 0,
352 &circuit->t_send_csnp[0]);
353 } else {
354 thread_add_timer(master, send_l2_csnp,
355 circuit, 0,
356 &circuit->t_send_csnp[1]);
357 }
8cea0065 358 } else if (old_state == ISIS_ADJ_UP) {
d62a17ae 359 if (adj->circuit->u.p2p.neighbor == adj)
360 adj->circuit->u.p2p.neighbor = NULL;
361 circuit->upadjcount[level - 1]--;
58e16237 362 if (circuit->upadjcount[level - 1] == 0)
9b39405f 363 isis_tx_queue_clean(circuit->tx_queue);
58e16237 364
8cea0065
EDP
365 if (new_state == ISIS_ADJ_DOWN)
366 del = true;
d62a17ae 367 }
368 }
16167b31 369 }
d62a17ae 370
e4229afd
EDP
371 hook_call(isis_adj_state_change_hook, adj);
372
16167b31
DS
373 if (del) {
374 isis_delete_adj(adj);
375 *padj = NULL;
d62a17ae 376 }
eb5d44eb 377}
378
379
d62a17ae 380void isis_adj_print(struct isis_adjacency *adj)
eb5d44eb 381{
d62a17ae 382 struct isis_dynhn *dyn;
d62a17ae 383
384 if (!adj)
385 return;
386 dyn = dynhn_find_by_id(adj->sysid);
387 if (dyn)
af8ac8f9 388 zlog_debug("%s", dyn->hostname);
d62a17ae 389
63efca0e 390 zlog_debug("SystemId %20s SNPA %s, level %d; Holding Time %d",
d62a17ae 391 sysid_print(adj->sysid), snpa_print(adj->snpa), adj->level,
392 adj->hold_time);
0c1bd758 393 if (adj->ipv4_address_count) {
d62a17ae 394 zlog_debug("IPv4 Address(es):");
0c1bd758 395 for (unsigned int i = 0; i < adj->ipv4_address_count; i++)
a854ea43 396 zlog_debug("%pI4", &adj->ipv4_addresses[i]);
d62a17ae 397 }
398
0c1bd758 399 if (adj->ipv6_address_count) {
d62a17ae 400 zlog_debug("IPv6 Address(es):");
0c1bd758
CF
401 for (unsigned int i = 0; i < adj->ipv6_address_count; i++) {
402 char buf[INET6_ADDRSTRLEN];
403 inet_ntop(AF_INET6, &adj->ipv6_addresses[i], buf,
404 sizeof(buf));
405 zlog_debug("%s", buf);
d62a17ae 406 }
f390d2c7 407 }
d62a17ae 408 zlog_debug("Speaks: %s", nlpid2string(&adj->nlpids));
eb5d44eb 409
d62a17ae 410 return;
eb5d44eb 411}
412
2a1c520e
RW
413const char *isis_adj_yang_state(enum isis_adj_state state)
414{
415 switch (state) {
416 case ISIS_ADJ_DOWN:
417 return "down";
418 case ISIS_ADJ_UP:
419 return "up";
420 case ISIS_ADJ_INITIALIZING:
421 return "init";
422 default:
423 return "failed";
424 }
425}
426
d62a17ae 427int isis_adj_expire(struct thread *thread)
eb5d44eb 428{
d62a17ae 429 struct isis_adjacency *adj;
eb5d44eb 430
d62a17ae 431 /*
432 * Get the adjacency
433 */
434 adj = THREAD_ARG(thread);
435 assert(adj);
436 adj->t_expire = NULL;
eb5d44eb 437
d62a17ae 438 /* trigger the adj expire event */
16167b31 439 isis_adj_state_change(&adj, ISIS_ADJ_DOWN, "holding time expired");
eb5d44eb 440
d62a17ae 441 return 0;
eb5d44eb 442}
443
eb5d44eb 444/*
3f045a08 445 * show isis neighbor [detail]
eb5d44eb 446 */
d62a17ae 447void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
448 char detail)
eb5d44eb 449{
d62a17ae 450 time_t now;
451 struct isis_dynhn *dyn;
452 int level;
d62a17ae 453
454 dyn = dynhn_find_by_id(adj->sysid);
455 if (dyn)
af8ac8f9 456 vty_out(vty, " %-20s", dyn->hostname);
d62a17ae 457 else
458 vty_out(vty, " %-20s", sysid_print(adj->sysid));
459
460 if (detail == ISIS_UI_LEVEL_BRIEF) {
461 if (adj->circuit)
462 vty_out(vty, "%-12s", adj->circuit->interface->name);
463 else
464 vty_out(vty, "NULL circuit!");
465 vty_out(vty, "%-3u", adj->level); /* level */
466 vty_out(vty, "%-13s", adj_state2string(adj->adj_state));
467 now = time(NULL);
3cbe31c7
EDP
468 if (adj->last_upd) {
469 if (adj->last_upd + adj->hold_time
470 < (unsigned long long)now)
471 vty_out(vty, " Expiring");
472 else
473 vty_out(vty, " %-9llu",
474 (unsigned long long)adj->last_upd
475 + adj->hold_time - now);
476 } else
d62a17ae 477 vty_out(vty, "- ");
478 vty_out(vty, "%-10s", snpa_print(adj->snpa));
479 vty_out(vty, "\n");
f390d2c7 480 }
d62a17ae 481
482 if (detail == ISIS_UI_LEVEL_DETAIL) {
26f6acaf
RW
483 struct sr_adjacency *sra;
484 struct listnode *anode;
485
d62a17ae 486 level = adj->level;
487 vty_out(vty, "\n");
488 if (adj->circuit)
489 vty_out(vty, " Interface: %s",
490 adj->circuit->interface->name);
491 else
492 vty_out(vty, " Interface: NULL circuit");
493 vty_out(vty, ", Level: %u", adj->level); /* level */
494 vty_out(vty, ", State: %s", adj_state2string(adj->adj_state));
495 now = time(NULL);
3cbe31c7
EDP
496 if (adj->last_upd) {
497 if (adj->last_upd + adj->hold_time
498 < (unsigned long long)now)
499 vty_out(vty, " Expiring");
500 else
501 vty_out(vty, ", Expires in %s",
502 time2string(adj->last_upd
503 + adj->hold_time - now));
504 } else
d62a17ae 505 vty_out(vty, ", Expires in %s",
506 time2string(adj->hold_time));
507 vty_out(vty, "\n");
508 vty_out(vty, " Adjacency flaps: %u", adj->flaps);
509 vty_out(vty, ", Last: %s ago",
510 time2string(now - adj->last_flap));
511 vty_out(vty, "\n");
512 vty_out(vty, " Circuit type: %s",
513 circuit_t2string(adj->circuit_t));
514 vty_out(vty, ", Speaks: %s", nlpid2string(&adj->nlpids));
515 vty_out(vty, "\n");
516 if (adj->mt_count != 1
517 || adj->mt_set[0] != ISIS_MT_IPV4_UNICAST) {
518 vty_out(vty, " Topologies:\n");
519 for (unsigned int i = 0; i < adj->mt_count; i++)
520 vty_out(vty, " %s\n",
521 isis_mtid2str(adj->mt_set[i]));
522 }
523 vty_out(vty, " SNPA: %s", snpa_print(adj->snpa));
524 if (adj->circuit
525 && (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) {
526 dyn = dynhn_find_by_id(adj->lanid);
527 if (dyn)
af8ac8f9 528 vty_out(vty, ", LAN id: %s.%02x", dyn->hostname,
d62a17ae 529 adj->lanid[ISIS_SYS_ID_LEN]);
530 else
531 vty_out(vty, ", LAN id: %s.%02x",
532 sysid_print(adj->lanid),
533 adj->lanid[ISIS_SYS_ID_LEN]);
534
535 vty_out(vty, "\n");
536 vty_out(vty, " LAN Priority: %u",
537 adj->prio[adj->level - 1]);
538
539 vty_out(vty, ", %s, DIS flaps: %u, Last: %s ago",
540 isis_disflag2string(
541 adj->dis_record[ISIS_LEVELS + level - 1]
542 .dis),
543 adj->dischanges[level - 1],
9d303b37
DL
544 time2string(now - (adj->dis_record[ISIS_LEVELS
545 + level - 1]
546 .last_dis_change)));
d62a17ae 547 }
548 vty_out(vty, "\n");
549
0c1bd758 550 if (adj->area_address_count) {
d62a17ae 551 vty_out(vty, " Area Address(es):\n");
0c1bd758
CF
552 for (unsigned int i = 0; i < adj->area_address_count;
553 i++) {
d62a17ae 554 vty_out(vty, " %s\n",
996c9314
LB
555 isonet_print(adj->area_addresses[i]
556 .area_addr,
557 adj->area_addresses[i]
558 .addr_len));
0c1bd758 559 }
d62a17ae 560 }
0c1bd758 561 if (adj->ipv4_address_count) {
d62a17ae 562 vty_out(vty, " IPv4 Address(es):\n");
0c1bd758
CF
563 for (unsigned int i = 0; i < adj->ipv4_address_count;
564 i++)
a854ea43
MS
565 vty_out(vty, " %pI4\n",
566 &adj->ipv4_addresses[i]);
d62a17ae 567 }
0c1bd758 568 if (adj->ipv6_address_count) {
d62a17ae 569 vty_out(vty, " IPv6 Address(es):\n");
0c1bd758
CF
570 for (unsigned int i = 0; i < adj->ipv6_address_count;
571 i++) {
572 char buf[INET6_ADDRSTRLEN];
573 inet_ntop(AF_INET6, &adj->ipv6_addresses[i],
574 buf, sizeof(buf));
575 vty_out(vty, " %s\n", buf);
d62a17ae 576 }
577 }
26f6acaf
RW
578 for (ALL_LIST_ELEMENTS_RO(adj->adj_sids, anode, sra)) {
579 const char *adj_type;
580 const char *backup;
581 uint32_t sid;
582
583 switch (sra->adj->circuit->circ_type) {
584 case CIRCUIT_T_BROADCAST:
585 adj_type = "LAN Adjacency-SID";
586 sid = sra->u.ladj_sid->sid;
587 break;
588 case CIRCUIT_T_P2P:
589 adj_type = "Adjacency-SID";
590 sid = sra->u.adj_sid->sid;
591 break;
592 default:
593 continue;
594 }
595 backup = (sra->type == ISIS_SR_LAN_BACKUP) ? " (backup)"
596 : "";
597
598 vty_out(vty, " %s %s%s: %u\n",
599 (sra->nexthop.family == AF_INET) ? "IPv4"
600 : "IPv6",
601 adj_type, backup, sid);
602 }
d62a17ae 603 vty_out(vty, "\n");
f390d2c7 604 }
d62a17ae 605 return;
eb5d44eb 606}
607
d62a17ae 608void isis_adj_build_neigh_list(struct list *adjdb, struct list *list)
eb5d44eb 609{
d62a17ae 610 struct isis_adjacency *adj;
611 struct listnode *node;
612
613 if (!list) {
614 zlog_warn("isis_adj_build_neigh_list(): NULL list");
615 return;
f390d2c7 616 }
617
d62a17ae 618 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) {
619 if (!adj) {
620 zlog_warn("isis_adj_build_neigh_list(): NULL adj");
621 return;
622 }
623
624 if ((adj->adj_state == ISIS_ADJ_UP
625 || adj->adj_state == ISIS_ADJ_INITIALIZING))
626 listnode_add(list, adj->snpa);
627 }
628 return;
eb5d44eb 629}
630
d62a17ae 631void isis_adj_build_up_list(struct list *adjdb, struct list *list)
eb5d44eb 632{
d62a17ae 633 struct isis_adjacency *adj;
634 struct listnode *node;
635
636 if (adjdb == NULL) {
637 zlog_warn("isis_adj_build_up_list(): adjacency DB is empty");
638 return;
639 }
640
641 if (!list) {
642 zlog_warn("isis_adj_build_up_list(): NULL list");
643 return;
f390d2c7 644 }
645
d62a17ae 646 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) {
647 if (!adj) {
648 zlog_warn("isis_adj_build_up_list(): NULL adj");
649 return;
650 }
f390d2c7 651
d62a17ae 652 if (adj->adj_state == ISIS_ADJ_UP)
653 listnode_add(list, adj);
654 }
655
656 return;
eb5d44eb 657}
d8fba7d9 658
d62a17ae 659int isis_adj_usage2levels(enum isis_adj_usage usage)
d8fba7d9 660{
d62a17ae 661 switch (usage) {
662 case ISIS_ADJ_LEVEL1:
663 return IS_LEVEL_1;
664 case ISIS_ADJ_LEVEL2:
665 return IS_LEVEL_2;
666 case ISIS_ADJ_LEVEL1AND2:
667 return IS_LEVEL_1 | IS_LEVEL_2;
668 default:
669 break;
670 }
671 return 0;
d8fba7d9 672}