]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_te.c
Merge pull request #12933 from Orange-OpenSource/link_state
[mirror_frr.git] / isisd / isis_te.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * IS-IS Rout(e)ing protocol - isis_te.c
4 *
5 * This is an implementation of RFC5305 & RFC 7810
6 *
7 * Author: Olivier Dugeon <olivier.dugeon@orange.com>
8 *
9 * Copyright (C) 2014 - 2019 Orange Labs http://www.orange.com
10 */
11
12 #include <zebra.h>
13 #include <math.h>
14
15 #include "linklist.h"
16 #include "frrevent.h"
17 #include "vty.h"
18 #include "stream.h"
19 #include "memory.h"
20 #include "log.h"
21 #include "prefix.h"
22 #include "command.h"
23 #include "hash.h"
24 #include "if.h"
25 #include "vrf.h"
26 #include "checksum.h"
27 #include "md5.h"
28 #include "sockunion.h"
29 #include "network.h"
30 #include "sbuf.h"
31 #include "link_state.h"
32 #include "lib/json.h"
33
34 #include "isisd/isis_constants.h"
35 #include "isisd/isis_common.h"
36 #include "isisd/isis_flags.h"
37 #include "isisd/isis_circuit.h"
38 #include "isisd/isis_adjacency.h"
39 #include "isisd/isisd.h"
40 #include "isisd/isis_lsp.h"
41 #include "isisd/isis_pdu.h"
42 #include "isisd/isis_dynhn.h"
43 #include "isisd/isis_misc.h"
44 #include "isisd/isis_csm.h"
45 #include "isisd/isis_adjacency.h"
46 #include "isisd/isis_spf.h"
47 #include "isisd/isis_tlvs.h"
48 #include "isisd/isis_mt.h"
49 #include "isisd/isis_te.h"
50 #include "isisd/isis_zebra.h"
51
52 DEFINE_MTYPE_STATIC(ISISD, ISIS_MPLS_TE, "ISIS MPLS_TE parameters");
53
54 static void isis_mpls_te_circuit_ip_update(struct isis_circuit *circuit);
55
56 /*------------------------------------------------------------------------*
57 * Following are control functions for MPLS-TE parameters management.
58 *------------------------------------------------------------------------*/
59
60 /**
61 * Create MPLS Traffic Engineering structure which belongs to given area.
62 *
63 * @param area IS-IS Area
64 */
65 void isis_mpls_te_create(struct isis_area *area)
66 {
67 struct listnode *node;
68 struct isis_circuit *circuit;
69
70 if (!area)
71 return;
72
73 if (area->mta == NULL) {
74
75 struct mpls_te_area *new;
76
77 zlog_debug("ISIS-TE(%s): Initialize MPLS Traffic Engineering",
78 area->area_tag);
79
80 new = XCALLOC(MTYPE_ISIS_MPLS_TE, sizeof(struct mpls_te_area));
81
82 /* Initialize MPLS_TE structure */
83 new->status = enable;
84 new->level = 0;
85 new->inter_as = off;
86 new->interas_areaid.s_addr = 0;
87 new->router_id.s_addr = 0;
88 new->ted = ls_ted_new(1, "ISIS", 0);
89 if (!new->ted)
90 zlog_warn("Unable to create Link State Data Base");
91
92 area->mta = new;
93 } else {
94 area->mta->status = enable;
95 }
96
97 /* Initialize Link State Database */
98 if (area->mta->ted)
99 isis_te_init_ted(area);
100
101 /* Update Extended TLVs according to Interface link parameters
102 * and neighbor IP addresses
103 */
104 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
105 isis_link_params_update(circuit, circuit->interface);
106 isis_mpls_te_circuit_ip_update(circuit);
107 }
108 }
109
110 /**
111 * Disable MPLS Traffic Engineering structure which belongs to given area.
112 *
113 * @param area IS-IS Area
114 */
115 void isis_mpls_te_disable(struct isis_area *area)
116 {
117 struct listnode *node;
118 struct isis_circuit *circuit;
119
120 if (!area->mta)
121 return;
122
123 area->mta->status = disable;
124
125 /* Remove Link State Database */
126 ls_ted_clean(area->mta->ted);
127
128 /* Disable Extended SubTLVs on all circuit */
129 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
130 if (!IS_EXT_TE(circuit->ext))
131 continue;
132
133 /* disable MPLS_TE Circuit keeping SR one's */
134 if (IS_SUBTLV(circuit->ext, EXT_ADJ_SID))
135 circuit->ext->status = EXT_ADJ_SID;
136 else if (IS_SUBTLV(circuit->ext, EXT_LAN_ADJ_SID))
137 circuit->ext->status = EXT_LAN_ADJ_SID;
138 else
139 circuit->ext->status = 0;
140 }
141 }
142
143 void isis_mpls_te_term(struct isis_area *area)
144 {
145 struct listnode *node;
146 struct isis_circuit *circuit;
147
148 if (!area->mta)
149 return;
150
151 zlog_info("TE(%s): Terminate MPLS TE", __func__);
152 /* Remove Link State Database */
153 ls_ted_del_all(&area->mta->ted);
154
155 /* Remove Extended SubTLVs */
156 zlog_info(" |- Remove Extended SubTLVS for all circuit");
157 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
158 zlog_info(" |- Call isis_del_ext_subtlvs()");
159 isis_del_ext_subtlvs(circuit->ext);
160 circuit->ext = NULL;
161 }
162
163 zlog_info(" |- Free MTA structure at %p", area->mta);
164 XFREE(MTYPE_ISIS_MPLS_TE, area->mta);
165 }
166
167 static void isis_link_params_update_asla(struct isis_circuit *circuit,
168 struct interface *ifp)
169 {
170 struct isis_asla_subtlvs *asla;
171 struct listnode *node, *nnode;
172 struct isis_ext_subtlvs *ext = circuit->ext;
173 int i;
174
175 if (!HAS_LINK_PARAMS(ifp)) {
176 list_delete_all_node(ext->aslas);
177 return;
178 }
179
180 #ifndef FABRICD
181 /* RFC 8919 Application Specific Link-Attributes
182 * is required by flex-algo application ISIS_SABM_FLAG_X
183 */
184 if (list_isempty(circuit->area->flex_algos->flex_algos))
185 isis_tlvs_free_asla(ext, ISIS_SABM_FLAG_X);
186 else
187 isis_tlvs_find_alloc_asla(ext, ISIS_SABM_FLAG_X);
188 #endif /* ifndef FABRICD */
189
190 if (list_isempty(ext->aslas))
191 return;
192
193 for (ALL_LIST_ELEMENTS(ext->aslas, node, nnode, asla)) {
194 asla->legacy = circuit->area->asla_legacy_flag;
195 RESET_SUBTLV(asla);
196
197 if (asla->legacy)
198 continue;
199
200 /* Fulfill ASLA subTLVs from interface link parameters */
201 if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) {
202 asla->admin_group = ifp->link_params->admin_grp;
203 SET_SUBTLV(asla, EXT_ADM_GRP);
204 } else
205 UNSET_SUBTLV(asla, EXT_ADM_GRP);
206
207 if (IS_PARAM_SET(ifp->link_params, LP_EXTEND_ADM_GRP)) {
208 admin_group_copy(&asla->ext_admin_group,
209 &ifp->link_params->ext_admin_grp);
210 SET_SUBTLV(asla, EXT_EXTEND_ADM_GRP);
211 } else
212 UNSET_SUBTLV(asla, EXT_EXTEND_ADM_GRP);
213
214 /* Send admin-group zero for better compatibility
215 * https://www.rfc-editor.org/rfc/rfc7308#section-2.3.2
216 */
217 if (circuit->area->admin_group_send_zero &&
218 !IS_SUBTLV(asla, EXT_ADM_GRP) &&
219 !IS_SUBTLV(asla, EXT_EXTEND_ADM_GRP)) {
220 asla->admin_group = 0;
221 SET_SUBTLV(asla, EXT_ADM_GRP);
222 admin_group_clear(&asla->ext_admin_group);
223 admin_group_allow_explicit_zero(&asla->ext_admin_group);
224 SET_SUBTLV(asla, EXT_EXTEND_ADM_GRP);
225 }
226
227 if (IS_PARAM_SET(ifp->link_params, LP_TE_METRIC)) {
228 asla->te_metric = ifp->link_params->te_metric;
229 SET_SUBTLV(asla, EXT_TE_METRIC);
230 } else
231 UNSET_SUBTLV(asla, EXT_TE_METRIC);
232
233 if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) {
234 asla->delay = ifp->link_params->av_delay;
235 SET_SUBTLV(asla, EXT_DELAY);
236 } else
237 UNSET_SUBTLV(asla, EXT_DELAY);
238
239 if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) {
240 asla->min_delay = ifp->link_params->min_delay;
241 asla->max_delay = ifp->link_params->max_delay;
242 SET_SUBTLV(asla, EXT_MM_DELAY);
243 } else {
244 UNSET_SUBTLV(asla, EXT_MM_DELAY);
245 }
246
247 if (asla->standard_apps == ISIS_SABM_FLAG_X)
248 /* Flex-Algo ASLA does not need the following TE
249 * sub-TLVs
250 */
251 continue;
252
253 if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) {
254 asla->max_bw = ifp->link_params->max_bw;
255 SET_SUBTLV(asla, EXT_MAX_BW);
256 } else
257 UNSET_SUBTLV(asla, EXT_MAX_BW);
258
259 if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) {
260 asla->max_rsv_bw = ifp->link_params->max_rsv_bw;
261 SET_SUBTLV(asla, EXT_MAX_RSV_BW);
262 } else
263 UNSET_SUBTLV(asla, EXT_MAX_RSV_BW);
264
265 if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) {
266 for (i = 0; i < MAX_CLASS_TYPE; i++)
267 asla->unrsv_bw[i] =
268 ifp->link_params->unrsv_bw[i];
269 SET_SUBTLV(asla, EXT_UNRSV_BW);
270 } else
271 UNSET_SUBTLV(asla, EXT_UNRSV_BW);
272
273 if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) {
274 asla->delay_var = ifp->link_params->delay_var;
275 SET_SUBTLV(asla, EXT_DELAY_VAR);
276 } else
277 UNSET_SUBTLV(asla, EXT_DELAY_VAR);
278
279 if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) {
280 asla->pkt_loss = ifp->link_params->pkt_loss;
281 SET_SUBTLV(asla, EXT_PKT_LOSS);
282 } else
283 UNSET_SUBTLV(asla, EXT_PKT_LOSS);
284
285 if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) {
286 asla->res_bw = ifp->link_params->res_bw;
287 SET_SUBTLV(asla, EXT_RES_BW);
288 } else
289 UNSET_SUBTLV(asla, EXT_RES_BW);
290
291 if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) {
292 asla->ava_bw = ifp->link_params->ava_bw;
293 SET_SUBTLV(asla, EXT_AVA_BW);
294 } else
295 UNSET_SUBTLV(asla, EXT_AVA_BW);
296
297 if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) {
298 asla->use_bw = ifp->link_params->use_bw;
299 SET_SUBTLV(asla, EXT_USE_BW);
300 } else
301 UNSET_SUBTLV(asla, EXT_USE_BW);
302 }
303
304
305 for (ALL_LIST_ELEMENTS(ext->aslas, node, nnode, asla)) {
306 if (!asla->legacy && NO_SUBTLV(asla) &&
307 admin_group_nb_words(&asla->ext_admin_group) == 0)
308 /* remove ASLA without info from the list of ASLAs to
309 * not send void ASLA
310 */
311 isis_tlvs_del_asla_flex_algo(ext, asla);
312 }
313 }
314
315 /* Main initialization / update function of the MPLS TE Circuit context */
316 /* Call when interface TE Link parameters are modified */
317 void isis_link_params_update(struct isis_circuit *circuit,
318 struct interface *ifp)
319 {
320 int i;
321 struct prefix_ipv4 *addr;
322 struct prefix_ipv6 *addr6;
323 struct isis_ext_subtlvs *ext;
324
325 /* Check if TE is enable or not */
326 if (!circuit->area || !IS_MPLS_TE(circuit->area->mta))
327 return;
328
329 /* Sanity Check */
330 if ((ifp == NULL) || (circuit->state != C_STATE_UP))
331 return;
332
333 te_debug("ISIS-TE(%s): Update circuit parameters for interface %s",
334 circuit->area->area_tag, ifp->name);
335
336 /* Check if MPLS TE Circuit context has not been already created */
337 if (circuit->ext == NULL) {
338 circuit->ext = isis_alloc_ext_subtlvs();
339 te_debug(" |- Allocated new Ext-subTLVs for interface %s",
340 ifp->name);
341 }
342
343 ext = circuit->ext;
344
345 /* Fulfill Extended subTLVs from interface link parameters */
346 if (HAS_LINK_PARAMS(ifp)) {
347 /* STD_TE metrics */
348 if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) {
349 ext->adm_group = ifp->link_params->admin_grp;
350 SET_SUBTLV(ext, EXT_ADM_GRP);
351 } else
352 UNSET_SUBTLV(ext, EXT_ADM_GRP);
353
354 if (IS_PARAM_SET(ifp->link_params, LP_EXTEND_ADM_GRP)) {
355 admin_group_copy(&ext->ext_admin_group,
356 &ifp->link_params->ext_admin_grp);
357 SET_SUBTLV(ext, EXT_EXTEND_ADM_GRP);
358 } else
359 UNSET_SUBTLV(ext, EXT_EXTEND_ADM_GRP);
360
361 /* Send admin-group zero for better compatibility
362 * https://www.rfc-editor.org/rfc/rfc7308#section-2.3.2
363 */
364 if (circuit->area->admin_group_send_zero &&
365 !IS_SUBTLV(ext, EXT_ADM_GRP) &&
366 !IS_SUBTLV(ext, EXT_EXTEND_ADM_GRP)) {
367 ext->adm_group = 0;
368 SET_SUBTLV(ext, EXT_ADM_GRP);
369 admin_group_clear(&ext->ext_admin_group);
370 admin_group_allow_explicit_zero(&ext->ext_admin_group);
371 SET_SUBTLV(ext, EXT_EXTEND_ADM_GRP);
372 }
373
374 /* If known, register local IPv4 addr from ip_addr list */
375 if (listcount(circuit->ip_addrs) != 0) {
376 addr = (struct prefix_ipv4 *)listgetdata(
377 (struct listnode *)listhead(circuit->ip_addrs));
378 IPV4_ADDR_COPY(&ext->local_addr, &addr->prefix);
379 SET_SUBTLV(ext, EXT_LOCAL_ADDR);
380 } else
381 UNSET_SUBTLV(ext, EXT_LOCAL_ADDR);
382
383 /* If known, register local IPv6 addr from ip_addr list */
384 if (listcount(circuit->ipv6_non_link) != 0) {
385 addr6 = (struct prefix_ipv6 *)listgetdata(
386 (struct listnode *)listhead(
387 circuit->ipv6_non_link));
388 IPV6_ADDR_COPY(&ext->local_addr6, &addr6->prefix);
389 SET_SUBTLV(ext, EXT_LOCAL_ADDR6);
390 } else
391 UNSET_SUBTLV(ext, EXT_LOCAL_ADDR6);
392
393 /*
394 * Remote IPv4 and IPv6 addresses are now added in
395 * isis_mpls_te_adj_ip_enabled() to get the right IP address
396 * in particular for IPv6 to get the global IPv6 address and
397 * not the link-local IPv6 address.
398 */
399
400 if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) {
401 ext->max_bw = ifp->link_params->max_bw;
402 SET_SUBTLV(ext, EXT_MAX_BW);
403 } else
404 UNSET_SUBTLV(ext, EXT_MAX_BW);
405
406 if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) {
407 ext->max_rsv_bw = ifp->link_params->max_rsv_bw;
408 SET_SUBTLV(ext, EXT_MAX_RSV_BW);
409 } else
410 UNSET_SUBTLV(ext, EXT_MAX_RSV_BW);
411
412 if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) {
413 for (i = 0; i < MAX_CLASS_TYPE; i++)
414 ext->unrsv_bw[i] =
415 ifp->link_params->unrsv_bw[i];
416 SET_SUBTLV(ext, EXT_UNRSV_BW);
417 } else
418 UNSET_SUBTLV(ext, EXT_UNRSV_BW);
419
420 if (IS_PARAM_SET(ifp->link_params, LP_TE_METRIC)) {
421 ext->te_metric = ifp->link_params->te_metric;
422 SET_SUBTLV(ext, EXT_TE_METRIC);
423 } else
424 UNSET_SUBTLV(ext, EXT_TE_METRIC);
425
426 /* TE metric extensions */
427 if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) {
428 ext->delay = ifp->link_params->av_delay;
429 SET_SUBTLV(ext, EXT_DELAY);
430 } else
431 UNSET_SUBTLV(ext, EXT_DELAY);
432
433 if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) {
434 ext->min_delay = ifp->link_params->min_delay;
435 ext->max_delay = ifp->link_params->max_delay;
436 SET_SUBTLV(ext, EXT_MM_DELAY);
437 } else
438 UNSET_SUBTLV(ext, EXT_MM_DELAY);
439
440 if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) {
441 ext->delay_var = ifp->link_params->delay_var;
442 SET_SUBTLV(ext, EXT_DELAY_VAR);
443 } else
444 UNSET_SUBTLV(ext, EXT_DELAY_VAR);
445
446 if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) {
447 ext->pkt_loss = ifp->link_params->pkt_loss;
448 SET_SUBTLV(ext, EXT_PKT_LOSS);
449 } else
450 UNSET_SUBTLV(ext, EXT_PKT_LOSS);
451
452 if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) {
453 ext->res_bw = ifp->link_params->res_bw;
454 SET_SUBTLV(ext, EXT_RES_BW);
455 } else
456 UNSET_SUBTLV(ext, EXT_RES_BW);
457
458 if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) {
459 ext->ava_bw = ifp->link_params->ava_bw;
460 SET_SUBTLV(ext, EXT_AVA_BW);
461 } else
462 UNSET_SUBTLV(ext, EXT_AVA_BW);
463
464 if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) {
465 ext->use_bw = ifp->link_params->use_bw;
466 SET_SUBTLV(ext, EXT_USE_BW);
467 } else
468 UNSET_SUBTLV(ext, EXT_USE_BW);
469
470 /* INTER_AS */
471 if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS)) {
472 ext->remote_as = ifp->link_params->rmt_as;
473 ext->remote_ip = ifp->link_params->rmt_ip;
474 SET_SUBTLV(ext, EXT_RMT_AS);
475 SET_SUBTLV(ext, EXT_RMT_IP);
476 } else {
477 /* reset inter-as TE params */
478 UNSET_SUBTLV(ext, EXT_RMT_AS);
479 UNSET_SUBTLV(ext, EXT_RMT_IP);
480 }
481 te_debug(" |- New MPLS-TE link parameters status 0x%x",
482 ext->status);
483 } else {
484 te_debug(" |- Reset Extended subTLVs status 0x%x",
485 ext->status);
486 /* Reset TE subTLVs keeping SR one's */
487 if (IS_SUBTLV(ext, EXT_ADJ_SID))
488 ext->status = EXT_ADJ_SID;
489 else if (IS_SUBTLV(ext, EXT_LAN_ADJ_SID))
490 ext->status = EXT_LAN_ADJ_SID;
491 else
492 ext->status = 0;
493 }
494
495 isis_link_params_update_asla(circuit, ifp);
496
497 return;
498 }
499
500 static int _isis_mpls_te_adj_ip_enabled(struct isis_adjacency *adj, int family,
501 bool global)
502 {
503 struct isis_circuit *circuit;
504 struct isis_ext_subtlvs *ext;
505
506 circuit = adj->circuit;
507
508 /* Check that MPLS TE is enabled */
509 if (!IS_MPLS_TE(circuit->area->mta) || !circuit->ext)
510 return 0;
511
512 ext = circuit->ext;
513
514 /* Determine nexthop IP address */
515 switch (family) {
516 case AF_INET:
517 if (!circuit->ip_router || !adj->ipv4_address_count)
518 UNSET_SUBTLV(ext, EXT_NEIGH_ADDR);
519 else {
520 IPV4_ADDR_COPY(&ext->neigh_addr,
521 &adj->ipv4_addresses[0]);
522 SET_SUBTLV(ext, EXT_NEIGH_ADDR);
523 }
524 break;
525 case AF_INET6:
526 /* Nothing to do for link-local addresses - ie. not global.
527 * https://datatracker.ietf.org/doc/html/rfc6119#section-3.1.1
528 * Because the IPv6 traffic engineering TLVs present in LSPs are
529 * propagated across networks, they MUST NOT use link-local
530 * addresses.
531 */
532 if (!global)
533 return 0;
534
535 if (!circuit->ipv6_router || !adj->global_ipv6_count)
536 UNSET_SUBTLV(ext, EXT_NEIGH_ADDR6);
537 else {
538 IPV6_ADDR_COPY(&ext->neigh_addr6,
539 &adj->global_ipv6_addrs[0]);
540 SET_SUBTLV(ext, EXT_NEIGH_ADDR6);
541 }
542 break;
543 default:
544 return 0;
545 }
546
547 return 0;
548 }
549
550 static int isis_mpls_te_adj_ip_enabled(struct isis_adjacency *adj, int family,
551 bool global)
552 {
553 int ret;
554
555 /* Sanity Check */
556 if (!adj || !adj->circuit)
557 return 0;
558
559 ret = _isis_mpls_te_adj_ip_enabled(adj, family, global);
560
561 /* Update LSP */
562 lsp_regenerate_schedule(adj->circuit->area, adj->circuit->is_type, 0);
563
564 return ret;
565 }
566
567 static int _isis_mpls_te_adj_ip_disabled(struct isis_adjacency *adj, int family,
568 bool global)
569 {
570 struct isis_circuit *circuit;
571 struct isis_ext_subtlvs *ext;
572
573 circuit = adj->circuit;
574
575 /* Check that MPLS TE is enabled */
576 if (!IS_MPLS_TE(circuit->area->mta) || !circuit->ext)
577 return 0;
578
579 ext = circuit->ext;
580
581 /* Update MPLS TE IP address parameters if possible */
582 if (!IS_MPLS_TE(circuit->area->mta) || !IS_EXT_TE(ext))
583 return 0;
584
585 /* Determine nexthop IP address */
586 switch (family) {
587 case AF_INET:
588 UNSET_SUBTLV(ext, EXT_NEIGH_ADDR);
589 break;
590 case AF_INET6:
591 if (global)
592 UNSET_SUBTLV(ext, EXT_NEIGH_ADDR6);
593 break;
594 default:
595 return 0;
596 }
597
598 return 0;
599 }
600
601 static int isis_mpls_te_adj_ip_disabled(struct isis_adjacency *adj, int family,
602 bool global)
603 {
604 int ret;
605
606 /* Sanity Check */
607 if (!adj || !adj->circuit || !adj->circuit->ext)
608 return 0;
609
610 ret = _isis_mpls_te_adj_ip_disabled(adj, family, global);
611
612 /* Update LSP */
613 lsp_regenerate_schedule(adj->circuit->area, adj->circuit->is_type, 0);
614
615 return ret;
616 }
617
618 static void isis_mpls_te_circuit_ip_update(struct isis_circuit *circuit)
619 {
620 struct isis_adjacency *adj;
621
622 /* https://datatracker.ietf.org/doc/html/rfc6119#section-3.2.3
623 * This sub-TLV of the Extended IS Reachability TLV is used for point-
624 * to-point links
625 */
626 if (circuit->circ_type != CIRCUIT_T_P2P)
627 return;
628
629 adj = circuit->u.p2p.neighbor;
630
631 if (!adj)
632 return;
633
634 /* Nothing to do for link-local addresses.
635 * https://datatracker.ietf.org/doc/html/rfc6119#section-3.1.1
636 * Because the IPv6 traffic engineering TLVs present in LSPs are
637 * propagated across networks, they MUST NOT use link-local addresses.
638 */
639 if (adj->ipv4_address_count > 0)
640 _isis_mpls_te_adj_ip_enabled(adj, AF_INET, false);
641 else
642 _isis_mpls_te_adj_ip_disabled(adj, AF_INET, false);
643
644 if (adj->global_ipv6_count > 0)
645 _isis_mpls_te_adj_ip_enabled(adj, AF_INET6, true);
646 else
647 _isis_mpls_te_adj_ip_disabled(adj, AF_INET6, true);
648 }
649
650
651 int isis_mpls_te_update(struct interface *ifp)
652 {
653 struct isis_circuit *circuit;
654 uint8_t rc = 1;
655
656 /* Sanity Check */
657 if (ifp == NULL)
658 return rc;
659
660 /* Get circuit context from interface */
661 circuit = circuit_scan_by_ifp(ifp);
662 if (circuit == NULL)
663 return rc;
664
665 /* Update TE TLVs ... */
666 isis_link_params_update(circuit, ifp);
667
668 /* ... and LSP */
669 if (circuit->area &&
670 (IS_MPLS_TE(circuit->area->mta)
671 #ifndef FABRICD
672 || !list_isempty(circuit->area->flex_algos->flex_algos)
673 #endif /* ifndef FABRICD */
674 ))
675 lsp_regenerate_schedule(circuit->area, circuit->is_type, 0);
676
677 rc = 0;
678 return rc;
679 }
680
681
682 /**
683 * Export Link State information to consumer daemon through ZAPI Link State
684 * Opaque Message.
685 *
686 * @param type Type of Link State Element i.e. Vertex, Edge or Subnet
687 * @param link_state Pointer to Link State Vertex, Edge or Subnet
688 *
689 * @return 0 if success, -1 otherwise
690 */
691 static int isis_te_export(uint8_t type, void *link_state)
692 {
693 struct ls_message msg = {};
694 int rc = 0;
695
696 switch (type) {
697 case LS_MSG_TYPE_NODE:
698 ls_vertex2msg(&msg, (struct ls_vertex *)link_state);
699 rc = ls_send_msg(zclient, &msg, NULL);
700 break;
701 case LS_MSG_TYPE_ATTRIBUTES:
702 ls_edge2msg(&msg, (struct ls_edge *)link_state);
703 rc = ls_send_msg(zclient, &msg, NULL);
704 break;
705 case LS_MSG_TYPE_PREFIX:
706 ls_subnet2msg(&msg, (struct ls_subnet *)link_state);
707 rc = ls_send_msg(zclient, &msg, NULL);
708 break;
709 default:
710 rc = -1;
711 break;
712 }
713
714 return rc;
715 }
716
717 /**
718 * Parse LSP and build corresponding vertex. If vertex doesn't exist in the
719 * Link State Database it is created otherwise updated.
720 *
721 * @param ted Traffic Engineering Link State Database
722 * @param lsp IS-IS Link State PDU
723 *
724 * @return Link State Vertex or NULL in case of error
725 */
726 static struct ls_vertex *lsp_to_vertex(struct ls_ted *ted, struct isis_lsp *lsp)
727 {
728 struct ls_vertex *vertex = NULL;
729 struct ls_node *old, lnode = {};
730 struct isis_tlvs *tlvs;
731 const struct in_addr inaddr_any = {.s_addr = INADDR_ANY};
732
733 /* Sanity check */
734 if (!ted || !lsp)
735 return NULL;
736
737 /* Compute Link State Node ID from IS-IS sysID ... */
738 if (lsp->level == ISIS_LEVEL1)
739 lnode.adv.origin = ISIS_L1;
740 else
741 lnode.adv.origin = ISIS_L2;
742 memcpy(&lnode.adv.id.iso.sys_id, &lsp->hdr.lsp_id, ISIS_SYS_ID_LEN);
743 lnode.adv.id.iso.level = lsp->level;
744 /* ... and search the corresponding vertex */
745 vertex = ls_find_vertex_by_id(ted, lnode.adv);
746 /* Create a new one if not found */
747 if (!vertex) {
748 old = ls_node_new(lnode.adv, inaddr_any, in6addr_any);
749 old->type = STANDARD;
750 vertex = ls_vertex_add(ted, old);
751 }
752 old = vertex->node;
753 te_debug(" |- %s Vertex (%" PRIu64 ") for node %s",
754 vertex->status == NEW ? "Create" : "Found", vertex->key,
755 print_sys_hostname(old->adv.id.iso.sys_id));
756
757 /* Fulfill Link State Node information */
758 tlvs = lsp->tlvs;
759 if (tlvs) {
760 if (tlvs->te_router_id) {
761 IPV4_ADDR_COPY(&lnode.router_id, tlvs->te_router_id);
762 SET_FLAG(lnode.flags, LS_NODE_ROUTER_ID);
763 }
764 if (tlvs->te_router_id_ipv6) {
765 IPV6_ADDR_COPY(&lnode.router_id6,
766 tlvs->te_router_id_ipv6);
767 SET_FLAG(lnode.flags, LS_NODE_ROUTER_ID6);
768 }
769 if (tlvs->hostname) {
770 strlcpy(lnode.name, tlvs->hostname, MAX_NAME_LENGTH);
771 SET_FLAG(lnode.flags, LS_NODE_NAME);
772 }
773 if (tlvs->router_cap) {
774 struct isis_router_cap *cap = tlvs->router_cap;
775
776 if (cap->srgb.lower_bound != 0
777 && cap->srgb.range_size != 0) {
778 SET_FLAG(lnode.flags, LS_NODE_SR);
779 lnode.srgb.flag = cap->srgb.flags;
780 lnode.srgb.lower_bound = cap->srgb.lower_bound;
781 lnode.srgb.range_size = cap->srgb.range_size;
782 for (int i = 0; i < LIB_LS_SR_ALGO_COUNT; i++)
783 lnode.algo[i] = cap->algo[i];
784 }
785
786 if (cap->srlb.lower_bound != 0
787 && cap->srlb.range_size != 0) {
788 lnode.srlb.lower_bound = cap->srlb.lower_bound;
789 lnode.srlb.range_size = cap->srlb.range_size;
790 SET_FLAG(lnode.flags, LS_NODE_SRLB);
791 }
792 if (cap->msd != 0) {
793 lnode.msd = cap->msd;
794 SET_FLAG(lnode.flags, LS_NODE_MSD);
795 }
796 }
797 }
798
799 /* Update Link State Node information */
800 if (!ls_node_same(old, &lnode)) {
801 te_debug(" |- Update Link State Node information");
802 memcpy(old, &lnode, sizeof(struct ls_node));
803 if (vertex->status != NEW)
804 vertex->status = UPDATE;
805 }
806
807 /* Set self TED vertex if LSP corresponds to the own router */
808 if (lsp->own_lsp)
809 ted->self = vertex;
810
811 return vertex;
812 }
813
814 /**
815 * Get Link State Edge from Link State Attributes in TE Database.
816 * Edge structure is dynamically allocated and fulfill with Link State
817 * Attributes if not found.
818 *
819 * @param ted Link State Database
820 * @param attr Link State Attributes
821 *
822 * @return New Link State Edge if success, NULL otherwise
823 */
824 static struct ls_edge *get_edge(struct ls_ted *ted, struct ls_attributes *attr)
825 {
826 struct ls_edge *edge;
827 struct ls_standard *std;
828 struct ls_edge_key key;
829
830 /* Check parameters */
831 if (!ted || !attr)
832 return NULL;
833
834 std = &attr->standard;
835
836 /* Compute keys in function of local address (IPv4/v6) or identifier */
837 if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR)) {
838 key.family = AF_INET;
839 IPV4_ADDR_COPY(&key.k.addr, &std->local);
840 } else if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR6)) {
841 key.family = AF_INET6;
842 IPV6_ADDR_COPY(&key.k.addr6, &std->local6);
843 } else if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ID)) {
844 key.family = AF_LOCAL;
845 key.k.link_id = (((uint64_t)std->local_id) & 0xffffffff) |
846 ((uint64_t)std->remote_id << 32);
847 } else {
848 key.family = AF_UNSPEC;
849 }
850
851 /* Stop here if we don't got a valid key */
852 if (key.family == AF_UNSPEC)
853 return NULL;
854
855 /* Get corresponding Edge by key from Link State Data Base */
856 edge = ls_find_edge_by_key(ted, key);
857
858 /* and create new one if not exist */
859 if (!edge) {
860 edge = ls_edge_add(ted, attr);
861 /*
862 * Edge could be Null if no local ID is found in Attributes.
863 * Stop the processing as without any local ID it is not
864 * possible to store Edge in the TED.
865 */
866 if (!edge)
867 return NULL;
868 }
869
870 if (CHECK_FLAG(edge->attributes->flags, LS_ATTR_LOCAL_ADDR))
871 te_debug(" |- %s Edge (%pI4) from Extended Reach. %pI4",
872 edge->status == NEW ? "Create" : "Found",
873 &edge->key.k.addr, &attr->standard.local);
874 else if (CHECK_FLAG(edge->attributes->flags, LS_ATTR_LOCAL_ADDR6))
875 te_debug(" |- %s Edge (%pI6) from Extended Reach. %pI6",
876 edge->status == NEW ? "Create" : "Found",
877 &edge->key.k.addr6, &attr->standard.local6);
878 else
879 te_debug(" |- %s Edge (%" PRIu64 ")",
880 edge->status == NEW ? "Create" : "Found",
881 edge->key.k.link_id);
882
883 return edge;
884 }
885
886 /**
887 * Get Link State Attributes from IS-IS Sub-TLVs. Structure is dynamically
888 * allocated and should be free once not use anymore.
889 *
890 * @param adv Link State Node ID
891 * @param tlvs IS-IS Sub TLVs
892 *
893 * @return New Link State attributes if success, NULL otherwise
894 */
895 static struct ls_attributes *get_attributes(struct ls_node_id adv,
896 struct isis_ext_subtlvs *tlvs)
897 {
898 struct ls_attributes *attr;
899 struct in_addr local = {.s_addr = INADDR_ANY};
900 struct in6_addr local6 = in6addr_any;
901 uint32_t local_id = 0;
902
903 /* Got Local identifier */
904 if (CHECK_FLAG(tlvs->status, EXT_LOCAL_ADDR))
905 local.s_addr = tlvs->local_addr.s_addr;
906
907 if (CHECK_FLAG(tlvs->status, EXT_LOCAL_ADDR6))
908 memcpy(&local6, &tlvs->local_addr6, IPV6_MAX_BYTELEN);
909
910 if (CHECK_FLAG(tlvs->status, EXT_LLRI))
911 local_id = tlvs->local_llri;
912
913 /* Create LS Attributes */
914 attr = ls_attributes_new(adv, local, local6, local_id);
915 if (!attr)
916 return NULL;
917
918 /* Browse sub-TLV and fulfill Link State Attributes */
919 if (CHECK_FLAG(tlvs->status, EXT_ADM_GRP)) {
920 attr->standard.admin_group = tlvs->adm_group;
921 SET_FLAG(attr->flags, LS_ATTR_ADM_GRP);
922 }
923 if (CHECK_FLAG(tlvs->status, EXT_EXTEND_ADM_GRP)) {
924 admin_group_copy(&attr->ext_admin_group,
925 &tlvs->ext_admin_group);
926 SET_FLAG(attr->flags, LS_ATTR_EXT_ADM_GRP);
927 }
928 if (CHECK_FLAG(tlvs->status, EXT_LLRI)) {
929 attr->standard.local_id = tlvs->local_llri;
930 attr->standard.remote_id = tlvs->remote_llri;
931 SET_FLAG(attr->flags, LS_ATTR_LOCAL_ID);
932 SET_FLAG(attr->flags, LS_ATTR_NEIGH_ID);
933 }
934 if (CHECK_FLAG(tlvs->status, EXT_NEIGH_ADDR)) {
935 attr->standard.remote.s_addr = tlvs->neigh_addr.s_addr;
936 SET_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR);
937 }
938 if (CHECK_FLAG(tlvs->status, EXT_NEIGH_ADDR6)) {
939 memcpy(&attr->standard.remote6, &tlvs->neigh_addr6,
940 IPV6_MAX_BYTELEN);
941 SET_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR6);
942 }
943 if (CHECK_FLAG(tlvs->status, EXT_MAX_BW)) {
944 attr->standard.max_bw = tlvs->max_bw;
945 SET_FLAG(attr->flags, LS_ATTR_MAX_BW);
946 }
947 if (CHECK_FLAG(tlvs->status, EXT_MAX_RSV_BW)) {
948 attr->standard.max_rsv_bw = tlvs->max_rsv_bw;
949 SET_FLAG(attr->flags, LS_ATTR_MAX_RSV_BW);
950 }
951 if (CHECK_FLAG(tlvs->status, EXT_UNRSV_BW)) {
952 memcpy(&attr->standard.unrsv_bw, tlvs->unrsv_bw,
953 ISIS_SUBTLV_UNRSV_BW_SIZE);
954 SET_FLAG(attr->flags, LS_ATTR_UNRSV_BW);
955 }
956 if (CHECK_FLAG(tlvs->status, EXT_TE_METRIC)) {
957 attr->standard.te_metric = tlvs->te_metric;
958 SET_FLAG(attr->flags, LS_ATTR_TE_METRIC);
959 }
960 if (CHECK_FLAG(tlvs->status, EXT_RMT_AS)) {
961 attr->standard.remote_as = tlvs->remote_as;
962 SET_FLAG(attr->flags, LS_ATTR_REMOTE_AS);
963 }
964 if (CHECK_FLAG(tlvs->status, EXT_RMT_IP)) {
965 attr->standard.remote_addr = tlvs->remote_ip;
966 SET_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR);
967 }
968 if (CHECK_FLAG(tlvs->status, EXT_DELAY)) {
969 attr->extended.delay = tlvs->delay;
970 SET_FLAG(attr->flags, LS_ATTR_DELAY);
971 }
972 if (CHECK_FLAG(tlvs->status, EXT_MM_DELAY)) {
973 attr->extended.min_delay = tlvs->min_delay;
974 attr->extended.max_delay = tlvs->max_delay;
975 SET_FLAG(attr->flags, LS_ATTR_MIN_MAX_DELAY);
976 }
977 if (CHECK_FLAG(tlvs->status, EXT_DELAY_VAR)) {
978 attr->extended.jitter = tlvs->delay_var;
979 SET_FLAG(attr->flags, LS_ATTR_JITTER);
980 }
981 if (CHECK_FLAG(tlvs->status, EXT_PKT_LOSS)) {
982 attr->extended.pkt_loss = tlvs->pkt_loss;
983 SET_FLAG(attr->flags, LS_ATTR_PACKET_LOSS);
984 }
985 if (CHECK_FLAG(tlvs->status, EXT_AVA_BW)) {
986 attr->extended.ava_bw = tlvs->ava_bw;
987 SET_FLAG(attr->flags, LS_ATTR_AVA_BW);
988 }
989 if (CHECK_FLAG(tlvs->status, EXT_RES_BW)) {
990 attr->extended.rsv_bw = tlvs->res_bw;
991 SET_FLAG(attr->flags, LS_ATTR_RSV_BW);
992 }
993 if (CHECK_FLAG(tlvs->status, EXT_USE_BW)) {
994 attr->extended.used_bw = tlvs->use_bw;
995 SET_FLAG(attr->flags, LS_ATTR_USE_BW);
996 }
997 if (CHECK_FLAG(tlvs->status, EXT_ADJ_SID)) {
998 struct isis_adj_sid *adj =
999 (struct isis_adj_sid *)tlvs->adj_sid.head;
1000 int i;
1001 for (; adj; adj = adj->next) {
1002 i = adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? 1 : 0;
1003 i += adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? 2 : 0;
1004 attr->adj_sid[i].flags = adj->flags;
1005 attr->adj_sid[i].weight = adj->weight;
1006 attr->adj_sid[i].sid = adj->sid;
1007 switch (i) {
1008 case ADJ_PRI_IPV4:
1009 SET_FLAG(attr->flags, LS_ATTR_ADJ_SID);
1010 break;
1011 case ADJ_BCK_IPV4:
1012 SET_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID);
1013 break;
1014 case ADJ_PRI_IPV6:
1015 SET_FLAG(attr->flags, LS_ATTR_ADJ_SID6);
1016 break;
1017 case ADJ_BCK_IPV6:
1018 SET_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID6);
1019 break;
1020 }
1021 }
1022 }
1023 if (CHECK_FLAG(tlvs->status, EXT_LAN_ADJ_SID)) {
1024 struct isis_lan_adj_sid *ladj =
1025 (struct isis_lan_adj_sid *)tlvs->lan_sid.head;
1026 int i;
1027 for (; ladj; ladj = ladj->next) {
1028 i = ladj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? 1 : 0;
1029 i += ladj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? 2 : 0;
1030 attr->adj_sid[i].flags = ladj->flags;
1031 attr->adj_sid[i].weight = ladj->weight;
1032 attr->adj_sid[i].sid = ladj->sid;
1033 memcpy(&attr->adj_sid[i].neighbor.sysid,
1034 &ladj->neighbor_id, ISIS_SYS_ID_LEN);
1035 switch (i) {
1036 case ADJ_PRI_IPV4:
1037 SET_FLAG(attr->flags, LS_ATTR_ADJ_SID);
1038 break;
1039 case ADJ_BCK_IPV4:
1040 SET_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID);
1041 break;
1042 case ADJ_PRI_IPV6:
1043 SET_FLAG(attr->flags, LS_ATTR_ADJ_SID6);
1044 break;
1045 case ADJ_BCK_IPV6:
1046 SET_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID6);
1047 break;
1048 }
1049 }
1050 }
1051
1052 return attr;
1053 }
1054
1055 /**
1056 * Parse Extended Reachability TLVs and create or update the corresponding
1057 * Link State Edge and Attributes. Vertex connections are also updated if
1058 * needed based on the remote IP address of the Edge and existing reverse Edge.
1059 *
1060 * @param id ID of Extended IS
1061 * @param metric Metric of the link
1062 * @param old_metric Boolean that indicate if it is an old metric (no TE)
1063 * @param tlvs SubTlvs that contains TE information
1064 * @param arg IS-IS TE argument (TED, Vertex, and export indication)
1065 *
1066 * @return 0 if success, -1 otherwise
1067 */
1068 static int lsp_to_edge_cb(const uint8_t *id, uint32_t metric, bool old_metric,
1069 struct isis_ext_subtlvs *tlvs, void *arg)
1070 {
1071 struct isis_te_args *args = (struct isis_te_args *)arg;
1072 struct ls_vertex *vertex;
1073 struct ls_edge *edge, *dst;
1074 struct ls_attributes *attr;
1075
1076 te_debug(" |- Process Extended IS for %pSY", id);
1077
1078 /* Check parameters */
1079 if (old_metric || !args || !tlvs)
1080 return LSP_ITER_CONTINUE;
1081
1082 /* Initialize Link State Attributes */
1083 vertex = args->vertex;
1084 attr = get_attributes(vertex->node->adv, tlvs);
1085 /*
1086 * Attributes may be Null if no local ID has been found in the LSP.
1087 * Stop processing here as without any local ID it is not possible to
1088 * create corresponding Edge in the TED.
1089 */
1090 if (!attr)
1091 return LSP_ITER_CONTINUE;
1092
1093 attr->metric = metric;
1094 SET_FLAG(attr->flags, LS_ATTR_METRIC);
1095
1096 /* Get corresponding Edge from Link State Data Base */
1097 edge = get_edge(args->ted, attr);
1098 /*
1099 * Edge could be Null if no local ID has been found in Attributes.
1100 * Stop processing here as without any local ID it is not possible to
1101 * create corresponding Edge in the TED.
1102 */
1103 if (!edge) {
1104 ls_attributes_del(attr);
1105 return LSP_ITER_CONTINUE;
1106 }
1107
1108 /* Update Attribute fields if there are different */
1109 if (edge->status != NEW) {
1110 if (!ls_attributes_same(edge->attributes, attr)) {
1111 te_debug(" |- Update Edge Attributes information");
1112 ls_attributes_del(edge->attributes);
1113 edge->attributes = attr;
1114 edge->status = UPDATE;
1115 } else {
1116 if (edge->attributes != attr)
1117 ls_attributes_del(attr);
1118 edge->status = SYNC;
1119 }
1120 }
1121
1122 /* Try to update remote Link from remote address or reachability ID */
1123 if (edge->key.family == AF_INET)
1124 te_debug(" |- Link Edge (%pI4) to destination vertex (%s)",
1125 &edge->key.k.addr, print_sys_hostname(id));
1126 else if (edge->key.family == AF_INET6)
1127 te_debug(" |- Link Edge (%pI6) to destination vertex (%s)",
1128 &edge->key.k.addr6, print_sys_hostname(id));
1129 else if (edge->key.family == AF_LOCAL)
1130 te_debug(" |- Link Edge (%" PRIu64
1131 ") to destination vertex (%s)",
1132 edge->key.k.link_id, print_sys_hostname(id));
1133 else
1134 te_debug(
1135 " |- Link Edge (Unknown) to destination vertex (%s)",
1136 print_sys_hostname(id));
1137
1138 dst = ls_find_edge_by_destination(args->ted, edge->attributes);
1139 if (dst) {
1140 /* Attach remote link if not set */
1141 if (edge->source && dst->destination == NULL) {
1142 vertex = edge->source;
1143 if (vertex->incoming_edges)
1144 listnode_add_sort_nodup(vertex->incoming_edges,
1145 dst);
1146 dst->destination = vertex;
1147 }
1148 /* and destination vertex to this edge if not set */
1149 if (dst->source && edge->destination == NULL) {
1150 vertex = dst->source;
1151 if (vertex->incoming_edges)
1152 listnode_add_sort_nodup(vertex->incoming_edges,
1153 edge);
1154 edge->destination = vertex;
1155 }
1156 } else {
1157 /* Search dst. Vertex by Extended Reach. ID if not found */
1158 if (edge->destination == NULL) {
1159 vertex = ls_find_vertex_by_key(args->ted,
1160 sysid_to_key(id));
1161 if (vertex && vertex->incoming_edges)
1162 listnode_add_sort_nodup(vertex->incoming_edges,
1163 edge);
1164 edge->destination = vertex;
1165 }
1166 }
1167
1168 /* Update status and Export Link State Edge if needed */
1169 if (edge->status != SYNC) {
1170 if (args->export)
1171 isis_te_export(LS_MSG_TYPE_ATTRIBUTES, edge);
1172 edge->status = SYNC;
1173 }
1174
1175 return LSP_ITER_CONTINUE;
1176 }
1177
1178 /**
1179 * Parse Extended IP Reachability or MT IPv6 Reachability TLVs and create or
1180 * update the corresponding Link State Subnet and Prefix.
1181 *
1182 * @param prefix Prefix associated to this subnet
1183 * @param metric Metric of this prefix
1184 * @param external Boolean to indicate if the prefix is external
1185 * @param subtlvs Subtlvs if any (mostly Segment Routing ID)
1186 * @param arg IS-IS TE argument (TED, Vertex, and export indication)
1187 *
1188 * @return 0 if success, -1 otherwise
1189 */
1190 static int lsp_to_subnet_cb(const struct prefix *prefix, uint32_t metric,
1191 bool external, struct isis_subtlvs *subtlvs,
1192 void *arg)
1193 {
1194 struct isis_te_args *args = (struct isis_te_args *)arg;
1195 struct ls_vertex *vertex;
1196 struct ls_subnet *subnet;
1197 struct ls_prefix *ls_pref;
1198 struct listnode *node;
1199 struct ls_edge *edge;
1200 struct ls_standard *std = NULL;
1201 struct prefix p;
1202
1203 /* Sanity Check */
1204 if (!args || !prefix)
1205 return LSP_ITER_CONTINUE;
1206
1207 te_debug(" |- Process Extended %s Reachability %pFX",
1208 prefix->family == AF_INET ? "IP" : "IPv6", prefix);
1209
1210 vertex = args->vertex;
1211
1212 /*
1213 * Prefix with mask different from /32 or /128 are advertised by at
1214 * least 2 nodes. To avoid subnet attached to undetermined vertex, and
1215 * gives the possibility to send the information to client e.g. BGP for
1216 * Link State advertisement, we adjust the prefix with the corresponding
1217 * IP address of the belonging interface when it is available. Other
1218 * prefixes are kept unchanged.
1219 */
1220 if (prefix->family == AF_INET && prefix->prefixlen < IPV4_MAX_BITLEN) {
1221 std = NULL;
1222 for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, node, edge)) {
1223 if (!CHECK_FLAG(edge->attributes->flags,
1224 LS_ATTR_LOCAL_ADDR))
1225 continue;
1226
1227 p.u.prefix4 = edge->attributes->standard.local;
1228 p.family = AF_INET;
1229 p.prefixlen = prefix->prefixlen;
1230 apply_mask_ipv4((struct prefix_ipv4 *)&p);
1231 if (IPV4_ADDR_SAME(&p.u.prefix4, &prefix->u.prefix4)) {
1232 std = &edge->attributes->standard;
1233 break;
1234 }
1235 }
1236 if (std)
1237 p.u.prefix4 = std->local;
1238
1239 } else if (prefix->family == AF_INET6
1240 && prefix->prefixlen < IPV6_MAX_BITLEN) {
1241 std = NULL;
1242 for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, node, edge)) {
1243 if (!CHECK_FLAG(edge->attributes->flags,
1244 LS_ATTR_LOCAL_ADDR6))
1245 continue;
1246
1247 p.u.prefix6 = edge->attributes->standard.local6;
1248 p.family = AF_INET6;
1249 p.prefixlen = prefix->prefixlen;
1250 apply_mask_ipv6((struct prefix_ipv6 *)&p);
1251 if (IPV6_ADDR_SAME(&p.u.prefix6, &prefix->u.prefix6)) {
1252 std = &edge->attributes->standard;
1253 break;
1254 }
1255 }
1256 if (std)
1257 p.u.prefix6 = std->local6;
1258 }
1259 if (!std)
1260 prefix_copy(&p, prefix);
1261 else {
1262 /* Remove old subnet if any before prefix adjustment */
1263 subnet = ls_find_subnet(args->ted, prefix);
1264 if (subnet) {
1265 if (args->export) {
1266 subnet->status = DELETE;
1267 isis_te_export(LS_MSG_TYPE_PREFIX, subnet);
1268 }
1269 te_debug(" |- Remove subnet with prefix %pFX",
1270 &subnet->key);
1271 ls_subnet_del_all(args->ted, subnet);
1272 }
1273 te_debug(" |- Adjust prefix %pFX with local address to: %pFX",
1274 prefix, &p);
1275 }
1276
1277 /* Search existing Subnet in TED ... */
1278 subnet = ls_find_subnet(args->ted, &p);
1279 /* ... and create a new Subnet if not found */
1280 if (!subnet) {
1281 ls_pref = ls_prefix_new(vertex->node->adv, &p);
1282 subnet = ls_subnet_add(args->ted, ls_pref);
1283 /* Stop processing if we are unable to create a new subnet */
1284 if (!subnet)
1285 return LSP_ITER_CONTINUE;
1286 }
1287 ls_pref = subnet->ls_pref;
1288
1289 te_debug(" |- %s Subnet from prefix %pFX",
1290 subnet->status == NEW ? "Create" : "Found", &p);
1291
1292 /* Update Metric */
1293 if (!CHECK_FLAG(ls_pref->flags, LS_PREF_METRIC)
1294 || (ls_pref->metric != metric)) {
1295 ls_pref->metric = metric;
1296 SET_FLAG(ls_pref->flags, LS_PREF_METRIC);
1297 if (subnet->status != NEW)
1298 subnet->status = UPDATE;
1299 } else {
1300 if (subnet->status == ORPHAN)
1301 subnet->status = SYNC;
1302 }
1303
1304 /* Update Prefix SID if any */
1305 if (subtlvs && subtlvs->prefix_sids.count != 0) {
1306 struct isis_prefix_sid *psid;
1307 struct ls_sid sr = {};
1308
1309 psid = (struct isis_prefix_sid *)subtlvs->prefix_sids.head;
1310 sr.algo = psid->algorithm;
1311 sr.sid_flag = psid->flags;
1312 sr.sid = psid->value;
1313
1314 if (!CHECK_FLAG(ls_pref->flags, LS_PREF_SR)
1315 || !memcmp(&ls_pref->sr, &sr, sizeof(struct ls_sid))) {
1316 memcpy(&ls_pref->sr, &sr, sizeof(struct ls_sid));
1317 SET_FLAG(ls_pref->flags, LS_PREF_SR);
1318 if (subnet->status != NEW)
1319 subnet->status = UPDATE;
1320 } else {
1321 if (subnet->status == ORPHAN)
1322 subnet->status = SYNC;
1323 }
1324 } else {
1325 if (CHECK_FLAG(ls_pref->flags, LS_PREF_SR)) {
1326 UNSET_FLAG(ls_pref->flags, LS_PREF_SR);
1327 if (subnet->status != NEW)
1328 subnet->status = UPDATE;
1329 } else {
1330 if (subnet->status == ORPHAN)
1331 subnet->status = SYNC;
1332 }
1333 }
1334
1335 /* Update status and Export Link State Edge if needed */
1336 if (subnet->status != SYNC) {
1337 if (args->export)
1338 isis_te_export(LS_MSG_TYPE_PREFIX, subnet);
1339 subnet->status = SYNC;
1340 }
1341
1342 return LSP_ITER_CONTINUE;
1343 }
1344
1345 /**
1346 * Parse ISIS LSP to fulfill the Link State Database
1347 *
1348 * @param ted Link State Database
1349 * @param lsp ISIS Link State PDU
1350 */
1351 static void isis_te_parse_lsp(struct mpls_te_area *mta, struct isis_lsp *lsp)
1352 {
1353 struct ls_ted *ted;
1354 struct ls_vertex *vertex;
1355 struct ls_edge *edge;
1356 struct ls_subnet *subnet;
1357 struct listnode *node;
1358 struct isis_te_args args;
1359
1360 /* Sanity Check */
1361 if (!IS_MPLS_TE(mta) || !mta->ted || !lsp)
1362 return;
1363
1364 ted = mta->ted;
1365
1366 te_debug("ISIS-TE(%s): Parse LSP %pSY", lsp->area->area_tag,
1367 lsp->hdr.lsp_id);
1368
1369 /* First parse LSP to obtain the corresponding Vertex */
1370 vertex = lsp_to_vertex(ted, lsp);
1371 if (!vertex) {
1372 zlog_warn("Unable to build Vertex from LSP %pSY. Abort!",
1373 lsp->hdr.lsp_id);
1374 return;
1375 }
1376
1377 /* Check if Vertex has been modified */
1378 if (vertex->status != SYNC) {
1379 /* Vertex is out of sync: export it if requested */
1380 if (IS_EXPORT_TE(mta))
1381 isis_te_export(LS_MSG_TYPE_NODE, vertex);
1382 vertex->status = SYNC;
1383 }
1384
1385 /* Mark outgoing Edges and Subnets as ORPHAN to detect deletion */
1386 for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, node, edge))
1387 edge->status = ORPHAN;
1388
1389 for (ALL_LIST_ELEMENTS_RO(vertex->prefixes, node, subnet))
1390 subnet->status = ORPHAN;
1391
1392 /* Process all Extended Reachability in LSP (all fragments) */
1393 args.ted = ted;
1394 args.vertex = vertex;
1395 args.export = mta->export;
1396 isis_lsp_iterate_is_reach(lsp, ISIS_MT_IPV4_UNICAST, lsp_to_edge_cb,
1397 &args);
1398
1399 isis_lsp_iterate_is_reach(lsp, ISIS_MT_IPV6_UNICAST, lsp_to_edge_cb,
1400 &args);
1401
1402 /* Process all Extended IP (v4 & v6) in LSP (all fragments) */
1403 isis_lsp_iterate_ip_reach(lsp, AF_INET, ISIS_MT_IPV4_UNICAST,
1404 lsp_to_subnet_cb, &args);
1405 isis_lsp_iterate_ip_reach(lsp, AF_INET6, ISIS_MT_IPV6_UNICAST,
1406 lsp_to_subnet_cb, &args);
1407 isis_lsp_iterate_ip_reach(lsp, AF_INET6, ISIS_MT_IPV4_UNICAST,
1408 lsp_to_subnet_cb, &args);
1409
1410 /* Clean remaining Orphan Edges or Subnets */
1411 if (IS_EXPORT_TE(mta))
1412 ls_vertex_clean(ted, vertex, zclient);
1413 else
1414 ls_vertex_clean(ted, vertex, NULL);
1415 }
1416
1417 /**
1418 * Delete Link State Database Vertex, Edge & Prefix that correspond to this
1419 * ISIS Link State PDU
1420 *
1421 * @param ted Link State Database
1422 * @param lsp ISIS Link State PDU
1423 */
1424 static void isis_te_delete_lsp(struct mpls_te_area *mta, struct isis_lsp *lsp)
1425 {
1426 struct ls_ted *ted;
1427 struct ls_vertex *vertex = NULL;
1428 struct ls_node lnode = {};
1429 struct ls_edge *edge;
1430 struct ls_subnet *subnet;
1431 struct listnode *nnode, *node;
1432
1433 /* Sanity Check */
1434 if (!IS_MPLS_TE(mta) || !mta->ted || !lsp)
1435 return;
1436
1437 te_debug("ISIS-TE(%s): Delete Link State TED objects from LSP %pSY",
1438 lsp->area->area_tag, lsp->hdr.lsp_id);
1439
1440 /* Compute Link State Node ID from IS-IS sysID ... */
1441 if (lsp->level == ISIS_LEVEL1)
1442 lnode.adv.origin = ISIS_L1;
1443 else
1444 lnode.adv.origin = ISIS_L2;
1445 memcpy(&lnode.adv.id.iso.sys_id, &lsp->hdr.lsp_id, ISIS_SYS_ID_LEN);
1446 lnode.adv.id.iso.level = lsp->level;
1447 ted = mta->ted;
1448 /* ... and search the corresponding vertex */
1449 vertex = ls_find_vertex_by_id(ted, lnode.adv);
1450 if (!vertex)
1451 return;
1452
1453 te_debug(" |- Delete Vertex %s", vertex->node->name);
1454
1455 /*
1456 * We can't use the ls_vertex_del_all() function if export TE is set,
1457 * as we must first advertise the client daemons of each removal.
1458 */
1459 /* Remove outgoing Edges */
1460 for (ALL_LIST_ELEMENTS(vertex->outgoing_edges, node, nnode, edge)) {
1461 if (IS_EXPORT_TE(mta)) {
1462 edge->status = DELETE;
1463 isis_te_export(LS_MSG_TYPE_ATTRIBUTES, edge);
1464 }
1465 ls_edge_del_all(ted, edge);
1466 }
1467
1468 /* Disconnect incoming Edges */
1469 for (ALL_LIST_ELEMENTS(vertex->incoming_edges, node, nnode, edge)) {
1470 ls_disconnect(vertex, edge, false);
1471 if (edge->source == NULL) {
1472 if (IS_EXPORT_TE(mta)) {
1473 edge->status = DELETE;
1474 isis_te_export(LS_MSG_TYPE_ATTRIBUTES, edge);
1475 }
1476 ls_edge_del_all(ted, edge);
1477 }
1478 }
1479
1480 /* Remove subnets */
1481 for (ALL_LIST_ELEMENTS(vertex->prefixes, node, nnode, subnet)) {
1482 if (IS_EXPORT_TE(mta)) {
1483 subnet->status = DELETE;
1484 isis_te_export(LS_MSG_TYPE_PREFIX, subnet);
1485 }
1486 ls_subnet_del_all(ted, subnet);
1487 }
1488
1489 /* Then remove Link State Node */
1490 if (IS_EXPORT_TE(mta)) {
1491 vertex->status = DELETE;
1492 isis_te_export(LS_MSG_TYPE_NODE, vertex);
1493 }
1494 ls_node_del(vertex->node);
1495
1496 /* Finally, remove Vertex */
1497 ls_vertex_del(ted, vertex);
1498 }
1499
1500 /**
1501 * Process ISIS LSP according to the event to add, update or remove
1502 * corresponding vertex, edge and prefix in the Link State database.
1503 * Since LSP could be fragmented, the function starts by searching the root LSP
1504 * to retrieve the complete LSP, including eventual fragment before processing
1505 * all of them.
1506 *
1507 * @param lsp ISIS Link State PDU
1508 * @param event LSP event: ADD, UPD, INC & DEL (TICK are ignored)
1509 *
1510 */
1511 void isis_te_lsp_event(struct isis_lsp *lsp, enum lsp_event event)
1512 {
1513 struct isis_area *area;
1514 struct isis_lsp *lsp0;
1515
1516 /* Sanity check */
1517 if (!lsp || !lsp->area)
1518 return;
1519
1520 area = lsp->area;
1521 if (!IS_MPLS_TE(area->mta))
1522 return;
1523
1524 /* Adjust LSP0 in case of fragment */
1525 if (LSP_FRAGMENT(lsp->hdr.lsp_id))
1526 lsp0 = lsp->lspu.zero_lsp;
1527 else
1528 lsp0 = lsp;
1529
1530 /* Then process event */
1531 switch (event) {
1532 case LSP_ADD:
1533 case LSP_UPD:
1534 case LSP_INC:
1535 isis_te_parse_lsp(area->mta, lsp0);
1536 break;
1537 case LSP_DEL:
1538 isis_te_delete_lsp(area->mta, lsp0);
1539 break;
1540 case LSP_UNKNOWN:
1541 case LSP_TICK:
1542 break;
1543 }
1544 }
1545
1546 /**
1547 * Send the whole Link State Traffic Engineering Database to the consumer that
1548 * request it through a ZAPI Link State Synchronous Opaque Message.
1549 *
1550 * @param info ZAPI Opaque message
1551 *
1552 * @return 0 if success, -1 otherwise
1553 */
1554 int isis_te_sync_ted(struct zapi_opaque_reg_info dst)
1555 {
1556 struct listnode *node, *inode;
1557 struct isis *isis;
1558 struct isis_area *area;
1559 struct mpls_te_area *mta;
1560 int rc = -1;
1561
1562 te_debug("ISIS-TE(%s): Received TED synchro from client %d", __func__,
1563 dst.proto);
1564 /* For each area, send TED if TE distribution is enabled */
1565 for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) {
1566 for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
1567 mta = area->mta;
1568 if (IS_MPLS_TE(mta) && IS_EXPORT_TE(mta)) {
1569 te_debug(" |- Export TED from area %s",
1570 area->area_tag);
1571 rc = ls_sync_ted(mta->ted, zclient, &dst);
1572 if (rc != 0)
1573 return rc;
1574 }
1575 }
1576 }
1577
1578 return rc;
1579 }
1580
1581 /**
1582 * Initialize the Link State database from the LSP already stored for this area
1583 *
1584 * @param area ISIS area
1585 */
1586 void isis_te_init_ted(struct isis_area *area)
1587 {
1588 struct isis_lsp *lsp;
1589
1590 /* Iterate over all lsp. */
1591 for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++)
1592 frr_each (lspdb, &area->lspdb[level - 1], lsp)
1593 isis_te_parse_lsp(area->mta, lsp);
1594 }
1595
1596 /* Following are vty command functions */
1597 #ifndef FABRICD
1598
1599 static void show_router_id(struct vty *vty, struct isis_area *area)
1600 {
1601 bool no_match = true;
1602
1603 vty_out(vty, "Area %s:\n", area->area_tag);
1604 if (area->mta->router_id.s_addr != 0) {
1605 vty_out(vty, " MPLS-TE IPv4 Router-Address: %pI4\n",
1606 &area->mta->router_id);
1607 no_match = false;
1608 }
1609 if (!IN6_IS_ADDR_UNSPECIFIED(&area->mta->router_id_ipv6)) {
1610 vty_out(vty, " MPLS-TE IPv6 Router-Address: %pI6\n",
1611 &area->mta->router_id_ipv6);
1612 no_match = false;
1613 }
1614 if (no_match)
1615 vty_out(vty, " N/A\n");
1616 }
1617
1618 DEFUN(show_isis_mpls_te_router,
1619 show_isis_mpls_te_router_cmd,
1620 "show " PROTO_NAME " [vrf <NAME|all>] mpls-te router",
1621 SHOW_STR
1622 PROTO_HELP
1623 VRF_CMD_HELP_STR "All VRFs\n"
1624 MPLS_TE_STR "Router information\n")
1625 {
1626
1627 struct listnode *anode, *inode;
1628 struct isis_area *area;
1629 struct isis *isis = NULL;
1630 const char *vrf_name = VRF_DEFAULT_NAME;
1631 bool all_vrf = false;
1632 int idx_vrf = 0;
1633
1634 if (!im) {
1635 vty_out(vty, "IS-IS Routing Process not enabled\n");
1636 return CMD_SUCCESS;
1637 }
1638 ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
1639 if (vrf_name) {
1640 if (all_vrf) {
1641 for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) {
1642 for (ALL_LIST_ELEMENTS_RO(isis->area_list,
1643 anode, area)) {
1644 if (!IS_MPLS_TE(area->mta))
1645 continue;
1646
1647 show_router_id(vty, area);
1648 }
1649 }
1650 return 0;
1651 }
1652 isis = isis_lookup_by_vrfname(vrf_name);
1653 if (isis != NULL) {
1654 for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode,
1655 area)) {
1656
1657 if (!IS_MPLS_TE(area->mta))
1658 continue;
1659
1660 show_router_id(vty, area);
1661 }
1662 }
1663 }
1664
1665 return CMD_SUCCESS;
1666 }
1667
1668 static void show_ext_sub(struct vty *vty, char *name,
1669 struct isis_ext_subtlvs *ext)
1670 {
1671 struct sbuf buf;
1672 char ibuf[PREFIX2STR_BUFFER];
1673
1674 sbuf_init(&buf, NULL, 0);
1675
1676 if (!ext || ext->status == EXT_DISABLE)
1677 return;
1678
1679 vty_out(vty, "-- MPLS-TE link parameters for %s --\n", name);
1680
1681 sbuf_reset(&buf);
1682
1683 if (IS_SUBTLV(ext, EXT_ADM_GRP))
1684 sbuf_push(&buf, 4, "Administrative Group: 0x%x\n",
1685 ext->adm_group);
1686 if (IS_SUBTLV(ext, EXT_LLRI)) {
1687 sbuf_push(&buf, 4, "Link Local ID: %u\n",
1688 ext->local_llri);
1689 sbuf_push(&buf, 4, "Link Remote ID: %u\n",
1690 ext->remote_llri);
1691 }
1692 if (IS_SUBTLV(ext, EXT_LOCAL_ADDR))
1693 sbuf_push(&buf, 4, "Local Interface IP Address(es): %pI4\n",
1694 &ext->local_addr);
1695 if (IS_SUBTLV(ext, EXT_NEIGH_ADDR))
1696 sbuf_push(&buf, 4, "Remote Interface IP Address(es): %pI4\n",
1697 &ext->neigh_addr);
1698 if (IS_SUBTLV(ext, EXT_LOCAL_ADDR6))
1699 sbuf_push(&buf, 4, "Local Interface IPv6 Address(es): %s\n",
1700 inet_ntop(AF_INET6, &ext->local_addr6, ibuf,
1701 PREFIX2STR_BUFFER));
1702 if (IS_SUBTLV(ext, EXT_NEIGH_ADDR6))
1703 sbuf_push(&buf, 4, "Remote Interface IPv6 Address(es): %s\n",
1704 inet_ntop(AF_INET6, &ext->local_addr6, ibuf,
1705 PREFIX2STR_BUFFER));
1706 if (IS_SUBTLV(ext, EXT_MAX_BW))
1707 sbuf_push(&buf, 4, "Maximum Bandwidth: %g (Bytes/sec)\n",
1708 ext->max_bw);
1709 if (IS_SUBTLV(ext, EXT_MAX_RSV_BW))
1710 sbuf_push(&buf, 4,
1711 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
1712 ext->max_rsv_bw);
1713 if (IS_SUBTLV(ext, EXT_UNRSV_BW)) {
1714 sbuf_push(&buf, 4, "Unreserved Bandwidth:\n");
1715 for (int j = 0; j < MAX_CLASS_TYPE; j += 2) {
1716 sbuf_push(&buf, 4 + 2,
1717 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
1718 j, ext->unrsv_bw[j],
1719 j + 1, ext->unrsv_bw[j + 1]);
1720 }
1721 }
1722 if (IS_SUBTLV(ext, EXT_TE_METRIC))
1723 sbuf_push(&buf, 4, "Traffic Engineering Metric: %u\n",
1724 ext->te_metric);
1725 if (IS_SUBTLV(ext, EXT_RMT_AS))
1726 sbuf_push(&buf, 4,
1727 "Inter-AS TE Remote AS number: %u\n",
1728 ext->remote_as);
1729 if (IS_SUBTLV(ext, EXT_RMT_IP))
1730 sbuf_push(&buf, 4,
1731 "Inter-AS TE Remote ASBR IP address: %pI4\n",
1732 &ext->remote_ip);
1733 if (IS_SUBTLV(ext, EXT_DELAY))
1734 sbuf_push(&buf, 4,
1735 "%s Average Link Delay: %u (micro-sec)\n",
1736 IS_ANORMAL(ext->delay) ? "Anomalous" : "Normal",
1737 ext->delay & TE_EXT_MASK);
1738 if (IS_SUBTLV(ext, EXT_MM_DELAY)) {
1739 sbuf_push(&buf, 4, "%s Min/Max Link Delay: %u / %u (micro-sec)\n",
1740 IS_ANORMAL(ext->min_delay) ? "Anomalous" : "Normal",
1741 ext->min_delay & TE_EXT_MASK,
1742 ext->max_delay & TE_EXT_MASK);
1743 }
1744 if (IS_SUBTLV(ext, EXT_DELAY_VAR))
1745 sbuf_push(&buf, 4,
1746 "Delay Variation: %u (micro-sec)\n",
1747 ext->delay_var & TE_EXT_MASK);
1748 if (IS_SUBTLV(ext, EXT_PKT_LOSS))
1749 sbuf_push(&buf, 4, "%s Link Packet Loss: %g (%%)\n",
1750 IS_ANORMAL(ext->pkt_loss) ? "Anomalous" : "Normal",
1751 (float)((ext->pkt_loss & TE_EXT_MASK)
1752 * LOSS_PRECISION));
1753 if (IS_SUBTLV(ext, EXT_RES_BW))
1754 sbuf_push(&buf, 4,
1755 "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n",
1756 ext->res_bw);
1757 if (IS_SUBTLV(ext, EXT_AVA_BW))
1758 sbuf_push(&buf, 4,
1759 "Unidirectional Available Bandwidth: %g (Bytes/sec)\n",
1760 ext->ava_bw);
1761 if (IS_SUBTLV(ext, EXT_USE_BW))
1762 sbuf_push(&buf, 4,
1763 "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n",
1764 ext->use_bw);
1765
1766 vty_multiline(vty, "", "%s", sbuf_buf(&buf));
1767 vty_out(vty, "---------------\n\n");
1768
1769 sbuf_free(&buf);
1770 return;
1771 }
1772
1773 DEFUN (show_isis_mpls_te_interface,
1774 show_isis_mpls_te_interface_cmd,
1775 "show " PROTO_NAME " mpls-te interface [INTERFACE]",
1776 SHOW_STR
1777 PROTO_HELP
1778 MPLS_TE_STR
1779 "Interface information\n"
1780 "Interface name\n")
1781 {
1782 struct listnode *anode, *cnode, *inode;
1783 struct isis_area *area;
1784 struct isis_circuit *circuit;
1785 struct interface *ifp;
1786 int idx_interface = 4;
1787 struct isis *isis = NULL;
1788
1789 if (!im) {
1790 vty_out(vty, "IS-IS Routing Process not enabled\n");
1791 return CMD_SUCCESS;
1792 }
1793
1794 if (argc == idx_interface) {
1795 /* Show All Interfaces. */
1796 for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) {
1797 for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode,
1798 area)) {
1799
1800 if (!IS_MPLS_TE(area->mta))
1801 continue;
1802
1803 vty_out(vty, "Area %s:\n", area->area_tag);
1804
1805 for (ALL_LIST_ELEMENTS_RO(area->circuit_list,
1806 cnode, circuit))
1807 show_ext_sub(vty,
1808 circuit->interface->name,
1809 circuit->ext);
1810 }
1811 }
1812 } else {
1813 /* Interface name is specified. */
1814 ifp = if_lookup_by_name(argv[idx_interface]->arg, VRF_DEFAULT);
1815 if (ifp == NULL)
1816 vty_out(vty, "No such interface name\n");
1817 else {
1818 circuit = circuit_scan_by_ifp(ifp);
1819 if (!circuit)
1820 vty_out(vty,
1821 "ISIS is not enabled on circuit %s\n",
1822 ifp->name);
1823 else
1824 show_ext_sub(vty, ifp->name, circuit->ext);
1825 }
1826 }
1827
1828 return CMD_SUCCESS;
1829 }
1830
1831 /**
1832 * Search Vertex in TED that corresponds to the given string that represent
1833 * the ISO system ID in the forms <systemid/hostname>[.<pseudo-id>-<framenent>]
1834 *
1835 * @param ted Link State Database
1836 * @param id ISO System ID
1837 * @param isis Main reference to the isis daemon
1838 *
1839 * @return Vertex if found, NULL otherwise
1840 */
1841 static struct ls_vertex *vertex_for_arg(struct ls_ted *ted, const char *id,
1842 struct isis *isis)
1843 {
1844 char sysid[255] = {0};
1845 uint8_t number[3];
1846 const char *pos;
1847 uint8_t lspid[ISIS_SYS_ID_LEN + 2] = {0};
1848 struct isis_dynhn *dynhn;
1849 uint64_t key = 0;
1850
1851 if (!id)
1852 return NULL;
1853
1854 /*
1855 * extract fragment and pseudo id from the string argv
1856 * in the forms:
1857 * (a) <systemid/hostname>.<pseudo-id>-<framenent> or
1858 * (b) <systemid/hostname>.<pseudo-id> or
1859 * (c) <systemid/hostname> or
1860 * Where systemid is in the form:
1861 * xxxx.xxxx.xxxx
1862 */
1863 strlcpy(sysid, id, sizeof(sysid));
1864 if (strlen(id) > 3) {
1865 pos = id + strlen(id) - 3;
1866 if (strncmp(pos, "-", 1) == 0) {
1867 memcpy(number, ++pos, 2);
1868 lspid[ISIS_SYS_ID_LEN + 1] =
1869 (uint8_t)strtol((char *)number, NULL, 16);
1870 pos -= 4;
1871 if (strncmp(pos, ".", 1) != 0)
1872 return NULL;
1873 }
1874 if (strncmp(pos, ".", 1) == 0) {
1875 memcpy(number, ++pos, 2);
1876 lspid[ISIS_SYS_ID_LEN] =
1877 (uint8_t)strtol((char *)number, NULL, 16);
1878 sysid[pos - id - 1] = '\0';
1879 }
1880 }
1881
1882 /*
1883 * Try to find the lsp-id if the argv
1884 * string is in
1885 * the form
1886 * hostname.<pseudo-id>-<fragment>
1887 */
1888 if (sysid2buff(lspid, sysid)) {
1889 key = sysid_to_key(lspid);
1890 } else if ((dynhn = dynhn_find_by_name(isis, sysid))) {
1891 memcpy(lspid, dynhn->id, ISIS_SYS_ID_LEN);
1892 key = sysid_to_key(lspid);
1893 } else if (strncmp(cmd_hostname_get(), sysid, 15) == 0) {
1894 memcpy(lspid, isis->sysid, ISIS_SYS_ID_LEN);
1895 key = sysid_to_key(lspid);
1896 }
1897
1898 if (key == 0)
1899 return NULL;
1900
1901 return ls_find_vertex_by_key(ted, key);
1902 }
1903
1904 /**
1905 * Show Link State Traffic Engineering Database extracted from IS-IS LSP.
1906 *
1907 * @param vty VTY output console
1908 * @param argv Command line argument
1909 * @param argc Number of command line argument
1910 * @param ted Traffic Engineering Database
1911 * @param isis isis Main reference to the isis daemon
1912 *
1913 * @return Command Success if OK, Command Warning otherwise
1914 */
1915 static int show_ted(struct vty *vty, struct cmd_token *argv[], int argc,
1916 struct isis_area *area, struct isis *isis)
1917 {
1918 int idx;
1919 char *id;
1920 struct in_addr ip_addr;
1921 struct in6_addr ip6_addr;
1922 struct prefix pref;
1923 struct ls_ted *ted;
1924 struct ls_vertex *vertex;
1925 struct ls_edge *edge;
1926 struct ls_subnet *subnet;
1927 struct ls_edge_key key;
1928 bool detail = false;
1929 bool uj = use_json(argc, argv);
1930 json_object *json = NULL;
1931
1932 if (!IS_MPLS_TE(area->mta) || !area->mta->ted) {
1933 vty_out(vty, "MPLS-TE is disabled for Area %s\n",
1934 area->area_tag ? area->area_tag : "null");
1935 return CMD_SUCCESS;
1936 }
1937
1938 ted = area->mta->ted;
1939
1940 if (uj)
1941 json = json_object_new_object();
1942 else
1943 vty_out(vty, "Area %s:\n",
1944 area->area_tag ? area->area_tag : "null");
1945
1946 if (argv[argc - 1]->arg && strmatch(argv[argc - 1]->text, "detail"))
1947 detail = true;
1948
1949 idx = 4;
1950 if (argv_find(argv, argc, "vertex", &idx)) {
1951 /* Show Vertex */
1952 id = argv_find(argv, argc, "WORD", &idx) ? argv[idx]->arg
1953 : NULL;
1954 if (!id)
1955 vertex = NULL;
1956 else if (!strncmp(id, "self", 4))
1957 vertex = ted->self;
1958 else {
1959 vertex = vertex_for_arg(ted, id, isis);
1960 if (!vertex) {
1961 vty_out(vty, "No vertex found for ID %s\n", id);
1962 return CMD_WARNING;
1963 }
1964 }
1965
1966 if (vertex)
1967 ls_show_vertex(vertex, vty, json, detail);
1968 else
1969 ls_show_vertices(ted, vty, json, detail);
1970
1971 } else if (argv_find(argv, argc, "edge", &idx)) {
1972 /* Show Edge */
1973 if (argv_find(argv, argc, "A.B.C.D", &idx)) {
1974 if (!inet_pton(AF_INET, argv[idx]->arg, &ip_addr)) {
1975 vty_out(vty,
1976 "Specified Edge ID %s is invalid\n",
1977 argv[idx]->arg);
1978 return CMD_WARNING_CONFIG_FAILED;
1979 }
1980 /* Get the Edge from the Link State Database */
1981 key.family = AF_INET;
1982 IPV4_ADDR_COPY(&key.k.addr, &ip_addr);
1983 edge = ls_find_edge_by_key(ted, key);
1984 if (!edge) {
1985 vty_out(vty, "No edge found for ID %pI4\n",
1986 &ip_addr);
1987 return CMD_WARNING;
1988 }
1989 } else if (argv_find(argv, argc, "X:X::X:X", &idx)) {
1990 if (!inet_pton(AF_INET6, argv[idx]->arg, &ip6_addr)) {
1991 vty_out(vty,
1992 "Specified Edge ID %s is invalid\n",
1993 argv[idx]->arg);
1994 return CMD_WARNING_CONFIG_FAILED;
1995 }
1996 /* Get the Edge from the Link State Database */
1997 key.family = AF_INET6;
1998 IPV6_ADDR_COPY(&key.k.addr6, &ip6_addr);
1999 edge = ls_find_edge_by_key(ted, key);
2000 if (!edge) {
2001 vty_out(vty, "No edge found for ID %pI6\n",
2002 &ip6_addr);
2003 return CMD_WARNING;
2004 }
2005 } else
2006 edge = NULL;
2007
2008 if (edge)
2009 ls_show_edge(edge, vty, json, detail);
2010 else
2011 ls_show_edges(ted, vty, json, detail);
2012
2013 } else if (argv_find(argv, argc, "subnet", &idx)) {
2014 /* Show Subnet */
2015 if (argv_find(argv, argc, "A.B.C.D/M", &idx)) {
2016 if (!str2prefix(argv[idx]->arg, &pref)) {
2017 vty_out(vty, "Invalid prefix format %s\n",
2018 argv[idx]->arg);
2019 return CMD_WARNING_CONFIG_FAILED;
2020 }
2021 /* Get the Subnet from the Link State Database */
2022 subnet = ls_find_subnet(ted, &pref);
2023 if (!subnet) {
2024 vty_out(vty, "No subnet found for ID %pFX\n",
2025 &pref);
2026 return CMD_WARNING;
2027 }
2028 } else if (argv_find(argv, argc, "X:X::X:X/M", &idx)) {
2029 if (!str2prefix(argv[idx]->arg, &pref)) {
2030 vty_out(vty, "Invalid prefix format %s\n",
2031 argv[idx]->arg);
2032 return CMD_WARNING_CONFIG_FAILED;
2033 }
2034 /* Get the Subnet from the Link State Database */
2035 subnet = ls_find_subnet(ted, &pref);
2036 if (!subnet) {
2037 vty_out(vty, "No subnet found for ID %pFX\n",
2038 &pref);
2039 return CMD_WARNING;
2040 }
2041 } else
2042 subnet = NULL;
2043
2044 if (subnet)
2045 ls_show_subnet(subnet, vty, json, detail);
2046 else
2047 ls_show_subnets(ted, vty, json, detail);
2048
2049 } else {
2050 /* Show the complete TED */
2051 ls_show_ted(ted, vty, json, detail);
2052 }
2053
2054 if (uj)
2055 vty_json(vty, json);
2056
2057 return CMD_SUCCESS;
2058 }
2059
2060 /**
2061 * Show ISIS Traffic Engineering Database
2062 *
2063 * @param vty VTY output console
2064 * @param argv Command line argument
2065 * @param argc Number of command line argument
2066 * @param isis isis Main reference to the isis daemon
2067
2068 * @return Command Success if OK, Command Warning otherwise
2069 */
2070 static int show_isis_ted(struct vty *vty, struct cmd_token *argv[], int argc,
2071 struct isis *isis)
2072 {
2073 struct listnode *node;
2074 struct isis_area *area;
2075 int rc;
2076
2077 for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
2078 rc = show_ted(vty, argv, argc, area, isis);
2079 if (rc != CMD_SUCCESS)
2080 return rc;
2081 }
2082 return CMD_SUCCESS;
2083 }
2084
2085 DEFUN(show_isis_mpls_te_db,
2086 show_isis_mpls_te_db_cmd,
2087 "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]",
2088 SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
2089 "All VRFs\n"
2090 MPLS_TE_STR
2091 "MPLS-TE database\n"
2092 "MPLS-TE Vertex\n"
2093 "MPLS-TE Vertex ID (as an ISO ID, hostname or \"self\")\n"
2094 "MPLS-TE Edge\n"
2095 "MPLS-TE Edge ID (as an IPv4 address)\n"
2096 "MPLS-TE Edge ID (as an IPv6 address)\n"
2097 "MPLS-TE Subnet\n"
2098 "MPLS-TE Subnet ID (as an IPv4 prefix)\n"
2099 "MPLS-TE Subnet ID (as an IPv6 prefix)\n"
2100 "Detailed information\n"
2101 JSON_STR)
2102 {
2103 int idx_vrf = 0;
2104 const char *vrf_name = VRF_DEFAULT_NAME;
2105 bool all_vrf = false;
2106 struct listnode *node;
2107 struct isis *isis;
2108 int rc = CMD_WARNING;
2109
2110 ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
2111 if (vrf_name) {
2112 if (all_vrf) {
2113 for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
2114 rc = show_isis_ted(vty, argv, argc, isis);
2115 if (rc != CMD_SUCCESS)
2116 return rc;
2117 }
2118 return CMD_SUCCESS;
2119 }
2120 isis = isis_lookup_by_vrfname(vrf_name);
2121 if (isis)
2122 rc = show_isis_ted(vty, argv, argc, isis);
2123 }
2124
2125 return rc;
2126 }
2127
2128 #endif /* #ifndef FRABRICD */
2129
2130 /* Initialize MPLS_TE */
2131 void isis_mpls_te_init(void)
2132 {
2133
2134 /* Register Circuit and Adjacency hook */
2135 hook_register(isis_if_new_hook, isis_mpls_te_update);
2136 hook_register(isis_adj_ip_enabled_hook, isis_mpls_te_adj_ip_enabled);
2137 hook_register(isis_adj_ip_disabled_hook, isis_mpls_te_adj_ip_disabled);
2138
2139 #ifndef FABRICD
2140 /* Register new VTY commands */
2141 install_element(VIEW_NODE, &show_isis_mpls_te_router_cmd);
2142 install_element(VIEW_NODE, &show_isis_mpls_te_interface_cmd);
2143 install_element(VIEW_NODE, &show_isis_mpls_te_db_cmd);
2144 #endif
2145
2146 return;
2147 }