#include "log.h"
#include "zclient.h"
#include "privs.h"
+#include "network.h"
+#include "buffer.h"
#include "zebra/zserv.h"
#include "zebra/router-id.h"
extern struct zebra_privs_t zserv_privs;
\f
/* For logging of zebra meesages. */
-static char *zebra_command_str [] =
+static const char *zebra_command_str [] =
{
"NULL",
"ZEBRA_INTERFACE_ADD",
"ZEBRA_ROUTER_ID_UPDATE"
};
\f
-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;
+static void zebra_client_close (struct zserv *client);
-int
-zebra_server_dequeue (struct thread *t)
+static int
+zserv_delayed_close(struct thread *thread)
{
- 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 (zebrad.master, t_write, zebra_server_dequeue,
- NULL, sock);
+ struct zserv *client = THREAD_ARG(thread);
+ client->t_suicide = NULL;
+ zebra_client_close(client);
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 (zebrad.master, t_write, zebra_server_dequeue, NULL, sock);
-}
-
-int
-zebra_server_send_message (int sock, u_char *buf, unsigned long length)
+static int
+zserv_flush_data(struct thread *thread)
{
- int nbytes;
+ struct zserv *client = THREAD_ARG(thread);
- if (FIFO_TOP (&message_queue))
+ client->t_write = NULL;
+ if (client->t_suicide)
{
- zebra_server_enqueue (sock, buf, length, 0);
- return 0;
+ zebra_client_close(client);
+ return -1;
}
-
- /* Send message. */
- nbytes = write (sock, buf, length);
-
- if (nbytes <= 0)
+ switch (buffer_flush_available(client->wb, client->sock))
{
- if (errno == EAGAIN)
- zebra_server_enqueue (sock, buf, length, 0);
- else
- return -1;
+ case BUFFER_ERROR:
+ zlog_warn("%s: buffer_flush_available failed on zserv client fd %d, "
+ "closing", __func__, client->sock);
+ zebra_client_close(client);
+ break;
+ case BUFFER_PENDING:
+ client->t_write = thread_add_write(zebrad.master, zserv_flush_data,
+ client, client->sock);
+ break;
+ case BUFFER_EMPTY:
+ break;
}
- else if (nbytes != length)
- zebra_server_enqueue (sock, buf, length, nbytes);
+ return 0;
+}
+static int
+zebra_server_send_message(struct zserv *client)
+{
+ if (client->t_suicide)
+ return -1;
+ switch (buffer_write(client->wb, client->sock, STREAM_DATA(client->obuf),
+ stream_get_endp(client->obuf)))
+ {
+ case BUFFER_ERROR:
+ zlog_warn("%s: buffer_write failed to zserv client fd %d, closing",
+ __func__, client->sock);
+ /* Schedule a delayed close since many of the functions that call this
+ one do not check the return code. They do not allow for the
+ possibility that an I/O error may have caused the client to be
+ deleted. */
+ client->t_suicide = thread_add_event(zebrad.master, zserv_delayed_close,
+ client, 0);
+ return -1;
+ case BUFFER_EMPTY:
+ THREAD_OFF(client->t_write);
+ break;
+ case BUFFER_PENDING:
+ THREAD_WRITE_ON(zebrad.master, client->t_write,
+ zserv_flush_data, client, client->sock);
+ break;
+ }
return 0;
}
+static void
+zserv_create_header (struct stream *s, uint16_t cmd)
+{
+ /* length placeholder, caller can update */
+ stream_putw (s, ZEBRA_HEADER_SIZE);
+ stream_putc (s, ZEBRA_HEADER_MARKER);
+ stream_putc (s, ZSERV_VERSION);
+ stream_putw (s, cmd);
+}
+
/* Interface is added. Send ZEBRA_INTERFACE_ADD to client. */
/*
* This function is called in the following situations:
/* Check this client need interface information. */
if (! client->ifinfo)
- return -1;
+ return 0;
s = client->obuf;
stream_reset (s);
- /* Place holder for size. */
- stream_putw (s, 0);
-
/* Message type. */
- stream_putc (s, ZEBRA_INTERFACE_ADD);
+ zserv_create_header (s, ZEBRA_INTERFACE_ADD);
/* Interface information. */
stream_put (s, ifp->name, INTERFACE_NAMSIZ);
stream_putl (s, ifp->ifindex);
stream_putc (s, ifp->status);
- stream_putl (s, ifp->flags);
+ stream_putq (s, ifp->flags);
stream_putl (s, ifp->metric);
stream_putl (s, ifp->mtu);
stream_putl (s, ifp->mtu6);
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
- zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
-
- return 0;
+ return zebra_server_send_message(client);
}
/* Interface deletion from zebra daemon. */
-/*
- * This function is only called when support for
- * RTM_IFANNOUNCE or AF_NETLINK sockets (RTM_DELLINK message)
- * is available. It is not called on Solaris.
- */
-#if (defined(RTM_IFANNOUNCE) || defined(HAVE_NETLINK))
int
zsend_interface_delete (struct zserv *client, struct interface *ifp)
{
/* Check this client need interface information. */
if (! client->ifinfo)
- return -1;
+ return 0;
s = client->obuf;
stream_reset (s);
-
- /* Packet length placeholder. */
- stream_putw (s, 0);
-
+
+ zserv_create_header (s, ZEBRA_INTERFACE_DELETE);
+
/* Interface information. */
- stream_putc (s, ZEBRA_INTERFACE_DELETE);
stream_put (s, ifp->name, INTERFACE_NAMSIZ);
stream_putl (s, ifp->ifindex);
stream_putc (s, ifp->status);
- stream_putl (s, ifp->flags);
+ stream_putq (s, ifp->flags);
stream_putl (s, ifp->metric);
stream_putl (s, ifp->mtu);
stream_putl (s, ifp->mtu6);
/* Write packet length. */
stream_putw_at (s, 0, stream_get_endp (s));
- zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
-
- return 0;
+ return zebra_server_send_message (client);
}
-#endif /* (defined(RTM_IFANNOUNCE) || defined(HAVE_LINUX_RTNETLINK_H)) */
/* Interface address is added/deleted. Send ZEBRA_INTERFACE_ADDRESS_ADD or
* ZEBRA_INTERFACE_ADDRESS_DELETE to the client.
* |
* zebra_interface_address_delete_update
* ^ ^ ^
- * | | if_delete_update (not called on
- * | | Solaris)
+ * | | if_delete_update
+ * | |
* ip_address_uninstall connected_delete_ipv4
* [ipv6_addresss_uninstall] [connected_delete_ipv6]
* ^ ^
/* Check this client need interface information. */
if (! client->ifinfo)
- return -1;
+ return 0;
s = client->obuf;
stream_reset (s);
-
- /* Place holder for size. */
- stream_putw (s, 0);
-
- stream_putc (s, cmd);
+
+ zserv_create_header (s, cmd);
stream_putl (s, ifp->ifindex);
/* Interface address flag. */
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
- zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
-
- return 0;
+ return zebra_server_send_message(client);
}
/*
/* Check this client need interface information. */
if (! client->ifinfo)
- return -1;
+ return 0;
s = client->obuf;
stream_reset (s);
- /* Place holder for size. */
- stream_putw (s, 0);
-
- /* Zebra command. */
- stream_putc (s, cmd);
+ zserv_create_header (s, cmd);
/* Interface information. */
stream_put (s, ifp->name, INTERFACE_NAMSIZ);
stream_putl (s, ifp->ifindex);
stream_putc (s, ifp->status);
- stream_putl (s, ifp->flags);
+ stream_putq (s, ifp->flags);
stream_putl (s, ifp->metric);
stream_putl (s, ifp->mtu);
stream_putl (s, ifp->mtu6);
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
- zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
-
- return 0;
+ return zebra_server_send_message(client);
}
/*
int psize;
struct stream *s;
struct nexthop *nexthop;
- unsigned long nhnummark = 0;
+ unsigned long nhnummark = 0, messmark = 0;
int nhnum = 0;
- u_char zapi_flags = ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_IFINDEX;
+ u_char zapi_flags = 0;
s = client->obuf;
stream_reset (s);
-
- /* Place holder for size. */
- stream_putw (s, 0);
-
- /* Put command, type and nexthop. */
- stream_putc (s, cmd);
+
+ zserv_create_header (s, cmd);
+
+ /* Put type and nexthop. */
stream_putc (s, rib->type);
stream_putc (s, rib->flags);
-
- /*
- * XXX no need to set ZAPI_MESSAGE_NEXTHOP if we are going to
- * send empty nexthop?
- */
- if (cmd == ZEBRA_IPV4_ROUTE_ADD || ZEBRA_IPV6_ROUTE_ADD)
- zapi_flags |= ZAPI_MESSAGE_METRIC;
-
- stream_putc (s, zapi_flags);
+
+ /* marker for message flags field */
+ messmark = stream_get_endp (s);
+ stream_putc (s, 0);
/* Prefix. */
psize = PSIZE (p->prefixlen);
* is hard-coded.
*/
/* Nexthop */
+
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
{
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
{
- nhnummark = stream_get_putp (s);
- stream_putc (s, 1); /* placeholder */
+ SET_FLAG (zapi_flags, ZAPI_MESSAGE_NEXTHOP);
+ SET_FLAG (zapi_flags, ZAPI_MESSAGE_IFINDEX);
+
+ if (nhnummark == 0)
+ {
+ nhnummark = stream_get_endp (s);
+ stream_putc (s, 1); /* placeholder */
+ }
+
nhnum++;
switch(nexthop->type)
}
/* Metric */
- stream_putl (s, rib->metric);
-
+ if (cmd == ZEBRA_IPV4_ROUTE_ADD || ZEBRA_IPV6_ROUTE_ADD)
+ {
+ SET_FLAG (zapi_flags, ZAPI_MESSAGE_DISTANCE);
+ stream_putc (s, rib->distance);
+ SET_FLAG (zapi_flags, ZAPI_MESSAGE_METRIC);
+ stream_putl (s, rib->metric);
+ }
+
+ /* write real message flags value */
+ stream_putc_at (s, messmark, zapi_flags);
+
/* Write next-hop number */
if (nhnummark)
- stream_putw_at (s, nhnummark, nhnum);
+ stream_putc_at (s, nhnummark, nhnum);
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
- zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
-
- return 0;
+ return zebra_server_send_message(client);
}
#ifdef HAVE_IPV6
-int
+static int
zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr)
{
struct stream *s;
stream_reset (s);
/* Fill in result. */
- stream_putw (s, 0);
- stream_putc (s, ZEBRA_IPV6_NEXTHOP_LOOKUP);
+ zserv_create_header (s, ZEBRA_IPV6_NEXTHOP_LOOKUP);
stream_put (s, &addr, 16);
if (rib)
{
stream_putl (s, rib->metric);
num = 0;
- nump = s->putp;
+ nump = stream_get_endp(s);
stream_putc (s, 0);
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
stream_putw_at (s, 0, stream_get_endp (s));
- zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
-
- return 0;
+ return zebra_server_send_message(client);
}
#endif /* HAVE_IPV6 */
stream_reset (s);
/* Fill in result. */
- stream_putw (s, 0);
- stream_putc (s, ZEBRA_IPV4_NEXTHOP_LOOKUP);
+ zserv_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP);
stream_put_in_addr (s, &addr);
if (rib)
{
stream_putl (s, rib->metric);
num = 0;
- nump = s->putp;
+ nump = stream_get_endp(s);
stream_putc (s, 0);
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
stream_putw_at (s, 0, stream_get_endp (s));
- zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
-
- return 0;
+ return zebra_server_send_message(client);
}
static int
stream_reset (s);
/* Fill in result. */
- stream_putw (s, 0);
- stream_putc (s, ZEBRA_IPV4_IMPORT_LOOKUP);
+ zserv_create_header (s, ZEBRA_IPV4_IMPORT_LOOKUP);
stream_put_in_addr (s, &p->prefix);
if (rib)
{
stream_putl (s, rib->metric);
num = 0;
- nump = s->putp;
+ nump = stream_get_endp(s);
stream_putc (s, 0);
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
stream_putw_at (s, 0, stream_get_endp (s));
- zebra_server_send_message (client->sock, s->data, stream_get_endp (s));
-
- return 0;
+ return zebra_server_send_message(client);
}
\f
/* Router-id is updated. Send ZEBRA_ROUTER_ID_ADD to client. */
/* Check this client need interface information. */
if (!client->ridinfo)
- return -1;
+ return 0;
s = client->obuf;
stream_reset (s);
- /* Place holder for size. */
- stream_putw (s, 0);
-
/* Message type. */
- stream_putc (s, ZEBRA_ROUTER_ID_UPDATE);
+ zserv_create_header (s, ZEBRA_ROUTER_ID_UPDATE);
/* Prefix information. */
stream_putc (s, p->family);
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
- return writen (client->sock, s->data, stream_get_endp (s));
+ return zebra_server_send_message(client);
}
\f
/* Register zebra server interface information. Send current all
interface and address information. */
-static void
+static int
zread_interface_add (struct zserv *client, u_short length)
{
- struct listnode *ifnode;
- struct listnode *cnode;
+ struct listnode *ifnode, *ifnnode;
+ struct listnode *cnode, *cnnode;
struct interface *ifp;
struct connected *c;
/* Interface information is needed. */
client->ifinfo = 1;
- for (ifnode = listhead (iflist); ifnode; ifnode = nextnode (ifnode))
+ for (ALL_LIST_ELEMENTS (iflist, ifnode, ifnnode, ifp))
{
- ifp = getdata (ifnode);
-
/* Skip pseudo interface. */
if (! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
continue;
- zsend_interface_add (client, ifp);
+ if (zsend_interface_add (client, ifp) < 0)
+ return -1;
- for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+ for (ALL_LIST_ELEMENTS (ifp->connected, cnode, cnnode, c))
{
- c = getdata (cnode);
- if (CHECK_FLAG (c->conf, ZEBRA_IFC_REAL))
- zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_ADD, client,
- ifp, c);
+ if (CHECK_FLAG (c->conf, ZEBRA_IFC_REAL) &&
+ (zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_ADD, client,
+ ifp, c) < 0))
+ return -1;
}
}
+ return 0;
}
/* Unregister zebra server interface information. */
-static void
+static int
zread_interface_delete (struct zserv *client, u_short length)
{
client->ifinfo = 0;
+ return 0;
}
/* This function support multiple nexthop. */
* Parse the ZEBRA_IPV4_ROUTE_ADD sent from client. Update rib and
* add kernel route.
*/
-static void
+static int
zread_ipv4_add (struct zserv *client, u_short length)
{
int i;
s = client->ibuf;
/* Allocate new rib. */
- rib = XMALLOC (MTYPE_RIB, sizeof (struct rib));
- memset (rib, 0, sizeof (struct rib));
-
+ rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
+
/* Type, flags, message. */
rib->type = stream_getc (s);
rib->flags = stream_getc (s);
break;
case ZEBRA_NEXTHOP_IFNAME:
ifname_len = stream_getc (s);
- stream_forward (s, ifname_len);
+ stream_forward_getp (s, ifname_len);
break;
case ZEBRA_NEXTHOP_IPV4:
nexthop.s_addr = stream_get_ipv4 (s);
nexthop_ipv4_add (rib, &nexthop);
break;
case ZEBRA_NEXTHOP_IPV6:
- stream_forward (s, IPV6_MAX_BYTELEN);
+ stream_forward_getp (s, IPV6_MAX_BYTELEN);
break;
case ZEBRA_NEXTHOP_BLACKHOLE:
nexthop_blackhole_add (rib);
rib->metric = stream_getl (s);
rib_add_ipv4_multipath (&p, rib);
+ return 0;
}
/* Zebra server IPv4 prefix delete function. */
-static void
+static int
zread_ipv4_delete (struct zserv *client, u_short length)
{
int i;
break;
case ZEBRA_NEXTHOP_IFNAME:
ifname_len = stream_getc (s);
- stream_forward (s, ifname_len);
+ stream_forward_getp (s, ifname_len);
break;
case ZEBRA_NEXTHOP_IPV4:
nexthop.s_addr = stream_get_ipv4 (s);
break;
case ZEBRA_NEXTHOP_IPV6:
- stream_forward (s, IPV6_MAX_BYTELEN);
+ stream_forward_getp (s, IPV6_MAX_BYTELEN);
break;
}
}
rib_delete_ipv4 (api.type, api.flags, &p, &nexthop, ifindex,
client->rtm_table);
+ return 0;
}
/* Nexthop lookup for IPv4. */
-static void
+static int
zread_ipv4_nexthop_lookup (struct zserv *client, u_short length)
{
struct in_addr addr;
addr.s_addr = stream_get_ipv4 (client->ibuf);
- zsend_ipv4_nexthop_lookup (client, addr);
+ return zsend_ipv4_nexthop_lookup (client, addr);
}
/* Nexthop lookup for IPv4. */
-static void
+static int
zread_ipv4_import_lookup (struct zserv *client, u_short length)
{
struct prefix_ipv4 p;
p.prefixlen = stream_getc (client->ibuf);
p.prefix.s_addr = stream_get_ipv4 (client->ibuf);
- zsend_ipv4_import_lookup (client, &p);
+ return zsend_ipv4_import_lookup (client, &p);
}
#ifdef HAVE_IPV6
/* Zebra server IPv6 prefix add function. */
-static void
+static int
zread_ipv6_add (struct zserv *client, u_short length)
{
int i;
api.metric = 0;
if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
- rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, 0);
+ rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, 0, api.metric,
+ api.distance);
else
- rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, 0);
+ rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, 0, api.metric,
+ api.distance);
+ return 0;
}
/* Zebra server IPv6 prefix delete function. */
-static void
+static int
zread_ipv6_delete (struct zserv *client, u_short length)
{
int i;
rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, 0);
else
rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, 0);
+ return 0;
}
-void
-zebra_read_ipv6 (int command, struct zserv *client, u_short length)
-{
- u_char type;
- u_char flags;
- struct in6_addr nexthop, *gate;
- u_char *lim;
- u_char *pnt;
- unsigned int ifindex;
-
- pnt = stream_pnt (client->ibuf);
- lim = pnt + length;
-
- type = stream_getc (client->ibuf);
- flags = stream_getc (client->ibuf);
- stream_get (&nexthop, client->ibuf, sizeof (struct in6_addr));
-
- while (stream_pnt (client->ibuf) < lim)
- {
- int size;
- struct prefix_ipv6 p;
-
- ifindex = stream_getl (client->ibuf);
-
- memset (&p, 0, sizeof (struct prefix_ipv6));
- p.family = AF_INET6;
- p.prefixlen = stream_getc (client->ibuf);
- size = PSIZE(p.prefixlen);
- stream_get (&p.prefix, client->ibuf, size);
-
- if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
- gate = NULL;
- else
- gate = &nexthop;
-
- if (command == ZEBRA_IPV6_ROUTE_ADD)
- rib_add_ipv6 (type, flags, &p, gate, ifindex, 0);
- else
- rib_delete_ipv6 (type, flags, &p, gate, ifindex, 0);
- }
-}
-
-static void
+static int
zread_ipv6_nexthop_lookup (struct zserv *client, u_short length)
{
struct in6_addr addr;
stream_get (&addr, client->ibuf, 16);
printf ("DEBUG %s\n", inet_ntop (AF_INET6, &addr, buf, BUFSIZ));
- zsend_ipv6_nexthop_lookup (client, &addr);
+ return zsend_ipv6_nexthop_lookup (client, &addr);
}
#endif /* HAVE_IPV6 */
/* Register zebra server router-id information. Send current router-id */
-void
+static int
zread_router_id_add (struct zserv *client, u_short length)
{
struct prefix p;
router_id_get (&p);
- zsend_router_id_update (client,&p);
+ return zsend_router_id_update (client,&p);
}
/* Unregister zebra server router-id information. */
-void
+static int
zread_router_id_delete (struct zserv *client, u_short length)
{
client->ridinfo = 0;
+ return 0;
}
/* Close zebra client. */
stream_free (client->ibuf);
if (client->obuf)
stream_free (client->obuf);
+ if (client->wb)
+ buffer_free(client->wb);
/* Release threads. */
if (client->t_read)
thread_cancel (client->t_read);
if (client->t_write)
thread_cancel (client->t_write);
+ if (client->t_suicide)
+ thread_cancel (client->t_suicide);
/* Free client structure. */
listnode_delete (zebrad.client_list, client);
client->sock = sock;
client->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
client->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
+ client->wb = buffer_new(0);
/* Set table number. */
client->rtm_table = zebrad.rtm_table_default;
{
int sock;
struct zserv *client;
- int nbyte;
- u_short length;
- u_char command;
+ size_t already;
+ uint16_t length, command;
+ uint8_t marker, version;
/* Get thread data. Reset reading thread because I'm running. */
sock = THREAD_FD (thread);
client = THREAD_ARG (thread);
client->t_read = NULL;
- /* Read length and command. */
- nbyte = stream_read (client->ibuf, sock, 3);
- if (nbyte <= 0)
+ if (client->t_suicide)
{
- if (IS_ZEBRA_DEBUG_EVENT)
- zlog_info ("connection closed socket [%d]", sock);
- zebra_client_close (client);
+ zebra_client_close(client);
return -1;
}
+
+ /* Read length and command (if we don't have it already). */
+ if ((already = stream_get_endp(client->ibuf)) < ZEBRA_HEADER_SIZE)
+ {
+ ssize_t nbyte;
+ if (((nbyte = stream_read_try (client->ibuf, sock,
+ ZEBRA_HEADER_SIZE-already)) == 0) ||
+ (nbyte == -1))
+ {
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug ("connection closed socket [%d]", sock);
+ zebra_client_close (client);
+ return -1;
+ }
+ if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE-already))
+ {
+ /* Try again later. */
+ zebra_event (ZEBRA_READ, sock, client);
+ return 0;
+ }
+ already = ZEBRA_HEADER_SIZE;
+ }
+
+ /* Reset to read from the beginning of the incoming packet. */
+ stream_set_getp(client->ibuf, 0);
+
+ /* Fetch header values */
length = stream_getw (client->ibuf);
- command = stream_getc (client->ibuf);
+ marker = stream_getc (client->ibuf);
+ version = stream_getc (client->ibuf);
+ command = stream_getw (client->ibuf);
- if (length < 3)
+ if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION)
{
- if (IS_ZEBRA_DEBUG_EVENT)
- zlog_info ("length %d is less than 3 ", length);
+ zlog_err("%s: socket %d version mismatch, marker %d, version %d",
+ __func__, sock, marker, version);
+ zebra_client_close (client);
+ return -1;
+ }
+ if (length < ZEBRA_HEADER_SIZE)
+ {
+ zlog_warn("%s: socket %d message length %u is less than header size %d",
+ __func__, sock, length, ZEBRA_HEADER_SIZE);
+ zebra_client_close (client);
+ return -1;
+ }
+ if (length > STREAM_SIZE(client->ibuf))
+ {
+ zlog_warn("%s: socket %d message length %u exceeds buffer size %lu",
+ __func__, sock, length, (u_long)STREAM_SIZE(client->ibuf));
zebra_client_close (client);
return -1;
}
-
- length -= 3;
/* Read rest of data. */
- if (length)
+ if (already < length)
{
- nbyte = stream_read (client->ibuf, sock, length);
- if (nbyte <= 0)
+ ssize_t nbyte;
+ if (((nbyte = stream_read_try (client->ibuf, sock,
+ length-already)) == 0) ||
+ (nbyte == -1))
{
if (IS_ZEBRA_DEBUG_EVENT)
- zlog_info ("connection closed [%d] when reading zebra data", sock);
+ zlog_debug ("connection closed [%d] when reading zebra data", sock);
zebra_client_close (client);
return -1;
}
+ if (nbyte != (ssize_t)(length-already))
+ {
+ /* Try again later. */
+ zebra_event (ZEBRA_READ, sock, client);
+ return 0;
+ }
}
+ length -= ZEBRA_HEADER_SIZE;
+
/* Debug packet information. */
if (IS_ZEBRA_DEBUG_EVENT)
- zlog_info ("zebra message comes from socket [%d]", sock);
+ zlog_debug ("zebra message comes from socket [%d]", sock);
if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
- zlog_info ("zebra message received [%s] %d",
+ zlog_debug ("zebra message received [%s] %d",
zebra_command_str[command], length);
switch (command)
break;
}
+ if (client->t_suicide)
+ {
+ /* No need to wait for thread callback, just kill immediately. */
+ zebra_client_close(client);
+ return -1;
+ }
+
stream_reset (client->ibuf);
zebra_event (ZEBRA_READ, sock, client);
-
return 0;
}
static int
zebra_accept (struct thread *thread)
{
- int val;
int accept_sock;
int client_sock;
struct sockaddr_in client;
accept_sock = THREAD_FD (thread);
+ /* Reregister myself. */
+ zebra_event (ZEBRA_SERV, accept_sock, NULL);
+
len = sizeof (struct sockaddr_in);
client_sock = accept (accept_sock, (struct sockaddr *) &client, &len);
if (client_sock < 0)
{
- zlog_warn ("Can't accept zebra socket: %s", strerror (errno));
+ zlog_warn ("Can't accept zebra socket: %s", safe_strerror (errno));
return -1;
}
/* Make client socket non-blocking. */
-
- val = fcntl (client_sock, F_GETFL, 0);
- fcntl (client_sock, F_SETFL, (val | O_NONBLOCK));
-
+ set_nonblocking(client_sock);
+
/* Create new zebra client. */
zebra_client_create (client_sock);
- /* Register myself. */
- zebra_event (ZEBRA_SERV, accept_sock, NULL);
-
return 0;
}
if (accept_sock < 0)
{
- zlog_warn ("Can't bind to socket: %s", strerror (errno));
+ zlog_warn ("Can't create zserv stream socket: %s",
+ safe_strerror (errno));
zlog_warn ("zebra can't provice full functionality due to above error");
return;
}
sizeof (struct sockaddr_in));
if (ret < 0)
{
- zlog_warn ("Can't bind to socket: %s", strerror (errno));
+ zlog_warn ("Can't bind to stream socket: %s",
+ safe_strerror (errno));
zlog_warn ("zebra can't provice full functionality due to above error");
close (accept_sock); /* Avoid sd leak. */
return;
ret = listen (accept_sock, 1);
if (ret < 0)
{
- zlog_warn ("Can't listen to socket: %s", strerror (errno));
+ zlog_warn ("Can't listen to stream socket: %s",
+ safe_strerror (errno));
zlog_warn ("zebra can't provice full functionality due to above error");
close (accept_sock); /* Avoid sd leak. */
return;
/* zebra server UNIX domain socket. */
static void
-zebra_serv_un (char *path)
+zebra_serv_un (const char *path)
{
int ret;
int sock, len;
sock = socket (AF_UNIX, SOCK_STREAM, 0);
if (sock < 0)
{
- perror ("sock");
+ zlog_warn ("Can't create zserv unix socket: %s",
+ safe_strerror (errno));
+ zlog_warn ("zebra can't provide full functionality due to above error");
return;
}
ret = bind (sock, (struct sockaddr *) &serv, len);
if (ret < 0)
{
- perror ("bind");
+ zlog_warn ("Can't bind to unix socket %s: %s",
+ path, safe_strerror (errno));
+ zlog_warn ("zebra can't provide full functionality due to above error");
close (sock);
return;
}
ret = listen (sock, 5);
if (ret < 0)
{
- perror ("listen");
+ zlog_warn ("Can't listen to unix socket %s: %s",
+ path, safe_strerror (errno));
+ zlog_warn ("zebra can't provide full functionality due to above error");
close (sock);
return;
}
int ret;
ret = ipforward ();
+ if (ret == 0)
+ ret = ipforward_on ();
- if (ret != 0)
- {
- vty_out (vty, "IP forwarding is already on%s", VTY_NEWLINE);
- return CMD_ERR_NOTHING_TODO;
- }
-
- ret = ipforward_on ();
if (ret == 0)
{
vty_out (vty, "Can't turn on IP forwarding%s", VTY_NEWLINE);
int ret;
ret = ipforward ();
+ if (ret != 0)
+ ret = ipforward_off ();
- if (ret == 0)
- {
- vty_out (vty, "IP forwarding is already off%s", VTY_NEWLINE);
- return CMD_ERR_NOTHING_TODO;
- }
-
- ret = ipforward_off ();
if (ret != 0)
{
vty_out (vty, "Can't turn off IP forwarding%s", VTY_NEWLINE);
struct listnode *node;
struct zserv *client;
- for (node = listhead (zebrad.client_list); node; nextnode (node))
- {
- client = getdata (node);
- vty_out (vty, "Client fd %d%s", client->sock, VTY_NEWLINE);
- }
+ for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client))
+ vty_out (vty, "Client fd %d%s", client->sock, VTY_NEWLINE);
+
return CMD_SUCCESS;
}
int ret;
ret = ipforward_ipv6 ();
- if (ret != 0)
- {
- vty_out (vty, "IPv6 forwarding is already on%s", VTY_NEWLINE);
- return CMD_ERR_NOTHING_TODO;
- }
+ if (ret == 0)
+ ret = ipforward_ipv6_on ();
- ret = ipforward_ipv6_on ();
if (ret == 0)
{
vty_out (vty, "Can't turn on IPv6 forwarding%s", VTY_NEWLINE);
int ret;
ret = ipforward_ipv6 ();
- if (ret == 0)
- {
- vty_out (vty, "IP forwarding is already off%s", VTY_NEWLINE);
- return CMD_ERR_NOTHING_TODO;
- }
+ if (ret != 0)
+ ret = ipforward_ipv6_off ();
- ret = ipforward_ipv6_off ();
if (ret != 0)
{
vty_out (vty, "Can't turn off IPv6 forwarding%s", VTY_NEWLINE);
#endif /* HAVE_IPV6 */
/* IPForwarding configuration write function. */
-int
+static int
config_write_forwarding (struct vty *vty)
{
/* FIXME: Find better place for that. */
\f
/* Initialisation of zebra and installation of commands. */
void
-zebra_init ()
+zebra_init (void)
{
/* Client list init. */
zebrad.client_list = list_new ();
install_element (CONFIG_NODE, &ipv6_forwarding_cmd);
install_element (CONFIG_NODE, &no_ipv6_forwarding_cmd);
#endif /* HAVE_IPV6 */
-
- FIFO_INIT(&message_queue);
- t_write = NULL;
}