isisd: Add unpack function for SRv6 Locator TLV

Add a function to unpack an SRv6 Locator TLV and all its Sub-TLVs
(RFC 9352 section #7.1).

Signed-off-by: Carmine Scarpitta <carmine.scarpitta@uniroma2.it>
This commit is contained in:
Carmine Scarpitta 2023-02-14 12:22:29 +01:00
parent b2f0b7d0b0
commit 0225f908e8

View File

@ -5625,6 +5625,103 @@ static int pack_item_srv6_locator(struct isis_item *i, struct stream *s,
return 0;
}
static int unpack_item_srv6_locator(uint16_t mtid, uint8_t len,
struct stream *s, struct sbuf *log,
void *dest, int indent)
{
struct isis_tlvs *tlvs = dest;
struct isis_srv6_locator_tlv *rv = NULL;
size_t consume;
uint8_t subtlv_len;
struct isis_item_list *items;
items = isis_get_mt_items(&tlvs->srv6_locator, mtid);
sbuf_push(log, indent, "Unpacking SRv6 Locator...\n");
consume = 7;
if (len < consume) {
sbuf_push(
log, indent,
"Not enough data left. (expected 7 or more bytes, got %hhu)\n",
len);
goto out;
}
rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
rv->metric = stream_getl(s);
rv->flags = stream_getc(s);
rv->algorithm = stream_getc(s);
rv->prefix.family = AF_INET6;
rv->prefix.prefixlen = stream_getc(s);
if (rv->prefix.prefixlen > IPV6_MAX_BITLEN) {
sbuf_push(log, indent, "Loc Size %u is implausible for SRv6\n",
rv->prefix.prefixlen);
goto out;
}
consume += PSIZE(rv->prefix.prefixlen);
if (len < consume) {
sbuf_push(
log, indent,
"Expected %u bytes of prefix, but only %u bytes available.\n",
PSIZE(rv->prefix.prefixlen), len - 7);
goto out;
}
stream_get(&rv->prefix.prefix.s6_addr, s, PSIZE(rv->prefix.prefixlen));
struct in6_addr orig_locator = rv->prefix.prefix;
apply_mask_ipv6(&rv->prefix);
if (memcmp(&orig_locator, &rv->prefix.prefix, sizeof(orig_locator)))
sbuf_push(log, indent + 2,
"WARNING: SRv6 Locator had hostbits set.\n");
format_item_srv6_locator(mtid, (struct isis_item *)rv, log, NULL,
indent + 2);
consume += 1;
if (len < consume) {
sbuf_push(
log, indent,
"Expected 1 byte of subtlv len, but no more data persent.\n");
goto out;
}
subtlv_len = stream_getc(s);
if (subtlv_len) {
consume += subtlv_len;
if (len < consume) {
sbuf_push(
log, indent,
"Expected %hhu bytes of subtlvs, but only %u bytes available.\n",
subtlv_len,
len - 7 - PSIZE(rv->prefix.prefixlen));
goto out;
}
rv->subtlvs =
isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_SRV6_LOCATOR);
bool unpacked_known_tlvs = false;
if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_SRV6_LOCATOR, subtlv_len, s,
log, rv->subtlvs, indent + 4,
&unpacked_known_tlvs)) {
goto out;
}
if (!unpacked_known_tlvs) {
isis_free_subtlvs(rv->subtlvs);
rv->subtlvs = NULL;
}
}
append_item(items, (struct isis_item *)rv);
return 0;
out:
if (rv)
free_item_srv6_locator((struct isis_item *)rv);
return 1;
}
/* Functions related to tlvs in general */
struct isis_tlvs *isis_alloc_tlvs(void)