]>
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_misc.h"
28 #include "isisd/isis_lsp.h"
29 #include "isisd/isis_mt.h"
30 #include "isisd/isis_tlvs.h"
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")
36 bool isis_area_ipv6_dstsrc_enabled(struct isis_area
*area
)
38 struct isis_area_mt_setting
*area_mt_setting
;
39 area_mt_setting
= area_lookup_mt_setting(area
, ISIS_MT_IPV6_DSTSRC
);
41 return (area_mt_setting
&& area_mt_setting
->enabled
);
44 uint16_t isis_area_ipv6_topology(struct isis_area
*area
)
46 struct isis_area_mt_setting
*area_mt_setting
;
47 area_mt_setting
= area_lookup_mt_setting(area
, ISIS_MT_IPV6_UNICAST
);
49 if (area_mt_setting
&& area_mt_setting
->enabled
)
50 return ISIS_MT_IPV6_UNICAST
;
51 return ISIS_MT_IPV4_UNICAST
;
55 const char *isis_mtid2str(uint16_t mtid
)
57 static char buf
[sizeof("65535")];
60 case ISIS_MT_IPV4_UNICAST
:
61 return "ipv4-unicast";
62 case ISIS_MT_IPV4_MGMT
:
64 case ISIS_MT_IPV6_UNICAST
:
65 return "ipv6-unicast";
66 case ISIS_MT_IPV4_MULTICAST
:
67 return "ipv4-multicast";
68 case ISIS_MT_IPV6_MULTICAST
:
69 return "ipv6-multicast";
70 case ISIS_MT_IPV6_MGMT
:
72 case ISIS_MT_IPV6_DSTSRC
:
75 snprintf(buf
, sizeof(buf
), "%" PRIu16
, mtid
);
80 uint16_t isis_str2mtid(const char *name
)
82 if (!strcmp(name
, "ipv4-unicast"))
83 return ISIS_MT_IPV4_UNICAST
;
84 if (!strcmp(name
, "ipv4-mgmt"))
85 return ISIS_MT_IPV4_MGMT
;
86 if (!strcmp(name
, "ipv6-unicast"))
87 return ISIS_MT_IPV6_UNICAST
;
88 if (!strcmp(name
, "ipv4-multicast"))
89 return ISIS_MT_IPV4_MULTICAST
;
90 if (!strcmp(name
, "ipv6-multicast"))
91 return ISIS_MT_IPV6_MULTICAST
;
92 if (!strcmp(name
, "ipv6-mgmt"))
93 return ISIS_MT_IPV6_MGMT
;
94 if (!strcmp(name
, "ipv6-dstsrc"))
95 return ISIS_MT_IPV6_DSTSRC
;
99 /* General MT settings api */
105 static void *lookup_mt_setting(struct list
*mt_list
, uint16_t mtid
)
107 struct listnode
*node
;
108 struct mt_setting
*setting
;
110 for (ALL_LIST_ELEMENTS_RO(mt_list
, node
, setting
)) {
111 if (setting
->mtid
== mtid
)
117 static void add_mt_setting(struct list
**mt_list
, void *setting
)
120 *mt_list
= list_new();
121 listnode_add(*mt_list
, setting
);
124 /* Area specific MT settings api */
126 struct isis_area_mt_setting
*area_lookup_mt_setting(struct isis_area
*area
,
129 return lookup_mt_setting(area
->mt_settings
, mtid
);
132 struct isis_area_mt_setting
*area_new_mt_setting(struct isis_area
*area
,
135 struct isis_area_mt_setting
*setting
;
137 setting
= XCALLOC(MTYPE_MT_AREA_SETTING
, sizeof(*setting
));
138 setting
->mtid
= mtid
;
142 static void area_free_mt_setting(void *setting
)
144 XFREE(MTYPE_MT_AREA_SETTING
, setting
);
147 void area_add_mt_setting(struct isis_area
*area
,
148 struct isis_area_mt_setting
*setting
)
150 add_mt_setting(&area
->mt_settings
, setting
);
153 void area_mt_init(struct isis_area
*area
)
155 struct isis_area_mt_setting
*v4_unicast_setting
;
157 /* MTID 0 is always enabled */
158 v4_unicast_setting
= area_new_mt_setting(area
, ISIS_MT_IPV4_UNICAST
);
159 v4_unicast_setting
->enabled
= true;
160 add_mt_setting(&area
->mt_settings
, v4_unicast_setting
);
161 area
->mt_settings
->del
= area_free_mt_setting
;
164 void area_mt_finish(struct isis_area
*area
)
166 list_delete(&area
->mt_settings
);
169 struct isis_area_mt_setting
*area_get_mt_setting(struct isis_area
*area
,
172 struct isis_area_mt_setting
*setting
;
174 setting
= area_lookup_mt_setting(area
, mtid
);
176 setting
= area_new_mt_setting(area
, mtid
);
177 area_add_mt_setting(area
, setting
);
182 int area_write_mt_settings(struct isis_area
*area
, struct vty
*vty
)
185 struct listnode
*node
;
186 struct isis_area_mt_setting
*setting
;
188 for (ALL_LIST_ELEMENTS_RO(area
->mt_settings
, node
, setting
)) {
189 const char *name
= isis_mtid2str(setting
->mtid
);
190 if (name
&& setting
->enabled
) {
191 if (setting
->mtid
== ISIS_MT_IPV4_UNICAST
)
192 continue; /* always enabled, no need to write
194 vty_out(vty
, " topology %s%s\n", name
,
195 setting
->overload
? " overload" : "");
202 bool area_is_mt(struct isis_area
*area
)
204 struct listnode
*node
, *node2
;
205 struct isis_area_mt_setting
*setting
;
206 struct isis_circuit
*circuit
;
207 struct isis_circuit_mt_setting
*csetting
;
209 for (ALL_LIST_ELEMENTS_RO(area
->mt_settings
, node
, setting
)) {
210 if (setting
->enabled
&& setting
->mtid
!= ISIS_MT_IPV4_UNICAST
)
213 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
214 for (ALL_LIST_ELEMENTS_RO(circuit
->mt_settings
, node2
,
216 if (!csetting
->enabled
217 && csetting
->mtid
== ISIS_MT_IPV4_UNICAST
)
225 struct isis_area_mt_setting
**area_mt_settings(struct isis_area
*area
,
226 unsigned int *mt_count
)
228 static unsigned int size
= 0;
229 static struct isis_area_mt_setting
**rv
= NULL
;
231 unsigned int count
= 0;
232 struct listnode
*node
;
233 struct isis_area_mt_setting
*setting
;
235 for (ALL_LIST_ELEMENTS_RO(area
->mt_settings
, node
, setting
)) {
236 if (!setting
->enabled
)
241 rv
= XREALLOC(MTYPE_TMP
, rv
, count
* sizeof(*rv
));
244 rv
[count
- 1] = setting
;
251 /* Circuit specific MT settings api */
253 struct isis_circuit_mt_setting
*
254 circuit_lookup_mt_setting(struct isis_circuit
*circuit
, uint16_t mtid
)
256 return lookup_mt_setting(circuit
->mt_settings
, mtid
);
259 struct isis_circuit_mt_setting
*
260 circuit_new_mt_setting(struct isis_circuit
*circuit
, uint16_t mtid
)
262 struct isis_circuit_mt_setting
*setting
;
264 setting
= XCALLOC(MTYPE_MT_CIRCUIT_SETTING
, sizeof(*setting
));
265 setting
->mtid
= mtid
;
266 setting
->enabled
= true; /* Enabled is default for circuit */
270 static void circuit_free_mt_setting(void *setting
)
272 XFREE(MTYPE_MT_CIRCUIT_SETTING
, setting
);
275 void circuit_add_mt_setting(struct isis_circuit
*circuit
,
276 struct isis_circuit_mt_setting
*setting
)
278 add_mt_setting(&circuit
->mt_settings
, setting
);
281 void circuit_mt_init(struct isis_circuit
*circuit
)
283 circuit
->mt_settings
= list_new();
284 circuit
->mt_settings
->del
= circuit_free_mt_setting
;
287 void circuit_mt_finish(struct isis_circuit
*circuit
)
289 list_delete(&circuit
->mt_settings
);
292 struct isis_circuit_mt_setting
*
293 circuit_get_mt_setting(struct isis_circuit
*circuit
, uint16_t mtid
)
295 struct isis_circuit_mt_setting
*setting
;
297 setting
= circuit_lookup_mt_setting(circuit
, mtid
);
299 setting
= circuit_new_mt_setting(circuit
, mtid
);
300 circuit_add_mt_setting(circuit
, setting
);
305 int circuit_write_mt_settings(struct isis_circuit
*circuit
, struct vty
*vty
)
308 struct listnode
*node
;
309 struct isis_circuit_mt_setting
*setting
;
311 for (ALL_LIST_ELEMENTS_RO(circuit
->mt_settings
, node
, setting
)) {
312 const char *name
= isis_mtid2str(setting
->mtid
);
313 if (name
&& !setting
->enabled
) {
314 vty_out(vty
, " no " PROTO_NAME
" topology %s\n", name
);
321 struct isis_circuit_mt_setting
**
322 circuit_mt_settings(struct isis_circuit
*circuit
, unsigned int *mt_count
)
324 static unsigned int size
= 0;
325 static struct isis_circuit_mt_setting
**rv
= NULL
;
327 struct isis_area_mt_setting
**area_settings
;
328 unsigned int area_count
;
330 unsigned int count
= 0;
332 struct listnode
*node
;
333 struct isis_circuit_mt_setting
*setting
;
335 area_settings
= area_mt_settings(circuit
->area
, &area_count
);
337 for (unsigned int i
= 0; i
< area_count
; i
++) {
338 for (ALL_LIST_ELEMENTS_RO(circuit
->mt_settings
, node
,
340 if (setting
->mtid
!= area_settings
[i
]->mtid
)
345 setting
= circuit_get_mt_setting(
346 circuit
, area_settings
[i
]->mtid
);
348 if (!setting
->enabled
)
353 rv
= XREALLOC(MTYPE_TMP
, rv
, count
* sizeof(*rv
));
356 rv
[count
- 1] = setting
;
363 /* ADJ specific MT API */
364 static void adj_mt_set(struct isis_adjacency
*adj
, unsigned int index
,
367 if (adj
->mt_count
< index
+ 1) {
368 adj
->mt_set
= XREALLOC(MTYPE_MT_ADJ_INFO
, adj
->mt_set
,
369 (index
+ 1) * sizeof(*adj
->mt_set
));
370 adj
->mt_count
= index
+ 1;
372 adj
->mt_set
[index
] = mtid
;
375 bool tlvs_to_adj_mt_set(struct isis_tlvs
*tlvs
, bool v4_usable
, bool v6_usable
,
376 struct isis_adjacency
*adj
)
378 struct isis_circuit_mt_setting
**mt_settings
;
379 unsigned int circuit_mt_count
;
381 unsigned int intersect_count
= 0;
383 uint16_t *old_mt_set
= NULL
;
384 unsigned int old_mt_count
;
386 old_mt_count
= adj
->mt_count
;
389 XCALLOC(MTYPE_TMP
, old_mt_count
* sizeof(*old_mt_set
));
390 memcpy(old_mt_set
, adj
->mt_set
,
391 old_mt_count
* sizeof(*old_mt_set
));
394 mt_settings
= circuit_mt_settings(adj
->circuit
, &circuit_mt_count
);
395 for (unsigned int i
= 0; i
< circuit_mt_count
; i
++) {
396 if (!tlvs
->mt_router_info
.count
397 && !tlvs
->mt_router_info_empty
) {
398 /* Other end does not have MT enabled */
399 if (mt_settings
[i
]->mtid
== ISIS_MT_IPV4_UNICAST
401 adj_mt_set(adj
, intersect_count
++,
402 ISIS_MT_IPV4_UNICAST
);
404 struct isis_mt_router_info
*info_head
;
406 info_head
= (struct isis_mt_router_info
*)
407 tlvs
->mt_router_info
.head
;
408 for (struct isis_mt_router_info
*info
= info_head
; info
;
410 if (mt_settings
[i
]->mtid
== info
->mtid
) {
412 switch (info
->mtid
) {
413 case ISIS_MT_IPV4_UNICAST
:
414 case ISIS_MT_IPV4_MGMT
:
415 case ISIS_MT_IPV4_MULTICAST
:
418 case ISIS_MT_IPV6_UNICAST
:
419 case ISIS_MT_IPV6_MGMT
:
420 case ISIS_MT_IPV6_MULTICAST
:
435 adj
->mt_count
= intersect_count
;
437 bool changed
= false;
439 if (adj
->mt_count
!= old_mt_count
)
442 if (!changed
&& old_mt_count
443 && memcmp(adj
->mt_set
, old_mt_set
,
444 old_mt_count
* sizeof(*old_mt_set
)))
448 XFREE(MTYPE_TMP
, old_mt_set
);
453 bool adj_has_mt(struct isis_adjacency
*adj
, uint16_t mtid
)
455 for (unsigned int i
= 0; i
< adj
->mt_count
; i
++)
456 if (adj
->mt_set
[i
] == mtid
)
461 void adj_mt_finish(struct isis_adjacency
*adj
)
463 XFREE(MTYPE_MT_ADJ_INFO
, adj
->mt_set
);
467 static void mt_set_add(uint16_t **mt_set
, unsigned int *size
,
468 unsigned int *index
, uint16_t mtid
)
470 for (unsigned int i
= 0; i
< *index
; i
++) {
471 if ((*mt_set
)[i
] == mtid
)
475 if (*index
>= *size
) {
476 *mt_set
= XREALLOC(MTYPE_TMP
, *mt_set
,
477 sizeof(**mt_set
) * ((*index
) + 1));
478 *size
= (*index
) + 1;
481 (*mt_set
)[*index
] = mtid
;
482 *index
= (*index
) + 1;
485 static uint16_t *circuit_bcast_mt_set(struct isis_circuit
*circuit
, int level
,
486 unsigned int *mt_count
)
489 static unsigned int size
;
490 struct listnode
*node
;
491 struct isis_adjacency
*adj
;
493 unsigned int count
= 0;
495 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
) {
500 for (ALL_LIST_ELEMENTS_RO(circuit
->u
.bc
.adjdb
[level
- 1], node
, adj
)) {
501 if (adj
->adj_state
!= ISIS_ADJ_UP
)
503 for (unsigned int i
= 0; i
< adj
->mt_count
; i
++)
504 mt_set_add(&rv
, &size
, &count
, adj
->mt_set
[i
]);
511 static void tlvs_add_mt_set(struct isis_area
*area
, struct isis_tlvs
*tlvs
,
512 unsigned int mt_count
, uint16_t *mt_set
,
513 uint8_t *id
, uint32_t metric
, uint8_t *subtlvs
,
516 for (unsigned int i
= 0; i
< mt_count
; i
++) {
517 uint16_t mtid
= mt_set
[i
];
518 if (mt_set
[i
] == ISIS_MT_IPV4_UNICAST
) {
520 "ISIS (%s): Adding %s.%02x as te-style neighbor",
521 area
->area_tag
, sysid_print(id
),
525 "ISIS (%s): Adding %s.%02x as mt-style neighbor for %s",
526 area
->area_tag
, sysid_print(id
),
527 LSP_PSEUDO_ID(id
), isis_mtid2str(mtid
));
529 isis_tlvs_add_extended_reach(tlvs
, mtid
, id
, metric
, subtlvs
,
534 void tlvs_add_mt_bcast(struct isis_tlvs
*tlvs
, struct isis_circuit
*circuit
,
535 int level
, uint8_t *id
, uint32_t metric
,
536 uint8_t *subtlvs
, uint8_t subtlv_len
)
538 unsigned int mt_count
;
539 uint16_t *mt_set
= circuit_bcast_mt_set(circuit
, level
, &mt_count
);
541 tlvs_add_mt_set(circuit
->area
, tlvs
, mt_count
, mt_set
, id
, metric
,
542 subtlvs
, subtlv_len
);
545 void tlvs_add_mt_p2p(struct isis_tlvs
*tlvs
, struct isis_circuit
*circuit
,
546 uint8_t *id
, uint32_t metric
, uint8_t *subtlvs
,
549 struct isis_adjacency
*adj
= circuit
->u
.p2p
.neighbor
;
551 tlvs_add_mt_set(circuit
->area
, tlvs
, adj
->mt_count
, adj
->mt_set
, id
,
552 metric
, subtlvs
, subtlv_len
);