]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_mt.c
*: make consistent & update GPLv2 file headers
[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
CF
26#include "isisd/isis_adjacency.h"
27#include "isisd/isis_tlv.h"
206f4aae
CF
28#include "isisd/isis_misc.h"
29#include "isisd/isis_lsp.h"
064f4896
CF
30#include "isisd/isis_mt.h"
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")
206f4aae 35DEFINE_MTYPE_STATIC(ISISD, MT_NEIGHBORS, "ISIS MT Neighbors for TLV")
c3ae3127
CF
36DEFINE_MTYPE_STATIC(ISISD, MT_IPV4_REACHS, "ISIS MT IPv4 Reachabilities for TLV")
37DEFINE_MTYPE_STATIC(ISISD, MT_IPV6_REACHS, "ISIS MT IPv6 Reachabilities for TLV")
38
39uint16_t isis_area_ipv6_topology(struct isis_area *area)
40{
41 struct isis_area_mt_setting *area_mt_setting;
42 area_mt_setting = area_lookup_mt_setting(area, ISIS_MT_IPV6_UNICAST);
43
44 if (area_mt_setting && area_mt_setting->enabled)
45 return ISIS_MT_IPV6_UNICAST;
46 return ISIS_MT_IPV4_UNICAST;
47}
064f4896
CF
48
49/* MT naming api */
50const char *isis_mtid2str(uint16_t mtid)
51{
d8fba7d9
CF
52 static char buf[sizeof("65535")];
53
064f4896
CF
54 switch(mtid)
55 {
56 case ISIS_MT_IPV4_UNICAST:
57 return "ipv4-unicast";
58 case ISIS_MT_IPV4_MGMT:
59 return "ipv4-mgmt";
60 case ISIS_MT_IPV6_UNICAST:
61 return "ipv6-unicast";
62 case ISIS_MT_IPV4_MULTICAST:
63 return "ipv4-multicast";
64 case ISIS_MT_IPV6_MULTICAST:
65 return "ipv6-multicast";
66 case ISIS_MT_IPV6_MGMT:
67 return "ipv6-mgmt";
68 default:
d8fba7d9
CF
69 snprintf(buf, sizeof(buf), "%" PRIu16, mtid);
70 return buf;
064f4896
CF
71 }
72}
73
74uint16_t isis_str2mtid(const char *name)
75{
76 if (!strcmp(name,"ipv4-unicast"))
77 return ISIS_MT_IPV4_UNICAST;
78 if (!strcmp(name,"ipv4-mgmt"))
79 return ISIS_MT_IPV4_MGMT;
80 if (!strcmp(name,"ipv6-unicast"))
81 return ISIS_MT_IPV6_UNICAST;
82 if (!strcmp(name,"ipv4-multicast"))
83 return ISIS_MT_IPV4_MULTICAST;
84 if (!strcmp(name,"ipv6-multicast"))
85 return ISIS_MT_IPV6_MULTICAST;
86 if (!strcmp(name,"ipv6-mgmt"))
87 return ISIS_MT_IPV6_MGMT;
88 return -1;
89}
90
91/* General MT settings api */
92
93struct mt_setting {
94 ISIS_MT_INFO_FIELDS;
95};
96
97static void *
98lookup_mt_setting(struct list *mt_list, uint16_t mtid)
99{
100 struct listnode *node;
101 struct mt_setting *setting;
102
103 for (ALL_LIST_ELEMENTS_RO(mt_list, node, setting))
104 {
105 if (setting->mtid == mtid)
106 return setting;
107 }
108 return NULL;
109}
110
111static void
112add_mt_setting(struct list **mt_list, void *setting)
113{
114 if (!*mt_list)
115 *mt_list = list_new();
116 listnode_add(*mt_list, setting);
117}
118
119/* Area specific MT settings api */
120
121struct isis_area_mt_setting*
122area_lookup_mt_setting(struct isis_area *area, uint16_t mtid)
123{
124 return lookup_mt_setting(area->mt_settings, mtid);
125}
126
127struct isis_area_mt_setting*
128area_new_mt_setting(struct isis_area *area, uint16_t mtid)
129{
130 struct isis_area_mt_setting *setting;
131
132 setting = XCALLOC(MTYPE_MT_AREA_SETTING, sizeof(*setting));
133 setting->mtid = mtid;
134 return setting;
135}
136
137static void
138area_free_mt_setting(void *setting)
139{
140 XFREE(MTYPE_MT_AREA_SETTING, setting);
141}
142
143void
144area_add_mt_setting(struct isis_area *area, struct isis_area_mt_setting *setting)
145{
146 add_mt_setting(&area->mt_settings, setting);
147}
148
149void
150area_mt_init(struct isis_area *area)
151{
152 struct isis_area_mt_setting *v4_unicast_setting;
153
154 /* MTID 0 is always enabled */
155 v4_unicast_setting = area_new_mt_setting(area, ISIS_MT_IPV4_UNICAST);
156 v4_unicast_setting->enabled = true;
157 add_mt_setting(&area->mt_settings, v4_unicast_setting);
158 area->mt_settings->del = area_free_mt_setting;
159}
160
161void
162area_mt_finish(struct isis_area *area)
163{
164 list_delete(area->mt_settings);
165 area->mt_settings = NULL;
166}
167
168struct isis_area_mt_setting *
169area_get_mt_setting(struct isis_area *area, uint16_t mtid)
170{
171 struct isis_area_mt_setting *setting;
172
173 setting = area_lookup_mt_setting(area, mtid);
174 if (!setting)
175 {
176 setting = area_new_mt_setting(area, mtid);
177 area_add_mt_setting(area, setting);
178 }
179 return setting;
180}
181
182int
183area_write_mt_settings(struct isis_area *area, struct vty *vty)
184{
185 int written = 0;
186 struct listnode *node;
187 struct isis_area_mt_setting *setting;
188
189 for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
190 {
191 const char *name = isis_mtid2str(setting->mtid);
192 if (name && setting->enabled)
193 {
194 if (setting->mtid == ISIS_MT_IPV4_UNICAST)
195 continue; /* always enabled, no need to write out config */
196 vty_out (vty, " topology %s%s%s", name,
197 setting->overload ? " overload" : "",
198 VTY_NEWLINE);
199 written++;
200 }
201 }
202 return written;
203}
204
99894f9a
CF
205bool area_is_mt(struct isis_area *area)
206{
207 struct listnode *node, *node2;
208 struct isis_area_mt_setting *setting;
209 struct isis_circuit *circuit;
210 struct isis_circuit_mt_setting *csetting;
211
212 for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
213 {
214 if (setting->enabled && setting->mtid != ISIS_MT_IPV4_UNICAST)
215 return true;
216 }
217 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
218 {
219 for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node2, csetting))
220 {
221 if (!csetting->enabled && csetting->mtid == ISIS_MT_IPV4_UNICAST)
222 return true;
223 }
224 }
225
226 return false;
227}
228
229struct isis_area_mt_setting**
230area_mt_settings(struct isis_area *area, unsigned int *mt_count)
231{
232 static unsigned int size = 0;
233 static struct isis_area_mt_setting **rv = NULL;
234
235 unsigned int count = 0;
236 struct listnode *node;
237 struct isis_area_mt_setting *setting;
238
239 for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
240 {
241 if (!setting->enabled)
242 continue;
243
244 count++;
245 if (count > size)
246 {
247 rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
248 size = count;
249 }
250 rv[count-1] = setting;
251 }
252
253 *mt_count = count;
254 return rv;
255}
256
064f4896
CF
257/* Circuit specific MT settings api */
258
259struct isis_circuit_mt_setting*
260circuit_lookup_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
261{
262 return lookup_mt_setting(circuit->mt_settings, mtid);
263}
264
265struct isis_circuit_mt_setting*
266circuit_new_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
267{
268 struct isis_circuit_mt_setting *setting;
269
270 setting = XCALLOC(MTYPE_MT_CIRCUIT_SETTING, sizeof(*setting));
271 setting->mtid = mtid;
272 setting->enabled = true; /* Enabled is default for circuit */
273 return setting;
274}
275
276static void
277circuit_free_mt_setting(void *setting)
278{
279 XFREE(MTYPE_MT_CIRCUIT_SETTING, setting);
280}
281
282void
283circuit_add_mt_setting(struct isis_circuit *circuit,
284 struct isis_circuit_mt_setting *setting)
285{
286 add_mt_setting(&circuit->mt_settings, setting);
287}
288
289void
290circuit_mt_init(struct isis_circuit *circuit)
291{
292 circuit->mt_settings = list_new();
293 circuit->mt_settings->del = circuit_free_mt_setting;
294}
295
296void
297circuit_mt_finish(struct isis_circuit *circuit)
298{
299 list_delete(circuit->mt_settings);
300 circuit->mt_settings = NULL;
301}
302
303struct isis_circuit_mt_setting*
304circuit_get_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
305{
306 struct isis_circuit_mt_setting *setting;
307
308 setting = circuit_lookup_mt_setting(circuit, mtid);
309 if (!setting)
310 {
311 setting = circuit_new_mt_setting(circuit, mtid);
312 circuit_add_mt_setting(circuit, setting);
313 }
314 return setting;
315}
316
317int
318circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty)
319{
320 int written = 0;
321 struct listnode *node;
322 struct isis_circuit_mt_setting *setting;
323
324 for (ALL_LIST_ELEMENTS_RO (circuit->mt_settings, node, setting))
325 {
326 const char *name = isis_mtid2str(setting->mtid);
327 if (name && !setting->enabled)
328 {
329 vty_out (vty, " no isis topology %s%s", name, VTY_NEWLINE);
330 written++;
331 }
332 }
333 return written;
334}
99894f9a
CF
335
336struct isis_circuit_mt_setting**
337circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count)
338{
339 static unsigned int size = 0;
340 static struct isis_circuit_mt_setting **rv = NULL;
341
342 struct isis_area_mt_setting **area_settings;
343 unsigned int area_count;
344
345 unsigned int count = 0;
346
347 struct listnode *node;
348 struct isis_circuit_mt_setting *setting;
349
350 area_settings = area_mt_settings(circuit->area, &area_count);
351
352 for (unsigned int i = 0; i < area_count; i++)
353 {
354 for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node, setting))
355 {
356 if (setting->mtid != area_settings[i]->mtid)
357 continue;
358 break;
359 }
360 if (!setting)
361 setting = circuit_get_mt_setting(circuit, area_settings[i]->mtid);
362
363 if (!setting->enabled)
364 continue;
365
366 count++;
367 if (count > size)
368 {
369 rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
370 size = count;
371 }
372 rv[count-1] = setting;
373 }
374
375 *mt_count = count;
376 return rv;
377}
d8fba7d9 378
206f4aae 379/* ADJ specific MT API */
d8fba7d9
CF
380static void adj_mt_set(struct isis_adjacency *adj, unsigned int index,
381 uint16_t mtid)
382{
383 if (adj->mt_count < index + 1)
384 {
385 adj->mt_set = XREALLOC(MTYPE_MT_ADJ_INFO, adj->mt_set,
386 (index + 1) * sizeof(*adj->mt_set));
387 adj->mt_count = index + 1;
388 }
389 adj->mt_set[index] = mtid;
390}
391
392bool
393tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable,
394 struct isis_adjacency *adj)
395{
396 struct isis_circuit_mt_setting **mt_settings;
397 unsigned int circuit_mt_count;
398
399 unsigned int intersect_count = 0;
400
11dde3fa 401 uint16_t *old_mt_set = NULL;
d8fba7d9
CF
402 unsigned int old_mt_count;
403
404 old_mt_count = adj->mt_count;
405 if (old_mt_count)
406 {
407 old_mt_set = XCALLOC(MTYPE_TMP, old_mt_count * sizeof(*old_mt_set));
408 memcpy(old_mt_set, adj->mt_set, old_mt_count * sizeof(*old_mt_set));
409 }
410
411 mt_settings = circuit_mt_settings(adj->circuit, &circuit_mt_count);
412 for (unsigned int i = 0; i < circuit_mt_count; i++)
413 {
414 if (!tlvs->mt_router_info)
415 {
416 /* Other end does not have MT enabled */
cb02eebe 417 if (mt_settings[i]->mtid == ISIS_MT_IPV4_UNICAST && v4_usable)
d8fba7d9
CF
418 adj_mt_set(adj, intersect_count++, ISIS_MT_IPV4_UNICAST);
419 }
420 else
421 {
422 struct listnode *node;
423 struct mt_router_info *info;
424 for (ALL_LIST_ELEMENTS_RO(tlvs->mt_router_info, node, info))
425 {
426 if (mt_settings[i]->mtid == info->mtid)
cb02eebe
CF
427 {
428 bool usable;
429 switch (info->mtid)
430 {
431 case ISIS_MT_IPV4_UNICAST:
432 case ISIS_MT_IPV4_MGMT:
433 case ISIS_MT_IPV4_MULTICAST:
434 usable = v4_usable;
435 break;
436 case ISIS_MT_IPV6_UNICAST:
437 case ISIS_MT_IPV6_MGMT:
438 case ISIS_MT_IPV6_MULTICAST:
439 usable = v6_usable;
440 break;
441 default:
442 usable = true;
443 break;
444 }
445 if (usable)
446 adj_mt_set(adj, intersect_count++, info->mtid);
447 }
d8fba7d9
CF
448 }
449 }
450 }
451 adj->mt_count = intersect_count;
452
453 bool changed = false;
454
455 if (adj->mt_count != old_mt_count)
456 changed = true;
457
458 if (!changed && old_mt_count
459 && memcmp(adj->mt_set, old_mt_set,
460 old_mt_count * sizeof(*old_mt_set)))
461 changed = true;
462
463 if (old_mt_count)
464 XFREE(MTYPE_TMP, old_mt_set);
465
466 return changed;
467}
468
2b67862c
CF
469bool
470adj_has_mt(struct isis_adjacency *adj, uint16_t mtid)
471{
472 for (unsigned int i = 0; i < adj->mt_count; i++)
473 if (adj->mt_set[i] == mtid)
474 return true;
475 return false;
476}
477
d8fba7d9
CF
478void
479adj_mt_finish(struct isis_adjacency *adj)
480{
481 XFREE(MTYPE_MT_ADJ_INFO, adj->mt_set);
482 adj->mt_count = 0;
483}
206f4aae 484
2b67862c
CF
485/* TLV Router info api */
486struct mt_router_info*
487tlvs_lookup_mt_router_info(struct tlvs *tlvs, uint16_t mtid)
488{
489 return lookup_mt_setting(tlvs->mt_router_info, mtid);
490}
491
206f4aae
CF
492/* TLV MT Neighbors api */
493struct tlv_mt_neighbors*
494tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
495{
496 return lookup_mt_setting(tlvs->mt_is_neighs, mtid);
497}
498
499static struct tlv_mt_neighbors*
500tlvs_new_mt_neighbors(uint16_t mtid)
501{
502 struct tlv_mt_neighbors *rv;
503
504 rv = XCALLOC(MTYPE_MT_NEIGHBORS, sizeof(*rv));
505 rv->mtid = mtid;
506 rv->list = list_new();
507
508 return rv;
509};
510
511static void
512tlvs_free_mt_neighbors(void *arg)
513{
514 struct tlv_mt_neighbors *neighbors = arg;
515
516 if (neighbors && neighbors->list)
517 list_delete(neighbors->list);
518 XFREE(MTYPE_MT_NEIGHBORS, neighbors);
519}
520
521static void
522tlvs_add_mt_neighbors(struct tlvs *tlvs, struct tlv_mt_neighbors *neighbors)
523{
524 add_mt_setting(&tlvs->mt_is_neighs, neighbors);
525 tlvs->mt_is_neighs->del = tlvs_free_mt_neighbors;
526}
527
528struct tlv_mt_neighbors*
529tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
530{
531 struct tlv_mt_neighbors *neighbors;
532
533 neighbors = tlvs_lookup_mt_neighbors(tlvs, mtid);
534 if (!neighbors)
535 {
536 neighbors = tlvs_new_mt_neighbors(mtid);
537 tlvs_add_mt_neighbors(tlvs, neighbors);
538 }
539 return neighbors;
540}
541
c3ae3127
CF
542/* TLV MT IPv4 reach api */
543struct tlv_mt_ipv4_reachs*
544tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid)
545{
546 return lookup_mt_setting(tlvs->mt_ipv4_reachs, mtid);
547}
548
549static struct tlv_mt_ipv4_reachs*
550tlvs_new_mt_ipv4_reachs(uint16_t mtid)
551{
552 struct tlv_mt_ipv4_reachs *rv;
553
554 rv = XCALLOC(MTYPE_MT_IPV4_REACHS, sizeof(*rv));
555 rv->mtid = mtid;
556 rv->list = list_new();
557
558 return rv;
559};
560
561static void
562tlvs_free_mt_ipv4_reachs(void *arg)
563{
564 struct tlv_mt_ipv4_reachs *reachs = arg;
565
566 if (reachs && reachs->list)
567 list_delete(reachs->list);
568 XFREE(MTYPE_MT_IPV4_REACHS, reachs);
569}
570
571static void
572tlvs_add_mt_ipv4_reachs(struct tlvs *tlvs, struct tlv_mt_ipv4_reachs *reachs)
573{
574 add_mt_setting(&tlvs->mt_ipv4_reachs, reachs);
575 tlvs->mt_ipv4_reachs->del = tlvs_free_mt_ipv4_reachs;
576}
577
578struct tlv_mt_ipv4_reachs*
579tlvs_get_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid)
580{
581 struct tlv_mt_ipv4_reachs *reachs;
582
583 reachs = tlvs_lookup_mt_ipv4_reachs(tlvs, mtid);
584 if (!reachs)
585 {
586 reachs = tlvs_new_mt_ipv4_reachs(mtid);
587 tlvs_add_mt_ipv4_reachs(tlvs, reachs);
588 }
589 return reachs;
590}
591
592/* TLV MT IPv6 reach api */
593struct tlv_mt_ipv6_reachs*
594tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid)
595{
596 return lookup_mt_setting(tlvs->mt_ipv6_reachs, mtid);
597}
598
599static struct tlv_mt_ipv6_reachs*
600tlvs_new_mt_ipv6_reachs(uint16_t mtid)
601{
602 struct tlv_mt_ipv6_reachs *rv;
603
604 rv = XCALLOC(MTYPE_MT_IPV6_REACHS, sizeof(*rv));
605 rv->mtid = mtid;
606 rv->list = list_new();
607
608 return rv;
609};
610
611static void
612tlvs_free_mt_ipv6_reachs(void *arg)
613{
614 struct tlv_mt_ipv6_reachs *reachs = arg;
615
616 if (reachs && reachs->list)
617 list_delete(reachs->list);
618 XFREE(MTYPE_MT_IPV6_REACHS, reachs);
619}
620
621static void
622tlvs_add_mt_ipv6_reachs(struct tlvs *tlvs, struct tlv_mt_ipv6_reachs *reachs)
623{
624 add_mt_setting(&tlvs->mt_ipv6_reachs, reachs);
625 tlvs->mt_ipv6_reachs->del = tlvs_free_mt_ipv6_reachs;
626}
627
628struct tlv_mt_ipv6_reachs*
629tlvs_get_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid)
630{
631 struct tlv_mt_ipv6_reachs *reachs;
632
633 reachs = tlvs_lookup_mt_ipv6_reachs(tlvs, mtid);
634 if (!reachs)
635 {
636 reachs = tlvs_new_mt_ipv6_reachs(mtid);
637 tlvs_add_mt_ipv6_reachs(tlvs, reachs);
638 }
639 return reachs;
640}
641
206f4aae
CF
642static void
643mt_set_add(uint16_t **mt_set, unsigned int *size,
644 unsigned int *index, uint16_t mtid)
645{
646 for (unsigned int i = 0; i < *index; i++)
647 {
648 if ((*mt_set)[i] == mtid)
649 return;
650 }
651
652 if (*index >= *size)
653 {
654 *mt_set = XREALLOC(MTYPE_TMP, *mt_set, sizeof(**mt_set) * ((*index) + 1));
655 *size = (*index) + 1;
656 }
657
658 (*mt_set)[*index] = mtid;
659 *index = (*index) + 1;
660}
661
662static uint16_t *
663circuit_bcast_mt_set(struct isis_circuit *circuit, int level,
664 unsigned int *mt_count)
665{
666 static uint16_t *rv;
667 static unsigned int size;
668 struct listnode *node;
669 struct isis_adjacency *adj;
670
671 unsigned int count = 0;
672
673 if (circuit->circ_type != CIRCUIT_T_BROADCAST)
674 {
675 *mt_count = 0;
676 return NULL;
677 }
678
679 for (ALL_LIST_ELEMENTS_RO(circuit->u.bc.adjdb[level - 1], node, adj))
680 {
681 if (adj->adj_state != ISIS_ADJ_UP)
682 continue;
683 for (unsigned int i = 0; i < adj->mt_count; i++)
684 mt_set_add(&rv, &size, &count, adj->mt_set[i]);
685 }
686
687 *mt_count = count;
688 return rv;
689}
690
691static void
692tlvs_add_mt_set(struct isis_area *area,
693 struct tlvs *tlvs, unsigned int mt_count,
694 uint16_t *mt_set, struct te_is_neigh *neigh)
695{
696 for (unsigned int i = 0; i < mt_count; i++)
697 {
698 uint16_t mtid = mt_set[i];
699 struct te_is_neigh *ne_copy;
700
701 ne_copy = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ne_copy));
702 memcpy(ne_copy, neigh, sizeof(*ne_copy));
703
704 if (mt_set[i] == ISIS_MT_IPV4_UNICAST)
705 {
706 listnode_add(tlvs->te_is_neighs, ne_copy);
707 lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor",
708 area->area_tag, sysid_print(ne_copy->neigh_id),
709 LSP_PSEUDO_ID(ne_copy->neigh_id));
710 }
711 else
712 {
713 struct tlv_mt_neighbors *neighbors;
714
715 neighbors = tlvs_get_mt_neighbors(tlvs, mtid);
716 neighbors->list->del = free_tlv;
717 listnode_add(neighbors->list, ne_copy);
718 lsp_debug("ISIS (%s): Adding %s.%02x as mt-style neighbor for %s",
719 area->area_tag, sysid_print(ne_copy->neigh_id),
720 LSP_PSEUDO_ID(ne_copy->neigh_id), isis_mtid2str(mtid));
721 }
722 }
723}
724
725void
726tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit,
727 int level, struct te_is_neigh *neigh)
728{
729 unsigned int mt_count;
730 uint16_t *mt_set = circuit_bcast_mt_set(circuit, level,
731 &mt_count);
732
733 tlvs_add_mt_set(circuit->area, tlvs, mt_count, mt_set, neigh);
734}
735
736void
737tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit,
738 struct te_is_neigh *neigh)
739{
740 struct isis_adjacency *adj = circuit->u.p2p.neighbor;
741
742 tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, neigh);
743}