zebra: Alloc/Release SIDs to daemons upon request

Previous commits introduced two new ZAPI operations,
`ZEBRA_SRV6_MANAGER_GET_SRV6_SID` and
`ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID`. These operations allow a daemon
to interact with the SRv6 SID Manager to get and release an SRv6 SID,
respectively.

This commit extends the SID Manager by adding logic to process the
requests `ZEBRA_SRV6_MANAGER_GET_SRV6_SID` and
`ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID`, and allocate/release SIDs to
requesting daemons.

Signed-off-by: Carmine Scarpitta <cscarpit@cisco.com>
This commit is contained in:
Carmine Scarpitta 2024-03-23 17:25:39 +01:00
parent c570d2bcae
commit 84dd482cb9
3 changed files with 254 additions and 0 deletions

View file

@ -3006,6 +3006,71 @@ stream_failure:
return; return;
} }
/**
* Handle SRv6 SID request received from a client daemon protocol.
*
* @param client The client zapi session
* @param msg The request message
*/
static void zread_srv6_manager_get_srv6_sid(struct zserv *client,
struct stream *msg)
{
struct stream *s;
struct srv6_sid_ctx ctx = {};
struct in6_addr sid_value = {};
struct in6_addr *sid_value_ptr = NULL;
char locator[SRV6_LOCNAME_SIZE] = { 0 };
uint16_t len;
struct zebra_srv6_sid *sid = NULL;
uint8_t flags;
/* Get input stream */
s = msg;
/* Get data */
STREAM_GET(&ctx, s, sizeof(struct srv6_sid_ctx));
STREAM_GETC(s, flags);
if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE)) {
STREAM_GET(&sid_value, s, sizeof(struct in6_addr));
sid_value_ptr = &sid_value;
}
if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR)) {
STREAM_GETW(s, len);
STREAM_GET(locator, s, len);
}
/* Call hook to get a SID using wrapper */
srv6_manager_get_sid_call(&sid, client, &ctx, sid_value_ptr, locator);
stream_failure:
return;
}
/**
* Handle SRv6 SID release request received from a client daemon protocol.
*
* @param client The client zapi session
* @param msg The request message
*/
static void zread_srv6_manager_release_srv6_sid(struct zserv *client,
struct stream *msg)
{
struct stream *s;
struct srv6_sid_ctx ctx = {};
/* Get input stream */
s = msg;
/* Get data */
STREAM_GET(&ctx, s, sizeof(struct srv6_sid_ctx));
/* Call hook to release a SID using wrapper */
srv6_manager_release_sid_call(client, &ctx);
stream_failure:
return;
}
/** /**
* Handle SRv6 locator get request received from a client daemon protocol. * Handle SRv6 locator get request received from a client daemon protocol.
* *
@ -3042,6 +3107,12 @@ static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS)
zread_srv6_manager_release_locator_chunk(client, msg, zread_srv6_manager_release_locator_chunk(client, msg,
zvrf_id(zvrf)); zvrf_id(zvrf));
break; break;
case ZEBRA_SRV6_MANAGER_GET_SRV6_SID:
zread_srv6_manager_get_srv6_sid(client, msg);
break;
case ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID:
zread_srv6_manager_release_srv6_sid(client, msg);
break;
case ZEBRA_SRV6_MANAGER_GET_LOCATOR: case ZEBRA_SRV6_MANAGER_GET_LOCATOR:
zread_srv6_manager_get_locator(client, msg); zread_srv6_manager_get_locator(client, msg);
break; break;
@ -3993,6 +4064,8 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
[ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg, [ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg,
[ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = zread_srv6_manager_request, [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = zread_srv6_manager_request,
[ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK] = zread_srv6_manager_request, [ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK] = zread_srv6_manager_request,
[ZEBRA_SRV6_MANAGER_GET_SRV6_SID] = zread_srv6_manager_request,
[ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID] = zread_srv6_manager_request,
[ZEBRA_SRV6_MANAGER_GET_LOCATOR] = zread_srv6_manager_request, [ZEBRA_SRV6_MANAGER_GET_LOCATOR] = zread_srv6_manager_request,
[ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities, [ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities,
[ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover, [ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover,

View file

@ -65,6 +65,13 @@ DEFINE_HOOK(srv6_manager_release_chunk,
vrf_id_t vrf_id), vrf_id_t vrf_id),
(client, locator_name, vrf_id)); (client, locator_name, vrf_id));
DEFINE_HOOK(srv6_manager_get_sid,
(struct zebra_srv6_sid **sid, struct zserv *client,
struct srv6_sid_ctx *ctx, struct in6_addr *sid_value,
const char *locator_name),
(sid, client, ctx, sid_value, locator_name));
DEFINE_HOOK(srv6_manager_release_sid,
(struct zserv *client, struct srv6_sid_ctx *ctx), (client, ctx));
DEFINE_HOOK(srv6_manager_get_locator, DEFINE_HOOK(srv6_manager_get_locator,
(struct srv6_locator **locator, struct zserv *client, (struct srv6_locator **locator, struct zserv *client,
const char *locator_name), const char *locator_name),
@ -100,6 +107,22 @@ int srv6_manager_client_disconnect_cb(struct zserv *client)
return 0; return 0;
} }
void srv6_manager_get_sid_call(struct zebra_srv6_sid **sid,
struct zserv *client, struct srv6_sid_ctx *ctx,
struct in6_addr *sid_value,
const char *locator_name)
{
hook_call(srv6_manager_get_sid, sid, client, ctx, sid_value,
locator_name);
}
void srv6_manager_release_sid_call(struct zserv *client,
struct srv6_sid_ctx *ctx)
{
hook_call(srv6_manager_release_sid, client, ctx);
}
void srv6_manager_get_locator_call(struct srv6_locator **locator, void srv6_manager_get_locator_call(struct srv6_locator **locator,
struct zserv *client, struct zserv *client,
const char *locator_name) const char *locator_name)
@ -109,6 +132,8 @@ void srv6_manager_get_locator_call(struct srv6_locator **locator,
static int zebra_srv6_cleanup(struct zserv *client) static int zebra_srv6_cleanup(struct zserv *client)
{ {
/* Client has disconnected, let's release all the SIDs allocated by it. */
release_daemon_srv6_sids(client);
return 0; return 0;
} }
@ -2225,6 +2250,141 @@ static int srv6_manager_get_srv6_locator_internal(struct srv6_locator **locator,
return zsend_zebra_srv6_locator_add(client, *locator); return zsend_zebra_srv6_locator_add(client, *locator);
} }
/**
* Handle a get SID request received from a client.
*
* It gets a SID for a given context. If there is no SID associated with the context yet,
* we allocate one and return it to the client. Otherwise, we return the existing SID.
*
* - When the `sid_value` parameter is non-NULL, SRv6 Manager assigns the requested SID value
* if it is available (explicit SID allocation).
* - When the `sid_value` parameter is NULL, SRv6 Manager assigns any available SID value
* (dynamic SID allocation).
*
* Finally, notify the client whether the SID allocation was successful or failed.
*
* @param sid SID returned by this function
* @param client The client that requested the SID
* @param ctx Context for which the SID was requested
* @param sid_value SID value (i.e., IPv6 address) that has to be assigned to the SID
* (for explicit SID allocation)
* @param locator_name Locator from which the SID has to be allocated (for dynamic SID allocation)
*
* @return 0 on success, -1 otherwise
*/
static int srv6_manager_get_sid_internal(struct zebra_srv6_sid **sid,
struct zserv *client,
struct srv6_sid_ctx *ctx,
struct in6_addr *sid_value,
const char *locator_name)
{
int ret = -1;
char buf[256];
if (IS_ZEBRA_DEBUG_PACKET)
zlog_debug("%s: getting SRv6 SID for ctx %s, sid_value=%pI6, locator_name=%s",
__func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx),
sid_value, locator_name);
ret = get_srv6_sid(sid, ctx, sid_value, locator_name);
if (ret < 0) {
zlog_warn("%s: not got SRv6 SID for ctx %s, sid_value=%pI6, locator_name=%s",
__func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx),
sid_value, locator_name);
} else if (ret == 0) {
if (IS_ZEBRA_DEBUG_PACKET)
zlog_debug("%s: got existing SRv6 SID for ctx %s: sid_value=%pI6 (func=%u) (proto=%u, instance=%u, sessionId=%u), notify client",
__func__,
srv6_sid_ctx2str(buf, sizeof(buf), ctx),
&(*sid)->value, (*sid)->func, client->proto,
client->instance, client->session_id);
if (!listnode_lookup((*sid)->client_list, client))
listnode_add((*sid)->client_list, client);
} else {
if (IS_ZEBRA_DEBUG_PACKET)
zlog_debug("%s: got new SRv6 SID for ctx %s: sid_value=%pI6 (func=%u) (proto=%u, instance=%u, sessionId=%u), notifying all clients",
__func__,
srv6_sid_ctx2str(buf, sizeof(buf), ctx),
&(*sid)->value, (*sid)->func, client->proto,
client->instance, client->session_id);
if (!listnode_lookup((*sid)->client_list, client))
listnode_add((*sid)->client_list, client);
}
return ret;
}
/**
* Release SRv6 SIDs from a client.
*
* Called on client disconnection or reconnection.
*
* @param client The client to release SIDs from
* @return Number of SIDs released
*/
int release_daemon_srv6_sids(struct zserv *client)
{
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
struct listnode *node, *nnode;
struct zebra_srv6_sid_ctx *ctx;
int count = 0;
int ret;
if (IS_ZEBRA_DEBUG_PACKET)
zlog_debug("%s: releasing SRv6 SIDs for client proto %s, instance %d, session %u",
__func__, zebra_route_string(client->proto),
client->instance, client->session_id);
/* Iterate over the SIDs and release SIDs used by the client daemon */
for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) {
if (!listnode_lookup(ctx->sid->client_list, client))
continue;
ret = release_srv6_sid(client, ctx);
if (ret == 0)
count++;
}
if (IS_ZEBRA_DEBUG_PACKET)
zlog_debug("%s: released %d SRv6 SIDs", __func__, count);
return count;
}
/**
* Release SRv6 SIDs from a client.
*
* @param client The client zapi session
* @param ctx Context associated with the SRv6 SID
* @return 0 on success, -1 on failure
*/
static int srv6_manager_release_sid_internal(struct zserv *client,
struct srv6_sid_ctx *ctx)
{
int ret = -1;
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
struct zebra_srv6_sid_ctx *zctx;
struct listnode *node, *nnode;
char buf[256];
if (IS_ZEBRA_DEBUG_PACKET)
zlog_debug("%s: releasing SRv6 SID associated with ctx %s",
__func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx));
/* Lookup Zebra SID context and release it */
for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, zctx))
if (memcmp(&zctx->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) {
ret = release_srv6_sid(client, zctx);
break;
}
if (IS_ZEBRA_DEBUG_PACKET)
zlog_debug("%s: no SID associated with ctx %s", __func__,
srv6_sid_ctx2str(buf, sizeof(buf), ctx));
return ret;
}
void zebra_srv6_terminate(void) void zebra_srv6_terminate(void)
{ {
struct srv6_locator *locator; struct srv6_locator *locator;
@ -2288,6 +2448,9 @@ void zebra_srv6_init(void)
hook_register(srv6_manager_release_chunk, hook_register(srv6_manager_release_chunk,
zebra_srv6_manager_release_locator_chunk); zebra_srv6_manager_release_locator_chunk);
hook_register(srv6_manager_get_sid, srv6_manager_get_sid_internal);
hook_register(srv6_manager_release_sid,
srv6_manager_release_sid_internal);
hook_register(srv6_manager_get_locator, hook_register(srv6_manager_get_locator,
srv6_manager_get_srv6_locator_internal); srv6_manager_get_srv6_locator_internal);
} }

