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