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