View file

@ -231,6 +231,13 @@ DECLARE_HOOK(srv6_manager_release_chunk,
vrf_id_t vrf_id), vrf_id_t vrf_id),
(client, locator_name, vrf_id)); (client, locator_name, vrf_id));
DECLARE_HOOK(srv6_manager_get_sid,
(struct zebra_srv6_sid **sid, struct zserv *client,
struct srv6_sid_ctx *ctx, struct in6_addr *sid_value,
const char *locator_name),
(sid, client, ctx, sid_value, locator_name));
DECLARE_HOOK(srv6_manager_release_sid,
(struct zserv *client, struct srv6_sid_ctx *ctx), (client, ctx));
DECLARE_HOOK(srv6_manager_get_locator, DECLARE_HOOK(srv6_manager_get_locator,
(struct srv6_locator **locator, struct zserv *client, (struct srv6_locator **locator, struct zserv *client,
const char *locator_name), const char *locator_name),
@ -290,6 +297,14 @@ zebra_srv6_sid_alloc(struct zebra_srv6_sid_ctx *ctx, struct in6_addr *sid_value,
extern void zebra_srv6_sid_free(struct zebra_srv6_sid *sid); extern void zebra_srv6_sid_free(struct zebra_srv6_sid *sid);
extern void delete_zebra_srv6_sid(void *val); extern void delete_zebra_srv6_sid(void *val);
extern void srv6_manager_get_sid_call(struct zebra_srv6_sid **sid,
struct zserv *client,
struct srv6_sid_ctx *ctx,
struct in6_addr *sid_value,
const char *locator_name);
extern void srv6_manager_release_sid_call(struct zserv *client,
struct srv6_sid_ctx *ctx);
extern void srv6_manager_get_locator_call(struct srv6_locator **locator, extern void srv6_manager_get_locator_call(struct srv6_locator **locator,
struct zserv *client, struct zserv *client,
const char *locator_name); const char *locator_name);
@ -298,6 +313,9 @@ extern int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx,
struct in6_addr *sid_value, const char *locator_name); struct in6_addr *sid_value, const char *locator_name);
extern int release_srv6_sid(struct zserv *client, extern int release_srv6_sid(struct zserv *client,
struct zebra_srv6_sid_ctx *zctx); struct zebra_srv6_sid_ctx *zctx);
extern int release_daemon_srv6_sids(struct zserv *client);
extern int srv6_manager_get_sid_response(struct zebra_srv6_sid *sid,
struct zserv *client);
extern struct zebra_srv6_sid_ctx *zebra_srv6_sid_ctx_alloc(void); extern struct zebra_srv6_sid_ctx *zebra_srv6_sid_ctx_alloc(void);
extern void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx); extern void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx);