]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_mt.c
isisd: make spf MT aware
[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
402 uint16_t *old_mt_set;
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)
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 adj_mt_set(adj, intersect_count++, info->mtid);
429 }
430 }
431 }
432 adj->mt_count = intersect_count;
433
434 bool changed = false;
435
436 if (adj->mt_count != old_mt_count)
437 changed = true;
438
439 if (!changed && old_mt_count
440 && memcmp(adj->mt_set, old_mt_set,
441 old_mt_count * sizeof(*old_mt_set)))
442 changed = true;
443
444 if (old_mt_count)
445 XFREE(MTYPE_TMP, old_mt_set);
446
447 return changed;
448}
449
2b67862c
CF
450bool
451adj_has_mt(struct isis_adjacency *adj, uint16_t mtid)
452{
453 for (unsigned int i = 0; i < adj->mt_count; i++)
454 if (adj->mt_set[i] == mtid)
455 return true;
456 return false;
457}
458
d8fba7d9
CF
459void
460adj_mt_finish(struct isis_adjacency *adj)
461{
462 XFREE(MTYPE_MT_ADJ_INFO, adj->mt_set);
463 adj->mt_count = 0;
464}
206f4aae 465
2b67862c
CF
466/* TLV Router info api */
467struct mt_router_info*
468tlvs_lookup_mt_router_info(struct tlvs *tlvs, uint16_t mtid)
469{
470 return lookup_mt_setting(tlvs->mt_router_info, mtid);
471}
472
206f4aae
CF
473/* TLV MT Neighbors api */
474struct tlv_mt_neighbors*
475tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
476{
477 return lookup_mt_setting(tlvs->mt_is_neighs, mtid);
478}
479
480static struct tlv_mt_neighbors*
481tlvs_new_mt_neighbors(uint16_t mtid)
482{
483 struct tlv_mt_neighbors *rv;
484
485 rv = XCALLOC(MTYPE_MT_NEIGHBORS, sizeof(*rv));
486 rv->mtid = mtid;
487 rv->list = list_new();
488
489 return rv;
490};
491
492static void
493tlvs_free_mt_neighbors(void *arg)
494{
495 struct tlv_mt_neighbors *neighbors = arg;
496
497 if (neighbors && neighbors->list)
498 list_delete(neighbors->list);
499 XFREE(MTYPE_MT_NEIGHBORS, neighbors);
500}
501
502static void
503tlvs_add_mt_neighbors(struct tlvs *tlvs, struct tlv_mt_neighbors *neighbors)
504{
505 add_mt_setting(&tlvs->mt_is_neighs, neighbors);
506 tlvs->mt_is_neighs->del = tlvs_free_mt_neighbors;
507}
508
509struct tlv_mt_neighbors*
510tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
511{
512 struct tlv_mt_neighbors *neighbors;
513
514 neighbors = tlvs_lookup_mt_neighbors(tlvs, mtid);
515 if (!neighbors)
516 {
517 neighbors = tlvs_new_mt_neighbors(mtid);
518 tlvs_add_mt_neighbors(tlvs, neighbors);
519 }
520 return neighbors;
521}
522
c3ae3127
CF
523/* TLV MT IPv4 reach api */
524struct tlv_mt_ipv4_reachs*
525tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid)
526{
527 return lookup_mt_setting(tlvs->mt_ipv4_reachs, mtid);
528}
529
530static struct tlv_mt_ipv4_reachs*
531tlvs_new_mt_ipv4_reachs(uint16_t mtid)
532{
533 struct tlv_mt_ipv4_reachs *rv;
534
535 rv = XCALLOC(MTYPE_MT_IPV4_REACHS, sizeof(*rv));
536 rv->mtid = mtid;
537 rv->list = list_new();
538
539 return rv;
540};
541
542static void
543tlvs_free_mt_ipv4_reachs(void *arg)
544{
545 struct tlv_mt_ipv4_reachs *reachs = arg;
546
547 if (reachs && reachs->list)
548 list_delete(reachs->list);
549 XFREE(MTYPE_MT_IPV4_REACHS, reachs);
550}
551
552static void
553tlvs_add_mt_ipv4_reachs(struct tlvs *tlvs, struct tlv_mt_ipv4_reachs *reachs)
554{
555 add_mt_setting(&tlvs->mt_ipv4_reachs, reachs);
556 tlvs->mt_ipv4_reachs->del = tlvs_free_mt_ipv4_reachs;
557}
558
559struct tlv_mt_ipv4_reachs*
560tlvs_get_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid)
561{
562 struct tlv_mt_ipv4_reachs *reachs;
563
564 reachs = tlvs_lookup_mt_ipv4_reachs(tlvs, mtid);
565 if (!reachs)
566 {
567 reachs = tlvs_new_mt_ipv4_reachs(mtid);
568 tlvs_add_mt_ipv4_reachs(tlvs, reachs);
569 }
570 return reachs;
571}
572
573/* TLV MT IPv6 reach api */
574struct tlv_mt_ipv6_reachs*
575tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid)
576{
577 return lookup_mt_setting(tlvs->mt_ipv6_reachs, mtid);
578}
579
580static struct tlv_mt_ipv6_reachs*
581tlvs_new_mt_ipv6_reachs(uint16_t mtid)
582{
583 struct tlv_mt_ipv6_reachs *rv;
584
585 rv = XCALLOC(MTYPE_MT_IPV6_REACHS, sizeof(*rv));
586 rv->mtid = mtid;
587 rv->list = list_new();
588
589 return rv;
590};
591
592static void
593tlvs_free_mt_ipv6_reachs(void *arg)
594{
595 struct tlv_mt_ipv6_reachs *reachs = arg;
596
597 if (reachs && reachs->list)
598 list_delete(reachs->list);
599 XFREE(MTYPE_MT_IPV6_REACHS, reachs);
600}
601
602static void
603tlvs_add_mt_ipv6_reachs(struct tlvs *tlvs, struct tlv_mt_ipv6_reachs *reachs)
604{
605 add_mt_setting(&tlvs->mt_ipv6_reachs, reachs);
606 tlvs->mt_ipv6_reachs->del = tlvs_free_mt_ipv6_reachs;
607}
608
609struct tlv_mt_ipv6_reachs*
610tlvs_get_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid)
611{
612 struct tlv_mt_ipv6_reachs *reachs;
613
614 reachs = tlvs_lookup_mt_ipv6_reachs(tlvs, mtid);
615 if (!reachs)
616 {
617 reachs = tlvs_new_mt_ipv6_reachs(mtid);
618 tlvs_add_mt_ipv6_reachs(tlvs, reachs);
619 }
620 return reachs;
621}
622
206f4aae
CF
623static void
624mt_set_add(uint16_t **mt_set, unsigned int *size,
625 unsigned int *index, uint16_t mtid)
626{
627 for (unsigned int i = 0; i < *index; i++)
628 {
629 if ((*mt_set)[i] == mtid)
630 return;
631 }
632
633 if (*index >= *size)
634 {
635 *mt_set = XREALLOC(MTYPE_TMP, *mt_set, sizeof(**mt_set) * ((*index) + 1));
636 *size = (*index) + 1;
637 }
638
639 (*mt_set)[*index] = mtid;
640 *index = (*index) + 1;
641}
642
643static uint16_t *
644circuit_bcast_mt_set(struct isis_circuit *circuit, int level,
645 unsigned int *mt_count)
646{
647 static uint16_t *rv;
648 static unsigned int size;
649 struct listnode *node;
650 struct isis_adjacency *adj;
651
652 unsigned int count = 0;
653
654 if (circuit->circ_type != CIRCUIT_T_BROADCAST)
655 {
656 *mt_count = 0;
657 return NULL;
658 }
659
660 for (ALL_LIST_ELEMENTS_RO(circuit->u.bc.adjdb[level - 1], node, adj))
661 {
662 if (adj->adj_state != ISIS_ADJ_UP)
663 continue;
664 for (unsigned int i = 0; i < adj->mt_count; i++)
665 mt_set_add(&rv, &size, &count, adj->mt_set[i]);
666 }
667
668 *mt_count = count;
669 return rv;
670}
671
672static void
673tlvs_add_mt_set(struct isis_area *area,
674 struct tlvs *tlvs, unsigned int mt_count,
675 uint16_t *mt_set, struct te_is_neigh *neigh)
676{
677 for (unsigned int i = 0; i < mt_count; i++)
678 {
679 uint16_t mtid = mt_set[i];
680 struct te_is_neigh *ne_copy;
681
682 ne_copy = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ne_copy));
683 memcpy(ne_copy, neigh, sizeof(*ne_copy));
684
685 if (mt_set[i] == ISIS_MT_IPV4_UNICAST)
686 {
687 listnode_add(tlvs->te_is_neighs, ne_copy);
688 lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor",
689 area->area_tag, sysid_print(ne_copy->neigh_id),
690 LSP_PSEUDO_ID(ne_copy->neigh_id));
691 }
692 else
693 {
694 struct tlv_mt_neighbors *neighbors;
695
696 neighbors = tlvs_get_mt_neighbors(tlvs, mtid);
697 neighbors->list->del = free_tlv;
698 listnode_add(neighbors->list, ne_copy);
699 lsp_debug("ISIS (%s): Adding %s.%02x as mt-style neighbor for %s",
700 area->area_tag, sysid_print(ne_copy->neigh_id),
701 LSP_PSEUDO_ID(ne_copy->neigh_id), isis_mtid2str(mtid));
702 }
703 }
704}
705
706void
707tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit,
708 int level, struct te_is_neigh *neigh)
709{
710 unsigned int mt_count;
711 uint16_t *mt_set = circuit_bcast_mt_set(circuit, level,
712 &mt_count);
713
714 tlvs_add_mt_set(circuit->area, tlvs, mt_count, mt_set, neigh);
715}
716
717void
718tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit,
719 struct te_is_neigh *neigh)
720{
721 struct isis_adjacency *adj = circuit->u.p2p.neighbor;
722
723 tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, neigh);
724}