summaryrefslogtreecommitdiffstats
path: root/lib/zclient.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/zclient.c')
-rw-r--r--lib/zclient.c332
1 files changed, 270 insertions, 62 deletions
diff --git a/lib/zclient.c b/lib/zclient.c
index 52a3627d..6803aa4a 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -32,18 +32,25 @@
#include "zclient.h"
#include "memory.h"
#include "table.h"
-
-/* Zebra client events. */
-enum event {ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT};
-/* Prototype for event manager. */
-static void zclient_event (enum event, struct zclient *);
+/* Zebra client events. */
+enum event {ZLOOKUP_SCHEDULE, ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT};
extern struct thread_master *master;
/* This file local debug flag. */
int zclient_debug = 0;
-
+
+/* Nexus to use, if any */
+static qpn_nexus zclient_nexus = NULL;
+
+/* prototypes */
+static int zclient_read (struct zclient *zclient);
+static void zclient_event (enum event, struct zclient *);
+static void zclient_event_r (enum event event, struct zclient *zclient);
+static void zclient_event_t (enum event event, struct zclient *zclient);
+static void zclient_connect_r (qtimer qtr, void* timer_info, qtime_t when);
+
/* Allocate zclient structure. */
struct zclient *
zclient_new ()
@@ -55,6 +62,13 @@ zclient_new ()
zclient->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
zclient->wb = buffer_new(0);
+ if (zclient_nexus)
+ {
+ zclient->qf = qps_file_init_new(zclient->qf, NULL);
+ zclient->qtr = qtimer_init_new(zclient->qtr, zclient_nexus->pile,
+ zclient_connect_r, zclient);
+ }
+
return zclient;
}
@@ -73,16 +87,36 @@ zclient_free (struct zclient *zclient)
if (zclient->wb)
buffer_free(zclient->wb);
+ /* qfile and qtimer */
+ if (zclient->qf)
+ {
+ qps_remove_file(zclient->qf);
+ qps_file_free(zclient->qf);
+ zclient->qf = NULL;
+ }
+ if (zclient->qtr)
+ {
+ qtimer_free(zclient->qtr);
+ zclient->qtr = NULL;
+ }
+
XFREE (MTYPE_ZCLIENT, zclient);
}
+/* Initialize to use a nexus (qpselect etc). */
+void
+zclient_init_r (qpn_nexus n)
+{
+ zclient_nexus = n;
+}
+
/* Initialize zebra client. Argument redist_default is unwanted
redistribute route type. */
void
zclient_init (struct zclient *zclient, int redist_default)
{
int i;
-
+
/* Enable zebra client connection by default. */
zclient->enable = 1;
@@ -108,6 +142,13 @@ zclient_init (struct zclient *zclient, int redist_default)
zclient_event (ZCLIENT_SCHEDULE, zclient);
}
+/* Schedule lookup connection */
+void
+zlookup_schedule(struct zclient *zclient)
+{
+ zclient_event (ZLOOKUP_SCHEDULE, zclient);
+}
+
/* Stop zebra client services. */
void
zclient_stop (struct zclient *zclient)
@@ -120,6 +161,12 @@ zclient_stop (struct zclient *zclient)
THREAD_OFF(zclient->t_connect);
THREAD_OFF(zclient->t_write);
+ if (zclient->qf)
+ qps_remove_file(zclient->qf);
+
+ if (zclient->qtr)
+ qtimer_unset(zclient->qtr);
+
/* Reset streams. */
stream_reset(zclient->ibuf);
stream_reset(zclient->obuf);
@@ -155,8 +202,8 @@ zclient_socket(void)
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock < 0)
return -1;
-
- /* Make server socket. */
+
+ /* Make server socket. */
memset (&serv, 0, sizeof (struct sockaddr_in));
serv.sin_family = AF_INET;
serv.sin_port = htons (ZEBRA_PORT);
@@ -188,8 +235,8 @@ zclient_socket_un (const char *path)
sock = socket (AF_UNIX, SOCK_STREAM, 0);
if (sock < 0)
return -1;
-
- /* Make server socket. */
+
+ /* Make server socket. */
memset (&addr, 0, sizeof (struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy (addr.sun_path, path, strlen (path));
@@ -217,8 +264,37 @@ zclient_failed(struct zclient *zclient)
return -1;
}
+/* Write as much data as possible.
+ * nexus version */
+static void
+zclient_flush_data_r(qps_file qf, void* file_info)
+{
+ struct zclient *zclient = file_info;
+
+ qps_disable_modes(qf, qps_write_mbit);
+
+ if (zclient->sock < 0)
+ return;
+
+ switch (buffer_flush_available(zclient->wb, zclient->sock))
+ {
+ case BUFFER_ERROR:
+ zlog_warn("%s: buffer_flush_available failed on zclient fd %d, closing",
+ __func__, zclient->sock);
+ zclient_failed(zclient);
+ break;
+ case BUFFER_PENDING:
+ qps_enable_mode(qf, qps_write_mnum, zclient_flush_data_r) ;
+ break;
+ case BUFFER_EMPTY:
+ break;
+ }
+}
+
+/* Write as much data as possible.
+ * thread version */
static int
-zclient_flush_data(struct thread *thread)
+zclient_flush_data_t(struct thread *thread)
{
struct zclient *zclient = THREAD_ARG(thread);
@@ -233,7 +309,7 @@ zclient_flush_data(struct thread *thread)
return zclient_failed(zclient);
break;
case BUFFER_PENDING:
- zclient->t_write = thread_add_write(master, zclient_flush_data,
+ zclient->t_write = thread_add_write(master, zclient_flush_data_t,
zclient, zclient->sock);
break;
case BUFFER_EMPTY:
@@ -256,11 +332,17 @@ zclient_send_message(struct zclient *zclient)
return zclient_failed(zclient);
break;
case BUFFER_EMPTY:
- THREAD_OFF(zclient->t_write);
+ if (zclient_nexus)
+ qps_disable_modes(zclient->qf, qps_write_mbit);
+ else
+ THREAD_OFF(zclient->t_write);
break;
case BUFFER_PENDING:
- THREAD_WRITE_ON(master, zclient->t_write,
- zclient_flush_data, zclient, zclient->sock);
+ if (zclient_nexus)
+ qps_enable_mode(zclient->qf, qps_write_mnum, zclient_flush_data_r) ;
+ else
+ THREAD_WRITE_ON(master, zclient->t_write,
+ zclient_flush_data_t, zclient, zclient->sock);
break;
}
return 0;
@@ -288,7 +370,7 @@ zebra_message_send (struct zclient *zclient, int command)
/* Send very simple command only Zebra message. */
zclient_create_header (s, command);
-
+
return zclient_send_message(zclient);
}
@@ -313,6 +395,10 @@ zclient_start (struct zclient *zclient)
if (zclient->t_connect)
return 0;
+ /* Check timer */
+ if (zclient->qtr && zclient->qtr->active)
+ return 0;
+
/* Make socket. */
#ifdef HAVE_TCP_ZEBRA
zclient->sock = zclient_socket ();
@@ -335,7 +421,10 @@ zclient_start (struct zclient *zclient)
zclient->fail = 0;
if (zclient_debug)
zlog_debug ("zclient connect success with socket [%d]", zclient->sock);
-
+
+ if (zclient_nexus)
+ qps_add_file(zclient_nexus->selection, zclient->qf, zclient->sock, zclient);
+
/* Create read thread. */
zclient_event (ZCLIENT_READ, zclient);
@@ -358,9 +447,24 @@ zclient_start (struct zclient *zclient)
}
/* This function is a wrapper function for calling zclient_start from
+ qtimer. */
+static void
+zclient_connect_r (qtimer qtr, void* timer_info, qtime_t when)
+{
+ struct zclient *zclient = timer_info;
+
+ qtimer_unset(qtr);
+
+ if (zclient_debug)
+ zlog_debug ("zclient_connect is called");
+
+ zclient_start (zclient);
+}
+
+/* This function is a wrapper function for calling zclient_start from
timer or event thread. */
static int
-zclient_connect (struct thread *t)
+zclient_connect_t (struct thread *t)
{
struct zclient *zclient;
@@ -372,14 +476,58 @@ zclient_connect (struct thread *t)
return zclient_start (zclient);
}
-
- /*
+
+/* Connect to zebra for nexthop lookup.
+ * thread version */
+static int
+zlookup_connect_t (struct thread *t)
+{
+ struct zclient *zlookup;
+
+ zlookup = THREAD_ARG (t);
+ zlookup->t_connect = NULL;
+
+ if (zlookup->sock != -1)
+ return 0;
+
+#ifdef HAVE_TCP_ZEBRA
+ zlookup->sock = zclient_socket ();
+#else
+ zlookup->sock = zclient_socket_un (ZEBRA_SERV_PATH);
+#endif /* HAVE_TCP_ZEBRA */
+ if (zlookup->sock < 0)
+ return -1;
+
+ return 0;
+}
+
+/* Connect to zebra for nexthop lookup.
+ * nexus version */
+static void
+zlookup_connect_r (qtimer qtr, void* timer_info, qtime_t when)
+{
+ struct zclient *zlookup = timer_info;
+
+ qtimer_unset(qtr);
+
+ if (zlookup->sock != -1)
+ return;
+
+#ifdef HAVE_TCP_ZEBRA
+ zlookup->sock = zclient_socket ();
+#else
+ zlookup->sock = zclient_socket_un (ZEBRA_SERV_PATH);
+#endif /* HAVE_TCP_ZEBRA */
+}
+
+
+ /*
* "xdr_encode"-like interface that allows daemon (client) to send
* a message to zebra server for a route that needs to be
* added/deleted to the kernel. Info about the route is specified
* by the caller in a struct zapi_ipv4. zapi_ipv4_read() then writes
* the info down the zclient socket using the stream_* functions.
- *
+ *
* The corresponding read ("xdr_decode") function on the server
* side is zread_ipv4_add()/zread_ipv4_delete().
*
@@ -391,11 +539,11 @@ zclient_connect (struct thread *t)
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Destination IPv4 Prefix for route |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Nexthop count |
+ * | Nexthop count |
* +-+-+-+-+-+-+-+-+
*
- *
- * A number of IPv4 nexthop(s) or nexthop interface index(es) are then
+ *
+ * A number of IPv4 nexthop(s) or nexthop interface index(es) are then
* described, as per the Nexthop count. Each nexthop described as:
*
* +-+-+-+-+-+-+-+-+
@@ -405,18 +553,18 @@ zclient_connect (struct thread *t)
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* Alternatively, if the flags field has ZEBRA_FLAG_BLACKHOLE or
- * ZEBRA_FLAG_REJECT is set then Nexthop count is set to 1, then _no_
+ * ZEBRA_FLAG_REJECT is set then Nexthop count is set to 1, then _no_
* nexthop information is provided, and the message describes a prefix
* to blackhole or reject route.
*
* If ZAPI_MESSAGE_DISTANCE is set, the distance value is written as a 1
* byte value.
- *
+ *
* If ZAPI_MESSAGE_METRIC is set, the metric value is written as an 8
* byte value.
*
* XXX: No attention paid to alignment.
- */
+ */
int
zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
struct zapi_ipv4 *api)
@@ -428,9 +576,9 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
/* Reset stream. */
s = zclient->obuf;
stream_reset (s);
-
+
zclient_create_header (s, cmd);
-
+
/* Put type and nexthop. */
stream_putc (s, api->type);
stream_putc (s, api->flags);
@@ -496,7 +644,7 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
stream_putc (s, api->type);
stream_putc (s, api->flags);
stream_putc (s, api->message);
-
+
/* Put prefix information. */
psize = PSIZE (p->prefixlen);
stream_putc (s, p->prefixlen);
@@ -531,10 +679,10 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
}
#endif /* HAVE_IPV6 */
-/*
+/*
* send a ZEBRA_REDISTRIBUTE_ADD or ZEBRA_REDISTRIBUTE_DELETE
* for the route type (ZEBRA_ROUTE_KERNEL etc.). The zebra server will
- * then set/unset redist[type] in the client handle (a struct zserv) for the
+ * then set/unset redist[type] in the client handle (a struct zserv) for the
* sending client
*/
int
@@ -544,12 +692,12 @@ zebra_redistribute_send (int command, struct zclient *zclient, int type)
s = zclient->obuf;
stream_reset(s);
-
+
zclient_create_header (s, command);
stream_putc (s, type);
-
+
stream_putw_at (s, 0, stream_get_endp (s));
-
+
return zclient_send_message(zclient);
}
@@ -568,7 +716,7 @@ zebra_router_id_update_read (struct stream *s, struct prefix *rid)
}
/* Interface addition from zebra daemon. */
-/*
+/*
* The format of the message sent with type ZEBRA_INTERFACE_ADD or
* ZEBRA_INTERFACE_DELETE from zebra to the client is:
* 0 1 2 3
@@ -628,11 +776,11 @@ zebra_interface_add_read (struct stream *s)
if (ifp->hw_addr_len)
stream_get (ifp->hw_addr, s, ifp->hw_addr_len);
#endif /* HAVE_STRUCT_SOCKADDR_DL */
-
+
return ifp;
}
-/*
+/*
* Read interface up/down msg (ZEBRA_INTERFACE_UP/ZEBRA_INTERFACE_DOWN)
* from zebra server. The format of this message is the same as
* that sent for ZEBRA_INTERFACE_ADD/ZEBRA_INTERFACE_DELETE (see
@@ -670,7 +818,7 @@ zebra_interface_state_read (struct stream *s)
return ifp;
}
-/*
+/*
* format of message for address additon is:
* 0
* 0 1 2 3 4 5 6 7
@@ -770,7 +918,7 @@ zebra_interface_address_read (int type, struct stream *s)
stream_get (&d.u.prefix, s, plen);
d.family = family;
- if (type == ZEBRA_INTERFACE_ADDRESS_ADD)
+ if (type == ZEBRA_INTERFACE_ADDRESS_ADD)
{
/* N.B. NULL destination pointers are encoded as all zeroes */
ifc = connected_add_by_prefix(ifp, &p,(memconstant(&d.u.prefix,0,plen) ?
@@ -791,20 +939,32 @@ zebra_interface_address_read (int type, struct stream *s)
return ifc;
}
-
+/* nexus: Zebra client message read function. */
+static void
+zclient_read_r (qps_file qf, void* file_info)
+{
+ struct zclient *zclient = file_info;
+ qps_disable_modes(qf, qps_read_mbit);
+ zclient_read(zclient);
+}
+
+/* thread: Zebra client message read function. */
+static int
+zclient_read_t (struct thread *thread)
+{
+ struct zclient *zclient = THREAD_ARG (thread);
+ zclient->t_read = NULL;
+ return zclient_read(zclient);
+}
+
/* Zebra client message read function. */
static int
-zclient_read (struct thread *thread)
+zclient_read (struct zclient *zclient)
{
int ret;
size_t already;
uint16_t length, command;
uint8_t marker, version;
- struct zclient *zclient;
-
- /* Get socket to zebra. */
- zclient = THREAD_ARG (thread);
- zclient->t_read = NULL;
/* Read zebra header (if we don't have it already). */
if ((already = stream_get_endp(zclient->ibuf)) < ZEBRA_HEADER_SIZE)
@@ -835,15 +995,15 @@ zclient_read (struct thread *thread)
marker = stream_getc (zclient->ibuf);
version = stream_getc (zclient->ibuf);
command = stream_getw (zclient->ibuf);
-
+
if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION)
{
zlog_err("%s: socket %d version mismatch, marker %d, version %d",
__func__, zclient->sock, marker, version);
return zclient_failed(zclient);
}
-
- if (length < ZEBRA_HEADER_SIZE)
+
+ if (length < ZEBRA_HEADER_SIZE)
{
zlog_err("%s: socket %d message length %u is less than %d ",
__func__, zclient->sock, length, ZEBRA_HEADER_SIZE);
@@ -952,7 +1112,7 @@ void
zclient_redistribute (int command, struct zclient *zclient, int type)
{
- if (command == ZEBRA_REDISTRIBUTE_ADD)
+ if (command == ZEBRA_REDISTRIBUTE_ADD)
{
if (zclient->redist[type])
return;
@@ -980,7 +1140,7 @@ zclient_redistribute_default (int command, struct zclient *zclient)
return;
zclient->default_information = 1;
}
- else
+ else
{
if (!zclient->default_information)
return;
@@ -991,30 +1151,78 @@ zclient_redistribute_default (int command, struct zclient *zclient)
zebra_message_send (zclient, command);
}
+/* Arm event. */
static void
zclient_event (enum event event, struct zclient *zclient)
{
+ if (zclient_nexus)
+ zclient_event_r(event, zclient);
+ else
+ zclient_event_t(event, zclient);
+}
+
+/* Arm event.
+ * nexus version */
+static void
+zclient_event_r (enum event event, struct zclient *zclient)
+{
switch (event)
{
+ case ZLOOKUP_SCHEDULE:
+ if (!zclient->qtr->active)
+ qtimer_set(zclient->qtr, qt_get_monotonic(), zlookup_connect_r) ;
+ break;
case ZCLIENT_SCHEDULE:
- if (! zclient->t_connect)
- zclient->t_connect =
- thread_add_event (master, zclient_connect, zclient, 0);
+ if (!zclient->qtr->active)
+ qtimer_set(zclient->qtr, qt_get_monotonic(), zclient_connect_r) ;
break;
case ZCLIENT_CONNECT:
if (zclient->fail >= 10)
return;
if (zclient_debug)
- zlog_debug ("zclient connect schedule interval is %d",
+ zlog_debug ("zclient connect schedule interval is %d",
zclient->fail < 3 ? 10 : 60);
+ if (!zclient->qtr->active)
+ qtimer_set(zclient->qtr,
+ qt_add_monotonic(QTIME(zclient->fail < 3 ? 10 : 60)), zclient_connect_r) ;
+ break;
+ case ZCLIENT_READ:
+ qps_enable_mode(zclient->qf, qps_read_mnum, zclient_read_r) ;
+ break;
+ }
+}
+
+/* Arm event.
+ * thread version */
+static void
+zclient_event_t (enum event event, struct zclient *zclient)
+{
+ switch (event)
+ {
+ case ZLOOKUP_SCHEDULE:
+ if (! zclient->t_connect)
+ zclient->t_connect =
+ thread_add_event (master, zlookup_connect_t, zclient, 0);
+ break;
+ case ZCLIENT_SCHEDULE:
+ if (! zclient->t_connect)
+ zclient->t_connect =
+ thread_add_event (master, zclient_connect_t, zclient, 0);
+ break;
+ case ZCLIENT_CONNECT:
+ if (zclient->fail >= 10)
+ return;
+ if (zclient_debug)
+ zlog_debug ("zclient connect schedule interval is %d",
+ zclient->fail < 3 ? 10 : 60);
if (! zclient->t_connect)
- zclient->t_connect =
- thread_add_timer (master, zclient_connect, zclient,
- zclient->fail < 3 ? 10 : 60);
+ zclient->t_connect =
+ thread_add_timer (master, zclient_connect_t, zclient,
+ zclient->fail < 3 ? 10 : 60);
break;
case ZCLIENT_READ:
- zclient->t_read =
- thread_add_read (master, zclient_read, zclient, zclient->sock);
+ zclient->t_read =
+ thread_add_read (master, zclient_read_t, zclient, zclient->sock);
break;
}
}