]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_mt.c
Merge remote-tracking branch 'origin/stable/3.0'
[mirror_frr.git] / isisd / isis_mt.c
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"
27 #include "isisd/isis_adjacency.h"
28 #include "isisd/isis_tlv.h"
29 #include "isisd/isis_misc.h"
30 #include "isisd/isis_lsp.h"
31 #include "isisd/isis_mt.h"
32
33 DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting")
34 DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting")
35 DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info")
36 DEFINE_MTYPE_STATIC(ISISD, MT_NEIGHBORS, "ISIS MT Neighbors for TLV")
37 DEFINE_MTYPE_STATIC(ISISD, MT_IPV4_REACHS, "ISIS MT IPv4 Reachabilities for TLV")
38 DEFINE_MTYPE_STATIC(ISISD, MT_IPV6_REACHS, "ISIS MT IPv6 Reachabilities for TLV")
39
40 uint16_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 }
49
50 /* MT naming api */
51 const char *isis_mtid2str(uint16_t mtid)
52 {
53 static char buf[sizeof("65535")];
54
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:
70 snprintf(buf, sizeof(buf), "%" PRIu16, mtid);
71 return buf;
72 }
73 }
74
75 uint16_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
94 struct mt_setting {
95 ISIS_MT_INFO_FIELDS;
96 };
97
98 static void *
99 lookup_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
112 static void
113 add_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
122 struct isis_area_mt_setting*
123 area_lookup_mt_setting(struct isis_area *area, uint16_t mtid)
124 {
125 return lookup_mt_setting(area->mt_settings, mtid);
126 }
127
128 struct isis_area_mt_setting*
129 area_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
138 static void
139 area_free_mt_setting(void *setting)
140 {
141 XFREE(MTYPE_MT_AREA_SETTING, setting);
142 }
143
144 void
145 area_add_mt_setting(struct isis_area *area, struct isis_area_mt_setting *setting)
146 {
147 add_mt_setting(&area->mt_settings, setting);
148 }
149
150 void
151 area_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
162 void
163 area_mt_finish(struct isis_area *area)
164 {
165 list_delete(area->mt_settings);
166 area->mt_settings = NULL;
167 }
168
169 struct isis_area_mt_setting *
170 area_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
183 int
184 area_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
206 bool 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
230 struct isis_area_mt_setting**
231 area_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
258 /* Circuit specific MT settings api */
259
260 struct isis_circuit_mt_setting*
261 circuit_lookup_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
262 {
263 return lookup_mt_setting(circuit->mt_settings, mtid);
264 }
265
266 struct isis_circuit_mt_setting*
267 circuit_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
277 static void
278 circuit_free_mt_setting(void *setting)
279 {
280 XFREE(MTYPE_MT_CIRCUIT_SETTING, setting);
281 }
282
283 void
284 circuit_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
290 void
291 circuit_mt_init(struct isis_circuit *circuit)
292 {
293 circuit->mt_settings = list_new();
294 circuit->mt_settings->del = circuit_free_mt_setting;
295 }
296
297 void
298 circuit_mt_finish(struct isis_circuit *circuit)
299 {
300 list_delete(circuit->mt_settings);
301 circuit->mt_settings = NULL;
302 }
303
304 struct isis_circuit_mt_setting*
305 circuit_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
318 int
319 circuit_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 }
336
337 struct isis_circuit_mt_setting**
338 circuit_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 }
379
380 /* ADJ specific MT API */
381 static 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
393 bool
394 tlvs_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
402 uint16_t *old_mt_set = NULL;
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 */
418 if (mt_settings[i]->mtid == ISIS_MT_IPV4_UNICAST && v4_usable)
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)
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 }
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
470 bool
471 adj_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
479 void
480 adj_mt_finish(struct isis_adjacency *adj)
481 {
482 XFREE(MTYPE_MT_ADJ_INFO, adj->mt_set);
483 adj->mt_count = 0;
484 }
485
486 /* TLV Router info api */
487 struct mt_router_info*
488 tlvs_lookup_mt_router_info(struct tlvs *tlvs, uint16_t mtid)
489 {
490 return lookup_mt_setting(tlvs->mt_router_info, mtid);
491 }
492
493 /* TLV MT Neighbors api */
494 struct tlv_mt_neighbors*
495 tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
496 {
497 return lookup_mt_setting(tlvs->mt_is_neighs, mtid);
498 }
499
500 static struct tlv_mt_neighbors*
501 tlvs_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
512 static void
513 tlvs_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
522 static void
523 tlvs_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
529 struct tlv_mt_neighbors*
530 tlvs_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
543 /* TLV MT IPv4 reach api */
544 struct tlv_mt_ipv4_reachs*
545 tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid)
546 {
547 return lookup_mt_setting(tlvs->mt_ipv4_reachs, mtid);
548 }
549
550 static struct tlv_mt_ipv4_reachs*
551 tlvs_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
562 static void
563 tlvs_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
572 static void
573 tlvs_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
579 struct tlv_mt_ipv4_reachs*
580 tlvs_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 */
594 struct tlv_mt_ipv6_reachs*
595 tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid)
596 {
597 return lookup_mt_setting(tlvs->mt_ipv6_reachs, mtid);
598 }
599
600 static struct tlv_mt_ipv6_reachs*
601 tlvs_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
612 static void
613 tlvs_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
622 static void
623 tlvs_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
629 struct tlv_mt_ipv6_reachs*
630 tlvs_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
643 static void
644 mt_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
663 static uint16_t *
664 circuit_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
692 static void
693 tlvs_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
726 void
727 tlvs_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
737 void
738 tlvs_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 }