]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_te.c
Merge pull request #4972 from mjstapp/fix_notif_installed
[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
47 #include "isisd/isis_constants.h"
48 #include "isisd/isis_common.h"
49 #include "isisd/isis_flags.h"
50 #include "isisd/isis_circuit.h"
51 #include "isisd/isis_adjacency.h"
52 #include "isisd/isisd.h"
53 #include "isisd/isis_lsp.h"
54 #include "isisd/isis_pdu.h"
55 #include "isisd/isis_dynhn.h"
56 #include "isisd/isis_misc.h"
57 #include "isisd/isis_csm.h"
58 #include "isisd/isis_adjacency.h"
59 #include "isisd/isis_spf.h"
60 #include "isisd/isis_te.h"
61 #include "isisd/isis_zebra.h"
62
63 const char *mode2text[] = {"Disable", "Area", "AS", "Emulate"};
64
65 /*------------------------------------------------------------------------*
66 * Followings are control functions for MPLS-TE parameters management.
67 *------------------------------------------------------------------------*/
68
69 /* Main initialization / update function of the MPLS TE Circuit context */
70 /* Call when interface TE Link parameters are modified */
71 void isis_link_params_update(struct isis_circuit *circuit,
72 struct interface *ifp)
73 {
74 int i;
75 struct prefix_ipv4 *addr;
76 struct prefix_ipv6 *addr6;
77 struct isis_ext_subtlvs *ext;
78
79 /* Check if TE is enable or not */
80 if (!circuit->area || !IS_MPLS_TE(circuit->area->mta))
81 return;
82
83 /* Sanity Check */
84 if ((circuit == NULL) || (ifp == NULL)
85 || (circuit->state != C_STATE_UP))
86 return;
87
88 zlog_debug("TE(%s): Update circuit parameters for interface %s",
89 circuit->area->area_tag, ifp->name);
90
91 /* Check if MPLS TE Circuit context has not been already created */
92 if (circuit->ext == NULL) {
93 circuit->ext = isis_alloc_ext_subtlvs();
94 zlog_debug(" |- Allocated new Ext-subTLVs for interface %s",
95 ifp->name);
96 }
97
98 ext = circuit->ext;
99
100 /* Fulfill Extended subTLVs from interface link parameters */
101 if (HAS_LINK_PARAMS(ifp)) {
102 /* STD_TE metrics */
103 if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) {
104 ext->adm_group = ifp->link_params->admin_grp;
105 SET_SUBTLV(ext, EXT_ADM_GRP);
106 } else
107 UNSET_SUBTLV(ext, EXT_ADM_GRP);
108
109 /* If known, register local IPv4 addr from ip_addr list */
110 if (circuit->ip_addrs != NULL
111 && listcount(circuit->ip_addrs) != 0) {
112 addr = (struct prefix_ipv4 *)listgetdata(
113 (struct listnode *)listhead(circuit->ip_addrs));
114 IPV4_ADDR_COPY(&ext->local_addr, &addr->prefix);
115 SET_SUBTLV(ext, EXT_LOCAL_ADDR);
116 } else
117 UNSET_SUBTLV(ext, EXT_LOCAL_ADDR);
118
119 /* Same for Remote IPv4 address */
120 if (circuit->circ_type == CIRCUIT_T_P2P) {
121 struct isis_adjacency *adj = circuit->u.p2p.neighbor;
122
123 if (adj && adj->adj_state == ISIS_ADJ_UP
124 && adj->ipv4_address_count) {
125 IPV4_ADDR_COPY(&ext->neigh_addr,
126 &adj->ipv4_addresses[0]);
127 SET_SUBTLV(ext, EXT_NEIGH_ADDR);
128 }
129 } else
130 UNSET_SUBTLV(ext, EXT_NEIGH_ADDR);
131
132 /* If known, register local IPv6 addr from ip_addr list */
133 if (circuit->ipv6_non_link != NULL
134 && listcount(circuit->ipv6_non_link) != 0) {
135 addr6 = (struct prefix_ipv6 *)listgetdata(
136 (struct listnode *)listhead(
137 circuit->ipv6_non_link));
138 IPV6_ADDR_COPY(&ext->local_addr6, &addr6->prefix);
139 SET_SUBTLV(ext, EXT_LOCAL_ADDR6);
140 } else
141 UNSET_SUBTLV(ext, EXT_LOCAL_ADDR6);
142
143 /* Same for Remote IPv6 address */
144 if (circuit->circ_type == CIRCUIT_T_P2P) {
145 struct isis_adjacency *adj = circuit->u.p2p.neighbor;
146
147 if (adj && adj->adj_state == ISIS_ADJ_UP
148 && adj->ipv6_address_count) {
149 IPV6_ADDR_COPY(&ext->neigh_addr6,
150 &adj->ipv6_addresses[0]);
151 SET_SUBTLV(ext, EXT_NEIGH_ADDR6);
152 }
153 } else
154 UNSET_SUBTLV(ext, EXT_NEIGH_ADDR6);
155
156 if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) {
157 ext->max_bw = ifp->link_params->max_bw;
158 SET_SUBTLV(ext, EXT_MAX_BW);
159 } else
160 UNSET_SUBTLV(ext, EXT_MAX_BW);
161
162 if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) {
163 ext->max_rsv_bw = ifp->link_params->max_rsv_bw;
164 SET_SUBTLV(ext, EXT_MAX_RSV_BW);
165 } else
166 UNSET_SUBTLV(ext, EXT_MAX_RSV_BW);
167
168 if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) {
169 for (i = 0; i < MAX_CLASS_TYPE; i++)
170 ext->unrsv_bw[i] =
171 ifp->link_params->unrsv_bw[i];
172 SET_SUBTLV(ext, EXT_UNRSV_BW);
173 } else
174 UNSET_SUBTLV(ext, EXT_UNRSV_BW);
175
176 if (IS_PARAM_SET(ifp->link_params, LP_TE_METRIC)) {
177 ext->te_metric = ifp->link_params->te_metric;
178 SET_SUBTLV(ext, EXT_TE_METRIC);
179 } else
180 UNSET_SUBTLV(ext, EXT_TE_METRIC);
181
182 /* TE metric extensions */
183 if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) {
184 ext->delay = ifp->link_params->av_delay;
185 SET_SUBTLV(ext, EXT_DELAY);
186 } else
187 UNSET_SUBTLV(ext, EXT_DELAY);
188
189 if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) {
190 ext->min_delay = ifp->link_params->min_delay;
191 ext->max_delay = ifp->link_params->max_delay;
192 SET_SUBTLV(ext, EXT_MM_DELAY);
193 } else
194 UNSET_SUBTLV(ext, EXT_MM_DELAY);
195
196 if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) {
197 ext->delay_var = ifp->link_params->delay_var;
198 SET_SUBTLV(ext, EXT_DELAY_VAR);
199 } else
200 UNSET_SUBTLV(ext, EXT_DELAY_VAR);
201
202 if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) {
203 ext->pkt_loss = ifp->link_params->pkt_loss;
204 SET_SUBTLV(ext, EXT_PKT_LOSS);
205 } else
206 UNSET_SUBTLV(ext, EXT_PKT_LOSS);
207
208 if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) {
209 ext->res_bw = ifp->link_params->res_bw;
210 SET_SUBTLV(ext, EXT_RES_BW);
211 } else
212 UNSET_SUBTLV(ext, EXT_RES_BW);
213
214 if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) {
215 ext->ava_bw = ifp->link_params->ava_bw;
216 SET_SUBTLV(ext, EXT_AVA_BW);
217 } else
218 UNSET_SUBTLV(ext, EXT_AVA_BW);
219
220 if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) {
221 ext->use_bw = ifp->link_params->use_bw;
222 SET_SUBTLV(ext, EXT_USE_BW);
223 } else
224 UNSET_SUBTLV(ext, EXT_USE_BW);
225
226 /* INTER_AS */
227 if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS)) {
228 ext->remote_as = ifp->link_params->rmt_as;
229 ext->remote_ip = ifp->link_params->rmt_ip;
230 SET_SUBTLV(ext, EXT_RMT_AS);
231 SET_SUBTLV(ext, EXT_RMT_IP);
232 } else {
233 /* reset inter-as TE params */
234 UNSET_SUBTLV(ext, EXT_RMT_AS);
235 UNSET_SUBTLV(ext, EXT_RMT_IP);
236 }
237 zlog_debug(" |- New MPLS-TE link parameters status 0x%x",
238 ext->status);
239 } else {
240 zlog_debug(" |- Reset Extended subTLVs status 0x%x",
241 ext->status);
242 /* Reset TE subTLVs keeping SR one's */
243 if (IS_SUBTLV(ext, EXT_ADJ_SID))
244 ext->status = EXT_ADJ_SID;
245 else if (IS_SUBTLV(ext, EXT_LAN_ADJ_SID))
246 ext->status = EXT_LAN_ADJ_SID;
247 else
248 ext->status = 0;
249 }
250
251 return;
252 }
253
254 static int isis_link_update_adj_hook(struct isis_adjacency *adj)
255 {
256
257 struct isis_circuit *circuit = adj->circuit;
258
259 /* Update MPLS TE Remote IP address parameter if possible */
260 if (!IS_MPLS_TE(circuit->area->mta) || !IS_EXT_TE(circuit->ext))
261 return 0;
262
263 /* IPv4 first */
264 if (adj->ipv4_address_count > 0) {
265 IPV4_ADDR_COPY(&circuit->ext->neigh_addr,
266 &adj->ipv4_addresses[0]);
267 SET_SUBTLV(circuit->ext, EXT_NEIGH_ADDR);
268 }
269
270 /* and IPv6 */
271 if (adj->ipv6_address_count > 0) {
272 IPV6_ADDR_COPY(&circuit->ext->neigh_addr6,
273 &adj->ipv6_addresses[0]);
274 SET_SUBTLV(circuit->ext, EXT_NEIGH_ADDR6);
275 }
276
277 return 0;
278 }
279
280 int isis_mpls_te_update(struct interface *ifp)
281 {
282 struct isis_circuit *circuit;
283 uint8_t rc = 1;
284
285 /* Sanity Check */
286 if (ifp == NULL)
287 return rc;
288
289 /* Get circuit context from interface */
290 circuit = circuit_scan_by_ifp(ifp);
291 if (circuit == NULL)
292 return rc;
293
294 /* Update TE TLVs ... */
295 isis_link_params_update(circuit, ifp);
296
297 /* ... and LSP */
298 if (circuit->area && IS_MPLS_TE(circuit->area->mta))
299 lsp_regenerate_schedule(circuit->area, circuit->is_type, 0);
300
301 rc = 0;
302 return rc;
303 }
304
305 /* Followings are vty command functions */
306 #ifndef FABRICD
307
308 DEFUN (show_isis_mpls_te_router,
309 show_isis_mpls_te_router_cmd,
310 "show " PROTO_NAME " mpls-te router",
311 SHOW_STR
312 PROTO_HELP
313 MPLS_TE_STR
314 "Router information\n")
315 {
316
317 struct listnode *anode;
318 struct isis_area *area;
319
320 if (!isis) {
321 vty_out(vty, "IS-IS Routing Process not enabled\n");
322 return CMD_SUCCESS;
323 }
324
325 for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
326
327 if (!IS_MPLS_TE(area->mta))
328 continue;
329
330 vty_out(vty, "Area %s:\n", area->area_tag);
331 if (ntohs(area->mta->router_id.s_addr) != 0)
332 vty_out(vty, " MPLS-TE Router-Address: %s\n",
333 inet_ntoa(area->mta->router_id));
334 else
335 vty_out(vty, " N/A\n");
336 }
337
338 return CMD_SUCCESS;
339 }
340
341 static void show_ext_sub(struct vty *vty, char *name,
342 struct isis_ext_subtlvs *ext)
343 {
344 struct sbuf buf;
345 char ibuf[PREFIX2STR_BUFFER];
346
347 sbuf_init(&buf, NULL, 0);
348
349 if (!ext || ext->status == EXT_DISABLE)
350 return;
351
352 vty_out(vty, "-- MPLS-TE link parameters for %s --\n", name);
353
354 sbuf_reset(&buf);
355
356 if (IS_SUBTLV(ext, EXT_ADM_GRP))
357 sbuf_push(&buf, 4, "Administrative Group: 0x%" PRIx32 "\n",
358 ext->adm_group);
359 if (IS_SUBTLV(ext, EXT_LLRI)) {
360 sbuf_push(&buf, 4, "Link Local ID: %" PRIu32 "\n",
361 ext->local_llri);
362 sbuf_push(&buf, 4, "Link Remote ID: %" PRIu32 "\n",
363 ext->remote_llri);
364 }
365 if (IS_SUBTLV(ext, EXT_LOCAL_ADDR))
366 sbuf_push(&buf, 4, "Local Interface IP Address(es): %s\n",
367 inet_ntoa(ext->local_addr));
368 if (IS_SUBTLV(ext, EXT_NEIGH_ADDR))
369 sbuf_push(&buf, 4, "Remote Interface IP Address(es): %s\n",
370 inet_ntoa(ext->neigh_addr));
371 if (IS_SUBTLV(ext, EXT_LOCAL_ADDR6))
372 sbuf_push(&buf, 4, "Local Interface IPv6 Address(es): %s\n",
373 inet_ntop(AF_INET6, &ext->local_addr6, ibuf,
374 PREFIX2STR_BUFFER));
375 if (IS_SUBTLV(ext, EXT_NEIGH_ADDR6))
376 sbuf_push(&buf, 4, "Remote Interface IPv6 Address(es): %s\n",
377 inet_ntop(AF_INET6, &ext->local_addr6, ibuf,
378 PREFIX2STR_BUFFER));
379 if (IS_SUBTLV(ext, EXT_MAX_BW))
380 sbuf_push(&buf, 4, "Maximum Bandwidth: %g (Bytes/sec)\n",
381 ext->max_bw);
382 if (IS_SUBTLV(ext, EXT_MAX_RSV_BW))
383 sbuf_push(&buf, 4,
384 "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
385 ext->max_rsv_bw);
386 if (IS_SUBTLV(ext, EXT_UNRSV_BW)) {
387 sbuf_push(&buf, 4, "Unreserved Bandwidth:\n");
388 for (int j = 0; j < MAX_CLASS_TYPE; j += 2) {
389 sbuf_push(&buf, 4 + 2,
390 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
391 j, ext->unrsv_bw[j],
392 j + 1, ext->unrsv_bw[j + 1]);
393 }
394 }
395 if (IS_SUBTLV(ext, EXT_TE_METRIC))
396 sbuf_push(&buf, 4, "Traffic Engineering Metric: %u\n",
397 ext->te_metric);
398 if (IS_SUBTLV(ext, EXT_RMT_AS))
399 sbuf_push(&buf, 4,
400 "Inter-AS TE Remote AS number: %" PRIu32 "\n",
401 ext->remote_as);
402 if (IS_SUBTLV(ext, EXT_RMT_IP))
403 sbuf_push(&buf, 4,
404 "Inter-AS TE Remote ASBR IP address: %s\n",
405 inet_ntoa(ext->remote_ip));
406 if (IS_SUBTLV(ext, EXT_DELAY))
407 sbuf_push(&buf, 4,
408 "%s Average Link Delay: %" PRIu32 " (micro-sec)\n",
409 IS_ANORMAL(ext->delay) ? "Anomalous" : "Normal",
410 ext->delay);
411 if (IS_SUBTLV(ext, EXT_MM_DELAY)) {
412 sbuf_push(&buf, 4, "%s Min/Max Link Delay: %" PRIu32 " / %"
413 PRIu32 " (micro-sec)\n",
414 IS_ANORMAL(ext->min_delay) ? "Anomalous" : "Normal",
415 ext->min_delay & TE_EXT_MASK,
416 ext->max_delay & TE_EXT_MASK);
417 }
418 if (IS_SUBTLV(ext, EXT_DELAY_VAR))
419 sbuf_push(&buf, 4,
420 "Delay Variation: %" PRIu32 " (micro-sec)\n",
421 ext->delay_var & TE_EXT_MASK);
422 if (IS_SUBTLV(ext, EXT_PKT_LOSS))
423 sbuf_push(&buf, 4, "%s Link Packet Loss: %g (%%)\n",
424 IS_ANORMAL(ext->pkt_loss) ? "Anomalous" : "Normal",
425 (float)((ext->pkt_loss & TE_EXT_MASK)
426 * LOSS_PRECISION));
427 if (IS_SUBTLV(ext, EXT_RES_BW))
428 sbuf_push(&buf, 4,
429 "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n",
430 ext->res_bw);
431 if (IS_SUBTLV(ext, EXT_AVA_BW))
432 sbuf_push(&buf, 4,
433 "Unidirectional Available Bandwidth: %g (Bytes/sec)\n",
434 ext->ava_bw);
435 if (IS_SUBTLV(ext, EXT_USE_BW))
436 sbuf_push(&buf, 4,
437 "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n",
438 ext->use_bw);
439
440 vty_multiline(vty, "", "%s", sbuf_buf(&buf));
441 vty_out(vty, "---------------\n\n");
442
443 sbuf_free(&buf);
444 return;
445 }
446
447 DEFUN (show_isis_mpls_te_interface,
448 show_isis_mpls_te_interface_cmd,
449 "show " PROTO_NAME " mpls-te interface [INTERFACE]",
450 SHOW_STR
451 PROTO_HELP
452 MPLS_TE_STR
453 "Interface information\n"
454 "Interface name\n")
455 {
456 struct listnode *anode, *cnode;
457 struct isis_area *area;
458 struct isis_circuit *circuit;
459 struct interface *ifp;
460 int idx_interface = 4;
461
462 if (!isis) {
463 vty_out(vty, "IS-IS Routing Process not enabled\n");
464 return CMD_SUCCESS;
465 }
466
467 if (argc == idx_interface) {
468 /* Show All Interfaces. */
469 for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
470
471 if (!IS_MPLS_TE(area->mta))
472 continue;
473
474 vty_out(vty, "Area %s:\n", area->area_tag);
475
476 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode,
477 circuit))
478 show_ext_sub(vty, circuit->interface->name,
479 circuit->ext);
480 }
481 } else {
482 /* Interface name is specified. */
483 ifp = if_lookup_by_name(argv[idx_interface]->arg, VRF_DEFAULT);
484 if (ifp == NULL)
485 vty_out(vty, "No such interface name\n");
486 else {
487 circuit = circuit_scan_by_ifp(ifp);
488 if (!circuit)
489 vty_out(vty,
490 "ISIS is not enabled on circuit %s\n",
491 ifp->name);
492 else
493 show_ext_sub(vty, ifp->name, circuit->ext);
494 }
495 }
496
497 return CMD_SUCCESS;
498 }
499 #endif
500
501 /* Initialize MPLS_TE */
502 void isis_mpls_te_init(void)
503 {
504
505 /* Register Circuit and Adjacency hook */
506 hook_register(isis_if_new_hook, isis_mpls_te_update);
507 hook_register(isis_adj_state_change_hook, isis_link_update_adj_hook);
508
509
510 #ifndef FABRICD
511 /* Register new VTY commands */
512 install_element(VIEW_NODE, &show_isis_mpls_te_router_cmd);
513 install_element(VIEW_NODE, &show_isis_mpls_te_interface_cmd);
514 #endif
515
516 return;
517 }