frr/lib/zclient.c
Feng Lu 7076bb2f52 *: add VRF ID in the API message header
The API messages are used by zebra to exchange the interfaces, addresses,
routes and router-id information with its clients. To distinguish which
VRF the information belongs to, a new field "VRF ID" is added in the
message header. And hence the message version is increased to 3.

* The new field "VRF ID" in the message header:

    Length    (2 bytes)
    Marker    (1 byte)
    Version   (1 byte)
    VRF ID    (2 bytes, newly added)
    Command   (2 bytes)

  - Client side:

    - zclient_create_header() adds the VRF ID in the message header.
    - zclient_read() extracts and validates the VRF ID from the header,
      and passes the VRF ID to the callback functions registered to
      the API messages.
    - All relative functions are appended with a new parameter "vrf_id",
      including all the callback functions.
    - "vrf_id" is also added to "struct zapi_ipv4" and "struct zapi_ipv6".
      Clients need to correctly set the VRF ID when using the API
      functions zapi_ipv4_route() and zapi_ipv6_route().
    - Till now all messages sent from a client have the default VRF ID
      "0" in the header.
    - The HELLO message is special, which is used as the heart-beat of
      a client, and has no relation with VRF. The VRF ID in the HELLO
      message header will always be 0 and ignored by zebra.

  - Zebra side:

    - zserv_create_header() adds the VRF ID in the message header.
    - zebra_client_read() extracts and validates the VRF ID from the
      header, and passes the VRF ID to the functions which process
      the received messages.
    - All relative functions are appended with a new parameter "vrf_id".

* Suppress the messages in a VRF which a client does not care:

  Some clients may not care about the information in the VRF X, and
  zebra should not send the messages in the VRF X to those clients.

  Extra flags are used to indicate which VRF is registered by a client,
  and a new message ZEBRA_VRF_UNREGISTER is introduced to let a client
  can unregister a VRF when it does not need any information in that
  VRF.

  A client sends any message other than ZEBRA_VRF_UNREGISTER in a VRF
  will automatically register to that VRF.

  - lib/vrf:

    A new utility "VRF bit-map" is provided to manage the flags for
    VRFs, one bit per VRF ID.

    - Use vrf_bitmap_init()/vrf_bitmap_free() to initialize/free a
      bit-map;
    - Use vrf_bitmap_set()/vrf_bitmap_unset() to set/unset a flag
      in the given bit-map, corresponding to the given VRF ID;
    - Use vrf_bitmap_check() to test whether the flag, in the given
      bit-map and for the given VRF ID, is set.

  - Client side:

    - In "struct zclient", the following flags are changed from
      "u_char" to "vrf_bitmap_t":
          redist[ZEBRA_ROUTE_MAX]
          default_information
      These flags are extended for each VRF, and controlled by the
      clients themselves (or with the help of zclient_redistribute()
      and zclient_redistribute_default()).

  - Zebra side:

    - In "struct zserv", the following flags are changed from
      "u_char" to "vrf_bitmap_t":
          redist[ZEBRA_ROUTE_MAX]
          redist_default
          ifinfo
          ridinfo

      These flags are extended for each VRF, as the VRF registration
      flags. They are maintained on receiving a ZEBRA_XXX_ADD or
      ZEBRA_XXX_DELETE message.

      When sending an interface/address/route/router-id message in
      a VRF to a client, if the corresponding VRF registration flag
      is not set, this message will not be dropped by zebra.

    - A new function zread_vrf_unregister() is introduced to process
      the new command ZEBRA_VRF_UNREGISTER. All the VRF registration
      flags are cleared for the requested VRF.

  Those clients, who support only the default VRF, will never receive
  a message in a non-default VRF, thanks to the filter in zebra.

* New callback for the event of successful connection to zebra:

  - zclient_start() is splitted, keeping only the code of connecting
    to zebra.

  - Now zclient_init()=>zclient_connect()=>zclient_start() operations
    are purely dealing with the connection to zbera.

  - Once zebra is successfully connected, at the end of zclient_start(),
    a new callback is used to inform the client about connection.

  - Till now, in the callback of connect-to-zebra event, all clients
    send messages to zebra to request the router-id/interface/routes
    information in the default VRF.

    Of corse in future the client can do anything it wants in this
    callback. For example, it may send requests for both default VRF
    and some non-default VRFs.

Signed-off-by: Feng Lu <lu.feng@6wind.com>
Reviewed-by: Alain Ritoux <alain.ritoux@6wind.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Acked-by: Donald Sharp <sharpd@cumulusnetworks.com>

Conflicts:
	lib/zclient.h
	lib/zebra.h
	zebra/zserv.c
	zebra/zserv.h

Conflicts:
	bgpd/bgp_nexthop.c
	bgpd/bgp_nht.c
	bgpd/bgp_zebra.c
	isisd/isis_zebra.c
	lib/zclient.c
	lib/zclient.h
	lib/zebra.h
	nhrpd/nhrp_interface.c
	nhrpd/nhrp_route.c
	nhrpd/nhrpd.h
	ospf6d/ospf6_zebra.c
	ospf6d/ospf6_zebra.h
	ospfd/ospf_vty.c
	ospfd/ospf_zebra.c
	pimd/pim_zebra.c
	pimd/pim_zlookup.c
	ripd/rip_zebra.c
	ripngd/ripng_zebra.c
	zebra/redistribute.c
	zebra/rt_netlink.c
	zebra/zebra_rnh.c
	zebra/zebra_rnh.h
	zebra/zserv.c
	zebra/zserv.h
