Skip to content

Commit

Permalink
zebra: Alloc/Release SIDs to daemons upon request
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
cscarpitta committed Apr 2, 2024
1 parent d023189 commit 0c54998
Show file tree
Hide file tree
Showing 4 changed files with 302 additions and 0 deletions.
112 changes: 112 additions & 0 deletions zebra/zapi_msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -1182,6 +1182,33 @@ int zsend_srv6_manager_get_locator_response(struct zserv *client,
return zserv_send_message(client, s);
}

/* Send response to a get SRv6 SID request to client */
int zsend_assign_srv6_sid_response(struct zserv *client,
struct zebra_srv6_sid *sid)
{
struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);

zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_SRV6_SID, VRF_DEFAULT);
/* proto */
stream_putc(s, client->proto);
/* instance */
stream_putw(s, client->instance);

if (sid) {
/* Context associated with the SRv6 SID */
stream_put(s, &sid->ctx->ctx, sizeof(struct srv6_sid_ctx));
/* SRv6 SID address */
stream_put(s, &sid->value, sizeof(struct in6_addr));
/* SRv6 SID function */
stream_putl(s, sid->func);
}

/* Write packet size. */
stream_putw_at(s, 0, stream_get_endp(s));

return zserv_send_message(client, s);
}

/* Inbound message handling ------------------------------------------------ */

/* Nexthop register */
Expand Down Expand Up @@ -3016,6 +3043,83 @@ static void zread_srv6_manager_release_locator_chunk(struct zserv *client,
return;
}

/**
* Handle SRv6 SID request received from a client daemon protocol.
*
* @param client 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 proto;
unsigned short instance;
uint8_t flags;

/* Get input stream */
s = msg;

/* Get data */
STREAM_GETC(s, proto);
STREAM_GETW(s, instance);
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);
}

assert(proto == client->proto && instance == client->instance);

/* 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 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 = {};
uint8_t proto;
unsigned short instance;

/* Get input stream */
s = msg;

/* Get data */
STREAM_GETC(s, proto);
STREAM_GETW(s, instance);
STREAM_GET(&ctx, s, sizeof(struct srv6_sid_ctx));

assert(proto == client->proto && instance == client->instance);

/* 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.
*
Expand Down Expand Up @@ -3052,6 +3156,12 @@ static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS)
zread_srv6_manager_release_locator_chunk(client, msg,
zvrf_id(zvrf));
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:
zread_srv6_manager_get_locator(client, msg);
break;
Expand Down Expand Up @@ -4003,6 +4113,8 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
[ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg,
[ZEBRA_SRV6_MANAGER_GET_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_CLIENT_CAPABILITIES] = zread_client_capabilities,
[ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover,
Expand Down
2 changes: 2 additions & 0 deletions zebra/zapi_msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ extern int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client,
extern int
zsend_srv6_manager_get_locator_response(struct zserv *client,
struct zebra_srv6_locator *locator);
extern int zsend_assign_srv6_sid_response(struct zserv *client,
struct zebra_srv6_sid *sid);

#ifdef __cplusplus
}
Expand Down
171 changes: 171 additions & 0 deletions zebra/zebra_srv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ DEFINE_HOOK(srv6_manager_release_chunk,
vrf_id_t 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,
(struct zebra_srv6_locator **locator, struct zserv *client,
const char *locator_name),
Expand Down Expand Up @@ -101,6 +108,21 @@ int srv6_manager_client_disconnect_cb(struct zserv *client)
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 zebra_srv6_locator **locator,
struct zserv *client,
const char *locator_name)
Expand All @@ -110,6 +132,7 @@ void srv6_manager_get_locator_call(struct zebra_srv6_locator **locator,

static int zebra_srv6_cleanup(struct zserv *client)
{
release_daemon_srv6_sids(client);
return 0;
}

Expand Down Expand Up @@ -1961,6 +1984,152 @@ static int srv6_manager_get_srv6_locator(struct zebra_srv6_locator **locator,
return zsend_srv6_manager_get_locator_response(client, *locator);
}

/* Respond to a get_sid request */
int srv6_manager_get_sid_response(struct zebra_srv6_sid *sid,
struct zserv *client)
{
char buf[256];

if (!sid)
flog_err(EC_ZEBRA_SM_CANNOT_ASSIGN_SID,
"Unable to assign SRv6 SID to %s instance %u",
zebra_route_string(client->proto), client->instance);
else if (IS_ZEBRA_DEBUG_PACKET)
zlog_debug("Assigned SRv6 SID %pI6 for ctx %s to %s instance %u",
&sid->value,
srv6_sid_ctx2str(buf, sizeof(buf), &sid->ctx->ctx),
zebra_route_string(client->proto), client->instance);

return zsend_assign_srv6_sid_response(client, sid);
}

