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