Skip to content
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