summaryrefslogtreecommitdiff
path: root/isisd
diff options
context:
space:
mode:
authorRuss White <russ@riw.us>2024-07-02 08:32:05 -0400
committerGitHub <noreply@github.com>2024-07-02 08:32:05 -0400
commit410947f6a71abfeb6e51ae04c8f54202d5484641 (patch)
tree3f4643e9af66cc9b6712f63bc5072f19de5f925e /isisd
parent667715df130cc900e8f5aec02249f8ecd5321409 (diff)
parentfe5b03a10b583d0a95104a43389a9b60ca9bc397 (diff)
Merge pull request #15677 from cscarpitta/isis-srv6-sid-manager
isisd: Extend IS-IS to communicate with the SRv6 SID Manager to allocate/release SRv6 SIDs
Diffstat (limited to 'isisd')
-rw-r--r--isisd/isis_lsp.c13
-rw-r--r--isisd/isis_nb_config.c6
-rw-r--r--isisd/isis_srv6.c201
-rw-r--r--isisd/isis_srv6.h14
-rw-r--r--isisd/isis_zebra.c428
-rw-r--r--isisd/isis_zebra.h7
6 files changed, 395 insertions, 274 deletions
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index c98cee06a5..13f5148d4a 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -1222,17 +1222,11 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
}
/* Add SRv6 Locator TLV. */
- if (area->srv6db.config.enabled &&
- !list_isempty(area->srv6db.srv6_locator_chunks)) {
+ if (area->srv6db.config.enabled && area->srv6db.srv6_locator) {
struct isis_srv6_locator locator = {};
- struct srv6_locator_chunk *chunk;
-
- /* TODO: support more than one locator */
- chunk = (struct srv6_locator_chunk *)listgetdata(
- listhead(area->srv6db.srv6_locator_chunks));
locator.metric = 0;
- locator.prefix = chunk->prefix;
+ locator.prefix = area->srv6db.srv6_locator->prefix;
locator.flags = 0;
locator.algorithm = 0;
@@ -1252,7 +1246,8 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
isis_tlvs_add_ipv6_reach(lsp->tlvs,
isis_area_ipv6_topology(area),
- &chunk->prefix, 0, false, NULL);
+ &area->srv6db.srv6_locator->prefix, 0,
+ false, NULL);
}
/* IPv4 address and TE router ID TLVs.
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index 763b8b73d2..30c90baa54 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -3518,10 +3518,10 @@ int isis_instance_segment_routing_srv6_locator_modify(
sr_debug("Configured SRv6 locator %s for IS-IS area %s", loc_name,
area->area_tag);
- sr_debug("Trying to get a chunk from locator %s for IS-IS area %s",
- loc_name, area->area_tag);
+ sr_debug("Trying to get locator %s for IS-IS area %s", loc_name,
+ area->area_tag);
- if (isis_zebra_srv6_manager_get_locator_chunk(loc_name) < 0)
+ if (isis_zebra_srv6_manager_get_locator(loc_name) < 0)
return NB_ERR;
return NB_OK;
diff --git a/isisd/isis_srv6.c b/isisd/isis_srv6.c
index 44fd599cbb..b5974b1a62 100644
--- a/isisd/isis_srv6.c
+++ b/isisd/isis_srv6.c
@@ -102,6 +102,7 @@ bool isis_srv6_locator_unset(struct isis_area *area)
struct srv6_locator_chunk *chunk;
struct isis_srv6_sid *sid;
struct srv6_adjacency *sra;
+ struct srv6_sid_ctx ctx = {};
if (strncmp(area->srv6db.config.srv6_locator_name, "",
sizeof(area->srv6db.config.srv6_locator_name)) == 0) {
@@ -120,13 +121,31 @@ bool isis_srv6_locator_unset(struct isis_area *area)
* Zebra */
isis_zebra_srv6_sid_uninstall(area, sid);
+ /*
+ * Inform the SID Manager that IS-IS will no longer use the SID, so
+ * that the SID Manager can remove the SID context ownership from IS-IS
+ * and release/free the SID context if it is not yes by other protocols.
+ */
+ ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END;
+ isis_zebra_release_srv6_sid(&ctx);
+
listnode_delete(area->srv6db.srv6_sids, sid);
isis_srv6_sid_free(sid);
}
/* Uninstall all local Adjacency-SIDs. */
- for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, sra))
+ for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, sra)) {
+ /*
+ * Inform the SID Manager that IS-IS will no longer use the SID, so
+ * that the SID Manager can remove the SID context ownership from IS-IS
+ * and release/free the SID context if it is not yes by other protocols.
+ */
+ ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_X;
+ ctx.nh6 = sra->nexthop;
+ isis_zebra_release_srv6_sid(&ctx);
+
srv6_endx_sid_del(sra);
+ }
/* Inform Zebra that we are releasing the SRv6 locator */
ret = isis_zebra_srv6_manager_release_locator_chunk(
@@ -146,6 +165,10 @@ bool isis_srv6_locator_unset(struct isis_area *area)
srv6_locator_chunk_free(&chunk);
}
+ /* Clear locator */
+ srv6_locator_free(area->srv6db.srv6_locator);
+ area->srv6db.srv6_locator = NULL;
+
/* Clear locator name */
memset(area->srv6db.config.srv6_locator_name, 0,
sizeof(area->srv6db.config.srv6_locator_name));
@@ -198,149 +221,35 @@ void isis_srv6_interface_set(struct isis_area *area, const char *ifname)
}
/**
- * Encode SID function in the SRv6 SID.
- *
- * @param sid
- * @param func
- * @param offset
- * @param len
- */
-static void encode_sid_func(struct in6_addr *sid, uint32_t func, uint8_t offset,
- uint8_t len)
-{
- for (uint8_t idx = 0; idx < len; idx++) {
- uint8_t tidx = offset + idx;
- sid->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8));
- if (func >> (len - 1 - idx) & 0x1)
- sid->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8);
- }
-}
-
-static bool sid_exist(struct isis_area *area, const struct in6_addr *sid)
-{
- struct listnode *node;
- struct isis_srv6_sid *s;
- struct srv6_adjacency *sra;
-
- for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_sids, node, s))
- if (sid_same(&s->sid, sid))
- return true;
- for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_endx_sids, node, sra))
- if (sid_same(&sra->sid, sid))
- return true;
- return false;
-}
-
-/**
- * Request a SID from the SRv6 locator.
- *
- * @param area IS-IS area
- * @param chunk SRv6 locator chunk
- * @param sid_func The FUNCTION part of the SID to be allocated (a negative
- * number will allocate the first available SID)
- *
- * @return First available SID on success or in6addr_any if the SRv6
- * locator chunk is full
- */
-static struct in6_addr
-srv6_locator_request_sid(struct isis_area *area,
- struct srv6_locator_chunk *chunk, int sid_func)
-{
- struct in6_addr sid;
- uint8_t offset = 0;
- uint8_t func_len = 0;
- uint32_t func_max;
- bool allocated = false;
-
- if (!area || !chunk)
- return in6addr_any;
-
- sr_debug("ISIS-SRv6 (%s): requested new SID from locator %s",
- area->area_tag, chunk->locator_name);
-
- /* Let's build the SID, step by step. A SID has the following structure
- (defined in RFC 8986): LOCATOR:FUNCTION:ARGUMENT.*/
-
- /* First, we encode the LOCATOR in the L most significant bits. */
- sid = chunk->prefix.prefix;
-
- /* The next part of the SID is the FUNCTION. Let's compute the length
- * and the offset of the FUNCTION in the SID */
- func_len = chunk->function_bits_length;
- offset = chunk->block_bits_length + chunk->node_bits_length;
-
- /* Then, encode the FUNCTION */
- if (sid_func >= 0) {
- /* SID FUNCTION has been specified. We need to allocate a SID
- * with the requested FUNCTION. */
- encode_sid_func(&sid, sid_func, offset, func_len);
- if (sid_exist(area, &sid)) {
- zlog_warn(
- "ISIS-SRv6 (%s): the requested SID %pI6 is already used",
- area->area_tag, &sid);
- return sid;
- }
- allocated = true;
- } else {
- /* SID FUNCTION not specified. We need to choose a FUNCTION that
- * is not already used. So let's iterate through all possible
- * functions and get the first available one. */
- func_max = (1 << func_len) - 1;
- for (uint32_t func = 1; func < func_max; func++) {
- encode_sid_func(&sid, func, offset, func_len);
- if (sid_exist(area, &sid))
- continue;
- allocated = true;
- break;
- }
- }
-
- if (!allocated) {
- /* We ran out of available SIDs */
- zlog_warn("ISIS-SRv6 (%s): no SIDs available in locator %s",
- area->area_tag, chunk->locator_name);
- return in6addr_any;
- }
-
- sr_debug("ISIS-SRv6 (%s): allocating new SID %pI6", area->area_tag,
- &sid);
-
- return sid;
-}
-
-/**
* Allocate an SRv6 SID from an SRv6 locator.
*
* @param area IS-IS area
- * @param chunk SRv6 locator chunk
+ * @param locator SRv6 locator
* @param behavior SRv6 Endpoint Behavior bound to the SID
+ * @param sid_value SRv6 SID value
*
* @result the allocated SID on success, NULL otherwise
*/
struct isis_srv6_sid *
-isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator_chunk *chunk,
+isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator *locator,
enum srv6_endpoint_behavior_codepoint behavior,
- int sid_func)
+ struct in6_addr *sid_value)
{
struct isis_srv6_sid *sid = NULL;
- if (!area || !chunk)
+ if (!area || !locator || !sid_value)
return NULL;
sid = XCALLOC(MTYPE_ISIS_SRV6_SID, sizeof(struct isis_srv6_sid));
- sid->sid = srv6_locator_request_sid(area, chunk, sid_func);
- if (IPV6_ADDR_SAME(&sid->sid, &in6addr_any)) {
- isis_srv6_sid_free(sid);
- return NULL;
- }
+ sid->sid = *sid_value;
sid->behavior = behavior;
- sid->structure.loc_block_len = chunk->block_bits_length;
- sid->structure.loc_node_len = chunk->node_bits_length;
- sid->structure.func_len = chunk->function_bits_length;
- sid->structure.arg_len = chunk->argument_bits_length;
- sid->locator = chunk;
+ sid->structure.loc_block_len = locator->block_bits_length;
+ sid->structure.loc_node_len = locator->node_bits_length;
+ sid->structure.func_len = locator->function_bits_length;
+ sid->structure.arg_len = locator->argument_bits_length;
+ sid->locator = locator;
sid->area = area;
return sid;
@@ -376,9 +285,10 @@ void isis_area_delete_backup_srv6_endx_sids(struct isis_area *area, int level)
* @param adj IS-IS Adjacency
* @param backup True to initialize backup Adjacency SID
* @param nexthops List of backup nexthops (for backup End.X SIDs only)
+ * @param sid_value SID value associated to be associated with the adjacency
*/
void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup,
- struct list *nexthops)
+ struct list *nexthops, struct in6_addr *sid_value)
{
struct isis_circuit *circuit = adj->circuit;
struct isis_area *area = circuit->area;
@@ -387,11 +297,10 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup,
struct isis_srv6_lan_endx_sid_subtlv *ladj_sid;
struct in6_addr nexthop;
uint8_t flags = 0;
- struct srv6_locator_chunk *chunk;
+ struct srv6_locator *locator;
uint32_t behavior;
- if (!area || !area->srv6db.srv6_locator_chunks ||
- list_isempty(area->srv6db.srv6_locator_chunks))
+ if (!area || !area->srv6db.srv6_locator)
return;
sr_debug("ISIS-SRv6 (%s): Add %s End.X SID", area->area_tag,
@@ -401,10 +310,7 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup,
if (!circuit->ipv6_router || !adj->ll_ipv6_count)
return;
- chunk = (struct srv6_locator_chunk *)listgetdata(
- listhead(area->srv6db.srv6_locator_chunks));
- if (!chunk)
- return;
+ locator = area->srv6db.srv6_locator;
nexthop = adj->ll_ipv6_addrs[0];
@@ -415,25 +321,21 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup,
if (circuit->ext == NULL)
circuit->ext = isis_alloc_ext_subtlvs();
- behavior = (CHECK_FLAG(chunk->flags, SRV6_LOCATOR_USID))
+ behavior = (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
? SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID
: SRV6_ENDPOINT_BEHAVIOR_END_X;
sra = XCALLOC(MTYPE_ISIS_SRV6_INFO, sizeof(*sra));
sra->type = backup ? ISIS_SRV6_ADJ_BACKUP : ISIS_SRV6_ADJ_NORMAL;
sra->behavior = behavior;
- sra->locator = chunk;
- sra->structure.loc_block_len = chunk->block_bits_length;
- sra->structure.loc_node_len = chunk->node_bits_length;
- sra->structure.func_len = chunk->function_bits_length;
- sra->structure.arg_len = chunk->argument_bits_length;
+ sra->locator = locator;
+ sra->structure.loc_block_len = locator->block_bits_length;
+ sra->structure.loc_node_len = locator->node_bits_length;
+ sra->structure.func_len = locator->function_bits_length;
+ sra->structure.arg_len = locator->argument_bits_length;
sra->nexthop = nexthop;
- sra->sid = srv6_locator_request_sid(area, chunk, -1);
- if (IPV6_ADDR_SAME(&sra->sid, &in6addr_any)) {
- XFREE(MTYPE_ISIS_SRV6_INFO, sra);
- return;
- }
+ sra->sid = *sid_value;
switch (circuit->circ_type) {
/* SRv6 LAN End.X SID for Broadcast interface section #8.2 */
@@ -505,9 +407,9 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup,
*
* @param adj IS-IS Adjacency
*/
-void srv6_endx_sid_add(struct isis_adjacency *adj)
+void srv6_endx_sid_add(struct isis_adjacency *adj, struct in6_addr *sid_value)
{
- srv6_endx_sid_add_single(adj, false, NULL);
+ srv6_endx_sid_add_single(adj, false, NULL, sid_value);
}
/**
@@ -610,7 +512,7 @@ static int srv6_adj_ip_enabled(struct isis_adjacency *adj, int family,
family != AF_INET6)
return 0;
- srv6_endx_sid_add(adj);
+ isis_zebra_request_srv6_sid_endx(adj);
return 0;
}
@@ -832,6 +734,9 @@ void isis_srv6_area_term(struct isis_area *area)
srv6_locator_chunk_free(&chunk);
list_delete(&srv6db->srv6_locator_chunks);
+ srv6_locator_free(area->srv6db.srv6_locator);
+ area->srv6db.srv6_locator = NULL;
+
/* Free SRv6 SIDs list */
list_delete(&srv6db->srv6_sids);
list_delete(&srv6db->srv6_endx_sids);
diff --git a/isisd/isis_srv6.h b/isisd/isis_srv6.h
index 7f16712ae3..bde14965f6 100644
--- a/isisd/isis_srv6.h
+++ b/isisd/isis_srv6.h
@@ -44,7 +44,7 @@ struct isis_srv6_sid {
struct isis_srv6_sid_structure structure;
/* Parent SRv6 locator */
- struct srv6_locator_chunk *locator;
+ struct srv6_locator *locator;
/* Backpointer to IS-IS area */
struct isis_area *area;
@@ -89,7 +89,7 @@ struct srv6_adjacency {
struct isis_srv6_sid_structure structure;
/* Parent SRv6 locator */
- struct srv6_locator_chunk *locator;
+ struct srv6_locator *locator;
/* Adjacency-SID nexthop information */
struct in6_addr nexthop;
@@ -109,6 +109,8 @@ struct srv6_adjacency {
/* Per-area IS-IS SRv6 Data Base (SRv6 DB) */
struct isis_srv6_db {
+ /* List of SRv6 Locator */
+ struct srv6_locator *srv6_locator;
/* List of SRv6 Locator chunks */
struct list *srv6_locator_chunks;
@@ -149,9 +151,9 @@ bool isis_srv6_locator_unset(struct isis_area *area);
void isis_srv6_interface_set(struct isis_area *area, const char *ifname);
struct isis_srv6_sid *
-isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator_chunk *chunk,
+isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator *locator,
enum srv6_endpoint_behavior_codepoint behavior,
- int sid_func);
+ struct in6_addr *sid_value);
extern void isis_srv6_sid_free(struct isis_srv6_sid *sid);
extern void isis_srv6_area_init(struct isis_area *area);
@@ -169,8 +171,8 @@ void isis_srv6_locator2tlv(const struct isis_srv6_locator *loc,
struct isis_srv6_locator_tlv *loc_tlv);
void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup,
- struct list *nexthops);
-void srv6_endx_sid_add(struct isis_adjacency *adj);
+ struct list *nexthops, struct in6_addr *sid_value);
+void srv6_endx_sid_add(struct isis_adjacency *adj, struct in6_addr *sid_value);
void srv6_endx_sid_del(struct srv6_adjacency *sra);
struct srv6_adjacency *isis_srv6_endx_sid_find(struct isis_adjacency *adj,
enum srv6_adj_type type);
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index 2412ec5e84..ce4eb74ec6 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -645,6 +645,70 @@ int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size)
}
/**
+ * Request an End.X SID for an IS-IS adjacency.
+ *
+ * @param adj IS-IS Adjacency
+ */
+void isis_zebra_request_srv6_sid_endx(struct isis_adjacency *adj)
+{
+ struct isis_circuit *circuit = adj->circuit;
+ struct isis_area *area = circuit->area;
+ struct in6_addr nexthop;
+ struct srv6_sid_ctx ctx = {};
+ struct in6_addr sid_value = {};
+ bool ret;
+
+ if (!area || !area->srv6db.srv6_locator)
+ return;
+
+ /* Determine nexthop IP address */
+ if (!circuit->ipv6_router || !adj->ll_ipv6_count)
+ return;
+
+ nexthop = adj->ll_ipv6_addrs[0];
+
+ ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_X;
+ ctx.nh6 = nexthop;
+ ret = isis_zebra_request_srv6_sid(&ctx, &sid_value,
+ area->srv6db.config.srv6_locator_name);
+ if (!ret) {
+ zlog_err("%s: not allocated new End.X SID for IS-IS area %s",
+ __func__, area->area_tag);
+ return;
+ }
+}
+
+static void request_srv6_sids(struct isis_area *area)
+{
+ struct srv6_sid_ctx ctx = {};
+ struct in6_addr sid_value = {};
+ struct listnode *node;
+ struct isis_adjacency *adj;
+ bool ret;
+
+ if (!area || !area->srv6db.config.enabled || !area->srv6db.srv6_locator)
+ return;
+
+ sr_debug("Requesting SRv6 SIDs for IS-IS area %s", area->area_tag);
+
+ /* Request new SRv6 End SID */
+ ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END;
+ ret = isis_zebra_request_srv6_sid(&ctx, &sid_value,
+ area->srv6db.config.srv6_locator_name);
+ if (!ret) {
+ zlog_err("%s: not allocated new End SID for IS-IS area %s",
+ __func__, area->area_tag);
+ return;
+ }
+
+ /* Create SRv6 End.X SIDs from existing IS-IS Adjacencies */
+ for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) {
+ if (adj->ll_ipv6_count > 0)
+ isis_zebra_request_srv6_sid_endx(adj);
+ }
+}
+
+/**
* Release Label Range to the Label Manager.
*
* @param start start of label range to release
@@ -1119,99 +1183,47 @@ void isis_zebra_srv6_adj_sid_uninstall(struct srv6_adjacency *sra)
}
/**
- * Callback to process an SRv6 locator chunk received from SRv6 Manager (zebra).
+ * Internal function to process an SRv6 locator
*
- * @result 0 on success, -1 otherwise
+ * @param locator The locator to be processed
*/
-static int isis_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS)
+static int isis_zebra_process_srv6_locator_internal(struct srv6_locator *locator)
{
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
- struct stream *s = NULL;
- struct listnode *node;
struct isis_area *area;
- struct srv6_locator_chunk *c;
- struct srv6_locator_chunk *chunk = srv6_locator_chunk_alloc();
- struct isis_srv6_sid *sid;
- struct isis_adjacency *adj;
- enum srv6_endpoint_behavior_codepoint behavior;
- bool allocated = false;
-
- if (!isis) {
- srv6_locator_chunk_free(&chunk);
- return -1;
- }
+ struct listnode *node;
- /* Decode the received zebra message */
- s = zclient->ibuf;
- if (zapi_srv6_locator_chunk_decode(s, chunk) < 0) {
- srv6_locator_chunk_free(&chunk);
+ if (!isis || !locator)
return -1;
- }
- sr_debug(
- "Received SRv6 locator chunk from zebra: name %s, "
- "prefix %pFX, block_len %u, node_len %u, func_len %u, arg_len %u",
- chunk->locator_name, &chunk->prefix, chunk->block_bits_length,
- chunk->node_bits_length, chunk->function_bits_length,
- chunk->argument_bits_length);
+ zlog_info("%s: Received SRv6 locator %s %pFX, loc-block-len=%u, loc-node-len=%u func-len=%u, arg-len=%u",
+ __func__, locator->name, &locator->prefix,
+ locator->block_bits_length, locator->node_bits_length,
+ locator->function_bits_length, locator->argument_bits_length);
/* Walk through all areas of the ISIS instance */
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
- if (strncmp(area->srv6db.config.srv6_locator_name,
- chunk->locator_name,
- sizeof(area->srv6db.config.srv6_locator_name)) != 0)
+ /*
+ * Check if the IS-IS area is configured to use the received
+ * locator
+ */
+ if (strncmp(area->srv6db.config.srv6_locator_name, locator->name,
+ sizeof(area->srv6db.config.srv6_locator_name)) != 0) {
+ zlog_err("%s: SRv6 Locator name unmatch %s:%s",
+ __func__, area->srv6db.config.srv6_locator_name,
+ locator->name);
continue;
-
- for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_locator_chunks,
- node, c)) {
- if (!prefix_cmp(&c->prefix, &chunk->prefix)) {
- srv6_locator_chunk_free(&chunk);
- return 0;
- }
- }
-
- sr_debug(
- "SRv6 locator chunk (locator %s, prefix %pFX) assigned to IS-IS area %s",
- chunk->locator_name, &chunk->prefix, area->area_tag);
-
- /* Add the SRv6 Locator chunk to the per-area chunks list */
- listnode_add(area->srv6db.srv6_locator_chunks, chunk);
-
- /* Decide which behavior to use,depending on the locator type
- * (i.e. uSID vs classic locator) */
- behavior = (CHECK_FLAG(chunk->flags, SRV6_LOCATOR_USID))
- ? SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID
- : SRV6_ENDPOINT_BEHAVIOR_END;
-
- /* Allocate new SRv6 End SID */
- sid = isis_srv6_sid_alloc(area, chunk, behavior, 0);
- if (!sid)
- return -1;
-
- /* Install the new SRv6 End SID in the forwarding plane through
- * Zebra */
- isis_zebra_srv6_sid_install(area, sid);
-
- /* Store the SID */
- listnode_add(area->srv6db.srv6_sids, sid);
-
- /* Create SRv6 End.X SIDs from existing IS-IS Adjacencies */
- for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) {
- if (adj->ll_ipv6_count > 0)
- srv6_endx_sid_add(adj);
}
- /* Regenerate LSPs to advertise the new locator and the SID */
- lsp_regenerate_schedule(area, area->is_type, 0);
+ sr_debug("SRv6 locator (locator %s, prefix %pFX) set for IS-IS area %s",
+ locator->name, &locator->prefix, area->area_tag);
- allocated = true;
- break;
- }
+ /* Store the locator in the IS-IS area */
+ area->srv6db.srv6_locator = srv6_locator_alloc(locator->name);
+ srv6_locator_copy(area->srv6db.srv6_locator, locator);
- if (!allocated) {
- sr_debug("No IS-IS area configured for the locator %s",
- chunk->locator_name);
- srv6_locator_chunk_free(&chunk);
+ /* Request SIDs from the locator */
+ request_srv6_sids(area);
}
return 0;
@@ -1226,8 +1238,6 @@ static int isis_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS)
{
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
struct srv6_locator loc = {};
- struct listnode *node;
- struct isis_area *area;
if (!isis)
return -1;
@@ -1236,33 +1246,7 @@ static int isis_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS)
if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0)
return -1;
- sr_debug(
- "New SRv6 locator allocated in zebra: name %s, "
- "prefix %pFX, block_len %u, node_len %u, func_len %u, arg_len %u",
- loc.name, &loc.prefix, loc.block_bits_length,
- loc.node_bits_length, loc.function_bits_length,
- loc.argument_bits_length);
-
- /* Lookup on the IS-IS areas */
- for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
- /* If SRv6 is enabled on this area and the configured locator
- * corresponds to the new locator, then request a chunk from the
- * locator */
- if (area->srv6db.config.enabled &&
- strncmp(area->srv6db.config.srv6_locator_name, loc.name,
- sizeof(area->srv6db.config.srv6_locator_name)) == 0) {
- sr_debug(
- "Sending a request to get a chunk from the SRv6 locator %s (%pFX) "
- "for IS-IS area %s",
- loc.name, &loc.prefix, area->area_tag);
-
- if (isis_zebra_srv6_manager_get_locator_chunk(
- loc.name) < 0)
- return -1;
- }
- }
-
- return 0;
+ return isis_zebra_process_srv6_locator_internal(&loc);
}
/**
@@ -1335,6 +1319,9 @@ static int isis_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
}
}
+ srv6_locator_free(area->srv6db.srv6_locator);
+ area->srv6db.srv6_locator = NULL;
+
/* Regenerate LSPs to advertise that the locator no longer
* exists */
lsp_regenerate_schedule(area, area->is_type, 0);
@@ -1368,6 +1355,232 @@ int isis_zebra_srv6_manager_release_locator_chunk(const char *name)
return srv6_manager_release_locator_chunk(zclient, name);
}
+/**
+ * Ask the SRv6 Manager (zebra) about a specific locator
+ *
+ * @param name Locator name
+ * @return 0 on success, -1 otherwise
+ */
+int isis_zebra_srv6_manager_get_locator(const char *name)
+{
+ if (!name)
+ return -1;
+
+ /*
+ * Send the Get Locator request to the SRv6 Manager and return the
+ * result
+ */
+ return srv6_manager_get_locator(zclient, name);
+}
+
+/**
+ * Ask the SRv6 Manager (zebra) to allocate a SID.
+ *
+ * Optionally, it is possible to provide an IPv6 address (sid_value parameter).
+ *
+ * When sid_value is provided, the SRv6 Manager allocates the requested SID
+ * address, if the request can be satisfied (explicit allocation).
+ *
+ * When sid_value is not provided, the SRv6 Manager allocates any available SID
+ * from the provided locator (dynamic allocation).
+ *
+ * @param ctx Context to be associated with the request SID
+ * @param sid_value IPv6 address to be associated with the requested SID (optional)
+ * @param locator_name Name of the locator from which the SID must be allocated
+ */
+bool isis_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx,
+ struct in6_addr *sid_value,
+ const char *locator_name)
+{
+ int ret;
+
+ if (!ctx || !locator_name)
+ return false;
+
+ /*
+ * Send the Get SRv6 SID request to the SRv6 Manager and check the
+ * result
+ */
+ ret = srv6_manager_get_sid(zclient, ctx, sid_value, locator_name, NULL);
+ if (ret < 0) {
+ zlog_warn("%s: error getting SRv6 SID!", __func__);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Ask the SRv6 Manager (zebra) to release a previously allocated SID.
+ *
+ * This function is used to tell the SRv6 Manager that IS-IS no longer intends
+ * to use the SID.
+ *
+ * @param ctx Context to be associated with the SID to be released
+ */
+void isis_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx)
+{
+ int ret;
+
+ if (!ctx)
+ return;
+
+ /*
+ * Send the Release SRv6 SID request to the SRv6 Manager and check the
+ * result
+ */
+ ret = srv6_manager_release_sid(zclient, ctx);
+ if (ret < 0) {
+ zlog_warn("%s: error releasing SRv6 SID!", __func__);
+ return;
+ }
+}
+
+static int isis_zebra_srv6_sid_notify(ZAPI_CALLBACK_ARGS)
+{
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+ struct srv6_sid_ctx ctx;
+ struct in6_addr sid_addr;
+ enum zapi_srv6_sid_notify note;
+ uint32_t sid_func;
+ struct isis_area *area;
+ struct listnode *node, *nnode, *n;
+ char buf[256];
+ struct srv6_locator *locator;
+ struct prefix_ipv6 tmp_prefix;
+ struct srv6_adjacency *sra;
+ enum srv6_endpoint_behavior_codepoint behavior;
+ struct isis_srv6_sid *sid;
+ struct isis_adjacency *adj;
+
+ if (!isis)
+ return -1;
+
+ /* Decode the received notification message */
+ if (!zapi_srv6_sid_notify_decode(zclient->ibuf, &ctx, &sid_addr,
+ &sid_func, NULL, &note, NULL)) {
+ zlog_err("%s : error in msg decode", __func__);
+ return -1;
+ }
+
+ sr_debug("%s: received SRv6 SID notify: ctx %s sid_value %pI6 sid_func %u note %s",
+ __func__, srv6_sid_ctx2str(buf, sizeof(buf), &ctx), &sid_addr,
+ sid_func, zapi_srv6_sid_notify2str(note));
+
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+ if (!area->srv6db.config.enabled || !area->srv6db.srv6_locator)
+ continue;
+
+ locator = area->srv6db.srv6_locator;
+
+ /* Verify that the received SID belongs to the configured locator */
+ if (note == ZAPI_SRV6_SID_ALLOCATED) {
+ tmp_prefix.family = AF_INET6;
+ tmp_prefix.prefixlen = IPV6_MAX_BITLEN;
+ tmp_prefix.prefix = sid_addr;
+
+ if (!prefix_match((struct prefix *)&locator->prefix,
+ (struct prefix *)&tmp_prefix)) {
+ sr_debug("%s : ignoring SRv6 SID notify: locator (area %s) does not match",
+ __func__, area->area_tag);
+ continue;
+ }
+ }
+
+ /* Handle notification */
+ switch (note) {
+ case ZAPI_SRV6_SID_ALLOCATED:
+ sr_debug("SRv6 SID %pI6 %s ALLOCATED", &sid_addr,
+ srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
+
+ if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END) {
+ /* Remove old End SIDs, if any */
+ for (ALL_LIST_ELEMENTS(area->srv6db.srv6_sids,
+ node, nnode, sid)) {
+ isis_zebra_srv6_sid_uninstall(area, sid);
+ listnode_delete(area->srv6db.srv6_sids,
+ sid);
+ }
+
+ /* Allocate new SRv6 End SID */
+ behavior =
+ (CHECK_FLAG(locator->flags,
+ SRV6_LOCATOR_USID))
+ ? SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID
+ : SRV6_ENDPOINT_BEHAVIOR_END;
+ sid = isis_srv6_sid_alloc(area,
+ area->srv6db
+ .srv6_locator,
+ behavior, &sid_addr);
+ if (!sid) {
+ zlog_warn("%s: isis_srv6_sid_alloc failed",
+ __func__);
+ return -1;
+ }
+
+ /*
+ * Install the new SRv6 End SID in the forwarding plane through
+ * Zebra
+ */
+ isis_zebra_srv6_sid_install(area, sid);
+
+ /* Store the SID */
+ listnode_add(area->srv6db.srv6_sids, sid);
+
+ } else if (ctx.behavior ==
+ ZEBRA_SEG6_LOCAL_ACTION_END_X) {
+ for (ALL_LIST_ELEMENTS_RO(area->adjacency_list,
+ n, adj)) {
+ /* Check if the End.X SID is for this adjacecny */
+ if (adj->ll_ipv6_count == 0 ||
+ memcmp(&adj->ll_ipv6_addrs[0],
+ &ctx.nh6,
+ sizeof(struct in6_addr)) != 0)
+ continue;
+
+ /* Remove old End.X SIDs, if any */
+ for (ALL_LIST_ELEMENTS(adj->srv6_endx_sids,
+ node, nnode, sra))
+ srv6_endx_sid_del(sra);
+
+ /* Allocate new End.X SID for the adjacency */
+ srv6_endx_sid_add_single(adj, false,
+ NULL,
+ &sid_addr);
+ }
+ } else {
+ zlog_warn("%s: unsupported behavior %u",
+ __func__, ctx.behavior);
+ return -1;
+ }
+ break;
+ case ZAPI_SRV6_SID_RELEASED:
+ sr_debug("SRv6 SID %pI6 %s: RELEASED", &sid_addr,
+ srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
+ break;
+ case ZAPI_SRV6_SID_FAIL_ALLOC:
+ sr_debug("SRv6 SID %pI6 %s: Failed to allocate",
+ &sid_addr,
+ srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
+
+ /* Error will be logged by zebra module */
+ break;
+ case ZAPI_SRV6_SID_FAIL_RELEASE:
+ zlog_warn("%s: SRv6 SID %pI6 %s failure to release",
+ __func__, &sid_addr,
+ srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
+
+ /* Error will be logged by zebra module */
+ break;
+ }
+
+ /* Regenerate LSPs to advertise the new locator and the SID */
+ lsp_regenerate_schedule(area, area->is_type, 0);
+ }
+
+ return 0;
+}
+
static zclient_handler *const isis_handlers[] = {
[ZEBRA_ROUTER_ID_UPDATE] = isis_router_id_update_zebra,
[ZEBRA_INTERFACE_ADDRESS_ADD] = isis_zebra_if_address_add,
@@ -1380,10 +1593,9 @@ static zclient_handler *const isis_handlers[] = {
[ZEBRA_CLIENT_CLOSE_NOTIFY] = isis_zebra_client_close_notify,
- [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] =
- isis_zebra_process_srv6_locator_chunk,
[ZEBRA_SRV6_LOCATOR_ADD] = isis_zebra_process_srv6_locator_add,
[ZEBRA_SRV6_LOCATOR_DELETE] = isis_zebra_process_srv6_locator_delete,
+ [ZEBRA_SRV6_SID_NOTIFY] = isis_zebra_srv6_sid_notify,
};
void isis_zebra_init(struct event_loop *master, int instance)
diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h
index f1684b7c25..79da16efac 100644
--- a/isisd/isis_zebra.h
+++ b/isisd/isis_zebra.h
@@ -68,4 +68,11 @@ void isis_zebra_srv6_adj_sid_uninstall(struct srv6_adjacency *sra);
extern int isis_zebra_srv6_manager_get_locator_chunk(const char *name);
extern int isis_zebra_srv6_manager_release_locator_chunk(const char *name);
+extern int isis_zebra_srv6_manager_get_locator(const char *name);
+extern void isis_zebra_request_srv6_sid_endx(struct isis_adjacency *adj);
+extern bool isis_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx,
+ struct in6_addr *sid_value,
+ const char *locator_name);
+extern void isis_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx);
+
#endif /* _ZEBRA_ISIS_ZEBRA_H */