]> git.proxmox.com Git - mirror_frr.git/commitdiff
lib, zebra: support label chunk requests for SRGB
authorEmanuele Di Pascale <emanuele@voltanet.io>
Wed, 12 Jun 2019 14:33:12 +0000 (16:33 +0200)
committerEmanuele Di Pascale <emanuele@voltanet.io>
Wed, 10 Jul 2019 13:20:27 +0000 (15:20 +0200)
For SRGB, we need to support chunk requests starting at a
specific point in the label space, rather than just asking
for any sufficiently large chunk. To this purpose, we extend
the label manager api to request a chunk with a base value;
if the base is set to 0, the label manager will behave as it
currently does, i.e. fetching the first free chunk big enough
to satisfy the request.

update all the existing calls to get chunks from the label
manager so that they use MPLS_LABEL_BASE_ANY as the base
for the requested chunk

Signed-off-by: Emanuele Di Pascale <emanuele@voltanet.io>
bgpd/bgp_labelpool.c
ldpd/lde.c
lib/mpls.h
lib/zclient.c
lib/zclient.h
tests/test_lblmgr.c
zebra/label_manager.c
zebra/label_manager.h
zebra/zapi_msg.c

index 7518f02acf1de606fc301957389fd18389a3023a..feda0328bd5af13228421d60914f716df65f9d71 100644 (file)
@@ -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;
 
        /*
index 2aa96546ecfb269f23c4c7011f5baf99a1f15847..0ddf4f07d99ef386aff2cdfce4f05ab0be7f9c0e 100644 (file)
@@ -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;
index b140c8e3176dec3f5ce6b400effde9a3cb73f427..d7b56c47bd072267aafa6546fbf615f53e3289eb 100644 (file)
@@ -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,
index e9b4f5a58b1797473f6b6f368ff3746a086f105c..c02ae5d0e4a1dffc1d69c4ebcb41afcd25ce945f 100644 (file)
@@ -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));
 
index d651738687cea819b656453f531d665acd684365..be2ef69dc185c18898520cbd6f84472654f7ce2a 100644 (file)
@@ -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);
index e71e680fad5983c49eaf9eaf7caa7b68f9ee0216..530375823060167aa084a11edfa86c8eb55a9147 100644 (file)
@@ -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));
index 8295e461ccf635a8be414b2fec3d8b6ed4081835..6de94e63daefdcb2a3fc797470874fea13420fea 100644 (file)
@@ -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
index 3ea89fbfc3ec928c25119909bf70cc8370a57aee..f1b7d050cf43b86a7eb668ae20ed768418e4e096 100644 (file)
@@ -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);
index 61200806ba84ca81b9077771dd0be3963b51b25e..f1081def974644465f4d7d557797a1633b19a6c6 100644 (file)
@@ -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,