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