#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");
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[] = {
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)
}
}
+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;
[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,
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 */