diff options
Diffstat (limited to 'lib/zclient.c')
-rw-r--r-- | lib/zclient.c | 332 |
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; } } |