summaryrefslogtreecommitdiffstats
path: root/isisd
diff options
context:
space:
mode:
authorChristian Franke <chris@opensourcerouting.org>2017-04-27 13:56:38 +0200
committerChristian Franke <chris@opensourcerouting.org>2017-04-28 12:03:23 +0200
commit99894f9a17b319ca80d4a667b13cbc1a87814d2d (patch)
tree2f896bb61aea2989d1a67b1884680d275529533a /isisd
parentisisd: add MT configuration (diff)
downloadfrr-99894f9a17b319ca80d4a667b13cbc1a87814d2d.tar.xz
frr-99894f9a17b319ca80d4a667b13cbc1a87814d2d.zip
isisd: announce MT capabilities in IIH and LSP
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
Diffstat (limited to 'isisd')
-rw-r--r--isisd/isis_lsp.c37
-rw-r--r--isisd/isis_mt.c95
-rw-r--r--isisd/isis_mt.h8
-rw-r--r--isisd/isis_pdu.c34
-rw-r--r--isisd/isis_tlv.c63
-rw-r--r--isisd/isis_tlv.h12
6 files changed, 249 insertions, 0 deletions
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index d490bc47c..d7d76942a 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -53,6 +53,7 @@
#include "isisd/isis_adjacency.h"
#include "isisd/isis_spf.h"
#include "isisd/isis_te.h"
+#include "isisd/isis_mt.h"
/* staticly assigned vars for printing purposes */
char lsp_bits_string[200]; /* FIXME: enough ? */
@@ -501,6 +502,7 @@ lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
expected |= TLVFLAG_TE_IPV4_REACHABILITY;
expected |= TLVFLAG_TE_ROUTER_ID;
}
+ expected |= TLVFLAG_MT_ROUTER_INFORMATION;
expected |= TLVFLAG_IPV4_ADDR;
expected |= TLVFLAG_IPV4_INT_REACHABILITY;
expected |= TLVFLAG_IPV4_EXT_REACHABILITY;
@@ -838,6 +840,7 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
struct in_addr *ipv4_addr;
struct te_ipv4_reachability *te_ipv4_reach;
struct ipv6_reachability *ipv6_reach;
+ struct mt_router_info *mt_router_info;
struct in6_addr in6;
u_char buff[BUFSIZ];
u_char LSPid[255];
@@ -877,6 +880,14 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
}
}
+ for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_router_info, lnode, mt_router_info))
+ {
+ vty_out (vty, " MT : %s%s%s",
+ isis_mtid2str(mt_router_info->mtid),
+ mt_router_info->overload ? " (overload)" : "",
+ VTY_NEWLINE);
+ }
+
/* for the hostname tlv */
if (lsp->tlv_data.hostname)
{
@@ -1344,6 +1355,32 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
}
+ if (area_is_mt(area))
+ {
+ lsp_debug("ISIS (%s): Adding MT router tlv...", area->area_tag);
+ lsp->tlv_data.mt_router_info = list_new();
+ lsp->tlv_data.mt_router_info->del = free_tlv;
+
+ struct isis_area_mt_setting **mt_settings;
+ unsigned int mt_count;
+
+ mt_settings = area_mt_settings(area, &mt_count);
+ for (unsigned int i = 0; i < mt_count; i++)
+ {
+ struct mt_router_info *info;
+
+ info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
+ info->mtid = mt_settings[i]->mtid;
+ info->overload = mt_settings[i]->overload;
+ listnode_add(lsp->tlv_data.mt_router_info, info);
+ lsp_debug("ISIS (%s): MT %s", area->area_tag, isis_mtid2str(info->mtid));
+ }
+ tlv_add_mt_router_info (lsp->tlv_data.mt_router_info, lsp->pdu);
+ }
+ else
+ {
+ lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)", area->area_tag);
+ }
/* Dynamic Hostname */
if (area->dynhostname)
{
diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c
index 7908fd4bb..6d43fdf03 100644
--- a/isisd/isis_mt.c
+++ b/isisd/isis_mt.c
@@ -182,6 +182,58 @@ area_write_mt_settings(struct isis_area *area, struct vty *vty)
return written;
}
+bool area_is_mt(struct isis_area *area)
+{
+ struct listnode *node, *node2;
+ struct isis_area_mt_setting *setting;
+ struct isis_circuit *circuit;
+ struct isis_circuit_mt_setting *csetting;
+
+ for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
+ {
+ if (setting->enabled && setting->mtid != ISIS_MT_IPV4_UNICAST)
+ return true;
+ }
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
+ {
+ for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node2, csetting))
+ {
+ if (!csetting->enabled && csetting->mtid == ISIS_MT_IPV4_UNICAST)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+struct isis_area_mt_setting**
+area_mt_settings(struct isis_area *area, unsigned int *mt_count)
+{
+ static unsigned int size = 0;
+ static struct isis_area_mt_setting **rv = NULL;
+
+ unsigned int count = 0;
+ struct listnode *node;
+ struct isis_area_mt_setting *setting;
+
+ for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
+ {
+ if (!setting->enabled)
+ continue;
+
+ count++;
+ if (count > size)
+ {
+ rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
+ size = count;
+ }
+ rv[count-1] = setting;
+ }
+
+ *mt_count = count;
+ return rv;
+}
+
/* Circuit specific MT settings api */
struct isis_circuit_mt_setting*
@@ -260,3 +312,46 @@ circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty)
}
return written;
}
+
+struct isis_circuit_mt_setting**
+circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count)
+{
+ static unsigned int size = 0;
+ static struct isis_circuit_mt_setting **rv = NULL;
+
+ struct isis_area_mt_setting **area_settings;
+ unsigned int area_count;
+
+ unsigned int count = 0;
+
+ struct listnode *node;
+ struct isis_circuit_mt_setting *setting;
+
+ area_settings = area_mt_settings(circuit->area, &area_count);
+
+ for (unsigned int i = 0; i < area_count; i++)
+ {
+ for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node, setting))
+ {
+ if (setting->mtid != area_settings[i]->mtid)
+ continue;
+ break;
+ }
+ if (!setting)
+ setting = circuit_get_mt_setting(circuit, area_settings[i]->mtid);
+
+ if (!setting->enabled)
+ continue;
+
+ count++;
+ if (count > size)
+ {
+ rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
+ size = count;
+ }
+ rv[count-1] = setting;
+ }
+
+ *mt_count = count;
+ return rv;
+}
diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h
index a6f401357..6b1711f4c 100644
--- a/isisd/isis_mt.h
+++ b/isisd/isis_mt.h
@@ -23,6 +23,9 @@
#ifndef ISIS_MT_H
#define ISIS_MT_H
+#define ISIS_MT_MASK 0x0fff
+#define ISIS_MT_OL_MASK 0x8000
+
#define ISIS_MT_IPV4_UNICAST 0
#define ISIS_MT_IPV4_MGMT 1
#define ISIS_MT_IPV6_UNICAST 2
@@ -79,6 +82,9 @@ void area_mt_finish(struct isis_area *area);
struct isis_area_mt_setting* area_get_mt_setting(struct isis_area *area,
uint16_t mtid);
int area_write_mt_settings(struct isis_area *area, struct vty *vty);
+bool area_is_mt(struct isis_area *area);
+struct isis_area_mt_setting** area_mt_settings(struct isis_area *area,
+ unsigned int *mt_count);
struct isis_circuit_mt_setting* circuit_lookup_mt_setting(
struct isis_circuit *circuit,
@@ -94,4 +100,6 @@ struct isis_circuit_mt_setting* circuit_get_mt_setting(
struct isis_circuit *circuit,
uint16_t mtid);
int circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty);
+struct isis_circuit_mt_setting** circuit_mt_settings(struct isis_circuit *circuit,
+ unsigned int *mt_count);
#endif
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index 5fbf6c194..8909eb31e 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -53,6 +53,7 @@
#include "isisd/isis_csm.h"
#include "isisd/isis_events.h"
#include "isisd/isis_te.h"
+#include "isisd/isis_mt.h"
#define ISIS_MINIMUM_FIXED_HDR_LEN 15
#define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */
@@ -471,6 +472,7 @@ process_p2p_hello (struct isis_circuit *circuit)
expected |= TLVFLAG_NLPID;
expected |= TLVFLAG_IPV4_ADDR;
expected |= TLVFLAG_IPV6_ADDR;
+ expected |= TLVFLAG_MT_ROUTER_INFORMATION;
auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
retval = parse_tlvs (circuit->area->area_tag,
@@ -1021,6 +1023,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)
expected |= TLVFLAG_NLPID;
expected |= TLVFLAG_IPV4_ADDR;
expected |= TLVFLAG_IPV6_ADDR;
+ expected |= TLVFLAG_MT_ROUTER_INFORMATION;
auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
retval = parse_tlvs (circuit->area->area_tag,
@@ -2337,6 +2340,37 @@ send_hello (struct isis_circuit *circuit, int level)
if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream))
return ISIS_WARNING;
+ /*
+ * MT Supported TLV
+ *
+ * TLV gets included if no topology is enabled on the interface,
+ * if one topology other than #0 is enabled, or if multiple topologies
+ * are enabled.
+ */
+ struct isis_circuit_mt_setting **mt_settings;
+ unsigned int mt_count;
+
+ mt_settings = circuit_mt_settings(circuit, &mt_count);
+ if ((mt_count == 0 && area_is_mt(circuit->area))
+ || (mt_count == 1 && mt_settings[0]->mtid != ISIS_MT_IPV4_UNICAST)
+ || (mt_count > 1))
+ {
+ struct list *mt_info = list_new();
+ mt_info->del = free_tlv;
+
+ for (unsigned int i = 0; i < mt_count; i++)
+ {
+ struct mt_router_info *info;
+
+ info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
+ info->mtid = mt_settings[i]->mtid;
+ /* overload info is not valid in IIH, so it's not included here */
+ listnode_add(mt_info, info);
+ }
+ tlv_add_mt_router_info (mt_info, circuit->snd_stream);
+ list_free(mt_info);
+ }
+
/* IPv6 Interface Address TLV */
if (circuit->ipv6_router && circuit->ipv6_link &&
listcount (circuit->ipv6_link) > 0)
diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c
index 4192fff9a..14ebed94d 100644
--- a/isisd/isis_tlv.c
+++ b/isisd/isis_tlv.c
@@ -61,6 +61,8 @@ free_tlvs (struct tlvs *tlvs)
{
if (tlvs->area_addrs)
list_delete (tlvs->area_addrs);
+ if (tlvs->mt_router_info)
+ list_delete (tlvs->mt_router_info);
if (tlvs->is_neighs)
list_delete (tlvs->is_neighs);
if (tlvs->te_is_neighs)
@@ -786,6 +788,42 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
pnt += length;
break;
+ case MT_ROUTER_INFORMATION:
+ *found |= TLVFLAG_MT_ROUTER_INFORMATION;
+ if (*expected & TLVFLAG_MT_ROUTER_INFORMATION)
+ {
+ if (!tlvs->mt_router_info)
+ {
+ tlvs->mt_router_info = list_new();
+ tlvs->mt_router_info->del = free_tlv;
+ }
+ while (length > value_len)
+ {
+ uint16_t mt_info;
+ struct mt_router_info *info;
+
+ if (value_len + sizeof(mt_info) > length) {
+ zlog_warn("ISIS-TLV (%s): TLV 229 is truncated.", areatag);
+ pnt += length - value_len;
+ break;
+ }
+
+ memcpy(&mt_info, pnt, sizeof(mt_info));
+ pnt += sizeof(mt_info);
+ value_len += sizeof(mt_info);
+
+ mt_info = ntohs(mt_info);
+ info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
+ info->mtid = mt_info & ISIS_MT_MASK;
+ info->overload = mt_info & ISIS_MT_OL_MASK;
+ listnode_add(tlvs->mt_router_info, info);
+ }
+ }
+ else
+ {
+ pnt += length;
+ }
+ break;
default:
zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
areatag, type, length);
@@ -826,6 +864,31 @@ add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
}
int
+tlv_add_mt_router_info (struct list *mt_router_info, struct stream *stream)
+{
+ struct listnode *node;
+ struct mt_router_info *info;
+
+ uint16_t value[127];
+ uint16_t *pos = value;
+
+ for (ALL_LIST_ELEMENTS_RO(mt_router_info, node, info))
+ {
+ uint16_t mt_info;
+
+ mt_info = info->mtid;
+ if (info->overload)
+ mt_info |= ISIS_MT_OL_MASK;
+
+ *pos = htons(mt_info);
+ pos++;
+ }
+
+ return add_tlv(MT_ROUTER_INFORMATION, (pos - value) * sizeof(*pos),
+ (u_char*)value, stream);
+}
+
+int
tlv_add_area_addrs (struct list *area_addrs, struct stream *stream)
{
struct listnode *node;
diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h
index f899b9e9d..12025ff73 100644
--- a/isisd/isis_tlv.h
+++ b/isisd/isis_tlv.h
@@ -24,6 +24,8 @@
#ifndef _ZEBRA_ISIS_TLV_H
#define _ZEBRA_ISIS_TLV_H
+#include "isisd/isis_mt.h"
+
/*
* The list of TLVs we (should) support.
* ____________________________________________________________________________
@@ -109,6 +111,7 @@
#define TE_IPV4_REACHABILITY 135
#define DYNAMIC_HOSTNAME 137
#define GRACEFUL_RESTART 211
+#define MT_ROUTER_INFORMATION 229
#define IPV6_ADDR 232
#define IPV6_REACHABILITY 236
#define WAY3_HELLO 240
@@ -250,6 +253,12 @@ struct ipv6_reachability
#define CTRL_INFO_SUBTLVS 0x20
+struct mt_router_info
+{
+ ISIS_MT_INFO_FIELDS
+ bool overload;
+};
+
/*
* Pointer to each tlv type, filled by parse_tlvs()
*/
@@ -260,6 +269,7 @@ struct tlvs
struct nlpids *nlpids;
struct te_router_id *router_id;
struct list *area_addrs;
+ struct list *mt_router_info;
struct list *is_neighs;
struct list *te_is_neighs;
struct list *es_neighs;
@@ -301,6 +311,7 @@ struct tlvs
#define TLVFLAG_TE_ROUTER_ID (1<<19)
#define TLVFLAG_CHECKSUM (1<<20)
#define TLVFLAG_GRACEFUL_RESTART (1<<21)
+#define TLVFLAG_MT_ROUTER_INFORMATION (1<<22)
void init_tlvs (struct tlvs *tlvs, uint32_t expected);
void free_tlvs (struct tlvs *tlvs);
@@ -310,6 +321,7 @@ int parse_tlvs (char *areatag, u_char * stream, int size,
int add_tlv (u_char, u_char, u_char *, struct stream *);
void free_tlv (void *val);
+int tlv_add_mt_router_info (struct list *mt_router_info, struct stream *stream);
int tlv_add_area_addrs (struct list *area_addrs, struct stream *stream);
int tlv_add_is_neighs (struct list *is_neighs, struct stream *stream);
int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream);