]> git.proxmox.com Git - mirror_frr.git/commitdiff
isisd: add isis flex-algo lsp advertisement
authorHiroki Shirokura <hiroki.shirokura@linecorp.com>
Tue, 4 Jan 2022 01:31:45 +0000 (01:31 +0000)
committerLouis Scalbert <louis.scalbert@6wind.com>
Tue, 18 Apr 2023 09:33:15 +0000 (11:33 +0200)
Deal with the packing and unpacking of following Flex-Algo
Sub-Sub-TLVs:

- Router Capability (already defined TLV 242)
- List of the Flex-Algo Definitions (Sub-TLV 26)
- Exclude admin group (Sub-Sub-TLV 1)
                - Include-any admin group (Sub-Sub-TLV 2)
                - Include-all admin group (Sub-Sub-TLV 3)
                - Flags (for prefix-metric) (Sub-Sub-TLV 4)

This commit splits data into multiple router capability TLVs if needed
because a TLV cannot contains more than 255 bytes.

Note that the list of SR Algorithm (Sub-TLV 19) within Router Capability
(TLV 242) is already set in a previous commit.

Signed-off-by: Hiroki Shirokura <hiroki.shirokura@linecorp.com>
Signed-off-by: Eric Kinzie <ekinzie@labn.net>
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
isisd/isis_lsp.c
isisd/isis_tlvs.c
isisd/isis_tlvs.h
tests/isisd/test_common.c

index 08fa845e8e558f46eee6ebccce0d44febb17dd04..c07083a06da0b5db7f9abac28b543106634b6e2a 100644 (file)
@@ -46,6 +46,7 @@
 #include "isisd/fabricd.h"
 #include "isisd/isis_tx_queue.h"
 #include "isisd/isis_nb.h"
+#include "isisd/isis_flex_algo.h"
 
 DEFINE_MTYPE_STATIC(ISISD, ISIS_LSP, "ISIS LSP");
 
@@ -898,9 +899,15 @@ static void lsp_build_internal_reach_ipv4(struct isis_lsp *lsp,
                          area->area_tag, ipv4);
 
                if (area->srdb.enabled)
-                       for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
+                       for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
+#ifndef FABRICD
+                               if (flex_algo_id_valid(i) &&
+                                   !isis_flex_algo_elected_supported(i, area))
+                                       continue;
+#endif /* ifndef FABRICD */
                                pcfgs[i] =
                                        isis_sr_cfg_prefix_find(area, ipv4, i);
+                       }
 
                isis_tlvs_add_extended_ip_reach(lsp->tlvs, ipv4, metric, false,
                                                pcfgs);
@@ -918,8 +925,14 @@ static void lsp_build_internal_reach_ipv6(struct isis_lsp *lsp,
                  area->area_tag, ipv6);
 
        if (area->srdb.enabled)
-               for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
+               for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
+#ifndef FABRICD
+                       if (flex_algo_id_valid(i) &&
+                           !isis_flex_algo_elected_supported(i, area))
+                               continue;
+#endif /* ifndef FABRICD */
                        pcfgs[i] = isis_sr_cfg_prefix_find(area, ipv6, i);
+               }
 
        isis_tlvs_add_ipv6_reach(lsp->tlvs, isis_area_ipv6_topology(area), ipv6,
                                 metric, false, pcfgs);
@@ -955,9 +968,16 @@ static void lsp_build_ext_reach_ipv4(struct isis_lsp *lsp,
                                NULL};
 
                        if (area->srdb.enabled)
-                               for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
+                               for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
+#ifndef FABRICD
+                                       if (flex_algo_id_valid(i) &&
+                                           !isis_flex_algo_elected_supported(
+                                                   i, area))
+                                               continue;
+#endif /* ifndef FABRICD */
                                        pcfgs[i] = isis_sr_cfg_prefix_find(
                                                area, ipv4, i);
+                               }
 
                        isis_tlvs_add_extended_ip_reach(lsp->tlvs, ipv4, metric,
                                                        true, pcfgs);
@@ -992,9 +1012,16 @@ static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp,
                                NULL};
 
                        if (area->srdb.enabled)
-                               for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
+                               for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
+#ifndef FABRICD
+                                       if (flex_algo_id_valid(i) &&
+                                           !isis_flex_algo_elected_supported(
+                                                   i, area))
+                                               continue;
+#endif /* ifndef FABRICD */
                                        pcfgs[i] = isis_sr_cfg_prefix_find(
                                                area, p, i);
