]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: ZAPI add new api to manipulate srv6-locator (step2)
authorHiroki Shirokura <slank.dev@gmail.com>
Wed, 9 Dec 2020 09:52:17 +0000 (18:52 +0900)
committerMark Stapp <mjs@voltanet.io>
Wed, 2 Jun 2021 14:24:47 +0000 (10:24 -0400)
This commit is a part of #5853 works that add new ZAPI to
configure SRv6 locator which manages chunk prefix for
SRv6 SID IPv6 address for each routing protocol daemons.

NEW-ZAPIs:
* ZEBRA_SRV6_LOCATOR_ADD
* ZEBRA_SRV6_LOCATOR_DELETE
* ZEBRA_SRV6_MANAGER_CONNECT
* ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK
* ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK

Zclient can connect to zebra's srv6-manager with
ZEBRA_SRV6_MANAGER_CONNECT api like a label-manager.
Then zclient uses ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK to
allocated dedicated locator chunk for it's routing protocol.
Zebra works for only prefix reservation and distribute
the ownership of the locator chunks for zcliens.

Then, zclient installs SRv6 function with
ZEBRA_ROUTE_ADD api with nh_seg6local_* fields.
This feature is already implemented by another PR(#7680).

Signed-off-by: Hiroki Shirokura <slank.dev@gmail.com>
zebra/main.c
zebra/subdir.am
zebra/zapi_msg.c
zebra/zapi_msg.h
zebra/zebra_errors.c
zebra/zebra_errors.h
zebra/zebra_srv6.c [new file with mode: 0644]
zebra/zebra_srv6.h [new file with mode: 0644]

index 259c70d0dfc757c5c1ec04ac4cf2ff1bf71b3684..e36af51005b587f790e0cf6b2a2f2fb42f063eff 100644 (file)
@@ -57,6 +57,7 @@
 #include "zebra/zebra_nb.h"
 #include "zebra/zebra_opaque.h"
 #include "zebra/zebra_srte.h"
+#include "zebra/zebra_srv6.h"
 #include "zebra/zebra_srv6_vty.h"
 
 #define ZEBRA_PTM_SUPPORT
@@ -419,6 +420,7 @@ int main(int argc, char **argv)
        zebra_pbr_init();
        zebra_opaque_init();
        zebra_srte_init();
+       zebra_srv6_init();
        zebra_srv6_vty_init();
 
        /* For debug purpose. */
index ca77502ba386b8655a3bcadd9f1b92c717fb0b73..4d8115597bb92abab7b780aa3c29b31145c44bd3 100644 (file)
@@ -93,6 +93,7 @@ zebra_zebra_SOURCES = \
        zebra/zebra_mpls_openbsd.c \
        zebra/zebra_mpls_null.c \
        zebra/zebra_mpls_vty.c \
+       zebra/zebra_srv6.c \
        zebra/zebra_srv6_vty.c \
        zebra/zebra_mroute.c \
        zebra/zebra_nb.c \
@@ -163,6 +164,7 @@ noinst_HEADERS += \
        zebra/zebra_mlag.h \
        zebra/zebra_mlag_vty.h \
        zebra/zebra_mpls.h \
+       zebra/zebra_srv6.h \
        zebra/zebra_srv6_vty.h \
        zebra/zebra_mroute.h \
        zebra/zebra_nb.h \
index 752738b2145ff7c6cc2cc084e08d6e47701815e4..fa6a4cfca7ca752b5802ea9799a5ab81878960a9 100644 (file)
@@ -60,6 +60,7 @@
 #include "zebra/connected.h"
 #include "zebra/zebra_opaque.h"
 #include "zebra/zebra_srte.h"
+#include "zebra/zebra_srv6.h"
 
 DEFINE_MTYPE_STATIC(ZEBRA, OPAQUE, "Opaque Data");
 
@@ -1136,6 +1137,29 @@ static int zsend_table_manager_connect_response(struct zserv *client,
        return zserv_send_message(client, s);
 }
 
+static int zsend_srv6_manager_connect_response(struct zserv *client,
+                                               vrf_id_t vrf_id,
+                                               uint16_t result)
+{
+       struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+       zclient_create_header(s, ZEBRA_SRV6_MANAGER_CONNECT, vrf_id);
+
+       /* proto */
+       stream_putc(s, client->proto);
+
+       /* instance */
+       stream_putw(s, client->instance);
+
+       /* result */
+       stream_putc(s, result);
+
+       /* Write packet size. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zserv_send_message(client, s);
+}
+
 /* Inbound message handling ------------------------------------------------ */
 
 const int cmd2type[] = {
@@ -2624,6 +2648,74 @@ int zsend_client_close_notify(struct zserv *client, struct zserv *closed_client)
        return zserv_send_message(client, s);
 }
 
+/* Send response to a srv6 manager connect request to client */
+static void zread_srv6_manager_connect(struct zserv *client,
+                                      struct stream *msg, vrf_id_t vrf_id)
+{
+       struct stream *s;
+       uint8_t proto;
+       uint16_t instance;
+       struct vrf *vrf = vrf_lookup_by_id(vrf_id);
+
+       s = msg;
+
+       /* Get data. */
+       STREAM_GETC(s, proto);
+       STREAM_GETW(s, instance);
+
+       /* accept only dynamic routing protocols */
+       if ((proto >= ZEBRA_ROUTE_MAX) || (proto <= ZEBRA_ROUTE_STATIC)) {
+               flog_err(EC_ZEBRA_TM_WRONG_PROTO,
+                        "client %d has wrong protocol %s", client->sock,
+                        zebra_route_string(proto));
+               zsend_srv6_manager_connect_response(client, vrf_id, 1);
+               return;
+       }
+       zlog_notice("client %d with vrf %s(%u) instance %u connected as %s",
+                   client->sock, VRF_LOGNAME(vrf), vrf_id, instance,
+                   zebra_route_string(proto));
+       client->proto = proto;
+       client->instance = instance;
+
+       /*
+        * Release previous locators of same protocol and instance.
+        * This is done in case it restarted from an unexpected shutdown.
+        */
+       release_daemon_srv6_locator_chunks(client);
+
+       zsend_srv6_manager_connect_response(client, vrf_id, 0);
+
+stream_failure:
+       return;
+}
+
+int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client,
+                                                 vrf_id_t vrf_id,
+                                                 struct srv6_locator *loc)
+{
+       struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+       zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, vrf_id);
+
+       /* proto */
+       stream_putc(s, client->proto);
+
+       /* instance */
+       stream_putw(s, client->instance);
+
+       if (loc) {
+               stream_putw(s, strlen(loc->name));
+               stream_put(s, loc->name, strlen(loc->name));
+               stream_putw(s, loc->prefix.prefixlen);
+               stream_put(s, &loc->prefix.prefix, 16);
+       }
+
+       /* Write packet size. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zserv_send_message(client, s);
+}
+
 /* Send response to a table manager connect request to client */
 static void zread_table_manager_connect(struct zserv *client,
                                        struct stream *msg, vrf_id_t vrf_id)
@@ -2833,6 +2925,77 @@ static void zread_table_manager_request(ZAPI_HANDLER_ARGS)
        }
 }
 
