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 const char *mode2text
[] = {"Disable", "Area", "AS", "Emulate"};
65 /*------------------------------------------------------------------------*
66 * Followings are control functions for MPLS-TE parameters management.
67 *------------------------------------------------------------------------*/
69 /* Main initialization / update function of the MPLS TE Circuit context */
70 /* Call when interface TE Link parameters are modified */
71 void isis_link_params_update(struct isis_circuit
*circuit
,
72 struct interface
*ifp
)
75 struct prefix_ipv4
*addr
;
76 struct prefix_ipv6
*addr6
;
77 struct isis_ext_subtlvs
*ext
;
79 /* Check if TE is enable or not */
80 if (!circuit
->area
|| !IS_MPLS_TE(circuit
->area
->mta
))
84 if ((circuit
== NULL
) || (ifp
== NULL
)
85 || (circuit
->state
!= C_STATE_UP
))
88 zlog_debug("TE(%s): Update circuit parameters for interface %s",
89 circuit
->area
->area_tag
, ifp
->name
);
91 /* Check if MPLS TE Circuit context has not been already created */
92 if (circuit
->ext
== NULL
) {
93 circuit
->ext
= isis_alloc_ext_subtlvs();
94 zlog_debug(" |- Allocated new Ext-subTLVs for interface %s",
100 /* Fulfill Extended subTLVs from interface link parameters */
101 if (HAS_LINK_PARAMS(ifp
)) {
103 if (IS_PARAM_SET(ifp
->link_params
, LP_ADM_GRP
)) {
104 ext
->adm_group
= ifp
->link_params
->admin_grp
;
105 SET_SUBTLV(ext
, EXT_ADM_GRP
);
107 UNSET_SUBTLV(ext
, EXT_ADM_GRP
);
109 /* If known, register local IPv4 addr from ip_addr list */
110 if (circuit
->ip_addrs
!= NULL
111 && listcount(circuit
->ip_addrs
) != 0) {
112 addr
= (struct prefix_ipv4
*)listgetdata(
113 (struct listnode
*)listhead(circuit
->ip_addrs
));
114 IPV4_ADDR_COPY(&ext
->local_addr
, &addr
->prefix
);
115 SET_SUBTLV(ext
, EXT_LOCAL_ADDR
);
117 UNSET_SUBTLV(ext
, EXT_LOCAL_ADDR
);
119 /* Same for Remote IPv4 address */
120 if (circuit
->circ_type
== CIRCUIT_T_P2P
) {
121 struct isis_adjacency
*adj
= circuit
->u
.p2p
.neighbor
;
123 if (adj
&& adj
->adj_state
== ISIS_ADJ_UP
124 && adj
->ipv4_address_count
) {
125 IPV4_ADDR_COPY(&ext
->neigh_addr
,
126 &adj
->ipv4_addresses
[0]);
127 SET_SUBTLV(ext
, EXT_NEIGH_ADDR
);
130 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR
);
132 /* If known, register local IPv6 addr from ip_addr list */
133 if (circuit
->ipv6_non_link
!= NULL
134 && listcount(circuit
->ipv6_non_link
) != 0) {
135 addr6
= (struct prefix_ipv6
*)listgetdata(
136 (struct listnode
*)listhead(
137 circuit
->ipv6_non_link
));
138 IPV6_ADDR_COPY(&ext
->local_addr6
, &addr6
->prefix
);
139 SET_SUBTLV(ext
, EXT_LOCAL_ADDR6
);
141 UNSET_SUBTLV(ext
, EXT_LOCAL_ADDR6
);
143 /* Same for Remote IPv6 address */
144 if (circuit
->circ_type
== CIRCUIT_T_P2P
) {
145 struct isis_adjacency
*adj
= circuit
->u
.p2p
.neighbor
;
147 if (adj
&& adj
->adj_state
== ISIS_ADJ_UP
148 && adj
->ipv6_address_count
) {
149 IPV6_ADDR_COPY(&ext
->neigh_addr6
,
150 &adj
->ipv6_addresses
[0]);
151 SET_SUBTLV(ext
, EXT_NEIGH_ADDR6
);
154 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR6
);
156 if (IS_PARAM_SET(ifp
->link_params
, LP_MAX_BW
)) {
157 ext
->max_bw
= ifp
->link_params
->max_bw
;
158 SET_SUBTLV(ext
, EXT_MAX_BW
);
160 UNSET_SUBTLV(ext
, EXT_MAX_BW
);
162 if (IS_PARAM_SET(ifp
->link_params
, LP_MAX_RSV_BW
)) {
163 ext
->max_rsv_bw
= ifp
->link_params
->max_rsv_bw
;
164 SET_SUBTLV(ext
, EXT_MAX_RSV_BW
);
166 UNSET_SUBTLV(ext
, EXT_MAX_RSV_BW
);
168 if (IS_PARAM_SET(ifp
->link_params
, LP_UNRSV_BW
)) {
169 for (i
= 0; i
< MAX_CLASS_TYPE
; i
++)
171 ifp
->link_params
->unrsv_bw
[i
];
172 SET_SUBTLV(ext
, EXT_UNRSV_BW
);
174 UNSET_SUBTLV(ext
, EXT_UNRSV_BW
);
176 if (IS_PARAM_SET(ifp
->link_params
, LP_TE_METRIC
)) {
177 ext
->te_metric
= ifp
->link_params
->te_metric
;
178 SET_SUBTLV(ext
, EXT_TE_METRIC
);
180 UNSET_SUBTLV(ext
, EXT_TE_METRIC
);
182 /* TE metric extensions */
183 if (IS_PARAM_SET(ifp
->link_params
, LP_DELAY
)) {
184 ext
->delay
= ifp
->link_params
->av_delay
;
185 SET_SUBTLV(ext
, EXT_DELAY
);
187 UNSET_SUBTLV(ext
, EXT_DELAY
);
189 if (IS_PARAM_SET(ifp
->link_params
, LP_MM_DELAY
)) {
190 ext
->min_delay
= ifp
->link_params
->min_delay
;
191 ext
->max_delay
= ifp
->link_params
->max_delay
;
192 SET_SUBTLV(ext
, EXT_MM_DELAY
);
194 UNSET_SUBTLV(ext
, EXT_MM_DELAY
);
196 if (IS_PARAM_SET(ifp
->link_params
, LP_DELAY_VAR
)) {
197 ext
->delay_var
= ifp
->link_params
->delay_var
;
198 SET_SUBTLV(ext
, EXT_DELAY_VAR
);
200 UNSET_SUBTLV(ext
, EXT_DELAY_VAR
);
202 if (IS_PARAM_SET(ifp
->link_params
, LP_PKT_LOSS
)) {
203 ext
->pkt_loss
= ifp
->link_params
->pkt_loss
;
204 SET_SUBTLV(ext
, EXT_PKT_LOSS
);
206 UNSET_SUBTLV(ext
, EXT_PKT_LOSS
);
208 if (IS_PARAM_SET(ifp
->link_params
, LP_RES_BW
)) {
209 ext
->res_bw
= ifp
->link_params
->res_bw
;
210 SET_SUBTLV(ext
, EXT_RES_BW
);
212 UNSET_SUBTLV(ext
, EXT_RES_BW
);
214 if (IS_PARAM_SET(ifp
->link_params
, LP_AVA_BW
)) {
215 ext
->ava_bw
= ifp
->link_params
->ava_bw
;
216 SET_SUBTLV(ext
, EXT_AVA_BW
);
218 UNSET_SUBTLV(ext
, EXT_AVA_BW
);
220 if (IS_PARAM_SET(ifp
->link_params
, LP_USE_BW
)) {
221 ext
->use_bw
= ifp
->link_params
->use_bw
;
222 SET_SUBTLV(ext
, EXT_USE_BW
);
224 UNSET_SUBTLV(ext
, EXT_USE_BW
);
227 if (IS_PARAM_SET(ifp
->link_params
, LP_RMT_AS
)) {
228 ext
->remote_as
= ifp
->link_params
->rmt_as
;
229 ext
->remote_ip
= ifp
->link_params
->rmt_ip
;
230 SET_SUBTLV(ext
, EXT_RMT_AS
);
231 SET_SUBTLV(ext
, EXT_RMT_IP
);
233 /* reset inter-as TE params */
234 UNSET_SUBTLV(ext
, EXT_RMT_AS
);
235 UNSET_SUBTLV(ext
, EXT_RMT_IP
);
237 zlog_debug(" |- New MPLS-TE link parameters status 0x%x",
240 zlog_debug(" |- Reset Extended subTLVs status 0x%x",
242 /* Reset TE subTLVs keeping SR one's */
243 if (IS_SUBTLV(ext
, EXT_ADJ_SID
))
244 ext
->status
= EXT_ADJ_SID
;
245 else if (IS_SUBTLV(ext
, EXT_LAN_ADJ_SID
))
246 ext
->status
= EXT_LAN_ADJ_SID
;
254 static int isis_link_update_adj_hook(struct isis_adjacency
*adj
)
257 struct isis_circuit
*circuit
= adj
->circuit
;
259 /* Update MPLS TE Remote IP address parameter if possible */
260 if (!IS_MPLS_TE(circuit
->area
->mta
) || !IS_EXT_TE(circuit
->ext
))
264 if (adj
->ipv4_address_count
> 0) {
265 IPV4_ADDR_COPY(&circuit
->ext
->neigh_addr
,
266 &adj
->ipv4_addresses
[0]);
267 SET_SUBTLV(circuit
->ext
, EXT_NEIGH_ADDR
);
271 if (adj
->ipv6_address_count
> 0) {
272 IPV6_ADDR_COPY(&circuit
->ext
->neigh_addr6
,
273 &adj
->ipv6_addresses
[0]);
274 SET_SUBTLV(circuit
->ext
, EXT_NEIGH_ADDR6
);
280 int isis_mpls_te_update(struct interface
*ifp
)
282 struct isis_circuit
*circuit
;
289 /* Get circuit context from interface */
290 circuit
= circuit_scan_by_ifp(ifp
);
294 /* Update TE TLVs ... */
295 isis_link_params_update(circuit
, ifp
);
298 if (circuit
->area
&& IS_MPLS_TE(circuit
->area
->mta
))
299 lsp_regenerate_schedule(circuit
->area
, circuit
->is_type
, 0);
305 /* Followings are vty command functions */
308 DEFUN (show_isis_mpls_te_router
,
309 show_isis_mpls_te_router_cmd
,
310 "show " PROTO_NAME
" mpls-te router",
314 "Router information\n")
317 struct listnode
*anode
;
318 struct isis_area
*area
;
321 vty_out(vty
, "IS-IS Routing Process not enabled\n");
325 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, anode
, area
)) {
327 if (!IS_MPLS_TE(area
->mta
))
330 vty_out(vty
, "Area %s:\n", area
->area_tag
);
331 if (ntohs(area
->mta
->router_id
.s_addr
) != 0)
332 vty_out(vty
, " MPLS-TE Router-Address: %s\n",
333 inet_ntoa(area
->mta
->router_id
));
335 vty_out(vty
, " N/A\n");
341 static void show_ext_sub(struct vty
*vty
, char *name
,
342 struct isis_ext_subtlvs
*ext
)
345 char ibuf
[PREFIX2STR_BUFFER
];
347 sbuf_init(&buf
, NULL
, 0);
349 if (!ext
|| ext
->status
== EXT_DISABLE
)
352 vty_out(vty
, "-- MPLS-TE link parameters for %s --\n", name
);
356 if (IS_SUBTLV(ext
, EXT_ADM_GRP
))
357 sbuf_push(&buf
, 4, "Administrative Group: 0x%" PRIx32
"\n",
359 if (IS_SUBTLV(ext
, EXT_LLRI
)) {
360 sbuf_push(&buf
, 4, "Link Local ID: %" PRIu32
"\n",
362 sbuf_push(&buf
, 4, "Link Remote ID: %" PRIu32
"\n",
365 if (IS_SUBTLV(ext
, EXT_LOCAL_ADDR
))
366 sbuf_push(&buf
, 4, "Local Interface IP Address(es): %s\n",
367 inet_ntoa(ext
->local_addr
));
368 if (IS_SUBTLV(ext
, EXT_NEIGH_ADDR
))
369 sbuf_push(&buf
, 4, "Remote Interface IP Address(es): %s\n",
370 inet_ntoa(ext
->neigh_addr
));
371 if (IS_SUBTLV(ext
, EXT_LOCAL_ADDR6
))
372 sbuf_push(&buf
, 4, "Local Interface IPv6 Address(es): %s\n",
373 inet_ntop(AF_INET6
, &ext
->local_addr6
, ibuf
,
375 if (IS_SUBTLV(ext
, EXT_NEIGH_ADDR6
))
376 sbuf_push(&buf
, 4, "Remote Interface IPv6 Address(es): %s\n",
377 inet_ntop(AF_INET6
, &ext
->local_addr6
, ibuf
,
379 if (IS_SUBTLV(ext
, EXT_MAX_BW
))
380 sbuf_push(&buf
, 4, "Maximum Bandwidth: %g (Bytes/sec)\n",
382 if (IS_SUBTLV(ext
, EXT_MAX_RSV_BW
))
384 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
386 if (IS_SUBTLV(ext
, EXT_UNRSV_BW
)) {
387 sbuf_push(&buf
, 4, "Unreserved Bandwidth:\n");
388 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 2) {
389 sbuf_push(&buf
, 4 + 2,
390 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
392 j
+ 1, ext
->unrsv_bw
[j
+ 1]);
395 if (IS_SUBTLV(ext
, EXT_TE_METRIC
))
396 sbuf_push(&buf
, 4, "Traffic Engineering Metric: %u\n",
398 if (IS_SUBTLV(ext
, EXT_RMT_AS
))
400 "Inter-AS TE Remote AS number: %" PRIu32
"\n",
402 if (IS_SUBTLV(ext
, EXT_RMT_IP
))
404 "Inter-AS TE Remote ASBR IP address: %s\n",
405 inet_ntoa(ext
->remote_ip
));
406 if (IS_SUBTLV(ext
, EXT_DELAY
))
408 "%s Average Link Delay: %" PRIu32
" (micro-sec)\n",
409 IS_ANORMAL(ext
->delay
) ? "Anomalous" : "Normal",
411 if (IS_SUBTLV(ext
, EXT_MM_DELAY
)) {
412 sbuf_push(&buf
, 4, "%s Min/Max Link Delay: %" PRIu32
" / %"
413 PRIu32
" (micro-sec)\n",
414 IS_ANORMAL(ext
->min_delay
) ? "Anomalous" : "Normal",
415 ext
->min_delay
& TE_EXT_MASK
,
416 ext
->max_delay
& TE_EXT_MASK
);
418 if (IS_SUBTLV(ext
, EXT_DELAY_VAR
))
420 "Delay Variation: %" PRIu32
" (micro-sec)\n",
421 ext
->delay_var
& TE_EXT_MASK
);
422 if (IS_SUBTLV(ext
, EXT_PKT_LOSS
))
423 sbuf_push(&buf
, 4, "%s Link Packet Loss: %g (%%)\n",
424 IS_ANORMAL(ext
->pkt_loss
) ? "Anomalous" : "Normal",
425 (float)((ext
->pkt_loss
& TE_EXT_MASK
)
427 if (IS_SUBTLV(ext
, EXT_RES_BW
))
429 "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n",
431 if (IS_SUBTLV(ext
, EXT_AVA_BW
))
433 "Unidirectional Available Bandwidth: %g (Bytes/sec)\n",
435 if (IS_SUBTLV(ext
, EXT_USE_BW
))
437 "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n",
440 vty_multiline(vty
, "", "%s", sbuf_buf(&buf
));
441 vty_out(vty
, "---------------\n\n");
447 DEFUN (show_isis_mpls_te_interface
,
448 show_isis_mpls_te_interface_cmd
,
449 "show " PROTO_NAME
" mpls-te interface [INTERFACE]",
453 "Interface information\n"
456 struct listnode
*anode
, *cnode
;
457 struct isis_area
*area
;
458 struct isis_circuit
*circuit
;
459 struct interface
*ifp
;
460 int idx_interface
= 4;
463 vty_out(vty
, "IS-IS Routing Process not enabled\n");
467 if (argc
== idx_interface
) {
468 /* Show All Interfaces. */
469 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, anode
, area
)) {
471 if (!IS_MPLS_TE(area
->mta
))
474 vty_out(vty
, "Area %s:\n", area
->area_tag
);
476 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, cnode
,
478 show_ext_sub(vty
, circuit
->interface
->name
,
482 /* Interface name is specified. */
483 ifp
= if_lookup_by_name(argv
[idx_interface
]->arg
, VRF_DEFAULT
);
485 vty_out(vty
, "No such interface name\n");
487 circuit
= circuit_scan_by_ifp(ifp
);
490 "ISIS is not enabled on circuit %s\n",
493 show_ext_sub(vty
, ifp
->name
, circuit
->ext
);
501 /* Initialize MPLS_TE */
502 void isis_mpls_te_init(void)
505 /* Register Circuit and Adjacency hook */
506 hook_register(isis_if_new_hook
, isis_mpls_te_update
);
507 hook_register(isis_adj_state_change_hook
, isis_link_update_adj_hook
);
511 /* Register new VTY commands */
512 install_element(VIEW_NODE
, &show_isis_mpls_te_router_cmd
);
513 install_element(VIEW_NODE
, &show_isis_mpls_te_interface_cmd
);