diff options
-rw-r--r-- | lib/admin_group.c | 402 | ||||
-rw-r--r-- | lib/admin_group.h | 68 | ||||
-rw-r--r-- | lib/if.c | 46 | ||||
-rw-r--r-- | lib/if.h | 23 | ||||
-rw-r--r-- | lib/subdir.am | 2 | ||||
-rw-r--r-- | lib/zclient.c | 65 | ||||
-rw-r--r-- | yang/frr-zebra.yang | 50 | ||||
-rw-r--r-- | zebra/interface.c | 201 | ||||
-rw-r--r-- | zebra/interface.h | 10 | ||||
-rw-r--r-- | zebra/zebra_nb.c | 36 | ||||
-rw-r--r-- | zebra/zebra_nb.h | 7 | ||||
-rw-r--r-- | zebra/zebra_nb_config.c | 271 |
12 files changed, 1133 insertions, 48 deletions
diff --git a/lib/admin_group.c b/lib/admin_group.c new file mode 100644 index 000000000..9c2c2c08e --- /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 000000000..60f4a05f2 --- /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 */ @@ -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); } @@ -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/subdir.am b/lib/subdir.am index faf77abad..ba576a80e 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -7,6 +7,7 @@ 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 \ @@ -164,6 +165,7 @@ clippy_scan += \ # end pkginclude_HEADERS += \ + lib/admin_group.h \ lib/affinitymap.h \ lib/agg_table.h \ lib/atomlist.h \ diff --git a/lib/zclient.c b/lib/zclient.c index d748bef33..413ae2c9f 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2402,9 +2402,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); @@ -2433,6 +2433,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); @@ -2456,9 +2465,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); @@ -2471,11 +2480,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 @@ -2484,24 +2495,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; - - iflp = if_link_params_get(ifp); + if (changed != NULL) { + 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; } @@ -2550,10 +2565,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; @@ -2579,6 +2595,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/yang/frr-zebra.yang b/yang/frr-zebra.yang index 3bf5203fb..7f4254cd4 100644 --- a/yang/frr-zebra.yang +++ b/yang/frr-zebra.yang @@ -1989,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/zebra/interface.c b/zebra/interface.c index 59563834e..a24f55dbb 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" @@ -3300,6 +3301,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) @@ -3308,6 +3311,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); @@ -3473,16 +3488,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", @@ -3490,27 +3516,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); - - /* Unset Admin Group */ - link_param_cmd_unset(ifp, LP_ADM_GRP); + nb_cli_enqueue_change( + vty, "./frr-zebra:zebra/link-params/legacy-admin-group", + NB_OP_DESTROY, NULL); - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, NULL); } /* RFC5392 & RFC5316: INTER-AS */ @@ -3927,6 +3955,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 <standard|extended|both>$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 [<standard|extended|both>]", + 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) { @@ -4523,6 +4663,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)) @@ -4545,8 +4687,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)) { @@ -4568,6 +4717,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; } @@ -4727,6 +4877,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 0242438dc..8e39ca8c9 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -302,6 +302,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/zebra_nb.c b/zebra/zebra_nb.c index 90d4ee7ce..5543b3f88 100644 --- a/zebra/zebra_nb.c +++ b/zebra/zebra_nb.c @@ -18,6 +18,7 @@ */ #include <zebra.h> +#include "interface.h" #include "northbound.h" #include "libfrr.h" #include "zebra_nb.h" @@ -351,6 +352,41 @@ const struct frr_yang_module_info frr_zebra_info = { } }, { + .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 = { .get_elem = lib_interface_zebra_state_up_count_get_elem, diff --git a/zebra/zebra_nb.h b/zebra/zebra_nb.h index 95907059a..484774521 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 dfb55b0d6..f68ecc307 100644 --- a/zebra/zebra_nb_config.c +++ b/zebra/zebra_nb_config.c @@ -19,6 +19,8 @@ #include <zebra.h> +#include "lib/admin_group.h" +#include "lib/affinitymap.h" #include "lib/log.h" #include "lib/northbound.h" #include "lib/printfrr.h" @@ -1140,6 +1142,275 @@ int lib_interface_zebra_bandwidth_destroy(struct nb_cb_destroy_args *args) } /* + * 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 */ int lib_vrf_zebra_l3vni_id_modify(struct nb_cb_modify_args *args) |