Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

isisd: Extend IS-IS to communicate with the SRv6 SID Manager to allocate/release SRv6 SIDs #15677

Merged
merged 10 commits into from
Jul 2, 2024
13 changes: 4 additions & 9 deletions isisd/isis_lsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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.
Expand Down
6 changes: 3 additions & 3 deletions isisd/isis_nb_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
201 changes: 53 additions & 148 deletions isisd/isis_srv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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(
Expand All @@ -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));
Expand Down Expand Up @@ -197,150 +220,36 @@ 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;
Expand Down Expand Up @@ -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;
Expand All @@ -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,
Expand All @@ -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];

Expand All @@ -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 */
Expand Down Expand Up @@ -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);
}

/**
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down
Loading
Loading