summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_labelpool.c7
-rw-r--r--ldpd/lde.c3
-rw-r--r--lib/mpls.h1
-rw-r--r--lib/zclient.c8
-rw-r--r--lib/zclient.h10
-rw-r--r--tests/test_lblmgr.c3
-rw-r--r--zebra/label_manager.c156
-rw-r--r--zebra/label_manager.h3
-rw-r--r--zebra/zapi_msg.c5
9 files changed, 165 insertions, 31 deletions
diff --git a/bgpd/bgp_labelpool.c b/bgpd/bgp_labelpool.c
index 7518f02ac..feda0328b 100644
--- a/bgpd/bgp_labelpool.c
+++ b/bgpd/bgp_labelpool.c
@@ -29,6 +29,7 @@
#include "skiplist.h"
#include "workqueue.h"
#include "zclient.h"
+#include "mpls.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_labelpool.h"
@@ -391,7 +392,8 @@ void bgp_lp_get(
if (lp_fifo_count(&lp->requests) > lp->pending_count) {
if (!zclient || zclient->sock < 0)
return;
- if (!zclient_send_get_label_chunk(zclient, 0, LP_CHUNK_SIZE))
+ if (!zclient_send_get_label_chunk(zclient, 0, LP_CHUNK_SIZE,
+ MPLS_LABEL_BASE_ANY))
lp->pending_count += LP_CHUNK_SIZE;
}
}
@@ -552,7 +554,8 @@ void bgp_lp_event_zebra_up(void)
return;
}
- zclient_send_get_label_chunk(zclient, 0, labels_needed);
+ zclient_send_get_label_chunk(zclient, 0, labels_needed,
+ MPLS_LABEL_BASE_ANY);
lp->pending_count = labels_needed;
/*
diff --git a/ldpd/lde.c b/ldpd/lde.c
index 2aa96546e..0ddf4f07d 100644
--- a/ldpd/lde.c
+++ b/ldpd/lde.c
@@ -1660,7 +1660,8 @@ lde_get_label_chunk(void)
uint32_t start, end;
debug_labels("getting label chunk (size %u)", CHUNK_SIZE);
- ret = lm_get_label_chunk(zclient_sync, 0, CHUNK_SIZE, &start, &end);
+ ret = lm_get_label_chunk(zclient_sync, 0, MPLS_LABEL_BASE_ANY,
+ CHUNK_SIZE, &start, &end);
if (ret < 0) {
log_warnx("Error getting label chunk!");
return -1;
diff --git a/lib/mpls.h b/lib/mpls.h
index b140c8e31..d7b56c47b 100644
--- a/lib/mpls.h
+++ b/lib/mpls.h
@@ -54,6 +54,7 @@ extern "C" {
#define MPLS_LABEL_RESERVED_MAX 15
#define MPLS_LABEL_UNRESERVED_MIN 16
#define MPLS_LABEL_UNRESERVED_MAX 1048575
+#define MPLS_LABEL_BASE_ANY 0
/* Default min and max SRGB label range */
/* Even if the SRGB allows to manage different Label space between routers,
diff --git a/lib/zclient.c b/lib/zclient.c
index e9b4f5a58..c02ae5d0e 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -1995,10 +1995,11 @@ int lm_label_manager_connect(struct zclient *zclient, int async)
* @param zclient Zclient used to connect to label manager (zebra)
* @param keep Avoid garbage collection
* @param chunk_size Amount of labels requested
+ * @param base Base for the label chunk. if MPLS_LABEL_BASE_ANY we do not care
* @result 0 on success, -1 otherwise
*/
int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
- uint32_t chunk_size)
+ uint32_t chunk_size, uint32_t base)
{
struct stream *s;
@@ -2018,6 +2019,7 @@ int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
stream_putw(s, zclient->instance);
stream_putc(s, keep);
stream_putl(s, chunk_size);
+ stream_putl(s, base);
/* Put length at the first point of the stream. */
stream_putw_at(s, 0, stream_get_endp(s));
@@ -2038,7 +2040,7 @@ int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
* @param end To write last assigned chunk label to
* @result 0 on success, -1 otherwise
*/
-int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
+int lm_get_label_chunk(struct zclient *zclient, uint8_t keep, uint32_t base,
uint32_t chunk_size, uint32_t *start, uint32_t *end)
{
int ret;
@@ -2063,6 +2065,8 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
stream_putc(s, keep);
/* chunk size */
stream_putl(s, chunk_size);
+ /* requested chunk base */
+ stream_putl(s, base);
/* Put length at the first point of the stream. */
stream_putw_at(s, 0, stream_get_endp(s));
diff --git a/lib/zclient.h b/lib/zclient.h
index d65173868..be2ef69dc 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -609,15 +609,13 @@ extern struct interface *zebra_interface_link_params_read(struct stream *s,
vrf_id_t vrf_id);
extern size_t zebra_interface_link_params_write(struct stream *,
struct interface *);
-extern int zclient_send_get_label_chunk(
- struct zclient *zclient,
- uint8_t keep,
- uint32_t chunk_size);
+extern int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
+ uint32_t chunk_size, uint32_t base);
extern int lm_label_manager_connect(struct zclient *zclient, int async);
extern int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
- uint32_t chunk_size, uint32_t *start,
- uint32_t *end);
+ uint32_t base, 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);
extern int tm_table_manager_connect(struct zclient *zclient);
diff --git a/tests/test_lblmgr.c b/tests/test_lblmgr.c
index e71e680fa..530375823 100644
--- a/tests/test_lblmgr.c
+++ b/tests/test_lblmgr.c
@@ -80,7 +80,8 @@ static int zebra_send_get_label_chunk()
printf("Ask for label chunk \n");
- ret = lm_get_label_chunk(zclient, KEEP, CHUNK_SIZE, &start, &end);
+ ret = lm_get_label_chunk(zclient, KEEP, MPLS_LABEL_BASE_ANY, CHUNK_SIZE,
+ &start, &end);
if (ret != 0) {
fprintf(stderr, "Error %d requesting label chunk %s\n", ret,
strerror(errno));
diff --git a/zebra/label_manager.c b/zebra/label_manager.c
index 8295e461c..6de94e63d 100644
--- a/zebra/label_manager.c
+++ b/zebra/label_manager.c
@@ -386,8 +386,112 @@ void label_manager_init(char *lm_zserv_path)
hook_register(zserv_client_close, release_daemon_label_chunks);
}
+/* 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)
+{
+ /* alloc chunk, fill it and return it */
+ struct label_manager_chunk *lmc =
+ XCALLOC(MTYPE_LM_CHUNK, sizeof(struct label_manager_chunk));
+
+ lmc->start = start;
+ lmc->end = end;
+ lmc->proto = proto;
+ lmc->instance = instance;
+ lmc->keep = keep;
+
+ return lmc;
+}
+
+/* attempt to get a specific label chunk */
+struct label_manager_chunk *
+assign_specific_label_chunk(uint8_t proto, unsigned short instance,
+ uint8_t keep, uint32_t size, uint32_t base)
+{
+ struct label_manager_chunk *lmc;
+ struct listnode *node, *next = NULL;
+ struct listnode *first_node = NULL;
+ struct listnode *last_node = NULL;
+ struct listnode *insert_node = NULL;
+
+ /* precompute last label from base and size */
+ uint32_t end = base + size - 1;
+
+ /* sanities */
+ if ((base < MPLS_LABEL_UNRESERVED_MIN)
+ || (end > MPLS_LABEL_UNRESERVED_MAX)) {
+ zlog_err("Invalid LM request arguments: base: %u, size: %u",
+ base, size);
+ return NULL;
+ }
+
+ /* Scan the existing chunks to see if the requested range of labels
+ * falls inside any of such chunks */
+ for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
+
+ /* skip chunks for labels < base */
+ if (base > lmc->end)
+ continue;
+
+ /* requested range is not covered by any existing, free chunk.
+ * Therefore, need to insert a chunk */
+ if ((end < lmc->start) && !first_node) {
+ insert_node = node;
+ break;
+ }
+
+ if (!first_node)
+ first_node = node;
+
+ /* if chunk is used, cannot honor request */
+ if (lmc->proto != NO_PROTO)
+ return NULL;
+
+ if (end < lmc->end) {
+ last_node = node;
+ break;
+ }
+ }
+
+ /* insert chunk between existing chunks */
+ if (insert_node) {
+ lmc = create_label_chunk(proto, instance, keep, base, end);
+ listnode_add_before(lbl_mgr.lc_list, insert_node, lmc);
+ return lmc;
+ }
+
+ if (first_node) {
+ /* get node past the last one, if there */
+ if (last_node)
+ last_node = listnextnode(last_node);
+
+ /* delete node coming after the above chunk whose labels are
+ * included in the previous one */
+ for (node = first_node; node && (node != last_node);
+ node = next) {
+ next = listnextnode(node);
+ list_delete_node(lbl_mgr.lc_list, node);
+ }
+
+ lmc = create_label_chunk(proto, instance, keep, base, end);
+ if (last_node)
+ listnode_add_before(lbl_mgr.lc_list, last_node, lmc);
+ else
+ listnode_add(lbl_mgr.lc_list, lmc);
+
+ return lmc;
+ } else {
+ /* create a new chunk past all the existing ones and link at
+ * tail */
+ lmc = create_label_chunk(proto, instance, keep, base, end);
+ listnode_add(lbl_mgr.lc_list, lmc);
+ return lmc;
+ }
+}
+
/**
- * Core function, assigns label cunks
+ * Core function, assigns label chunks
*
* It first searches through the list to check if there's one available
* (previously released). Otherwise it creates and assigns a new one
@@ -395,15 +499,26 @@ void label_manager_init(char *lm_zserv_path)
* @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
+ * @param size Size of the label chunk
+ * @param base Desired starting label of the chunk; if MPLS_LABEL_BASE_ANY it does not apply
+ * @return Pointer to the assigned label chunk, or NULL if the request could not be satisfied
*/
struct label_manager_chunk *assign_label_chunk(uint8_t proto,
unsigned short instance,
- uint8_t keep, uint32_t size)
+ uint8_t keep, uint32_t size,
+ uint32_t base)
{
struct label_manager_chunk *lmc;
struct listnode *node;
+ uint32_t prev_end = 0;
+
+ /* handle chunks request with a specific base label */
+ if (base != MPLS_LABEL_BASE_ANY)
+ return assign_specific_label_chunk(proto, instance, keep, size,
+ base);
+
+ /* appease scan-build, who gets confused by the use of macros */
+ assert(lbl_mgr.lc_list);
/* first check if there's one available */
for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
@@ -414,35 +529,44 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,
lmc->keep = keep;
return lmc;
}
+ /* check if we hadve a "hole" behind us that we can squeeze into
+ */
+ if ((lmc->start > prev_end)
+ && (lmc->start - prev_end >= size)) {
+ lmc = create_label_chunk(proto, instance, keep,
+ prev_end + 1, prev_end + size);
+ listnode_add_before(lbl_mgr.lc_list, node, lmc);
+ return lmc;
+ }
+ prev_end = lmc->end;
}
/* otherwise create a new one */
- lmc = XCALLOC(MTYPE_LM_CHUNK, sizeof(struct label_manager_chunk));
+ uint32_t start_free;
if (list_isempty(lbl_mgr.lc_list))
- lmc->start = MPLS_LABEL_UNRESERVED_MIN;
+ start_free = MPLS_LABEL_UNRESERVED_MIN;
else
- lmc->start = ((struct label_manager_chunk *)listgetdata(
+ start_free = ((struct label_manager_chunk *)listgetdata(
listtail(lbl_mgr.lc_list)))
->end
+ 1;
- if (lmc->start > MPLS_LABEL_UNRESERVED_MAX - size + 1) {
+
+ if (start_free > MPLS_LABEL_UNRESERVED_MAX - size + 1) {
flog_err(EC_ZEBRA_LM_EXHAUSTED_LABELS,
- "Reached max labels. Start: %u, size: %u", lmc->start,
+ "Reached max labels. Start: %u, size: %u", start_free,
size);
- XFREE(MTYPE_LM_CHUNK, lmc);
return NULL;
}
- lmc->end = lmc->start + size - 1;
- lmc->proto = proto;
- lmc->instance = instance;
- lmc->keep = keep;
- listnode_add(lbl_mgr.lc_list, lmc);
+ /* create chunk and link at tail */
+ lmc = create_label_chunk(proto, instance, keep, start_free,
+ start_free + size - 1);
+ listnode_add(lbl_mgr.lc_list, lmc);
return lmc;
}
/**
- * Core function, release no longer used label cunks
+ * Core function, release no longer used label chunks
*
* @param proto Daemon protocol of client, to identify the owner
* @param instance Instance, to identify the owner
diff --git a/zebra/label_manager.h b/zebra/label_manager.h
index 3ea89fbfc..f1b7d050c 100644
--- a/zebra/label_manager.h
+++ b/zebra/label_manager.h
@@ -72,7 +72,8 @@ 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(uint8_t proto,
unsigned short instance,
- uint8_t keep, uint32_t size);
+ uint8_t keep, uint32_t size,
+ uint32_t base);
int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
uint32_t end);
int release_daemon_label_chunks(struct zserv *client);
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 61200806b..f1081def9 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -1927,7 +1927,7 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg,
{
struct stream *s;
uint8_t keep;
- uint32_t size;
+ uint32_t size, base;
struct label_manager_chunk *lmc;
uint8_t proto;
unsigned short instance;
@@ -1940,8 +1940,9 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg,
STREAM_GETW(s, instance);
STREAM_GETC(s, keep);
STREAM_GETL(s, size);
+ STREAM_GETL(s, base);
- lmc = assign_label_chunk(proto, instance, keep, size);
+ lmc = assign_label_chunk(proto, instance, keep, size, base);
if (!lmc)
flog_err(
EC_ZEBRA_LM_CANNOT_ASSIGN_CHUNK,