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