]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_adjacency.c
isisd: Prevent direct copy of different size prefix'es
[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"
ae59cfd7 34#include "bfd.h"
eb5d44eb 35
eb5d44eb 36#include "isisd/isis_constants.h"
37#include "isisd/isis_common.h"
3f045a08 38#include "isisd/isis_flags.h"
eb5d44eb 39#include "isisd/isisd.h"
40#include "isisd/isis_circuit.h"
41#include "isisd/isis_adjacency.h"
42#include "isisd/isis_misc.h"
43#include "isisd/isis_dr.h"
44#include "isisd/isis_dynhn.h"
45#include "isisd/isis_pdu.h"
3f045a08 46#include "isisd/isis_lsp.h"
3f045a08 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
66b9a381
DL
53DEFINE_MTYPE_STATIC(ISISD, ISIS_ADJACENCY, "ISIS adjacency");
54DEFINE_MTYPE(ISISD, ISIS_ADJACENCY_INFO, "ISIS adjacency info");
55
1ee746d9 56static struct isis_adjacency *adj_alloc(struct isis_circuit *circuit,
57 const uint8_t *id)
eb5d44eb 58{
d62a17ae 59 struct isis_adjacency *adj;
eb5d44eb 60
d62a17ae 61 adj = XCALLOC(MTYPE_ISIS_ADJACENCY, sizeof(struct isis_adjacency));
62 memcpy(adj->sysid, id, ISIS_SYS_ID_LEN);
f390d2c7 63
1ee746d9 64 adj->snmp_idx = ++circuit->snmp_adj_idx_gen;
65
66 if (circuit->snmp_adj_list == NULL)
67 circuit->snmp_adj_list = list_new();
68
69 adj->snmp_list_node = listnode_add(circuit->snmp_adj_list, adj);
70
d62a17ae 71 return adj;
eb5d44eb 72}
73
d7c0a89a 74struct isis_adjacency *isis_new_adj(const uint8_t *id, const uint8_t *snpa,
d62a17ae 75 int level, struct isis_circuit *circuit)
eb5d44eb 76{
d62a17ae 77 struct isis_adjacency *adj;
78 int i;
79
1ee746d9 80 adj = adj_alloc(circuit, id); /* P2P kludge */
d62a17ae 81
d62a17ae 82 if (snpa) {
83 memcpy(adj->snpa, snpa, ETH_ALEN);
84 } else {
85 memset(adj->snpa, ' ', ETH_ALEN);
eb5d44eb 86 }
eb5d44eb 87
d62a17ae 88 adj->circuit = circuit;
89 adj->level = level;
90 adj->flaps = 0;
91 adj->last_flap = time(NULL);
42fe2621 92 adj->threeway_state = ISIS_THREEWAY_DOWN;
d62a17ae 93 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
94 listnode_add(circuit->u.bc.adjdb[level - 1], adj);
95 adj->dischanges[level - 1] = 0;
96 for (i = 0; i < DIS_RECORDS;
97 i++) /* clear N DIS state change records */
98 {
99 adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis =
100 ISIS_UNKNOWN_DIS;
101 adj->dis_record[(i * ISIS_LEVELS) + level - 1]
102 .last_dis_change = time(NULL);
103 }
104 }
26f6acaf 105 adj->adj_sids = list_new();
75eddbc3 106 listnode_add(circuit->area->adjacency_list, adj);
d62a17ae 107
108 return adj;
eb5d44eb 109}
110
d7c0a89a 111struct isis_adjacency *isis_adj_lookup(const uint8_t *sysid, struct list *adjdb)
eb5d44eb 112{
d62a17ae 113 struct isis_adjacency *adj;
114 struct listnode *node;
eb5d44eb 115
d62a17ae 116 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj))
117 if (memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN) == 0)
118 return adj;
f390d2c7 119
d62a17ae 120 return NULL;
eb5d44eb 121}
122
d7c0a89a 123struct isis_adjacency *isis_adj_lookup_snpa(const uint8_t *ssnpa,
d62a17ae 124 struct list *adjdb)
eb5d44eb 125{
d62a17ae 126 struct listnode *node;
127 struct isis_adjacency *adj;
eb5d44eb 128
d62a17ae 129 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj))
130 if (memcmp(adj->snpa, ssnpa, ETH_ALEN) == 0)
131 return adj;
f390d2c7 132
d62a17ae 133 return NULL;
eb5d44eb 134}
135
75eddbc3
RW
136struct isis_adjacency *isis_adj_find(const struct isis_area *area, int level,
137 const uint8_t *sysid)
26f6acaf 138{
75eddbc3 139 struct isis_adjacency *adj;
26f6acaf
RW
140 struct listnode *node;
141
75eddbc3
RW
142 for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) {
143 if (!(adj->level & level))
144 continue;
145
146 if (!memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN))
147 return adj;
26f6acaf
RW
148 }
149
75eddbc3 150 return NULL;
26f6acaf
RW
151}
152
8451921b 153DEFINE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj));
a5b5e946 154
d62a17ae 155void isis_delete_adj(void *arg)
eb5d44eb 156{
d62a17ae 157 struct isis_adjacency *adj = arg;
3f045a08 158
d62a17ae 159 if (!adj)
160 return;
1ee746d9 161 /* Remove self from snmp list without walking the list*/
162 list_delete_node(adj->circuit->snmp_adj_list, adj->snmp_list_node);
f390d2c7 163
50478845 164 thread_cancel(&adj->t_expire);
690497fb 165 if (adj->adj_state != ISIS_ADJ_DOWN)
a5b5e946 166 adj->adj_state = ISIS_ADJ_DOWN;
3f045a08 167
690497fb
G
168 hook_call(isis_adj_state_change_hook, adj);
169
0a22ddfb
QY
170 XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses);
171 XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses);
173f8887 172 XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ll_ipv6_addrs);
3f045a08 173
d62a17ae 174 adj_mt_finish(adj);
26f6acaf 175 list_delete(&adj->adj_sids);
d8fba7d9 176
75eddbc3 177 listnode_delete(adj->circuit->area->adjacency_list, adj);
d62a17ae 178 XFREE(MTYPE_ISIS_ADJACENCY, adj);
179 return;
eb5d44eb 180}
181
d62a17ae 182static const char *adj_state2string(int state)
3f045a08
JB
183{
184
d62a17ae 185 switch (state) {
186 case ISIS_ADJ_INITIALIZING:
187 return "Initializing";
188 case ISIS_ADJ_UP:
189 return "Up";
190 case ISIS_ADJ_DOWN:
191 return "Down";
192 default:
193 return "Unknown";
194 }
195
196 return NULL; /* not reached */
3f045a08
JB
197}
198
7145d5bb
EDP
199static const char *adj_level2string(int level)
200{
201 switch (level) {
202 case IS_LEVEL_1:
203 return "level-1";
204 case IS_LEVEL_2:
205 return "level-2";
206 case IS_LEVEL_1_AND_2:
207 return "level-1-2";
208 default:
209 return "unknown";
210 }
211
212 return NULL; /* not reached */
213}
214
42fe2621
CF
215void isis_adj_process_threeway(struct isis_adjacency *adj,
216 struct isis_threeway_adj *tw_adj,
217 enum isis_adj_usage adj_usage)
218{
219 enum isis_threeway_state next_tw_state = ISIS_THREEWAY_DOWN;
220
58e5d748 221 if (tw_adj && !adj->circuit->disable_threeway_adj) {
42fe2621
CF
222 if (tw_adj->state == ISIS_THREEWAY_DOWN) {
223 next_tw_state = ISIS_THREEWAY_INITIALIZING;
224 } else if (tw_adj->state == ISIS_THREEWAY_INITIALIZING) {
225 next_tw_state = ISIS_THREEWAY_UP;
226 } else if (tw_adj->state == ISIS_THREEWAY_UP) {
227 if (adj->threeway_state == ISIS_THREEWAY_DOWN)
228 next_tw_state = ISIS_THREEWAY_DOWN;
229 else
230 next_tw_state = ISIS_THREEWAY_UP;
231 }
232 } else {
233 next_tw_state = ISIS_THREEWAY_UP;
234 }
235
236 if (next_tw_state != adj->threeway_state) {
e740f9c1 237 if (IS_DEBUG_ADJ_PACKETS) {
42fe2621
CF
238 zlog_info("ISIS-Adj (%s): Threeway state change %s to %s",
239 adj->circuit->area->area_tag,
240 isis_threeway_state_name(adj->threeway_state),
241 isis_threeway_state_name(next_tw_state));
242 }
243 }
244
8e6fb83b
CF
245 if (next_tw_state != ISIS_THREEWAY_DOWN)
246 fabricd_initial_sync_hello(adj->circuit);
247
42fe2621 248 if (next_tw_state == ISIS_THREEWAY_DOWN) {
16167b31
DS
249 isis_adj_state_change(&adj, ISIS_ADJ_DOWN,
250 "Neighbor restarted");
42fe2621
CF
251 return;
252 }
253
254 if (next_tw_state == ISIS_THREEWAY_UP) {
255 if (adj->adj_state != ISIS_ADJ_UP) {
16167b31 256 isis_adj_state_change(&adj, ISIS_ADJ_UP, NULL);
42fe2621
CF
257 adj->adj_usage = adj_usage;
258 }
259 }
260
5346acec
CF
261 if (adj->threeway_state != next_tw_state) {
262 send_hello_sched(adj->circuit, 0, TRIGGERED_IIH_DELAY);
263 }
264
42fe2621
CF
265 adj->threeway_state = next_tw_state;
266}
0d5b1a3a 267const char *isis_adj_name(const struct isis_adjacency *adj)
7145d5bb 268{
0d5b1a3a
EDP
269 if (!adj)
270 return "NONE";
271
7145d5bb
EDP
272 struct isis_dynhn *dyn;
273
240f48b3 274 dyn = dynhn_find_by_id(adj->circuit->isis, adj->sysid);
7145d5bb 275 if (dyn)
0d5b1a3a 276 return dyn->hostname;
7145d5bb 277 else
0d5b1a3a
EDP
278 return sysid_print(adj->sysid);
279}
280void isis_log_adj_change(struct isis_adjacency *adj,
281 enum isis_adj_state old_state,
282 enum isis_adj_state new_state, const char *reason)
283{
7145d5bb
EDP
284 zlog_info(
285 "%%ADJCHANGE: Adjacency to %s (%s) for %s changed from %s to %s, %s",
0d5b1a3a 286 isis_adj_name(adj), adj->circuit->interface->name,
7145d5bb
EDP
287 adj_level2string(adj->level), adj_state2string(old_state),
288 adj_state2string(new_state), reason ? reason : "unspecified");
289}
16167b31 290void isis_adj_state_change(struct isis_adjacency **padj,
d62a17ae 291 enum isis_adj_state new_state, const char *reason)
eb5d44eb 292{
16167b31 293 struct isis_adjacency *adj = *padj;
5346acec
CF
294 enum isis_adj_state old_state = adj->adj_state;
295 struct isis_circuit *circuit = adj->circuit;
16167b31 296 bool del = false;
d62a17ae 297
8cea0065
EDP
298 if (new_state == old_state)
299 return;
300
d62a17ae 301 adj->adj_state = new_state;
8cea0065 302 send_hello_sched(circuit, adj->level, TRIGGERED_IIH_DELAY);
d62a17ae 303
e740f9c1 304 if (IS_DEBUG_ADJ_PACKETS) {
d62a17ae 305 zlog_debug("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
306 circuit->area->area_tag, old_state, new_state,
307 reason ? reason : "unspecified");
308 }
309
7145d5bb
EDP
310 if (circuit->area->log_adj_changes)
311 isis_log_adj_change(adj, old_state, new_state, reason);
d62a17ae 312
de983bb8
EDP
313#ifndef FABRICD
314 /* send northbound notification */
315 isis_notif_adj_state_change(adj, new_state, reason);
316#endif /* ifndef FABRICD */
317
d62a17ae 318 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
5346acec 319 for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
d62a17ae 320 if ((adj->level & level) == 0)
321 continue;
322 if (new_state == ISIS_ADJ_UP) {
1ee746d9 323 circuit->adj_state_changes++;
d62a17ae 324 circuit->upadjcount[level - 1]++;
d62a17ae 325 /* update counter & timers for debugging
326 * purposes */
327 adj->last_flap = time(NULL);
328 adj->flaps++;
8cea0065 329 } else if (old_state == ISIS_ADJ_UP) {
1ee746d9 330 circuit->adj_state_changes++;
58e16237 331
d62a17ae 332 circuit->upadjcount[level - 1]--;
58e16237 333 if (circuit->upadjcount[level - 1] == 0)
9b39405f 334 isis_tx_queue_clean(circuit->tx_queue);
58e16237 335
7209d2a4
IR
336 if (new_state == ISIS_ADJ_DOWN) {
337 listnode_delete(
338 circuit->u.bc.adjdb[level - 1],
339 adj);
340
8cea0065 341 del = true;
7209d2a4 342 }
d62a17ae 343 }
344
345 if (circuit->u.bc.lan_neighs[level - 1]) {
346 list_delete_all_node(
347 circuit->u.bc.lan_neighs[level - 1]);
348 isis_adj_build_neigh_list(
349 circuit->u.bc.adjdb[level - 1],
350 circuit->u.bc.lan_neighs[level - 1]);
351 }
352
353 /* On adjacency state change send new pseudo LSP if we
354 * are the DR */
355 if (circuit->u.bc.is_dr[level - 1])
356 lsp_regenerate_schedule_pseudo(circuit, level);
357 }
358
d62a17ae 359 } else if (circuit->circ_type == CIRCUIT_T_P2P) {
5346acec 360 for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
d62a17ae 361 if ((adj->level & level) == 0)
362 continue;
363 if (new_state == ISIS_ADJ_UP) {
364 circuit->upadjcount[level - 1]++;
d62a17ae 365
d62a17ae 366 /* update counter & timers for debugging
367 * purposes */
368 adj->last_flap = time(NULL);
369 adj->flaps++;
370
8e6fb83b
CF
371 if (level == IS_LEVEL_1) {
372 thread_add_timer(master, send_l1_csnp,
373 circuit, 0,
374 &circuit->t_send_csnp[0]);
375 } else {
376 thread_add_timer(master, send_l2_csnp,
377 circuit, 0,
378 &circuit->t_send_csnp[1]);
379 }
8cea0065 380 } else if (old_state == ISIS_ADJ_UP) {
d62a17ae 381 circuit->upadjcount[level - 1]--;
58e16237 382 if (circuit->upadjcount[level - 1] == 0)
9b39405f 383 isis_tx_queue_clean(circuit->tx_queue);
58e16237 384
7209d2a4
IR
385 if (new_state == ISIS_ADJ_DOWN) {
386 if (adj->circuit->u.p2p.neighbor == adj)
387 adj->circuit->u.p2p.neighbor =
388 NULL;
389
8cea0065 390 del = true;
7209d2a4 391 }
d62a17ae 392 }
393 }
16167b31 394 }
d62a17ae 395
e4229afd
EDP
396 hook_call(isis_adj_state_change_hook, adj);
397
16167b31
DS
398 if (del) {
399 isis_delete_adj(adj);
400 *padj = NULL;
d62a17ae 401 }
eb5d44eb 402}
403
404
d62a17ae 405void isis_adj_print(struct isis_adjacency *adj)
eb5d44eb 406{
d62a17ae 407 struct isis_dynhn *dyn;
d62a17ae 408
409 if (!adj)
410 return;
240f48b3 411 dyn = dynhn_find_by_id(adj->circuit->isis, adj->sysid);
d62a17ae 412 if (dyn)
af8ac8f9 413 zlog_debug("%s", dyn->hostname);
d62a17ae 414
63efca0e 415 zlog_debug("SystemId %20s SNPA %s, level %d; Holding Time %d",
d62a17ae 416 sysid_print(adj->sysid), snpa_print(adj->snpa), adj->level,
417 adj->hold_time);
0c1bd758 418 if (adj->ipv4_address_count) {
d62a17ae 419 zlog_debug("IPv4 Address(es):");
0c1bd758 420 for (unsigned int i = 0; i < adj->ipv4_address_count; i++)
a854ea43 421 zlog_debug("%pI4", &adj->ipv4_addresses[i]);
d62a17ae 422 }
423
173f8887 424 if (adj->ll_ipv6_count) {
d62a17ae 425 zlog_debug("IPv6 Address(es):");
173f8887 426 for (unsigned int i = 0; i < adj->ll_ipv6_count; i++) {
0c1bd758 427 char buf[INET6_ADDRSTRLEN];
173f8887 428 inet_ntop(AF_INET6, &adj->ll_ipv6_addrs[i], buf,
0c1bd758
CF
429 sizeof(buf));
430 zlog_debug("%s", buf);
d62a17ae 431 }
f390d2c7 432 }
d62a17ae 433 zlog_debug("Speaks: %s", nlpid2string(&adj->nlpids));
eb5d44eb 434
d62a17ae 435 return;
eb5d44eb 436}
437
2a1c520e
RW
438const char *isis_adj_yang_state(enum isis_adj_state state)
439{
440 switch (state) {
441 case ISIS_ADJ_DOWN:
442 return "down";
443 case ISIS_ADJ_UP:
444 return "up";
445 case ISIS_ADJ_INITIALIZING:
446 return "init";
447 default:
448 return "failed";
449 }
450}
451
cc9f21da 452void isis_adj_expire(struct thread *thread)
eb5d44eb 453{
d62a17ae 454 struct isis_adjacency *adj;
eb5d44eb 455
d62a17ae 456 /*
457 * Get the adjacency
458 */
459 adj = THREAD_ARG(thread);
460 assert(adj);
461 adj->t_expire = NULL;
eb5d44eb 462
d62a17ae 463 /* trigger the adj expire event */
16167b31 464 isis_adj_state_change(&adj, ISIS_ADJ_DOWN, "holding time expired");
eb5d44eb 465}
466
a21177f2
JG
467/*
468 * show isis neighbor [detail] json
469 */
470void isis_adj_print_json(struct isis_adjacency *adj, struct json_object *json,
471 char detail)
472{
473 json_object *iface_json, *ipv4_addr_json, *ipv6_link_json,
474 *ipv6_non_link_json, *topo_json, *dis_flaps_json,
475 *area_addr_json, *adj_sid_json;
476 time_t now;
477 struct isis_dynhn *dyn;
478 int level;
479 char buf[256];
480
481 json_object_string_add(json, "adj", isis_adj_name(adj));
482
483 if (detail == ISIS_UI_LEVEL_BRIEF) {
484 if (adj->circuit)
485 json_object_string_add(json, "interface",
486 adj->circuit->interface->name);
487 else
488 json_object_string_add(json, "interface",
489 "NULL circuit!");
490 json_object_int_add(json, "level", adj->level);
491 json_object_string_add(json, "state",
492 adj_state2string(adj->adj_state));
493 now = time(NULL);
494 if (adj->last_upd) {
495 if (adj->last_upd + adj->hold_time < now)
496 json_object_string_add(json, "last-upd",
497 "expiring");
498 else
499 json_object_string_add(
500 json, "expires-in",
501 time2string(adj->last_upd +
502 adj->hold_time - now));
503 }
504 json_object_string_add(json, "snpa", snpa_print(adj->snpa));
505 }
506
507 if (detail == ISIS_UI_LEVEL_DETAIL) {
508 struct sr_adjacency *sra;
509 struct listnode *anode;
510
511 level = adj->level;
512 iface_json = json_object_new_object();
513 json_object_object_add(json, "interface", iface_json);
514 if (adj->circuit)
515 json_object_string_add(iface_json, "name",
516 adj->circuit->interface->name);
517 else
518 json_object_string_add(iface_json, "name",
519 "null-circuit");
520 json_object_int_add(json, "level", adj->level);
521 json_object_string_add(iface_json, "state",
522 adj_state2string(adj->adj_state));
523 now = time(NULL);
524 if (adj->last_upd) {
525 if (adj->last_upd + adj->hold_time < now)
526 json_object_string_add(iface_json, "last-upd",
527 "expiring");
528 else
529 json_object_string_add(
530 json, "expires-in",
531 time2string(adj->last_upd +
532 adj->hold_time - now));
533 } else
534 json_object_string_add(json, "expires-in",
535 time2string(adj->hold_time));
536 json_object_int_add(iface_json, "adj-flaps", adj->flaps);
537 json_object_string_add(iface_json, "last-ago",
538 time2string(now - adj->last_flap));
539 json_object_string_add(iface_json, "circuit-type",
540 circuit_t2string(adj->circuit_t));
541 json_object_string_add(iface_json, "speaks",
542 nlpid2string(&adj->nlpids));
543 if (adj->mt_count != 1 ||
544 adj->mt_set[0] != ISIS_MT_IPV4_UNICAST) {
545 topo_json = json_object_new_object();
546 json_object_object_add(iface_json, "topologies",
547 topo_json);
548 for (unsigned int i = 0; i < adj->mt_count; i++) {
549 snprintfrr(buf, sizeof(buf), "topo-%d", i);
550 json_object_string_add(
551 topo_json, buf,
552 isis_mtid2str(adj->mt_set[i]));
553 }
554 }
555 json_object_string_add(iface_json, "snpa",
556 snpa_print(adj->snpa));
557 if (adj->circuit &&
558 (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) {
559 dyn = dynhn_find_by_id(adj->circuit->isis, adj->lanid);
560 if (dyn) {
561 snprintfrr(buf, sizeof(buf), "%s-%02x",
562 dyn->hostname,
563 adj->lanid[ISIS_SYS_ID_LEN]);
564 json_object_string_add(iface_json, "lan-id",
565 buf);
566 } else {
567 snprintfrr(buf, sizeof(buf), "%s-%02x",
568 sysid_print(adj->lanid),
569 adj->lanid[ISIS_SYS_ID_LEN]);
570 json_object_string_add(iface_json, "lan-id",
571 buf);
572 }
573
574 json_object_int_add(iface_json, "lan-prio",
575 adj->prio[adj->level - 1]);
576
577 dis_flaps_json = json_object_new_object();
578 json_object_object_add(iface_json, "dis-flaps",
579 dis_flaps_json);
580 json_object_string_add(
581 dis_flaps_json, "dis-record",
582 isis_disflag2string(
583 adj->dis_record[ISIS_LEVELS + level - 1]
584 .dis));
585 json_object_int_add(dis_flaps_json, "last",
586 adj->dischanges[level - 1]);
587 json_object_string_add(
588 dis_flaps_json, "ago",
589 time2string(now - (adj->dis_record[ISIS_LEVELS +
590 level - 1]
591 .last_dis_change)));
592 }
593
594 if (adj->area_address_count) {
595 area_addr_json = json_object_new_object();
596 json_object_object_add(iface_json, "area-address",
597 area_addr_json);
598 for (unsigned int i = 0; i < adj->area_address_count;
599 i++) {
600 json_object_string_add(
601 area_addr_json, "isonet",
602 isonet_print(adj->area_addresses[i]
603 .area_addr,
604 adj->area_addresses[i]
605 .addr_len));
606 }
607 }
608 if (adj->ipv4_address_count) {
609 ipv4_addr_json = json_object_new_object();
610 json_object_object_add(iface_json, "ipv4-address",
611 ipv4_addr_json);
612 for (unsigned int i = 0; i < adj->ipv4_address_count;
613 i++){
614 inet_ntop(AF_INET, &adj->ipv4_addresses[i], buf,
615 sizeof(buf));
616 json_object_string_add(ipv4_addr_json, "ipv4", buf);
617 }
618 }
619 if (adj->ll_ipv6_count) {
620 ipv6_link_json = json_object_new_object();
621 json_object_object_add(iface_json, "ipv6-link-local",
622 ipv6_link_json);
623 for (unsigned int i = 0; i < adj->ll_ipv6_count; i++) {
624 char buf[INET6_ADDRSTRLEN];
625 inet_ntop(AF_INET6, &adj->ll_ipv6_addrs[i], buf,
626 sizeof(buf));
627 json_object_string_add(ipv6_link_json, "ipv6",
628 buf);
629 }
630 }
631 if (adj->global_ipv6_count) {
632 ipv6_non_link_json = json_object_new_object();
633 json_object_object_add(iface_json, "ipv6-global",
634 ipv6_non_link_json);
635 for (unsigned int i = 0; i < adj->global_ipv6_count;
636 i++) {
637 char buf[INET6_ADDRSTRLEN];
638 inet_ntop(AF_INET6, &adj->global_ipv6_addrs[i],
639 buf, sizeof(buf));
640 json_object_string_add(ipv6_non_link_json,
641 "ipv6", buf);
642 }
643 }
644
645 adj_sid_json = json_object_new_object();
646 json_object_object_add(iface_json, "adj-sid", adj_sid_json);
647 for (ALL_LIST_ELEMENTS_RO(adj->adj_sids, anode, sra)) {
648 const char *adj_type;
649 const char *backup;
650 uint32_t sid;
651
652 switch (sra->adj->circuit->circ_type) {
653 case CIRCUIT_T_BROADCAST:
654 adj_type = "LAN Adjacency-SID";
655 sid = sra->u.ladj_sid->sid;
656 break;
657 case CIRCUIT_T_P2P:
658 adj_type = "Adjacency-SID";
659 sid = sra->u.adj_sid->sid;
660 break;
661 default:
662 continue;
663 }
664 backup = (sra->type == ISIS_SR_LAN_BACKUP) ? " (backup)"
665 : "";
666
667 json_object_string_add(adj_sid_json, "nexthop",
668 (sra->nexthop.family == AF_INET)
669 ? "IPv4"
670 : "IPv6");
671 json_object_string_add(adj_sid_json, "adj-type",
672 adj_type);
673 json_object_string_add(adj_sid_json, "is-backup",
674 backup);
675 json_object_int_add(adj_sid_json, "sid", sid);
676 }
677 }
678 return;
679}
680
eb5d44eb 681/*
3f045a08 682 * show isis neighbor [detail]
eb5d44eb 683 */
d62a17ae 684void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
685 char detail)
eb5d44eb 686{
d62a17ae 687 time_t now;
688 struct isis_dynhn *dyn;
689 int level;
d62a17ae 690
0d5b1a3a 691 vty_out(vty, " %-20s", isis_adj_name(adj));
d62a17ae 692
693 if (detail == ISIS_UI_LEVEL_BRIEF) {
694 if (adj->circuit)
695 vty_out(vty, "%-12s", adj->circuit->interface->name);
696 else
697 vty_out(vty, "NULL circuit!");
698 vty_out(vty, "%-3u", adj->level); /* level */
699 vty_out(vty, "%-13s", adj_state2string(adj->adj_state));
700 now = time(NULL);
3cbe31c7 701 if (adj->last_upd) {
ac716cdf 702 if (adj->last_upd + adj->hold_time < now)
3cbe31c7
EDP
703 vty_out(vty, " Expiring");
704 else
705 vty_out(vty, " %-9llu",
706 (unsigned long long)adj->last_upd
707 + adj->hold_time - now);
708 } else
d62a17ae 709 vty_out(vty, "- ");
710 vty_out(vty, "%-10s", snpa_print(adj->snpa));
711 vty_out(vty, "\n");
f390d2c7 712 }
d62a17ae 713
714 if (detail == ISIS_UI_LEVEL_DETAIL) {
26f6acaf
RW
715 struct sr_adjacency *sra;
716 struct listnode *anode;
717
d62a17ae 718 level = adj->level;
719 vty_out(vty, "\n");
720 if (adj->circuit)
721 vty_out(vty, " Interface: %s",
722 adj->circuit->interface->name);
723 else
724 vty_out(vty, " Interface: NULL circuit");
725 vty_out(vty, ", Level: %u", adj->level); /* level */
726 vty_out(vty, ", State: %s", adj_state2string(adj->adj_state));
727 now = time(NULL);
3cbe31c7 728 if (adj->last_upd) {
ac716cdf 729 if (adj->last_upd + adj->hold_time < now)
3cbe31c7
EDP
730 vty_out(vty, " Expiring");
731 else
732 vty_out(vty, ", Expires in %s",
733 time2string(adj->last_upd
734 + adj->hold_time - now));
735 } else
d62a17ae 736 vty_out(vty, ", Expires in %s",
737 time2string(adj->hold_time));
738 vty_out(vty, "\n");
739 vty_out(vty, " Adjacency flaps: %u", adj->flaps);
740 vty_out(vty, ", Last: %s ago",
741 time2string(now - adj->last_flap));
742 vty_out(vty, "\n");
743 vty_out(vty, " Circuit type: %s",
744 circuit_t2string(adj->circuit_t));
745 vty_out(vty, ", Speaks: %s", nlpid2string(&adj->nlpids));
746 vty_out(vty, "\n");
747 if (adj->mt_count != 1
748 || adj->mt_set[0] != ISIS_MT_IPV4_UNICAST) {
749 vty_out(vty, " Topologies:\n");
750 for (unsigned int i = 0; i < adj->mt_count; i++)
751 vty_out(vty, " %s\n",
752 isis_mtid2str(adj->mt_set[i]));
753 }
754 vty_out(vty, " SNPA: %s", snpa_print(adj->snpa));
755 if (adj->circuit
756 && (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) {
240f48b3 757 dyn = dynhn_find_by_id(adj->circuit->isis, adj->lanid);
d62a17ae 758 if (dyn)
af8ac8f9 759 vty_out(vty, ", LAN id: %s.%02x", dyn->hostname,
d62a17ae 760 adj->lanid[ISIS_SYS_ID_LEN]);
761 else
762 vty_out(vty, ", LAN id: %s.%02x",
763 sysid_print(adj->lanid),
764 adj->lanid[ISIS_SYS_ID_LEN]);
765
766 vty_out(vty, "\n");
767 vty_out(vty, " LAN Priority: %u",
768 adj->prio[adj->level - 1]);
769
770 vty_out(vty, ", %s, DIS flaps: %u, Last: %s ago",
771 isis_disflag2string(
772 adj->dis_record[ISIS_LEVELS + level - 1]
773 .dis),
774 adj->dischanges[level - 1],
9d303b37
DL
775 time2string(now - (adj->dis_record[ISIS_LEVELS
776 + level - 1]
777 .last_dis_change)));
d62a17ae 778 }
779 vty_out(vty, "\n");
780
0c1bd758 781 if (adj->area_address_count) {
d62a17ae 782 vty_out(vty, " Area Address(es):\n");
0c1bd758
CF
783 for (unsigned int i = 0; i < adj->area_address_count;
784 i++) {
d62a17ae 785 vty_out(vty, " %s\n",
996c9314
LB
786 isonet_print(adj->area_addresses[i]
787 .area_addr,
788 adj->area_addresses[i]
789 .addr_len));
0c1bd758 790 }
d62a17ae 791 }
0c1bd758 792 if (adj->ipv4_address_count) {
d62a17ae 793 vty_out(vty, " IPv4 Address(es):\n");
0c1bd758
CF
794 for (unsigned int i = 0; i < adj->ipv4_address_count;
795 i++)
a854ea43
MS
796 vty_out(vty, " %pI4\n",
797 &adj->ipv4_addresses[i]);
d62a17ae 798 }
173f8887 799 if (adj->ll_ipv6_count) {
d62a17ae 800 vty_out(vty, " IPv6 Address(es):\n");
173f8887
OD
801 for (unsigned int i = 0; i < adj->ll_ipv6_count; i++) {
802 char buf[INET6_ADDRSTRLEN];
803 inet_ntop(AF_INET6, &adj->ll_ipv6_addrs[i],
804 buf, sizeof(buf));
805 vty_out(vty, " %s\n", buf);
806 }
807 }
808 if (adj->global_ipv6_count) {
809 vty_out(vty, " Global IPv6 Address(es):\n");
810 for (unsigned int i = 0; i < adj->global_ipv6_count;
0c1bd758
CF
811 i++) {
812 char buf[INET6_ADDRSTRLEN];
173f8887 813 inet_ntop(AF_INET6, &adj->global_ipv6_addrs[i],
0c1bd758
CF
814 buf, sizeof(buf));
815 vty_out(vty, " %s\n", buf);
d62a17ae 816 }
817 }
ae59cfd7
PG
818 if (adj->circuit && adj->circuit->bfd_config.enabled) {
819 vty_out(vty, " BFD is %s%s\n",
820 adj->bfd_session ? "active, status "
821 : "configured",
822 !adj->bfd_session
823 ? ""
824 : bfd_get_status_str(bfd_sess_status(
825 adj->bfd_session)));
826 }
26f6acaf
RW
827 for (ALL_LIST_ELEMENTS_RO(adj->adj_sids, anode, sra)) {
828 const char *adj_type;
829 const char *backup;
830 uint32_t sid;
831
832 switch (sra->adj->circuit->circ_type) {
833 case CIRCUIT_T_BROADCAST:
834 adj_type = "LAN Adjacency-SID";
835 sid = sra->u.ladj_sid->sid;
836 break;
837 case CIRCUIT_T_P2P:
838 adj_type = "Adjacency-SID";
839 sid = sra->u.adj_sid->sid;
840 break;
841 default:
842 continue;
843 }
844 backup = (sra->type == ISIS_SR_LAN_BACKUP) ? " (backup)"
845 : "";
846
847 vty_out(vty, " %s %s%s: %u\n",
848 (sra->nexthop.family == AF_INET) ? "IPv4"
849 : "IPv6",
850 adj_type, backup, sid);
851 }
d62a17ae 852 vty_out(vty, "\n");
f390d2c7 853 }
d62a17ae 854 return;
eb5d44eb 855}
856
d62a17ae 857void isis_adj_build_neigh_list(struct list *adjdb, struct list *list)
eb5d44eb 858{
d62a17ae 859 struct isis_adjacency *adj;
860 struct listnode *node;
861
862 if (!list) {
863 zlog_warn("isis_adj_build_neigh_list(): NULL list");
864 return;
f390d2c7 865 }
866
d62a17ae 867 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) {
868 if (!adj) {
869 zlog_warn("isis_adj_build_neigh_list(): NULL adj");
870 return;
871 }
872
873 if ((adj->adj_state == ISIS_ADJ_UP
874 || adj->adj_state == ISIS_ADJ_INITIALIZING))
875 listnode_add(list, adj->snpa);
876 }
877 return;
eb5d44eb 878}
879
d62a17ae 880void isis_adj_build_up_list(struct list *adjdb, struct list *list)
eb5d44eb 881{
d62a17ae 882 struct isis_adjacency *adj;
883 struct listnode *node;
884
885 if (adjdb == NULL) {
886 zlog_warn("isis_adj_build_up_list(): adjacency DB is empty");
887 return;
888 }
889
890 if (!list) {
891 zlog_warn("isis_adj_build_up_list(): NULL list");
892 return;
f390d2c7 893 }
894
d62a17ae 895 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) {
896 if (!adj) {
897 zlog_warn("isis_adj_build_up_list(): NULL adj");
898 return;
899 }
f390d2c7 900
d62a17ae 901 if (adj->adj_state == ISIS_ADJ_UP)
902 listnode_add(list, adj);
903 }
904
905 return;
eb5d44eb 906}
d8fba7d9 907
d62a17ae 908int isis_adj_usage2levels(enum isis_adj_usage usage)
d8fba7d9 909{
d62a17ae 910 switch (usage) {
911 case ISIS_ADJ_LEVEL1:
912 return IS_LEVEL_1;
913 case ISIS_ADJ_LEVEL2:
914 return IS_LEVEL_2;
915 case ISIS_ADJ_LEVEL1AND2:
916 return IS_LEVEL_1 | IS_LEVEL_2;
917 default:
918 break;
919 }
920 return 0;
d8fba7d9 921}