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