lm: Make relay label manager async

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 <bingen@voltanet.io>
This commit is contained in:
ßingen 2017-04-26 11:50:21 +02:00
parent 42025b43f2
commit 5c7ef8dc4f
5 changed files with 159 additions and 85 deletions

View File

@ -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;
}

View File

@ -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 */
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 */
@ -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) ",

View File

@ -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);
}
/**

View File

@ -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);

View File

@ -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
{