2015-11-03 22:04:36 -08:00

1450 lines
40 KiB
C

/* Zebra's client library.
* Copyright (C) 1999 Kunihiro Ishiguro
* Copyright (C) 2005 Andrew J. Schorr
*
* This file is part of GNU Zebra.
*
* GNU Zebra 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, or (at your
* option) any later version.
*
* GNU Zebra 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.
*
* You should have received a copy of the GNU General Public License
* along with GNU Zebra; see the file COPYING. If not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include <zebra.h>
#include "prefix.h"
#include "stream.h"
#include "buffer.h"
#include "network.h"
#include "if.h"
#include "log.h"
#include "thread.h"
#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 *);
char *zclient_serv_path = NULL;
/* This file local debug flag. */
int zclient_debug = 0;
/* Allocate zclient structure. */
struct zclient *
zclient_new (struct thread_master *master)
{
struct zclient *zclient;
zclient = XCALLOC (MTYPE_ZCLIENT, sizeof (struct zclient));
zclient->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
zclient->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
zclient->wb = buffer_new(0);
zclient->master = master;
return zclient;
}
/* This function is only called when exiting, because
many parts of the code do not check for I/O errors, so they could
reference an invalid pointer if the structure was ever freed.
Free zclient structure. */
void
zclient_free (struct zclient *zclient)
{
if (zclient->ibuf)
stream_free(zclient->ibuf);
if (zclient->obuf)
stream_free(zclient->obuf);
if (zclient->wb)
buffer_free(zclient->wb);
XFREE (MTYPE_ZCLIENT, zclient);
}
int
redist_check_instance (struct redist_proto *red, u_short instance)
{
struct listnode *node;
u_short *id;
if (!red->instances)
return 0;
for (ALL_LIST_ELEMENTS_RO (red->instances, node, id))
if (*id == instance)
return 1;
return 0;
}
void
redist_add_instance (struct redist_proto *red, u_short instance)
{
u_short *in;
red->enabled = 1;
if (!red->instances)
red->instances = list_new();
in = (u_short *)calloc(1, sizeof(u_short));
*in = instance;
listnode_add (red->instances, in);
}
void
redist_del_instance (struct redist_proto *red, u_short instance)
{
struct listnode *node;
u_short *id = NULL;
if (!red->instances)
return;
for (ALL_LIST_ELEMENTS_RO (red->instances, node, id))
if (*id == instance)
break;
if (id)
{
listnode_delete(red->instances, id);
if (!red->instances->count)
{
red->enabled = 0;
list_free(red->instances);
red->instances = NULL;
}
}
}
/* Stop zebra client services. */
void
zclient_stop (struct zclient *zclient)
{
if (zclient_debug)
zlog_debug ("zclient stopped");
/* Stop threads. */
THREAD_OFF(zclient->t_read);
THREAD_OFF(zclient->t_connect);
THREAD_OFF(zclient->t_write);
/* Reset streams. */
stream_reset(zclient->ibuf);
stream_reset(zclient->obuf);
/* Empty the write buffer. */
buffer_reset(zclient->wb);
/* Close socket. */
if (zclient->sock >= 0)
{
close (zclient->sock);
zclient->sock = -1;
}
zclient->fail = 0;
}
void
zclient_reset (struct zclient *zclient)
{
afi_t afi;
zclient_stop (zclient);
for (afi = AFI_IP; afi < AFI_MAX; afi++)
redist_del_instance (&zclient->mi_redist[afi][zclient->redist_default], zclient->instance);
zclient_init (zclient, zclient->redist_default, zclient->instance);
}
#ifdef HAVE_TCP_ZEBRA
/* Make socket to zebra daemon. Return zebra socket. */
static int
zclient_socket(void)
{
int sock;
int ret;
struct sockaddr_in serv;
/* We should think about IPv6 connection. */
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock < 0)
return -1;
/* Make server socket. */
memset (&serv, 0, sizeof (struct sockaddr_in));
serv.sin_family = AF_INET;
serv.sin_port = htons (ZEBRA_PORT);
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
serv.sin_len = sizeof (struct sockaddr_in);
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
/* Connect to zebra. */
ret = connect (sock, (struct sockaddr *) &serv, sizeof (serv));
if (ret < 0)
{
close (sock);
return -1;
}
return sock;
}
#else
/* For sockaddr_un. */
#include <sys/un.h>
static int
zclient_socket_un (const char *path)
{
int ret;
int sock, len;
struct sockaddr_un addr;
sock = socket (AF_UNIX, SOCK_STREAM, 0);
if (sock < 0)
return -1;
/* Make server socket. */
memset (&addr, 0, sizeof (struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy (addr.sun_path, path, strlen (path));
#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
len = addr.sun_len = SUN_LEN(&addr);
#else
len = sizeof (addr.sun_family) + strlen (addr.sun_path);
#endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */
ret = connect (sock, (struct sockaddr *) &addr, len);
if (ret < 0)
{
close (sock);
return -1;
}
return sock;
}
#endif /* HAVE_TCP_ZEBRA */
/**
* Connect to zebra daemon.
* @param zclient a pointer to zclient structure
* @return socket fd just to make sure that connection established
* @see zclient_init
* @see zclient_new
*/
int
zclient_socket_connect (struct zclient *zclient)
{
#ifdef HAVE_TCP_ZEBRA
zclient->sock = zclient_socket ();
#else
zclient->sock = zclient_socket_un (zclient_serv_path ? zclient_serv_path : ZEBRA_SERV_PATH);
#endif
return zclient->sock;
}
static int
zclient_failed(struct zclient *zclient)
{
zclient->fail++;
zclient_stop(zclient);
zclient_event(ZCLIENT_CONNECT, zclient);
return -1;
}
static int
zclient_flush_data(struct thread *thread)
{
struct zclient *zclient = THREAD_ARG(thread);
zclient->t_write = NULL;
if (zclient->sock < 0)
return -1;
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);
return zclient_failed(zclient);
break;
case BUFFER_PENDING:
zclient->t_write = thread_add_write(zclient->master, zclient_flush_data,
zclient, zclient->sock);
break;
case BUFFER_EMPTY:
break;
}
return 0;
}
int
zclient_send_message(struct zclient *zclient)
{
if (zclient->sock < 0)
return -1;
switch (buffer_write(zclient->wb, zclient->sock, STREAM_DATA(zclient->obuf),
stream_get_endp(zclient->obuf)))
{
case BUFFER_ERROR:
zlog_warn("%s: buffer_write failed to zclient fd %d, closing",
__func__, zclient->sock);
return zclient_failed(zclient);
break;
case BUFFER_EMPTY:
THREAD_OFF(zclient->t_write);
break;
case BUFFER_PENDING:
THREAD_WRITE_ON(zclient->master, zclient->t_write,
zclient_flush_data, zclient, zclient->sock);
break;
}
return 0;
}
void
zclient_create_header (struct stream *s, uint16_t command, vrf_id_t vrf_id)
{
/* 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, vrf_id);
stream_putw (s, command);
}
/* Send simple Zebra message. */
static int
zebra_message_send (struct zclient *zclient, int command, vrf_id_t vrf_id)
{
struct stream *s;
/* Get zclient output buffer. */
s = zclient->obuf;
stream_reset (s);
/* Send very simple command only Zebra message. */
zclient_create_header (s, command, vrf_id);
return zclient_send_message(zclient);
}
static int
zebra_hello_send (struct zclient *zclient)
{
struct stream *s;
if (zclient->redist_default)
{
s = zclient->obuf;
stream_reset (s);
/* The VRF ID in the HELLO message is always 0. */
zclient_create_header (s, ZEBRA_HELLO, VRF_DEFAULT);
stream_putc (s, zclient->redist_default);
stream_putw (s, zclient->instance);
stream_putw_at (s, 0, stream_get_endp (s));
return zclient_send_message(zclient);
}
return 0;
}
/* Send requests to zebra daemon for the information in a VRF. */
void
zclient_send_requests (struct zclient *zclient, vrf_id_t vrf_id)
{
int i;
afi_t afi;
/* zclient is disabled. */
if (! zclient->enable)
return;
/* If not connected to the zebra yet. */
if (zclient->sock < 0)
return;
if (zclient_debug)
zlog_debug ("%s: send messages for VRF %u", __func__, vrf_id);
/* We need router-id information. */
zebra_message_send (zclient, ZEBRA_ROUTER_ID_ADD, vrf_id);
/* We need interface information. */
zebra_message_send (zclient, ZEBRA_INTERFACE_ADD, vrf_id);
/* Set unwanted redistribute route. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
vrf_bitmap_set (zclient->redist[afi][zclient->redist_default], vrf_id);
/* Flush all redistribute request. */
if (vrf_id == VRF_DEFAULT)
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
if (zclient->mi_redist[afi][i].enabled)
{
struct listnode *node;
u_short *id;
for (ALL_LIST_ELEMENTS_RO(zclient->mi_redist[afi][i].instances, node, id))
if (!(i == zclient->redist_default && *id == zclient->instance))
zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, afi, i,
*id, VRF_DEFAULT);
}
/* Flush all redistribute request. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
if (i != zclient->redist_default &&
vrf_bitmap_check (zclient->redist[afi][i], vrf_id))
zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, afi, i, 0, vrf_id);
/* If default information is needed. */
if (vrf_bitmap_check (zclient->default_information, VRF_DEFAULT))
zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_ADD, vrf_id);
}
/* Make connection to zebra daemon. */
int
zclient_start (struct zclient *zclient)
{
if (zclient_debug)
zlog_info ("zclient_start is called");
/* zclient is disabled. */
if (! zclient->enable)
return 0;
/* If already connected to the zebra. */
if (zclient->sock >= 0)
return 0;
/* Check connect thread. */
if (zclient->t_connect)
return 0;
if (zclient_socket_connect(zclient) < 0)
{
if (zclient_debug)
zlog_debug ("zclient connection fail");
zclient->fail++;
zclient_event (ZCLIENT_CONNECT, zclient);
return -1;
}
if (set_nonblocking(zclient->sock) < 0)
zlog_warn("%s: set_nonblocking(%d) failed", __func__, zclient->sock);
/* Clear fail count. */
zclient->fail = 0;
if (zclient_debug)
zlog_debug ("zclient connect success with socket [%d]", zclient->sock);
/* Create read thread. */
zclient_event (ZCLIENT_READ, zclient);
zebra_hello_send (zclient);
/* Inform the successful connection. */
if (zclient->zebra_connected)
(*zclient->zebra_connected) (zclient);
return 0;
}
/* Initialize zebra client. Argument redist_default is unwanted
redistribute route type. */
void
zclient_init (struct zclient *zclient, int redist_default, u_short instance)
{
int afi, i;
/* Enable zebra client connection by default. */
zclient->enable = 1;
/* Set -1 to the default socket value. */
zclient->sock = -1;
/* Clear redistribution flags. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
zclient->redist[afi][i] = vrf_bitmap_init();
/* Set unwanted redistribute route. bgpd does not need BGP route
redistribution. */
zclient->redist_default = redist_default;
zclient->instance = instance;
/* Pending: make afi(s) an arg. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
redist_add_instance (&zclient->mi_redist[afi][redist_default], instance);
/* Set default-information redistribute to zero. */
zclient->default_information = vrf_bitmap_init ();;
if (zclient_debug)
zlog_debug ("zclient_start is called");
zclient_event (ZCLIENT_SCHEDULE, zclient);
}
/* This function is a wrapper function for calling zclient_start from
timer or event thread. */
static int
zclient_connect (struct thread *t)
{
struct zclient *zclient;
zclient = THREAD_ARG (t);
zclient->t_connect = NULL;
if (zclient_debug)
zlog_debug ("zclient_connect is called");
return zclient_start (zclient);
}
/*
* "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().
*
* 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Length (2) | Command | Route Type |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | ZEBRA Flags | Message Flags | Prefix length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Destination IPv4 Prefix for route |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Nexthop count |
* +-+-+-+-+-+-+-+-+
*
*
* A number of IPv4 nexthop(s) or nexthop interface index(es) are then
* described, as per the Nexthop count. Each nexthop described as:
*
* +-+-+-+-+-+-+-+-+
* | Nexthop Type | Set to one of ZEBRA_NEXTHOP_*
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | IPv4 Nexthop address or Interface Index number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* Alternatively, if the flags field has ZEBRA_FLAG_BLACKHOLE or
* 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.
*
* The original struct zapi_ipv4, zapi_ipv4_route() and zread_ipv4_*()
* infrastructure was built around the traditional (32-bit "gate OR
* ifindex") nexthop data unit. A special encoding can be used to feed
* onlink (64-bit "gate AND ifindex") nexthops into zapi_ipv4_route()
* using the same zapi_ipv4 structure. This is done by setting zapi_ipv4
* fields as follows:
* - .message |= ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_ONLINK
* - .nexthop_num == .ifindex_num
* - .nexthop and .ifindex are filled with gate and ifindex parts of
* each compound nexthop, both in the same order
*
* zapi_ipv4_route() will produce two nexthop data units for each such
* interleaved 64-bit nexthop. On the zserv side of the socket it will be
* mapped to a singlle NEXTHOP_TYPE_IPV4_IFINDEX_OL RIB nexthop structure.
*
* 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.
*
* If ZAPI_MESSAGE_TAG is set, the tag value is written as a 2 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)
{
int i;
int psize;
struct stream *s;
/* Reset stream. */
s = zclient->obuf;
stream_reset (s);
zclient_create_header (s, cmd, api->vrf_id);
/* Put type and nexthop. */
stream_putc (s, api->type);
stream_putw (s, api->instance);
stream_putc (s, api->flags);
stream_putc (s, api->message);
stream_putw (s, api->safi);
/* Put prefix information. */
psize = PSIZE (p->prefixlen);
stream_putc (s, p->prefixlen);
stream_write (s, (u_char *) & p->prefix, psize);
/* Nexthop, ifindex, distance and metric information. */
/* ZAPI_MESSAGE_ONLINK implies interleaving */
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_ONLINK))
{
/* ZAPI_MESSAGE_NEXTHOP is required for proper receiving */
assert (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP));
/* 64-bit data units, interleaved between nexthop[] and ifindex[] */
assert (api->nexthop_num == api->ifindex_num);
stream_putc (s, api->nexthop_num * 2);
for (i = 0; i < api->nexthop_num; i++)
{
stream_putc (s, ZEBRA_NEXTHOP_IPV4_ONLINK);
stream_put_in_addr (s, api->nexthop[i]);
stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
stream_putl (s, api->ifindex[i]);
}
}
else if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
{
/* traditional 32-bit data units */
if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE))
{
stream_putc (s, 1);
stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE);
/* XXX assert(api->nexthop_num == 0); */
/* XXX assert(api->ifindex_num == 0); */
}
else
stream_putc (s, api->nexthop_num + api->ifindex_num);
for (i = 0; i < api->nexthop_num; i++)
{
stream_putc (s, ZEBRA_NEXTHOP_IPV4);
stream_put_in_addr (s, api->nexthop[i]);
}
for (i = 0; i < api->ifindex_num; i++)
{
stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
stream_putl (s, api->ifindex[i]);
}
}
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE))
stream_putc (s, api->distance);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
stream_putl (s, api->metric);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG))
stream_putw (s, api->tag);
/* Put length at the first point of the stream. */
stream_putw_at (s, 0, stream_get_endp (s));
return zclient_send_message(zclient);
}
#ifdef HAVE_IPV6
int
zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient,
struct prefix_ipv4 *p, struct zapi_ipv6 *api)
{
int i;
int psize;
struct stream *s;
/* Reset stream. */
s = zclient->obuf;
stream_reset (s);
zclient_create_header (s, cmd, api->vrf_id);
/* Put type and nexthop. */
stream_putc (s, api->type);
stream_putw (s, api->instance);
stream_putc (s, api->flags);
stream_putc (s, api->message);
stream_putw (s, api->safi);
/* Put prefix information. */
psize = PSIZE (p->prefixlen);
stream_putc (s, p->prefixlen);
stream_write (s, (u_char *) & p->prefix, psize);
/* Nexthop, ifindex, distance and metric information. */
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
{
if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE))
{
stream_putc (s, 1);
stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE);
/* XXX assert(api->nexthop_num == 0); */
/* XXX assert(api->ifindex_num == 0); */
}
else
stream_putc (s, api->nexthop_num + api->ifindex_num);
for (i = 0; i < api->nexthop_num; i++)
{
stream_putc (s, ZEBRA_NEXTHOP_IPV6);
stream_write (s, (u_char *)api->nexthop[i], 16);
}
for (i = 0; i < api->ifindex_num; i++)
{
stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
stream_putl (s, api->ifindex[i]);
}
}
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE))
stream_putc (s, api->distance);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
stream_putl (s, api->metric);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG))
stream_putw (s, api->tag);
/* Put length at the first point of the stream. */
stream_putw_at (s, 0, stream_get_endp (s));
return zclient_send_message(zclient);
}
int
zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
struct zapi_ipv6 *api)
{
int i;
int psize;
struct stream *s;
/* Reset stream. */
s = zclient->obuf;
stream_reset (s);
zclient_create_header (s, cmd, api->vrf_id);
/* Put type and nexthop. */
stream_putc (s, api->type);
stream_putw (s, api->instance);
stream_putc (s, api->flags);
stream_putc (s, api->message);
stream_putw (s, api->safi);
/* Put prefix information. */
psize = PSIZE (p->prefixlen);
stream_putc (s, p->prefixlen);
stream_write (s, (u_char *)&p->prefix, psize);
/* Nexthop, ifindex, distance and metric information. */
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
{
if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE))
{
stream_putc (s, 1);
stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE);
/* XXX assert(api->nexthop_num == 0); */
/* XXX assert(api->ifindex_num == 0); */
}
else
stream_putc (s, api->nexthop_num + api->ifindex_num);
for (i = 0; i < api->nexthop_num; i++)
{
stream_putc (s, ZEBRA_NEXTHOP_IPV6);
stream_write (s, (u_char *)api->nexthop[i], 16);
}
for (i = 0; i < api->ifindex_num; i++)
{
stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
stream_putl (s, api->ifindex[i]);
}
}
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE))
stream_putc (s, api->distance);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
stream_putl (s, api->metric);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG))
stream_putw (s, api->tag);
/* Put length at the first point of the stream. */
stream_putw_at (s, 0, stream_get_endp (s));
return zclient_send_message(zclient);
}
#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
* sending client
*/
int
zebra_redistribute_send (int command, struct zclient *zclient, afi_t afi, int type,
u_short instance, vrf_id_t vrf_id)
{
struct stream *s;
s = zclient->obuf;
stream_reset(s);
zclient_create_header (s, command, vrf_id);
stream_putc (s, afi);
stream_putc (s, type);
stream_putw (s, instance);
stream_putw_at (s, 0, stream_get_endp (s));
return zclient_send_message(zclient);
}
/* Router-id update from zebra daemon. */
void
zebra_router_id_update_read (struct stream *s, struct prefix *rid)
{
int plen;
/* Fetch interface address. */
rid->family = stream_getc (s);
plen = prefix_blen (rid);
stream_get (&rid->u.prefix, s, plen);
rid->prefixlen = stream_getc (s);
}
/* 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
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+
* | type |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | ifname |
* | |
* | |
* | |
* | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | ifindex |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | if_flags |
* | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | metric |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | ifmtu |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | ifmtu6 |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | bandwidth |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | sockaddr_dl |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
struct interface *
zebra_interface_add_read (struct stream *s, vrf_id_t vrf_id)
{
struct interface *ifp;
char ifname_tmp[INTERFACE_NAMSIZ];
/* Read interface name. */
stream_get (ifname_tmp, s, INTERFACE_NAMSIZ);
/* Lookup/create interface by name. */
ifp = if_get_by_name_len_vrf (ifname_tmp,
strnlen (ifname_tmp, INTERFACE_NAMSIZ),
vrf_id);
zebra_interface_if_set_value (s, ifp);
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
* comments for zebra_interface_add_read), except that no sockaddr_dl
* is sent at the tail of the message.
*/
struct interface *
zebra_interface_state_read (struct stream *s, vrf_id_t vrf_id)
{
struct interface *ifp;
char ifname_tmp[INTERFACE_NAMSIZ];
/* Read interface name. */
stream_get (ifname_tmp, s, INTERFACE_NAMSIZ);
/* Lookup this by interface index. */
ifp = if_lookup_by_name_len_vrf (ifname_tmp,
strnlen (ifname_tmp, INTERFACE_NAMSIZ),
vrf_id);
/* If such interface does not exist, indicate an error */
if (! ifp)
return NULL;
zebra_interface_if_set_value (s, ifp);
return ifp;
}
/*
* format of message for address additon is:
* 0
* 0 1 2 3 4 5 6 7
* +-+-+-+-+-+-+-+-+
* | type | ZEBRA_INTERFACE_ADDRESS_ADD or
* +-+-+-+-+-+-+-+-+ ZEBRA_INTERFACE_ADDRES_DELETE
* | |
* + +
* | ifindex |
* + +
* | |
* + +
* | |
* +-+-+-+-+-+-+-+-+
* | ifc_flags | flags for connected address
* +-+-+-+-+-+-+-+-+
* | addr_family |
* +-+-+-+-+-+-+-+-+
* | addr... |
* : :
* | |
* +-+-+-+-+-+-+-+-+
* | addr_len | len of addr. E.g., addr_len = 4 for ipv4 addrs.
* +-+-+-+-+-+-+-+-+
* | daddr.. |
* : :
* | |
* +-+-+-+-+-+-+-+-+
*
*/
void
zebra_interface_if_set_value (struct stream *s, struct interface *ifp)
{
/* Read interface's index. */
ifp->ifindex = stream_getl (s);
ifp->status = stream_getc (s);
/* Read interface's value. */
ifp->flags = stream_getq (s);
ifp->ptm_enable = stream_getc (s);
ifp->ptm_status = stream_getc (s);
ifp->metric = stream_getl (s);
ifp->mtu = stream_getl (s);
ifp->mtu6 = stream_getl (s);
ifp->bandwidth = stream_getl (s);
#ifdef HAVE_STRUCT_SOCKADDR_DL
stream_get (&ifp->sdl, s, sizeof (ifp->sdl_storage));
#else
ifp->hw_addr_len = stream_getl (s);
if (ifp->hw_addr_len)
stream_get (ifp->hw_addr, s, ifp->hw_addr_len);
#endif /* HAVE_STRUCT_SOCKADDR_DL */
}
static int
memconstant(const void *s, int c, size_t n)
{
const u_char *p = s;
while (n-- > 0)
if (*p++ != c)
return 0;
return 1;
}
struct connected *
zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id)
{
unsigned int ifindex;
struct interface *ifp;
struct connected *ifc;
struct prefix p, d;
int family;
int plen;
u_char ifc_flags;
memset (&p, 0, sizeof(p));
memset (&d, 0, sizeof(d));
/* Get interface index. */
ifindex = stream_getl (s);
/* Lookup index. */
ifp = if_lookup_by_index_vrf (ifindex, vrf_id);
if (ifp == NULL)
{
zlog_warn ("zebra_interface_address_read(%s): "
"Can't find interface by ifindex: %d ",
(type == ZEBRA_INTERFACE_ADDRESS_ADD? "ADD" : "DELETE"),
ifindex);
return NULL;
}
/* Fetch flag. */
ifc_flags = stream_getc (s);
/* Fetch interface address. */
family = p.family = stream_getc (s);
plen = prefix_blen (&p);
stream_get (&p.u.prefix, s, plen);
p.prefixlen = stream_getc (s);
/* Fetch destination address. */
stream_get (&d.u.prefix, s, plen);
d.family = family;
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) ?
NULL : &d));
if (ifc != NULL)
{
ifc->flags = ifc_flags;
if (ifc->destination)
ifc->destination->prefixlen = ifc->address->prefixlen;
else if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER))
{
/* carp interfaces on OpenBSD with 0.0.0.0/0 as "peer" */
char buf[BUFSIZ];
prefix2str (ifc->address, buf, sizeof(buf));
zlog_warn("warning: interface %s address %s "
"with peer flag set, but no peer address!",
ifp->name, buf);
UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
}
}
}
else
{
assert (type == ZEBRA_INTERFACE_ADDRESS_DELETE);
ifc = connected_delete_by_prefix(ifp, &p);
}
return ifc;
}
/*
* format of message for neighbor connected address is:
* 0
* 0 1 2 3 4 5 6 7
* +-+-+-+-+-+-+-+-+
* | type | ZEBRA_INTERFACE_NBR_ADDRESS_ADD or
* +-+-+-+-+-+-+-+-+ ZEBRA_INTERFACE_NBR_ADDRES_DELETE
* | |
* + +
* | ifindex |
* + +
* | |
* + +
* | |
* +-+-+-+-+-+-+-+-+
* | addr_family |
* +-+-+-+-+-+-+-+-+
* | addr... |
* : :
* | |
* +-+-+-+-+-+-+-+-+
* | addr_len | len of addr.
* +-+-+-+-+-+-+-+-+
*/
struct nbr_connected *
zebra_interface_nbr_address_read (int type, struct stream *s, vrf_id_t vrf_id)
{
unsigned int ifindex;
struct interface *ifp;
struct prefix p;
struct nbr_connected *ifc;
/* Get interface index. */
ifindex = stream_getl (s);
/* Lookup index. */
ifp = if_lookup_by_index (ifindex);
if (ifp == NULL)
{
zlog_warn ("zebra_nbr_interface_address_read(%s): "
"Can't find interface by ifindex: %d ",
(type == ZEBRA_INTERFACE_NBR_ADDRESS_ADD? "ADD" : "DELETE"),
ifindex);
return NULL;
}
p.family = stream_getc (s);
stream_get (&p.u.prefix, s, prefix_blen (&p));
p.prefixlen = stream_getc (s);
if (type == ZEBRA_INTERFACE_NBR_ADDRESS_ADD)
{
/* Currently only supporting P2P links, so any new RA source address is
considered as the replacement of the previously learnt Link-Local address. */
if (!(ifc = listnode_head(ifp->nbr_connected)))
{
ifc = nbr_connected_new ();
ifc->address = prefix_new ();
ifc->ifp = ifp;
listnode_add (ifp->nbr_connected, ifc);
}
prefix_copy(ifc->address, &p);
}
else
{
assert (type == ZEBRA_INTERFACE_NBR_ADDRESS_DELETE);
ifc = nbr_connected_check(ifp, &p);
if (ifc)
listnode_delete (ifp->nbr_connected, ifc);
}
return ifc;
}
/* Zebra client message read function. */
static int
zclient_read (struct thread *thread)
{
size_t already;
uint16_t length, command;
uint8_t marker, version;
vrf_id_t vrf_id;
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)
{
ssize_t nbyte;
if (((nbyte = stream_read_try(zclient->ibuf, zclient->sock,
ZEBRA_HEADER_SIZE-already)) == 0) ||
(nbyte == -1))
{
if (zclient_debug)
zlog_debug ("zclient connection closed socket [%d].", zclient->sock);
return zclient_failed(zclient);
}
if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE-already))
{
/* Try again later. */
zclient_event (ZCLIENT_READ, zclient);
return 0;
}
already = ZEBRA_HEADER_SIZE;
}
/* Reset to read from the beginning of the incoming packet. */
stream_set_getp(zclient->ibuf, 0);
/* Fetch header values. */
length = stream_getw (zclient->ibuf);
marker = stream_getc (zclient->ibuf);
version = stream_getc (zclient->ibuf);
vrf_id = stream_getw (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)
{
zlog_err("%s: socket %d message length %u is less than %d ",
__func__, zclient->sock, length, ZEBRA_HEADER_SIZE);
return zclient_failed(zclient);
}
/* Length check. */
if (length > STREAM_SIZE(zclient->ibuf))
{
struct stream *ns;
zlog_warn("%s: message size %u exceeds buffer size %lu, expanding...",
__func__, length, (u_long)STREAM_SIZE(zclient->ibuf));
ns = stream_new(length);
stream_copy(ns, zclient->ibuf);
stream_free (zclient->ibuf);
zclient->ibuf = ns;
}
/* Read rest of zebra packet. */
if (already < length)
{
ssize_t nbyte;
if (((nbyte = stream_read_try(zclient->ibuf, zclient->sock,
length-already)) == 0) ||
(nbyte == -1))
{
if (zclient_debug)
zlog_debug("zclient connection closed socket [%d].", zclient->sock);
return zclient_failed(zclient);
}
if (nbyte != (ssize_t)(length-already))
{
/* Try again later. */
zclient_event (ZCLIENT_READ, zclient);
return 0;
}
}
length -= ZEBRA_HEADER_SIZE;
if (zclient_debug)
zlog_debug("zclient 0x%p command 0x%x VRF %u\n", (void *)zclient, command, vrf_id);
switch (command)
{
case ZEBRA_ROUTER_ID_UPDATE:
if (zclient->router_id_update)
(*zclient->router_id_update) (command, zclient, length, vrf_id);
break;
case ZEBRA_INTERFACE_ADD:
if (zclient->interface_add)
(*zclient->interface_add) (command, zclient, length, vrf_id);
break;
case ZEBRA_INTERFACE_DELETE:
if (zclient->interface_delete)
(*zclient->interface_delete) (command, zclient, length, vrf_id);
break;
case ZEBRA_INTERFACE_ADDRESS_ADD:
if (zclient->interface_address_add)
(*zclient->interface_address_add) (command, zclient, length, vrf_id);
break;
case ZEBRA_INTERFACE_ADDRESS_DELETE:
if (zclient->interface_address_delete)
(*zclient->interface_address_delete) (command, zclient, length, vrf_id);
break;
case ZEBRA_INTERFACE_BFD_DEST_UPDATE:
if (zclient->interface_bfd_dest_update)
(*zclient->interface_bfd_dest_update) (command, zclient, length, vrf_id);
break;
case ZEBRA_INTERFACE_NBR_ADDRESS_ADD:
if (zclient->interface_nbr_address_add)
(*zclient->interface_nbr_address_add) (command, zclient, length, vrf_id);
break;
case ZEBRA_INTERFACE_NBR_ADDRESS_DELETE:
if (zclient->interface_nbr_address_delete)
(*zclient->interface_nbr_address_delete) (command, zclient, length, vrf_id);
break;
case ZEBRA_INTERFACE_UP:
if (zclient->interface_up)
(*zclient->interface_up) (command, zclient, length, vrf_id);
break;
case ZEBRA_INTERFACE_DOWN:
if (zclient->interface_down)
(*zclient->interface_down) (command, zclient, length, vrf_id);
break;
case ZEBRA_IPV4_ROUTE_ADD:
if (zclient->ipv4_route_add)
(*zclient->ipv4_route_add) (command, zclient, length, vrf_id);
break;
case ZEBRA_IPV4_ROUTE_DELETE:
if (zclient->ipv4_route_delete)
(*zclient->ipv4_route_delete) (command, zclient, length, vrf_id);
break;
case ZEBRA_IPV6_ROUTE_ADD:
if (zclient->ipv6_route_add)
(*zclient->ipv6_route_add) (command, zclient, length, vrf_id);
break;
case ZEBRA_IPV6_ROUTE_DELETE:
if (zclient->ipv6_route_delete)
(*zclient->ipv6_route_delete) (command, zclient, length, vrf_id);
break;
case ZEBRA_NEXTHOP_UPDATE:
if (zclient_debug)
zlog_debug("zclient rcvd nexthop update\n");
if (zclient->nexthop_update)
(*zclient->nexthop_update) (command, zclient, length, vrf_id);
break;
case ZEBRA_IMPORT_CHECK_UPDATE:
if (zclient_debug)
zlog_debug("zclient rcvd import check update\n");
if (zclient->import_check_update)
(*zclient->import_check_update) (command, zclient, length, vrf_id);
break;
case ZEBRA_BFD_DEST_REPLAY:
if (zclient->bfd_dest_replay)
(*zclient->bfd_dest_replay) (command, zclient, length, vrf_id);
break;
case ZEBRA_REDISTRIBUTE_IPV4_ADD:
if (zclient->redistribute_route_ipv4_add)
(*zclient->redistribute_route_ipv4_add) (command, zclient, length, vrf_id);
break;
case ZEBRA_REDISTRIBUTE_IPV4_DEL:
if (zclient->redistribute_route_ipv4_del)
(*zclient->redistribute_route_ipv4_del) (command, zclient, length, vrf_id);
break;
case ZEBRA_REDISTRIBUTE_IPV6_ADD:
if (zclient->redistribute_route_ipv6_add)
(*zclient->redistribute_route_ipv6_add) (command, zclient, length, vrf_id);
break;
case ZEBRA_REDISTRIBUTE_IPV6_DEL:
if (zclient->redistribute_route_ipv6_del)
(*zclient->redistribute_route_ipv6_del) (command, zclient, length, vrf_id);
break;
default:
break;
}
if (zclient->sock < 0)
/* Connection was closed during packet processing. */
return -1;
/* Register read thread. */
stream_reset(zclient->ibuf);
zclient_event (ZCLIENT_READ, zclient);
return 0;
}
void
zclient_redistribute (int command, struct zclient *zclient, afi_t afi, int type,
u_short instance, vrf_id_t vrf_id)
{
if (instance) {
if (command == ZEBRA_REDISTRIBUTE_ADD)
{
if (redist_check_instance(&zclient->mi_redist[afi][type], instance))
return;
redist_add_instance(&zclient->mi_redist[afi][type], instance);
}
else
{
if (!redist_check_instance(&zclient->mi_redist[afi][type], instance))
return;
redist_del_instance(&zclient->mi_redist[afi][type], instance);
}
} else {
if (command == ZEBRA_REDISTRIBUTE_ADD)
{
if (vrf_bitmap_check (zclient->redist[afi][type], vrf_id))
return;
vrf_bitmap_set (zclient->redist[afi][type], vrf_id);
}
else
{
if (!vrf_bitmap_check (zclient->redist[afi][type], vrf_id))
return;
vrf_bitmap_unset (zclient->redist[afi][type], vrf_id);
}
}
if (zclient->sock > 0)
zebra_redistribute_send (command, zclient, afi, type, instance, vrf_id);
}
void
zclient_redistribute_default (int command, struct zclient *zclient,
vrf_id_t vrf_id)
{
if (command == ZEBRA_REDISTRIBUTE_DEFAULT_ADD)
{
if (vrf_bitmap_check (zclient->default_information, vrf_id))
return;
vrf_bitmap_set (zclient->default_information, vrf_id);
}
else
{
if (!vrf_bitmap_check (zclient->default_information, vrf_id))
return;
vrf_bitmap_unset (zclient->default_information, vrf_id);
}
if (zclient->sock > 0)
zebra_message_send (zclient, command, vrf_id);
}
static void
zclient_event (enum event event, struct zclient *zclient)
{
switch (event)
{
case ZCLIENT_SCHEDULE:
if (! zclient->t_connect)
zclient->t_connect =
thread_add_event (zclient->master, zclient_connect, 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 (zclient->master, zclient_connect, zclient,
zclient->fail < 3 ? 10 : 60);
break;
case ZCLIENT_READ:
zclient->t_read =
thread_add_read (zclient->master, zclient_read, zclient, zclient->sock);
break;
}
}
void
zclient_serv_path_set (char *path)
{
struct stat sb;
/* reset */
zclient_serv_path = NULL;
/* test if `path' is socket. don't set it otherwise. */
if (stat(path, &sb) == -1)
{
zlog_warn ("%s: zebra socket `%s' does not exist", __func__, path);
return;
}
if ((sb.st_mode & S_IFMT) != S_IFSOCK)
{
zlog_warn ("%s: `%s' is not unix socket, sir", __func__, path);
return;
}
/* it seems that path is unix socket */
zclient_serv_path = path;
}