2 * IS-IS Rout(e)ing protocol - isis_te.c
4 * This is an implementation of RFC5305 & RFC 7810
6 * Author: Olivier Dugeon <olivier.dugeon@orange.com>
8 * Copyright (C) 2014 - 2019 Orange Labs http://www.orange.com
10 * This file is part of GNU Zebra.
12 * GNU Zebra is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2, or (at your option) any
17 * GNU Zebra is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with this program; see the file COPYING; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
43 #include "sockunion.h"
46 #include "link_state.h"
49 #include "isisd/isis_constants.h"
50 #include "isisd/isis_common.h"
51 #include "isisd/isis_flags.h"
52 #include "isisd/isis_circuit.h"
53 #include "isisd/isis_adjacency.h"
54 #include "isisd/isisd.h"
55 #include "isisd/isis_lsp.h"
56 #include "isisd/isis_pdu.h"
57 #include "isisd/isis_dynhn.h"
58 #include "isisd/isis_misc.h"
59 #include "isisd/isis_csm.h"
60 #include "isisd/isis_adjacency.h"
61 #include "isisd/isis_spf.h"
62 #include "isisd/isis_tlvs.h"
63 #include "isisd/isis_mt.h"
64 #include "isisd/isis_te.h"
65 #include "isisd/isis_zebra.h"
67 DEFINE_MTYPE_STATIC(ISISD
, ISIS_MPLS_TE
, "ISIS MPLS_TE parameters");
69 static void isis_mpls_te_circuit_ip_update(struct isis_circuit
*circuit
);
71 /*------------------------------------------------------------------------*
72 * Following are control functions for MPLS-TE parameters management.
73 *------------------------------------------------------------------------*/
76 * Create MPLS Traffic Engineering structure which belongs to given area.
78 * @param area IS-IS Area
80 void isis_mpls_te_create(struct isis_area
*area
)
82 struct listnode
*node
;
83 struct isis_circuit
*circuit
;
88 if (area
->mta
== NULL
) {
90 struct mpls_te_area
*new;
92 zlog_debug("ISIS-TE(%s): Initialize MPLS Traffic Engineering",
95 new = XCALLOC(MTYPE_ISIS_MPLS_TE
, sizeof(struct mpls_te_area
));
97 /* Initialize MPLS_TE structure */
101 new->interas_areaid
.s_addr
= 0;
102 new->router_id
.s_addr
= 0;
103 new->ted
= ls_ted_new(1, "ISIS", 0);
105 zlog_warn("Unable to create Link State Data Base");
109 area
->mta
->status
= enable
;
112 /* Initialize Link State Database */
114 isis_te_init_ted(area
);
116 /* Update Extended TLVs according to Interface link parameters
117 * and neighbor IP addresses
119 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
120 isis_link_params_update(circuit
, circuit
->interface
);
121 isis_mpls_te_circuit_ip_update(circuit
);
126 * Disable MPLS Traffic Engineering structure which belongs to given area.
128 * @param area IS-IS Area
130 void isis_mpls_te_disable(struct isis_area
*area
)
132 struct listnode
*node
;
133 struct isis_circuit
*circuit
;
138 area
->mta
->status
= disable
;
140 /* Remove Link State Database */
141 ls_ted_clean(area
->mta
->ted
);
143 /* Disable Extended SubTLVs on all circuit */
144 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
145 if (!IS_EXT_TE(circuit
->ext
))
148 /* disable MPLS_TE Circuit keeping SR one's */
149 if (IS_SUBTLV(circuit
->ext
, EXT_ADJ_SID
))
150 circuit
->ext
->status
= EXT_ADJ_SID
;
151 else if (IS_SUBTLV(circuit
->ext
, EXT_LAN_ADJ_SID
))
152 circuit
->ext
->status
= EXT_LAN_ADJ_SID
;
154 circuit
->ext
->status
= 0;
158 void isis_mpls_te_term(struct isis_area
*area
)
160 struct listnode
*node
;
161 struct isis_circuit
*circuit
;
166 zlog_info("TE(%s): Terminate MPLS TE", __func__
);
167 /* Remove Link State Database */
168 ls_ted_del_all(&area
->mta
->ted
);
170 /* Remove Extended SubTLVs */
171 zlog_info(" |- Remove Extended SubTLVS for all circuit");
172 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
173 zlog_info(" |- Call isis_del_ext_subtlvs()");
174 isis_del_ext_subtlvs(circuit
->ext
);
178 zlog_info(" |- Free MTA structure at %p", area
->mta
);
179 XFREE(MTYPE_ISIS_MPLS_TE
, area
->mta
);
182 /* Main initialization / update function of the MPLS TE Circuit context */
183 /* Call when interface TE Link parameters are modified */
184 void isis_link_params_update(struct isis_circuit
*circuit
,
185 struct interface
*ifp
)
188 struct prefix_ipv4
*addr
;
189 struct prefix_ipv6
*addr6
;
190 struct isis_ext_subtlvs
*ext
;
192 /* Check if TE is enable or not */
193 if (!circuit
->area
|| !IS_MPLS_TE(circuit
->area
->mta
))
197 if ((ifp
== NULL
) || (circuit
->state
!= C_STATE_UP
))
200 te_debug("ISIS-TE(%s): Update circuit parameters for interface %s",
201 circuit
->area
->area_tag
, ifp
->name
);
203 /* Check if MPLS TE Circuit context has not been already created */
204 if (circuit
->ext
== NULL
) {
205 circuit
->ext
= isis_alloc_ext_subtlvs();
206 te_debug(" |- Allocated new Ext-subTLVs for interface %s",
212 /* Fulfill Extended subTLVs from interface link parameters */
213 if (HAS_LINK_PARAMS(ifp
)) {
215 if (IS_PARAM_SET(ifp
->link_params
, LP_ADM_GRP
)) {
216 ext
->adm_group
= ifp
->link_params
->admin_grp
;
217 SET_SUBTLV(ext
, EXT_ADM_GRP
);
219 UNSET_SUBTLV(ext
, EXT_ADM_GRP
);
221 /* If known, register local IPv4 addr from ip_addr list */
222 if (listcount(circuit
->ip_addrs
) != 0) {
223 addr
= (struct prefix_ipv4
*)listgetdata(
224 (struct listnode
*)listhead(circuit
->ip_addrs
));
225 IPV4_ADDR_COPY(&ext
->local_addr
, &addr
->prefix
);
226 SET_SUBTLV(ext
, EXT_LOCAL_ADDR
);
228 UNSET_SUBTLV(ext
, EXT_LOCAL_ADDR
);
230 /* If known, register local IPv6 addr from ip_addr list */
231 if (listcount(circuit
->ipv6_non_link
) != 0) {
232 addr6
= (struct prefix_ipv6
*)listgetdata(
233 (struct listnode
*)listhead(
234 circuit
->ipv6_non_link
));
235 IPV6_ADDR_COPY(&ext
->local_addr6
, &addr6
->prefix
);
236 SET_SUBTLV(ext
, EXT_LOCAL_ADDR6
);
238 UNSET_SUBTLV(ext
, EXT_LOCAL_ADDR6
);
241 * Remote IPv4 and IPv6 addresses are now added in
242 * isis_mpls_te_adj_ip_enabled() to get the right IP address
243 * in particular for IPv6 to get the global IPv6 address and
244 * not the link-local IPv6 address.
247 if (IS_PARAM_SET(ifp
->link_params
, LP_MAX_BW
)) {
248 ext
->max_bw
= ifp
->link_params
->max_bw
;
249 SET_SUBTLV(ext
, EXT_MAX_BW
);
251 UNSET_SUBTLV(ext
, EXT_MAX_BW
);
253 if (IS_PARAM_SET(ifp
->link_params
, LP_MAX_RSV_BW
)) {
254 ext
->max_rsv_bw
= ifp
->link_params
->max_rsv_bw
;
255 SET_SUBTLV(ext
, EXT_MAX_RSV_BW
);
257 UNSET_SUBTLV(ext
, EXT_MAX_RSV_BW
);
259 if (IS_PARAM_SET(ifp
->link_params
, LP_UNRSV_BW
)) {
260 for (i
= 0; i
< MAX_CLASS_TYPE
; i
++)
262 ifp
->link_params
->unrsv_bw
[i
];
263 SET_SUBTLV(ext
, EXT_UNRSV_BW
);
265 UNSET_SUBTLV(ext
, EXT_UNRSV_BW
);
267 if (IS_PARAM_SET(ifp
->link_params
, LP_TE_METRIC
)) {
268 ext
->te_metric
= ifp
->link_params
->te_metric
;
269 SET_SUBTLV(ext
, EXT_TE_METRIC
);
271 UNSET_SUBTLV(ext
, EXT_TE_METRIC
);
273 /* TE metric extensions */
274 if (IS_PARAM_SET(ifp
->link_params
, LP_DELAY
)) {
275 ext
->delay
= ifp
->link_params
->av_delay
;
276 SET_SUBTLV(ext
, EXT_DELAY
);
278 UNSET_SUBTLV(ext
, EXT_DELAY
);
280 if (IS_PARAM_SET(ifp
->link_params
, LP_MM_DELAY
)) {
281 ext
->min_delay
= ifp
->link_params
->min_delay
;
282 ext
->max_delay
= ifp
->link_params
->max_delay
;
283 SET_SUBTLV(ext
, EXT_MM_DELAY
);
285 UNSET_SUBTLV(ext
, EXT_MM_DELAY
);
287 if (IS_PARAM_SET(ifp
->link_params
, LP_DELAY_VAR
)) {
288 ext
->delay_var
= ifp
->link_params
->delay_var
;
289 SET_SUBTLV(ext
, EXT_DELAY_VAR
);
291 UNSET_SUBTLV(ext
, EXT_DELAY_VAR
);
293 if (IS_PARAM_SET(ifp
->link_params
, LP_PKT_LOSS
)) {
294 ext
->pkt_loss
= ifp
->link_params
->pkt_loss
;
295 SET_SUBTLV(ext
, EXT_PKT_LOSS
);
297 UNSET_SUBTLV(ext
, EXT_PKT_LOSS
);
299 if (IS_PARAM_SET(ifp
->link_params
, LP_RES_BW
)) {
300 ext
->res_bw
= ifp
->link_params
->res_bw
;
301 SET_SUBTLV(ext
, EXT_RES_BW
);
303 UNSET_SUBTLV(ext
, EXT_RES_BW
);
305 if (IS_PARAM_SET(ifp
->link_params
, LP_AVA_BW
)) {
306 ext
->ava_bw
= ifp
->link_params
->ava_bw
;
307 SET_SUBTLV(ext
, EXT_AVA_BW
);
309 UNSET_SUBTLV(ext
, EXT_AVA_BW
);
311 if (IS_PARAM_SET(ifp
->link_params
, LP_USE_BW
)) {
312 ext
->use_bw
= ifp
->link_params
->use_bw
;
313 SET_SUBTLV(ext
, EXT_USE_BW
);
315 UNSET_SUBTLV(ext
, EXT_USE_BW
);
318 if (IS_PARAM_SET(ifp
->link_params
, LP_RMT_AS
)) {
319 ext
->remote_as
= ifp
->link_params
->rmt_as
;
320 ext
->remote_ip
= ifp
->link_params
->rmt_ip
;
321 SET_SUBTLV(ext
, EXT_RMT_AS
);
322 SET_SUBTLV(ext
, EXT_RMT_IP
);
324 /* reset inter-as TE params */
325 UNSET_SUBTLV(ext
, EXT_RMT_AS
);
326 UNSET_SUBTLV(ext
, EXT_RMT_IP
);
328 te_debug(" |- New MPLS-TE link parameters status 0x%x",
331 te_debug(" |- Reset Extended subTLVs status 0x%x",
333 /* Reset TE subTLVs keeping SR one's */
334 if (IS_SUBTLV(ext
, EXT_ADJ_SID
))
335 ext
->status
= EXT_ADJ_SID
;
336 else if (IS_SUBTLV(ext
, EXT_LAN_ADJ_SID
))
337 ext
->status
= EXT_LAN_ADJ_SID
;
345 static int _isis_mpls_te_adj_ip_enabled(struct isis_adjacency
*adj
, int family
,
348 struct isis_circuit
*circuit
;
349 struct isis_ext_subtlvs
*ext
;
351 circuit
= adj
->circuit
;
353 /* Check that MPLS TE is enabled */
354 if (!IS_MPLS_TE(circuit
->area
->mta
) || !circuit
->ext
)
359 /* Determine nexthop IP address */
362 if (!circuit
->ip_router
|| !adj
->ipv4_address_count
)
363 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR
);
365 IPV4_ADDR_COPY(&ext
->neigh_addr
,
366 &adj
->ipv4_addresses
[0]);
367 SET_SUBTLV(ext
, EXT_NEIGH_ADDR
);
371 /* Nothing to do for link-local addresses - ie. not global.
372 * https://datatracker.ietf.org/doc/html/rfc6119#section-3.1.1
373 * Because the IPv6 traffic engineering TLVs present in LSPs are
374 * propagated across networks, they MUST NOT use link-local
380 if (!circuit
->ipv6_router
|| !adj
->global_ipv6_count
)
381 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR6
);
383 IPV6_ADDR_COPY(&ext
->neigh_addr6
,
384 &adj
->global_ipv6_addrs
[0]);
385 SET_SUBTLV(ext
, EXT_NEIGH_ADDR6
);
395 static int isis_mpls_te_adj_ip_enabled(struct isis_adjacency
*adj
, int family
,
401 if (!adj
|| !adj
->circuit
)
404 ret
= _isis_mpls_te_adj_ip_enabled(adj
, family
, global
);
407 lsp_regenerate_schedule(adj
->circuit
->area
, adj
->circuit
->is_type
, 0);
412 static int _isis_mpls_te_adj_ip_disabled(struct isis_adjacency
*adj
, int family
,
415 struct isis_circuit
*circuit
;
416 struct isis_ext_subtlvs
*ext
;
418 circuit
= adj
->circuit
;
420 /* Check that MPLS TE is enabled */
421 if (!IS_MPLS_TE(circuit
->area
->mta
) || !circuit
->ext
)
426 /* Update MPLS TE IP address parameters if possible */
427 if (!IS_MPLS_TE(circuit
->area
->mta
) || !IS_EXT_TE(ext
))
430 /* Determine nexthop IP address */
433 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR
);
437 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR6
);
446 static int isis_mpls_te_adj_ip_disabled(struct isis_adjacency
*adj
, int family
,
452 if (!adj
|| !adj
->circuit
|| !adj
->circuit
->ext
)
455 ret
= _isis_mpls_te_adj_ip_disabled(adj
, family
, global
);
458 lsp_regenerate_schedule(adj
->circuit
->area
, adj
->circuit
->is_type
, 0);
463 static void isis_mpls_te_circuit_ip_update(struct isis_circuit
*circuit
)
465 struct isis_adjacency
*adj
;
467 /* https://datatracker.ietf.org/doc/html/rfc6119#section-3.2.3
468 * This sub-TLV of the Extended IS Reachability TLV is used for point-
471 if (circuit
->circ_type
!= CIRCUIT_T_P2P
)
474 adj
= circuit
->u
.p2p
.neighbor
;
479 /* Nothing to do for link-local addresses.
480 * https://datatracker.ietf.org/doc/html/rfc6119#section-3.1.1
481 * Because the IPv6 traffic engineering TLVs present in LSPs are
482 * propagated across networks, they MUST NOT use link-local addresses.
484 if (adj
->ipv4_address_count
> 0)
485 _isis_mpls_te_adj_ip_enabled(adj
, AF_INET
, false);
487 _isis_mpls_te_adj_ip_disabled(adj
, AF_INET
, false);
489 if (adj
->global_ipv6_count
> 0)
490 _isis_mpls_te_adj_ip_enabled(adj
, AF_INET6
, true);
492 _isis_mpls_te_adj_ip_disabled(adj
, AF_INET6
, true);
496 int isis_mpls_te_update(struct interface
*ifp
)
498 struct isis_circuit
*circuit
;
505 /* Get circuit context from interface */
506 circuit
= circuit_scan_by_ifp(ifp
);
510 /* Update TE TLVs ... */
511 isis_link_params_update(circuit
, ifp
);
514 if (circuit
->area
&& IS_MPLS_TE(circuit
->area
->mta
))
515 lsp_regenerate_schedule(circuit
->area
, circuit
->is_type
, 0);
523 * Export Link State information to consumer daemon through ZAPI Link State
526 * @param type Type of Link State Element i.e. Vertex, Edge or Subnet
527 * @param link_state Pointer to Link State Vertex, Edge or Subnet
529 * @return 0 if success, -1 otherwise
531 static int isis_te_export(uint8_t type
, void *link_state
)
533 struct ls_message msg
= {};
537 case LS_MSG_TYPE_NODE
:
538 ls_vertex2msg(&msg
, (struct ls_vertex
*)link_state
);
539 rc
= ls_send_msg(zclient
, &msg
, NULL
);
541 case LS_MSG_TYPE_ATTRIBUTES
:
542 ls_edge2msg(&msg
, (struct ls_edge
*)link_state
);
543 rc
= ls_send_msg(zclient
, &msg
, NULL
);
545 case LS_MSG_TYPE_PREFIX
:
546 ls_subnet2msg(&msg
, (struct ls_subnet
*)link_state
);
547 rc
= ls_send_msg(zclient
, &msg
, NULL
);
558 * Parse LSP and build corresponding vertex. If vertex doesn't exist in the
559 * Link State Database it is created otherwise updated.
561 * @param ted Traffic Engineering Link State Database
562 * @param lsp IS-IS Link State PDU
564 * @return Link State Vertex or NULL in case of error
566 static struct ls_vertex
*lsp_to_vertex(struct ls_ted
*ted
, struct isis_lsp
*lsp
)
568 struct ls_vertex
*vertex
= NULL
;
569 struct ls_node
*old
, lnode
= {};
570 struct isis_tlvs
*tlvs
;
571 const struct in_addr inaddr_any
= {.s_addr
= INADDR_ANY
};
577 /* Compute Link State Node ID from IS-IS sysID ... */
578 if (lsp
->level
== ISIS_LEVEL1
)
579 lnode
.adv
.origin
= ISIS_L1
;
581 lnode
.adv
.origin
= ISIS_L2
;
582 memcpy(&lnode
.adv
.id
.iso
.sys_id
, &lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
);
583 lnode
.adv
.id
.iso
.level
= lsp
->level
;
584 /* ... and search the corresponding vertex */
585 vertex
= ls_find_vertex_by_id(ted
, lnode
.adv
);
586 /* Create a new one if not found */
588 old
= ls_node_new(lnode
.adv
, inaddr_any
, in6addr_any
);
589 old
->type
= STANDARD
;
590 vertex
= ls_vertex_add(ted
, old
);
593 te_debug(" |- %s Vertex (%" PRIu64
") for node %s",
594 vertex
->status
== NEW
? "Create" : "Found", vertex
->key
,
595 print_sys_hostname(old
->adv
.id
.iso
.sys_id
));
597 /* Fulfill Link State Node information */
600 if (tlvs
->te_router_id
) {
601 IPV4_ADDR_COPY(&lnode
.router_id
, tlvs
->te_router_id
);
602 SET_FLAG(lnode
.flags
, LS_NODE_ROUTER_ID
);
604 if (tlvs
->te_router_id_ipv6
) {
605 IPV6_ADDR_COPY(&lnode
.router_id6
,
606 tlvs
->te_router_id_ipv6
);
607 SET_FLAG(lnode
.flags
, LS_NODE_ROUTER_ID6
);
609 if (tlvs
->hostname
) {
610 strlcpy(lnode
.name
, tlvs
->hostname
, MAX_NAME_LENGTH
);
611 SET_FLAG(lnode
.flags
, LS_NODE_NAME
);
613 if (tlvs
->router_cap
) {
614 struct isis_router_cap
*cap
= tlvs
->router_cap
;
616 if (cap
->srgb
.lower_bound
!= 0
617 && cap
->srgb
.range_size
!= 0) {
618 SET_FLAG(lnode
.flags
, LS_NODE_SR
);
619 lnode
.srgb
.flag
= cap
->srgb
.flags
;
620 lnode
.srgb
.lower_bound
= cap
->srgb
.lower_bound
;
621 lnode
.srgb
.range_size
= cap
->srgb
.range_size
;
622 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
623 lnode
.algo
[i
] = cap
->algo
[i
];
626 if (cap
->srlb
.lower_bound
!= 0
627 && cap
->srlb
.range_size
!= 0) {
628 lnode
.srlb
.lower_bound
= cap
->srlb
.lower_bound
;
629 lnode
.srlb
.range_size
= cap
->srlb
.range_size
;
630 SET_FLAG(lnode
.flags
, LS_NODE_SRLB
);
633 lnode
.msd
= cap
->msd
;
634 SET_FLAG(lnode
.flags
, LS_NODE_MSD
);
639 /* Update Link State Node information */
640 if (!ls_node_same(old
, &lnode
)) {
641 te_debug(" |- Update Link State Node information");
642 memcpy(old
, &lnode
, sizeof(struct ls_node
));
643 if (vertex
->status
!= NEW
)
644 vertex
->status
= UPDATE
;
647 /* Set self TED vertex if LSP corresponds to the own router */
655 * Get Link State Edge from Link State Attributes in TE Database.
656 * Edge structure is dynamically allocated and fulfill with Link State
657 * Attributes if not found.
659 * @param ted Link State Database
660 * @param attr Link State Attributes
662 * @return New Link State Edge if success, NULL otherwise
664 static struct ls_edge
*get_edge(struct ls_ted
*ted
, struct ls_attributes
*attr
)
666 struct ls_edge
*edge
;
667 struct ls_standard
*std
;
670 /* Check parameters */
674 std
= &attr
->standard
;
676 /* Compute keys in function of local address (IPv4/v6) or identifier */
677 if (CHECK_FLAG(attr
->flags
, LS_ATTR_LOCAL_ADDR
))
678 key
= ((uint64_t)ntohl(std
->local
.s_addr
)) & 0xffffffff;
679 else if (CHECK_FLAG(attr
->flags
, LS_ATTR_LOCAL_ADDR6
))
680 key
= ((uint64_t)ntohl(std
->local6
.s6_addr32
[2]) << 32
681 | (uint64_t)ntohl(std
->local6
.s6_addr32
[3]));
682 else if (CHECK_FLAG(attr
->flags
, LS_ATTR_LOCAL_ID
))
683 key
= ((uint64_t)std
->remote_id
<< 32)
684 | (((uint64_t)std
->local_id
) & 0xffffffff);
688 /* Stop here if we don't got a valid key */
692 /* Get corresponding Edge by key from Link State Data Base */
693 edge
= ls_find_edge_by_key(ted
, key
);
695 /* and create new one if not exist */
697 edge
= ls_edge_add(ted
, attr
);
699 * Edge could be Null if no local ID is found in Attributes.
700 * Stop the processing as without any local ID it is not
701 * possible to store Edge in the TED.
707 if (CHECK_FLAG(edge
->attributes
->flags
, LS_ATTR_LOCAL_ADDR
))
708 te_debug(" |- %s Edge (%" PRIu64
709 ") from Extended Reach. %pI4",
710 edge
->status
== NEW
? "Create" : "Found", edge
->key
,
711 &attr
->standard
.local
);
712 else if (CHECK_FLAG(edge
->attributes
->flags
, LS_ATTR_LOCAL_ADDR6
))
713 te_debug(" |- %s Edge (%" PRIu64
714 ") from Extended Reach. %pI6",
715 edge
->status
== NEW
? "Create" : "Found", edge
->key
,
716 &attr
->standard
.local6
);
718 te_debug(" |- %s Edge (%" PRIu64
")",
719 edge
->status
== NEW
? "Create" : "Found", edge
->key
);
725 * Get Link State Attributes from IS-IS Sub-TLVs. Structure is dynamically
726 * allocated and should be free once not use anymore.
728 * @param adv Link State Node ID
729 * @param tlvs IS-IS Sub TLVs
731 * @return New Link State attributes if success, NULL otherwise
733 static struct ls_attributes
*get_attributes(struct ls_node_id adv
,
734 struct isis_ext_subtlvs
*tlvs
)
736 struct ls_attributes
*attr
;
737 struct in_addr local
= {.s_addr
= INADDR_ANY
};
738 struct in6_addr local6
= in6addr_any
;
739 uint32_t local_id
= 0;
741 /* Got Local identifier */
742 if (CHECK_FLAG(tlvs
->status
, EXT_LOCAL_ADDR
))
743 local
.s_addr
= tlvs
->local_addr
.s_addr
;
745 if (CHECK_FLAG(tlvs
->status
, EXT_LOCAL_ADDR6
))
746 memcpy(&local6
, &tlvs
->local_addr6
, IPV6_MAX_BYTELEN
);
748 if (CHECK_FLAG(tlvs
->status
, EXT_LLRI
))
749 local_id
= tlvs
->local_llri
;
751 /* Create LS Attributes */
752 attr
= ls_attributes_new(adv
, local
, local6
, local_id
);
756 /* Browse sub-TLV and fulfill Link State Attributes */
757 if (CHECK_FLAG(tlvs
->status
, EXT_ADM_GRP
)) {
758 attr
->standard
.admin_group
= tlvs
->adm_group
;
759 SET_FLAG(attr
->flags
, LS_ATTR_ADM_GRP
);
761 if (CHECK_FLAG(tlvs
->status
, EXT_LLRI
)) {
762 attr
->standard
.local_id
= tlvs
->local_llri
;
763 attr
->standard
.remote_id
= tlvs
->remote_llri
;
764 SET_FLAG(attr
->flags
, LS_ATTR_LOCAL_ID
);
765 SET_FLAG(attr
->flags
, LS_ATTR_NEIGH_ID
);
767 if (CHECK_FLAG(tlvs
->status
, EXT_NEIGH_ADDR
)) {
768 attr
->standard
.remote
.s_addr
= tlvs
->neigh_addr
.s_addr
;
769 SET_FLAG(attr
->flags
, LS_ATTR_NEIGH_ADDR
);
771 if (CHECK_FLAG(tlvs
->status
, EXT_NEIGH_ADDR6
)) {
772 memcpy(&attr
->standard
.remote6
, &tlvs
->neigh_addr6
,
774 SET_FLAG(attr
->flags
, LS_ATTR_NEIGH_ADDR6
);
776 if (CHECK_FLAG(tlvs
->status
, EXT_MAX_BW
)) {
777 attr
->standard
.max_bw
= tlvs
->max_bw
;
778 SET_FLAG(attr
->flags
, LS_ATTR_MAX_BW
);
780 if (CHECK_FLAG(tlvs
->status
, EXT_MAX_RSV_BW
)) {
781 attr
->standard
.max_rsv_bw
= tlvs
->max_rsv_bw
;
782 SET_FLAG(attr
->flags
, LS_ATTR_MAX_RSV_BW
);
784 if (CHECK_FLAG(tlvs
->status
, EXT_UNRSV_BW
)) {
785 memcpy(&attr
->standard
.unrsv_bw
, tlvs
->unrsv_bw
,
786 ISIS_SUBTLV_UNRSV_BW_SIZE
);
787 SET_FLAG(attr
->flags
, LS_ATTR_UNRSV_BW
);
789 if (CHECK_FLAG(tlvs
->status
, EXT_TE_METRIC
)) {
790 attr
->standard
.te_metric
= tlvs
->te_metric
;
791 SET_FLAG(attr
->flags
, LS_ATTR_TE_METRIC
);
793 if (CHECK_FLAG(tlvs
->status
, EXT_RMT_AS
)) {
794 attr
->standard
.remote_as
= tlvs
->remote_as
;
795 SET_FLAG(attr
->flags
, LS_ATTR_REMOTE_AS
);
797 if (CHECK_FLAG(tlvs
->status
, EXT_RMT_IP
)) {
798 attr
->standard
.remote_addr
= tlvs
->remote_ip
;
799 SET_FLAG(attr
->flags
, LS_ATTR_REMOTE_ADDR
);
801 if (CHECK_FLAG(tlvs
->status
, EXT_DELAY
)) {
802 attr
->extended
.delay
= tlvs
->delay
;
803 SET_FLAG(attr
->flags
, LS_ATTR_DELAY
);
805 if (CHECK_FLAG(tlvs
->status
, EXT_MM_DELAY
)) {
806 attr
->extended
.min_delay
= tlvs
->min_delay
;
807 attr
->extended
.max_delay
= tlvs
->max_delay
;
808 SET_FLAG(attr
->flags
, LS_ATTR_MIN_MAX_DELAY
);
810 if (CHECK_FLAG(tlvs
->status
, EXT_DELAY_VAR
)) {
811 attr
->extended
.jitter
= tlvs
->delay_var
;
812 SET_FLAG(attr
->flags
, LS_ATTR_JITTER
);
814 if (CHECK_FLAG(tlvs
->status
, EXT_PKT_LOSS
)) {
815 attr
->extended
.pkt_loss
= tlvs
->pkt_loss
;
816 SET_FLAG(attr
->flags
, LS_ATTR_PACKET_LOSS
);
818 if (CHECK_FLAG(tlvs
->status
, EXT_AVA_BW
)) {
819 attr
->extended
.ava_bw
= tlvs
->ava_bw
;
820 SET_FLAG(attr
->flags
, LS_ATTR_AVA_BW
);
822 if (CHECK_FLAG(tlvs
->status
, EXT_RES_BW
)) {
823 attr
->extended
.rsv_bw
= tlvs
->res_bw
;
824 SET_FLAG(attr
->flags
, LS_ATTR_RSV_BW
);
826 if (CHECK_FLAG(tlvs
->status
, EXT_USE_BW
)) {
827 attr
->extended
.used_bw
= tlvs
->use_bw
;
828 SET_FLAG(attr
->flags
, LS_ATTR_USE_BW
);
830 if (CHECK_FLAG(tlvs
->status
, EXT_ADJ_SID
)) {
831 struct isis_adj_sid
*adj
=
832 (struct isis_adj_sid
*)tlvs
->adj_sid
.head
;
834 for (; adj
; adj
= adj
->next
) {
835 i
= adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
? 1 : 0;
836 i
+= adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
? 2 : 0;
837 attr
->adj_sid
[i
].flags
= adj
->flags
;
838 attr
->adj_sid
[i
].weight
= adj
->weight
;
839 attr
->adj_sid
[i
].sid
= adj
->sid
;
842 SET_FLAG(attr
->flags
, LS_ATTR_ADJ_SID
);
845 SET_FLAG(attr
->flags
, LS_ATTR_BCK_ADJ_SID
);
848 SET_FLAG(attr
->flags
, LS_ATTR_ADJ_SID6
);
851 SET_FLAG(attr
->flags
, LS_ATTR_BCK_ADJ_SID6
);
856 if (CHECK_FLAG(tlvs
->status
, EXT_LAN_ADJ_SID
)) {
857 struct isis_lan_adj_sid
*ladj
=
858 (struct isis_lan_adj_sid
*)tlvs
->lan_sid
.head
;
860 for (; ladj
; ladj
= ladj
->next
) {
861 i
= ladj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
? 1 : 0;
862 i
+= ladj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
? 2 : 0;
863 attr
->adj_sid
[i
].flags
= ladj
->flags
;
864 attr
->adj_sid
[i
].weight
= ladj
->weight
;
865 attr
->adj_sid
[i
].sid
= ladj
->sid
;
866 memcpy(&attr
->adj_sid
[i
].neighbor
.sysid
,
867 &ladj
->neighbor_id
, ISIS_SYS_ID_LEN
);
870 SET_FLAG(attr
->flags
, LS_ATTR_ADJ_SID
);
873 SET_FLAG(attr
->flags
, LS_ATTR_BCK_ADJ_SID
);
876 SET_FLAG(attr
->flags
, LS_ATTR_ADJ_SID6
);
879 SET_FLAG(attr
->flags
, LS_ATTR_BCK_ADJ_SID6
);
889 * Parse Extended Reachability TLVs and create or update the corresponding
890 * Link State Edge and Attributes. Vertex connections are also updated if
891 * needed based on the remote IP address of the Edge and existing reverse Edge.
893 * @param id ID of Extended IS
894 * @param metric Metric of the link
895 * @param old_metric Boolean that indicate if it is an old metric (no TE)
896 * @param tlvs SubTlvs that contains TE information
897 * @param arg IS-IS TE argument (TED, Vertex, and export indication)
899 * @return 0 if success, -1 otherwise
901 static int lsp_to_edge_cb(const uint8_t *id
, uint32_t metric
, bool old_metric
,
902 struct isis_ext_subtlvs
*tlvs
, void *arg
)
904 struct isis_te_args
*args
= (struct isis_te_args
*)arg
;
905 struct ls_vertex
*vertex
;
906 struct ls_edge
*edge
, *dst
;
907 struct ls_attributes
*attr
;
909 te_debug(" |- Process Extended IS for %s", sysid_print(id
));
911 /* Check parameters */
912 if (old_metric
|| !args
|| !tlvs
)
913 return LSP_ITER_CONTINUE
;
915 /* Initialize Link State Attributes */
916 vertex
= args
->vertex
;
917 attr
= get_attributes(vertex
->node
->adv
, tlvs
);
919 * Attributes may be Null if no local ID has been found in the LSP.
920 * Stop processing here as without any local ID it is not possible to
921 * create corresponding Edge in the TED.
924 return LSP_ITER_CONTINUE
;
926 attr
->metric
= metric
;
927 SET_FLAG(attr
->flags
, LS_ATTR_METRIC
);
929 /* Get corresponding Edge from Link State Data Base */
930 edge
= get_edge(args
->ted
, attr
);
932 * Edge could be Null if no local ID has been found in Attributes.
933 * Stop processing here as without any local ID it is not possible to
934 * create corresponding Edge in the TED.
937 ls_attributes_del(attr
);
938 return LSP_ITER_CONTINUE
;
941 /* Update Attribute fields if there are different */
942 if (edge
->status
!= NEW
) {
943 if (!ls_attributes_same(edge
->attributes
, attr
)) {
944 te_debug(" |- Update Edge Attributes information");
945 ls_attributes_del(edge
->attributes
);
946 edge
->attributes
= attr
;
947 edge
->status
= UPDATE
;
949 if (edge
->attributes
!= attr
)
950 ls_attributes_del(attr
);
955 /* Try to update remote Link from remote address or reachability ID */
956 te_debug(" |- Link Edge (%" PRIu64
") to destination vertex (%s)",
957 edge
->key
, print_sys_hostname(id
));
958 dst
= ls_find_edge_by_destination(args
->ted
, edge
->attributes
);
960 /* Attach remote link if not set */
961 if (edge
->source
&& dst
->destination
== NULL
) {
962 vertex
= edge
->source
;
963 if (vertex
->incoming_edges
)
964 listnode_add_sort_nodup(vertex
->incoming_edges
,
966 dst
->destination
= vertex
;
968 /* and destination vertex to this edge if not set */
969 if (dst
->source
&& edge
->destination
== NULL
) {
970 vertex
= dst
->source
;
971 if (vertex
->incoming_edges
)
972 listnode_add_sort_nodup(vertex
->incoming_edges
,
974 edge
->destination
= vertex
;
977 /* Search dst. Vertex by Extended Reach. ID if not found */
978 if (edge
->destination
== NULL
) {
979 vertex
= ls_find_vertex_by_key(args
->ted
,
981 if (vertex
&& vertex
->incoming_edges
)
982 listnode_add_sort_nodup(vertex
->incoming_edges
,
984 edge
->destination
= vertex
;
988 /* Update status and Export Link State Edge if needed */
989 if (edge
->status
!= SYNC
) {
991 isis_te_export(LS_MSG_TYPE_ATTRIBUTES
, edge
);
995 return LSP_ITER_CONTINUE
;
999 * Parse Extended IP Reachability or MT IPv6 Reachability TLVs and create or
1000 * update the corresponding Link State Subnet and Prefix.
1002 * @param prefix Prefix associated to this subnet
1003 * @param metric Metric of this prefix
1004 * @param external Boolean to indicate if the prefix is external
1005 * @param subtlvs Subtlvs if any (mostly Segment Routing ID)
1006 * @param arg IS-IS TE argument (TED, Vertex, and export indication)
1008 * @return 0 if success, -1 otherwise
1010 static int lsp_to_subnet_cb(const struct prefix
*prefix
, uint32_t metric
,
1011 bool external
, struct isis_subtlvs
*subtlvs
,
1014 struct isis_te_args
*args
= (struct isis_te_args
*)arg
;
1015 struct ls_vertex
*vertex
;
1016 struct ls_subnet
*subnet
;
1017 struct ls_prefix
*ls_pref
;
1018 struct listnode
*node
;
1019 struct ls_edge
*edge
;
1020 struct ls_standard
*std
= NULL
;
1024 if (!args
|| !prefix
)
1025 return LSP_ITER_CONTINUE
;
1027 te_debug(" |- Process Extended %s Reachability %pFX",
1028 prefix
->family
== AF_INET
? "IP" : "IPv6", prefix
);
1030 vertex
= args
->vertex
;
1033 * Prefix with mask different from /32 or /128 are advertised by at
1034 * least 2 nodes. To avoid subnet attached to undetermined vertex, and
1035 * gives the possibility to send the information to client e.g. BGP for
1036 * Link State advertisement, we adjust the prefix with the corresponding
1037 * IP address of the belonging interface when it is available. Other
1038 * prefixes are kept unchanged.
1040 if (prefix
->family
== AF_INET
&& prefix
->prefixlen
< IPV4_MAX_BITLEN
) {
1042 for (ALL_LIST_ELEMENTS_RO(vertex
->outgoing_edges
, node
, edge
)) {
1043 if (!CHECK_FLAG(edge
->attributes
->flags
,
1044 LS_ATTR_LOCAL_ADDR
))
1047 p
.u
.prefix4
= edge
->attributes
->standard
.local
;
1049 p
.prefixlen
= prefix
->prefixlen
;
1050 apply_mask_ipv4((struct prefix_ipv4
*)&p
);
1051 if (IPV4_ADDR_SAME(&p
.u
.prefix4
, &prefix
->u
.prefix4
)) {
1052 std
= &edge
->attributes
->standard
;
1057 p
.u
.prefix4
= std
->local
;
1059 } else if (prefix
->family
== AF_INET6
1060 && prefix
->prefixlen
< IPV6_MAX_BITLEN
) {
1062 for (ALL_LIST_ELEMENTS_RO(vertex
->outgoing_edges
, node
, edge
)) {
1063 if (!CHECK_FLAG(edge
->attributes
->flags
,
1064 LS_ATTR_LOCAL_ADDR6
))
1067 p
.u
.prefix6
= edge
->attributes
->standard
.local6
;
1068 p
.family
= AF_INET6
;
1069 p
.prefixlen
= prefix
->prefixlen
;
1070 apply_mask_ipv6((struct prefix_ipv6
*)&p
);
1071 if (IPV6_ADDR_SAME(&p
.u
.prefix6
, &prefix
->u
.prefix6
)) {
1072 std
= &edge
->attributes
->standard
;
1077 p
.u
.prefix6
= std
->local6
;
1080 prefix_copy(&p
, prefix
);
1082 te_debug(" |- Adjust prefix %pFX with local address to: %pFX",
1085 /* Search existing Subnet in TED ... */
1086 subnet
= ls_find_subnet(args
->ted
, p
);
1087 /* ... and create a new Subnet if not found */
1089 ls_pref
= ls_prefix_new(vertex
->node
->adv
, p
);
1090 subnet
= ls_subnet_add(args
->ted
, ls_pref
);
1092 return LSP_ITER_CONTINUE
;
1094 ls_pref
= subnet
->ls_pref
;
1096 te_debug(" |- %s Subnet from prefix %pFX",
1097 subnet
->status
== NEW
? "Create" : "Found", &p
);
1100 if (!CHECK_FLAG(ls_pref
->flags
, LS_PREF_METRIC
)
1101 || (ls_pref
->metric
!= metric
)) {
1102 ls_pref
->metric
= metric
;
1103 SET_FLAG(ls_pref
->flags
, LS_PREF_METRIC
);
1104 if (subnet
->status
!= NEW
)
1105 subnet
->status
= UPDATE
;
1107 if (subnet
->status
== ORPHAN
)
1108 subnet
->status
= SYNC
;
1111 /* Update Prefix SID if any */
1112 if (subtlvs
&& subtlvs
->prefix_sids
.count
!= 0) {
1113 struct isis_prefix_sid
*psid
;
1114 struct ls_sid sr
= {};
1116 psid
= (struct isis_prefix_sid
*)subtlvs
->prefix_sids
.head
;
1117 sr
.algo
= psid
->algorithm
;
1118 sr
.sid_flag
= psid
->flags
;
1119 sr
.sid
= psid
->value
;
1121 if (!CHECK_FLAG(ls_pref
->flags
, LS_PREF_SR
)
1122 || !memcmp(&ls_pref
->sr
, &sr
, sizeof(struct ls_sid
))) {
1123 memcpy(&ls_pref
->sr
, &sr
, sizeof(struct ls_sid
));
1124 SET_FLAG(ls_pref
->flags
, LS_PREF_SR
);
1125 if (subnet
->status
!= NEW
)
1126 subnet
->status
= UPDATE
;
1128 if (subnet
->status
== ORPHAN
)
1129 subnet
->status
= SYNC
;
1132 if (CHECK_FLAG(ls_pref
->flags
, LS_PREF_SR
)) {
1133 UNSET_FLAG(ls_pref
->flags
, LS_PREF_SR
);
1134 if (subnet
->status
!= NEW
)
1135 subnet
->status
= UPDATE
;
1137 if (subnet
->status
== ORPHAN
)
1138 subnet
->status
= SYNC
;
1142 /* Update status and Export Link State Edge if needed */
1143 if (subnet
->status
!= SYNC
) {
1145 isis_te_export(LS_MSG_TYPE_PREFIX
, subnet
);
1146 subnet
->status
= SYNC
;
1149 return LSP_ITER_CONTINUE
;
1153 * Parse ISIS LSP to fulfill the Link State Database
1155 * @param ted Link State Database
1156 * @param lsp ISIS Link State PDU
1158 static void isis_te_parse_lsp(struct mpls_te_area
*mta
, struct isis_lsp
*lsp
)
1161 struct ls_vertex
*vertex
;
1162 struct ls_edge
*edge
;
1163 struct ls_subnet
*subnet
;
1164 struct listnode
*node
;
1165 struct isis_te_args args
;
1168 if (!IS_MPLS_TE(mta
) || !mta
->ted
|| !lsp
)
1173 te_debug("ISIS-TE(%s): Parse LSP %s", lsp
->area
->area_tag
,
1174 sysid_print(lsp
->hdr
.lsp_id
));
1176 /* First parse LSP to obtain the corresponding Vertex */
1177 vertex
= lsp_to_vertex(ted
, lsp
);
1179 zlog_warn("Unable to build Vertex from LSP %s. Abort!",
1180 sysid_print(lsp
->hdr
.lsp_id
));
1184 /* Check if Vertex has been modified */
1185 if (vertex
->status
!= SYNC
) {
1186 /* Vertex is out of sync: export it if requested */
1187 if (IS_EXPORT_TE(mta
))
1188 isis_te_export(LS_MSG_TYPE_NODE
, vertex
);
1189 vertex
->status
= SYNC
;
1192 /* Mark outgoing Edges and Subnets as ORPHAN to detect deletion */
1193 for (ALL_LIST_ELEMENTS_RO(vertex
->outgoing_edges
, node
, edge
))
1194 edge
->status
= ORPHAN
;
1196 for (ALL_LIST_ELEMENTS_RO(vertex
->prefixes
, node
, subnet
))
1197 subnet
->status
= ORPHAN
;
1199 /* Process all Extended Reachability in LSP (all fragments) */
1201 args
.vertex
= vertex
;
1202 args
.export
= mta
->export
;
1203 isis_lsp_iterate_is_reach(lsp
, ISIS_MT_IPV4_UNICAST
, lsp_to_edge_cb
,
1206 isis_lsp_iterate_is_reach(lsp
, ISIS_MT_IPV6_UNICAST
, lsp_to_edge_cb
,
1209 /* Process all Extended IP (v4 & v6) in LSP (all fragments) */
1210 isis_lsp_iterate_ip_reach(lsp
, AF_INET
, ISIS_MT_IPV4_UNICAST
,
1211 lsp_to_subnet_cb
, &args
);
1212 isis_lsp_iterate_ip_reach(lsp
, AF_INET6
, ISIS_MT_IPV6_UNICAST
,
1213 lsp_to_subnet_cb
, &args
);
1214 isis_lsp_iterate_ip_reach(lsp
, AF_INET6
, ISIS_MT_IPV4_UNICAST
,
1215 lsp_to_subnet_cb
, &args
);
1217 /* Clean remaining Orphan Edges or Subnets */
1218 if (IS_EXPORT_TE(mta
))
1219 ls_vertex_clean(ted
, vertex
, zclient
);
1221 ls_vertex_clean(ted
, vertex
, NULL
);
1225 * Delete Link State Database Vertex, Edge & Prefix that correspond to this
1226 * ISIS Link State PDU
1228 * @param ted Link State Database
1229 * @param lsp ISIS Link State PDU
1231 static void isis_te_delete_lsp(struct mpls_te_area
*mta
, struct isis_lsp
*lsp
)
1234 struct ls_vertex
*vertex
= NULL
;
1235 struct ls_node lnode
= {};
1236 struct ls_edge
*edge
;
1237 struct ls_subnet
*subnet
;
1238 struct listnode
*nnode
, *node
;
1241 if (!IS_MPLS_TE(mta
) || !mta
->ted
|| !lsp
)
1244 te_debug("ISIS-TE(%s): Delete Link State TED objects from LSP %s",
1245 lsp
->area
->area_tag
, sysid_print(lsp
->hdr
.lsp_id
));
1247 /* Compute Link State Node ID from IS-IS sysID ... */
1248 if (lsp
->level
== ISIS_LEVEL1
)
1249 lnode
.adv
.origin
= ISIS_L1
;
1251 lnode
.adv
.origin
= ISIS_L2
;
1252 memcpy(&lnode
.adv
.id
.iso
.sys_id
, &lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
);
1253 lnode
.adv
.id
.iso
.level
= lsp
->level
;
1255 /* ... and search the corresponding vertex */
1256 vertex
= ls_find_vertex_by_id(ted
, lnode
.adv
);
1260 te_debug(" |- Delete Vertex %s", vertex
->node
->name
);
1263 * We can't use the ls_vertex_del_all() function if export TE is set,
1264 * as we must first advertise the client daemons of each removal.
1266 /* Remove outgoing Edges */
1267 for (ALL_LIST_ELEMENTS(vertex
->outgoing_edges
, node
, nnode
, edge
)) {
1268 if (IS_EXPORT_TE(mta
)) {
1269 edge
->status
= DELETE
;
1270 isis_te_export(LS_MSG_TYPE_ATTRIBUTES
, edge
);
1272 ls_edge_del_all(ted
, edge
);
1275 /* Disconnect incoming Edges */
1276 for (ALL_LIST_ELEMENTS(vertex
->incoming_edges
, node
, nnode
, edge
)) {
1277 ls_disconnect(vertex
, edge
, false);
1278 if (edge
->source
== NULL
) {
1279 if (IS_EXPORT_TE(mta
)) {
1280 edge
->status
= DELETE
;
1281 isis_te_export(LS_MSG_TYPE_ATTRIBUTES
, edge
);
1283 ls_edge_del_all(ted
, edge
);
1287 /* Remove subnets */
1288 for (ALL_LIST_ELEMENTS(vertex
->prefixes
, node
, nnode
, subnet
)) {
1289 if (IS_EXPORT_TE(mta
)) {
1290 subnet
->status
= DELETE
;
1291 isis_te_export(LS_MSG_TYPE_PREFIX
, subnet
);
1293 ls_subnet_del_all(ted
, subnet
);
1296 /* Then remove Link State Node */
1297 if (IS_EXPORT_TE(mta
)) {
1298 vertex
->status
= DELETE
;
1299 isis_te_export(LS_MSG_TYPE_NODE
, vertex
);
1301 ls_node_del(vertex
->node
);
1303 /* Finally, remove Vertex */
1304 ls_vertex_del(ted
, vertex
);
1308 * Process ISIS LSP according to the event to add, update or remove
1309 * corresponding vertex, edge and prefix in the Link State database.
1310 * Since LSP could be fragmented, the function starts by searching the root LSP
1311 * to retrieve the complete LSP, including eventual fragment before processing
1314 * @param lsp ISIS Link State PDU
1315 * @param event LSP event: ADD, UPD, INC & DEL (TICK are ignored)
1318 void isis_te_lsp_event(struct isis_lsp
*lsp
, enum lsp_event event
)
1320 struct isis_area
*area
;
1321 struct isis_lsp
*lsp0
;
1324 if (!lsp
|| !lsp
->area
)
1328 if (!IS_MPLS_TE(area
->mta
))
1331 /* Adjust LSP0 in case of fragment */
1332 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
))
1333 lsp0
= lsp
->lspu
.zero_lsp
;
1337 /* Then process event */
1342 isis_te_parse_lsp(area
->mta
, lsp0
);
1345 isis_te_delete_lsp(area
->mta
, lsp0
);
1353 * Send the whole Link State Traffic Engineering Database to the consumer that
1354 * request it through a ZAPI Link State Synchronous Opaque Message.
1356 * @param info ZAPI Opaque message
1358 * @return 0 if success, -1 otherwise
1360 int isis_te_sync_ted(struct zapi_opaque_reg_info dst
)
1362 struct listnode
*node
, *inode
;
1364 struct isis_area
*area
;
1365 struct mpls_te_area
*mta
;
1368 te_debug("ISIS-TE(%s): Received TED synchro from client %d", __func__
,
1370 /* For each area, send TED if TE distribution is enabled */
1371 for (ALL_LIST_ELEMENTS_RO(im
->isis
, inode
, isis
)) {
1372 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
, area
)) {
1374 if (IS_MPLS_TE(mta
) && IS_EXPORT_TE(mta
)) {
1375 te_debug(" |- Export TED from area %s",
1377 rc
= ls_sync_ted(mta
->ted
, zclient
, &dst
);
1388 * Initialize the Link State database from the LSP already stored for this area
1390 * @param area ISIS area
1392 void isis_te_init_ted(struct isis_area
*area
)
1394 struct isis_lsp
*lsp
;
1396 /* Iterate over all lsp. */
1397 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++)
1398 frr_each (lspdb
, &area
->lspdb
[level
- 1], lsp
)
1399 isis_te_parse_lsp(area
->mta
, lsp
);
1402 /* Following are vty command functions */
1405 static void show_router_id(struct vty
*vty
, struct isis_area
*area
)
1407 bool no_match
= true;
1409 vty_out(vty
, "Area %s:\n", area
->area_tag
);
1410 if (area
->mta
->router_id
.s_addr
!= 0) {
1411 vty_out(vty
, " MPLS-TE IPv4 Router-Address: %pI4\n",
1412 &area
->mta
->router_id
);
1415 if (!IN6_IS_ADDR_UNSPECIFIED(&area
->mta
->router_id_ipv6
)) {
1416 vty_out(vty
, " MPLS-TE IPv6 Router-Address: %pI6\n",
1417 &area
->mta
->router_id_ipv6
);
1421 vty_out(vty
, " N/A\n");
1424 DEFUN(show_isis_mpls_te_router
,
1425 show_isis_mpls_te_router_cmd
,
1426 "show " PROTO_NAME
" [vrf <NAME|all>] mpls-te router",
1429 VRF_CMD_HELP_STR
"All VRFs\n"
1430 MPLS_TE_STR
"Router information\n")
1433 struct listnode
*anode
, *inode
;
1434 struct isis_area
*area
;
1435 struct isis
*isis
= NULL
;
1436 const char *vrf_name
= VRF_DEFAULT_NAME
;
1437 bool all_vrf
= false;
1441 vty_out(vty
, "IS-IS Routing Process not enabled\n");
1444 ISIS_FIND_VRF_ARGS(argv
, argc
, idx_vrf
, vrf_name
, all_vrf
);
1447 for (ALL_LIST_ELEMENTS_RO(im
->isis
, inode
, isis
)) {
1448 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
,
1450 if (!IS_MPLS_TE(area
->mta
))
1453 show_router_id(vty
, area
);
1458 isis
= isis_lookup_by_vrfname(vrf_name
);
1460 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, anode
,
1463 if (!IS_MPLS_TE(area
->mta
))
1466 show_router_id(vty
, area
);
1474 static void show_ext_sub(struct vty
*vty
, char *name
,
1475 struct isis_ext_subtlvs
*ext
)
1478 char ibuf
[PREFIX2STR_BUFFER
];
1480 sbuf_init(&buf
, NULL
, 0);
1482 if (!ext
|| ext
->status
== EXT_DISABLE
)
1485 vty_out(vty
, "-- MPLS-TE link parameters for %s --\n", name
);
1489 if (IS_SUBTLV(ext
, EXT_ADM_GRP
))
1490 sbuf_push(&buf
, 4, "Administrative Group: 0x%x\n",
1492 if (IS_SUBTLV(ext
, EXT_LLRI
)) {
1493 sbuf_push(&buf
, 4, "Link Local ID: %u\n",
1495 sbuf_push(&buf
, 4, "Link Remote ID: %u\n",
1498 if (IS_SUBTLV(ext
, EXT_LOCAL_ADDR
))
1499 sbuf_push(&buf
, 4, "Local Interface IP Address(es): %pI4\n",
1501 if (IS_SUBTLV(ext
, EXT_NEIGH_ADDR
))
1502 sbuf_push(&buf
, 4, "Remote Interface IP Address(es): %pI4\n",
1504 if (IS_SUBTLV(ext
, EXT_LOCAL_ADDR6
))
1505 sbuf_push(&buf
, 4, "Local Interface IPv6 Address(es): %s\n",
1506 inet_ntop(AF_INET6
, &ext
->local_addr6
, ibuf
,
1507 PREFIX2STR_BUFFER
));
1508 if (IS_SUBTLV(ext
, EXT_NEIGH_ADDR6
))
1509 sbuf_push(&buf
, 4, "Remote Interface IPv6 Address(es): %s\n",
1510 inet_ntop(AF_INET6
, &ext
->local_addr6
, ibuf
,
1511 PREFIX2STR_BUFFER
));
1512 if (IS_SUBTLV(ext
, EXT_MAX_BW
))
1513 sbuf_push(&buf
, 4, "Maximum Bandwidth: %g (Bytes/sec)\n",
1515 if (IS_SUBTLV(ext
, EXT_MAX_RSV_BW
))
1517 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
1519 if (IS_SUBTLV(ext
, EXT_UNRSV_BW
)) {
1520 sbuf_push(&buf
, 4, "Unreserved Bandwidth:\n");
1521 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 2) {
1522 sbuf_push(&buf
, 4 + 2,
1523 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
1524 j
, ext
->unrsv_bw
[j
],
1525 j
+ 1, ext
->unrsv_bw
[j
+ 1]);
1528 if (IS_SUBTLV(ext
, EXT_TE_METRIC
))
1529 sbuf_push(&buf
, 4, "Traffic Engineering Metric: %u\n",
1531 if (IS_SUBTLV(ext
, EXT_RMT_AS
))
1533 "Inter-AS TE Remote AS number: %u\n",
1535 if (IS_SUBTLV(ext
, EXT_RMT_IP
))
1537 "Inter-AS TE Remote ASBR IP address: %pI4\n",
1539 if (IS_SUBTLV(ext
, EXT_DELAY
))
1541 "%s Average Link Delay: %u (micro-sec)\n",
1542 IS_ANORMAL(ext
->delay
) ? "Anomalous" : "Normal",
1544 if (IS_SUBTLV(ext
, EXT_MM_DELAY
)) {
1545 sbuf_push(&buf
, 4, "%s Min/Max Link Delay: %u / %u (micro-sec)\n",
1546 IS_ANORMAL(ext
->min_delay
) ? "Anomalous" : "Normal",
1547 ext
->min_delay
& TE_EXT_MASK
,
1548 ext
->max_delay
& TE_EXT_MASK
);
1550 if (IS_SUBTLV(ext
, EXT_DELAY_VAR
))
1552 "Delay Variation: %u (micro-sec)\n",
1553 ext
->delay_var
& TE_EXT_MASK
);
1554 if (IS_SUBTLV(ext
, EXT_PKT_LOSS
))
1555 sbuf_push(&buf
, 4, "%s Link Packet Loss: %g (%%)\n",
1556 IS_ANORMAL(ext
->pkt_loss
) ? "Anomalous" : "Normal",
1557 (float)((ext
->pkt_loss
& TE_EXT_MASK
)
1559 if (IS_SUBTLV(ext
, EXT_RES_BW
))
1561 "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n",
1563 if (IS_SUBTLV(ext
, EXT_AVA_BW
))
1565 "Unidirectional Available Bandwidth: %g (Bytes/sec)\n",
1567 if (IS_SUBTLV(ext
, EXT_USE_BW
))
1569 "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n",
1572 vty_multiline(vty
, "", "%s", sbuf_buf(&buf
));
1573 vty_out(vty
, "---------------\n\n");
1579 DEFUN (show_isis_mpls_te_interface
,
1580 show_isis_mpls_te_interface_cmd
,
1581 "show " PROTO_NAME
" mpls-te interface [INTERFACE]",
1585 "Interface information\n"
1588 struct listnode
*anode
, *cnode
, *inode
;
1589 struct isis_area
*area
;
1590 struct isis_circuit
*circuit
;
1591 struct interface
*ifp
;
1592 int idx_interface
= 4;
1593 struct isis
*isis
= NULL
;
1596 vty_out(vty
, "IS-IS Routing Process not enabled\n");
1600 if (argc
== idx_interface
) {
1601 /* Show All Interfaces. */
1602 for (ALL_LIST_ELEMENTS_RO(im
->isis
, inode
, isis
)) {
1603 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, anode
,
1606 if (!IS_MPLS_TE(area
->mta
))
1609 vty_out(vty
, "Area %s:\n", area
->area_tag
);
1611 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
,
1614 circuit
->interface
->name
,
1619 /* Interface name is specified. */
1620 ifp
= if_lookup_by_name(argv
[idx_interface
]->arg
, VRF_DEFAULT
);
1622 vty_out(vty
, "No such interface name\n");
1624 circuit
= circuit_scan_by_ifp(ifp
);
1627 "ISIS is not enabled on circuit %s\n",
1630 show_ext_sub(vty
, ifp
->name
, circuit
->ext
);
1638 * Search Vertex in TED that corresponds to the given string that represent
1639 * the ISO system ID in the forms <systemid/hostname>[.<pseudo-id>-<framenent>]
1641 * @param ted Link State Database
1642 * @param id ISO System ID
1643 * @param isis Main reference to the isis daemon
1645 * @return Vertex if found, NULL otherwise
1647 static struct ls_vertex
*vertex_for_arg(struct ls_ted
*ted
, const char *id
,
1650 char sysid
[255] = {0};
1653 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2] = {0};
1654 struct isis_dynhn
*dynhn
;
1661 * extract fragment and pseudo id from the string argv
1663 * (a) <systemid/hostname>.<pseudo-id>-<framenent> or
1664 * (b) <systemid/hostname>.<pseudo-id> or
1665 * (c) <systemid/hostname> or
1666 * Where systemid is in the form:
1669 strlcpy(sysid
, id
, sizeof(sysid
));
1670 if (strlen(id
) > 3) {
1671 pos
= id
+ strlen(id
) - 3;
1672 if (strncmp(pos
, "-", 1) == 0) {
1673 memcpy(number
, ++pos
, 2);
1674 lspid
[ISIS_SYS_ID_LEN
+ 1] =
1675 (uint8_t)strtol((char *)number
, NULL
, 16);
1677 if (strncmp(pos
, ".", 1) != 0)
1680 if (strncmp(pos
, ".", 1) == 0) {
1681 memcpy(number
, ++pos
, 2);
1682 lspid
[ISIS_SYS_ID_LEN
] =
1683 (uint8_t)strtol((char *)number
, NULL
, 16);
1684 sysid
[pos
- id
- 1] = '\0';
1689 * Try to find the lsp-id if the argv
1692 * hostname.<pseudo-id>-<fragment>
1694 if (sysid2buff(lspid
, sysid
)) {
1695 key
= sysid_to_key(lspid
);
1696 } else if ((dynhn
= dynhn_find_by_name(isis
, sysid
))) {
1697 memcpy(lspid
, dynhn
->id
, ISIS_SYS_ID_LEN
);
1698 key
= sysid_to_key(lspid
);
1699 } else if (strncmp(cmd_hostname_get(), sysid
, 15) == 0) {
1700 memcpy(lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1701 key
= sysid_to_key(lspid
);
1707 return ls_find_vertex_by_key(ted
, key
);
1711 * Show Link State Traffic Engineering Database extracted from IS-IS LSP.
1713 * @param vty VTY output console
1714 * @param argv Command line argument
1715 * @param argc Number of command line argument
1716 * @param ted Traffic Engineering Database
1717 * @param isis isis Main reference to the isis daemon
1719 * @return Command Success if OK, Command Warning otherwise
1721 static int show_ted(struct vty
*vty
, struct cmd_token
*argv
[], int argc
,
1722 struct isis_area
*area
, struct isis
*isis
)
1726 struct in_addr ip_addr
;
1727 struct in6_addr ip6_addr
;
1730 struct ls_vertex
*vertex
;
1731 struct ls_edge
*edge
;
1732 struct ls_subnet
*subnet
;
1734 bool detail
= false;
1735 bool uj
= use_json(argc
, argv
);
1736 json_object
*json
= NULL
;
1738 if (!IS_MPLS_TE(area
->mta
) || !area
->mta
->ted
) {
1739 vty_out(vty
, "MPLS-TE is disabled for Area %s\n",
1740 area
->area_tag
? area
->area_tag
: "null");
1744 ted
= area
->mta
->ted
;
1747 json
= json_object_new_object();
1749 vty_out(vty
, "Area %s:\n",
1750 area
->area_tag
? area
->area_tag
: "null");
1752 if (argv
[argc
- 1]->arg
&& strmatch(argv
[argc
- 1]->text
, "detail"))
1756 if (argv_find(argv
, argc
, "vertex", &idx
)) {
1758 id
= argv_find(argv
, argc
, "WORD", &idx
) ? argv
[idx
]->arg
1762 else if (!strncmp(id
, "self", 4))
1765 vertex
= vertex_for_arg(ted
, id
, isis
);
1767 vty_out(vty
, "No vertex found for ID %s\n", id
);
1773 ls_show_vertex(vertex
, vty
, json
, detail
);
1775 ls_show_vertices(ted
, vty
, json
, detail
);
1777 } else if (argv_find(argv
, argc
, "edge", &idx
)) {
1779 if (argv_find(argv
, argc
, "A.B.C.D", &idx
)) {
1780 if (!inet_pton(AF_INET
, argv
[idx
]->arg
, &ip_addr
)) {
1782 "Specified Edge ID %s is invalid\n",
1784 return CMD_WARNING_CONFIG_FAILED
;
1786 /* Get the Edge from the Link State Database */
1787 key
= ((uint64_t)ntohl(ip_addr
.s_addr
)) & 0xffffffff;
1788 edge
= ls_find_edge_by_key(ted
, key
);
1790 vty_out(vty
, "No edge found for ID %pI4\n",
1794 } else if (argv_find(argv
, argc
, "X:X::X:X", &idx
)) {
1795 if (!inet_pton(AF_INET6
, argv
[idx
]->arg
, &ip6_addr
)) {
1797 "Specified Edge ID %s is invalid\n",
1799 return CMD_WARNING_CONFIG_FAILED
;
1801 /* Get the Edge from the Link State Database */
1802 key
= (uint64_t)ntohl(ip6_addr
.s6_addr32
[3])
1803 | ((uint64_t)ntohl(ip6_addr
.s6_addr32
[2]) << 32);
1804 edge
= ls_find_edge_by_key(ted
, key
);
1806 vty_out(vty
, "No edge found for ID %pI6\n",
1814 ls_show_edge(edge
, vty
, json
, detail
);
1816 ls_show_edges(ted
, vty
, json
, detail
);
1818 } else if (argv_find(argv
, argc
, "subnet", &idx
)) {
1820 if (argv_find(argv
, argc
, "A.B.C.D/M", &idx
)) {
1821 if (!str2prefix(argv
[idx
]->arg
, &pref
)) {
1822 vty_out(vty
, "Invalid prefix format %s\n",
1824 return CMD_WARNING_CONFIG_FAILED
;
1826 /* Get the Subnet from the Link State Database */
1827 subnet
= ls_find_subnet(ted
, pref
);
1829 vty_out(vty
, "No subnet found for ID %pFX\n",
1833 } else if (argv_find(argv
, argc
, "X:X::X:X/M", &idx
)) {
1834 if (!str2prefix(argv
[idx
]->arg
, &pref
)) {
1835 vty_out(vty
, "Invalid prefix format %s\n",
1837 return CMD_WARNING_CONFIG_FAILED
;
1839 /* Get the Subnet from the Link State Database */
1840 subnet
= ls_find_subnet(ted
, pref
);
1842 vty_out(vty
, "No subnet found for ID %pFX\n",
1850 ls_show_subnet(subnet
, vty
, json
, detail
);
1852 ls_show_subnets(ted
, vty
, json
, detail
);
1855 /* Show the complete TED */
1856 ls_show_ted(ted
, vty
, json
, detail
);
1860 vty_json(vty
, json
);
1866 * Show ISIS Traffic Engineering Database
1868 * @param vty VTY output console
1869 * @param argv Command line argument
1870 * @param argc Number of command line argument
1871 * @param isis isis Main reference to the isis daemon
1873 * @return Command Success if OK, Command Warning otherwise
1875 static int show_isis_ted(struct vty
*vty
, struct cmd_token
*argv
[], int argc
,
1878 struct listnode
*node
;
1879 struct isis_area
*area
;
1882 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
, area
)) {
1883 rc
= show_ted(vty
, argv
, argc
, area
, isis
);
1884 if (rc
!= CMD_SUCCESS
)
1890 DEFUN(show_isis_mpls_te_db
,
1891 show_isis_mpls_te_db_cmd
,
1892 "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]",
1893 SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
1896 "MPLS-TE database\n"
1898 "MPLS-TE Vertex ID (as an ISO ID, hostname or \"self\")\n"
1900 "MPLS-TE Edge ID (as an IPv4 address)\n"
1901 "MPLS-TE Edge ID (as an IPv6 address)\n"
1903 "MPLS-TE Subnet ID (as an IPv4 prefix)\n"
1904 "MPLS-TE Subnet ID (as an IPv6 prefix)\n"
1905 "Detailed information\n"
1909 const char *vrf_name
= VRF_DEFAULT_NAME
;
1910 bool all_vrf
= false;
1911 struct listnode
*node
;
1913 int rc
= CMD_WARNING
;
1915 ISIS_FIND_VRF_ARGS(argv
, argc
, idx_vrf
, vrf_name
, all_vrf
);
1918 for (ALL_LIST_ELEMENTS_RO(im
->isis
, node
, isis
)) {
1919 rc
= show_isis_ted(vty
, argv
, argc
, isis
);
1920 if (rc
!= CMD_SUCCESS
)
1925 isis
= isis_lookup_by_vrfname(vrf_name
);
1927 rc
= show_isis_ted(vty
, argv
, argc
, isis
);
1933 #endif /* #ifndef FRABRICD */
1935 /* Initialize MPLS_TE */
1936 void isis_mpls_te_init(void)
1939 /* Register Circuit and Adjacency hook */
1940 hook_register(isis_if_new_hook
, isis_mpls_te_update
);
1941 hook_register(isis_adj_ip_enabled_hook
, isis_mpls_te_adj_ip_enabled
);
1942 hook_register(isis_adj_ip_disabled_hook
, isis_mpls_te_adj_ip_disabled
);
1945 /* Register new VTY commands */
1946 install_element(VIEW_NODE
, &show_isis_mpls_te_router_cmd
);
1947 install_element(VIEW_NODE
, &show_isis_mpls_te_interface_cmd
);
1948 install_element(VIEW_NODE
, &show_isis_mpls_te_db_cmd
);