summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/admin_group.c402
-rw-r--r--lib/admin_group.h68
-rw-r--r--lib/if.c46
-rw-r--r--lib/if.h23
-rw-r--r--lib/subdir.am2
-rw-r--r--lib/zclient.c65
-rw-r--r--yang/frr-zebra.yang50
-rw-r--r--zebra/interface.c201
-rw-r--r--zebra/interface.h10
-rw-r--r--zebra/zebra_nb.c36
-rw-r--r--zebra/zebra_nb.h7
-rw-r--r--zebra/zebra_nb_config.c271
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 */
diff --git a/lib/if.c b/lib/if.c
index b75c2a4db..be7fe544c 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 acd60e9d0..b79ed5ad8 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/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)