From 5c7ef8dc4fee3521a225aec0a3d42912a5bfd247 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C3=9Fingen?= Date: Wed, 26 Apr 2017 11:50:21 +0200 Subject: [PATCH] lm: Make relay label manager async MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit To avoid blocking zebra when it's acting as a proxy for an external label manager. Besides: Fix get chunk reconnection. Socket was still being destroyed on failure, so next attempt would never work. Filter out unwanted messages in lm sync sock. Until LDE client sends ZEBRA_LABEL_MANAGER_CONNECT message, zserv doesn't know which kind of client it is, so it might enqueue unwanted messages like interface add, interface up, etc. Changes in this commit discard those messages in the client side in case they arrive before the expected response. Change function name for zclient_connect in label manager to avoid confusion with zclient one. Signed-off-by: ßingen --- ldpd/lde.c | 4 +- lib/zclient.c | 100 ++++++++++++++++++------------- zebra/label_manager.c | 133 ++++++++++++++++++++++++++++++------------ zebra/label_manager.h | 2 +- zebra/zserv.c | 5 +- 5 files changed, 159 insertions(+), 85 deletions(-) diff --git a/ldpd/lde.c b/ldpd/lde.c index d8a2924b31..36998e7cf8 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -140,6 +140,8 @@ zclient_sync_init(u_short instance) fprintf(stderr, "Error connecting synchronous zclient!\n"); lde_sleep(); } + /* make socket non-blocking */ + sock_set_nonblock(zclient_sync->sock); /* Connect to label manager */ while (lm_label_manager_connect (zclient_sync) != 0) { @@ -1596,8 +1598,6 @@ lde_get_label_chunk(void) if (ret < 0) { log_warnx("Error getting label chunk!"); - close(zclient_sync->sock); - zclient_sync->sock = -1; return -1; } diff --git a/lib/zclient.c b/lib/zclient.c index d2a5186315..6aea4bd0a3 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1465,6 +1465,47 @@ zebra_interface_vrf_update_read (struct stream *s, vrf_id_t vrf_id, *new_vrf_id = new_id; return ifp; } + +/* filter unwanted messages until the expected one arrives */ +static int +zclient_read_sync_response (struct zclient *zclient, u_int16_t expected_cmd) +{ + struct stream *s; + u_int16_t size; + u_char marker; + u_char version; + vrf_id_t vrf_id; + u_int16_t cmd; + fd_set readfds; + int ret; + + ret = 0; + cmd = expected_cmd + 1; + while (ret == 0 && cmd != expected_cmd) + { + s = zclient->ibuf; + stream_reset (s); + + /* wait until response arrives */ + FD_ZERO (&readfds); + FD_SET (zclient->sock, &readfds); + select (zclient->sock+1, &readfds, NULL, NULL, NULL); + if (!FD_ISSET(zclient->sock, &readfds)) + continue; + /* read response */ + ret = zclient_read_header (s, zclient->sock, &size, &marker, &version, + &vrf_id, &cmd); + if (zclient_debug) + zlog_debug ("%s: Response (%d bytes) received", __func__, size); + } + if (ret != 0) + { + zlog_err ("%s: Invalid Sync Message Reply", __func__); + return -1; + } + + return 0; +} /** * Connect to label manager in a syncronous way * @@ -1480,11 +1521,6 @@ lm_label_manager_connect (struct zclient *zclient) int ret; struct stream *s; u_char result; - u_int16_t size; - u_char marker; - u_char version; - vrf_id_t vrf_id; - u_int16_t cmd; if (zclient_debug) zlog_debug ("Connecting to Label Manager"); @@ -1524,20 +1560,15 @@ lm_label_manager_connect (struct zclient *zclient) zlog_debug ("%s: Label manager connect request (%d bytes) sent", __func__, ret); /* read response */ - s = zclient->ibuf; - stream_reset (s); + if (zclient_read_sync_response (zclient, ZEBRA_LABEL_MANAGER_CONNECT) != 0) + return -1; - ret = zclient_read_header (s, zclient->sock, &size, &marker, &version, - &vrf_id, &cmd); - if (ret != 0 || cmd != ZEBRA_LABEL_MANAGER_CONNECT) { - zlog_err ("%s: Invalid Label Manager Connect Message Reply Header", __func__); - return -1; - } /* result */ + s = zclient->ibuf; result = stream_getc(s); if (zclient_debug) - zlog_debug ("%s: Label Manager connect response (%d bytes) received, result %u", - __func__, size, result); + zlog_debug ("%s: Label Manager connect response received, result %u", + __func__, result); return (int)result; } @@ -1561,11 +1592,6 @@ lm_get_label_chunk (struct zclient *zclient, u_char keep, uint32_t chunk_size, { int ret; struct stream *s; - u_int16_t size; - u_char marker; - u_char version; - vrf_id_t vrf_id; - u_int16_t cmd; u_char response_keep; if (zclient_debug) @@ -1604,18 +1630,10 @@ lm_get_label_chunk (struct zclient *zclient, u_char keep, uint32_t chunk_size, zlog_debug ("%s: Label chunk request (%d bytes) sent", __func__, ret); /* read response */ - s = zclient->ibuf; - stream_reset (s); - - ret = zclient_read_header (s, zclient->sock, &size, &marker, &version, - &vrf_id, &cmd); - if (ret != 0 || cmd != ZEBRA_GET_LABEL_CHUNK) { - zlog_err ("%s: Invalid Get Label Chunk Message Reply Header", __func__); - return -1; - } - if (zclient_debug) - zlog_debug ("%s: Label chunk response (%d bytes) received", __func__, size); + if (zclient_read_sync_response (zclient, ZEBRA_GET_LABEL_CHUNK) != 0) + return -1; + s = zclient->ibuf; /* keep */ response_keep = stream_getc(s); /* start and end labels */ @@ -1623,18 +1641,20 @@ lm_get_label_chunk (struct zclient *zclient, u_char keep, uint32_t chunk_size, *end = stream_getl(s); /* not owning this response */ - if (keep != response_keep) { - zlog_err ("%s: Invalid Label chunk: %u - %u, keeps mismatch %u != %u", - __func__, *start, *end, keep, response_keep); - } + if (keep != response_keep) + { + zlog_err ("%s: Invalid Label chunk: %u - %u, keeps mismatch %u != %u", + __func__, *start, *end, keep, response_keep); + } /* sanity */ if (*start > *end || *start < MPLS_MIN_UNRESERVED_LABEL - || *end > MPLS_MAX_UNRESERVED_LABEL) { - zlog_err ("%s: Invalid Label chunk: %u - %u", __func__, - *start, *end); - return -1; - } + || *end > MPLS_MAX_UNRESERVED_LABEL) + { + zlog_err ("%s: Invalid Label chunk: %u - %u", __func__, + *start, *end); + return -1; + } if (zclient_debug) zlog_debug ("Label Chunk assign: %u - %u (%u) ", diff --git a/zebra/label_manager.c b/zebra/label_manager.c index 7dbb36edb8..08f3c3cfe9 100644 --- a/zebra/label_manager.c +++ b/zebra/label_manager.c @@ -56,6 +56,80 @@ static void delete_label_chunk(void *val) XFREE(MTYPE_LM_CHUNK, val); } +static int relay_response_back(struct zserv *zserv) +{ + int ret = 0; + struct stream *src, *dst; + u_int16_t size = 0; + u_char marker; + u_char version; + vrf_id_t vrf_id; + u_int16_t resp_cmd; + + src = zclient->ibuf; + dst = zserv->obuf; + + stream_reset(src); + + ret = zclient_read_header(src, zclient->sock, &size, &marker, &version, + &vrf_id, &resp_cmd); + if (ret < 0 && errno != EAGAIN) { + zlog_err("%s: Error reading Label Manager response: %s", __func__, + strerror(errno)); + return -1; + } + zlog_debug("%s: Label Manager response received, %d bytes", __func__, + size); + if (size == 0) + return -1; + + /* send response back */ + stream_copy(dst, src); + 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)); + return -1; + } + zlog_debug("%s: Label Manager response (%d bytes) sent back", __func__, + ret); + + 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); + + return ret; +} + +static int reply_error (int cmd, struct zserv *zserv, vrf_id_t vrf_id) +{ + struct stream *s; + + s = zserv->obuf; + stream_reset (s); + + zserv_create_header (s, cmd, vrf_id); + + /* result */ + stream_putc (s, 1); + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + return writen (zserv->sock, s->data, stream_get_endp (s)); + +} /** * Receive a request to get or release a label chunk and forward it to external * label manager. @@ -64,19 +138,25 @@ static void delete_label_chunk(void *val) * proxy. * * @param cmd Type of request (connect, get or release) - * @param src Input buffer from zserv + * @param zserv * @return 0 on success, -1 otherwise */ -int zread_relay_label_manager_request(int cmd, struct zserv *zserv) +int zread_relay_label_manager_request(int cmd, struct zserv *zserv, vrf_id_t vrf_id) { struct stream *src, *dst; - int ret; + int ret = 0; if (zclient->sock < 0) { zlog_err("%s: Error relaying label chunk request: no zclient socket", __func__); + reply_error (cmd, zserv, vrf_id); return -1; } + + /* in case there's any incoming message enqueued, read and forward it */ + while (ret == 0) + ret = relay_response_back(zserv); + /* Send request to external label manager */ src = zserv->ibuf; dst = zclient->obuf; @@ -87,6 +167,7 @@ int zread_relay_label_manager_request(int cmd, struct zserv *zserv) if (ret <= 0) { zlog_err("%s: Error relaying label chunk request: %s", __func__, strerror(errno)); + reply_error (cmd, zserv, vrf_id); return -1; } zlog_debug("%s: Label chunk request relayed. %d bytes sent", __func__, @@ -96,43 +177,15 @@ int zread_relay_label_manager_request(int cmd, struct zserv *zserv) if (cmd == ZEBRA_RELEASE_LABEL_CHUNK) return 0; - /* read response */ - src = zclient->ibuf; - dst = zserv->obuf; - - stream_reset(src); - - u_int16_t size; - u_char marker; - u_char version; - vrf_id_t vrf_id; - u_int16_t resp_cmd; - ret = zclient_read_header(src, zclient->sock, &size, &marker, &version, - &vrf_id, &resp_cmd); - if (ret < 0) { - zlog_err("%s: Error reading label chunk response: %s", __func__, - strerror(errno)); - return -1; - } - zlog_debug("%s: Label chunk response received, %d bytes", __func__, - size); - - /* send response back */ - stream_copy(dst, src); - stream_copy(zserv->obuf, zclient->ibuf); - ret = writen(zserv->sock, dst->data, stream_get_endp(dst)); - if (ret <= 0) { - zlog_err("%s: Error sending label chunk response back: %s", - __func__, strerror(errno)); - return -1; - } - zlog_debug("%s: Label chunk response (%d bytes) sent back", __func__, - ret); + /* make sure we listen to the response */ + if (!zclient->t_read) + zclient->t_read = + thread_add_read(zclient->master, lm_zclient_read, zserv, zclient->sock); return 0; } -static int zclient_connect(struct thread *t) +static int lm_zclient_connect(struct thread *t) { zclient->t_connect = NULL; @@ -142,11 +195,15 @@ static int zclient_connect(struct thread *t) if (zclient_socket_connect(zclient) < 0) { zlog_err("Error connecting synchronous zclient!"); THREAD_TIMER_ON(zebrad.master, zclient->t_connect, - zclient_connect, + lm_zclient_connect, zclient, CONNECTION_DELAY); return -1; } + /* make socket non-blocking */ + if (set_nonblocking(zclient->sock) < 0) + zlog_warn("%s: set_nonblocking(%d) failed", __func__, zclient->sock); + return 0; } @@ -165,7 +222,7 @@ static void lm_zclient_init(char *lm_zserv_path) zclient = zclient_new(zebrad.master); zclient->sock = -1; zclient->t_connect = NULL; - zclient_connect (NULL); + lm_zclient_connect(NULL); } /** diff --git a/zebra/label_manager.h b/zebra/label_manager.h index 0c6a5ebc7d..fd0b3b549b 100644 --- a/zebra/label_manager.h +++ b/zebra/label_manager.h @@ -62,7 +62,7 @@ struct label_manager { bool lm_is_external; -int zread_relay_label_manager_request(int cmd, struct zserv *zserv); +int zread_relay_label_manager_request(int cmd, struct zserv *zserv, vrf_id_t vrf_id); void label_manager_init(char *lm_zserv_path); struct label_manager_chunk *assign_label_chunk(u_char proto, u_short instance, u_char keep, uint32_t size); diff --git a/zebra/zserv.c b/zebra/zserv.c index 3477dc36d2..533678f16d 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1911,10 +1911,7 @@ zread_label_manager_request (int cmd, struct zserv *client, vrf_id_t vrf_id) /* external label manager */ if (lm_is_external) - { - if (zread_relay_label_manager_request (cmd, client) != 0) - zsend_label_manager_connect_response (client, vrf_id, 1); - } + zread_relay_label_manager_request (cmd, client, vrf_id); /* this is a label manager */ else { -- 2.39.5