1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * IS-IS Rout(e)ing protocol - isis_circuit.h
5 * Copyright (C) 2001,2002 Sampo Saaristo
6 * Tampere University of Technology
7 * Institute of Communications Engineering
11 #include <net/ethernet.h>
13 #include <netinet/if_ether.h>
28 #include "lib/northbound_cli.h"
30 #include "isisd/isis_constants.h"
31 #include "isisd/isis_common.h"
32 #include "isisd/isis_flags.h"
33 #include "isisd/isis_circuit.h"
34 #include "isisd/isis_lsp.h"
35 #include "isisd/isis_pdu.h"
36 #include "isisd/isis_network.h"
37 #include "isisd/isis_misc.h"
38 #include "isisd/isis_constants.h"
39 #include "isisd/isis_adjacency.h"
40 #include "isisd/isis_dr.h"
41 #include "isisd/isisd.h"
42 #include "isisd/isis_csm.h"
43 #include "isisd/isis_events.h"
44 #include "isisd/isis_te.h"
45 #include "isisd/isis_mt.h"
46 #include "isisd/isis_errors.h"
47 #include "isisd/isis_tx_queue.h"
48 #include "isisd/isis_nb.h"
49 #include "isisd/isis_ldp_sync.h"
51 DEFINE_MTYPE_STATIC(ISISD
, ISIS_CIRCUIT
, "ISIS circuit");
53 DEFINE_QOBJ_TYPE(isis_circuit
);
55 DEFINE_HOOK(isis_if_new_hook
, (struct interface
*ifp
), (ifp
));
60 int isis_if_new_hook(struct interface
*);
61 int isis_if_delete_hook(struct interface
*);
63 DEFINE_HOOK(isis_circuit_new_hook
, (struct isis_circuit
*circuit
), (circuit
));
64 DEFINE_HOOK(isis_circuit_del_hook
, (struct isis_circuit
*circuit
), (circuit
));
66 static void isis_circuit_enable(struct isis_circuit
*circuit
)
68 struct isis_area
*area
= circuit
->area
;
69 struct interface
*ifp
= circuit
->interface
;
72 area
= isis_area_lookup(circuit
->tag
, ifp
->vrf
->vrf_id
);
74 isis_area_add_circuit(area
, circuit
);
77 if (if_is_operative(ifp
))
78 isis_csm_state_change(IF_UP_FROM_Z
, circuit
, ifp
);
81 static void isis_circuit_disable(struct isis_circuit
*circuit
)
83 struct isis_area
*area
= circuit
->area
;
84 struct interface
*ifp
= circuit
->interface
;
86 if (if_is_operative(ifp
))
87 isis_csm_state_change(IF_DOWN_FROM_Z
, circuit
, ifp
);
90 isis_area_del_circuit(area
, circuit
);
93 struct isis_circuit
*isis_circuit_new(struct interface
*ifp
, const char *tag
)
95 struct isis_circuit
*circuit
;
98 circuit
= XCALLOC(MTYPE_ISIS_CIRCUIT
, sizeof(struct isis_circuit
));
100 circuit
->tag
= XSTRDUP(MTYPE_ISIS_CIRCUIT
, tag
);
106 circuit
->is_type_config
= yang_get_default_enum(
107 "/frr-interface:lib/interface/frr-isisd:isis/circuit-type");
110 circuit
->pad_hellos
= yang_get_default_bool(
111 "/frr-interface:lib/interface/frr-isisd:isis/hello/padding");
112 circuit
->hello_interval
[0] = yang_get_default_uint32(
113 "/frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-1");
114 circuit
->hello_interval
[1] = yang_get_default_uint32(
115 "/frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-2");
116 circuit
->hello_multiplier
[0] = yang_get_default_uint32(
117 "/frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-1");
118 circuit
->hello_multiplier
[1] = yang_get_default_uint32(
119 "/frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-2");
120 circuit
->csnp_interval
[0] = yang_get_default_uint16(
121 "/frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-1");
122 circuit
->csnp_interval
[1] = yang_get_default_uint16(
123 "/frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-2");
124 circuit
->psnp_interval
[0] = yang_get_default_uint16(
125 "/frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-1");
126 circuit
->psnp_interval
[1] = yang_get_default_uint16(
127 "/frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-2");
128 circuit
->priority
[0] = yang_get_default_uint8(
129 "/frr-interface:lib/interface/frr-isisd:isis/priority/level-1");
130 circuit
->priority
[1] = yang_get_default_uint8(
131 "/frr-interface:lib/interface/frr-isisd:isis/priority/level-2");
132 circuit
->metric
[0] = yang_get_default_uint32(
133 "/frr-interface:lib/interface/frr-isisd:isis/metric/level-1");
134 circuit
->metric
[1] = yang_get_default_uint32(
135 "/frr-interface:lib/interface/frr-isisd:isis/metric/level-2");
136 circuit
->te_metric
[0] = yang_get_default_uint32(
137 "/frr-interface:lib/interface/frr-isisd:isis/metric/level-1");
138 circuit
->te_metric
[1] = yang_get_default_uint32(
139 "/frr-interface:lib/interface/frr-isisd:isis/metric/level-2");
141 for (i
= 0; i
< 2; i
++) {
142 circuit
->level_arg
[i
].level
= i
+ 1;
143 circuit
->level_arg
[i
].circuit
= circuit
;
146 circuit
->is_type_config
= IS_LEVEL_1_AND_2
;
148 circuit
->pad_hellos
= 1;
149 for (i
= 0; i
< 2; i
++) {
150 circuit
->hello_interval
[i
] = DEFAULT_HELLO_INTERVAL
;
151 circuit
->hello_multiplier
[i
] = DEFAULT_HELLO_MULTIPLIER
;
152 circuit
->csnp_interval
[i
] = DEFAULT_CSNP_INTERVAL
;
153 circuit
->psnp_interval
[i
] = DEFAULT_PSNP_INTERVAL
;
154 circuit
->priority
[i
] = DEFAULT_PRIORITY
;
155 circuit
->metric
[i
] = DEFAULT_CIRCUIT_METRIC
;
156 circuit
->te_metric
[i
] = DEFAULT_CIRCUIT_METRIC
;
157 circuit
->level_arg
[i
].level
= i
+ 1;
158 circuit
->level_arg
[i
].circuit
= circuit
;
160 #endif /* ifndef FABRICD */
162 circuit
->is_type
= circuit
->is_type_config
;
164 circuit_mt_init(circuit
);
165 isis_lfa_excluded_ifaces_init(circuit
, ISIS_LEVEL1
);
166 isis_lfa_excluded_ifaces_init(circuit
, ISIS_LEVEL2
);
168 circuit
->ldp_sync_info
= ldp_sync_info_create();
169 circuit
->ldp_sync_info
->enabled
= LDP_IGP_SYNC_ENABLED
;
171 QOBJ_REG(circuit
, isis_circuit
);
173 isis_circuit_if_bind(circuit
, ifp
);
175 circuit
->ip_addrs
= list_new();
176 circuit
->ipv6_link
= list_new();
177 circuit
->ipv6_non_link
= list_new();
179 if (ifp
->ifindex
!= IFINDEX_INTERNAL
)
180 isis_circuit_enable(circuit
);
185 void isis_circuit_del(struct isis_circuit
*circuit
)
190 if (circuit
->interface
->ifindex
!= IFINDEX_INTERNAL
)
191 isis_circuit_disable(circuit
);
193 isis_circuit_if_unbind(circuit
, circuit
->interface
);
197 ldp_sync_info_free(&circuit
->ldp_sync_info
);
199 circuit_mt_finish(circuit
);
200 isis_lfa_excluded_ifaces_clear(circuit
, ISIS_LEVEL1
);
201 isis_lfa_excluded_ifaces_clear(circuit
, ISIS_LEVEL2
);
203 list_delete(&circuit
->ip_addrs
);
204 list_delete(&circuit
->ipv6_link
);
205 list_delete(&circuit
->ipv6_non_link
);
208 isis_del_ext_subtlvs(circuit
->ext
);
212 XFREE(MTYPE_TMP
, circuit
->bfd_config
.profile
);
213 XFREE(MTYPE_ISIS_CIRCUIT
, circuit
->tag
);
215 /* and lastly the circuit itself */
216 XFREE(MTYPE_ISIS_CIRCUIT
, circuit
);
221 void isis_circuit_configure(struct isis_circuit
*circuit
,
222 struct isis_area
*area
)
225 circuit
->isis
= area
->isis
;
226 circuit
->area
= area
;
229 * Whenever the is-type of an area is changed, the is-type of each
231 * in that area is updated to a non-empty subset of the area is-type.
232 * Inversely, when configuring a new circuit, this property should be
235 if (area
->is_type
!= IS_LEVEL_1_AND_2
)
236 circuit
->is_type
= area
->is_type
;
239 * Add the circuit into area
241 listnode_add(area
->circuit_list
, circuit
);
243 circuit
->idx
= flags_get_index(&area
->flags
);
245 hook_call(isis_circuit_new_hook
, circuit
);
250 void isis_circuit_deconfigure(struct isis_circuit
*circuit
,
251 struct isis_area
*area
)
253 hook_call(isis_circuit_del_hook
, circuit
);
255 /* Free the index of SRM and SSN flags */
256 flags_free_index(&area
->flags
, circuit
->idx
);
259 /* Reset IS type to configured */
260 circuit
->is_type
= circuit
->is_type_config
;
262 /* Remove circuit from area */
263 assert(circuit
->area
== area
);
264 listnode_delete(area
->circuit_list
, circuit
);
265 circuit
->area
= NULL
;
266 circuit
->isis
= NULL
;
271 struct isis_circuit
*circuit_scan_by_ifp(struct interface
*ifp
)
273 return (struct isis_circuit
*)ifp
->info
;
276 DEFINE_HOOK(isis_circuit_add_addr_hook
, (struct isis_circuit
*circuit
),
279 void isis_circuit_add_addr(struct isis_circuit
*circuit
,
280 struct connected
*connected
)
282 struct listnode
*node
;
283 struct prefix_ipv4
*ipv4
;
284 struct prefix_ipv6
*ipv6
;
286 if (connected
->address
->family
== AF_INET
) {
287 uint32_t addr
= connected
->address
->u
.prefix4
.s_addr
;
289 if (IPV4_NET0(addr
) || IPV4_NET127(addr
) || IN_CLASSD(addr
)
290 || IPV4_LINKLOCAL(addr
))
293 for (ALL_LIST_ELEMENTS_RO(circuit
->ip_addrs
, node
, ipv4
))
294 if (prefix_same((struct prefix
*)ipv4
,
298 ipv4
= prefix_ipv4_new();
299 ipv4
->prefixlen
= connected
->address
->prefixlen
;
300 ipv4
->prefix
= connected
->address
->u
.prefix4
;
301 listnode_add(circuit
->ip_addrs
, ipv4
);
303 /* Update Local IP address parameter if MPLS TE is enable */
304 if (circuit
->ext
&& circuit
->area
305 && IS_MPLS_TE(circuit
->area
->mta
)) {
306 circuit
->ext
->local_addr
.s_addr
= ipv4
->prefix
.s_addr
;
307 SET_SUBTLV(circuit
->ext
, EXT_LOCAL_ADDR
);
311 lsp_regenerate_schedule(circuit
->area
, circuit
->is_type
,
316 zlog_debug("Added IP address %pFX to circuit %s",
318 circuit
->interface
->name
);
319 #endif /* EXTREME_DEBUG */
321 if (connected
->address
->family
== AF_INET6
) {
322 if (IN6_IS_ADDR_LOOPBACK(&connected
->address
->u
.prefix6
))
325 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_link
, node
, ipv6
))
326 if (prefix_same((struct prefix
*)ipv6
,
329 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_non_link
, node
, ipv6
))
330 if (prefix_same((struct prefix
*)ipv6
,
334 ipv6
= prefix_ipv6_new();
335 ipv6
->prefixlen
= connected
->address
->prefixlen
;
336 ipv6
->prefix
= connected
->address
->u
.prefix6
;
338 if (IN6_IS_ADDR_LINKLOCAL(&ipv6
->prefix
))
339 listnode_add(circuit
->ipv6_link
, ipv6
);
341 listnode_add(circuit
->ipv6_non_link
, ipv6
);
342 /* Update Local IPv6 address param. if MPLS TE is on */
343 if (circuit
->ext
&& circuit
->area
344 && IS_MPLS_TE(circuit
->area
->mta
)) {
345 IPV6_ADDR_COPY(&circuit
->ext
->local_addr6
,
347 SET_SUBTLV(circuit
->ext
, EXT_LOCAL_ADDR6
);
351 lsp_regenerate_schedule(circuit
->area
, circuit
->is_type
,
356 zlog_debug("Added IPv6 address %pFX to circuit %s",
358 circuit
->interface
->name
);
359 #endif /* EXTREME_DEBUG */
362 hook_call(isis_circuit_add_addr_hook
, circuit
);
367 void isis_circuit_del_addr(struct isis_circuit
*circuit
,
368 struct connected
*connected
)
370 struct prefix_ipv4
*ipv4
, *ip
= NULL
;
371 struct listnode
*node
;
372 struct prefix_ipv6
*ipv6
, *ip6
= NULL
;
375 if (connected
->address
->family
== AF_INET
) {
376 ipv4
= prefix_ipv4_new();
377 ipv4
->prefixlen
= connected
->address
->prefixlen
;
378 ipv4
->prefix
= connected
->address
->u
.prefix4
;
380 for (ALL_LIST_ELEMENTS_RO(circuit
->ip_addrs
, node
, ip
))
381 if (prefix_same((struct prefix
*)ip
,
382 (struct prefix
*)ipv4
))
386 listnode_delete(circuit
->ip_addrs
, ip
);
387 prefix_ipv4_free(&ip
);
389 lsp_regenerate_schedule(circuit
->area
,
390 circuit
->is_type
, 0);
393 "Nonexistent ip address %pFX removal attempt from circuit %s",
394 connected
->address
, circuit
->interface
->name
);
395 zlog_warn("Current ip addresses on %s:",
396 circuit
->interface
->name
);
397 for (ALL_LIST_ELEMENTS_RO(circuit
->ip_addrs
, node
,
399 zlog_warn(" %pFX", ip
);
401 zlog_warn("End of addresses");
404 prefix_ipv4_free(&ipv4
);
406 if (connected
->address
->family
== AF_INET6
) {
407 ipv6
= prefix_ipv6_new();
408 ipv6
->prefixlen
= connected
->address
->prefixlen
;
409 ipv6
->prefix
= connected
->address
->u
.prefix6
;
411 if (IN6_IS_ADDR_LINKLOCAL(&ipv6
->prefix
)) {
412 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_link
, node
,
414 if (prefix_same((struct prefix
*)ip6
,
415 (struct prefix
*)ipv6
))
419 listnode_delete(circuit
->ipv6_link
, ip6
);
420 prefix_ipv6_free(&ip6
);
424 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_non_link
, node
,
426 if (prefix_same((struct prefix
*)ip6
,
427 (struct prefix
*)ipv6
))
431 listnode_delete(circuit
->ipv6_non_link
, ip6
);
432 prefix_ipv6_free(&ip6
);
439 "Nonexistent ip address %pFX removal attempt from circuit %s",
440 connected
->address
, circuit
->interface
->name
);
441 zlog_warn("Current ip addresses on %s:",
442 circuit
->interface
->name
);
443 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_link
, node
,
445 zlog_warn(" %pFX", (struct prefix
*)ip6
);
447 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_non_link
, node
,
449 zlog_warn(" %pFX", (struct prefix
*)ip6
);
450 zlog_warn("End of addresses");
451 } else if (circuit
->area
)
452 lsp_regenerate_schedule(circuit
->area
, circuit
->is_type
,
455 prefix_ipv6_free(&ipv6
);
460 static uint8_t isis_circuit_id_gen(struct isis
*isis
, struct interface
*ifp
)
462 /* Circuit ids MUST be unique for any broadcast circuits. Otherwise,
463 * Pseudo-Node LSPs cannot be generated correctly.
465 * Currently, allocate one circuit ID for any circuit, limiting the total
466 * numer of circuits IS-IS can run on to 255.
468 * We should revisit this when implementing 3-way adjacencies for p2p, since
469 * we then have extended interface IDs available.
471 uint8_t id
= ifp
->ifindex
;
474 for (i
= 0; i
< 256; i
++) {
475 if (id
&& !_ISIS_CHECK_FLAG(isis
->circuit_ids_used
, id
))
481 zlog_warn("Could not allocate a circuit id for '%s'",
486 _ISIS_SET_FLAG(isis
->circuit_ids_used
, id
);
490 void isis_circuit_if_add(struct isis_circuit
*circuit
, struct interface
*ifp
)
492 struct listnode
*node
, *nnode
;
493 struct connected
*conn
;
495 if (if_is_broadcast(ifp
)) {
496 if (fabricd
|| circuit
->circ_type_config
== CIRCUIT_T_P2P
)
497 circuit
->circ_type
= CIRCUIT_T_P2P
;
499 circuit
->circ_type
= CIRCUIT_T_BROADCAST
;
500 } else if (if_is_pointopoint(ifp
)) {
501 circuit
->circ_type
= CIRCUIT_T_P2P
;
502 } else if (if_is_loopback(ifp
)) {
503 circuit
->circ_type
= CIRCUIT_T_LOOPBACK
;
504 circuit
->is_passive
= 1;
506 /* It's normal in case of loopback etc. */
508 zlog_debug("%s: unsupported media", __func__
);
509 circuit
->circ_type
= CIRCUIT_T_UNKNOWN
;
512 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nnode
, conn
))
513 isis_circuit_add_addr(circuit
, conn
);
517 void isis_circuit_if_del(struct isis_circuit
*circuit
, struct interface
*ifp
)
519 struct listnode
*node
, *nnode
;
520 struct connected
*conn
;
522 assert(circuit
->interface
== ifp
);
524 /* destroy addresses */
525 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nnode
, conn
))
526 isis_circuit_del_addr(circuit
, conn
);
528 circuit
->circ_type
= CIRCUIT_T_UNKNOWN
;
531 void isis_circuit_if_bind(struct isis_circuit
*circuit
, struct interface
*ifp
)
533 assert(circuit
!= NULL
);
535 if (circuit
->interface
)
536 assert(circuit
->interface
== ifp
);
538 circuit
->interface
= ifp
;
540 assert(ifp
->info
== circuit
);
545 void isis_circuit_if_unbind(struct isis_circuit
*circuit
, struct interface
*ifp
)
547 assert(circuit
!= NULL
);
549 assert(circuit
->interface
== ifp
);
550 assert(ifp
->info
== circuit
);
551 circuit
->interface
= NULL
;
555 static void isis_circuit_update_all_srmflags(struct isis_circuit
*circuit
,
558 struct isis_area
*area
;
559 struct isis_lsp
*lsp
;
563 area
= circuit
->area
;
565 for (level
= ISIS_LEVEL1
; level
<= ISIS_LEVEL2
; level
++) {
566 if (!(level
& circuit
->is_type
))
569 if (!lspdb_count(&area
->lspdb
[level
- 1]))
572 frr_each (lspdb
, &area
->lspdb
[level
- 1], lsp
) {
574 isis_tx_queue_add(circuit
->tx_queue
, lsp
,
577 isis_tx_queue_del(circuit
->tx_queue
, lsp
);
583 size_t isis_circuit_pdu_size(struct isis_circuit
*circuit
)
585 return ISO_MTU(circuit
);
588 static bool isis_circuit_lfa_enabled(struct isis_circuit
*circuit
, int level
)
590 return (circuit
->lfa_protection
[level
- 1] ||
591 circuit
->rlfa_protection
[level
- 1] ||
592 circuit
->tilfa_protection
[level
- 1]);
595 void isis_circuit_switchover_routes(struct isis_circuit
*circuit
, int family
,
596 union g_addr
*nexthop_ip
, ifindex_t ifindex
)
603 is_type
= circuit
->area
->is_type
;
604 if ((is_type
== IS_LEVEL_1
|| is_type
== IS_LEVEL_1_AND_2
) &&
605 isis_circuit_lfa_enabled(circuit
, IS_LEVEL_1
))
606 isis_area_switchover_routes(circuit
->area
, family
, nexthop_ip
,
607 ifindex
, IS_LEVEL_1
);
608 if ((is_type
== IS_LEVEL_2
|| is_type
== IS_LEVEL_1_AND_2
) &&
609 isis_circuit_lfa_enabled(circuit
, IS_LEVEL_2
))
610 isis_area_switchover_routes(circuit
->area
, family
, nexthop_ip
,
611 ifindex
, IS_LEVEL_2
);
614 void isis_circuit_stream(struct isis_circuit
*circuit
, struct stream
**stream
)
616 size_t stream_size
= isis_circuit_pdu_size(circuit
);
619 *stream
= stream_new(stream_size
);
621 if (STREAM_SIZE(*stream
) != stream_size
)
622 stream_resize_inplace(stream
, stream_size
);
623 stream_reset(*stream
);
627 void isis_circuit_prepare(struct isis_circuit
*circuit
)
629 #if ISIS_METHOD != ISIS_METHOD_DLPI
630 thread_add_read(master
, isis_receive
, circuit
, circuit
->fd
,
633 thread_add_timer_msec(master
, isis_receive
, circuit
,
634 listcount(circuit
->area
->circuit_list
) * 100,
639 int isis_circuit_up(struct isis_circuit
*circuit
)
643 /* Set the flags for all the lsps of the circuit. */
644 isis_circuit_update_all_srmflags(circuit
, 1);
646 if (circuit
->state
== C_STATE_UP
)
649 if (circuit
->is_passive
) {
650 circuit
->last_uptime
= time(NULL
);
651 /* make sure the union fields are initialized, else we
652 * could end with garbage values from a previous circuit
653 * type, which would then cause a segfault when building
654 * LSPs or computing the SPF tree
656 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
) {
657 circuit
->u
.bc
.adjdb
[0] = list_new();
658 circuit
->u
.bc
.adjdb
[1] = list_new();
659 } else if (circuit
->circ_type
== CIRCUIT_T_P2P
) {
660 circuit
->u
.p2p
.neighbor
= NULL
;
665 if (circuit
->area
->lsp_mtu
> isis_circuit_pdu_size(circuit
)) {
668 "Interface MTU %zu on %s is too low to support area lsp mtu %u!",
669 isis_circuit_pdu_size(circuit
),
670 circuit
->interface
->name
, circuit
->area
->lsp_mtu
);
672 /* Allow ISIS to continue configuration. With this
673 * configuration failure ISIS will attempt to send lsp
674 * packets but will fail until the mtu is configured properly
678 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
) {
679 circuit
->circuit_id
=
680 isis_circuit_id_gen(circuit
->isis
, circuit
->interface
);
681 if (!circuit
->circuit_id
) {
684 "There are already 255 broadcast circuits active!");
689 * Get the Hardware Address
691 if (circuit
->interface
->hw_addr_len
!= ETH_ALEN
) {
692 zlog_warn("unsupported link layer");
694 memcpy(circuit
->u
.bc
.snpa
, circuit
->interface
->hw_addr
,
699 zlog_debug("%s: if_id %d, isomtu %d snpa %s", __func__
,
700 circuit
->interface
->ifindex
,
702 snpa_print(circuit
->u
.bc
.snpa
));
703 #endif /* EXTREME_DEBUG */
705 circuit
->u
.bc
.adjdb
[0] = list_new();
706 circuit
->u
.bc
.adjdb
[1] = list_new();
709 * ISO 10589 - 8.4.1 Enabling of broadcast circuits
712 /* initilizing the hello sending threads
716 /* 8.4.1 a) commence sending of IIH PDUs */
718 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVEL2
; level
++) {
719 if (!(circuit
->is_type
& level
))
722 send_hello_sched(circuit
, level
, TRIGGERED_IIH_DELAY
);
723 circuit
->u
.bc
.lan_neighs
[level
- 1] = list_new();
725 thread_add_timer(master
, isis_run_dr
,
726 &circuit
->level_arg
[level
- 1],
727 2 * circuit
->hello_interval
[level
- 1],
728 &circuit
->u
.bc
.t_run_dr
[level
- 1]);
731 /* 8.4.1 b) FIXME: solicit ES - 8.4.6 */
732 /* 8.4.1 c) FIXME: listen for ESH PDUs */
733 } else if (circuit
->circ_type
== CIRCUIT_T_P2P
) {
734 /* initializing the hello send threads
737 circuit
->u
.p2p
.neighbor
= NULL
;
738 send_hello_sched(circuit
, 0, TRIGGERED_IIH_DELAY
);
741 /* initializing PSNP timers */
742 if (circuit
->is_type
& IS_LEVEL_1
)
744 master
, send_l1_psnp
, circuit
,
745 isis_jitter(circuit
->psnp_interval
[0], PSNP_JITTER
),
746 &circuit
->t_send_psnp
[0]);
748 if (circuit
->is_type
& IS_LEVEL_2
)
750 master
, send_l2_psnp
, circuit
,
751 isis_jitter(circuit
->psnp_interval
[1], PSNP_JITTER
),
752 &circuit
->t_send_psnp
[1]);
754 /* unified init for circuits; ignore warnings below this level */
755 retv
= isis_sock_init(circuit
);
756 if (retv
!= ISIS_OK
) {
757 isis_circuit_down(circuit
);
761 /* initialize the circuit streams after opening connection */
762 isis_circuit_stream(circuit
, &circuit
->rcv_stream
);
763 isis_circuit_stream(circuit
, &circuit
->snd_stream
);
765 isis_circuit_prepare(circuit
);
767 circuit
->tx_queue
= isis_tx_queue_new(circuit
, send_lsp
);
769 circuit
->last_uptime
= time(NULL
);
771 if (circuit
->area
->mta
&& circuit
->area
->mta
->status
)
772 isis_link_params_update(circuit
, circuit
->interface
);
774 isis_if_ldp_sync_enable(circuit
);
777 /* send northbound notification */
778 isis_notif_if_state_change(circuit
, false);
779 #endif /* ifndef FABRICD */
784 void isis_circuit_down(struct isis_circuit
*circuit
)
787 /* send northbound notification */
788 isis_notif_if_state_change(circuit
, true);
789 #endif /* ifndef FABRICD */
791 isis_if_ldp_sync_disable(circuit
);
793 /* log adjacency changes if configured to do so */
794 if (circuit
->area
->log_adj_changes
) {
795 struct isis_adjacency
*adj
= NULL
;
796 if (circuit
->circ_type
== CIRCUIT_T_P2P
) {
797 adj
= circuit
->u
.p2p
.neighbor
;
800 adj
, adj
->adj_state
, ISIS_ADJ_DOWN
,
801 "circuit is being brought down");
802 } else if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
) {
803 struct list
*adj_list
;
804 struct listnode
*node
;
805 if (circuit
->u
.bc
.adjdb
[0]) {
806 adj_list
= list_new();
807 isis_adj_build_up_list(circuit
->u
.bc
.adjdb
[0],
809 for (ALL_LIST_ELEMENTS_RO(adj_list
, node
, adj
))
813 "circuit is being brought down");
814 list_delete(&adj_list
);
816 if (circuit
->u
.bc
.adjdb
[1]) {
817 adj_list
= list_new();
818 isis_adj_build_up_list(circuit
->u
.bc
.adjdb
[1],
820 for (ALL_LIST_ELEMENTS_RO(adj_list
, node
, adj
))
824 "circuit is being brought down");
825 list_delete(&adj_list
);
830 /* Clear the flags for all the lsps of the circuit. */
831 isis_circuit_update_all_srmflags(circuit
, 0);
833 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
) {
834 /* destroy neighbour lists */
835 if (circuit
->u
.bc
.lan_neighs
[0]) {
836 list_delete(&circuit
->u
.bc
.lan_neighs
[0]);
837 circuit
->u
.bc
.lan_neighs
[0] = NULL
;
839 if (circuit
->u
.bc
.lan_neighs
[1]) {
840 list_delete(&circuit
->u
.bc
.lan_neighs
[1]);
841 circuit
->u
.bc
.lan_neighs
[1] = NULL
;
843 /* destroy adjacency databases */
844 if (circuit
->u
.bc
.adjdb
[0]) {
845 circuit
->u
.bc
.adjdb
[0]->del
= isis_delete_adj
;
846 list_delete(&circuit
->u
.bc
.adjdb
[0]);
847 circuit
->u
.bc
.adjdb
[0] = NULL
;
849 if (circuit
->u
.bc
.adjdb
[1]) {
850 circuit
->u
.bc
.adjdb
[1]->del
= isis_delete_adj
;
851 list_delete(&circuit
->u
.bc
.adjdb
[1]);
852 circuit
->u
.bc
.adjdb
[1] = NULL
;
854 if (circuit
->u
.bc
.is_dr
[0]) {
855 isis_dr_resign(circuit
, 1);
856 circuit
->u
.bc
.is_dr
[0] = 0;
858 memset(circuit
->u
.bc
.l1_desig_is
, 0, ISIS_SYS_ID_LEN
+ 1);
859 if (circuit
->u
.bc
.is_dr
[1]) {
860 isis_dr_resign(circuit
, 2);
861 circuit
->u
.bc
.is_dr
[1] = 0;
863 memset(circuit
->u
.bc
.l2_desig_is
, 0, ISIS_SYS_ID_LEN
+ 1);
864 memset(circuit
->u
.bc
.snpa
, 0, ETH_ALEN
);
866 THREAD_OFF(circuit
->u
.bc
.t_send_lan_hello
[0]);
867 THREAD_OFF(circuit
->u
.bc
.t_send_lan_hello
[1]);
868 THREAD_OFF(circuit
->u
.bc
.t_run_dr
[0]);
869 THREAD_OFF(circuit
->u
.bc
.t_run_dr
[1]);
870 THREAD_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[0]);
871 THREAD_OFF(circuit
->u
.bc
.t_refresh_pseudo_lsp
[1]);
872 circuit
->lsp_regenerate_pending
[0] = 0;
873 circuit
->lsp_regenerate_pending
[1] = 0;
875 _ISIS_CLEAR_FLAG(circuit
->isis
->circuit_ids_used
,
876 circuit
->circuit_id
);
877 circuit
->circuit_id
= 0;
878 } else if (circuit
->circ_type
== CIRCUIT_T_P2P
) {
879 isis_delete_adj(circuit
->u
.p2p
.neighbor
);
880 circuit
->u
.p2p
.neighbor
= NULL
;
881 THREAD_OFF(circuit
->u
.p2p
.t_send_p2p_hello
);
885 * All adjacencies have to be gone, delete snmp list
886 * and reset snmpd idx generator
888 if (circuit
->snmp_adj_list
!= NULL
)
889 list_delete(&circuit
->snmp_adj_list
);
891 circuit
->snmp_adj_idx_gen
= 0;
893 /* Cancel all active threads */
894 THREAD_OFF(circuit
->t_send_csnp
[0]);
895 THREAD_OFF(circuit
->t_send_csnp
[1]);
896 THREAD_OFF(circuit
->t_send_psnp
[0]);
897 THREAD_OFF(circuit
->t_send_psnp
[1]);
898 THREAD_OFF(circuit
->t_read
);
900 if (circuit
->tx_queue
) {
901 isis_tx_queue_free(circuit
->tx_queue
);
902 circuit
->tx_queue
= NULL
;
905 /* send one gratuitous hello to spead up convergence */
906 if (circuit
->state
== C_STATE_UP
) {
907 if (circuit
->is_type
& IS_LEVEL_1
)
908 send_hello(circuit
, IS_LEVEL_1
);
909 if (circuit
->is_type
& IS_LEVEL_2
)
910 send_hello(circuit
, IS_LEVEL_2
);
913 circuit
->upadjcount
[0] = 0;
914 circuit
->upadjcount
[1] = 0;
916 /* close the socket */
922 if (circuit
->rcv_stream
!= NULL
) {
923 stream_free(circuit
->rcv_stream
);
924 circuit
->rcv_stream
= NULL
;
927 if (circuit
->snd_stream
!= NULL
) {
928 stream_free(circuit
->snd_stream
);
929 circuit
->snd_stream
= NULL
;
932 thread_cancel_event(master
, circuit
);
937 void circuit_update_nlpids(struct isis_circuit
*circuit
)
939 circuit
->nlpids
.count
= 0;
941 if (circuit
->ip_router
) {
942 circuit
->nlpids
.nlpids
[0] = NLPID_IP
;
943 circuit
->nlpids
.count
++;
945 if (circuit
->ipv6_router
) {
946 circuit
->nlpids
.nlpids
[circuit
->nlpids
.count
] = NLPID_IPV6
;
947 circuit
->nlpids
.count
++;
952 void isis_circuit_print_json(struct isis_circuit
*circuit
,
953 struct json_object
*json
, char detail
)
956 json_object
*iface_json
, *ipv4_addr_json
, *ipv6_link_json
,
957 *ipv6_non_link_json
, *hold_json
, *lan_prio_json
, *levels_json
,
959 char buf_prx
[INET6_BUFSIZ
];
962 snprintfrr(buf
, sizeof(buf
), "0x%x", circuit
->circuit_id
);
963 if (detail
== ISIS_UI_LEVEL_BRIEF
) {
964 iface_json
= json_object_new_object();
965 json_object_object_add(json
, "interface", iface_json
);
966 json_object_string_add(iface_json
, "name",
967 circuit
->interface
->name
);
968 json_object_string_add(iface_json
, "circuit-id", buf
);
969 json_object_string_add(iface_json
, "state",
970 circuit_state2string(circuit
->state
));
971 json_object_string_add(iface_json
, "type",
972 circuit_type2string(circuit
->circ_type
));
973 json_object_string_add(iface_json
, "level",
974 circuit_t2string(circuit
->is_type
));
977 if (detail
== ISIS_UI_LEVEL_DETAIL
) {
978 struct listnode
*node
;
979 struct prefix
*ip_addr
;
981 iface_json
= json_object_new_object();
982 json_object_object_add(json
, "interface", iface_json
);
983 json_object_string_add(iface_json
, "name",
984 circuit
->interface
->name
);
985 json_object_string_add(iface_json
, "state",
986 circuit_state2string(circuit
->state
));
987 if (circuit
->is_passive
)
988 json_object_string_add(iface_json
, "is-passive",
991 json_object_string_add(iface_json
, "is-passive",
993 json_object_string_add(iface_json
, "circuit-id", buf
);
994 json_object_string_add(iface_json
, "type",
995 circuit_type2string(circuit
->circ_type
));
996 json_object_string_add(iface_json
, "level",
997 circuit_t2string(circuit
->is_type
));
998 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
999 json_object_string_add(iface_json
, "snpa",
1000 snpa_print(circuit
->u
.bc
.snpa
));
1003 levels_json
= json_object_new_array();
1004 json_object_object_add(iface_json
, "levels", levels_json
);
1005 for (level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++) {
1006 if ((circuit
->is_type
& level
) == 0)
1008 level_json
= json_object_new_object();
1009 json_object_string_add(level_json
, "level",
1010 circuit_t2string(level
));
1011 if (circuit
->area
->newmetric
)
1012 json_object_int_add(level_json
, "metric",
1013 circuit
->te_metric
[0]);
1015 json_object_int_add(level_json
, "metric",
1016 circuit
->metric
[0]);
1017 if (!circuit
->is_passive
) {
1018 json_object_int_add(level_json
,
1020 circuit
->upadjcount
[0]);
1021 json_object_int_add(level_json
,
1023 circuit
->hello_interval
[0]);
1024 hold_json
= json_object_new_object();
1025 json_object_object_add(level_json
, "holddown",
1027 json_object_int_add(
1029 circuit
->hello_multiplier
[0]);
1030 json_object_string_add(
1032 (circuit
->pad_hellos
? "yes" : "no"));
1033 json_object_int_add(level_json
, "cnsp-interval",
1034 circuit
->csnp_interval
[0]);
1035 json_object_int_add(level_json
, "psnp-interval",
1036 circuit
->psnp_interval
[0]);
1037 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
) {
1039 json_object_new_object();
1040 json_object_object_add(level_json
,
1043 json_object_int_add(
1044 lan_prio_json
, "priority",
1045 circuit
->priority
[0]);
1046 json_object_string_add(
1047 lan_prio_json
, "is-dis",
1048 (circuit
->u
.bc
.is_dr
[0]
1053 json_object_array_add(levels_json
, level_json
);
1056 if (listcount(circuit
->ip_addrs
) > 0) {
1057 ipv4_addr_json
= json_object_new_object();
1058 json_object_object_add(iface_json
, "ip-prefix",
1060 for (ALL_LIST_ELEMENTS_RO(circuit
->ip_addrs
, node
,
1062 snprintfrr(buf_prx
, INET6_BUFSIZ
, "%pFX",
1064 json_object_string_add(ipv4_addr_json
, "ip",
1068 if (listcount(circuit
->ipv6_link
) > 0) {
1069 ipv6_link_json
= json_object_new_object();
1070 json_object_object_add(iface_json
, "ipv6-link-locals",
1072 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_link
, node
,
1074 snprintfrr(buf_prx
, INET6_BUFSIZ
, "%pFX",
1076 json_object_string_add(ipv6_link_json
, "ipv6",
1080 if (listcount(circuit
->ipv6_non_link
) > 0) {
1081 ipv6_non_link_json
= json_object_new_object();
1082 json_object_object_add(iface_json
, "ipv6-prefixes",
1083 ipv6_non_link_json
);
1084 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_non_link
, node
,
1086 snprintfrr(buf_prx
, INET6_BUFSIZ
, "%pFX",
1088 json_object_string_add(ipv6_non_link_json
,
1096 void isis_circuit_print_vty(struct isis_circuit
*circuit
, struct vty
*vty
,
1099 if (detail
== ISIS_UI_LEVEL_BRIEF
) {
1100 vty_out(vty
, " %-12s", circuit
->interface
->name
);
1101 vty_out(vty
, "0x%-7x", circuit
->circuit_id
);
1102 vty_out(vty
, "%-9s", circuit_state2string(circuit
->state
));
1103 vty_out(vty
, "%-9s", circuit_type2string(circuit
->circ_type
));
1104 vty_out(vty
, "%-9s", circuit_t2string(circuit
->is_type
));
1108 if (detail
== ISIS_UI_LEVEL_DETAIL
) {
1109 struct listnode
*node
;
1110 struct prefix
*ip_addr
;
1112 vty_out(vty
, " Interface: %s", circuit
->interface
->name
);
1113 vty_out(vty
, ", State: %s",
1114 circuit_state2string(circuit
->state
));
1115 if (circuit
->is_passive
)
1116 vty_out(vty
, ", Passive");
1118 vty_out(vty
, ", Active");
1119 vty_out(vty
, ", Circuit Id: 0x%x", circuit
->circuit_id
);
1121 vty_out(vty
, " Type: %s",
1122 circuit_type2string(circuit
->circ_type
));
1123 vty_out(vty
, ", Level: %s", circuit_t2string(circuit
->is_type
));
1124 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1125 vty_out(vty
, ", SNPA: %-10s",
1126 snpa_print(circuit
->u
.bc
.snpa
));
1128 if (circuit
->is_type
& IS_LEVEL_1
) {
1129 vty_out(vty
, " Level-1 Information:\n");
1130 if (circuit
->area
->newmetric
)
1131 vty_out(vty
, " Metric: %d",
1132 circuit
->te_metric
[0]);
1134 vty_out(vty
, " Metric: %d",
1135 circuit
->metric
[0]);
1136 if (!circuit
->is_passive
) {
1137 vty_out(vty
, ", Active neighbors: %u\n",
1138 circuit
->upadjcount
[0]);
1140 " Hello interval: %u, Holddown count: %u %s\n",
1141 circuit
->hello_interval
[0],
1142 circuit
->hello_multiplier
[0],
1143 (circuit
->pad_hellos
? "(pad)"
1146 " CNSP interval: %u, PSNP interval: %u\n",
1147 circuit
->csnp_interval
[0],
1148 circuit
->psnp_interval
[0]);
1149 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1151 " LAN Priority: %u, %s\n",
1152 circuit
->priority
[0],
1153 (circuit
->u
.bc
.is_dr
[0]
1160 if (circuit
->is_type
& IS_LEVEL_2
) {
1161 vty_out(vty
, " Level-2 Information:\n");
1162 if (circuit
->area
->newmetric
)
1163 vty_out(vty
, " Metric: %d",
1164 circuit
->te_metric
[1]);
1166 vty_out(vty
, " Metric: %d",
1167 circuit
->metric
[1]);
1168 if (!circuit
->is_passive
) {
1169 vty_out(vty
, ", Active neighbors: %u\n",
1170 circuit
->upadjcount
[1]);
1172 " Hello interval: %u, Holddown count: %u %s\n",
1173 circuit
->hello_interval
[1],
1174 circuit
->hello_multiplier
[1],
1175 (circuit
->pad_hellos
? "(pad)"
1178 " CNSP interval: %u, PSNP interval: %u\n",
1179 circuit
->csnp_interval
[1],
1180 circuit
->psnp_interval
[1]);
1181 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
1183 " LAN Priority: %u, %s\n",
1184 circuit
->priority
[1],
1185 (circuit
->u
.bc
.is_dr
[1]
1192 if (listcount(circuit
->ip_addrs
) > 0) {
1193 vty_out(vty
, " IP Prefix(es):\n");
1194 for (ALL_LIST_ELEMENTS_RO(circuit
->ip_addrs
, node
,
1196 vty_out(vty
, " %pFX\n", ip_addr
);
1198 if (listcount(circuit
->ipv6_link
) > 0) {
1199 vty_out(vty
, " IPv6 Link-Locals:\n");
1200 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_link
, node
,
1202 vty_out(vty
, " %pFX\n", ip_addr
);
1204 if (listcount(circuit
->ipv6_non_link
) > 0) {
1205 vty_out(vty
, " IPv6 Prefixes:\n");
1206 for (ALL_LIST_ELEMENTS_RO(circuit
->ipv6_non_link
, node
,
1208 vty_out(vty
, " %pFX\n", ip_addr
);
1217 DEFINE_HOOK(isis_circuit_config_write
,
1218 (struct isis_circuit
*circuit
, struct vty
*vty
),
1221 static int isis_interface_config_write(struct vty
*vty
)
1223 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
1225 struct interface
*ifp
;
1226 struct isis_circuit
*circuit
;
1229 FOR_ALL_INTERFACES (vrf
, ifp
) {
1231 if_vty_config_start(vty
, ifp
);
1235 vty_out(vty
, " description %s\n", ifp
->desc
);
1240 circuit
= circuit_scan_by_ifp(ifp
);
1241 if (circuit
== NULL
)
1243 if (circuit
->ip_router
) {
1244 vty_out(vty
, " ip router " PROTO_NAME
" %s\n",
1248 if (circuit
->is_passive
) {
1249 vty_out(vty
, " " PROTO_NAME
" passive\n");
1252 if (circuit
->circ_type_config
== CIRCUIT_T_P2P
) {
1253 vty_out(vty
, " " PROTO_NAME
" network point-to-point\n");
1256 if (circuit
->ipv6_router
) {
1257 vty_out(vty
, " ipv6 router " PROTO_NAME
" %s\n",
1262 /* ISIS - circuit type */
1264 if (circuit
->is_type
== IS_LEVEL_1
) {
1265 vty_out(vty
, " " PROTO_NAME
" circuit-type level-1\n");
1268 if (circuit
->is_type
== IS_LEVEL_2
) {
1270 " " PROTO_NAME
" circuit-type level-2-only\n");
1276 /* ISIS - CSNP interval */
1277 if (circuit
->csnp_interval
[0]
1278 == circuit
->csnp_interval
[1]) {
1279 if (circuit
->csnp_interval
[0]
1280 != DEFAULT_CSNP_INTERVAL
) {
1281 vty_out(vty
, " " PROTO_NAME
" csnp-interval %d\n",
1282 circuit
->csnp_interval
[0]);
1286 for (i
= 0; i
< 2; i
++) {
1287 if (circuit
->csnp_interval
[i
]
1288 != DEFAULT_CSNP_INTERVAL
) {
1290 " " PROTO_NAME
" csnp-interval %d level-%d\n",
1291 circuit
->csnp_interval
1299 /* ISIS - PSNP interval */
1300 if (circuit
->psnp_interval
[0]
1301 == circuit
->psnp_interval
[1]) {
1302 if (circuit
->psnp_interval
[0]
1303 != DEFAULT_PSNP_INTERVAL
) {
1304 vty_out(vty
, " " PROTO_NAME
" psnp-interval %d\n",
1305 circuit
->psnp_interval
[0]);
1309 for (i
= 0; i
< 2; i
++) {
1310 if (circuit
->psnp_interval
[i
]
1311 != DEFAULT_PSNP_INTERVAL
) {
1313 " " PROTO_NAME
" psnp-interval %d level-%d\n",
1314 circuit
->psnp_interval
1322 /* ISIS - Hello padding - Defaults to true so only
1323 * display if false */
1324 if (circuit
->pad_hellos
== 0) {
1325 vty_out(vty
, " no " PROTO_NAME
" hello padding\n");
1329 if (circuit
->disable_threeway_adj
) {
1330 vty_out(vty
, " no isis three-way-handshake\n");
1334 /* ISIS - Hello interval */
1335 if (circuit
->hello_interval
[0]
1336 == circuit
->hello_interval
[1]) {
1337 if (circuit
->hello_interval
[0]
1338 != DEFAULT_HELLO_INTERVAL
) {
1340 " " PROTO_NAME
" hello-interval %d\n",
1341 circuit
->hello_interval
[0]);
1345 for (i
= 0; i
< 2; i
++) {
1346 if (circuit
->hello_interval
[i
]
1347 != DEFAULT_HELLO_INTERVAL
) {
1349 " " PROTO_NAME
" hello-interval %d level-%d\n",
1350 circuit
->hello_interval
1358 /* ISIS - Hello Multiplier */
1359 if (circuit
->hello_multiplier
[0]
1360 == circuit
->hello_multiplier
[1]) {
1361 if (circuit
->hello_multiplier
[0]
1362 != DEFAULT_HELLO_MULTIPLIER
) {
1364 " " PROTO_NAME
" hello-multiplier %d\n",
1365 circuit
->hello_multiplier
[0]);
1369 for (i
= 0; i
< 2; i
++) {
1370 if (circuit
->hello_multiplier
[i
]
1371 != DEFAULT_HELLO_MULTIPLIER
) {
1373 " " PROTO_NAME
" hello-multiplier %d level-%d\n",
1374 circuit
->hello_multiplier
1382 /* ISIS - Priority */
1383 if (circuit
->priority
[0] == circuit
->priority
[1]) {
1384 if (circuit
->priority
[0] != DEFAULT_PRIORITY
) {
1385 vty_out(vty
, " " PROTO_NAME
" priority %d\n",
1386 circuit
->priority
[0]);
1390 for (i
= 0; i
< 2; i
++) {
1391 if (circuit
->priority
[i
]
1392 != DEFAULT_PRIORITY
) {
1394 " " PROTO_NAME
" priority %d level-%d\n",
1395 circuit
->priority
[i
],
1403 if (circuit
->te_metric
[0] == circuit
->te_metric
[1]) {
1404 if (circuit
->te_metric
[0]
1405 != DEFAULT_CIRCUIT_METRIC
) {
1406 vty_out(vty
, " " PROTO_NAME
" metric %d\n",
1407 circuit
->te_metric
[0]);
1411 for (i
= 0; i
< 2; i
++) {
1412 if (circuit
->te_metric
[i
]
1413 != DEFAULT_CIRCUIT_METRIC
) {
1415 " " PROTO_NAME
" metric %d level-%d\n",
1416 circuit
->te_metric
[i
],
1422 if (circuit
->passwd
.type
== ISIS_PASSWD_TYPE_HMAC_MD5
) {
1423 vty_out(vty
, " " PROTO_NAME
" password md5 %s\n",
1424 circuit
->passwd
.passwd
);
1426 } else if (circuit
->passwd
.type
1427 == ISIS_PASSWD_TYPE_CLEARTXT
) {
1428 vty_out(vty
, " " PROTO_NAME
" password clear %s\n",
1429 circuit
->passwd
.passwd
);
1432 if (circuit
->bfd_config
.enabled
) {
1433 vty_out(vty
, " " PROTO_NAME
" bfd\n");
1436 write
+= hook_call(isis_circuit_config_write
,
1439 if_vty_config_end(vty
);
1444 #endif /* ifdef FABRICD */
1446 void isis_circuit_af_set(struct isis_circuit
*circuit
, bool ip_router
,
1449 struct isis_area
*area
= circuit
->area
;
1450 int old_ipr
= circuit
->ip_router
;
1451 int old_ipv6r
= circuit
->ipv6_router
;
1453 /* is there something to do? */
1454 if (old_ipr
== ip_router
&& old_ipv6r
== ipv6_router
)
1457 circuit
->ip_router
= ip_router
;
1458 circuit
->ipv6_router
= ipv6_router
;
1459 circuit_update_nlpids(circuit
);
1462 area
->ip_circuits
+= ip_router
- old_ipr
;
1463 area
->ipv6_circuits
+= ipv6_router
- old_ipv6r
;
1465 if (ip_router
|| ipv6_router
)
1466 lsp_regenerate_schedule(area
, circuit
->is_type
, 0);
1470 ferr_r
isis_circuit_passive_set(struct isis_circuit
*circuit
, bool passive
)
1472 if (circuit
->is_passive
== passive
)
1475 if (if_is_loopback(circuit
->interface
) && !passive
)
1476 return ferr_cfg_invalid("loopback is always passive");
1478 if (circuit
->state
!= C_STATE_UP
) {
1479 circuit
->is_passive
= passive
;
1481 struct isis_area
*area
= circuit
->area
;
1482 isis_csm_state_change(ISIS_DISABLE
, circuit
, area
);
1483 circuit
->is_passive
= passive
;
1484 isis_csm_state_change(ISIS_ENABLE
, circuit
, area
);
1490 ferr_r
isis_circuit_metric_set(struct isis_circuit
*circuit
, int level
,
1493 assert(level
== IS_LEVEL_1
|| level
== IS_LEVEL_2
);
1494 if (metric
> MAX_WIDE_LINK_METRIC
)
1495 return ferr_cfg_invalid("metric %d too large for wide metric",
1497 if (circuit
->area
&& circuit
->area
->oldmetric
1498 && metric
> MAX_NARROW_LINK_METRIC
)
1499 return ferr_cfg_invalid("metric %d too large for narrow metric",
1502 /* inform ldp-sync of metric change
1503 * if ldp-sync is running need to save metric
1504 * and restore new values after ldp-sync completion.
1506 if (isis_ldp_sync_if_metric_config(circuit
, level
, metric
)) {
1507 circuit
->te_metric
[level
- 1] = metric
;
1508 circuit
->metric
[level
- 1] = metric
;
1510 lsp_regenerate_schedule(circuit
->area
, level
, 0);
1515 ferr_r
isis_circuit_passwd_unset(struct isis_circuit
*circuit
)
1517 memset(&circuit
->passwd
, 0, sizeof(circuit
->passwd
));
1521 ferr_r
isis_circuit_passwd_set(struct isis_circuit
*circuit
,
1522 uint8_t passwd_type
, const char *passwd
)
1527 return ferr_code_bug("no circuit password given");
1529 len
= strlen(passwd
);
1531 return ferr_code_bug(
1532 "circuit password too long (max 254 chars)");
1534 circuit
->passwd
.len
= len
;
1535 strlcpy((char *)circuit
->passwd
.passwd
, passwd
,
1536 sizeof(circuit
->passwd
.passwd
));
1537 circuit
->passwd
.type
= passwd_type
;
1541 ferr_r
isis_circuit_passwd_cleartext_set(struct isis_circuit
*circuit
,
1544 return isis_circuit_passwd_set(circuit
, ISIS_PASSWD_TYPE_CLEARTXT
,
1548 ferr_r
isis_circuit_passwd_hmac_md5_set(struct isis_circuit
*circuit
,
1551 return isis_circuit_passwd_set(circuit
, ISIS_PASSWD_TYPE_HMAC_MD5
,
1555 void isis_circuit_circ_type_set(struct isis_circuit
*circuit
, int circ_type
)
1557 if (circuit
->circ_type
== circ_type
)
1560 if (circuit
->state
!= C_STATE_UP
) {
1561 circuit
->circ_type
= circ_type
;
1562 circuit
->circ_type_config
= circ_type
;
1564 struct isis_area
*area
= circuit
->area
;
1566 isis_csm_state_change(ISIS_DISABLE
, circuit
, area
);
1567 circuit
->circ_type
= circ_type
;
1568 circuit
->circ_type_config
= circ_type
;
1569 isis_csm_state_change(ISIS_ENABLE
, circuit
, area
);
1573 int isis_circuit_mt_enabled_set(struct isis_circuit
*circuit
, uint16_t mtid
,
1576 struct isis_circuit_mt_setting
*setting
;
1578 setting
= circuit_get_mt_setting(circuit
, mtid
);
1579 if (setting
->enabled
!= enabled
) {
1580 setting
->enabled
= enabled
;
1582 lsp_regenerate_schedule(circuit
->area
,
1583 IS_LEVEL_1
| IS_LEVEL_2
, 0);
1589 int isis_if_new_hook(struct interface
*ifp
)
1594 int isis_if_delete_hook(struct interface
*ifp
)
1597 isis_circuit_del(ifp
->info
);
1602 static int isis_ifp_create(struct interface
*ifp
)
1604 struct isis_circuit
*circuit
= ifp
->info
;
1607 isis_circuit_enable(circuit
);
1609 hook_call(isis_if_new_hook
, ifp
);
1614 static int isis_ifp_up(struct interface
*ifp
)
1616 struct isis_circuit
*circuit
= ifp
->info
;
1619 UNSET_FLAG(circuit
->flags
, ISIS_CIRCUIT_IF_DOWN_FROM_Z
);
1620 isis_csm_state_change(IF_UP_FROM_Z
, circuit
, ifp
);
1626 static int isis_ifp_down(struct interface
*ifp
)
1629 struct isis_circuit
*circuit
= ifp
->info
;
1632 !CHECK_FLAG(circuit
->flags
, ISIS_CIRCUIT_IF_DOWN_FROM_Z
)) {
1633 SET_FLAG(circuit
->flags
, ISIS_CIRCUIT_IF_DOWN_FROM_Z
);
1634 for (afi
= AFI_IP
; afi
<= AFI_IP6
; afi
++)
1635 isis_circuit_switchover_routes(
1636 circuit
, afi
== AFI_IP
? AF_INET
: AF_INET6
,
1637 NULL
, ifp
->ifindex
);
1638 isis_csm_state_change(IF_DOWN_FROM_Z
, circuit
, ifp
);
1640 SET_FLAG(circuit
->flags
, ISIS_CIRCUIT_FLAPPED_AFTER_SPF
);
1646 static int isis_ifp_destroy(struct interface
*ifp
)
1648 struct isis_circuit
*circuit
= ifp
->info
;
1651 isis_circuit_disable(circuit
);
1656 void isis_circuit_init(void)
1658 /* Initialize Zebra interface data structure */
1659 hook_register_prio(if_add
, 0, isis_if_new_hook
);
1660 hook_register_prio(if_del
, 0, isis_if_delete_hook
);
1662 /* Install interface node */
1664 if_cmd_init(isis_interface_config_write
);
1666 if_cmd_init_default();
1668 if_zapi_callbacks(isis_ifp_create
, isis_ifp_up
,
1669 isis_ifp_down
, isis_ifp_destroy
);