+                               }
 
                        isis_tlvs_add_ipv6_reach(lsp->tlvs,
                                                 isis_area_ipv6_topology(area),
@@ -1115,13 +1142,30 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
 
        /* Add Router Capability TLV. */
        if (area->isis->router_id != 0) {
-               struct isis_router_cap cap = {};
+               struct isis_router_cap *rcap;
+#ifndef FABRICD
+               struct isis_router_cap_fad *rcap_fad;
+               struct listnode *node;
+               struct flex_algo *fa;
+#endif /* ifndef FABRICD */
 
-               /* init SR algo list content to the default value */
-               for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
-                       cap.algo[i] = SR_ALGORITHM_UNSET;
+               rcap = isis_tlvs_init_router_capability(lsp->tlvs);
 
-               cap.router_id.s_addr = area->isis->router_id;
+               rcap->router_id.s_addr = area->isis->router_id;
+
+#ifndef FABRICD
+               /* Set flex-algo definitions */
+               for (ALL_LIST_ELEMENTS_RO(area->flex_algos->flex_algos, node,
+                                         fa)) {
+                       if (!fa->advertise_definition)
+                               continue;
+                       lsp_debug("ISIS (%s):   Flex-Algo Definition %u",
+                                 area->area_tag, fa->algorithm);
+                       isis_tlvs_set_router_capability_fad(lsp->tlvs, fa,
+                                                           fa->algorithm,
+                                                           area->isis->sysid);
+               }
+#endif /* ifndef FABRICD */
 
                /* Add SR Sub-TLVs if SR is enabled. */
                if (area->srdb.enabled) {
@@ -1131,26 +1175,38 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                        /* SRGB first */
                        range_size = srdb->config.srgb_upper_bound
                                     - srdb->config.srgb_lower_bound + 1;
-                       cap.srgb.flags = ISIS_SUBTLV_SRGB_FLAG_I
-                                        | ISIS_SUBTLV_SRGB_FLAG_V;
-                       cap.srgb.range_size = range_size;
-                       cap.srgb.lower_bound = srdb->config.srgb_lower_bound;
+                       rcap->srgb.flags = ISIS_SUBTLV_SRGB_FLAG_I |
+                                          ISIS_SUBTLV_SRGB_FLAG_V;
+                       rcap->srgb.range_size = range_size;
+                       rcap->srgb.lower_bound = srdb->config.srgb_lower_bound;
                        /* Then Algorithm */
-                       cap.algo[0] = SR_ALGORITHM_SPF;
-                       cap.algo[1] = SR_ALGORITHM_UNSET;
+                       rcap->algo[0] = SR_ALGORITHM_SPF;
+                       rcap->algo[1] = SR_ALGORITHM_UNSET;
+#ifndef FABRICD
+                       for (ALL_LIST_ELEMENTS_RO(area->flex_algos->flex_algos,
+                                                 node, fa)) {
+                               if (fa->advertise_definition)
+                                       rcap_fad = rcap->fads[fa->algorithm];
+                               else
+                                       rcap_fad = NULL;
+
+                               if (!isis_flex_algo_elected_supported_local_fad(
+                                           fa->algorithm, area, &rcap_fad))
+                                       continue;
+                               lsp_debug("ISIS (%s):   SR Algorithm %u",
+                                         area->area_tag, fa->algorithm);
+                               rcap->algo[fa->algorithm] = fa->algorithm;
+                       }
+#endif /* ifndef FABRICD */
                        /* SRLB */
-                       cap.srlb.flags = 0;
+                       rcap->srlb.flags = 0;
                        range_size = srdb->config.srlb_upper_bound
                                     - srdb->config.srlb_lower_bound + 1;
-                       cap.srlb.range_size = range_size;
-                       cap.srlb.lower_bound = srdb->config.srlb_lower_bound;
+                       rcap->srlb.range_size = range_size;
+                       rcap->srlb.lower_bound = srdb->config.srlb_lower_bound;
                        /* And finally MSD */
-                       cap.msd = srdb->config.msd;
+                       rcap->msd = srdb->config.msd;
                }
-
-               isis_tlvs_set_router_capability(lsp->tlvs, &cap);
-               lsp_debug("ISIS (%s): Adding Router Capabilities information",
-                         area->area_tag);
        }
 
        /* IPv4 address and TE router ID TLVs.
index 368973dfd9f4d6c0e6faf86974959bf910019e67..4ad877ce0f19054c4ad91606a61f82d3e8a94ae7 100644 (file)
@@ -29,6 +29,7 @@
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_te.h"
 #include "isisd/isis_sr.h"
+#include "isisd/isis_flex_algo.h"
 
 #define TLV_SIZE_MISMATCH(log, indent, target)                                 \
        sbuf_push(log, indent,                                                 \
@@ -36,6 +37,7 @@
 
 DEFINE_MTYPE_STATIC(ISISD, ISIS_TLV, "ISIS TLVs");
 DEFINE_MTYPE(ISISD, ISIS_SUBTLV, "ISIS Sub-TLVs");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_SUBSUBTLV, "ISIS Sub-Sub-TLVs");
 DEFINE_MTYPE_STATIC(ISISD, ISIS_MT_ITEM_LIST, "ISIS MT Item Lists");
 
 typedef int (*unpack_tlv_func)(enum isis_tlv_context context, uint8_t tlv_type,
@@ -381,7 +383,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
                                   exts->adm_group);
                        json_object_string_add(json, "adm-group", aux_buf);
                } else {
-                       sbuf_push(buf, indent, "Administrative Group: 0x%x\n",
+                       sbuf_push(buf, indent, "Admin Group: 0x%08x\n",
                                  exts->adm_group);
                        sbuf_push(buf, indent + 2, "Bit positions: %s\n",
                                  admin_group_standard_print(
@@ -3912,6 +3914,39 @@ static struct isis_router_cap *copy_tlv_router_cap(
 
        memcpy(rv, router_cap, sizeof(*rv));
 
+#ifndef FABRICD
+       for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
+               struct isis_router_cap_fad *sc_fad;
+               struct isis_router_cap_fad *rv_fad;
+
+               sc_fad = router_cap->fads[i];
+               if (!sc_fad)
+                       continue;
+               rv_fad = XMALLOC(MTYPE_ISIS_TLV,
+                                sizeof(struct isis_router_cap_fad));
+               *rv_fad = *sc_fad;
+               rv_fad->fad.admin_group_exclude_any.bitmap.data = NULL;
+               rv_fad->fad.admin_group_include_any.bitmap.data = NULL;
+               rv_fad->fad.admin_group_include_all.bitmap.data = NULL;
+
+               assert(bf_is_inited(
+                       sc_fad->fad.admin_group_exclude_any.bitmap));
+               assert(bf_is_inited(
+                       sc_fad->fad.admin_group_include_any.bitmap));
+               assert(bf_is_inited(
+                       sc_fad->fad.admin_group_include_all.bitmap));
+
+               admin_group_copy(&rv_fad->fad.admin_group_exclude_any,
+                                &sc_fad->fad.admin_group_exclude_any);
+               admin_group_copy(&rv_fad->fad.admin_group_include_any,
+                                &sc_fad->fad.admin_group_include_any);
+               admin_group_copy(&rv_fad->fad.admin_group_include_all,
+                                &sc_fad->fad.admin_group_include_all);
+
+               rv->fads[i] = rv_fad;
+       }
+#endif /* ifndef FABRICD */
+
        return rv;
 }
 
