]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_te.c
Merge pull request #5022 from chiragshah6/mdev
[mirror_frr.git] / isisd / isis_te.c
1 /*
2 * IS-IS Rout(e)ing protocol - isis_te.c
3 *
4 * This is an implementation of RFC5305 & RFC 7810
5 *
6 * Author: Olivier Dugeon <olivier.dugeon@orange.com>
7 *
8 * Copyright (C) 2014 - 2019 Orange Labs http://www.orange.com
9 *
10 * This file is part of GNU Zebra.
11 *
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
15 * later version.
16 *
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.
21 *
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
25 */
26
27 #include <zebra.h>
28 #include <math.h>
29
30 #include "linklist.h"
31 #include "thread.h"
32 #include "vty.h"
33 #include "stream.h"
34 #include "memory.h"
35 #include "log.h"
36 #include "prefix.h"
37 #include "command.h"
38 #include "hash.h"
39 #include "if.h"
40 #include "vrf.h"
41 #include "checksum.h"
42 #include "md5.h"
43 #include "sockunion.h"
44 #include "network.h"
45 #include "sbuf.h"
46
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"
62
63 const char *mode2text[] = {"Disable", "Area", "AS", "Emulate"};
64
65 /*------------------------------------------------------------------------*
66 * Followings are control functions for MPLS-TE parameters management.
67 *------------------------------------------------------------------------*/
68
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)
73 {
74 int i;
75 struct prefix_ipv4 *addr;
76 struct prefix_ipv6 *addr6;
77 struct isis_ext_subtlvs *ext;
78
79 /* Check if TE is enable or not */
80 if (!circuit->area || !IS_MPLS_TE(circuit->area->mta))
81 return;
82
83 /* Sanity Check */
84 if ((ifp == NULL) || (circuit->state != C_STATE_UP))
85 return;
86
87 zlog_debug("TE(%s): Update circuit parameters for interface %s",
88 circuit->area->area_tag, ifp->name);
89
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",
94 ifp->name);
95 }
96
97 ext = circuit->ext;
98
99 /* Fulfill Extended subTLVs from interface link parameters */
100 if (HAS_LINK_PARAMS(ifp)) {
101 /* STD_TE metrics */
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);
105 } else
106 UNSET_SUBTLV(ext, EXT_ADM_GRP);
107
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);
115 } else
116 UNSET_SUBTLV(ext, EXT_LOCAL_ADDR);
117
118 /* Same for Remote IPv4 address */
119 if (circuit->circ_type == CIRCUIT_T_P2P) {
120 struct isis_adjacency *adj = circuit->u.p2p.neighbor;
121
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);
127 }
128 } else
129 UNSET_SUBTLV(ext, EXT_NEIGH_ADDR);
130
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);
139 } else
140 UNSET_SUBTLV(ext, EXT_LOCAL_ADDR6);
141
142 /* Same for Remote IPv6 address */
143 if (circuit->circ_type == CIRCUIT_T_P2P) {
144 struct isis_adjacency *adj = circuit->u.p2p.neighbor;
145
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);
151 }
152 } else
153 UNSET_SUBTLV(ext, EXT_NEIGH_ADDR6);
154
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);
158 } else
159 UNSET_SUBTLV(ext, EXT_MAX_BW);
160
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);
164 } else
165 UNSET_SUBTLV(ext, EXT_MAX_RSV_BW);
166
167 if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) {
168 for (i = 0; i < MAX_CLASS_TYPE; i++)
169 ext->unrsv_bw[i] =
170 ifp->link_params->unrsv_bw[i];
171 SET_SUBTLV(ext, EXT_UNRSV_BW);
172 } else
173 UNSET_SUBTLV(ext, EXT_UNRSV_BW);
174
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);
178 } else
179 UNSET_SUBTLV(ext, EXT_TE_METRIC);
180
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);
185 } else
186 UNSET_SUBTLV(ext, EXT_DELAY);
187
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);
192 } else
193 UNSET_SUBTLV(ext, EXT_MM_DELAY);
194
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);
198 } else
199 UNSET_SUBTLV(ext, EXT_DELAY_VAR);
200
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);
204 } else
205 UNSET_SUBTLV(ext, EXT_PKT_LOSS);
206
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);
210 } else
211 UNSET_SUBTLV(ext, EXT_RES_BW);
212
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);
216 } else
217 UNSET_SUBTLV(ext, EXT_AVA_BW);
218
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);
222 } else
223 UNSET_SUBTLV(ext, EXT_USE_BW);
224
225 /* INTER_AS */
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);
231 } else {
232 /* reset inter-as TE params */
233 UNSET_SUBTLV(ext, EXT_RMT_AS);
234 UNSET_SUBTLV(ext, EXT_RMT_IP);
235 }
236 zlog_debug(" |- New MPLS-TE link parameters status 0x%x",
237 ext->status);
238 } else {
239 zlog_debug(" |- Reset Extended subTLVs status 0x%x",
240 ext->status);
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;
246 else
247 ext->status = 0;
248 }
249
250 return;
251 }
252
253 static int isis_link_update_adj_hook(struct isis_adjacency *adj)
254 {
255
256 struct isis_circuit *circuit = adj->circuit;
257
258 /* Update MPLS TE Remote IP address parameter if possible */
259 if (!IS_MPLS_TE(circuit->area->mta) || !IS_EXT_TE(circuit->ext))
260 return 0;
261
262 /* IPv4 first */
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);
267 }
268
269 /* and IPv6 */
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);
274 }
275
276 return 0;
277 }
278
279 int isis_mpls_te_update(struct interface *ifp)
280 {
281 struct isis_circuit *circuit;
282 uint8_t rc = 1;
283
284 /* Sanity Check */
285 if (ifp == NULL)
286 return rc;
287
288 /* Get circuit context from interface */
289 circuit = circuit_scan_by_ifp(ifp);
290 if (circuit == NULL)
291 return rc;
292
293 /* Update TE TLVs ... */
294 isis_link_params_update(circuit, ifp);
295
296 /* ... and LSP */
297 if (circuit->area && IS_MPLS_TE(circuit->area->mta))
298 lsp_regenerate_schedule(circuit->area, circuit->is_type, 0);
299
300 rc = 0;
301 return rc;
302 }
303
304 /* Followings are vty command functions */
305 #ifndef FABRICD
306
307 DEFUN (show_isis_mpls_te_router,
308 show_isis_mpls_te_router_cmd,
309 "show " PROTO_NAME " mpls-te router",
310 SHOW_STR
311 PROTO_HELP
312 MPLS_TE_STR
313 "Router information\n")
314 {
315
316 struct listnode *anode;
317 struct isis_area *area;
318
319 if (!isis) {
320 vty_out(vty, "IS-IS Routing Process not enabled\n");
321 return CMD_SUCCESS;
322 }
323
324 for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
325
326 if (!IS_MPLS_TE(area->mta))
327 continue;
328
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));
333 else
334 vty_out(vty, " N/A\n");
335 }
336
337 return CMD_SUCCESS;
338 }
339
340 static void show_ext_sub(struct vty *vty, char *name,
341 struct isis_ext_subtlvs *ext)
342 {
343 struct sbuf buf;
344 char ibuf[PREFIX2STR_BUFFER];
345
346 sbuf_init(&buf, NULL, 0);
347
348 if (!ext || ext->status == EXT_DISABLE)
349 return;
350
351 vty_out(vty, "-- MPLS-TE link parameters for %s --\n", name);
352
353 sbuf_reset(&buf);
354
355 if (IS_SUBTLV(ext, EXT_ADM_GRP))
356 sbuf_push(&buf, 4, "Administrative Group: 0x%" PRIx32 "\n",
357 ext->adm_group);
358 if (IS_SUBTLV(ext, EXT_LLRI)) {
359 sbuf_push(&buf, 4, "Link Local ID: %" PRIu32 "\n",
360 ext->local_llri);
361 sbuf_push(&buf, 4, "Link Remote ID: %" PRIu32 "\n",
362 ext->remote_llri);
363 }
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,
373 PREFIX2STR_BUFFER));
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,
377 PREFIX2STR_BUFFER));
378 if (IS_SUBTLV(ext, EXT_MAX_BW))
379 sbuf_push(&buf, 4, "Maximum Bandwidth: %g (Bytes/sec)\n",
380 ext->max_bw);
381 if (IS_SUBTLV(ext, EXT_MAX_RSV_BW))
382 sbuf_push(&buf, 4,
383 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
384 ext->max_rsv_bw);
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",
390 j, ext->unrsv_bw[j],
391 j + 1, ext->unrsv_bw[j + 1]);
392 }
393 }
394 if (IS_SUBTLV(ext, EXT_TE_METRIC))
395 sbuf_push(&buf, 4, "Traffic Engineering Metric: %u\n",
396 ext->te_metric);
397 if (IS_SUBTLV(ext, EXT_RMT_AS))
398 sbuf_push(&buf, 4,
399 "Inter-AS TE Remote AS number: %" PRIu32 "\n",
400 ext->remote_as);
401 if (IS_SUBTLV(ext, EXT_RMT_IP))
402 sbuf_push(&buf, 4,
403 "Inter-AS TE Remote ASBR IP address: %s\n",
404 inet_ntoa(ext->remote_ip));
405 if (IS_SUBTLV(ext, EXT_DELAY))
406 sbuf_push(&buf, 4,
407 "%s Average Link Delay: %" PRIu32 " (micro-sec)\n",
408 IS_ANORMAL(ext->delay) ? "Anomalous" : "Normal",
409 ext->delay);
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);
416 }
417 if (IS_SUBTLV(ext, EXT_DELAY_VAR))
418 sbuf_push(&buf, 4,
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)
425 * LOSS_PRECISION));
426 if (IS_SUBTLV(ext, EXT_RES_BW))
427 sbuf_push(&buf, 4,
428 "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n",
429 ext->res_bw);
430 if (IS_SUBTLV(ext, EXT_AVA_BW))
431 sbuf_push(&buf, 4,
432 "Unidirectional Available Bandwidth: %g (Bytes/sec)\n",
433 ext->ava_bw);
434 if (IS_SUBTLV(ext, EXT_USE_BW))
435 sbuf_push(&buf, 4,
436 "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n",
437 ext->use_bw);
438
439 vty_multiline(vty, "", "%s", sbuf_buf(&buf));
440 vty_out(vty, "---------------\n\n");
441
442 sbuf_free(&buf);
443 return;
444 }
445
446 DEFUN (show_isis_mpls_te_interface,
447 show_isis_mpls_te_interface_cmd,
448 "show " PROTO_NAME " mpls-te interface [INTERFACE]",
449 SHOW_STR
450 PROTO_HELP
451 MPLS_TE_STR
452 "Interface information\n"
453 "Interface name\n")
454 {
455 struct listnode *anode, *cnode;
456 struct isis_area *area;
457 struct isis_circuit *circuit;
458 struct interface *ifp;
459 int idx_interface = 4;
460
461 if (!isis) {
462 vty_out(vty, "IS-IS Routing Process not enabled\n");
463 return CMD_SUCCESS;
464 }
465
466 if (argc == idx_interface) {
467 /* Show All Interfaces. */
468 for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
469
470 if (!IS_MPLS_TE(area->mta))
471 continue;
472
473 vty_out(vty, "Area %s:\n", area->area_tag);
474
475 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode,
476 circuit))
477 show_ext_sub(vty, circuit->interface->name,
478 circuit->ext);
479 }
480 } else {
481 /* Interface name is specified. */
482 ifp = if_lookup_by_name(argv[idx_interface]->arg, VRF_DEFAULT);
483 if (ifp == NULL)
484 vty_out(vty, "No such interface name\n");
485 else {
486 circuit = circuit_scan_by_ifp(ifp);
487 if (!circuit)
488 vty_out(vty,
489 "ISIS is not enabled on circuit %s\n",
490 ifp->name);
491 else
492 show_ext_sub(vty, ifp->name, circuit->ext);
493 }
494 }
495
496 return CMD_SUCCESS;
497 }
498 #endif
499
500 /* Initialize MPLS_TE */
501 void isis_mpls_te_init(void)
502 {
503
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);
507
508
509 #ifndef FABRICD
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);
513 #endif
514
515 return;
516 }