mirror_frr/zebra/zebra_ptm.c
Donald Sharp c8ed14ddb6 ptm-integration.patch
Integrates Prescriptive Topology Module(ptm) into quagga.

If this module is enabled, link ups are notified only after the link is verified
as being connected to the neighbor specified. The neighbor specification and
checking is done by the ptm daemon.

<This is a recommit of this patch because it was changed in situ>
2015-07-22 13:07:08 -07:00

865 lines
24 KiB
C

/* Kernel routing table updates using netlink over GNU/Linux system.
* Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
*
* 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 <sys/un.h> /* for sockaddr_un */
#include <net/if.h>
#include "vty.h"
#include "zebra/zserv.h"
#include "zebra/interface.h"
#include "zebra/debug.h"
#include "zebra/zebra_ptm.h"
#include "if.h"
#include "command.h"
#include "stream.h"
#include "ptm_lib.h"
#include "buffer.h"
#include "zebra/zebra_ptm_redistribute.h"
#define ZEBRA_PTM_RECONNECT_TIME_INITIAL 1 /* initial reconnect is 1s */
#define ZEBRA_PTM_RECONNECT_TIME_MAX 300
#define PTM_MSG_LEN 4
#define PTM_HEADER_LEN 37
const char ZEBRA_PTM_GET_STATUS_CMD[] = "get-status";
const char ZEBRA_PTM_BFD_START_CMD[] = "start-bfd-sess";
const char ZEBRA_PTM_BFD_STOP_CMD[] = "stop-bfd-sess";
const char ZEBRA_PTM_CMD_STR[] = "cmd";
const char ZEBRA_PTM_PORT_STR[] = "port";
const char ZEBRA_PTM_CBL_STR[] = "cbl status";
const char ZEBRA_PTM_PASS_STR[] = "pass";
const char ZEBRA_PTM_FAIL_STR[] = "fail";
const char ZEBRA_PTM_BFDSTATUS_STR[] = "state";
const char ZEBRA_PTM_BFDSTATUS_UP_STR[] = "Up";
const char ZEBRA_PTM_BFDSTATUS_DOWN_STR[] = "Down";
const char ZEBRA_PTM_BFDDEST_STR[] = "peer";
const char ZEBRA_PTM_BFDSRC_STR[] = "local";
const char ZEBRA_PTM_INVALID_PORT_NAME[] = "N/A";
const char ZEBRA_PTM_INVALID_SRC_IP[] = "N/A";
const char ZEBRA_PTM_BFD_DST_IP_FIELD[] = "dstIPaddr";
const char ZEBRA_PTM_BFD_SRC_IP_FIELD[] = "srcIPaddr";
const char ZEBRA_PTM_BFD_MIN_RX_FIELD[] = "requiredMinRx";
const char ZEBRA_PTM_BFD_MIN_TX_FIELD[] = "upMinTx";
const char ZEBRA_PTM_BFD_DETECT_MULT_FIELD[] = "detectMult";
const char ZEBRA_PTM_BFD_MULTI_HOP_FIELD[] = "multiHop";
const char ZEBRA_PTM_BFD_CLIENT_FIELD[] = "client";
const char ZEBRA_PTM_BFD_SEQID_FIELD[] = "seqid";
const char ZEBRA_PTM_BFD_IFNAME_FIELD[] = "ifName";
const char ZEBRA_PTM_BFD_MAX_HOP_CNT_FIELD[] = "maxHopCnt";
extern struct zebra_t zebrad;
static ptm_lib_handle_t *ptm_hdl;
struct zebra_ptm_cb ptm_cb;
static int zebra_ptm_socket_init(void);
int zebra_ptm_sock_read(struct thread *);
static void zebra_ptm_install_commands (void);
static int zebra_ptm_handle_cbl_msg(void *arg, void *in_ctxt);
static int zebra_ptm_handle_bfd_msg(void *arg, void *in_ctxt);
void zebra_bfd_peer_replay_req (void);
const char ZEBRA_PTM_SOCK_NAME[] = "\0/var/run/ptmd.socket";
void
zebra_ptm_init (void)
{
char buf[64];
memset(&ptm_cb, 0, sizeof(struct zebra_ptm_cb));
ptm_cb.out_data = calloc(1, ZEBRA_PTM_SEND_MAX_SOCKBUF);
if (!ptm_cb.out_data)
{
zlog_warn("%s: Allocation of send data failed", __func__);
return;
}
ptm_cb.in_data = calloc(1, ZEBRA_PTM_MAX_SOCKBUF);
if (!ptm_cb.in_data)
{
zlog_warn("%s: Allocation of recv data failed", __func__);
free(ptm_cb.out_data);
return;
}
ptm_cb.pid = getpid();
zebra_ptm_install_commands();
sprintf(buf, "%s", "quagga");
ptm_hdl = ptm_lib_register(buf, NULL, zebra_ptm_handle_bfd_msg,
zebra_ptm_handle_cbl_msg);
ptm_cb.wb = buffer_new(0);
ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
ptm_cb.ptm_sock = -1;
}
void
zebra_ptm_finish(void)
{
if (ptm_cb.ptm_sock != -1)
close(ptm_cb.ptm_sock);
if (ptm_cb.wb)
buffer_free(ptm_cb.wb);
if (ptm_cb.out_data)
free(ptm_cb.out_data);
if (ptm_cb.in_data)
free(ptm_cb.in_data);
/* Release threads. */
if (ptm_cb.t_read)
thread_cancel (ptm_cb.t_read);
if (ptm_cb.t_write)
thread_cancel (ptm_cb.t_write);
if (ptm_cb.t_timer)
thread_cancel (ptm_cb.t_timer);
}
static int
zebra_ptm_flush_messages (struct thread *thread)
{
ptm_cb.t_write = NULL;
if (ptm_cb.ptm_sock == -1)
return -1;
errno = 0;
switch (buffer_flush_available(ptm_cb.wb, ptm_cb.ptm_sock))
{
case BUFFER_ERROR:
zlog_warn ("%s ptm socket error: %s", __func__,
safe_strerror (errno));
close(ptm_cb.ptm_sock);
ptm_cb.ptm_sock = -1;
ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect,
NULL, ptm_cb.reconnect_time);
return (-1);
case BUFFER_PENDING:
ptm_cb.t_write = thread_add_write(zebrad.master, zebra_ptm_flush_messages,
NULL, ptm_cb.ptm_sock);
break;
case BUFFER_EMPTY:
break;
}
return(0);
}
static int
zebra_ptm_send_message(char *data, int size)
{
errno = 0;
switch (buffer_write(ptm_cb.wb, ptm_cb.ptm_sock, data, size))
{
case BUFFER_ERROR:
zlog_warn ("%s ptm socket error: %s", __func__, safe_strerror (errno));
close(ptm_cb.ptm_sock);
ptm_cb.ptm_sock = -1;
ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect,
NULL, ptm_cb.reconnect_time);
return -1;
case BUFFER_EMPTY:
THREAD_OFF(ptm_cb.t_write);
break;
case BUFFER_PENDING:
THREAD_WRITE_ON(zebrad.master, ptm_cb.t_write,
zebra_ptm_flush_messages, NULL, ptm_cb.ptm_sock);
break;
}
return 0;
}
int
zebra_ptm_connect (struct thread *t)
{
int init = 0;
void *out_ctxt;
int len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
if (ptm_cb.ptm_sock == -1) {
zebra_ptm_socket_init();
init = 1;
}
if (ptm_cb.ptm_sock != -1) {
if (init) {
ptm_cb.t_read = thread_add_read (zebrad.master, zebra_ptm_sock_read,
NULL, ptm_cb.ptm_sock);
zebra_bfd_peer_replay_req();
}
if (ptm_cb.ptm_enable) {
ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR,
ZEBRA_PTM_GET_STATUS_CMD);
ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &len);
zebra_ptm_send_message(ptm_cb.out_data, len);
}
ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
} else {
ptm_cb.reconnect_time *= 2;
if (ptm_cb.reconnect_time > ZEBRA_PTM_RECONNECT_TIME_MAX)
ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_MAX;
ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect, NULL,
ptm_cb.reconnect_time);
}
return(errno);
}
DEFUN (zebra_ptm_enable,
zebra_ptm_enable_cmd,
"ptm-enable",
"Enable neighbor check with specified topology\n")
{
struct listnode *i;
struct interface *ifp;
ptm_cb.ptm_enable = 1;
for (ALL_LIST_ELEMENTS_RO (iflist, i, ifp))
if (!ifp->ptm_enable)
{
ifp->ptm_enable = 1;
ifp->ptm_status = 1; /* to bring down ports that may fail check */
}
zebra_ptm_connect(NULL);
return CMD_SUCCESS;
}
DEFUN (no_zebra_ptm_enable,
no_zebra_ptm_enable_cmd,
"no ptm-enable",
NO_STR
"Enable neighbor check with specified topology\n")
{
struct listnode *i;
struct interface *ifp;
int send_linkup;
ptm_cb.ptm_enable = 0;
for (ALL_LIST_ELEMENTS_RO (iflist, i, ifp))
{
if (ifp->ptm_enable)
{
if (!if_is_operative(ifp))
send_linkup = 1;
ifp->ptm_enable = 0;
if (if_is_operative (ifp) && send_linkup) {
if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug ("%s: Bringing up interface %s", __func__,
ifp->name);
if_up (ifp);
}
}
}
return CMD_SUCCESS;
}
void
zebra_ptm_write (struct vty *vty)
{
if (ptm_cb.ptm_enable)
vty_out (vty, "ptm-enable%s", VTY_NEWLINE);
return;
}
static int
zebra_ptm_socket_init (void)
{
int ret;
int sock;
struct sockaddr_un addr;
ptm_cb.ptm_sock = -1;
sock = socket (PF_UNIX, (SOCK_STREAM | SOCK_NONBLOCK), 0);
if (sock < 0)
return -1;
/* Make server socket. */
memset (&addr, 0, sizeof (struct sockaddr_un));
addr.sun_family = AF_UNIX;
memcpy (&addr.sun_path, ZEBRA_PTM_SOCK_NAME,
sizeof(ZEBRA_PTM_SOCK_NAME));
ret = connect(sock, (struct sockaddr *) &addr,
sizeof (addr.sun_family)+sizeof (ZEBRA_PTM_SOCK_NAME)-1);
if (ret < 0)
{
zlog_warn("%s: Unable to connect to socket %s [%s]",
__func__, ZEBRA_PTM_SOCK_NAME, safe_strerror(errno));
close (sock);
return -1;
}
ptm_cb.ptm_sock = sock;
return sock;
}
static void
zebra_ptm_install_commands (void)
{
install_element (CONFIG_NODE, &zebra_ptm_enable_cmd);
install_element (CONFIG_NODE, &no_zebra_ptm_enable_cmd);
}
/* BFD session goes down, send message to the protocols. */
static void
if_bfd_session_down (struct interface *ifp, struct prefix *dp, struct prefix *sp)
{
if (IS_ZEBRA_DEBUG_EVENT)
{
char buf[2][INET6_ADDRSTRLEN];
if (ifp)
{
zlog_debug ("MESSAGE: ZEBRA_INTERFACE_BFD_DEST_DOWN %s/%d on %s",
inet_ntop (dp->family, &dp->u.prefix, buf[0],
INET6_ADDRSTRLEN), dp->prefixlen, ifp->name);
}
else
{
zlog_debug ("MESSAGE: ZEBRA_INTERFACE_BFD_DEST_DOWN %s/%d "
"with src %s/%d",
inet_ntop (dp->family, &dp->u.prefix, buf[0], INET6_ADDRSTRLEN),
dp->prefixlen,
inet_ntop (sp->family, &sp->u.prefix, buf[1], INET6_ADDRSTRLEN),
sp->prefixlen);
}
}
zebra_interface_bfd_update (ifp, dp, sp);
}
static int
zebra_ptm_handle_bfd_msg(void *arg, void *in_ctxt)
{
struct interface *ifp = NULL;
char port_str[128];
char bfdst_str[32];
char dest_str[64];
char src_str[64];
struct prefix dest_prefix;
struct prefix src_prefix;
ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_PORT_STR, port_str);
if (port_str[0] == '\0') {
zlog_debug("%s: Key %s not found in PTM msg", __func__,
ZEBRA_PTM_PORT_STR);
return -1;
}
if (strcmp(ZEBRA_PTM_INVALID_PORT_NAME, port_str)) {
ifp = if_lookup_by_name(port_str);
if (!ifp) {
zlog_err("%s: %s not found in interface list", __func__, port_str);
return -1;
}
}
ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDSTATUS_STR, bfdst_str);
if (bfdst_str[0] == '\0') {
return -1;
}
ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDDEST_STR, dest_str);
if (dest_str[0] == '\0') {
zlog_debug("%s: Key %s not found in PTM msg", __func__,
ZEBRA_PTM_BFDDEST_STR);
return -1;
}
ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDSRC_STR, src_str);
if (src_str[0] == '\0') {
zlog_debug("%s: Key %s not found in PTM msg", __func__,
ZEBRA_PTM_BFDSRC_STR);
return -1;
}
if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug("%s: Recv Port [%s] bfd status [%s] peer [%s] local [%s]",
__func__, port_str, bfdst_str, dest_str, src_str);
/* we only care if bfd session goes down */
if (!strcmp (bfdst_str, ZEBRA_PTM_BFDSTATUS_DOWN_STR)) {
if (inet_pton(AF_INET, dest_str, &dest_prefix.u.prefix4) > 0) {
dest_prefix.family = AF_INET;
dest_prefix.prefixlen = IPV4_MAX_PREFIXLEN;
}
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, dest_str, &dest_prefix.u.prefix6) > 0) {
dest_prefix.family = AF_INET6;
dest_prefix.prefixlen = IPV6_MAX_PREFIXLEN;
}
#endif /* HAVE_IPV6 */
else {
zlog_err("%s: Peer addr %s not found", __func__,
dest_str);
return -1;
}
memset(&src_prefix, 0, sizeof(struct prefix));
if (strcmp(ZEBRA_PTM_INVALID_SRC_IP, src_str)) {
if (inet_pton(AF_INET, src_str, &src_prefix.u.prefix4) > 0) {
src_prefix.family = AF_INET;
src_prefix.prefixlen = IPV4_MAX_PREFIXLEN;
}
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, src_str, &src_prefix.u.prefix6) > 0) {
src_prefix.family = AF_INET6;
src_prefix.prefixlen = IPV6_MAX_PREFIXLEN;
}
#endif /* HAVE_IPV6 */
else {
zlog_err("%s: Local addr %s not found", __func__,
src_str);
return -1;
}
}
if_bfd_session_down(ifp, &dest_prefix, &src_prefix);
}
return 0;
}
static int
zebra_ptm_handle_cbl_msg(void *arg, void *in_ctxt)
{
struct interface *ifp;
char cbl_str[32];
char port_str[128];
char cmd_str[32];
ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_CMD_STR, cmd_str);
/* Drop command response messages */
if (cmd_str[0] != '\0') {
return 0;
}
ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_PORT_STR, port_str);
if (port_str[0] == '\0') {
zlog_debug("%s: key %s not found in PTM msg", __func__,
ZEBRA_PTM_PORT_STR);
return 0;
}
ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_CBL_STR, cbl_str);
if (cbl_str[0] == '\0') {
zlog_debug("%s: Key %s not found in PTM msg", __func__,
ZEBRA_PTM_CBL_STR);
return 0;
}
if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug("%s: Recv Port [%s] cbl status [%s]", __func__,
port_str, cbl_str);
ifp = if_lookup_by_name(port_str);
if (!ifp) {
zlog_err("%s: %s not found in interface list", __func__, port_str);
return -1;
}
if (!strcmp(cbl_str, ZEBRA_PTM_PASS_STR) && (!ifp->ptm_status)) {
ifp->ptm_status = 1;
if (ifp->ptm_enable && if_is_no_ptm_operative (ifp))
if_up (ifp);
} else if (!strcmp (cbl_str, ZEBRA_PTM_FAIL_STR) && (ifp->ptm_status)) {
ifp->ptm_status = 0;
if (ifp->ptm_enable && if_is_no_ptm_operative (ifp))
if_down (ifp);
}
return 0;
}
int
zebra_ptm_sock_read (struct thread *thread)
{
int sock, done = 0;
int rc;
errno = 0;
sock = THREAD_FD (thread);
if (sock == -1)
return -1;
/* PTM communicates in CSV format */
while(!done) {
rc = ptm_lib_process_msg(ptm_hdl, sock, ptm_cb.in_data, ZEBRA_PTM_MAX_SOCKBUF,
NULL);
if (rc <= 0)
break;
}
if (rc <= 0) {
if (((rc == 0) && !errno) || (errno && (errno != EWOULDBLOCK) && (errno != EAGAIN))) {
zlog_warn ("%s routing socket error: %s(%d) bytes %d", __func__,
safe_strerror (errno), errno, rc);
close (ptm_cb.ptm_sock);
ptm_cb.ptm_sock = -1;
ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect,
NULL, ptm_cb.reconnect_time);
return (-1);
}
}
ptm_cb.t_read = thread_add_read (zebrad.master, zebra_ptm_sock_read,
NULL, ptm_cb.ptm_sock);
return 0;
}
/* BFD peer/dst register/update */
int
zebra_ptm_bfd_dst_register (struct zserv *client, int sock, u_short length,
int command)
{
struct stream *s;
struct prefix src_p;
struct prefix dst_p;
u_char multi_hop;
u_char multi_hop_cnt;
u_char detect_mul;
unsigned int min_rx_timer;
unsigned int min_tx_timer;
char if_name[INTERFACE_NAMSIZ];
u_char len;
void *out_ctxt;
char buf[INET6_ADDRSTRLEN];
char tmp_buf[64];
int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
if (command == ZEBRA_BFD_DEST_UPDATE)
client->bfd_peer_upd8_cnt++;
else
client->bfd_peer_add_cnt++;
if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug("bfd_dst_register msg from client %s: length=%d",
zebra_route_string(client->proto), length);
if (ptm_cb.ptm_sock == -1)
{
ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect,
NULL, ptm_cb.reconnect_time);
return -1;
}
ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
sprintf(tmp_buf, "%s", ZEBRA_PTM_BFD_START_CMD);
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
sprintf(tmp_buf, "quagga");
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
tmp_buf);
sprintf(tmp_buf, "%d", ptm_cb.pid);
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD,
tmp_buf);
s = client->ibuf;
dst_p.family = stream_getw(s);
if (dst_p.family == AF_INET)
dst_p.prefixlen = IPV4_MAX_BYTELEN;
else
dst_p.prefixlen = IPV6_MAX_BYTELEN;
stream_get(&dst_p.u.prefix, s, dst_p.prefixlen);
if (dst_p.family == AF_INET)
{
inet_ntop(AF_INET, &dst_p.u.prefix4, buf, sizeof(buf));
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
}
#ifdef HAVE_IPV6
else
{
inet_ntop(AF_INET6, &dst_p.u.prefix6, buf, sizeof(buf));
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
}
#endif /* HAVE_IPV6 */
min_rx_timer = stream_getl(s);
sprintf(tmp_buf, "%d", min_rx_timer);
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MIN_RX_FIELD,
tmp_buf);
min_tx_timer = stream_getl(s);
sprintf(tmp_buf, "%d", min_tx_timer);
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MIN_TX_FIELD,
tmp_buf);
detect_mul = stream_getc(s);
sprintf(tmp_buf, "%d", detect_mul);
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DETECT_MULT_FIELD,
tmp_buf);
multi_hop = stream_getc(s);
if (multi_hop)
{
sprintf(tmp_buf, "%d", 1);
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MULTI_HOP_FIELD,
tmp_buf);
src_p.family = stream_getw(s);
if (src_p.family == AF_INET)
src_p.prefixlen = IPV4_MAX_BYTELEN;
else
src_p.prefixlen = IPV6_MAX_BYTELEN;
stream_get(&src_p.u.prefix, s, src_p.prefixlen);
if (src_p.family == AF_INET)
{
inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf));
ptm_lib_append_msg(ptm_hdl, out_ctxt,
ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
}
#ifdef HAVE_IPV6
else
{
inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf));
ptm_lib_append_msg(ptm_hdl, out_ctxt,
ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
}
#endif /* HAVE_IPV6 */
multi_hop_cnt = stream_getc(s);
sprintf(tmp_buf, "%d", multi_hop_cnt);
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MAX_HOP_CNT_FIELD,
tmp_buf);
}
else
{
#ifdef HAVE_IPV6
if (dst_p.family == AF_INET6)
{
src_p.family = stream_getw(s);
if (src_p.family == AF_INET)
src_p.prefixlen = IPV4_MAX_BYTELEN;
else
src_p.prefixlen = IPV6_MAX_BYTELEN;
stream_get(&src_p.u.prefix, s, src_p.prefixlen);
if (src_p.family == AF_INET)
{
inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf));
ptm_lib_append_msg(ptm_hdl, out_ctxt,
ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
}
else
{
inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf));
ptm_lib_append_msg(ptm_hdl, out_ctxt,
ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
}
}
#endif /* HAVE_IPV6 */
len = stream_getc(s);
stream_get(if_name, s, len);
if_name[len] = '\0';
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_IFNAME_FIELD,
if_name);
}
ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
if (IS_ZEBRA_DEBUG_SEND)
zlog_debug ("%s: Sent message (%d) %s", __func__, data_len,
ptm_cb.out_data);
zebra_ptm_send_message(ptm_cb.out_data, data_len);
return 0;
}
/* BFD peer/dst deregister */
int
zebra_ptm_bfd_dst_deregister (struct zserv *client, int sock, u_short length)
{
struct stream *s;
struct prefix src_p;
struct prefix dst_p;
u_char multi_hop;
char if_name[INTERFACE_NAMSIZ];
u_char len;
char buf[INET6_ADDRSTRLEN];
char tmp_buf[64];
int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
void *out_ctxt;
client->bfd_peer_del_cnt++;
if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug("bfd_dst_deregister msg from client %s: length=%d",
zebra_route_string(client->proto), length);
if (ptm_cb.ptm_sock == -1)
{
ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect,
NULL, ptm_cb.reconnect_time);
return -1;
}
ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt);
sprintf(tmp_buf, "%s", ZEBRA_PTM_BFD_STOP_CMD);
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf);
sprintf(tmp_buf, "%s", "quagga");
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD,
tmp_buf);
sprintf(tmp_buf, "%d", ptm_cb.pid);
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD,
tmp_buf);
s = client->ibuf;
dst_p.family = stream_getw(s);
if (dst_p.family == AF_INET)
dst_p.prefixlen = IPV4_MAX_BYTELEN;
else
dst_p.prefixlen = IPV6_MAX_BYTELEN;
stream_get(&dst_p.u.prefix, s, dst_p.prefixlen);
if (dst_p.family == AF_INET)
{
inet_ntop(AF_INET, &dst_p.u.prefix4, buf, sizeof(buf));
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
}
#ifdef HAVE_IPV6
else
{
inet_ntop(AF_INET6, &dst_p.u.prefix6, buf, sizeof(buf));
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DST_IP_FIELD, buf);
}
#endif /* HAVE_IPV6 */
multi_hop = stream_getc(s);
if (multi_hop)
{
sprintf(tmp_buf, "%d", 1);
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MULTI_HOP_FIELD,
tmp_buf);
src_p.family = stream_getw(s);
if (src_p.family == AF_INET)
src_p.prefixlen = IPV4_MAX_BYTELEN;
else
src_p.prefixlen = IPV6_MAX_BYTELEN;
stream_get(&src_p.u.prefix, s, src_p.prefixlen);
if (src_p.family == AF_INET)
{
inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf));
ptm_lib_append_msg(ptm_hdl, out_ctxt,
ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
}
#ifdef HAVE_IPV6
else
{
inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf));
ptm_lib_append_msg(ptm_hdl, out_ctxt,
ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
}
#endif /* HAVE_IPV6 */
}
else
{
#ifdef HAVE_IPV6
if (dst_p.family == AF_INET6)
{
src_p.family = stream_getw(s);
if (src_p.family == AF_INET)
src_p.prefixlen = IPV4_MAX_BYTELEN;
else
src_p.prefixlen = IPV6_MAX_BYTELEN;
stream_get(&src_p.u.prefix, s, src_p.prefixlen);
if (src_p.family == AF_INET)
{
inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf));
ptm_lib_append_msg(ptm_hdl, out_ctxt,
ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
}
else
{
inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf));
ptm_lib_append_msg(ptm_hdl, out_ctxt,
ZEBRA_PTM_BFD_SRC_IP_FIELD, buf);
}
}
#endif /* HAVE_IPV6 */
len = stream_getc(s);
stream_get(if_name, s, len);
if_name[len] = '\0';
ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_IFNAME_FIELD,
if_name);
}
ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len);
if (IS_ZEBRA_DEBUG_SEND)
zlog_debug ("%s: Sent message (%d) %s", __func__, data_len,
ptm_cb.out_data);
zebra_ptm_send_message(ptm_cb.out_data, data_len);
return 0;
}
int
zebra_ptm_get_enable_state(void)
{
return ptm_cb.ptm_enable;
}