@@ -4031,37 +4066,178 @@ static void format_tlv_router_cap(const struct isis_router_cap *router_cap,
        if (router_cap->msd != 0)
                sbuf_push(buf, indent, "  Node Maximum SID Depth: %u\n",
                          router_cap->msd);
+
+#ifndef FABRICD
+       /* Flex-Algo */
+       for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
+               char admin_group_buf[ADMIN_GROUP_PRINT_MAX_SIZE];
+               int indent2;
+               struct admin_group *admin_group;
+               struct isis_router_cap_fad *fad;
+
+               fad = router_cap->fads[i];
+               if (!fad)
+                       continue;
+
+               sbuf_push(buf, indent, "  Flex-Algo Definition: %d\n",
+                         fad->fad.algorithm);
+               sbuf_push(buf, indent, "    Metric-Type: %d\n",
+                         fad->fad.metric_type);
+               sbuf_push(buf, indent, "    Calc-Type: %d\n",
+                         fad->fad.calc_type);
+               sbuf_push(buf, indent, "    Priority: %d\n", fad->fad.priority);
+
+               indent2 = indent + strlen("    Exclude-Any: ");
+               admin_group = &fad->fad.admin_group_exclude_any;
+               sbuf_push(buf, indent, "    Exclude-Any: ");
+               sbuf_push(buf, 0, "%s\n",
+                         admin_group_string(admin_group_buf,
+                                            ADMIN_GROUP_PRINT_MAX_SIZE,
+                                            indent2, admin_group));
+
+               indent2 = indent + strlen("    Include-Any: ");
+               admin_group = &fad->fad.admin_group_include_any;
+               sbuf_push(buf, indent, "    Include-Any: ");
+               sbuf_push(buf, 0, "%s\n",
+                         admin_group_string(admin_group_buf,
+                                            ADMIN_GROUP_PRINT_MAX_SIZE,
+                                            indent2, admin_group));
+
+               indent2 = indent + strlen("    Include-All: ");
+               admin_group = &fad->fad.admin_group_include_all;
+               sbuf_push(buf, indent, "    Include-All: ");
+               sbuf_push(buf, 0, "%s\n",
+                         admin_group_string(admin_group_buf,
+                                            ADMIN_GROUP_PRINT_MAX_SIZE,
+                                            indent2, admin_group));
+
+               sbuf_push(buf, indent, "    M-Flag: %c\n",
+                         CHECK_FLAG(fad->fad.flags, FAD_FLAG_M) ? '1' : '0');
+
+               if (fad->fad.flags != 0 && fad->fad.flags != FAD_FLAG_M)
+                       sbuf_push(buf, indent, "    Flags: 0x%x\n",
+                                 fad->fad.flags);
+               if (fad->fad.exclude_srlg)
+                       sbuf_push(buf, indent, "    Exclude SRLG: Enabled\n");
+               if (fad->fad.unsupported_subtlv)
+                       sbuf_push(buf, indent,
+                                 "    Got an unsupported sub-TLV: Yes\n");
+       }
+#endif /* ifndef FABRICD */
 }
 
 static void free_tlv_router_cap(struct isis_router_cap *router_cap)
 {
+       if (!router_cap)
+               return;
+
+#ifndef FABRICD
+       for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
+               struct isis_router_cap_fad *fad;
+
+               fad = router_cap->fads[i];
+               if (!fad)
+                       continue;
+               admin_group_term(&fad->fad.admin_group_exclude_any);
+               admin_group_term(&fad->fad.admin_group_include_any);
+               admin_group_term(&fad->fad.admin_group_include_all);
+               XFREE(MTYPE_ISIS_TLV, fad);
+       }
+#endif /* ifndef FABRICD */
+
        XFREE(MTYPE_ISIS_TLV, router_cap);
 }
 
