From cb721084fd83394050624061027ae9cefa6bd7e9 Mon Sep 17 00:00:00 2001 From: Fredi Raspall Date: Fri, 27 Apr 2018 18:47:51 +0200 Subject: [PATCH] zebra: Fix label manager proxy mode. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The current implementation did not consider multiple clients to a label-manager acting as proxy, i.e. relaying messages to another label manager. Specifically, upon a client's request, it checked the socket & buffer from the actual label manager for pending responses and directly copìed them to the client --currently-- being served. As a result, if two clients (e.g. ldpd and bgpd) sent requests, it could happen that responses being 'on the wire' from the real label manager towards the proxy, where relayed to the wrong client. This patch, which requires all msgs to include a a proto & instance pair, lookups up the zserv client that a message (response) is to be relayed to. Signed-off-by: Fredi Raspall --- zebra/label_manager.c | 112 ++++++++++++++++++++++++++++++++---------- 1 file changed, 87 insertions(+), 25 deletions(-) diff --git a/zebra/label_manager.c b/zebra/label_manager.c index 4ae8fde0c2..1e69423dc9 100644 --- a/zebra/label_manager.c +++ b/zebra/label_manager.c @@ -59,7 +59,7 @@ static void delete_label_chunk(void *val) XFREE(MTYPE_LM_CHUNK, val); } -static int relay_response_back(struct zserv *zserv) +static int relay_response_back(void) { int ret = 0; struct stream *src, *dst; @@ -68,12 +68,18 @@ static int relay_response_back(struct zserv *zserv) 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; + /* input buffer with msg from label manager */ src = zclient->ibuf; dst = obuf; stream_reset(src); + /* parse header */ ret = zclient_read_header(src, zclient->sock, &size, &marker, &version, &vrf_id, &resp_cmd); if (ret < 0 && errno != EAGAIN) { @@ -81,36 +87,53 @@ static int relay_response_back(struct zserv *zserv) __func__, strerror(errno)); return -1; } - zlog_debug("%s: Label Manager response received, %d bytes", __func__, - size); + zlog_debug("Label Manager response received, %d bytes", size); if (size == 0) return -1; - /* send response back */ + /* 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 = zebra_find_client(proto, instance); + if (!zserv) { + zlog_err("Error sending LM response back: can't find client with proto %s, instance %u", + proto_str, instance); + return -1; + } + zlog_debug("Found client to relay LM msg to: %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) { - zlog_err("%s: Error sending Label Manager response back: %s", - __func__, strerror(errno)); + zlog_err("Error relaying Label Manager response to %s instance %u: %s", + proto_str, instance, strerror(errno)); return -1; } - zlog_debug("%s: Label Manager response (%d bytes) sent back", __func__, - ret); + zlog_debug("Relayed Label Manager response (%d bytes) to %s instance %u", + ret, proto_str, instance); return 0; } static int lm_zclient_read(struct thread *t) { - struct zserv *zserv; int ret; - /* Get socket to zebra. */ - zserv = THREAD_ARG(t); zclient->t_read = NULL; /* read response and send it back */ - ret = relay_response_back(zserv); + ret = relay_response_back(); return ret; } @@ -124,6 +147,10 @@ static int reply_error(int cmd, struct zserv *zserv, vrf_id_t vrf_id) zclient_create_header(s, cmd, vrf_id); + /* proto */ + stream_putc(s, zserv->proto); + /* instance */ + stream_putw(s, zserv->instance); /* result */ stream_putc(s, 1); @@ -149,36 +176,71 @@ static int reply_error(int cmd, struct zserv *zserv, vrf_id_t vrf_id) int zread_relay_label_manager_request(int cmd, struct zserv *zserv, struct stream *msg, vrf_id_t vrf_id) { - struct stream *src, *dst; + struct stream *dst; int ret = 0; + uint8_t proto; + const char *proto_str; + unsigned short instance; if (zclient->sock < 0) { - zlog_err( - "%s: Error relaying label chunk request: no zclient socket", - __func__); + zlog_err("Unable to relay label manager 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) { + zlog_warn("Client proto(%u) != msg proto(%u)", + zserv->proto, proto); + return -1; + } + + /* check & set client instance if unset */ + if (zserv->instance && zserv->instance != instance) { + zlog_err("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 */ while (ret == 0) - ret = relay_response_back(zserv); + ret = relay_response_back(); - /* Send request to external label manager */ - src = msg; + /* get the msg buffer used toward the 'master' Label Manager */ dst = zclient->obuf; - stream_copy(dst, src); + /* 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) { - zlog_err("%s: Error relaying label chunk request: %s", __func__, - strerror(errno)); + zlog_err("Error relaying label manager request from %s instance %u: %s", + proto_str, instance, strerror(errno)); reply_error(cmd, zserv, vrf_id); return -1; } - zlog_debug("%s: Label chunk request relayed. %d bytes sent", __func__, - ret); + zlog_debug("Relayed Label manager request (%d bytes) from %s instance %u", + ret, proto_str, instance); + /* Release label chunk has no response */ if (cmd == ZEBRA_RELEASE_LABEL_CHUNK) @@ -186,7 +248,7 @@ int zread_relay_label_manager_request(int cmd, struct zserv *zserv, /* make sure we listen to the response */ if (!zclient->t_read) - thread_add_read(zclient->master, lm_zclient_read, zserv, + thread_add_read(zclient->master, lm_zclient_read, NULL, zclient->sock, &zclient->t_read); return 0; -- 2.39.5