summaryrefslogtreecommitdiff
path: root/zebra/zserv.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zserv.c')
-rw-r--r--zebra/zserv.c176
1 files changed, 159 insertions, 17 deletions
diff --git a/zebra/zserv.c b/zebra/zserv.c
index d447d065..e27db449 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -49,6 +49,8 @@ list client_list;
int rtm_table_default = 0;
void zebra_event (enum event event, int sock, struct zserv *client);
+
+extern struct thread_master *master;
/* For logging of zebra meesages. */
char *zebra_command_str [] =
@@ -74,6 +76,103 @@ char *zebra_command_str [] =
"ZEBRA_IPV6_IMPORT_LOOKUP"
};
+struct zebra_message_queue
+{
+ struct nsm_message_queue *next;
+ struct nsm_message_queue *prev;
+
+ u_char *buf;
+ u_int16_t length;
+ u_int16_t written;
+};
+
+struct thread *t_write;
+struct fifo message_queue;
+
+int
+zebra_server_dequeue (struct thread *t)
+{
+ int sock;
+ int nbytes;
+ struct zebra_message_queue *queue;
+
+ sock = THREAD_FD (t);
+ t_write = NULL;
+
+ queue = (struct zebra_message_queue *) FIFO_HEAD (&message_queue);
+ if (queue)
+ {
+ nbytes = write (sock, queue->buf + queue->written,
+ queue->length - queue->written);
+
+ if (nbytes <= 0)
+ {
+ if (errno != EAGAIN)
+ return -1;
+ }
+ else if (nbytes != (queue->length - queue->written))
+ {
+ queue->written += nbytes;
+ }
+ else
+ {
+ FIFO_DEL (queue);
+ XFREE (MTYPE_TMP, queue->buf);
+ XFREE (MTYPE_TMP, queue);
+ }
+ }
+
+ if (FIFO_TOP (&message_queue))
+ THREAD_WRITE_ON (master, t_write, zebra_server_dequeue, NULL, sock);
+
+ return 0;
+}
+
+/* Enqueu message. */
+void
+zebra_server_enqueue (int sock, u_char *buf, unsigned long length,
+ unsigned long written)
+{
+ struct zebra_message_queue *queue;
+
+ queue = XCALLOC (MTYPE_TMP, sizeof (struct zebra_message_queue));
+ queue->buf = XMALLOC (MTYPE_TMP, length);
+ memcpy (queue->buf, buf, length);
+ queue->length = length;
+ queue->written = written;
+
+ FIFO_ADD (&message_queue, queue);
+
+ THREAD_WRITE_ON (master, t_write, zebra_server_dequeue, NULL, sock);
+}
+
+int
+zebra_server_send_message (int sock, u_char *buf, unsigned long length)
+{
+ int nbytes;
+
+ if (FIFO_TOP (&message_queue))
+ {
+ zebra_server_enqueue (sock, buf, length, 0);
+ return 0;
+ }
+
+ /* Send message. */
+ nbytes = write (sock, buf, length);
+
+ if (nbytes <= 0)
+ {
+ if (errno == EAGAIN)
+ zebra_server_enqueue (sock, buf, length, 0);
+ else
+ return -1;
+ }
+ else if (nbytes != length)
+ zebra_server_enqueue (sock, buf, length, nbytes);
+
+ return 0;
+}
+
/* Interface is added. Send ZEBRA_INTERFACE_ADD to client. */
int
zsend_interface_add (struct zserv *client, struct interface *ifp)
@@ -112,7 +211,9 @@ zsend_interface_add (struct zserv *client, struct interface *ifp)
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
- return writen (client->sock, s->data, stream_get_endp (s));
+ zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
+
+ return 0;
}
/* Interface deletion from zebra daemon. */
@@ -144,7 +245,9 @@ zsend_interface_delete (struct zserv *client, struct interface *ifp)
/* Write packet length. */
stream_putw_at (s, 0, stream_get_endp (s));
- return writen (client->sock, s->data, stream_get_endp (s));
+ zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
+
+ return 0;
}
/* Interface address is added. Send ZEBRA_INTERFACE_ADDRESS_ADD to the
@@ -190,7 +293,9 @@ zsend_interface_address_add (struct zserv *client, struct interface *ifp,
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
- return writen (client->sock, s->data, stream_get_endp (s));
+ zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
+
+ return 0;
}
/* Interface address is deleted. Send ZEBRA_INTERFACE_ADDRESS_DELETE
@@ -234,7 +339,9 @@ zsend_interface_address_delete (struct zserv *client, struct interface *ifp,
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
- return writen (client->sock, s->data, stream_get_endp (s));
+ zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
+
+ return 0;
}
int
@@ -267,7 +374,9 @@ zsend_interface_up (struct zserv *client, struct interface *ifp)
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
- return writen (client->sock, s->data, stream_get_endp (s));
+ zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
+
+ return 0;
}
int
@@ -300,7 +409,9 @@ zsend_interface_down (struct zserv *client, struct interface *ifp)
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
- return writen (client->sock, s->data, stream_get_endp (s));
+ zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
+
+ return 0;
}
int
@@ -357,7 +468,9 @@ zsend_ipv4_add_multipath (struct zserv *client, struct prefix *p,
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
- return writen (client->sock, s->data, stream_get_endp (s));
+ zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
+
+ return 0;
}
int
@@ -411,7 +524,9 @@ zsend_ipv4_delete_multipath (struct zserv *client, struct prefix *p,
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
- return writen (client->sock, s->data, stream_get_endp (s));
+ zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
+
+ return 0;
}
int
@@ -450,7 +565,9 @@ zsend_ipv4_add (struct zserv *client, int type, int flags,
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
- return writen (client->sock, s->data, stream_get_endp (s));
+ zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
+
+ return 0;
}
int
@@ -489,7 +606,9 @@ zsend_ipv4_delete (struct zserv *client, int type, int flags,
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
- return writen (client->sock, s->data, stream_get_endp (s));
+ zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
+
+ return 0;
}
#ifdef HAVE_IPV6
@@ -529,7 +648,9 @@ zsend_ipv6_add (struct zserv *client, int type, int flags,
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
- return writen (client->sock, s->data, stream_get_endp (s));
+ zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
+
+ return 0;
}
int
@@ -585,7 +706,9 @@ zsend_ipv6_add_multipath (struct zserv *client, struct prefix *p,
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
- return writen (client->sock, s->data, stream_get_endp (s));
+ zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
+
+ return 0;
}
int
@@ -624,7 +747,9 @@ zsend_ipv6_delete (struct zserv *client, int type, int flags,
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
- return writen (client->sock, s->data, stream_get_endp (s));
+ zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
+
+ return 0;
}
int
@@ -677,7 +802,9 @@ zsend_ipv6_delete_multipath (struct zserv *client, struct prefix *p,
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
- return writen (client->sock, s->data, stream_get_endp (s));
+ zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
+
+ return 0;
}
int
@@ -738,7 +865,9 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr)
stream_putw_at (s, 0, stream_get_endp (s));
- return writen (client->sock, s->data, stream_get_endp (s));
+ zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
+
+ return 0;
}
#endif /* HAVE_IPV6 */
@@ -795,7 +924,9 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr)
stream_putw_at (s, 0, stream_get_endp (s));
- return writen (client->sock, s->data, stream_get_endp (s));
+ zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
+
+ return 0;
}
int
@@ -851,7 +982,9 @@ zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p)
stream_putw_at (s, 0, stream_get_endp (s));
- return writen (client->sock, s->data, stream_get_endp (s));
+ zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
+
+ return 0;
}
/* Register zebra server interface information. Send current all
@@ -1434,6 +1567,7 @@ zebra_write (struct thread *thread)
int
zebra_accept (struct thread *thread)
{
+ int val;
int accept_sock;
int client_sock;
struct sockaddr_in client;
@@ -1450,6 +1584,11 @@ zebra_accept (struct thread *thread)
return -1;
}
+ /* Make client socket non-blocking. */
+
+ val = fcntl (client_sock, F_GETFL, 0);
+ fcntl (client_sock, F_SETFL, (val | O_NONBLOCK));
+
/* Create new zebra client. */
zebra_client_create (client_sock);
@@ -1807,4 +1946,7 @@ zebra_init ()
install_element (ENABLE_NODE, &show_ipv6_forwarding_cmd);
install_element (CONFIG_NODE, &no_ipv6_forwarding_cmd);
#endif /* HAVE_IPV6 */
+
+ FIFO_INIT(&message_queue);
+ t_write = NULL;
}