]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_mt.c
isisd: send/receive LSPs with new parser
[mirror_frr.git] / isisd / isis_mt.c
CommitLineData
064f4896
CF
1/*
2 * IS-IS Rout(e)ing protocol - Multi Topology Support
3 *
4 * Copyright (C) 2017 Christian Franke
5 *
6 * This file is part of FreeRangeRouting (FRR)
7 *
8 * FRR is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * FRR is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
896014f4
DL
18 * You should have received a copy of the GNU General Public License along
19 * with this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
064f4896
CF
21 */
22#include <zebra.h>
23#include "isisd/isisd.h"
24#include "isisd/isis_memory.h"
25#include "isisd/isis_circuit.h"
d8fba7d9 26#include "isisd/isis_adjacency.h"
206f4aae
CF
27#include "isisd/isis_misc.h"
28#include "isisd/isis_lsp.h"
064f4896 29#include "isisd/isis_mt.h"
0c1bd758 30#include "isisd/isis_tlvs2.h"
064f4896
CF
31
32DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting")
33DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting")
d8fba7d9 34DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info")
c3ae3127
CF
35
36uint16_t isis_area_ipv6_topology(struct isis_area *area)
37{
d62a17ae 38 struct isis_area_mt_setting *area_mt_setting;
39 area_mt_setting = area_lookup_mt_setting(area, ISIS_MT_IPV6_UNICAST);
c3ae3127 40
d62a17ae 41 if (area_mt_setting && area_mt_setting->enabled)
42 return ISIS_MT_IPV6_UNICAST;
43 return ISIS_MT_IPV4_UNICAST;
c3ae3127 44}
064f4896
CF
45
46/* MT naming api */
47const char *isis_mtid2str(uint16_t mtid)
48{
d62a17ae 49 static char buf[sizeof("65535")];
50
51 switch (mtid) {
52 case ISIS_MT_IPV4_UNICAST:
53 return "ipv4-unicast";
54 case ISIS_MT_IPV4_MGMT:
55 return "ipv4-mgmt";
56 case ISIS_MT_IPV6_UNICAST:
57 return "ipv6-unicast";
58 case ISIS_MT_IPV4_MULTICAST:
59 return "ipv4-multicast";
60 case ISIS_MT_IPV6_MULTICAST:
61 return "ipv6-multicast";
62 case ISIS_MT_IPV6_MGMT:
63 return "ipv6-mgmt";
64 default:
65 snprintf(buf, sizeof(buf), "%" PRIu16, mtid);
66 return buf;
67 }
064f4896
CF
68}
69
70uint16_t isis_str2mtid(const char *name)
71{
d62a17ae 72 if (!strcmp(name, "ipv4-unicast"))
73 return ISIS_MT_IPV4_UNICAST;
74 if (!strcmp(name, "ipv4-mgmt"))
75 return ISIS_MT_IPV4_MGMT;
76 if (!strcmp(name, "ipv6-unicast"))
77 return ISIS_MT_IPV6_UNICAST;
78 if (!strcmp(name, "ipv4-multicast"))
79 return ISIS_MT_IPV4_MULTICAST;
80 if (!strcmp(name, "ipv6-multicast"))
81 return ISIS_MT_IPV6_MULTICAST;
82 if (!strcmp(name, "ipv6-mgmt"))
83 return ISIS_MT_IPV6_MGMT;
84 return -1;
064f4896
CF
85}
86
87/* General MT settings api */
88
89struct mt_setting {
90 ISIS_MT_INFO_FIELDS;
91};
92
d62a17ae 93static void *lookup_mt_setting(struct list *mt_list, uint16_t mtid)
064f4896 94{
d62a17ae 95 struct listnode *node;
96 struct mt_setting *setting;
064f4896 97
d62a17ae 98 for (ALL_LIST_ELEMENTS_RO(mt_list, node, setting)) {
99 if (setting->mtid == mtid)
100 return setting;
101 }
102 return NULL;
064f4896
CF
103}
104
d62a17ae 105static void add_mt_setting(struct list **mt_list, void *setting)
064f4896 106{
d62a17ae 107 if (!*mt_list)
108 *mt_list = list_new();
109 listnode_add(*mt_list, setting);
064f4896
CF
110}
111
112/* Area specific MT settings api */
113
d62a17ae 114struct isis_area_mt_setting *area_lookup_mt_setting(struct isis_area *area,
115 uint16_t mtid)
064f4896 116{
d62a17ae 117 return lookup_mt_setting(area->mt_settings, mtid);
064f4896
CF
118}
119
d62a17ae 120struct isis_area_mt_setting *area_new_mt_setting(struct isis_area *area,
121 uint16_t mtid)
064f4896 122{
d62a17ae 123 struct isis_area_mt_setting *setting;
064f4896 124
d62a17ae 125 setting = XCALLOC(MTYPE_MT_AREA_SETTING, sizeof(*setting));
126 setting->mtid = mtid;
127 return setting;
064f4896
CF
128}
129
d62a17ae 130static void area_free_mt_setting(void *setting)
064f4896 131{
d62a17ae 132 XFREE(MTYPE_MT_AREA_SETTING, setting);
064f4896
CF
133}
134
d62a17ae 135void area_add_mt_setting(struct isis_area *area,
136 struct isis_area_mt_setting *setting)
064f4896 137{
d62a17ae 138 add_mt_setting(&area->mt_settings, setting);
064f4896
CF
139}
140
d62a17ae 141void area_mt_init(struct isis_area *area)
064f4896 142{
d62a17ae 143 struct isis_area_mt_setting *v4_unicast_setting;
064f4896 144
d62a17ae 145 /* MTID 0 is always enabled */
146 v4_unicast_setting = area_new_mt_setting(area, ISIS_MT_IPV4_UNICAST);
147 v4_unicast_setting->enabled = true;
148 add_mt_setting(&area->mt_settings, v4_unicast_setting);
149 area->mt_settings->del = area_free_mt_setting;
064f4896
CF
150}
151
d62a17ae 152void area_mt_finish(struct isis_area *area)
064f4896 153{
d62a17ae 154 list_delete(area->mt_settings);
155 area->mt_settings = NULL;
064f4896
CF
156}
157
d62a17ae 158struct isis_area_mt_setting *area_get_mt_setting(struct isis_area *area,
159 uint16_t mtid)
064f4896 160{
d62a17ae 161 struct isis_area_mt_setting *setting;
064f4896 162
d62a17ae 163 setting = area_lookup_mt_setting(area, mtid);
164 if (!setting) {
165 setting = area_new_mt_setting(area, mtid);
166 area_add_mt_setting(area, setting);
167 }
168 return setting;
064f4896
CF
169}
170
d62a17ae 171int area_write_mt_settings(struct isis_area *area, struct vty *vty)
064f4896 172{
d62a17ae 173 int written = 0;
174 struct listnode *node;
175 struct isis_area_mt_setting *setting;
064f4896 176
d62a17ae 177 for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting)) {
178 const char *name = isis_mtid2str(setting->mtid);
179 if (name && setting->enabled) {
180 if (setting->mtid == ISIS_MT_IPV4_UNICAST)
181 continue; /* always enabled, no need to write
182 out config */
183 vty_out(vty, " topology %s%s\n", name,
184 setting->overload ? " overload" : "");
185 written++;
186 }
187 }
188 return written;
064f4896
CF
189}
190
99894f9a
CF
191bool area_is_mt(struct isis_area *area)
192{
d62a17ae 193 struct listnode *node, *node2;
194 struct isis_area_mt_setting *setting;
195 struct isis_circuit *circuit;
196 struct isis_circuit_mt_setting *csetting;
99894f9a 197
d62a17ae 198 for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting)) {
199 if (setting->enabled && setting->mtid != ISIS_MT_IPV4_UNICAST)
200 return true;
201 }
202 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
203 for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node2,
204 csetting)) {
205 if (!csetting->enabled
206 && csetting->mtid == ISIS_MT_IPV4_UNICAST)
207 return true;
208 }
209 }
99894f9a 210
d62a17ae 211 return false;
99894f9a
CF
212}
213
d62a17ae 214struct isis_area_mt_setting **area_mt_settings(struct isis_area *area,
215 unsigned int *mt_count)
99894f9a 216{
d62a17ae 217 static unsigned int size = 0;
218 static struct isis_area_mt_setting **rv = NULL;
99894f9a 219
d62a17ae 220 unsigned int count = 0;
221 struct listnode *node;
222 struct isis_area_mt_setting *setting;
99894f9a 223
d62a17ae 224 for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting)) {
225 if (!setting->enabled)
226 continue;
99894f9a 227
d62a17ae 228 count++;
229 if (count > size) {
230 rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
231 size = count;
232 }
233 rv[count - 1] = setting;
234 }
99894f9a 235
d62a17ae 236 *mt_count = count;
237 return rv;
99894f9a
CF
238}
239
064f4896
CF
240/* Circuit specific MT settings api */
241
d62a17ae 242struct isis_circuit_mt_setting *
064f4896
CF
243circuit_lookup_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
244{
d62a17ae 245 return lookup_mt_setting(circuit->mt_settings, mtid);
064f4896
CF
246}
247
d62a17ae 248struct isis_circuit_mt_setting *
064f4896
CF
249circuit_new_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
250{
d62a17ae 251 struct isis_circuit_mt_setting *setting;
064f4896 252
d62a17ae 253 setting = XCALLOC(MTYPE_MT_CIRCUIT_SETTING, sizeof(*setting));
254 setting->mtid = mtid;
255 setting->enabled = true; /* Enabled is default for circuit */
256 return setting;
064f4896
CF
257}
258
d62a17ae 259static void circuit_free_mt_setting(void *setting)
064f4896 260{
d62a17ae 261 XFREE(MTYPE_MT_CIRCUIT_SETTING, setting);
064f4896
CF
262}
263
d62a17ae 264void circuit_add_mt_setting(struct isis_circuit *circuit,
265 struct isis_circuit_mt_setting *setting)
064f4896 266{
d62a17ae 267 add_mt_setting(&circuit->mt_settings, setting);
064f4896
CF
268}
269
d62a17ae 270void circuit_mt_init(struct isis_circuit *circuit)
064f4896 271{
d62a17ae 272 circuit->mt_settings = list_new();
273 circuit->mt_settings->del = circuit_free_mt_setting;
064f4896
CF
274}
275
d62a17ae 276void circuit_mt_finish(struct isis_circuit *circuit)
064f4896 277{
d62a17ae 278 list_delete(circuit->mt_settings);
279 circuit->mt_settings = NULL;
064f4896
CF
280}
281
d62a17ae 282struct isis_circuit_mt_setting *
064f4896
CF
283circuit_get_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
284{
d62a17ae 285 struct isis_circuit_mt_setting *setting;
064f4896 286
d62a17ae 287 setting = circuit_lookup_mt_setting(circuit, mtid);
288 if (!setting) {
289 setting = circuit_new_mt_setting(circuit, mtid);
290 circuit_add_mt_setting(circuit, setting);
291 }
292 return setting;
064f4896
CF
293}
294
d62a17ae 295int circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty)
064f4896 296{
d62a17ae 297 int written = 0;
298 struct listnode *node;
299 struct isis_circuit_mt_setting *setting;
064f4896 300
d62a17ae 301 for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node, setting)) {
302 const char *name = isis_mtid2str(setting->mtid);
303 if (name && !setting->enabled) {
304 vty_out(vty, " no isis topology %s\n", name);
305 written++;
306 }
307 }
308 return written;
064f4896 309}
99894f9a 310
d62a17ae 311struct isis_circuit_mt_setting **
99894f9a
CF
312circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count)
313{
d62a17ae 314 static unsigned int size = 0;
315 static struct isis_circuit_mt_setting **rv = NULL;
99894f9a 316
d62a17ae 317 struct isis_area_mt_setting **area_settings;
318 unsigned int area_count;
99894f9a 319
d62a17ae 320 unsigned int count = 0;
99894f9a 321
d62a17ae 322 struct listnode *node;
323 struct isis_circuit_mt_setting *setting;
99894f9a 324
d62a17ae 325 area_settings = area_mt_settings(circuit->area, &area_count);
99894f9a 326
d62a17ae 327 for (unsigned int i = 0; i < area_count; i++) {
328 for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node,
329 setting)) {
330 if (setting->mtid != area_settings[i]->mtid)
331 continue;
332 break;
333 }
334 if (!setting)
335 setting = circuit_get_mt_setting(
336 circuit, area_settings[i]->mtid);
99894f9a 337
d62a17ae 338 if (!setting->enabled)
339 continue;
99894f9a 340
d62a17ae 341 count++;
342 if (count > size) {
343 rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
344 size = count;
345 }
346 rv[count - 1] = setting;
347 }
99894f9a 348
d62a17ae 349 *mt_count = count;
350 return rv;
99894f9a 351}
d8fba7d9 352
206f4aae 353/* ADJ specific MT API */
d8fba7d9 354static void adj_mt_set(struct isis_adjacency *adj, unsigned int index,
d62a17ae 355 uint16_t mtid)
356{
357 if (adj->mt_count < index + 1) {
358 adj->mt_set = XREALLOC(MTYPE_MT_ADJ_INFO, adj->mt_set,
359 (index + 1) * sizeof(*adj->mt_set));
360 adj->mt_count = index + 1;
361 }
362 adj->mt_set[index] = mtid;
363}
364
0c1bd758 365bool tlvs_to_adj_mt_set(struct isis_tlvs *tlvs, bool v4_usable, bool v6_usable,
d62a17ae 366 struct isis_adjacency *adj)
367{
368 struct isis_circuit_mt_setting **mt_settings;
369 unsigned int circuit_mt_count;
370
371 unsigned int intersect_count = 0;
372
373 uint16_t *old_mt_set = NULL;
374 unsigned int old_mt_count;
375
376 old_mt_count = adj->mt_count;
377 if (old_mt_count) {
378 old_mt_set =
379 XCALLOC(MTYPE_TMP, old_mt_count * sizeof(*old_mt_set));
380 memcpy(old_mt_set, adj->mt_set,
381 old_mt_count * sizeof(*old_mt_set));
382 }
383
384 mt_settings = circuit_mt_settings(adj->circuit, &circuit_mt_count);
385 for (unsigned int i = 0; i < circuit_mt_count; i++) {
af8ac8f9
CF
386 if (!tlvs->mt_router_info.count
387 && !tlvs->mt_router_info_empty) {
d62a17ae 388 /* Other end does not have MT enabled */
389 if (mt_settings[i]->mtid == ISIS_MT_IPV4_UNICAST
390 && v4_usable)
391 adj_mt_set(adj, intersect_count++,
392 ISIS_MT_IPV4_UNICAST);
393 } else {
0c1bd758
CF
394 struct isis_mt_router_info *info_head;
395
396 info_head = (struct isis_mt_router_info *)
397 tlvs->mt_router_info.head;
398 for (struct isis_mt_router_info *info = info_head; info;
399 info = info->next) {
d62a17ae 400 if (mt_settings[i]->mtid == info->mtid) {
401 bool usable;
402 switch (info->mtid) {
403 case ISIS_MT_IPV4_UNICAST:
404 case ISIS_MT_IPV4_MGMT:
405 case ISIS_MT_IPV4_MULTICAST:
406 usable = v4_usable;
407 break;
408 case ISIS_MT_IPV6_UNICAST:
409 case ISIS_MT_IPV6_MGMT:
410 case ISIS_MT_IPV6_MULTICAST:
411 usable = v6_usable;
412 break;
413 default:
414 usable = true;
415 break;
416 }
417 if (usable)
418 adj_mt_set(adj,
419 intersect_count++,
420 info->mtid);
421 }
422 }
423 }
424 }
425 adj->mt_count = intersect_count;
426
427 bool changed = false;
428
429 if (adj->mt_count != old_mt_count)
430 changed = true;
431
432 if (!changed && old_mt_count
433 && memcmp(adj->mt_set, old_mt_set,
434 old_mt_count * sizeof(*old_mt_set)))
435 changed = true;
436
437 if (old_mt_count)
438 XFREE(MTYPE_TMP, old_mt_set);
439
440 return changed;
441}
442
443bool adj_has_mt(struct isis_adjacency *adj, uint16_t mtid)
444{
445 for (unsigned int i = 0; i < adj->mt_count; i++)
446 if (adj->mt_set[i] == mtid)
447 return true;
448 return false;
449}
450
451void adj_mt_finish(struct isis_adjacency *adj)
452{
453 XFREE(MTYPE_MT_ADJ_INFO, adj->mt_set);
454 adj->mt_count = 0;
d8fba7d9 455}
206f4aae 456
d62a17ae 457static void mt_set_add(uint16_t **mt_set, unsigned int *size,
458 unsigned int *index, uint16_t mtid)
206f4aae 459{
d62a17ae 460 for (unsigned int i = 0; i < *index; i++) {
461 if ((*mt_set)[i] == mtid)
462 return;
463 }
206f4aae 464
d62a17ae 465 if (*index >= *size) {
466 *mt_set = XREALLOC(MTYPE_TMP, *mt_set,
467 sizeof(**mt_set) * ((*index) + 1));
468 *size = (*index) + 1;
469 }
206f4aae 470
d62a17ae 471 (*mt_set)[*index] = mtid;
472 *index = (*index) + 1;
206f4aae
CF
473}
474
d62a17ae 475static uint16_t *circuit_bcast_mt_set(struct isis_circuit *circuit, int level,
476 unsigned int *mt_count)
206f4aae 477{
d62a17ae 478 static uint16_t *rv;
479 static unsigned int size;
480 struct listnode *node;
481 struct isis_adjacency *adj;
206f4aae 482
d62a17ae 483 unsigned int count = 0;
206f4aae 484
d62a17ae 485 if (circuit->circ_type != CIRCUIT_T_BROADCAST) {
486 *mt_count = 0;
487 return NULL;
488 }
206f4aae 489
d62a17ae 490 for (ALL_LIST_ELEMENTS_RO(circuit->u.bc.adjdb[level - 1], node, adj)) {
491 if (adj->adj_state != ISIS_ADJ_UP)
492 continue;
493 for (unsigned int i = 0; i < adj->mt_count; i++)
494 mt_set_add(&rv, &size, &count, adj->mt_set[i]);
495 }
206f4aae 496
d62a17ae 497 *mt_count = count;
498 return rv;
206f4aae
CF
499}
500
af8ac8f9 501static void tlvs_add_mt_set(struct isis_area *area, struct isis_tlvs *tlvs,
d62a17ae 502 unsigned int mt_count, uint16_t *mt_set,
af8ac8f9
CF
503 uint8_t *id, uint32_t metric, uint8_t *subtlvs,
504 uint8_t subtlv_len)
206f4aae 505{
d62a17ae 506 for (unsigned int i = 0; i < mt_count; i++) {
507 uint16_t mtid = mt_set[i];
d62a17ae 508 if (mt_set[i] == ISIS_MT_IPV4_UNICAST) {
d62a17ae 509 lsp_debug(
510 "ISIS (%s): Adding %s.%02x as te-style neighbor",
af8ac8f9
CF
511 area->area_tag, sysid_print(id),
512 LSP_PSEUDO_ID(id));
d62a17ae 513 } else {
d62a17ae 514 lsp_debug(
515 "ISIS (%s): Adding %s.%02x as mt-style neighbor for %s",
af8ac8f9
CF
516 area->area_tag, sysid_print(id),
517 LSP_PSEUDO_ID(id), isis_mtid2str(mtid));
d62a17ae 518 }
af8ac8f9
CF
519 isis_tlvs_add_extended_reach(tlvs, mtid, id, metric, subtlvs,
520 subtlv_len);
d62a17ae 521 }
206f4aae
CF
522}
523
af8ac8f9
CF
524void tlvs_add_mt_bcast(struct isis_tlvs *tlvs, struct isis_circuit *circuit,
525 int level, uint8_t *id, uint32_t metric,
526 uint8_t *subtlvs, uint8_t subtlv_len)
206f4aae 527{
d62a17ae 528 unsigned int mt_count;
529 uint16_t *mt_set = circuit_bcast_mt_set(circuit, level, &mt_count);
206f4aae 530
af8ac8f9
CF
531 tlvs_add_mt_set(circuit->area, tlvs, mt_count, mt_set, id, metric,
532 subtlvs, subtlv_len);
d62a17ae 533}
534
af8ac8f9
CF
535void tlvs_add_mt_p2p(struct isis_tlvs *tlvs, struct isis_circuit *circuit,
536 uint8_t *id, uint32_t metric, uint8_t *subtlvs,
537 uint8_t subtlv_len)
206f4aae 538{
d62a17ae 539 struct isis_adjacency *adj = circuit->u.p2p.neighbor;
206f4aae 540
af8ac8f9
CF
541 tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, id,
542 metric, subtlvs, subtlv_len);
206f4aae 543}