mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
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:
parent
c570d2bcae
commit
84dd482cb9
|
@ -3006,6 +3006,71 @@ stream_failure:
|
|||
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.
|
||||
*
|
||||
|
@ -3042,6 +3107,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;
|
||||
|
@ -3993,6 +4064,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,
|
||||
|
|
|
@ -65,6 +65,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 srv6_locator **locator, struct zserv *client,
|
||||
const char *locator_name),
|
||||
|
@ -100,6 +107,22 @@ 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 srv6_locator **locator,
|
||||
struct zserv *client,
|
||||
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)
|
||||
{
|
||||
/* Client has disconnected, let's release all the SIDs allocated by it. */
|
||||
release_daemon_srv6_sids(client);
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
struct srv6_locator *locator;
|
||||
|
@ -2288,6 +2448,9 @@ 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_internal);
|
||||
hook_register(srv6_manager_release_sid,
|
||||
srv6_manager_release_sid_internal);
|
||||
hook_register(srv6_manager_get_locator,
|
||||
srv6_manager_get_srv6_locator_internal);
|
||||
}
|
||||
|
|
|
@ -231,6 +231,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 srv6_locator **locator, struct zserv *client,
|
||||
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 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,
|
||||
struct zserv *client,
|
||||
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);
|
||||
extern int release_srv6_sid(struct zserv *client,
|
||||
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 void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx);
|
||||
|
|
Loading…
Reference in a new issue