+#ifndef FABRICD
+static size_t
+isis_router_cap_fad_sub_tlv_len(const struct isis_router_cap_fad *fad)
+{
+       size_t sz = ISIS_SUBTLV_FAD_MIN_SIZE;
+       uint32_t admin_group_length;
+
+       admin_group_length =
+               admin_group_nb_words(&fad->fad.admin_group_exclude_any);
+       if (admin_group_length)
+               sz += sizeof(uint32_t) * admin_group_length + 2;
+
+       admin_group_length =
+               admin_group_nb_words(&fad->fad.admin_group_include_any);
+       if (admin_group_length)
+               sz += sizeof(uint32_t) * admin_group_length + 2;
+
+       admin_group_length =
+               admin_group_nb_words(&fad->fad.admin_group_include_all);
+       if (admin_group_length)
+               sz += sizeof(uint32_t) * admin_group_length + 2;
+
+       if (fad->fad.flags != 0)
+               sz += ISIS_SUBTLV_FAD_SUBSUBTLV_FLAGS_SIZE + 2;
+
+       /* TODO: add exclude SRLG sub-sub-TLV length when supported */
+
+       return sz;
+}
+#endif /* ifndef FABRICD */
+
+static size_t isis_router_cap_tlv_size(const struct isis_router_cap *router_cap)
+{
+       size_t sz = 2 + ISIS_ROUTER_CAP_SIZE;
+#ifndef FABRICD
+       size_t fad_sz;
+#endif /* ifndef FABRICD */
+       int nb_algo;
+
+       if ((router_cap->srgb.range_size != 0) &&
+           (router_cap->srgb.lower_bound != 0)) {
+               sz += 2 + ISIS_SUBTLV_SID_LABEL_RANGE_SIZE;
+               sz += 2 + ISIS_SUBTLV_SID_LABEL_SIZE;
+
+               nb_algo = isis_tlvs_sr_algo_count(router_cap);
+               if (nb_algo != 0)
+                       sz += 2 + nb_algo;
+
+               if ((router_cap->srlb.range_size != 0) &&
+                   (router_cap->srlb.lower_bound != 0)) {
+                       sz += 2 + ISIS_SUBTLV_SID_LABEL_RANGE_SIZE;
+                       sz += 2 + ISIS_SUBTLV_SID_LABEL_SIZE;
+               }
+
+               if (router_cap->msd != 0)
+                       sz += 2 + ISIS_SUBTLV_NODE_MSD_SIZE;
+       }
+
+#ifndef FABRICD
+       for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
+               if (!router_cap->fads[i])
+                       continue;
+               fad_sz = 2 +
+                        isis_router_cap_fad_sub_tlv_len(router_cap->fads[i]);
+               if (((sz + fad_sz) % 256) < (sz % 256))
+                       sz += 2 + ISIS_ROUTER_CAP_SIZE + fad_sz;
+               else
+                       sz += fad_sz;
+       }
+#endif /* ifndef FABRICD */
+
+       return sz;
+}
+
 static int pack_tlv_router_cap(const struct isis_router_cap *router_cap,
                               struct stream *s)
 {
-       size_t tlv_len = ISIS_ROUTER_CAP_SIZE;
-       size_t len_pos;
+       size_t tlv_len, len_pos;
        uint8_t nb_algo;
 
        if (!router_cap)
                return 0;
 
-       /* Compute Maximum TLV size */
-       tlv_len += ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
-               + ISIS_SUBTLV_HDR_SIZE
-               + ISIS_SUBTLV_ALGORITHM_SIZE
-               + ISIS_SUBTLV_NODE_MSD_SIZE;
-
-       if (STREAM_WRITEABLE(s) < (unsigned int)(2 + tlv_len))
+       if (STREAM_WRITEABLE(s) < isis_router_cap_tlv_size(router_cap))
                return 1;
 
        /* Add Router Capability TLV 242 with Router ID and Flags */
        stream_putc(s, ISIS_TLV_ROUTER_CAPABILITY);
-       /* Real length will be adjusted later */
        len_pos = stream_get_endp(s);
-       stream_putc(s, tlv_len);
+       stream_putc(s, 0); /* Real length will be adjusted later */
        stream_put_ipv4(s, router_cap->router_id.s_addr);
        stream_putc(s, router_cap->flags);
 
@@ -4108,6 +4284,80 @@ static int pack_tlv_router_cap(const struct isis_router_cap *router_cap,
                }
        }
 
