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"
47 #include "isisd/isis_constants.h"
48 #include "isisd/isis_common.h"
49 #include "isisd/isis_flags.h"
50 #include "isisd/isis_circuit.h"
51 #include "isisd/isis_adjacency.h"
52 #include "isisd/isisd.h"
53 #include "isisd/isis_lsp.h"
54 #include "isisd/isis_pdu.h"
55 #include "isisd/isis_dynhn.h"
56 #include "isisd/isis_misc.h"
57 #include "isisd/isis_csm.h"
58 #include "isisd/isis_adjacency.h"
59 #include "isisd/isis_spf.h"
60 #include "isisd/isis_te.h"
61 #include "isisd/isis_zebra.h"
63 /*------------------------------------------------------------------------*
64 * Followings are control functions for MPLS-TE parameters management.
65 *------------------------------------------------------------------------*/
67 /* Main initialization / update function of the MPLS TE Circuit context */
68 /* Call when interface TE Link parameters are modified */
69 void isis_link_params_update(struct isis_circuit
*circuit
,
70 struct interface
*ifp
)
73 struct prefix_ipv4
*addr
;
74 struct prefix_ipv6
*addr6
;
75 struct isis_ext_subtlvs
*ext
;
77 /* Check if TE is enable or not */
78 if (!circuit
->area
|| !IS_MPLS_TE(circuit
->area
->mta
))
82 if ((ifp
== NULL
) || (circuit
->state
!= C_STATE_UP
))
85 zlog_debug("TE(%s): Update circuit parameters for interface %s",
86 circuit
->area
->area_tag
, ifp
->name
);
88 /* Check if MPLS TE Circuit context has not been already created */
89 if (circuit
->ext
== NULL
) {
90 circuit
->ext
= isis_alloc_ext_subtlvs();
91 zlog_debug(" |- Allocated new Ext-subTLVs for interface %s",
97 /* Fulfill Extended subTLVs from interface link parameters */
98 if (HAS_LINK_PARAMS(ifp
)) {
100 if (IS_PARAM_SET(ifp
->link_params
, LP_ADM_GRP
)) {
101 ext
->adm_group
= ifp
->link_params
->admin_grp
;
102 SET_SUBTLV(ext
, EXT_ADM_GRP
);
104 UNSET_SUBTLV(ext
, EXT_ADM_GRP
);
106 /* If known, register local IPv4 addr from ip_addr list */
107 if (circuit
->ip_addrs
!= NULL
108 && listcount(circuit
->ip_addrs
) != 0) {
109 addr
= (struct prefix_ipv4
*)listgetdata(
110 (struct listnode
*)listhead(circuit
->ip_addrs
));
111 IPV4_ADDR_COPY(&ext
->local_addr
, &addr
->prefix
);
112 SET_SUBTLV(ext
, EXT_LOCAL_ADDR
);
114 UNSET_SUBTLV(ext
, EXT_LOCAL_ADDR
);
116 /* Same for Remote IPv4 address */
117 if (circuit
->circ_type
== CIRCUIT_T_P2P
) {
118 struct isis_adjacency
*adj
= circuit
->u
.p2p
.neighbor
;
120 if (adj
&& adj
->adj_state
== ISIS_ADJ_UP
121 && adj
->ipv4_address_count
) {
122 IPV4_ADDR_COPY(&ext
->neigh_addr
,
123 &adj
->ipv4_addresses
[0]);
124 SET_SUBTLV(ext
, EXT_NEIGH_ADDR
);
127 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR
);
129 /* If known, register local IPv6 addr from ip_addr list */
130 if (circuit
->ipv6_non_link
!= NULL
131 && listcount(circuit
->ipv6_non_link
) != 0) {
132 addr6
= (struct prefix_ipv6
*)listgetdata(
133 (struct listnode
*)listhead(
134 circuit
->ipv6_non_link
));
135 IPV6_ADDR_COPY(&ext
->local_addr6
, &addr6
->prefix
);
136 SET_SUBTLV(ext
, EXT_LOCAL_ADDR6
);
138 UNSET_SUBTLV(ext
, EXT_LOCAL_ADDR6
);
140 /* Same for Remote IPv6 address */
141 if (circuit
->circ_type
== CIRCUIT_T_P2P
) {
142 struct isis_adjacency
*adj
= circuit
->u
.p2p
.neighbor
;
144 if (adj
&& adj
->adj_state
== ISIS_ADJ_UP
145 && adj
->ipv6_address_count
) {
146 IPV6_ADDR_COPY(&ext
->neigh_addr6
,
147 &adj
->ipv6_addresses
[0]);
148 SET_SUBTLV(ext
, EXT_NEIGH_ADDR6
);
151 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR6
);
153 if (IS_PARAM_SET(ifp
->link_params
, LP_MAX_BW
)) {
154 ext
->max_bw
= ifp
->link_params
->max_bw
;
155 SET_SUBTLV(ext
, EXT_MAX_BW
);
157 UNSET_SUBTLV(ext
, EXT_MAX_BW
);
159 if (IS_PARAM_SET(ifp
->link_params
, LP_MAX_RSV_BW
)) {
160 ext
->max_rsv_bw
= ifp
->link_params
->max_rsv_bw
;
161 SET_SUBTLV(ext
, EXT_MAX_RSV_BW
);
163 UNSET_SUBTLV(ext
, EXT_MAX_RSV_BW
);
165 if (IS_PARAM_SET(ifp
->link_params
, LP_UNRSV_BW
)) {
166 for (i
= 0; i
< MAX_CLASS_TYPE
; i
++)
168 ifp
->link_params
->unrsv_bw
[i
];
169 SET_SUBTLV(ext
, EXT_UNRSV_BW
);
171 UNSET_SUBTLV(ext
, EXT_UNRSV_BW
);
173 if (IS_PARAM_SET(ifp
->link_params
, LP_TE_METRIC
)) {
174 ext
->te_metric
= ifp
->link_params
->te_metric
;
175 SET_SUBTLV(ext
, EXT_TE_METRIC
);
177 UNSET_SUBTLV(ext
, EXT_TE_METRIC
);
179 /* TE metric extensions */
180 if (IS_PARAM_SET(ifp
->link_params
, LP_DELAY
)) {
181 ext
->delay
= ifp
->link_params
->av_delay
;
182 SET_SUBTLV(ext
, EXT_DELAY
);
184 UNSET_SUBTLV(ext
, EXT_DELAY
);
186 if (IS_PARAM_SET(ifp
->link_params
, LP_MM_DELAY
)) {
187 ext
->min_delay
= ifp
->link_params
->min_delay
;
188 ext
->max_delay
= ifp
->link_params
->max_delay
;
189 SET_SUBTLV(ext
, EXT_MM_DELAY
);
191 UNSET_SUBTLV(ext
, EXT_MM_DELAY
);
193 if (IS_PARAM_SET(ifp
->link_params
, LP_DELAY_VAR
)) {
194 ext
->delay_var
= ifp
->link_params
->delay_var
;
195 SET_SUBTLV(ext
, EXT_DELAY_VAR
);
197 UNSET_SUBTLV(ext
, EXT_DELAY_VAR
);
199 if (IS_PARAM_SET(ifp
->link_params
, LP_PKT_LOSS
)) {
200 ext
->pkt_loss
= ifp
->link_params
->pkt_loss
;
201 SET_SUBTLV(ext
, EXT_PKT_LOSS
);
203 UNSET_SUBTLV(ext
, EXT_PKT_LOSS
);
205 if (IS_PARAM_SET(ifp
->link_params
, LP_RES_BW
)) {
206 ext
->res_bw
= ifp
->link_params
->res_bw
;
207 SET_SUBTLV(ext
, EXT_RES_BW
);
209 UNSET_SUBTLV(ext
, EXT_RES_BW
);
211 if (IS_PARAM_SET(ifp
->link_params
, LP_AVA_BW
)) {
212 ext
->ava_bw
= ifp
->link_params
->ava_bw
;
213 SET_SUBTLV(ext
, EXT_AVA_BW
);
215 UNSET_SUBTLV(ext
, EXT_AVA_BW
);
217 if (IS_PARAM_SET(ifp
->link_params
, LP_USE_BW
)) {
218 ext
->use_bw
= ifp
->link_params
->use_bw
;
219 SET_SUBTLV(ext
, EXT_USE_BW
);
221 UNSET_SUBTLV(ext
, EXT_USE_BW
);
224 if (IS_PARAM_SET(ifp
->link_params
, LP_RMT_AS
)) {
225 ext
->remote_as
= ifp
->link_params
->rmt_as
;
226 ext
->remote_ip
= ifp
->link_params
->rmt_ip
;
227 SET_SUBTLV(ext
, EXT_RMT_AS
);
228 SET_SUBTLV(ext
, EXT_RMT_IP
);
230 /* reset inter-as TE params */
231 UNSET_SUBTLV(ext
, EXT_RMT_AS
);
232 UNSET_SUBTLV(ext
, EXT_RMT_IP
);
234 zlog_debug(" |- New MPLS-TE link parameters status 0x%x",
237 zlog_debug(" |- Reset Extended subTLVs status 0x%x",
239 /* Reset TE subTLVs keeping SR one's */
240 if (IS_SUBTLV(ext
, EXT_ADJ_SID
))
241 ext
->status
= EXT_ADJ_SID
;
242 else if (IS_SUBTLV(ext
, EXT_LAN_ADJ_SID
))
243 ext
->status
= EXT_LAN_ADJ_SID
;
251 static int isis_link_update_adj_hook(struct isis_adjacency
*adj
)
254 struct isis_circuit
*circuit
= adj
->circuit
;
256 /* Update MPLS TE Remote IP address parameter if possible */
257 if (!IS_MPLS_TE(circuit
->area
->mta
) || !IS_EXT_TE(circuit
->ext
))
261 if (adj
->ipv4_address_count
> 0) {
262 IPV4_ADDR_COPY(&circuit
->ext
->neigh_addr
,
263 &adj
->ipv4_addresses
[0]);
264 SET_SUBTLV(circuit
->ext
, EXT_NEIGH_ADDR
);
268 if (adj
->ipv6_address_count
> 0) {
269 IPV6_ADDR_COPY(&circuit
->ext
->neigh_addr6
,
270 &adj
->ipv6_addresses
[0]);
271 SET_SUBTLV(circuit
->ext
, EXT_NEIGH_ADDR6
);
277 int isis_mpls_te_update(struct interface
*ifp
)
279 struct isis_circuit
*circuit
;
286 /* Get circuit context from interface */
287 circuit
= circuit_scan_by_ifp(ifp
);
291 /* Update TE TLVs ... */
292 isis_link_params_update(circuit
, ifp
);
295 if (circuit
->area
&& IS_MPLS_TE(circuit
->area
->mta
))
296 lsp_regenerate_schedule(circuit
->area
, circuit
->is_type
, 0);
302 /* Followings are vty command functions */
305 DEFUN(show_isis_mpls_te_router
,
306 show_isis_mpls_te_router_cmd
,
307 "show " PROTO_NAME
" [vrf <NAME|all>] mpls-te router",
310 VRF_CMD_HELP_STR
"All VRFs\n"
311 MPLS_TE_STR
"Router information\n")
314 struct listnode
*anode
, *inode
;
315 struct isis_area
*area
;
316 struct isis
*isis
= NULL
;
317 const char *vrf_name
= VRF_DEFAULT_NAME
;
318 bool all_vrf
= false;
322 vty_out(vty
, "IS-IS Routing Process not enabled\n");
325 ISIS_FIND_VRF_ARGS(argv
, argc
, idx_vrf
, vrf_name
, all_vrf
);
328 for (ALL_LIST_ELEMENTS_RO(im
->isis
, inode
, isis
)) {
329 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
,
331 if (!IS_MPLS_TE(area
->mta
))
334 vty_out(vty
, "Area %s:\n",
336 if (ntohs(area
->mta
->router_id
.s_addr
)
339 " MPLS-TE Router-Address: %pI4\n",
340 &area
->mta
->router_id
);
342 vty_out(vty
, " N/A\n");
347 isis
= isis_lookup_by_vrfname(vrf_name
);
349 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, anode
,
352 if (!IS_MPLS_TE(area
->mta
))
355 vty_out(vty
, "Area %s:\n", area
->area_tag
);
356 if (ntohs(area
->mta
->router_id
.s_addr
) != 0)
358 " MPLS-TE Router-Address: %pI4\n",
359 &area
->mta
->router_id
);
361 vty_out(vty
, " N/A\n");
369 static void show_ext_sub(struct vty
*vty
, char *name
,
370 struct isis_ext_subtlvs
*ext
)
373 char ibuf
[PREFIX2STR_BUFFER
];
375 sbuf_init(&buf
, NULL
, 0);
377 if (!ext
|| ext
->status
== EXT_DISABLE
)
380 vty_out(vty
, "-- MPLS-TE link parameters for %s --\n", name
);
384 if (IS_SUBTLV(ext
, EXT_ADM_GRP
))
385 sbuf_push(&buf
, 4, "Administrative Group: 0x%x\n",
387 if (IS_SUBTLV(ext
, EXT_LLRI
)) {
388 sbuf_push(&buf
, 4, "Link Local ID: %u\n",
390 sbuf_push(&buf
, 4, "Link Remote ID: %u\n",
393 if (IS_SUBTLV(ext
, EXT_LOCAL_ADDR
))
394 sbuf_push(&buf
, 4, "Local Interface IP Address(es): %pI4\n",
396 if (IS_SUBTLV(ext
, EXT_NEIGH_ADDR
))
397 sbuf_push(&buf
, 4, "Remote Interface IP Address(es): %pI4\n",
399 if (IS_SUBTLV(ext
, EXT_LOCAL_ADDR6
))
400 sbuf_push(&buf
, 4, "Local Interface IPv6 Address(es): %s\n",
401 inet_ntop(AF_INET6
, &ext
->local_addr6
, ibuf
,
403 if (IS_SUBTLV(ext
, EXT_NEIGH_ADDR6
))
404 sbuf_push(&buf
, 4, "Remote Interface IPv6 Address(es): %s\n",
405 inet_ntop(AF_INET6
, &ext
->local_addr6
, ibuf
,
407 if (IS_SUBTLV(ext
, EXT_MAX_BW
))
408 sbuf_push(&buf
, 4, "Maximum Bandwidth: %g (Bytes/sec)\n",
410 if (IS_SUBTLV(ext
, EXT_MAX_RSV_BW
))
412 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
414 if (IS_SUBTLV(ext
, EXT_UNRSV_BW
)) {
415 sbuf_push(&buf
, 4, "Unreserved Bandwidth:\n");
416 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 2) {
417 sbuf_push(&buf
, 4 + 2,
418 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
420 j
+ 1, ext
->unrsv_bw
[j
+ 1]);
423 if (IS_SUBTLV(ext
, EXT_TE_METRIC
))
424 sbuf_push(&buf
, 4, "Traffic Engineering Metric: %u\n",
426 if (IS_SUBTLV(ext
, EXT_RMT_AS
))
428 "Inter-AS TE Remote AS number: %u\n",
430 if (IS_SUBTLV(ext
, EXT_RMT_IP
))
432 "Inter-AS TE Remote ASBR IP address: %pI4\n",
434 if (IS_SUBTLV(ext
, EXT_DELAY
))
436 "%s Average Link Delay: %u (micro-sec)\n",
437 IS_ANORMAL(ext
->delay
) ? "Anomalous" : "Normal",
439 if (IS_SUBTLV(ext
, EXT_MM_DELAY
)) {
440 sbuf_push(&buf
, 4, "%s Min/Max Link Delay: %u / %u (micro-sec)\n",
441 IS_ANORMAL(ext
->min_delay
) ? "Anomalous" : "Normal",
442 ext
->min_delay
& TE_EXT_MASK
,
443 ext
->max_delay
& TE_EXT_MASK
);
445 if (IS_SUBTLV(ext
, EXT_DELAY_VAR
))
447 "Delay Variation: %u (micro-sec)\n",
448 ext
->delay_var
& TE_EXT_MASK
);
449 if (IS_SUBTLV(ext
, EXT_PKT_LOSS
))
450 sbuf_push(&buf
, 4, "%s Link Packet Loss: %g (%%)\n",
451 IS_ANORMAL(ext
->pkt_loss
) ? "Anomalous" : "Normal",
452 (float)((ext
->pkt_loss
& TE_EXT_MASK
)
454 if (IS_SUBTLV(ext
, EXT_RES_BW
))
456 "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n",
458 if (IS_SUBTLV(ext
, EXT_AVA_BW
))
460 "Unidirectional Available Bandwidth: %g (Bytes/sec)\n",
462 if (IS_SUBTLV(ext
, EXT_USE_BW
))
464 "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n",
467 vty_multiline(vty
, "", "%s", sbuf_buf(&buf
));
468 vty_out(vty
, "---------------\n\n");
474 DEFUN (show_isis_mpls_te_interface
,
475 show_isis_mpls_te_interface_cmd
,
476 "show " PROTO_NAME
" mpls-te interface [INTERFACE]",
480 "Interface information\n"
483 struct listnode
*anode
, *cnode
, *inode
;
484 struct isis_area
*area
;
485 struct isis_circuit
*circuit
;
486 struct interface
*ifp
;
487 int idx_interface
= 4;
488 struct isis
*isis
= NULL
;
491 vty_out(vty
, "IS-IS Routing Process not enabled\n");
495 if (argc
== idx_interface
) {
496 /* Show All Interfaces. */
497 for (ALL_LIST_ELEMENTS_RO(im
->isis
, inode
, isis
)) {
498 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, anode
,
501 if (!IS_MPLS_TE(area
->mta
))
504 vty_out(vty
, "Area %s:\n", area
->area_tag
);
506 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
,
509 circuit
->interface
->name
,
514 /* Interface name is specified. */
515 ifp
= if_lookup_by_name(argv
[idx_interface
]->arg
, VRF_DEFAULT
);
517 vty_out(vty
, "No such interface name\n");
519 circuit
= circuit_scan_by_ifp(ifp
);
522 "ISIS is not enabled on circuit %s\n",
525 show_ext_sub(vty
, ifp
->name
, circuit
->ext
);
533 /* Initialize MPLS_TE */
534 void isis_mpls_te_init(void)
537 /* Register Circuit and Adjacency hook */
538 hook_register(isis_if_new_hook
, isis_mpls_te_update
);
539 hook_register(isis_adj_state_change_hook
, isis_link_update_adj_hook
);
543 /* Register new VTY commands */
544 install_element(VIEW_NODE
, &show_isis_mpls_te_router_cmd
);
545 install_element(VIEW_NODE
, &show_isis_mpls_te_interface_cmd
);