diff options
| author | Olivier Dugeon <olivier.dugeon@orange.com> | 2023-02-15 09:42:03 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-02-15 09:42:03 +0100 |
| commit | e2b958ecbcd855dbaab6ba2e18550626befd3136 (patch) | |
| tree | 6b2ddd9ed915e0a732c0fc0a4d85e1b9bc232f9d /lib | |
| parent | 423c8035807d78ad9044068a9f45505d0208e981 (diff) | |
| parent | 66a45dae56e0e70a49168f6750b8342e1edbc5fe (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.c | 402 | ||||
| -rw-r--r-- | lib/admin_group.h | 68 | ||||
| -rw-r--r-- | lib/affinitymap.c | 173 | ||||
| -rw-r--r-- | lib/affinitymap.h | 90 | ||||
| -rw-r--r-- | lib/affinitymap_cli.c | 107 | ||||
| -rw-r--r-- | lib/affinitymap_northbound.c | 136 | ||||
| -rw-r--r-- | lib/bitfield.h | 16 | ||||
| -rw-r--r-- | lib/command.h | 3 | ||||
| -rw-r--r-- | lib/if.c | 46 | ||||
| -rw-r--r-- | lib/if.h | 23 | ||||
| -rw-r--r-- | lib/link_state.c | 76 | ||||
| -rw-r--r-- | lib/link_state.h | 3 | ||||
| -rw-r--r-- | lib/sbuf.c | 4 | ||||
| -rw-r--r-- | lib/sbuf.h | 2 | ||||
| -rw-r--r-- | lib/subdir.am | 8 | ||||
| -rw-r--r-- | lib/yang.c | 1 | ||||
| -rw-r--r-- | lib/zclient.c | 65 |
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[]; @@ -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/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); |
