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