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 /* Main initialization / update function of the MPLS TE Circuit context */
168 /* Call when interface TE Link parameters are modified */
169 void isis_link_params_update(struct isis_circuit
*circuit
,
170 struct interface
*ifp
)
173 struct prefix_ipv4
*addr
;
174 struct prefix_ipv6
*addr6
;
175 struct isis_ext_subtlvs
*ext
;
177 /* Check if TE is enable or not */
178 if (!circuit
->area
|| !IS_MPLS_TE(circuit
->area
->mta
))
182 if ((ifp
== NULL
) || (circuit
->state
!= C_STATE_UP
))
185 te_debug("ISIS-TE(%s): Update circuit parameters for interface %s",
186 circuit
->area
->area_tag
, ifp
->name
);
188 /* Check if MPLS TE Circuit context has not been already created */
189 if (circuit
->ext
== NULL
) {
190 circuit
->ext
= isis_alloc_ext_subtlvs();
191 te_debug(" |- Allocated new Ext-subTLVs for interface %s",
197 /* Fulfill Extended subTLVs from interface link parameters */
198 if (HAS_LINK_PARAMS(ifp
)) {
200 if (IS_PARAM_SET(ifp
->link_params
, LP_ADM_GRP
)) {
201 ext
->adm_group
= ifp
->link_params
->admin_grp
;
202 SET_SUBTLV(ext
, EXT_ADM_GRP
);
204 UNSET_SUBTLV(ext
, EXT_ADM_GRP
);
206 if (IS_PARAM_SET(ifp
->link_params
, LP_EXTEND_ADM_GRP
)) {
207 admin_group_copy(&ext
->ext_admin_group
,
208 &ifp
->link_params
->ext_admin_grp
);
209 SET_SUBTLV(ext
, EXT_EXTEND_ADM_GRP
);
211 UNSET_SUBTLV(ext
, EXT_EXTEND_ADM_GRP
);
213 /* If known, register local IPv4 addr from ip_addr list */
214 if (listcount(circuit
->ip_addrs
) != 0) {
215 addr
= (struct prefix_ipv4
*)listgetdata(
216 (struct listnode
*)listhead(circuit
->ip_addrs
));
217 IPV4_ADDR_COPY(&ext
->local_addr
, &addr
->prefix
);
218 SET_SUBTLV(ext
, EXT_LOCAL_ADDR
);
220 UNSET_SUBTLV(ext
, EXT_LOCAL_ADDR
);
222 /* If known, register local IPv6 addr from ip_addr list */
223 if (listcount(circuit
->ipv6_non_link
) != 0) {
224 addr6
= (struct prefix_ipv6
*)listgetdata(
225 (struct listnode
*)listhead(
226 circuit
->ipv6_non_link
));
227 IPV6_ADDR_COPY(&ext
->local_addr6
, &addr6
->prefix
);
228 SET_SUBTLV(ext
, EXT_LOCAL_ADDR6
);
230 UNSET_SUBTLV(ext
, EXT_LOCAL_ADDR6
);
233 * Remote IPv4 and IPv6 addresses are now added in
234 * isis_mpls_te_adj_ip_enabled() to get the right IP address
235 * in particular for IPv6 to get the global IPv6 address and
236 * not the link-local IPv6 address.
239 if (IS_PARAM_SET(ifp
->link_params
, LP_MAX_BW
)) {
240 ext
->max_bw
= ifp
->link_params
->max_bw
;
241 SET_SUBTLV(ext
, EXT_MAX_BW
);
243 UNSET_SUBTLV(ext
, EXT_MAX_BW
);
245 if (IS_PARAM_SET(ifp
->link_params
, LP_MAX_RSV_BW
)) {
246 ext
->max_rsv_bw
= ifp
->link_params
->max_rsv_bw
;
247 SET_SUBTLV(ext
, EXT_MAX_RSV_BW
);
249 UNSET_SUBTLV(ext
, EXT_MAX_RSV_BW
);
251 if (IS_PARAM_SET(ifp
->link_params
, LP_UNRSV_BW
)) {
252 for (i
= 0; i
< MAX_CLASS_TYPE
; i
++)
254 ifp
->link_params
->unrsv_bw
[i
];
255 SET_SUBTLV(ext
, EXT_UNRSV_BW
);
257 UNSET_SUBTLV(ext
, EXT_UNRSV_BW
);
259 if (IS_PARAM_SET(ifp
->link_params
, LP_TE_METRIC
)) {
260 ext
->te_metric
= ifp
->link_params
->te_metric
;
261 SET_SUBTLV(ext
, EXT_TE_METRIC
);
263 UNSET_SUBTLV(ext
, EXT_TE_METRIC
);
265 /* TE metric extensions */
266 if (IS_PARAM_SET(ifp
->link_params
, LP_DELAY
)) {
267 ext
->delay
= ifp
->link_params
->av_delay
;
268 SET_SUBTLV(ext
, EXT_DELAY
);
270 UNSET_SUBTLV(ext
, EXT_DELAY
);
272 if (IS_PARAM_SET(ifp
->link_params
, LP_MM_DELAY
)) {
273 ext
->min_delay
= ifp
->link_params
->min_delay
;
274 ext
->max_delay
= ifp
->link_params
->max_delay
;
275 SET_SUBTLV(ext
, EXT_MM_DELAY
);
277 UNSET_SUBTLV(ext
, EXT_MM_DELAY
);
279 if (IS_PARAM_SET(ifp
->link_params
, LP_DELAY_VAR
)) {
280 ext
->delay_var
= ifp
->link_params
->delay_var
;
281 SET_SUBTLV(ext
, EXT_DELAY_VAR
);
283 UNSET_SUBTLV(ext
, EXT_DELAY_VAR
);
285 if (IS_PARAM_SET(ifp
->link_params
, LP_PKT_LOSS
)) {
286 ext
->pkt_loss
= ifp
->link_params
->pkt_loss
;
287 SET_SUBTLV(ext
, EXT_PKT_LOSS
);
289 UNSET_SUBTLV(ext
, EXT_PKT_LOSS
);
291 if (IS_PARAM_SET(ifp
->link_params
, LP_RES_BW
)) {
292 ext
->res_bw
= ifp
->link_params
->res_bw
;
293 SET_SUBTLV(ext
, EXT_RES_BW
);
295 UNSET_SUBTLV(ext
, EXT_RES_BW
);
297 if (IS_PARAM_SET(ifp
->link_params
, LP_AVA_BW
)) {
298 ext
->ava_bw
= ifp
->link_params
->ava_bw
;
299 SET_SUBTLV(ext
, EXT_AVA_BW
);
301 UNSET_SUBTLV(ext
, EXT_AVA_BW
);
303 if (IS_PARAM_SET(ifp
->link_params
, LP_USE_BW
)) {
304 ext
->use_bw
= ifp
->link_params
->use_bw
;
305 SET_SUBTLV(ext
, EXT_USE_BW
);
307 UNSET_SUBTLV(ext
, EXT_USE_BW
);
310 if (IS_PARAM_SET(ifp
->link_params
, LP_RMT_AS
)) {
311 ext
->remote_as
= ifp
->link_params
->rmt_as
;
312 ext
->remote_ip
= ifp
->link_params
->rmt_ip
;
313 SET_SUBTLV(ext
, EXT_RMT_AS
);
314 SET_SUBTLV(ext
, EXT_RMT_IP
);
316 /* reset inter-as TE params */
317 UNSET_SUBTLV(ext
, EXT_RMT_AS
);
318 UNSET_SUBTLV(ext
, EXT_RMT_IP
);
320 te_debug(" |- New MPLS-TE link parameters status 0x%x",
323 te_debug(" |- Reset Extended subTLVs status 0x%x",
325 /* Reset TE subTLVs keeping SR one's */
326 if (IS_SUBTLV(ext
, EXT_ADJ_SID
))
327 ext
->status
= EXT_ADJ_SID
;
328 else if (IS_SUBTLV(ext
, EXT_LAN_ADJ_SID
))
329 ext
->status
= EXT_LAN_ADJ_SID
;
337 static int _isis_mpls_te_adj_ip_enabled(struct isis_adjacency
*adj
, int family
,
340 struct isis_circuit
*circuit
;
341 struct isis_ext_subtlvs
*ext
;
343 circuit
= adj
->circuit
;
345 /* Check that MPLS TE is enabled */
346 if (!IS_MPLS_TE(circuit
->area
->mta
) || !circuit
->ext
)
351 /* Determine nexthop IP address */
354 if (!circuit
->ip_router
|| !adj
->ipv4_address_count
)
355 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR
);
357 IPV4_ADDR_COPY(&ext
->neigh_addr
,
358 &adj
->ipv4_addresses
[0]);
359 SET_SUBTLV(ext
, EXT_NEIGH_ADDR
);
363 /* Nothing to do for link-local addresses - ie. not global.
364 * https://datatracker.ietf.org/doc/html/rfc6119#section-3.1.1
365 * Because the IPv6 traffic engineering TLVs present in LSPs are
366 * propagated across networks, they MUST NOT use link-local
372 if (!circuit
->ipv6_router
|| !adj
->global_ipv6_count
)
373 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR6
);
375 IPV6_ADDR_COPY(&ext
->neigh_addr6
,
376 &adj
->global_ipv6_addrs
[0]);
377 SET_SUBTLV(ext
, EXT_NEIGH_ADDR6
);
387 static int isis_mpls_te_adj_ip_enabled(struct isis_adjacency
*adj
, int family
,
393 if (!adj
|| !adj
->circuit
)
396 ret
= _isis_mpls_te_adj_ip_enabled(adj
, family
, global
);
399 lsp_regenerate_schedule(adj
->circuit
->area
, adj
->circuit
->is_type
, 0);
404 static int _isis_mpls_te_adj_ip_disabled(struct isis_adjacency
*adj
, int family
,
407 struct isis_circuit
*circuit
;
408 struct isis_ext_subtlvs
*ext
;
410 circuit
= adj
->circuit
;
412 /* Check that MPLS TE is enabled */
413 if (!IS_MPLS_TE(circuit
->area
->mta
) || !circuit
->ext
)
418 /* Update MPLS TE IP address parameters if possible */
419 if (!IS_MPLS_TE(circuit
->area
->mta
) || !IS_EXT_TE(ext
))
422 /* Determine nexthop IP address */
425 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR
);
429 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR6
);
438 static int isis_mpls_te_adj_ip_disabled(struct isis_adjacency
*adj
, int family
,
444 if (!adj
|| !adj
->circuit
|| !adj
->circuit
->ext
)
447 ret
= _isis_mpls_te_adj_ip_disabled(adj
, family
, global
);
450 lsp_regenerate_schedule(adj
->circuit
->area
, adj
->circuit
->is_type
, 0);
455 static void isis_mpls_te_circuit_ip_update(struct isis_circuit
*circuit
)
457 struct isis_adjacency
*adj
;
459 /* https://datatracker.ietf.org/doc/html/rfc6119#section-3.2.3
460 * This sub-TLV of the Extended IS Reachability TLV is used for point-
463 if (circuit
->circ_type
!= CIRCUIT_T_P2P
)
466 adj
= circuit
->u
.p2p
.neighbor
;
471 /* Nothing to do for link-local addresses.
472 * https://datatracker.ietf.org/doc/html/rfc6119#section-3.1.1
473 * Because the IPv6 traffic engineering TLVs present in LSPs are
474 * propagated across networks, they MUST NOT use link-local addresses.
476 if (adj
->ipv4_address_count
> 0)
477 _isis_mpls_te_adj_ip_enabled(adj
, AF_INET
, false);
479 _isis_mpls_te_adj_ip_disabled(adj
, AF_INET
, false);
481 if (adj
->global_ipv6_count
> 0)
482 _isis_mpls_te_adj_ip_enabled(adj
, AF_INET6
, true);
484 _isis_mpls_te_adj_ip_disabled(adj
, AF_INET6
, true);
488 int isis_mpls_te_update(struct interface
*ifp
)
490 struct isis_circuit
*circuit
;
497 /* Get circuit context from interface */
498 circuit
= circuit_scan_by_ifp(ifp
);
502 /* Update TE TLVs ... */
503 isis_link_params_update(circuit
, ifp
);
506 if (circuit
->area
&& IS_MPLS_TE(circuit
->area
->mta
))
507 lsp_regenerate_schedule(circuit
->area
, circuit
->is_type
, 0);
515 * Export Link State information to consumer daemon through ZAPI Link State
518 * @param type Type of Link State Element i.e. Vertex, Edge or Subnet
519 * @param link_state Pointer to Link State Vertex, Edge or Subnet
521 * @return 0 if success, -1 otherwise
523 static int isis_te_export(uint8_t type
, void *link_state
)
525 struct ls_message msg
= {};
529 case LS_MSG_TYPE_NODE
:
530 ls_vertex2msg(&msg
, (struct ls_vertex
*)link_state
);
531 rc
= ls_send_msg(zclient
, &msg
, NULL
);
533 case LS_MSG_TYPE_ATTRIBUTES
:
534 ls_edge2msg(&msg
, (struct ls_edge
*)link_state
);
535 rc
= ls_send_msg(zclient
, &msg
, NULL
);
537 case LS_MSG_TYPE_PREFIX
:
538 ls_subnet2msg(&msg
, (struct ls_subnet
*)link_state
);
539 rc
= ls_send_msg(zclient
, &msg
, NULL
);
550 * Parse LSP and build corresponding vertex. If vertex doesn't exist in the
551 * Link State Database it is created otherwise updated.
553 * @param ted Traffic Engineering Link State Database
554 * @param lsp IS-IS Link State PDU
556 * @return Link State Vertex or NULL in case of error
558 static struct ls_vertex
*lsp_to_vertex(struct ls_ted
*ted
, struct isis_lsp
*lsp
)
560 struct ls_vertex
*vertex
= NULL
;
561 struct ls_node
*old
, lnode
= {};
562 struct isis_tlvs
*tlvs
;
563 const struct in_addr inaddr_any
= {.s_addr
= INADDR_ANY
};
569 /* Compute Link State Node ID from IS-IS sysID ... */
570 if (lsp
->level
== ISIS_LEVEL1
)
571 lnode
.adv
.origin
= ISIS_L1
;
573 lnode
.adv
.origin
= ISIS_L2
;
574 memcpy(&lnode
.adv
.id
.iso
.sys_id
, &lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
);
575 lnode
.adv
.id
.iso
.level
= lsp
->level
;
576 /* ... and search the corresponding vertex */
577 vertex
= ls_find_vertex_by_id(ted
, lnode
.adv
);
578 /* Create a new one if not found */
580 old
= ls_node_new(lnode
.adv
, inaddr_any
, in6addr_any
);
581 old
->type
= STANDARD
;
582 vertex
= ls_vertex_add(ted
, old
);
585 te_debug(" |- %s Vertex (%" PRIu64
") for node %s",
586 vertex
->status
== NEW
? "Create" : "Found", vertex
->key
,
587 print_sys_hostname(old
->adv
.id
.iso
.sys_id
));
589 /* Fulfill Link State Node information */
592 if (tlvs
->te_router_id
) {
593 IPV4_ADDR_COPY(&lnode
.router_id
, tlvs
->te_router_id
);
594 SET_FLAG(lnode
.flags
, LS_NODE_ROUTER_ID
);
596 if (tlvs
->te_router_id_ipv6
) {
597 IPV6_ADDR_COPY(&lnode
.router_id6
,
598 tlvs
->te_router_id_ipv6
);
599 SET_FLAG(lnode
.flags
, LS_NODE_ROUTER_ID6
);
601 if (tlvs
->hostname
) {
602 strlcpy(lnode
.name
, tlvs
->hostname
, MAX_NAME_LENGTH
);
603 SET_FLAG(lnode
.flags
, LS_NODE_NAME
);
605 if (tlvs
->router_cap
) {
606 struct isis_router_cap
*cap
= tlvs
->router_cap
;
608 if (cap
->srgb
.lower_bound
!= 0
609 && cap
->srgb
.range_size
!= 0) {
610 SET_FLAG(lnode
.flags
, LS_NODE_SR
);
611 lnode
.srgb
.flag
= cap
->srgb
.flags
;
612 lnode
.srgb
.lower_bound
= cap
->srgb
.lower_bound
;
613 lnode
.srgb
.range_size
= cap
->srgb
.range_size
;
614 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
615 lnode
.algo
[i
] = cap
->algo
[i
];
618 if (cap
->srlb
.lower_bound
!= 0
619 && cap
->srlb
.range_size
!= 0) {
620 lnode
.srlb
.lower_bound
= cap
->srlb
.lower_bound
;
621 lnode
.srlb
.range_size
= cap
->srlb
.range_size
;
622 SET_FLAG(lnode
.flags
, LS_NODE_SRLB
);
625 lnode
.msd
= cap
->msd
;
626 SET_FLAG(lnode
.flags
, LS_NODE_MSD
);
631 /* Update Link State Node information */
632 if (!ls_node_same(old
, &lnode
)) {
633 te_debug(" |- Update Link State Node information");
634 memcpy(old
, &lnode
, sizeof(struct ls_node
));
635 if (vertex
->status
!= NEW
)
636 vertex
->status
= UPDATE
;
639 /* Set self TED vertex if LSP corresponds to the own router */
647 * Get Link State Edge from Link State Attributes in TE Database.
648 * Edge structure is dynamically allocated and fulfill with Link State
649 * Attributes if not found.
651 * @param ted Link State Database
652 * @param attr Link State Attributes
654 * @return New Link State Edge if success, NULL otherwise
656 static struct ls_edge
*get_edge(struct ls_ted
*ted
, struct ls_attributes
*attr
)
658 struct ls_edge
*edge
;
659 struct ls_standard
*std
;
662 /* Check parameters */
666 std
= &attr
->standard
;
668 /* Compute keys in function of local address (IPv4/v6) or identifier */
669 if (CHECK_FLAG(attr
->flags
, LS_ATTR_LOCAL_ADDR
))
670 key
= ((uint64_t)ntohl(std
->local
.s_addr
)) & 0xffffffff;
671 else if (CHECK_FLAG(attr
->flags
, LS_ATTR_LOCAL_ADDR6
))
672 key
= ((uint64_t)ntohl(std
->local6
.s6_addr32
[2]) << 32
673 | (uint64_t)ntohl(std
->local6
.s6_addr32
[3]));
674 else if (CHECK_FLAG(attr
->flags
, LS_ATTR_LOCAL_ID
))
675 key
= ((uint64_t)std
->remote_id
<< 32)
676 | (((uint64_t)std
->local_id
) & 0xffffffff);
680 /* Stop here if we don't got a valid key */
684 /* Get corresponding Edge by key from Link State Data Base */
685 edge
= ls_find_edge_by_key(ted
, key
);
687 /* and create new one if not exist */
689 edge
= ls_edge_add(ted
, attr
);
691 * Edge could be Null if no local ID is found in Attributes.
692 * Stop the processing as without any local ID it is not
693 * possible to store Edge in the TED.
699 if (CHECK_FLAG(edge
->attributes
->flags
, LS_ATTR_LOCAL_ADDR
))
700 te_debug(" |- %s Edge (%" PRIu64
701 ") from Extended Reach. %pI4",
702 edge
->status
== NEW
? "Create" : "Found", edge
->key
,
703 &attr
->standard
.local
);
704 else if (CHECK_FLAG(edge
->attributes
->flags
, LS_ATTR_LOCAL_ADDR6
))
705 te_debug(" |- %s Edge (%" PRIu64
706 ") from Extended Reach. %pI6",
707 edge
->status
== NEW
? "Create" : "Found", edge
->key
,
708 &attr
->standard
.local6
);
710 te_debug(" |- %s Edge (%" PRIu64
")",
711 edge
->status
== NEW
? "Create" : "Found", edge
->key
);
717 * Get Link State Attributes from IS-IS Sub-TLVs. Structure is dynamically
718 * allocated and should be free once not use anymore.
720 * @param adv Link State Node ID
721 * @param tlvs IS-IS Sub TLVs
723 * @return New Link State attributes if success, NULL otherwise
725 static struct ls_attributes
*get_attributes(struct ls_node_id adv
,
726 struct isis_ext_subtlvs
*tlvs
)
728 struct ls_attributes
*attr
;
729 struct in_addr local
= {.s_addr
= INADDR_ANY
};
730 struct in6_addr local6
= in6addr_any
;
731 uint32_t local_id
= 0;
733 /* Got Local identifier */
734 if (CHECK_FLAG(tlvs
->status
, EXT_LOCAL_ADDR
))
735 local
.s_addr
= tlvs
->local_addr
.s_addr
;
737 if (CHECK_FLAG(tlvs
->status
, EXT_LOCAL_ADDR6
))
738 memcpy(&local6
, &tlvs
->local_addr6
, IPV6_MAX_BYTELEN
);
740 if (CHECK_FLAG(tlvs
->status
, EXT_LLRI
))
741 local_id
= tlvs
->local_llri
;
743 /* Create LS Attributes */
744 attr
= ls_attributes_new(adv
, local
, local6
, local_id
);
748 /* Browse sub-TLV and fulfill Link State Attributes */
749 if (CHECK_FLAG(tlvs
->status
, EXT_ADM_GRP
)) {
750 attr
->standard
.admin_group
= tlvs
->adm_group
;
751 SET_FLAG(attr
->flags
, LS_ATTR_ADM_GRP
);
753 if (CHECK_FLAG(tlvs
->status
, EXT_EXTEND_ADM_GRP
)) {
754 admin_group_copy(&attr
->ext_admin_group
,
755 &tlvs
->ext_admin_group
);
756 SET_FLAG(attr
->flags
, LS_ATTR_EXT_ADM_GRP
);
758 if (CHECK_FLAG(tlvs
->status
, EXT_LLRI
)) {
759 attr
->standard
.local_id
= tlvs
->local_llri
;
760 attr
->standard
.remote_id
= tlvs
->remote_llri
;
761 SET_FLAG(attr
->flags
, LS_ATTR_LOCAL_ID
);
762 SET_FLAG(attr
->flags
, LS_ATTR_NEIGH_ID
);
764 if (CHECK_FLAG(tlvs
->status
, EXT_NEIGH_ADDR
)) {
765 attr
->standard
.remote
.s_addr
= tlvs
->neigh_addr
.s_addr
;
766 SET_FLAG(attr
->flags
, LS_ATTR_NEIGH_ADDR
);
768 if (CHECK_FLAG(tlvs
->status
, EXT_NEIGH_ADDR6
)) {
769 memcpy(&attr
->standard
.remote6
, &tlvs
->neigh_addr6
,
771 SET_FLAG(attr
->flags
, LS_ATTR_NEIGH_ADDR6
);
773 if (CHECK_FLAG(tlvs
->status
, EXT_MAX_BW
)) {
774 attr
->standard
.max_bw
= tlvs
->max_bw
;
775 SET_FLAG(attr
->flags
, LS_ATTR_MAX_BW
);
777 if (CHECK_FLAG(tlvs
->status
, EXT_MAX_RSV_BW
)) {
778 attr
->standard
.max_rsv_bw
= tlvs
->max_rsv_bw
;
779 SET_FLAG(attr
->flags
, LS_ATTR_MAX_RSV_BW
);
781 if (CHECK_FLAG(tlvs
->status
, EXT_UNRSV_BW
)) {
782 memcpy(&attr
->standard
.unrsv_bw
, tlvs
->unrsv_bw
,
783 ISIS_SUBTLV_UNRSV_BW_SIZE
);
784 SET_FLAG(attr
->flags
, LS_ATTR_UNRSV_BW
);
786 if (CHECK_FLAG(tlvs
->status
, EXT_TE_METRIC
)) {
787 attr
->standard
.te_metric
= tlvs
->te_metric
;
788 SET_FLAG(attr
->flags
, LS_ATTR_TE_METRIC
);
790 if (CHECK_FLAG(tlvs
->status
, EXT_RMT_AS
)) {
791 attr
->standard
.remote_as
= tlvs
->remote_as
;
792 SET_FLAG(attr
->flags
, LS_ATTR_REMOTE_AS
);
794 if (CHECK_FLAG(tlvs
->status
, EXT_RMT_IP
)) {
795 attr
->standard
.remote_addr
= tlvs
->remote_ip
;
796 SET_FLAG(attr
->flags
, LS_ATTR_REMOTE_ADDR
);
798 if (CHECK_FLAG(tlvs
->status
, EXT_DELAY
)) {
799 attr
->extended
.delay
= tlvs
->delay
;
800 SET_FLAG(attr
->flags
, LS_ATTR_DELAY
);
802 if (CHECK_FLAG(tlvs
->status
, EXT_MM_DELAY
)) {
803 attr
->extended
.min_delay
= tlvs
->min_delay
;
804 attr
->extended
.max_delay
= tlvs
->max_delay
;
805 SET_FLAG(attr
->flags
, LS_ATTR_MIN_MAX_DELAY
);
807 if (CHECK_FLAG(tlvs
->status
, EXT_DELAY_VAR
)) {
808 attr
->extended
.jitter
= tlvs
->delay_var
;
809 SET_FLAG(attr
->flags
, LS_ATTR_JITTER
);
811 if (CHECK_FLAG(tlvs
->status
, EXT_PKT_LOSS
)) {
812 attr
->extended
.pkt_loss
= tlvs
->pkt_loss
;
813 SET_FLAG(attr
->flags
, LS_ATTR_PACKET_LOSS
);
815 if (CHECK_FLAG(tlvs
->status
, EXT_AVA_BW
)) {
816 attr
->extended
.ava_bw
= tlvs
->ava_bw
;
817 SET_FLAG(attr
->flags
, LS_ATTR_AVA_BW
);
819 if (CHECK_FLAG(tlvs
->status
, EXT_RES_BW
)) {
820 attr
->extended
.rsv_bw
= tlvs
->res_bw
;
821 SET_FLAG(attr
->flags
, LS_ATTR_RSV_BW
);
823 if (CHECK_FLAG(tlvs
->status
, EXT_USE_BW
)) {
824 attr
->extended
.used_bw
= tlvs
->use_bw
;
825 SET_FLAG(attr
->flags
, LS_ATTR_USE_BW
);
827 if (CHECK_FLAG(tlvs
->status
, EXT_ADJ_SID
)) {
828 struct isis_adj_sid
*adj
=
829 (struct isis_adj_sid
*)tlvs
->adj_sid
.head
;
831 for (; adj
; adj
= adj
->next
) {
832 i
= adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
? 1 : 0;
833 i
+= adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
? 2 : 0;
834 attr
->adj_sid
[i
].flags
= adj
->flags
;
835 attr
->adj_sid
[i
].weight
= adj
->weight
;
836 attr
->adj_sid
[i
].sid
= adj
->sid
;
839 SET_FLAG(attr
->flags
, LS_ATTR_ADJ_SID
);
842 SET_FLAG(attr
->flags
, LS_ATTR_BCK_ADJ_SID
);
845 SET_FLAG(attr
->flags
, LS_ATTR_ADJ_SID6
);
848 SET_FLAG(attr
->flags
, LS_ATTR_BCK_ADJ_SID6
);
853 if (CHECK_FLAG(tlvs
->status
, EXT_LAN_ADJ_SID
)) {
854 struct isis_lan_adj_sid
*ladj
=
855 (struct isis_lan_adj_sid
*)tlvs
->lan_sid
.head
;
857 for (; ladj
; ladj
= ladj
->next
) {
858 i
= ladj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
? 1 : 0;
859 i
+= ladj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
? 2 : 0;
860 attr
->adj_sid
[i
].flags
= ladj
->flags
;
861 attr
->adj_sid
[i
].weight
= ladj
->weight
;
862 attr
->adj_sid
[i
].sid
= ladj
->sid
;
863 memcpy(&attr
->adj_sid
[i
].neighbor
.sysid
,
864 &ladj
->neighbor_id
, ISIS_SYS_ID_LEN
);
867 SET_FLAG(attr
->flags
, LS_ATTR_ADJ_SID
);
870 SET_FLAG(attr
->flags
, LS_ATTR_BCK_ADJ_SID
);
873 SET_FLAG(attr
->flags
, LS_ATTR_ADJ_SID6
);
876 SET_FLAG(attr
->flags
, LS_ATTR_BCK_ADJ_SID6
);
886 * Parse Extended Reachability TLVs and create or update the corresponding
887 * Link State Edge and Attributes. Vertex connections are also updated if
888 * needed based on the remote IP address of the Edge and existing reverse Edge.
890 * @param id ID of Extended IS
891 * @param metric Metric of the link
892 * @param old_metric Boolean that indicate if it is an old metric (no TE)
893 * @param tlvs SubTlvs that contains TE information
894 * @param arg IS-IS TE argument (TED, Vertex, and export indication)
896 * @return 0 if success, -1 otherwise
898 static int lsp_to_edge_cb(const uint8_t *id
, uint32_t metric
, bool old_metric
,
899 struct isis_ext_subtlvs
*tlvs
, void *arg
)
901 struct isis_te_args
*args
= (struct isis_te_args
*)arg
;
902 struct ls_vertex
*vertex
;
903 struct ls_edge
*edge
, *dst
;
904 struct ls_attributes
*attr
;
906 te_debug(" |- Process Extended IS for %s", sysid_print(id
));
908 /* Check parameters */
909 if (old_metric
|| !args
|| !tlvs
)
910 return LSP_ITER_CONTINUE
;
912 /* Initialize Link State Attributes */
913 vertex
= args
->vertex
;
914 attr
= get_attributes(vertex
->node
->adv
, tlvs
);
916 * Attributes may be Null if no local ID has been found in the LSP.
917 * Stop processing here as without any local ID it is not possible to
918 * create corresponding Edge in the TED.
921 return LSP_ITER_CONTINUE
;
923 attr
->metric
= metric
;
924 SET_FLAG(attr
->flags
, LS_ATTR_METRIC
);
926 /* Get corresponding Edge from Link State Data Base */
927 edge
= get_edge(args
->ted
, attr
);
929 * Edge could be Null if no local ID has been found in Attributes.
930 * Stop processing here as without any local ID it is not possible to
931 * create corresponding Edge in the TED.
934 ls_attributes_del(attr
);
935 return LSP_ITER_CONTINUE
;
938 /* Update Attribute fields if there are different */
939 if (edge
->status
!= NEW
) {
940 if (!ls_attributes_same(edge
->attributes
, attr
)) {
941 te_debug(" |- Update Edge Attributes information");
942 ls_attributes_del(edge
->attributes
);
943 edge
->attributes
= attr
;
944 edge
->status
= UPDATE
;
946 if (edge
->attributes
!= attr
)
947 ls_attributes_del(attr
);
952 /* Try to update remote Link from remote address or reachability ID */
953 te_debug(" |- Link Edge (%" PRIu64
") to destination vertex (%s)",
954 edge
->key
, print_sys_hostname(id
));
955 dst
= ls_find_edge_by_destination(args
->ted
, edge
->attributes
);
957 /* Attach remote link if not set */
958 if (edge
->source
&& dst
->destination
== NULL
) {
959 vertex
= edge
->source
;
960 if (vertex
->incoming_edges
)
961 listnode_add_sort_nodup(vertex
->incoming_edges
,
963 dst
->destination
= vertex
;
965 /* and destination vertex to this edge if not set */
966 if (dst
->source
&& edge
->destination
== NULL
) {
967 vertex
= dst
->source
;
968 if (vertex
->incoming_edges
)
969 listnode_add_sort_nodup(vertex
->incoming_edges
,
971 edge
->destination
= vertex
;
974 /* Search dst. Vertex by Extended Reach. ID if not found */
975 if (edge
->destination
== NULL
) {
976 vertex
= ls_find_vertex_by_key(args
->ted
,
978 if (vertex
&& vertex
->incoming_edges
)
979 listnode_add_sort_nodup(vertex
->incoming_edges
,
981 edge
->destination
= vertex
;
985 /* Update status and Export Link State Edge if needed */
986 if (edge
->status
!= SYNC
) {
988 isis_te_export(LS_MSG_TYPE_ATTRIBUTES
, edge
);
992 return LSP_ITER_CONTINUE
;
996 * Parse Extended IP Reachability or MT IPv6 Reachability TLVs and create or
997 * update the corresponding Link State Subnet and Prefix.
999 * @param prefix Prefix associated to this subnet
1000 * @param metric Metric of this prefix
1001 * @param external Boolean to indicate if the prefix is external
1002 * @param subtlvs Subtlvs if any (mostly Segment Routing ID)
1003 * @param arg IS-IS TE argument (TED, Vertex, and export indication)
1005 * @return 0 if success, -1 otherwise
1007 static int lsp_to_subnet_cb(const struct prefix
*prefix
, uint32_t metric
,
1008 bool external
, struct isis_subtlvs
*subtlvs
,
1011 struct isis_te_args
*args
= (struct isis_te_args
*)arg
;
1012 struct ls_vertex
*vertex
;
1013 struct ls_subnet
*subnet
;
1014 struct ls_prefix
*ls_pref
;
1015 struct listnode
*node
;
1016 struct ls_edge
*edge
;
1017 struct ls_standard
*std
= NULL
;
1021 if (!args
|| !prefix
)
1022 return LSP_ITER_CONTINUE
;
1024 te_debug(" |- Process Extended %s Reachability %pFX",
1025 prefix
->family
== AF_INET
? "IP" : "IPv6", prefix
);
1027 vertex
= args
->vertex
;
1030 * Prefix with mask different from /32 or /128 are advertised by at
1031 * least 2 nodes. To avoid subnet attached to undetermined vertex, and
1032 * gives the possibility to send the information to client e.g. BGP for
1033 * Link State advertisement, we adjust the prefix with the corresponding
1034 * IP address of the belonging interface when it is available. Other
1035 * prefixes are kept unchanged.
1037 if (prefix
->family
== AF_INET
&& prefix
->prefixlen
< IPV4_MAX_BITLEN
) {
1039 for (ALL_LIST_ELEMENTS_RO(vertex
->outgoing_edges
, node
, edge
)) {
1040 if (!CHECK_FLAG(edge
->attributes
->flags
,
1041 LS_ATTR_LOCAL_ADDR
))
1044 p
.u
.prefix4
= edge
->attributes
->standard
.local
;
1046 p
.prefixlen
= prefix
->prefixlen
;
1047 apply_mask_ipv4((struct prefix_ipv4
*)&p
);
1048 if (IPV4_ADDR_SAME(&p
.u
.prefix4
, &prefix
->u
.prefix4
)) {
1049 std
= &edge
->attributes
->standard
;
1054 p
.u
.prefix4
= std
->local
;
1056 } else if (prefix
->family
== AF_INET6
1057 && prefix
->prefixlen
< IPV6_MAX_BITLEN
) {
1059 for (ALL_LIST_ELEMENTS_RO(vertex
->outgoing_edges
, node
, edge
)) {
1060 if (!CHECK_FLAG(edge
->attributes
->flags
,
1061 LS_ATTR_LOCAL_ADDR6
))
1064 p
.u
.prefix6
= edge
->attributes
->standard
.local6
;
1065 p
.family
= AF_INET6
;
1066 p
.prefixlen
= prefix
->prefixlen
;
1067 apply_mask_ipv6((struct prefix_ipv6
*)&p
);
1068 if (IPV6_ADDR_SAME(&p
.u
.prefix6
, &prefix
->u
.prefix6
)) {
1069 std
= &edge
->attributes
->standard
;
1074 p
.u
.prefix6
= std
->local6
;
1077 prefix_copy(&p
, prefix
);
1079 te_debug(" |- Adjust prefix %pFX with local address to: %pFX",
1082 /* Search existing Subnet in TED ... */
1083 subnet
= ls_find_subnet(args
->ted
, p
);
1084 /* ... and create a new Subnet if not found */
1086 ls_pref
= ls_prefix_new(vertex
->node
->adv
, p
);
1087 subnet
= ls_subnet_add(args
->ted
, ls_pref
);
1089 return LSP_ITER_CONTINUE
;
1091 ls_pref
= subnet
->ls_pref
;
1093 te_debug(" |- %s Subnet from prefix %pFX",
1094 subnet
->status
== NEW
? "Create" : "Found", &p
);
1097 if (!CHECK_FLAG(ls_pref
->flags
, LS_PREF_METRIC
)
1098 || (ls_pref
->metric
!= metric
)) {
1099 ls_pref
->metric
= metric
;
1100 SET_FLAG(ls_pref
->flags
, LS_PREF_METRIC
);
1101 if (subnet
->status
!= NEW
)
1102 subnet
->status
= UPDATE
;
1104 if (subnet
->status
== ORPHAN
)
1105 subnet
->status
= SYNC
;
1108 /* Update Prefix SID if any */
1109 if (subtlvs
&& subtlvs
->prefix_sids
.count
!= 0) {
1110 struct isis_prefix_sid
*psid
;
1111 struct ls_sid sr
= {};
1113 psid
= (struct isis_prefix_sid
*)subtlvs
->prefix_sids
.head
;
1114 sr
.algo
= psid
->algorithm
;
1115 sr
.sid_flag
= psid
->flags
;
1116 sr
.sid
= psid
->value
;
1118 if (!CHECK_FLAG(ls_pref
->flags
, LS_PREF_SR
)
1119 || !memcmp(&ls_pref
->sr
, &sr
, sizeof(struct ls_sid
))) {
1120 memcpy(&ls_pref
->sr
, &sr
, sizeof(struct ls_sid
));
1121 SET_FLAG(ls_pref
->flags
, LS_PREF_SR
);
1122 if (subnet
->status
!= NEW
)
1123 subnet
->status
= UPDATE
;
1125 if (subnet
->status
== ORPHAN
)
1126 subnet
->status
= SYNC
;
1129 if (CHECK_FLAG(ls_pref
->flags
, LS_PREF_SR
)) {
1130 UNSET_FLAG(ls_pref
->flags
, LS_PREF_SR
);
1131 if (subnet
->status
!= NEW
)
1132 subnet
->status
= UPDATE
;
1134 if (subnet
->status
== ORPHAN
)
1135 subnet
->status
= SYNC
;
1139 /* Update status and Export Link State Edge if needed */
1140 if (subnet
->status
!= SYNC
) {
1142 isis_te_export(LS_MSG_TYPE_PREFIX
, subnet
);
1143 subnet
->status
= SYNC
;
1146 return LSP_ITER_CONTINUE
;
1150 * Parse ISIS LSP to fulfill the Link State Database
1152 * @param ted Link State Database
1153 * @param lsp ISIS Link State PDU
1155 static void isis_te_parse_lsp(struct mpls_te_area
*mta
, struct isis_lsp
*lsp
)
1158 struct ls_vertex
*vertex
;
1159 struct ls_edge
*edge
;
1160 struct ls_subnet
*subnet
;
1161 struct listnode
*node
;
1162 struct isis_te_args args
;
1165 if (!IS_MPLS_TE(mta
) || !mta
->ted
|| !lsp
)
1170 te_debug("ISIS-TE(%s): Parse LSP %s", lsp
->area
->area_tag
,
1171 sysid_print(lsp
->hdr
.lsp_id
));
1173 /* First parse LSP to obtain the corresponding Vertex */
1174 vertex
= lsp_to_vertex(ted
, lsp
);
1176 zlog_warn("Unable to build Vertex from LSP %s. Abort!",
1177 sysid_print(lsp
->hdr
.lsp_id
));
1181 /* Check if Vertex has been modified */
1182 if (vertex
->status
!= SYNC
) {
1183 /* Vertex is out of sync: export it if requested */
1184 if (IS_EXPORT_TE(mta
))
1185 isis_te_export(LS_MSG_TYPE_NODE
, vertex
);
1186 vertex
->status
= SYNC
;
1189 /* Mark outgoing Edges and Subnets as ORPHAN to detect deletion */
1190 for (ALL_LIST_ELEMENTS_RO(vertex
->outgoing_edges
, node
, edge
))
1191 edge
->status
= ORPHAN
;
1193 for (ALL_LIST_ELEMENTS_RO(vertex
->prefixes
, node
, subnet
))
1194 subnet
->status
= ORPHAN
;
1196 /* Process all Extended Reachability in LSP (all fragments) */
1198 args
.vertex
= vertex
;
1199 args
.export
= mta
->export
;
1200 isis_lsp_iterate_is_reach(lsp
, ISIS_MT_IPV4_UNICAST
, lsp_to_edge_cb
,
1203 isis_lsp_iterate_is_reach(lsp
, ISIS_MT_IPV6_UNICAST
, lsp_to_edge_cb
,
1206 /* Process all Extended IP (v4 & v6) in LSP (all fragments) */
1207 isis_lsp_iterate_ip_reach(lsp
, AF_INET
, ISIS_MT_IPV4_UNICAST
,
1208 lsp_to_subnet_cb
, &args
);
1209 isis_lsp_iterate_ip_reach(lsp
, AF_INET6
, ISIS_MT_IPV6_UNICAST
,
1210 lsp_to_subnet_cb
, &args
);
1211 isis_lsp_iterate_ip_reach(lsp
, AF_INET6
, ISIS_MT_IPV4_UNICAST
,
1212 lsp_to_subnet_cb
, &args
);
1214 /* Clean remaining Orphan Edges or Subnets */
1215 if (IS_EXPORT_TE(mta
))
1216 ls_vertex_clean(ted
, vertex
, zclient
);
1218 ls_vertex_clean(ted
, vertex
, NULL
);
1222 * Delete Link State Database Vertex, Edge & Prefix that correspond to this
1223 * ISIS Link State PDU
1225 * @param ted Link State Database
1226 * @param lsp ISIS Link State PDU
1228 static void isis_te_delete_lsp(struct mpls_te_area
*mta
, struct isis_lsp
*lsp
)
1231 struct ls_vertex
*vertex
= NULL
;
1232 struct ls_node lnode
= {};
1233 struct ls_edge
*edge
;
1234 struct ls_subnet
*subnet
;
1235 struct listnode
*nnode
, *node
;
1238 if (!IS_MPLS_TE(mta
) || !mta
->ted
|| !lsp
)
1241 te_debug("ISIS-TE(%s): Delete Link State TED objects from LSP %s",
1242 lsp
->area
->area_tag
, sysid_print(lsp
->hdr
.lsp_id
));
1244 /* Compute Link State Node ID from IS-IS sysID ... */
1245 if (lsp
->level
== ISIS_LEVEL1
)
1246 lnode
.adv
.origin
= ISIS_L1
;
1248 lnode
.adv
.origin
= ISIS_L2
;
1249 memcpy(&lnode
.adv
.id
.iso
.sys_id
, &lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
);
1250 lnode
.adv
.id
.iso
.level
= lsp
->level
;
1252 /* ... and search the corresponding vertex */
1253 vertex
= ls_find_vertex_by_id(ted
, lnode
.adv
);
1257 te_debug(" |- Delete Vertex %s", vertex
->node
->name
);
1260 * We can't use the ls_vertex_del_all() function if export TE is set,
1261 * as we must first advertise the client daemons of each removal.
1263 /* Remove outgoing Edges */
1264 for (ALL_LIST_ELEMENTS(vertex
->outgoing_edges
, node
, nnode
, edge
)) {
1265 if (IS_EXPORT_TE(mta
)) {
1266 edge
->status
= DELETE
;
1267 isis_te_export(LS_MSG_TYPE_ATTRIBUTES
, edge
);
1269 ls_edge_del_all(ted
, edge
);
1272 /* Disconnect incoming Edges */
1273 for (ALL_LIST_ELEMENTS(vertex
->incoming_edges
, node
, nnode
, edge
)) {
1274 ls_disconnect(vertex
, edge
, false);
1275 if (edge
->source
== NULL
) {
1276 if (IS_EXPORT_TE(mta
)) {
1277 edge
->status
= DELETE
;
1278 isis_te_export(LS_MSG_TYPE_ATTRIBUTES
, edge
);
1280 ls_edge_del_all(ted
, edge
);
1284 /* Remove subnets */
1285 for (ALL_LIST_ELEMENTS(vertex
->prefixes
, node
, nnode
, subnet
)) {
1286 if (IS_EXPORT_TE(mta
)) {
1287 subnet
->status
= DELETE
;
1288 isis_te_export(LS_MSG_TYPE_PREFIX
, subnet
);
1290 ls_subnet_del_all(ted
, subnet
);
1293 /* Then remove Link State Node */
1294 if (IS_EXPORT_TE(mta
)) {
1295 vertex
->status
= DELETE
;
1296 isis_te_export(LS_MSG_TYPE_NODE
, vertex
);
1298 ls_node_del(vertex
->node
);
1300 /* Finally, remove Vertex */
1301 ls_vertex_del(ted
, vertex
);
1305 * Process ISIS LSP according to the event to add, update or remove
1306 * corresponding vertex, edge and prefix in the Link State database.
1307 * Since LSP could be fragmented, the function starts by searching the root LSP
1308 * to retrieve the complete LSP, including eventual fragment before processing
1311 * @param lsp ISIS Link State PDU
1312 * @param event LSP event: ADD, UPD, INC & DEL (TICK are ignored)
1315 void isis_te_lsp_event(struct isis_lsp
*lsp
, enum lsp_event event
)
1317 struct isis_area
*area
;
1318 struct isis_lsp
*lsp0
;
1321 if (!lsp
|| !lsp
->area
)
1325 if (!IS_MPLS_TE(area
->mta
))
1328 /* Adjust LSP0 in case of fragment */
1329 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
))
1330 lsp0
= lsp
->lspu
.zero_lsp
;
1334 /* Then process event */
1339 isis_te_parse_lsp(area
->mta
, lsp0
);
1342 isis_te_delete_lsp(area
->mta
, lsp0
);
1351 * Send the whole Link State Traffic Engineering Database to the consumer that
1352 * request it through a ZAPI Link State Synchronous Opaque Message.
1354 * @param info ZAPI Opaque message
1356 * @return 0 if success, -1 otherwise
1358 int isis_te_sync_ted(struct zapi_opaque_reg_info dst
)
1360 struct listnode
*node
, *inode
;
1362 struct isis_area
*area
;
1363 struct mpls_te_area
*mta
;
1366 te_debug("ISIS-TE(%s): Received TED synchro from client %d", __func__
,
1368 /* For each area, send TED if TE distribution is enabled */
1369 for (ALL_LIST_ELEMENTS_RO(im
->isis
, inode
, isis
)) {
1370 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
, area
)) {
1372 if (IS_MPLS_TE(mta
) && IS_EXPORT_TE(mta
)) {
1373 te_debug(" |- Export TED from area %s",
1375 rc
= ls_sync_ted(mta
->ted
, zclient
, &dst
);
1386 * Initialize the Link State database from the LSP already stored for this area
1388 * @param area ISIS area
1390 void isis_te_init_ted(struct isis_area
*area
)
1392 struct isis_lsp
*lsp
;
1394 /* Iterate over all lsp. */
1395 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++)
1396 frr_each (lspdb
, &area
->lspdb
[level
- 1], lsp
)
1397 isis_te_parse_lsp(area
->mta
, lsp
);
1400 /* Following are vty command functions */
1403 static void show_router_id(struct vty
*vty
, struct isis_area
*area
)
1405 bool no_match
= true;
1407 vty_out(vty
, "Area %s:\n", area
->area_tag
);
1408 if (area
->mta
->router_id
.s_addr
!= 0) {
1409 vty_out(vty
, " MPLS-TE IPv4 Router-Address: %pI4\n",
1410 &area
->mta
->router_id
);
1413 if (!IN6_IS_ADDR_UNSPECIFIED(&area
->mta
->router_id_ipv6
)) {
1414 vty_out(vty
, " MPLS-TE IPv6 Router-Address: %pI6\n",
1415 &area
->mta
->router_id_ipv6
);
1419 vty_out(vty
, " N/A\n");
1422 DEFUN(show_isis_mpls_te_router
,
1423 show_isis_mpls_te_router_cmd
,
1424 "show " PROTO_NAME
" [vrf <NAME|all>] mpls-te router",
1427 VRF_CMD_HELP_STR
"All VRFs\n"
1428 MPLS_TE_STR
"Router information\n")
1431 struct listnode
*anode
, *inode
;
1432 struct isis_area
*area
;
1433 struct isis
*isis
= NULL
;
1434 const char *vrf_name
= VRF_DEFAULT_NAME
;
1435 bool all_vrf
= false;
1439 vty_out(vty
, "IS-IS Routing Process not enabled\n");
1442 ISIS_FIND_VRF_ARGS(argv
, argc
, idx_vrf
, vrf_name
, all_vrf
);
1445 for (ALL_LIST_ELEMENTS_RO(im
->isis
, inode
, isis
)) {
1446 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
,
1448 if (!IS_MPLS_TE(area
->mta
))
1451 show_router_id(vty
, area
);
1456 isis
= isis_lookup_by_vrfname(vrf_name
);
1458 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, anode
,
1461 if (!IS_MPLS_TE(area
->mta
))
1464 show_router_id(vty
, area
);
1472 static void show_ext_sub(struct vty
*vty
, char *name
,
1473 struct isis_ext_subtlvs
*ext
)
1476 char ibuf
[PREFIX2STR_BUFFER
];
1478 sbuf_init(&buf
, NULL
, 0);
1480 if (!ext
|| ext
->status
== EXT_DISABLE
)
1483 vty_out(vty
, "-- MPLS-TE link parameters for %s --\n", name
);
1487 if (IS_SUBTLV(ext
, EXT_ADM_GRP
))
1488 sbuf_push(&buf
, 4, "Administrative Group: 0x%x\n",
1490 if (IS_SUBTLV(ext
, EXT_LLRI
)) {
1491 sbuf_push(&buf
, 4, "Link Local ID: %u\n",
1493 sbuf_push(&buf
, 4, "Link Remote ID: %u\n",
1496 if (IS_SUBTLV(ext
, EXT_LOCAL_ADDR
))
1497 sbuf_push(&buf
, 4, "Local Interface IP Address(es): %pI4\n",
1499 if (IS_SUBTLV(ext
, EXT_NEIGH_ADDR
))
1500 sbuf_push(&buf
, 4, "Remote Interface IP Address(es): %pI4\n",
1502 if (IS_SUBTLV(ext
, EXT_LOCAL_ADDR6
))
1503 sbuf_push(&buf
, 4, "Local Interface IPv6 Address(es): %s\n",
1504 inet_ntop(AF_INET6
, &ext
->local_addr6
, ibuf
,
1505 PREFIX2STR_BUFFER
));
1506 if (IS_SUBTLV(ext
, EXT_NEIGH_ADDR6
))
1507 sbuf_push(&buf
, 4, "Remote Interface IPv6 Address(es): %s\n",
1508 inet_ntop(AF_INET6
, &ext
->local_addr6
, ibuf
,
1509 PREFIX2STR_BUFFER
));
1510 if (IS_SUBTLV(ext
, EXT_MAX_BW
))
1511 sbuf_push(&buf
, 4, "Maximum Bandwidth: %g (Bytes/sec)\n",
1513 if (IS_SUBTLV(ext
, EXT_MAX_RSV_BW
))
1515 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
1517 if (IS_SUBTLV(ext
, EXT_UNRSV_BW
)) {
1518 sbuf_push(&buf
, 4, "Unreserved Bandwidth:\n");
1519 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 2) {
1520 sbuf_push(&buf
, 4 + 2,
1521 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
1522 j
, ext
->unrsv_bw
[j
],
1523 j
+ 1, ext
->unrsv_bw
[j
+ 1]);
1526 if (IS_SUBTLV(ext
, EXT_TE_METRIC
))
1527 sbuf_push(&buf
, 4, "Traffic Engineering Metric: %u\n",
1529 if (IS_SUBTLV(ext
, EXT_RMT_AS
))
1531 "Inter-AS TE Remote AS number: %u\n",
1533 if (IS_SUBTLV(ext
, EXT_RMT_IP
))
1535 "Inter-AS TE Remote ASBR IP address: %pI4\n",
1537 if (IS_SUBTLV(ext
, EXT_DELAY
))
1539 "%s Average Link Delay: %u (micro-sec)\n",
1540 IS_ANORMAL(ext
->delay
) ? "Anomalous" : "Normal",
1541 ext
->delay
& TE_EXT_MASK
);
1542 if (IS_SUBTLV(ext
, EXT_MM_DELAY
)) {
1543 sbuf_push(&buf
, 4, "%s Min/Max Link Delay: %u / %u (micro-sec)\n",
1544 IS_ANORMAL(ext
->min_delay
) ? "Anomalous" : "Normal",
1545 ext
->min_delay
& TE_EXT_MASK
,
1546 ext
->max_delay
& TE_EXT_MASK
);
1548 if (IS_SUBTLV(ext
, EXT_DELAY_VAR
))
1550 "Delay Variation: %u (micro-sec)\n",
1551 ext
->delay_var
& TE_EXT_MASK
);
1552 if (IS_SUBTLV(ext
, EXT_PKT_LOSS
))
1553 sbuf_push(&buf
, 4, "%s Link Packet Loss: %g (%%)\n",
1554 IS_ANORMAL(ext
->pkt_loss
) ? "Anomalous" : "Normal",
1555 (float)((ext
->pkt_loss
& TE_EXT_MASK
)
1557 if (IS_SUBTLV(ext
, EXT_RES_BW
))
1559 "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n",
1561 if (IS_SUBTLV(ext
, EXT_AVA_BW
))
1563 "Unidirectional Available Bandwidth: %g (Bytes/sec)\n",
1565 if (IS_SUBTLV(ext
, EXT_USE_BW
))
1567 "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n",
1570 vty_multiline(vty
, "", "%s", sbuf_buf(&buf
));
1571 vty_out(vty
, "---------------\n\n");
1577 DEFUN (show_isis_mpls_te_interface
,
1578 show_isis_mpls_te_interface_cmd
,
1579 "show " PROTO_NAME
" mpls-te interface [INTERFACE]",
1583 "Interface information\n"
1586 struct listnode
*anode
, *cnode
, *inode
;
1587 struct isis_area
*area
;
1588 struct isis_circuit
*circuit
;
1589 struct interface
*ifp
;
1590 int idx_interface
= 4;
1591 struct isis
*isis
= NULL
;
1594 vty_out(vty
, "IS-IS Routing Process not enabled\n");
1598 if (argc
== idx_interface
) {
1599 /* Show All Interfaces. */
1600 for (ALL_LIST_ELEMENTS_RO(im
->isis
, inode
, isis
)) {
1601 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, anode
,
1604 if (!IS_MPLS_TE(area
->mta
))
1607 vty_out(vty
, "Area %s:\n", area
->area_tag
);
1609 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
,
1612 circuit
->interface
->name
,
1617 /* Interface name is specified. */
1618 ifp
= if_lookup_by_name(argv
[idx_interface
]->arg
, VRF_DEFAULT
);
1620 vty_out(vty
, "No such interface name\n");
1622 circuit
= circuit_scan_by_ifp(ifp
);
1625 "ISIS is not enabled on circuit %s\n",
1628 show_ext_sub(vty
, ifp
->name
, circuit
->ext
);
1636 * Search Vertex in TED that corresponds to the given string that represent
1637 * the ISO system ID in the forms <systemid/hostname>[.<pseudo-id>-<framenent>]
1639 * @param ted Link State Database
1640 * @param id ISO System ID
1641 * @param isis Main reference to the isis daemon
1643 * @return Vertex if found, NULL otherwise
1645 static struct ls_vertex
*vertex_for_arg(struct ls_ted
*ted
, const char *id
,
1648 char sysid
[255] = {0};
1651 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2] = {0};
1652 struct isis_dynhn
*dynhn
;
1659 * extract fragment and pseudo id from the string argv
1661 * (a) <systemid/hostname>.<pseudo-id>-<framenent> or
1662 * (b) <systemid/hostname>.<pseudo-id> or
1663 * (c) <systemid/hostname> or
1664 * Where systemid is in the form:
1667 strlcpy(sysid
, id
, sizeof(sysid
));
1668 if (strlen(id
) > 3) {
1669 pos
= id
+ strlen(id
) - 3;
1670 if (strncmp(pos
, "-", 1) == 0) {
1671 memcpy(number
, ++pos
, 2);
1672 lspid
[ISIS_SYS_ID_LEN
+ 1] =
1673 (uint8_t)strtol((char *)number
, NULL
, 16);
1675 if (strncmp(pos
, ".", 1) != 0)
1678 if (strncmp(pos
, ".", 1) == 0) {
1679 memcpy(number
, ++pos
, 2);
1680 lspid
[ISIS_SYS_ID_LEN
] =
1681 (uint8_t)strtol((char *)number
, NULL
, 16);
1682 sysid
[pos
- id
- 1] = '\0';
1687 * Try to find the lsp-id if the argv
1690 * hostname.<pseudo-id>-<fragment>
1692 if (sysid2buff(lspid
, sysid
)) {
1693 key
= sysid_to_key(lspid
);
1694 } else if ((dynhn
= dynhn_find_by_name(isis
, sysid
))) {
1695 memcpy(lspid
, dynhn
->id
, ISIS_SYS_ID_LEN
);
1696 key
= sysid_to_key(lspid
);
1697 } else if (strncmp(cmd_hostname_get(), sysid
, 15) == 0) {
1698 memcpy(lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1699 key
= sysid_to_key(lspid
);
1705 return ls_find_vertex_by_key(ted
, key
);
1709 * Show Link State Traffic Engineering Database extracted from IS-IS LSP.
1711 * @param vty VTY output console
1712 * @param argv Command line argument
1713 * @param argc Number of command line argument
1714 * @param ted Traffic Engineering Database
1715 * @param isis isis Main reference to the isis daemon
1717 * @return Command Success if OK, Command Warning otherwise
1719 static int show_ted(struct vty
*vty
, struct cmd_token
*argv
[], int argc
,
1720 struct isis_area
*area
, struct isis
*isis
)
1724 struct in_addr ip_addr
;
1725 struct in6_addr ip6_addr
;
1728 struct ls_vertex
*vertex
;
1729 struct ls_edge
*edge
;
1730 struct ls_subnet
*subnet
;
1732 bool detail
= false;
1733 bool uj
= use_json(argc
, argv
);
1734 json_object
*json
= NULL
;
1736 if (!IS_MPLS_TE(area
->mta
) || !area
->mta
->ted
) {
1737 vty_out(vty
, "MPLS-TE is disabled for Area %s\n",
1738 area
->area_tag
? area
->area_tag
: "null");
1742 ted
= area
->mta
->ted
;
1745 json
= json_object_new_object();
1747 vty_out(vty
, "Area %s:\n",
1748 area
->area_tag
? area
->area_tag
: "null");
1750 if (argv
[argc
- 1]->arg
&& strmatch(argv
[argc
- 1]->text
, "detail"))
1754 if (argv_find(argv
, argc
, "vertex", &idx
)) {
1756 id
= argv_find(argv
, argc
, "WORD", &idx
) ? argv
[idx
]->arg
1760 else if (!strncmp(id
, "self", 4))
1763 vertex
= vertex_for_arg(ted
, id
, isis
);
1765 vty_out(vty
, "No vertex found for ID %s\n", id
);
1771 ls_show_vertex(vertex
, vty
, json
, detail
);
1773 ls_show_vertices(ted
, vty
, json
, detail
);
1775 } else if (argv_find(argv
, argc
, "edge", &idx
)) {
1777 if (argv_find(argv
, argc
, "A.B.C.D", &idx
)) {
1778 if (!inet_pton(AF_INET
, argv
[idx
]->arg
, &ip_addr
)) {
1780 "Specified Edge ID %s is invalid\n",
1782 return CMD_WARNING_CONFIG_FAILED
;
1784 /* Get the Edge from the Link State Database */
1785 key
= ((uint64_t)ntohl(ip_addr
.s_addr
)) & 0xffffffff;
1786 edge
= ls_find_edge_by_key(ted
, key
);
1788 vty_out(vty
, "No edge found for ID %pI4\n",
1792 } else if (argv_find(argv
, argc
, "X:X::X:X", &idx
)) {
1793 if (!inet_pton(AF_INET6
, argv
[idx
]->arg
, &ip6_addr
)) {
1795 "Specified Edge ID %s is invalid\n",
1797 return CMD_WARNING_CONFIG_FAILED
;
1799 /* Get the Edge from the Link State Database */
1800 key
= (uint64_t)ntohl(ip6_addr
.s6_addr32
[3])
1801 | ((uint64_t)ntohl(ip6_addr
.s6_addr32
[2]) << 32);
1802 edge
= ls_find_edge_by_key(ted
, key
);
1804 vty_out(vty
, "No edge found for ID %pI6\n",
1812 ls_show_edge(edge
, vty
, json
, detail
);
1814 ls_show_edges(ted
, vty
, json
, detail
);
1816 } else if (argv_find(argv
, argc
, "subnet", &idx
)) {
1818 if (argv_find(argv
, argc
, "A.B.C.D/M", &idx
)) {
1819 if (!str2prefix(argv
[idx
]->arg
, &pref
)) {
1820 vty_out(vty
, "Invalid prefix format %s\n",
1822 return CMD_WARNING_CONFIG_FAILED
;
1824 /* Get the Subnet from the Link State Database */
1825 subnet
= ls_find_subnet(ted
, pref
);
1827 vty_out(vty
, "No subnet found for ID %pFX\n",
1831 } else if (argv_find(argv
, argc
, "X:X::X:X/M", &idx
)) {
1832 if (!str2prefix(argv
[idx
]->arg
, &pref
)) {
1833 vty_out(vty
, "Invalid prefix format %s\n",
1835 return CMD_WARNING_CONFIG_FAILED
;
1837 /* Get the Subnet from the Link State Database */
1838 subnet
= ls_find_subnet(ted
, pref
);
1840 vty_out(vty
, "No subnet found for ID %pFX\n",
1848 ls_show_subnet(subnet
, vty
, json
, detail
);
1850 ls_show_subnets(ted
, vty
, json
, detail
);
1853 /* Show the complete TED */
1854 ls_show_ted(ted
, vty
, json
, detail
);
1858 vty_json(vty
, json
);
1864 * Show ISIS Traffic Engineering Database
1866 * @param vty VTY output console
1867 * @param argv Command line argument
1868 * @param argc Number of command line argument
1869 * @param isis isis Main reference to the isis daemon
1871 * @return Command Success if OK, Command Warning otherwise
1873 static int show_isis_ted(struct vty
*vty
, struct cmd_token
*argv
[], int argc
,
1876 struct listnode
*node
;
1877 struct isis_area
*area
;
1880 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
, area
)) {
1881 rc
= show_ted(vty
, argv
, argc
, area
, isis
);
1882 if (rc
!= CMD_SUCCESS
)
1888 DEFUN(show_isis_mpls_te_db
,
1889 show_isis_mpls_te_db_cmd
,
1890 "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]",
1891 SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
1894 "MPLS-TE database\n"
1896 "MPLS-TE Vertex ID (as an ISO ID, hostname or \"self\")\n"
1898 "MPLS-TE Edge ID (as an IPv4 address)\n"
1899 "MPLS-TE Edge ID (as an IPv6 address)\n"
1901 "MPLS-TE Subnet ID (as an IPv4 prefix)\n"
1902 "MPLS-TE Subnet ID (as an IPv6 prefix)\n"
1903 "Detailed information\n"
1907 const char *vrf_name
= VRF_DEFAULT_NAME
;
1908 bool all_vrf
= false;
1909 struct listnode
*node
;
1911 int rc
= CMD_WARNING
;
1913 ISIS_FIND_VRF_ARGS(argv
, argc
, idx_vrf
, vrf_name
, all_vrf
);
1916 for (ALL_LIST_ELEMENTS_RO(im
->isis
, node
, isis
)) {
1917 rc
= show_isis_ted(vty
, argv
, argc
, isis
);
1918 if (rc
!= CMD_SUCCESS
)
1923 isis
= isis_lookup_by_vrfname(vrf_name
);
1925 rc
= show_isis_ted(vty
, argv
, argc
, isis
);
1931 #endif /* #ifndef FRABRICD */
1933 /* Initialize MPLS_TE */
1934 void isis_mpls_te_init(void)
1937 /* Register Circuit and Adjacency hook */
1938 hook_register(isis_if_new_hook
, isis_mpls_te_update
);
1939 hook_register(isis_adj_ip_enabled_hook
, isis_mpls_te_adj_ip_enabled
);
1940 hook_register(isis_adj_ip_disabled_hook
, isis_mpls_te_adj_ip_disabled
);
1943 /* Register new VTY commands */
1944 install_element(VIEW_NODE
, &show_isis_mpls_te_router_cmd
);
1945 install_element(VIEW_NODE
, &show_isis_mpls_te_interface_cmd
);
1946 install_element(VIEW_NODE
, &show_isis_mpls_te_db_cmd
);