summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ldpd/lde.c150
-rw-r--r--ldpd/lde.h9
-rw-r--r--ldpd/ldpd.c35
-rw-r--r--ldpd/ldpd.h4
-rw-r--r--lib/log.c3
-rw-r--r--lib/mpls.h2
-rw-r--r--lib/zclient.c218
-rw-r--r--lib/zclient.h7
-rw-r--r--tests/test_lblmgr.c150
-rw-r--r--zebra/Makefile.am4
-rw-r--r--zebra/label_manager.c317
-rw-r--r--zebra/label_manager.h74
-rw-r--r--zebra/main.c28
-rw-r--r--zebra/zserv.c176
-rw-r--r--zebra/zserv.h1
15 files changed, 1150 insertions, 28 deletions
diff --git a/ldpd/lde.c b/ldpd/lde.c
index 08339c720..d4b95637f 100644
--- a/ldpd/lde.c
+++ b/ldpd/lde.c
@@ -33,6 +33,10 @@
#include "privs.h"
#include "sigevent.h"
#include "mpls.h"
+#include <lib/linklist.h>
+#include "zclient.h"
+#include "stream.h"
+#include "network.h"
static void lde_shutdown(void);
static int lde_dispatch_imsg(struct thread *);
@@ -50,6 +54,11 @@ static void lde_map_free(void *);
static int lde_address_add(struct lde_nbr *, struct lde_addr *);
static int lde_address_del(struct lde_nbr *, struct lde_addr *);
static void lde_address_list_free(struct lde_nbr *);
+static void zclient_sync_init (u_short instance);
+static void lde_label_list_init(void);
+static int lde_get_label_chunk (void);
+static void on_get_label_chunk_response(uint32_t start, uint32_t end);
+static uint32_t lde_get_next_label(void);
RB_GENERATE(nbr_tree, lde_nbr, entry, lde_nbr_compare)
RB_GENERATE(lde_map_head, lde_map, entry, lde_map_compare)
@@ -83,6 +92,10 @@ static struct zebra_privs_t lde_privs =
.cap_num_i = 0
};
+/* List of chunks of labels externally assigned by Zebra */
+struct list *label_chunk_list;
+struct listnode *current_label_chunk;
+
/* SIGINT / SIGTERM handler. */
static void
sigint(void)
@@ -102,9 +115,31 @@ static struct quagga_signal_t lde_signals[] =
},
};
+struct zclient *zclient_sync = NULL;
+static void
+zclient_sync_init(u_short instance)
+{
+ /* Initialize special zclient for synchronous message exchanges. */
+ log_debug("Initializing synchronous zclient for label manager");
+ zclient_sync = zclient_new(master);
+ zclient_sync->sock = -1;
+ zclient_sync->redist_default = ZEBRA_ROUTE_LDP;
+ zclient_sync->instance = instance;
+ while (zclient_socket_connect(zclient_sync) < 0) {
+ fprintf(stderr, "Error connecting synchronous zclient!\n");
+ sleep(1);
+ }
+
+ /* Connect to label manager */
+ while (lm_label_manager_connect(zclient_sync) != 0) {
+ fprintf(stderr, "Error connecting to label manager!\n");
+ sleep(1);
+ }
+}
+
/* label decision engine */
void
-lde(const char *user, const char *group)
+lde(const char *user, const char *group, u_short instance)
{
struct thread thread;
struct timeval now;
@@ -152,6 +187,10 @@ lde(const char *user, const char *group)
gettimeofday(&now, NULL);
global.uptime = now.tv_sec;
+ /* Init synchronous zclient and label list */
+ zclient_sync_init(instance);
+ lde_label_list_init();
+
/* Fetch next active thread. */
while (thread_fetch(master, &thread))
thread_call(&thread);
@@ -587,7 +626,6 @@ lde_acl_check(char *acl_name, int af, union ldpd_addr *addr, uint8_t prefixlen)
uint32_t
lde_update_label(struct fec_node *fn)
{
- static uint32_t label = MPLS_LABEL_RESERVED_MAX;
struct fec_nh *fnh;
int connected = 0;
@@ -652,12 +690,7 @@ lde_update_label(struct fec_node *fn)
fn->local_label > MPLS_LABEL_RESERVED_MAX)
return (fn->local_label);
- /*
- * TODO: request label to zebra or define a range of labels for ldpd.
- */
-
- label++;
- return (label);
+ return lde_get_next_label ();
}
void
@@ -1533,3 +1566,104 @@ lde_address_list_free(struct lde_nbr *ln)
free(lde_addr);
}
}
+
+static void
+lde_del_label_chunk(void *val)
+{
+ free(val);
+}
+static int
+lde_get_label_chunk(void)
+{
+ int ret;
+ uint32_t start, end;
+
+ log_debug("Getting label chunk");
+ ret = lm_get_label_chunk(zclient_sync, 0, CHUNK_SIZE, &start, &end);
+ if (ret < 0)
+ {
+ log_warnx("Error getting label chunk!");
+ close(zclient_sync->sock);
+ zclient_sync->sock = -1;
+ return -1;
+ }
+
+ on_get_label_chunk_response(start, end);
+
+ return 0;
+}
+static void
+lde_label_list_init(void)
+{
+ label_chunk_list = list_new();
+ label_chunk_list->del = lde_del_label_chunk;
+
+ /* get first chunk */
+ while (lde_get_label_chunk() != 0) {
+ fprintf(stderr, "Error getting first label chunk!\n");
+ sleep(1);
+ }
+}
+
+static void
+on_get_label_chunk_response(uint32_t start, uint32_t end)
+{
+ struct label_chunk *new_label_chunk;
+
+ log_debug("Label Chunk assign: %u - %u", start, end);
+
+ new_label_chunk = calloc(1, sizeof(struct label_chunk));
+
+ new_label_chunk->start = start;
+ new_label_chunk->end = end;
+ new_label_chunk->used_mask = 0;
+
+ listnode_add(label_chunk_list, (void *)new_label_chunk);
+
+ /* let's update current if needed */
+ if (!current_label_chunk)
+ current_label_chunk = listtail(label_chunk_list);
+}
+
+static uint32_t
+lde_get_next_label(void)
+{
+ struct label_chunk *label_chunk;
+ uint32_t i, pos, size;
+ uint32_t label = NO_LABEL;
+
+ while (current_label_chunk) {
+ label_chunk = listgetdata(current_label_chunk);
+ if (!label_chunk)
+ goto end;
+
+ /* try to get next free label in currently used label chunk */
+ size = label_chunk->end - label_chunk->start + 1;
+ for (i = 0, pos = 1; i < size; i++, pos <<= 1) {
+ if (!(pos & label_chunk->used_mask)) {
+ label_chunk->used_mask |= pos;
+ label = label_chunk->start + i;
+ goto end;
+ }
+ }
+ current_label_chunk = listnextnode(current_label_chunk);
+ }
+
+end:
+ /* we moved till the last chunk, or were not able to find a label,
+ so let's ask for another one */
+ if (!current_label_chunk || current_label_chunk == listtail(label_chunk_list)
+ || label == NO_LABEL) {
+ if (lde_get_label_chunk() != 0)
+ log_warn("%s: Error getting label chunk!", __func__);
+
+ }
+
+ return NO_LABEL;
+}
+/* TODO: not used yet. Have to check label release */
+static void
+lde_release_label_chunk(void)
+{
+ return;
+}
diff --git a/ldpd/lde.h b/ldpd/lde.h
index b5bcb42c8..d9836097a 100644
--- a/ldpd/lde.h
+++ b/ldpd/lde.h
@@ -124,6 +124,13 @@ struct fec_node {
void *data; /* fec specific data */
};
+#define CHUNK_SIZE 64
+struct label_chunk {
+ uint32_t start;
+ uint32_t end;
+ uint64_t used_mask;
+};
+
#define LDE_GC_INTERVAL 300
extern struct ldpd_conf *ldeconf;
@@ -132,7 +139,7 @@ extern struct nbr_tree lde_nbrs;
extern struct thread *gc_timer;
/* lde.c */
-void lde(const char *, const char *);
+void lde(const char *, const char *, u_short instance);
int lde_imsg_compose_parent(int, pid_t, void *, uint16_t);
int lde_imsg_compose_ldpe(int, uint32_t, pid_t, void *, uint16_t);
int lde_acl_check(char *, int, union ldpd_addr *, uint8_t);
diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
index 98ea5ca53..8fa33ff09 100644
--- a/ldpd/ldpd.c
+++ b/ldpd/ldpd.c
@@ -45,7 +45,7 @@
static void ldpd_shutdown(void);
static pid_t start_child(enum ldpd_process, char *, int, int,
- const char *, const char *, const char *);
+ const char *, const char *, const char *, const char *);
static int main_dispatch_ldpe(struct thread *);
static int main_dispatch_lde(struct thread *);
static int main_imsg_send_ipc_sockets(struct imsgbuf *,
@@ -119,6 +119,7 @@ char ctl_sock_path[MAXPATHLEN] = LDPD_SOCKET;
static struct option longopts[] =
{
{ "ctl_socket", required_argument, NULL, OPTION_CTLSOCK},
+ { "instance", required_argument, NULL, 'n'},
{ 0 }
};
@@ -186,6 +187,8 @@ main(int argc, char *argv[])
char *ctl_sock_name;
const char *user = NULL;
const char *group = NULL;
+ u_short instance = 0;
+ const char *instance_char = NULL;
ldpd_process = PROC_MAIN;
@@ -194,8 +197,9 @@ main(int argc, char *argv[])
saved_argv0 = (char *)"ldpd";
frr_preinit(&ldpd_di, argc, argv);
- frr_opt_add("LE", longopts,
- " --ctl_socket Override ctl socket path\n");
+ frr_opt_add("LEn:", longopts,
+ " --ctl_socket Override ctl socket path\n"
+ "-n, --instance Instance id\n");
while (1) {
int opt;
@@ -227,6 +231,12 @@ main(int argc, char *argv[])
strlcat(ctl_sock_path, ctl_sock_name,
sizeof(ctl_sock_path));
break;
+ case 'n':
+ instance = atoi(optarg);
+ instance_char = optarg;
+ if (instance < 1)
+ exit(0);
+ break;
case 'L':
lflag = 1;
break;
@@ -258,7 +268,7 @@ main(int argc, char *argv[])
LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON);
if (lflag)
- lde(user, group);
+ lde(user, group, instance);
else if (eflag)
ldpe(user, group, ctl_sock_path);
@@ -308,10 +318,10 @@ main(int argc, char *argv[])
/* start children */
lde_pid = start_child(PROC_LDE_ENGINE, saved_argv0,
pipe_parent2lde[1], pipe_parent2lde_sync[1],
- user, group, ctl_sock_custom_path);
+ user, group, ctl_sock_custom_path, instance_char);
ldpe_pid = start_child(PROC_LDP_ENGINE, saved_argv0,
pipe_parent2ldpe[1], pipe_parent2ldpe_sync[1],
- user, group, ctl_sock_custom_path);
+ user, group, ctl_sock_custom_path, instance_char);
/* drop privileges */
zprivs_init(&ldpd_privs);
@@ -414,9 +424,10 @@ ldpd_shutdown(void)
static pid_t
start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync,
- const char *user, const char *group, const char *ctl_sock_custom_path)
+ const char *user, const char *group, const char *ctl_sock_custom_path,
+ const char *instance)
{
- char *argv[9];
+ char *argv[13];
int argc = 0;
pid_t pid;
@@ -459,6 +470,14 @@ start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync,
argv[argc++] = (char *)"--ctl_socket";
argv[argc++] = (char *)ctl_sock_custom_path;
}
+ /* zclient serv path */
+ argv[argc++] = (char *)"-z";
+ argv[argc++] = (char *)zclient_serv_path_get();
+ /* instance */
+ if (instance) {
+ argv[argc++] = (char *)"-n";
+ argv[argc++] = (char *)instance;
+ }
argv[argc++] = NULL;
execvp(argv0, argv);
diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h
index 0a7e1177b..c665656aa 100644
--- a/ldpd/ldpd.h
+++ b/ldpd/ldpd.h
@@ -140,7 +140,9 @@ enum imsg_type {
IMSG_RECONF_END,
IMSG_DEBUG_UPDATE,
IMSG_LOG,
- IMSG_ACL_CHECK
+ IMSG_ACL_CHECK,
+ IMSG_GET_LABEL_CHUNK,
+ IMSG_RELEASE_LABEL_CHUNK
};
union ldpd_addr {
diff --git a/lib/log.c b/lib/log.c
index 0fd9621f3..69225dbf7 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -964,6 +964,9 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY (ZEBRA_IPV6_NEXTHOP_ADD),
DESC_ENTRY (ZEBRA_IPV6_NEXTHOP_DELETE),
DESC_ENTRY (ZEBRA_IPMR_ROUTE_STATS),
+ DESC_ENTRY (ZEBRA_LABEL_MANAGER_CONNECT),
+ DESC_ENTRY (ZEBRA_GET_LABEL_CHUNK),
+ DESC_ENTRY (ZEBRA_RELEASE_LABEL_CHUNK),
};
#undef DESC_ENTRY
diff --git a/lib/mpls.h b/lib/mpls.h
index b5c1a653b..13a46e101 100644
--- a/lib/mpls.h
+++ b/lib/mpls.h
@@ -23,6 +23,8 @@
#ifndef _QUAGGA_MPLS_H
#define _QUAGGA_MPLS_H
+#include <arpa/inet.h>
+
/* Well-known MPLS label values (RFC 3032 etc). */
#define MPLS_V4_EXP_NULL_LABEL 0
#define MPLS_RA_LABEL 1
diff --git a/lib/zclient.c b/lib/zclient.c
index 859751deb..6f7fb9b1b 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -33,6 +33,7 @@
#include "memory.h"
#include "table.h"
#include "nexthop.h"
+#include "mpls.h"
DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient")
DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs")
@@ -1461,6 +1462,223 @@ zebra_interface_vrf_update_read (struct stream *s, vrf_id_t vrf_id,
*new_vrf_id = new_id;
return ifp;
}
+/**
+ * Connect to label manager in a syncronous way
+ *
+ * It first writes the request to zcient output buffer and then
+ * immediately reads the answer from the input buffer.
+ *
+ * @param zclient Zclient used to connect to label manager (zebra)
+ * @result Result of response
+ */
+int
+lm_label_manager_connect (struct zclient *zclient)
+{
+ int ret;
+ struct stream *s;
+ u_char result;
+ u_int16_t size;
+ u_char marker;
+ u_char version;
+ vrf_id_t vrf_id;
+ u_int16_t cmd;
+
+ zlog_debug ("Connecting to Label Manager");
+ if (zclient->sock < 0)
+ return -1;
+
+ /* send request */
+ s = zclient->obuf;
+ stream_reset (s);
+ zclient_create_header (s, ZEBRA_LABEL_MANAGER_CONNECT, VRF_DEFAULT);
+
+ /* proto */
+ stream_putc (s, zclient->redist_default);
+ /* instance */
+ stream_putw (s, zclient->instance);
+
+ /* Put length at the first point of the stream. */
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ ret = writen (zclient->sock, s->data, stream_get_endp (s));
+ if (ret < 0)
+ {
+ zlog_err ("%s: can't write to zclient->sock", __func__);
+ close (zclient->sock);
+ zclient->sock = -1;
+ return -1;
+ }
+ if (ret == 0)
+ {
+ zlog_err ("%s: zclient->sock connection closed", __func__);
+ close (zclient->sock);
+ zclient->sock = -1;
+ return -1;
+ }
+ zlog_debug ("%s: Label manager connect request (%d bytes) sent", __func__, ret);
+
+ /* read response */
+ s = zclient->ibuf;
+ stream_reset (s);
+
+ ret = zclient_read_header (s, zclient->sock, &size, &marker, &version,
+ &vrf_id, &cmd);
+ if (ret != 0 || cmd != ZEBRA_LABEL_MANAGER_CONNECT) {
+ zlog_err ("%s: Invalid Label Manager Connect Message Reply Header", __func__);
+ return -1;
+ }
+ /* result */
+ result = stream_getc(s);
+ zlog_debug ("%s: Label Manager connect response (%d bytes) received, result %u",
+ __func__, size, result);
+
+ return (int)result;
+}
+
+/**
+ * Function to request a label chunk in a syncronous way
+ *
+ * It first writes the request to zlcient output buffer and then
+ * immediately reads the answer from the input buffer.
+ *
+ * @param zclient Zclient used to connect to label manager (zebra)
+ * @param keep Avoid garbage collection
+ * @param chunk_size Amount of labels requested
+ * @param start To write first assigned chunk label to
+ * @param end To write last assigned chunk label to
+ * @result 0 on success, -1 otherwise
+ */
+int
+lm_get_label_chunk (struct zclient *zclient, u_char keep, uint32_t chunk_size,
+ uint32_t *start, uint32_t *end)
+{
+ int ret;
+ struct stream *s;
+ u_int16_t size;
+ u_char marker;
+ u_char version;
+ vrf_id_t vrf_id;
+ u_int16_t cmd;
+ u_char response_keep;
+
+ zlog_debug ("Getting Label Chunk");
+ if (zclient->sock < 0)
+ return -1;
+
+ /* send request */
+ s = zclient->obuf;
+ stream_reset (s);
+ zclient_create_header (s, ZEBRA_GET_LABEL_CHUNK, VRF_DEFAULT);
+ /* keep */
+ stream_putc (s, keep);
+ /* chunk size */
+ stream_putl (s, chunk_size);
+ /* Put length at the first point of the stream. */
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ ret = writen (zclient->sock, s->data, stream_get_endp (s));
+ if (ret < 0)
+ {
+ zlog_err ("%s: can't write to zclient->sock", __func__);
+ close (zclient->sock);
+ zclient->sock = -1;
+ return -1;
+ }
+ if (ret == 0)
+ {
+ zlog_err ("%s: zclient->sock connection closed", __func__);
+ close (zclient->sock);
+ zclient->sock = -1;
+ return -1;
+ }
+ zlog_debug ("%s: Label chunk request (%d bytes) sent", __func__, ret);
+
+ /* read response */
+ s = zclient->ibuf;
+ stream_reset (s);
+
+ ret = zclient_read_header (s, zclient->sock, &size, &marker, &version,
+ &vrf_id, &cmd);
+ if (ret != 0 || cmd != ZEBRA_GET_LABEL_CHUNK) {
+ zlog_err ("%s: Invalid Get Label Chunk Message Reply Header", __func__);
+ return -1;
+ }
+ zlog_debug ("%s: Label chunk response (%d bytes) received", __func__, size);
+ /* keep */
+ response_keep = stream_getc(s);
+ /* start and end labels */
+ *start = stream_getl(s);
+ *end = stream_getl(s);
+
+ /* not owning this response */
+ if (keep != response_keep) {
+ zlog_err ("%s: Invalid Label chunk: %u - %u, keeps mismatch %u != %u",
+ __func__, *start, *end, keep, response_keep);
+ }
+ /* sanity */
+ if (*start > *end
+ || *start < MPLS_MIN_UNRESERVED_LABEL
+ || *end > MPLS_MAX_UNRESERVED_LABEL) {
+ zlog_err ("%s: Invalid Label chunk: %u - %u", __func__,
+ *start, *end);
+ return -1;
+ }
+
+ zlog_debug ("Label Chunk assign: %u - %u (%u) ",
+ *start, *end, response_keep);
+
+ return 0;
+}
+
+/**
+ * Function to release a label chunk
+ *
+ * @param zclient Zclient used to connect to label manager (zebra)
+ * @param start First label of chunk
+ * @param end Last label of chunk
+ * @result 0 on success, -1 otherwise
+ */
+int
+lm_release_label_chunk (struct zclient *zclient, uint32_t start, uint32_t end)
+{
+ int ret;
+ struct stream *s;
+
+ zlog_debug ("Releasing Label Chunk");
+ if (zclient->sock < 0)
+ return -1;
+
+ /* send request */
+ s = zclient->obuf;
+ stream_reset (s);
+ zclient_create_header (s, ZEBRA_RELEASE_LABEL_CHUNK, VRF_DEFAULT);
+
+ /* start */
+ stream_putl (s, start);
+ /* end */
+ stream_putl (s, end);
+
+ /* Put length at the first point of the stream. */
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ ret = writen (zclient->sock, s->data, stream_get_endp (s));
+ if (ret < 0)
+ {
+ zlog_err ("%s: can't write to zclient->sock", __func__);
+ close (zclient->sock);
+ zclient->sock = -1;
+ return -1;
+ }
+ if (ret == 0)
+ {
+ zlog_err ("%s: zclient->sock connection closed", __func__);
+ close (zclient->sock);
+ zclient->sock = -1;
+ return -1;
+ }
+
+ return 0;
+}
/* Zebra client message read function. */
static int
diff --git a/lib/zclient.h b/lib/zclient.h
index 89fc865c7..d3d0a202c 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -91,6 +91,9 @@ typedef enum {
ZEBRA_IPV6_NEXTHOP_ADD,
ZEBRA_IPV6_NEXTHOP_DELETE,
ZEBRA_IPMR_ROUTE_STATS,
+ ZEBRA_LABEL_MANAGER_CONNECT,
+ ZEBRA_GET_LABEL_CHUNK,
+ ZEBRA_RELEASE_LABEL_CHUNK,
} zebra_message_types_t;
struct redist_proto
@@ -271,6 +274,10 @@ extern int zapi_ipv4_route (u_char, struct zclient *, struct prefix_ipv4 *,
extern struct interface *zebra_interface_link_params_read (struct stream *);
extern size_t zebra_interface_link_params_write (struct stream *,
struct interface *);
+extern int lm_label_manager_connect (struct zclient *zclient);
+extern int lm_get_label_chunk (struct zclient *zclient, u_char keep,
+ uint32_t chunk_size, uint32_t *start, uint32_t *end);
+extern int lm_release_label_chunk (struct zclient *zclient, uint32_t start, uint32_t end);
/* IPv6 prefix add and delete function prototype. */
struct zapi_ipv6
diff --git a/tests/test_lblmgr.c b/tests/test_lblmgr.c
new file mode 100644
index 000000000..4a4aaa001
--- /dev/null
+++ b/tests/test_lblmgr.c
@@ -0,0 +1,150 @@
+/*
+ * Label Manager Test
+ *
+ * Copyright (C) 2017 by Bingen Eguzkitza,
+ * Volta Networks Inc.
+ *
+ * This file is part of FreeRangeRouting (FRR)
+ *
+ * FRR 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, or (at your option) any
+ * later version.
+ *
+ * FRR 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 FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "lib/stream.h"
+#include "lib/zclient.h"
+
+#define ZSERV_PATH "/tmp/zserv.api" // TODO!!
+#define KEEP 0 /* change to 1 to avoid garbage collection */
+#define CHUNK_SIZE 32
+
+struct zclient *zclient;
+u_short instance = 1;
+
+const char *sequence = "GGRGGGRRG";
+
+static int zebra_send_get_label_chunk (void);
+static int zebra_send_release_label_chunk (uint32_t start, uint32_t end);
+
+static void
+process_next_call (uint32_t start, uint32_t end)
+{
+ sleep (3);
+ if (!*sequence)
+ exit (0);
+ if (*sequence == 'G')
+ zebra_send_get_label_chunk ();
+ else if (*sequence == 'R')
+ zebra_send_release_label_chunk (start, end);
+}
+
+/* Connect to Label Manager */
+
+static int
+zebra_send_label_manager_connect ()
+{
+ int ret;
+
+ printf("Connect to Label Manager\n");
+
+ ret = lm_label_manager_connect (zclient);
+ printf ("Label Manager connection result: %u \n", ret);
+ if (ret != 0 ) {
+ fprintf (stderr, "Error %d connecting to Label Manager %s\n", ret,
+ strerror(errno));
+ exit (1);
+ }
+
+ process_next_call (0, 0);
+}
+
+/* Get Label Chunk */
+
+static int
+zebra_send_get_label_chunk ()
+{
+ uint32_t start;
+ uint32_t end;
+ int ret;
+
+ printf("Ask for label chunk \n");
+
+ ret = lm_get_label_chunk (zclient, KEEP, CHUNK_SIZE, &start, &end);
+ if (ret != 0 ) {
+ fprintf (stderr, "Error %d requesting label chunk %s\n", ret, strerror(errno));
+ exit (1);
+ }
+
+ sequence++;
+
+ printf ("Label Chunk assign: %u - %u \n",
+ start, end);
+
+ process_next_call (start, end);
+}
+
+/* Release Label Chunk */
+
+static int
+zebra_send_release_label_chunk (uint32_t start, uint32_t end)
+{
+ struct stream *s;
+ int ret;
+
+ printf("Release label chunk: %u - %u\n", start, end);
+
+ ret = lm_release_label_chunk (zclient, start, end);
+ if (ret != 0 ) {
+ fprintf (stderr, "Error releasing label chunk\n");
+ exit (1);
+ }
+
+ sequence++;
+
+ process_next_call (start-CHUNK_SIZE, end-CHUNK_SIZE);
+}
+
+
+void init_zclient (struct thread_master *master, char *lm_zserv_path)
+{
+ if (lm_zserv_path)
+ zclient_serv_path_set(lm_zserv_path);
+
+ zclient = zclient_new(master);
+ /* zclient_init(zclient, ZEBRA_LABEL_MANAGER, 0); */
+ zclient->sock = -1;
+ zclient->redist_default = ZEBRA_ROUTE_LDP;
+ zclient->instance = instance;
+ if (zclient_socket_connect (zclient) < 0) {
+ printf ("Error connecting synchronous zclient!\n");
+ exit (1);
+ }
+
+}
+
+int main (int argc, char *argv[])
+{
+ struct thread_master *master;
+ struct thread thread;
+ int ret;
+
+ printf ("Sequence to be tested: %s\n", sequence);
+
+ master = thread_master_create();
+ init_zclient (master, ZSERV_PATH);
+
+ zebra_send_label_manager_connect ();
+
+ return 0;
+}
diff --git a/zebra/Makefile.am b/zebra/Makefile.am
index 1910e7b80..50bc065c6 100644
--- a/zebra/Makefile.am
+++ b/zebra/Makefile.am
@@ -45,7 +45,7 @@ zebra_SOURCES = \
$(othersrc) zebra_ptm.c zebra_rnh.c zebra_ptm_redistribute.c \
zebra_ns.c zebra_vrf.c zebra_static.c zebra_mpls.c zebra_mpls_vty.c \
$(protobuf_srcs) zebra_mroute.c \
- $(dev_srcs)
+ $(dev_srcs) label_manager.c
testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \
zebra_vty.c zebra_ptm.c zebra_routemap.c zebra_ns.c zebra_vrf.c \
@@ -60,7 +60,7 @@ noinst_HEADERS = \
rt_netlink.h zebra_fpm.h zebra_fpm_private.h zebra_rnh.h \
zebra_ptm_redistribute.h zebra_ptm.h zebra_routemap.h \
zebra_ns.h zebra_vrf.h ioctl_solaris.h zebra_static.h zebra_mpls.h \
- kernel_netlink.h if_netlink.h zebra_mroute.h
+ kernel_netlink.h if_netlink.h zebra_mroute.h label_manager.h
zebra_LDADD = $(otherobj) ../lib/libfrr.la $(LIBCAP) $(Q_FPM_PB_CLIENT_LDOPTS)
diff --git a/zebra/label_manager.c b/zebra/label_manager.c
new file mode 100644
index 000000000..2e96c4eba
--- /dev/null
+++ b/zebra/label_manager.c
@@ -0,0 +1,317 @@
+/*
+ * Label Manager for FRR
+ *
+ * Copyright (C) 2017 by Bingen Eguzkitza,
+ * Volta Networks Inc.
+ *
+ * This file is part of FreeRangeRouting (FRR)
+ *
+ * FRR 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, or (at your option) any
+ * later version.
+ *
+ * FRR 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 FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "zebra.h"
+#include "zserv.h"
+#include "lib/log.h"
+#include "lib/memory.h"
+#include "lib/mpls.h"
+#include "lib/network.h"
+#include "lib/stream.h"
+#include "lib/zclient.h"
+
+#include "label_manager.h"
+
+#define CONNECTION_DELAY 5
+
+struct label_manager lbl_mgr;
+
+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
+ */
+static struct zclient *zclient;
+bool lm_is_external;
+
+static void delete_label_chunk(void *val)
+{
+ XFREE(MTYPE_LM_CHUNK, val);
+}
+
+/**
+ * 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 src Input buffer from zserv
+ * @return 0 on success, -1 otherwise
+ */
+int zread_relay_label_manager_request(int cmd, struct zserv *zserv)
+{
+ struct stream *src, *dst;
+ int ret;
+
+ if (zclient->sock < 0) {
+ zlog_err("%s: Error relaying label chunk request: no zclient socket",
+ __func__);
+ return -1;
+ }
+ /* Send request to external label manager */
+ src = zserv->ibuf;
+ dst = zclient->obuf;
+
+ stream_copy(dst, src);
+
+ ret = writen(zclient->sock, dst->data, stream_get_endp(dst));
+ if (ret <= 0) {
+ zlog_err("%s: Error relaying label chunk request: %s", __func__,
+ strerror(errno));
+ return -1;
+ }
+ zlog_debug("%s: Label chunk request relayed. %d bytes sent", __func__,
+ ret);
+
+ /* Release label chunk has no response */
+ if (cmd == ZEBRA_RELEASE_LABEL_CHUNK)
+ return 0;
+
+ /* read response */
+ src = zclient->ibuf;
+ dst = zserv->obuf;
+
+ stream_reset(src);
+
+ u_int16_t size;
+ u_char marker;
+ u_char version;
+ vrf_id_t vrf_id;
+ u_int16_t resp_cmd;
+ ret = zclient_read_header(src, zclient->sock, &size, &marker, &version,
+ &vrf_id, &resp_cmd);
+ if (ret < 0) {
+ zlog_err("%s: Error reading label chunk response: %s", __func__,
+ strerror(errno));
+ return -1;
+ }
+ zlog_debug("%s: Label chunk response received, %d bytes", __func__,
+ size);
+
+ /* send response back */
+ stream_copy(dst, src);
+ stream_copy(zserv->obuf, zclient->ibuf);
+ ret = writen(zserv->sock, dst->data, stream_get_endp(dst));
+ if (ret <= 0) {
+ zlog_err("%s: Error sending label chunk response back: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+ zlog_debug("%s: Label chunk response (%d bytes) sent back", __func__,
+ ret);
+
+ return 0;
+}
+
+static int zclient_connect(struct thread *t)
+{
+ zclient->t_connect = NULL;
+
+ if (zclient->sock >= 0)
+ return 0;
+
+ if (zclient_socket_connect(zclient) < 0) {
+ zlog_err("Error connecting synchronous zclient!");
+ THREAD_TIMER_ON(zebrad.master, zclient->t_connect,
+ zclient_connect,
+ zclient, CONNECTION_DELAY);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * 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)
+{
+ if (lm_zserv_path)
+ zclient_serv_path_set(lm_zserv_path);
+
+ /* Set default values. */
+ zclient = zclient_new(zebrad.master);
+ zclient->sock = -1;
+ zclient->t_connect = NULL;
+ zclient_connect (NULL);
+}
+
+/**
+ * Init label manager (or proxy to an external one)
+ */
+void label_manager_init(char *lm_zserv_path)
+{
+ /* this is an actual label manager */
+ if (!lm_zserv_path) {
+ zlog_debug("Initializing own 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);
+ }
+}
+
+/**
+ * Core function, assigns label cunks
+ *
+ * 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 keep If set, avoid garbage collection
+ * @para size Size of the label chunk
+ * @return Pointer to the assigned label chunk
+ */
+struct label_manager_chunk *assign_label_chunk(u_char proto, u_short instance,
+ u_char keep, uint32_t size)
+{
+ struct label_manager_chunk *lmc;
+ struct listnode *node;
+
+ node = lbl_mgr.lc_list->head;
+ /* first check if there's one available */
+ for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
+ if (lmc->proto == NO_PROTO && lmc->end - lmc->start + 1 == size) {
+ lmc->proto = proto;
+ lmc->instance = instance;
+ lmc->keep = keep;
+ return lmc;
+ }
+ }
+ /* otherwise create a new one */
+ lmc = XCALLOC(MTYPE_LM_CHUNK, sizeof(struct label_manager_chunk));
+
+ if (list_isempty(lbl_mgr.lc_list))
+ lmc->start = MPLS_MIN_UNRESERVED_LABEL;
+ else
+ lmc->start = ((struct label_manager_chunk *)
+ listgetdata(listtail(lbl_mgr.lc_list)))->end + 1;
+ if (lmc->start > MPLS_MAX_UNRESERVED_LABEL - size + 1) {
+ zlog_err("Reached max labels. Start: %u, size: %u", lmc->start,
+ size);
+ return NULL;
+ }
+ lmc->end = lmc->start + size - 1;
+ lmc->proto = proto;
+ lmc->instance = instance;
+ lmc->keep = keep;
+ listnode_add(lbl_mgr.lc_list, lmc);
+
+ return lmc;
+}
+
+/**
+ * Core function, release no longer used label cunks
+ *
+ * @param proto Daemon protocol of client, to identify the owner
+ * @param instance Instance, to identify the owner
+ * @param start First label of the chunk
+ * @param end Last label of the chunk
+ * @return 0 on success, -1 otherwise
+ */
+int
+release_label_chunk(u_char proto, u_short instance, uint32_t start,
+ uint32_t end)
+{
+ struct listnode *node;
+ struct label_manager_chunk *lmc;
+ int ret = -1;
+
+ /* check that size matches */
+ zlog_debug("Releasing label chunk: %u - %u", start, end);
+ /* find chunk and disown */
+ for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
+ if (lmc->start != start)
+ continue;
+ if (lmc->end != end)
+ continue;
+ if (lmc->proto != proto || lmc->instance != instance) {
+ zlog_err("%s: Daemon mismatch!!", __func__);
+ continue;
+ }
+ lmc->proto = NO_PROTO;
+ lmc->instance = 0;
+ lmc->keep = 0;
+ ret = 0;
+ break;
+ }
+ if (ret != 0)
+ zlog_err("%s: Label chunk not released!!", __func__);
+
+ return ret;
+}
+
+/**
+ * Release label 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_chunks(u_char proto, u_short instance)
+{
+ struct listnode *node;
+ struct label_manager_chunk *lmc;
+ int count = 0;
+ int ret;
+
+ for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
+ if (lmc->proto == proto && lmc->instance == instance
+ && lmc->keep == 0) {
+ ret =
+ release_label_chunk(lmc->proto, lmc->instance,
+ lmc->start, lmc->end);
+ if (ret == 0)
+ count++;
+ }
+ }
+
+ zlog_debug("%s: Released %d label chunks", __func__, count);
+
+ return count;
+}
+
+void label_manager_close()
+{
+ list_delete(lbl_mgr.lc_list);
+}
diff --git a/zebra/label_manager.h b/zebra/label_manager.h
new file mode 100644
index 000000000..0c6a5ebc7
--- /dev/null
+++ b/zebra/label_manager.h
@@ -0,0 +1,74 @@
+/*
+ * Label Manager header
+ *
+ * Copyright (C) 2017 by Bingen Eguzkitza,
+ * Volta Networks Inc.
+ *
+ * This file is part of FreeRangeRouting (FRR)
+ *
+ * FRR 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, or (at your option) any
+ * later version.
+ *
+ * FRR 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 FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _LABEL_MANAGER_H
+#define _LABEL_MANAGER_H
+
+#include <stdint.h>
+
+#include "lib/linklist.h"
+#include "lib/thread.h"
+
+#define NO_PROTO 0
+
+/*
+ * Label chunk struct
+ * Client daemon which the chunk belongs to can be identified by either
+ * proto (daemon protocol) + instance.
+ * If the client then passes a non-empty value to keep field when it requests
+ * for chunks, the chunks won't be garbage collected and the client will be
+ * responsible of its release.
+ * Otherwise, if the keep field is not set (value 0) for the chunk, it will be
+ * automatically released when the client disconnects or when it reconnects
+ * (in case it died unexpectedly, we can know it's the same because it will have
+ * the same proto and instance values)
+ */
+struct label_manager_chunk {
+ u_char proto;
+ u_short instance;
+ u_char keep;
+ uint32_t start; /* First label of the chunk */
+ uint32_t end; /* Last label of the chunk */
+};
+
+/*
+ * Main label manager struct
+ * Holds a linked list of label chunks.
+ */
+struct label_manager {
+ struct list *lc_list;
+};
+
+bool lm_is_external;
+
+int zread_relay_label_manager_request(int cmd, struct zserv *zserv);
+void label_manager_init(char *lm_zserv_path);
+struct label_manager_chunk *assign_label_chunk(u_char proto, u_short instance,
+ u_char keep, uint32_t size);
+int release_label_chunk(u_char proto, u_short instance, uint32_t start,
+ uint32_t end);
+int release_daemon_chunks(u_char proto, u_short instance);
+void label_manager_close(void);
+
+#endif /* _LABEL_MANAGER_H */
diff --git a/zebra/main.c b/zebra/main.c
index 98177a423..26e66f961 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU General Public License
* along with GNU Zebra; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
+ * 02111-1307, USA.
*/
#include <zebra.h>
@@ -48,6 +48,7 @@
#include "zebra/zebra_ns.h"
#include "zebra/redistribute.h"
#include "zebra/zebra_mpls.h"
+#include "zebra/label_manager.h"
#define ZEBRA_PTM_SUPPORT
@@ -78,7 +79,7 @@ u_int32_t nl_rcvbufsize = 4194304;
#endif /* HAVE_NETLINK */
/* Command line options. */
-struct option longopts[] =
+struct option longopts[] =
{
{ "batch", no_argument, NULL, 'b'},
{ "allow_delete", no_argument, NULL, 'a'},
@@ -86,6 +87,7 @@ struct option longopts[] =
{ "fpm_format", required_argument, NULL, 'F'},
{ "socket", required_argument, NULL, 'z'},
{ "ecmp", required_argument, NULL, 'e'},
+ { "label_socket", no_argument, NULL, 'l'},
{ "retain", no_argument, NULL, 'r'},
#ifdef HAVE_NETLINK
{ "nl-bufsize", required_argument, NULL, 's'},
@@ -93,7 +95,7 @@ struct option longopts[] =
{ 0 }
};
-zebra_capabilities_t _caps_p [] =
+zebra_capabilities_t _caps_p [] =
{
ZCAP_NET_ADMIN,
ZCAP_SYS_ADMIN,
@@ -118,7 +120,7 @@ struct zebra_privs_t zserv_privs =
unsigned int multipath_num = MULTIPATH_NUM;
/* SIGHUP handler. */
-static void
+static void
sighup (void)
{
zlog_info ("SIGHUP received");
@@ -182,8 +184,8 @@ sigusr1 (void)
struct quagga_signal_t zebra_signals[] =
{
- {
- .signal = SIGHUP,
+ {
+ .signal = SIGHUP,
.handler = &sighup,
},
{
@@ -220,10 +222,13 @@ main (int argc, char **argv)
// int batch_mode = 0;
char *zserv_path = NULL;
char *fpm_format = NULL;
+ /* Socket to external label manager */
+ char *lblmgr_path = NULL;
+
frr_preinit(&zebra_di, argc, argv);
- frr_opt_add("bakF:z:e:r"
+ frr_opt_add("bakF:z:e:l:r"
#ifdef HAVE_NETLINK
"s:"
#endif
@@ -233,6 +238,7 @@ main (int argc, char **argv)
" -F, --fpm_format Set fpm format to 'netlink' or 'protobuf'\n"
" -z, --socket Set path of zebra socket\n"
" -e, --ecmp Specify ECMP to use.\n"
+ " -l, --label_socket Socket to external label manager\n"\
" -k, --keep_kernel Don't delete old routes which installed by zebra.\n"
" -r, --retain When program terminates, retain added route by zebra.\n"
#ifdef HAVE_NETLINK
@@ -247,7 +253,7 @@ main (int argc, char **argv)
if (opt == EOF)
break;
- switch (opt)
+ switch (opt)
{
case 0:
break;
@@ -274,6 +280,9 @@ main (int argc, char **argv)
case 'z':
zserv_path = optarg;
break;
+ case 'l':
+ lblmgr_path = optarg;
+ break;
case 'r':
retain_mode = 1;
break;
@@ -359,6 +368,9 @@ main (int argc, char **argv)
/* This must be done only after locking pidfile (bug #403). */
zebra_zserv_socket_init (zserv_path);
+ /* Init label manager */
+ label_manager_init (lblmgr_path);
+
frr_run (zebrad.master);
/* Not reached... */
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 064489acd..f9205a12c 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -55,6 +55,7 @@
#include "zebra/zebra_mpls.h"
#include "zebra/zebra_fpm.h"
#include "zebra/zebra_mroute.h"
+#include "zebra/label_manager.h"
/* Event list of zebra. */
enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE };
@@ -113,6 +114,9 @@ zebra_server_send_message(struct zserv *client)
if (client->t_suicide)
return -1;
+ if (client->is_synchronous)
+ return 0;
+
stream_set_getp(client->obuf, 0);
client->last_write_cmd = stream_getw_from(client->obuf, 6);
switch (buffer_write(client->wb, client->sock, STREAM_DATA(client->obuf),
@@ -1770,6 +1774,167 @@ zread_mpls_labels (int command, struct zserv *client, u_short length,
distance, out_label);
}
}
+/* Send response to a label manager connect request to client */
+static int
+zsend_label_manager_connect_response (struct zserv *client, vrf_id_t vrf_id, u_short result)
+{
+ struct stream *s;
+
+ s = client->obuf;
+ stream_reset (s);
+
+ zserv_create_header (s, ZEBRA_LABEL_MANAGER_CONNECT, vrf_id);
+
+ /* result */
+ stream_putc (s, result);
+
+ /* Write packet size. */
+ stream_putw_at (s, 0, stream_get_endp (s));
+
+ return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+static void
+zread_label_manager_connect (struct zserv *client, vrf_id_t vrf_id)
+{
+ struct stream *s;
+ /* type of protocol (lib/zebra.h) */
+ u_char proto;
+ u_short instance;
+
+ /* Get input stream. */
+ s = client->ibuf;
+
+ /* Get data. */
+ proto = stream_getc (s);
+ instance = stream_getw (s);
+
+ /* accept only dynamic routing protocols */
+ if ((proto >= ZEBRA_ROUTE_MAX)
+ || (proto <= ZEBRA_ROUTE_STATIC))
+ {
+ zlog_err ("client %d has wrong protocol %s",
+ client->sock, zebra_route_string(proto));
+ zsend_label_manager_connect_response (client, vrf_id, 1);
+ return;
+ }
+ zlog_notice ("client %d with instance %u connected as %s",
+ client->sock, instance, zebra_route_string(proto));
+ client->proto = proto;
+ client->instance = instance;
+
+ /*
+ Release previous labels of same protocol and instance.
+ This is done in case it restarted from an unexpected shutdown.
+ */
+ release_daemon_chunks (proto, instance);
+
+ zlog_debug (" Label Manager client connected: sock %d, proto %s, instance %u",
+ client->sock, zebra_route_string(proto), instance);
+ /* send response back */
+ zsend_label_manager_connect_response (client, vrf_id, 0);
+}
+/* Send response to a get label chunk request to client */
+static int
+zsend_assign_label_chunk_response (struct zserv *client, vrf_id_t vrf_id,
+ struct label_manager_chunk *lmc)
+{
+ struct stream *s;
+
+ s = client->obuf;
+ stream_reset (s);
+
+ zserv_create_header (s, ZEBRA_GET_LABEL_CHUNK, vrf_id);
+
+ if (lmc)
+ {
+ /* keep */
+ stream_putc (s, lmc->keep);
+ /* start and end labels */
+ stream_putl (s, lmc->start);
+ stream_putl (s, lmc->end);
+
+ }
+
+ /* Write packet size. */
+ stream_putw_at (s, 0, stream_get_endp (s));
+
+ return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+static void
+zread_get_label_chunk (struct zserv *client, vrf_id_t vrf_id)
+{
+ struct stream *s;
+ u_char keep;
+ uint32_t size;
+ struct label_manager_chunk *lmc;
+
+ /* Get input stream. */
+ s = client->ibuf;
+
+ /* Get data. */
+ keep = stream_getc (s);
+ size = stream_getl (s);
+
+ lmc = assign_label_chunk (client->proto, client->instance, keep, size);
+ if (!lmc)
+ zlog_err ("%s: Unable to assign Label Chunk of size %u", __func__, size);
+ else
+ zlog_debug ("Assigned Label Chunk %u - %u to %u",
+ lmc->start, lmc->end, keep);
+ /* send response back */
+ zsend_assign_label_chunk_response (client, vrf_id, lmc);
+}
+
+static void
+zread_release_label_chunk (struct zserv *client)
+{
+ struct stream *s;
+ uint32_t start, end;
+
+ /* Get input stream. */
+ s = client->ibuf;
+
+ /* Get data. */
+ start = stream_getl (s);
+ end = stream_getl (s);
+
+ release_label_chunk (client->proto, client->instance, start, end);
+}
+static void
+zread_label_manager_request (int cmd, struct zserv *client, vrf_id_t vrf_id)
+{
+ /* to avoid sending other messages like ZERBA_INTERFACE_UP */
+ if (cmd == ZEBRA_LABEL_MANAGER_CONNECT)
+ client->is_synchronous = 1;
+
+ /* external label manager */
+ if (lm_is_external)
+ {
+ if (zread_relay_label_manager_request (cmd, client) != 0)
+ zsend_label_manager_connect_response (client, vrf_id, 1);
+ }
+ /* this is a label manager */
+ else
+ {
+ if (cmd == ZEBRA_LABEL_MANAGER_CONNECT)
+ zread_label_manager_connect (client, vrf_id);
+ else
+ {
+ /* Sanity: don't allow 'unidentified' requests */
+ if (!client->proto)
+ {
+ zlog_err ("Got label request from an unidentified client");
+ return;
+ }
+ if (cmd == ZEBRA_GET_LABEL_CHUNK)
+ zread_get_label_chunk (client, vrf_id);
+ else if (cmd == ZEBRA_RELEASE_LABEL_CHUNK)
+ zread_release_label_chunk (client);
+ }
+ }
+}
/* Cleanup registered nexthops (across VRFs) upon client disconnect. */
static void
@@ -1807,6 +1972,9 @@ zebra_client_close (struct zserv *client)
/* Cleanup any registered nexthops - across all VRFs. */
zebra_client_close_cleanup_rnh (client);
+ /* Release Label Manager chunks */
+ release_daemon_chunks (client->proto, client->instance);
+
/* Close file descriptor. */
if (client->sock)
{
@@ -1868,6 +2036,9 @@ zebra_client_create (int sock)
client->ifinfo = vrf_bitmap_init ();
client->ridinfo = vrf_bitmap_init ();
+ /* by default, it's not a synchronous client */
+ client->is_synchronous = 0;
+
/* Add this client to linked list. */
listnode_add (zebrad.client_list, client);
@@ -2087,6 +2258,11 @@ zebra_client_read (struct thread *thread)
case ZEBRA_IPMR_ROUTE_STATS:
zebra_ipmr_route_stats (client, sock, length, zvrf);
break;
+ case ZEBRA_LABEL_MANAGER_CONNECT:
+ case ZEBRA_GET_LABEL_CHUNK:
+ case ZEBRA_RELEASE_LABEL_CHUNK:
+ zread_label_manager_request (command, client, vrf_id);
+ break;
default:
zlog_info ("Zebra received unknown command %d", command);
break;
diff --git a/zebra/zserv.h b/zebra/zserv.h
index 21cf1004b..9e3473823 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -78,6 +78,7 @@ struct zserv
/* client's protocol */
u_char proto;
u_short instance;
+ u_char is_synchronous;
/* Statistics */
u_int32_t redist_v4_add_cnt;