]>
git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_mt.c
2 * IS-IS Rout(e)ing protocol - Multi Topology Support
4 * Copyright (C) 2017 Christian Franke
6 * This file is part of FreeRangeRouting (FRR)
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
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.
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
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"
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")
42 uint16_t isis_area_ipv6_topology(struct isis_area
*area
)
44 struct isis_area_mt_setting
*area_mt_setting
;
45 area_mt_setting
= area_lookup_mt_setting(area
, ISIS_MT_IPV6_UNICAST
);
47 if (area_mt_setting
&& area_mt_setting
->enabled
)
48 return ISIS_MT_IPV6_UNICAST
;
49 return ISIS_MT_IPV4_UNICAST
;
53 const char *isis_mtid2str(uint16_t mtid
)
55 static char buf
[sizeof("65535")];
58 case ISIS_MT_IPV4_UNICAST
:
59 return "ipv4-unicast";
60 case ISIS_MT_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
:
71 snprintf(buf
, sizeof(buf
), "%" PRIu16
, mtid
);
76 uint16_t isis_str2mtid(const char *name
)
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
;
93 /* General MT settings api */
99 static void *lookup_mt_setting(struct list
*mt_list
, uint16_t mtid
)
101 struct listnode
*node
;
102 struct mt_setting
*setting
;
104 for (ALL_LIST_ELEMENTS_RO(mt_list
, node
, setting
)) {
105 if (setting
->mtid
== mtid
)
111 static void add_mt_setting(struct list
**mt_list
, void *setting
)
114 *mt_list
= list_new();
115 listnode_add(*mt_list
, setting
);
118 /* Area specific MT settings api */
120 struct isis_area_mt_setting
*area_lookup_mt_setting(struct isis_area
*area
,
123 return lookup_mt_setting(area
->mt_settings
, mtid
);
126 struct isis_area_mt_setting
*area_new_mt_setting(struct isis_area
*area
,
129 struct isis_area_mt_setting
*setting
;
131 setting
= XCALLOC(MTYPE_MT_AREA_SETTING
, sizeof(*setting
));
132 setting
->mtid
= mtid
;
136 static void area_free_mt_setting(void *setting
)
138 XFREE(MTYPE_MT_AREA_SETTING
, setting
);
141 void area_add_mt_setting(struct isis_area
*area
,
142 struct isis_area_mt_setting
*setting
)
144 add_mt_setting(&area
->mt_settings
, setting
);
147 void area_mt_init(struct isis_area
*area
)
149 struct isis_area_mt_setting
*v4_unicast_setting
;
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
;
158 void area_mt_finish(struct isis_area
*area
)
160 list_delete(area
->mt_settings
);
161 area
->mt_settings
= NULL
;
164 struct isis_area_mt_setting
*area_get_mt_setting(struct isis_area
*area
,
167 struct isis_area_mt_setting
*setting
;
169 setting
= area_lookup_mt_setting(area
, mtid
);
171 setting
= area_new_mt_setting(area
, mtid
);
172 area_add_mt_setting(area
, setting
);
177 int area_write_mt_settings(struct isis_area
*area
, struct vty
*vty
)
180 struct listnode
*node
;
181 struct isis_area_mt_setting
*setting
;
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
189 vty_out(vty
, " topology %s%s\n", name
,
190 setting
->overload
? " overload" : "");
197 bool area_is_mt(struct isis_area
*area
)
199 struct listnode
*node
, *node2
;
200 struct isis_area_mt_setting
*setting
;
201 struct isis_circuit
*circuit
;
202 struct isis_circuit_mt_setting
*csetting
;
204 for (ALL_LIST_ELEMENTS_RO(area
->mt_settings
, node
, setting
)) {
205 if (setting
->enabled
&& setting
->mtid
!= ISIS_MT_IPV4_UNICAST
)
208 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
209 for (ALL_LIST_ELEMENTS_RO(circuit
->mt_settings
, node2
,
211 if (!csetting
->enabled
212 && csetting
->mtid
== ISIS_MT_IPV4_UNICAST
)
220 struct isis_area_mt_setting
**area_mt_settings(struct isis_area
*area
,
221 unsigned int *mt_count
)
223 static unsigned int size
= 0;
224 static struct isis_area_mt_setting
**rv
= NULL
;
226 unsigned int count
= 0;
227 struct listnode
*node
;
228 struct isis_area_mt_setting
*setting
;
230 for (ALL_LIST_ELEMENTS_RO(area
->mt_settings
, node
, setting
)) {
231 if (!setting
->enabled
)
236 rv
= XREALLOC(MTYPE_TMP
, rv
, count
* sizeof(*rv
));
239 rv
[count
- 1] = setting
;
246 /* Circuit specific MT settings api */
248 struct isis_circuit_mt_setting
*
249 circuit_lookup_mt_setting(struct isis_circuit
*circuit
, uint16_t mtid
)
251 return lookup_mt_setting(circuit
->mt_settings
, mtid
);
254 struct isis_circuit_mt_setting
*
255 circuit_new_mt_setting(struct isis_circuit
*circuit
, uint16_t mtid
)
257 struct isis_circuit_mt_setting
*setting
;
259 setting
= XCALLOC(MTYPE_MT_CIRCUIT_SETTING
, sizeof(*setting
));
260 setting
->mtid
= mtid
;
261 setting
->enabled
= true; /* Enabled is default for circuit */
265 static void circuit_free_mt_setting(void *setting
)
267 XFREE(MTYPE_MT_CIRCUIT_SETTING
, setting
);
270 void circuit_add_mt_setting(struct isis_circuit
*circuit
,
271 struct isis_circuit_mt_setting
*setting
)
273 add_mt_setting(&circuit
->mt_settings
, setting
);
276 void circuit_mt_init(struct isis_circuit
*circuit
)
278 circuit
->mt_settings
= list_new();
279 circuit
->mt_settings
->del
= circuit_free_mt_setting
;
282 void circuit_mt_finish(struct isis_circuit
*circuit
)
284 list_delete(circuit
->mt_settings
);
285 circuit
->mt_settings
= NULL
;
288 struct isis_circuit_mt_setting
*
289 circuit_get_mt_setting(struct isis_circuit
*circuit
, uint16_t mtid
)
291 struct isis_circuit_mt_setting
*setting
;
293 setting
= circuit_lookup_mt_setting(circuit
, mtid
);
295 setting
= circuit_new_mt_setting(circuit
, mtid
);
296 circuit_add_mt_setting(circuit
, setting
);
301 int circuit_write_mt_settings(struct isis_circuit
*circuit
, struct vty
*vty
)
304 struct listnode
*node
;
305 struct isis_circuit_mt_setting
*setting
;
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
);
317 struct isis_circuit_mt_setting
**
318 circuit_mt_settings(struct isis_circuit
*circuit
, unsigned int *mt_count
)
320 static unsigned int size
= 0;
321 static struct isis_circuit_mt_setting
**rv
= NULL
;
323 struct isis_area_mt_setting
**area_settings
;
324 unsigned int area_count
;
326 unsigned int count
= 0;
328 struct listnode
*node
;
329 struct isis_circuit_mt_setting
*setting
;
331 area_settings
= area_mt_settings(circuit
->area
, &area_count
);
333 for (unsigned int i
= 0; i
< area_count
; i
++) {
334 for (ALL_LIST_ELEMENTS_RO(circuit
->mt_settings
, node
,
336 if (setting
->mtid
!= area_settings
[i
]->mtid
)
341 setting
= circuit_get_mt_setting(
342 circuit
, area_settings
[i
]->mtid
);
344 if (!setting
->enabled
)
349 rv
= XREALLOC(MTYPE_TMP
, rv
, count
* sizeof(*rv
));
352 rv
[count
- 1] = setting
;
359 /* ADJ specific MT API */
360 static void adj_mt_set(struct isis_adjacency
*adj
, unsigned int index
,
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;
368 adj
->mt_set
[index
] = mtid
;
371 bool tlvs_to_adj_mt_set(struct isis_tlvs
*tlvs
, bool v4_usable
, bool v6_usable
,
372 struct isis_adjacency
*adj
)
374 struct isis_circuit_mt_setting
**mt_settings
;
375 unsigned int circuit_mt_count
;
377 unsigned int intersect_count
= 0;
379 uint16_t *old_mt_set
= NULL
;
380 unsigned int old_mt_count
;
382 old_mt_count
= adj
->mt_count
;
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
));
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
396 adj_mt_set(adj
, intersect_count
++,
397 ISIS_MT_IPV4_UNICAST
);
399 struct isis_mt_router_info
*info_head
;
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
;
405 if (mt_settings
[i
]->mtid
== info
->mtid
) {
407 switch (info
->mtid
) {
408 case ISIS_MT_IPV4_UNICAST
:
409 case ISIS_MT_IPV4_MGMT
:
410 case ISIS_MT_IPV4_MULTICAST
:
413 case ISIS_MT_IPV6_UNICAST
:
414 case ISIS_MT_IPV6_MGMT
:
415 case ISIS_MT_IPV6_MULTICAST
:
430 adj
->mt_count
= intersect_count
;
432 bool changed
= false;
434 if (adj
->mt_count
!= old_mt_count
)
437 if (!changed
&& old_mt_count
438 && memcmp(adj
->mt_set
, old_mt_set
,
439 old_mt_count
* sizeof(*old_mt_set
)))
443 XFREE(MTYPE_TMP
, old_mt_set
);
448 bool adj_has_mt(struct isis_adjacency
*adj
, uint16_t mtid
)
450 for (unsigned int i
= 0; i
< adj
->mt_count
; i
++)
451 if (adj
->mt_set
[i
] == mtid
)
456 void adj_mt_finish(struct isis_adjacency
*adj
)
458 XFREE(MTYPE_MT_ADJ_INFO
, adj
->mt_set
);
462 /* TLV Router info api */
463 struct mt_router_info
*tlvs_lookup_mt_router_info(struct tlvs
*tlvs
,
466 return lookup_mt_setting(tlvs
->mt_router_info
, mtid
);
469 /* TLV MT Neighbors api */
470 struct tlv_mt_neighbors
*tlvs_lookup_mt_neighbors(struct tlvs
*tlvs
,
473 return lookup_mt_setting(tlvs
->mt_is_neighs
, mtid
);
476 static struct tlv_mt_neighbors
*tlvs_new_mt_neighbors(uint16_t mtid
)
478 struct tlv_mt_neighbors
*rv
;
480 rv
= XCALLOC(MTYPE_MT_NEIGHBORS
, sizeof(*rv
));
482 rv
->list
= list_new();
487 static void tlvs_free_mt_neighbors(void *arg
)
489 struct tlv_mt_neighbors
*neighbors
= arg
;
491 if (neighbors
&& neighbors
->list
)
492 list_delete(neighbors
->list
);
493 XFREE(MTYPE_MT_NEIGHBORS
, neighbors
);
496 static void tlvs_add_mt_neighbors(struct tlvs
*tlvs
,
497 struct tlv_mt_neighbors
*neighbors
)
499 add_mt_setting(&tlvs
->mt_is_neighs
, neighbors
);
500 tlvs
->mt_is_neighs
->del
= tlvs_free_mt_neighbors
;
503 struct tlv_mt_neighbors
*tlvs_get_mt_neighbors(struct tlvs
*tlvs
, uint16_t mtid
)
505 struct tlv_mt_neighbors
*neighbors
;
507 neighbors
= tlvs_lookup_mt_neighbors(tlvs
, mtid
);
509 neighbors
= tlvs_new_mt_neighbors(mtid
);
510 tlvs_add_mt_neighbors(tlvs
, neighbors
);
515 /* TLV MT IPv4 reach api */
516 struct tlv_mt_ipv4_reachs
*tlvs_lookup_mt_ipv4_reachs(struct tlvs
*tlvs
,
519 return lookup_mt_setting(tlvs
->mt_ipv4_reachs
, mtid
);
522 static struct tlv_mt_ipv4_reachs
*tlvs_new_mt_ipv4_reachs(uint16_t mtid
)
524 struct tlv_mt_ipv4_reachs
*rv
;
526 rv
= XCALLOC(MTYPE_MT_IPV4_REACHS
, sizeof(*rv
));
528 rv
->list
= list_new();
533 static void tlvs_free_mt_ipv4_reachs(void *arg
)
535 struct tlv_mt_ipv4_reachs
*reachs
= arg
;
537 if (reachs
&& reachs
->list
)
538 list_delete(reachs
->list
);
539 XFREE(MTYPE_MT_IPV4_REACHS
, reachs
);
542 static void tlvs_add_mt_ipv4_reachs(struct tlvs
*tlvs
,
543 struct tlv_mt_ipv4_reachs
*reachs
)
545 add_mt_setting(&tlvs
->mt_ipv4_reachs
, reachs
);
546 tlvs
->mt_ipv4_reachs
->del
= tlvs_free_mt_ipv4_reachs
;
549 struct tlv_mt_ipv4_reachs
*tlvs_get_mt_ipv4_reachs(struct tlvs
*tlvs
,
552 struct tlv_mt_ipv4_reachs
*reachs
;
554 reachs
= tlvs_lookup_mt_ipv4_reachs(tlvs
, mtid
);
556 reachs
= tlvs_new_mt_ipv4_reachs(mtid
);
557 tlvs_add_mt_ipv4_reachs(tlvs
, reachs
);
562 /* TLV MT IPv6 reach api */
563 struct tlv_mt_ipv6_reachs
*tlvs_lookup_mt_ipv6_reachs(struct tlvs
*tlvs
,
566 return lookup_mt_setting(tlvs
->mt_ipv6_reachs
, mtid
);
569 static struct tlv_mt_ipv6_reachs
*tlvs_new_mt_ipv6_reachs(uint16_t mtid
)
571 struct tlv_mt_ipv6_reachs
*rv
;
573 rv
= XCALLOC(MTYPE_MT_IPV6_REACHS
, sizeof(*rv
));
575 rv
->list
= list_new();
580 static void tlvs_free_mt_ipv6_reachs(void *arg
)
582 struct tlv_mt_ipv6_reachs
*reachs
= arg
;
584 if (reachs
&& reachs
->list
)
585 list_delete(reachs
->list
);
586 XFREE(MTYPE_MT_IPV6_REACHS
, reachs
);
589 static void tlvs_add_mt_ipv6_reachs(struct tlvs
*tlvs
,
590 struct tlv_mt_ipv6_reachs
*reachs
)
592 add_mt_setting(&tlvs
->mt_ipv6_reachs
, reachs
);
593 tlvs
->mt_ipv6_reachs
->del
= tlvs_free_mt_ipv6_reachs
;
596 struct tlv_mt_ipv6_reachs
*tlvs_get_mt_ipv6_reachs(struct tlvs
*tlvs
,
599 struct tlv_mt_ipv6_reachs
*reachs
;
601 reachs
= tlvs_lookup_mt_ipv6_reachs(tlvs
, mtid
);
603 reachs
= tlvs_new_mt_ipv6_reachs(mtid
);
604 tlvs_add_mt_ipv6_reachs(tlvs
, reachs
);
609 static void mt_set_add(uint16_t **mt_set
, unsigned int *size
,
610 unsigned int *index
, uint16_t mtid
)
612 for (unsigned int i
= 0; i
< *index
; i
++) {
613 if ((*mt_set
)[i
] == mtid
)
617 if (*index
>= *size
) {
618 *mt_set
= XREALLOC(MTYPE_TMP
, *mt_set
,
619 sizeof(**mt_set
) * ((*index
) + 1));
620 *size
= (*index
) + 1;
623 (*mt_set
)[*index
] = mtid
;
624 *index
= (*index
) + 1;
627 static uint16_t *circuit_bcast_mt_set(struct isis_circuit
*circuit
, int level
,
628 unsigned int *mt_count
)
631 static unsigned int size
;
632 struct listnode
*node
;
633 struct isis_adjacency
*adj
;
635 unsigned int count
= 0;
637 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
) {
642 for (ALL_LIST_ELEMENTS_RO(circuit
->u
.bc
.adjdb
[level
- 1], node
, adj
)) {
643 if (adj
->adj_state
!= ISIS_ADJ_UP
)
645 for (unsigned int i
= 0; i
< adj
->mt_count
; i
++)
646 mt_set_add(&rv
, &size
, &count
, adj
->mt_set
[i
]);
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
)
657 for (unsigned int i
= 0; i
< mt_count
; i
++) {
658 uint16_t mtid
= mt_set
[i
];
659 struct te_is_neigh
*ne_copy
;
661 ne_copy
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*ne_copy
));
662 memcpy(ne_copy
, neigh
, sizeof(*ne_copy
));
664 if (mt_set
[i
] == ISIS_MT_IPV4_UNICAST
) {
665 listnode_add(tlvs
->te_is_neighs
, ne_copy
);
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
));
671 struct tlv_mt_neighbors
*neighbors
;
673 neighbors
= tlvs_get_mt_neighbors(tlvs
, mtid
);
674 neighbors
->list
->del
= free_tlv
;
675 listnode_add(neighbors
->list
, ne_copy
);
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
));
685 void tlvs_add_mt_bcast(struct tlvs
*tlvs
, struct isis_circuit
*circuit
,
686 int level
, struct te_is_neigh
*neigh
)
688 unsigned int mt_count
;
689 uint16_t *mt_set
= circuit_bcast_mt_set(circuit
, level
, &mt_count
);
691 tlvs_add_mt_set(circuit
->area
, tlvs
, mt_count
, mt_set
, neigh
);
694 void tlvs_add_mt_p2p(struct tlvs
*tlvs
, struct isis_circuit
*circuit
,
695 struct te_is_neigh
*neigh
)
697 struct isis_adjacency
*adj
= circuit
->u
.p2p
.neighbor
;
699 tlvs_add_mt_set(circuit
->area
, tlvs
, adj
->mt_count
, adj
->mt_set
, neigh
);