2018-04-22 22:01:20 +02:00
|
|
|
/*
|
|
|
|
* Zebra API server.
|
|
|
|
* Portions:
|
|
|
|
* Copyright (C) 1997-1999 Kunihiro Ishiguro
|
|
|
|
* Copyright (C) 2015-2018 Cumulus Networks, Inc.
|
|
|
|
* et al.
|
2002-12-13 21:15:29 +01:00
|
|
|
*
|
2018-04-22 22:01:20 +02:00
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
|
|
* any later version.
|
2002-12-13 21:15:29 +01:00
|
|
|
*
|
2018-04-22 22:01:20 +02:00
|
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
|
|
* more details.
|
2002-12-13 21:15:29 +01:00
|
|
|
*
|
2017-05-13 10:25:29 +02:00
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; see the file COPYING; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
2002-12-13 21:15:29 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <zebra.h>
|
2018-04-23 04:10:54 +02:00
|
|
|
|
|
|
|
/* clang-format off */
|
2018-04-22 22:01:20 +02:00
|
|
|
#include <errno.h> /* for errno */
|
|
|
|
#include <netinet/in.h> /* for sockaddr_in */
|
|
|
|
#include <stdint.h> /* for uint8_t */
|
|
|
|
#include <stdio.h> /* for snprintf */
|
|
|
|
#include <sys/socket.h> /* for sockaddr_storage, AF_UNIX, accept... */
|
|
|
|
#include <sys/stat.h> /* for umask, mode_t */
|
|
|
|
#include <sys/un.h> /* for sockaddr_un */
|
|
|
|
#include <time.h> /* for NULL, tm, gmtime, time_t */
|
|
|
|
#include <unistd.h> /* for close, unlink, ssize_t */
|
|
|
|
|
|
|
|
#include "lib/buffer.h" /* for BUFFER_EMPTY, BUFFER_ERROR, BUFFE... */
|
|
|
|
#include "lib/command.h" /* for vty, install_element, CMD_SUCCESS... */
|
2018-04-22 23:03:52 +02:00
|
|
|
#include "lib/hook.h" /* for DEFINE_HOOK, DEFINE_KOOH, hook_call */
|
2018-04-22 22:01:20 +02:00
|
|
|
#include "lib/linklist.h" /* for ALL_LIST_ELEMENTS_RO, ALL_LIST_EL... */
|
|
|
|
#include "lib/libfrr.h" /* for frr_zclient_addr */
|
|
|
|
#include "lib/log.h" /* for zlog_warn, zlog_debug, safe_strerror */
|
|
|
|
#include "lib/memory.h" /* for MTYPE_TMP, XCALLOC, XFREE */
|
|
|
|
#include "lib/monotime.h" /* for monotime, ONE_DAY_SECOND, ONE_WEE... */
|
|
|
|
#include "lib/network.h" /* for set_nonblocking */
|
|
|
|
#include "lib/privs.h" /* for zebra_privs_t, ZPRIVS_LOWER, ZPRI... */
|
|
|
|
#include "lib/route_types.h" /* for ZEBRA_ROUTE_MAX */
|
|
|
|
#include "lib/sockopt.h" /* for setsockopt_so_recvbuf, setsockopt... */
|
|
|
|
#include "lib/sockunion.h" /* for sockopt_reuseaddr, sockopt_reuseport */
|
|
|
|
#include "lib/stream.h" /* for STREAM_SIZE, stream (ptr only), ... */
|
|
|
|
#include "lib/thread.h" /* for thread (ptr only), THREAD_ARG, ... */
|
|
|
|
#include "lib/vrf.h" /* for vrf_info_lookup, VRF_DEFAULT */
|
|
|
|
#include "lib/vty.h" /* for vty_out, vty (ptr only) */
|
|
|
|
#include "lib/zassert.h" /* for assert */
|
|
|
|
#include "lib/zclient.h" /* for zmsghdr, ZEBRA_HEADER_SIZE, ZEBRA... */
|
|
|
|
|
|
|
|
#include "zebra/debug.h" /* for various debugging macros */
|
|
|
|
#include "zebra/rib.h" /* for rib_score_proto */
|
|
|
|
#include "zebra/zapi_msg.h" /* for zserv_handle_commands */
|
|
|
|
#include "zebra/zebra_vrf.h" /* for zebra_vrf_lookup_by_id, zvrf */
|
2018-04-23 04:10:54 +02:00
|
|
|
#include "zebra/zserv.h" /* for zserv */
|
|
|
|
/* clang-format on */
|
2014-06-04 06:53:35 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Event list of zebra. */
|
2018-03-07 00:08:37 +01:00
|
|
|
enum event { ZEBRA_READ, ZEBRA_WRITE };
|
|
|
|
/* privileges */
|
2003-06-04 15:59:38 +02:00
|
|
|
extern struct zebra_privs_t zserv_privs;
|
2018-03-07 00:08:37 +01:00
|
|
|
/* post event into client */
|
|
|
|
static void zebra_event(struct zserv *client, enum event event);
|
2014-06-04 06:53:35 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-04-22 22:01:20 +02:00
|
|
|
/* Public interface --------------------------------------------------------- */
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
int zebra_server_send_message(struct zserv *client, struct stream *msg)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2018-03-07 00:08:37 +01:00
|
|
|
stream_fifo_push(client->obuf_fifo, msg);
|
|
|
|
zebra_event(client, ZEBRA_WRITE);
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
/* Lifecycle ---------------------------------------------------------------- */
|
|
|
|
|
2018-04-22 23:03:52 +02:00
|
|
|
/* Hooks for client connect / disconnect */
|
2018-04-23 04:32:49 +02:00
|
|
|
DEFINE_HOOK(zapi_client_connect, (struct zserv *client), (client));
|
|
|
|
DEFINE_KOOH(zapi_client_close, (struct zserv *client), (client));
|
2018-04-22 23:03:52 +02:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
/* free zebra client information. */
|
|
|
|
static void zebra_client_free(struct zserv *client)
|
|
|
|
{
|
2018-04-23 04:10:54 +02:00
|
|
|
hook_call(zapi_client_close, client);
|
2018-03-07 00:08:37 +01:00
|
|
|
|
|
|
|
/* Close file descriptor. */
|
|
|
|
if (client->sock) {
|
|
|
|
unsigned long nroutes;
|
|
|
|
|
|
|
|
close(client->sock);
|
|
|
|
nroutes = rib_score_proto(client->proto, client->instance);
|
|
|
|
zlog_notice(
|
|
|
|
"client %d disconnected. %lu %s routes removed from the rib",
|
|
|
|
client->sock, nroutes,
|
|
|
|
zebra_route_string(client->proto));
|
|
|
|
client->sock = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free stream buffers. */
|
|
|
|
if (client->ibuf_work)
|
|
|
|
stream_free(client->ibuf_work);
|
|
|
|
if (client->obuf_work)
|
|
|
|
stream_free(client->obuf_work);
|
|
|
|
if (client->ibuf_fifo)
|
|
|
|
stream_fifo_free(client->ibuf_fifo);
|
|
|
|
if (client->obuf_fifo)
|
|
|
|
stream_fifo_free(client->obuf_fifo);
|
|
|
|
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 bitmaps. */
|
|
|
|
for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++)
|
|
|
|
for (int i = 0; i < ZEBRA_ROUTE_MAX; i++)
|
|
|
|
vrf_bitmap_free(client->redist[afi][i]);
|
|
|
|
|
|
|
|
vrf_bitmap_free(client->redist_default);
|
|
|
|
vrf_bitmap_free(client->ifinfo);
|
|
|
|
vrf_bitmap_free(client->ridinfo);
|
|
|
|
|
|
|
|
XFREE(MTYPE_TMP, client);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Called from client thread to terminate itself.
|
|
|
|
*/
|
|
|
|
static void zebra_client_close(struct zserv *client)
|
|
|
|
{
|
|
|
|
listnode_delete(zebrad.client_list, client);
|
|
|
|
zebra_client_free(client);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make new client. */
|
|
|
|
static void zebra_client_create(int sock)
|
|
|
|
{
|
|
|
|
struct zserv *client;
|
|
|
|
int i;
|
|
|
|
afi_t afi;
|
|
|
|
|
|
|
|
client = XCALLOC(MTYPE_TMP, sizeof(struct zserv));
|
2018-02-15 01:52:01 +01:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
/* Make client input/output buffer. */
|
|
|
|
client->sock = sock;
|
|
|
|
client->ibuf_fifo = stream_fifo_new();
|
|
|
|
client->obuf_fifo = stream_fifo_new();
|
|
|
|
client->ibuf_work = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
|
|
|
client->obuf_work = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
|
|
|
client->wb = buffer_new(0);
|
2018-02-15 01:52:01 +01:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
/* Set table number. */
|
|
|
|
client->rtm_table = zebrad.rtm_table_default;
|
2018-02-15 01:52:01 +01:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
client->connect_time = monotime(NULL);
|
|
|
|
/* Initialize flags */
|
|
|
|
for (afi = AFI_IP; afi < AFI_MAX; afi++)
|
|
|
|
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
|
|
|
|
client->redist[afi][i] = vrf_bitmap_init();
|
|
|
|
client->redist_default = vrf_bitmap_init();
|
|
|
|
client->ifinfo = vrf_bitmap_init();
|
|
|
|
client->ridinfo = vrf_bitmap_init();
|
2018-02-15 01:52:01 +01:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
/* by default, it's not a synchronous client */
|
|
|
|
client->is_synchronous = 0;
|
2018-02-15 01:52:01 +01:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
/* Add this client to linked list. */
|
|
|
|
listnode_add(zebrad.client_list, client);
|
2018-02-15 01:52:01 +01:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
zebra_vrf_update_all(client);
|
2018-02-15 01:52:01 +01:00
|
|
|
|
2018-04-23 04:10:54 +02:00
|
|
|
hook_call(zapi_client_connect, client);
|
2018-04-22 23:03:52 +02:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
/* start read loop */
|
|
|
|
zebra_event(client, ZEBRA_READ);
|
|
|
|
}
|
2018-02-15 01:52:01 +01:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
static int zserv_delayed_close(struct thread *thread)
|
|
|
|
{
|
|
|
|
struct zserv *client = THREAD_ARG(thread);
|
2018-02-15 01:52:01 +01:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
client->t_suicide = NULL;
|
|
|
|
zebra_client_close(client);
|
|
|
|
return 0;
|
2018-02-15 01:52:01 +01:00
|
|
|
}
|
|
|
|
|
2018-03-06 23:09:36 +01:00
|
|
|
/*
|
2018-03-07 00:08:37 +01:00
|
|
|
* Log zapi message to zlog.
|
|
|
|
*
|
|
|
|
* errmsg (optional)
|
|
|
|
* Debugging message
|
2018-03-06 23:09:36 +01:00
|
|
|
*
|
2018-03-07 00:08:37 +01:00
|
|
|
* msg
|
|
|
|
* The message
|
|
|
|
*
|
|
|
|
* hdr (optional)
|
|
|
|
* The message header
|
2018-03-06 23:09:36 +01:00
|
|
|
*/
|
2018-03-07 00:08:37 +01:00
|
|
|
static void zserv_log_message(const char *errmsg, struct stream *msg,
|
|
|
|
struct zmsghdr *hdr)
|
|
|
|
{
|
|
|
|
zlog_debug("Rx'd ZAPI message");
|
|
|
|
if (errmsg)
|
|
|
|
zlog_debug("%s", errmsg);
|
|
|
|
if (hdr) {
|
|
|
|
zlog_debug(" Length: %d", hdr->length);
|
|
|
|
zlog_debug("Command: %s", zserv_command_string(hdr->command));
|
|
|
|
zlog_debug(" VRF: %u", hdr->vrf_id);
|
|
|
|
}
|
|
|
|
zlog_hexdump(msg->data, STREAM_READABLE(msg));
|
2018-03-06 23:09:36 +01:00
|
|
|
}
|
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
static int zserv_flush_data(struct thread *thread)
|
|
|
|
{
|
|
|
|
struct zserv *client = THREAD_ARG(thread);
|
2018-03-06 23:57:33 +01:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
client->t_write = NULL;
|
|
|
|
if (client->t_suicide) {
|
|
|
|
zebra_client_close(client);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
switch (buffer_flush_available(client->wb, client->sock)) {
|
|
|
|
case BUFFER_ERROR:
|
|
|
|
zlog_warn(
|
|
|
|
"%s: buffer_flush_available failed on zserv client fd %d, closing",
|
|
|
|
__func__, client->sock);
|
|
|
|
zebra_client_close(client);
|
|
|
|
client = NULL;
|
|
|
|
break;
|
|
|
|
case BUFFER_PENDING:
|
|
|
|
client->t_write = NULL;
|
|
|
|
thread_add_write(zebrad.master, zserv_flush_data, client,
|
|
|
|
client->sock, &client->t_write);
|
|
|
|
break;
|
|
|
|
case BUFFER_EMPTY:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (client)
|
|
|
|
client->last_write_time = monotime(NULL);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write a single packet.
|
|
|
|
*/
|
|
|
|
static int zserv_write(struct thread *thread)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2018-03-07 00:08:37 +01:00
|
|
|
struct zserv *client = THREAD_ARG(thread);
|
|
|
|
struct stream *msg;
|
|
|
|
int writerv;
|
2018-03-06 23:57:33 +01:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
if (client->t_suicide)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (client->is_synchronous)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
msg = stream_fifo_pop(client->obuf_fifo);
|
|
|
|
stream_set_getp(msg, 0);
|
|
|
|
client->last_write_cmd = stream_getw_from(msg, 6);
|
|
|
|
|
|
|
|
writerv = buffer_write(client->wb, client->sock, STREAM_DATA(msg),
|
|
|
|
stream_get_endp(msg));
|
|
|
|
|
|
|
|
stream_free(msg);
|
|
|
|
|
|
|
|
switch (writerv) {
|
|
|
|
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 = NULL;
|
|
|
|
thread_add_event(zebrad.master, zserv_delayed_close, client, 0,
|
|
|
|
&client->t_suicide);
|
|
|
|
return -1;
|
|
|
|
case BUFFER_EMPTY:
|
|
|
|
THREAD_OFF(client->t_write);
|
|
|
|
break;
|
|
|
|
case BUFFER_PENDING:
|
|
|
|
thread_add_write(zebrad.master, zserv_flush_data, client,
|
|
|
|
client->sock, &client->t_write);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (client->obuf_fifo->count)
|
|
|
|
zebra_event(client, ZEBRA_WRITE);
|
|
|
|
|
|
|
|
client->last_write_time = monotime(NULL);
|
|
|
|
return 0;
|
2017-10-11 14:58:02 +02:00
|
|
|
}
|
|
|
|
|
2017-11-02 15:56:03 +01:00
|
|
|
#if defined(HANDLE_ZAPI_FUZZING)
|
|
|
|
static void zserv_write_incoming(struct stream *orig, uint16_t command)
|
|
|
|
{
|
|
|
|
char fname[MAXPATHLEN];
|
|
|
|
struct stream *copy;
|
|
|
|
int fd = -1;
|
|
|
|
|
|
|
|
copy = stream_dup(orig);
|
|
|
|
stream_set_getp(copy, 0);
|
|
|
|
|
|
|
|
zserv_privs.change(ZPRIVS_RAISE);
|
|
|
|
snprintf(fname, MAXPATHLEN, "%s/%u", DAEMON_VTY_DIR, command);
|
|
|
|
fd = open(fname, O_CREAT | O_WRONLY | O_EXCL, 0644);
|
|
|
|
stream_flush(copy, fd);
|
|
|
|
close(fd);
|
|
|
|
zserv_privs.change(ZPRIVS_LOWER);
|
|
|
|
stream_free(copy);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
static int zserv_process_messages(struct thread *thread)
|
|
|
|
{
|
|
|
|
struct zserv *client = THREAD_ARG(thread);
|
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
struct zmsghdr hdr;
|
|
|
|
struct stream *msg;
|
|
|
|
bool hdrvalid;
|
|
|
|
|
|
|
|
do {
|
|
|
|
msg = stream_fifo_pop(client->ibuf_fifo);
|
|
|
|
|
|
|
|
/* break if out of messages */
|
|
|
|
if (!msg)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* read & check header */
|
|
|
|
hdrvalid = zapi_parse_header(msg, &hdr);
|
|
|
|
if (!hdrvalid && IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) {
|
|
|
|
const char *emsg = "Message has corrupt header";
|
|
|
|
zserv_log_message(emsg, msg, NULL);
|
|
|
|
}
|
|
|
|
if (!hdrvalid)
|
|
|
|
continue;
|
|
|
|
|
2018-03-29 14:52:39 +02:00
|
|
|
hdr.length -= ZEBRA_HEADER_SIZE;
|
2018-03-07 00:08:37 +01:00
|
|
|
/* lookup vrf */
|
|
|
|
zvrf = zebra_vrf_lookup_by_id(hdr.vrf_id);
|
|
|
|
if (!zvrf && IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) {
|
|
|
|
const char *emsg = "Message specifies unknown VRF";
|
|
|
|
zserv_log_message(emsg, msg, &hdr);
|
|
|
|
}
|
|
|
|
if (!zvrf)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* process commands */
|
|
|
|
zserv_handle_commands(client, &hdr, msg, zvrf);
|
|
|
|
|
|
|
|
} while (msg);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-11 14:58:02 +02:00
|
|
|
/* Handler of zebra service request. */
|
2018-03-07 00:08:37 +01:00
|
|
|
static int zserv_read(struct thread *thread)
|
2017-10-11 14:58:02 +02:00
|
|
|
{
|
|
|
|
int sock;
|
|
|
|
struct zserv *client;
|
|
|
|
size_t already;
|
2017-11-02 15:56:03 +01:00
|
|
|
#if defined(HANDLE_ZAPI_FUZZING)
|
|
|
|
int packets = 1;
|
|
|
|
#else
|
2017-10-25 17:03:41 +02:00
|
|
|
int packets = zebrad.packets_to_process;
|
2017-11-02 15:56:03 +01:00
|
|
|
#endif
|
2017-10-11 14:58:02 +02:00
|
|
|
/* Get thread data. Reset reading thread because I'm running. */
|
|
|
|
sock = THREAD_FD(thread);
|
|
|
|
client = THREAD_ARG(thread);
|
|
|
|
|
|
|
|
if (client->t_suicide) {
|
|
|
|
zebra_client_close(client);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-10-11 21:05:06 +02:00
|
|
|
while (packets) {
|
2018-03-09 21:59:39 +01:00
|
|
|
struct zmsghdr hdr;
|
|
|
|
ssize_t nb;
|
|
|
|
bool hdrvalid;
|
|
|
|
char errmsg[256];
|
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
already = stream_get_endp(client->ibuf_work);
|
|
|
|
|
2017-10-11 21:05:06 +02:00
|
|
|
/* Read length and command (if we don't have it already). */
|
2018-03-07 00:08:37 +01:00
|
|
|
if (already < ZEBRA_HEADER_SIZE) {
|
|
|
|
nb = stream_read_try(client->ibuf_work, sock,
|
|
|
|
ZEBRA_HEADER_SIZE - already);
|
|
|
|
if ((nb == 0 || nb == -1) && IS_ZEBRA_DEBUG_EVENT)
|
|
|
|
zlog_debug("connection closed socket [%d]",
|
|
|
|
sock);
|
|
|
|
if ((nb == 0 || nb == -1))
|
|
|
|
goto zread_fail;
|
|
|
|
if (nb != (ssize_t)(ZEBRA_HEADER_SIZE - already)) {
|
2017-10-11 21:05:06 +02:00
|
|
|
/* Try again later. */
|
2018-03-07 00:08:37 +01:00
|
|
|
break;
|
2017-10-11 21:05:06 +02:00
|
|
|
}
|
|
|
|
already = ZEBRA_HEADER_SIZE;
|
2017-10-11 14:58:02 +02:00
|
|
|
}
|
|
|
|
|
2017-10-11 21:05:06 +02:00
|
|
|
/* Reset to read from the beginning of the incoming packet. */
|
2018-03-07 00:08:37 +01:00
|
|
|
stream_set_getp(client->ibuf_work, 0);
|
2017-10-11 14:58:02 +02:00
|
|
|
|
2017-10-11 21:05:06 +02:00
|
|
|
/* Fetch header values */
|
2018-03-07 00:08:37 +01:00
|
|
|
hdrvalid = zapi_parse_header(client->ibuf_work, &hdr);
|
2017-10-11 14:58:02 +02:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
if (!hdrvalid) {
|
|
|
|
snprintf(errmsg, sizeof(errmsg),
|
|
|
|
"%s: Message has corrupt header", __func__);
|
|
|
|
zserv_log_message(errmsg, client->ibuf_work, NULL);
|
|
|
|
goto zread_fail;
|
2017-10-11 14:58:02 +02:00
|
|
|
}
|
2018-03-07 00:08:37 +01:00
|
|
|
|
|
|
|
/* Validate header */
|
|
|
|
if (hdr.marker != ZEBRA_HEADER_MARKER
|
|
|
|
|| hdr.version != ZSERV_VERSION) {
|
|
|
|
snprintf(
|
|
|
|
errmsg, sizeof(errmsg),
|
|
|
|
"Message has corrupt header\n%s: socket %d version mismatch, marker %d, version %d",
|
|
|
|
__func__, sock, hdr.marker, hdr.version);
|
|
|
|
zserv_log_message(errmsg, client->ibuf_work, &hdr);
|
|
|
|
goto zread_fail;
|
2017-10-11 21:05:06 +02:00
|
|
|
}
|
2018-03-07 00:08:37 +01:00
|
|
|
if (hdr.length < ZEBRA_HEADER_SIZE) {
|
|
|
|
snprintf(
|
|
|
|
errmsg, sizeof(errmsg),
|
|
|
|
"Message has corrupt header\n%s: socket %d message length %u is less than header size %d",
|
|
|
|
__func__, sock, hdr.length, ZEBRA_HEADER_SIZE);
|
|
|
|
zserv_log_message(errmsg, client->ibuf_work, &hdr);
|
|
|
|
goto zread_fail;
|
|
|
|
}
|
|
|
|
if (hdr.length > STREAM_SIZE(client->ibuf_work)) {
|
|
|
|
snprintf(
|
|
|
|
errmsg, sizeof(errmsg),
|
|
|
|
"Message has corrupt header\n%s: socket %d message length %u exceeds buffer size %lu",
|
|
|
|
__func__, sock, hdr.length,
|
|
|
|
(unsigned long)STREAM_SIZE(client->ibuf_work));
|
|
|
|
goto zread_fail;
|
2017-10-11 14:58:02 +02:00
|
|
|
}
|
|
|
|
|
2017-10-11 21:05:06 +02:00
|
|
|
/* Read rest of data. */
|
2018-03-07 00:08:37 +01:00
|
|
|
if (already < hdr.length) {
|
|
|
|
nb = stream_read_try(client->ibuf_work, sock,
|
|
|
|
hdr.length - already);
|
|
|
|
if ((nb == 0 || nb == -1) && IS_ZEBRA_DEBUG_EVENT)
|
|
|
|
zlog_debug(
|
|
|
|
"connection closed [%d] when reading zebra data",
|
|
|
|
sock);
|
|
|
|
if ((nb == 0 || nb == -1))
|
|
|
|
goto zread_fail;
|
|
|
|
if (nb != (ssize_t)(hdr.length - already)) {
|
2017-10-11 21:05:06 +02:00
|
|
|
/* Try again later. */
|
2018-03-07 00:08:37 +01:00
|
|
|
break;
|
2017-10-11 21:05:06 +02:00
|
|
|
}
|
|
|
|
}
|
2017-10-11 14:58:02 +02:00
|
|
|
|
2017-11-02 15:56:03 +01:00
|
|
|
#if defined(HANDLE_ZAPI_FUZZING)
|
2018-03-07 00:08:37 +01:00
|
|
|
zserv_write_incoming(client->ibuf_work, command);
|
2017-11-02 15:56:03 +01:00
|
|
|
#endif
|
2017-10-11 14:58:02 +02:00
|
|
|
|
2017-10-11 21:05:06 +02:00
|
|
|
/* Debug packet information. */
|
|
|
|
if (IS_ZEBRA_DEBUG_EVENT)
|
2018-03-06 20:02:52 +01:00
|
|
|
zlog_debug("zebra message comes from socket [%d]",
|
|
|
|
sock);
|
2017-10-11 14:58:02 +02:00
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
|
2018-03-07 00:08:37 +01:00
|
|
|
zserv_log_message(NULL, client->ibuf_work, &hdr);
|
2017-10-11 14:58:02 +02:00
|
|
|
|
2017-10-11 21:05:06 +02:00
|
|
|
client->last_read_time = monotime(NULL);
|
2018-03-07 00:08:37 +01:00
|
|
|
client->last_read_cmd = hdr.command;
|
2017-10-11 21:05:06 +02:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
stream_set_getp(client->ibuf_work, 0);
|
|
|
|
struct stream *msg = stream_dup(client->ibuf_work);
|
2017-10-11 21:05:06 +02:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
stream_fifo_push(client->ibuf_fifo, msg);
|
|
|
|
|
|
|
|
if (client->t_suicide)
|
|
|
|
goto zread_fail;
|
|
|
|
|
|
|
|
--packets;
|
|
|
|
stream_reset(client->ibuf_work);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
if (IS_ZEBRA_DEBUG_PACKET)
|
|
|
|
zlog_debug("Read %d packets",
|
|
|
|
zebrad.packets_to_process - packets);
|
|
|
|
|
|
|
|
/* Schedule job to process those packets */
|
|
|
|
thread_add_event(zebrad.master, &zserv_process_messages, client, 0,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
/* Reschedule ourselves */
|
|
|
|
zebra_event(client, ZEBRA_READ);
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2018-03-07 00:08:37 +01:00
|
|
|
|
|
|
|
zread_fail:
|
|
|
|
zebra_client_close(client);
|
|
|
|
return -1;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
static void zebra_event(struct zserv *client, enum event event)
|
|
|
|
{
|
|
|
|
switch (event) {
|
|
|
|
case ZEBRA_READ:
|
|
|
|
thread_add_read(zebrad.master, zserv_read, client, client->sock,
|
|
|
|
&client->t_read);
|
|
|
|
break;
|
|
|
|
case ZEBRA_WRITE:
|
|
|
|
thread_add_write(zebrad.master, zserv_write, client,
|
|
|
|
client->sock, &client->t_write);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* Accept code of zebra server socket. */
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zebra_accept(struct thread *thread)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
int accept_sock;
|
|
|
|
int client_sock;
|
|
|
|
struct sockaddr_in client;
|
|
|
|
socklen_t len;
|
|
|
|
|
|
|
|
accept_sock = THREAD_FD(thread);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Reregister myself. */
|
2018-03-07 00:08:37 +01:00
|
|
|
thread_add_read(zebrad.master, zebra_accept, NULL, accept_sock, NULL);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
len = sizeof(struct sockaddr_in);
|
|
|
|
client_sock = accept(accept_sock, (struct sockaddr *)&client, &len);
|
2005-02-28 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* zserv.c: Must include network.h and buffer.h for non-blocking I/O.
Remove global message_queue and t_write (need separate buffering for
each client).
(zebra_server_dequeue,zebra_server_enqueue) Remove functions
related to old buggy buffering code.
(zserv_delayed_close) New thread callback function to delete a client.
(zserv_flush_data) New thread callback function to flush buffered
data to client.
(zebra_server_send_message) Rewritten to use buffer_write (so
buffering of writes and non-blocking I/O work properly).
(zsend_interface_add,zsend_interface_delete,zsend_interface_address,
zsend_interface_update) Return 0 instead of -1 if !client->ifinfo
(this is not really an error). Return value from
zebra_server_send_message.
(zsend_route_multipath,zsend_ipv4_nexthop_lookup,
zsend_ipv4_import_lookup) Return value from zebra_server_send_message.
(zsend_ipv6_nexthop_lookup) Fix scope to static, and return value
from zebra_server_send_message.
(zsend_router_id_update) Must use zebra_server_send_message instead
of deprecated writen function. Return 0 instead of -1 if this client
is not subscribed to router-id updates (since this is not really
an error).
(zread_interface_add) Change type to static int. If
zsend_interface_add fails or zsend_interface_address fails, return -1
immediately (since the client has had an I/O error).
(zread_interface_delete,zread_ipv4_add,zread_ipv4_delete,
zread_ipv6_add,zread_ipv6_delete,zread_router_id_delete) Return 0
to indicate success.
(zread_ipv4_nexthop_lookup) Return value from
zsend_ipv4_nexthop_lookup.
(zread_ipv4_import_lookup) Return value from zsend_ipv4_import_lookup.
(zebra_read_ipv6) Remove unused function.
(zread_ipv6_nexthop_lookup) Return value from
zsend_ipv6_nexthop_lookup.
(zread_router_id_add) Return value from zsend_router_id_update.
(zebra_client_close) Call buffer_free(client->wb) and
thread_cancel(client->t_suicide).
(zebra_client_create) Allocate client->wb using buffer_new.
(zebra_client_read) Support non-blocking I/O by using stream_read_try.
Use ZEBRA_HEADER_SIZE instead of 3.
(zebra_accept) Fix bug: reset accept thread at top. Make client
socket non-blocking using the set_nonblocking function.
(config_write_forwarding) Fix scope to static.
(zebra_init) Remove initialization code for old buggy write buffering.
* zserv.h: Add 2 new fields to struct zserv: struct buffer *wb
(to enable buffered writes with non-blocking I/), and
struct thread *t_suicide to support delayed close on I/O
errors.
* router-id.h: Remove prototypes for zread_router_id_add and
zread_router_id_delete (their scope should be static to zserv.c).
2005-02-28 21:52:15 +01:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (client_sock < 0) {
|
|
|
|
zlog_warn("Can't accept zebra socket: %s",
|
|
|
|
safe_strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Make client socket non-blocking. */
|
|
|
|
set_nonblocking(client_sock);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Create new zebra client. */
|
|
|
|
zebra_client_create(client_sock);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2017-08-06 07:35:50 +02:00
|
|
|
/* Make zebra server socket, wiping any existing one (see bug #403). */
|
|
|
|
void zebra_zserv_socket_init(char *path)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
|
|
|
int ret;
|
2017-08-06 07:35:50 +02:00
|
|
|
int sock;
|
2017-07-17 14:03:14 +02:00
|
|
|
mode_t old_mask;
|
2017-08-06 07:35:50 +02:00
|
|
|
struct sockaddr_storage sa;
|
|
|
|
socklen_t sa_len;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-08-06 07:35:50 +02:00
|
|
|
if (!frr_zclient_addr(&sa, &sa_len, path))
|
|
|
|
/* should be caught in zebra main() */
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
/* Set umask */
|
|
|
|
old_mask = umask(0077);
|
|
|
|
|
|
|
|
/* Make UNIX domain socket. */
|
2017-08-06 07:35:50 +02:00
|
|
|
sock = socket(sa.ss_family, SOCK_STREAM, 0);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (sock < 0) {
|
2017-08-06 07:35:50 +02:00
|
|
|
zlog_warn("Can't create zserv socket: %s",
|
2017-07-17 14:03:14 +02:00
|
|
|
safe_strerror(errno));
|
|
|
|
zlog_warn(
|
|
|
|
"zebra can't provide full functionality due to above error");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-08-06 07:35:50 +02:00
|
|
|
if (sa.ss_family != AF_UNIX) {
|
|
|
|
sockopt_reuseaddr(sock);
|
|
|
|
sockopt_reuseport(sock);
|
|
|
|
} else {
|
|
|
|
struct sockaddr_un *suna = (struct sockaddr_un *)&sa;
|
|
|
|
if (suna->sun_path[0])
|
|
|
|
unlink(suna->sun_path);
|
|
|
|
}
|
|
|
|
|
2017-10-11 15:16:46 +02:00
|
|
|
zserv_privs.change(ZPRIVS_RAISE);
|
|
|
|
setsockopt_so_recvbuf(sock, 1048576);
|
|
|
|
setsockopt_so_sendbuf(sock, 1048576);
|
|
|
|
zserv_privs.change(ZPRIVS_LOWER);
|
|
|
|
|
2017-08-12 21:02:42 +02:00
|
|
|
if (sa.ss_family != AF_UNIX && zserv_privs.change(ZPRIVS_RAISE))
|
2017-08-06 07:35:50 +02:00
|
|
|
zlog_err("Can't raise privileges");
|
|
|
|
|
|
|
|
ret = bind(sock, (struct sockaddr *)&sa, sa_len);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (ret < 0) {
|
2017-08-06 07:35:50 +02:00
|
|
|
zlog_warn("Can't bind zserv socket on %s: %s", path,
|
2017-07-17 14:03:14 +02:00
|
|
|
safe_strerror(errno));
|
|
|
|
zlog_warn(
|
|
|
|
"zebra can't provide full functionality due to above error");
|
|
|
|
close(sock);
|
|
|
|
return;
|
|
|
|
}
|
2017-08-12 21:02:42 +02:00
|
|
|
if (sa.ss_family != AF_UNIX && zserv_privs.change(ZPRIVS_LOWER))
|
2017-08-06 07:35:50 +02:00
|
|
|
zlog_err("Can't lower privileges");
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
ret = listen(sock, 5);
|
|
|
|
if (ret < 0) {
|
2017-08-06 07:35:50 +02:00
|
|
|
zlog_warn("Can't listen to zserv socket %s: %s", path,
|
2017-07-17 14:03:14 +02:00
|
|
|
safe_strerror(errno));
|
|
|
|
zlog_warn(
|
|
|
|
"zebra can't provide full functionality due to above error");
|
|
|
|
close(sock);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
umask(old_mask);
|
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
thread_add_read(zebrad.master, zebra_accept, NULL, sock, NULL);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2014-06-04 06:53:35 +02:00
|
|
|
|
2015-05-20 02:47:22 +02:00
|
|
|
#define ZEBRA_TIME_BUF 32
|
2017-07-17 14:03:14 +02:00
|
|
|
static char *zserv_time_buf(time_t *time1, char *buf, int buflen)
|
2015-05-20 02:47:22 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct tm *tm;
|
|
|
|
time_t now;
|
2015-05-20 02:47:22 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
assert(buf != NULL);
|
|
|
|
assert(buflen >= ZEBRA_TIME_BUF);
|
|
|
|
assert(time1 != NULL);
|
2015-05-20 02:47:22 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!*time1) {
|
|
|
|
snprintf(buf, buflen, "never ");
|
|
|
|
return (buf);
|
|
|
|
}
|
2015-05-20 02:47:22 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
now = monotime(NULL);
|
|
|
|
now -= *time1;
|
|
|
|
tm = gmtime(&now);
|
2015-05-20 02:47:22 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (now < ONE_DAY_SECOND)
|
|
|
|
snprintf(buf, buflen, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
|
|
|
|
tm->tm_sec);
|
|
|
|
else if (now < ONE_WEEK_SECOND)
|
|
|
|
snprintf(buf, buflen, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour,
|
|
|
|
tm->tm_min);
|
2017-06-21 05:10:57 +02:00
|
|
|
else
|
2017-07-17 14:03:14 +02:00
|
|
|
snprintf(buf, buflen, "%02dw%dd%02dh", tm->tm_yday / 7,
|
|
|
|
tm->tm_yday - ((tm->tm_yday / 7) * 7), tm->tm_hour);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
|
|
|
|
{
|
|
|
|
char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF];
|
|
|
|
char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF];
|
|
|
|
|
|
|
|
vty_out(vty, "Client: %s", zebra_route_string(client->proto));
|
|
|
|
if (client->instance)
|
|
|
|
vty_out(vty, " Instance: %d", client->instance);
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
|
|
|
|
vty_out(vty, "------------------------ \n");
|
|
|
|
vty_out(vty, "FD: %d \n", client->sock);
|
|
|
|
vty_out(vty, "Route Table ID: %d \n", client->rtm_table);
|
|
|
|
|
|
|
|
vty_out(vty, "Connect Time: %s \n",
|
|
|
|
zserv_time_buf(&client->connect_time, cbuf, ZEBRA_TIME_BUF));
|
|
|
|
if (client->nh_reg_time) {
|
|
|
|
vty_out(vty, "Nexthop Registry Time: %s \n",
|
|
|
|
zserv_time_buf(&client->nh_reg_time, nhbuf,
|
|
|
|
ZEBRA_TIME_BUF));
|
|
|
|
if (client->nh_last_upd_time)
|
|
|
|
vty_out(vty, "Nexthop Last Update Time: %s \n",
|
|
|
|
zserv_time_buf(&client->nh_last_upd_time, mbuf,
|
|
|
|
ZEBRA_TIME_BUF));
|
|
|
|
else
|
|
|
|
vty_out(vty, "No Nexthop Update sent\n");
|
|
|
|
} else
|
|
|
|
vty_out(vty, "Not registered for Nexthop Updates\n");
|
|
|
|
|
|
|
|
vty_out(vty, "Last Msg Rx Time: %s \n",
|
|
|
|
zserv_time_buf(&client->last_read_time, rbuf, ZEBRA_TIME_BUF));
|
|
|
|
vty_out(vty, "Last Msg Tx Time: %s \n",
|
|
|
|
zserv_time_buf(&client->last_write_time, wbuf, ZEBRA_TIME_BUF));
|
|
|
|
if (client->last_read_time)
|
|
|
|
vty_out(vty, "Last Rcvd Cmd: %s \n",
|
|
|
|
zserv_command_string(client->last_read_cmd));
|
|
|
|
if (client->last_write_time)
|
|
|
|
vty_out(vty, "Last Sent Cmd: %s \n",
|
|
|
|
zserv_command_string(client->last_write_cmd));
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
|
|
|
|
vty_out(vty, "Type Add Update Del \n");
|
|
|
|
vty_out(vty, "================================================== \n");
|
|
|
|
vty_out(vty, "IPv4 %-12d%-12d%-12d\n", client->v4_route_add_cnt,
|
|
|
|
client->v4_route_upd8_cnt, client->v4_route_del_cnt);
|
|
|
|
vty_out(vty, "IPv6 %-12d%-12d%-12d\n", client->v6_route_add_cnt,
|
|
|
|
client->v6_route_upd8_cnt, client->v6_route_del_cnt);
|
|
|
|
vty_out(vty, "Redist:v4 %-12d%-12d%-12d\n", client->redist_v4_add_cnt,
|
|
|
|
0, client->redist_v4_del_cnt);
|
|
|
|
vty_out(vty, "Redist:v6 %-12d%-12d%-12d\n", client->redist_v6_add_cnt,
|
|
|
|
0, client->redist_v6_del_cnt);
|
|
|
|
vty_out(vty, "Connected %-12d%-12d%-12d\n", client->ifadd_cnt, 0,
|
|
|
|
client->ifdel_cnt);
|
|
|
|
vty_out(vty, "BFD peer %-12d%-12d%-12d\n", client->bfd_peer_add_cnt,
|
|
|
|
client->bfd_peer_upd8_cnt, client->bfd_peer_del_cnt);
|
|
|
|
vty_out(vty, "Interface Up Notifications: %d\n", client->ifup_cnt);
|
|
|
|
vty_out(vty, "Interface Down Notifications: %d\n", client->ifdown_cnt);
|
|
|
|
vty_out(vty, "VNI add notifications: %d\n", client->vniadd_cnt);
|
|
|
|
vty_out(vty, "VNI delete notifications: %d\n", client->vnidel_cnt);
|
2017-10-08 03:49:27 +02:00
|
|
|
vty_out(vty, "L3-VNI add notifications: %d\n", client->l3vniadd_cnt);
|
|
|
|
vty_out(vty, "L3-VNI delete notifications: %d\n", client->l3vnidel_cnt);
|
2017-07-17 14:03:14 +02:00
|
|
|
vty_out(vty, "MAC-IP add notifications: %d\n", client->macipadd_cnt);
|
|
|
|
vty_out(vty, "MAC-IP delete notifications: %d\n", client->macipdel_cnt);
|
|
|
|
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void zebra_show_client_brief(struct vty *vty, struct zserv *client)
|
|
|
|
{
|
|
|
|
char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF];
|
|
|
|
char wbuf[ZEBRA_TIME_BUF];
|
|
|
|
|
|
|
|
vty_out(vty, "%-8s%12s %12s%12s%8d/%-8d%8d/%-8d\n",
|
|
|
|
zebra_route_string(client->proto),
|
|
|
|
zserv_time_buf(&client->connect_time, cbuf, ZEBRA_TIME_BUF),
|
|
|
|
zserv_time_buf(&client->last_read_time, rbuf, ZEBRA_TIME_BUF),
|
|
|
|
zserv_time_buf(&client->last_write_time, wbuf, ZEBRA_TIME_BUF),
|
|
|
|
client->v4_route_add_cnt + client->v4_route_upd8_cnt,
|
|
|
|
client->v4_route_del_cnt,
|
|
|
|
client->v6_route_add_cnt + client->v6_route_upd8_cnt,
|
|
|
|
client->v6_route_del_cnt);
|
|
|
|
}
|
|
|
|
|
2018-03-27 21:13:34 +02:00
|
|
|
struct zserv *zebra_find_client(uint8_t proto, unsigned short instance)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
|
|
|
struct listnode *node, *nnode;
|
|
|
|
struct zserv *client;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) {
|
2018-03-06 20:02:52 +01:00
|
|
|
if (client->proto == proto && client->instance == instance)
|
2017-07-17 14:03:14 +02:00
|
|
|
return client;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2016-07-21 17:50:17 +02:00
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* This command is for debugging purpose. */
|
|
|
|
DEFUN (show_zebra_client,
|
|
|
|
show_zebra_client_cmd,
|
|
|
|
"show zebra client",
|
|
|
|
SHOW_STR
|
2017-10-25 16:52:24 +02:00
|
|
|
ZEBRA_STR
|
2017-01-30 01:07:04 +01:00
|
|
|
"Client information\n")
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct listnode *node;
|
|
|
|
struct zserv *client;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client))
|
|
|
|
zebra_show_client_detail(vty, client);
|
2015-05-20 02:47:22 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return CMD_SUCCESS;
|
2015-05-20 02:47:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* This command is for debugging purpose. */
|
|
|
|
DEFUN (show_zebra_client_summary,
|
|
|
|
show_zebra_client_summary_cmd,
|
|
|
|
"show zebra client summary",
|
|
|
|
SHOW_STR
|
2017-10-25 16:52:24 +02:00
|
|
|
ZEBRA_STR
|
2017-01-30 01:07:04 +01:00
|
|
|
"Client information brief\n"
|
|
|
|
"Brief Summary\n")
|
2015-05-20 02:47:22 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct listnode *node;
|
|
|
|
struct zserv *client;
|
2015-05-20 02:47:22 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
vty_out(vty,
|
|
|
|
"Name Connect Time Last Read Last Write IPv4 Routes IPv6 Routes \n");
|
|
|
|
vty_out(vty,
|
|
|
|
"--------------------------------------------------------------------------------\n");
|
2015-05-20 02:47:22 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client))
|
|
|
|
zebra_show_client_brief(vty, client);
|
2015-05-20 02:40:34 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
vty_out(vty, "Routes column shows (added+updated)/deleted\n");
|
|
|
|
return CMD_SUCCESS;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2017-11-02 15:56:03 +01:00
|
|
|
#if defined(HANDLE_ZAPI_FUZZING)
|
|
|
|
void zserv_read_file(char *input)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
struct zserv *client = NULL;
|
|
|
|
struct thread t;
|
|
|
|
|
|
|
|
zebra_client_create(-1);
|
|
|
|
client = zebrad.client_list->head->data;
|
|
|
|
t.arg = client;
|
|
|
|
|
2018-03-06 20:02:52 +01:00
|
|
|
fd = open(input, O_RDONLY | O_NONBLOCK);
|
2017-11-02 15:56:03 +01:00
|
|
|
t.u.fd = fd;
|
|
|
|
|
|
|
|
zebra_client_read(&t);
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-12-06 02:21:37 +01:00
|
|
|
void zserv_init(void)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Client list init. */
|
|
|
|
zebrad.client_list = list_new();
|
2017-09-20 18:52:38 +02:00
|
|
|
zebrad.client_list->del = (void (*)(void *))zebra_client_free;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
install_element(ENABLE_NODE, &show_zebra_client_cmd);
|
|
|
|
install_element(ENABLE_NODE, &show_zebra_client_summary_cmd);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|