summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorOlivier Dugeon <olivier.dugeon@orange.com>2023-02-15 09:42:03 +0100
committerGitHub <noreply@github.com>2023-02-15 09:42:03 +0100
commite2b958ecbcd855dbaab6ba2e18550626befd3136 (patch)
tree6b2ddd9ed915e0a732c0fc0a4d85e1b9bc232f9d /lib
parent423c8035807d78ad9044068a9f45505d0208e981 (diff)
parent66a45dae56e0e70a49168f6750b8342e1edbc5fe (diff)
Merge pull request #12494 from louis-6wind/ext_admin_group
lib,zebra,isisd: add support for extended admin group RFC7308
Diffstat (limited to 'lib')
-rw-r--r--lib/admin_group.c402
-rw-r--r--lib/admin_group.h68
-rw-r--r--lib/affinitymap.c173
-rw-r--r--lib/affinitymap.h90
-rw-r--r--lib/affinitymap_cli.c107
-rw-r--r--lib/affinitymap_northbound.c136
-rw-r--r--lib/bitfield.h16
-rw-r--r--lib/command.h3
-rw-r--r--lib/if.c46
-rw-r--r--lib/if.h23
-rw-r--r--lib/link_state.c76
-rw-r--r--lib/link_state.h3
-rw-r--r--lib/sbuf.c4
-rw-r--r--lib/sbuf.h2
-rw-r--r--lib/subdir.am8
-rw-r--r--lib/yang.c1
-rw-r--r--lib/zclient.c65
17 files changed, 1195 insertions, 28 deletions
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 <zebra.h>
+
+#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 <zebra.h>
+
+#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 <zebra.h>
+
+#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;
-
- 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;
}
@@ -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);