From 44e1ae95158733b96269b861c96ee3e584a0d084 Mon Sep 17 00:00:00 2001 From: Yamato Sugawara Date: Fri, 22 Oct 2021 15:29:50 +0000 Subject: [PATCH 1/6] zebra: step1 separate locator prefix into multi chunks with 4-bits length Signed-off-by: Yamato Sugawara Signed-off-by: Philippe Guibert --- lib/srv6.c | 13 ++++ lib/srv6.h | 2 + sharpd/sharp_zebra.c | 15 ++-- .../srv6_locator/expected_chunks2.json | 12 ++-- .../srv6_locator/expected_locators1.json | 48 ++++++------- .../srv6_locator/expected_locators2.json | 48 ++++++------- .../srv6_locator/expected_locators3.json | 48 ++++++------- .../srv6_locator/expected_locators4.json | 71 +++++++++---------- .../srv6_locator/expected_locators5.json | 49 +++++++------ zebra/zapi_msg.c | 19 +---- zebra/zapi_msg.h | 4 +- zebra/zebra_srv6.c | 58 ++++++++++----- zebra/zebra_srv6.h | 6 +- zebra/zebra_srv6_vty.c | 9 ++- 14 files changed, 209 insertions(+), 193 deletions(-) diff --git a/lib/srv6.c b/lib/srv6.c index 09835f3ea8b4..10197d613cd4 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -152,6 +152,19 @@ void srv6_locator_chunk_free(struct srv6_locator_chunk **chunk) XFREE(MTYPE_SRV6_LOCATOR_CHUNK, *chunk); } +bool srv6_locator_chunks_exhausted(const struct srv6_locator *loc) +{ + struct listnode *node; + struct srv6_locator_chunk *chunk; + + for (ALL_LIST_ELEMENTS_RO(loc->chunks, node, chunk)) + if (chunk->proto == 0 && chunk->instance == 0 && + chunk->session_id == 0 && chunk->keep == 0) + return false; + + return true; +} + json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk) { json_object *jo_root = NULL; diff --git a/lib/srv6.h b/lib/srv6.h index 0d3ee7d2ffa8..f088464fe140 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -78,6 +78,7 @@ struct srv6_locator { uint64_t current; bool status_up; struct list *chunks; + uint8_t chunk_bits_length; uint8_t flags; #define SRV6_LOCATOR_USID (1 << 0) /* The SRv6 Locator is a uSID Locator */ @@ -195,6 +196,7 @@ extern struct srv6_locator *srv6_locator_alloc(const char *name); extern struct srv6_locator_chunk *srv6_locator_chunk_alloc(void); extern void srv6_locator_free(struct srv6_locator *locator); extern void srv6_locator_chunk_free(struct srv6_locator_chunk **chunk); +extern bool srv6_locator_chunks_exhausted(const struct srv6_locator *loc); json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk); json_object *srv6_locator_json(const struct srv6_locator *loc); json_object *srv6_locator_detailed_json(const struct srv6_locator *loc); diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index c095fec17b20..f4c6bcb295ef 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -965,23 +965,16 @@ static int sharp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) zapi_srv6_locator_chunk_decode(s, &s6c); for (ALL_LIST_ELEMENTS(sg.srv6_locators, node, nnode, loc)) { - struct prefix_ipv6 *chunk = NULL; - struct listnode *chunk_node; - struct prefix_ipv6 *c; - + struct prefix_ipv6 *chunk_prefix = NULL; if (strcmp(loc->name, s6c.locator_name) != 0) { zlog_err("%s: Locator name unmatch %s:%s", __func__, loc->name, s6c.locator_name); continue; } - for (ALL_LIST_ELEMENTS_RO(loc->chunks, chunk_node, c)) - if (!prefix_cmp(c, &s6c.prefix)) - return 0; - - chunk = prefix_ipv6_new(); - *chunk = s6c.prefix; - listnode_add(loc->chunks, chunk); + chunk_prefix = prefix_ipv6_new(); + *chunk_prefix = s6c.prefix; + listnode_add(loc->chunks, chunk_prefix); return 0; } diff --git a/tests/topotests/srv6_locator/expected_chunks2.json b/tests/topotests/srv6_locator/expected_chunks2.json index 8707384777ac..68fd6bf56296 100644 --- a/tests/topotests/srv6_locator/expected_chunks2.json +++ b/tests/topotests/srv6_locator/expected_chunks2.json @@ -1,8 +1,8 @@ [ - { - "name": "loc1", - "chunks": [ - "2001:db8:1:1::/64" - ] - } + { + "name": "loc1", + "chunks": [ + "2001:db8:1:1::/80" + ] + } ] diff --git a/tests/topotests/srv6_locator/expected_locators1.json b/tests/topotests/srv6_locator/expected_locators1.json index 3953bb07234f..833e9fe44fdd 100644 --- a/tests/topotests/srv6_locator/expected_locators1.json +++ b/tests/topotests/srv6_locator/expected_locators1.json @@ -1,26 +1,26 @@ { - "locators":[ - { - "name": "loc1", - "prefix": "2001:db8:1:1::/64", - "statusUp": true, - "chunks": [ - { - "prefix": "2001:db8:1:1::/64", - "proto": "system" - } - ] - }, - { - "name": "loc2", - "prefix": "2001:db8:2:2::/64", - "statusUp": true, - "chunks": [ - { - "prefix": "2001:db8:2:2::/64", - "proto": "system" - } - ] - } - ] + "locators": [ + { + "name": "loc1", + "prefix": "2001:db8:1:1::/64", + "statusUp": true, + "chunks": [ + { + "prefix": "2001:db8:1:1::/80", + "proto": "system" + } + ] + }, + { + "name": "loc2", + "prefix": "2001:db8:2:2::/64", + "statusUp": true, + "chunks": [ + { + "prefix": "2001:db8:2:2::/80", + "proto": "system" + } + ] + } + ] } diff --git a/tests/topotests/srv6_locator/expected_locators2.json b/tests/topotests/srv6_locator/expected_locators2.json index ce3a4045d75b..c02be341de01 100644 --- a/tests/topotests/srv6_locator/expected_locators2.json +++ b/tests/topotests/srv6_locator/expected_locators2.json @@ -1,26 +1,26 @@ { - "locators":[ - { - "name": "loc1", - "prefix": "2001:db8:1:1::/64", - "statusUp": true, - "chunks": [ - { - "prefix": "2001:db8:1:1::/64", - "proto": "sharp" - } - ] - }, - { - "name": "loc2", - "prefix": "2001:db8:2:2::/64", - "statusUp": true, - "chunks": [ - { - "prefix": "2001:db8:2:2::/64", - "proto": "system" - } - ] - } - ] + "locators": [ + { + "name": "loc1", + "prefix": "2001:db8:1:1::/64", + "statusUp": true, + "chunks": [ + { + "prefix": "2001:db8:1:1::/80", + "proto": "sharp" + } + ] + }, + { + "name": "loc2", + "prefix": "2001:db8:2:2::/64", + "statusUp": true, + "chunks": [ + { + "prefix": "2001:db8:2:2::/80", + "proto": "system" + } + ] + } + ] } diff --git a/tests/topotests/srv6_locator/expected_locators3.json b/tests/topotests/srv6_locator/expected_locators3.json index 3953bb07234f..833e9fe44fdd 100644 --- a/tests/topotests/srv6_locator/expected_locators3.json +++ b/tests/topotests/srv6_locator/expected_locators3.json @@ -1,26 +1,26 @@ { - "locators":[ - { - "name": "loc1", - "prefix": "2001:db8:1:1::/64", - "statusUp": true, - "chunks": [ - { - "prefix": "2001:db8:1:1::/64", - "proto": "system" - } - ] - }, - { - "name": "loc2", - "prefix": "2001:db8:2:2::/64", - "statusUp": true, - "chunks": [ - { - "prefix": "2001:db8:2:2::/64", - "proto": "system" - } - ] - } - ] + "locators": [ + { + "name": "loc1", + "prefix": "2001:db8:1:1::/64", + "statusUp": true, + "chunks": [ + { + "prefix": "2001:db8:1:1::/80", + "proto": "system" + } + ] + }, + { + "name": "loc2", + "prefix": "2001:db8:2:2::/64", + "statusUp": true, + "chunks": [ + { + "prefix": "2001:db8:2:2::/80", + "proto": "system" + } + ] + } + ] } diff --git a/tests/topotests/srv6_locator/expected_locators4.json b/tests/topotests/srv6_locator/expected_locators4.json index 4b0f95f7be2e..2d9ee645bcd1 100644 --- a/tests/topotests/srv6_locator/expected_locators4.json +++ b/tests/topotests/srv6_locator/expected_locators4.json @@ -1,38 +1,37 @@ { - "locators":[ - { - "name": "loc1", - "prefix": "2001:db8:1:1::/64", - "statusUp": true, - "chunks": [ - { - "prefix": "2001:db8:1:1::/64", - "proto": "system" - } - ] - }, - { - "name": "loc2", - "prefix": "2001:db8:2:2::/64", - "statusUp": true, - "chunks": [ - { - "prefix": "2001:db8:2:2::/64", - "proto": "system" - } - ] - }, - { - "name": "loc3", - "prefix": "2001:db8:3:3::/64", - "statusUp": true, - "chunks": [ - { - "prefix": "2001:db8:3:3::/64", - "proto": "system" - } - ] - } - ] + "locators": [ + { + "name": "loc1", + "prefix": "2001:db8:1:1::/64", + "statusUp": true, + "chunks": [ + { + "prefix": "2001:db8:1:1::/80", + "proto": "system" + } + ] + }, + { + "name": "loc2", + "prefix": "2001:db8:2:2::/64", + "statusUp": true, + "chunks": [ + { + "prefix": "2001:db8:2:2::/80", + "proto": "system" + } + ] + }, + { + "name": "loc3", + "prefix": "2001:db8:3:3::/64", + "statusUp": true, + "chunks": [ + { + "prefix": "2001:db8:3:3::/80", + "proto": "system" + } + ] + } + ] } - diff --git a/tests/topotests/srv6_locator/expected_locators5.json b/tests/topotests/srv6_locator/expected_locators5.json index bcffa004bdd4..e48d08880776 100644 --- a/tests/topotests/srv6_locator/expected_locators5.json +++ b/tests/topotests/srv6_locator/expected_locators5.json @@ -1,27 +1,26 @@ { - "locators":[ - { - "name": "loc2", - "prefix": "2001:db8:2:2::/64", - "statusUp": true, - "chunks": [ - { - "prefix": "2001:db8:2:2::/64", - "proto": "system" - } - ] - }, - { - "name": "loc3", - "prefix": "2001:db8:3:3::/64", - "statusUp": true, - "chunks":[ - { - "prefix": "2001:db8:3:3::/64", - "proto": "system" - } - ] - } - ] + "locators": [ + { + "name": "loc2", + "prefix": "2001:db8:2:2::/64", + "statusUp": true, + "chunks": [ + { + "prefix": "2001:db8:2:2::/80", + "proto": "system" + } + ] + }, + { + "name": "loc3", + "prefix": "2001:db8:3:3::/64", + "statusUp": true, + "chunks": [ + { + "prefix": "2001:db8:3:3::/80", + "proto": "system" + } + ] + } + ] } - diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index e9c243217a5d..0766eb1557fa 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2685,26 +2685,13 @@ int zsend_client_close_notify(struct zserv *client, struct zserv *closed_client) return zserv_send_message(client, s); } -int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client, - vrf_id_t vrf_id, - struct srv6_locator *loc) +int zsend_srv6_manager_get_locator_chunk_response( + struct zserv *client, vrf_id_t vrf_id, struct srv6_locator_chunk *chunk) { - struct srv6_locator_chunk chunk = {}; struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); - strlcpy(chunk.locator_name, loc->name, sizeof(chunk.locator_name)); - chunk.prefix = loc->prefix; - chunk.block_bits_length = loc->block_bits_length; - chunk.node_bits_length = loc->node_bits_length; - chunk.function_bits_length = loc->function_bits_length; - chunk.argument_bits_length = loc->argument_bits_length; - chunk.keep = 0; - chunk.proto = client->proto; - chunk.instance = client->instance; - chunk.flags = loc->flags; - zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, vrf_id); - zapi_srv6_locator_chunk_encode(s, &chunk); + zapi_srv6_locator_chunk_encode(s, chunk); stream_putw_at(s, 0, stream_get_endp(s)); return zserv_send_message(client, s); } diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index ce8e154465ff..6ece40177606 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -108,8 +108,8 @@ extern int zsend_zebra_srv6_locator_add(struct zserv *client, struct srv6_locator *loc); extern int zsend_zebra_srv6_locator_delete(struct zserv *client, struct srv6_locator *loc); -extern int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client, - vrf_id_t vrf_id, struct srv6_locator *loc); +extern int zsend_srv6_manager_get_locator_chunk_response( + struct zserv *client, vrf_id_t vrf_id, struct srv6_locator_chunk *chunk); #ifdef __cplusplus } diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 94b93e5e8dbb..8b6ff5d734d7 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -241,10 +241,8 @@ struct zebra_srv6 *zebra_srv6_get_default(void) * @return Pointer to the assigned srv6-locator chunk, * or NULL if the request could not be satisfied */ -static struct srv6_locator * -assign_srv6_locator_chunk(uint8_t proto, - uint16_t instance, - uint32_t session_id, +static struct srv6_locator_chunk * +assign_srv6_locator_chunk(uint8_t proto, uint16_t instance, uint32_t session_id, const char *locator_name) { bool chunk_found = false; @@ -259,6 +257,29 @@ assign_srv6_locator_chunk(uint8_t proto, return NULL; } + if (srv6_locator_chunks_exhausted(loc)) { + zlog_info("DRUMATO: chunk exhaustion"); + for (size_t i = listcount(loc->chunks); + 2 * listcount(loc->chunks) + 1; i++) { + chunk = srv6_locator_chunk_alloc(); + chunk->block_bits_length = loc->block_bits_length; + chunk->node_bits_length = loc->node_bits_length; + chunk->function_bits_length = loc->function_bits_length; + chunk->argument_bits_length = loc->argument_bits_length; + chunk->prefix = loc->prefix; + chunk->prefix.prefixlen += loc->chunk_bits_length; + chunk->flags = loc->flags; + strlcpy(chunk->locator_name, loc->name, + sizeof(chunk->locator_name)); + + // TODO: (drumato) + // Now the chunk bits are fixed to 16 but its not + // enough to use. + chunk->prefix.prefix.__in6_u.__u6_addr16[5] = i; + listnode_add(loc->chunks, chunk); + } + } + for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) { if (chunk->proto != NO_PROTO && chunk->proto != proto) continue; @@ -274,31 +295,32 @@ assign_srv6_locator_chunk(uint8_t proto, chunk->proto = proto; chunk->instance = instance; chunk->session_id = session_id; - return loc; + return chunk; } -static int zebra_srv6_manager_get_locator_chunk(struct srv6_locator **loc, - struct zserv *client, - const char *locator_name, - vrf_id_t vrf_id) +static int +zebra_srv6_manager_get_locator_chunk(struct srv6_locator_chunk **chunk, + struct zserv *client, + const char *locator_name, vrf_id_t vrf_id) { int ret = 0; - *loc = assign_srv6_locator_chunk(client->proto, client->instance, - client->session_id, locator_name); + *chunk = assign_srv6_locator_chunk(client->proto, client->instance, + client->session_id, locator_name); - if (!*loc) + if (!*chunk) { zlog_err("Unable to assign locator chunk to %s instance %u", zebra_route_string(client->proto), client->instance); - else if (IS_ZEBRA_DEBUG_PACKET) + return ret; + } + + if (IS_ZEBRA_DEBUG_PACKET) zlog_info("Assigned locator chunk %s to %s instance %u", - (*loc)->name, zebra_route_string(client->proto), + locator_name, zebra_route_string(client->proto), client->instance); - if (*loc && (*loc)->status_up) - ret = zsend_srv6_manager_get_locator_chunk_response(client, - vrf_id, - *loc); + ret = zsend_srv6_manager_get_locator_chunk_response(client, vrf_id, + *chunk); return ret; } diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index 51db83d6fb64..8de986171b41 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -32,10 +32,8 @@ DECLARE_HOOK(srv6_manager_client_connect, DECLARE_HOOK(srv6_manager_client_disconnect, (struct zserv *client), (client)); DECLARE_HOOK(srv6_manager_get_chunk, - (struct srv6_locator **loc, - struct zserv *client, - const char *locator_name, - vrf_id_t vrf_id), + (struct srv6_locator_chunk * *chunk, struct zserv *client, + const char *locator_name, vrf_id_t vrf_id), (mc, client, keep, size, base, vrf_id)); DECLARE_HOOK(srv6_manager_release_chunk, (struct zserv *client, diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index 3775d3dcdfc4..2a5138a40dd2 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -324,10 +324,14 @@ DEFPY (locator_prefix, locator->function_bits_length = func_bit_len; locator->argument_bits_length = 0; + locator->chunk_bits_length = 16; + if (list_isempty(locator->chunks)) { chunk = srv6_locator_chunk_alloc(); - chunk->prefix = *prefix; - chunk->proto = 0; + strlcpy(chunk->locator_name, locator->name, + sizeof(chunk->locator_name)); + chunk->prefix = locator->prefix; + chunk->prefix.prefixlen += locator->chunk_bits_length; listnode_add(locator->chunks, chunk); } else { for (ALL_LIST_ELEMENTS_RO(locator->chunks, node, chunk)) { @@ -337,7 +341,6 @@ DEFPY (locator_prefix, struct zserv *client; struct listnode *client_node; - chunk->prefix = *prefix; for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, client_node, client)) { From 41c36a4cae8ccd3fafcdf420feee923306c02396 Mon Sep 17 00:00:00 2001 From: Yamato Sugawara Date: Sun, 24 Oct 2021 10:31:28 +0000 Subject: [PATCH 2/6] zebra: step2 chunk pool expansion and move locator_add to the proper cmd Signed-off-by: Yamato Sugawara Signed-off-by: Philippe Guibert --- lib/srv6.c | 1 - sharpd/sharp_zebra.c | 1 + .../srv6_locator/expected_chunks2.json | 2 +- .../srv6_locator/expected_locators1.json | 8 -- .../srv6_locator/expected_locators2.json | 6 +- .../srv6_locator/expected_locators3.json | 6 +- .../srv6_locator/expected_locators4.json | 10 +-- .../srv6_locator/expected_locators5.json | 8 -- zebra/zapi_msg.c | 5 +- zebra/zebra_srv6.c | 86 +++++++++++++------ zebra/zebra_srv6.h | 10 ++- zebra/zebra_srv6_vty.c | 17 ++-- 12 files changed, 81 insertions(+), 79 deletions(-) diff --git a/lib/srv6.c b/lib/srv6.c index 10197d613cd4..cd254cda4fb2 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -161,7 +161,6 @@ bool srv6_locator_chunks_exhausted(const struct srv6_locator *loc) if (chunk->proto == 0 && chunk->instance == 0 && chunk->session_id == 0 && chunk->keep == 0) return false; - return true; } diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index f4c6bcb295ef..9193ce9e3859 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -966,6 +966,7 @@ static int sharp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) for (ALL_LIST_ELEMENTS(sg.srv6_locators, node, nnode, loc)) { struct prefix_ipv6 *chunk_prefix = NULL; + if (strcmp(loc->name, s6c.locator_name) != 0) { zlog_err("%s: Locator name unmatch %s:%s", __func__, loc->name, s6c.locator_name); diff --git a/tests/topotests/srv6_locator/expected_chunks2.json b/tests/topotests/srv6_locator/expected_chunks2.json index 68fd6bf56296..5cc7eec3de34 100644 --- a/tests/topotests/srv6_locator/expected_chunks2.json +++ b/tests/topotests/srv6_locator/expected_chunks2.json @@ -2,7 +2,7 @@ { "name": "loc1", "chunks": [ - "2001:db8:1:1::/80" + "2001:db8:1:1::/68" ] } ] diff --git a/tests/topotests/srv6_locator/expected_locators1.json b/tests/topotests/srv6_locator/expected_locators1.json index 833e9fe44fdd..733b3387c235 100644 --- a/tests/topotests/srv6_locator/expected_locators1.json +++ b/tests/topotests/srv6_locator/expected_locators1.json @@ -5,10 +5,6 @@ "prefix": "2001:db8:1:1::/64", "statusUp": true, "chunks": [ - { - "prefix": "2001:db8:1:1::/80", - "proto": "system" - } ] }, { @@ -16,10 +12,6 @@ "prefix": "2001:db8:2:2::/64", "statusUp": true, "chunks": [ - { - "prefix": "2001:db8:2:2::/80", - "proto": "system" - } ] } ] diff --git a/tests/topotests/srv6_locator/expected_locators2.json b/tests/topotests/srv6_locator/expected_locators2.json index c02be341de01..93b731298296 100644 --- a/tests/topotests/srv6_locator/expected_locators2.json +++ b/tests/topotests/srv6_locator/expected_locators2.json @@ -6,7 +6,7 @@ "statusUp": true, "chunks": [ { - "prefix": "2001:db8:1:1::/80", + "prefix": "2001:db8:1:1::/68", "proto": "sharp" } ] @@ -16,10 +16,6 @@ "prefix": "2001:db8:2:2::/64", "statusUp": true, "chunks": [ - { - "prefix": "2001:db8:2:2::/80", - "proto": "system" - } ] } ] diff --git a/tests/topotests/srv6_locator/expected_locators3.json b/tests/topotests/srv6_locator/expected_locators3.json index 833e9fe44fdd..dfdec88514f9 100644 --- a/tests/topotests/srv6_locator/expected_locators3.json +++ b/tests/topotests/srv6_locator/expected_locators3.json @@ -6,7 +6,7 @@ "statusUp": true, "chunks": [ { - "prefix": "2001:db8:1:1::/80", + "prefix": "2001:db8:1:1::/68", "proto": "system" } ] @@ -16,10 +16,6 @@ "prefix": "2001:db8:2:2::/64", "statusUp": true, "chunks": [ - { - "prefix": "2001:db8:2:2::/80", - "proto": "system" - } ] } ] diff --git a/tests/topotests/srv6_locator/expected_locators4.json b/tests/topotests/srv6_locator/expected_locators4.json index 2d9ee645bcd1..78bd5b667e5e 100644 --- a/tests/topotests/srv6_locator/expected_locators4.json +++ b/tests/topotests/srv6_locator/expected_locators4.json @@ -6,7 +6,7 @@ "statusUp": true, "chunks": [ { - "prefix": "2001:db8:1:1::/80", + "prefix": "2001:db8:1:1::/68", "proto": "system" } ] @@ -16,10 +16,6 @@ "prefix": "2001:db8:2:2::/64", "statusUp": true, "chunks": [ - { - "prefix": "2001:db8:2:2::/80", - "proto": "system" - } ] }, { @@ -27,10 +23,6 @@ "prefix": "2001:db8:3:3::/64", "statusUp": true, "chunks": [ - { - "prefix": "2001:db8:3:3::/80", - "proto": "system" - } ] } ] diff --git a/tests/topotests/srv6_locator/expected_locators5.json b/tests/topotests/srv6_locator/expected_locators5.json index e48d08880776..ea1728d39396 100644 --- a/tests/topotests/srv6_locator/expected_locators5.json +++ b/tests/topotests/srv6_locator/expected_locators5.json @@ -5,10 +5,6 @@ "prefix": "2001:db8:2:2::/64", "statusUp": true, "chunks": [ - { - "prefix": "2001:db8:2:2::/80", - "proto": "system" - } ] }, { @@ -16,10 +12,6 @@ "prefix": "2001:db8:3:3::/64", "statusUp": true, "chunks": [ - { - "prefix": "2001:db8:3:3::/80", - "proto": "system" - } ] } ] diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 0766eb1557fa..e7f9cbffdf2c 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2919,8 +2919,9 @@ static void zread_srv6_manager_get_locator_chunk(struct zserv *client, STREAM_GET(locator_name, s, len); /* call hook to get a chunk using wrapper */ - struct srv6_locator *loc = NULL; - srv6_manager_get_locator_chunk_call(&loc, client, locator_name, vrf_id); + struct srv6_locator_chunk *chunk = NULL; + srv6_manager_get_locator_chunk_call(&chunk, client, locator_name, + vrf_id); stream_failure: return; diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 8b6ff5d734d7..0a54736af948 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -43,11 +43,9 @@ DEFINE_HOOK(srv6_manager_client_connect, DEFINE_HOOK(srv6_manager_client_disconnect, (struct zserv *client), (client)); DEFINE_HOOK(srv6_manager_get_chunk, - (struct srv6_locator **loc, - struct zserv *client, - const char *locator_name, - vrf_id_t vrf_id), - (loc, client, locator_name, vrf_id)); + (struct srv6_locator_chunk * *chunk, struct zserv *client, + const char *locator_name, vrf_id_t vrf_id), + (chunk, client, locator_name, vrf_id)); DEFINE_HOOK(srv6_manager_release_chunk, (struct zserv *client, const char *locator_name, @@ -63,12 +61,12 @@ void srv6_manager_client_connect_call(struct zserv *client, vrf_id_t vrf_id) hook_call(srv6_manager_client_connect, client, vrf_id); } -void srv6_manager_get_locator_chunk_call(struct srv6_locator **loc, +void srv6_manager_get_locator_chunk_call(struct srv6_locator_chunk **chunk, struct zserv *client, const char *locator_name, vrf_id_t vrf_id) { - hook_call(srv6_manager_get_chunk, loc, client, locator_name, vrf_id); + hook_call(srv6_manager_get_chunk, chunk, client, locator_name, vrf_id); } void srv6_manager_release_locator_chunk_call(struct zserv *client, @@ -228,6 +226,45 @@ struct zebra_srv6 *zebra_srv6_get_default(void) return &srv6; } +/** + * inherit attributes from locator to chunk + * + * Inherits attributes from locator to chunk. + * @param loc SRv6 locator that is a source of shared attributes. + * @param chunk SRv6 chunk that receives attributes from the parent locator. + * @return void + */ +static void inherit_attrs_from_locator_to_chunk(struct srv6_locator *loc, + struct srv6_locator_chunk *chunk) +{ + chunk->block_bits_length = loc->block_bits_length; + chunk->node_bits_length = loc->node_bits_length; + chunk->function_bits_length = loc->function_bits_length; + chunk->argument_bits_length = loc->argument_bits_length; + strlcpy(chunk->locator_name, loc->name, sizeof(chunk->locator_name)); + return; +} + +/** + * separate locator prefix into chunk + * + * currently each locator-chunk only uses /68 prefix. + * we may need to change the ipv6-block operation for supporting + * more flexible chunk_length. + * @param loc SRv6 locator that is a source of shared attributes. + * @param chunk_index Index of locator's chunk pool. + * @return the new chunk's prefix or NULL. + */ +static struct prefix_ipv6 +separate_locator_prefix_into_chunk(struct srv6_locator *loc, + uint16_t chunk_index) +{ + struct prefix_ipv6 chunk_prefix = loc->prefix; + chunk_prefix.prefixlen += loc->chunk_bits_length; + chunk_prefix.prefix.__in6_u.__u6_addr16[4] = htons(chunk_index); + return chunk_prefix; +} + /** * Core function, assigns srv6-locator chunks * @@ -257,25 +294,24 @@ assign_srv6_locator_chunk(uint8_t proto, uint16_t instance, uint32_t session_id, return NULL; } - if (srv6_locator_chunks_exhausted(loc)) { - zlog_info("DRUMATO: chunk exhaustion"); - for (size_t i = listcount(loc->chunks); - 2 * listcount(loc->chunks) + 1; i++) { + if (list_isempty(loc->chunks) || srv6_locator_chunks_exhausted(loc)) { + uint16_t current_chunks = listcount(loc->chunks); + uint16_t expansion_end = current_chunks ? 2 * current_chunks : 1; + + // currently each locator-chunk only uses /68 prefix. + if (expansion_end > DEFAULT_SRV6_LOCATOR_CHUNK_ENTRIES) { + zlog_err("%s: locator %s chunk pool no longer expanded", + __func__, locator_name); + return NULL; + } + + for (uint16_t chunk_index = current_chunks; + chunk_index < expansion_end; chunk_index++) { chunk = srv6_locator_chunk_alloc(); - chunk->block_bits_length = loc->block_bits_length; - chunk->node_bits_length = loc->node_bits_length; - chunk->function_bits_length = loc->function_bits_length; - chunk->argument_bits_length = loc->argument_bits_length; - chunk->prefix = loc->prefix; - chunk->prefix.prefixlen += loc->chunk_bits_length; - chunk->flags = loc->flags; - strlcpy(chunk->locator_name, loc->name, - sizeof(chunk->locator_name)); - - // TODO: (drumato) - // Now the chunk bits are fixed to 16 but its not - // enough to use. - chunk->prefix.prefix.__in6_u.__u6_addr16[5] = i; + inherit_attrs_from_locator_to_chunk(loc, chunk); + chunk->prefix = + separate_locator_prefix_into_chunk(loc, + chunk_index); listnode_add(loc->chunks, chunk); } } diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index 8de986171b41..64ba11105c85 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -55,14 +55,16 @@ extern bool zebra_srv6_is_enable(void); extern void srv6_manager_client_connect_call(struct zserv *client, vrf_id_t vrf_id); -extern void srv6_manager_get_locator_chunk_call(struct srv6_locator **loc, - struct zserv *client, - const char *locator_name, - vrf_id_t vrf_id); +extern void +srv6_manager_get_locator_chunk_call(struct srv6_locator_chunk **chunk, + struct zserv *client, + const char *locator_name, vrf_id_t vrf_id); extern void srv6_manager_release_locator_chunk_call(struct zserv *client, const char *locator_name, vrf_id_t vrf_id); extern int srv6_manager_client_disconnect_cb(struct zserv *client); extern int release_daemon_srv6_locator_chunks(struct zserv *client); +#define DEFAULT_SRV6_LOCATOR_PERCHUNK_LEN 4 +#define DEFAULT_SRV6_LOCATOR_CHUNK_ENTRIES 16 #endif /* _ZEBRA_SRV6_H */ diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index 2a5138a40dd2..cebd527ba36e 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -241,6 +241,7 @@ DEFUN_NOSH (srv6_locator, VTY_PUSH_CONTEXT(SRV6_LOC_NODE, locator); vty->node = SRV6_LOC_NODE; + zebra_srv6_locator_add(locator); return CMD_SUCCESS; } @@ -324,16 +325,11 @@ DEFPY (locator_prefix, locator->function_bits_length = func_bit_len; locator->argument_bits_length = 0; - locator->chunk_bits_length = 16; + // currently srv6 manager supports the chunk_length to only 4 bits. + // the feature enables us to manipulate at most 16 chunks. + locator->chunk_bits_length = DEFAULT_SRV6_LOCATOR_PERCHUNK_LEN; - if (list_isempty(locator->chunks)) { - chunk = srv6_locator_chunk_alloc(); - strlcpy(chunk->locator_name, locator->name, - sizeof(chunk->locator_name)); - chunk->prefix = locator->prefix; - chunk->prefix.prefixlen += locator->chunk_bits_length; - listnode_add(locator->chunks, chunk); - } else { + if (!list_isempty(locator->chunks)) { for (ALL_LIST_ELEMENTS_RO(locator->chunks, node, chunk)) { uint8_t zero[16] = {0}; @@ -344,7 +340,7 @@ DEFPY (locator_prefix, for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, client_node, client)) { - struct srv6_locator *tmp; + struct srv6_locator_chunk *tmp; if (client->proto != chunk->proto) continue; @@ -358,7 +354,6 @@ DEFPY (locator_prefix, } } - zebra_srv6_locator_add(locator); return CMD_SUCCESS; } From 6e587fbc820acd9565837fd701958707bfc038cd Mon Sep 17 00:00:00 2001 From: Yamato Sugawara Date: Wed, 3 Nov 2021 06:35:03 +0000 Subject: [PATCH 3/6] zebra: avoiding build error on bsd by using s6_addr16 macro Signed-off-by: Yamato Sugawara Signed-off-by: Philippe Guibert --- zebra/zebra_srv6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 0a54736af948..fd659f0a1017 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -261,7 +261,7 @@ separate_locator_prefix_into_chunk(struct srv6_locator *loc, { struct prefix_ipv6 chunk_prefix = loc->prefix; chunk_prefix.prefixlen += loc->chunk_bits_length; - chunk_prefix.prefix.__in6_u.__u6_addr16[4] = htons(chunk_index); + chunk_prefix.prefix.s6_addr16[4] = htons(chunk_index); return chunk_prefix; } From 3b37df9b260d4618adc2716a9f0f3d48d1c3119b Mon Sep 17 00:00:00 2001 From: Yamato Sugawara Date: Wed, 3 Nov 2021 08:08:00 +0000 Subject: [PATCH 4/6] zebra: avoiding build error on *bsd again Signed-off-by: Yamato Sugawara Signed-off-by: Philippe Guibert --- zebra/zebra_srv6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index fd659f0a1017..e8ab921df25f 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -261,7 +261,7 @@ separate_locator_prefix_into_chunk(struct srv6_locator *loc, { struct prefix_ipv6 chunk_prefix = loc->prefix; chunk_prefix.prefixlen += loc->chunk_bits_length; - chunk_prefix.prefix.s6_addr16[4] = htons(chunk_index); + chunk_prefix.prefix.s6_addr32[2] = (uint32_t)htons(chunk_index); return chunk_prefix; } From dac9ba22a4cee88b554749e06c14161fb5e73afb Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 11 Aug 2023 12:26:01 +0200 Subject: [PATCH 5/6] bgpd: add json output for `show bgp segment-routing srv6` Add json support for 'show bgp segment-routing srv6' command. Signed-off-by: Yamato Sugawara Signed-off-by: Philippe Guibert --- bgpd/bgp_vty.c | 139 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 112 insertions(+), 27 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 573abf0cda2e..bd242a7367a8 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -10322,50 +10322,135 @@ DEFPY (no_bgp_srv6_locator, return CMD_SUCCESS; } -DEFPY (show_bgp_srv6, - show_bgp_srv6_cmd, - "show bgp segment-routing srv6", - SHOW_STR - BGP_STR - "BGP Segment Routing\n" - "BGP Segment Routing SRv6\n") +DEFPY(show_bgp_srv6, show_bgp_srv6_cmd, "show bgp segment-routing srv6 [json]", + SHOW_STR BGP_STR "BGP Segment Routing\n" + "BGP Segment Routing SRv6\n" JSON_STR) { struct bgp *bgp; struct listnode *node; struct srv6_locator_chunk *chunk; struct bgp_srv6_function *func; + json_object *json = NULL; + json_object *json_chunk = NULL; + json_object *json_chunks = NULL; + json_object *json_function = NULL; + json_object *json_functions = NULL; + json_object *json_bgp = NULL; + json_object *json_bgps = NULL; + json_object *json_vpn_policy = NULL; + json_object *json_vpn_policy_ip = NULL; + json_object *json_vpn_policy_ip6 = NULL; + bool uj = use_json(argc, argv); bgp = bgp_get_default(); if (!bgp) return CMD_SUCCESS; - vty_out(vty, "locator_name: %s\n", bgp->srv6_locator_name); - vty_out(vty, "locator_chunks:\n"); - for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) { - vty_out(vty, "- %pFX\n", &chunk->prefix); - vty_out(vty, " block-length: %d\n", chunk->block_bits_length); - vty_out(vty, " node-length: %d\n", chunk->node_bits_length); - vty_out(vty, " func-length: %d\n", - chunk->function_bits_length); - vty_out(vty, " arg-length: %d\n", chunk->argument_bits_length); - } - - vty_out(vty, "functions:\n"); - for (ALL_LIST_ELEMENTS_RO(bgp->srv6_functions, node, func)) { - vty_out(vty, "- sid: %pI6\n", &func->sid); - vty_out(vty, " locator: %s\n", func->locator_name); - } + if (!uj) { + vty_out(vty, "locator_name: %s\n", bgp->srv6_locator_name); + vty_out(vty, "locator_chunks:\n"); + for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, + chunk)) { + vty_out(vty, "- %pFX\n", &chunk->prefix); + vty_out(vty, " block-length: %d\n", + chunk->block_bits_length); + vty_out(vty, " node-length: %d\n", + chunk->node_bits_length); + vty_out(vty, " func-length: %d\n", + chunk->function_bits_length); + vty_out(vty, " arg-length: %d\n", + chunk->argument_bits_length); + } - vty_out(vty, "bgps:\n"); - for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) { - vty_out(vty, "- name: %s\n", - bgp->name ? bgp->name : "default"); + vty_out(vty, "functions:\n"); + for (ALL_LIST_ELEMENTS_RO(bgp->srv6_functions, node, func)) { + vty_out(vty, "- sid: %pI6\n", &func->sid); + vty_out(vty, " locator: %s\n", func->locator_name); + } vty_out(vty, " vpn_policy[AFI_IP].tovpn_sid: %pI6\n", bgp->vpn_policy[AFI_IP].tovpn_sid); vty_out(vty, " vpn_policy[AFI_IP6].tovpn_sid: %pI6\n", bgp->vpn_policy[AFI_IP6].tovpn_sid); vty_out(vty, " per-vrf tovpn_sid: %pI6\n", bgp->tovpn_sid); + + } else { + json = json_object_new_object(); + json_chunks = json_object_new_array(); + json_functions = json_object_new_array(); + json_bgps = json_object_new_array(); + json_object_string_add(json, "locatorName", + bgp->srv6_locator_name); + json_object_object_add(json, "locatorChunks", json_chunks); + json_object_object_add(json, "functions", json_functions); + json_object_object_add(json, "bgps", json_bgps); + + /* collect all chunk to json array*/ + for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, + chunk)) { + json_chunk = json_object_new_object(); + json_object_array_add(json_chunks, json_chunk); + json_object_string_addf(json_chunk, "chunk", "%pFX", + &chunk->prefix); + json_object_int_add(json_chunk, "block-length", + chunk->block_bits_length); + json_object_int_add(json_chunk, "node-bits-length", + chunk->node_bits_length); + json_object_int_add(json_chunk, "function-bits-length", + chunk->function_bits_length); + json_object_int_add(json_chunk, "arg-length", + chunk->argument_bits_length); + } + + /* collect all function to json array*/ + for (ALL_LIST_ELEMENTS_RO(bgp->srv6_functions, node, func)) { + json_function = json_object_new_object(); + json_object_array_add(json_functions, json_function); + json_object_string_addf(json_function, "Sid", "%pI6", + &func->sid); + json_object_string_add(json_function, "locator", + func->locator_name); + } + + /* collect all bgp instance to json array*/ + for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) { + json_bgp = json_object_new_object(); + json_object_array_add(json_bgps, json_bgp); + json_object_string_add(json_bgp, "name", + bgp->name ? bgp->name + : "default"); + + json_vpn_policy = json_object_new_object(); + json_vpn_policy_ip = json_object_new_object(); + json_vpn_policy_ip6 = json_object_new_object(); + json_object_object_add(json_bgp, "vpnPolicy", + json_vpn_policy); + json_object_object_add(json_vpn_policy, "ip", + json_vpn_policy_ip); + json_object_object_add(json_vpn_policy, "ip6", + json_vpn_policy_ip6); + if (bgp->vpn_policy[AFI_IP].tovpn_sid) + json_object_string_addf(json_vpn_policy_ip, + "toVpnSid", "%pI6", + bgp->vpn_policy[AFI_IP] + .tovpn_sid); + else + json_object_string_add(json_vpn_policy_ip, + "toVpnSid", "none"); + if (bgp->vpn_policy[AFI_IP6].tovpn_sid) + json_object_string_addf(json_vpn_policy_ip6, + "toVpnSid", "%pI6", + bgp->vpn_policy[AFI_IP6] + .tovpn_sid); + else + json_object_string_add(json_vpn_policy_ip6, + "toVpnSid", "none"); + } + + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); } return CMD_SUCCESS; From d80110a8543b3825126b5851e283c00045833ff4 Mon Sep 17 00:00:00 2001 From: Yamato Sugawara Date: Tue, 2 Nov 2021 05:54:09 +0000 Subject: [PATCH 6/6] topotests: add srv6_locator_chunks test for testing multi chunks This test checks sharing locator sids between sharpd and bgpd. Signed-off-by: Yamato Sugawara Signed-off-by: Philippe Guibert --- lib/srv6.c | 6 + .../topotests/srv6_locator_chunks/__init__.py | 0 .../srv6_locator_chunks/r1/bgpd.conf | 3 + .../topotests/srv6_locator_chunks/r1/setup.sh | 2 + .../srv6_locator_chunks/r1/sharpd.conf | 7 + .../srv6_locator_chunks/r1/zebra.conf | 19 ++ .../step1/expected_bgpd_chunks.json | 18 ++ .../step1/expected_locators.json | 10 + .../step1/expected_sharpd_chunks.json | 1 + .../step2/expected_bgpd_chunks.json | 18 ++ .../step2/expected_locators.json | 15 ++ .../step2/expected_sharpd_chunks.json | 8 + .../step3/expected_bgpd_chunks.json | 22 ++ .../step3/expected_locators.json | 19 ++ .../step3/expected_sharpd_chunks.json | 8 + .../step4/expected_bgpd_chunks.json | 22 ++ .../step4/expected_locators.json | 19 ++ .../step4/expected_sharpd_chunks.json | 1 + .../step5/expected_bgpd_chunks.json | 18 ++ .../step5/expected_locators.json | 19 ++ .../step5/expected_sharpd_chunks.json | 8 + .../step6/expected_bgpd_chunks.json | 18 ++ .../step6/expected_locators.json | 19 ++ .../step6/expected_sharpd_chunks.json | 1 + .../test_srv6_locator_chunks.py | 193 ++++++++++++++++++ 25 files changed, 474 insertions(+) create mode 100644 tests/topotests/srv6_locator_chunks/__init__.py create mode 100644 tests/topotests/srv6_locator_chunks/r1/bgpd.conf create mode 100644 tests/topotests/srv6_locator_chunks/r1/setup.sh create mode 100644 tests/topotests/srv6_locator_chunks/r1/sharpd.conf create mode 100644 tests/topotests/srv6_locator_chunks/r1/zebra.conf create mode 100644 tests/topotests/srv6_locator_chunks/step1/expected_bgpd_chunks.json create mode 100644 tests/topotests/srv6_locator_chunks/step1/expected_locators.json create mode 100644 tests/topotests/srv6_locator_chunks/step1/expected_sharpd_chunks.json create mode 100644 tests/topotests/srv6_locator_chunks/step2/expected_bgpd_chunks.json create mode 100644 tests/topotests/srv6_locator_chunks/step2/expected_locators.json create mode 100644 tests/topotests/srv6_locator_chunks/step2/expected_sharpd_chunks.json create mode 100644 tests/topotests/srv6_locator_chunks/step3/expected_bgpd_chunks.json create mode 100644 tests/topotests/srv6_locator_chunks/step3/expected_locators.json create mode 100644 tests/topotests/srv6_locator_chunks/step3/expected_sharpd_chunks.json create mode 100644 tests/topotests/srv6_locator_chunks/step4/expected_bgpd_chunks.json create mode 100644 tests/topotests/srv6_locator_chunks/step4/expected_locators.json create mode 100644 tests/topotests/srv6_locator_chunks/step4/expected_sharpd_chunks.json create mode 100644 tests/topotests/srv6_locator_chunks/step5/expected_bgpd_chunks.json create mode 100644 tests/topotests/srv6_locator_chunks/step5/expected_locators.json create mode 100644 tests/topotests/srv6_locator_chunks/step5/expected_sharpd_chunks.json create mode 100644 tests/topotests/srv6_locator_chunks/step6/expected_bgpd_chunks.json create mode 100644 tests/topotests/srv6_locator_chunks/step6/expected_locators.json create mode 100644 tests/topotests/srv6_locator_chunks/step6/expected_sharpd_chunks.json create mode 100755 tests/topotests/srv6_locator_chunks/test_srv6_locator_chunks.py diff --git a/lib/srv6.c b/lib/srv6.c index cd254cda4fb2..0ddaea19d96d 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -152,6 +152,12 @@ void srv6_locator_chunk_free(struct srv6_locator_chunk **chunk) XFREE(MTYPE_SRV6_LOCATOR_CHUNK, *chunk); } +/** + * check all chunk in the locator are used by clients + * + * @param loc SRv6 locator + * @return true if all chunks are used. + */ bool srv6_locator_chunks_exhausted(const struct srv6_locator *loc) { struct listnode *node; diff --git a/tests/topotests/srv6_locator_chunks/__init__.py b/tests/topotests/srv6_locator_chunks/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/topotests/srv6_locator_chunks/r1/bgpd.conf b/tests/topotests/srv6_locator_chunks/r1/bgpd.conf new file mode 100644 index 000000000000..340dfba39b5a --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/r1/bgpd.conf @@ -0,0 +1,3 @@ +router bgp 100 + bgp router-id 1.1.1.1 +! diff --git a/tests/topotests/srv6_locator_chunks/r1/setup.sh b/tests/topotests/srv6_locator_chunks/r1/setup.sh new file mode 100644 index 000000000000..36ed713f2416 --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/r1/setup.sh @@ -0,0 +1,2 @@ +ip link add dummy0 type dummy +ip link set dummy0 up diff --git a/tests/topotests/srv6_locator_chunks/r1/sharpd.conf b/tests/topotests/srv6_locator_chunks/r1/sharpd.conf new file mode 100644 index 000000000000..d46085935c80 --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/r1/sharpd.conf @@ -0,0 +1,7 @@ +hostname r1 +! +log stdout notifications +log monitor notifications +log commands +log file sharpd.log debugging +! diff --git a/tests/topotests/srv6_locator_chunks/r1/zebra.conf b/tests/topotests/srv6_locator_chunks/r1/zebra.conf new file mode 100644 index 000000000000..cb73bec9772f --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/r1/zebra.conf @@ -0,0 +1,19 @@ +hostname r1 +! +debug zebra events +debug zebra rib detailed +! +log stdout notifications +log monitor notifications +log commands +log file zebra.log debugging +! +segment-routing + srv6 + locators + locator loc1 + prefix 2001:db8:1:1::/64 + ! + ! + ! +! diff --git a/tests/topotests/srv6_locator_chunks/step1/expected_bgpd_chunks.json b/tests/topotests/srv6_locator_chunks/step1/expected_bgpd_chunks.json new file mode 100644 index 000000000000..2a3296c09787 --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/step1/expected_bgpd_chunks.json @@ -0,0 +1,18 @@ +{ + "locatorName": "", + "locatorChunks": [], + "functions": [], + "bgps": [ + { + "name": "default", + "vpnPolicy": { + "ip": { + "toVpnSid": "none" + }, + "ip6": { + "toVpnSid": "none" + } + } + } + ] +} \ No newline at end of file diff --git a/tests/topotests/srv6_locator_chunks/step1/expected_locators.json b/tests/topotests/srv6_locator_chunks/step1/expected_locators.json new file mode 100644 index 000000000000..a750c8fbe792 --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/step1/expected_locators.json @@ -0,0 +1,10 @@ +{ + "locators": [ + { + "name": "loc1", + "prefix": "2001:db8:1:1::/64", + "statusUp": true, + "chunks": [] + } + ] +} diff --git a/tests/topotests/srv6_locator_chunks/step1/expected_sharpd_chunks.json b/tests/topotests/srv6_locator_chunks/step1/expected_sharpd_chunks.json new file mode 100644 index 000000000000..fe51488c7066 --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/step1/expected_sharpd_chunks.json @@ -0,0 +1 @@ +[] diff --git a/tests/topotests/srv6_locator_chunks/step2/expected_bgpd_chunks.json b/tests/topotests/srv6_locator_chunks/step2/expected_bgpd_chunks.json new file mode 100644 index 000000000000..2a3296c09787 --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/step2/expected_bgpd_chunks.json @@ -0,0 +1,18 @@ +{ + "locatorName": "", + "locatorChunks": [], + "functions": [], + "bgps": [ + { + "name": "default", + "vpnPolicy": { + "ip": { + "toVpnSid": "none" + }, + "ip6": { + "toVpnSid": "none" + } + } + } + ] +} \ No newline at end of file diff --git a/tests/topotests/srv6_locator_chunks/step2/expected_locators.json b/tests/topotests/srv6_locator_chunks/step2/expected_locators.json new file mode 100644 index 000000000000..7ed48ed5252f --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/step2/expected_locators.json @@ -0,0 +1,15 @@ +{ + "locators": [ + { + "name": "loc1", + "prefix": "2001:db8:1:1::/64", + "statusUp": true, + "chunks": [ + { + "prefix": "2001:db8:1:1::/68", + "proto": "sharp" + } + ] + } + ] +} diff --git a/tests/topotests/srv6_locator_chunks/step2/expected_sharpd_chunks.json b/tests/topotests/srv6_locator_chunks/step2/expected_sharpd_chunks.json new file mode 100644 index 000000000000..5cc7eec3de34 --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/step2/expected_sharpd_chunks.json @@ -0,0 +1,8 @@ +[ + { + "name": "loc1", + "chunks": [ + "2001:db8:1:1::/68" + ] + } +] diff --git a/tests/topotests/srv6_locator_chunks/step3/expected_bgpd_chunks.json b/tests/topotests/srv6_locator_chunks/step3/expected_bgpd_chunks.json new file mode 100644 index 000000000000..f5311e9dbc6f --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/step3/expected_bgpd_chunks.json @@ -0,0 +1,22 @@ +{ + "locatorName": "loc1", + "locatorChunks": [ + { + "chunk":"2001:db8:1:1:1::/68" + } + ], + "functions": [], + "bgps": [ + { + "name": "default", + "vpnPolicy": { + "ip": { + "toVpnSid": "none" + }, + "ip6": { + "toVpnSid": "none" + } + } + } + ] +} \ No newline at end of file diff --git a/tests/topotests/srv6_locator_chunks/step3/expected_locators.json b/tests/topotests/srv6_locator_chunks/step3/expected_locators.json new file mode 100644 index 000000000000..0e0638b4ffbd --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/step3/expected_locators.json @@ -0,0 +1,19 @@ +{ + "locators": [ + { + "name": "loc1", + "prefix": "2001:db8:1:1::/64", + "statusUp": true, + "chunks": [ + { + "prefix": "2001:db8:1:1::/68", + "proto": "sharp" + }, + { + "prefix": "2001:db8:1:1:1::/68", + "proto": "bgp" + } + ] + } + ] +} diff --git a/tests/topotests/srv6_locator_chunks/step3/expected_sharpd_chunks.json b/tests/topotests/srv6_locator_chunks/step3/expected_sharpd_chunks.json new file mode 100644 index 000000000000..5cc7eec3de34 --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/step3/expected_sharpd_chunks.json @@ -0,0 +1,8 @@ +[ + { + "name": "loc1", + "chunks": [ + "2001:db8:1:1::/68" + ] + } +] diff --git a/tests/topotests/srv6_locator_chunks/step4/expected_bgpd_chunks.json b/tests/topotests/srv6_locator_chunks/step4/expected_bgpd_chunks.json new file mode 100644 index 000000000000..e1e53ef5d79d --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/step4/expected_bgpd_chunks.json @@ -0,0 +1,22 @@ +{ + "locatorName": "loc1", + "locatorChunks": [ + { + "chunk": "2001:db8:1:1:1::/68" + } + ], + "functions": [], + "bgps": [ + { + "name": "default", + "vpnPolicy": { + "ip": { + "toVpnSid": "none" + }, + "ip6": { + "toVpnSid": "none" + } + } + } + ] +} \ No newline at end of file diff --git a/tests/topotests/srv6_locator_chunks/step4/expected_locators.json b/tests/topotests/srv6_locator_chunks/step4/expected_locators.json new file mode 100644 index 000000000000..23da7f5dc6bd --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/step4/expected_locators.json @@ -0,0 +1,19 @@ +{ + "locators": [ + { + "name": "loc1", + "prefix": "2001:db8:1:1::/64", + "statusUp": true, + "chunks": [ + { + "prefix": "2001:db8:1:1::/68", + "proto": "system" + }, + { + "prefix": "2001:db8:1:1:1::/68", + "proto": "bgp" + } + ] + } + ] +} diff --git a/tests/topotests/srv6_locator_chunks/step4/expected_sharpd_chunks.json b/tests/topotests/srv6_locator_chunks/step4/expected_sharpd_chunks.json new file mode 100644 index 000000000000..fe51488c7066 --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/step4/expected_sharpd_chunks.json @@ -0,0 +1 @@ +[] diff --git a/tests/topotests/srv6_locator_chunks/step5/expected_bgpd_chunks.json b/tests/topotests/srv6_locator_chunks/step5/expected_bgpd_chunks.json new file mode 100644 index 000000000000..2a3296c09787 --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/step5/expected_bgpd_chunks.json @@ -0,0 +1,18 @@ +{ + "locatorName": "", + "locatorChunks": [], + "functions": [], + "bgps": [ + { + "name": "default", + "vpnPolicy": { + "ip": { + "toVpnSid": "none" + }, + "ip6": { + "toVpnSid": "none" + } + } + } + ] +} \ No newline at end of file diff --git a/tests/topotests/srv6_locator_chunks/step5/expected_locators.json b/tests/topotests/srv6_locator_chunks/step5/expected_locators.json new file mode 100644 index 000000000000..57ebd7d2ba5c --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/step5/expected_locators.json @@ -0,0 +1,19 @@ +{ + "locators": [ + { + "name": "loc1", + "prefix": "2001:db8:1:1::/64", + "statusUp": true, + "chunks": [ + { + "prefix": "2001:db8:1:1::/68", + "proto": "sharp" + }, + { + "prefix": "2001:db8:1:1:1::/68", + "proto": "system" + } + ] + } + ] +} diff --git a/tests/topotests/srv6_locator_chunks/step5/expected_sharpd_chunks.json b/tests/topotests/srv6_locator_chunks/step5/expected_sharpd_chunks.json new file mode 100644 index 000000000000..5cc7eec3de34 --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/step5/expected_sharpd_chunks.json @@ -0,0 +1,8 @@ +[ + { + "name": "loc1", + "chunks": [ + "2001:db8:1:1::/68" + ] + } +] diff --git a/tests/topotests/srv6_locator_chunks/step6/expected_bgpd_chunks.json b/tests/topotests/srv6_locator_chunks/step6/expected_bgpd_chunks.json new file mode 100644 index 000000000000..2a3296c09787 --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/step6/expected_bgpd_chunks.json @@ -0,0 +1,18 @@ +{ + "locatorName": "", + "locatorChunks": [], + "functions": [], + "bgps": [ + { + "name": "default", + "vpnPolicy": { + "ip": { + "toVpnSid": "none" + }, + "ip6": { + "toVpnSid": "none" + } + } + } + ] +} \ No newline at end of file diff --git a/tests/topotests/srv6_locator_chunks/step6/expected_locators.json b/tests/topotests/srv6_locator_chunks/step6/expected_locators.json new file mode 100644 index 000000000000..21165556bb15 --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/step6/expected_locators.json @@ -0,0 +1,19 @@ +{ + "locators": [ + { + "name": "loc1", + "prefix": "2001:db8:1:1::/64", + "statusUp": true, + "chunks": [ + { + "prefix": "2001:db8:1:1::/68", + "proto": "system" + }, + { + "prefix": "2001:db8:1:1:1::/68", + "proto": "system" + } + ] + } + ] +} diff --git a/tests/topotests/srv6_locator_chunks/step6/expected_sharpd_chunks.json b/tests/topotests/srv6_locator_chunks/step6/expected_sharpd_chunks.json new file mode 100644 index 000000000000..fe51488c7066 --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/step6/expected_sharpd_chunks.json @@ -0,0 +1 @@ +[] diff --git a/tests/topotests/srv6_locator_chunks/test_srv6_locator_chunks.py b/tests/topotests/srv6_locator_chunks/test_srv6_locator_chunks.py new file mode 100755 index 000000000000..78c9381ddf93 --- /dev/null +++ b/tests/topotests/srv6_locator_chunks/test_srv6_locator_chunks.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python + +# +# test_srv6_locator_chunks.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2021 by +# Yamato Sugawara +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_srv6_locator_chunks.py: +Test SRv6 manager for multi chunks on zebra +""" + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +pytestmark = [pytest.mark.bgpd, pytest.mark.sharpd] + + +def open_json_file(filename): + try: + with open(filename, "r") as f: + return json.load(f) + except IOError: + assert False, "Could not read file {}".format(filename) + + +def setup_module(mod): + tgen = Topogen({None: "r1"}, mod.__name__) + tgen.start_topology() + for rname, router in tgen.routers().items(): + router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname)) + ) + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def get_locator_chunk_from_bgpd(router, locator): + router.vtysh_cmd( + """ + configure terminal + router bgp 100 + segment-routing srv6 + locator {} + """.format( + locator + ) + ) + + +def get_locator_chunk_from_sharpd(router, locator): + router.vtysh_cmd("sharp srv6-manager get-locator-chunk {}".format(locator)) + + +def release_locator_chunk_from_bgpd(router, locator): + router.vtysh_cmd( + """ + configure terminal + router bgp 100 + segment-routing srv6 + no locator {} + """.format( + locator + ) + ) + + +def release_locator_chunk_from_sharpd(router, locator): + router.vtysh_cmd("sharp srv6-manager release-locator-chunk {}".format(locator)) + + +def test_srv6(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + router = tgen.gears["r1"] + + def _check_srv6_locator(router, expected_locator_file): + logger.info("checking zebra locator status") + output = json.loads(router.vtysh_cmd("show segment-routing srv6 locator json")) + expected = open_json_file("{}/{}".format(CWD, expected_locator_file)) + return topotest.json_cmp(output, expected) + + def _check_sharpd_chunk(router, expected_chunk_file): + logger.info("checking sharpd locator chunk status") + output = json.loads(router.vtysh_cmd("show sharp segment-routing srv6 json")) + expected = open_json_file("{}/{}".format(CWD, expected_chunk_file)) + return topotest.json_cmp(output, expected) + + def _check_bgpd_chunk(router, expected_chunk_file): + logger.info("checking bgpd locator chunk status") + output = json.loads(router.vtysh_cmd("show bgp segment-routing srv6 json")) + expected = open_json_file("{}/{}".format(CWD, expected_chunk_file)) + return topotest.json_cmp(output, expected) + + def check_srv6_locator(router, expected_file): + func = functools.partial(_check_srv6_locator, router, expected_file) + success, result = topotest.run_and_expect(func, None, count=5, wait=1) + assert result is None, "Failed" + + def check_sharpd_chunk(router, expected_file): + func = functools.partial(_check_sharpd_chunk, router, expected_file) + success, result = topotest.run_and_expect(func, None, count=5, wait=1) + assert result is None, "Failed" + + def check_bgpd_chunk(router, expected_file): + func = functools.partial(_check_bgpd_chunk, router, expected_file) + success, result = topotest.run_and_expect(func, None, count=5, wait=1) + assert result is None, "Failed" + + # FOR DEVELOPER: + # If you want to stop some specific line and start interactive shell, + # please use tgen.mininet_cli() to start it. + + logger.info("Test STEP1: locator configuration") + check_srv6_locator(router, "step1/expected_locators.json") + check_sharpd_chunk(router, "step1/expected_sharpd_chunks.json") + check_bgpd_chunk(router, "step1/expected_bgpd_chunks.json") + + logger.info("Test STEP2: get locator chunk for locator loc1 from sharpd") + get_locator_chunk_from_sharpd(router, "loc1") + check_srv6_locator(router, "step2/expected_locators.json") + check_sharpd_chunk(router, "step2/expected_sharpd_chunks.json") + check_bgpd_chunk(router, "step2/expected_bgpd_chunks.json") + + logger.info("Test STEP3: get locator chunk for locator loc1 from bgpd") + get_locator_chunk_from_bgpd(router, "loc1") + check_srv6_locator(router, "step3/expected_locators.json") + check_sharpd_chunk(router, "step3/expected_sharpd_chunks.json") + check_bgpd_chunk(router, "step3/expected_bgpd_chunks.json") + + logger.info("Test STEP4: release locator chunk loc1 by sharpd") + release_locator_chunk_from_sharpd(router, "loc1") + check_srv6_locator(router, "step4/expected_locators.json") + check_sharpd_chunk(router, "step4/expected_sharpd_chunks.json") + check_bgpd_chunk(router, "step4/expected_bgpd_chunks.json") + + logger.info("Test STEP5: release locator chunk loc1 by bgpd") + get_locator_chunk_from_sharpd(router, "loc1") + release_locator_chunk_from_bgpd(router, "loc1") + check_srv6_locator(router, "step5/expected_locators.json") + check_sharpd_chunk(router, "step5/expected_sharpd_chunks.json") + check_bgpd_chunk(router, "step5/expected_bgpd_chunks.json") + + logger.info("Test STEP6: release all chunk") + release_locator_chunk_from_sharpd(router, "loc1") + check_srv6_locator(router, "step6/expected_locators.json") + check_sharpd_chunk(router, "step6/expected_sharpd_chunks.json") + check_bgpd_chunk(router, "step6/expected_bgpd_chunks.json") + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args))