diff --git a/doc/user/affinitymap.rst b/doc/user/affinitymap.rst new file mode 100644 index 0000000000..b7dcb146c7 --- /dev/null +++ b/doc/user/affinitymap.rst @@ -0,0 +1,32 @@ +.. _affinity-map: + +************* +Affinity Maps +************* + +Affinity maps provide a means of configuring Standard Admininistrative-Group +(RFC3630, RFC5305 and RFC5329) and Extended Admininistrative-Group (RFC7308). +An affinity-map maps a specific bit position to a human readable-name. + +An affinity refers to a color or a ressource class in the Traffic Engineering +terminology. The bit position means the position of the bit set starting from +the least significant bit. For example, if the affinity 'blue' has bit position +0 the extended Admin-Group value will be 0x01. If the affinity 'red' bit +position 2 was added to a link in combination with the 'blue' affinity, the +Admin-Group value would be 0x05. + +Command +------- + +.. clicmd:: affinity-map NAME bit-position (0-1023) + + Map the affinity name NAME to the bit-position. The bit-position is the key + so that only one name can be mapped to particular bit-position. + +.. clicmd:: no affinity-map NAME + + Remove the affinity-map mapping. + +Affinity-maps with a bit-position value higher than 31 are not compatible with +Standard Admininistrative-Group. The CLI disallow the usage of such +affinity-maps when Standard Admininistrative-Groups are required. \ No newline at end of file diff --git a/doc/user/subdir.am b/doc/user/subdir.am index 706e1ea449..b8c5c70d9c 100644 --- a/doc/user/subdir.am +++ b/doc/user/subdir.am @@ -3,6 +3,7 @@ # user_RSTFILES = \ + doc/user/affinitymap.rst \ doc/user/babeld.rst \ doc/user/ldpd.rst \ doc/user/basic.rst \ diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 45453ea77b..e7e2e5d2ed 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -222,8 +222,6 @@ Link Parameters Commands .. clicmd:: unrsv-bw (0-7) BANDWIDTH -.. clicmd:: admin-grp BANDWIDTH - These commands specifies the Traffic Engineering parameters of the interface in conformity to RFC3630 (OSPF) or RFC5305 (ISIS). There are respectively the TE Metric (different from the OSPF or ISIS metric), Maximum Bandwidth @@ -234,6 +232,36 @@ Link Parameters Commands Note that BANDWIDTH is specified in IEEE floating point format and express in Bytes/second. +.. clicmd:: admin-grp 0x(0-FFFFFFFF) + + This commands configures the Traffic Engineering Admin-Group of the interface + as specified in RFC3630 (OSPF) or RFC5305 (ISIS). Admin-group is also known + as Resource Class/Color in the OSPF protocol. + +.. clicmd:: [no] affinity AFFINITY-MAP-NAME + + This commands configures the Traffic Engineering Admin-Group of the + interface using the affinity-map definitions (:ref:`affinity-map`). + Multiple AFFINITY-MAP-NAME can be specified at the same time. Affinity-map + names are added or removed if ``no`` is present. It means that specifying one + value does not override the full list. + + ``admin-grp`` and ``affinity`` commands provide two ways of setting + admin-groups. They cannot be both set on the same interface. + +.. clicmd:: [no] affinity-mode [extended|standard|both] + + This commands configures which admin-group format is set by the affinity + command. ``extended`` Admin-Group is the default and uses the RFC7308 format. + ``standard`` mode uses the standard admin-group format that is defined by + RFC3630, RFC5305 and RFC5329. When the ``standard`` mode is set, + affinity-maps with bit-positions higher than 31 cannot be applied to the + interface. The ``both`` mode allows setting standard and extended admin-group + on the link at the same time. In this case, the bit-positions 0 to 31 are + the same on standard and extended admin-groups. + + Note that extended admin-groups are only supported by IS-IS for the moment. + .. clicmd:: delay (0-16777215) [min (0-16777215) | max (0-16777215)] .. clicmd:: delay-variation (0-16777215) diff --git a/isisd/isis_main.c b/isisd/isis_main.c index fb4237f002..607661b540 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -40,6 +40,7 @@ #include "qobj.h" #include "libfrr.h" #include "routemap.h" +#include "affinitymap.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" @@ -167,6 +168,7 @@ struct frr_signal_t isisd_signals[] = { }; +/* clang-format off */ static const struct frr_yang_module_info *const isisd_yang_modules[] = { &frr_filter_info, &frr_interface_info, @@ -174,8 +176,10 @@ static const struct frr_yang_module_info *const isisd_yang_modules[] = { &frr_isisd_info, #endif /* ifndef FABRICD */ &frr_route_map_info, + &frr_affinity_map_info, &frr_vrf_info, }; +/* clang-format on */ #ifdef FABRICD FRR_DAEMON_INFO(fabricd, OPEN_FABRIC, .vty_port = FABRICD_VTY_PORT, @@ -264,6 +268,8 @@ int main(int argc, char **argv, char **envp) lsp_init(); mt_init(); + affinity_map_init(); + isis_zebra_init(master, instance); isis_bfd_init(master); isis_ldp_sync_init(); diff --git a/isisd/isis_te.c b/isisd/isis_te.c index 993d894f22..cf23c1a5af 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -218,6 +218,13 @@ void isis_link_params_update(struct isis_circuit *circuit, } else UNSET_SUBTLV(ext, EXT_ADM_GRP); + if (IS_PARAM_SET(ifp->link_params, LP_EXTEND_ADM_GRP)) { + admin_group_copy(&ext->ext_admin_group, + &ifp->link_params->ext_admin_grp); + SET_SUBTLV(ext, EXT_EXTEND_ADM_GRP); + } else + UNSET_SUBTLV(ext, EXT_EXTEND_ADM_GRP); + /* If known, register local IPv4 addr from ip_addr list */ if (listcount(circuit->ip_addrs) != 0) { addr = (struct prefix_ipv4 *)listgetdata( @@ -758,6 +765,11 @@ static struct ls_attributes *get_attributes(struct ls_node_id adv, attr->standard.admin_group = tlvs->adm_group; SET_FLAG(attr->flags, LS_ATTR_ADM_GRP); } + if (CHECK_FLAG(tlvs->status, EXT_EXTEND_ADM_GRP)) { + admin_group_copy(&attr->ext_admin_group, + &tlvs->ext_admin_group); + SET_FLAG(attr->flags, LS_ATTR_EXT_ADM_GRP); + } if (CHECK_FLAG(tlvs->status, EXT_LLRI)) { attr->standard.local_id = tlvs->local_llri; attr->standard.remote_id = tlvs->remote_llri; diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index ae0a208d21..8ece697b70 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -136,6 +136,8 @@ struct isis_ext_subtlvs *isis_alloc_ext_subtlvs(void) init_item_list(&ext->adj_sid); init_item_list(&ext->lan_sid); + admin_group_init(&ext->ext_admin_group); + return ext; } @@ -155,6 +157,9 @@ void isis_del_ext_subtlvs(struct isis_ext_subtlvs *ext) next_item = item->next; XFREE(MTYPE_ISIS_SUBTLV, item); } + + admin_group_term(&ext->ext_admin_group); + XFREE(MTYPE_ISIS_SUBTLV, ext); } @@ -233,6 +238,9 @@ copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, uint16_t mtid) SET_SUBTLV(rv, EXT_LAN_ADJ_SID); } + rv->ext_admin_group.bitmap.data = NULL; + admin_group_copy(&rv->ext_admin_group, &exts->ext_admin_group); + return rv; } @@ -241,6 +249,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, struct sbuf *buf, struct json_object *json, int indent, uint16_t mtid) { + char admin_group_buf[ADMIN_GROUP_PRINT_MAX_SIZE]; char aux_buf[255]; char cnt_buf[255]; @@ -250,9 +259,37 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, snprintfrr(aux_buf, sizeof(aux_buf), "0x%x", exts->adm_group); json_object_string_add(json, "adm-group", aux_buf); - } else + } else { sbuf_push(buf, indent, "Administrative Group: 0x%x\n", exts->adm_group); + sbuf_push(buf, indent + 2, "Bit positions: %s\n", + admin_group_standard_print( + admin_group_buf, + indent + strlen("Admin Group: "), + exts->adm_group)); + } + } + + if (IS_SUBTLV(exts, EXT_EXTEND_ADM_GRP) && + admin_group_nb_words(&exts->ext_admin_group) != 0) { + if (!json) { + /* TODO json after fix show database detail json */ + sbuf_push(buf, indent, "Ext Admin Group: %s\n", + admin_group_string( + admin_group_buf, + ADMIN_GROUP_PRINT_MAX_SIZE, + indent + strlen("Ext Admin Group: "), + &exts->ext_admin_group)); + admin_group_print(admin_group_buf, + indent + strlen("Ext Admin Group: "), + &exts->ext_admin_group); + if (admin_group_buf[0] != '\0' && + (buf->pos + strlen(admin_group_buf) + + SBUF_DEFAULT_SIZE / 2) < buf->size) + sbuf_push(buf, indent + 2, + "Bit positions: %s\n", + admin_group_buf); + } } if (IS_SUBTLV(exts, EXT_LLRI)) { if (json) { @@ -685,6 +722,24 @@ static int pack_item_ext_subtlvs(struct isis_ext_subtlvs *exts, stream_putc(s, ISIS_SUBTLV_DEF_SIZE); stream_putl(s, exts->adm_group); } + if (IS_SUBTLV(exts, EXT_EXTEND_ADM_GRP) && + admin_group_nb_words(&exts->ext_admin_group) != 0) { + /* Extended Administrative Group */ + size_t ag_length; + size_t ag_length_pos; + struct admin_group *ag; + + stream_putc(s, ISIS_SUBTLV_EXT_ADMIN_GRP); + ag_length_pos = stream_get_endp(s); + stream_putc(s, 0); /* length will be filled later*/ + + ag = &exts->ext_admin_group; + for (size_t i = 0; i < admin_group_nb_words(ag); i++) + stream_putl(s, ag->bitmap.data[i]); + + ag_length = stream_get_endp(s) - ag_length_pos - 1; + stream_putc_at(s, ag_length_pos, ag_length); + } if (IS_SUBTLV(exts, EXT_LLRI)) { stream_putc(s, ISIS_SUBTLV_LLRI); stream_putc(s, ISIS_SUBTLV_LLRI_SIZE); @@ -828,6 +883,8 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, uint8_t sum = 0; uint8_t subtlv_type; uint8_t subtlv_len; + size_t nb_groups; + uint32_t val; struct isis_extended_reach *rv = dest; struct isis_ext_subtlvs *exts = isis_alloc_ext_subtlvs(); @@ -863,6 +920,15 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, SET_SUBTLV(exts, EXT_ADM_GRP); } break; + case ISIS_SUBTLV_EXT_ADMIN_GRP: + nb_groups = subtlv_len / sizeof(uint32_t); + for (size_t i = 0; i < nb_groups; i++) { + val = stream_getl(s); + admin_group_bulk_set(&exts->ext_admin_group, + val, i); + } + SET_SUBTLV(exts, EXT_EXTEND_ADM_GRP); + break; case ISIS_SUBTLV_LLRI: if (subtlv_len != ISIS_SUBTLV_LLRI_SIZE) { sbuf_push(log, indent, diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h index 52dfb7a84f..1dad9b1870 100644 --- a/isisd/isis_tlvs.h +++ b/isisd/isis_tlvs.h @@ -441,6 +441,9 @@ enum ext_subtlv_size { ISIS_SUBTLV_HDR_SIZE = 2, ISIS_SUBTLV_DEF_SIZE = 4, + /* RFC 7308 */ + ISIS_SUBTLV_EXT_ADMIN_GRP = 14, + ISIS_SUBTLV_MAX_SIZE = 180 }; @@ -471,6 +474,7 @@ enum ext_subtlv_size { #define EXT_RES_BW 0x040000 #define EXT_AVA_BW 0x080000 #define EXT_USE_BW 0x100000 +#define EXT_EXTEND_ADM_GRP 0x200000 /* * This structure groups all Extended IS Reachability subTLVs. @@ -491,6 +495,7 @@ struct isis_ext_subtlvs { uint32_t status; uint32_t adm_group; /* Resource Class/Color - RFC 5305 */ + struct admin_group ext_admin_group; /* Res. Class/Color - RFC 7308 */ /* Link Local/Remote Identifiers - RFC 5307 */ uint32_t local_llri; uint32_t remote_llri; diff --git a/lib/admin_group.c b/lib/admin_group.c new file mode 100644 index 0000000000..9c2c2c08ee --- /dev/null +++ b/lib/admin_group.c @@ -0,0 +1,402 @@ +/* + * Administrative-group library (RFC3630, RFC5305, RFC5329, RFC7308) + * + * Copyright 2022 Hiroki Shirokura, LINE Corporation + * Copyright 2022 Masakazu Asama + * Copyright 2022 6WIND S.A. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "admin_group.h" +#include "bitfield.h" + +char *admin_group_string(char *out, size_t sz, int indent, + const struct admin_group *ag) +{ + bool printed = false; + size_t index = 2; + int nb_print = 0; + + if (sz < index) + return out; + + if (admin_group_explicit_zero(ag)) { + snprintf(out, sz, "0x00000000"); + return out; + } + + if (admin_group_zero(ag)) { + snprintf(out, sz, "not-set"); + return out; + } + + snprintf(out, sz, "0x"); + for (ssize_t i = ag->bitmap.m - 1; i >= 0; i--) { + if (sz - index <= 0) + break; + if (ag->bitmap.data[i] == 0 && !printed) + continue; + if (nb_print != 0 && (nb_print % 4) == 0) { + snprintf(&out[index], sz - index, "\n%*s", indent, ""); + index += indent + 1; + snprintf(&out[index], sz - index, "0x%08x ", + ag->bitmap.data[i]); + index += 2; + } else + snprintf(&out[index], sz - index, "%08x ", + ag->bitmap.data[i]); + index += 9; + nb_print++; + printed = true; + } + return out; +} + +char *admin_group_standard_print(char *out, int indent, uint32_t bitmap) +{ + bool first = true; + int bit, i; + size_t ret, line_sz = 0, line_max_sz; + + out[0] = '\0'; + + if (bitmap == 0) { + snprintf(out, ADMIN_GROUP_PRINT_MAX_SIZE, "not-set"); + return out; + } + + line_max_sz = strlen("0xffffffff ffffffff ffffffff ffffffff"); + + for (i = 0; i < 32; i++) { + bit = bitmap >> i & 1; + if (bit == 0) + continue; + if (!first) { + ret = snprintf(&out[strlen(out)], + ADMIN_GROUP_PRINT_MAX_SIZE - strlen(out), + ", "); + line_sz += ret; + } + if (line_sz >= line_max_sz) { + snprintf(&out[strlen(out)], + ADMIN_GROUP_PRINT_MAX_SIZE - strlen(out), + "\n%*s", indent, ""); + + line_sz = 0; + } + ret = snprintf(&out[strlen(out)], + ADMIN_GROUP_PRINT_MAX_SIZE - strlen(out), "%d", + i); + line_sz += ret; + first = false; + } + + return out; +} + +char *admin_group_print(char *out, int indent, const struct admin_group *ag) +{ + bool first = true; + uint32_t i; + size_t ret, line_sz = 0, line_max_sz; + + out[0] = '\0'; + + if (admin_group_size(ag) == 0) { + snprintf(out, ADMIN_GROUP_PRINT_MAX_SIZE, "not-set"); + return out; + } + + line_max_sz = strlen("0xffffffff ffffffff ffffffff ffffffff"); + + for (i = 0; i < (admin_group_size(ag) * WORD_SIZE); i++) { + if (!admin_group_get(ag, i)) + continue; + if (!first) { + ret = snprintf(&out[strlen(out)], + ADMIN_GROUP_PRINT_MAX_SIZE - strlen(out), + ", "); + line_sz += ret; + } + if (line_sz >= line_max_sz) { + snprintf(&out[strlen(out)], + ADMIN_GROUP_PRINT_MAX_SIZE - strlen(out), + "\n%*s", indent, ""); + + line_sz = 0; + } + ret = snprintf(&out[strlen(out)], + ADMIN_GROUP_PRINT_MAX_SIZE - strlen(out), "%d", + i); + line_sz += ret; + if (ret >= (ADMIN_GROUP_PRINT_MAX_SIZE - strlen(out))) { + out[0] = '\0'; + return out; + } + first = false; + } + + return out; +} + +bool admin_group_cmp(const struct admin_group *ag1, + const struct admin_group *ag2) +{ + size_t i; + + for (i = 0; i < ag1->bitmap.m || i < ag2->bitmap.m; i++) { + if (i >= ag1->bitmap.m) { + if (ag2->bitmap.data[i] != 0) + return false; + } else if (i >= ag2->bitmap.m) { + if (ag1->bitmap.data[i] != 0) + return false; + } else if (memcmp(&ag1->bitmap.data[i], &ag2->bitmap.data[i], + sizeof(word_t)) != 0) + return false; + } + + return true; +} + +void admin_group_copy(struct admin_group *dst, const struct admin_group *src) +{ + assert(bf_is_inited(src->bitmap)); + if (bf_is_inited(dst->bitmap)) + bf_free(dst->bitmap); + dst->bitmap = bf_copy(src->bitmap); +} + +void admin_group_init(struct admin_group *ag) +{ + assert(!bf_is_inited(ag->bitmap)); + bf_init(ag->bitmap, WORD_SIZE); +} + +void admin_group_term(struct admin_group *ag) +{ + assert(bf_is_inited(ag->bitmap)); + bf_free(ag->bitmap); +} + +word_t admin_group_get_offset(const struct admin_group *ag, size_t oct_offset) +{ + assert(bf_is_inited(ag->bitmap)); + if (ag->bitmap.m < oct_offset) + return 0; + return ag->bitmap.data[oct_offset]; +} + +static void admin_group_extend(struct admin_group *ag, size_t idx) +{ + size_t old_m, m; + + old_m = ag->bitmap.m; + m = idx + 1; + ag->bitmap.m = m; + ag->bitmap.data = + XREALLOC(MTYPE_BITFIELD, ag->bitmap.data, m * sizeof(word_t)); + memset(&ag->bitmap.data[old_m], 0, (m - old_m) * sizeof(word_t)); +} + +void admin_group_set(struct admin_group *ag, size_t pos) +{ + size_t idx = bf_index(pos); + + if (idx >= ag->bitmap.m) + admin_group_extend(ag, idx); + + ag->bitmap.data[idx] |= 1 << (bf_offset(pos)); + + if (idx >= ag->bitmap.n) + ag->bitmap.n = idx + 1; +} + +void admin_group_unset(struct admin_group *ag, size_t pos) +{ + if (bf_index(pos) > (ag->bitmap.m - 1)) + return; + bf_release_index(ag->bitmap, pos); + ag->bitmap.n = admin_group_size(ag); +} + +int admin_group_get(const struct admin_group *ag, size_t pos) +{ + size_t admin_group_length = admin_group_size(ag); + uint32_t oct_offset; + size_t idx; + + if (admin_group_length == 0) + return 0; + + idx = bf_index(pos); + + if (idx >= admin_group_length) + return 0; + + oct_offset = admin_group_get_offset(ag, idx); + return oct_offset >> pos & 1; +} + +void admin_group_bulk_set(struct admin_group *ag, uint32_t bitmap, + size_t oct_offset) +{ + + if (bitmap == 0 && oct_offset == 0) { + admin_group_allow_explicit_zero(ag); + return; + } + + if (oct_offset >= ag->bitmap.m) + admin_group_extend(ag, oct_offset); + + ag->bitmap.data[oct_offset] = bitmap; + + if (oct_offset >= ag->bitmap.n) + ag->bitmap.n = oct_offset + 1; +} + +size_t admin_group_size(const struct admin_group *ag) +{ + size_t size = 0; + + for (size_t i = 0; i < ag->bitmap.m; i++) + if (ag->bitmap.data[i] != 0) + size = i + 1; + return size; +} + +size_t admin_group_nb_words(const struct admin_group *ag) +{ + return ag->bitmap.n; +} + +void admin_group_clear(struct admin_group *ag) +{ + for (size_t i = 0; i < ag->bitmap.m; i++) + ag->bitmap.data[i] = 0; + ag->bitmap.n = 0; +} + +bool admin_group_zero(const struct admin_group *ag) +{ + for (size_t i = 0; i < ag->bitmap.m; i++) + if (ag->bitmap.data[i] != 0) + return false; + return true; +} + + +bool admin_group_explicit_zero(const struct admin_group *ag) +{ + return ag->bitmap.n == 1 && ag->bitmap.data[0] == 0; +} + +void admin_group_allow_explicit_zero(struct admin_group *ag) +{ + if (admin_group_zero(ag)) + ag->bitmap.n = 1; +} + +void admin_group_disallow_explicit_zero(struct admin_group *ag) +{ + if (admin_group_zero(ag)) + ag->bitmap.n = 0; +} + +/* link_std_ag: admin-group in the RFC5305 section 3.1 format + * link_ext_ag: admin-group in the RFC7308 format + * RFC7308 specifies in section 2.3.1 that: + * "If both an AG and EAG are present, a receiving node MUST use the AG + * as the first 32 bits (0-31) of administrative color and use the EAG + * for bits 32 and higher, if present." + */ +bool admin_group_match_any(const struct admin_group *fad_ag, + const uint32_t *link_std_ag, + const struct admin_group *link_ext_ag) +{ + size_t fad_ag_sz, link_ag_sz, i; + uint32_t link_ag_bitmap, fad_ag_bitmap; + + assert(fad_ag); + + /* get the size of admin-groups: i.e. number of used words */ + fad_ag_sz = admin_group_size(fad_ag); + if (link_std_ag && link_ext_ag) { + link_ag_sz = admin_group_size(link_ext_ag); + if (link_ag_sz == 0) + link_ag_sz = 1; + } else if (link_std_ag && !link_ext_ag) + link_ag_sz = 1; + else if (!link_std_ag && link_ext_ag) + link_ag_sz = admin_group_size(link_ext_ag); + else + link_ag_sz = 0; + + for (i = 0; i < fad_ag_sz && i < link_ag_sz; i++) { + fad_ag_bitmap = fad_ag->bitmap.data[i]; + if (i == 0 && link_std_ag) + link_ag_bitmap = *link_std_ag; + else + link_ag_bitmap = link_ext_ag->bitmap.data[i]; + + if (fad_ag_bitmap & link_ag_bitmap) + return true; + } + return false; +} + +/* same comments as admin_group_match_any() */ +bool admin_group_match_all(const struct admin_group *fad_ag, + const uint32_t *link_std_ag, + const struct admin_group *link_ext_ag) +{ + size_t fad_ag_sz, link_ag_sz, i; + uint32_t link_ag_bitmap, fad_ag_bitmap; + + assert(fad_ag); + + /* get the size of admin-groups: i.e. number of used words */ + fad_ag_sz = admin_group_size(fad_ag); + if (link_std_ag && link_ext_ag) { + link_ag_sz = admin_group_size(link_ext_ag); + if (link_ag_sz == 0) + link_ag_sz = 1; + } else if (link_std_ag && !link_ext_ag) + link_ag_sz = 1; + else if (!link_std_ag && link_ext_ag) + link_ag_sz = admin_group_size(link_ext_ag); + else + link_ag_sz = 0; + + if (fad_ag_sz > link_ag_sz) + return false; + + for (i = 0; i < fad_ag_sz; i++) { + fad_ag_bitmap = fad_ag->bitmap.data[i]; + if (fad_ag_bitmap == 0) + continue; + + if (i == 0 && link_std_ag) + link_ag_bitmap = *link_std_ag; + else + link_ag_bitmap = link_ext_ag->bitmap.data[i]; + + if ((fad_ag_bitmap & link_ag_bitmap) != fad_ag_bitmap) + return false; + } + return true; +} diff --git a/lib/admin_group.h b/lib/admin_group.h new file mode 100644 index 0000000000..60f4a05f2b --- /dev/null +++ b/lib/admin_group.h @@ -0,0 +1,68 @@ +/* + * Administrative-group library (RFC3630, RFC5305, RFC5329, RFC7308) + * + * Copyright 2022 Hiroki Shirokura, LINE Corporation + * Copyright 2022 Masakazu Asama + * Copyright 2022 6WIND S.A. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _FRR_ADMIN_GROUP_H +#define _FRR_ADMIN_GROUP_H + +#include "zebra.h" +#include "memory.h" +#include "bitfield.h" + +#define ADMIN_GROUP_PRINT_MAX_SIZE 2048 +#define EXT_ADMIN_GROUP_MAX_POSITIONS 1024 + +struct admin_group { + bitfield_t bitmap; +}; + +char *admin_group_string(char *out, size_t sz, int indent, + const struct admin_group *ag); +char *admin_group_standard_print(char *out, int indent, uint32_t bitmap); +char *admin_group_print(char *out, int indent, const struct admin_group *ag); +bool admin_group_cmp(const struct admin_group *ag1, + const struct admin_group *ag2); +void admin_group_copy(struct admin_group *dst, const struct admin_group *src); +void admin_group_init(struct admin_group *ag); +void admin_group_term(struct admin_group *ag); +uint32_t admin_group_get_offset(const struct admin_group *ag, + size_t oct_offset); +void admin_group_set(struct admin_group *ag, size_t pos); +void admin_group_unset(struct admin_group *ag, size_t pos); +int admin_group_get(const struct admin_group *ag, size_t pos); +void admin_group_bulk_set(struct admin_group *ag, uint32_t bitmap, + size_t oct_offset); +size_t admin_group_size(const struct admin_group *ag); +size_t admin_group_nb_words(const struct admin_group *ag); +void admin_group_clear(struct admin_group *ag); +bool admin_group_zero(const struct admin_group *ag); +bool admin_group_explicit_zero(const struct admin_group *ag); +void admin_group_allow_explicit_zero(struct admin_group *ag); +void admin_group_disallow_explicit_zero(struct admin_group *ag); + +bool admin_group_match_any(const struct admin_group *fad_ag, + const uint32_t *link_std_ag, + const struct admin_group *link_ag); +bool admin_group_match_all(const struct admin_group *fad_ag, + const uint32_t *link_std_ag, + const struct admin_group *link_ag); + +#endif /* _FRR_ADMIN_GROUP_H */ diff --git a/lib/affinitymap.c b/lib/affinitymap.c new file mode 100644 index 0000000000..17e1b2cc01 --- /dev/null +++ b/lib/affinitymap.c @@ -0,0 +1,173 @@ +/* + * Affinity map function. + * + * Copyright 2022 Hiroki Shirokura, LINE Corporation + * Copyright 2022 Masakazu Asama + * Copyright 2022 6WIND S.A. + * + * This file is part of Free Range Routing (FRR). + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "linklist.h" +#include "memory.h" +#include "command.h" +#include "vector.h" +#include "prefix.h" +#include "vty.h" +#include "affinitymap.h" +#include "command.h" +#include "log.h" +#include "hash.h" +#include "libfrr.h" +#include "lib_errors.h" +#include "table.h" +#include "json.h" +#include "jhash.h" + +DEFINE_MTYPE_STATIC(LIB, AFFINITY_MAP, "Affinity map"); +DEFINE_MTYPE(LIB, AFFINITY_MAP_NAME, "Affinity map name"); +DEFINE_MTYPE_STATIC(LIB, AFFINITY_MAP_INDEX, "Affinity map index"); + +DEFINE_QOBJ_TYPE(affinity_maps); +DEFINE_QOBJ_TYPE(affinity_map); + +struct affinity_maps affinity_map_master = {NULL, NULL, NULL, NULL}; + +static void affinity_map_free(struct affinity_map *map) +{ + XFREE(MTYPE_AFFINITY_MAP, map); +} + +void affinity_map_set(const char *name, int pos) +{ + struct listnode *node; + struct affinity_map *map; + + if (!affinity_map_master.maps) + affinity_map_master.maps = list_new(); + + for (ALL_LIST_ELEMENTS_RO(affinity_map_master.maps, node, map)) { + if (strncmp(name, map->name, AFFINITY_NAME_SIZE) != 0) + continue; + map->bit_position = pos; + return; + } + + map = XCALLOC(MTYPE_AFFINITY_MAP, sizeof(*map)); + map->bit_position = pos; + snprintf(map->name, sizeof(map->name), "%s", name); + listnode_add(affinity_map_master.maps, map); +} + +void affinity_map_unset(const char *name) +{ + struct listnode *node, *nnode; + struct affinity_map *map; + + if (!affinity_map_master.maps) + return; + + for (ALL_LIST_ELEMENTS(affinity_map_master.maps, node, nnode, map)) { + if (strncmp(name, map->name, AFFINITY_NAME_SIZE) != 0) + continue; + listnode_delete(affinity_map_master.maps, map); + affinity_map_free(map); + return; + } +} + +struct affinity_map *affinity_map_get(const char *name) +{ + struct listnode *node; + struct affinity_map *map; + + if (!affinity_map_master.maps) + return NULL; + + for (ALL_LIST_ELEMENTS_RO(affinity_map_master.maps, node, map)) + if (strncmp(name, map->name, AFFINITY_NAME_SIZE) == 0) + return map; + return NULL; +} + + +char *affinity_map_name_get(int pos) +{ + struct listnode *node; + struct affinity_map *map; + + if (!affinity_map_master.maps) + return NULL; + + for (ALL_LIST_ELEMENTS_RO(affinity_map_master.maps, node, map)) + if (map->bit_position == pos) + return map->name; + return NULL; +} + +bool affinity_map_check_use_hook(const char *affmap_name) +{ + if (affinity_map_master.check_use_hook) + return (*affinity_map_master.check_use_hook)(affmap_name); + return false; +} + +bool affinity_map_check_update_hook(const char *affmap_name, uint16_t new_pos) +{ + if (affinity_map_master.check_update_hook) + return (*affinity_map_master.check_update_hook)(affmap_name, + new_pos); + return true; +} + +void affinity_map_update_hook(const char *affmap_name, uint16_t new_pos) +{ + struct affinity_map *map; + + if (!affinity_map_master.update_hook) + return; + + map = affinity_map_get(affmap_name); + + if (!map) + /* Affinity-map creation */ + return; + + (*affinity_map_master.update_hook)(affmap_name, map->bit_position, + new_pos); +} + + +void affinity_map_set_check_use_hook(bool (*func)(const char *affmap_name)) +{ + affinity_map_master.check_use_hook = func; +} + +void affinity_map_set_check_update_hook(bool (*func)(const char *affmap_name, + uint16_t new_pos)) +{ + affinity_map_master.check_update_hook = func; +} + +void affinity_map_set_update_hook(void (*func)(const char *affmap_name, + uint16_t old_pos, + uint16_t new_pos)) +{ + affinity_map_master.update_hook = func; +} diff --git a/lib/affinitymap.h b/lib/affinitymap.h new file mode 100644 index 0000000000..19edf5a269 --- /dev/null +++ b/lib/affinitymap.h @@ -0,0 +1,90 @@ +/* + * Affinity-map function. + * + * Copyright 2022 Hiroki Shirokura, LINE Corporation + * Copyright 2022 Masakazu Asama + * Copyright 2022 6WIND S.A. + * + * This file is part of Free Range Routing (FRR). + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _ZEBRA_AFFINITYMAP_H +#define _ZEBRA_AFFINITYMAP_H + +#include "typesafe.h" +#include "prefix.h" +#include "memory.h" +#include "qobj.h" +#include "vty.h" +#include "lib/plist.h" +#include "lib/plist_int.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define AFFINITY_NAME_SIZE 32 + +struct affinity_map { + char name[AFFINITY_NAME_SIZE]; + uint16_t bit_position; + + QOBJ_FIELDS; +}; +DECLARE_QOBJ_TYPE(affinity_map); + +struct affinity_maps { + struct list *maps; + + bool (*check_use_hook)(const char *affmap_name); + bool (*check_update_hook)(const char *affmap_name, uint16_t new_pos); + void (*update_hook)(const char *affmap_name, uint16_t old_pos, + uint16_t new_pos); + + QOBJ_FIELDS; +}; +DECLARE_QOBJ_TYPE(affinity_maps); + +extern const struct frr_yang_module_info frr_affinity_map_info; + +void affinity_map_set(const char *name, int pos); +void affinity_map_unset(const char *name); +struct affinity_map *affinity_map_get(const char *name); +char *affinity_map_name_get(const int pos); + +bool affinity_map_check_use_hook(const char *affmap_name); +bool affinity_map_check_update_hook(const char *affmap_name, uint16_t new_pos); +void affinity_map_update_hook(const char *affmap_name, uint16_t new_pos); + +void affinity_map_set_check_use_hook(bool (*func)(const char *affmap_name)); +void affinity_map_set_check_update_hook(bool (*func)(const char *affmap_name, + uint16_t new_pos)); +void affinity_map_set_update_hook(void (*func)(const char *affmap_name, + uint16_t old_pos, + uint16_t new_pos)); + +void cli_show_affinity_map(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults); + +void affinity_map_init(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* _ZEBRA_AFFINITYMAP_H */ diff --git a/lib/affinitymap_cli.c b/lib/affinitymap_cli.c new file mode 100644 index 0000000000..a2d5e8eccf --- /dev/null +++ b/lib/affinitymap_cli.c @@ -0,0 +1,107 @@ +/* + * Affinity map northbound CLI implementation. + * + * Copyright 2022 Hiroki Shirokura, LINE Corporation + * Copyright 2022 Masakazu Asama + * Copyright 2022 6WIND S.A. + * + * + * This file is part of Free Range Routing (FRR). + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "lib/command.h" +#include "lib/northbound_cli.h" +#include "lib/affinitymap.h" +#include "lib/affinitymap_cli_clippy.c" + +/* Route map node structure. */ +static int affinity_map_config_write(struct vty *vty); +static struct cmd_node affinitymap_node = { + .name = "affinity-map", + .node = AFFMAP_NODE, + .prompt = "", + .config_write = affinity_map_config_write, +}; + +/* max value is EXT_ADMIN_GROUP_MAX_POSITIONS - 1 */ +DEFPY_YANG_NOSH(affinity_map, affinity_map_cmd, + "affinity-map NAME$name bit-position (0-1023)$position", + "Affinity map configuration\n" + "Affinity attribute name\n" + "Bit position for affinity attribute value\n" + "Bit position\n") +{ + char xpathr[XPATH_MAXLEN]; + + snprintf( + xpathr, sizeof(xpathr), + "/frr-affinity-map:lib/affinity-maps/affinity-map[name='%s']/value", + name); + nb_cli_enqueue_change(vty, xpathr, NB_OP_MODIFY, position_str); + return nb_cli_apply_changes(vty, NULL); +} + +/* max value is EXT_ADMIN_GROUP_MAX_POSITIONS - 1 */ +DEFPY_YANG_NOSH(no_affinity_map, no_affinity_map_cmd, + "no affinity-map NAME$name [bit-position (0-1023)$position]", + NO_STR + "Affinity map configuration\n" + "Affinity attribute name\n" + "Bit position for affinity attribute value\n" + "Bit position\n") +{ + char xpathr[XPATH_MAXLEN]; + + snprintf(xpathr, sizeof(xpathr), + "/frr-affinity-map:lib/affinity-maps/affinity-map[name='%s']", + name); + nb_cli_enqueue_change(vty, xpathr, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static int affinity_map_config_write(struct vty *vty) +{ + const struct lyd_node *dnode; + int written = 0; + + dnode = yang_dnode_get(running_config->dnode, "/frr-affinity-map:lib"); + if (dnode) { + nb_cli_show_dnode_cmds(vty, dnode, false); + written = 1; + } + + return written; +} + +void cli_show_affinity_map(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults __attribute__((__unused__))) +{ + vty_out(vty, "affinity-map %s bit-position %u\n", + yang_dnode_get_string(dnode, "./name"), + yang_dnode_get_uint16(dnode, "./value")); +} + +/* Initialization of affinity map vector. */ +void affinity_map_init(void) +{ + /* CLI commands. */ + install_node(&affinitymap_node); + install_element(CONFIG_NODE, &affinity_map_cmd); + install_element(CONFIG_NODE, &no_affinity_map_cmd); +} diff --git a/lib/affinitymap_northbound.c b/lib/affinitymap_northbound.c new file mode 100644 index 0000000000..331075f5c1 --- /dev/null +++ b/lib/affinitymap_northbound.c @@ -0,0 +1,136 @@ +/* + * affinity map northbound implementation. + * + * Copyright 2022 Hiroki Shirokura, LINE Corporation + * Copyright 2022 Masakazu Asama + * Copyright 2022 6WIND S.A. + * + * This file is part of Free Range Routing (FRR). + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "lib/command.h" +#include "lib/log.h" +#include "lib/northbound.h" +#include "lib/affinitymap.h" + +/* + * XPath: /frr-affinity-map:lib/affinity-maps/affinity-map + */ + +static int lib_affinity_map_create(struct nb_cb_create_args *args) +{ + return NB_OK; +} + +static int lib_affinity_map_destroy(struct nb_cb_destroy_args *args) +{ + const char *name; + + name = yang_dnode_get_string((const struct lyd_node *)args->dnode, + "./name"); + + switch (args->event) { + case NB_EV_VALIDATE: + if (!affinity_map_check_use_hook(name)) + break; + snprintf(args->errmsg, args->errmsg_len, + "affinity-map %s is used", name); + return NB_ERR_VALIDATION; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + affinity_map_unset(name); + break; + } + return NB_OK; +} + +/* + * XPath: /frr-affinity-map:lib/affinity-maps/affinity-map/value + */ +static int lib_affinity_map_value_modify(struct nb_cb_modify_args *args) +{ + const char *name; + char *map_name; + uint16_t pos; + + name = yang_dnode_get_string( + (const struct lyd_node *)args->dnode->parent, "./name"); + + pos = yang_dnode_get_uint16( + (const struct lyd_node *)args->dnode->parent, "./value"); + + switch (args->event) { + case NB_EV_VALIDATE: + map_name = affinity_map_name_get(pos); + if (map_name && + strncmp(map_name, name, AFFINITY_NAME_SIZE) != 0) { + snprintf(args->errmsg, args->errmsg_len, + "bit-position is used by %s.", map_name); + return NB_ERR_VALIDATION; + } + if (!affinity_map_check_update_hook(name, pos)) { + snprintf( + args->errmsg, args->errmsg_len, + "affinity-map new bit-position > 31 but is used with standard admin-groups"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + affinity_map_update_hook(name, pos); + affinity_map_set(name, pos); + break; + } + + return NB_OK; +} + +static int lib_affinity_map_value_destroy(struct nb_cb_destroy_args *args) +{ + return NB_OK; +} + +/* clang-format off */ +const struct frr_yang_module_info frr_affinity_map_info = { + .name = "frr-affinity-map", + .nodes = { + { + .xpath = "/frr-affinity-map:lib/affinity-maps/affinity-map", + .cbs = { + .create = lib_affinity_map_create, + .destroy = lib_affinity_map_destroy, + .cli_show = cli_show_affinity_map, + } + }, + { + .xpath = "/frr-affinity-map:lib/affinity-maps/affinity-map/value", + .cbs = { + .modify = lib_affinity_map_value_modify, + .destroy = lib_affinity_map_value_destroy, + } + }, + { + .xpath = NULL, + }, + } +}; diff --git a/lib/bitfield.h b/lib/bitfield.h index 9af4053daf..79f6f205c3 100644 --- a/lib/bitfield.h +++ b/lib/bitfield.h @@ -72,7 +72,8 @@ DECLARE_MTYPE(BITFIELD); do { \ (v).n = 0; \ (v).m = ((N) / WORD_SIZE + 1); \ - (v).data = XCALLOC(MTYPE_BITFIELD, ((v).m * sizeof(word_t))); \ + (v).data = (word_t *)XCALLOC(MTYPE_BITFIELD, \ + ((v).m * sizeof(word_t))); \ } while (0) /** @@ -268,6 +269,19 @@ static inline unsigned int bf_find_next_set_bit(bitfield_t v, (v).data = NULL; \ } while (0) +static inline bitfield_t bf_copy(bitfield_t src) +{ + bitfield_t dst; + + assert(bf_is_inited(src)); + bf_init(dst, WORD_SIZE * (src.m - 1)); + for (size_t i = 0; i < src.m; i++) + dst.data[i] = src.data[i]; + dst.n = src.n; + return dst; +} + + #ifdef __cplusplus } #endif diff --git a/lib/command.h b/lib/command.h index 8f5d96053c..5aaa6d6cd8 100644 --- a/lib/command.h +++ b/lib/command.h @@ -90,6 +90,7 @@ struct host { }; /* List of CLI nodes. Please remember to update the name array in command.c. */ +/* clang-format off */ enum node_type { AUTH_NODE, /* Authentication mode of vty interface. */ VIEW_NODE, /* View node. Default mode of vty interface. */ @@ -106,6 +107,7 @@ enum node_type { EXTLOG_NODE, /* RFC5424 & co. extended syslog */ KEYCHAIN_NODE, /* Key-chain node. */ KEYCHAIN_KEY_NODE, /* Key-chain key node. */ + AFFMAP_NODE, /* Affinity map node. */ IP_NODE, /* Static ip route node. */ VRF_NODE, /* VRF mode node. */ INTERFACE_NODE, /* Interface mode node. */ @@ -186,6 +188,7 @@ enum node_type { BMP_NODE, /* BMP config under router bgp */ NODE_TYPE_MAX, /* maximum */ }; +/* clang-format on */ extern vector cmdvec; extern const struct message tokennames[]; diff --git a/lib/if.c b/lib/if.c index b75c2a4dbe..be7fe544cd 100644 --- a/lib/if.c +++ b/lib/if.c @@ -35,6 +35,7 @@ #include "buffer.h" #include "log.h" #include "northbound_cli.h" +#include "admin_group.h" #include "lib/if_clippy.c" DEFINE_MTYPE_STATIC(LIB, IF, "Interface"); @@ -1106,6 +1107,45 @@ const char *if_link_type_str(enum zebra_link_type llt) return NULL; } +bool if_link_params_cmp(struct if_link_params *iflp1, + struct if_link_params *iflp2) +{ + struct if_link_params iflp1_copy, iflp2_copy; + + /* Extended admin-groups in if_link_params contain pointers. + * They cannot be compared with memcpy. + * Make copies of if_link_params without ext. admin-groups + * and compare separately the ext. admin-groups. + */ + memcpy(&iflp1_copy, iflp1, sizeof(struct if_link_params)); + memset(&iflp1_copy.ext_admin_grp, 0, sizeof(struct admin_group)); + + memcpy(&iflp2_copy, iflp2, sizeof(struct if_link_params)); + memset(&iflp2_copy.ext_admin_grp, 0, sizeof(struct admin_group)); + + if (memcmp(&iflp1_copy, &iflp2_copy, sizeof(struct if_link_params))) + return false; + + if (!admin_group_cmp(&iflp1->ext_admin_grp, &iflp2->ext_admin_grp)) + return false; + + return true; +} + +void if_link_params_copy(struct if_link_params *dst, struct if_link_params *src) +{ + struct admin_group dst_ag; + + /* backup the admin_group structure that contains a pointer */ + memcpy(&dst_ag, &dst->ext_admin_grp, sizeof(struct admin_group)); + /* copy the if_link_params structure */ + memcpy(dst, src, sizeof(struct if_link_params)); + /* restore the admin_group structure */ + memcpy(&dst->ext_admin_grp, &dst_ag, sizeof(struct admin_group)); + /* copy src->ext_admin_grp data to dst->ext_admin_grp data memory */ + admin_group_copy(&dst->ext_admin_grp, &src->ext_admin_grp); +} + struct if_link_params *if_link_params_get(struct interface *ifp) { return ifp->link_params; @@ -1153,6 +1193,8 @@ struct if_link_params *if_link_params_init(struct interface *ifp) iflp = XCALLOC(MTYPE_IF_LINK_PARAMS, sizeof(struct if_link_params)); + admin_group_init(&iflp->ext_admin_grp); + ifp->link_params = iflp; return iflp; @@ -1160,6 +1202,10 @@ struct if_link_params *if_link_params_init(struct interface *ifp) void if_link_params_free(struct interface *ifp) { + if (!ifp->link_params) + return; + + admin_group_term(&ifp->link_params->ext_admin_grp); XFREE(MTYPE_IF_LINK_PARAMS, ifp->link_params); } diff --git a/lib/if.h b/lib/if.h index acd60e9d06..b79ed5ad84 100644 --- a/lib/if.h +++ b/lib/if.h @@ -26,6 +26,7 @@ #include "memory.h" #include "qobj.h" #include "hook.h" +#include "admin_group.h" #ifdef __cplusplus extern "C" { @@ -153,6 +154,15 @@ struct if_stats { #define MAX_CLASS_TYPE 8 #define MAX_PKT_LOSS 50.331642 +enum affinity_mode { + /* RFC7308 Extended Administrative group */ + AFFINITY_MODE_EXTENDED = 0, + /* RFC3630/RFC5305/RFC5329 Administrative group */ + AFFINITY_MODE_STANDARD = 1, + /* Standard and Extended Administrative group */ + AFFINITY_MODE_BOTH = 2, +}; + /* * Link Parameters Status: * equal to 0: unset @@ -172,6 +182,7 @@ struct if_stats { #define LP_RES_BW 0x0400 #define LP_AVA_BW 0x0800 #define LP_USE_BW 0x1000 +#define LP_EXTEND_ADM_GRP 0x2000 #define IS_PARAM_UNSET(lp, st) !(lp->lp_status & st) #define IS_PARAM_SET(lp, st) (lp->lp_status & st) @@ -181,7 +192,10 @@ struct if_stats { #define UNSET_PARAM(lp, st) (lp->lp_status) &= ~(st) #define RESET_LINK_PARAM(lp) (lp->lp_status = LP_UNSET) -/* Link Parameters for Traffic Engineering */ +/* Link Parameters for Traffic Engineering + * Do not forget to update if_link_params_copy() + * and if_link_params_cmp() when updating the structure + */ struct if_link_params { uint32_t lp_status; /* Status of Link Parameters: */ uint32_t te_metric; /* Traffic Engineering metric */ @@ -190,7 +204,8 @@ struct if_link_params { float max_rsv_bw; /* Maximum Reservable Bandwidth */ float unrsv_bw[MAX_CLASS_TYPE]; /* Unreserved Bandwidth per Class Type (8) */ - uint32_t admin_grp; /* Administrative group */ + uint32_t admin_grp; /* RFC5305/RFC5329 Administrative group */ + struct admin_group ext_admin_grp; /* RFC7308 Extended Admin group */ uint32_t rmt_as; /* Remote AS number */ struct in_addr rmt_ip; /* Remote IP address */ uint32_t av_delay; /* Link Average Delay */ @@ -592,6 +607,10 @@ struct nbr_connected *nbr_connected_check(struct interface *, struct prefix *); struct connected *connected_get_linklocal(struct interface *ifp); /* link parameters */ +bool if_link_params_cmp(struct if_link_params *iflp1, + struct if_link_params *iflp2); +void if_link_params_copy(struct if_link_params *dst, + struct if_link_params *src); struct if_link_params *if_link_params_get(struct interface *); struct if_link_params *if_link_params_enable(struct interface *ifp); struct if_link_params *if_link_params_init(struct interface *ifp); diff --git a/lib/link_state.c b/lib/link_state.c index c59cd040c8..9649a5f375 100644 --- a/lib/link_state.c +++ b/lib/link_state.c @@ -192,6 +192,8 @@ struct ls_attributes *ls_attributes_new(struct ls_node_id adv, return NULL; } + admin_group_init(&new->ext_admin_group); + return new; } @@ -215,6 +217,8 @@ void ls_attributes_del(struct ls_attributes *attr) ls_attributes_srlg_del(attr); + admin_group_term(&attr->ext_admin_group); + XFREE(MTYPE_LS_DB, attr); } @@ -246,6 +250,9 @@ int ls_attributes_same(struct ls_attributes *l1, struct ls_attributes *l2) if (CHECK_FLAG(l1->flags, LS_ATTR_ADM_GRP) && (l1->standard.admin_group != l2->standard.admin_group)) return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_EXT_ADM_GRP) && + !admin_group_cmp(&l1->ext_admin_group, &l2->ext_admin_group)) + return 0; if (CHECK_FLAG(l1->flags, LS_ATTR_LOCAL_ADDR) && !IPV4_ADDR_SAME(&l1->standard.local, &l2->standard.local)) return 0; @@ -1206,9 +1213,12 @@ stream_failure: static struct ls_attributes *ls_parse_attributes(struct stream *s) { struct ls_attributes *attr; + uint8_t nb_ext_adm_grp; + uint32_t bitmap_data; size_t len; attr = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_attributes)); + admin_group_init(&attr->ext_admin_group); attr->srlgs = NULL; STREAM_GET(&attr->adv, s, sizeof(struct ls_node_id)); @@ -1223,6 +1233,15 @@ static struct ls_attributes *ls_parse_attributes(struct stream *s) STREAM_GETL(s, attr->standard.te_metric); if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP)) STREAM_GETL(s, attr->standard.admin_group); + if (CHECK_FLAG(attr->flags, LS_ATTR_EXT_ADM_GRP)) { + /* Extended Administrative Group */ + STREAM_GETC(s, nb_ext_adm_grp); + for (size_t i = 0; i < nb_ext_adm_grp; i++) { + STREAM_GETL(s, bitmap_data); + admin_group_bulk_set(&attr->ext_admin_group, + bitmap_data, i); + } + } if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR)) attr->standard.local.s_addr = stream_get_ipv4(s); if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR)) @@ -1430,7 +1449,7 @@ static int ls_format_node(struct stream *s, struct ls_node *node) static int ls_format_attributes(struct stream *s, struct ls_attributes *attr) { - size_t len; + size_t len, nb_ext_adm_grp; /* Push Advertise node information first */ stream_put(s, &attr->adv, sizeof(struct ls_node_id)); @@ -1449,6 +1468,14 @@ static int ls_format_attributes(struct stream *s, struct ls_attributes *attr) stream_putl(s, attr->standard.te_metric); if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP)) stream_putl(s, attr->standard.admin_group); + if (CHECK_FLAG(attr->flags, LS_ATTR_EXT_ADM_GRP)) { + /* Extended Administrative Group */ + nb_ext_adm_grp = admin_group_nb_words(&attr->ext_admin_group); + stream_putc(s, nb_ext_adm_grp); + for (size_t i = 0; i < nb_ext_adm_grp; i++) + stream_putl(s, admin_group_get_offset( + &attr->ext_admin_group, i)); + } if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR)) stream_put_ipv4(s, attr->standard.local.s_addr); if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR)) @@ -2166,9 +2193,11 @@ void ls_show_vertices(struct ls_ted *ted, struct vty *vty, static void ls_show_edge_vty(struct ls_edge *edge, struct vty *vty, bool verbose) { + char admin_group_buf[ADMIN_GROUP_PRINT_MAX_SIZE]; struct ls_attributes *attr; struct sbuf sbuf; char buf[INET6_BUFSIZ]; + int indent; attr = edge->attributes; sbuf_init(&sbuf, NULL, 0); @@ -2198,6 +2227,20 @@ static void ls_show_edge_vty(struct ls_edge *edge, struct vty *vty, if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP)) sbuf_push(&sbuf, 4, "Admin Group: 0x%x\n", attr->standard.admin_group); + if (CHECK_FLAG(attr->flags, LS_ATTR_EXT_ADM_GRP) && + admin_group_nb_words(&attr->ext_admin_group) != 0) { + indent = 4; + sbuf_push(&sbuf, indent, "Ext Admin Group: %s\n", + admin_group_string( + admin_group_buf, ADMIN_GROUP_PRINT_MAX_SIZE, + indent + strlen("Ext Admin Group: "), + &attr->ext_admin_group)); + if (admin_group_buf[0] != '\0' && + (sbuf.pos + strlen(admin_group_buf) + + SBUF_DEFAULT_SIZE / 2) < sbuf.size) + sbuf_push(&sbuf, indent + 2, "Bit positions: %s\n", + admin_group_buf); + } if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR)) sbuf_push(&sbuf, 4, "Local IPv4 address: %pI4\n", &attr->standard.local); @@ -2308,8 +2351,13 @@ end: static void ls_show_edge_json(struct ls_edge *edge, struct json_object *json) { struct ls_attributes *attr; - struct json_object *jte, *jbw, *jobj, *jsr = NULL, *jsrlg; + struct json_object *jte, *jbw, *jobj, *jsr = NULL, *jsrlg, *js_ext_ag, + *js_ext_ag_arr_word, + *js_ext_ag_arr_bit; char buf[INET6_BUFSIZ]; + char buf_ag[strlen("0xffffffff") + 1]; + uint32_t bitmap; + size_t i; attr = edge->attributes; @@ -2333,6 +2381,30 @@ static void ls_show_edge_json(struct ls_edge *edge, struct json_object *json) if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP)) json_object_int_add(jte, "admin-group", attr->standard.admin_group); + if (CHECK_FLAG(attr->flags, LS_ATTR_EXT_ADM_GRP)) { + js_ext_ag = json_object_new_object(); + json_object_object_add(jte, "extAdminGroup", js_ext_ag); + js_ext_ag_arr_word = json_object_new_array(); + json_object_object_add(js_ext_ag, "words", js_ext_ag_arr_word); + js_ext_ag_arr_bit = json_object_new_array(); + json_object_object_add(js_ext_ag, "bitPositions", + js_ext_ag_arr_bit); + for (i = 0; i < admin_group_nb_words(&attr->ext_admin_group); + i++) { + bitmap = admin_group_get_offset(&attr->ext_admin_group, + i); + snprintf(buf_ag, sizeof(buf_ag), "0x%08x", bitmap); + json_object_array_add(js_ext_ag_arr_word, + json_object_new_string(buf_ag)); + } + for (i = 0; + i < (admin_group_size(&attr->ext_admin_group) * WORD_SIZE); + i++) { + if (admin_group_get(&attr->ext_admin_group, i)) + json_object_array_add(js_ext_ag_arr_bit, + json_object_new_int(i)); + } + } if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR)) { snprintfrr(buf, INET6_BUFSIZ, "%pI4", &attr->standard.local); json_object_string_add(jte, "local-address", buf); diff --git a/lib/link_state.h b/lib/link_state.h index ed315452da..35e6c9311b 100644 --- a/lib/link_state.h +++ b/lib/link_state.h @@ -25,6 +25,7 @@ #ifndef _FRR_LINK_STATE_H_ #define _FRR_LINK_STATE_H_ +#include "admin_group.h" #include "typesafe.h" #ifdef __cplusplus @@ -169,6 +170,7 @@ struct ls_node { #define LS_ATTR_ADJ_SID6 0x04000000 #define LS_ATTR_BCK_ADJ_SID6 0x08000000 #define LS_ATTR_SRLG 0x10000000 +#define LS_ATTR_EXT_ADM_GRP 0x20000000 /* Link State Attributes */ struct ls_attributes { @@ -202,6 +204,7 @@ struct ls_attributes { float rsv_bw; /* Reserved Bandwidth */ float used_bw; /* Utilized Bandwidth */ } extended; + struct admin_group ext_admin_group; /* Extended Admin. Group */ #define ADJ_PRI_IPV4 0 #define ADJ_BCK_IPV4 1 #define ADJ_PRI_IPV6 2 diff --git a/lib/sbuf.c b/lib/sbuf.c index c04af153b1..3f1b02eaf8 100644 --- a/lib/sbuf.c +++ b/lib/sbuf.c @@ -33,8 +33,8 @@ void sbuf_init(struct sbuf *dest, char *buf, size_t size) dest->buf = buf; dest->size = size; } else { - dest->buf = XMALLOC(MTYPE_TMP, 4096); - dest->size = 4096; + dest->buf = XMALLOC(MTYPE_TMP, SBUF_DEFAULT_SIZE); + dest->size = SBUF_DEFAULT_SIZE; } dest->pos = 0; diff --git a/lib/sbuf.h b/lib/sbuf.h index aaa2db0edb..e5a43c0e37 100644 --- a/lib/sbuf.h +++ b/lib/sbuf.h @@ -64,6 +64,8 @@ extern "C" { * the string returned in parser_log. */ +#define SBUF_DEFAULT_SIZE 8192 + struct sbuf { bool fixed; char *buf; diff --git a/lib/subdir.am b/lib/subdir.am index dcff31ebba..8d00668c8c 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -7,6 +7,10 @@ lib_libfrr_la_LDFLAGS = $(LIB_LDFLAGS) -version-info 0:0:0 -Xlinker -e_libfrr_ve lib_libfrr_la_LIBADD = $(LIBCAP) $(UNWIND_LIBS) $(LIBYANG_LIBS) $(LUA_LIB) $(UST_LIBS) $(LIBCRYPT) $(LIBDL) $(LIBM) lib_libfrr_la_SOURCES = \ + lib/admin_group.c \ + lib/affinitymap.c \ + lib/affinitymap_cli.c \ + lib/affinitymap_northbound.c \ lib/agg_table.c \ lib/atomlist.c \ lib/base64.c \ @@ -127,6 +131,7 @@ lib_libfrr_la_SOURCES = \ # end nodist_lib_libfrr_la_SOURCES = \ + yang/frr-affinity-map.yang.c \ yang/frr-filter.yang.c \ yang/frr-interface.yang.c \ yang/frr-route-map.yang.c \ @@ -146,6 +151,7 @@ lib_libfrr_la_SOURCES += lib/db.c endif clippy_scan += \ + lib/affinitymap_cli.c \ lib/if.c \ lib/filter_cli.c \ lib/log_vty.c \ @@ -160,6 +166,8 @@ clippy_scan += \ # end pkginclude_HEADERS += \ + lib/admin_group.h \ + lib/affinitymap.h \ lib/agg_table.h \ lib/atomlist.h \ lib/base64.h \ diff --git a/lib/yang.c b/lib/yang.c index ef1cf898aa..ec8de85e90 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -88,6 +88,7 @@ static const char *const frr_native_modules[] = { "frr-interface", "frr-vrf", "frr-routing", + "frr-affinity-map", "frr-route-map", "frr-nexthop", "frr-ripd", diff --git a/lib/zclient.c b/lib/zclient.c index 42d5c33a1b..57c038a03f 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2405,9 +2405,9 @@ static int zclient_handle_error(ZAPI_CALLBACK_ARGS) static int link_params_set_value(struct stream *s, struct interface *ifp) { - uint8_t link_params_enabled; + uint8_t link_params_enabled, nb_ext_adm_grp; struct if_link_params *iflp; - uint32_t bwclassnum; + uint32_t bwclassnum, bitmap_data; iflp = if_link_params_get(ifp); @@ -2436,6 +2436,15 @@ static int link_params_set_value(struct stream *s, struct interface *ifp) __func__, bwclassnum, MAX_CLASS_TYPE); } STREAM_GETL(s, iflp->admin_grp); + + /* Extended Administrative Group */ + admin_group_clear(&iflp->ext_admin_grp); + STREAM_GETC(s, nb_ext_adm_grp); + for (size_t i = 0; i < nb_ext_adm_grp; i++) { + STREAM_GETL(s, bitmap_data); + admin_group_bulk_set(&iflp->ext_admin_grp, bitmap_data, i); + } + STREAM_GETL(s, iflp->rmt_as); iflp->rmt_ip.s_addr = stream_get_ipv4(s); @@ -2459,9 +2468,9 @@ struct interface *zebra_interface_link_params_read(struct stream *s, bool *changed) { struct if_link_params *iflp; - struct if_link_params iflp_prev; + struct if_link_params iflp_prev = {0}; ifindex_t ifindex; - bool iflp_prev_set; + bool iflp_prev_set = false; STREAM_GETL(s, ifindex); @@ -2474,11 +2483,13 @@ struct interface *zebra_interface_link_params_read(struct stream *s, return NULL; } - if (if_link_params_get(ifp)) { + iflp = if_link_params_get(ifp); + + if (iflp) { iflp_prev_set = true; - memcpy(&iflp_prev, ifp->link_params, sizeof(iflp_prev)); - } else - iflp_prev_set = false; + admin_group_init(&iflp_prev.ext_admin_grp); + if_link_params_copy(&iflp_prev, iflp); + } /* read the link_params from stream * Free ifp->link_params if the stream has no params @@ -2487,24 +2498,28 @@ struct interface *zebra_interface_link_params_read(struct stream *s, if (link_params_set_value(s, ifp) != 0) goto stream_failure; - if (changed == NULL) - return ifp; + if (changed != NULL) { + iflp = if_link_params_get(ifp); - iflp = if_link_params_get(ifp); - - if (iflp_prev_set && iflp) { - if (memcmp(&iflp_prev, iflp, sizeof(iflp_prev))) - *changed = true; - else + if (iflp_prev_set && iflp) { + if (if_link_params_cmp(&iflp_prev, iflp)) + *changed = false; + else + *changed = true; + } else if (!iflp_prev_set && !iflp) *changed = false; - } else if (!iflp_prev_set && !iflp) - *changed = false; - else - *changed = true; + else + *changed = true; + } + + if (iflp_prev_set) + admin_group_term(&iflp_prev.ext_admin_grp); return ifp; stream_failure: + if (iflp_prev_set) + admin_group_term(&iflp_prev.ext_admin_grp); return NULL; } @@ -2553,10 +2568,11 @@ stream_failure: size_t zebra_interface_link_params_write(struct stream *s, struct interface *ifp) { - size_t w; + size_t w, nb_ext_adm_grp; struct if_link_params *iflp; int i; + if (s == NULL || ifp == NULL) return 0; @@ -2582,6 +2598,13 @@ size_t zebra_interface_link_params_write(struct stream *s, w += stream_putf(s, iflp->unrsv_bw[i]); w += stream_putl(s, iflp->admin_grp); + + /* Extended Administrative Group */ + nb_ext_adm_grp = admin_group_nb_words(&iflp->ext_admin_grp); + w += stream_putc(s, nb_ext_adm_grp); + for (size_t i = 0; i < nb_ext_adm_grp; i++) + stream_putl(s, admin_group_get_offset(&iflp->ext_admin_grp, i)); + w += stream_putl(s, iflp->rmt_as); w += stream_put_in_addr(s, &iflp->rmt_ip); diff --git a/tests/topotests/isis_te_topo1/reference/ted_step10.json b/tests/topotests/isis_te_topo1/reference/ted_step10.json new file mode 100644 index 0000000000..7d017b3430 --- /dev/null +++ b/tests/topotests/isis_te_topo1/reference/ted_step10.json @@ -0,0 +1,969 @@ +{ + "ted":{ + "name":"ISIS", + "key":1, + "verticesCount":4, + "edgesCount":16, + "subnetsCount":24, + "vertices":[ + { + "vertex-id":1, + "status":"Sync", + "origin":"ISIS_L2", + "name":"r1", + "router-id":"10.0.255.1" + }, + { + "vertex-id":2, + "status":"Sync", + "origin":"ISIS_L2", + "name":"r2", + "router-id":"10.0.255.2" + }, + { + "vertex-id":3, + "status":"Sync", + "origin":"ISIS_L2", + "name":"r3", + "router-id":"10.0.255.3", + "router-id-v6":"2001:db8:1000::3" + }, + { + "vertex-id":4, + "status":"Sync", + "origin":"ISIS_L2", + "name":"r4", + "router-id":"10.0.255.4", + "segment-routing":{ + "srgb-size":10000, + "srgb-lower":10000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":5000, + "msd":12 + } + } + ], + "edges":[ + { + "edge-id":1, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "local-vertex-id":1, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "extAdminGroup":{ + "words":[ + "0x80000001", + "0x00000000", + "0x00000000", + "0x00000000", + "0x00000001" + ], + "bitPositions":[ + 0, + 31, + 128 + ] + }, + "local-address-v6":"2001:db8::1", + "remote-address-v6":"2001:db8::2", + "max-link-bandwidth":99999997952, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + } + }, + { + "edge-id":2, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":1, + "metric":10, + "edge-attributes":{ + "local-address-v6":"2001:db8::2", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":65537, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "local-vertex-id":1, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "local-address-v6":"2001:db8:1::1:1", + "remote-address-v6":"2001:db8:1::1:2", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":65538, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":1, + "metric":10, + "edge-attributes":{ + "local-address-v6":"2001:db8:1::1:2", + "remote-address-v6":"2001:db8:1::1:1", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":196610, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":3, + "metric":10, + "edge-attributes":{ + "local-address-v6":"2001:db8:3::3:2", + "remote-address-v6":"2001:db8:3::3:3", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":196611, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "local-vertex-id":3, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "admin-group":32, + "local-address-v6":"2001:db8:3::3:3", + "remote-address-v6":"2001:db8:3::3:2", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":196612, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "local-vertex-id":4, + "remote-vertex-id":3, + "metric":10, + "edge-attributes":{ + "local-address-v6":"2001:db8:5::3:4", + "remote-address-v6":"2001:db8:5::4:3", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0xb0", + "weight":0 + } + ] + }, + { + "edge-id":262147, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "local-vertex-id":3, + "remote-vertex-id":4, + "metric":10, + "edge-attributes":{ + "te-metric":10, + "local-address-v6":"2001:db8:5::4:3", + "remote-address-v6":"2001:db8:5::3:4", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ], + "delay":50000 + } + }, + { + "edge-id":167772161, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "local-vertex-id":1, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "extAdminGroup":{ + "words":[ + "0x80000001", + "0x00000000", + "0x00000000", + "0x00000000", + "0x00000001" + ], + "bitPositions":[ + 0, + 31, + 128 + ] + }, + "local-address":"10.0.0.1", + "remote-address":"10.0.0.2", + "max-link-bandwidth":99999997952, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + } + }, + { + "edge-id":167772162, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":1, + "metric":10, + "edge-attributes":{ + "local-address":"10.0.0.2", + "remote-address":"10.0.0.1", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":167772417, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "local-vertex-id":1, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "local-address":"10.0.1.1", + "remote-address":"10.0.1.2", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":167772418, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":1, + "metric":10, + "edge-attributes":{ + "local-address":"10.0.1.2", + "remote-address":"10.0.1.1", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":167772930, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":3, + "metric":10, + "edge-attributes":{ + "local-address":"10.0.3.2", + "remote-address":"10.0.3.3", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":167772931, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "local-vertex-id":3, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "admin-group":32, + "local-address":"10.0.3.3", + "remote-address":"10.0.3.2", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":167773186, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":4, + "metric":10, + "edge-attributes":{ + "te-metric":30, + "local-address":"10.0.4.2", + "remote-address":"10.0.4.4", + "max-link-bandwidth":99999997952, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ], + "delay":25000 + } + }, + { + "edge-id":167773188, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "local-vertex-id":4, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "local-address":"10.0.4.4", + "remote-address":"10.0.4.2", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ], + "delay":20000, + "jitter":10000 + }, + "segment-routing":[ + { + "adj-sid":5000, + "flags":"0x30", + "weight":0 + } + ] + } + ], + "subnets":[ + { + "subnet-id":"10.0.0.1\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"10.0.0.2\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.1.1\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"10.0.1.2\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.3.2\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.3.3\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"10.0.4.2\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.4.4\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "vertex-id":4, + "metric":10 + }, + { + "subnet-id":"10.0.255.1\/32", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"10.0.255.2\/32", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.255.3\/32", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"10.0.255.4\/32", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "vertex-id":4, + "metric":10, + "segment-routing":{ + "pref-sid":400, + "algo":0, + "flags":"0x60" + } + }, + { + "subnet-id":"2001:db8::1\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"2001:db8::2\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"2001:db8:1::1:1\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"2001:db8:1::1:2\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"2001:db8:3::3:2\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"2001:db8:3::3:3\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"2001:db8:5::3:4\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "vertex-id":4, + "metric":10 + }, + { + "subnet-id":"2001:db8:5::4:3\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"2001:db8:ffff::1\/128", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"2001:db8:ffff::2\/128", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"2001:db8:ffff::3\/128", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"2001:db8:ffff::4\/128", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "vertex-id":4, + "metric":10, + "segment-routing":{ + "pref-sid":1400, + "algo":0, + "flags":"0x60" + } + } + ] + } +} diff --git a/tests/topotests/isis_te_topo1/reference/ted_step7.json b/tests/topotests/isis_te_topo1/reference/ted_step7.json new file mode 100644 index 0000000000..447febce48 --- /dev/null +++ b/tests/topotests/isis_te_topo1/reference/ted_step7.json @@ -0,0 +1,971 @@ +{ + "ted":{ + "name":"ISIS", + "key":1, + "verticesCount":4, + "edgesCount":16, + "subnetsCount":24, + "vertices":[ + { + "vertex-id":1, + "status":"Sync", + "origin":"ISIS_L2", + "name":"r1", + "router-id":"10.0.255.1" + }, + { + "vertex-id":2, + "status":"Sync", + "origin":"ISIS_L2", + "name":"r2", + "router-id":"10.0.255.2" + }, + { + "vertex-id":3, + "status":"Sync", + "origin":"ISIS_L2", + "name":"r3", + "router-id":"10.0.255.3", + "router-id-v6":"2001:db8:1000::3" + }, + { + "vertex-id":4, + "status":"Sync", + "origin":"ISIS_L2", + "name":"r4", + "router-id":"10.0.255.4", + "segment-routing":{ + "srgb-size":10000, + "srgb-lower":10000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":5000, + "msd":12 + } + } + ], + "edges":[ + { + "edge-id":1, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "local-vertex-id":1, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "extAdminGroup":{ + "words":[ + "0x80000001", + "0x00000001", + "0x00000000", + "0x00000000", + "0x00000001" + ], + "bitPositions":[ + 0, + 31, + 32, + 128 + ] + }, + "local-address-v6":"2001:db8::1", + "remote-address-v6":"2001:db8::2", + "max-link-bandwidth":99999997952, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + } + }, + { + "edge-id":2, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":1, + "metric":10, + "edge-attributes":{ + "local-address-v6":"2001:db8::2", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":65537, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "local-vertex-id":1, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "local-address-v6":"2001:db8:1::1:1", + "remote-address-v6":"2001:db8:1::1:2", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":65538, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":1, + "metric":10, + "edge-attributes":{ + "local-address-v6":"2001:db8:1::1:2", + "remote-address-v6":"2001:db8:1::1:1", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":196610, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":3, + "metric":10, + "edge-attributes":{ + "local-address-v6":"2001:db8:3::3:2", + "remote-address-v6":"2001:db8:3::3:3", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":196611, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "local-vertex-id":3, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "admin-group":32, + "local-address-v6":"2001:db8:3::3:3", + "remote-address-v6":"2001:db8:3::3:2", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":196612, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "local-vertex-id":4, + "remote-vertex-id":3, + "metric":10, + "edge-attributes":{ + "local-address-v6":"2001:db8:5::3:4", + "remote-address-v6":"2001:db8:5::4:3", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0xb0", + "weight":0 + } + ] + }, + { + "edge-id":262147, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "local-vertex-id":3, + "remote-vertex-id":4, + "metric":10, + "edge-attributes":{ + "te-metric":10, + "local-address-v6":"2001:db8:5::4:3", + "remote-address-v6":"2001:db8:5::3:4", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ], + "delay":50000 + } + }, + { + "edge-id":167772161, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "local-vertex-id":1, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "extAdminGroup":{ + "words":[ + "0x80000001", + "0x00000001", + "0x00000000", + "0x00000000", + "0x00000001" + ], + "bitPositions":[ + 0, + 31, + 32, + 128 + ] + }, + "local-address":"10.0.0.1", + "remote-address":"10.0.0.2", + "max-link-bandwidth":99999997952, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + } + }, + { + "edge-id":167772162, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":1, + "metric":10, + "edge-attributes":{ + "local-address":"10.0.0.2", + "remote-address":"10.0.0.1", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":167772417, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "local-vertex-id":1, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "local-address":"10.0.1.1", + "remote-address":"10.0.1.2", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":167772418, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":1, + "metric":10, + "edge-attributes":{ + "local-address":"10.0.1.2", + "remote-address":"10.0.1.1", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":167772930, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":3, + "metric":10, + "edge-attributes":{ + "local-address":"10.0.3.2", + "remote-address":"10.0.3.3", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":167772931, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "local-vertex-id":3, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "admin-group":32, + "local-address":"10.0.3.3", + "remote-address":"10.0.3.2", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":167773186, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":4, + "metric":10, + "edge-attributes":{ + "te-metric":30, + "local-address":"10.0.4.2", + "remote-address":"10.0.4.4", + "max-link-bandwidth":99999997952, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ], + "delay":25000 + } + }, + { + "edge-id":167773188, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "local-vertex-id":4, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "local-address":"10.0.4.4", + "remote-address":"10.0.4.2", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ], + "delay":20000, + "jitter":10000 + }, + "segment-routing":[ + { + "adj-sid":5000, + "flags":"0x30", + "weight":0 + } + ] + } + ], + "subnets":[ + { + "subnet-id":"10.0.0.1\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"10.0.0.2\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.1.1\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"10.0.1.2\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.3.2\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.3.3\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"10.0.4.2\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.4.4\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "vertex-id":4, + "metric":10 + }, + { + "subnet-id":"10.0.255.1\/32", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"10.0.255.2\/32", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.255.3\/32", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"10.0.255.4\/32", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "vertex-id":4, + "metric":10, + "segment-routing":{ + "pref-sid":400, + "algo":0, + "flags":"0x60" + } + }, + { + "subnet-id":"2001:db8::1\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"2001:db8::2\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"2001:db8:1::1:1\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"2001:db8:1::1:2\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"2001:db8:3::3:2\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"2001:db8:3::3:3\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"2001:db8:5::3:4\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "vertex-id":4, + "metric":10 + }, + { + "subnet-id":"2001:db8:5::4:3\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"2001:db8:ffff::1\/128", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"2001:db8:ffff::2\/128", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"2001:db8:ffff::3\/128", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"2001:db8:ffff::4\/128", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "vertex-id":4, + "metric":10, + "segment-routing":{ + "pref-sid":1400, + "algo":0, + "flags":"0x60" + } + } + ] + } +} diff --git a/tests/topotests/isis_te_topo1/reference/ted_step8.json b/tests/topotests/isis_te_topo1/reference/ted_step8.json new file mode 100644 index 0000000000..510e034eba --- /dev/null +++ b/tests/topotests/isis_te_topo1/reference/ted_step8.json @@ -0,0 +1,971 @@ +{ + "ted":{ + "name":"ISIS", + "key":1, + "verticesCount":4, + "edgesCount":16, + "subnetsCount":24, + "vertices":[ + { + "vertex-id":1, + "status":"Sync", + "origin":"ISIS_L2", + "name":"r1", + "router-id":"10.0.255.1" + }, + { + "vertex-id":2, + "status":"Sync", + "origin":"ISIS_L2", + "name":"r2", + "router-id":"10.0.255.2" + }, + { + "vertex-id":3, + "status":"Sync", + "origin":"ISIS_L2", + "name":"r3", + "router-id":"10.0.255.3", + "router-id-v6":"2001:db8:1000::3" + }, + { + "vertex-id":4, + "status":"Sync", + "origin":"ISIS_L2", + "name":"r4", + "router-id":"10.0.255.4", + "segment-routing":{ + "srgb-size":10000, + "srgb-lower":10000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":5000, + "msd":12 + } + } + ], + "edges":[ + { + "edge-id":1, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "local-vertex-id":1, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "extAdminGroup":{ + "words":[ + "0x80000001", + "0x00000002", + "0x00000000", + "0x00000000", + "0x00000001" + ], + "bitPositions":[ + 0, + 31, + 33, + 128 + ] + }, + "local-address-v6":"2001:db8::1", + "remote-address-v6":"2001:db8::2", + "max-link-bandwidth":99999997952, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + } + }, + { + "edge-id":2, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":1, + "metric":10, + "edge-attributes":{ + "local-address-v6":"2001:db8::2", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":65537, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "local-vertex-id":1, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "local-address-v6":"2001:db8:1::1:1", + "remote-address-v6":"2001:db8:1::1:2", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":65538, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":1, + "metric":10, + "edge-attributes":{ + "local-address-v6":"2001:db8:1::1:2", + "remote-address-v6":"2001:db8:1::1:1", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":196610, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":3, + "metric":10, + "edge-attributes":{ + "local-address-v6":"2001:db8:3::3:2", + "remote-address-v6":"2001:db8:3::3:3", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":196611, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "local-vertex-id":3, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "admin-group":32, + "local-address-v6":"2001:db8:3::3:3", + "remote-address-v6":"2001:db8:3::3:2", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":196612, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "local-vertex-id":4, + "remote-vertex-id":3, + "metric":10, + "edge-attributes":{ + "local-address-v6":"2001:db8:5::3:4", + "remote-address-v6":"2001:db8:5::4:3", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0xb0", + "weight":0 + } + ] + }, + { + "edge-id":262147, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "local-vertex-id":3, + "remote-vertex-id":4, + "metric":10, + "edge-attributes":{ + "te-metric":10, + "local-address-v6":"2001:db8:5::4:3", + "remote-address-v6":"2001:db8:5::3:4", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ], + "delay":50000 + } + }, + { + "edge-id":167772161, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "local-vertex-id":1, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "extAdminGroup":{ + "words":[ + "0x80000001", + "0x00000002", + "0x00000000", + "0x00000000", + "0x00000001" + ], + "bitPositions":[ + 0, + 31, + 33, + 128 + ] + }, + "local-address":"10.0.0.1", + "remote-address":"10.0.0.2", + "max-link-bandwidth":99999997952, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + } + }, + { + "edge-id":167772162, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":1, + "metric":10, + "edge-attributes":{ + "local-address":"10.0.0.2", + "remote-address":"10.0.0.1", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":167772417, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "local-vertex-id":1, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "local-address":"10.0.1.1", + "remote-address":"10.0.1.2", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":167772418, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":1, + "metric":10, + "edge-attributes":{ + "local-address":"10.0.1.2", + "remote-address":"10.0.1.1", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":167772930, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":3, + "metric":10, + "edge-attributes":{ + "local-address":"10.0.3.2", + "remote-address":"10.0.3.3", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":167772931, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "local-vertex-id":3, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "admin-group":32, + "local-address":"10.0.3.3", + "remote-address":"10.0.3.2", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ] + } + }, + { + "edge-id":167773186, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":4, + "metric":10, + "edge-attributes":{ + "te-metric":30, + "local-address":"10.0.4.2", + "remote-address":"10.0.4.4", + "max-link-bandwidth":99999997952, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ], + "delay":25000 + } + }, + { + "edge-id":167773188, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "local-vertex-id":4, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "local-address":"10.0.4.4", + "remote-address":"10.0.4.2", + "max-link-bandwidth":1250000, + "max-resv-link-bandwidth":1250000, + "unreserved-bandwidth":[ + { + "class-type-0":1250000 + }, + { + "class-type-1":1250000 + }, + { + "class-type-2":1250000 + }, + { + "class-type-3":1250000 + }, + { + "class-type-4":1250000 + }, + { + "class-type-5":1250000 + }, + { + "class-type-6":1250000 + }, + { + "class-type-7":1250000 + } + ], + "delay":20000, + "jitter":10000 + }, + "segment-routing":[ + { + "adj-sid":5000, + "flags":"0x30", + "weight":0 + } + ] + } + ], + "subnets":[ + { + "subnet-id":"10.0.0.1\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"10.0.0.2\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.1.1\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"10.0.1.2\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.3.2\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.3.3\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"10.0.4.2\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.4.4\/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "vertex-id":4, + "metric":10 + }, + { + "subnet-id":"10.0.255.1\/32", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"10.0.255.2\/32", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.255.3\/32", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"10.0.255.4\/32", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "vertex-id":4, + "metric":10, + "segment-routing":{ + "pref-sid":400, + "algo":0, + "flags":"0x60" + } + }, + { + "subnet-id":"2001:db8::1\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"2001:db8::2\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"2001:db8:1::1:1\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"2001:db8:1::1:2\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"2001:db8:3::3:2\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"2001:db8:3::3:3\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"2001:db8:5::3:4\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "vertex-id":4, + "metric":10 + }, + { + "subnet-id":"2001:db8:5::4:3\/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"2001:db8:ffff::1\/128", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"2001:db8:ffff::2\/128", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"2001:db8:ffff::3\/128", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"2001:db8:ffff::4\/128", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "vertex-id":4, + "metric":10, + "segment-routing":{ + "pref-sid":1400, + "algo":0, + "flags":"0x60" + } + } + ] + } +} diff --git a/tests/topotests/isis_te_topo1/reference/ted_step9.json b/tests/topotests/isis_te_topo1/reference/ted_step9.json new file mode 120000 index 0000000000..1c01a91c26 --- /dev/null +++ b/tests/topotests/isis_te_topo1/reference/ted_step9.json @@ -0,0 +1 @@ +ted_step8.json \ No newline at end of file diff --git a/tests/topotests/isis_te_topo1/test_isis_te_topo1.py b/tests/topotests/isis_te_topo1/test_isis_te_topo1.py index 0e453d30e3..213b3f9f3c 100644 --- a/tests/topotests/isis_te_topo1/test_isis_te_topo1.py +++ b/tests/topotests/isis_te_topo1/test_isis_te_topo1.py @@ -250,6 +250,60 @@ def test_step6(): compare_ted_json_output(tgen, rname, "ted_step6.json") +def test_step7(): + "Step7: Set extended admin-group on r1-eth0" + + tgen = setup_testcase("Step7: Modify link parameters on r1") + + tgen.net["r1"].cmd('vtysh -c "conf t" -c "affinity-map WHITE bit-position 0"') + tgen.net["r1"].cmd('vtysh -c "conf t" -c "affinity-map RED bit-position 31"') + tgen.net["r1"].cmd('vtysh -c "conf t" -c "affinity-map GREEN bit-position 32"') + tgen.net["r1"].cmd('vtysh -c "conf t" -c "affinity-map BLACK bit-position 128"') + + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "interface r1-eth0" -c "link-params" -c "affinity RED WHITE BLACK GREEN"' + ) + + for rname in ["r1", "r2", "r3", "r4"]: + compare_ted_json_output(tgen, rname, "ted_step7.json") + + +def test_step8(): + "Step8: Change value of affinity-map GREEN" + + tgen = setup_testcase("Step8: Change value of affinity-map GREEN") + + tgen.net["r1"].cmd('vtysh -c "conf t" -c "affinity-map GREEN bit-position 33"') + + for rname in ["r1", "r2", "r3", "r4"]: + compare_ted_json_output(tgen, rname, "ted_step8.json") + + +def test_step9(): + "Step9: Trying to remove affinity-map GREEN. \ + Must not succeed because in use" + + tgen = setup_testcase("Step9: Trying to remove affinity-map GREEN") + + tgen.net["r1"].cmd('vtysh -c "conf t" -c "no affinity-map GREEN"') + + for rname in ["r1", "r2", "r3", "r4"]: + compare_ted_json_output(tgen, rname, "ted_step9.json") + + +def test_step10(): + "Step10: Removing r1-eth0 affinity GREEN" + + tgen = setup_testcase("Step10: Removing r1-eth0 affinity GREEN") + + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "interface r1-eth0" -c "link-params" -c "no affinity GREEN"' + ) + + for rname in ["r1", "r2", "r3", "r4"]: + compare_ted_json_output(tgen, rname, "ted_step10.json") + + def test_memory_leak(): "Run the memory leak test and report results." diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index acc984ced7..2538d2073d 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2216,6 +2216,29 @@ DEFUNSH(VTYSH_PATHD, pcep_cli_pcep_pce_config, pcep_cli_pcep_pce_config_cmd, #endif /* HAVE_PATHD */ +/* max value is EXT_ADMIN_GROUP_MAX_POSITIONS - 1 */ +DEFUNSH(VTYSH_AFFMAP, affinity_map, vtysh_affinity_map_cmd, + "affinity-map NAME bit-position (0-1023)", + "Affinity map configuration\n" + "Affinity attribute name\n" + "Bit position for affinity attribute value\n" + "Bit position\n") +{ + return CMD_SUCCESS; +} + +/* max value is EXT_ADMIN_GROUP_MAX_POSITIONS - 1 */ +DEFUNSH(VTYSH_AFFMAP, no_affinity_map, vtysh_no_affinity_map_cmd, + "no affinity-map NAME$name [bit-position (0-1023)$position]", + NO_STR + "Affinity map configuration\n" + "Affinity attribute name\n" + "Bit position for affinity attribute value\n" + "Bit position\n") +{ + return CMD_SUCCESS; +} + DEFUNSH(VTYSH_RMAP, vtysh_route_map, vtysh_route_map_cmd, "route-map RMAP_NAME (1-65535)", "Create route-map or enter route-map command mode\n" @@ -4850,6 +4873,9 @@ void vtysh_init_vty(void) install_element(VRF_NODE, &vtysh_exit_vrf_cmd); install_element(VRF_NODE, &vtysh_quit_vrf_cmd); + install_element(CONFIG_NODE, &vtysh_affinity_map_cmd); + install_element(CONFIG_NODE, &vtysh_no_affinity_map_cmd); + install_node(&rmap_node); install_element(CONFIG_NODE, &vtysh_route_map_cmd); install_element(RMAP_NODE, &vtysh_exit_rmap_cmd); diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index 1de4ab0179..5e050bde99 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -59,6 +59,7 @@ extern struct thread_master *master; * things like prefix lists are not even initialised) */ #define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD|VTYSH_PATHD #define VTYSH_ACL VTYSH_BFDD|VTYSH_BABELD|VTYSH_BGPD|VTYSH_EIGRPD|VTYSH_ISISD|VTYSH_FABRICD|VTYSH_LDPD|VTYSH_NHRPD|VTYSH_OSPF6D|VTYSH_OSPFD|VTYSH_PBRD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_VRRPD|VTYSH_ZEBRA +#define VTYSH_AFFMAP VTYSH_ZEBRA | VTYSH_ISISD #define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_FABRICD #define VTYSH_INTERFACE_SUBSET \ VTYSH_ZEBRA | VTYSH_RIPD | VTYSH_RIPNGD | VTYSH_OSPFD | VTYSH_OSPF6D | \ diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index ac32f0a774..6dce99a574 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -395,6 +395,9 @@ void vtysh_config_parse_line(void *arg, const char *line) else if (strncmp(line, "router openfabric", strlen("router openfabric")) == 0) config = config_get(OPENFABRIC_NODE, line); + else if (strncmp(line, "affinity-map", + strlen("affinity-map")) == 0) + config = config_get(AFFMAP_NODE, line); else if (strncmp(line, "route-map", strlen("route-map")) == 0) config = config_get(RMAP_NODE, line); else if (strncmp(line, "no route-map", strlen("no route-map")) @@ -526,14 +529,15 @@ void vtysh_config_parse_line(void *arg, const char *line) /* Macro to check delimiter is needed between each configuration line * or not. */ #define NO_DELIMITER(I) \ - ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \ - || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE \ - || (I) == COMMUNITY_ALIAS_NODE || (I) == ACCESS_IPV6_NODE \ - || (I) == ACCESS_MAC_NODE || (I) == PREFIX_IPV6_NODE \ - || (I) == FORWARDING_NODE || (I) == DEBUG_NODE || (I) == AAA_NODE \ - || (I) == VRF_DEBUG_NODE || (I) == NORTHBOUND_DEBUG_NODE \ - || (I) == RMAP_DEBUG_NODE || (I) == RESOLVER_DEBUG_NODE \ - || (I) == MPLS_NODE || (I) == KEYCHAIN_KEY_NODE) + ((I) == AFFMAP_NODE || (I) == ACCESS_NODE || (I) == PREFIX_NODE || \ + (I) == IP_NODE || (I) == AS_LIST_NODE || \ + (I) == COMMUNITY_LIST_NODE || (I) == COMMUNITY_ALIAS_NODE || \ + (I) == ACCESS_IPV6_NODE || (I) == ACCESS_MAC_NODE || \ + (I) == PREFIX_IPV6_NODE || (I) == FORWARDING_NODE || \ + (I) == DEBUG_NODE || (I) == AAA_NODE || (I) == VRF_DEBUG_NODE || \ + (I) == NORTHBOUND_DEBUG_NODE || (I) == RMAP_DEBUG_NODE || \ + (I) == RESOLVER_DEBUG_NODE || (I) == MPLS_NODE || \ + (I) == KEYCHAIN_KEY_NODE) static void configvec_dump(vector vec, bool nested) { diff --git a/yang/frr-affinity-map.yang b/yang/frr-affinity-map.yang new file mode 100644 index 0000000000..c4377e6246 --- /dev/null +++ b/yang/frr-affinity-map.yang @@ -0,0 +1,81 @@ +module frr-affinity-map { + yang-version 1.1; + namespace "http://frrouting.org/yang/affinity-map"; + prefix frr-affinity-map; + + import ietf-inet-types { + prefix inet; + } + + import frr-filter { + prefix filter; + } + + import frr-interface { + prefix frr-interface; + } + + organization + "FRRouting"; + contact + "FRR Users List: + FRR Development List: "; + description + "This module defines route map settings + + Copyright 2022 FRRouting + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."; + + revision 2022-11-03 { + description + "Initial revision"; + } + + container lib { + container affinity-maps { + description + "Affinity Mapping Table"; + list affinity-map { + key "name"; + description + "Affinity Mapping configuration"; + leaf name { + type string { + length "1..32"; + } + description + "Affinity Name"; + } + leaf value { + type uint16 { + range "0..1023"; + } + description + "Bit position"; + } + } + } + } +} diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang index a2c6bb4c2b..7f4254cd41 100644 --- a/yang/frr-zebra.yang +++ b/yang/frr-zebra.yang @@ -11,6 +11,10 @@ module frr-zebra { prefix inet; } + import frr-affinity-map { + prefix frr-affinity-map; + } + import frr-route-map { prefix frr-route-map; } @@ -1985,7 +1989,55 @@ module frr-zebra { description "Link bandwidth informational parameter, in megabits."; } - // TODO -- link-params for (experimental/partial TE use in IGP extensions) + container link-params { + description + "link-params for Traffic-Engineering (TE) use in IGP extensions."; + choice admin-group-mode { + description "Admin-group mode"; + case legacy { + description + "Legacy mode. Only support standard admin-group (RFC3630/5305/5329)"; + leaf legacy-admin-group { + description "Admin-Group value"; + type uint32; + } + } + case affinity { + container affinities { + leaf-list affinity { + type string; + max-elements "256"; + description + "Array of Attribute Names"; + } + } + } + } + leaf affinity-mode { + description + "Affinity mode"; + default "extended"; + type enumeration { + enum extended { + value 0; + description + "Extended Admin-Group only (RFC7308)"; + } + enum standard { + value 1; + description + "Standard Admin-Group only (RFC3630/5305/5329)"; + } + enum both { + value 2; + description + "Standard and extended Admin-Group"; + } + } + } + // TODO -- other link-params options + // for (experimental/partial TE use in IGP extensions) + } container state { config false; description diff --git a/yang/subdir.am b/yang/subdir.am index 80028fcb18..82a6a01474 100644 --- a/yang/subdir.am +++ b/yang/subdir.am @@ -19,6 +19,7 @@ EXTRA_DIST += yang/embedmodel.py # global symbols :(. Just put it in the daemon. Dynamic libraries.so work # without problems, as seen in libfrr. +dist_yangmodels_DATA += yang/frr-affinity-map.yang dist_yangmodels_DATA += yang/frr-filter.yang dist_yangmodels_DATA += yang/frr-module-translator.yang dist_yangmodels_DATA += yang/frr-nexthop.yang diff --git a/zebra/interface.c b/zebra/interface.c index 2e6ee65e92..5c60d355c2 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -33,6 +33,7 @@ #include "log.h" #include "zclient.h" #include "vrf.h" +#include "lib/northbound_cli.h" #include "zebra/rtadv.h" #include "zebra_ns.h" @@ -3362,6 +3363,8 @@ DEFUN (no_link_params_enable, NO_STR "Disable link parameters on this interface\n") { + char xpath[XPATH_MAXLEN]; + int ret; VTY_DECLVAR_CONTEXT(interface, ifp); if (IS_ZEBRA_DEBUG_EVENT || IS_ZEBRA_DEBUG_MPLS) @@ -3370,6 +3373,18 @@ DEFUN (no_link_params_enable, if_link_params_free(ifp); + snprintf( + xpath, sizeof(xpath), + "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinities", + ifp->name); + if (yang_dnode_exists(running_config->dnode, xpath)) + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + ret = nb_cli_apply_changes(vty, NULL); + + if (ret != CMD_SUCCESS) + return ret; + /* force protocols to update LINK STATE due to parameters change */ if (if_is_operative(ifp)) zebra_interface_parameters_update(ifp); @@ -3535,16 +3550,27 @@ DEFUN (link_params_unrsv_bw, return CMD_SUCCESS; } -DEFUN (link_params_admin_grp, - link_params_admin_grp_cmd, - "admin-grp BITPATTERN", - "Administrative group membership\n" - "32-bit Hexadecimal value (e.g. 0xa1)\n") +DEFPY_YANG(link_params_admin_grp, link_params_admin_grp_cmd, + "admin-grp BITPATTERN", + "Administrative group membership\n" + "32-bit Hexadecimal value (e.g. 0xa1)\n") { + char xpath[XPATH_MAXLEN]; int idx_bitpattern = 1; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); unsigned long value; + char value_str[11]; + + VTY_DECLVAR_CONTEXT(interface, ifp); + + snprintf( + xpath, sizeof(xpath), + "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinities", + ifp->name); + if (yang_dnode_exists(running_config->dnode, xpath)) { + vty_out(vty, + "cannot use the admin-grp command when affinity is set\n"); + return CMD_WARNING_CONFIG_FAILED; + } if (sscanf(argv[idx_bitpattern]->arg, "0x%lx", &value) != 1) { vty_out(vty, "link_params_admin_grp: fscanf: %s\n", @@ -3552,27 +3578,29 @@ DEFUN (link_params_admin_grp, return CMD_WARNING_CONFIG_FAILED; } - if (!iflp) - iflp = if_link_params_enable(ifp); + if (value > 0xFFFFFFFF) { + vty_out(vty, "value must be not be superior to 0xFFFFFFFF\n"); + return CMD_WARNING_CONFIG_FAILED; + } - /* Update Administrative Group if needed */ - link_param_cmd_set_uint32(ifp, &iflp->admin_grp, LP_ADM_GRP, value); + snprintf(value_str, sizeof(value_str), "%ld", value); - return CMD_SUCCESS; + nb_cli_enqueue_change( + vty, "./frr-zebra:zebra/link-params/legacy-admin-group", + NB_OP_MODIFY, value_str); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_link_params_admin_grp, - no_link_params_admin_grp_cmd, - "no admin-grp", - NO_STR - "Disable Administrative group membership on this interface\n") +DEFPY_YANG(no_link_params_admin_grp, no_link_params_admin_grp_cmd, + "no admin-grp", + NO_STR "Disable Administrative group membership on this interface\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); + nb_cli_enqueue_change( + vty, "./frr-zebra:zebra/link-params/legacy-admin-group", + NB_OP_DESTROY, NULL); - /* Unset Admin Group */ - link_param_cmd_unset(ifp, LP_ADM_GRP); - - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, NULL); } /* RFC5392 & RFC5316: INTER-AS */ @@ -3989,6 +4017,118 @@ DEFUN (no_link_params_use_bw, return CMD_SUCCESS; } +static int ag_change(struct vty *vty, int argc, struct cmd_token **argv, + const char *xpath, bool no, int start_idx) +{ + for (int i = start_idx; i < argc; i++) + nb_cli_enqueue_change(vty, xpath, + no ? NB_OP_DESTROY : NB_OP_CREATE, + argv[i]->arg); + return nb_cli_apply_changes(vty, NULL); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities/affinity + */ +DEFPY_YANG(link_params_affinity, link_params_affinity_cmd, + "[no] affinity NAME...", + NO_STR + "Interface affinities\n" + "Affinity names\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + char xpath[XPATH_MAXLEN]; + + snprintf( + xpath, sizeof(xpath), + "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/legacy-admin-group", + ifp->name); + if (yang_dnode_exists(running_config->dnode, xpath)) { + vty_out(vty, + "cannot use the affinity command when admin-grp is set\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + return ag_change(vty, argc, argv, + "./frr-zebra:zebra/link-params/affinities/affinity", + no, no ? 2 : 1); +} + + +/* + * XPath: + * /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities/affinity-mode + */ +DEFPY_YANG(link_params_affinity_mode, link_params_affinity_mode_cmd, + "affinity-mode $affmode", + "Interface affinity mode\n" + "Standard Admin-Group only RFC3630,5305,5329 (default)\n" + "Extended Admin-Group only RFC7308\n" + "Standard and extended Admin-Group format\n") +{ + const char *xpath = "./frr-zebra:zebra/link-params/affinity-mode"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, affmode); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG(no_link_params_affinity_mode, no_link_params_affinity_mode_cmd, + "no affinity-mode []", + NO_STR + "Interface affinity mode\n" + "Standard Admin-Group only RFC3630,5305,5329 (default)\n" + "Extended Admin-Group only RFC7308\n" + "Standard and extended Admin-Group format\n") +{ + const char *xpath = "./frr-zebra:zebra/link-params/affinity-mode"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "standard"); + + return nb_cli_apply_changes(vty, NULL); +} + +static int ag_iter_cb(const struct lyd_node *dnode, void *arg) +{ + struct vty *vty = (struct vty *)arg; + + vty_out(vty, " %s", yang_dnode_get_string(dnode, ".")); + return YANG_ITER_CONTINUE; +} + +void cli_show_legacy_admin_group(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) +{ + if (!yang_dnode_exists(dnode, "./legacy-admin-group")) + return; + + vty_out(vty, " admin-group 0x%x\n", + yang_dnode_get_uint32(dnode, "./legacy-admin-group")); +} + +void cli_show_affinity_mode(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) +{ + enum affinity_mode affinity_mode = yang_dnode_get_enum(dnode, "."); + + if (affinity_mode == AFFINITY_MODE_STANDARD) + vty_out(vty, " affinity-mode standard\n"); + else if (affinity_mode == AFFINITY_MODE_BOTH) + vty_out(vty, " affinity-mode both\n"); +} + +void cli_show_affinity(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) +{ + if (!yang_dnode_exists(dnode, "./affinity")) + return; + + vty_out(vty, " affinity"); + yang_dnode_iterate(ag_iter_cb, vty, dnode, "./affinity"); + vty_out(vty, "\n"); +} + int if_ip_address_install(struct interface *ifp, struct prefix *prefix, const char *label, struct prefix *pp) { @@ -4585,6 +4725,8 @@ DEFUN (no_ipv6_address, static int link_params_config_write(struct vty *vty, struct interface *ifp) { + const struct lyd_node *dnode; + char xpath[XPATH_MAXLEN]; int i; if ((ifp == NULL) || !HAS_LINK_PARAMS(ifp)) @@ -4607,8 +4749,15 @@ static int link_params_config_write(struct vty *vty, struct interface *ifp) vty_out(vty, " unrsv-bw %d %g\n", i, iflp->unrsv_bw[i]); } - if (IS_PARAM_SET(iflp, LP_ADM_GRP)) - vty_out(vty, " admin-grp 0x%x\n", iflp->admin_grp); + + snprintf( + xpath, sizeof(xpath), + "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params", + ifp->name); + dnode = yang_dnode_get(running_config->dnode, xpath); + if (dnode) + nb_cli_show_dnode_cmds(vty, dnode, false); + if (IS_PARAM_SET(iflp, LP_DELAY)) { vty_out(vty, " delay %u", iflp->av_delay); if (IS_PARAM_SET(iflp, LP_MM_DELAY)) { @@ -4630,6 +4779,7 @@ static int link_params_config_write(struct vty *vty, struct interface *ifp) if (IS_PARAM_SET(iflp, LP_RMT_AS)) vty_out(vty, " neighbor %pI4 as %u\n", &iflp->rmt_ip, iflp->rmt_as); + vty_out(vty, " exit-link-params\n"); return 0; } @@ -4789,6 +4939,9 @@ void zebra_if_init(void) install_element(LINK_PARAMS_NODE, &no_link_params_res_bw_cmd); install_element(LINK_PARAMS_NODE, &link_params_use_bw_cmd); install_element(LINK_PARAMS_NODE, &no_link_params_use_bw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_affinity_cmd); + install_element(LINK_PARAMS_NODE, &link_params_affinity_mode_cmd); + install_element(LINK_PARAMS_NODE, &no_link_params_affinity_mode_cmd); install_element(LINK_PARAMS_NODE, &exit_link_params_cmd); /* setup EVPN MH elements */ diff --git a/zebra/interface.h b/zebra/interface.h index cc88141541..7e52990002 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -303,6 +303,16 @@ extern void zebra_if_update_all_links(struct zebra_ns *zns); */ extern int zebra_if_update_protodown_rc(struct interface *ifp, bool new_down, uint32_t new_protodown_rc); + +extern void cli_show_legacy_admin_group(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults); +extern void cli_show_affinity_mode(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults); +extern void cli_show_affinity(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults); + /** * Set protodown with single reason. */ diff --git a/zebra/main.c b/zebra/main.c index e38f9a85e3..e38f203710 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -33,6 +33,7 @@ #include "sigevent.h" #include "vrf.h" #include "libfrr.h" +#include "affinitymap.h" #include "routemap.h" #include "routing_nb.h" @@ -259,6 +260,7 @@ struct frr_signal_t zebra_signals[] = { }, }; +/* clang-format off */ static const struct frr_yang_module_info *const zebra_yang_modules[] = { &frr_filter_info, &frr_interface_info, @@ -266,8 +268,10 @@ static const struct frr_yang_module_info *const zebra_yang_modules[] = { &frr_zebra_info, &frr_vrf_info, &frr_routing_info, + &frr_affinity_map_info, &frr_zebra_route_map_info, }; +/* clang-format on */ FRR_DAEMON_INFO( zebra, ZEBRA, .vty_port = ZEBRA_VTY_PORT, .flags = FRR_NO_ZCLIENT, diff --git a/zebra/subdir.am b/zebra/subdir.am index 259782a34d..1060e38785 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -62,6 +62,7 @@ zebra_zebra_SOURCES = \ zebra/tc_netlink.c \ zebra/tc_socket.c \ zebra/zapi_msg.c \ + zebra/zebra_affinitymap.c \ zebra/zebra_dplane.c \ zebra/zebra_errors.c \ zebra/zebra_gr.c \ @@ -147,6 +148,7 @@ noinst_HEADERS += \ zebra/table_manager.h \ zebra/tc_netlink.h \ zebra/zapi_msg.h \ + zebra/zebra_affinitymap.h \ zebra/zebra_dplane.h \ zebra/zebra_errors.h \ zebra/zebra_evpn.h \ diff --git a/zebra/zebra_affinitymap.c b/zebra/zebra_affinitymap.c new file mode 100644 index 0000000000..ae0f9a8a35 --- /dev/null +++ b/zebra/zebra_affinitymap.c @@ -0,0 +1,144 @@ +/* + * zebra affinity-map. + * + * Copyright 2022 6WIND S.A. + * + * This file is part of Free Range Routing (FRR). + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "lib/if.h" +#include "lib/vrf.h" +#include "zebra/redistribute.h" +#include "zebra/zebra_affinitymap.h" + +static bool zebra_affinity_map_check_use(const char *affmap_name) +{ + char xpath[XPATH_MAXLEN]; + struct interface *ifp; + struct vrf *vrf; + + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { + FOR_ALL_INTERFACES (vrf, ifp) { + snprintf(xpath, sizeof(xpath), + "/frr-interface:lib/interface[name='%s']", + ifp->name); + if (!yang_dnode_exists(running_config->dnode, xpath)) + continue; + snprintf( + xpath, sizeof(xpath), + "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinities[affinity='%s']", + ifp->name, affmap_name); + if (yang_dnode_exists(running_config->dnode, xpath)) + return true; + } + } + return false; +} + +static bool zebra_affinity_map_check_update(const char *affmap_name, + uint16_t new_pos) +{ + char xpath[XPATH_MAXLEN]; + struct interface *ifp; + struct vrf *vrf; + + /* check whether the affinity-map new bit position is upper than 31 + * but is used on an interface on which affinity-mode is standard. + * Return false if the change is not possible. + */ + if (new_pos < 32) + return true; + + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { + FOR_ALL_INTERFACES (vrf, ifp) { + snprintf(xpath, sizeof(xpath), + "/frr-interface:lib/interface[name='%s']", + ifp->name); + if (!yang_dnode_exists(running_config->dnode, xpath)) + continue; + snprintf( + xpath, sizeof(xpath), + "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinities[affinity='%s']", + ifp->name, affmap_name); + if (!yang_dnode_exists(running_config->dnode, xpath)) + continue; + if (yang_dnode_get_enum( + running_config->dnode, + "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinity-mode", + ifp->name) == AFFINITY_MODE_STANDARD) + return false; + } + } + return true; +} + +static void zebra_affinity_map_update(const char *affmap_name, uint16_t old_pos, + uint16_t new_pos) +{ + struct if_link_params *iflp; + enum affinity_mode aff_mode; + char xpath[XPATH_MAXLEN]; + struct interface *ifp; + struct vrf *vrf; + + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { + FOR_ALL_INTERFACES (vrf, ifp) { + snprintf(xpath, sizeof(xpath), + "/frr-interface:lib/interface[name='%s']", + ifp->name); + if (!yang_dnode_exists(running_config->dnode, xpath)) + continue; + snprintf( + xpath, sizeof(xpath), + "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinities[affinity='%s']", + ifp->name, affmap_name); + if (!yang_dnode_exists(running_config->dnode, xpath)) + continue; + aff_mode = yang_dnode_get_enum( + running_config->dnode, + "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinity-mode", + ifp->name); + iflp = if_link_params_get(ifp); + if (aff_mode == AFFINITY_MODE_EXTENDED || + aff_mode == AFFINITY_MODE_BOTH) { + admin_group_unset(&iflp->ext_admin_grp, + old_pos); + admin_group_set(&iflp->ext_admin_grp, new_pos); + } + if (aff_mode == AFFINITY_MODE_STANDARD || + aff_mode == AFFINITY_MODE_BOTH) { + iflp->admin_grp &= ~(1 << old_pos); + if (new_pos < 32) + iflp->admin_grp |= 1 << new_pos; + if (iflp->admin_grp == 0) + UNSET_PARAM(iflp, LP_ADM_GRP); + } + if (if_is_operative(ifp)) + zebra_interface_parameters_update(ifp); + } + } +} + +void zebra_affinity_map_init(void) +{ + affinity_map_init(); + + affinity_map_set_check_use_hook(zebra_affinity_map_check_use); + affinity_map_set_check_update_hook(zebra_affinity_map_check_update); + affinity_map_set_update_hook(zebra_affinity_map_update); +} diff --git a/zebra/zebra_affinitymap.h b/zebra/zebra_affinitymap.h new file mode 100644 index 0000000000..5ddc998bda --- /dev/null +++ b/zebra/zebra_affinitymap.h @@ -0,0 +1,38 @@ +/* + * Zebra affinity-map header + * + * Copyright 2022 6WIND S.A. + * + * This file is part of Free Range Routing (FRR). + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __ZEBRA_AFFINITYMAP_H__ +#define __ZEBRA_AFFINITYMAP_H__ + +#include "lib/affinitymap.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern void zebra_affinity_map_init(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/zebra/zebra_nb.c b/zebra/zebra_nb.c index 90d4ee7ced..5543b3f884 100644 --- a/zebra/zebra_nb.c +++ b/zebra/zebra_nb.c @@ -18,6 +18,7 @@ */ #include +#include "interface.h" #include "northbound.h" #include "libfrr.h" #include "zebra_nb.h" @@ -350,6 +351,41 @@ const struct frr_yang_module_info frr_zebra_info = { .destroy = lib_interface_zebra_bandwidth_destroy, } }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/bandwidth", + .cbs = { + .modify = lib_interface_zebra_bandwidth_modify, + .destroy = lib_interface_zebra_bandwidth_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/legacy-admin-group", + .cbs = { + .modify = lib_interface_zebra_legacy_admin_group_modify, + .destroy = lib_interface_zebra_legacy_admin_group_destroy, + .cli_show = cli_show_legacy_admin_group, + }, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities", + .cbs = { + .cli_show = cli_show_affinity, + }, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities/affinity", + .cbs = { + .create = lib_interface_zebra_affinity_create, + .destroy = lib_interface_zebra_affinity_destroy, + }, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/affinity-mode", + .cbs = { + .modify = lib_interface_zebra_affinity_mode_modify, + .cli_show = cli_show_affinity_mode, + }, + }, { .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/state/up-count", .cbs = { diff --git a/zebra/zebra_nb.h b/zebra/zebra_nb.h index 95907059a8..4847745218 100644 --- a/zebra/zebra_nb.h +++ b/zebra/zebra_nb.h @@ -109,6 +109,13 @@ int lib_interface_zebra_shutdown_modify(struct nb_cb_modify_args *args); int lib_interface_zebra_shutdown_destroy(struct nb_cb_destroy_args *args); int lib_interface_zebra_bandwidth_modify(struct nb_cb_modify_args *args); int lib_interface_zebra_bandwidth_destroy(struct nb_cb_destroy_args *args); +int lib_interface_zebra_legacy_admin_group_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_legacy_admin_group_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_affinity_create(struct nb_cb_create_args *args); +int lib_interface_zebra_affinity_destroy(struct nb_cb_destroy_args *args); +int lib_interface_zebra_affinity_mode_modify(struct nb_cb_modify_args *args); struct yang_data * lib_interface_zebra_state_up_count_get_elem(struct nb_cb_get_elem_args *args); struct yang_data * diff --git a/zebra/zebra_nb_config.c b/zebra/zebra_nb_config.c index dfb55b0d6d..f68ecc3076 100644 --- a/zebra/zebra_nb_config.c +++ b/zebra/zebra_nb_config.c @@ -19,6 +19,8 @@ #include +#include "lib/admin_group.h" +#include "lib/affinitymap.h" #include "lib/log.h" #include "lib/northbound.h" #include "lib/printfrr.h" @@ -1139,6 +1141,275 @@ int lib_interface_zebra_bandwidth_destroy(struct nb_cb_destroy_args *args) return NB_OK; } +/* + * XPath: + * /frr-interface:lib/interface/frr-zebra:zebra/link-params/legacy-admin-group + */ +int lib_interface_zebra_legacy_admin_group_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint32_t admin_group_value; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + admin_group_value = yang_dnode_get_uint32(args->dnode, "."); + + if (!ifp) + return NB_ERR_RESOURCE; + + iflp = if_link_params_get(ifp); + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + if (!iflp) + iflp = if_link_params_enable(ifp); + + iflp->admin_grp = admin_group_value; + SET_PARAM(iflp, LP_ADM_GRP); + + admin_group_clear(&iflp->ext_admin_grp); + UNSET_PARAM(iflp, LP_EXTEND_ADM_GRP); + + if (if_is_operative(ifp)) + zebra_interface_parameters_update(ifp); + break; + } + return NB_OK; +} + +int lib_interface_zebra_legacy_admin_group_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + + if (!ifp) + return NB_ERR_RESOURCE; + + iflp = if_link_params_get(ifp); + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + if (!iflp) + iflp = if_link_params_enable(ifp); + + iflp->admin_grp = 0; + UNSET_PARAM(iflp, LP_ADM_GRP); + + if (if_is_operative(ifp)) + zebra_interface_parameters_update(ifp); + break; + } + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities/affinity + */ +int lib_interface_zebra_affinity_create(struct nb_cb_create_args *args) +{ + struct interface *ifp; + const char *affname; + struct if_link_params *iflp; + struct affinity_map *affmap; + enum affinity_mode affinity_mode; + + + ifp = nb_running_get_entry(args->dnode, NULL, true); + affname = yang_dnode_get_string(args->dnode, "."); + affinity_mode = yang_dnode_get_enum(args->dnode, "../../affinity-mode"); + + if (!ifp) + return NB_ERR_RESOURCE; + + affmap = affinity_map_get(affname); + iflp = if_link_params_get(ifp); + + switch (args->event) { + case NB_EV_VALIDATE: + if (!affmap) { + snprintf(args->errmsg, args->errmsg_len, + "affinity-map %s not found.", affname); + return NB_ERR_VALIDATION; + } + if (affinity_mode == AFFINITY_MODE_STANDARD && + affmap->bit_position > 31) { + snprintf( + args->errmsg, args->errmsg_len, + "affinity %s bit-position %d is not compatible with affinity-mode standard (bit-position > 31).", + affname, affmap->bit_position); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + if (!iflp) + iflp = if_link_params_enable(ifp); + + if (affmap->bit_position < 32 && + (affinity_mode == AFFINITY_MODE_STANDARD || + affinity_mode == AFFINITY_MODE_BOTH)) { + iflp->admin_grp |= 1 << affmap->bit_position; + SET_PARAM(iflp, LP_ADM_GRP); + } + if (affinity_mode == AFFINITY_MODE_EXTENDED || + affinity_mode == AFFINITY_MODE_BOTH) { + admin_group_set(&iflp->ext_admin_grp, + affmap->bit_position); + SET_PARAM(iflp, LP_EXTEND_ADM_GRP); + } + + if (if_is_operative(ifp)) + zebra_interface_parameters_update(ifp); + break; + } + return NB_OK; +} + +int lib_interface_zebra_affinity_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + const char *affname; + struct if_link_params *iflp; + struct affinity_map *affmap; + enum affinity_mode affinity_mode; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + affname = yang_dnode_get_string(args->dnode, "."); + affinity_mode = yang_dnode_get_enum(args->dnode, "../../affinity-mode"); + + if (!ifp) + return NB_ERR_RESOURCE; + + affmap = affinity_map_get(affname); + iflp = if_link_params_get(ifp); + + switch (args->event) { + case NB_EV_VALIDATE: + if (!affmap) { + snprintf(args->errmsg, args->errmsg_len, + "affinity-map %s not found.", affname); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + if (!iflp) + return NB_OK; + if (affmap->bit_position < 32 && + (affinity_mode == AFFINITY_MODE_STANDARD || + affinity_mode == AFFINITY_MODE_BOTH)) { + iflp->admin_grp &= ~(1 << affmap->bit_position); + if (iflp->admin_grp == 0) + UNSET_PARAM(iflp, LP_ADM_GRP); + } + if (affinity_mode == AFFINITY_MODE_EXTENDED || + affinity_mode == AFFINITY_MODE_BOTH) { + admin_group_unset(&iflp->ext_admin_grp, + affmap->bit_position); + if (admin_group_zero(&iflp->ext_admin_grp)) + UNSET_PARAM(iflp, LP_EXTEND_ADM_GRP); + } + + if (if_is_operative(ifp)) + zebra_interface_parameters_update(ifp); + break; + } + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinity-mode + */ +int lib_interface_zebra_affinity_mode_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + enum affinity_mode affinity_mode; + + + ifp = nb_running_get_entry(args->dnode, NULL, true); + affinity_mode = yang_dnode_get_enum(args->dnode, "."); + + if (!ifp) + return NB_ERR_RESOURCE; + + iflp = if_link_params_get(ifp); + + switch (args->event) { + case NB_EV_VALIDATE: + if (affinity_mode == AFFINITY_MODE_STANDARD && + admin_group_nb_words(&iflp->ext_admin_grp) > 1) { + snprintf( + args->errmsg, args->errmsg_len, + "affinity-mode standard cannot be set when a bit-position > 31 is set."); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + if (!iflp) + iflp = if_link_params_enable(ifp); + if (affinity_mode == AFFINITY_MODE_STANDARD) { + if (!IS_PARAM_SET(iflp, LP_ADM_GRP) && + IS_PARAM_SET(iflp, LP_EXTEND_ADM_GRP)) { + iflp->admin_grp = admin_group_get_offset( + &iflp->ext_admin_grp, 0); + SET_PARAM(iflp, LP_ADM_GRP); + } + admin_group_clear(&iflp->ext_admin_grp); + UNSET_PARAM(iflp, LP_EXTEND_ADM_GRP); + } + if (affinity_mode == AFFINITY_MODE_EXTENDED) { + if (!IS_PARAM_SET(iflp, LP_EXTEND_ADM_GRP) && + IS_PARAM_SET(iflp, LP_ADM_GRP)) { + admin_group_bulk_set(&iflp->ext_admin_grp, + iflp->admin_grp, 0); + SET_PARAM(iflp, LP_EXTEND_ADM_GRP); + } + iflp->admin_grp = 0; + UNSET_PARAM(iflp, LP_ADM_GRP); + } + if (affinity_mode == AFFINITY_MODE_BOTH) { + if (!IS_PARAM_SET(iflp, LP_EXTEND_ADM_GRP) && + IS_PARAM_SET(iflp, LP_ADM_GRP)) { + admin_group_bulk_set(&iflp->ext_admin_grp, + iflp->admin_grp, 0); + SET_PARAM(iflp, LP_EXTEND_ADM_GRP); + } else if (!IS_PARAM_SET(iflp, LP_ADM_GRP) && + IS_PARAM_SET(iflp, LP_EXTEND_ADM_GRP)) { + iflp->admin_grp = admin_group_get_offset( + &iflp->ext_admin_grp, 0); + SET_PARAM(iflp, LP_ADM_GRP); + } + } + + if (if_is_operative(ifp)) + zebra_interface_parameters_update(ifp); + break; + } + return NB_OK; +} + /* * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/l3vni-id */ diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 58b0c9910a..3b63821d37 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -34,6 +34,7 @@ #include "srcdest_table.h" #include "vxlan.h" #include "termtable.h" +#include "affinitymap.h" #include "zebra/zebra_router.h" #include "zebra/zserv.h" @@ -41,6 +42,7 @@ #include "zebra/zebra_mpls.h" #include "zebra/zebra_rnh.h" #include "zebra/redistribute.h" +#include "zebra/zebra_affinitymap.h" #include "zebra/zebra_routemap.h" #include "lib/json.h" #include "lib/route_opaque.h" @@ -4554,6 +4556,8 @@ void zebra_vty_init(void) /* Route-map */ zebra_route_map_init(); + zebra_affinity_map_init(); + install_node(&ip_node); install_node(&protocol_node);