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