diff options
author | Christian Franke <chris@opensourcerouting.org> | 2017-04-27 13:56:38 +0200 |
---|---|---|
committer | Christian Franke <chris@opensourcerouting.org> | 2017-04-28 12:03:23 +0200 |
commit | 99894f9a17b319ca80d4a667b13cbc1a87814d2d (patch) | |
tree | 2f896bb61aea2989d1a67b1884680d275529533a /isisd | |
parent | isisd: add MT configuration (diff) | |
download | frr-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.c | 37 | ||||
-rw-r--r-- | isisd/isis_mt.c | 95 | ||||
-rw-r--r-- | isisd/isis_mt.h | 8 | ||||
-rw-r--r-- | isisd/isis_pdu.c | 34 | ||||
-rw-r--r-- | isisd/isis_tlv.c | 63 | ||||
-rw-r--r-- | isisd/isis_tlv.h | 12 |
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); |