/**
* Handle a get SID request received from a client.
*
* It allocates a SID for a given context.
* If the sid_value parameter is non-null, the request is considered an explicit
* allocation request and SRv6 Manager assigns the requested SID value
* (if it is not already assigned to another context).
* If the sid_value parameter is null, the request is considered a dynamic allocation
* request, and SRv6 Manager assigns the first available SID value.
* Notify the client that the SID allocation was successful or failed.
*
* @param sid SID returned by this function
* @param client Client that sent the Get SID request
* @param ctx Context associated with the SID to be created
* @param sid_value IPv6 address associated with the SID to be created (for explicit allocation)
* @param locator_name Name of the parent locator of the SID to be created (for dynamic allocation)
*
* @return 0 on success, -1 otherwise
*/
static int 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)
{
char buf[256];

enum srv6_sid_alloc_mode alloc_mode =
(sid_value) ? SRV6_SID_ALLOC_MODE_EXPLICIT
: SRV6_SID_ALLOC_MODE_DYNAMIC;

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);

*sid = assign_srv6_sid(client->proto, client->instance,
client->session_id, alloc_mode, ctx, sid_value,
locator_name);
if (!(*sid)) {
zlog_warn("%s: not assigned 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 (IS_ZEBRA_DEBUG_PACKET)
zlog_debug("%s: assigned SRv6 SID for ctx %s: sid_value=%pI6 (func=%u) (proto=%u, instance=%u, sessionId=%u)",
__func__,
srv6_sid_ctx2str(buf, sizeof(buf), ctx),
&(*sid)->value, (*sid)->func, client->proto,
client->instance, client->session_id);
}

return srv6_manager_get_sid_response(*sid, client);
}

/**
* 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 remove SIDs owned by the client daemon */
for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) {
if (!sid_is_owned_by_proto(client->proto, client->instance,
ctx->sid))
continue;

ret = release_srv6_sid(client->proto, client->instance,
client->session_id, 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.
*
* Called on client disconnection or reconnection.
*
* @param client Client zapi session
* @param ctx Context associated with the SRv6 SID
* @return 0 on success
*/
static int srv6_manager_release_srv6_sid(struct zserv *client,
struct srv6_sid_ctx *ctx)
{
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)
return release_srv6_sid(client->proto, client->instance,
client->session_id, zctx);

if (IS_ZEBRA_DEBUG_PACKET)
zlog_debug("%s: no SID associated with ctx %s", __func__,
srv6_sid_ctx2str(buf, sizeof(buf), ctx));

return -1;
}

void zebra_srv6_terminate(void)
{
struct zebra_srv6_locator *locator;
Expand Down Expand Up @@ -2024,6 +2193,8 @@ void zebra_srv6_init(void)
hook_register(srv6_manager_release_chunk,
zebra_srv6_manager_release_locator_chunk);

hook_register(srv6_manager_get_sid, srv6_manager_get_sid);
hook_register(srv6_manager_release_sid, srv6_manager_release_srv6_sid);
hook_register(srv6_manager_get_locator, srv6_manager_get_srv6_locator);
}

Expand Down
17 changes: 17 additions & 0 deletions zebra/zebra_srv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,13 @@ DECLARE_HOOK(srv6_manager_release_chunk,
vrf_id_t 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,
(struct zebra_srv6_locator **locator, struct zserv *client,
const char *locator_name),
Expand Down Expand Up @@ -391,6 +398,13 @@ 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 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 zebra_srv6_locator **locator,
struct zserv *client,
const char *locator_name);
Expand All @@ -401,6 +415,9 @@ assign_srv6_sid(uint8_t proto, unsigned short instance, uint32_t session_id,
struct in6_addr *sid_value, const char *locator);
int release_srv6_sid(uint8_t proto, unsigned short instance,
uint32_t session_id, struct zebra_srv6_sid_ctx *ctx);
int release_daemon_srv6_sids(struct zserv *client);
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 void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx);
Expand Down

0 comments on commit 0c54998

Please sign in to comment.