1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * IS-IS Rout(e)ing protocol - isis_te.c
5 * This is an implementation of RFC5305 & RFC 7810
7 * Author: Olivier Dugeon <olivier.dugeon@orange.com>
9 * Copyright (C) 2014 - 2019 Orange Labs http://www.orange.com
28 #include "sockunion.h"
31 #include "link_state.h"
34 #include "isisd/isis_constants.h"
35 #include "isisd/isis_common.h"
36 #include "isisd/isis_flags.h"
37 #include "isisd/isis_circuit.h"
38 #include "isisd/isis_adjacency.h"
39 #include "isisd/isisd.h"
40 #include "isisd/isis_lsp.h"
41 #include "isisd/isis_pdu.h"
42 #include "isisd/isis_dynhn.h"
43 #include "isisd/isis_misc.h"
44 #include "isisd/isis_csm.h"
45 #include "isisd/isis_adjacency.h"
46 #include "isisd/isis_spf.h"
47 #include "isisd/isis_tlvs.h"
48 #include "isisd/isis_mt.h"
49 #include "isisd/isis_te.h"
50 #include "isisd/isis_zebra.h"
52 DEFINE_MTYPE_STATIC(ISISD
, ISIS_MPLS_TE
, "ISIS MPLS_TE parameters");
54 static void isis_mpls_te_circuit_ip_update(struct isis_circuit
*circuit
);
56 /*------------------------------------------------------------------------*
57 * Following are control functions for MPLS-TE parameters management.
58 *------------------------------------------------------------------------*/
61 * Create MPLS Traffic Engineering structure which belongs to given area.
63 * @param area IS-IS Area
65 void isis_mpls_te_create(struct isis_area
*area
)
67 struct listnode
*node
;
68 struct isis_circuit
*circuit
;
73 if (area
->mta
== NULL
) {
75 struct mpls_te_area
*new;
77 zlog_debug("ISIS-TE(%s): Initialize MPLS Traffic Engineering",
80 new = XCALLOC(MTYPE_ISIS_MPLS_TE
, sizeof(struct mpls_te_area
));
82 /* Initialize MPLS_TE structure */
86 new->interas_areaid
.s_addr
= 0;
87 new->router_id
.s_addr
= 0;
88 new->ted
= ls_ted_new(1, "ISIS", 0);
90 zlog_warn("Unable to create Link State Data Base");
94 area
->mta
->status
= enable
;
97 /* Initialize Link State Database */
99 isis_te_init_ted(area
);
101 /* Update Extended TLVs according to Interface link parameters
102 * and neighbor IP addresses
104 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
105 isis_link_params_update(circuit
, circuit
->interface
);
106 isis_mpls_te_circuit_ip_update(circuit
);
111 * Disable MPLS Traffic Engineering structure which belongs to given area.
113 * @param area IS-IS Area
115 void isis_mpls_te_disable(struct isis_area
*area
)
117 struct listnode
*node
;
118 struct isis_circuit
*circuit
;
123 area
->mta
->status
= disable
;
125 /* Remove Link State Database */
126 ls_ted_clean(area
->mta
->ted
);
128 /* Disable Extended SubTLVs on all circuit */
129 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
130 if (!IS_EXT_TE(circuit
->ext
))
133 /* disable MPLS_TE Circuit keeping SR one's */
134 if (IS_SUBTLV(circuit
->ext
, EXT_ADJ_SID
))
135 circuit
->ext
->status
= EXT_ADJ_SID
;
136 else if (IS_SUBTLV(circuit
->ext
, EXT_LAN_ADJ_SID
))
137 circuit
->ext
->status
= EXT_LAN_ADJ_SID
;
139 circuit
->ext
->status
= 0;
143 void isis_mpls_te_term(struct isis_area
*area
)
145 struct listnode
*node
;
146 struct isis_circuit
*circuit
;
151 zlog_info("TE(%s): Terminate MPLS TE", __func__
);
152 /* Remove Link State Database */
153 ls_ted_del_all(&area
->mta
->ted
);
155 /* Remove Extended SubTLVs */
156 zlog_info(" |- Remove Extended SubTLVS for all circuit");
157 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
158 zlog_info(" |- Call isis_del_ext_subtlvs()");
159 isis_del_ext_subtlvs(circuit
->ext
);
163 zlog_info(" |- Free MTA structure at %p", area
->mta
);
164 XFREE(MTYPE_ISIS_MPLS_TE
, area
->mta
);
167 static void isis_link_params_update_asla(struct isis_circuit
*circuit
,
168 struct interface
*ifp
)
170 struct isis_asla_subtlvs
*asla
;
171 struct listnode
*node
, *nnode
;
172 struct isis_ext_subtlvs
*ext
= circuit
->ext
;
175 if (!HAS_LINK_PARAMS(ifp
)) {
176 list_delete_all_node(ext
->aslas
);
181 /* RFC 8919 Application Specific Link-Attributes
182 * is required by flex-algo application ISIS_SABM_FLAG_X
184 if (list_isempty(circuit
->area
->flex_algos
->flex_algos
))
185 isis_tlvs_free_asla(ext
, ISIS_SABM_FLAG_X
);
187 isis_tlvs_find_alloc_asla(ext
, ISIS_SABM_FLAG_X
);
188 #endif /* ifndef FABRICD */
190 if (list_isempty(ext
->aslas
))
193 for (ALL_LIST_ELEMENTS(ext
->aslas
, node
, nnode
, asla
)) {
194 asla
->legacy
= circuit
->area
->asla_legacy_flag
;
200 /* Fulfill ASLA subTLVs from interface link parameters */
201 if (IS_PARAM_SET(ifp
->link_params
, LP_ADM_GRP
)) {
202 asla
->admin_group
= ifp
->link_params
->admin_grp
;
203 SET_SUBTLV(asla
, EXT_ADM_GRP
);
205 UNSET_SUBTLV(asla
, EXT_ADM_GRP
);
207 if (IS_PARAM_SET(ifp
->link_params
, LP_EXTEND_ADM_GRP
)) {
208 admin_group_copy(&asla
->ext_admin_group
,
209 &ifp
->link_params
->ext_admin_grp
);
210 SET_SUBTLV(asla
, EXT_EXTEND_ADM_GRP
);
212 UNSET_SUBTLV(asla
, EXT_EXTEND_ADM_GRP
);
214 /* Send admin-group zero for better compatibility
215 * https://www.rfc-editor.org/rfc/rfc7308#section-2.3.2
217 if (circuit
->area
->admin_group_send_zero
&&
218 !IS_SUBTLV(asla
, EXT_ADM_GRP
) &&
219 !IS_SUBTLV(asla
, EXT_EXTEND_ADM_GRP
)) {
220 asla
->admin_group
= 0;
221 SET_SUBTLV(asla
, EXT_ADM_GRP
);
222 admin_group_clear(&asla
->ext_admin_group
);
223 admin_group_allow_explicit_zero(&asla
->ext_admin_group
);
224 SET_SUBTLV(asla
, EXT_EXTEND_ADM_GRP
);
227 if (IS_PARAM_SET(ifp
->link_params
, LP_TE_METRIC
)) {
228 asla
->te_metric
= ifp
->link_params
->te_metric
;
229 SET_SUBTLV(asla
, EXT_TE_METRIC
);
231 UNSET_SUBTLV(asla
, EXT_TE_METRIC
);
233 if (IS_PARAM_SET(ifp
->link_params
, LP_DELAY
)) {
234 asla
->delay
= ifp
->link_params
->av_delay
;
235 SET_SUBTLV(asla
, EXT_DELAY
);
237 UNSET_SUBTLV(asla
, EXT_DELAY
);
239 if (IS_PARAM_SET(ifp
->link_params
, LP_MM_DELAY
)) {
240 asla
->min_delay
= ifp
->link_params
->min_delay
;
241 asla
->max_delay
= ifp
->link_params
->max_delay
;
242 SET_SUBTLV(asla
, EXT_MM_DELAY
);
244 UNSET_SUBTLV(asla
, EXT_MM_DELAY
);
247 if (asla
->standard_apps
== ISIS_SABM_FLAG_X
)
248 /* Flex-Algo ASLA does not need the following TE
253 if (IS_PARAM_SET(ifp
->link_params
, LP_MAX_BW
)) {
254 asla
->max_bw
= ifp
->link_params
->max_bw
;
255 SET_SUBTLV(asla
, EXT_MAX_BW
);
257 UNSET_SUBTLV(asla
, EXT_MAX_BW
);
259 if (IS_PARAM_SET(ifp
->link_params
, LP_MAX_RSV_BW
)) {
260 asla
->max_rsv_bw
= ifp
->link_params
->max_rsv_bw
;
261 SET_SUBTLV(asla
, EXT_MAX_RSV_BW
);
263 UNSET_SUBTLV(asla
, EXT_MAX_RSV_BW
);
265 if (IS_PARAM_SET(ifp
->link_params
, LP_UNRSV_BW
)) {
266 for (i
= 0; i
< MAX_CLASS_TYPE
; i
++)
268 ifp
->link_params
->unrsv_bw
[i
];
269 SET_SUBTLV(asla
, EXT_UNRSV_BW
);
271 UNSET_SUBTLV(asla
, EXT_UNRSV_BW
);
273 if (IS_PARAM_SET(ifp
->link_params
, LP_DELAY_VAR
)) {
274 asla
->delay_var
= ifp
->link_params
->delay_var
;
275 SET_SUBTLV(asla
, EXT_DELAY_VAR
);
277 UNSET_SUBTLV(asla
, EXT_DELAY_VAR
);
279 if (IS_PARAM_SET(ifp
->link_params
, LP_PKT_LOSS
)) {
280 asla
->pkt_loss
= ifp
->link_params
->pkt_loss
;
281 SET_SUBTLV(asla
, EXT_PKT_LOSS
);
283 UNSET_SUBTLV(asla
, EXT_PKT_LOSS
);
285 if (IS_PARAM_SET(ifp
->link_params
, LP_RES_BW
)) {
286 asla
->res_bw
= ifp
->link_params
->res_bw
;
287 SET_SUBTLV(asla
, EXT_RES_BW
);
289 UNSET_SUBTLV(asla
, EXT_RES_BW
);
291 if (IS_PARAM_SET(ifp
->link_params
, LP_AVA_BW
)) {
292 asla
->ava_bw
= ifp
->link_params
->ava_bw
;
293 SET_SUBTLV(asla
, EXT_AVA_BW
);
295 UNSET_SUBTLV(asla
, EXT_AVA_BW
);
297 if (IS_PARAM_SET(ifp
->link_params
, LP_USE_BW
)) {
298 asla
->use_bw
= ifp
->link_params
->use_bw
;
299 SET_SUBTLV(asla
, EXT_USE_BW
);
301 UNSET_SUBTLV(asla
, EXT_USE_BW
);
305 for (ALL_LIST_ELEMENTS(ext
->aslas
, node
, nnode
, asla
)) {
306 if (!asla
->legacy
&& NO_SUBTLV(asla
) &&
307 admin_group_nb_words(&asla
->ext_admin_group
) == 0)
308 /* remove ASLA without info from the list of ASLAs to
311 isis_tlvs_del_asla_flex_algo(ext
, asla
);
315 /* Main initialization / update function of the MPLS TE Circuit context */
316 /* Call when interface TE Link parameters are modified */
317 void isis_link_params_update(struct isis_circuit
*circuit
,
318 struct interface
*ifp
)
321 struct prefix_ipv4
*addr
;
322 struct prefix_ipv6
*addr6
;
323 struct isis_ext_subtlvs
*ext
;
325 /* Check if TE is enable or not */
326 if (!circuit
->area
|| !IS_MPLS_TE(circuit
->area
->mta
))
330 if ((ifp
== NULL
) || (circuit
->state
!= C_STATE_UP
))
333 te_debug("ISIS-TE(%s): Update circuit parameters for interface %s",
334 circuit
->area
->area_tag
, ifp
->name
);
336 /* Check if MPLS TE Circuit context has not been already created */
337 if (circuit
->ext
== NULL
) {
338 circuit
->ext
= isis_alloc_ext_subtlvs();
339 te_debug(" |- Allocated new Ext-subTLVs for interface %s",
345 /* Fulfill Extended subTLVs from interface link parameters */
346 if (HAS_LINK_PARAMS(ifp
)) {
348 if (IS_PARAM_SET(ifp
->link_params
, LP_ADM_GRP
)) {
349 ext
->adm_group
= ifp
->link_params
->admin_grp
;
350 SET_SUBTLV(ext
, EXT_ADM_GRP
);
352 UNSET_SUBTLV(ext
, EXT_ADM_GRP
);
354 if (IS_PARAM_SET(ifp
->link_params
, LP_EXTEND_ADM_GRP
)) {
355 admin_group_copy(&ext
->ext_admin_group
,
356 &ifp
->link_params
->ext_admin_grp
);
357 SET_SUBTLV(ext
, EXT_EXTEND_ADM_GRP
);
359 UNSET_SUBTLV(ext
, EXT_EXTEND_ADM_GRP
);
361 /* Send admin-group zero for better compatibility
362 * https://www.rfc-editor.org/rfc/rfc7308#section-2.3.2
364 if (circuit
->area
->admin_group_send_zero
&&
365 !IS_SUBTLV(ext
, EXT_ADM_GRP
) &&
366 !IS_SUBTLV(ext
, EXT_EXTEND_ADM_GRP
)) {
368 SET_SUBTLV(ext
, EXT_ADM_GRP
);
369 admin_group_clear(&ext
->ext_admin_group
);
370 admin_group_allow_explicit_zero(&ext
->ext_admin_group
);
371 SET_SUBTLV(ext
, EXT_EXTEND_ADM_GRP
);
374 /* If known, register local IPv4 addr from ip_addr list */
375 if (listcount(circuit
->ip_addrs
) != 0) {
376 addr
= (struct prefix_ipv4
*)listgetdata(
377 (struct listnode
*)listhead(circuit
->ip_addrs
));
378 IPV4_ADDR_COPY(&ext
->local_addr
, &addr
->prefix
);
379 SET_SUBTLV(ext
, EXT_LOCAL_ADDR
);
381 UNSET_SUBTLV(ext
, EXT_LOCAL_ADDR
);
383 /* If known, register local IPv6 addr from ip_addr list */
384 if (listcount(circuit
->ipv6_non_link
) != 0) {
385 addr6
= (struct prefix_ipv6
*)listgetdata(
386 (struct listnode
*)listhead(
387 circuit
->ipv6_non_link
));
388 IPV6_ADDR_COPY(&ext
->local_addr6
, &addr6
->prefix
);
389 SET_SUBTLV(ext
, EXT_LOCAL_ADDR6
);
391 UNSET_SUBTLV(ext
, EXT_LOCAL_ADDR6
);
394 * Remote IPv4 and IPv6 addresses are now added in
395 * isis_mpls_te_adj_ip_enabled() to get the right IP address
396 * in particular for IPv6 to get the global IPv6 address and
397 * not the link-local IPv6 address.
400 if (IS_PARAM_SET(ifp
->link_params
, LP_MAX_BW
)) {
401 ext
->max_bw
= ifp
->link_params
->max_bw
;
402 SET_SUBTLV(ext
, EXT_MAX_BW
);
404 UNSET_SUBTLV(ext
, EXT_MAX_BW
);
406 if (IS_PARAM_SET(ifp
->link_params
, LP_MAX_RSV_BW
)) {
407 ext
->max_rsv_bw
= ifp
->link_params
->max_rsv_bw
;
408 SET_SUBTLV(ext
, EXT_MAX_RSV_BW
);
410 UNSET_SUBTLV(ext
, EXT_MAX_RSV_BW
);
412 if (IS_PARAM_SET(ifp
->link_params
, LP_UNRSV_BW
)) {
413 for (i
= 0; i
< MAX_CLASS_TYPE
; i
++)
415 ifp
->link_params
->unrsv_bw
[i
];
416 SET_SUBTLV(ext
, EXT_UNRSV_BW
);
418 UNSET_SUBTLV(ext
, EXT_UNRSV_BW
);
420 if (IS_PARAM_SET(ifp
->link_params
, LP_TE_METRIC
)) {
421 ext
->te_metric
= ifp
->link_params
->te_metric
;
422 SET_SUBTLV(ext
, EXT_TE_METRIC
);
424 UNSET_SUBTLV(ext
, EXT_TE_METRIC
);
426 /* TE metric extensions */
427 if (IS_PARAM_SET(ifp
->link_params
, LP_DELAY
)) {
428 ext
->delay
= ifp
->link_params
->av_delay
;
429 SET_SUBTLV(ext
, EXT_DELAY
);
431 UNSET_SUBTLV(ext
, EXT_DELAY
);
433 if (IS_PARAM_SET(ifp
->link_params
, LP_MM_DELAY
)) {
434 ext
->min_delay
= ifp
->link_params
->min_delay
;
435 ext
->max_delay
= ifp
->link_params
->max_delay
;
436 SET_SUBTLV(ext
, EXT_MM_DELAY
);
438 UNSET_SUBTLV(ext
, EXT_MM_DELAY
);
440 if (IS_PARAM_SET(ifp
->link_params
, LP_DELAY_VAR
)) {
441 ext
->delay_var
= ifp
->link_params
->delay_var
;
442 SET_SUBTLV(ext
, EXT_DELAY_VAR
);
444 UNSET_SUBTLV(ext
, EXT_DELAY_VAR
);
446 if (IS_PARAM_SET(ifp
->link_params
, LP_PKT_LOSS
)) {
447 ext
->pkt_loss
= ifp
->link_params
->pkt_loss
;
448 SET_SUBTLV(ext
, EXT_PKT_LOSS
);
450 UNSET_SUBTLV(ext
, EXT_PKT_LOSS
);
452 if (IS_PARAM_SET(ifp
->link_params
, LP_RES_BW
)) {
453 ext
->res_bw
= ifp
->link_params
->res_bw
;
454 SET_SUBTLV(ext
, EXT_RES_BW
);
456 UNSET_SUBTLV(ext
, EXT_RES_BW
);
458 if (IS_PARAM_SET(ifp
->link_params
, LP_AVA_BW
)) {
459 ext
->ava_bw
= ifp
->link_params
->ava_bw
;
460 SET_SUBTLV(ext
, EXT_AVA_BW
);
462 UNSET_SUBTLV(ext
, EXT_AVA_BW
);
464 if (IS_PARAM_SET(ifp
->link_params
, LP_USE_BW
)) {
465 ext
->use_bw
= ifp
->link_params
->use_bw
;
466 SET_SUBTLV(ext
, EXT_USE_BW
);
468 UNSET_SUBTLV(ext
, EXT_USE_BW
);
471 if (IS_PARAM_SET(ifp
->link_params
, LP_RMT_AS
)) {
472 ext
->remote_as
= ifp
->link_params
->rmt_as
;
473 ext
->remote_ip
= ifp
->link_params
->rmt_ip
;
474 SET_SUBTLV(ext
, EXT_RMT_AS
);
475 SET_SUBTLV(ext
, EXT_RMT_IP
);
477 /* reset inter-as TE params */
478 UNSET_SUBTLV(ext
, EXT_RMT_AS
);
479 UNSET_SUBTLV(ext
, EXT_RMT_IP
);
481 te_debug(" |- New MPLS-TE link parameters status 0x%x",
484 te_debug(" |- Reset Extended subTLVs status 0x%x",
486 /* Reset TE subTLVs keeping SR one's */
487 if (IS_SUBTLV(ext
, EXT_ADJ_SID
))
488 ext
->status
= EXT_ADJ_SID
;
489 else if (IS_SUBTLV(ext
, EXT_LAN_ADJ_SID
))
490 ext
->status
= EXT_LAN_ADJ_SID
;
495 isis_link_params_update_asla(circuit
, ifp
);
500 static int _isis_mpls_te_adj_ip_enabled(struct isis_adjacency
*adj
, int family
,
503 struct isis_circuit
*circuit
;
504 struct isis_ext_subtlvs
*ext
;
506 circuit
= adj
->circuit
;
508 /* Check that MPLS TE is enabled */
509 if (!IS_MPLS_TE(circuit
->area
->mta
) || !circuit
->ext
)
514 /* Determine nexthop IP address */
517 if (!circuit
->ip_router
|| !adj
->ipv4_address_count
)
518 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR
);
520 IPV4_ADDR_COPY(&ext
->neigh_addr
,
521 &adj
->ipv4_addresses
[0]);
522 SET_SUBTLV(ext
, EXT_NEIGH_ADDR
);
526 /* Nothing to do for link-local addresses - ie. not global.
527 * https://datatracker.ietf.org/doc/html/rfc6119#section-3.1.1
528 * Because the IPv6 traffic engineering TLVs present in LSPs are
529 * propagated across networks, they MUST NOT use link-local
535 if (!circuit
->ipv6_router
|| !adj
->global_ipv6_count
)
536 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR6
);
538 IPV6_ADDR_COPY(&ext
->neigh_addr6
,
539 &adj
->global_ipv6_addrs
[0]);
540 SET_SUBTLV(ext
, EXT_NEIGH_ADDR6
);
550 static int isis_mpls_te_adj_ip_enabled(struct isis_adjacency
*adj
, int family
,
556 if (!adj
|| !adj
->circuit
)
559 ret
= _isis_mpls_te_adj_ip_enabled(adj
, family
, global
);
562 lsp_regenerate_schedule(adj
->circuit
->area
, adj
->circuit
->is_type
, 0);
567 static int _isis_mpls_te_adj_ip_disabled(struct isis_adjacency
*adj
, int family
,
570 struct isis_circuit
*circuit
;
571 struct isis_ext_subtlvs
*ext
;
573 circuit
= adj
->circuit
;
575 /* Check that MPLS TE is enabled */
576 if (!IS_MPLS_TE(circuit
->area
->mta
) || !circuit
->ext
)
581 /* Update MPLS TE IP address parameters if possible */
582 if (!IS_MPLS_TE(circuit
->area
->mta
) || !IS_EXT_TE(ext
))
585 /* Determine nexthop IP address */
588 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR
);
592 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR6
);
601 static int isis_mpls_te_adj_ip_disabled(struct isis_adjacency
*adj
, int family
,
607 if (!adj
|| !adj
->circuit
|| !adj
->circuit
->ext
)
610 ret
= _isis_mpls_te_adj_ip_disabled(adj
, family
, global
);
613 lsp_regenerate_schedule(adj
->circuit
->area
, adj
->circuit
->is_type
, 0);
618 static void isis_mpls_te_circuit_ip_update(struct isis_circuit
*circuit
)
620 struct isis_adjacency
*adj
;
622 /* https://datatracker.ietf.org/doc/html/rfc6119#section-3.2.3
623 * This sub-TLV of the Extended IS Reachability TLV is used for point-
626 if (circuit
->circ_type
!= CIRCUIT_T_P2P
)
629 adj
= circuit
->u
.p2p
.neighbor
;
634 /* Nothing to do for link-local addresses.
635 * https://datatracker.ietf.org/doc/html/rfc6119#section-3.1.1
636 * Because the IPv6 traffic engineering TLVs present in LSPs are
637 * propagated across networks, they MUST NOT use link-local addresses.
639 if (adj
->ipv4_address_count
> 0)
640 _isis_mpls_te_adj_ip_enabled(adj
, AF_INET
, false);
642 _isis_mpls_te_adj_ip_disabled(adj
, AF_INET
, false);
644 if (adj
->global_ipv6_count
> 0)
645 _isis_mpls_te_adj_ip_enabled(adj
, AF_INET6
, true);
647 _isis_mpls_te_adj_ip_disabled(adj
, AF_INET6
, true);
651 int isis_mpls_te_update(struct interface
*ifp
)
653 struct isis_circuit
*circuit
;
660 /* Get circuit context from interface */
661 circuit
= circuit_scan_by_ifp(ifp
);
665 /* Update TE TLVs ... */
666 isis_link_params_update(circuit
, ifp
);
670 (IS_MPLS_TE(circuit
->area
->mta
)
672 || !list_isempty(circuit
->area
->flex_algos
->flex_algos
)
673 #endif /* ifndef FABRICD */
675 lsp_regenerate_schedule(circuit
->area
, circuit
->is_type
, 0);
683 * Export Link State information to consumer daemon through ZAPI Link State
686 * @param type Type of Link State Element i.e. Vertex, Edge or Subnet
687 * @param link_state Pointer to Link State Vertex, Edge or Subnet
689 * @return 0 if success, -1 otherwise
691 static int isis_te_export(uint8_t type
, void *link_state
)
693 struct ls_message msg
= {};
697 case LS_MSG_TYPE_NODE
:
698 ls_vertex2msg(&msg
, (struct ls_vertex
*)link_state
);
699 rc
= ls_send_msg(zclient
, &msg
, NULL
);
701 case LS_MSG_TYPE_ATTRIBUTES
:
702 ls_edge2msg(&msg
, (struct ls_edge
*)link_state
);
703 rc
= ls_send_msg(zclient
, &msg
, NULL
);
705 case LS_MSG_TYPE_PREFIX
:
706 ls_subnet2msg(&msg
, (struct ls_subnet
*)link_state
);
707 rc
= ls_send_msg(zclient
, &msg
, NULL
);
718 * Parse LSP and build corresponding vertex. If vertex doesn't exist in the
719 * Link State Database it is created otherwise updated.
721 * @param ted Traffic Engineering Link State Database
722 * @param lsp IS-IS Link State PDU
724 * @return Link State Vertex or NULL in case of error
726 static struct ls_vertex
*lsp_to_vertex(struct ls_ted
*ted
, struct isis_lsp
*lsp
)
728 struct ls_vertex
*vertex
= NULL
;
729 struct ls_node
*old
, lnode
= {};
730 struct isis_tlvs
*tlvs
;
731 const struct in_addr inaddr_any
= {.s_addr
= INADDR_ANY
};
737 /* Compute Link State Node ID from IS-IS sysID ... */
738 if (lsp
->level
== ISIS_LEVEL1
)
739 lnode
.adv
.origin
= ISIS_L1
;
741 lnode
.adv
.origin
= ISIS_L2
;
742 memcpy(&lnode
.adv
.id
.iso
.sys_id
, &lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
);
743 lnode
.adv
.id
.iso
.level
= lsp
->level
;
744 /* ... and search the corresponding vertex */
745 vertex
= ls_find_vertex_by_id(ted
, lnode
.adv
);
746 /* Create a new one if not found */
748 old
= ls_node_new(lnode
.adv
, inaddr_any
, in6addr_any
);
749 old
->type
= STANDARD
;
750 vertex
= ls_vertex_add(ted
, old
);
753 te_debug(" |- %s Vertex (%" PRIu64
") for node %s",
754 vertex
->status
== NEW
? "Create" : "Found", vertex
->key
,
755 print_sys_hostname(old
->adv
.id
.iso
.sys_id
));
757 /* Fulfill Link State Node information */
760 if (tlvs
->te_router_id
) {
761 IPV4_ADDR_COPY(&lnode
.router_id
, tlvs
->te_router_id
);
762 SET_FLAG(lnode
.flags
, LS_NODE_ROUTER_ID
);
764 if (tlvs
->te_router_id_ipv6
) {
765 IPV6_ADDR_COPY(&lnode
.router_id6
,
766 tlvs
->te_router_id_ipv6
);
767 SET_FLAG(lnode
.flags
, LS_NODE_ROUTER_ID6
);
769 if (tlvs
->hostname
) {
770 strlcpy(lnode
.name
, tlvs
->hostname
, MAX_NAME_LENGTH
);
771 SET_FLAG(lnode
.flags
, LS_NODE_NAME
);
773 if (tlvs
->router_cap
) {
774 struct isis_router_cap
*cap
= tlvs
->router_cap
;
776 if (cap
->srgb
.lower_bound
!= 0
777 && cap
->srgb
.range_size
!= 0) {
778 SET_FLAG(lnode
.flags
, LS_NODE_SR
);
779 lnode
.srgb
.flag
= cap
->srgb
.flags
;
780 lnode
.srgb
.lower_bound
= cap
->srgb
.lower_bound
;
781 lnode
.srgb
.range_size
= cap
->srgb
.range_size
;
782 for (int i
= 0; i
< LIB_LS_SR_ALGO_COUNT
; i
++)
783 lnode
.algo
[i
] = cap
->algo
[i
];
786 if (cap
->srlb
.lower_bound
!= 0
787 && cap
->srlb
.range_size
!= 0) {
788 lnode
.srlb
.lower_bound
= cap
->srlb
.lower_bound
;
789 lnode
.srlb
.range_size
= cap
->srlb
.range_size
;
790 SET_FLAG(lnode
.flags
, LS_NODE_SRLB
);
793 lnode
.msd
= cap
->msd
;
794 SET_FLAG(lnode
.flags
, LS_NODE_MSD
);
799 /* Update Link State Node information */
800 if (!ls_node_same(old
, &lnode
)) {
801 te_debug(" |- Update Link State Node information");
802 memcpy(old
, &lnode
, sizeof(struct ls_node
));
803 if (vertex
->status
!= NEW
)
804 vertex
->status
= UPDATE
;
807 /* Set self TED vertex if LSP corresponds to the own router */
815 * Get Link State Edge from Link State Attributes in TE Database.
816 * Edge structure is dynamically allocated and fulfill with Link State
817 * Attributes if not found.
819 * @param ted Link State Database
820 * @param attr Link State Attributes
822 * @return New Link State Edge if success, NULL otherwise
824 static struct ls_edge
*get_edge(struct ls_ted
*ted
, struct ls_attributes
*attr
)
826 struct ls_edge
*edge
;
827 struct ls_standard
*std
;
828 struct ls_edge_key key
;
830 /* Check parameters */
834 std
= &attr
->standard
;
836 /* Compute keys in function of local address (IPv4/v6) or identifier */
837 if (CHECK_FLAG(attr
->flags
, LS_ATTR_LOCAL_ADDR
)) {
838 key
.family
= AF_INET
;
839 IPV4_ADDR_COPY(&key
.k
.addr
, &std
->local
);
840 } else if (CHECK_FLAG(attr
->flags
, LS_ATTR_LOCAL_ADDR6
)) {
841 key
.family
= AF_INET6
;
842 IPV6_ADDR_COPY(&key
.k
.addr6
, &std
->local6
);
843 } else if (CHECK_FLAG(attr
->flags
, LS_ATTR_LOCAL_ID
)) {
844 key
.family
= AF_LOCAL
;
845 key
.k
.link_id
= (((uint64_t)std
->local_id
) & 0xffffffff) |
846 ((uint64_t)std
->remote_id
<< 32);
848 key
.family
= AF_UNSPEC
;
851 /* Stop here if we don't got a valid key */
852 if (key
.family
== AF_UNSPEC
)
855 /* Get corresponding Edge by key from Link State Data Base */
856 edge
= ls_find_edge_by_key(ted
, key
);
858 /* and create new one if not exist */
860 edge
= ls_edge_add(ted
, attr
);
862 * Edge could be Null if no local ID is found in Attributes.
863 * Stop the processing as without any local ID it is not
864 * possible to store Edge in the TED.
870 if (CHECK_FLAG(edge
->attributes
->flags
, LS_ATTR_LOCAL_ADDR
))
871 te_debug(" |- %s Edge (%pI4) from Extended Reach. %pI4",
872 edge
->status
== NEW
? "Create" : "Found",
873 &edge
->key
.k
.addr
, &attr
->standard
.local
);
874 else if (CHECK_FLAG(edge
->attributes
->flags
, LS_ATTR_LOCAL_ADDR6
))
875 te_debug(" |- %s Edge (%pI6) from Extended Reach. %pI6",
876 edge
->status
== NEW
? "Create" : "Found",
877 &edge
->key
.k
.addr6
, &attr
->standard
.local6
);
879 te_debug(" |- %s Edge (%" PRIu64
")",
880 edge
->status
== NEW
? "Create" : "Found",
881 edge
->key
.k
.link_id
);
887 * Get Link State Attributes from IS-IS Sub-TLVs. Structure is dynamically
888 * allocated and should be free once not use anymore.
890 * @param adv Link State Node ID
891 * @param tlvs IS-IS Sub TLVs
893 * @return New Link State attributes if success, NULL otherwise
895 static struct ls_attributes
*get_attributes(struct ls_node_id adv
,
896 struct isis_ext_subtlvs
*tlvs
)
898 struct ls_attributes
*attr
;
899 struct in_addr local
= {.s_addr
= INADDR_ANY
};
900 struct in6_addr local6
= in6addr_any
;
901 uint32_t local_id
= 0;
903 /* Got Local identifier */
904 if (CHECK_FLAG(tlvs
->status
, EXT_LOCAL_ADDR
))
905 local
.s_addr
= tlvs
->local_addr
.s_addr
;
907 if (CHECK_FLAG(tlvs
->status
, EXT_LOCAL_ADDR6
))
908 memcpy(&local6
, &tlvs
->local_addr6
, IPV6_MAX_BYTELEN
);
910 if (CHECK_FLAG(tlvs
->status
, EXT_LLRI
))
911 local_id
= tlvs
->local_llri
;
913 /* Create LS Attributes */
914 attr
= ls_attributes_new(adv
, local
, local6
, local_id
);
918 /* Browse sub-TLV and fulfill Link State Attributes */
919 if (CHECK_FLAG(tlvs
->status
, EXT_ADM_GRP
)) {
920 attr
->standard
.admin_group
= tlvs
->adm_group
;
921 SET_FLAG(attr
->flags
, LS_ATTR_ADM_GRP
);
923 if (CHECK_FLAG(tlvs
->status
, EXT_EXTEND_ADM_GRP
)) {
924 admin_group_copy(&attr
->ext_admin_group
,
925 &tlvs
->ext_admin_group
);
926 SET_FLAG(attr
->flags
, LS_ATTR_EXT_ADM_GRP
);
928 if (CHECK_FLAG(tlvs
->status
, EXT_LLRI
)) {
929 attr
->standard
.local_id
= tlvs
->local_llri
;
930 attr
->standard
.remote_id
= tlvs
->remote_llri
;
931 SET_FLAG(attr
->flags
, LS_ATTR_LOCAL_ID
);
932 SET_FLAG(attr
->flags
, LS_ATTR_NEIGH_ID
);
934 if (CHECK_FLAG(tlvs
->status
, EXT_NEIGH_ADDR
)) {
935 attr
->standard
.remote
.s_addr
= tlvs
->neigh_addr
.s_addr
;
936 SET_FLAG(attr
->flags
, LS_ATTR_NEIGH_ADDR
);
938 if (CHECK_FLAG(tlvs
->status
, EXT_NEIGH_ADDR6
)) {
939 memcpy(&attr
->standard
.remote6
, &tlvs
->neigh_addr6
,
941 SET_FLAG(attr
->flags
, LS_ATTR_NEIGH_ADDR6
);
943 if (CHECK_FLAG(tlvs
->status
, EXT_MAX_BW
)) {
944 attr
->standard
.max_bw
= tlvs
->max_bw
;
945 SET_FLAG(attr
->flags
, LS_ATTR_MAX_BW
);
947 if (CHECK_FLAG(tlvs
->status
, EXT_MAX_RSV_BW
)) {
948 attr
->standard
.max_rsv_bw
= tlvs
->max_rsv_bw
;
949 SET_FLAG(attr
->flags
, LS_ATTR_MAX_RSV_BW
);
951 if (CHECK_FLAG(tlvs
->status
, EXT_UNRSV_BW
)) {
952 memcpy(&attr
->standard
.unrsv_bw
, tlvs
->unrsv_bw
,
953 ISIS_SUBTLV_UNRSV_BW_SIZE
);
954 SET_FLAG(attr
->flags
, LS_ATTR_UNRSV_BW
);
956 if (CHECK_FLAG(tlvs
->status
, EXT_TE_METRIC
)) {
957 attr
->standard
.te_metric
= tlvs
->te_metric
;
958 SET_FLAG(attr
->flags
, LS_ATTR_TE_METRIC
);
960 if (CHECK_FLAG(tlvs
->status
, EXT_RMT_AS
)) {
961 attr
->standard
.remote_as
= tlvs
->remote_as
;
962 SET_FLAG(attr
->flags
, LS_ATTR_REMOTE_AS
);
964 if (CHECK_FLAG(tlvs
->status
, EXT_RMT_IP
)) {
965 attr
->standard
.remote_addr
= tlvs
->remote_ip
;
966 SET_FLAG(attr
->flags
, LS_ATTR_REMOTE_ADDR
);
968 if (CHECK_FLAG(tlvs
->status
, EXT_DELAY
)) {
969 attr
->extended
.delay
= tlvs
->delay
;
970 SET_FLAG(attr
->flags
, LS_ATTR_DELAY
);
972 if (CHECK_FLAG(tlvs
->status
, EXT_MM_DELAY
)) {
973 attr
->extended
.min_delay
= tlvs
->min_delay
;
974 attr
->extended
.max_delay
= tlvs
->max_delay
;
975 SET_FLAG(attr
->flags
, LS_ATTR_MIN_MAX_DELAY
);
977 if (CHECK_FLAG(tlvs
->status
, EXT_DELAY_VAR
)) {
978 attr
->extended
.jitter
= tlvs
->delay_var
;
979 SET_FLAG(attr
->flags
, LS_ATTR_JITTER
);
981 if (CHECK_FLAG(tlvs
->status
, EXT_PKT_LOSS
)) {
982 attr
->extended
.pkt_loss
= tlvs
->pkt_loss
;
983 SET_FLAG(attr
->flags
, LS_ATTR_PACKET_LOSS
);
985 if (CHECK_FLAG(tlvs
->status
, EXT_AVA_BW
)) {
986 attr
->extended
.ava_bw
= tlvs
->ava_bw
;
987 SET_FLAG(attr
->flags
, LS_ATTR_AVA_BW
);
989 if (CHECK_FLAG(tlvs
->status
, EXT_RES_BW
)) {
990 attr
->extended
.rsv_bw
= tlvs
->res_bw
;
991 SET_FLAG(attr
->flags
, LS_ATTR_RSV_BW
);
993 if (CHECK_FLAG(tlvs
->status
, EXT_USE_BW
)) {
994 attr
->extended
.used_bw
= tlvs
->use_bw
;
995 SET_FLAG(attr
->flags
, LS_ATTR_USE_BW
);
997 if (CHECK_FLAG(tlvs
->status
, EXT_ADJ_SID
)) {
998 struct isis_adj_sid
*adj
=
999 (struct isis_adj_sid
*)tlvs
->adj_sid
.head
;
1001 for (; adj
; adj
= adj
->next
) {
1002 i
= adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
? 1 : 0;
1003 i
+= adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
? 2 : 0;
1004 attr
->adj_sid
[i
].flags
= adj
->flags
;
1005 attr
->adj_sid
[i
].weight
= adj
->weight
;
1006 attr
->adj_sid
[i
].sid
= adj
->sid
;
1009 SET_FLAG(attr
->flags
, LS_ATTR_ADJ_SID
);
1012 SET_FLAG(attr
->flags
, LS_ATTR_BCK_ADJ_SID
);
1015 SET_FLAG(attr
->flags
, LS_ATTR_ADJ_SID6
);
1018 SET_FLAG(attr
->flags
, LS_ATTR_BCK_ADJ_SID6
);
1023 if (CHECK_FLAG(tlvs
->status
, EXT_LAN_ADJ_SID
)) {
1024 struct isis_lan_adj_sid
*ladj
=
1025 (struct isis_lan_adj_sid
*)tlvs
->lan_sid
.head
;
1027 for (; ladj
; ladj
= ladj
->next
) {
1028 i
= ladj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
? 1 : 0;
1029 i
+= ladj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
? 2 : 0;
1030 attr
->adj_sid
[i
].flags
= ladj
->flags
;
1031 attr
->adj_sid
[i
].weight
= ladj
->weight
;
1032 attr
->adj_sid
[i
].sid
= ladj
->sid
;
1033 memcpy(&attr
->adj_sid
[i
].neighbor
.sysid
,
1034 &ladj
->neighbor_id
, ISIS_SYS_ID_LEN
);
1037 SET_FLAG(attr
->flags
, LS_ATTR_ADJ_SID
);
1040 SET_FLAG(attr
->flags
, LS_ATTR_BCK_ADJ_SID
);
1043 SET_FLAG(attr
->flags
, LS_ATTR_ADJ_SID6
);
1046 SET_FLAG(attr
->flags
, LS_ATTR_BCK_ADJ_SID6
);
1056 * Parse Extended Reachability TLVs and create or update the corresponding
1057 * Link State Edge and Attributes. Vertex connections are also updated if
1058 * needed based on the remote IP address of the Edge and existing reverse Edge.
1060 * @param id ID of Extended IS
1061 * @param metric Metric of the link
1062 * @param old_metric Boolean that indicate if it is an old metric (no TE)
1063 * @param tlvs SubTlvs that contains TE information
1064 * @param arg IS-IS TE argument (TED, Vertex, and export indication)
1066 * @return 0 if success, -1 otherwise
1068 static int lsp_to_edge_cb(const uint8_t *id
, uint32_t metric
, bool old_metric
,
1069 struct isis_ext_subtlvs
*tlvs
, void *arg
)
1071 struct isis_te_args
*args
= (struct isis_te_args
*)arg
;
1072 struct ls_vertex
*vertex
;
1073 struct ls_edge
*edge
, *dst
;
1074 struct ls_attributes
*attr
;
1076 te_debug(" |- Process Extended IS for %pSY", id
);
1078 /* Check parameters */
1079 if (old_metric
|| !args
|| !tlvs
)
1080 return LSP_ITER_CONTINUE
;
1082 /* Initialize Link State Attributes */
1083 vertex
= args
->vertex
;
1084 attr
= get_attributes(vertex
->node
->adv
, tlvs
);
1086 * Attributes may be Null if no local ID has been found in the LSP.
1087 * Stop processing here as without any local ID it is not possible to
1088 * create corresponding Edge in the TED.
1091 return LSP_ITER_CONTINUE
;
1093 attr
->metric
= metric
;
1094 SET_FLAG(attr
->flags
, LS_ATTR_METRIC
);
1096 /* Get corresponding Edge from Link State Data Base */
1097 edge
= get_edge(args
->ted
, attr
);
1099 * Edge could be Null if no local ID has been found in Attributes.
1100 * Stop processing here as without any local ID it is not possible to
1101 * create corresponding Edge in the TED.
1104 ls_attributes_del(attr
);
1105 return LSP_ITER_CONTINUE
;
1108 /* Update Attribute fields if there are different */
1109 if (edge
->status
!= NEW
) {
1110 if (!ls_attributes_same(edge
->attributes
, attr
)) {
1111 te_debug(" |- Update Edge Attributes information");
1112 ls_attributes_del(edge
->attributes
);
1113 edge
->attributes
= attr
;
1114 edge
->status
= UPDATE
;
1116 if (edge
->attributes
!= attr
)
1117 ls_attributes_del(attr
);
1118 edge
->status
= SYNC
;
1122 /* Try to update remote Link from remote address or reachability ID */
1123 if (edge
->key
.family
== AF_INET
)
1124 te_debug(" |- Link Edge (%pI4) to destination vertex (%s)",
1125 &edge
->key
.k
.addr
, print_sys_hostname(id
));
1126 else if (edge
->key
.family
== AF_INET6
)
1127 te_debug(" |- Link Edge (%pI6) to destination vertex (%s)",
1128 &edge
->key
.k
.addr6
, print_sys_hostname(id
));
1129 else if (edge
->key
.family
== AF_LOCAL
)
1130 te_debug(" |- Link Edge (%" PRIu64
1131 ") to destination vertex (%s)",
1132 edge
->key
.k
.link_id
, print_sys_hostname(id
));
1135 " |- Link Edge (Unknown) to destination vertex (%s)",
1136 print_sys_hostname(id
));
1138 dst
= ls_find_edge_by_destination(args
->ted
, edge
->attributes
);
1140 /* Attach remote link if not set */
1141 if (edge
->source
&& dst
->destination
== NULL
) {
1142 vertex
= edge
->source
;
1143 if (vertex
->incoming_edges
)
1144 listnode_add_sort_nodup(vertex
->incoming_edges
,
1146 dst
->destination
= vertex
;
1148 /* and destination vertex to this edge if not set */
1149 if (dst
->source
&& edge
->destination
== NULL
) {
1150 vertex
= dst
->source
;
1151 if (vertex
->incoming_edges
)
1152 listnode_add_sort_nodup(vertex
->incoming_edges
,
1154 edge
->destination
= vertex
;
1157 /* Search dst. Vertex by Extended Reach. ID if not found */
1158 if (edge
->destination
== NULL
) {
1159 vertex
= ls_find_vertex_by_key(args
->ted
,
1161 if (vertex
&& vertex
->incoming_edges
)
1162 listnode_add_sort_nodup(vertex
->incoming_edges
,
1164 edge
->destination
= vertex
;
1168 /* Update status and Export Link State Edge if needed */
1169 if (edge
->status
!= SYNC
) {
1171 isis_te_export(LS_MSG_TYPE_ATTRIBUTES
, edge
);
1172 edge
->status
= SYNC
;
1175 return LSP_ITER_CONTINUE
;
1179 * Parse Extended IP Reachability or MT IPv6 Reachability TLVs and create or
1180 * update the corresponding Link State Subnet and Prefix.
1182 * @param prefix Prefix associated to this subnet
1183 * @param metric Metric of this prefix
1184 * @param external Boolean to indicate if the prefix is external
1185 * @param subtlvs Subtlvs if any (mostly Segment Routing ID)
1186 * @param arg IS-IS TE argument (TED, Vertex, and export indication)
1188 * @return 0 if success, -1 otherwise
1190 static int lsp_to_subnet_cb(const struct prefix
*prefix
, uint32_t metric
,
1191 bool external
, struct isis_subtlvs
*subtlvs
,
1194 struct isis_te_args
*args
= (struct isis_te_args
*)arg
;
1195 struct ls_vertex
*vertex
;
1196 struct ls_subnet
*subnet
;
1197 struct ls_prefix
*ls_pref
;
1198 struct listnode
*node
;
1199 struct ls_edge
*edge
;
1200 struct ls_standard
*std
= NULL
;
1204 if (!args
|| !prefix
)
1205 return LSP_ITER_CONTINUE
;
1207 te_debug(" |- Process Extended %s Reachability %pFX",
1208 prefix
->family
== AF_INET
? "IP" : "IPv6", prefix
);
1210 vertex
= args
->vertex
;
1213 * Prefix with mask different from /32 or /128 are advertised by at
1214 * least 2 nodes. To avoid subnet attached to undetermined vertex, and
1215 * gives the possibility to send the information to client e.g. BGP for
1216 * Link State advertisement, we adjust the prefix with the corresponding
1217 * IP address of the belonging interface when it is available. Other
1218 * prefixes are kept unchanged.
1220 if (prefix
->family
== AF_INET
&& prefix
->prefixlen
< IPV4_MAX_BITLEN
) {
1222 for (ALL_LIST_ELEMENTS_RO(vertex
->outgoing_edges
, node
, edge
)) {
1223 if (!CHECK_FLAG(edge
->attributes
->flags
,
1224 LS_ATTR_LOCAL_ADDR
))
1227 p
.u
.prefix4
= edge
->attributes
->standard
.local
;
1229 p
.prefixlen
= prefix
->prefixlen
;
1230 apply_mask_ipv4((struct prefix_ipv4
*)&p
);
1231 if (IPV4_ADDR_SAME(&p
.u
.prefix4
, &prefix
->u
.prefix4
)) {
1232 std
= &edge
->attributes
->standard
;
1237 p
.u
.prefix4
= std
->local
;
1239 } else if (prefix
->family
== AF_INET6
1240 && prefix
->prefixlen
< IPV6_MAX_BITLEN
) {
1242 for (ALL_LIST_ELEMENTS_RO(vertex
->outgoing_edges
, node
, edge
)) {
1243 if (!CHECK_FLAG(edge
->attributes
->flags
,
1244 LS_ATTR_LOCAL_ADDR6
))
1247 p
.u
.prefix6
= edge
->attributes
->standard
.local6
;
1248 p
.family
= AF_INET6
;
1249 p
.prefixlen
= prefix
->prefixlen
;
1250 apply_mask_ipv6((struct prefix_ipv6
*)&p
);
1251 if (IPV6_ADDR_SAME(&p
.u
.prefix6
, &prefix
->u
.prefix6
)) {
1252 std
= &edge
->attributes
->standard
;
1257 p
.u
.prefix6
= std
->local6
;
1260 prefix_copy(&p
, prefix
);
1262 /* Remove old subnet if any before prefix adjustment */
1263 subnet
= ls_find_subnet(args
->ted
, prefix
);
1266 subnet
->status
= DELETE
;
1267 isis_te_export(LS_MSG_TYPE_PREFIX
, subnet
);
1269 te_debug(" |- Remove subnet with prefix %pFX",
1271 ls_subnet_del_all(args
->ted
, subnet
);
1273 te_debug(" |- Adjust prefix %pFX with local address to: %pFX",
1277 /* Search existing Subnet in TED ... */
1278 subnet
= ls_find_subnet(args
->ted
, &p
);
1279 /* ... and create a new Subnet if not found */
1281 ls_pref
= ls_prefix_new(vertex
->node
->adv
, &p
);
1282 subnet
= ls_subnet_add(args
->ted
, ls_pref
);
1283 /* Stop processing if we are unable to create a new subnet */
1285 return LSP_ITER_CONTINUE
;
1287 ls_pref
= subnet
->ls_pref
;
1289 te_debug(" |- %s Subnet from prefix %pFX",
1290 subnet
->status
== NEW
? "Create" : "Found", &p
);
1293 if (!CHECK_FLAG(ls_pref
->flags
, LS_PREF_METRIC
)
1294 || (ls_pref
->metric
!= metric
)) {
1295 ls_pref
->metric
= metric
;
1296 SET_FLAG(ls_pref
->flags
, LS_PREF_METRIC
);
1297 if (subnet
->status
!= NEW
)
1298 subnet
->status
= UPDATE
;
1300 if (subnet
->status
== ORPHAN
)
1301 subnet
->status
= SYNC
;
1304 /* Update Prefix SID if any */
1305 if (subtlvs
&& subtlvs
->prefix_sids
.count
!= 0) {
1306 struct isis_prefix_sid
*psid
;
1307 struct ls_sid sr
= {};
1309 psid
= (struct isis_prefix_sid
*)subtlvs
->prefix_sids
.head
;
1310 sr
.algo
= psid
->algorithm
;
1311 sr
.sid_flag
= psid
->flags
;
1312 sr
.sid
= psid
->value
;
1314 if (!CHECK_FLAG(ls_pref
->flags
, LS_PREF_SR
)
1315 || !memcmp(&ls_pref
->sr
, &sr
, sizeof(struct ls_sid
))) {
1316 memcpy(&ls_pref
->sr
, &sr
, sizeof(struct ls_sid
));
1317 SET_FLAG(ls_pref
->flags
, LS_PREF_SR
);
1318 if (subnet
->status
!= NEW
)
1319 subnet
->status
= UPDATE
;
1321 if (subnet
->status
== ORPHAN
)
1322 subnet
->status
= SYNC
;
1325 if (CHECK_FLAG(ls_pref
->flags
, LS_PREF_SR
)) {
1326 UNSET_FLAG(ls_pref
->flags
, LS_PREF_SR
);
1327 if (subnet
->status
!= NEW
)
1328 subnet
->status
= UPDATE
;
1330 if (subnet
->status
== ORPHAN
)
1331 subnet
->status
= SYNC
;
1335 /* Update status and Export Link State Edge if needed */
1336 if (subnet
->status
!= SYNC
) {
1338 isis_te_export(LS_MSG_TYPE_PREFIX
, subnet
);
1339 subnet
->status
= SYNC
;
1342 return LSP_ITER_CONTINUE
;
1346 * Parse ISIS LSP to fulfill the Link State Database
1348 * @param ted Link State Database
1349 * @param lsp ISIS Link State PDU
1351 static void isis_te_parse_lsp(struct mpls_te_area
*mta
, struct isis_lsp
*lsp
)
1354 struct ls_vertex
*vertex
;
1355 struct ls_edge
*edge
;
1356 struct ls_subnet
*subnet
;
1357 struct listnode
*node
;
1358 struct isis_te_args args
;
1361 if (!IS_MPLS_TE(mta
) || !mta
->ted
|| !lsp
)
1366 te_debug("ISIS-TE(%s): Parse LSP %pSY", lsp
->area
->area_tag
,
1369 /* First parse LSP to obtain the corresponding Vertex */
1370 vertex
= lsp_to_vertex(ted
, lsp
);
1372 zlog_warn("Unable to build Vertex from LSP %pSY. Abort!",
1377 /* Check if Vertex has been modified */
1378 if (vertex
->status
!= SYNC
) {
1379 /* Vertex is out of sync: export it if requested */
1380 if (IS_EXPORT_TE(mta
))
1381 isis_te_export(LS_MSG_TYPE_NODE
, vertex
);
1382 vertex
->status
= SYNC
;
1385 /* Mark outgoing Edges and Subnets as ORPHAN to detect deletion */
1386 for (ALL_LIST_ELEMENTS_RO(vertex
->outgoing_edges
, node
, edge
))
1387 edge
->status
= ORPHAN
;
1389 for (ALL_LIST_ELEMENTS_RO(vertex
->prefixes
, node
, subnet
))
1390 subnet
->status
= ORPHAN
;
1392 /* Process all Extended Reachability in LSP (all fragments) */
1394 args
.vertex
= vertex
;
1395 args
.export
= mta
->export
;
1396 isis_lsp_iterate_is_reach(lsp
, ISIS_MT_IPV4_UNICAST
, lsp_to_edge_cb
,
1399 isis_lsp_iterate_is_reach(lsp
, ISIS_MT_IPV6_UNICAST
, lsp_to_edge_cb
,
1402 /* Process all Extended IP (v4 & v6) in LSP (all fragments) */
1403 isis_lsp_iterate_ip_reach(lsp
, AF_INET
, ISIS_MT_IPV4_UNICAST
,
1404 lsp_to_subnet_cb
, &args
);
1405 isis_lsp_iterate_ip_reach(lsp
, AF_INET6
, ISIS_MT_IPV6_UNICAST
,
1406 lsp_to_subnet_cb
, &args
);
1407 isis_lsp_iterate_ip_reach(lsp
, AF_INET6
, ISIS_MT_IPV4_UNICAST
,
1408 lsp_to_subnet_cb
, &args
);
1410 /* Clean remaining Orphan Edges or Subnets */
1411 if (IS_EXPORT_TE(mta
))
1412 ls_vertex_clean(ted
, vertex
, zclient
);
1414 ls_vertex_clean(ted
, vertex
, NULL
);
1418 * Delete Link State Database Vertex, Edge & Prefix that correspond to this
1419 * ISIS Link State PDU
1421 * @param ted Link State Database
1422 * @param lsp ISIS Link State PDU
1424 static void isis_te_delete_lsp(struct mpls_te_area
*mta
, struct isis_lsp
*lsp
)
1427 struct ls_vertex
*vertex
= NULL
;
1428 struct ls_node lnode
= {};
1429 struct ls_edge
*edge
;
1430 struct ls_subnet
*subnet
;
1431 struct listnode
*nnode
, *node
;
1434 if (!IS_MPLS_TE(mta
) || !mta
->ted
|| !lsp
)
1437 te_debug("ISIS-TE(%s): Delete Link State TED objects from LSP %pSY",
1438 lsp
->area
->area_tag
, lsp
->hdr
.lsp_id
);
1440 /* Compute Link State Node ID from IS-IS sysID ... */
1441 if (lsp
->level
== ISIS_LEVEL1
)
1442 lnode
.adv
.origin
= ISIS_L1
;
1444 lnode
.adv
.origin
= ISIS_L2
;
1445 memcpy(&lnode
.adv
.id
.iso
.sys_id
, &lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
);
1446 lnode
.adv
.id
.iso
.level
= lsp
->level
;
1448 /* ... and search the corresponding vertex */
1449 vertex
= ls_find_vertex_by_id(ted
, lnode
.adv
);
1453 te_debug(" |- Delete Vertex %s", vertex
->node
->name
);
1456 * We can't use the ls_vertex_del_all() function if export TE is set,
1457 * as we must first advertise the client daemons of each removal.
1459 /* Remove outgoing Edges */
1460 for (ALL_LIST_ELEMENTS(vertex
->outgoing_edges
, node
, nnode
, edge
)) {
1461 if (IS_EXPORT_TE(mta
)) {
1462 edge
->status
= DELETE
;
1463 isis_te_export(LS_MSG_TYPE_ATTRIBUTES
, edge
);
1465 ls_edge_del_all(ted
, edge
);
1468 /* Disconnect incoming Edges */
1469 for (ALL_LIST_ELEMENTS(vertex
->incoming_edges
, node
, nnode
, edge
)) {
1470 ls_disconnect(vertex
, edge
, false);
1471 if (edge
->source
== NULL
) {
1472 if (IS_EXPORT_TE(mta
)) {
1473 edge
->status
= DELETE
;
1474 isis_te_export(LS_MSG_TYPE_ATTRIBUTES
, edge
);
1476 ls_edge_del_all(ted
, edge
);
1480 /* Remove subnets */
1481 for (ALL_LIST_ELEMENTS(vertex
->prefixes
, node
, nnode
, subnet
)) {
1482 if (IS_EXPORT_TE(mta
)) {
1483 subnet
->status
= DELETE
;
1484 isis_te_export(LS_MSG_TYPE_PREFIX
, subnet
);
1486 ls_subnet_del_all(ted
, subnet
);
1489 /* Then remove Link State Node */
1490 if (IS_EXPORT_TE(mta
)) {
1491 vertex
->status
= DELETE
;
1492 isis_te_export(LS_MSG_TYPE_NODE
, vertex
);
1494 ls_node_del(vertex
->node
);
1496 /* Finally, remove Vertex */
1497 ls_vertex_del(ted
, vertex
);
1501 * Process ISIS LSP according to the event to add, update or remove
1502 * corresponding vertex, edge and prefix in the Link State database.
1503 * Since LSP could be fragmented, the function starts by searching the root LSP
1504 * to retrieve the complete LSP, including eventual fragment before processing
1507 * @param lsp ISIS Link State PDU
1508 * @param event LSP event: ADD, UPD, INC & DEL (TICK are ignored)
1511 void isis_te_lsp_event(struct isis_lsp
*lsp
, enum lsp_event event
)
1513 struct isis_area
*area
;
1514 struct isis_lsp
*lsp0
;
1517 if (!lsp
|| !lsp
->area
)
1521 if (!IS_MPLS_TE(area
->mta
))
1524 /* Adjust LSP0 in case of fragment */
1525 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
))
1526 lsp0
= lsp
->lspu
.zero_lsp
;
1530 /* Then process event */
1535 isis_te_parse_lsp(area
->mta
, lsp0
);
1538 isis_te_delete_lsp(area
->mta
, lsp0
);
1547 * Send the whole Link State Traffic Engineering Database to the consumer that
1548 * request it through a ZAPI Link State Synchronous Opaque Message.
1550 * @param info ZAPI Opaque message
1552 * @return 0 if success, -1 otherwise
1554 int isis_te_sync_ted(struct zapi_opaque_reg_info dst
)
1556 struct listnode
*node
, *inode
;
1558 struct isis_area
*area
;
1559 struct mpls_te_area
*mta
;
1562 te_debug("ISIS-TE(%s): Received TED synchro from client %d", __func__
,
1564 /* For each area, send TED if TE distribution is enabled */
1565 for (ALL_LIST_ELEMENTS_RO(im
->isis
, inode
, isis
)) {
1566 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
, area
)) {
1568 if (IS_MPLS_TE(mta
) && IS_EXPORT_TE(mta
)) {
1569 te_debug(" |- Export TED from area %s",
1571 rc
= ls_sync_ted(mta
->ted
, zclient
, &dst
);
1582 * Initialize the Link State database from the LSP already stored for this area
1584 * @param area ISIS area
1586 void isis_te_init_ted(struct isis_area
*area
)
1588 struct isis_lsp
*lsp
;
1590 /* Iterate over all lsp. */
1591 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++)
1592 frr_each (lspdb
, &area
->lspdb
[level
- 1], lsp
)
1593 isis_te_parse_lsp(area
->mta
, lsp
);
1596 /* Following are vty command functions */
1599 static void show_router_id(struct vty
*vty
, struct isis_area
*area
)
1601 bool no_match
= true;
1603 vty_out(vty
, "Area %s:\n", area
->area_tag
);
1604 if (area
->mta
->router_id
.s_addr
!= 0) {
1605 vty_out(vty
, " MPLS-TE IPv4 Router-Address: %pI4\n",
1606 &area
->mta
->router_id
);
1609 if (!IN6_IS_ADDR_UNSPECIFIED(&area
->mta
->router_id_ipv6
)) {
1610 vty_out(vty
, " MPLS-TE IPv6 Router-Address: %pI6\n",
1611 &area
->mta
->router_id_ipv6
);
1615 vty_out(vty
, " N/A\n");
1618 DEFUN(show_isis_mpls_te_router
,
1619 show_isis_mpls_te_router_cmd
,
1620 "show " PROTO_NAME
" [vrf <NAME|all>] mpls-te router",
1623 VRF_CMD_HELP_STR
"All VRFs\n"
1624 MPLS_TE_STR
"Router information\n")
1627 struct listnode
*anode
, *inode
;
1628 struct isis_area
*area
;
1629 struct isis
*isis
= NULL
;
1630 const char *vrf_name
= VRF_DEFAULT_NAME
;
1631 bool all_vrf
= false;
1635 vty_out(vty
, "IS-IS Routing Process not enabled\n");
1638 ISIS_FIND_VRF_ARGS(argv
, argc
, idx_vrf
, vrf_name
, all_vrf
);
1641 for (ALL_LIST_ELEMENTS_RO(im
->isis
, inode
, isis
)) {
1642 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
,
1644 if (!IS_MPLS_TE(area
->mta
))
1647 show_router_id(vty
, area
);
1652 isis
= isis_lookup_by_vrfname(vrf_name
);
1654 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, anode
,
1657 if (!IS_MPLS_TE(area
->mta
))
1660 show_router_id(vty
, area
);
1668 static void show_ext_sub(struct vty
*vty
, char *name
,
1669 struct isis_ext_subtlvs
*ext
)
1672 char ibuf
[PREFIX2STR_BUFFER
];
1674 sbuf_init(&buf
, NULL
, 0);
1676 if (!ext
|| ext
->status
== EXT_DISABLE
)
1679 vty_out(vty
, "-- MPLS-TE link parameters for %s --\n", name
);
1683 if (IS_SUBTLV(ext
, EXT_ADM_GRP
))
1684 sbuf_push(&buf
, 4, "Administrative Group: 0x%x\n",
1686 if (IS_SUBTLV(ext
, EXT_LLRI
)) {
1687 sbuf_push(&buf
, 4, "Link Local ID: %u\n",
1689 sbuf_push(&buf
, 4, "Link Remote ID: %u\n",
1692 if (IS_SUBTLV(ext
, EXT_LOCAL_ADDR
))
1693 sbuf_push(&buf
, 4, "Local Interface IP Address(es): %pI4\n",
1695 if (IS_SUBTLV(ext
, EXT_NEIGH_ADDR
))
1696 sbuf_push(&buf
, 4, "Remote Interface IP Address(es): %pI4\n",
1698 if (IS_SUBTLV(ext
, EXT_LOCAL_ADDR6
))
1699 sbuf_push(&buf
, 4, "Local Interface IPv6 Address(es): %s\n",
1700 inet_ntop(AF_INET6
, &ext
->local_addr6
, ibuf
,
1701 PREFIX2STR_BUFFER
));
1702 if (IS_SUBTLV(ext
, EXT_NEIGH_ADDR6
))
1703 sbuf_push(&buf
, 4, "Remote Interface IPv6 Address(es): %s\n",
1704 inet_ntop(AF_INET6
, &ext
->local_addr6
, ibuf
,
1705 PREFIX2STR_BUFFER
));
1706 if (IS_SUBTLV(ext
, EXT_MAX_BW
))
1707 sbuf_push(&buf
, 4, "Maximum Bandwidth: %g (Bytes/sec)\n",
1709 if (IS_SUBTLV(ext
, EXT_MAX_RSV_BW
))
1711 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
1713 if (IS_SUBTLV(ext
, EXT_UNRSV_BW
)) {
1714 sbuf_push(&buf
, 4, "Unreserved Bandwidth:\n");
1715 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 2) {
1716 sbuf_push(&buf
, 4 + 2,
1717 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
1718 j
, ext
->unrsv_bw
[j
],
1719 j
+ 1, ext
->unrsv_bw
[j
+ 1]);
1722 if (IS_SUBTLV(ext
, EXT_TE_METRIC
))
1723 sbuf_push(&buf
, 4, "Traffic Engineering Metric: %u\n",
1725 if (IS_SUBTLV(ext
, EXT_RMT_AS
))
1727 "Inter-AS TE Remote AS number: %u\n",
1729 if (IS_SUBTLV(ext
, EXT_RMT_IP
))
1731 "Inter-AS TE Remote ASBR IP address: %pI4\n",
1733 if (IS_SUBTLV(ext
, EXT_DELAY
))
1735 "%s Average Link Delay: %u (micro-sec)\n",
1736 IS_ANORMAL(ext
->delay
) ? "Anomalous" : "Normal",
1737 ext
->delay
& TE_EXT_MASK
);
1738 if (IS_SUBTLV(ext
, EXT_MM_DELAY
)) {
1739 sbuf_push(&buf
, 4, "%s Min/Max Link Delay: %u / %u (micro-sec)\n",
1740 IS_ANORMAL(ext
->min_delay
) ? "Anomalous" : "Normal",
1741 ext
->min_delay
& TE_EXT_MASK
,
1742 ext
->max_delay
& TE_EXT_MASK
);
1744 if (IS_SUBTLV(ext
, EXT_DELAY_VAR
))
1746 "Delay Variation: %u (micro-sec)\n",
1747 ext
->delay_var
& TE_EXT_MASK
);
1748 if (IS_SUBTLV(ext
, EXT_PKT_LOSS
))
1749 sbuf_push(&buf
, 4, "%s Link Packet Loss: %g (%%)\n",
1750 IS_ANORMAL(ext
->pkt_loss
) ? "Anomalous" : "Normal",
1751 (float)((ext
->pkt_loss
& TE_EXT_MASK
)
1753 if (IS_SUBTLV(ext
, EXT_RES_BW
))
1755 "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n",
1757 if (IS_SUBTLV(ext
, EXT_AVA_BW
))
1759 "Unidirectional Available Bandwidth: %g (Bytes/sec)\n",
1761 if (IS_SUBTLV(ext
, EXT_USE_BW
))
1763 "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n",
1766 vty_multiline(vty
, "", "%s", sbuf_buf(&buf
));
1767 vty_out(vty
, "---------------\n\n");
1773 DEFUN (show_isis_mpls_te_interface
,
1774 show_isis_mpls_te_interface_cmd
,
1775 "show " PROTO_NAME
" mpls-te interface [INTERFACE]",
1779 "Interface information\n"
1782 struct listnode
*anode
, *cnode
, *inode
;
1783 struct isis_area
*area
;
1784 struct isis_circuit
*circuit
;
1785 struct interface
*ifp
;
1786 int idx_interface
= 4;
1787 struct isis
*isis
= NULL
;
1790 vty_out(vty
, "IS-IS Routing Process not enabled\n");
1794 if (argc
== idx_interface
) {
1795 /* Show All Interfaces. */
1796 for (ALL_LIST_ELEMENTS_RO(im
->isis
, inode
, isis
)) {
1797 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, anode
,
1800 if (!IS_MPLS_TE(area
->mta
))
1803 vty_out(vty
, "Area %s:\n", area
->area_tag
);
1805 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
,
1808 circuit
->interface
->name
,
1813 /* Interface name is specified. */
1814 ifp
= if_lookup_by_name(argv
[idx_interface
]->arg
, VRF_DEFAULT
);
1816 vty_out(vty
, "No such interface name\n");
1818 circuit
= circuit_scan_by_ifp(ifp
);
1821 "ISIS is not enabled on circuit %s\n",
1824 show_ext_sub(vty
, ifp
->name
, circuit
->ext
);
1832 * Search Vertex in TED that corresponds to the given string that represent
1833 * the ISO system ID in the forms <systemid/hostname>[.<pseudo-id>-<framenent>]
1835 * @param ted Link State Database
1836 * @param id ISO System ID
1837 * @param isis Main reference to the isis daemon
1839 * @return Vertex if found, NULL otherwise
1841 static struct ls_vertex
*vertex_for_arg(struct ls_ted
*ted
, const char *id
,
1844 char sysid
[255] = {0};
1847 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2] = {0};
1848 struct isis_dynhn
*dynhn
;
1855 * extract fragment and pseudo id from the string argv
1857 * (a) <systemid/hostname>.<pseudo-id>-<framenent> or
1858 * (b) <systemid/hostname>.<pseudo-id> or
1859 * (c) <systemid/hostname> or
1860 * Where systemid is in the form:
1863 strlcpy(sysid
, id
, sizeof(sysid
));
1864 if (strlen(id
) > 3) {
1865 pos
= id
+ strlen(id
) - 3;
1866 if (strncmp(pos
, "-", 1) == 0) {
1867 memcpy(number
, ++pos
, 2);
1868 lspid
[ISIS_SYS_ID_LEN
+ 1] =
1869 (uint8_t)strtol((char *)number
, NULL
, 16);
1871 if (strncmp(pos
, ".", 1) != 0)
1874 if (strncmp(pos
, ".", 1) == 0) {
1875 memcpy(number
, ++pos
, 2);
1876 lspid
[ISIS_SYS_ID_LEN
] =
1877 (uint8_t)strtol((char *)number
, NULL
, 16);
1878 sysid
[pos
- id
- 1] = '\0';
1883 * Try to find the lsp-id if the argv
1886 * hostname.<pseudo-id>-<fragment>
1888 if (sysid2buff(lspid
, sysid
)) {
1889 key
= sysid_to_key(lspid
);
1890 } else if ((dynhn
= dynhn_find_by_name(isis
, sysid
))) {
1891 memcpy(lspid
, dynhn
->id
, ISIS_SYS_ID_LEN
);
1892 key
= sysid_to_key(lspid
);
1893 } else if (strncmp(cmd_hostname_get(), sysid
, 15) == 0) {
1894 memcpy(lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1895 key
= sysid_to_key(lspid
);
1901 return ls_find_vertex_by_key(ted
, key
);
1905 * Show Link State Traffic Engineering Database extracted from IS-IS LSP.
1907 * @param vty VTY output console
1908 * @param argv Command line argument
1909 * @param argc Number of command line argument
1910 * @param ted Traffic Engineering Database
1911 * @param isis isis Main reference to the isis daemon
1913 * @return Command Success if OK, Command Warning otherwise
1915 static int show_ted(struct vty
*vty
, struct cmd_token
*argv
[], int argc
,
1916 struct isis_area
*area
, struct isis
*isis
)
1920 struct in_addr ip_addr
;
1921 struct in6_addr ip6_addr
;
1924 struct ls_vertex
*vertex
;
1925 struct ls_edge
*edge
;
1926 struct ls_subnet
*subnet
;
1927 struct ls_edge_key key
;
1928 bool detail
= false;
1929 bool uj
= use_json(argc
, argv
);
1930 json_object
*json
= NULL
;
1932 if (!IS_MPLS_TE(area
->mta
) || !area
->mta
->ted
) {
1933 vty_out(vty
, "MPLS-TE is disabled for Area %s\n",
1934 area
->area_tag
? area
->area_tag
: "null");
1938 ted
= area
->mta
->ted
;
1941 json
= json_object_new_object();
1943 vty_out(vty
, "Area %s:\n",
1944 area
->area_tag
? area
->area_tag
: "null");
1946 if (argv
[argc
- 1]->arg
&& strmatch(argv
[argc
- 1]->text
, "detail"))
1950 if (argv_find(argv
, argc
, "vertex", &idx
)) {
1952 id
= argv_find(argv
, argc
, "WORD", &idx
) ? argv
[idx
]->arg
1956 else if (!strncmp(id
, "self", 4))
1959 vertex
= vertex_for_arg(ted
, id
, isis
);
1961 vty_out(vty
, "No vertex found for ID %s\n", id
);
1967 ls_show_vertex(vertex
, vty
, json
, detail
);
1969 ls_show_vertices(ted
, vty
, json
, detail
);
1971 } else if (argv_find(argv
, argc
, "edge", &idx
)) {
1973 if (argv_find(argv
, argc
, "A.B.C.D", &idx
)) {
1974 if (!inet_pton(AF_INET
, argv
[idx
]->arg
, &ip_addr
)) {
1976 "Specified Edge ID %s is invalid\n",
1978 return CMD_WARNING_CONFIG_FAILED
;
1980 /* Get the Edge from the Link State Database */
1981 key
.family
= AF_INET
;
1982 IPV4_ADDR_COPY(&key
.k
.addr
, &ip_addr
);
1983 edge
= ls_find_edge_by_key(ted
, key
);
1985 vty_out(vty
, "No edge found for ID %pI4\n",
1989 } else if (argv_find(argv
, argc
, "X:X::X:X", &idx
)) {
1990 if (!inet_pton(AF_INET6
, argv
[idx
]->arg
, &ip6_addr
)) {
1992 "Specified Edge ID %s is invalid\n",
1994 return CMD_WARNING_CONFIG_FAILED
;
1996 /* Get the Edge from the Link State Database */
1997 key
.family
= AF_INET6
;
1998 IPV6_ADDR_COPY(&key
.k
.addr6
, &ip6_addr
);
1999 edge
= ls_find_edge_by_key(ted
, key
);
2001 vty_out(vty
, "No edge found for ID %pI6\n",
2009 ls_show_edge(edge
, vty
, json
, detail
);
2011 ls_show_edges(ted
, vty
, json
, detail
);
2013 } else if (argv_find(argv
, argc
, "subnet", &idx
)) {
2015 if (argv_find(argv
, argc
, "A.B.C.D/M", &idx
)) {
2016 if (!str2prefix(argv
[idx
]->arg
, &pref
)) {
2017 vty_out(vty
, "Invalid prefix format %s\n",
2019 return CMD_WARNING_CONFIG_FAILED
;
2021 /* Get the Subnet from the Link State Database */
2022 subnet
= ls_find_subnet(ted
, &pref
);
2024 vty_out(vty
, "No subnet found for ID %pFX\n",
2028 } else if (argv_find(argv
, argc
, "X:X::X:X/M", &idx
)) {
2029 if (!str2prefix(argv
[idx
]->arg
, &pref
)) {
2030 vty_out(vty
, "Invalid prefix format %s\n",
2032 return CMD_WARNING_CONFIG_FAILED
;
2034 /* Get the Subnet from the Link State Database */
2035 subnet
= ls_find_subnet(ted
, &pref
);
2037 vty_out(vty
, "No subnet found for ID %pFX\n",
2045 ls_show_subnet(subnet
, vty
, json
, detail
);
2047 ls_show_subnets(ted
, vty
, json
, detail
);
2050 /* Show the complete TED */
2051 ls_show_ted(ted
, vty
, json
, detail
);
2055 vty_json(vty
, json
);
2061 * Show ISIS Traffic Engineering Database
2063 * @param vty VTY output console
2064 * @param argv Command line argument
2065 * @param argc Number of command line argument
2066 * @param isis isis Main reference to the isis daemon
2068 * @return Command Success if OK, Command Warning otherwise
2070 static int show_isis_ted(struct vty
*vty
, struct cmd_token
*argv
[], int argc
,
2073 struct listnode
*node
;
2074 struct isis_area
*area
;
2077 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
, area
)) {
2078 rc
= show_ted(vty
, argv
, argc
, area
, isis
);
2079 if (rc
!= CMD_SUCCESS
)
2085 DEFUN(show_isis_mpls_te_db
,
2086 show_isis_mpls_te_db_cmd
,
2087 "show " PROTO_NAME
" [vrf <NAME|all>] mpls-te database [<vertex [WORD]|edge [A.B.C.D|X:X::X:X]|subnet [A.B.C.D/M|X:X::X:X/M]>] [detail|json]",
2088 SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
2091 "MPLS-TE database\n"
2093 "MPLS-TE Vertex ID (as an ISO ID, hostname or \"self\")\n"
2095 "MPLS-TE Edge ID (as an IPv4 address)\n"
2096 "MPLS-TE Edge ID (as an IPv6 address)\n"
2098 "MPLS-TE Subnet ID (as an IPv4 prefix)\n"
2099 "MPLS-TE Subnet ID (as an IPv6 prefix)\n"
2100 "Detailed information\n"
2104 const char *vrf_name
= VRF_DEFAULT_NAME
;
2105 bool all_vrf
= false;
2106 struct listnode
*node
;
2108 int rc
= CMD_WARNING
;
2110 ISIS_FIND_VRF_ARGS(argv
, argc
, idx_vrf
, vrf_name
, all_vrf
);
2113 for (ALL_LIST_ELEMENTS_RO(im
->isis
, node
, isis
)) {
2114 rc
= show_isis_ted(vty
, argv
, argc
, isis
);
2115 if (rc
!= CMD_SUCCESS
)
2120 isis
= isis_lookup_by_vrfname(vrf_name
);
2122 rc
= show_isis_ted(vty
, argv
, argc
, isis
);
2128 #endif /* #ifndef FRABRICD */
2130 /* Initialize MPLS_TE */
2131 void isis_mpls_te_init(void)
2134 /* Register Circuit and Adjacency hook */
2135 hook_register(isis_if_new_hook
, isis_mpls_te_update
);
2136 hook_register(isis_adj_ip_enabled_hook
, isis_mpls_te_adj_ip_enabled
);
2137 hook_register(isis_adj_ip_disabled_hook
, isis_mpls_te_adj_ip_disabled
);
2140 /* Register new VTY commands */
2141 install_element(VIEW_NODE
, &show_isis_mpls_te_router_cmd
);
2142 install_element(VIEW_NODE
, &show_isis_mpls_te_interface_cmd
);
2143 install_element(VIEW_NODE
, &show_isis_mpls_te_db_cmd
);