]> git.puffer.fish Git - mirror/frr.git/commitdiff
isisd: Add unpack function for SRv6 Locator TLV
authorCarmine Scarpitta <carmine.scarpitta@uniroma2.it>
Tue, 14 Feb 2023 11:22:29 +0000 (12:22 +0100)
committerCarmine Scarpitta <carmine.scarpitta@uniroma2.it>
Mon, 11 Sep 2023 15:35:13 +0000 (17:35 +0200)
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>
isisd/isis_tlvs.c

index b0ec3d2d6473574d1cba7ef5596f2e41cb617c8d..c09a7b2615df6d4e2deddc3ecdb4d1d9e57406b0 100644 (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)