+#ifndef FABRICD
+       /* Flex Algo Definitions */
+       for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
+               struct isis_router_cap_fad *fad;
+               size_t subtlv_len;
+               struct admin_group *ag;
+               uint32_t admin_group_length;
+
+               fad = router_cap->fads[i];
+               if (!fad)
+                       continue;
+
+               subtlv_len = isis_router_cap_fad_sub_tlv_len(fad);
+
+               if ((stream_get_endp(s) - len_pos - 1) > 250) {
+                       /* Adjust TLV length which depends on subTLVs presence
+                        */
+                       tlv_len = stream_get_endp(s) - len_pos - 1;
+                       stream_putc_at(s, len_pos, tlv_len);
+
+                       /* Add Router Capability TLV 242 with Router ID and
+                        * Flags
+                        */
+                       stream_putc(s, ISIS_TLV_ROUTER_CAPABILITY);
+                       /* Real length will be adjusted later */
+                       len_pos = stream_get_endp(s);
+                       stream_putc(s, 0);
+                       stream_put_ipv4(s, router_cap->router_id.s_addr);
+                       stream_putc(s, router_cap->flags);
+               }
+
+               stream_putc(s, ISIS_SUBTLV_FAD);
+               stream_putc(s, subtlv_len); /* length will be filled later */
+
+               stream_putc(s, fad->fad.algorithm);
+               stream_putc(s, fad->fad.metric_type);
+               stream_putc(s, fad->fad.calc_type);
+               stream_putc(s, fad->fad.priority);
+
+               ag = &fad->fad.admin_group_exclude_any;
+               admin_group_length = admin_group_nb_words(ag);
+               if (admin_group_length) {
+                       stream_putc(s, ISIS_SUBTLV_FAD_SUBSUBTLV_EXCAG);
+                       stream_putc(s, sizeof(uint32_t) * admin_group_length);
+                       for (size_t i = 0; i < admin_group_length; i++)
+                               stream_putl(s, admin_group_get_offset(ag, i));
+               }
+
+               ag = &fad->fad.admin_group_include_any;
+               admin_group_length = admin_group_nb_words(ag);
+               if (admin_group_length) {
+                       stream_putc(s, ISIS_SUBTLV_FAD_SUBSUBTLV_INCANYAG);
+                       stream_putc(s, sizeof(uint32_t) * admin_group_length);
+                       for (size_t i = 0; i < admin_group_length; i++)
+                               stream_putl(s, admin_group_get_offset(ag, i));
+               }
+
+               ag = &fad->fad.admin_group_include_all;
+               admin_group_length = admin_group_nb_words(ag);
+               if (admin_group_length) {
+                       stream_putc(s, ISIS_SUBTLV_FAD_SUBSUBTLV_INCALLAG);
+                       stream_putc(s, sizeof(uint32_t) * admin_group_length);
+                       for (size_t i = 0; i < admin_group_length; i++)
+                               stream_putl(s, admin_group_get_offset(ag, i));
+               }
+
+               if (fad->fad.flags != 0) {
+                       stream_putc(s, ISIS_SUBTLV_FAD_SUBSUBTLV_FLAGS);
+                       stream_putc(s, ISIS_SUBTLV_FAD_SUBSUBTLV_FLAGS_SIZE);
+                       stream_putc(s, fad->fad.flags);
+               }
+       }
+#endif /* ifndef FABRICD */
+
        /* Adjust TLV length which depends on subTLVs presence */
        tlv_len = stream_get_endp(s) - len_pos - 1;
        stream_putc_at(s, len_pos, tlv_len);
