fabricd: Add support for TLV 150 (Spine-Leaf-Extension)

To flood the tier calculated by the fabric locality detection,
OpenFabric makes use of TLV 150, defined in
draft-shen-isis-spine-leaf-ext-06, so add support for that TLV.

Signed-off-by: Christian Franke <chris@opensourcerouting.org>
This commit is contained in:
Christian Franke 2018-04-06 13:49:38 +02:00
parent cbd8e49e3e
commit 41a145f18d
2 changed files with 170 additions and 0 deletions

View File

@ -1329,6 +1329,126 @@ static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context,
return 0;
}
/* Functions related to TLV 150 Spine-Leaf-Extension */
static struct isis_spine_leaf *copy_tlv_spine_leaf(
const struct isis_spine_leaf *spine_leaf)
{
if (!spine_leaf)
return NULL;
struct isis_spine_leaf *rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
memcpy(rv, spine_leaf, sizeof(*rv));
return rv;
}
static void format_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf,
struct sbuf *buf, int indent)
{
if (!spine_leaf)
return;
sbuf_push(buf, indent, "Spine-Leaf-Extension:\n");
if (spine_leaf->has_tier) {
if (spine_leaf->tier == ISIS_TIER_UNDEFINED) {
sbuf_push(buf, indent, " Tier: undefined\n");
} else {
sbuf_push(buf, indent, " Tier: %" PRIu8 "\n",
spine_leaf->tier);
}
}
sbuf_push(buf, indent, " Flags:%s%s%s\n",
spine_leaf->is_leaf ? " LEAF" : "",
spine_leaf->is_spine ? " SPINE" : "",
spine_leaf->is_backup ? " BACKUP" : "");
}
static void free_tlv_spine_leaf(struct isis_spine_leaf *spine_leaf)
{
XFREE(MTYPE_ISIS_TLV, spine_leaf);
}
#define ISIS_SPINE_LEAF_FLAG_TIER 0x08
#define ISIS_SPINE_LEAF_FLAG_BACKUP 0x04
#define ISIS_SPINE_LEAF_FLAG_SPINE 0x02
#define ISIS_SPINE_LEAF_FLAG_LEAF 0x01
static int pack_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf,
struct stream *s)
{
if (!spine_leaf)
return 0;
uint8_t tlv_len = 2;
if (STREAM_WRITEABLE(s) < (unsigned)(2 + tlv_len))
return 1;
stream_putc(s, ISIS_TLV_SPINE_LEAF_EXT);
stream_putc(s, tlv_len);
uint16_t spine_leaf_flags = 0;
if (spine_leaf->has_tier) {
spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_TIER;
spine_leaf_flags |= spine_leaf->tier << 12;
}
if (spine_leaf->is_leaf)
spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_LEAF;
if (spine_leaf->is_spine)
spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_SPINE;
if (spine_leaf->is_backup)
spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_BACKUP;
stream_putw(s, spine_leaf_flags);
return 0;
}
static int unpack_tlv_spine_leaf(enum isis_tlv_context context,
uint8_t tlv_type, uint8_t tlv_len,
struct stream *s, struct sbuf *log,
void *dest, int indent)
{
struct isis_tlvs *tlvs = dest;
sbuf_push(log, indent, "Unpacking Spine Leaf Extension TLV...\n");
if (tlv_len < 2) {
sbuf_push(log, indent, "WARNING: Unexepected TLV size\n");
stream_forward_getp(s, tlv_len);
return 0;
}
if (tlvs->spine_leaf) {
sbuf_push(log, indent,
"WARNING: Spine Leaf Extension TLV present multiple times.\n");
stream_forward_getp(s, tlv_len);
return 0;
}
tlvs->spine_leaf = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->spine_leaf));
uint16_t spine_leaf_flags = stream_getw(s);
if (spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_TIER) {
tlvs->spine_leaf->has_tier = true;
tlvs->spine_leaf->tier = spine_leaf_flags >> 12;
}
tlvs->spine_leaf->is_leaf = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_LEAF;
tlvs->spine_leaf->is_spine = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_SPINE;
tlvs->spine_leaf->is_backup = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_BACKUP;
stream_forward_getp(s, tlv_len - 2);
return 0;
}
/* Functions related to TLV 240 P2P Three-Way Adjacency */
const char *isis_threeway_state_name(enum isis_threeway_state state)
@ -2187,6 +2307,8 @@ struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs)
rv->threeway_adj = copy_tlv_threeway_adj(tlvs->threeway_adj);
rv->spine_leaf = copy_tlv_spine_leaf(tlvs->spine_leaf);
return rv;
}
@ -2250,6 +2372,8 @@ static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent)
&tlvs->mt_ipv6_reach, buf, indent);
format_tlv_threeway_adj(tlvs->threeway_adj, buf, indent);
format_tlv_spine_leaf(tlvs->spine_leaf, buf, indent);
}
const char *isis_format_tlvs(struct isis_tlvs *tlvs)
@ -2301,6 +2425,7 @@ void isis_free_tlvs(struct isis_tlvs *tlvs)
free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
&tlvs->mt_ipv6_reach);
free_tlv_threeway_adj(tlvs->threeway_adj);
free_tlv_spine_leaf(tlvs->spine_leaf);
XFREE(MTYPE_ISIS_TLV, tlvs);
}
@ -2480,6 +2605,14 @@ static int pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
copy_tlv_threeway_adj(tlvs->threeway_adj);
}
rv = pack_tlv_spine_leaf(tlvs->spine_leaf, stream);
if (rv)
return rv;
if (fragment_tlvs) {
fragment_tlvs->spine_leaf =
copy_tlv_spine_leaf(tlvs->spine_leaf);
}
for (size_t pack_idx = 0; pack_idx < array_size(pack_order);
pack_idx++) {
rv = handle_pack_entry(&pack_order[pack_idx], tlvs, stream,
@ -2679,6 +2812,7 @@ ITEM_TLV_OPS(ipv4_address, "TLV 132 IPv4 Interface Address");
TLV_OPS(te_router_id, "TLV 134 TE Router ID");
ITEM_TLV_OPS(extended_ip_reach, "TLV 135 Extended IP Reachability");
TLV_OPS(dynamic_hostname, "TLV 137 Dynamic Hostname");
TLV_OPS(spine_leaf, "TLV 150 Spine Leaf Extensions");
ITEM_TLV_OPS(mt_router_info, "TLV 229 MT Router Information");
TLV_OPS(threeway_adj, "TLV 240 P2P Three-Way Adjacency");
ITEM_TLV_OPS(ipv6_address, "TLV 232 IPv6 Interface Address");
@ -2703,6 +2837,7 @@ static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = {
[ISIS_TLV_EXTENDED_IP_REACH] = &tlv_extended_ip_reach_ops,
[ISIS_TLV_MT_IP_REACH] = &tlv_extended_ip_reach_ops,
[ISIS_TLV_DYNAMIC_HOSTNAME] = &tlv_dynamic_hostname_ops,
[ISIS_TLV_SPINE_LEAF_EXT] = &tlv_spine_leaf_ops,
[ISIS_TLV_MT_ROUTER_INFO] = &tlv_mt_router_info_ops,
[ISIS_TLV_THREE_WAY_ADJ] = &tlv_threeway_adj_ops,
[ISIS_TLV_IPV6_ADDRESS] = &tlv_ipv6_address_ops,
@ -3239,6 +3374,24 @@ void isis_tlvs_add_threeway_adj(struct isis_tlvs *tlvs,
}
}
void isis_tlvs_add_spine_leaf(struct isis_tlvs *tlvs, uint8_t tier,
bool has_tier, bool is_leaf, bool is_spine,
bool is_backup)
{
assert(!tlvs->spine_leaf);
tlvs->spine_leaf = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->spine_leaf));
if (has_tier) {
tlvs->spine_leaf->tier = tier;
}
tlvs->spine_leaf->has_tier = has_tier;
tlvs->spine_leaf->is_leaf = is_leaf;
tlvs->spine_leaf->is_spine = is_spine;
tlvs->spine_leaf->is_backup = is_backup;
}
struct isis_mt_router_info *
isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid)
{

View File

@ -103,6 +103,17 @@ struct isis_protocols_supported {
uint8_t *protocols;
};
#define ISIS_TIER_UNDEFINED 15
struct isis_spine_leaf {
uint8_t tier;
bool has_tier;
bool is_leaf;
bool is_spine;
bool is_backup;
};
enum isis_threeway_state {
ISIS_THREEWAY_DOWN = 2,
ISIS_THREEWAY_INITIALIZING = 1,
@ -205,6 +216,7 @@ struct isis_tlvs {
struct isis_item_list ipv6_reach;
struct isis_mt_item_list mt_ipv6_reach;
struct isis_threeway_adj *threeway_adj;
struct isis_spine_leaf *spine_leaf;
};
struct isis_subtlvs {
@ -236,6 +248,7 @@ enum isis_tlv_type {
ISIS_TLV_TE_ROUTER_ID = 134,
ISIS_TLV_EXTENDED_IP_REACH = 135,
ISIS_TLV_DYNAMIC_HOSTNAME = 137,
ISIS_TLV_SPINE_LEAF_EXT = 150,
ISIS_TLV_MT_REACH = 222,
ISIS_TLV_MT_ROUTER_INFO = 229,
ISIS_TLV_IPV6_ADDRESS = 232,
@ -331,6 +344,10 @@ void isis_tlvs_add_threeway_adj(struct isis_tlvs *tlvs,
const uint8_t *neighbor_id,
uint32_t neighbor_circuit_id);
void isis_tlvs_add_spine_leaf(struct isis_tlvs *tlvs, uint8_t tier,
bool has_tier, bool is_leaf, bool is_spine,
bool is_backup);
struct isis_mt_router_info *
isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid);
#endif