+static void zread_srv6_manager_get_locator_chunk(struct zserv *client,
+                                                struct stream *msg,
+                                                vrf_id_t vrf_id)
+{
+       struct stream *s = msg;
+       uint8_t proto;
+       uint16_t instance;
+       uint16_t len;
+       char locator_name[SRV6_LOCNAME_SIZE] = {0};
+
+       /* Get data. */
+       STREAM_GETC(s, proto);
+       STREAM_GETW(s, instance);
+       STREAM_GETW(s, len);
+       STREAM_GET(locator_name, s, len);
+
+       assert(proto == client->proto && instance == client->instance);
+
+       /* call hook to get a chunk using wrapper */
+       struct srv6_locator *loc = NULL;
+       srv6_manager_get_locator_chunk_call(&loc, client, locator_name, vrf_id);
+
+stream_failure:
+       return;
+}
+
+static void zread_srv6_manager_release_locator_chunk(struct zserv *client,
+                                                    struct stream *msg,
+                                                    vrf_id_t vrf_id)
+{
+       struct stream *s = msg;
+       uint8_t proto;
+       uint16_t instance;
+       uint16_t len;
+       char locator_name[SRV6_LOCNAME_SIZE] = {0};
+
+       /* Get data. */
+       STREAM_GETC(s, proto);
+       STREAM_GETW(s, instance);
+       STREAM_GETW(s, len);
+       STREAM_GET(locator_name, s, len);
+
+       assert(proto == client->proto && instance == client->instance);
+
+       /* call hook to release a chunk using wrapper */
+       srv6_manager_release_locator_chunk_call(client, locator_name, vrf_id);
+
+stream_failure:
+       return;
+}
+
+static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS)
+{
+       switch (hdr->command) {
+       case ZEBRA_SRV6_MANAGER_CONNECT:
+               zread_srv6_manager_connect(client, msg, zvrf_id(zvrf));
+               break;
+       case ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK:
+               zread_srv6_manager_get_locator_chunk(client, msg,
+                                                    zvrf_id(zvrf));
+               break;
+       case ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK:
+               zread_srv6_manager_release_locator_chunk(client, msg,
+                                                        zvrf_id(zvrf));
+               break;
+       default:
+               zlog_err("%s: unknown SRv6 Mamanger command", __func__);
+               break;
+       }
+}
+
 static void zread_pseudowire(ZAPI_HANDLER_ARGS)
 {
        struct stream *s;
@@ -3592,6 +3755,9 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
        [ZEBRA_MLAG_CLIENT_REGISTER] = zebra_mlag_client_register,
        [ZEBRA_MLAG_CLIENT_UNREGISTER] = zebra_mlag_client_unregister,
        [ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg,
+       [ZEBRA_SRV6_MANAGER_CONNECT] = 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_CLIENT_CAPABILITIES] = zread_client_capabilities,
        [ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover,
        [ZEBRA_NHG_ADD] = zread_nhg_add,
index 0beb3cc100d8da6b4b9e2cea2f09d6aa8b902609..35bb5541212e66cb81703661c5dfaa3ba585f74c 100644 (file)
@@ -30,6 +30,7 @@
 #include "zebra/zebra_pbr.h"
 #include "zebra/zebra_errors.h"
 #include "zebra/label_manager.h"
+#include "zebra/zebra_srv6.h"
 
 
 #ifdef __cplusplus
@@ -116,6 +117,14 @@ int zsend_nhg_notify(uint16_t type, uint16_t instance, uint32_t session_id,
 
 extern void zapi_opaque_free(struct opaque *opaque);
 
+extern int zsend_zebra_srv6_locator_add(struct zserv *client,
+                                       struct srv6_locator *loc);
+extern int zsend_zebra_srv6_locator_delete(struct zserv *client,
+                                          struct srv6_locator *loc);
+extern int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client,
+                                                        vrf_id_t vrf_id,
+                                                        struct srv6_locator *loc);
+
 #ifdef __cplusplus
 }
 #endif
index 29b271425dc35b00a1e68e01162760a6a64fc997..c3890f7220ac2f3f0ad5038c532f9c932166aaba 100644 (file)
@@ -785,6 +785,12 @@ static struct log_ref ferr_zebra_err[] = {
                .description = "Zebra has detected a situation where there are two vrf devices with the exact same tableid.  This is considered a complete misconfiguration of VRF devices and breaks a fundamental assumption in FRR about how VRF's work",
                .suggestion = "Use different table id's for the VRF's in question"
        },
+       {
+               .code = EC_ZEBRA_SRV6M_UNRELEASED_LOCATOR_CHUNK,
+               .title = "Zebra did not free any srv6 locator chunks",
+               .description = "Zebra's srv6-locator chunk cleanup procedure ran, but no srv6 locator chunks were released.",
+               .suggestion = "Ignore this error.",
+       },
        {
                .code = END_FERR,
        }
index 200a977a69f99a4dd9cc95a60e1ccd94dec4ff34..540c6dd7d071ad2bfc844fa5faa2153210444b59 100644 (file)
@@ -135,6 +135,7 @@ enum zebra_log_refs {
        EC_ZEBRA_VRF_MISCONFIGURED,
        EC_ZEBRA_ES_CREATE,
        EC_ZEBRA_GRE_SET_UPDATE,
+       EC_ZEBRA_SRV6M_UNRELEASED_LOCATOR_CHUNK,
 };
 
 void zebra_error_init(void);
diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c
new file mode 100644 (file)
index 0000000..b4b691e
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * Zebra SRv6 definitions
+ * Copyright (C) 2020  Hiroki Shirokura, LINE Corporation
+ * Copyright (C) 2020  Masakazu Asama
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "network.h"
+#include "prefix.h"
+#include "stream.h"
+#include "srv6.h"
+#include "zebra/debug.h"
+#include "zebra/zapi_msg.h"
+#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
+#include "zebra/zebra_srv6.h"
+#include "zebra/zebra_errors.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+
+DEFINE_MGROUP(SRV6_MGR, "SRv6 Manager");
+DEFINE_MTYPE_STATIC(SRV6_MGR, SRV6M_CHUNK, "SRv6 Manager Chunk");
+
+/* define hooks for the basic API, so that it can be specialized or served
+ * externally
+ */
+
+DEFINE_HOOK(srv6_manager_client_connect,
+           (struct zserv *client, vrf_id_t vrf_id),
+           (client, vrf_id));
+DEFINE_HOOK(srv6_manager_client_disconnect,
+           (struct zserv *client), (client));
+DEFINE_HOOK(srv6_manager_get_chunk,
+           (struct srv6_locator **loc,
+            struct zserv *client,
+            const char *locator_name,
+            vrf_id_t vrf_id),
+           (loc, client, locator_name, vrf_id));
+DEFINE_HOOK(srv6_manager_release_chunk,
+           (struct zserv *client,
+            const char *locator_name,
+            vrf_id_t vrf_id),
+           (client, locator_name, vrf_id));
+
+/* define wrappers to be called in zapi_msg.c (as hooks must be called in
+ * source file where they were defined)
+ */
+
+void srv6_manager_client_connect_call(struct zserv *client, vrf_id_t vrf_id)
+{
+       hook_call(srv6_manager_client_connect, client, vrf_id);
+}
+
+void srv6_manager_get_locator_chunk_call(struct srv6_locator **loc,
+                                        struct zserv *client,
+                                        const char *locator_name,
+                                        vrf_id_t vrf_id)
+{
+       hook_call(srv6_manager_get_chunk, loc, client, locator_name, vrf_id);
+}
+
+void srv6_manager_release_locator_chunk_call(struct zserv *client,
+                                            const char *locator_name,
+                                            vrf_id_t vrf_id)
+{
+       hook_call(srv6_manager_release_chunk, client, locator_name, vrf_id);
+}
+
+int srv6_manager_client_disconnect_cb(struct zserv *client)
+{
+       hook_call(srv6_manager_client_disconnect, client);
+       return 0;
+}
+
+static int zebra_srv6_cleanup(struct zserv *client)
+{
+       return 0;
+}
+
+void zebra_srv6_locator_add(struct srv6_locator *locator)
+{
+       struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+       struct srv6_locator *tmp;
+
+       tmp = zebra_srv6_locator_lookup(locator->name);
+       if (!tmp)
+               listnode_add(srv6->locators, locator);
+}
+
+void zebra_srv6_locator_delete(struct srv6_locator *locator)
+{
+       struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+       listnode_delete(srv6->locators, locator);
+}
+
+struct srv6_locator *zebra_srv6_locator_lookup(const char *name)
+{
+       struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+       struct srv6_locator *locator;
+       struct listnode *node;
+
+       for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator))
+               if (!strncmp(name, locator->name, SRV6_LOCNAME_SIZE))
+                       return locator;
+       return NULL;
+}
+
+struct zebra_srv6 *zebra_srv6_get_default(void)
+{
+       static struct zebra_srv6 srv6;
+       static bool first_execution = true;
+
+       if (first_execution) {
+               first_execution = false;
+               srv6.locators = list_new();
+       }
+       return &srv6;
+}
+
+/**
+ * Core function, assigns srv6-locator chunks
+ *
+ * It first searches through the list to check if there's one available
+ * (previously released). Otherwise it creates and assigns a new one
+ *
+ * @param proto Daemon protocol of client, to identify the owner
+ * @param instance Instance, to identify the owner
+ * @param session_id SessionID of client
+ * @param name Name of SRv6-locator
+ * @return Pointer to the assigned srv6-locator chunk,
+ *         or NULL if the request could not be satisfied
+ */
+static struct srv6_locator *
+assign_srv6_locator_chunk(uint8_t proto,
+                         uint16_t instance,
+                         uint32_t session_id,
+                         const char *locator_name)
+{
+       bool chunk_found = false;
+       struct listnode *node = NULL;
+       struct srv6_locator *loc = NULL;
+       struct srv6_locator_chunk *chunk = NULL;
+
+       loc = zebra_srv6_locator_lookup(locator_name);
+       if (!loc) {
+               zlog_info("%s: locator %s was not found",
+                         __func__, locator_name);
+
+               loc = srv6_locator_alloc(locator_name);
+               if (!loc) {
+                       zlog_info("%s: locator %s can't allocated",
+                                 __func__, locator_name);
+                       return NULL;
+               }
+
+               loc->status_up = false;
+               chunk = srv6_locator_chunk_alloc();
+               chunk->proto = 0;
+               listnode_add(loc->chunks, chunk);
+               zebra_srv6_locator_add(loc);
+       }
+
+       for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) {
+               if (chunk->proto != 0 && chunk->proto != proto)
+                       continue;
+               chunk_found = true;
+               break;
+       }
+
+       if (!chunk_found) {
+               zlog_info("%s: locator is already owned", __func__);
+               return NULL;
+       }
+
+       chunk->proto = proto;
+       return loc;
+}
+
+static int zebra_srv6_manager_get_locator_chunk(struct srv6_locator **loc,
+                                               struct zserv *client,
+                                               const char *locator_name,
+                                               vrf_id_t vrf_id)
+{
+       *loc = assign_srv6_locator_chunk(client->proto, client->instance,
+                                        client->session_id, locator_name);
+
+       if (!*loc)
+               zlog_err("Unable to assign locator chunk to %s instance %u",
+                        zebra_route_string(client->proto), client->instance);
+       else if (IS_ZEBRA_DEBUG_PACKET)
+               zlog_info("Assigned locator chunk %s to %s instance %u",
+                         (*loc)->name, zebra_route_string(client->proto),
+                         client->instance);
+
+       int ret = 0;
+       if ((*loc)->status_up)
+               ret = zsend_srv6_manager_get_locator_chunk_response(client,
+                                                                   vrf_id,
+                                                                   *loc);
+       return ret;
+}
+
+/**
+ * Core function, release no longer used srv6-locator chunks
+ *
+ * @param proto Daemon protocol of client, to identify the owner
+ * @param instance Instance, to identify the owner
+ * @param session_id Zclient session ID, to identify the zclient session
+ * @param locator_name SRv6-locator name, to identify the actual locator
+ * @return 0 on success, -1 otherwise
+ */
+static int release_srv6_locator_chunk(uint8_t proto, uint16_t instance,
+                                     uint32_t session_id,
+                                     const char *locator_name)
+{
+       int ret = -1;
+       struct listnode *node;
+       struct srv6_locator_chunk *chunk;
+       struct srv6_locator *loc = NULL;
+
+       loc = zebra_srv6_locator_lookup(locator_name);
+       if (!loc) {
+               return -1;
+       }
+
+       if (IS_ZEBRA_DEBUG_PACKET)
+               zlog_debug("%s: Releasing srv6-locator on %s", __func__,
+                          locator_name);
+
+       for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) {
+               if (chunk->proto != proto ||
+                   chunk->instance != instance ||
+                   chunk->session_id != session_id)
+                       continue;
+               chunk->proto = NO_PROTO;
+               chunk->instance = 0;
+               chunk->session_id = 0;
+               chunk->keep = 0;
+               ret = 0;
+               break;
+       }
+
+       if (ret != 0)
+               flog_err(EC_ZEBRA_SRV6M_UNRELEASED_LOCATOR_CHUNK,
+                        "%s: SRv6 locator chunk not released", __func__);
+
+       return ret;
+}
+
+static int zebra_srv6_manager_release_locator_chunk(struct zserv *client,
+                                                   const char *locator_name,
+                                                   vrf_id_t vrf_id)
+{
+       if (vrf_id != VRF_DEFAULT) {
+               zlog_err("SRv6 locator doesn't support vrf");
+               return -1;
+       }
+
+       return release_srv6_locator_chunk(client->proto, client->instance,
+                                         client->session_id, locator_name);
+}
+
+/**
+ * Release srv6-locator chunks from a client.
+ *
+ * Called on client disconnection or reconnection. It only releases chunks
+ * with empty keep value.
+ *
+ * @param proto Daemon protocol of client, to identify the owner
+ * @param instance Instance, to identify the owner
+ * @return Number of chunks released
+ */
+int release_daemon_srv6_locator_chunks(struct zserv *client)
+{
+       int ret;
+       int count = 0;
+       struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+       struct listnode *loc_node;
+       struct listnode *chunk_node;
+       struct srv6_locator *loc;
+       struct srv6_locator_chunk *chunk;
+
+       if (IS_ZEBRA_DEBUG_PACKET)
+               zlog_debug("%s: Releasing chunks for client proto %s, instance %d, session %u",
+                          __func__, zebra_route_string(client->proto),
+                          client->instance, client->session_id);
+
+       for (ALL_LIST_ELEMENTS_RO(srv6->locators, loc_node, loc)) {
+               for (ALL_LIST_ELEMENTS_RO(loc->chunks, chunk_node, chunk)) {
+                       if (chunk->proto == client->proto &&
+                           chunk->instance == client->instance &&
+                           chunk->session_id == client->session_id &&
+                           chunk->keep == 0) {
+                               ret = release_srv6_locator_chunk(
+                                               chunk->proto, chunk->instance,
+                                               chunk->session_id, loc->name);
+                               if (ret == 0)
+                                       count++;
+                       }
+               }
+       }
+
+       if (IS_ZEBRA_DEBUG_PACKET)
+               zlog_debug("%s: Released %d srv6-locator chunks",
+                          __func__, count);
+
+       return count;
+}
+
+void zebra_srv6_init(void)
+{
+       hook_register(zserv_client_close, zebra_srv6_cleanup);
+       hook_register(srv6_manager_get_chunk,
+                     zebra_srv6_manager_get_locator_chunk);
+       hook_register(srv6_manager_release_chunk,
+                     zebra_srv6_manager_release_locator_chunk);
+}
+
+bool zebra_srv6_is_enable(void)
+{
+       struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+
+       return listcount(srv6->locators);
+}
diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h
new file mode 100644 (file)
index 0000000..751cee6
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Zebra SRv6 definitions
+ * Copyright (C) 2020  Hiroki Shirokura, LINE Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _ZEBRA_SRV6_H
+#define _ZEBRA_SRV6_H
+
+#include <zebra.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "qobj.h"
+#include "prefix.h"
+#include <pthread.h>
+#include <plist.h>
+
+/* SRv6 instance structure. */
+struct zebra_srv6 {
+       struct list *locators;
+};
+
+/* declare hooks for the basic API, so that it can be specialized or served
+ * externally. Also declare a hook when those functions have been registered,
+ * so that any external module wanting to replace those can react
+ */
+
+DECLARE_HOOK(srv6_manager_client_connect,
+           (struct zserv *client, vrf_id_t vrf_id),
+           (client, vrf_id));
+DECLARE_HOOK(srv6_manager_client_disconnect,
+            (struct zserv *client), (client));
+DECLARE_HOOK(srv6_manager_get_chunk,
+            (struct srv6_locator **loc,
+             struct zserv *client,
+             const char *locator_name,
+             vrf_id_t vrf_id),
+            (mc, client, keep, size, base, vrf_id));
+DECLARE_HOOK(srv6_manager_release_chunk,
+            (struct zserv *client,
+             const char *locator_name,
+             vrf_id_t vrf_id),
+            (client, locator_name, vrf_id));
+
+
+extern void zebra_srv6_locator_add(struct srv6_locator *locator);
+extern void zebra_srv6_locator_delete(struct srv6_locator *locator);
+extern struct srv6_locator *zebra_srv6_locator_lookup(const char *name);
+
+extern void zebra_srv6_init(void);
+extern struct zebra_srv6 *zebra_srv6_get_default(void);
+extern bool zebra_srv6_is_enable(void);
+
+extern void srv6_manager_client_connect_call(struct zserv *client, vrf_id_t vrf_id);
+extern void srv6_manager_get_locator_chunk_call(struct srv6_locator **loc,
+                                               struct zserv *client,
+                                               const char *locator_name,
+                                               vrf_id_t vrf_id);
+extern void srv6_manager_release_locator_chunk_call(struct zserv *client,
+                                                   const char *locator_name,
+                                                   vrf_id_t vrf_id);
+extern int srv6_manager_client_disconnect_cb(struct zserv *client);
+extern int release_daemon_srv6_locator_chunks(struct zserv *client);
+
+#endif /* _ZEBRA_SRV6_H */