@@ -4134,18 +4384,16 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context,
                return 0;
        }
 
-       if (tlvs->router_cap) {
-               sbuf_push(log, indent,
-                         "WARNING: Router Capability TLV present multiple times.\n");
-               stream_forward_getp(s, tlv_len);
-               return 0;
+       if (tlvs->router_cap)
+               /* Multiple Router Capability found */
+               rcap = tlvs->router_cap;
+       else {
+               /* Allocate router cap structure and initialize SR Algorithms */
+               rcap = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct isis_router_cap));
+               for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
+                       rcap->algo[i] = SR_ALGORITHM_UNSET;
        }
 
-       /* Allocate router cap structure and initialize SR Algorithms */
-       rcap = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct isis_router_cap));
-       for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
-               rcap->algo[i] = SR_ALGORITHM_UNSET;
-
        /* Get Router ID and Flags */
        rcap->router_id.s_addr = stream_get_ipv4(s);
        rcap->flags = stream_getc(s);
@@ -4153,6 +4401,10 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context,
        /* Parse remaining part of the TLV if present */
        subtlv_len = tlv_len - ISIS_ROUTER_CAP_SIZE;
        while (subtlv_len > 2) {
+#ifndef FABRICD
+               struct isis_router_cap_fad *fad;
+               uint8_t subsubtlvs_len;
+#endif /* ifndef FABRICD */
                uint8_t msd_type;
 
                type = stream_getc(s);
@@ -4306,6 +4558,80 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context,
                        if (length > MSD_TLV_SIZE)
                                stream_forward_getp(s, length - MSD_TLV_SIZE);
                        break;
+#ifndef FABRICD
+               case ISIS_SUBTLV_FAD:
+                       fad = XCALLOC(MTYPE_ISIS_TLV,
+                                     sizeof(struct isis_router_cap_fad));
+                       fad->fad.algorithm = stream_getc(s);
+                       fad->fad.metric_type = stream_getc(s);
+                       fad->fad.calc_type = stream_getc(s);
+                       fad->fad.priority = stream_getc(s);
+                       rcap->fads[fad->fad.algorithm] = fad;
+                       admin_group_init(&fad->fad.admin_group_exclude_any);
+                       admin_group_init(&fad->fad.admin_group_include_any);
+                       admin_group_init(&fad->fad.admin_group_include_all);
+
+                       subsubtlvs_len = length - 4;
+                       while (subsubtlvs_len > 2) {
+                               struct admin_group *ag;
+                               uint8_t subsubtlv_type;
+                               uint8_t subsubtlv_len;
+                               uint32_t v;
+                               int n_ag, i;
+
+                               subsubtlv_type = stream_getc(s);
+                               subsubtlv_len = stream_getc(s);
+
+                               switch (subsubtlv_type) {
+                               case ISIS_SUBTLV_FAD_SUBSUBTLV_EXCAG:
+                                       ag = &fad->fad.admin_group_exclude_any;
+                                       n_ag = subsubtlv_len / sizeof(uint32_t);
+                                       for (i = 0; i < n_ag; i++) {
+                                               v = stream_getl(s);
+                                               admin_group_bulk_set(ag, v, i);
+                                       }
+                                       break;
+                               case ISIS_SUBTLV_FAD_SUBSUBTLV_INCANYAG:
+                                       ag = &fad->fad.admin_group_include_any;
+                                       n_ag = subsubtlv_len / sizeof(uint32_t);
+                                       for (i = 0; i < n_ag; i++) {
+                                               v = stream_getl(s);
+                                               admin_group_bulk_set(ag, v, i);
+                                       }
+                                       break;
+                               case ISIS_SUBTLV_FAD_SUBSUBTLV_INCALLAG:
+                                       ag = &fad->fad.admin_group_include_all;
+                                       n_ag = subsubtlv_len / sizeof(uint32_t);
+                                       for (i = 0; i < n_ag; i++) {
+                                               v = stream_getl(s);
+                                               admin_group_bulk_set(ag, v, i);
+                                       }
+                                       break;
+                               case ISIS_SUBTLV_FAD_SUBSUBTLV_FLAGS:
+                                       if (subsubtlv_len == 0)
+                                               break;
+
+                                       fad->fad.flags = stream_getc(s);
+                                       for (i = subsubtlv_len - 1; i > 0; --i)
+                                               stream_getc(s);
+                                       break;
+                               case ISIS_SUBTLV_FAD_SUBSUBTLV_ESRLG:
+                                       fad->fad.exclude_srlg = true;
+                                       stream_forward_getp(s, subsubtlv_len);
+                                       break;
+                               default:
+                                       sbuf_push(
+                                               log, indent,
+                                               "Received an unsupported Flex-Algo sub-TLV type %u\n",
+                                               subsubtlv_type);
+                                       fad->fad.unsupported_subtlv = true;
+                                       stream_forward_getp(s, subsubtlv_len);
+                                       break;
+                               }
+                               subsubtlvs_len -= 2 + subsubtlv_len;
+                       }
+                       break;
+#endif /* ifndef FABRICD */
                default:
                        stream_forward_getp(s, length);
                        break;
@@ -6253,17 +6579,52 @@ void isis_tlvs_set_dynamic_hostname(struct isis_tlvs *tlvs,
                tlvs->hostname = XSTRDUP(MTYPE_ISIS_TLV, hostname);
 }
 
-/* Set Router Capability TLV parameters */
-void isis_tlvs_set_router_capability(struct isis_tlvs *tlvs,
-                                    const struct isis_router_cap *cap)
+/* Init Router Capability TLV parameters */
+struct isis_router_cap *isis_tlvs_init_router_capability(struct isis_tlvs *tlvs)
 {
-       XFREE(MTYPE_ISIS_TLV, tlvs->router_cap);
-       if (!cap)
-               return;
-
        tlvs->router_cap = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->router_cap));
