From 0e3b6a926a98a028fa9ed8a8a1d00b429f547c03 Mon Sep 17 00:00:00 2001 From: Emanuele Di Pascale Date: Wed, 12 Jun 2019 16:33:12 +0200 Subject: [PATCH 1/6] lib, zebra: support label chunk requests for SRGB 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 --- bgpd/bgp_labelpool.c | 7 +- ldpd/lde.c | 3 +- lib/mpls.h | 1 + lib/zclient.c | 8 ++- lib/zclient.h | 10 ++- tests/test_lblmgr.c | 3 +- zebra/label_manager.c | 156 +++++++++++++++++++++++++++++++++++++----- zebra/label_manager.h | 3 +- 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 7518f02acf..feda0328bd 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 2aa96546ec..0ddf4f07d9 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 b140c8e317..d7b56c47bd 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 e9b4f5a58b..c02ae5d0e4 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 d651738687..be2ef69dc1 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 e71e680fad..5303758230 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 8295e461cc..6de94e63da 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 3ea89fbfc3..f1b7d050cf 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 61200806ba..f1081def97 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, From f004f7c3cea1b0e68a6f150e52f387bf8509df5d Mon Sep 17 00:00:00 2001 From: Emanuele Di Pascale Date: Thu, 27 Jun 2019 10:59:22 +0200 Subject: [PATCH 2/6] lib, zebra: handle failure in get chunk when requesting a specific label chunk (e.g. for the SRGB), it might happen that we cannot get what we want. In this event, we must be prepared to receive a response with no label chunk. Without this fix, if the remote label manager was not able to alloate the chunk we requested, we would hang indefinitely trying to read data from the stream which was not there. Signed-off-by: Emanuele Di Pascale --- lib/zclient.c | 9 +++++++++ zebra/zapi_msg.c | 13 +++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/lib/zclient.c b/lib/zclient.c index c02ae5d0e4..6937700199 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2107,6 +2107,15 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep, uint32_t base, "Wrong instId (%u) in get chunk response Should be %u", instance, zclient->instance); + /* if we requested a specific chunk and it could not be allocated, the + * response message will end here + */ + if (!STREAM_READABLE(s)) { + zlog_info("Unable to assign Label Chunk to %s instance %u", + zebra_route_string(proto), instance); + return -1; + } + /* keep */ response_keep = stream_getc(s); /* start and end labels */ diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index f1081def97..198a47a21f 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -929,19 +929,20 @@ int zsend_pw_update(struct zserv *client, struct zebra_pw *pw) /* 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, + vrf_id_t vrf_id, uint8_t proto, + uint16_t instance, struct label_manager_chunk *lmc) { int ret; struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, vrf_id); + /* proto */ + stream_putc(s, proto); + /* instance */ + stream_putw(s, instance); if (lmc) { - /* proto */ - stream_putc(s, lmc->proto); - /* instance */ - stream_putw(s, lmc->instance); /* keep */ stream_putc(s, lmc->keep); /* start and end labels */ @@ -1953,7 +1954,7 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg, lmc->start, lmc->end, zebra_route_string(proto), instance); /* send response back */ - zsend_assign_label_chunk_response(client, vrf_id, lmc); + zsend_assign_label_chunk_response(client, vrf_id, proto, instance, lmc); stream_failure: return; From ff90cc95d510a314e1741357a945a9fabc8a22fb Mon Sep 17 00:00:00 2001 From: Emanuele Di Pascale Date: Fri, 28 Jun 2019 10:01:56 +0200 Subject: [PATCH 3/6] tests: remove test_lblmgr.c This is not part of the make check tests and it has been broken for a while, apparently. The way the label manager is coded makes it very hard to code unit tests, and testing the relay of requests to an external label manager is probably better done through a topotest, so remove this. Signed-off-by: Emanuele Di Pascale --- tests/test_lblmgr.c | 148 -------------------------------------------- 1 file changed, 148 deletions(-) delete mode 100644 tests/test_lblmgr.c diff --git a/tests/test_lblmgr.c b/tests/test_lblmgr.c deleted file mode 100644 index 5303758230..0000000000 --- a/tests/test_lblmgr.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * 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 this program; see the file COPYING; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#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; -unsigned 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, 0); - 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, MPLS_LABEL_BASE_ANY, 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) -{ - frr_zclient_addr(&zclient_addr, &zclient_addr_len, lm_zserv_path); - - zclient = zclient_new(master, &zclient_options_default); - /* 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(NULL); - init_zclient(master, ZSERV_PATH); - - zebra_send_label_manager_connect(); - - return 0; -} From e11d7c96d7de7f7117dc544f2e6a59a83335d185 Mon Sep 17 00:00:00 2001 From: Emanuele Di Pascale Date: Thu, 27 Jun 2019 10:11:35 +0200 Subject: [PATCH 4/6] zebra: label manager refactor in order to both streamline the code and allow users to define their own specialized versions of the LM api handlers, define hooks for the 4 main primitives offered by the label manager (i.e. connect, disconnect, get_chunk and release_chunk), and have the existing code be run in response to a hook_call. Additionally, have the responses to the requesting daemon be callable from an external API. Note that the proxy version of the label manager was a source of issues and hardly used in practice. With the new hooks, users with more complex requirements can simply plug in their own code to handle label distribution remotely, so there is no longer a reason to maintain this code. Signed-off-by: Emanuele Di Pascale --- zebra/label_manager.c | 439 +++++++++++++----------------------------- zebra/label_manager.h | 58 +++++- zebra/main.c | 11 +- zebra/zapi_msg.c | 72 +++---- zebra/zapi_msg.h | 10 + zebra/zserv.c | 25 --- zebra/zserv.h | 1 - 7 files changed, 227 insertions(+), 389 deletions(-) diff --git a/zebra/label_manager.c b/zebra/label_manager.c index 6de94e63da..03cfa572db 100644 --- a/zebra/label_manager.c +++ b/zebra/label_manager.c @@ -38,297 +38,67 @@ #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) +{ + hook_call(lm_client_connect, proto, instance, vrf_id); +} +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) +{ + hook_call(lm_get_chunk, lmc, proto, instance, keep, size, base, vrf_id); +} +void lm_release_chunk_call(uint8_t proto, uint16_t instance, uint32_t start, + uint32_t end) +{ + hook_call(lm_release_chunk, proto, instance, start, end); +} + +/* 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); + +void delete_label_chunk(void *val) { XFREE(MTYPE_LM_CHUNK, val); } -static int relay_response_back(void) -{ - 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; -} - -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) -{ - 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; -} - -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; -} - -/** - * 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) - 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); -} - /** * Release label chunks from a client. * @@ -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); } diff --git a/zebra/label_manager.h b/zebra/label_manager.h index f1b7d050cf..74e283e85e 100644 --- a/zebra/label_manager.h +++ b/zebra/label_manager.h @@ -28,6 +28,7 @@ #include "lib/linklist.h" #include "lib/thread.h" +#include "lib/hook.h" #include "zebra/zserv.h" @@ -57,6 +58,54 @@ struct label_manager_chunk { uint32_t end; /* Last label of the chunk */ }; +/* declare hooks for the basic API, so that it can be specialized or served + * externally. Also declare a hook when those functions have been registered, + * so that any external module wanting to replace those can react + */ + +DECLARE_HOOK(lm_client_connect, + (uint8_t proto, uint16_t instance, vrf_id_t vrf_id), + (proto, instance, vrf_id)); +DECLARE_HOOK(lm_client_disconnect, (uint8_t proto, uint16_t instance), + (proto, instance)); +DECLARE_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)); +DECLARE_HOOK(lm_release_chunk, + (uint8_t proto, uint16_t instance, uint32_t start, uint32_t end), + (proto, instance, start, end)); +DECLARE_HOOK(lm_cbs_inited, (), ()); + + +/* declare 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); +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); +void lm_release_chunk_call(uint8_t proto, uint16_t instance, uint32_t start, + uint32_t end); + +/* API for an external LM to return responses for requests */ +int lm_client_connect_response(uint8_t proto, uint16_t instance, + vrf_id_t vrf_id, uint8_t result); +int lm_get_chunk_response(struct label_manager_chunk *lmc, uint8_t proto, + uint16_t instance, vrf_id_t vrf_id); + +/* convenience function to allocate an lmc to be consumed by the above API */ +struct label_manager_chunk *create_label_chunk(uint8_t proto, + unsigned short instance, + uint8_t keep, uint32_t start, + uint32_t end); +void delete_label_chunk(void *val); + +/* register/unregister callbacks for hooks */ +void lm_hooks_register(void); +void lm_hooks_unregister(void); + /* * Main label manager struct * Holds a linked list of label chunks. @@ -65,18 +114,15 @@ struct label_manager { struct list *lc_list; }; -bool lm_is_external; - -int zread_relay_label_manager_request(int cmd, struct zserv *zserv, - struct stream *msg, vrf_id_t vrf_id); -void label_manager_init(char *lm_zserv_path); +void label_manager_init(void); struct label_manager_chunk *assign_label_chunk(uint8_t proto, unsigned short instance, 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); +int lm_client_disconnect_cb(struct zserv *client); +int release_daemon_label_chunks(uint8_t proto, unsigned short instance); void label_manager_close(void); #ifdef __cplusplus diff --git a/zebra/main.c b/zebra/main.c index 1947106750..84e83bc37e 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -92,7 +92,6 @@ struct option longopts[] = { {"keep_kernel", no_argument, NULL, 'k'}, {"socket", required_argument, NULL, 'z'}, {"ecmp", required_argument, NULL, 'e'}, - {"label_socket", no_argument, NULL, 'l'}, {"retain", no_argument, NULL, 'r'}, {"vrfdefaultname", required_argument, NULL, 'o'}, {"graceful_restart", required_argument, NULL, 'K'}, @@ -252,8 +251,6 @@ int main(int argc, char **argv) // int batch_mode = 0; char *zserv_path = NULL; char *vrf_default_name_configured = NULL; - /* Socket to external label manager */ - char *lblmgr_path = NULL; struct sockaddr_storage dummy; socklen_t dummylen; #if defined(HANDLE_ZAPI_FUZZING) @@ -270,7 +267,7 @@ int main(int argc, char **argv) frr_preinit(&zebra_di, argc, argv); frr_opt_add( - "baz:e:l:o:rK:" + "baz:e:o:rK:" #ifdef HAVE_NETLINK "s:n" #endif @@ -286,7 +283,6 @@ int main(int argc, char **argv) " -a, --allow_delete Allow other processes to delete zebra routes\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" " -r, --retain When program terminates, retain added route by zebra.\n" " -o, --vrfdefaultname Set default VRF name.\n" " -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n" @@ -341,9 +337,6 @@ int main(int argc, char **argv) exit(1); } break; - case 'l': - lblmgr_path = optarg; - break; case 'r': retain_mode = 1; break; @@ -451,7 +444,7 @@ int main(int argc, char **argv) zserv_start(zserv_path); /* Init label manager */ - label_manager_init(lblmgr_path); + label_manager_init(); /* RNH init */ zebra_rnh_init(); diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 198a47a21f..e018b9595c 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -57,7 +57,6 @@ #include "zebra/rtadv.h" #include "zebra/zebra_mpls.h" #include "zebra/zebra_mroute.h" -#include "zebra/label_manager.h" #include "zebra/zebra_vxlan.h" #include "zebra/rt.h" #include "zebra/zebra_pbr.h" @@ -928,10 +927,9 @@ int zsend_pw_update(struct zserv *client, struct zebra_pw *pw) } /* 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, uint8_t proto, - uint16_t instance, - struct label_manager_chunk *lmc) +int zsend_assign_label_chunk_response(struct zserv *client, vrf_id_t vrf_id, + uint8_t proto, uint16_t instance, + struct label_manager_chunk *lmc) { int ret; struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); @@ -959,9 +957,8 @@ static int zsend_assign_label_chunk_response(struct zserv *client, } /* 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, - unsigned short result) +int zsend_label_manager_connect_response(struct zserv *client, vrf_id_t vrf_id, + unsigned short result) { int ret; struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); @@ -1897,27 +1894,16 @@ static void zread_label_manager_connect(struct zserv *client, flog_err(EC_ZEBRA_TM_WRONG_PROTO, "client %d has wrong protocol %s", client->sock, zebra_route_string(proto)); - if (client->is_synchronous) - zsend_label_manager_connect_response(client, vrf_id, 1); + zsend_label_manager_connect_response(client, vrf_id, 1); return; } - zlog_notice("client %d with vrf %u instance %u connected as %s", - client->sock, vrf_id, instance, zebra_route_string(proto)); + + /* recall proto and instance in this socket */ 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_label_chunks(client); - - zlog_debug( - " Label Manager client connected: sock %d, proto %s, vrf %u instance %u", - client->sock, zebra_route_string(proto), vrf_id, instance); - /* send response back */ - if (client->is_synchronous) - zsend_label_manager_connect_response(client, vrf_id, 0); + /* call hook for connection using wrapper */ + lm_client_connect_call(proto, instance, vrf_id); stream_failure: return; @@ -1929,7 +1915,7 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg, struct stream *s; uint8_t keep; uint32_t size, base; - struct label_manager_chunk *lmc; + struct label_manager_chunk *lmc = NULL; uint8_t proto; unsigned short instance; @@ -1943,7 +1929,9 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg, STREAM_GETL(s, size); STREAM_GETL(s, base); - lmc = assign_label_chunk(proto, instance, keep, size, base); + /* call hook to get a chunk using wrapper */ + lm_get_chunk_call(&lmc, proto, instance, keep, size, base, vrf_id); + if (!lmc) flog_err( EC_ZEBRA_LM_CANNOT_ASSIGN_CHUNK, @@ -1953,8 +1941,6 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg, zlog_debug("Assigned Label Chunk %u - %u to %s instance %u", lmc->start, lmc->end, zebra_route_string(proto), instance); - /* send response back */ - zsend_assign_label_chunk_response(client, vrf_id, proto, instance, lmc); stream_failure: return; @@ -1976,33 +1962,23 @@ static void zread_release_label_chunk(struct zserv *client, struct stream *msg) STREAM_GETL(s, start); STREAM_GETL(s, end); - release_label_chunk(proto, instance, start, end); + /* call hook to release a chunk using wrapper */ + lm_release_chunk_call(proto, instance, start, end); stream_failure: return; } + static void zread_label_manager_request(ZAPI_HANDLER_ARGS) { - /* to avoid sending other messages like ZERBA_INTERFACE_UP */ - client->is_synchronous = hdr->command == - ZEBRA_LABEL_MANAGER_CONNECT; - - /* external label manager */ - if (lm_is_external) - zread_relay_label_manager_request(hdr->command, client, msg, - zvrf_id(zvrf)); - /* this is a label manager */ + if (hdr->command == ZEBRA_LABEL_MANAGER_CONNECT + || hdr->command == ZEBRA_LABEL_MANAGER_CONNECT_ASYNC) + zread_label_manager_connect(client, msg, zvrf_id(zvrf)); else { - if (hdr->command == ZEBRA_LABEL_MANAGER_CONNECT || - hdr->command == ZEBRA_LABEL_MANAGER_CONNECT_ASYNC) - zread_label_manager_connect(client, msg, zvrf_id(zvrf)); - else { - if (hdr->command == ZEBRA_GET_LABEL_CHUNK) - zread_get_label_chunk(client, msg, - zvrf_id(zvrf)); - else if (hdr->command == ZEBRA_RELEASE_LABEL_CHUNK) - zread_release_label_chunk(client, msg); - } + if (hdr->command == ZEBRA_GET_LABEL_CHUNK) + zread_get_label_chunk(client, msg, zvrf_id(zvrf)); + else if (hdr->command == ZEBRA_RELEASE_LABEL_CHUNK) + zread_release_label_chunk(client, msg); } } diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index d30fa2d0ef..884edfef04 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -29,6 +29,8 @@ #include "zebra/zserv.h" #include "zebra/zebra_pbr.h" #include "zebra/zebra_errors.h" +#include "zebra/label_manager.h" + #ifdef __cplusplus extern "C" { @@ -90,6 +92,14 @@ extern void zserv_nexthop_num_warn(const char *caller, const struct prefix *p, const unsigned int nexthop_num); extern void zsend_capabilities_all_clients(void); +extern int zsend_assign_label_chunk_response(struct zserv *client, + vrf_id_t vrf_id, uint8_t proto, + uint16_t instance, + struct label_manager_chunk *lmc); +extern int zsend_label_manager_connect_response(struct zserv *client, + vrf_id_t vrf_id, + unsigned short result); + #ifdef __cplusplus } diff --git a/zebra/zserv.c b/zebra/zserv.c index cb9ca6578b..70b4594813 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -535,28 +535,6 @@ static int zserv_process_messages(struct thread *thread) int zserv_send_message(struct zserv *client, struct stream *msg) { - /* - * This is a somewhat poorly named variable added with Zebra's portion - * of the label manager. That component does not use the regular - * zserv/zapi_msg interface for handling its messages, as the client - * itself runs in-process. Instead it uses synchronous writes on the - * zserv client's socket directly in the zread* handlers for its - * message types. Furthermore, it cannot handle the usual messages - * Zebra sends (such as those for interface changes) and so has added - * this flag and check here as a hack to suppress all messages that it - * does not explicitly know about. - * - * In any case this needs to be cleaned up at some point. - * - * See also: - * zread_label_manager_request - * zsend_label_manager_connect_response - * zsend_assign_label_chunk_response - * ... - */ - if (client->is_synchronous) - return 0; - pthread_mutex_lock(&client->obuf_mtx); { stream_fifo_push(client->obuf_fifo, msg); @@ -710,9 +688,6 @@ static struct zserv *zserv_client_create(int sock) } 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(zrouter.client_list, client); diff --git a/zebra/zserv.h b/zebra/zserv.h index 34965618f2..708ff1e226 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -98,7 +98,6 @@ struct zserv { /* client's protocol */ uint8_t proto; uint16_t instance; - uint8_t is_synchronous; /* Statistics */ uint32_t redist_v4_add_cnt; From dcfeb7a956b9737ea1ef5bd2eec14e7c4284bc1e Mon Sep 17 00:00:00 2001 From: Emanuele Di Pascale Date: Wed, 10 Jul 2019 15:20:14 +0200 Subject: [PATCH 5/6] ldpd: set default instance to 1 LDP opens two sockets to zebra, one through ldpd (always using instance 0) and another through lde (using whatever instance was set through the -n command line parameter). If no instance was set, both connections would use the same protocol and instance, making it impossible to distinguish them through zserv_find_client. This meant that a response to a lm connect would erroneously go to the wrong process. Fix this by having a default instance value of 1, in case the user does not specify a different one. Signed-off-by: Emanuele Di Pascale --- ldpd/ldpd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 9fccb085dd..a6f0519bd7 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -236,6 +236,9 @@ main(int argc, char *argv[]) " --ctl_socket Override ctl socket path\n" " -n, --instance Instance id\n"); + /* set default instance (to differentiate ldpd socket from lde one */ + init.instance = 1; + while (1) { int opt; From 0b0b502f08736f1e5470fd64b9c480c7cced46a1 Mon Sep 17 00:00:00 2001 From: Emanuele Di Pascale Date: Wed, 10 Jul 2019 15:50:22 +0200 Subject: [PATCH 6/6] tests: remove lm-proxy-topo1 topotest Signed-off-by: Emanuele Di Pascale --- tests/topotests/lm-proxy-topo1/ce1/bgpd.conf | 9 - tests/topotests/lm-proxy-topo1/ce1/zebra.conf | 11 - tests/topotests/lm-proxy-topo1/ce2/bgpd.conf | 9 - tests/topotests/lm-proxy-topo1/ce2/zebra.conf | 11 - .../lm-proxy-topo1/lm-proxy-topo1.dot | 102 --------- .../lm-proxy-topo1/lm-proxy-topo1.pdf | Bin 16393 -> 0 bytes tests/topotests/lm-proxy-topo1/lm/zebra.conf | 3 - tests/topotests/lm-proxy-topo1/p1/ldpd.conf | 9 - tests/topotests/lm-proxy-topo1/p1/ospfd.conf | 7 - tests/topotests/lm-proxy-topo1/p1/zebra.conf | 12 - tests/topotests/lm-proxy-topo1/pe1/bgpd.conf | 26 --- tests/topotests/lm-proxy-topo1/pe1/ldpd.conf | 8 - tests/topotests/lm-proxy-topo1/pe1/ospfd.conf | 6 - tests/topotests/lm-proxy-topo1/pe1/zebra.conf | 14 -- tests/topotests/lm-proxy-topo1/pe2/bgpd.conf | 26 --- tests/topotests/lm-proxy-topo1/pe2/ldpd.conf | 8 - tests/topotests/lm-proxy-topo1/pe2/ospfd.conf | 6 - tests/topotests/lm-proxy-topo1/pe2/zebra.conf | 14 -- .../lm-proxy-topo1/test_lm-proxy-topo1.py | 205 ------------------ 19 files changed, 486 deletions(-) delete mode 100644 tests/topotests/lm-proxy-topo1/ce1/bgpd.conf delete mode 100644 tests/topotests/lm-proxy-topo1/ce1/zebra.conf delete mode 100644 tests/topotests/lm-proxy-topo1/ce2/bgpd.conf delete mode 100644 tests/topotests/lm-proxy-topo1/ce2/zebra.conf delete mode 100644 tests/topotests/lm-proxy-topo1/lm-proxy-topo1.dot delete mode 100644 tests/topotests/lm-proxy-topo1/lm-proxy-topo1.pdf delete mode 100644 tests/topotests/lm-proxy-topo1/lm/zebra.conf delete mode 100644 tests/topotests/lm-proxy-topo1/p1/ldpd.conf delete mode 100644 tests/topotests/lm-proxy-topo1/p1/ospfd.conf delete mode 100644 tests/topotests/lm-proxy-topo1/p1/zebra.conf delete mode 100644 tests/topotests/lm-proxy-topo1/pe1/bgpd.conf delete mode 100644 tests/topotests/lm-proxy-topo1/pe1/ldpd.conf delete mode 100644 tests/topotests/lm-proxy-topo1/pe1/ospfd.conf delete mode 100644 tests/topotests/lm-proxy-topo1/pe1/zebra.conf delete mode 100644 tests/topotests/lm-proxy-topo1/pe2/bgpd.conf delete mode 100644 tests/topotests/lm-proxy-topo1/pe2/ldpd.conf delete mode 100644 tests/topotests/lm-proxy-topo1/pe2/ospfd.conf delete mode 100644 tests/topotests/lm-proxy-topo1/pe2/zebra.conf delete mode 100644 tests/topotests/lm-proxy-topo1/test_lm-proxy-topo1.py diff --git a/tests/topotests/lm-proxy-topo1/ce1/bgpd.conf b/tests/topotests/lm-proxy-topo1/ce1/bgpd.conf deleted file mode 100644 index 33cb3d3209..0000000000 --- a/tests/topotests/lm-proxy-topo1/ce1/bgpd.conf +++ /dev/null @@ -1,9 +0,0 @@ -debug bgp vpn label -! -router bgp 9101 - bgp router-id 10.1.1.2 - neighbor 10.1.1.1 remote-as 7777 - address-family ipv4 unicast - redistribute connected - exit-address-family -! diff --git a/tests/topotests/lm-proxy-topo1/ce1/zebra.conf b/tests/topotests/lm-proxy-topo1/ce1/zebra.conf deleted file mode 100644 index 7118cc6b88..0000000000 --- a/tests/topotests/lm-proxy-topo1/ce1/zebra.conf +++ /dev/null @@ -1,11 +0,0 @@ -debug zebra events -debug zebra packet -! -interface lo - ip address 66.1.0.1/32 -! -interface ce1-eth0 - ip address 10.1.1.2/30 -! -ip forwarding -! diff --git a/tests/topotests/lm-proxy-topo1/ce2/bgpd.conf b/tests/topotests/lm-proxy-topo1/ce2/bgpd.conf deleted file mode 100644 index 358be342a4..0000000000 --- a/tests/topotests/lm-proxy-topo1/ce2/bgpd.conf +++ /dev/null @@ -1,9 +0,0 @@ -debug bgp vpn label -! -router bgp 9102 - bgp router-id 10.1.2.2 - neighbor 10.1.2.1 remote-as 7777 - address-family ipv4 unicast - redistribute connected - exit-address-family -! diff --git a/tests/topotests/lm-proxy-topo1/ce2/zebra.conf b/tests/topotests/lm-proxy-topo1/ce2/zebra.conf deleted file mode 100644 index 8b4e3e31d7..0000000000 --- a/tests/topotests/lm-proxy-topo1/ce2/zebra.conf +++ /dev/null @@ -1,11 +0,0 @@ -debug zebra events -debug zebra packet -! -interface lo - ip address 66.1.0.2/32 -! -interface ce2-eth0 - ip address 10.1.2.2/30 -! -ip forwarding -! diff --git a/tests/topotests/lm-proxy-topo1/lm-proxy-topo1.dot b/tests/topotests/lm-proxy-topo1/lm-proxy-topo1.dot deleted file mode 100644 index 71e6f34ba0..0000000000 --- a/tests/topotests/lm-proxy-topo1/lm-proxy-topo1.dot +++ /dev/null @@ -1,102 +0,0 @@ -## Color coding: -######################### -## Main FRR: #f08080 red -## Switches: #d0e0d0 gray -## RIP: #19e3d9 Cyan -## RIPng: #fcb314 dark yellow -## OSPFv2: #32b835 Green -## OSPFv3: #19e3d9 Cyan -## ISIS IPv4 #fcb314 dark yellow -## ISIS IPv6 #9a81ec purple -## BGP IPv4 #eee3d3 beige -## BGP IPv6 #fdff00 yellow -##### Colors (see http://www.color-hex.com/) - -graph template { - label="Test Topology - Label Manager proxy"; - - # Routers - - lm [ shape=doubleoctagon, - label="label manager", - fillcolor="#f08080", - style=filled - ]; - ce1 [ - shape=doubleoctagon, - label="ce1", - fillcolor="#f08080", - style=filled - ]; - ce2 [ - shape=doubleoctagon - label="ce2", - fillcolor="#f08080", - style=filled - ]; - pe1 [ - shape=doubleoctagon, - label="pe1", - fillcolor="#f08080", - style=filled - ]; - pe2 [ - shape=doubleoctagon - label="pe2", - fillcolor="#f08080", - style=filled - ]; - p1 [ - shape=doubleoctagon - label="p1", - fillcolor="#f08080", - style=filled - ]; - - # Switches - - s1 [ - shape=oval, - label="s1\n10.1.1.0/30", - fillcolor="#d0e0d0", - style=filled - ]; - s2 [ - shape=oval, - label="s2\n77.0.1.0/24", - fillcolor="#d0e0d0", - style=filled - ]; - s3 [ - shape=oval, - label="s3\n77.0.2.0/24", - fillcolor="#d0e0d0", - style=filled - ]; - s4 [ - shape=oval, - label="s4\n10.1.2.0/30", - fillcolor="#d0e0d0", - style=filled - ]; - - # Connections - - ce1 -- s1 [label="eth0\n.2"]; - pe1 -- s1 [label="eth0\n.1"]; - - pe1 -- s2 [label="eth1\n.1"]; - p1 -- s2 [label="eth0\n.2"]; - - pe2 -- s3 [label="eth1\n.1"]; - p1 -- s3 [label="eth1\n.2"]; - - ce2 -- s4 [label="eth0\n.2"]; - pe2 -- s4 [label="eth0\n.1"]; - - lm -- ce1; - lm -- pe1; - lm -- p1; - lm -- pe2; - lm -- ce2; -} diff --git a/tests/topotests/lm-proxy-topo1/lm-proxy-topo1.pdf b/tests/topotests/lm-proxy-topo1/lm-proxy-topo1.pdf deleted file mode 100644 index 7f7e09ed0921c1a3c520b5a2abd8938d022e779b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16393 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 /proc/sys/net/mpls/platform_labels', - 'ip link add dev ' + vrf + ' type vrf table ' + vrf_table, - 'ip link set ' + vrf + ' up', - 'ip link set ' + eth_in + ' vrf ' + vrf, - 'echo 1 > /proc/sys/net/mpls/conf/' + vrf + '/input' - ] - vrf_destroy(router, vrf) - for cmd in cmds: - logger.info('[vrf_setup] cmd: ' + cmd) - out = router.run(cmd) - if out != None and len(out) > 0: - logger.info('[vrf_setup] "{}" error: out="{}"'.format(cmd, out)) - -def setup_module(mod): - "pytest environment setup" - - tgen = Topogen(NetworkTopo, mod.__name__) - tgen.start_topology() - - router_list = tgen.routers() - - # Load router configuration - - ldp_id = 1 - bgp_id = 101 - lm_sock = '../lm/label_mgr.sock' - - for rname, router in router_list.iteritems(): - if rname == 'lm' : - router.load_config( - TopoRouter.RD_ZEBRA, - os.path.join(CWD, '{}/zebra.conf'.format(rname)), - '-z ' + lm_sock - ) - continue - - rtype = ''.join([i for i in rname if not i.isdigit()]) - - router.load_config( - TopoRouter.RD_ZEBRA, - os.path.join(CWD, '{}/zebra.conf'.format(rname)), - '-l ' + lm_sock - ) - - if router.check_capability(TopoRouter.RD_ZEBRA, '--vrfwnetns') == False: - return pytest.skip('Skipping test: no VRF support') - - if rtype == 'ce' or rtype == 'pe': - if router.check_capability(TopoRouter.RD_BGP, '--int_num') == False: - return pytest.skip('Skipping test: no BGP LM support') - router.load_config( - TopoRouter.RD_BGP, - os.path.join(CWD, '{}/bgpd.conf'.format(rname)), - '-I %d' % bgp_id - ) - bgp_id += 1 - - if rtype == 'pe' or rtype == 'p': - router.load_config( - TopoRouter.RD_OSPF, - os.path.join(CWD, '{}/ospfd.conf'.format(rname)) - ) - router.load_config( - TopoRouter.RD_LDP, - os.path.join(CWD, '{}/ldpd.conf'.format(rname)), - '-n %d' % ldp_id - ) - ldp_id += 1 - - # Prepare VRF's - - router = tgen.gears['pe1'] - out = router.run('ip -h 2>&1 | grep vrf | wc -l') - if int(out) == 0: - return pytest.skip('Skipping test: ip/iproute2 has no VRF support') - - vrf_setup(tgen.gears['pe1'], 'pe1-eth0', vrf_name, '1') - vrf_setup(tgen.gears['pe2'], 'pe2-eth0', vrf_name, '1') - - # Start routers - - tgen.start_router(tgen.gears['lm']) - for rname, router in router_list.iteritems(): - if rname != 'lm': - tgen.start_router(router) - -def teardown_module(mod): - tgen = get_topogen() - for router in ['pe1', 'pe2']: - vrf_destroy(tgen.gears[router], vrf_name) - tgen.stop_topology() - -def test_lm_proxy(): - logger.info('Test: label manager (LDP and BGP)') - tgen = get_topogen() - - # Skip if previous fatal error condition is raised - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - cmd = 'show mpls ldp binding' - - router = tgen.gears['p1'] - - def check_labels(router, cmd): - output = router.vtysh_cmd(cmd, isjson=False) - logger.info('chk_labels [' + cmd + ']: ' + output) - return output.count('\n') - - test_func = partial(check_labels, router, cmd) - result, diff = topotest.run_and_expect(test_func, 12, count=6, wait=30) - assert result, 'wrong labels' - -if __name__ == '__main__': - args = ["-s"] + sys.argv[1:] - sys.exit(pytest.main(args)) -