diff options
-rw-r--r-- | bgpd/bgp_labelpool.c | 7 | ||||
-rw-r--r-- | ldpd/lde.c | 3 | ||||
-rw-r--r-- | lib/mpls.h | 1 | ||||
-rw-r--r-- | lib/zclient.c | 8 | ||||
-rw-r--r-- | lib/zclient.h | 10 | ||||
-rw-r--r-- | tests/test_lblmgr.c | 3 | ||||
-rw-r--r-- | zebra/label_manager.c | 156 | ||||
-rw-r--r-- | zebra/label_manager.h | 3 | ||||
-rw-r--r-- | zebra/zapi_msg.c | 5 |
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, |