diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 37d532f56b..4fff339b85 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1550,8 +1550,7 @@ bgp_zebra_announce (struct bgp_node *rn, struct prefix *p, struct bgp_info *info if (!ifindex) { if (info->peer->conf_if || info->peer->ifname) - ifindex = ifname2ifindex_vrf (info->peer->conf_if ? info->peer->conf_if : - info->peer->ifname, bgp->vrf_id); + ifindex = if_nametoindex (info->peer->conf_if ? info->peer->conf_if : info->peer->ifname); else if (info->peer->nexthop.ifp) ifindex = info->peer->nexthop.ifp->ifindex; } diff --git a/ldpd/lde.c b/ldpd/lde.c index bef35f3194..8d2a9dd9dc 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -1623,6 +1623,8 @@ zclient_sync_init(u_short instance) log_warnx("Error connecting synchronous zclient!"); sleep(1); } + /* make socket non-blocking */ + sock_set_nonblock(zclient_sync->sock); /* Connect to label manager */ while (lm_label_manager_connect(zclient_sync) != 0) { @@ -1647,8 +1649,6 @@ lde_get_label_chunk(void) ret = lm_get_label_chunk(zclient_sync, 0, CHUNK_SIZE, &start, &end); 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 9823bc8d99..a53e8112c8 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1512,6 +1512,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 * @@ -1527,11 +1568,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"); @@ -1571,20 +1607,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; } @@ -1608,11 +1639,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) @@ -1651,18 +1677,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 */ + if (zclient_read_sync_response (zclient, ZEBRA_GET_LABEL_CHUNK) != 0) + return -1; + 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); - /* keep */ response_keep = stream_getc(s); /* start and end labels */ @@ -1670,18 +1688,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 cbb35631ac..508ba5b923 100644 --- a/zebra/label_manager.c +++ b/zebra/label_manager.c @@ -55,6 +55,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. @@ -63,19 +137,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; @@ -86,6 +166,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__, @@ -95,43 +176,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; @@ -140,11 +193,15 @@ static int zclient_connect(struct thread *t) if (zclient_socket_connect(zclient) < 0) { zlog_err("Error connecting synchronous zclient!"); - thread_add_timer(zebrad.master, zclient_connect, zclient, + thread_add_timer(zebrad.master, lm_zclient_connect, zclient, CONNECTION_DELAY, &zclient->t_connect); return -1; } + /* make socket non-blocking */ + if (set_nonblocking(zclient->sock) < 0) + zlog_warn("%s: set_nonblocking(%d) failed", __func__, zclient->sock); + return 0; } @@ -163,7 +220,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 a68c301f16..b7d6118a0e 100644 --- a/zebra/label_manager.h +++ b/zebra/label_manager.h @@ -61,7 +61,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 a59ef3031d..76c0756ada 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -2045,10 +2045,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 {