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 ((ifp
== NULL
) || (circuit
->state
!= C_STATE_UP
))
87 zlog_debug("TE(%s): Update circuit parameters for interface %s",
88 circuit
->area
->area_tag
, ifp
->name
);
90 /* Check if MPLS TE Circuit context has not been already created */
91 if (circuit
->ext
== NULL
) {
92 circuit
->ext
= isis_alloc_ext_subtlvs();
93 zlog_debug(" |- Allocated new Ext-subTLVs for interface %s",
99 /* Fulfill Extended subTLVs from interface link parameters */
100 if (HAS_LINK_PARAMS(ifp
)) {
102 if (IS_PARAM_SET(ifp
->link_params
, LP_ADM_GRP
)) {
103 ext
->adm_group
= ifp
->link_params
->admin_grp
;
104 SET_SUBTLV(ext
, EXT_ADM_GRP
);
106 UNSET_SUBTLV(ext
, EXT_ADM_GRP
);
108 /* If known, register local IPv4 addr from ip_addr list */
109 if (circuit
->ip_addrs
!= NULL
110 && listcount(circuit
->ip_addrs
) != 0) {
111 addr
= (struct prefix_ipv4
*)listgetdata(
112 (struct listnode
*)listhead(circuit
->ip_addrs
));
113 IPV4_ADDR_COPY(&ext
->local_addr
, &addr
->prefix
);
114 SET_SUBTLV(ext
, EXT_LOCAL_ADDR
);
116 UNSET_SUBTLV(ext
, EXT_LOCAL_ADDR
);
118 /* Same for Remote IPv4 address */
119 if (circuit
->circ_type
== CIRCUIT_T_P2P
) {
120 struct isis_adjacency
*adj
= circuit
->u
.p2p
.neighbor
;
122 if (adj
&& adj
->adj_state
== ISIS_ADJ_UP
123 && adj
->ipv4_address_count
) {
124 IPV4_ADDR_COPY(&ext
->neigh_addr
,
125 &adj
->ipv4_addresses
[0]);
126 SET_SUBTLV(ext
, EXT_NEIGH_ADDR
);
129 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR
);
131 /* If known, register local IPv6 addr from ip_addr list */
132 if (circuit
->ipv6_non_link
!= NULL
133 && listcount(circuit
->ipv6_non_link
) != 0) {
134 addr6
= (struct prefix_ipv6
*)listgetdata(
135 (struct listnode
*)listhead(
136 circuit
->ipv6_non_link
));
137 IPV6_ADDR_COPY(&ext
->local_addr6
, &addr6
->prefix
);
138 SET_SUBTLV(ext
, EXT_LOCAL_ADDR6
);
140 UNSET_SUBTLV(ext
, EXT_LOCAL_ADDR6
);
142 /* Same for Remote IPv6 address */
143 if (circuit
->circ_type
== CIRCUIT_T_P2P
) {
144 struct isis_adjacency
*adj
= circuit
->u
.p2p
.neighbor
;
146 if (adj
&& adj
->adj_state
== ISIS_ADJ_UP
147 && adj
->ipv6_address_count
) {
148 IPV6_ADDR_COPY(&ext
->neigh_addr6
,
149 &adj
->ipv6_addresses
[0]);
150 SET_SUBTLV(ext
, EXT_NEIGH_ADDR6
);
153 UNSET_SUBTLV(ext
, EXT_NEIGH_ADDR6
);
155 if (IS_PARAM_SET(ifp
->link_params
, LP_MAX_BW
)) {
156 ext
->max_bw
= ifp
->link_params
->max_bw
;
157 SET_SUBTLV(ext
, EXT_MAX_BW
);
159 UNSET_SUBTLV(ext
, EXT_MAX_BW
);
161 if (IS_PARAM_SET(ifp
->link_params
, LP_MAX_RSV_BW
)) {
162 ext
->max_rsv_bw
= ifp
->link_params
->max_rsv_bw
;
163 SET_SUBTLV(ext
, EXT_MAX_RSV_BW
);
165 UNSET_SUBTLV(ext
, EXT_MAX_RSV_BW
);
167 if (IS_PARAM_SET(ifp
->link_params
, LP_UNRSV_BW
)) {
168 for (i
= 0; i
< MAX_CLASS_TYPE
; i
++)
170 ifp
->link_params
->unrsv_bw
[i
];
171 SET_SUBTLV(ext
, EXT_UNRSV_BW
);
173 UNSET_SUBTLV(ext
, EXT_UNRSV_BW
);
175 if (IS_PARAM_SET(ifp
->link_params
, LP_TE_METRIC
)) {
176 ext
->te_metric
= ifp
->link_params
->te_metric
;
177 SET_SUBTLV(ext
, EXT_TE_METRIC
);
179 UNSET_SUBTLV(ext
, EXT_TE_METRIC
);
181 /* TE metric extensions */
182 if (IS_PARAM_SET(ifp
->link_params
, LP_DELAY
)) {
183 ext
->delay
= ifp
->link_params
->av_delay
;
184 SET_SUBTLV(ext
, EXT_DELAY
);
186 UNSET_SUBTLV(ext
, EXT_DELAY
);
188 if (IS_PARAM_SET(ifp
->link_params
, LP_MM_DELAY
)) {
189 ext
->min_delay
= ifp
->link_params
->min_delay
;
190 ext
->max_delay
= ifp
->link_params
->max_delay
;
191 SET_SUBTLV(ext
, EXT_MM_DELAY
);
193 UNSET_SUBTLV(ext
, EXT_MM_DELAY
);
195 if (IS_PARAM_SET(ifp
->link_params
, LP_DELAY_VAR
)) {
196 ext
->delay_var
= ifp
->link_params
->delay_var
;
197 SET_SUBTLV(ext
, EXT_DELAY_VAR
);
199 UNSET_SUBTLV(ext
, EXT_DELAY_VAR
);
201 if (IS_PARAM_SET(ifp
->link_params
, LP_PKT_LOSS
)) {
202 ext
->pkt_loss
= ifp
->link_params
->pkt_loss
;
203 SET_SUBTLV(ext
, EXT_PKT_LOSS
);
205 UNSET_SUBTLV(ext
, EXT_PKT_LOSS
);
207 if (IS_PARAM_SET(ifp
->link_params
, LP_RES_BW
)) {
208 ext
->res_bw
= ifp
->link_params
->res_bw
;
209 SET_SUBTLV(ext
, EXT_RES_BW
);
211 UNSET_SUBTLV(ext
, EXT_RES_BW
);
213 if (IS_PARAM_SET(ifp
->link_params
, LP_AVA_BW
)) {
214 ext
->ava_bw
= ifp
->link_params
->ava_bw
;
215 SET_SUBTLV(ext
, EXT_AVA_BW
);
217 UNSET_SUBTLV(ext
, EXT_AVA_BW
);
219 if (IS_PARAM_SET(ifp
->link_params
, LP_USE_BW
)) {
220 ext
->use_bw
= ifp
->link_params
->use_bw
;
221 SET_SUBTLV(ext
, EXT_USE_BW
);
223 UNSET_SUBTLV(ext
, EXT_USE_BW
);
226 if (IS_PARAM_SET(ifp
->link_params
, LP_RMT_AS
)) {
227 ext
->remote_as
= ifp
->link_params
->rmt_as
;
228 ext
->remote_ip
= ifp
->link_params
->rmt_ip
;
229 SET_SUBTLV(ext
, EXT_RMT_AS
);
230 SET_SUBTLV(ext
, EXT_RMT_IP
);
232 /* reset inter-as TE params */
233 UNSET_SUBTLV(ext
, EXT_RMT_AS
);
234 UNSET_SUBTLV(ext
, EXT_RMT_IP
);
236 zlog_debug(" |- New MPLS-TE link parameters status 0x%x",
239 zlog_debug(" |- Reset Extended subTLVs status 0x%x",
241 /* Reset TE subTLVs keeping SR one's */
242 if (IS_SUBTLV(ext
, EXT_ADJ_SID
))
243 ext
->status
= EXT_ADJ_SID
;
244 else if (IS_SUBTLV(ext
, EXT_LAN_ADJ_SID
))
245 ext
->status
= EXT_LAN_ADJ_SID
;
253 static int isis_link_update_adj_hook(struct isis_adjacency
*adj
)
256 struct isis_circuit
*circuit
= adj
->circuit
;
258 /* Update MPLS TE Remote IP address parameter if possible */
259 if (!IS_MPLS_TE(circuit
->area
->mta
) || !IS_EXT_TE(circuit
->ext
))
263 if (adj
->ipv4_address_count
> 0) {
264 IPV4_ADDR_COPY(&circuit
->ext
->neigh_addr
,
265 &adj
->ipv4_addresses
[0]);
266 SET_SUBTLV(circuit
->ext
, EXT_NEIGH_ADDR
);
270 if (adj
->ipv6_address_count
> 0) {
271 IPV6_ADDR_COPY(&circuit
->ext
->neigh_addr6
,
272 &adj
->ipv6_addresses
[0]);
273 SET_SUBTLV(circuit
->ext
, EXT_NEIGH_ADDR6
);
279 int isis_mpls_te_update(struct interface
*ifp
)
281 struct isis_circuit
*circuit
;
288 /* Get circuit context from interface */
289 circuit
= circuit_scan_by_ifp(ifp
);
293 /* Update TE TLVs ... */
294 isis_link_params_update(circuit
, ifp
);
297 if (circuit
->area
&& IS_MPLS_TE(circuit
->area
->mta
))
298 lsp_regenerate_schedule(circuit
->area
, circuit
->is_type
, 0);
304 /* Followings are vty command functions */
307 DEFUN (show_isis_mpls_te_router
,
308 show_isis_mpls_te_router_cmd
,
309 "show " PROTO_NAME
" mpls-te router",
313 "Router information\n")
316 struct listnode
*anode
;
317 struct isis_area
*area
;
320 vty_out(vty
, "IS-IS Routing Process not enabled\n");
324 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, anode
, area
)) {
326 if (!IS_MPLS_TE(area
->mta
))
329 vty_out(vty
, "Area %s:\n", area
->area_tag
);
330 if (ntohs(area
->mta
->router_id
.s_addr
) != 0)
331 vty_out(vty
, " MPLS-TE Router-Address: %s\n",
332 inet_ntoa(area
->mta
->router_id
));
334 vty_out(vty
, " N/A\n");
340 static void show_ext_sub(struct vty
*vty
, char *name
,
341 struct isis_ext_subtlvs
*ext
)
344 char ibuf
[PREFIX2STR_BUFFER
];
346 sbuf_init(&buf
, NULL
, 0);
348 if (!ext
|| ext
->status
== EXT_DISABLE
)
351 vty_out(vty
, "-- MPLS-TE link parameters for %s --\n", name
);
355 if (IS_SUBTLV(ext
, EXT_ADM_GRP
))
356 sbuf_push(&buf
, 4, "Administrative Group: 0x%" PRIx32
"\n",
358 if (IS_SUBTLV(ext
, EXT_LLRI
)) {
359 sbuf_push(&buf
, 4, "Link Local ID: %" PRIu32
"\n",
361 sbuf_push(&buf
, 4, "Link Remote ID: %" PRIu32
"\n",
364 if (IS_SUBTLV(ext
, EXT_LOCAL_ADDR
))
365 sbuf_push(&buf
, 4, "Local Interface IP Address(es): %s\n",
366 inet_ntoa(ext
->local_addr
));
367 if (IS_SUBTLV(ext
, EXT_NEIGH_ADDR
))
368 sbuf_push(&buf
, 4, "Remote Interface IP Address(es): %s\n",
369 inet_ntoa(ext
->neigh_addr
));
370 if (IS_SUBTLV(ext
, EXT_LOCAL_ADDR6
))
371 sbuf_push(&buf
, 4, "Local Interface IPv6 Address(es): %s\n",
372 inet_ntop(AF_INET6
, &ext
->local_addr6
, ibuf
,
374 if (IS_SUBTLV(ext
, EXT_NEIGH_ADDR6
))
375 sbuf_push(&buf
, 4, "Remote Interface IPv6 Address(es): %s\n",
376 inet_ntop(AF_INET6
, &ext
->local_addr6
, ibuf
,
378 if (IS_SUBTLV(ext
, EXT_MAX_BW
))
379 sbuf_push(&buf
, 4, "Maximum Bandwidth: %g (Bytes/sec)\n",
381 if (IS_SUBTLV(ext
, EXT_MAX_RSV_BW
))
383 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
385 if (IS_SUBTLV(ext
, EXT_UNRSV_BW
)) {
386 sbuf_push(&buf
, 4, "Unreserved Bandwidth:\n");
387 for (int j
= 0; j
< MAX_CLASS_TYPE
; j
+= 2) {
388 sbuf_push(&buf
, 4 + 2,
389 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
391 j
+ 1, ext
->unrsv_bw
[j
+ 1]);
394 if (IS_SUBTLV(ext
, EXT_TE_METRIC
))
395 sbuf_push(&buf
, 4, "Traffic Engineering Metric: %u\n",
397 if (IS_SUBTLV(ext
, EXT_RMT_AS
))
399 "Inter-AS TE Remote AS number: %" PRIu32
"\n",
401 if (IS_SUBTLV(ext
, EXT_RMT_IP
))
403 "Inter-AS TE Remote ASBR IP address: %s\n",
404 inet_ntoa(ext
->remote_ip
));
405 if (IS_SUBTLV(ext
, EXT_DELAY
))
407 "%s Average Link Delay: %" PRIu32
" (micro-sec)\n",
408 IS_ANORMAL(ext
->delay
) ? "Anomalous" : "Normal",
410 if (IS_SUBTLV(ext
, EXT_MM_DELAY
)) {
411 sbuf_push(&buf
, 4, "%s Min/Max Link Delay: %" PRIu32
" / %"
412 PRIu32
" (micro-sec)\n",
413 IS_ANORMAL(ext
->min_delay
) ? "Anomalous" : "Normal",
414 ext
->min_delay
& TE_EXT_MASK
,
415 ext
->max_delay
& TE_EXT_MASK
);
417 if (IS_SUBTLV(ext
, EXT_DELAY_VAR
))
419 "Delay Variation: %" PRIu32
" (micro-sec)\n",
420 ext
->delay_var
& TE_EXT_MASK
);
421 if (IS_SUBTLV(ext
, EXT_PKT_LOSS
))
422 sbuf_push(&buf
, 4, "%s Link Packet Loss: %g (%%)\n",
423 IS_ANORMAL(ext
->pkt_loss
) ? "Anomalous" : "Normal",
424 (float)((ext
->pkt_loss
& TE_EXT_MASK
)
426 if (IS_SUBTLV(ext
, EXT_RES_BW
))
428 "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n",
430 if (IS_SUBTLV(ext
, EXT_AVA_BW
))
432 "Unidirectional Available Bandwidth: %g (Bytes/sec)\n",
434 if (IS_SUBTLV(ext
, EXT_USE_BW
))
436 "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n",
439 vty_multiline(vty
, "", "%s", sbuf_buf(&buf
));
440 vty_out(vty
, "---------------\n\n");
446 DEFUN (show_isis_mpls_te_interface
,
447 show_isis_mpls_te_interface_cmd
,
448 "show " PROTO_NAME
" mpls-te interface [INTERFACE]",
452 "Interface information\n"
455 struct listnode
*anode
, *cnode
;
456 struct isis_area
*area
;
457 struct isis_circuit
*circuit
;
458 struct interface
*ifp
;
459 int idx_interface
= 4;
462 vty_out(vty
, "IS-IS Routing Process not enabled\n");
466 if (argc
== idx_interface
) {
467 /* Show All Interfaces. */
468 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, anode
, area
)) {
470 if (!IS_MPLS_TE(area
->mta
))
473 vty_out(vty
, "Area %s:\n", area
->area_tag
);
475 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, cnode
,
477 show_ext_sub(vty
, circuit
->interface
->name
,
481 /* Interface name is specified. */
482 ifp
= if_lookup_by_name(argv
[idx_interface
]->arg
, VRF_DEFAULT
);
484 vty_out(vty
, "No such interface name\n");
486 circuit
= circuit_scan_by_ifp(ifp
);
489 "ISIS is not enabled on circuit %s\n",
492 show_ext_sub(vty
, ifp
->name
, circuit
->ext
);
500 /* Initialize MPLS_TE */
501 void isis_mpls_te_init(void)
504 /* Register Circuit and Adjacency hook */
505 hook_register(isis_if_new_hook
, isis_mpls_te_update
);
506 hook_register(isis_adj_state_change_hook
, isis_link_update_adj_hook
);
510 /* Register new VTY commands */
511 install_element(VIEW_NODE
, &show_isis_mpls_te_router_cmd
);
512 install_element(VIEW_NODE
, &show_isis_mpls_te_interface_cmd
);