]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_adjacency.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[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"
18#include "thread.h"
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
fa935aa7 151 THREAD_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{
0d5b1a3a
EDP
286 if (!adj)
287 return "NONE";
288
7145d5bb
EDP
289 struct isis_dynhn *dyn;
290
240f48b3 291 dyn = dynhn_find_by_id(adj->circuit->isis, adj->sysid);
7145d5bb 292 if (dyn)
0d5b1a3a 293 return dyn->hostname;
7145d5bb 294 else
0d5b1a3a
EDP
295 return sysid_print(adj->sysid);
296}
297void isis_log_adj_change(struct isis_adjacency *adj,
298 enum isis_adj_state old_state,
299 enum isis_adj_state new_state, const char *reason)
300{
7145d5bb
EDP
301 zlog_info(
302 "%%ADJCHANGE: Adjacency to %s (%s) for %s changed from %s to %s, %s",
0d5b1a3a 303 isis_adj_name(adj), adj->circuit->interface->name,
7145d5bb
EDP
304 adj_level2string(adj->level), adj_state2string(old_state),
305 adj_state2string(new_state), reason ? reason : "unspecified");
306}
16167b31 307void isis_adj_state_change(struct isis_adjacency **padj,
d62a17ae 308 enum isis_adj_state new_state, const char *reason)
eb5d44eb 309{
16167b31 310 struct isis_adjacency *adj = *padj;
5346acec
CF
311 enum isis_adj_state old_state = adj->adj_state;
312 struct isis_circuit *circuit = adj->circuit;
16167b31 313 bool del = false;
d62a17ae 314
8cea0065
EDP
315 if (new_state == old_state)
316 return;
317
4e689dcd
LS
318 if (old_state == ISIS_ADJ_UP &&
319 !CHECK_FLAG(adj->circuit->flags, ISIS_CIRCUIT_IF_DOWN_FROM_Z)) {
694fa867
LS
320 if (IS_DEBUG_EVENTS)
321 zlog_debug(
322 "ISIS-Adj (%s): Starting fast-reroute on state change %d->%d: %s",
323 circuit->area->area_tag, old_state, new_state,
324 reason ? reason : "unspecified");
325 isis_adj_route_switchover(adj);
326 }
327
d62a17ae 328 adj->adj_state = new_state;
8cea0065 329 send_hello_sched(circuit, adj->level, TRIGGERED_IIH_DELAY);
d62a17ae 330
e740f9c1 331 if (IS_DEBUG_ADJ_PACKETS) {
d62a17ae 332 zlog_debug("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
333 circuit->area->area_tag, old_state, new_state,
334 reason ? reason : "unspecified");
335 }
336
7145d5bb
EDP
337 if (circuit->area->log_adj_changes)
338 isis_log_adj_change(adj, old_state, new_state, reason);
d62a17ae 339
de983bb8
EDP
340#ifndef FABRICD
341 /* send northbound notification */
342 isis_notif_adj_state_change(adj, new_state, reason);
343#endif /* ifndef FABRICD */
344
d62a17ae 345 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
5346acec 346 for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
d62a17ae 347 if ((adj->level & level) == 0)
348 continue;
349 if (new_state == ISIS_ADJ_UP) {
1ee746d9 350 circuit->adj_state_changes++;
d62a17ae 351 circuit->upadjcount[level - 1]++;
d62a17ae 352 /* update counter & timers for debugging
353 * purposes */
354 adj->last_flap = time(NULL);
355 adj->flaps++;
8cea0065 356 } else if (old_state == ISIS_ADJ_UP) {
1ee746d9 357 circuit->adj_state_changes++;
58e16237 358
d62a17ae 359 circuit->upadjcount[level - 1]--;
58e16237 360 if (circuit->upadjcount[level - 1] == 0)
9b39405f 361 isis_tx_queue_clean(circuit->tx_queue);
58e16237 362
7209d2a4
IR
363 if (new_state == ISIS_ADJ_DOWN) {
364 listnode_delete(
365 circuit->u.bc.adjdb[level - 1],
366 adj);
367
8cea0065 368 del = true;
7209d2a4 369 }
d62a17ae 370 }
371
372 if (circuit->u.bc.lan_neighs[level - 1]) {
373 list_delete_all_node(
374 circuit->u.bc.lan_neighs[level - 1]);
375 isis_adj_build_neigh_list(
376 circuit->u.bc.adjdb[level - 1],
377 circuit->u.bc.lan_neighs[level - 1]);
378 }
379
380 /* On adjacency state change send new pseudo LSP if we
381 * are the DR */
382 if (circuit->u.bc.is_dr[level - 1])
383 lsp_regenerate_schedule_pseudo(circuit, level);
384 }
385
d62a17ae 386 } else if (circuit->circ_type == CIRCUIT_T_P2P) {
5346acec 387 for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
d62a17ae 388 if ((adj->level & level) == 0)
389 continue;
390 if (new_state == ISIS_ADJ_UP) {
391 circuit->upadjcount[level - 1]++;
d62a17ae 392
d62a17ae 393 /* update counter & timers for debugging
394 * purposes */
395 adj->last_flap = time(NULL);
396 adj->flaps++;
397
8e6fb83b
CF
398 if (level == IS_LEVEL_1) {
399 thread_add_timer(master, send_l1_csnp,
400 circuit, 0,
401 &circuit->t_send_csnp[0]);
402 } else {
403 thread_add_timer(master, send_l2_csnp,
404 circuit, 0,
405 &circuit->t_send_csnp[1]);
406 }
8cea0065 407 } else if (old_state == ISIS_ADJ_UP) {
d62a17ae 408 circuit->upadjcount[level - 1]--;
58e16237 409 if (circuit->upadjcount[level - 1] == 0)
9b39405f 410 isis_tx_queue_clean(circuit->tx_queue);
58e16237 411
7209d2a4
IR
412 if (new_state == ISIS_ADJ_DOWN) {
413 if (adj->circuit->u.p2p.neighbor == adj)
414 adj->circuit->u.p2p.neighbor =
415 NULL;
416
8cea0065 417 del = true;
7209d2a4 418 }
d62a17ae 419 }
420 }
16167b31 421 }
d62a17ae 422
e4229afd
EDP
423 hook_call(isis_adj_state_change_hook, adj);
424
16167b31
DS
425 if (del) {
426 isis_delete_adj(adj);
427 *padj = NULL;
d62a17ae 428 }
eb5d44eb 429}
430
431
d62a17ae 432void isis_adj_print(struct isis_adjacency *adj)
eb5d44eb 433{
d62a17ae 434 struct isis_dynhn *dyn;
d62a17ae 435
436 if (!adj)
437 return;
240f48b3 438 dyn = dynhn_find_by_id(adj->circuit->isis, adj->sysid);
d62a17ae 439 if (dyn)
af8ac8f9 440 zlog_debug("%s", dyn->hostname);
d62a17ae 441
63efca0e 442 zlog_debug("SystemId %20s SNPA %s, level %d; Holding Time %d",
d62a17ae 443 sysid_print(adj->sysid), snpa_print(adj->snpa), adj->level,
444 adj->hold_time);
0c1bd758 445 if (adj->ipv4_address_count) {
d62a17ae 446 zlog_debug("IPv4 Address(es):");
0c1bd758 447 for (unsigned int i = 0; i < adj->ipv4_address_count; i++)
a854ea43 448 zlog_debug("%pI4", &adj->ipv4_addresses[i]);
d62a17ae 449 }
450
173f8887 451 if (adj->ll_ipv6_count) {
d62a17ae 452 zlog_debug("IPv6 Address(es):");
173f8887 453 for (unsigned int i = 0; i < adj->ll_ipv6_count; i++) {
0c1bd758 454 char buf[INET6_ADDRSTRLEN];
173f8887 455 inet_ntop(AF_INET6, &adj->ll_ipv6_addrs[i], buf,
0c1bd758
CF
456 sizeof(buf));
457 zlog_debug("%s", buf);
d62a17ae 458 }
f390d2c7 459 }
d62a17ae 460 zlog_debug("Speaks: %s", nlpid2string(&adj->nlpids));
eb5d44eb 461
d62a17ae 462 return;
eb5d44eb 463}
464
2a1c520e
RW
465const char *isis_adj_yang_state(enum isis_adj_state state)
466{
467 switch (state) {
468 case ISIS_ADJ_DOWN:
469 return "down";
470 case ISIS_ADJ_UP:
471 return "up";
472 case ISIS_ADJ_INITIALIZING:
473 return "init";
a348c945 474 case ISIS_ADJ_UNKNOWN:
2a1c520e
RW
475 return "failed";
476 }
a348c945
DS
477
478 assert(!"Reached end of function where we are not expecting to");
2a1c520e
RW
479}
480
cc9f21da 481void isis_adj_expire(struct thread *thread)
eb5d44eb 482{
d62a17ae 483 struct isis_adjacency *adj;
eb5d44eb 484
d62a17ae 485 /*
486 * Get the adjacency
487 */
488 adj = THREAD_ARG(thread);
489 assert(adj);
490 adj->t_expire = NULL;
eb5d44eb 491
d62a17ae 492 /* trigger the adj expire event */
16167b31 493 isis_adj_state_change(&adj, ISIS_ADJ_DOWN, "holding time expired");
eb5d44eb 494}
495
a21177f2
JG
496/*
497 * show isis neighbor [detail] json
498 */
499void isis_adj_print_json(struct isis_adjacency *adj, struct json_object *json,
500 char detail)
501{
502 json_object *iface_json, *ipv4_addr_json, *ipv6_link_json,
503 *ipv6_non_link_json, *topo_json, *dis_flaps_json,
504 *area_addr_json, *adj_sid_json;
505 time_t now;
506 struct isis_dynhn *dyn;
507 int level;
508 char buf[256];
509
510 json_object_string_add(json, "adj", isis_adj_name(adj));
511
512 if (detail == ISIS_UI_LEVEL_BRIEF) {
513 if (adj->circuit)
514 json_object_string_add(json, "interface",
515 adj->circuit->interface->name);
516 else
517 json_object_string_add(json, "interface",
518 "NULL circuit!");
519 json_object_int_add(json, "level", adj->level);
520 json_object_string_add(json, "state",
521 adj_state2string(adj->adj_state));
522 now = time(NULL);
523 if (adj->last_upd) {
524 if (adj->last_upd + adj->hold_time < now)
525 json_object_string_add(json, "last-upd",
526 "expiring");
527 else
528 json_object_string_add(
529 json, "expires-in",
530 time2string(adj->last_upd +
531 adj->hold_time - now));
532 }
533 json_object_string_add(json, "snpa", snpa_print(adj->snpa));
534 }
535
536 if (detail == ISIS_UI_LEVEL_DETAIL) {
537 struct sr_adjacency *sra;
538 struct listnode *anode;
539
540 level = adj->level;
541 iface_json = json_object_new_object();
542 json_object_object_add(json, "interface", iface_json);
543 if (adj->circuit)
544 json_object_string_add(iface_json, "name",
545 adj->circuit->interface->name);
546 else
547 json_object_string_add(iface_json, "name",
548 "null-circuit");
549 json_object_int_add(json, "level", adj->level);
550 json_object_string_add(iface_json, "state",
551 adj_state2string(adj->adj_state));
552 now = time(NULL);
553 if (adj->last_upd) {
554 if (adj->last_upd + adj->hold_time < now)
555 json_object_string_add(iface_json, "last-upd",
556 "expiring");
557 else
558 json_object_string_add(
559 json, "expires-in",
560 time2string(adj->last_upd +
561 adj->hold_time - now));
562 } else
563 json_object_string_add(json, "expires-in",
564 time2string(adj->hold_time));
565 json_object_int_add(iface_json, "adj-flaps", adj->flaps);
566 json_object_string_add(iface_json, "last-ago",
567 time2string(now - adj->last_flap));
568 json_object_string_add(iface_json, "circuit-type",
569 circuit_t2string(adj->circuit_t));
570 json_object_string_add(iface_json, "speaks",
571 nlpid2string(&adj->nlpids));
572 if (adj->mt_count != 1 ||
573 adj->mt_set[0] != ISIS_MT_IPV4_UNICAST) {
574 topo_json = json_object_new_object();
575 json_object_object_add(iface_json, "topologies",
576 topo_json);
577 for (unsigned int i = 0; i < adj->mt_count; i++) {
578 snprintfrr(buf, sizeof(buf), "topo-%d", i);
579 json_object_string_add(
580 topo_json, buf,
581 isis_mtid2str(adj->mt_set[i]));
582 }
583 }
584 json_object_string_add(iface_json, "snpa",
585 snpa_print(adj->snpa));
586 if (adj->circuit &&
587 (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) {
588 dyn = dynhn_find_by_id(adj->circuit->isis, adj->lanid);
589 if (dyn) {
590 snprintfrr(buf, sizeof(buf), "%s-%02x",
591 dyn->hostname,
592 adj->lanid[ISIS_SYS_ID_LEN]);
593 json_object_string_add(iface_json, "lan-id",
594 buf);
595 } else {
596 snprintfrr(buf, sizeof(buf), "%s-%02x",
597 sysid_print(adj->lanid),
598 adj->lanid[ISIS_SYS_ID_LEN]);
599 json_object_string_add(iface_json, "lan-id",
600 buf);
601 }
602
603 json_object_int_add(iface_json, "lan-prio",
604 adj->prio[adj->level - 1]);
605
606 dis_flaps_json = json_object_new_object();
607 json_object_object_add(iface_json, "dis-flaps",
608 dis_flaps_json);
609 json_object_string_add(
610 dis_flaps_json, "dis-record",
611 isis_disflag2string(
612 adj->dis_record[ISIS_LEVELS + level - 1]
613 .dis));
614 json_object_int_add(dis_flaps_json, "last",
615 adj->dischanges[level - 1]);
616 json_object_string_add(
617 dis_flaps_json, "ago",
618 time2string(now - (adj->dis_record[ISIS_LEVELS +
619 level - 1]
620 .last_dis_change)));
621 }
622
623 if (adj->area_address_count) {
624 area_addr_json = json_object_new_object();
625 json_object_object_add(iface_json, "area-address",
626 area_addr_json);
627 for (unsigned int i = 0; i < adj->area_address_count;
628 i++) {
629 json_object_string_add(
630 area_addr_json, "isonet",
631 isonet_print(adj->area_addresses[i]
632 .area_addr,
633 adj->area_addresses[i]
634 .addr_len));
635 }
636 }
637 if (adj->ipv4_address_count) {
638 ipv4_addr_json = json_object_new_object();
639 json_object_object_add(iface_json, "ipv4-address",
640 ipv4_addr_json);
641 for (unsigned int i = 0; i < adj->ipv4_address_count;
642 i++){
643 inet_ntop(AF_INET, &adj->ipv4_addresses[i], buf,
644 sizeof(buf));
645 json_object_string_add(ipv4_addr_json, "ipv4", buf);
646 }
647 }
648 if (adj->ll_ipv6_count) {
649 ipv6_link_json = json_object_new_object();
650 json_object_object_add(iface_json, "ipv6-link-local",
651 ipv6_link_json);
652 for (unsigned int i = 0; i < adj->ll_ipv6_count; i++) {
653 char buf[INET6_ADDRSTRLEN];
654 inet_ntop(AF_INET6, &adj->ll_ipv6_addrs[i], buf,
655 sizeof(buf));
656 json_object_string_add(ipv6_link_json, "ipv6",
657 buf);
658 }
659 }
660 if (adj->global_ipv6_count) {
661 ipv6_non_link_json = json_object_new_object();
662 json_object_object_add(iface_json, "ipv6-global",
663 ipv6_non_link_json);
664 for (unsigned int i = 0; i < adj->global_ipv6_count;
665 i++) {
666 char buf[INET6_ADDRSTRLEN];
667 inet_ntop(AF_INET6, &adj->global_ipv6_addrs[i],
668 buf, sizeof(buf));
669 json_object_string_add(ipv6_non_link_json,
670 "ipv6", buf);
671 }
672 }
673
674 adj_sid_json = json_object_new_object();
675 json_object_object_add(iface_json, "adj-sid", adj_sid_json);
676 for (ALL_LIST_ELEMENTS_RO(adj->adj_sids, anode, sra)) {
677 const char *adj_type;
678 const char *backup;
679 uint32_t sid;
680
681 switch (sra->adj->circuit->circ_type) {
682 case CIRCUIT_T_BROADCAST:
683 adj_type = "LAN Adjacency-SID";
684 sid = sra->u.ladj_sid->sid;
685 break;
686 case CIRCUIT_T_P2P:
687 adj_type = "Adjacency-SID";
688 sid = sra->u.adj_sid->sid;
689 break;
690 default:
691 continue;
692 }
693 backup = (sra->type == ISIS_SR_LAN_BACKUP) ? " (backup)"
694 : "";
695
696 json_object_string_add(adj_sid_json, "nexthop",
697 (sra->nexthop.family == AF_INET)
698 ? "IPv4"
699 : "IPv6");
700 json_object_string_add(adj_sid_json, "adj-type",
701 adj_type);
702 json_object_string_add(adj_sid_json, "is-backup",
703 backup);
704 json_object_int_add(adj_sid_json, "sid", sid);
705 }
706 }
707 return;
708}
709
eb5d44eb 710/*
3f045a08 711 * show isis neighbor [detail]
eb5d44eb 712 */
d62a17ae 713void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
714 char detail)
eb5d44eb 715{
d62a17ae 716 time_t now;
717 struct isis_dynhn *dyn;
718 int level;
d62a17ae 719
0d5b1a3a 720 vty_out(vty, " %-20s", isis_adj_name(adj));
d62a17ae 721
722 if (detail == ISIS_UI_LEVEL_BRIEF) {
723 if (adj->circuit)
724 vty_out(vty, "%-12s", adj->circuit->interface->name);
725 else
726 vty_out(vty, "NULL circuit!");
727 vty_out(vty, "%-3u", adj->level); /* level */
728 vty_out(vty, "%-13s", adj_state2string(adj->adj_state));
729 now = time(NULL);
3cbe31c7 730 if (adj->last_upd) {
ac716cdf 731 if (adj->last_upd + adj->hold_time < now)
3cbe31c7
EDP
732 vty_out(vty, " Expiring");
733 else
734 vty_out(vty, " %-9llu",
735 (unsigned long long)adj->last_upd
736 + adj->hold_time - now);
737 } else
d62a17ae 738 vty_out(vty, "- ");
739 vty_out(vty, "%-10s", snpa_print(adj->snpa));
740 vty_out(vty, "\n");
f390d2c7 741 }
d62a17ae 742
743 if (detail == ISIS_UI_LEVEL_DETAIL) {
26f6acaf
RW
744 struct sr_adjacency *sra;
745 struct listnode *anode;
746
d62a17ae 747 level = adj->level;
748 vty_out(vty, "\n");
749 if (adj->circuit)
750 vty_out(vty, " Interface: %s",
751 adj->circuit->interface->name);
752 else
753 vty_out(vty, " Interface: NULL circuit");
754 vty_out(vty, ", Level: %u", adj->level); /* level */
755 vty_out(vty, ", State: %s", adj_state2string(adj->adj_state));
756 now = time(NULL);
3cbe31c7 757 if (adj->last_upd) {
ac716cdf 758 if (adj->last_upd + adj->hold_time < now)
3cbe31c7
EDP
759 vty_out(vty, " Expiring");
760 else
761 vty_out(vty, ", Expires in %s",
762 time2string(adj->last_upd
763 + adj->hold_time - now));
764 } else
d62a17ae 765 vty_out(vty, ", Expires in %s",
766 time2string(adj->hold_time));
767 vty_out(vty, "\n");
768 vty_out(vty, " Adjacency flaps: %u", adj->flaps);
769 vty_out(vty, ", Last: %s ago",
770 time2string(now - adj->last_flap));
771 vty_out(vty, "\n");
772 vty_out(vty, " Circuit type: %s",
773 circuit_t2string(adj->circuit_t));
774 vty_out(vty, ", Speaks: %s", nlpid2string(&adj->nlpids));
775 vty_out(vty, "\n");
776 if (adj->mt_count != 1
777 || adj->mt_set[0] != ISIS_MT_IPV4_UNICAST) {
778 vty_out(vty, " Topologies:\n");
779 for (unsigned int i = 0; i < adj->mt_count; i++)
780 vty_out(vty, " %s\n",
781 isis_mtid2str(adj->mt_set[i]));
782 }
783 vty_out(vty, " SNPA: %s", snpa_print(adj->snpa));
784 if (adj->circuit
785 && (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) {
240f48b3 786 dyn = dynhn_find_by_id(adj->circuit->isis, adj->lanid);
d62a17ae 787 if (dyn)
af8ac8f9 788 vty_out(vty, ", LAN id: %s.%02x", dyn->hostname,
d62a17ae 789 adj->lanid[ISIS_SYS_ID_LEN]);
790 else
791 vty_out(vty, ", LAN id: %s.%02x",
792 sysid_print(adj->lanid),
793 adj->lanid[ISIS_SYS_ID_LEN]);
794
795 vty_out(vty, "\n");
796 vty_out(vty, " LAN Priority: %u",
797 adj->prio[adj->level - 1]);
798
799 vty_out(vty, ", %s, DIS flaps: %u, Last: %s ago",
800 isis_disflag2string(
801 adj->dis_record[ISIS_LEVELS + level - 1]
802 .dis),
803 adj->dischanges[level - 1],
9d303b37
DL
804 time2string(now - (adj->dis_record[ISIS_LEVELS
805 + level - 1]
806 .last_dis_change)));
d62a17ae 807 }
808 vty_out(vty, "\n");
809
0c1bd758 810 if (adj->area_address_count) {
d62a17ae 811 vty_out(vty, " Area Address(es):\n");
0c1bd758
CF
812 for (unsigned int i = 0; i < adj->area_address_count;
813 i++) {
d62a17ae 814 vty_out(vty, " %s\n",
996c9314
LB
815 isonet_print(adj->area_addresses[i]
816 .area_addr,
817 adj->area_addresses[i]
818 .addr_len));
0c1bd758 819 }
d62a17ae 820 }
0c1bd758 821 if (adj->ipv4_address_count) {
d62a17ae 822 vty_out(vty, " IPv4 Address(es):\n");
0c1bd758
CF
823 for (unsigned int i = 0; i < adj->ipv4_address_count;
824 i++)
a854ea43
MS
825 vty_out(vty, " %pI4\n",
826 &adj->ipv4_addresses[i]);
d62a17ae 827 }
173f8887 828 if (adj->ll_ipv6_count) {
d62a17ae 829 vty_out(vty, " IPv6 Address(es):\n");
173f8887
OD
830 for (unsigned int i = 0; i < adj->ll_ipv6_count; i++) {
831 char buf[INET6_ADDRSTRLEN];
832 inet_ntop(AF_INET6, &adj->ll_ipv6_addrs[i],
833 buf, sizeof(buf));
834 vty_out(vty, " %s\n", buf);
835 }
836 }
837 if (adj->global_ipv6_count) {
838 vty_out(vty, " Global IPv6 Address(es):\n");
839 for (unsigned int i = 0; i < adj->global_ipv6_count;
0c1bd758
CF
840 i++) {
841 char buf[INET6_ADDRSTRLEN];
173f8887 842 inet_ntop(AF_INET6, &adj->global_ipv6_addrs[i],
0c1bd758
CF
843 buf, sizeof(buf));
844 vty_out(vty, " %s\n", buf);
d62a17ae 845 }
846 }
ae59cfd7
PG
847 if (adj->circuit && adj->circuit->bfd_config.enabled) {
848 vty_out(vty, " BFD is %s%s\n",
849 adj->bfd_session ? "active, status "
850 : "configured",
851 !adj->bfd_session
852 ? ""
853 : bfd_get_status_str(bfd_sess_status(
854 adj->bfd_session)));
855 }
26f6acaf
RW
856 for (ALL_LIST_ELEMENTS_RO(adj->adj_sids, anode, sra)) {
857 const char *adj_type;
858 const char *backup;
859 uint32_t sid;
860
861 switch (sra->adj->circuit->circ_type) {
862 case CIRCUIT_T_BROADCAST:
863 adj_type = "LAN Adjacency-SID";
864 sid = sra->u.ladj_sid->sid;
865 break;
866 case CIRCUIT_T_P2P:
867 adj_type = "Adjacency-SID";
868 sid = sra->u.adj_sid->sid;
869 break;
870 default:
871 continue;
872 }
873 backup = (sra->type == ISIS_SR_LAN_BACKUP) ? " (backup)"
874 : "";
875
876 vty_out(vty, " %s %s%s: %u\n",
877 (sra->nexthop.family == AF_INET) ? "IPv4"
878 : "IPv6",
879 adj_type, backup, sid);
880 }
d62a17ae 881 vty_out(vty, "\n");
f390d2c7 882 }
d62a17ae 883 return;
eb5d44eb 884}
885
d62a17ae 886void isis_adj_build_neigh_list(struct list *adjdb, struct list *list)
eb5d44eb 887{
d62a17ae 888 struct isis_adjacency *adj;
889 struct listnode *node;
890
891 if (!list) {
1f46f33f 892 zlog_warn("%s: NULL list", __func__);
d62a17ae 893 return;
f390d2c7 894 }
895
d62a17ae 896 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) {
897 if (!adj) {
1f46f33f 898 zlog_warn("%s: NULL adj", __func__);
d62a17ae 899 return;
900 }
901
902 if ((adj->adj_state == ISIS_ADJ_UP
903 || adj->adj_state == ISIS_ADJ_INITIALIZING))
904 listnode_add(list, adj->snpa);
905 }
906 return;
eb5d44eb 907}
908
d62a17ae 909void isis_adj_build_up_list(struct list *adjdb, struct list *list)
eb5d44eb 910{
d62a17ae 911 struct isis_adjacency *adj;
912 struct listnode *node;
913
914 if (adjdb == NULL) {
1f46f33f 915 zlog_warn("%s: adjacency DB is empty", __func__);
d62a17ae 916 return;
917 }
918
919 if (!list) {
1f46f33f 920 zlog_warn("%s: NULL list", __func__);
d62a17ae 921 return;
f390d2c7 922 }
923
d62a17ae 924 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) {
925 if (!adj) {
1f46f33f 926 zlog_warn("%s: NULL adj", __func__);
d62a17ae 927 return;
928 }
f390d2c7 929
d62a17ae 930 if (adj->adj_state == ISIS_ADJ_UP)
931 listnode_add(list, adj);
932 }
933
934 return;
eb5d44eb 935}
d8fba7d9 936
d62a17ae 937int isis_adj_usage2levels(enum isis_adj_usage usage)
d8fba7d9 938{
d62a17ae 939 switch (usage) {
940 case ISIS_ADJ_LEVEL1:
941 return IS_LEVEL_1;
942 case ISIS_ADJ_LEVEL2:
943 return IS_LEVEL_2;
944 case ISIS_ADJ_LEVEL1AND2:
945 return IS_LEVEL_1 | IS_LEVEL_2;
a348c945
DS
946 case ISIS_ADJ_NONE:
947 return 0;
d62a17ae 948 }
a348c945
DS
949
950 assert(!"Reached end of function where we are not expecting to");
d8fba7d9 951}