summaryrefslogtreecommitdiffstats
path: root/zebra/label_manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/label_manager.c')
-rw-r--r--zebra/label_manager.c425
1 files changed, 132 insertions, 293 deletions
diff --git a/zebra/label_manager.c b/zebra/label_manager.c
index 6de94e63d..03cfa572d 100644
--- a/zebra/label_manager.c
+++ b/zebra/label_manager.c
@@ -38,295 +38,65 @@
#include "zebra/zebra_router.h"
#include "zebra/label_manager.h"
#include "zebra/zebra_errors.h"
+#include "zebra/zapi_msg.h"
#define CONNECTION_DELAY 5
struct label_manager lbl_mgr;
-extern struct zebra_privs_t zserv_privs;
-
DEFINE_MGROUP(LBL_MGR, "Label Manager");
DEFINE_MTYPE_STATIC(LBL_MGR, LM_CHUNK, "Label Manager Chunk");
-/* In case this zebra daemon is not acting as label manager,
- * it will be a proxy to relay messages to external label manager
- * This zclient thus is to connect to it
+/* define hooks for the basic API, so that it can be specialized or served
+ * externally
*/
-static struct stream *obuf;
-static struct zclient *zclient;
-bool lm_is_external;
-static void delete_label_chunk(void *val)
+DEFINE_HOOK(lm_client_connect,
+ (uint8_t proto, uint16_t instance, vrf_id_t vrf_id),
+ (proto, instance, vrf_id));
+DEFINE_HOOK(lm_client_disconnect, (uint8_t proto, uint16_t instance),
+ (proto, instance));
+DEFINE_HOOK(lm_get_chunk,
+ (struct label_manager_chunk * *lmc, uint8_t proto,
+ uint16_t instance, uint8_t keep, uint32_t size, uint32_t base,
+ vrf_id_t vrf_id),
+ (lmc, proto, instance, keep, size, base, vrf_id));
+DEFINE_HOOK(lm_release_chunk,
+ (uint8_t proto, uint16_t instance, uint32_t start, uint32_t end),
+ (proto, instance, start, end));
+DEFINE_HOOK(lm_cbs_inited, (), ());
+
+/* define wrappers to be called in zapi_msg.c (as hooks must be called in
+ * source file where they were defined)
+ */
+void lm_client_connect_call(uint8_t proto, uint16_t instance, vrf_id_t vrf_id)
{
- XFREE(MTYPE_LM_CHUNK, val);
+ hook_call(lm_client_connect, proto, instance, vrf_id);
}
-
-static int relay_response_back(void)
+void lm_get_chunk_call(struct label_manager_chunk **lmc, uint8_t proto,
+ uint16_t instance, uint8_t keep, uint32_t size,
+ uint32_t base, vrf_id_t vrf_id)
{
- int ret = 0;
- struct stream *src, *dst;
- uint16_t size = 0;
- uint8_t marker;
- uint8_t version;
- vrf_id_t vrf_id;
- uint16_t resp_cmd;
- uint8_t proto;
- const char *proto_str;
- unsigned short instance;
- struct zserv *zserv;
-
- /* sanity */
- if (!zclient || zclient->sock < 0)
- return -1;
-
- /* input buffer with msg from label manager */
- src = zclient->ibuf;
-
- stream_reset(src);
-
- /* parse header */
- ret = zclient_read_header(src, zclient->sock, &size, &marker, &version,
- &vrf_id, &resp_cmd);
- if (ret < 0) {
- if (errno != EAGAIN)
- flog_err(EC_ZEBRA_LM_RESPONSE,
- "Error reading Label Manager response: %s",
- strerror(errno));
- return -1;
- }
-
- /* do not relay a msg that has nothing to do with LM */
- switch (resp_cmd) {
- case ZEBRA_LABEL_MANAGER_CONNECT:
- case ZEBRA_LABEL_MANAGER_CONNECT_ASYNC: /* should not be seen */
- case ZEBRA_GET_LABEL_CHUNK:
- case ZEBRA_RELEASE_LABEL_CHUNK:
- break;
- default:
- zlog_debug("Not relaying '%s' response (size %d) from LM",
- zserv_command_string(resp_cmd), size);
- return -1;
- }
-
- zlog_debug("Received '%s' response (size %d) from LM",
- zserv_command_string(resp_cmd), size);
-
- if (size == 0)
- return -1;
-
- /* Get the 'proto' field of the message */
- proto = stream_getc(src);
-
- /* Get the 'instance' field of the message */
- instance = stream_getw(src);
-
- proto_str = zebra_route_string(proto);
-
- /* lookup the client to relay the msg to */
- zserv = zserv_find_client(proto, instance);
- if (!zserv) {
- flog_err(
- EC_ZEBRA_LM_NO_SUCH_CLIENT,
- "Error relaying LM response: can't find client %s, instance %u",
- proto_str, instance);
- return -1;
- }
- zlog_debug("Found client to relay LM response to client %s instance %u",
- proto_str, instance);
-
- /* copy msg into output buffer */
- dst = obuf;
- stream_copy(dst, src);
-
- /* send response back */
- ret = writen(zserv->sock, dst->data, stream_get_endp(dst));
- if (ret <= 0) {
- flog_err(EC_ZEBRA_LM_RELAY_FAILED,
- "Error relaying LM response to %s instance %u: %s",
- proto_str, instance, strerror(errno));
- return -1;
- }
- zlog_debug("Relayed LM response (%d bytes) to %s instance %u", ret,
- proto_str, instance);
-
- return 0;
+ hook_call(lm_get_chunk, lmc, proto, instance, keep, size, base, vrf_id);
}
-
-static int lm_zclient_read(struct thread *t)
-{
- int ret;
-
- zclient->t_read = NULL;
-
- /* read response and send it back */
- ret = relay_response_back();
-
- /* re-arm read */
- thread_add_read(zclient->master, lm_zclient_read, NULL,
- zclient->sock, &zclient->t_read);
- return ret;
-}
-
-static int reply_error(int cmd, struct zserv *zserv, vrf_id_t vrf_id)
+void lm_release_chunk_call(uint8_t proto, uint16_t instance, uint32_t start,
+ uint32_t end)
{
- int ret;
- struct stream *s;
-
- s = stream_new(ZEBRA_MAX_PACKET_SIZ);
-
- zclient_create_header(s, cmd, vrf_id);
-
- /* proto */
- stream_putc(s, zserv->proto);
- /* instance */
- stream_putw(s, zserv->instance);
- /* result */
- stream_putc(s, 1);
-
- /* Write packet size. */
- stream_putw_at(s, 0, stream_get_endp(s));
-
- ret = writen(zserv->sock, s->data, stream_get_endp(s));
-
- stream_free(s);
- return ret;
-}
-/**
- * Receive a request to get or release a label chunk and forward it to external
- * label manager.
- *
- * It's called from zserv in case it's not an actual label manager, but just a
- * proxy.
- *
- * @param cmd Type of request (connect, get or release)
- * @param zserv
- * @return 0 on success, -1 otherwise
- */
-int zread_relay_label_manager_request(int cmd, struct zserv *zserv,
- struct stream *msg, vrf_id_t vrf_id)
-{
- struct stream *dst;
- int ret = 0;
- uint8_t proto;
- const char *proto_str;
- unsigned short instance;
-
- if (zclient->sock < 0) {
- flog_err(EC_ZEBRA_LM_NO_SOCKET,
- "Unable to relay LM request: no socket");
- reply_error(cmd, zserv, vrf_id);
- return -1;
- }
-
- /* peek msg to get proto and instance id. This zebra, which acts as
- * a proxy needs to have such values for each client in order to
- * relay responses back to it.
- */
-
- /* Get the 'proto' field of incoming msg */
- proto = stream_getc(msg);
-
- /* Get the 'instance' field of incoming msg */
- instance = stream_getw(msg);
-
- /* stringify proto */
- proto_str = zebra_route_string(proto);
-
- /* check & set client proto if unset */
- if (zserv->proto && zserv->proto != proto) {
- flog_warn(EC_ZEBRAING_LM_PROTO_MISMATCH,
- "Client proto(%u) != msg proto(%u)", zserv->proto,
- proto);
- return -1;
- }
-
- /* check & set client instance if unset */
- if (zserv->instance && zserv->instance != instance) {
- flog_err(EC_ZEBRA_LM_BAD_INSTANCE,
- "Client instance(%u) != msg instance(%u)",
- zserv->instance, instance);
- return -1;
- }
-
- /* recall proto and instance */
- zserv->instance = instance;
- zserv->proto = proto;
-
- /* in case there's any incoming message enqueued, read and forward it */
- if (zserv->is_synchronous)
- while (ret == 0)
- ret = relay_response_back();
-
- /* get the msg buffer used toward the 'master' Label Manager */
- dst = zclient->obuf;
-
- /* copy the message */
- stream_copy(dst, msg);
-
- /* Send request to external label manager */
- ret = writen(zclient->sock, dst->data, stream_get_endp(dst));
- if (ret <= 0) {
- flog_err(EC_ZEBRA_LM_RELAY_FAILED,
- "Error relaying LM request from %s instance %u: %s",
- proto_str, instance, strerror(errno));
- reply_error(cmd, zserv, vrf_id);
- return -1;
- }
- zlog_debug("Relayed LM request (%d bytes) from %s instance %u", ret,
- proto_str, instance);
-
-
- /* Release label chunk has no response */
- if (cmd == ZEBRA_RELEASE_LABEL_CHUNK)
- return 0;
-
- /* make sure we listen to the response */
- if (!zclient->t_read)
- thread_add_read(zclient->master, lm_zclient_read, NULL,
- zclient->sock, &zclient->t_read);
-
- return 0;
+ hook_call(lm_release_chunk, proto, instance, start, end);
}
-static int lm_zclient_connect(struct thread *t)
-{
- zclient->t_connect = NULL;
-
- if (zclient->sock >= 0)
- return 0;
-
- if (zclient_socket_connect(zclient) < 0) {
- flog_err(EC_ZEBRA_LM_CLIENT_CONNECTION_FAILED,
- "Error connecting synchronous zclient!");
- thread_add_timer(zrouter.master, lm_zclient_connect, zclient,
- CONNECTION_DELAY, &zclient->t_connect);
- return -1;
- }
-
- /* make socket non-blocking */
- (void)set_nonblocking(zclient->sock);
-
- return 0;
-}
+/* forward declarations of the static functions to be used for some hooks */
+static int label_manager_connect(uint8_t proto, uint16_t instance,
+ vrf_id_t vrf_id);
+static int label_manager_disconnect(uint8_t proto, uint16_t instance);
+static int label_manager_get_chunk(struct label_manager_chunk **lmc,
+ uint8_t proto, uint16_t instance,
+ uint8_t keep, uint32_t size, uint32_t base,
+ vrf_id_t vrf_id);
-/**
- * Function to initialize zclient in case this is not an actual
- * label manager, but just a proxy to an external one.
- *
- * @param lm_zserv_path Path to zserv socket of external label manager
- */
-static void lm_zclient_init(char *lm_zserv_path)
+void delete_label_chunk(void *val)
{
- if (lm_zserv_path)
- frr_zclient_addr(&zclient_addr, &zclient_addr_len,
- lm_zserv_path);
-
- /* Set default values. */
- zclient = zclient_new(zrouter.master, &zclient_options_default);
- zclient->privs = &zserv_privs;
- zclient->sock = -1;
- zclient->t_connect = NULL;
- lm_zclient_connect(NULL);
+ XFREE(MTYPE_LM_CHUNK, val);
}
/**
@@ -339,15 +109,16 @@ static void lm_zclient_init(char *lm_zserv_path)
* @param instance Instance, to identify the owner
* @return Number of chunks released
*/
-int release_daemon_label_chunks(struct zserv *client)
+int release_daemon_label_chunks(uint8_t proto, unsigned short instance)
{
- uint8_t proto = client->proto;
- uint16_t instance = client->instance;
struct listnode *node;
struct label_manager_chunk *lmc;
int count = 0;
int ret;
+ zlog_debug("%s: Releasing chunks for client proto %s, instance %d",
+ __func__, zebra_route_string(proto), instance);
+
for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
if (lmc->proto == proto && lmc->instance == instance
&& lmc->keep == 0) {
@@ -363,33 +134,51 @@ int release_daemon_label_chunks(struct zserv *client)
return count;
}
+int lm_client_disconnect_cb(struct zserv *client)
+{
+ uint8_t proto = client->proto;
+ uint16_t instance = client->instance;
+
+ hook_call(lm_client_disconnect, proto, instance);
+ return 0;
+}
+
+void lm_hooks_register(void)
+{
+ hook_register(lm_client_connect, label_manager_connect);
+ hook_register(lm_client_disconnect, label_manager_disconnect);
+ hook_register(lm_get_chunk, label_manager_get_chunk);
+ hook_register(lm_release_chunk, release_label_chunk);
+}
+void lm_hooks_unregister(void)
+{
+ hook_unregister(lm_client_connect, label_manager_connect);
+ hook_unregister(lm_client_disconnect, label_manager_disconnect);
+ hook_unregister(lm_get_chunk, label_manager_get_chunk);
+ hook_unregister(lm_release_chunk, release_label_chunk);
+}
+
/**
* Init label manager (or proxy to an external one)
*/
-void label_manager_init(char *lm_zserv_path)
+void label_manager_init(void)
{
- /* this is an actual label manager */
- if (!lm_zserv_path) {
- zlog_debug("Initializing internal label manager");
- lm_is_external = false;
- lbl_mgr.lc_list = list_new();
- lbl_mgr.lc_list->del = delete_label_chunk;
- } else { /* it's acting just as a proxy */
- zlog_debug("Initializing external label manager at %s",
- lm_zserv_path);
- lm_is_external = true;
- lm_zclient_init(lm_zserv_path);
- }
+ lbl_mgr.lc_list = list_new();
+ lbl_mgr.lc_list->del = delete_label_chunk;
+ hook_register(zserv_client_close, lm_client_disconnect_cb);
- obuf = stream_new(ZEBRA_MAX_PACKET_SIZ);
+ /* register default hooks for the label manager actions */
+ lm_hooks_register();
- hook_register(zserv_client_close, release_daemon_label_chunks);
+ /* notify any external module that we are done */
+ hook_call(lm_cbs_inited);
}
/* alloc and fill a label chunk */
-static struct label_manager_chunk *
-create_label_chunk(uint8_t proto, unsigned short instance, uint8_t keep,
- uint32_t start, uint32_t end)
+struct label_manager_chunk *create_label_chunk(uint8_t proto,
+ unsigned short instance,
+ uint8_t keep, uint32_t start,
+ uint32_t end)
{
/* alloc chunk, fill it and return it */
struct label_manager_chunk *lmc =
@@ -405,7 +194,7 @@ create_label_chunk(uint8_t proto, unsigned short instance, uint8_t keep,
}
/* attempt to get a specific label chunk */
-struct label_manager_chunk *
+static struct label_manager_chunk *
assign_specific_label_chunk(uint8_t proto, unsigned short instance,
uint8_t keep, uint32_t size, uint32_t base)
{
@@ -607,9 +396,59 @@ int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
return ret;
}
+/* default functions to be called on hooks */
+static int label_manager_connect(uint8_t proto, uint16_t instance,
+ vrf_id_t vrf_id)
+{
+ /*
+ * Release previous labels of same protocol and instance.
+ * This is done in case it restarted from an unexpected shutdown.
+ */
+ release_daemon_label_chunks(proto, instance);
+ return lm_client_connect_response(proto, instance, vrf_id, 0);
+}
+static int label_manager_disconnect(uint8_t proto, uint16_t instance)
+{
+ release_daemon_label_chunks(proto, instance);
+ return 0;
+}
+static int label_manager_get_chunk(struct label_manager_chunk **lmc,
+ uint8_t proto, uint16_t instance,
+ uint8_t keep, uint32_t size, uint32_t base,
+ vrf_id_t vrf_id)
+{
+ *lmc = assign_label_chunk(proto, instance, keep, size, base);
+ return lm_get_chunk_response(*lmc, proto, instance, vrf_id);
+}
+
+/* Respond to a connect request */
+int lm_client_connect_response(uint8_t proto, uint16_t instance,
+ vrf_id_t vrf_id, uint8_t result)
+{
+ struct zserv *client = zserv_find_client(proto, instance);
+ if (!client) {
+ zlog_err("%s: could not find client for daemon %s instance %u",
+ __func__, zebra_route_string(proto), instance);
+ return 1;
+ }
+ return zsend_label_manager_connect_response(client, vrf_id, result);
+}
+
+/* Respond to a get_chunk request */
+int lm_get_chunk_response(struct label_manager_chunk *lmc, uint8_t proto,
+ uint16_t instance, vrf_id_t vrf_id)
+{
+ struct zserv *client = zserv_find_client(proto, instance);
+ if (!client) {
+ zlog_err("%s: could not find client for daemon %s instance %u",
+ __func__, zebra_route_string(proto), instance);
+ return 1;
+ }
+ return zsend_assign_label_chunk_response(client, vrf_id, proto,
+ instance, lmc);
+}
void label_manager_close(void)
{
list_delete(&lbl_mgr.lc_list);
- stream_free(obuf);
}