]>
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"
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")
39 uint16_t isis_area_ipv6_topology(struct isis_area
*area
)
41 struct isis_area_mt_setting
*area_mt_setting
;
42 area_mt_setting
= area_lookup_mt_setting(area
, ISIS_MT_IPV6_UNICAST
);
44 if (area_mt_setting
&& area_mt_setting
->enabled
)
45 return ISIS_MT_IPV6_UNICAST
;
46 return ISIS_MT_IPV4_UNICAST
;
50 const char *isis_mtid2str(uint16_t mtid
)
52 static char buf
[sizeof("65535")];
56 case ISIS_MT_IPV4_UNICAST
:
57 return "ipv4-unicast";
58 case ISIS_MT_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
:
69 snprintf(buf
, sizeof(buf
), "%" PRIu16
, mtid
);
74 uint16_t isis_str2mtid(const char *name
)
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
;
91 /* General MT settings api */
98 lookup_mt_setting(struct list
*mt_list
, uint16_t mtid
)
100 struct listnode
*node
;
101 struct mt_setting
*setting
;
103 for (ALL_LIST_ELEMENTS_RO(mt_list
, node
, setting
))
105 if (setting
->mtid
== mtid
)
112 add_mt_setting(struct list
**mt_list
, void *setting
)
115 *mt_list
= list_new();
116 listnode_add(*mt_list
, setting
);
119 /* Area specific MT settings api */
121 struct isis_area_mt_setting
*
122 area_lookup_mt_setting(struct isis_area
*area
, uint16_t mtid
)
124 return lookup_mt_setting(area
->mt_settings
, mtid
);
127 struct isis_area_mt_setting
*
128 area_new_mt_setting(struct isis_area
*area
, uint16_t mtid
)
130 struct isis_area_mt_setting
*setting
;
132 setting
= XCALLOC(MTYPE_MT_AREA_SETTING
, sizeof(*setting
));
133 setting
->mtid
= mtid
;
138 area_free_mt_setting(void *setting
)
140 XFREE(MTYPE_MT_AREA_SETTING
, setting
);
144 area_add_mt_setting(struct isis_area
*area
, struct isis_area_mt_setting
*setting
)
146 add_mt_setting(&area
->mt_settings
, setting
);
150 area_mt_init(struct isis_area
*area
)
152 struct isis_area_mt_setting
*v4_unicast_setting
;
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
;
162 area_mt_finish(struct isis_area
*area
)
164 list_delete(area
->mt_settings
);
165 area
->mt_settings
= NULL
;
168 struct isis_area_mt_setting
*
169 area_get_mt_setting(struct isis_area
*area
, uint16_t mtid
)
171 struct isis_area_mt_setting
*setting
;
173 setting
= area_lookup_mt_setting(area
, mtid
);
176 setting
= area_new_mt_setting(area
, mtid
);
177 area_add_mt_setting(area
, setting
);
183 area_write_mt_settings(struct isis_area
*area
, struct vty
*vty
)
186 struct listnode
*node
;
187 struct isis_area_mt_setting
*setting
;
189 for (ALL_LIST_ELEMENTS_RO(area
->mt_settings
, node
, setting
))
191 const char *name
= isis_mtid2str(setting
->mtid
);
192 if (name
&& setting
->enabled
)
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" : "");
204 bool area_is_mt(struct isis_area
*area
)
206 struct listnode
*node
, *node2
;
207 struct isis_area_mt_setting
*setting
;
208 struct isis_circuit
*circuit
;
209 struct isis_circuit_mt_setting
*csetting
;
211 for (ALL_LIST_ELEMENTS_RO(area
->mt_settings
, node
, setting
))
213 if (setting
->enabled
&& setting
->mtid
!= ISIS_MT_IPV4_UNICAST
)
216 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
))
218 for (ALL_LIST_ELEMENTS_RO(circuit
->mt_settings
, node2
, csetting
))
220 if (!csetting
->enabled
&& csetting
->mtid
== ISIS_MT_IPV4_UNICAST
)
228 struct isis_area_mt_setting
**
229 area_mt_settings(struct isis_area
*area
, unsigned int *mt_count
)
231 static unsigned int size
= 0;
232 static struct isis_area_mt_setting
**rv
= NULL
;
234 unsigned int count
= 0;
235 struct listnode
*node
;
236 struct isis_area_mt_setting
*setting
;
238 for (ALL_LIST_ELEMENTS_RO(area
->mt_settings
, node
, setting
))
240 if (!setting
->enabled
)
246 rv
= XREALLOC(MTYPE_TMP
, rv
, count
* sizeof(*rv
));
249 rv
[count
-1] = setting
;
256 /* Circuit specific MT settings api */
258 struct isis_circuit_mt_setting
*
259 circuit_lookup_mt_setting(struct isis_circuit
*circuit
, uint16_t mtid
)
261 return lookup_mt_setting(circuit
->mt_settings
, mtid
);
264 struct isis_circuit_mt_setting
*
265 circuit_new_mt_setting(struct isis_circuit
*circuit
, uint16_t mtid
)
267 struct isis_circuit_mt_setting
*setting
;
269 setting
= XCALLOC(MTYPE_MT_CIRCUIT_SETTING
, sizeof(*setting
));
270 setting
->mtid
= mtid
;
271 setting
->enabled
= true; /* Enabled is default for circuit */
276 circuit_free_mt_setting(void *setting
)
278 XFREE(MTYPE_MT_CIRCUIT_SETTING
, setting
);
282 circuit_add_mt_setting(struct isis_circuit
*circuit
,
283 struct isis_circuit_mt_setting
*setting
)
285 add_mt_setting(&circuit
->mt_settings
, setting
);
289 circuit_mt_init(struct isis_circuit
*circuit
)
291 circuit
->mt_settings
= list_new();
292 circuit
->mt_settings
->del
= circuit_free_mt_setting
;
296 circuit_mt_finish(struct isis_circuit
*circuit
)
298 list_delete(circuit
->mt_settings
);
299 circuit
->mt_settings
= NULL
;
302 struct isis_circuit_mt_setting
*
303 circuit_get_mt_setting(struct isis_circuit
*circuit
, uint16_t mtid
)
305 struct isis_circuit_mt_setting
*setting
;
307 setting
= circuit_lookup_mt_setting(circuit
, mtid
);
310 setting
= circuit_new_mt_setting(circuit
, mtid
);
311 circuit_add_mt_setting(circuit
, setting
);
317 circuit_write_mt_settings(struct isis_circuit
*circuit
, struct vty
*vty
)
320 struct listnode
*node
;
321 struct isis_circuit_mt_setting
*setting
;
323 for (ALL_LIST_ELEMENTS_RO (circuit
->mt_settings
, node
, setting
))
325 const char *name
= isis_mtid2str(setting
->mtid
);
326 if (name
&& !setting
->enabled
)
328 vty_outln (vty
, " no isis topology %s", name
);
335 struct isis_circuit_mt_setting
**
336 circuit_mt_settings(struct isis_circuit
*circuit
, unsigned int *mt_count
)
338 static unsigned int size
= 0;
339 static struct isis_circuit_mt_setting
**rv
= NULL
;
341 struct isis_area_mt_setting
**area_settings
;
342 unsigned int area_count
;
344 unsigned int count
= 0;
346 struct listnode
*node
;
347 struct isis_circuit_mt_setting
*setting
;
349 area_settings
= area_mt_settings(circuit
->area
, &area_count
);
351 for (unsigned int i
= 0; i
< area_count
; i
++)
353 for (ALL_LIST_ELEMENTS_RO(circuit
->mt_settings
, node
, setting
))
355 if (setting
->mtid
!= area_settings
[i
]->mtid
)
360 setting
= circuit_get_mt_setting(circuit
, area_settings
[i
]->mtid
);
362 if (!setting
->enabled
)
368 rv
= XREALLOC(MTYPE_TMP
, rv
, count
* sizeof(*rv
));
371 rv
[count
-1] = setting
;
378 /* ADJ specific MT API */
379 static void adj_mt_set(struct isis_adjacency
*adj
, unsigned int index
,
382 if (adj
->mt_count
< index
+ 1)
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;
388 adj
->mt_set
[index
] = mtid
;
392 tlvs_to_adj_mt_set(struct tlvs
*tlvs
, bool v4_usable
, bool v6_usable
,
393 struct isis_adjacency
*adj
)
395 struct isis_circuit_mt_setting
**mt_settings
;
396 unsigned int circuit_mt_count
;
398 unsigned int intersect_count
= 0;
400 uint16_t *old_mt_set
= NULL
;
401 unsigned int old_mt_count
;
403 old_mt_count
= adj
->mt_count
;
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
));
410 mt_settings
= circuit_mt_settings(adj
->circuit
, &circuit_mt_count
);
411 for (unsigned int i
= 0; i
< circuit_mt_count
; i
++)
413 if (!tlvs
->mt_router_info
)
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
);
421 struct listnode
*node
;
422 struct mt_router_info
*info
;
423 for (ALL_LIST_ELEMENTS_RO(tlvs
->mt_router_info
, node
, info
))
425 if (mt_settings
[i
]->mtid
== info
->mtid
)
430 case ISIS_MT_IPV4_UNICAST
:
431 case ISIS_MT_IPV4_MGMT
:
432 case ISIS_MT_IPV4_MULTICAST
:
435 case ISIS_MT_IPV6_UNICAST
:
436 case ISIS_MT_IPV6_MGMT
:
437 case ISIS_MT_IPV6_MULTICAST
:
445 adj_mt_set(adj
, intersect_count
++, info
->mtid
);
450 adj
->mt_count
= intersect_count
;
452 bool changed
= false;
454 if (adj
->mt_count
!= old_mt_count
)
457 if (!changed
&& old_mt_count
458 && memcmp(adj
->mt_set
, old_mt_set
,
459 old_mt_count
* sizeof(*old_mt_set
)))
463 XFREE(MTYPE_TMP
, old_mt_set
);
469 adj_has_mt(struct isis_adjacency
*adj
, uint16_t mtid
)
471 for (unsigned int i
= 0; i
< adj
->mt_count
; i
++)
472 if (adj
->mt_set
[i
] == mtid
)
478 adj_mt_finish(struct isis_adjacency
*adj
)
480 XFREE(MTYPE_MT_ADJ_INFO
, adj
->mt_set
);
484 /* TLV Router info api */
485 struct mt_router_info
*
486 tlvs_lookup_mt_router_info(struct tlvs
*tlvs
, uint16_t mtid
)
488 return lookup_mt_setting(tlvs
->mt_router_info
, mtid
);
491 /* TLV MT Neighbors api */
492 struct tlv_mt_neighbors
*
493 tlvs_lookup_mt_neighbors(struct tlvs
*tlvs
, uint16_t mtid
)
495 return lookup_mt_setting(tlvs
->mt_is_neighs
, mtid
);
498 static struct tlv_mt_neighbors
*
499 tlvs_new_mt_neighbors(uint16_t mtid
)
501 struct tlv_mt_neighbors
*rv
;
503 rv
= XCALLOC(MTYPE_MT_NEIGHBORS
, sizeof(*rv
));
505 rv
->list
= list_new();
511 tlvs_free_mt_neighbors(void *arg
)
513 struct tlv_mt_neighbors
*neighbors
= arg
;
515 if (neighbors
&& neighbors
->list
)
516 list_delete(neighbors
->list
);
517 XFREE(MTYPE_MT_NEIGHBORS
, neighbors
);
521 tlvs_add_mt_neighbors(struct tlvs
*tlvs
, struct tlv_mt_neighbors
*neighbors
)
523 add_mt_setting(&tlvs
->mt_is_neighs
, neighbors
);
524 tlvs
->mt_is_neighs
->del
= tlvs_free_mt_neighbors
;
527 struct tlv_mt_neighbors
*
528 tlvs_get_mt_neighbors(struct tlvs
*tlvs
, uint16_t mtid
)
530 struct tlv_mt_neighbors
*neighbors
;
532 neighbors
= tlvs_lookup_mt_neighbors(tlvs
, mtid
);
535 neighbors
= tlvs_new_mt_neighbors(mtid
);
536 tlvs_add_mt_neighbors(tlvs
, neighbors
);
541 /* TLV MT IPv4 reach api */
542 struct tlv_mt_ipv4_reachs
*
543 tlvs_lookup_mt_ipv4_reachs(struct tlvs
*tlvs
, uint16_t mtid
)
545 return lookup_mt_setting(tlvs
->mt_ipv4_reachs
, mtid
);
548 static struct tlv_mt_ipv4_reachs
*
549 tlvs_new_mt_ipv4_reachs(uint16_t mtid
)
551 struct tlv_mt_ipv4_reachs
*rv
;
553 rv
= XCALLOC(MTYPE_MT_IPV4_REACHS
, sizeof(*rv
));
555 rv
->list
= list_new();
561 tlvs_free_mt_ipv4_reachs(void *arg
)
563 struct tlv_mt_ipv4_reachs
*reachs
= arg
;
565 if (reachs
&& reachs
->list
)
566 list_delete(reachs
->list
);
567 XFREE(MTYPE_MT_IPV4_REACHS
, reachs
);
571 tlvs_add_mt_ipv4_reachs(struct tlvs
*tlvs
, struct tlv_mt_ipv4_reachs
*reachs
)
573 add_mt_setting(&tlvs
->mt_ipv4_reachs
, reachs
);
574 tlvs
->mt_ipv4_reachs
->del
= tlvs_free_mt_ipv4_reachs
;
577 struct tlv_mt_ipv4_reachs
*
578 tlvs_get_mt_ipv4_reachs(struct tlvs
*tlvs
, uint16_t mtid
)
580 struct tlv_mt_ipv4_reachs
*reachs
;
582 reachs
= tlvs_lookup_mt_ipv4_reachs(tlvs
, mtid
);
585 reachs
= tlvs_new_mt_ipv4_reachs(mtid
);
586 tlvs_add_mt_ipv4_reachs(tlvs
, reachs
);
591 /* TLV MT IPv6 reach api */
592 struct tlv_mt_ipv6_reachs
*
593 tlvs_lookup_mt_ipv6_reachs(struct tlvs
*tlvs
, uint16_t mtid
)
595 return lookup_mt_setting(tlvs
->mt_ipv6_reachs
, mtid
);
598 static struct tlv_mt_ipv6_reachs
*
599 tlvs_new_mt_ipv6_reachs(uint16_t mtid
)
601 struct tlv_mt_ipv6_reachs
*rv
;
603 rv
= XCALLOC(MTYPE_MT_IPV6_REACHS
, sizeof(*rv
));
605 rv
->list
= list_new();
611 tlvs_free_mt_ipv6_reachs(void *arg
)
613 struct tlv_mt_ipv6_reachs
*reachs
= arg
;
615 if (reachs
&& reachs
->list
)
616 list_delete(reachs
->list
);
617 XFREE(MTYPE_MT_IPV6_REACHS
, reachs
);
621 tlvs_add_mt_ipv6_reachs(struct tlvs
*tlvs
, struct tlv_mt_ipv6_reachs
*reachs
)
623 add_mt_setting(&tlvs
->mt_ipv6_reachs
, reachs
);
624 tlvs
->mt_ipv6_reachs
->del
= tlvs_free_mt_ipv6_reachs
;
627 struct tlv_mt_ipv6_reachs
*
628 tlvs_get_mt_ipv6_reachs(struct tlvs
*tlvs
, uint16_t mtid
)
630 struct tlv_mt_ipv6_reachs
*reachs
;
632 reachs
= tlvs_lookup_mt_ipv6_reachs(tlvs
, mtid
);
635 reachs
= tlvs_new_mt_ipv6_reachs(mtid
);
636 tlvs_add_mt_ipv6_reachs(tlvs
, reachs
);
642 mt_set_add(uint16_t **mt_set
, unsigned int *size
,
643 unsigned int *index
, uint16_t mtid
)
645 for (unsigned int i
= 0; i
< *index
; i
++)
647 if ((*mt_set
)[i
] == mtid
)
653 *mt_set
= XREALLOC(MTYPE_TMP
, *mt_set
, sizeof(**mt_set
) * ((*index
) + 1));
654 *size
= (*index
) + 1;
657 (*mt_set
)[*index
] = mtid
;
658 *index
= (*index
) + 1;
662 circuit_bcast_mt_set(struct isis_circuit
*circuit
, int level
,
663 unsigned int *mt_count
)
666 static unsigned int size
;
667 struct listnode
*node
;
668 struct isis_adjacency
*adj
;
670 unsigned int count
= 0;
672 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
678 for (ALL_LIST_ELEMENTS_RO(circuit
->u
.bc
.adjdb
[level
- 1], node
, adj
))
680 if (adj
->adj_state
!= ISIS_ADJ_UP
)
682 for (unsigned int i
= 0; i
< adj
->mt_count
; i
++)
683 mt_set_add(&rv
, &size
, &count
, adj
->mt_set
[i
]);
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
)
695 for (unsigned int i
= 0; i
< mt_count
; i
++)
697 uint16_t mtid
= mt_set
[i
];
698 struct te_is_neigh
*ne_copy
;
700 ne_copy
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*ne_copy
));
701 memcpy(ne_copy
, neigh
, sizeof(*ne_copy
));
703 if (mt_set
[i
] == ISIS_MT_IPV4_UNICAST
)
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
));
712 struct tlv_mt_neighbors
*neighbors
;
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
));
725 tlvs_add_mt_bcast(struct tlvs
*tlvs
, struct isis_circuit
*circuit
,
726 int level
, struct te_is_neigh
*neigh
)
728 unsigned int mt_count
;
729 uint16_t *mt_set
= circuit_bcast_mt_set(circuit
, level
,
732 tlvs_add_mt_set(circuit
->area
, tlvs
, mt_count
, mt_set
, neigh
);
736 tlvs_add_mt_p2p(struct tlvs
*tlvs
, struct isis_circuit
*circuit
,
737 struct te_is_neigh
*neigh
)
739 struct isis_adjacency
*adj
= circuit
->u
.p2p
.neighbor
;
741 tlvs_add_mt_set(circuit
->area
, tlvs
, adj
->mt_count
, adj
->mt_set
, neigh
);