diff options
Diffstat (limited to 'zebra')
-rw-r--r-- | zebra/Makefile.am | 8 | ||||
-rw-r--r-- | zebra/interface.c | 16 | ||||
-rw-r--r-- | zebra/interface.h | 1 | ||||
-rw-r--r-- | zebra/redistribute.c | 17 | ||||
-rw-r--r-- | zebra/redistribute.h | 1 | ||||
-rw-r--r-- | zebra/redistribute_null.c | 3 | ||||
-rw-r--r-- | zebra/zebra_ptm.c | 678 | ||||
-rw-r--r-- | zebra/zebra_ptm.h | 4 | ||||
-rw-r--r-- | zebra/zebra_ptm_null.c | 29 | ||||
-rw-r--r-- | zebra/zebra_ptm_redistribute.c | 122 | ||||
-rw-r--r-- | zebra/zebra_ptm_redistribute.h | 28 | ||||
-rw-r--r-- | zebra/zserv.c | 39 | ||||
-rw-r--r-- | zebra/zserv.h | 6 |
13 files changed, 722 insertions, 230 deletions
diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 470e8a1a2..a4e6f2c18 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -34,16 +34,18 @@ zebra_SOURCES = \ zserv.c main.c interface.c connected.c zebra_rib.c zebra_routemap.c \ redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c \ irdp_main.c irdp_interface.c irdp_packet.c router-id.c zebra_fpm.c \ - $(othersrc) zebra_ptm.c zebra_rnh.c + $(othersrc) zebra_ptm.c zebra_rnh.c zebra_ptm_redistribute.c testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \ zebra_vty.c zebra_ptm.c zebra_routemap.c \ - kernel_null.c redistribute_null.c ioctl_null.c misc_null.c zebra_rnh_null.c + kernel_null.c redistribute_null.c ioctl_null.c misc_null.c zebra_rnh_null.c \ + zebra_ptm_null.c noinst_HEADERS = \ connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \ interface.h ipforward.h irdp.h router-id.h kernel_socket.h \ - rt_netlink.h zebra_fpm.h zebra_fpm_private.h zebra_rnh.h + rt_netlink.h zebra_fpm.h zebra_fpm_private.h zebra_rnh.h \ + zebra_ptm_redistribute.h zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) $(LIB_IPV6) diff --git a/zebra/interface.c b/zebra/interface.c index 2f8de0b03..cd9c21a61 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -684,22 +684,6 @@ if_refresh (struct interface *ifp) if_get_flags (ifp); } -/* BFD session goes down, send message to the protocols. */ -void -if_bfd_session_down (struct interface *ifp, struct prefix *p) -{ - if (IS_ZEBRA_DEBUG_EVENT) - { - char buf[INET6_ADDRSTRLEN]; - - zlog_debug ("MESSAGE: ZEBRA_INTERFACE_BFD_DEST_DOWN %s/%d on %s", - inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN), - p->prefixlen, ifp->name); - } - - zebra_interface_bfd_update (ifp, p); -} - /* Output prefix string to vty. */ static int diff --git a/zebra/interface.h b/zebra/interface.h index 72e40044f..e8456ce59 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -221,7 +221,6 @@ extern void if_add_update (struct interface *ifp); extern void if_up (struct interface *); extern void if_down (struct interface *); extern void if_refresh (struct interface *); -extern void if_bfd_session_down(struct interface *, struct prefix *); extern void if_flags_update (struct interface *, uint64_t); extern int if_subnet_add (struct interface *, struct connected *); extern int if_subnet_delete (struct interface *, struct connected *); diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 843f5ad4b..6dfb455f4 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -482,23 +482,6 @@ zebra_interface_address_delete_update (struct interface *ifp, } } -void -zebra_interface_bfd_update (struct interface *ifp, struct prefix *p) -{ - struct listnode *node, *nnode; - struct zserv *client; - - for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) - { - /* Supporting for OSPF and BGP */ - if (client->proto != ZEBRA_ROUTE_OSPF && client->proto != ZEBRA_ROUTE_BGP) - continue; - - /* Notify to the protocol daemons. */ - zsend_interface_bfd_update (ZEBRA_INTERFACE_BFD_DEST_DOWN, client, ifp, p); - } -} - int zebra_add_import_table_entry (struct route_node *rn, struct rib *rib) { diff --git a/zebra/redistribute.h b/zebra/redistribute.h index aef944ca2..a4f321979 100644 --- a/zebra/redistribute.h +++ b/zebra/redistribute.h @@ -46,7 +46,6 @@ extern void zebra_interface_address_add_update (struct interface *, struct connected *); extern void zebra_interface_address_delete_update (struct interface *, struct connected *c); -extern void zebra_interface_bfd_update (struct interface *, struct prefix *); extern int zebra_check_addr (struct prefix *); extern int zebra_import_table (afi_t afi, u_int32_t table_id, diff --git a/zebra/redistribute_null.c b/zebra/redistribute_null.c index c40938c4d..04a36ab8b 100644 --- a/zebra/redistribute_null.c +++ b/zebra/redistribute_null.c @@ -53,9 +53,6 @@ void zebra_interface_address_delete_update (struct interface *a, struct connected *b) { return; } #endif -void zebra_interface_bfd_update (struct interface *a, struct prefix *b) -{ return; } - int zebra_import_table (afi_t afi, u_int32_t table_id, u_int32_t metric, int add) diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index 58f2514ad..468164947 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -28,19 +28,42 @@ #include "zebra/zebra_ptm.h" #include "if.h" #include "command.h" +#include "stream.h" +#include "ptm_lib.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_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 = "BFD status"; -const char *ZEBRA_PTM_BFDDEST_STR = "BFD peer"; + +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_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; int ptm_enable; @@ -49,29 +72,63 @@ int zebra_ptm_sock = -1; struct thread *zebra_ptm_thread = NULL; static int zebra_ptm_reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL; +int zebra_ptm_pid = 0; +static ptm_lib_handle_t *ptm_hdl; -static void zebra_ptm_finish(void); static int zebra_ptm_socket_init(void); int zebra_ptm_sock_read(struct thread *); int zebra_ptm_sock_write(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]; + + zebra_ptm_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); } int zebra_ptm_connect (struct thread *t) { - zebra_ptm_socket_init(); + int init = 0; + char *data; + void *out_ctxt; + int len = ZEBRA_PTM_SEND_MAX_SOCKBUF; + + if (zebra_ptm_sock == -1) { + zebra_ptm_socket_init(); + init = 1; + } if (zebra_ptm_sock != -1) { - zebra_ptm_thread = thread_add_write (zebrad.master, zebra_ptm_sock_write, - NULL, zebra_ptm_sock); + if (init) { + zebra_bfd_peer_replay_req(); + } + + if (ptm_enable) { + data = calloc(1, len); + if (!data) { + zlog_debug("%s: Allocation of send data failed", __func__); + return -1; + } + ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt); + ptm_lib_append_msg(ptm_hdl, out_ctxt, "cmd", ZEBRA_PTM_GET_STATUS_CMD); + ptm_lib_complete_msg(ptm_hdl, out_ctxt, data, &len); + + zebra_ptm_thread = thread_add_write (zebrad.master, zebra_ptm_sock_write, + data, zebra_ptm_sock); + } zebra_ptm_reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL; } else { zebra_ptm_reconnect_time *= 2; @@ -85,21 +142,6 @@ zebra_ptm_connect (struct thread *t) return(errno); } -static void -zebra_ptm_finish (void) -{ - if (zebra_ptm_sock != -1) - { - if (zebra_ptm_thread != NULL) - { - thread_cancel(zebra_ptm_thread); - zebra_ptm_thread = NULL; - } - close (zebra_ptm_sock); - zebra_ptm_sock = -1; - } -} - DEFUN (zebra_ptm_enable, zebra_ptm_enable_cmd, "ptm-enable", @@ -142,13 +184,12 @@ DEFUN (no_zebra_ptm_enable, ifp->ptm_enable = 0; if (if_is_operative (ifp) && send_linkup) { - zlog_debug ("%s: Bringing up interface %s\n", __func__, + zlog_debug ("%s: Bringing up interface %s", __func__, ifp->name); if_up (ifp); } } } - zebra_ptm_finish(); return CMD_SUCCESS; } @@ -185,12 +226,12 @@ zebra_ptm_socket_init (void) sizeof (addr.sun_family)+sizeof (ZEBRA_PTM_SOCK_NAME)-1); if (ret < 0) { - zlog_debug("%s: Unable to connect to socket %s [%s]\n", + zlog_warn("%s: Unable to connect to socket %s [%s]", __func__, ZEBRA_PTM_SOCK_NAME, safe_strerror(errno)); close (sock); return -1; } - zlog_debug ("%s: connection to ptm socket %s succeeded\n", + zlog_debug ("%s: connection to ptm socket %s succeeded", __func__, ZEBRA_PTM_SOCK_NAME); zebra_ptm_sock = sock; return sock; @@ -203,134 +244,163 @@ zebra_ptm_install_commands (void) install_element (CONFIG_NODE, &no_zebra_ptm_enable_cmd); } -static char * -zebra_ptm_find_key(const char *key_arg, char *arg, int arglen) +/* BFD session goes down, send message to the protocols. */ +void +if_bfd_session_down (struct interface *ifp, struct prefix *dp, struct prefix *sp) { - char buf[ZEBRA_PTM_MAX_SOCKBUF]; - char *data, *hdr, *key, *val; - char *currd, *currh; - char *savd, *savh; - - snprintf(buf, sizeof(buf), "%s", arg); - /* split up row header and data */ - hdr = buf; - data = strstr(hdr, "\n"); - if (!data) - return NULL; - *data = '\0'; - data++; - - currh = strtok_r(hdr, ",\n\0", &savh); - currd = strtok_r(data, ",\n\0", &savd); - while(currh && currd) { - key = currh; - val = currd; - if (!strcmp(key, key_arg)) { - /* found the value */ - return val; + 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, 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); + } } - currh = strtok_r(NULL, ",\n\0", &savh); - currd = strtok_r(NULL, ",\n\0", &savd); - } - return NULL; + zebra_interface_bfd_update (ifp, dp, sp); } -static void -zebra_ptm_handle_bfd_msg(char *buf, int buflen) +static int +zebra_ptm_handle_bfd_msg(void *arg, void *in_ctxt) { - struct interface *ifp; - char *port_str, *bfdst_str, *dest_str; - struct in_addr dest_addr; + 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; - port_str = zebra_ptm_find_key(ZEBRA_PTM_PORT_STR, buf, buflen); + ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_PORT_STR, port_str); - if (!port_str) { - zlog_debug("%s: Key %s not found in PTM msg\n", __func__, + if (port_str[0] == '\0') { + zlog_debug("%s: Key %s not found in PTM msg", __func__, ZEBRA_PTM_PORT_STR); - return; + return -1; } - ifp = if_lookup_by_name(port_str); + 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\n", __func__, port_str); - return; + if (!ifp) { + zlog_err("%s: %s not found in interface list", __func__, port_str); + return -1; + } } - bfdst_str = zebra_ptm_find_key(ZEBRA_PTM_BFDSTATUS_STR, buf, buflen); + ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDSTATUS_STR, bfdst_str); - if (!bfdst_str) { - zlog_debug("%s: Key %s not found in PTM msg\n", __func__, + if (bfdst_str[0] == '\0') { + zlog_debug("%s: Key %s not found in PTM msg", __func__, ZEBRA_PTM_BFDSTATUS_STR); - return; + return -1; } - dest_str = zebra_ptm_find_key(ZEBRA_PTM_BFDDEST_STR, buf, buflen); + ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDDEST_STR, dest_str); - if (!dest_str) { - zlog_debug("%s: Key %s not found in PTM msg\n", __func__, + if (dest_str[0] == '\0') { + zlog_debug("%s: Key %s not found in PTM msg", __func__, ZEBRA_PTM_BFDDEST_STR); - return; + return -1; } - zlog_debug("%s: Recv Port [%s] bfd status [%s] peer [%s]\n", __func__, - port_str, bfdst_str, dest_str); + ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDSRC_STR, src_str); - /* if ptm cbl checks fail then no more processing required */ - if (!ifp->ptm_status) { - return; + if (src_str[0] == '\0') { + zlog_debug("%s: Key %s not found in PTM msg", __func__, + ZEBRA_PTM_BFDSRC_STR); + return -1; } + 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_FAIL_STR)) { - if (ifp->ptm_enable && if_is_no_ptm_operative (ifp)) { - if (inet_pton(AF_INET, dest_str, &dest_addr) <= 0) { - zlog_err("%s: Peer addr(%s) not found\n", __func__, - dest_str); - return; - } - dest_prefix.family = AF_INET; - dest_prefix.u.prefix4 = dest_addr; - dest_prefix.prefixlen = IPV4_MAX_PREFIXLEN; + 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; + } - zlog_debug("%s: bfd session down [%s]\n", __func__, dest_str); - if_bfd_session_down(ifp, &dest_prefix); + 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 void -zebra_ptm_handle_cbl_msg(char *buf, int buflen) +static int +zebra_ptm_handle_cbl_msg(void *arg, void *in_ctxt) { struct interface *ifp; - char *cbl_str, *port_str; + char cbl_str[32]; + char port_str[128]; - port_str = zebra_ptm_find_key(ZEBRA_PTM_PORT_STR, buf, buflen); + ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_PORT_STR, port_str); - if (!port_str) { - zlog_debug("%s: Key %s not found in PTM msg\n", __func__, + if (port_str[0] == '\0') { + zlog_debug("%s: Key %s not found in PTM msg", __func__, ZEBRA_PTM_PORT_STR); - return; + return 0; } - cbl_str = zebra_ptm_find_key(ZEBRA_PTM_CBL_STR, buf, buflen); + ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_CBL_STR, cbl_str); - if (!cbl_str) { - zlog_debug("%s: Key %s not found in PTM msg\n", __func__, + if (cbl_str[0] == '\0') { + zlog_debug("%s: Key %s not found in PTM msg", __func__, ZEBRA_PTM_CBL_STR); - return; + return 0; } - zlog_debug("%s: Recv Port [%s] cbl status [%s]\n", __func__, + 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\n", __func__, port_str); - return; + 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)) { @@ -342,17 +412,8 @@ zebra_ptm_handle_cbl_msg(char *buf, int buflen) if (ifp->ptm_enable && if_is_no_ptm_operative (ifp)) if_down (ifp); } -} - -static void -zebra_ptm_process_csv (char *buf, int buflen) -{ - /* handle any cbl messages */ - zebra_ptm_handle_cbl_msg(buf, buflen); - - /* handle any bfd messages */ - zebra_ptm_handle_bfd_msg(buf, buflen); + return 0; } int @@ -360,29 +421,33 @@ zebra_ptm_sock_write (struct thread *thread) { int sock; int nbytes; + char *data; sock = THREAD_FD (thread); + data = THREAD_ARG (thread); if (sock == -1) return -1; - nbytes = send(sock, ZEBRA_PTM_GET_STATUS_CMD, - strlen(ZEBRA_PTM_GET_STATUS_CMD), 0); + errno = 0; - if (nbytes <= 0) - { - if (nbytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN) - zlog_warn ("routing socket error: %s", safe_strerror (errno)); + nbytes = send(sock, data, strlen(data), 0); - zebra_ptm_sock = -1; - zebra_ptm_thread = thread_add_timer (zebrad.master, zebra_ptm_connect, NULL, - zebra_ptm_reconnect_time); - return (-1); + if (nbytes <= 0) { + if (errno && errno != EWOULDBLOCK && errno != EAGAIN) { + zlog_warn ("%s routing socket error: %s", __func__, + safe_strerror (errno)); + zebra_ptm_sock = -1; + zebra_ptm_thread = thread_add_timer (zebrad.master, zebra_ptm_connect, + NULL, zebra_ptm_reconnect_time); + return (-1); } + } - zlog_debug ("%s: Sent message %s\n", __func__, ZEBRA_PTM_GET_STATUS_CMD); - zebra_ptm_thread = thread_add_read (zebrad.master, zebra_ptm_sock_read, NULL, sock); - + zlog_debug ("%s: Sent message (%d) %s", __func__, strlen(data), data); + zebra_ptm_thread = thread_add_read (zebrad.master, zebra_ptm_sock_read, + NULL, sock); + free (data); return(0); } @@ -390,11 +455,10 @@ int zebra_ptm_sock_read (struct thread *thread) { int sock, done = 0; - char rcvbuf[ZEBRA_PTM_MAX_SOCKBUF]; - int nbytes, msglen; + int rc; char *rcvptr; - char msgbuf[ZEBRA_PTM_MAX_SOCKBUF]; + errno = 0; sock = THREAD_FD (thread); if (sock == -1) @@ -402,37 +466,337 @@ zebra_ptm_sock_read (struct thread *thread) /* PTM communicates in CSV format */ while(!done) { - rcvptr = rcvbuf; - /* get PTM header */ - nbytes = recv(sock, rcvptr, PTM_HEADER_LEN, 0); - if (nbytes <= 0) - break; - snprintf(msgbuf, PTM_MSG_LEN+1, "%s", rcvptr); - msglen = strtol(msgbuf, NULL, 10); - - /* get the PTM message */ - rcvptr = calloc(1, msglen); - nbytes = recv(sock, rcvptr, msglen, 0); - if (nbytes <= 0) - break; - /* process one PTM message */ - zebra_ptm_process_csv(rcvptr, msglen); - free(rcvptr); + rcvptr = calloc(1, ZEBRA_PTM_MAX_SOCKBUF); + + rc = ptm_lib_process_msg(ptm_hdl, sock, rcvptr, ZEBRA_PTM_MAX_SOCKBUF, + NULL); + if (rc <= 0) + break; } - if (nbytes <= 0) { - if (errno && errno != EWOULDBLOCK && errno != EAGAIN) { - zlog_warn ("routing socket error: %s", safe_strerror (errno)); + 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 (zebra_ptm_sock); zebra_ptm_sock = -1; zebra_ptm_thread = thread_add_timer (zebrad.master, zebra_ptm_connect, - NULL, zebra_ptm_reconnect_time); + NULL, zebra_ptm_reconnect_time); return (-1); } } - zebra_ptm_thread = thread_add_read (zebrad.master, zebra_ptm_sock_read, NULL, sock); + free(rcvptr); + zebra_ptm_thread = thread_add_read (zebrad.master, zebra_ptm_sock_read, + NULL, sock); + + return 0; +} + +/* BFD peer/dst register/update */ +int +zebra_ptm_bfd_dst_register (struct zserv *client, int sock, u_short length, + int command) +{ + char *data; + 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++; + + zlog_debug("bfd_dst_register msg from client %s: length=%d", + zebra_route_string(client->proto), length); + + if (zebra_ptm_sock == -1) + { + zebra_ptm_thread = thread_add_timer (zebrad.master, zebra_ptm_connect, + NULL, zebra_ptm_reconnect_time); + return -1; + } + + data = calloc(1, data_len); + if (!data) + { + zlog_debug("%s: Allocation of send data failed", __func__); + 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, "cmd", 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", zebra_ptm_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, data, &data_len); + zebra_ptm_thread = thread_add_write (zebrad.master, zebra_ptm_sock_write, + data, zebra_ptm_sock); + return 0; +} + +/* BFD peer/dst deregister */ +int +zebra_ptm_bfd_dst_deregister (struct zserv *client, int sock, u_short length) +{ + char *data; + 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++; + + zlog_debug("bfd_dst_deregister msg from client %s: length=%d", + zebra_route_string(client->proto), length); + + if (zebra_ptm_sock == -1) + { + zebra_ptm_thread = thread_add_timer (zebrad.master, zebra_ptm_connect, + NULL, zebra_ptm_reconnect_time); + return -1; + } + + data = calloc(1, data_len); + if (!data) + { + zlog_debug("%s: Allocation of send data failed", __func__); + 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, "cmd", 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", zebra_ptm_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, data, &data_len); + zebra_ptm_thread = thread_add_write (zebrad.master, zebra_ptm_sock_write, + data, zebra_ptm_sock); return 0; } diff --git a/zebra/zebra_ptm.h b/zebra/zebra_ptm.h index 126c44811..85a0bdced 100644 --- a/zebra/zebra_ptm.h +++ b/zebra/zebra_ptm.h @@ -25,10 +25,14 @@ extern const char ZEBRA_PTM_SOCK_NAME[]; #define ZEBRA_PTM_MAX_SOCKBUF 3200 /* 25B *128 ports */ +#define ZEBRA_PTM_SEND_MAX_SOCKBUF 512 extern int ptm_enable; void zebra_ptm_init (void); int zebra_ptm_connect (struct thread *t); void zebra_ptm_write (struct vty *vty); +int zebra_ptm_bfd_dst_register (struct zserv *client, int sock, u_short length, + int command); +int zebra_ptm_bfd_dst_deregister (struct zserv *client, int sock, u_short length); #endif diff --git a/zebra/zebra_ptm_null.c b/zebra/zebra_ptm_null.c new file mode 100644 index 000000000..a9e233376 --- /dev/null +++ b/zebra/zebra_ptm_null.c @@ -0,0 +1,29 @@ +/** + * @copyright Copyright (C) 2015 Cumulus Networks, Inc. + * + * 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" + +void zebra_interface_bfd_update (struct interface *a, struct prefix *dp, + struct prefix *sp) +{ return; } + +void zebra_bfd_peer_replay_req (void) +{ return; } diff --git a/zebra/zebra_ptm_redistribute.c b/zebra/zebra_ptm_redistribute.c new file mode 100644 index 000000000..5d231de85 --- /dev/null +++ b/zebra/zebra_ptm_redistribute.c @@ -0,0 +1,122 @@ +/** + * @copyright Copyright (C) 2015 Cumulus Networks, Inc. + * + * 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 "vty.h" +#include "stream.h" +#include "zebra/zserv.h" + +/* master zebra server structure */ +extern struct zebra_t zebrad; + +int +zsend_interface_bfd_update (int cmd, struct zserv *client, + struct interface *ifp, struct prefix *dp, + struct prefix *sp) +{ + int blen; + struct stream *s; + + /* Check this client need interface information. */ + if (! client->ifinfo) + return 0; + + s = client->obuf; + stream_reset (s); + + zserv_create_header (s, cmd); + if (ifp) + stream_putl (s, ifp->ifindex); + else + stream_putl (s, 0); + + /* BFD destination prefix information. */ + stream_putc (s, dp->family); + blen = prefix_blen (dp); + stream_put (s, &dp->u.prefix, blen); + stream_putc (s, dp->prefixlen); + + /* BFD source prefix information. */ + stream_putc (s, sp->family); + blen = prefix_blen (sp); + stream_put (s, &sp->u.prefix, blen); + stream_putc (s, sp->prefixlen); + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + client->if_bfd_cnt++; + return zebra_server_send_message(client); +} + +void +zebra_interface_bfd_update (struct interface *ifp, struct prefix *dp, + struct prefix *sp) +{ + struct listnode *node, *nnode; + struct zserv *client; + + for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) + { + /* Supporting for OSPF and BGP */ + if (client->proto != ZEBRA_ROUTE_OSPF && client->proto != ZEBRA_ROUTE_BGP) + continue; + + /* Notify to the protocol daemons. */ + zsend_interface_bfd_update (ZEBRA_INTERFACE_BFD_DEST_DOWN, client, ifp, + dp, sp); + } +} + +int +zsend_bfd_peer_replay (int cmd, struct zserv *client) +{ + struct stream *s; + + s = client->obuf; + stream_reset (s); + + zserv_create_header (s, cmd); + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + client->bfd_peer_replay_cnt++; + return zebra_server_send_message(client); +} + +void +zebra_bfd_peer_replay_req (void) +{ + struct listnode *node, *nnode; + struct zserv *client; + + for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) + { + /* Supporting for BGP */ + if (client->proto != ZEBRA_ROUTE_BGP) + continue; + + /* Notify to the protocol daemons. */ + zsend_bfd_peer_replay (ZEBRA_BFD_DEST_REPLAY, client); + } +} diff --git a/zebra/zebra_ptm_redistribute.h b/zebra/zebra_ptm_redistribute.h new file mode 100644 index 000000000..b79d122af --- /dev/null +++ b/zebra/zebra_ptm_redistribute.h @@ -0,0 +1,28 @@ +/** + * @copyright Copyright (C) 2015 Cumulus Networks, Inc. + * + * 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. + */ + + +#ifndef _ZEBRA_PTM_REDISTRIBUTE_H +#define _ZEBRA_PTM_REDISTRIBUTE_H +extern void zebra_interface_bfd_update (struct interface *, struct prefix *, + struct prefix *); +extern void zebra_bfd_peer_replay_req (void); +#endif /* _ZEBRA_PTM_REDISTRIBUTE_H */ diff --git a/zebra/zserv.c b/zebra/zserv.c index cd986daee..51a69a961 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -477,36 +477,6 @@ zsend_interface_update (int cmd, struct zserv *client, struct interface *ifp) return zebra_server_send_message(client); } -int -zsend_interface_bfd_update (int cmd, struct zserv *client, - struct interface *ifp, struct prefix *p) -{ - int blen; - struct stream *s; - - /* Check this client need interface information. */ - if (! client->ifinfo) - return 0; - - s = client->obuf; - stream_reset (s); - - zserv_create_header (s, cmd); - stream_putl (s, ifp->ifindex); - - /* BFD destination prefix information. */ - stream_putc (s, p->family); - blen = prefix_blen (p); - stream_put (s, &p->u.prefix, blen); - stream_putc (s, p->prefixlen); - - /* Write packet size. */ - stream_putw_at (s, 0, stream_get_endp (s)); - - client->if_bfd_cnt++; - return zebra_server_send_message(client); -} - /* * The zebra server sends the clients a ZEBRA_IPV4_ROUTE_ADD or a * ZEBRA_IPV6_ROUTE_ADD via zsend_route_multipath in the following @@ -1905,6 +1875,13 @@ zebra_client_read (struct thread *thread) case ZEBRA_IMPORT_ROUTE_UNREGISTER: zserv_rnh_unregister(client, sock, length, RNH_IMPORT_CHECK_TYPE); break; + case ZEBRA_BFD_DEST_UPDATE: + case ZEBRA_BFD_DEST_REGISTER: + zebra_ptm_bfd_dst_register(client, sock, length, command); + break; + case ZEBRA_BFD_DEST_DEREGISTER: + zebra_ptm_bfd_dst_deregister(client, sock, length); + break; default: zlog_info ("Zebra received unknown command %d", command); break; @@ -2194,6 +2171,8 @@ zebra_show_client_detail (struct vty *vty, struct zserv *client) client->redist_v6_del_cnt, VTY_NEWLINE); vty_out (vty, "Connected %-12d%-12d%-12d%s", client->ifadd_cnt, 0, client->ifdel_cnt, VTY_NEWLINE); + vty_out (vty, "BFD peer %-12d%-12d%-12d%s", client->bfd_peer_add_cnt, + client->bfd_peer_upd8_cnt, client->bfd_peer_del_cnt, VTY_NEWLINE); vty_out (vty, "Interface Up Notifications: %d%s", client->ifup_cnt, VTY_NEWLINE); vty_out (vty, "Interface Down Notifications: %d%s", client->ifdown_cnt, diff --git a/zebra/zserv.h b/zebra/zserv.h index a344cbd0c..db20bad26 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -94,6 +94,10 @@ struct zserv u_int32_t ifadd_cnt; u_int32_t ifdel_cnt; u_int32_t if_bfd_cnt; + u_int32_t bfd_peer_add_cnt; + u_int32_t bfd_peer_upd8_cnt; + u_int32_t bfd_peer_del_cnt; + u_int32_t bfd_peer_replay_cnt; time_t connect_time; time_t last_read_time; @@ -148,8 +152,6 @@ extern int zsend_interface_update (int, struct zserv *, struct interface *); extern int zsend_route_multipath (int, struct zserv *, struct prefix *, struct rib *); extern int zsend_router_id_update(struct zserv *, struct prefix *); -extern int zsend_interface_bfd_update(int, struct zserv *, struct interface *, - struct prefix *); extern pid_t pid; extern void zserv_create_header(struct stream *s, uint16_t cmd); |