mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 04:26:12 +00:00
isisd: add support for Prefix-SID subtlv
Extend isisd's TLV parser to support the Prefix-SID subtlv as per draft-ietf-isis-segment-routing-extensions-19 Signed-off-by: Christian Franke <chris@opensourcerouting.org>
This commit is contained in:
parent
d4cff91a06
commit
bd507085e0
@ -107,6 +107,111 @@ static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX];
|
||||
/* Prototypes */
|
||||
static void append_item(struct isis_item_list *dest, struct isis_item *item);
|
||||
|
||||
/* Functions for Sub-TLV 3 SR Prefix-SID */
|
||||
|
||||
static struct isis_item *copy_item_prefix_sid(struct isis_item *i)
|
||||
{
|
||||
struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
|
||||
struct isis_prefix_sid *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
|
||||
|
||||
rv->flags = sid->flags;
|
||||
rv->algorithm = sid->algorithm;
|
||||
rv->value = sid->value;
|
||||
return (struct isis_item *)rv;
|
||||
}
|
||||
|
||||
static void format_item_prefix_sid(uint16_t mtid, struct isis_item *i,
|
||||
struct sbuf *buf, int indent)
|
||||
{
|
||||
struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
|
||||
|
||||
sbuf_push(buf, indent, "SR Prefix-SID:\n");
|
||||
sbuf_push(buf, indent, " Flags:%s%s%s%s%s%s\n",
|
||||
sid->flags & ISIS_PREFIX_SID_READVERTISED ? " READVERTISED" : "",
|
||||
sid->flags & ISIS_PREFIX_SID_NODE ? " NODE" : "",
|
||||
sid->flags & ISIS_PREFIX_SID_NO_PHP ? " NO_PHP" : "",
|
||||
sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL ? " EXPLICIT-NULL" : "",
|
||||
sid->flags & ISIS_PREFIX_SID_VALUE ? " VALUE" : "",
|
||||
sid->flags & ISIS_PREFIX_SID_LOCAL ? " LOCAL" : "");
|
||||
sbuf_push(buf, indent, " Algorithm: %" PRIu8 "\n", sid->algorithm);
|
||||
if (sid->flags & ISIS_PREFIX_SID_VALUE) {
|
||||
sbuf_push(buf, indent, "Label: %" PRIu32 "\n", sid->value);
|
||||
} else {
|
||||
sbuf_push(buf, indent, "Index: %" PRIu32 "\n", sid->value);
|
||||
}
|
||||
}
|
||||
|
||||
static void free_item_prefix_sid(struct isis_item *i)
|
||||
{
|
||||
XFREE(MTYPE_ISIS_SUBTLV, i);
|
||||
}
|
||||
|
||||
static int pack_item_prefix_sid(struct isis_item *i, struct stream *s)
|
||||
{
|
||||
struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
|
||||
|
||||
uint8_t size = (sid->flags & ISIS_PREFIX_SID_VALUE) ? 5 : 6;
|
||||
|
||||
if (STREAM_WRITEABLE(s) < size)
|
||||
return 1;
|
||||
|
||||
stream_putc(s, sid->flags);
|
||||
stream_putc(s, sid->algorithm);
|
||||
|
||||
if (sid->flags & ISIS_PREFIX_SID_VALUE) {
|
||||
stream_put3(s, sid->value);
|
||||
} else {
|
||||
stream_putl(s, sid->value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unpack_item_prefix_sid(uint16_t mtid, uint8_t len, struct stream *s,
|
||||
struct sbuf *log, void *dest, int indent)
|
||||
{
|
||||
struct isis_subtlvs *subtlvs = dest;
|
||||
struct isis_prefix_sid sid = {
|
||||
};
|
||||
|
||||
sbuf_push(log, indent, "Unpacking SR Prefix-SID...\n");
|
||||
|
||||
if (len < 5) {
|
||||
sbuf_push(log, indent,
|
||||
"Not enough data left. (expected 5 or more bytes, got %" PRIu8 ")\n",
|
||||
len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sid.flags = stream_getc(s);
|
||||
if ((sid.flags & ISIS_PREFIX_SID_VALUE)
|
||||
!= (sid.flags & ISIS_PREFIX_SID_LOCAL)) {
|
||||
sbuf_push(log, indent, "Flags inplausible: Local Flag needs to match Value Flag\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
sid.algorithm = stream_getc(s);
|
||||
|
||||
uint8_t expected_size = (sid.flags & ISIS_PREFIX_SID_VALUE) ? 5 : 6;
|
||||
if (len != expected_size) {
|
||||
sbuf_push(log, indent,
|
||||
"TLV size differs from expected size. "
|
||||
"(expected %u but got %" PRIu8 ")\n",
|
||||
expected_size, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sid.flags & ISIS_PREFIX_SID_VALUE) {
|
||||
sid.value = stream_get3(s);
|
||||
} else {
|
||||
sid.value = stream_getl(s);
|
||||
}
|
||||
|
||||
format_item_prefix_sid(mtid, (struct isis_item *)&sid, log, indent + 2);
|
||||
append_item(&subtlvs->prefix_sids, copy_item_prefix_sid((struct isis_item *)&sid));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Functions for Sub-TVL ??? IPv6 Source Prefix */
|
||||
|
||||
static struct prefix_ipv6 *copy_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p)
|
||||
@ -198,14 +303,36 @@ static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context,
|
||||
memcpy(subtlvs->source_prefix, &p, sizeof(p));
|
||||
return 0;
|
||||
}
|
||||
static void init_item_list(struct isis_item_list *items);
|
||||
static struct isis_item *copy_item(enum isis_tlv_context context,
|
||||
enum isis_tlv_type type,
|
||||
struct isis_item *item);
|
||||
static void copy_items(enum isis_tlv_context context, enum isis_tlv_type type,
|
||||
struct isis_item_list *src, struct isis_item_list *dest);
|
||||
static void format_items_(uint16_t mtid, enum isis_tlv_context context,
|
||||
enum isis_tlv_type type, struct isis_item_list *items,
|
||||
struct sbuf *buf, int indent);
|
||||
#define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
|
||||
static void free_items(enum isis_tlv_context context, enum isis_tlv_type type,
|
||||
struct isis_item_list *items);
|
||||
static int pack_items_(uint16_t mtid, enum isis_tlv_context context,
|
||||
enum isis_tlv_type type, struct isis_item_list *items,
|
||||
struct stream *s, struct isis_tlvs **fragment_tlvs,
|
||||
struct pack_order_entry *pe,
|
||||
struct isis_tlvs *(*new_fragment)(struct list *l),
|
||||
struct list *new_fragment_arg);
|
||||
#define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
|
||||
|
||||
/* Functions related to subtlvs */
|
||||
|
||||
static struct isis_subtlvs *isis_alloc_subtlvs(void)
|
||||
static struct isis_subtlvs *isis_alloc_subtlvs(enum isis_tlv_context context)
|
||||
{
|
||||
struct isis_subtlvs *result;
|
||||
|
||||
result = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*result));
|
||||
result->context = context;
|
||||
|
||||
init_item_list(&result->prefix_sids);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -217,6 +344,11 @@ static struct isis_subtlvs *copy_subtlvs(struct isis_subtlvs *subtlvs)
|
||||
|
||||
struct isis_subtlvs *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
|
||||
|
||||
rv->context = subtlvs->context;
|
||||
|
||||
copy_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
|
||||
&subtlvs->prefix_sids, &rv->prefix_sids);
|
||||
|
||||
rv->source_prefix =
|
||||
copy_subtlv_ipv6_source_prefix(subtlvs->source_prefix);
|
||||
return rv;
|
||||
@ -225,6 +357,9 @@ static struct isis_subtlvs *copy_subtlvs(struct isis_subtlvs *subtlvs)
|
||||
static void format_subtlvs(struct isis_subtlvs *subtlvs, struct sbuf *buf,
|
||||
int indent)
|
||||
{
|
||||
format_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
|
||||
&subtlvs->prefix_sids, buf, indent);
|
||||
|
||||
format_subtlv_ipv6_source_prefix(subtlvs->source_prefix, buf, indent);
|
||||
}
|
||||
|
||||
@ -233,6 +368,9 @@ static void isis_free_subtlvs(struct isis_subtlvs *subtlvs)
|
||||
if (!subtlvs)
|
||||
return;
|
||||
|
||||
free_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
|
||||
&subtlvs->prefix_sids);
|
||||
|
||||
XFREE(MTYPE_ISIS_SUBTLV, subtlvs->source_prefix);
|
||||
|
||||
XFREE(MTYPE_ISIS_SUBTLV, subtlvs);
|
||||
@ -248,6 +386,11 @@ static int pack_subtlvs(struct isis_subtlvs *subtlvs, struct stream *s)
|
||||
|
||||
stream_putc(s, 0); /* Put 0 as subtlvs length, filled in later */
|
||||
|
||||
rv = pack_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
|
||||
&subtlvs->prefix_sids, s, NULL, NULL, NULL, NULL);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv = pack_subtlv_ipv6_source_prefix(subtlvs->source_prefix, s);
|
||||
if (rv)
|
||||
return rv;
|
||||
@ -1135,6 +1278,7 @@ static void free_item_extended_ip_reach(struct isis_item *i)
|
||||
{
|
||||
struct isis_extended_ip_reach *item =
|
||||
(struct isis_extended_ip_reach *)i;
|
||||
isis_free_subtlvs(item->subtlvs);
|
||||
XFREE(MTYPE_ISIS_TLV, item);
|
||||
}
|
||||
|
||||
@ -1149,11 +1293,16 @@ static int pack_item_extended_ip_reach(struct isis_item *i, struct stream *s)
|
||||
|
||||
control = r->down ? ISIS_EXTENDED_IP_REACH_DOWN : 0;
|
||||
control |= r->prefix.prefixlen;
|
||||
control |= r->subtlvs ? ISIS_EXTENDED_IP_REACH_SUBTLV : 0;
|
||||
|
||||
stream_putc(s, control);
|
||||
|
||||
if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen))
|
||||
return 1;
|
||||
stream_put(s, &r->prefix.prefix.s_addr, PSIZE(r->prefix.prefixlen));
|
||||
|
||||
if (r->subtlvs)
|
||||
return pack_subtlvs(r->subtlvs, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1235,9 +1384,12 @@ static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len,
|
||||
len - 6 - PSIZE(rv->prefix.prefixlen));
|
||||
goto out;
|
||||
}
|
||||
sbuf_push(log, indent, "Skipping %" PRIu8 " bytes of subvls",
|
||||
subtlv_len);
|
||||
stream_forward_getp(s, subtlv_len);
|
||||
|
||||
rv->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH);
|
||||
if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH, subtlv_len, s,
|
||||
log, rv->subtlvs, indent + 4)) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
append_item(items, (struct isis_item *)rv);
|
||||
@ -1712,7 +1864,7 @@ static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s,
|
||||
goto out;
|
||||
}
|
||||
|
||||
rv->subtlvs = isis_alloc_subtlvs();
|
||||
rv->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH);
|
||||
if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH, subtlv_len, s,
|
||||
log, rv->subtlvs, indent + 4)) {
|
||||
goto out;
|
||||
@ -1890,7 +2042,6 @@ static void format_items_(uint16_t mtid, enum isis_tlv_context context,
|
||||
for (i = items->head; i; i = i->next)
|
||||
format_item(mtid, context, type, i, buf, indent);
|
||||
}
|
||||
#define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
|
||||
|
||||
static void free_item(enum isis_tlv_context tlv_context,
|
||||
enum isis_tlv_type tlv_type, struct isis_item *item)
|
||||
@ -1996,6 +2147,14 @@ top:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Multiple prefix-sids don't go into one TLV, so always break */
|
||||
if (type == ISIS_SUBTLV_PREFIX_SID
|
||||
&& (context == ISIS_CONTEXT_SUBTLV_IP_REACH
|
||||
|| context == ISIS_CONTEXT_SUBTLV_IPV6_REACH)) {
|
||||
item = item->next;
|
||||
break;
|
||||
}
|
||||
|
||||
if (len > 255) {
|
||||
if (!last_len) /* strange, not a single item fit */
|
||||
return 1;
|
||||
@ -2800,6 +2959,9 @@ int isis_unpack_tlvs(size_t avail_len, struct stream *stream,
|
||||
.name = _desc_, .unpack = unpack_subtlv_##_name_, \
|
||||
}
|
||||
|
||||
#define ITEM_SUBTLV_OPS(_name_, _desc_) \
|
||||
ITEM_TLV_OPS(_name_, _desc_)
|
||||
|
||||
ITEM_TLV_OPS(area_address, "TLV 1 Area Addresses");
|
||||
ITEM_TLV_OPS(oldstyle_reach, "TLV 2 IS Reachability");
|
||||
ITEM_TLV_OPS(lan_neighbor, "TLV 6 LAN Neighbors");
|
||||
@ -2818,6 +2980,7 @@ TLV_OPS(threeway_adj, "TLV 240 P2P Three-Way Adjacency");
|
||||
ITEM_TLV_OPS(ipv6_address, "TLV 232 IPv6 Interface Address");
|
||||
ITEM_TLV_OPS(ipv6_reach, "TLV 236 IPv6 Reachability");
|
||||
|
||||
ITEM_SUBTLV_OPS(prefix_sid, "Sub-TLV 3 SR Prefix-SID");
|
||||
SUBTLV_OPS(ipv6_source_prefix, "Sub-TLV 22 IPv6 Source Prefix");
|
||||
|
||||
static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = {
|
||||
@ -2845,8 +3008,11 @@ static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = {
|
||||
[ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops,
|
||||
},
|
||||
[ISIS_CONTEXT_SUBTLV_NE_REACH] = {},
|
||||
[ISIS_CONTEXT_SUBTLV_IP_REACH] = {},
|
||||
[ISIS_CONTEXT_SUBTLV_IP_REACH] = {
|
||||
[ISIS_SUBTLV_PREFIX_SID] = &tlv_prefix_sid_ops,
|
||||
},
|
||||
[ISIS_CONTEXT_SUBTLV_IPV6_REACH] = {
|
||||
[ISIS_SUBTLV_PREFIX_SID] = &tlv_prefix_sid_ops,
|
||||
[ISIS_SUBTLV_IPV6_SOURCE_PREFIX] = &subtlv_ipv6_source_prefix_ops,
|
||||
}
|
||||
};
|
||||
@ -3318,7 +3484,7 @@ void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid,
|
||||
mtid);
|
||||
|
||||
struct isis_ipv6_reach *r = (struct isis_ipv6_reach*)last_item(l);
|
||||
r->subtlvs = isis_alloc_subtlvs();
|
||||
r->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH);
|
||||
r->subtlvs->source_prefix = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*src));
|
||||
memcpy(r->subtlvs->source_prefix, src, sizeof(*src));
|
||||
}
|
||||
|
@ -83,6 +83,8 @@ struct isis_extended_ip_reach {
|
||||
uint32_t metric;
|
||||
bool down;
|
||||
struct prefix_ipv4 prefix;
|
||||
|
||||
struct isis_subtlvs *subtlvs;
|
||||
};
|
||||
|
||||
struct isis_ipv6_reach;
|
||||
@ -219,9 +221,21 @@ struct isis_tlvs {
|
||||
struct isis_spine_leaf *spine_leaf;
|
||||
};
|
||||
|
||||
struct isis_subtlvs {
|
||||
/* draft-baker-ipv6-isis-dst-src-routing-06 */
|
||||
struct prefix_ipv6 *source_prefix;
|
||||
#define ISIS_PREFIX_SID_READVERTISED 0x80
|
||||
#define ISIS_PREFIX_SID_NODE 0x40
|
||||
#define ISIS_PREFIX_SID_NO_PHP 0x20
|
||||
#define ISIS_PREFIX_SID_EXPLICIT_NULL 0x10
|
||||
#define ISIS_PREFIX_SID_VALUE 0x08
|
||||
#define ISIS_PREFIX_SID_LOCAL 0x04
|
||||
|
||||
struct isis_prefix_sid;
|
||||
struct isis_prefix_sid {
|
||||
struct isis_prefix_sid *next;
|
||||
|
||||
uint8_t flags;
|
||||
uint8_t algorithm;
|
||||
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
enum isis_tlv_context {
|
||||
@ -232,6 +246,15 @@ enum isis_tlv_context {
|
||||
ISIS_CONTEXT_MAX
|
||||
};
|
||||
|
||||
struct isis_subtlvs {
|
||||
enum isis_tlv_context context;
|
||||
|
||||
/* draft-baker-ipv6-isis-dst-src-routing-06 */
|
||||
struct prefix_ipv6 *source_prefix;
|
||||
/* draft-ietf-isis-segment-routing-extensions-16 */
|
||||
struct isis_item_list prefix_sids;
|
||||
};
|
||||
|
||||
enum isis_tlv_type {
|
||||
ISIS_TLV_AREA_ADDRESSES = 1,
|
||||
ISIS_TLV_OLDSTYLE_REACH = 2,
|
||||
@ -258,6 +281,7 @@ enum isis_tlv_type {
|
||||
ISIS_TLV_THREE_WAY_ADJ = 240,
|
||||
ISIS_TLV_MAX = 256,
|
||||
|
||||
ISIS_SUBTLV_PREFIX_SID = 3,
|
||||
ISIS_SUBTLV_IPV6_SOURCE_PREFIX = 22
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user