-       *tlvs->router_cap = *cap;
+
+       /* init SR algo list content to the default value */
+       for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
+               tlvs->router_cap->algo[i] = SR_ALGORITHM_UNSET;
+
+       return tlvs->router_cap;
+}
+
+#ifndef FABRICD
+void isis_tlvs_set_router_capability_fad(struct isis_tlvs *tlvs,
+                                        struct flex_algo *fa, int algorithm,
+                                        uint8_t *sysid)
+{
+       struct isis_router_cap_fad *rcap_fad;
+
+       assert(tlvs->router_cap);
+
+       rcap_fad = tlvs->router_cap->fads[algorithm];
+
+       if (!rcap_fad)
+               rcap_fad = XCALLOC(MTYPE_ISIS_TLV,
+                                  sizeof(struct isis_router_cap_fad));
+
+       memset(rcap_fad->sysid, 0, ISIS_SYS_ID_LEN + 2);
+       memcpy(rcap_fad->sysid, sysid, ISIS_SYS_ID_LEN);
+
+       memcpy(&rcap_fad->fad, fa, sizeof(struct flex_algo));
+
+       rcap_fad->fad.admin_group_exclude_any.bitmap.data = NULL;
+       rcap_fad->fad.admin_group_include_any.bitmap.data = NULL;
+       rcap_fad->fad.admin_group_include_all.bitmap.data = NULL;
+
+       admin_group_copy(&rcap_fad->fad.admin_group_exclude_any,
+                        &fa->admin_group_exclude_any);
+       admin_group_copy(&rcap_fad->fad.admin_group_include_any,
+                        &fa->admin_group_include_any);
+       admin_group_copy(&rcap_fad->fad.admin_group_include_all,
+                        &fa->admin_group_include_all);
+
+       tlvs->router_cap->fads[algorithm] = rcap_fad;
 }
+#endif /* ifndef FABRICD */
 
 int isis_tlvs_sr_algo_count(const struct isis_router_cap *cap)
 {
index 331cad93e9c0433786d7a793bdba360241b95b22..03e2b2edccca44ed27fa347b96020e1a4a849b03 100644 (file)
@@ -13,6 +13,8 @@
 #include "openbsd-tree.h"
 #include "prefix.h"
 #include "flex_algo.h"
+#include "affinitymap.h"
+
 
 DECLARE_MTYPE(ISIS_SUBTLV);
 
@@ -400,10 +402,22 @@ enum isis_tlv_type {
        ISIS_SUBTLV_AVA_BW = 38,
        ISIS_SUBTLV_USE_BW = 39,
 
+       /* RFC 7308 */
+       ISIS_SUBTLV_EXT_ADMIN_GRP = 14,
+
        /* RFC 8919 */
        ISIS_SUBTLV_ASLA = 16,
 
+       /* draft-ietf-lsr-isis-srv6-extensions */
+       ISIS_SUBTLV_SID_END = 5,
+       ISIS_SUBTLV_SID_END_X = 43,
+
        ISIS_SUBTLV_MAX = 40,
+
+       /* draft-ietf-lsr-isis-srv6-extensions */
+       ISIS_SUBSUBTLV_SID_STRUCTURE = 1,
+
+       ISIS_SUBSUBTLV_MAX = 256,
 };
 
 /* subTLVs size for TE and SR */
@@ -431,15 +445,31 @@ enum ext_subtlv_size {
        /* RFC 7810 */
        ISIS_SUBTLV_MM_DELAY_SIZE = 8,
 
+       /* RFC9350 - Flex-Algorithm */
+       ISIS_SUBTLV_FAD = 26,
+       ISIS_SUBTLV_FAD_MIN_SIZE = 4,
+
        ISIS_SUBTLV_HDR_SIZE = 2,
        ISIS_SUBTLV_DEF_SIZE = 4,
 
-       /* RFC 7308 */
-       ISIS_SUBTLV_EXT_ADMIN_GRP = 14,
+       ISIS_SUBTLV_MAX_SIZE = 180,
+
+       /* draft-ietf-lsr-isis-srv6-extensions */
+       ISIS_SUBSUBTLV_SID_STRUCTURE_SIZE = 4,
 
        ISIS_SUBSUBTLV_HDR_SIZE = 2,
+       ISIS_SUBSUBTLV_MAX_SIZE = 180,
 
-       ISIS_SUBTLV_MAX_SIZE = 180,
+       /* RFC9350 - Flex-Algorithm */
+       ISIS_SUBTLV_FAD_SUBSUBTLV_FLAGS_SIZE = 1,
+};
+
+enum ext_subsubtlv_types {
+       ISIS_SUBTLV_FAD_SUBSUBTLV_EXCAG = 1,
+       ISIS_SUBTLV_FAD_SUBSUBTLV_INCANYAG = 2,
+       ISIS_SUBTLV_FAD_SUBSUBTLV_INCALLAG = 3,
+       ISIS_SUBTLV_FAD_SUBSUBTLV_FLAGS = 4,
+       ISIS_SUBTLV_FAD_SUBSUBTLV_ESRLG = 5,
 };
 
 /* Macros to manage the optional presence of EXT subTLVs */
@@ -625,8 +655,16 @@ void isis_tlvs_add_csnp_entries(struct isis_tlvs *tlvs, uint8_t *start_id,
                                struct isis_lsp **last_lsp);
 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs *tlvs,
                                    const char *hostname);
