]> 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 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
21 */
22 #include <zebra.h>
23 #include "isisd/isisd.h"
24 #include "isisd/isis_memory.h"
25 #include "isisd/isis_circuit.h"
26 #include "isisd/isis_adjacency.h"
27 #include "isisd/isis_tlv.h"
28 #include "isisd/isis_misc.h"
29 #include "isisd/isis_lsp.h"
30 #include "isisd/isis_mt.h"
31
32 DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting")
33 DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting")
34 DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info")
35 DEFINE_MTYPE_STATIC(ISISD, MT_NEIGHBORS, "ISIS MT Neighbors for TLV")
36 DEFINE_MTYPE_STATIC(ISISD, MT_IPV4_REACHS, "ISIS MT IPv4 Reachabilities for TLV")
37 DEFINE_MTYPE_STATIC(ISISD, MT_IPV6_REACHS, "ISIS MT IPv6 Reachabilities for TLV")
38
39 uint16_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 }
48
49 /* MT naming api */
50 const char *isis_mtid2str(uint16_t mtid)
51 {
52 static char buf[sizeof("65535")];
53
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:
69 snprintf(buf, sizeof(buf), "%" PRIu16, mtid);
70 return buf;
71 }
72 }
73
74 uint16_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
93 struct mt_setting {
94 ISIS_MT_INFO_FIELDS;
95 };
96
97 static void *
98 lookup_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
111 static void
112 add_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
121 struct isis_area_mt_setting*
122 area_lookup_mt_setting(struct isis_area *area, uint16_t mtid)
123 {
124 return lookup_mt_setting(area->mt_settings, mtid);
125 }
126
127 struct isis_area_mt_setting*
128 area_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
137 static void
138 area_free_mt_setting(void *setting)
139 {
140 XFREE(MTYPE_MT_AREA_SETTING, setting);
141 }
142
143 void
144 area_add_mt_setting(struct isis_area *area, struct isis_area_mt_setting *setting)
145 {
146 add_mt_setting(&area->mt_settings, setting);
147 }
148
149 void
150 area_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
161 void
162 area_mt_finish(struct isis_area *area)
163 {
164 list_delete(area->mt_settings);
165 area->mt_settings = NULL;
166 }
167
168 struct isis_area_mt_setting *
169 area_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
182 int
183 area_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
205 bool 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
229 struct isis_area_mt_setting**
230 area_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
257 /* Circuit specific MT settings api */
258
259 struct isis_circuit_mt_setting*
260 circuit_lookup_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
261 {
262 return lookup_mt_setting(circuit->mt_settings, mtid);
263 }
264
265 struct isis_circuit_mt_setting*
266 circuit_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
276 static void
277 circuit_free_mt_setting(void *setting)
278 {
279 XFREE(MTYPE_MT_CIRCUIT_SETTING, setting);
280 }
281
282 void
283 circuit_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
289 void
290 circuit_mt_init(struct isis_circuit *circuit)
291 {
292 circuit->mt_settings = list_new();
293 circuit->mt_settings->del = circuit_free_mt_setting;
294 }
295
296 void
297 circuit_mt_finish(struct isis_circuit *circuit)
298 {
299 list_delete(circuit->mt_settings);
300 circuit->mt_settings = NULL;
301 }
302
303 struct isis_circuit_mt_setting*
304 circuit_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
317 int
318 circuit_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 }
335
336 struct isis_circuit_mt_setting**
337 circuit_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 }
378
379 /* ADJ specific MT API */
380 static 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
392 bool
393 tlvs_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
401 uint16_t *old_mt_set = NULL;
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 */
417 if (mt_settings[i]->mtid == ISIS_MT_IPV4_UNICAST && v4_usable)
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)
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 }
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
469 bool
470 adj_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
478 void
479 adj_mt_finish(struct isis_adjacency *adj)
480 {
481 XFREE(MTYPE_MT_ADJ_INFO, adj->mt_set);
482 adj->mt_count = 0;
483 }
484
485 /* TLV Router info api */
486 struct mt_router_info*
487 tlvs_lookup_mt_router_info(struct tlvs *tlvs, uint16_t mtid)
488 {
489 return lookup_mt_setting(tlvs->mt_router_info, mtid);
490 }
491
492 /* TLV MT Neighbors api */
493 struct tlv_mt_neighbors*
494 tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
495 {
496 return lookup_mt_setting(tlvs->mt_is_neighs, mtid);
497 }
498
499 static struct tlv_mt_neighbors*
500 tlvs_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
511 static void
512 tlvs_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
521 static void
522 tlvs_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
528 struct tlv_mt_neighbors*
529 tlvs_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
542 /* TLV MT IPv4 reach api */
543 struct tlv_mt_ipv4_reachs*
544 tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid)
545 {
546 return lookup_mt_setting(tlvs->mt_ipv4_reachs, mtid);
547 }
548
549 static struct tlv_mt_ipv4_reachs*
550 tlvs_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
561 static void
562 tlvs_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
571 static void
572 tlvs_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
578 struct tlv_mt_ipv4_reachs*
579 tlvs_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 */
593 struct tlv_mt_ipv6_reachs*
594 tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid)
595 {
596 return lookup_mt_setting(tlvs->mt_ipv6_reachs, mtid);
597 }
598
599 static struct tlv_mt_ipv6_reachs*
600 tlvs_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
611 static void
612 tlvs_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
621 static void
622 tlvs_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
628 struct tlv_mt_ipv6_reachs*
629 tlvs_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
642 static void
643 mt_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
662 static uint16_t *
663 circuit_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
691 static void
692 tlvs_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
725 void
726 tlvs_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
736 void
737 tlvs_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 }