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 /*------------------------------------------------------------------------*
70 * Following are control functions for MPLS-TE parameters management.
71 *------------------------------------------------------------------------*/
74 * Create MPLS Traffic Engineering structure which belongs to given area.
76 * @param area IS-IS Area
78 void isis_mpls_te_create(struct isis_area
*area
)
80 struct listnode
*node
;
81 struct isis_circuit
*circuit
;
86 if (area
->mta
== NULL
) {
88 struct mpls_te_area
*new;
90 zlog_debug("ISIS-TE(%s): Initialize MPLS Traffic Engineering",
93 new = XCALLOC(MTYPE_ISIS_MPLS_TE
, sizeof(struct mpls_te_area
));
95 /* Initialize MPLS_TE structure */
99 new->interas_areaid
.s_addr
= 0;
100 new->router_id
.s_addr
= 0;
101 new->ted
= ls_ted_new(1, "ISIS", 0);
103 zlog_warn("Unable to create Link State Data Base");
107 area
->mta
->status
= enable
;
110 /* Initialize Link State Database */
112 isis_te_init_ted(area
);
114 /* Update Extended TLVs according to Interface link parameters */
115 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
))
116 isis_link_params_update(circuit
, circuit
->interface
);
120 * Disable MPLS Traffic Engineering structure which belongs to given area.
122 * @param area IS-IS Area
124 void isis_mpls_te_disable(struct isis_area
*area
)
126 struct listnode
*node
;
127 struct isis_circuit
*circuit
;
132 area
->mta
->status
= disable
;
134 /* Remove Link State Database */
135 ls_ted_del_all(&area
->mta
->ted
);
137 /* Disable Extended SubTLVs on all circuit */
138 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
139 if (!IS_EXT_TE(circuit
->ext
))
142 /* disable MPLS_TE Circuit keeping SR one's */
143 if (IS_SUBTLV(circuit
->ext
, EXT_ADJ_SID
))
144 circuit
->ext
->status
= EXT_ADJ_SID
;
145 else if (IS_SUBTLV(circuit
->ext
, EXT_LAN_ADJ_SID
))
146 circuit
->ext
->status
= EXT_LAN_ADJ_SID
;
148 circuit
->ext
->status
= 0;
152 void isis_mpls_te_term(struct isis_area
*area
)
154 struct listnode
*node
;
155 struct isis_circuit
*circuit
;
160 zlog_info("TE(%s): Terminate MPLS TE", __func__
);
161 /* Remove Link State Database */
162 ls_ted_del_all(&area
->mta
->ted
);
164 /* Remove Extended SubTLVs */
165 zlog_info(" |- Remove Extended SubTLVS for all circuit");
166 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
167 zlog_info(" |- Call isis_del_ext_subtlvs()");
168 isis_del_ext_subtlvs(circuit
->ext
);
172 zlog_info(" |- Free MTA structure at %p", area
->mta
);
173 XFREE(MTYPE_ISIS_MPLS_TE
, area
->mta
);
176 /* Main initialization / update function of the MPLS TE Circuit context */
177 /* Call when interface TE Link parameters are modified */
178 void isis_link_params_update(struct isis_circuit
*circuit
,
179 struct interface
*ifp
)
182 struct prefix_ipv4
*addr
;
183 struct prefix_ipv6
*addr6
;
184 struct isis_ext_subtlvs
*ext
;
186 /* Check if TE is enable or not */
187 if (!circuit
->area
|| !IS_MPLS_TE(circuit
->area
->mta
))
191 if ((ifp
== NULL
) || (circuit
->state
!= C_STATE_UP
))
194 te_debug("ISIS-TE(%s): Update circuit parameters for interface %s",
195 circuit
->area
->area_tag
, ifp
->name
);
197 /* Check if MPLS TE Circuit context has not been already created */
198 if (circuit
->ext
== NULL
) {
199 circuit
->ext
= isis_alloc_ext_subtlvs();
200 te_debug(" |- Allocated new Ext-subTLVs for interface %s",
206 /* Fulfill Extended subTLVs from interface link parameters */
207 if (HAS_LINK_PARAMS(ifp
)) {
209 if (IS_PARAM_SET(ifp
->link_params
, LP_ADM_GRP
)) {
210 ext
->adm_group
= ifp
->link_params
->admin_grp
;
211 SET_SUBTLV(ext
, EXT_ADM_GRP
);
213 UNSET_SUBTLV(ext
, EXT_ADM_GRP
);
215 /* If known, register local IPv4 addr from ip_addr list */
216 if (listcount(circuit
->ip_addrs
) != 0) {
217 addr
= (struct prefix_ipv4
*)listgetdata(
218 (struct listnode
*)listhead(circuit
->ip_addrs
));
219 IPV4_ADDR_COPY(&ext
->local_addr
, &addr
->prefix
);
220 SET_SUBTLV(ext
, EXT_LOCAL_ADDR
);
222 UNSET_SUBTLV(ext
, EXT_LOCAL_ADDR
);
224 /* If known, register local IPv6 addr from ip_addr list */
225 if (listcount(circuit
->ipv6_non_link
) != 0) {
226 addr6
= (struct prefix_ipv6
*)listgetdata(
227 (struct listnode
*)listhead(
228 circuit
->ipv6_non_link
));
229 IPV6_ADDR_COPY(&ext
->local_addr6
, &addr6
->prefix
);
230 SET_SUBTLV(ext
, EXT_LOCAL_ADDR6
);
232 UNSET_SUBTLV(ext
, EXT_LOCAL_ADDR6
);
235 * Remote IPv4 and IPv6 addresses are now added in
236 * isis_mpls_te_adj_ip_enabled() to get the right IP address
237 * in particular for IPv6 to get the global IPv6 address and
238 * not the link-local IPv6 address.
241 if (IS_PARAM_SET(ifp
->link_params
, LP_MAX_BW
)) {
242 ext
->max_bw
= ifp
->link_params
->max_bw
;
243 SET_SUBTLV(ext
, EXT_MAX_BW
);
245 UNSET_SUBTLV(ext
, EXT_MAX_BW
);
247 if (IS_PARAM_SET(ifp
->link_params
, LP_MAX_RSV_BW
)) {
248 ext
->max_rsv_bw
= ifp
->link_params
->max_rsv_bw
;
249 SET_SUBTLV(ext
, EXT_MAX_RSV_BW
);
251 UNSET_SUBTLV(ext
, EXT_MAX_RSV_BW
);
253 if (IS_PARAM_SET(ifp
->link_params
, LP_UNRSV_BW
)) {
254 for (i
= 0; i
< MAX_CLASS_TYPE
; i
++)
256 ifp
->link_params
->unrsv_bw
[i
];
257 SET_SUBTLV(ext
, EXT_UNRSV_BW
);
259 UNSET_SUBTLV(ext
, EXT_UNRSV_BW
);
261 if (IS_PARAM_SET(ifp
->link_params
, LP_TE_METRIC
)) {
262 ext
->te_metric
= ifp
->link_params
->te_metric
;
263 SET_SUBTLV(ext
, EXT_TE_METRIC
);
265 UNSET_SUBTLV(ext
, EXT_TE_METRIC
);
267 /* TE metric extensions */
268 if (IS_PARAM_SET(ifp
->link_params
, LP_DELAY
)) {
269 ext
->delay
= ifp
->link_params
->av_delay
;
270 SET_SUBTLV(ext
, EXT_DELAY
);
272 UNSET_SUBTLV(ext
, EXT_DELAY
);
274 if (IS_PARAM_SET(ifp
->link_params
, LP_MM_DELAY
)) {
275 ext
->min_delay
= ifp
->link_params
->min_delay
;
276 ext
->max_delay
= ifp
->link_params
->max_delay
;
277 SET_SUBTLV(ext
, EXT_MM_DELAY
);
279 UNSET_SUBTLV(ext
, EXT_MM_DELAY
);
281 if (IS_PARAM_SET(ifp
->link_params
, LP_DELAY_VAR
)) {
282 ext
->delay_var
= ifp
->link_params
->delay_var
;
283 SET_SUBTLV(ext
, EXT_DELAY_VAR
);
285 UNSET_SUBTLV(ext
, EXT_DELAY_VAR
);
287 if (IS_PARAM_SET(ifp
->link_params
, LP_PKT_LOSS
)) {
288 ext
->pkt_loss
= ifp
->link_params
->pkt_loss
;
289 SET_SUBTLV(ext
, EXT_PKT_LOSS
);
291 UNSET_SUBTLV(ext
, EXT_PKT_LOSS
);
293 if (IS_PARAM_SET(ifp
->link_params
, LP_RES_BW
)) {
294 ext
->res_bw
= ifp
->link_params
->res_bw
;
295 SET_SUBTLV(ext
, EXT_RES_BW
);
297 UNSET_SUBTLV(ext
, EXT_RES_BW
);
299 if (IS_PARAM_SET(ifp
->link_params
, LP_AVA_BW
)) {
300 ext
->ava_bw
= ifp
->link_params
->ava_bw
;
301 SET_SUBTLV(ext
, EXT_AVA_BW
);
303 UNSET_SUBTLV(ext
, EXT_AVA_BW
);
305 if (IS_PARAM_SET(ifp
->link_params
, LP_USE_BW
)) {
306 ext
->use_bw
= ifp
->link_params
->use_bw
;
307 SET_SUBTLV(ext
, EXT_USE_BW
);
309 UNSET_SUBTLV(ext
, EXT_USE_BW
);
312 if (IS_PARAM_SET(ifp
->link_params
, LP_RMT_AS
)) {
313 ext
->remote_as
= ifp
->link_params
->rmt_as
;
314 ext
->remote_ip
= ifp
->link_params
->rmt_ip
;
315 SET_SUBTLV(ext
, EXT_RMT_AS
);
316 SET_SUBTLV(ext
, EXT_RMT_IP
);
318 /* reset inter-as TE params */
319 UNSET_SUBTLV(ext
, EXT_RMT_AS
);
320 UNSET_SUBTLV(ext
, EXT_RMT_IP
);
322 te_debug(" |- New MPLS-TE link parameters status 0x%x",
325 te_debug(" |- Reset Extended subTLVs status 0x%x",
327 /* Reset TE subTLVs keeping SR one's */
328 if (IS_SUBTLV(ext
, EXT_ADJ_SID
))
329 ext
->status
= EXT_ADJ_SID
;
330 else if (IS_SUBTLV(ext
, EXT_LAN_ADJ_SID
))
331 ext
->status
= EXT_LAN_ADJ_SID
;
339 static int isis_mpls_te_adj_ip_enabled(struct isis_adjacency
*adj
, int family
,
342 struct isis_circuit
*circuit
;
343 struct isis_ext_subtlvs
*ext
;
346 if (!adj
|| !adj
->circuit
)
349 circuit
= adj
->circuit
;
351 /* Check that MPLS TE is enabled */
352 if (!IS_MPLS_TE(circuit
->area
->mta
) || !circuit
->ext
)
357 /* Determine nexthop IP address */
360 if (!circuit
->ip_router
|| !adj
->ipv4_address_count
)
361 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR
);
363 IPV4_ADDR_COPY(&ext
->neigh_addr
,
364 &adj
->ipv4_addresses
[0]);
365 SET_SUBTLV(ext
, EXT_NEIGH_ADDR
);
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
);
385 lsp_regenerate_schedule(circuit
->area
, circuit
->is_type
, 0);
390 static int isis_mpls_te_adj_ip_disabled(struct isis_adjacency
*adj
, int family
,
393 struct isis_circuit
*circuit
;
394 struct isis_ext_subtlvs
*ext
;
397 if (!adj
|| !adj
->circuit
|| !adj
->circuit
->ext
)
400 circuit
= adj
->circuit
;
402 /* Check that MPLS TE is enabled */
403 if (!IS_MPLS_TE(circuit
->area
->mta
) || !circuit
->ext
)
408 /* Update MPLS TE IP address parameters if possible */
409 if (!IS_MPLS_TE(circuit
->area
->mta
) || !IS_EXT_TE(ext
))
412 /* Determine nexthop IP address */
415 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR
);
419 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR6
);
426 lsp_regenerate_schedule(circuit
->area
, circuit
->is_type
, 0);
431 int isis_mpls_te_update(struct interface
*ifp
)
433 struct isis_circuit
*circuit
;
440 /* Get circuit context from interface */
441 circuit
= circuit_scan_by_ifp(ifp
);
445 /* Update TE TLVs ... */
446 isis_link_params_update(circuit
, ifp
);
449 if (circuit
->area
&& IS_MPLS_TE(circuit
->area
->mta
))
450 lsp_regenerate_schedule(circuit
->area
, circuit
->is_type
, 0);
458 * Export Link State information to consumer daemon through ZAPI Link State
461 * @param type Type of Link State Element i.e. Vertex, Edge or Subnet
462 * @param link_state Pointer to Link State Vertex, Edge or Subnet
464 * @return 0 if success, -1 otherwise
466 static int isis_te_export(uint8_t type
, void *link_state
)
468 struct ls_message msg
= {};
472 case LS_MSG_TYPE_NODE
:
473 ls_vertex2msg(&msg
, (struct ls_vertex
*)link_state
);
474 rc
= ls_send_msg(zclient
, &msg
, NULL
);
476 case LS_MSG_TYPE_ATTRIBUTES
:
477 ls_edge2msg(&msg
, (struct ls_edge
*)link_state
);
478 rc
= ls_send_msg(zclient
, &msg
, NULL
);
480 case LS_MSG_TYPE_PREFIX
:
481 ls_subnet2msg(&msg
, (struct ls_subnet
*)link_state
);
482 rc
= ls_send_msg(zclient
, &msg
, NULL
);
493 * Parse LSP and build corresponding vertex. If vertex doesn't exist in the
494 * Link State Database it is created otherwise updated.
496 * @param ted Traffic Engineering Link State Database
497 * @param lsp IS-IS Link State PDU
499 * @return Link State Vertex or NULL in case of error
501 static struct ls_vertex
*lsp_to_vertex(struct ls_ted
*ted
, struct isis_lsp
*lsp
)
503 struct ls_vertex
*vertex
= NULL
;
504 struct ls_node
*old
, lnode
= {};
505 struct isis_tlvs
*tlvs
;
506 const struct in_addr inaddr_any
= {.s_addr
= INADDR_ANY
};
512 /* Compute Link State Node ID from IS-IS sysID ... */
513 if (lsp
->level
== ISIS_LEVEL1
)
514 lnode
.adv
.origin
= ISIS_L1
;
516 lnode
.adv
.origin
= ISIS_L2
;
517 memcpy(&lnode
.adv
.id
.iso
.sys_id
, &lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
);
518 lnode
.adv
.id
.iso
.level
= lsp
->level
;
519 /* ... and search the corresponding vertex */
520 vertex
= ls_find_vertex_by_id(ted
, lnode
.adv
);
521 /* Create a new one if not found */
523 old
= ls_node_new(lnode
.adv
, inaddr_any
, in6addr_any
);
524 old
->type
= STANDARD
;
525 vertex
= ls_vertex_add(ted
, old
);
528 te_debug(" |- %s Vertex (%" PRIu64
") for node %s",
529 vertex
->status
== NEW
? "Create" : "Found", vertex
->key
,
530 print_sys_hostname(old
->adv
.id
.iso
.sys_id
));
532 /* Fulfill Link State Node information */
535 if (tlvs
->te_router_id
) {
536 IPV4_ADDR_COPY(&lnode
.router_id
, tlvs
->te_router_id
);
537 SET_FLAG(lnode
.flags
, LS_NODE_ROUTER_ID
);
539 if (tlvs
->te_router_id_ipv6
) {
540 IPV6_ADDR_COPY(&lnode
.router_id6
,
541 tlvs
->te_router_id_ipv6
);
542 SET_FLAG(lnode
.flags
, LS_NODE_ROUTER_ID6
);
544 if (tlvs
->hostname
) {
545 strlcpy(lnode
.name
, tlvs
->hostname
, MAX_NAME_LENGTH
);
546 SET_FLAG(lnode
.flags
, LS_NODE_NAME
);
548 if (tlvs
->router_cap
) {
549 struct isis_router_cap
*cap
= tlvs
->router_cap
;
551 if (cap
->srgb
.lower_bound
!= 0
552 && cap
->srgb
.range_size
!= 0) {
553 SET_FLAG(lnode
.flags
, LS_NODE_SR
);
554 lnode
.srgb
.flag
= cap
->srgb
.flags
;
555 lnode
.srgb
.lower_bound
= cap
->srgb
.lower_bound
;
556 lnode
.srgb
.range_size
= cap
->srgb
.range_size
;
557 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++)
558 lnode
.algo
[i
] = cap
->algo
[i
];
561 if (cap
->srlb
.lower_bound
!= 0
562 && cap
->srlb
.range_size
!= 0) {
563 lnode
.srlb
.lower_bound
= cap
->srlb
.lower_bound
;
564 lnode
.srlb
.range_size
= cap
->srlb
.range_size
;
565 SET_FLAG(lnode
.flags
, LS_NODE_SRLB
);
568 lnode
.msd
= cap
->msd
;
569 SET_FLAG(lnode
.flags
, LS_NODE_MSD
);
574 /* Update Link State Node information */
575 if (!ls_node_same(old
, &lnode
)) {
576 te_debug(" |- Update Link State Node information");
577 memcpy(old
, &lnode
, sizeof(struct ls_node
));
578 if (vertex
->status
!= NEW
)
579 vertex
->status
= UPDATE
;
582 /* Set self TED vertex if LSP corresponds to the own router */
590 * Get Link State Edge from Link State Attributes in TE Database.
591 * Edge structure is dynamically allocated and fulfill with Link State
592 * Attributes if not found.
594 * @param ted Link State Database
595 * @param attr Link State Attributes
597 * @return New Link State Edge if success, NULL otherwise
599 static struct ls_edge
*get_edge(struct ls_ted
*ted
, struct ls_attributes
*attr
)
601 struct ls_edge
*edge
;
602 struct ls_standard
*std
;
605 /* Check parameters */
609 std
= &attr
->standard
;
611 /* Compute keys in function of local address (IPv4/v6) or identifier */
612 if (CHECK_FLAG(attr
->flags
, LS_ATTR_LOCAL_ADDR
))
613 key
= ((uint64_t)ntohl(std
->local
.s_addr
)) & 0xffffffff;
614 else if (CHECK_FLAG(attr
->flags
, LS_ATTR_LOCAL_ADDR6
))
615 key
= ((uint64_t)ntohl(std
->local6
.s6_addr32
[2]) << 32
616 | (uint64_t)ntohl(std
->local6
.s6_addr32
[3]));
617 else if (CHECK_FLAG(attr
->flags
, LS_ATTR_LOCAL_ID
))
618 key
= ((uint64_t)std
->remote_id
<< 32)
619 | (((uint64_t)std
->local_id
) & 0xffffffff);
623 /* Stop here if we don't got a valid key */
627 /* Get corresponding Edge by key from Link State Data Base */
628 edge
= ls_find_edge_by_key(ted
, key
);
630 /* and create new one if not exist */
632 edge
= ls_edge_add(ted
, attr
);
634 * Edge could be Null if no local ID is found in Attributes.
635 * Stop the processing as without any local ID it is not
636 * possible to store Edge in the TED.
642 if (CHECK_FLAG(edge
->attributes
->flags
, LS_ATTR_LOCAL_ADDR
))
643 te_debug(" |- %s Edge (%" PRIu64
644 ") from Extended Reach. %pI4",
645 edge
->status
== NEW
? "Create" : "Found", edge
->key
,
646 &attr
->standard
.local
);
647 else if (CHECK_FLAG(edge
->attributes
->flags
, LS_ATTR_LOCAL_ADDR6
))
648 te_debug(" |- %s Edge (%" PRIu64
649 ") from Extended Reach. %pI6",
650 edge
->status
== NEW
? "Create" : "Found", edge
->key
,
651 &attr
->standard
.local6
);
653 te_debug(" |- %s Edge (%" PRIu64
")",
654 edge
->status
== NEW
? "Create" : "Found", edge
->key
);
660 * Get Link State Attributes from IS-IS Sub-TLVs. Structure is dynamically
661 * allocated and should be free once not use anymore.
663 * @param adv Link State Node ID
664 * @param tlvs IS-IS Sub TLVs
666 * @return New Link State attributes if success, NULL otherwise
668 static struct ls_attributes
*get_attributes(struct ls_node_id adv
,
669 struct isis_ext_subtlvs
*tlvs
)
671 struct ls_attributes
*attr
;
672 struct in_addr local
= {.s_addr
= INADDR_ANY
};
673 struct in6_addr local6
= in6addr_any
;
674 uint32_t local_id
= 0;
676 /* Got Local identifier */
677 if (CHECK_FLAG(tlvs
->status
, EXT_LOCAL_ADDR
))
678 local
.s_addr
= tlvs
->local_addr
.s_addr
;
680 if (CHECK_FLAG(tlvs
->status
, EXT_LOCAL_ADDR6
))
681 memcpy(&local6
, &tlvs
->local_addr6
, IPV6_MAX_BYTELEN
);
683 if (CHECK_FLAG(tlvs
->status
, EXT_LLRI
))
684 local_id
= tlvs
->local_llri
;
686 /* Create LS Attributes */
687 attr
= ls_attributes_new(adv
, local
, local6
, local_id
);
691 /* Browse sub-TLV and fulfill Link State Attributes */
692 if (CHECK_FLAG(tlvs
->status
, EXT_ADM_GRP
)) {
693 attr
->standard
.admin_group
= tlvs
->adm_group
;
694 SET_FLAG(attr
->flags
, LS_ATTR_ADM_GRP
);
696 if (CHECK_FLAG(tlvs
->status
, EXT_LLRI
)) {
697 attr
->standard
.local_id
= tlvs
->local_llri
;
698 attr
->standard
.remote_id
= tlvs
->remote_llri
;
699 SET_FLAG(attr
->flags
, LS_ATTR_LOCAL_ID
);
700 SET_FLAG(attr
->flags
, LS_ATTR_NEIGH_ID
);
702 if (CHECK_FLAG(tlvs
->status
, EXT_NEIGH_ADDR
)) {
703 attr
->standard
.remote
.s_addr
= tlvs
->neigh_addr
.s_addr
;
704 SET_FLAG(attr
->flags
, LS_ATTR_NEIGH_ADDR
);
706 if (CHECK_FLAG(tlvs
->status
, EXT_NEIGH_ADDR6
)) {
707 memcpy(&attr
->standard
.remote6
, &tlvs
->neigh_addr6
,
709 SET_FLAG(attr
->flags
, LS_ATTR_NEIGH_ADDR6
);
711 if (CHECK_FLAG(tlvs
->status
, EXT_MAX_BW
)) {
712 attr
->standard
.max_bw
= tlvs
->max_bw
;
713 SET_FLAG(attr
->flags
, LS_ATTR_MAX_BW
);
715 if (CHECK_FLAG(tlvs
->status
, EXT_MAX_RSV_BW
)) {
716 attr
->standard
.max_rsv_bw
= tlvs
->max_rsv_bw
;
717 SET_FLAG(attr
->flags
, LS_ATTR_MAX_RSV_BW
);
719 if (CHECK_FLAG(tlvs
->status
, EXT_UNRSV_BW
)) {
720 memcpy(&attr
->standard
.unrsv_bw
, tlvs
->unrsv_bw
,
721 ISIS_SUBTLV_UNRSV_BW_SIZE
);
722 SET_FLAG(attr
->flags
, LS_ATTR_UNRSV_BW
);
724 if (CHECK_FLAG(tlvs
->status
, EXT_TE_METRIC
)) {
725 attr
->standard
.te_metric
= tlvs
->te_metric
;
726 SET_FLAG(attr
->flags
, LS_ATTR_TE_METRIC
);
728 if (CHECK_FLAG(tlvs
->status
, EXT_RMT_AS
)) {
729 attr
->standard
.remote_as
= tlvs
->remote_as
;
730 SET_FLAG(attr
->flags
, LS_ATTR_REMOTE_AS
);
732 if (CHECK_FLAG(tlvs
->status
, EXT_RMT_IP
)) {
733 attr
->standard
.remote_addr
= tlvs
->remote_ip
;
734 SET_FLAG(attr
->flags
, LS_ATTR_REMOTE_ADDR
);
736 if (CHECK_FLAG(tlvs
->status
, EXT_DELAY
)) {
737 attr
->extended
.delay
= tlvs
->delay
;
738 SET_FLAG(attr
->flags
, LS_ATTR_DELAY
);
740 if (CHECK_FLAG(tlvs
->status
, EXT_MM_DELAY
)) {
741 attr
->extended
.min_delay
= tlvs
->min_delay
;
742 attr
->extended
.max_delay
= tlvs
->max_delay
;
743 SET_FLAG(attr
->flags
, LS_ATTR_MIN_MAX_DELAY
);
745 if (CHECK_FLAG(tlvs
->status
, EXT_DELAY_VAR
)) {
746 attr
->extended
.jitter
= tlvs
->delay_var
;
747 SET_FLAG(attr
->flags
, LS_ATTR_JITTER
);
749 if (CHECK_FLAG(tlvs
->status
, EXT_PKT_LOSS
)) {
750 attr
->extended
.pkt_loss
= tlvs
->pkt_loss
;
751 SET_FLAG(attr
->flags
, LS_ATTR_PACKET_LOSS
);
753 if (CHECK_FLAG(tlvs
->status
, EXT_AVA_BW
)) {
754 attr
->extended
.ava_bw
= tlvs
->ava_bw
;
755 SET_FLAG(attr
->flags
, LS_ATTR_AVA_BW
);
757 if (CHECK_FLAG(tlvs
->status
, EXT_RES_BW
)) {
758 attr
->extended
.rsv_bw
= tlvs
->res_bw
;
759 SET_FLAG(attr
->flags
, LS_ATTR_RSV_BW
);
761 if (CHECK_FLAG(tlvs
->status
, EXT_USE_BW
)) {
762 attr
->extended
.used_bw
= tlvs
->use_bw
;
763 SET_FLAG(attr
->flags
, LS_ATTR_USE_BW
);
765 if (CHECK_FLAG(tlvs
->status
, EXT_ADJ_SID
)) {
766 struct isis_adj_sid
*adj
=
767 (struct isis_adj_sid
*)tlvs
->adj_sid
.head
;
769 for (; adj
; adj
= adj
->next
) {
770 i
= adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
? 1 : 0;
771 i
+= adj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
? 2 : 0;
772 attr
->adj_sid
[i
].flags
= adj
->flags
;
773 attr
->adj_sid
[i
].weight
= adj
->weight
;
774 attr
->adj_sid
[i
].sid
= adj
->sid
;
777 SET_FLAG(attr
->flags
, LS_ATTR_ADJ_SID
);
780 SET_FLAG(attr
->flags
, LS_ATTR_BCK_ADJ_SID
);
783 SET_FLAG(attr
->flags
, LS_ATTR_ADJ_SID6
);
786 SET_FLAG(attr
->flags
, LS_ATTR_BCK_ADJ_SID6
);
791 if (CHECK_FLAG(tlvs
->status
, EXT_LAN_ADJ_SID
)) {
792 struct isis_lan_adj_sid
*ladj
=
793 (struct isis_lan_adj_sid
*)tlvs
->lan_sid
.head
;
795 for (; ladj
; ladj
= ladj
->next
) {
796 i
= ladj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_BFLG
? 1 : 0;
797 i
+= ladj
->flags
& EXT_SUBTLV_LINK_ADJ_SID_FFLG
? 2 : 0;
798 attr
->adj_sid
[i
].flags
= ladj
->flags
;
799 attr
->adj_sid
[i
].weight
= ladj
->weight
;
800 attr
->adj_sid
[i
].sid
= ladj
->sid
;
801 memcpy(&attr
->adj_sid
[i
].neighbor
.sysid
,
802 &ladj
->neighbor_id
, ISIS_SYS_ID_LEN
);
805 SET_FLAG(attr
->flags
, LS_ATTR_ADJ_SID
);
808 SET_FLAG(attr
->flags
, LS_ATTR_BCK_ADJ_SID
);
811 SET_FLAG(attr
->flags
, LS_ATTR_ADJ_SID6
);
814 SET_FLAG(attr
->flags
, LS_ATTR_BCK_ADJ_SID6
);
824 * Parse Extended Reachability TLVs and create or update the corresponding
825 * Link State Edge and Attributes. Vertex connections are also updated if
826 * needed based on the remote IP address of the Edge and existing reverse Edge.
828 * @param id ID of Extended IS
829 * @param metric Metric of the link
830 * @param old_metric Boolean that indicate if it is an old metric (no TE)
831 * @param tlvs SubTlvs that contains TE information
832 * @param arg IS-IS TE argument (TED, Vertex, and export indication)
834 * @return 0 if success, -1 otherwise
836 static int lsp_to_edge_cb(const uint8_t *id
, uint32_t metric
, bool old_metric
,
837 struct isis_ext_subtlvs
*tlvs
, void *arg
)
839 struct isis_te_args
*args
= (struct isis_te_args
*)arg
;
840 struct ls_vertex
*vertex
;
841 struct ls_edge
*edge
, *dst
;
842 struct ls_attributes
*attr
;
844 te_debug(" |- Process Extended IS for %s", sysid_print(id
));
846 /* Check parameters */
847 if (old_metric
|| !args
|| !tlvs
)
848 return LSP_ITER_CONTINUE
;
850 /* Initialize Link State Attributes */
851 vertex
= args
->vertex
;
852 attr
= get_attributes(vertex
->node
->adv
, tlvs
);
854 * Attributes may be Null if no local ID has been found in the LSP.
855 * Stop processing here as without any local ID it is not possible to
856 * create corresponding Edge in the TED.
859 return LSP_ITER_CONTINUE
;
861 attr
->metric
= metric
;
862 SET_FLAG(attr
->flags
, LS_ATTR_METRIC
);
864 /* Get corresponding Edge from Link State Data Base */
865 edge
= get_edge(args
->ted
, attr
);
867 * Edge could be Null if no local ID has been found in Attributes.
868 * Stop processing here as without any local ID it is not possible to
869 * create corresponding Edge in the TED.
872 ls_attributes_del(attr
);
873 return LSP_ITER_CONTINUE
;
876 /* Update Attribute fields if there are different */
877 if (edge
->status
!= NEW
) {
878 if (!ls_attributes_same(edge
->attributes
, attr
)) {
879 te_debug(" |- Update Edge Attributes information");
880 ls_attributes_del(edge
->attributes
);
881 edge
->attributes
= attr
;
882 edge
->status
= UPDATE
;
884 if (edge
->attributes
!= attr
)
885 ls_attributes_del(attr
);
890 /* Try to update remote Link from remote address or reachability ID */
891 te_debug(" |- Link Edge (%" PRIu64
") to destination vertex (%s)",
892 edge
->key
, print_sys_hostname(id
));
893 dst
= ls_find_edge_by_destination(args
->ted
, edge
->attributes
);
895 /* Attach remote link if not set */
896 if (edge
->source
&& dst
->destination
== NULL
) {
897 vertex
= edge
->source
;
898 if (vertex
->incoming_edges
)
899 listnode_add_sort_nodup(vertex
->incoming_edges
,
901 dst
->destination
= vertex
;
903 /* and destination vertex to this edge if not set */
904 if (dst
->source
&& edge
->destination
== NULL
) {
905 vertex
= dst
->source
;
906 if (vertex
->incoming_edges
)
907 listnode_add_sort_nodup(vertex
->incoming_edges
,
909 edge
->destination
= vertex
;
912 /* Search dst. Vertex by Extended Reach. ID if not found */
913 if (edge
->destination
== NULL
) {
914 vertex
= ls_find_vertex_by_key(args
->ted
,
916 if (vertex
&& vertex
->incoming_edges
)
917 listnode_add_sort_nodup(vertex
->incoming_edges
,
919 edge
->destination
= vertex
;
923 /* Update status and Export Link State Edge if needed */
924 if (edge
->status
!= SYNC
) {
926 isis_te_export(LS_MSG_TYPE_ATTRIBUTES
, edge
);
930 return LSP_ITER_CONTINUE
;
934 * Parse Extended IP Reachability or MT IPv6 Reachability TLVs and create or
935 * update the corresponding Link State Subnet and Prefix.
937 * @param prefix Prefix associated to this subnet
938 * @param metric Metric of this prefix
939 * @param external Boolean to indicate if the prefix is external
940 * @param subtlvs Subtlvs if any (mostly Segment Routing ID)
941 * @param arg IS-IS TE argument (TED, Vertex, and export indication)
943 * @return 0 if success, -1 otherwise
945 static int lsp_to_subnet_cb(const struct prefix
*prefix
, uint32_t metric
,
946 bool external
, struct isis_subtlvs
*subtlvs
,
949 struct isis_te_args
*args
= (struct isis_te_args
*)arg
;
950 struct ls_vertex
*vertex
;
951 struct ls_subnet
*subnet
;
952 struct ls_prefix
*ls_pref
;
953 struct listnode
*node
;
954 struct ls_edge
*edge
;
955 struct ls_standard
*std
= NULL
;
959 if (!args
|| !prefix
)
960 return LSP_ITER_CONTINUE
;
962 te_debug(" |- Process Extended %s Reachability %pFX",
963 prefix
->family
== AF_INET
? "IP" : "IPv6", prefix
);
965 vertex
= args
->vertex
;
968 * Prefix with mask different from /32 or /128 are advertised by at
969 * least 2 nodes. To avoid subnet attached to undetermined vertex, and
970 * gives the possibility to send the information to client e.g. BGP for
971 * Link State advertisement, we adjust the prefix with the corresponding
972 * IP address of the belonging interface when it is available. Other
973 * prefixes are kept unchanged.
975 if (prefix
->family
== AF_INET
&& prefix
->prefixlen
< IPV4_MAX_BITLEN
) {
977 for (ALL_LIST_ELEMENTS_RO(vertex
->outgoing_edges
, node
, edge
)) {
978 if (!CHECK_FLAG(edge
->attributes
->flags
,
982 p
.u
.prefix4
= edge
->attributes
->standard
.local
;
984 p
.prefixlen
= prefix
->prefixlen
;
985 apply_mask_ipv4((struct prefix_ipv4
*)&p
);
986 if (IPV4_ADDR_SAME(&p
.u
.prefix4
, &prefix
->u
.prefix4
)) {
987 std
= &edge
->attributes
->standard
;
992 p
.u
.prefix4
= std
->local
;
994 } else if (prefix
->family
== AF_INET6
995 && prefix
->prefixlen
< IPV6_MAX_BITLEN
) {
997 for (ALL_LIST_ELEMENTS_RO(vertex
->outgoing_edges
, node
, edge
)) {
998 if (!CHECK_FLAG(edge
->attributes
->flags
,
999 LS_ATTR_LOCAL_ADDR6
))
1002 p
.u
.prefix6
= edge
->attributes
->standard
.local6
;
1003 p
.family
= AF_INET6
;
1004 p
.prefixlen
= prefix
->prefixlen
;
1005 apply_mask_ipv6((struct prefix_ipv6
*)&p
);
1006 if (IPV6_ADDR_SAME(&p
.u
.prefix6
, &prefix
->u
.prefix6
)) {
1007 std
= &edge
->attributes
->standard
;
1012 p
.u
.prefix6
= std
->local6
;
1015 prefix_copy(&p
, prefix
);
1017 te_debug(" |- Adjust prefix %pFX with local address to: %pFX",
1020 /* Search existing Subnet in TED ... */
1021 subnet
= ls_find_subnet(args
->ted
, p
);
1022 /* ... and create a new Subnet if not found */
1024 ls_pref
= ls_prefix_new(vertex
->node
->adv
, p
);
1025 subnet
= ls_subnet_add(args
->ted
, ls_pref
);
1027 return LSP_ITER_CONTINUE
;
1029 ls_pref
= subnet
->ls_pref
;
1031 te_debug(" |- %s Subnet from prefix %pFX",
1032 subnet
->status
== NEW
? "Create" : "Found", &p
);
1035 if (!CHECK_FLAG(ls_pref
->flags
, LS_PREF_METRIC
)
1036 || (ls_pref
->metric
!= metric
)) {
1037 ls_pref
->metric
= metric
;
1038 SET_FLAG(ls_pref
->flags
, LS_PREF_METRIC
);
1039 if (subnet
->status
!= NEW
)
1040 subnet
->status
= UPDATE
;
1042 if (subnet
->status
== ORPHAN
)
1043 subnet
->status
= SYNC
;
1046 /* Update Prefix SID if any */
1047 if (subtlvs
&& subtlvs
->prefix_sids
.count
!= 0) {
1048 struct isis_prefix_sid
*psid
;
1049 struct ls_sid sr
= {};
1051 psid
= (struct isis_prefix_sid
*)subtlvs
->prefix_sids
.head
;
1052 sr
.algo
= psid
->algorithm
;
1053 sr
.sid_flag
= psid
->flags
;
1054 sr
.sid
= psid
->value
;
1056 if (!CHECK_FLAG(ls_pref
->flags
, LS_PREF_SR
)
1057 || !memcmp(&ls_pref
->sr
, &sr
, sizeof(struct ls_sid
))) {
1058 memcpy(&ls_pref
->sr
, &sr
, sizeof(struct ls_sid
));
1059 SET_FLAG(ls_pref
->flags
, LS_PREF_SR
);
1060 if (subnet
->status
!= NEW
)
1061 subnet
->status
= UPDATE
;
1063 if (subnet
->status
== ORPHAN
)
1064 subnet
->status
= SYNC
;
1067 if (CHECK_FLAG(ls_pref
->flags
, LS_PREF_SR
)) {
1068 UNSET_FLAG(ls_pref
->flags
, LS_PREF_SR
);
1069 if (subnet
->status
!= NEW
)
1070 subnet
->status
= UPDATE
;
1072 if (subnet
->status
== ORPHAN
)
1073 subnet
->status
= SYNC
;
1077 /* Update status and Export Link State Edge if needed */
1078 if (subnet
->status
!= SYNC
) {
1080 isis_te_export(LS_MSG_TYPE_PREFIX
, subnet
);
1081 subnet
->status
= SYNC
;
1084 return LSP_ITER_CONTINUE
;
1088 * Parse ISIS LSP to fulfill the Link State Database
1090 * @param ted Link State Database
1091 * @param lsp ISIS Link State PDU
1093 static void isis_te_parse_lsp(struct mpls_te_area
*mta
, struct isis_lsp
*lsp
)
1096 struct ls_vertex
*vertex
;
1097 struct ls_edge
*edge
;
1098 struct ls_subnet
*subnet
;
1099 struct listnode
*node
;
1100 struct isis_te_args args
;
1103 if (!IS_MPLS_TE(mta
) || !mta
->ted
|| !lsp
)
1108 te_debug("ISIS-TE(%s): Parse LSP %s", lsp
->area
->area_tag
,
1109 sysid_print(lsp
->hdr
.lsp_id
));
1111 /* First parse LSP to obtain the corresponding Vertex */
1112 vertex
= lsp_to_vertex(ted
, lsp
);
1114 zlog_warn("Unable to build Vertex from LSP %s. Abort!",
1115 sysid_print(lsp
->hdr
.lsp_id
));
1119 /* Check if Vertex has been modified */
1120 if (vertex
->status
!= SYNC
) {
1121 /* Vertex is out of sync: export it if requested */
1122 if (IS_EXPORT_TE(mta
))
1123 isis_te_export(LS_MSG_TYPE_NODE
, vertex
);
1124 vertex
->status
= SYNC
;
1127 /* Mark outgoing Edges and Subnets as ORPHAN to detect deletion */
1128 for (ALL_LIST_ELEMENTS_RO(vertex
->outgoing_edges
, node
, edge
))
1129 edge
->status
= ORPHAN
;
1131 for (ALL_LIST_ELEMENTS_RO(vertex
->prefixes
, node
, subnet
))
1132 subnet
->status
= ORPHAN
;
1134 /* Process all Extended Reachability in LSP (all fragments) */
1136 args
.vertex
= vertex
;
1137 args
.export
= mta
->export
;
1138 isis_lsp_iterate_is_reach(lsp
, ISIS_MT_IPV4_UNICAST
, lsp_to_edge_cb
,
1141 isis_lsp_iterate_is_reach(lsp
, ISIS_MT_IPV6_UNICAST
, lsp_to_edge_cb
,
1144 /* Process all Extended IP (v4 & v6) in LSP (all fragments) */
1145 isis_lsp_iterate_ip_reach(lsp
, AF_INET
, ISIS_MT_IPV4_UNICAST
,
1146 lsp_to_subnet_cb
, &args
);
1147 isis_lsp_iterate_ip_reach(lsp
, AF_INET6
, ISIS_MT_IPV6_UNICAST
,
1148 lsp_to_subnet_cb
, &args
);
1149 isis_lsp_iterate_ip_reach(lsp
, AF_INET6
, ISIS_MT_IPV4_UNICAST
,
1150 lsp_to_subnet_cb
, &args
);
1152 /* Clean remaining Orphan Edges or Subnets */
1153 if (IS_EXPORT_TE(mta
))
1154 ls_vertex_clean(ted
, vertex
, zclient
);
1156 ls_vertex_clean(ted
, vertex
, NULL
);
1160 * Delete Link State Database Vertex, Edge & Prefix that correspond to this
1161 * ISIS Link State PDU
1163 * @param ted Link State Database
1164 * @param lsp ISIS Link State PDU
1166 static void isis_te_delete_lsp(struct mpls_te_area
*mta
, struct isis_lsp
*lsp
)
1169 struct ls_vertex
*vertex
= NULL
;
1170 struct ls_node lnode
= {};
1171 struct ls_edge
*edge
;
1172 struct ls_subnet
*subnet
;
1173 struct listnode
*nnode
, *node
;
1176 if (!IS_MPLS_TE(mta
) || !mta
->ted
|| !lsp
)
1179 te_debug("ISIS-TE(%s): Delete Link State TED objects from LSP %s",
1180 lsp
->area
->area_tag
, sysid_print(lsp
->hdr
.lsp_id
));
1182 /* Compute Link State Node ID from IS-IS sysID ... */
1183 if (lsp
->level
== ISIS_LEVEL1
)
1184 lnode
.adv
.origin
= ISIS_L1
;
1186 lnode
.adv
.origin
= ISIS_L2
;
1187 memcpy(&lnode
.adv
.id
.iso
.sys_id
, &lsp
->hdr
.lsp_id
, ISIS_SYS_ID_LEN
);
1188 lnode
.adv
.id
.iso
.level
= lsp
->level
;
1190 /* ... and search the corresponding vertex */
1191 vertex
= ls_find_vertex_by_id(ted
, lnode
.adv
);
1195 te_debug(" |- Delete Vertex %s", vertex
->node
->name
);
1198 * We can't use the ls_vertex_del_all() function if export TE is set,
1199 * as we must first advertise the client daemons of each removal.
1201 /* Remove outgoing Edges */
1202 for (ALL_LIST_ELEMENTS(vertex
->outgoing_edges
, node
, nnode
, edge
)) {
1203 if (IS_EXPORT_TE(mta
)) {
1204 edge
->status
= DELETE
;
1205 isis_te_export(LS_MSG_TYPE_ATTRIBUTES
, edge
);
1207 ls_edge_del_all(ted
, edge
);
1210 /* Disconnect incoming Edges */
1211 for (ALL_LIST_ELEMENTS(vertex
->incoming_edges
, node
, nnode
, edge
)) {
1212 ls_disconnect(vertex
, edge
, false);
1213 if (edge
->source
== NULL
) {
1214 if (IS_EXPORT_TE(mta
)) {
1215 edge
->status
= DELETE
;
1216 isis_te_export(LS_MSG_TYPE_ATTRIBUTES
, edge
);
1218 ls_edge_del_all(ted
, edge
);
1222 /* Remove subnets */
1223 for (ALL_LIST_ELEMENTS(vertex
->prefixes
, node
, nnode
, subnet
)) {
1224 if (IS_EXPORT_TE(mta
)) {
1225 subnet
->status
= DELETE
;
1226 isis_te_export(LS_MSG_TYPE_PREFIX
, subnet
);
1228 ls_subnet_del_all(ted
, subnet
);
1231 /* Then remove Link State Node */
1232 if (IS_EXPORT_TE(mta
)) {
1233 vertex
->status
= DELETE
;
1234 isis_te_export(LS_MSG_TYPE_NODE
, vertex
);
1236 ls_node_del(vertex
->node
);
1238 /* Finally, remove Vertex */
1239 ls_vertex_del(ted
, vertex
);
1243 * Process ISIS LSP according to the event to add, update or remove
1244 * corresponding vertex, edge and prefix in the Link State database.
1245 * Since LSP could be fragmented, the function starts by searching the root LSP
1246 * to retrieve the complete LSP, including eventual fragment before processing
1249 * @param lsp ISIS Link State PDU
1250 * @param event LSP event: ADD, UPD, INC & DEL (TICK are ignored)
1253 void isis_te_lsp_event(struct isis_lsp
*lsp
, enum lsp_event event
)
1255 struct isis_area
*area
;
1256 struct isis_lsp
*lsp0
;
1259 if (!lsp
|| !lsp
->area
)
1263 if (!IS_MPLS_TE(area
->mta
))
1266 /* Adjust LSP0 in case of fragment */
1267 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
))
1268 lsp0
= lsp
->lspu
.zero_lsp
;
1272 /* Then process event */
1277 isis_te_parse_lsp(area
->mta
, lsp0
);
1280 isis_te_delete_lsp(area
->mta
, lsp0
);
1288 * Send the whole Link State Traffic Engineering Database to the consumer that
1289 * request it through a ZAPI Link State Synchronous Opaque Message.
1291 * @param info ZAPI Opaque message
1293 * @return 0 if success, -1 otherwise
1295 int isis_te_sync_ted(struct zapi_opaque_reg_info dst
)
1297 struct listnode
*node
, *inode
;
1299 struct isis_area
*area
;
1300 struct mpls_te_area
*mta
;
1303 te_debug("ISIS-TE(%s): Received TED synchro from client %d", __func__
,
1305 /* For each area, send TED if TE distribution is enabled */
1306 for (ALL_LIST_ELEMENTS_RO(im
->isis
, inode
, isis
)) {
1307 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
, area
)) {
1309 if (IS_MPLS_TE(mta
) && IS_EXPORT_TE(mta
)) {
1310 te_debug(" |- Export TED from area %s",
1312 rc
= ls_sync_ted(mta
->ted
, zclient
, &dst
);
1323 * Initialize the Link State database from the LSP already stored for this area
1325 * @param area ISIS area
1327 void isis_te_init_ted(struct isis_area
*area
)
1329 struct isis_lsp
*lsp
;
1331 /* Iterate over all lsp. */
1332 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++)
1333 frr_each (lspdb
, &area
->lspdb
[level
- 1], lsp
)
1334 isis_te_parse_lsp(area
->mta
, lsp
);
1337 /* Following are vty command functions */
1340 static void show_router_id(struct vty
*vty
, struct isis_area
*area
)
1342 bool no_match
= true;
1344 vty_out(vty
, "Area %s:\n", area
->area_tag
);
1345 if (area
->mta
->router_id
.s_addr
!= 0) {
1346 vty_out(vty
, " MPLS-TE IPv4 Router-Address: %pI4\n",
1347 &area
->mta
->router_id
);
1350 if (!IN6_IS_ADDR_UNSPECIFIED(&area
->mta
->router_id_ipv6
)) {
1351 vty_out(vty
, " MPLS-TE IPv6 Router-Address: %pI6\n",
1352 &area
->mta
->router_id_ipv6
);
1356 vty_out(vty
, " N/A\n");
1359 DEFUN(show_isis_mpls_te_router
,
1360 show_isis_mpls_te_router_cmd
,
1361 "show " PROTO_NAME
" [vrf <NAME|all>] mpls-te router",
1364 VRF_CMD_HELP_STR
"All VRFs\n"
1365 MPLS_TE_STR
"Router information\n")
1368 struct listnode
*anode
, *inode
;
1369 struct isis_area
*area
;
1370 struct isis
*isis
= NULL
;
1371 const char *vrf_name
= VRF_DEFAULT_NAME
;
1372 bool all_vrf
= false;
1376 vty_out(vty
, "IS-IS Routing Process not enabled\n");
1379 ISIS_FIND_VRF_ARGS(argv
, argc
, idx_vrf
, vrf_name
, all_vrf
);
1382 for (ALL_LIST_ELEMENTS_RO(im
->isis
, inode
, isis
)) {
1383 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
,
1385 if (!IS_MPLS_TE(area
->mta
))
1388 show_router_id(vty
, area
);
1393 isis
= isis_lookup_by_vrfname(vrf_name
);
1395 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, anode
,
1398 if (!IS_MPLS_TE(area
->mta
))
1401 show_router_id(vty
, area
);
1409 static void show_ext_sub(struct vty
*vty
, char *name
,
1410 struct isis_ext_subtlvs
*ext
)
1413 char ibuf
[PREFIX2STR_BUFFER
];
1415 sbuf_init(&buf
, NULL
, 0);
1417 if (!ext
|| ext
->status
== EXT_DISABLE
)
1420 vty_out(vty
, "-- MPLS-TE link parameters for %s --\n", name
);
1424 if (IS_SUBTLV(ext
, EXT_ADM_GRP
))
1425 sbuf_push(&buf
, 4, "Administrative Group: 0x%x\n",
1427 if (IS_SUBTLV(ext
, EXT_LLRI
)) {
1428 sbuf_push(&buf
, 4, "Link Local ID: %u\n",
1430 sbuf_push(&buf
, 4, "Link Remote ID: %u\n",
1433 if (IS_SUBTLV(ext
, EXT_LOCAL_ADDR
))
1434 sbuf_push(&buf
, 4, "Local Interface IP Address(es): %pI4\n",
1436 if (IS_SUBTLV(ext
, EXT_NEIGH_ADDR
))
1437 sbuf_push(&buf
, 4, "Remote Interface IP Address(es): %pI4\n",
1439 if (IS_SUBTLV(ext
, EXT_LOCAL_ADDR6
))
1440 sbuf_push(&buf
, 4, "Local Interface IPv6 Address(es): %s\n",
1441 inet_ntop(AF_INET6
, &ext
->local_addr6
, ibuf
,
1442 PREFIX2STR_BUFFER
));
1443 if (IS_SUBTLV(ext
, EXT_NEIGH_ADDR6
))
1444 sbuf_push(&buf
, 4, "Remote Interface IPv6 Address(es): %s\n",
1445 inet_ntop(AF_INET6
, &ext
->local_addr6
, ibuf
,
1446 PREFIX2STR_BUFFER
));
1447 if (IS_SUBTLV(ext
, EXT_MAX_BW
))
1448 sbuf_push(&buf
, 4, "Maximum Bandwidth: %g (Bytes/sec)\n",
1450 if (IS_SUBTLV(ext
, EXT_MAX_RSV_BW
))
1452 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
1454 if (IS_SUBTLV(ext
, EXT_UNRSV_BW
)) {
1455 sbuf_push(&buf
, 4, "Unreserved Bandwidth:\n");
1456 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 2) {
1457 sbuf_push(&buf
, 4 + 2,
1458 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
1459 j
, ext
->unrsv_bw
[j
],
1460 j
+ 1, ext
->unrsv_bw
[j
+ 1]);
1463 if (IS_SUBTLV(ext
, EXT_TE_METRIC
))
1464 sbuf_push(&buf
, 4, "Traffic Engineering Metric: %u\n",
1466 if (IS_SUBTLV(ext
, EXT_RMT_AS
))
1468 "Inter-AS TE Remote AS number: %u\n",
1470 if (IS_SUBTLV(ext
, EXT_RMT_IP
))
1472 "Inter-AS TE Remote ASBR IP address: %pI4\n",
1474 if (IS_SUBTLV(ext
, EXT_DELAY
))
1476 "%s Average Link Delay: %u (micro-sec)\n",
1477 IS_ANORMAL(ext
->delay
) ? "Anomalous" : "Normal",
1479 if (IS_SUBTLV(ext
, EXT_MM_DELAY
)) {
1480 sbuf_push(&buf
, 4, "%s Min/Max Link Delay: %u / %u (micro-sec)\n",
1481 IS_ANORMAL(ext
->min_delay
) ? "Anomalous" : "Normal",
1482 ext
->min_delay
& TE_EXT_MASK
,
1483 ext
->max_delay
& TE_EXT_MASK
);
1485 if (IS_SUBTLV(ext
, EXT_DELAY_VAR
))
1487 "Delay Variation: %u (micro-sec)\n",
1488 ext
->delay_var
& TE_EXT_MASK
);
1489 if (IS_SUBTLV(ext
, EXT_PKT_LOSS
))
1490 sbuf_push(&buf
, 4, "%s Link Packet Loss: %g (%%)\n",
1491 IS_ANORMAL(ext
->pkt_loss
) ? "Anomalous" : "Normal",
1492 (float)((ext
->pkt_loss
& TE_EXT_MASK
)
1494 if (IS_SUBTLV(ext
, EXT_RES_BW
))
1496 "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n",
1498 if (IS_SUBTLV(ext
, EXT_AVA_BW
))
1500 "Unidirectional Available Bandwidth: %g (Bytes/sec)\n",
1502 if (IS_SUBTLV(ext
, EXT_USE_BW
))
1504 "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n",
1507 vty_multiline(vty
, "", "%s", sbuf_buf(&buf
));
1508 vty_out(vty
, "---------------\n\n");
1514 DEFUN (show_isis_mpls_te_interface
,
1515 show_isis_mpls_te_interface_cmd
,
1516 "show " PROTO_NAME
" mpls-te interface [INTERFACE]",
1520 "Interface information\n"
1523 struct listnode
*anode
, *cnode
, *inode
;
1524 struct isis_area
*area
;
1525 struct isis_circuit
*circuit
;
1526 struct interface
*ifp
;
1527 int idx_interface
= 4;
1528 struct isis
*isis
= NULL
;
1531 vty_out(vty
, "IS-IS Routing Process not enabled\n");
1535 if (argc
== idx_interface
) {
1536 /* Show All Interfaces. */
1537 for (ALL_LIST_ELEMENTS_RO(im
->isis
, inode
, isis
)) {
1538 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, anode
,
1541 if (!IS_MPLS_TE(area
->mta
))
1544 vty_out(vty
, "Area %s:\n", area
->area_tag
);
1546 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
,
1549 circuit
->interface
->name
,
1554 /* Interface name is specified. */
1555 ifp
= if_lookup_by_name(argv
[idx_interface
]->arg
, VRF_DEFAULT
);
1557 vty_out(vty
, "No such interface name\n");
1559 circuit
= circuit_scan_by_ifp(ifp
);
1562 "ISIS is not enabled on circuit %s\n",
1565 show_ext_sub(vty
, ifp
->name
, circuit
->ext
);
1573 * Search Vertex in TED that corresponds to the given string that represent
1574 * the ISO system ID in the forms <systemid/hostname>[.<pseudo-id>-<framenent>]
1576 * @param ted Link State Database
1577 * @param id ISO System ID
1578 * @param isis Main reference to the isis daemon
1580 * @return Vertex if found, NULL otherwise
1582 static struct ls_vertex
*vertex_for_arg(struct ls_ted
*ted
, const char *id
,
1585 char sysid
[255] = {0};
1588 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2] = {0};
1589 struct isis_dynhn
*dynhn
;
1596 * extract fragment and pseudo id from the string argv
1598 * (a) <systemid/hostname>.<pseudo-id>-<framenent> or
1599 * (b) <systemid/hostname>.<pseudo-id> or
1600 * (c) <systemid/hostname> or
1601 * Where systemid is in the form:
1604 strlcpy(sysid
, id
, sizeof(sysid
));
1605 if (strlen(id
) > 3) {
1606 pos
= id
+ strlen(id
) - 3;
1607 if (strncmp(pos
, "-", 1) == 0) {
1608 memcpy(number
, ++pos
, 2);
1609 lspid
[ISIS_SYS_ID_LEN
+ 1] =
1610 (uint8_t)strtol((char *)number
, NULL
, 16);
1612 if (strncmp(pos
, ".", 1) != 0)
1615 if (strncmp(pos
, ".", 1) == 0) {
1616 memcpy(number
, ++pos
, 2);
1617 lspid
[ISIS_SYS_ID_LEN
] =
1618 (uint8_t)strtol((char *)number
, NULL
, 16);
1619 sysid
[pos
- id
- 1] = '\0';
1624 * Try to find the lsp-id if the argv
1627 * hostname.<pseudo-id>-<fragment>
1629 if (sysid2buff(lspid
, sysid
)) {
1630 key
= sysid_to_key(lspid
);
1631 } else if ((dynhn
= dynhn_find_by_name(isis
, sysid
))) {
1632 memcpy(lspid
, dynhn
->id
, ISIS_SYS_ID_LEN
);
1633 key
= sysid_to_key(lspid
);
1634 } else if (strncmp(cmd_hostname_get(), sysid
, 15) == 0) {
1635 memcpy(lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
1636 key
= sysid_to_key(lspid
);
1642 return ls_find_vertex_by_key(ted
, key
);
1646 * Show Link State Traffic Engineering Database extracted from IS-IS LSP.
1648 * @param vty VTY output console
1649 * @param argv Command line argument
1650 * @param argc Number of command line argument
1651 * @param ted Traffic Engineering Database
1652 * @param isis isis Main reference to the isis daemon
1654 * @return Command Success if OK, Command Warning otherwise
1656 static int show_ted(struct vty
*vty
, struct cmd_token
*argv
[], int argc
,
1657 struct isis_area
*area
, struct isis
*isis
)
1661 struct in_addr ip_addr
;
1662 struct in6_addr ip6_addr
;
1665 struct ls_vertex
*vertex
;
1666 struct ls_edge
*edge
;
1667 struct ls_subnet
*subnet
;
1669 bool detail
= false;
1670 bool uj
= use_json(argc
, argv
);
1671 json_object
*json
= NULL
;
1673 if (!IS_MPLS_TE(area
->mta
) || !area
->mta
->ted
) {
1674 vty_out(vty
, "MPLS-TE is disabled for Area %s\n",
1675 area
->area_tag
? area
->area_tag
: "null");
1679 ted
= area
->mta
->ted
;
1682 json
= json_object_new_object();
1684 vty_out(vty
, "Area %s:\n",
1685 area
->area_tag
? area
->area_tag
: "null");
1687 if (argv
[argc
- 1]->arg
&& strmatch(argv
[argc
- 1]->text
, "detail"))
1691 if (argv_find(argv
, argc
, "vertex", &idx
)) {
1693 id
= argv_find(argv
, argc
, "WORD", &idx
) ? argv
[idx
]->arg
1697 else if (!strncmp(id
, "self", 4))
1700 vertex
= vertex_for_arg(ted
, id
, isis
);
1702 vty_out(vty
, "No vertex found for ID %s\n", id
);
1708 ls_show_vertex(vertex
, vty
, json
, detail
);
1710 ls_show_vertices(ted
, vty
, json
, detail
);
1712 } else if (argv_find(argv
, argc
, "edge", &idx
)) {
1714 if (argv_find(argv
, argc
, "A.B.C.D", &idx
)) {
1715 if (!inet_pton(AF_INET
, argv
[idx
]->arg
, &ip_addr
)) {
1717 "Specified Edge ID %s is invalid\n",
1719 return CMD_WARNING_CONFIG_FAILED
;
1721 /* Get the Edge from the Link State Database */
1722 key
= ((uint64_t)ntohl(ip_addr
.s_addr
)) & 0xffffffff;
1723 edge
= ls_find_edge_by_key(ted
, key
);
1725 vty_out(vty
, "No edge found for ID %pI4\n",
1729 } else if (argv_find(argv
, argc
, "X:X::X:X", &idx
)) {
1730 if (!inet_pton(AF_INET6
, argv
[idx
]->arg
, &ip6_addr
)) {
1732 "Specified Edge ID %s is invalid\n",
1734 return CMD_WARNING_CONFIG_FAILED
;
1736 /* Get the Edge from the Link State Database */
1737 key
= (uint64_t)ntohl(ip6_addr
.s6_addr32
[3])
1738 | ((uint64_t)ntohl(ip6_addr
.s6_addr32
[2]) << 32);
1739 edge
= ls_find_edge_by_key(ted
, key
);
1741 vty_out(vty
, "No edge found for ID %pI6\n",
1749 ls_show_edge(edge
, vty
, json
, detail
);
1751 ls_show_edges(ted
, vty
, json
, detail
);
1753 } else if (argv_find(argv
, argc
, "subnet", &idx
)) {
1755 if (argv_find(argv
, argc
, "A.B.C.D/M", &idx
)) {
1756 if (!str2prefix(argv
[idx
]->arg
, &pref
)) {
1757 vty_out(vty
, "Invalid prefix format %s\n",
1759 return CMD_WARNING_CONFIG_FAILED
;
1761 /* Get the Subnet from the Link State Database */
1762 subnet
= ls_find_subnet(ted
, pref
);
1764 vty_out(vty
, "No subnet found for ID %pFX\n",
1768 } else if (argv_find(argv
, argc
, "X:X::X:X/M", &idx
)) {
1769 if (!str2prefix(argv
[idx
]->arg
, &pref
)) {
1770 vty_out(vty
, "Invalid prefix format %s\n",
1772 return CMD_WARNING_CONFIG_FAILED
;
1774 /* Get the Subnet from the Link State Database */
1775 subnet
= ls_find_subnet(ted
, pref
);
1777 vty_out(vty
, "No subnet found for ID %pFX\n",
1785 ls_show_subnet(subnet
, vty
, json
, detail
);
1787 ls_show_subnets(ted
, vty
, json
, detail
);
1790 /* Show the complete TED */
1791 ls_show_ted(ted
, vty
, json
, detail
);
1795 vty_json(vty
, json
);
1801 * Show ISIS Traffic Engineering Database
1803 * @param vty VTY output console
1804 * @param argv Command line argument
1805 * @param argc Number of command line argument
1806 * @param isis isis Main reference to the isis daemon
1808 * @return Command Success if OK, Command Warning otherwise
1810 static int show_isis_ted(struct vty
*vty
, struct cmd_token
*argv
[], int argc
,
1813 struct listnode
*node
;
1814 struct isis_area
*area
;
1817 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
, area
)) {
1818 rc
= show_ted(vty
, argv
, argc
, area
, isis
);
1819 if (rc
!= CMD_SUCCESS
)
1825 DEFUN(show_isis_mpls_te_db
,
1826 show_isis_mpls_te_db_cmd
,
1827 "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]",
1828 SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
1831 "MPLS-TE database\n"
1833 "MPLS-TE Vertex ID (as an ISO ID, hostname or \"self\")\n"
1835 "MPLS-TE Edge ID (as an IPv4 address)\n"
1836 "MPLS-TE Edge ID (as an IPv6 address)\n"
1838 "MPLS-TE Subnet ID (as an IPv4 prefix)\n"
1839 "MPLS-TE Subnet ID (as an IPv6 prefix)\n"
1840 "Detailed information\n"
1844 const char *vrf_name
= VRF_DEFAULT_NAME
;
1845 bool all_vrf
= false;
1846 struct listnode
*node
;
1848 int rc
= CMD_WARNING
;
1850 ISIS_FIND_VRF_ARGS(argv
, argc
, idx_vrf
, vrf_name
, all_vrf
);
1853 for (ALL_LIST_ELEMENTS_RO(im
->isis
, node
, isis
)) {
1854 rc
= show_isis_ted(vty
, argv
, argc
, isis
);
1855 if (rc
!= CMD_SUCCESS
)
1860 isis
= isis_lookup_by_vrfname(vrf_name
);
1862 rc
= show_isis_ted(vty
, argv
, argc
, isis
);
1868 #endif /* #ifndef FRABRICD */
1870 /* Initialize MPLS_TE */
1871 void isis_mpls_te_init(void)
1874 /* Register Circuit and Adjacency hook */
1875 hook_register(isis_if_new_hook
, isis_mpls_te_update
);
1876 hook_register(isis_adj_ip_enabled_hook
, isis_mpls_te_adj_ip_enabled
);
1877 hook_register(isis_adj_ip_disabled_hook
, isis_mpls_te_adj_ip_disabled
);
1880 /* Register new VTY commands */
1881 install_element(VIEW_NODE
, &show_isis_mpls_te_router_cmd
);
1882 install_element(VIEW_NODE
, &show_isis_mpls_te_interface_cmd
);
1883 install_element(VIEW_NODE
, &show_isis_mpls_te_db_cmd
);