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