]>
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
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
24 #include "isisd/isisd.h"
25 #include "isisd/isis_memory.h"
26 #include "isisd/isis_circuit.h"
27 #include "isisd/isis_adjacency.h"
28 #include "isisd/isis_tlv.h"
29 #include "isisd/isis_misc.h"
30 #include "isisd/isis_lsp.h"
31 #include "isisd/isis_mt.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
, "ISIS MT IPv4 Reachabilities for TLV")
38 DEFINE_MTYPE_STATIC(ISISD
, MT_IPV6_REACHS
, "ISIS MT IPv6 Reachabilities for TLV")
40 uint16_t isis_area_ipv6_topology(struct isis_area
*area
)
42 struct isis_area_mt_setting
*area_mt_setting
;
43 area_mt_setting
= area_lookup_mt_setting(area
, ISIS_MT_IPV6_UNICAST
);
45 if (area_mt_setting
&& area_mt_setting
->enabled
)
46 return ISIS_MT_IPV6_UNICAST
;
47 return ISIS_MT_IPV4_UNICAST
;
51 const char *isis_mtid2str(uint16_t mtid
)
53 static char buf
[sizeof("65535")];
57 case ISIS_MT_IPV4_UNICAST
:
58 return "ipv4-unicast";
59 case ISIS_MT_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
:
70 snprintf(buf
, sizeof(buf
), "%" PRIu16
, mtid
);
75 uint16_t isis_str2mtid(const char *name
)
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
;
92 /* General MT settings api */
99 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
))
106 if (setting
->mtid
== mtid
)
113 add_mt_setting(struct list
**mt_list
, void *setting
)
116 *mt_list
= list_new();
117 listnode_add(*mt_list
, setting
);
120 /* Area specific MT settings api */
122 struct isis_area_mt_setting
*
123 area_lookup_mt_setting(struct isis_area
*area
, uint16_t mtid
)
125 return lookup_mt_setting(area
->mt_settings
, mtid
);
128 struct isis_area_mt_setting
*
129 area_new_mt_setting(struct isis_area
*area
, uint16_t mtid
)
131 struct isis_area_mt_setting
*setting
;
133 setting
= XCALLOC(MTYPE_MT_AREA_SETTING
, sizeof(*setting
));
134 setting
->mtid
= mtid
;
139 area_free_mt_setting(void *setting
)
141 XFREE(MTYPE_MT_AREA_SETTING
, setting
);
145 area_add_mt_setting(struct isis_area
*area
, struct isis_area_mt_setting
*setting
)
147 add_mt_setting(&area
->mt_settings
, setting
);
151 area_mt_init(struct isis_area
*area
)
153 struct isis_area_mt_setting
*v4_unicast_setting
;
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
;
163 area_mt_finish(struct isis_area
*area
)
165 list_delete(area
->mt_settings
);
166 area
->mt_settings
= NULL
;
169 struct isis_area_mt_setting
*
170 area_get_mt_setting(struct isis_area
*area
, uint16_t mtid
)
172 struct isis_area_mt_setting
*setting
;
174 setting
= area_lookup_mt_setting(area
, mtid
);
177 setting
= area_new_mt_setting(area
, mtid
);
178 area_add_mt_setting(area
, setting
);
184 area_write_mt_settings(struct isis_area
*area
, struct vty
*vty
)
187 struct listnode
*node
;
188 struct isis_area_mt_setting
*setting
;
190 for (ALL_LIST_ELEMENTS_RO(area
->mt_settings
, node
, setting
))
192 const char *name
= isis_mtid2str(setting
->mtid
);
193 if (name
&& setting
->enabled
)
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" : "",
206 bool area_is_mt(struct isis_area
*area
)
208 struct listnode
*node
, *node2
;
209 struct isis_area_mt_setting
*setting
;
210 struct isis_circuit
*circuit
;
211 struct isis_circuit_mt_setting
*csetting
;
213 for (ALL_LIST_ELEMENTS_RO(area
->mt_settings
, node
, setting
))
215 if (setting
->enabled
&& setting
->mtid
!= ISIS_MT_IPV4_UNICAST
)
218 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
))
220 for (ALL_LIST_ELEMENTS_RO(circuit
->mt_settings
, node2
, csetting
))
222 if (!csetting
->enabled
&& csetting
->mtid
== ISIS_MT_IPV4_UNICAST
)
230 struct isis_area_mt_setting
**
231 area_mt_settings(struct isis_area
*area
, unsigned int *mt_count
)
233 static unsigned int size
= 0;
234 static struct isis_area_mt_setting
**rv
= NULL
;
236 unsigned int count
= 0;
237 struct listnode
*node
;
238 struct isis_area_mt_setting
*setting
;
240 for (ALL_LIST_ELEMENTS_RO(area
->mt_settings
, node
, setting
))
242 if (!setting
->enabled
)
248 rv
= XREALLOC(MTYPE_TMP
, rv
, count
* sizeof(*rv
));
251 rv
[count
-1] = setting
;
258 /* Circuit specific MT settings api */
260 struct isis_circuit_mt_setting
*
261 circuit_lookup_mt_setting(struct isis_circuit
*circuit
, uint16_t mtid
)
263 return lookup_mt_setting(circuit
->mt_settings
, mtid
);
266 struct isis_circuit_mt_setting
*
267 circuit_new_mt_setting(struct isis_circuit
*circuit
, uint16_t mtid
)
269 struct isis_circuit_mt_setting
*setting
;
271 setting
= XCALLOC(MTYPE_MT_CIRCUIT_SETTING
, sizeof(*setting
));
272 setting
->mtid
= mtid
;
273 setting
->enabled
= true; /* Enabled is default for circuit */
278 circuit_free_mt_setting(void *setting
)
280 XFREE(MTYPE_MT_CIRCUIT_SETTING
, setting
);
284 circuit_add_mt_setting(struct isis_circuit
*circuit
,
285 struct isis_circuit_mt_setting
*setting
)
287 add_mt_setting(&circuit
->mt_settings
, setting
);
291 circuit_mt_init(struct isis_circuit
*circuit
)
293 circuit
->mt_settings
= list_new();
294 circuit
->mt_settings
->del
= circuit_free_mt_setting
;
298 circuit_mt_finish(struct isis_circuit
*circuit
)
300 list_delete(circuit
->mt_settings
);
301 circuit
->mt_settings
= NULL
;
304 struct isis_circuit_mt_setting
*
305 circuit_get_mt_setting(struct isis_circuit
*circuit
, uint16_t mtid
)
307 struct isis_circuit_mt_setting
*setting
;
309 setting
= circuit_lookup_mt_setting(circuit
, mtid
);
312 setting
= circuit_new_mt_setting(circuit
, mtid
);
313 circuit_add_mt_setting(circuit
, setting
);
319 circuit_write_mt_settings(struct isis_circuit
*circuit
, struct vty
*vty
)
322 struct listnode
*node
;
323 struct isis_circuit_mt_setting
*setting
;
325 for (ALL_LIST_ELEMENTS_RO (circuit
->mt_settings
, node
, setting
))
327 const char *name
= isis_mtid2str(setting
->mtid
);
328 if (name
&& !setting
->enabled
)
330 vty_out (vty
, " no isis topology %s%s", name
, VTY_NEWLINE
);
337 struct isis_circuit_mt_setting
**
338 circuit_mt_settings(struct isis_circuit
*circuit
, unsigned int *mt_count
)
340 static unsigned int size
= 0;
341 static struct isis_circuit_mt_setting
**rv
= NULL
;
343 struct isis_area_mt_setting
**area_settings
;
344 unsigned int area_count
;
346 unsigned int count
= 0;
348 struct listnode
*node
;
349 struct isis_circuit_mt_setting
*setting
;
351 area_settings
= area_mt_settings(circuit
->area
, &area_count
);
353 for (unsigned int i
= 0; i
< area_count
; i
++)
355 for (ALL_LIST_ELEMENTS_RO(circuit
->mt_settings
, node
, setting
))
357 if (setting
->mtid
!= area_settings
[i
]->mtid
)
362 setting
= circuit_get_mt_setting(circuit
, area_settings
[i
]->mtid
);
364 if (!setting
->enabled
)
370 rv
= XREALLOC(MTYPE_TMP
, rv
, count
* sizeof(*rv
));
373 rv
[count
-1] = setting
;
380 /* ADJ specific MT API */
381 static void adj_mt_set(struct isis_adjacency
*adj
, unsigned int index
,
384 if (adj
->mt_count
< index
+ 1)
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;
390 adj
->mt_set
[index
] = mtid
;
394 tlvs_to_adj_mt_set(struct tlvs
*tlvs
, bool v4_usable
, bool v6_usable
,
395 struct isis_adjacency
*adj
)
397 struct isis_circuit_mt_setting
**mt_settings
;
398 unsigned int circuit_mt_count
;
400 unsigned int intersect_count
= 0;
402 uint16_t *old_mt_set
= NULL
;
403 unsigned int old_mt_count
;
405 old_mt_count
= adj
->mt_count
;
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
));
412 mt_settings
= circuit_mt_settings(adj
->circuit
, &circuit_mt_count
);
413 for (unsigned int i
= 0; i
< circuit_mt_count
; i
++)
415 if (!tlvs
->mt_router_info
)
417 /* Other end does not have MT enabled */
418 if (mt_settings
[i
]->mtid
== ISIS_MT_IPV4_UNICAST
&& v4_usable
)
419 adj_mt_set(adj
, intersect_count
++, ISIS_MT_IPV4_UNICAST
);
423 struct listnode
*node
;
424 struct mt_router_info
*info
;
425 for (ALL_LIST_ELEMENTS_RO(tlvs
->mt_router_info
, node
, info
))
427 if (mt_settings
[i
]->mtid
== info
->mtid
)
432 case ISIS_MT_IPV4_UNICAST
:
433 case ISIS_MT_IPV4_MGMT
:
434 case ISIS_MT_IPV4_MULTICAST
:
437 case ISIS_MT_IPV6_UNICAST
:
438 case ISIS_MT_IPV6_MGMT
:
439 case ISIS_MT_IPV6_MULTICAST
:
447 adj_mt_set(adj
, intersect_count
++, info
->mtid
);
452 adj
->mt_count
= intersect_count
;
454 bool changed
= false;
456 if (adj
->mt_count
!= old_mt_count
)
459 if (!changed
&& old_mt_count
460 && memcmp(adj
->mt_set
, old_mt_set
,
461 old_mt_count
* sizeof(*old_mt_set
)))
465 XFREE(MTYPE_TMP
, old_mt_set
);
471 adj_has_mt(struct isis_adjacency
*adj
, uint16_t mtid
)
473 for (unsigned int i
= 0; i
< adj
->mt_count
; i
++)
474 if (adj
->mt_set
[i
] == mtid
)
480 adj_mt_finish(struct isis_adjacency
*adj
)
482 XFREE(MTYPE_MT_ADJ_INFO
, adj
->mt_set
);
486 /* TLV Router info api */
487 struct mt_router_info
*
488 tlvs_lookup_mt_router_info(struct tlvs
*tlvs
, uint16_t mtid
)
490 return lookup_mt_setting(tlvs
->mt_router_info
, mtid
);
493 /* TLV MT Neighbors api */
494 struct tlv_mt_neighbors
*
495 tlvs_lookup_mt_neighbors(struct tlvs
*tlvs
, uint16_t mtid
)
497 return lookup_mt_setting(tlvs
->mt_is_neighs
, mtid
);
500 static struct tlv_mt_neighbors
*
501 tlvs_new_mt_neighbors(uint16_t mtid
)
503 struct tlv_mt_neighbors
*rv
;
505 rv
= XCALLOC(MTYPE_MT_NEIGHBORS
, sizeof(*rv
));
507 rv
->list
= list_new();
513 tlvs_free_mt_neighbors(void *arg
)
515 struct tlv_mt_neighbors
*neighbors
= arg
;
517 if (neighbors
&& neighbors
->list
)
518 list_delete(neighbors
->list
);
519 XFREE(MTYPE_MT_NEIGHBORS
, neighbors
);
523 tlvs_add_mt_neighbors(struct tlvs
*tlvs
, struct tlv_mt_neighbors
*neighbors
)
525 add_mt_setting(&tlvs
->mt_is_neighs
, neighbors
);
526 tlvs
->mt_is_neighs
->del
= tlvs_free_mt_neighbors
;
529 struct tlv_mt_neighbors
*
530 tlvs_get_mt_neighbors(struct tlvs
*tlvs
, uint16_t mtid
)
532 struct tlv_mt_neighbors
*neighbors
;
534 neighbors
= tlvs_lookup_mt_neighbors(tlvs
, mtid
);
537 neighbors
= tlvs_new_mt_neighbors(mtid
);
538 tlvs_add_mt_neighbors(tlvs
, neighbors
);
543 /* TLV MT IPv4 reach api */
544 struct tlv_mt_ipv4_reachs
*
545 tlvs_lookup_mt_ipv4_reachs(struct tlvs
*tlvs
, uint16_t mtid
)
547 return lookup_mt_setting(tlvs
->mt_ipv4_reachs
, mtid
);
550 static struct tlv_mt_ipv4_reachs
*
551 tlvs_new_mt_ipv4_reachs(uint16_t mtid
)
553 struct tlv_mt_ipv4_reachs
*rv
;
555 rv
= XCALLOC(MTYPE_MT_IPV4_REACHS
, sizeof(*rv
));
557 rv
->list
= list_new();
563 tlvs_free_mt_ipv4_reachs(void *arg
)
565 struct tlv_mt_ipv4_reachs
*reachs
= arg
;
567 if (reachs
&& reachs
->list
)
568 list_delete(reachs
->list
);
569 XFREE(MTYPE_MT_IPV4_REACHS
, reachs
);
573 tlvs_add_mt_ipv4_reachs(struct tlvs
*tlvs
, struct tlv_mt_ipv4_reachs
*reachs
)
575 add_mt_setting(&tlvs
->mt_ipv4_reachs
, reachs
);
576 tlvs
->mt_ipv4_reachs
->del
= tlvs_free_mt_ipv4_reachs
;
579 struct tlv_mt_ipv4_reachs
*
580 tlvs_get_mt_ipv4_reachs(struct tlvs
*tlvs
, uint16_t mtid
)
582 struct tlv_mt_ipv4_reachs
*reachs
;
584 reachs
= tlvs_lookup_mt_ipv4_reachs(tlvs
, mtid
);
587 reachs
= tlvs_new_mt_ipv4_reachs(mtid
);
588 tlvs_add_mt_ipv4_reachs(tlvs
, reachs
);
593 /* TLV MT IPv6 reach api */
594 struct tlv_mt_ipv6_reachs
*
595 tlvs_lookup_mt_ipv6_reachs(struct tlvs
*tlvs
, uint16_t mtid
)
597 return lookup_mt_setting(tlvs
->mt_ipv6_reachs
, mtid
);
600 static struct tlv_mt_ipv6_reachs
*
601 tlvs_new_mt_ipv6_reachs(uint16_t mtid
)
603 struct tlv_mt_ipv6_reachs
*rv
;
605 rv
= XCALLOC(MTYPE_MT_IPV6_REACHS
, sizeof(*rv
));
607 rv
->list
= list_new();
613 tlvs_free_mt_ipv6_reachs(void *arg
)
615 struct tlv_mt_ipv6_reachs
*reachs
= arg
;
617 if (reachs
&& reachs
->list
)
618 list_delete(reachs
->list
);
619 XFREE(MTYPE_MT_IPV6_REACHS
, reachs
);
623 tlvs_add_mt_ipv6_reachs(struct tlvs
*tlvs
, struct tlv_mt_ipv6_reachs
*reachs
)
625 add_mt_setting(&tlvs
->mt_ipv6_reachs
, reachs
);
626 tlvs
->mt_ipv6_reachs
->del
= tlvs_free_mt_ipv6_reachs
;
629 struct tlv_mt_ipv6_reachs
*
630 tlvs_get_mt_ipv6_reachs(struct tlvs
*tlvs
, uint16_t mtid
)
632 struct tlv_mt_ipv6_reachs
*reachs
;
634 reachs
= tlvs_lookup_mt_ipv6_reachs(tlvs
, mtid
);
637 reachs
= tlvs_new_mt_ipv6_reachs(mtid
);
638 tlvs_add_mt_ipv6_reachs(tlvs
, reachs
);
644 mt_set_add(uint16_t **mt_set
, unsigned int *size
,
645 unsigned int *index
, uint16_t mtid
)
647 for (unsigned int i
= 0; i
< *index
; i
++)
649 if ((*mt_set
)[i
] == mtid
)
655 *mt_set
= XREALLOC(MTYPE_TMP
, *mt_set
, sizeof(**mt_set
) * ((*index
) + 1));
656 *size
= (*index
) + 1;
659 (*mt_set
)[*index
] = mtid
;
660 *index
= (*index
) + 1;
664 circuit_bcast_mt_set(struct isis_circuit
*circuit
, int level
,
665 unsigned int *mt_count
)
668 static unsigned int size
;
669 struct listnode
*node
;
670 struct isis_adjacency
*adj
;
672 unsigned int count
= 0;
674 if (circuit
->circ_type
!= CIRCUIT_T_BROADCAST
)
680 for (ALL_LIST_ELEMENTS_RO(circuit
->u
.bc
.adjdb
[level
- 1], node
, adj
))
682 if (adj
->adj_state
!= ISIS_ADJ_UP
)
684 for (unsigned int i
= 0; i
< adj
->mt_count
; i
++)
685 mt_set_add(&rv
, &size
, &count
, adj
->mt_set
[i
]);
693 tlvs_add_mt_set(struct isis_area
*area
,
694 struct tlvs
*tlvs
, unsigned int mt_count
,
695 uint16_t *mt_set
, struct te_is_neigh
*neigh
)
697 for (unsigned int i
= 0; i
< mt_count
; i
++)
699 uint16_t mtid
= mt_set
[i
];
700 struct te_is_neigh
*ne_copy
;
702 ne_copy
= XCALLOC(MTYPE_ISIS_TLV
, sizeof(*ne_copy
));
703 memcpy(ne_copy
, neigh
, sizeof(*ne_copy
));
705 if (mt_set
[i
] == ISIS_MT_IPV4_UNICAST
)
707 listnode_add(tlvs
->te_is_neighs
, ne_copy
);
708 lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor",
709 area
->area_tag
, sysid_print(ne_copy
->neigh_id
),
710 LSP_PSEUDO_ID(ne_copy
->neigh_id
));
714 struct tlv_mt_neighbors
*neighbors
;
716 neighbors
= tlvs_get_mt_neighbors(tlvs
, mtid
);
717 neighbors
->list
->del
= free_tlv
;
718 listnode_add(neighbors
->list
, ne_copy
);
719 lsp_debug("ISIS (%s): Adding %s.%02x as mt-style neighbor for %s",
720 area
->area_tag
, sysid_print(ne_copy
->neigh_id
),
721 LSP_PSEUDO_ID(ne_copy
->neigh_id
), isis_mtid2str(mtid
));
727 tlvs_add_mt_bcast(struct tlvs
*tlvs
, struct isis_circuit
*circuit
,
728 int level
, struct te_is_neigh
*neigh
)
730 unsigned int mt_count
;
731 uint16_t *mt_set
= circuit_bcast_mt_set(circuit
, level
,
734 tlvs_add_mt_set(circuit
->area
, tlvs
, mt_count
, mt_set
, neigh
);
738 tlvs_add_mt_p2p(struct tlvs
*tlvs
, struct isis_circuit
*circuit
,
739 struct te_is_neigh
*neigh
)
741 struct isis_adjacency
*adj
= circuit
->u
.p2p
.neighbor
;
743 tlvs_add_mt_set(circuit
->area
, tlvs
, adj
->mt_count
, adj
->mt_set
, neigh
);