]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: Alloc/Release SIDs to daemons upon request
authorCarmine Scarpitta <cscarpit@cisco.com>
Sat, 23 Mar 2024 16:25:39 +0000 (17:25 +0100)
committerCarmine Scarpitta <cscarpit@cisco.com>
Thu, 13 Jun 2024 12:54:16 +0000 (14:54 +0200)
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>
zebra/zapi_msg.c
zebra/zebra_srv6.c
zebra/zebra_srv6.h

index 52ee0876896af30531f566a41dd12a76d25fc3c3..bab4c4fa3d7489603d121e58b044d36c7fb8eef7 100644 (file)
@@ -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,
index 047422b9e33f82c1c3149c05f6c63f36b08d3689..d93f09f1b4fd225bb8f9f5fa52fa8a38260f8c3c 100644 (file)
@@ -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);
 }
index 7d989f180f54a1492fa58a3bfbe73b42f4356809..1599fd7adfbd3bcb31a1e29933665352634e53a8 100644 (file)
@@ -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);