mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-13 21:01:47 +00:00
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:
parent
42025b43f2
commit
5c7ef8dc4f
@ -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;
|
||||
}
|
||||
|
||||
|
100
lib/zclient.c
100
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 */
|
||||
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) ",
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user