-void isis_tlvs_set_router_capability(struct isis_tlvs *tlvs,
-                     const struct isis_router_cap *cap);
+struct isis_router_cap *
+isis_tlvs_init_router_capability(struct isis_tlvs *tlvs);
+
+struct isis_area;
+struct isis_flex_algo;
+void isis_tlvs_set_router_capability_fad(struct isis_tlvs *tlvs,
+                                        struct flex_algo *fa, int algorithm,
+                                        uint8_t *sysid);
+
+struct isis_area;
 
 int isis_tlvs_sr_algo_count(const struct isis_router_cap *cap);
 
index 5c1debca8d7b4a7ca6c9ce5460f052eaf4440258..e47456965e0e2f43734d61cc49263269fb34ab7b 100644 (file)
@@ -163,31 +163,32 @@ static void lsp_add_reach(struct isis_lsp *lsp,
 static void lsp_add_router_capability(struct isis_lsp *lsp,
                                      const struct isis_test_node *tnode)
 {
-       struct isis_router_cap cap = {};
+       struct isis_router_cap *cap;
 
        if (!tnode->router_id)
                return;
 
-       if (inet_pton(AF_INET, tnode->router_id, &cap.router_id) != 1) {
+       cap = isis_tlvs_init_router_capability(lsp->tlvs);
+
+       if (inet_pton(AF_INET, tnode->router_id, &cap->router_id) != 1) {
                zlog_debug("%s: invalid router-id: %s", __func__,
                           tnode->router_id);
                return;
        }
 
        if (CHECK_FLAG(tnode->flags, F_ISIS_TEST_NODE_SR)) {
-               cap.srgb.flags =
+               cap->srgb.flags =
                        ISIS_SUBTLV_SRGB_FLAG_I | ISIS_SUBTLV_SRGB_FLAG_V;
-               cap.srgb.lower_bound = tnode->srgb.lower_bound
-                                              ? tnode->srgb.lower_bound
-                                              : SRGB_DFTL_LOWER_BOUND;
-               cap.srgb.range_size = tnode->srgb.range_size
-                                             ? tnode->srgb.range_size
-                                             : SRGB_DFTL_RANGE_SIZE;
-               cap.algo[0] = SR_ALGORITHM_SPF;
-               cap.algo[1] = SR_ALGORITHM_UNSET;
+               cap->srgb.lower_bound = tnode->srgb.lower_bound
+                                               ? tnode->srgb.lower_bound
+                                               : SRGB_DFTL_LOWER_BOUND;
+               cap->srgb.range_size = tnode->srgb.range_size
+                                              ? tnode->srgb.range_size
+                                              : SRGB_DFTL_RANGE_SIZE;
+               cap->algo[0] = SR_ALGORITHM_SPF;
+               cap->algo[1] = SR_ALGORITHM_UNSET;
        }
 
-       isis_tlvs_set_router_capability(lsp->tlvs, &cap);
 }
 
 static void lsp_add_mt_router_info(struct isis_lsp *lsp,