]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_mt.c
Merge pull request #767 from donaldsharp/if_update
[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_outln (vty, " topology %s%s", name,
197 setting->overload ? " overload" : "");
198 written++;
199 }
200 }
201 return written;
202 }
203
204 bool area_is_mt(struct isis_area *area)
205 {
206 struct listnode *node, *node2;
207 struct isis_area_mt_setting *setting;
208 struct isis_circuit *circuit;
209 struct isis_circuit_mt_setting *csetting;
210
211 for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
212 {
213 if (setting->enabled && setting->mtid != ISIS_MT_IPV4_UNICAST)
214 return true;
215 }
216 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
217 {
218 for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node2, csetting))
219 {
220 if (!csetting->enabled && csetting->mtid == ISIS_MT_IPV4_UNICAST)
221 return true;
222 }
223 }
224
225 return false;
226 }
227
228 struct isis_area_mt_setting**
229 area_mt_settings(struct isis_area *area, unsigned int *mt_count)
230 {
231 static unsigned int size = 0;
232 static struct isis_area_mt_setting **rv = NULL;
233
234 unsigned int count = 0;
235 struct listnode *node;
236 struct isis_area_mt_setting *setting;
237
238 for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
239 {
240 if (!setting->enabled)
241 continue;
242
243 count++;
244 if (count > size)
245 {
246 rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
247 size = count;
248 }
249 rv[count-1] = setting;
250 }
251
252 *mt_count = count;
253 return rv;
254 }
255
256 /* Circuit specific MT settings api */
257
258 struct isis_circuit_mt_setting*
259 circuit_lookup_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
260 {
261 return lookup_mt_setting(circuit->mt_settings, mtid);
262 }
263
264 struct isis_circuit_mt_setting*
265 circuit_new_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
266 {
267 struct isis_circuit_mt_setting *setting;
268
269 setting = XCALLOC(MTYPE_MT_CIRCUIT_SETTING, sizeof(*setting));
270 setting->mtid = mtid;
271 setting->enabled = true; /* Enabled is default for circuit */
272 return setting;
273 }
274
275 static void
276 circuit_free_mt_setting(void *setting)
277 {
278 XFREE(MTYPE_MT_CIRCUIT_SETTING, setting);
279 }
280
281 void
282 circuit_add_mt_setting(struct isis_circuit *circuit,
283 struct isis_circuit_mt_setting *setting)
284 {
285 add_mt_setting(&circuit->mt_settings, setting);
286 }
287
288 void
289 circuit_mt_init(struct isis_circuit *circuit)
290 {
291 circuit->mt_settings = list_new();
292 circuit->mt_settings->del = circuit_free_mt_setting;
293 }
294
295 void
296 circuit_mt_finish(struct isis_circuit *circuit)
297 {
298 list_delete(circuit->mt_settings);
299 circuit->mt_settings = NULL;
300 }
301
302 struct isis_circuit_mt_setting*
303 circuit_get_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
304 {
305 struct isis_circuit_mt_setting *setting;
306
307 setting = circuit_lookup_mt_setting(circuit, mtid);
308 if (!setting)
309 {
310 setting = circuit_new_mt_setting(circuit, mtid);
311 circuit_add_mt_setting(circuit, setting);
312 }
313 return setting;
314 }
315
316 int
317 circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty)
318 {
319 int written = 0;
320 struct listnode *node;
321 struct isis_circuit_mt_setting *setting;
322
323 for (ALL_LIST_ELEMENTS_RO (circuit->mt_settings, node, setting))
324 {
325 const char *name = isis_mtid2str(setting->mtid);
326 if (name && !setting->enabled)
327 {
328 vty_outln (vty, " no isis topology %s", name);
329 written++;
330 }
331 }
332 return written;
333 }
334
335 struct isis_circuit_mt_setting**
336 circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count)
337 {
338 static unsigned int size = 0;
339 static struct isis_circuit_mt_setting **rv = NULL;
340
341 struct isis_area_mt_setting **area_settings;
342 unsigned int area_count;
343
344 unsigned int count = 0;
345
346 struct listnode *node;
347 struct isis_circuit_mt_setting *setting;
348
349 area_settings = area_mt_settings(circuit->area, &area_count);
350
351 for (unsigned int i = 0; i < area_count; i++)
352 {
353 for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node, setting))
354 {
355 if (setting->mtid != area_settings[i]->mtid)
356 continue;
357 break;
358 }
359 if (!setting)
360 setting = circuit_get_mt_setting(circuit, area_settings[i]->mtid);
361
362 if (!setting->enabled)
363 continue;
364
365 count++;
366 if (count > size)
367 {
368 rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
369 size = count;
370 }
371 rv[count-1] = setting;
372 }
373
374 *mt_count = count;
375 return rv;
376 }
377
378 /* ADJ specific MT API */
379 static void adj_mt_set(struct isis_adjacency *adj, unsigned int index,
380 uint16_t mtid)
381 {
382 if (adj->mt_count < index + 1)
383 {
384 adj->mt_set = XREALLOC(MTYPE_MT_ADJ_INFO, adj->mt_set,
385 (index + 1) * sizeof(*adj->mt_set));
386 adj->mt_count = index + 1;
387 }
388 adj->mt_set[index] = mtid;
389 }
390
391 bool
392 tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable,
393 struct isis_adjacency *adj)
394 {
395 struct isis_circuit_mt_setting **mt_settings;
396 unsigned int circuit_mt_count;
397
398 unsigned int intersect_count = 0;
399
400 uint16_t *old_mt_set = NULL;
401 unsigned int old_mt_count;
402
403 old_mt_count = adj->mt_count;
404 if (old_mt_count)
405 {
406 old_mt_set = XCALLOC(MTYPE_TMP, old_mt_count * sizeof(*old_mt_set));
407 memcpy(old_mt_set, adj->mt_set, old_mt_count * sizeof(*old_mt_set));
408 }
409
410 mt_settings = circuit_mt_settings(adj->circuit, &circuit_mt_count);
411 for (unsigned int i = 0; i < circuit_mt_count; i++)
412 {
413 if (!tlvs->mt_router_info)
414 {
415 /* Other end does not have MT enabled */
416 if (mt_settings[i]->mtid == ISIS_MT_IPV4_UNICAST && v4_usable)
417 adj_mt_set(adj, intersect_count++, ISIS_MT_IPV4_UNICAST);
418 }
419 else
420 {
421 struct listnode *node;
422 struct mt_router_info *info;
423 for (ALL_LIST_ELEMENTS_RO(tlvs->mt_router_info, node, info))
424 {
425 if (mt_settings[i]->mtid == info->mtid)
426 {
427 bool usable;
428 switch (info->mtid)
429 {
430 case ISIS_MT_IPV4_UNICAST:
431 case ISIS_MT_IPV4_MGMT:
432 case ISIS_MT_IPV4_MULTICAST:
433 usable = v4_usable;
434 break;
435 case ISIS_MT_IPV6_UNICAST:
436 case ISIS_MT_IPV6_MGMT:
437 case ISIS_MT_IPV6_MULTICAST:
438 usable = v6_usable;
439 break;
440 default:
441 usable = true;
442 break;
443 }
444 if (usable)
445 adj_mt_set(adj, intersect_count++, info->mtid);
446 }
447 }
448 }
449 }
450 adj->mt_count = intersect_count;
451
452 bool changed = false;
453
454 if (adj->mt_count != old_mt_count)
455 changed = true;
456
457 if (!changed && old_mt_count
458 && memcmp(adj->mt_set, old_mt_set,
459 old_mt_count * sizeof(*old_mt_set)))
460 changed = true;
461
462 if (old_mt_count)
463 XFREE(MTYPE_TMP, old_mt_set);
464
465 return changed;
466 }
467
468 bool
469 adj_has_mt(struct isis_adjacency *adj, uint16_t mtid)
470 {
471 for (unsigned int i = 0; i < adj->mt_count; i++)
472 if (adj->mt_set[i] == mtid)
473 return true;
474 return false;
475 }
476
477 void
478 adj_mt_finish(struct isis_adjacency *adj)
479 {
480 XFREE(MTYPE_MT_ADJ_INFO, adj->mt_set);
481 adj->mt_count = 0;
482 }
483
484 /* TLV Router info api */
485 struct mt_router_info*
486 tlvs_lookup_mt_router_info(struct tlvs *tlvs, uint16_t mtid)
487 {
488 return lookup_mt_setting(tlvs->mt_router_info, mtid);
489 }
490
491 /* TLV MT Neighbors api */
492 struct tlv_mt_neighbors*
493 tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
494 {
495 return lookup_mt_setting(tlvs->mt_is_neighs, mtid);
496 }
497
498 static struct tlv_mt_neighbors*
499 tlvs_new_mt_neighbors(uint16_t mtid)
500 {
501 struct tlv_mt_neighbors *rv;
502
503 rv = XCALLOC(MTYPE_MT_NEIGHBORS, sizeof(*rv));
504 rv->mtid = mtid;
505 rv->list = list_new();
506
507 return rv;
508 };
509
510 static void
511 tlvs_free_mt_neighbors(void *arg)
512 {
513 struct tlv_mt_neighbors *neighbors = arg;
514
515 if (neighbors && neighbors->list)
516 list_delete(neighbors->list);
517 XFREE(MTYPE_MT_NEIGHBORS, neighbors);
518 }
519
520 static void
521 tlvs_add_mt_neighbors(struct tlvs *tlvs, struct tlv_mt_neighbors *neighbors)
522 {
523 add_mt_setting(&tlvs->mt_is_neighs, neighbors);
524 tlvs->mt_is_neighs->del = tlvs_free_mt_neighbors;
525 }
526
527 struct tlv_mt_neighbors*
528 tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
529 {
530 struct tlv_mt_neighbors *neighbors;
531
532 neighbors = tlvs_lookup_mt_neighbors(tlvs, mtid);
533 if (!neighbors)
534 {
535 neighbors = tlvs_new_mt_neighbors(mtid);
536 tlvs_add_mt_neighbors(tlvs, neighbors);
537 }
538 return neighbors;
539 }
540
541 /* TLV MT IPv4 reach api */
542 struct tlv_mt_ipv4_reachs*
543 tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid)
544 {
545 return lookup_mt_setting(tlvs->mt_ipv4_reachs, mtid);
546 }
547
548 static struct tlv_mt_ipv4_reachs*
549 tlvs_new_mt_ipv4_reachs(uint16_t mtid)
550 {
551 struct tlv_mt_ipv4_reachs *rv;
552
553 rv = XCALLOC(MTYPE_MT_IPV4_REACHS, sizeof(*rv));
554 rv->mtid = mtid;
555 rv->list = list_new();
556
557 return rv;
558 };
559
560 static void
561 tlvs_free_mt_ipv4_reachs(void *arg)
562 {
563 struct tlv_mt_ipv4_reachs *reachs = arg;
564
565 if (reachs && reachs->list)
566 list_delete(reachs->list);
567 XFREE(MTYPE_MT_IPV4_REACHS, reachs);
568 }
569
570 static void
571 tlvs_add_mt_ipv4_reachs(struct tlvs *tlvs, struct tlv_mt_ipv4_reachs *reachs)
572 {
573 add_mt_setting(&tlvs->mt_ipv4_reachs, reachs);
574 tlvs->mt_ipv4_reachs->del = tlvs_free_mt_ipv4_reachs;
575 }
576
577 struct tlv_mt_ipv4_reachs*
578 tlvs_get_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid)
579 {
580 struct tlv_mt_ipv4_reachs *reachs;
581
582 reachs = tlvs_lookup_mt_ipv4_reachs(tlvs, mtid);
583 if (!reachs)
584 {
585 reachs = tlvs_new_mt_ipv4_reachs(mtid);
586 tlvs_add_mt_ipv4_reachs(tlvs, reachs);
587 }
588 return reachs;
589 }
590
591 /* TLV MT IPv6 reach api */
592 struct tlv_mt_ipv6_reachs*
593 tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid)
594 {
595 return lookup_mt_setting(tlvs->mt_ipv6_reachs, mtid);
596 }
597
598 static struct tlv_mt_ipv6_reachs*
599 tlvs_new_mt_ipv6_reachs(uint16_t mtid)
600 {
601 struct tlv_mt_ipv6_reachs *rv;
602
603 rv = XCALLOC(MTYPE_MT_IPV6_REACHS, sizeof(*rv));
604 rv->mtid = mtid;
605 rv->list = list_new();
606
607 return rv;
608 };
609
610 static void
611 tlvs_free_mt_ipv6_reachs(void *arg)
612 {
613 struct tlv_mt_ipv6_reachs *reachs = arg;
614
615 if (reachs && reachs->list)
616 list_delete(reachs->list);
617 XFREE(MTYPE_MT_IPV6_REACHS, reachs);
618 }
619
620 static void
621 tlvs_add_mt_ipv6_reachs(struct tlvs *tlvs, struct tlv_mt_ipv6_reachs *reachs)
622 {
623 add_mt_setting(&tlvs->mt_ipv6_reachs, reachs);
624 tlvs->mt_ipv6_reachs->del = tlvs_free_mt_ipv6_reachs;
625 }
626
627 struct tlv_mt_ipv6_reachs*
628 tlvs_get_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid)
629 {
630 struct tlv_mt_ipv6_reachs *reachs;
631
632 reachs = tlvs_lookup_mt_ipv6_reachs(tlvs, mtid);
633 if (!reachs)
634 {
635 reachs = tlvs_new_mt_ipv6_reachs(mtid);
636 tlvs_add_mt_ipv6_reachs(tlvs, reachs);
637 }
638 return reachs;
639 }
640
641 static void
642 mt_set_add(uint16_t **mt_set, unsigned int *size,
643 unsigned int *index, uint16_t mtid)
644 {
645 for (unsigned int i = 0; i < *index; i++)
646 {
647 if ((*mt_set)[i] == mtid)
648 return;
649 }
650
651 if (*index >= *size)
652 {
653 *mt_set = XREALLOC(MTYPE_TMP, *mt_set, sizeof(**mt_set) * ((*index) + 1));
654 *size = (*index) + 1;
655 }
656
657 (*mt_set)[*index] = mtid;
658 *index = (*index) + 1;
659 }
660
661 static uint16_t *
662 circuit_bcast_mt_set(struct isis_circuit *circuit, int level,
663 unsigned int *mt_count)
664 {
665 static uint16_t *rv;
666 static unsigned int size;
667 struct listnode *node;
668 struct isis_adjacency *adj;
669
670 unsigned int count = 0;
671
672 if (circuit->circ_type != CIRCUIT_T_BROADCAST)
673 {
674 *mt_count = 0;
675 return NULL;
676 }
677
678 for (ALL_LIST_ELEMENTS_RO(circuit->u.bc.adjdb[level - 1], node, adj))
679 {
680 if (adj->adj_state != ISIS_ADJ_UP)
681 continue;
682 for (unsigned int i = 0; i < adj->mt_count; i++)
683 mt_set_add(&rv, &size, &count, adj->mt_set[i]);
684 }
685
686 *mt_count = count;
687 return rv;
688 }
689
690 static void
691 tlvs_add_mt_set(struct isis_area *area,
692 struct tlvs *tlvs, unsigned int mt_count,
693 uint16_t *mt_set, struct te_is_neigh *neigh)
694 {
695 for (unsigned int i = 0; i < mt_count; i++)
696 {
697 uint16_t mtid = mt_set[i];
698 struct te_is_neigh *ne_copy;
699
700 ne_copy = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ne_copy));
701 memcpy(ne_copy, neigh, sizeof(*ne_copy));
702
703 if (mt_set[i] == ISIS_MT_IPV4_UNICAST)
704 {
705 listnode_add(tlvs->te_is_neighs, ne_copy);
706 lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor",
707 area->area_tag, sysid_print(ne_copy->neigh_id),
708 LSP_PSEUDO_ID(ne_copy->neigh_id));
709 }
710 else
711 {
712 struct tlv_mt_neighbors *neighbors;
713
714 neighbors = tlvs_get_mt_neighbors(tlvs, mtid);
715 neighbors->list->del = free_tlv;
716 listnode_add(neighbors->list, ne_copy);
717 lsp_debug("ISIS (%s): Adding %s.%02x as mt-style neighbor for %s",
718 area->area_tag, sysid_print(ne_copy->neigh_id),
719 LSP_PSEUDO_ID(ne_copy->neigh_id), isis_mtid2str(mtid));
720 }
721 }
722 }
723
724 void
725 tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit,
726 int level, struct te_is_neigh *neigh)
727 {
728 unsigned int mt_count;
729 uint16_t *mt_set = circuit_bcast_mt_set(circuit, level,
730 &mt_count);
731
732 tlvs_add_mt_set(circuit->area, tlvs, mt_count, mt_set, neigh);
733 }
734
735 void
736 tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit,
737 struct te_is_neigh *neigh)
738 {
739 struct isis_adjacency *adj = circuit->u.p2p.neighbor;
740
741 tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, neigh);
742 }