1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * IS-IS Rout(e)ing protocol - isis_adjacency.c
4 * handling of IS-IS adjacencies
6 * Copyright (C) 2001,2002 Sampo Saaristo
7 * Tampere University of Technology
8 * Institute of Communications Engineering
23 #include "isisd/isis_constants.h"
24 #include "isisd/isis_common.h"
25 #include "isisd/isis_flags.h"
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"
33 #include "isisd/isis_lsp.h"
34 #include "isisd/isis_events.h"
35 #include "isisd/isis_mt.h"
36 #include "isisd/isis_tlvs.h"
37 #include "isisd/fabricd.h"
38 #include "isisd/isis_nb.h"
40 DEFINE_MTYPE_STATIC(ISISD
, ISIS_ADJACENCY
, "ISIS adjacency");
41 DEFINE_MTYPE(ISISD
, ISIS_ADJACENCY_INFO
, "ISIS adjacency info");
43 static struct isis_adjacency
*adj_alloc(struct isis_circuit
*circuit
,
46 struct isis_adjacency
*adj
;
48 adj
= XCALLOC(MTYPE_ISIS_ADJACENCY
, sizeof(struct isis_adjacency
));
49 memcpy(adj
->sysid
, id
, ISIS_SYS_ID_LEN
);
51 adj
->snmp_idx
= ++circuit
->snmp_adj_idx_gen
;
53 if (circuit
->snmp_adj_list
== NULL
)
54 circuit
->snmp_adj_list
= list_new();
56 adj
->snmp_list_node
= listnode_add(circuit
->snmp_adj_list
, adj
);
61 struct isis_adjacency
*isis_new_adj(const uint8_t *id
, const uint8_t *snpa
,
62 int level
, struct isis_circuit
*circuit
)
64 struct isis_adjacency
*adj
;
67 adj
= adj_alloc(circuit
, id
); /* P2P kludge */
70 memcpy(adj
->snpa
, snpa
, ETH_ALEN
);
72 memset(adj
->snpa
, ' ', ETH_ALEN
);
75 adj
->circuit
= circuit
;
78 adj
->last_flap
= time(NULL
);
79 adj
->threeway_state
= ISIS_THREEWAY_DOWN
;
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 */
86 adj
->dis_record
[(i
* ISIS_LEVELS
) + level
- 1].dis
=
88 adj
->dis_record
[(i
* ISIS_LEVELS
) + level
- 1]
89 .last_dis_change
= time(NULL
);
92 adj
->adj_sids
= list_new();
93 listnode_add(circuit
->area
->adjacency_list
, adj
);
98 struct isis_adjacency
*isis_adj_lookup(const uint8_t *sysid
, struct list
*adjdb
)
100 struct isis_adjacency
*adj
;
101 struct listnode
*node
;
103 for (ALL_LIST_ELEMENTS_RO(adjdb
, node
, adj
))
104 if (memcmp(adj
->sysid
, sysid
, ISIS_SYS_ID_LEN
) == 0)
110 struct isis_adjacency
*isis_adj_lookup_snpa(const uint8_t *ssnpa
,
113 struct listnode
*node
;
114 struct isis_adjacency
*adj
;
116 for (ALL_LIST_ELEMENTS_RO(adjdb
, node
, adj
))
117 if (memcmp(adj
->snpa
, ssnpa
, ETH_ALEN
) == 0)
123 struct isis_adjacency
*isis_adj_find(const struct isis_area
*area
, int level
,
124 const uint8_t *sysid
)
126 struct isis_adjacency
*adj
;
127 struct listnode
*node
;
129 for (ALL_LIST_ELEMENTS_RO(area
->adjacency_list
, node
, adj
)) {
130 if (!(adj
->level
& level
))
133 if (!memcmp(adj
->sysid
, sysid
, ISIS_SYS_ID_LEN
))
140 DEFINE_HOOK(isis_adj_state_change_hook
, (struct isis_adjacency
*adj
), (adj
));
142 void isis_delete_adj(void *arg
)
144 struct isis_adjacency
*adj
= arg
;
148 /* Remove self from snmp list without walking the list*/
149 list_delete_node(adj
->circuit
->snmp_adj_list
, adj
->snmp_list_node
);
151 EVENT_OFF(adj
->t_expire
);
152 if (adj
->adj_state
!= ISIS_ADJ_DOWN
)
153 adj
->adj_state
= ISIS_ADJ_DOWN
;
155 hook_call(isis_adj_state_change_hook
, adj
);
157 XFREE(MTYPE_ISIS_ADJACENCY_INFO
, adj
->area_addresses
);
158 XFREE(MTYPE_ISIS_ADJACENCY_INFO
, adj
->ipv4_addresses
);
159 XFREE(MTYPE_ISIS_ADJACENCY_INFO
, adj
->ll_ipv6_addrs
);
160 XFREE(MTYPE_ISIS_ADJACENCY_INFO
, adj
->global_ipv6_addrs
);
162 list_delete(&adj
->adj_sids
);
164 listnode_delete(adj
->circuit
->area
->adjacency_list
, adj
);
165 XFREE(MTYPE_ISIS_ADJACENCY
, adj
);
169 static const char *adj_state2string(int state
)
173 case ISIS_ADJ_INITIALIZING
:
174 return "Initializing";
183 return NULL
; /* not reached */
186 static const char *adj_level2string(int level
)
193 case IS_LEVEL_1_AND_2
:
199 return NULL
; /* not reached */
202 static void isis_adj_route_switchover(struct isis_adjacency
*adj
)
204 union g_addr ip
= {};
208 if (!adj
->circuit
|| !adj
->circuit
->interface
)
211 ifindex
= adj
->circuit
->interface
->ifindex
;
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
,
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
,
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
,
232 void isis_adj_process_threeway(struct isis_adjacency
*adj
,
233 struct isis_threeway_adj
*tw_adj
,
234 enum isis_adj_usage adj_usage
)
236 enum isis_threeway_state next_tw_state
= ISIS_THREEWAY_DOWN
;
238 if (tw_adj
&& !adj
->circuit
->disable_threeway_adj
) {
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
;
247 next_tw_state
= ISIS_THREEWAY_UP
;
250 next_tw_state
= ISIS_THREEWAY_UP
;
253 if (next_tw_state
!= adj
->threeway_state
) {
254 if (IS_DEBUG_ADJ_PACKETS
) {
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
));
262 if (next_tw_state
!= ISIS_THREEWAY_DOWN
)
263 fabricd_initial_sync_hello(adj
->circuit
);
265 if (next_tw_state
== ISIS_THREEWAY_DOWN
) {
266 isis_adj_state_change(&adj
, ISIS_ADJ_DOWN
,
267 "Neighbor restarted");
271 if (next_tw_state
== ISIS_THREEWAY_UP
) {
272 if (adj
->adj_state
!= ISIS_ADJ_UP
) {
273 isis_adj_state_change(&adj
, ISIS_ADJ_UP
, NULL
);
274 adj
->adj_usage
= adj_usage
;
278 if (adj
->threeway_state
!= next_tw_state
) {
279 send_hello_sched(adj
->circuit
, 0, TRIGGERED_IIH_DELAY
);
282 adj
->threeway_state
= next_tw_state
;
284 const char *isis_adj_name(const struct isis_adjacency
*adj
)
289 struct isis_dynhn
*dyn
;
291 dyn
= dynhn_find_by_id(adj
->circuit
->isis
, adj
->sysid
);
293 return dyn
->hostname
;
295 return sysid_print(adj
->sysid
);
297 void 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
)
302 "%%ADJCHANGE: Adjacency to %s (%s) for %s changed from %s to %s, %s",
303 isis_adj_name(adj
), adj
->circuit
->interface
->name
,
304 adj_level2string(adj
->level
), adj_state2string(old_state
),
305 adj_state2string(new_state
), reason
? reason
: "unspecified");
307 void isis_adj_state_change(struct isis_adjacency
**padj
,
308 enum isis_adj_state new_state
, const char *reason
)
310 struct isis_adjacency
*adj
= *padj
;
311 enum isis_adj_state old_state
= adj
->adj_state
;
312 struct isis_circuit
*circuit
= adj
->circuit
;
315 if (new_state
== old_state
)
318 if (old_state
== ISIS_ADJ_UP
&&
319 !CHECK_FLAG(adj
->circuit
->flags
, ISIS_CIRCUIT_IF_DOWN_FROM_Z
)) {
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
);
328 adj
->adj_state
= new_state
;
329 send_hello_sched(circuit
, adj
->level
, TRIGGERED_IIH_DELAY
);
331 if (IS_DEBUG_ADJ_PACKETS
) {
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");
337 if (circuit
->area
->log_adj_changes
)
338 isis_log_adj_change(adj
, old_state
, new_state
, reason
);
341 /* send northbound notification */
342 isis_notif_adj_state_change(adj
, new_state
, reason
);
343 #endif /* ifndef FABRICD */
345 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
) {
346 for (int level
= IS_LEVEL_1
; level
<= IS_LEVEL_2
; level
++) {
347 if ((adj
->level
& level
) == 0)
349 if (new_state
== ISIS_ADJ_UP
) {
350 circuit
->adj_state_changes
++;
351 circuit
->upadjcount
[level
- 1]++;
352 /* update counter & timers for debugging
354 adj
->last_flap
= time(NULL
);
356 } else if (old_state
== ISIS_ADJ_UP
) {
357 circuit
->adj_state_changes
++;
359 circuit
->upadjcount
[level
- 1]--;
360 if (circuit
->upadjcount
[level
- 1] == 0)
361 isis_tx_queue_clean(circuit
->tx_queue
);
363 if (new_state
== ISIS_ADJ_DOWN
) {
365 circuit
->u
.bc
.adjdb
[level
- 1],
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]);
380 /* On adjacency state change send new pseudo LSP if we
382 if (circuit
->u
.bc
.is_dr
[level
- 1])
383 lsp_regenerate_schedule_pseudo(circuit
, level
);
386 } else if (circuit
->circ_type
== CIRCUIT_T_P2P
) {
387 for (int level
= IS_LEVEL_1
; level
<= IS_LEVEL_2
; level
++) {
388 if ((adj
->level
& level
) == 0)
390 if (new_state
== ISIS_ADJ_UP
) {
391 circuit
->upadjcount
[level
- 1]++;
393 /* update counter & timers for debugging
395 adj
->last_flap
= time(NULL
);
398 if (level
== IS_LEVEL_1
) {
400 master
, send_l1_csnp
, circuit
,
401 0, &circuit
->t_send_csnp
[0]);
404 master
, send_l2_csnp
, circuit
,
405 0, &circuit
->t_send_csnp
[1]);
407 } else if (old_state
== ISIS_ADJ_UP
) {
408 circuit
->upadjcount
[level
- 1]--;
409 if (circuit
->upadjcount
[level
- 1] == 0)
410 isis_tx_queue_clean(circuit
->tx_queue
);
412 if (new_state
== ISIS_ADJ_DOWN
) {
413 if (adj
->circuit
->u
.p2p
.neighbor
== adj
)
414 adj
->circuit
->u
.p2p
.neighbor
=
423 hook_call(isis_adj_state_change_hook
, adj
);
426 isis_delete_adj(adj
);
432 void isis_adj_print(struct isis_adjacency
*adj
)
434 struct isis_dynhn
*dyn
;
438 dyn
= dynhn_find_by_id(adj
->circuit
->isis
, adj
->sysid
);
440 zlog_debug("%s", dyn
->hostname
);
442 zlog_debug("SystemId %20s SNPA %s, level %d; Holding Time %d",
443 sysid_print(adj
->sysid
), snpa_print(adj
->snpa
), adj
->level
,
445 if (adj
->ipv4_address_count
) {
446 zlog_debug("IPv4 Address(es):");
447 for (unsigned int i
= 0; i
< adj
->ipv4_address_count
; i
++)
448 zlog_debug("%pI4", &adj
->ipv4_addresses
[i
]);
451 if (adj
->ll_ipv6_count
) {
452 zlog_debug("IPv6 Address(es):");
453 for (unsigned int i
= 0; i
< adj
->ll_ipv6_count
; i
++) {
454 char buf
[INET6_ADDRSTRLEN
];
455 inet_ntop(AF_INET6
, &adj
->ll_ipv6_addrs
[i
], buf
,
457 zlog_debug("%s", buf
);
460 zlog_debug("Speaks: %s", nlpid2string(&adj
->nlpids
));
465 const char *isis_adj_yang_state(enum isis_adj_state state
)
472 case ISIS_ADJ_INITIALIZING
:
474 case ISIS_ADJ_UNKNOWN
:
478 assert(!"Reached end of function where we are not expecting to");
481 void isis_adj_expire(struct event
*thread
)
483 struct isis_adjacency
*adj
;
488 adj
= EVENT_ARG(thread
);
490 adj
->t_expire
= NULL
;
492 /* trigger the adj expire event */
493 isis_adj_state_change(&adj
, ISIS_ADJ_DOWN
, "holding time expired");
497 * show isis neighbor [detail] json
499 void isis_adj_print_json(struct isis_adjacency
*adj
, struct json_object
*json
,
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
;
506 struct isis_dynhn
*dyn
;
510 json_object_string_add(json
, "adj", isis_adj_name(adj
));
512 if (detail
== ISIS_UI_LEVEL_BRIEF
) {
514 json_object_string_add(json
, "interface",
515 adj
->circuit
->interface
->name
);
517 json_object_string_add(json
, "interface",
519 json_object_int_add(json
, "level", adj
->level
);
520 json_object_string_add(json
, "state",
521 adj_state2string(adj
->adj_state
));
524 if (adj
->last_upd
+ adj
->hold_time
< now
)
525 json_object_string_add(json
, "last-upd",
528 json_object_string_add(
530 time2string(adj
->last_upd
+
531 adj
->hold_time
- now
));
533 json_object_string_add(json
, "snpa", snpa_print(adj
->snpa
));
536 if (detail
== ISIS_UI_LEVEL_DETAIL
) {
537 struct sr_adjacency
*sra
;
538 struct listnode
*anode
;
541 iface_json
= json_object_new_object();
542 json_object_object_add(json
, "interface", iface_json
);
544 json_object_string_add(iface_json
, "name",
545 adj
->circuit
->interface
->name
);
547 json_object_string_add(iface_json
, "name",
549 json_object_int_add(json
, "level", adj
->level
);
550 json_object_string_add(iface_json
, "state",
551 adj_state2string(adj
->adj_state
));
554 if (adj
->last_upd
+ adj
->hold_time
< now
)
555 json_object_string_add(iface_json
, "last-upd",
558 json_object_string_add(
560 time2string(adj
->last_upd
+
561 adj
->hold_time
- now
));
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",
577 for (unsigned int i
= 0; i
< adj
->mt_count
; i
++) {
578 snprintfrr(buf
, sizeof(buf
), "topo-%d", i
);
579 json_object_string_add(
581 isis_mtid2str(adj
->mt_set
[i
]));
584 json_object_string_add(iface_json
, "snpa",
585 snpa_print(adj
->snpa
));
587 (adj
->circuit
->circ_type
== CIRCUIT_T_BROADCAST
)) {
588 dyn
= dynhn_find_by_id(adj
->circuit
->isis
, adj
->lanid
);
590 snprintfrr(buf
, sizeof(buf
), "%s-%02x",
592 adj
->lanid
[ISIS_SYS_ID_LEN
]);
593 json_object_string_add(iface_json
, "lan-id",
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",
603 json_object_int_add(iface_json
, "lan-prio",
604 adj
->prio
[adj
->level
- 1]);
606 dis_flaps_json
= json_object_new_object();
607 json_object_object_add(iface_json
, "dis-flaps",
609 json_object_string_add(
610 dis_flaps_json
, "dis-record",
612 adj
->dis_record
[ISIS_LEVELS
+ level
- 1]
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
+
623 if (adj
->area_address_count
) {
624 area_addr_json
= json_object_new_object();
625 json_object_object_add(iface_json
, "area-address",
627 for (unsigned int i
= 0; i
< adj
->area_address_count
;
629 json_object_string_add(
630 area_addr_json
, "isonet",
631 isonet_print(adj
->area_addresses
[i
]
633 adj
->area_addresses
[i
]
637 if (adj
->ipv4_address_count
) {
638 ipv4_addr_json
= json_object_new_object();
639 json_object_object_add(iface_json
, "ipv4-address",
641 for (unsigned int i
= 0; i
< adj
->ipv4_address_count
;
643 inet_ntop(AF_INET
, &adj
->ipv4_addresses
[i
], buf
,
645 json_object_string_add(ipv4_addr_json
, "ipv4", buf
);
648 if (adj
->ll_ipv6_count
) {
649 ipv6_link_json
= json_object_new_object();
650 json_object_object_add(iface_json
, "ipv6-link-local",
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
,
656 json_object_string_add(ipv6_link_json
, "ipv6",
660 if (adj
->global_ipv6_count
) {
661 ipv6_non_link_json
= json_object_new_object();
662 json_object_object_add(iface_json
, "ipv6-global",
664 for (unsigned int i
= 0; i
< adj
->global_ipv6_count
;
666 char buf
[INET6_ADDRSTRLEN
];
667 inet_ntop(AF_INET6
, &adj
->global_ipv6_addrs
[i
],
669 json_object_string_add(ipv6_non_link_json
,
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
;
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
;
687 adj_type
= "Adjacency-SID";
688 sid
= sra
->u
.adj_sid
->sid
;
693 backup
= (sra
->type
== ISIS_SR_LAN_BACKUP
) ? " (backup)"
696 json_object_string_add(adj_sid_json
, "nexthop",
697 (sra
->nexthop
.family
== AF_INET
)
700 json_object_string_add(adj_sid_json
, "adj-type",
702 json_object_string_add(adj_sid_json
, "is-backup",
704 json_object_int_add(adj_sid_json
, "sid", sid
);
711 * show isis neighbor [detail]
713 void isis_adj_print_vty(struct isis_adjacency
*adj
, struct vty
*vty
,
717 struct isis_dynhn
*dyn
;
720 vty_out(vty
, " %-20s", isis_adj_name(adj
));
722 if (detail
== ISIS_UI_LEVEL_BRIEF
) {
724 vty_out(vty
, "%-12s", adj
->circuit
->interface
->name
);
726 vty_out(vty
, "NULL circuit!");
727 vty_out(vty
, "%-3u", adj
->level
); /* level */
728 vty_out(vty
, "%-13s", adj_state2string(adj
->adj_state
));
731 if (adj
->last_upd
+ adj
->hold_time
< now
)
732 vty_out(vty
, " Expiring");
734 vty_out(vty
, " %-9llu",
735 (unsigned long long)adj
->last_upd
736 + adj
->hold_time
- now
);
739 vty_out(vty
, "%-10s", snpa_print(adj
->snpa
));
743 if (detail
== ISIS_UI_LEVEL_DETAIL
) {
744 struct sr_adjacency
*sra
;
745 struct listnode
*anode
;
750 vty_out(vty
, " Interface: %s",
751 adj
->circuit
->interface
->name
);
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
));
758 if (adj
->last_upd
+ adj
->hold_time
< now
)
759 vty_out(vty
, " Expiring");
761 vty_out(vty
, ", Expires in %s",
762 time2string(adj
->last_upd
763 + adj
->hold_time
- now
));
765 vty_out(vty
, ", Expires in %s",
766 time2string(adj
->hold_time
));
768 vty_out(vty
, " Adjacency flaps: %u", adj
->flaps
);
769 vty_out(vty
, ", Last: %s ago",
770 time2string(now
- adj
->last_flap
));
772 vty_out(vty
, " Circuit type: %s",
773 circuit_t2string(adj
->circuit_t
));
774 vty_out(vty
, ", Speaks: %s", nlpid2string(&adj
->nlpids
));
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
]));
783 vty_out(vty
, " SNPA: %s", snpa_print(adj
->snpa
));
785 && (adj
->circuit
->circ_type
== CIRCUIT_T_BROADCAST
)) {
786 dyn
= dynhn_find_by_id(adj
->circuit
->isis
, adj
->lanid
);
788 vty_out(vty
, ", LAN id: %s.%02x", dyn
->hostname
,
789 adj
->lanid
[ISIS_SYS_ID_LEN
]);
791 vty_out(vty
, ", LAN id: %s.%02x",
792 sysid_print(adj
->lanid
),
793 adj
->lanid
[ISIS_SYS_ID_LEN
]);
796 vty_out(vty
, " LAN Priority: %u",
797 adj
->prio
[adj
->level
- 1]);
799 vty_out(vty
, ", %s, DIS flaps: %u, Last: %s ago",
801 adj
->dis_record
[ISIS_LEVELS
+ level
- 1]
803 adj
->dischanges
[level
- 1],
804 time2string(now
- (adj
->dis_record
[ISIS_LEVELS
810 if (adj
->area_address_count
) {
811 vty_out(vty
, " Area Address(es):\n");
812 for (unsigned int i
= 0; i
< adj
->area_address_count
;
814 vty_out(vty
, " %s\n",
815 isonet_print(adj
->area_addresses
[i
]
817 adj
->area_addresses
[i
]
821 if (adj
->ipv4_address_count
) {
822 vty_out(vty
, " IPv4 Address(es):\n");
823 for (unsigned int i
= 0; i
< adj
->ipv4_address_count
;
825 vty_out(vty
, " %pI4\n",
826 &adj
->ipv4_addresses
[i
]);
828 if (adj
->ll_ipv6_count
) {
829 vty_out(vty
, " IPv6 Address(es):\n");
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
],
834 vty_out(vty
, " %s\n", buf
);
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
;
841 char buf
[INET6_ADDRSTRLEN
];
842 inet_ntop(AF_INET6
, &adj
->global_ipv6_addrs
[i
],
844 vty_out(vty
, " %s\n", buf
);
847 if (adj
->circuit
&& adj
->circuit
->bfd_config
.enabled
) {
848 vty_out(vty
, " BFD is %s%s\n",
849 adj
->bfd_session
? "active, status "
853 : bfd_get_status_str(bfd_sess_status(
856 for (ALL_LIST_ELEMENTS_RO(adj
->adj_sids
, anode
, sra
)) {
857 const char *adj_type
;
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
;
867 adj_type
= "Adjacency-SID";
868 sid
= sra
->u
.adj_sid
->sid
;
873 backup
= (sra
->type
== ISIS_SR_LAN_BACKUP
) ? " (backup)"
876 vty_out(vty
, " %s %s%s: %u\n",
877 (sra
->nexthop
.family
== AF_INET
) ? "IPv4"
879 adj_type
, backup
, sid
);
886 void isis_adj_build_neigh_list(struct list
*adjdb
, struct list
*list
)
888 struct isis_adjacency
*adj
;
889 struct listnode
*node
;
892 zlog_warn("%s: NULL list", __func__
);
896 for (ALL_LIST_ELEMENTS_RO(adjdb
, node
, adj
)) {
898 zlog_warn("%s: NULL adj", __func__
);
902 if ((adj
->adj_state
== ISIS_ADJ_UP
903 || adj
->adj_state
== ISIS_ADJ_INITIALIZING
))
904 listnode_add(list
, adj
->snpa
);
909 void isis_adj_build_up_list(struct list
*adjdb
, struct list
*list
)
911 struct isis_adjacency
*adj
;
912 struct listnode
*node
;
915 zlog_warn("%s: adjacency DB is empty", __func__
);
920 zlog_warn("%s: NULL list", __func__
);
924 for (ALL_LIST_ELEMENTS_RO(adjdb
, node
, adj
)) {
926 zlog_warn("%s: NULL adj", __func__
);
930 if (adj
->adj_state
== ISIS_ADJ_UP
)
931 listnode_add(list
, adj
);
937 int isis_adj_usage2levels(enum isis_adj_usage usage
)
940 case ISIS_ADJ_LEVEL1
:
942 case ISIS_ADJ_LEVEL2
:
944 case ISIS_ADJ_LEVEL1AND2
:
945 return IS_LEVEL_1
| IS_LEVEL_2
;
950 assert(!"Reached end of function where we are not expecting to");