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