diff options
| author | Donald Sharp <sharpd@cumulusnetworks.com> | 2015-07-22 12:35:37 -0700 |
|---|---|---|
| committer | Donald Sharp <sharpd@cumulusnetworks.com> | 2015-07-22 12:35:37 -0700 |
| commit | 7f342629a9eae034138fd542734fe2e6eca8085d (patch) | |
| tree | e11971e7ac8a8d76ee978dd19691efe64570ebc1 /lib/bfd.c | |
| parent | 7bbc6864de7071873fc47680cb80a583280495b3 (diff) | |
This patch changes ospfd from only listening mode for BFD status updates to interactive mode of dynamically registering/deregistering neighbors discovered on BFD enabled interfaces with PTM/BFD through zebra. Neighbor is registered with BFD when 2-way adjacency is established and deregistered when adjacency goes down if the BFD is enabled on the interface through which the neighbor was discovered.
OSPF BFD command enhancement to configure BFD parameters (detect multiplier, min rx and min tx).
interface <if-name>
ip ospf bfd <detect mult> <min rx> <min tx>
This patch also adds BFD support for IPv6 OSPF. ospf6d will dynamically register/deregister IPv6 neighbors with BFD for monitoring the connectivity of the neighbor. Neighbor is registered with BFD when 2-way adjacency is established and deregistered when adjacency goes down if the BFD is enabled on the interface through which the neighbor was discovered.
OSPF6 BFD command added to configure BFD and parameters (detect multiplier, min rx and min tx).
interface <if-name>
ipv6 ospf6 bfd <detect mult> <min rx> <min tx>
Signed-off-by: Radhika Mahankali <radhika@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Kanna Rajagopal <kanna@cumulusnetworks.com>
Diffstat (limited to 'lib/bfd.c')
| -rw-r--r-- | lib/bfd.c | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/lib/bfd.c b/lib/bfd.c new file mode 100644 index 0000000000..78e015898f --- /dev/null +++ b/lib/bfd.c @@ -0,0 +1,287 @@ +/** + * bfd.c: BFD handling routines + * + * @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 "command.h" +#include "memory.h" +#include "prefix.h" +#include "thread.h" +#include "stream.h" +#include "zclient.h" +#include "table.h" +#include "vty.h" +#include "bfd.h" + +/* + * bfd_info_create - Allocate the BFD information + */ +struct bfd_info * +bfd_info_create(void) +{ + struct bfd_info *bfd_info; + + bfd_info = XCALLOC (MTYPE_BFD_INFO, sizeof (struct bfd_info)); + assert(bfd_info); + + return bfd_info; +} + +/* + * bfd_info_free - Free the BFD information. + */ +void +bfd_info_free(void **bfd_info) +{ + if (*bfd_info) + { + XFREE (MTYPE_BFD_INFO, *bfd_info); + *bfd_info = NULL; + } +} + +/* + * bfd_validate_param - Validate the BFD paramter information. + */ +int +bfd_validate_param(struct vty *vty, const char *dm_str, const char *rx_str, + const char *tx_str, u_int8_t *dm_val, u_int32_t *rx_val, + u_int32_t *tx_val) +{ + VTY_GET_INTEGER_RANGE ("detect-mul", *dm_val, dm_str, + BFD_MIN_DETECT_MULT, BFD_MAX_DETECT_MULT); + VTY_GET_INTEGER_RANGE ("min-rx", *rx_val, rx_str, + BFD_MIN_MIN_RX, BFD_MAX_MIN_RX); + VTY_GET_INTEGER_RANGE ("min-tx", *tx_val, tx_str, + BFD_MIN_MIN_TX, BFD_MAX_MIN_TX); + return CMD_SUCCESS; +} + +/* + * bfd_set_param - Set the configured BFD paramter values + */ +void +bfd_set_param (struct bfd_info **bfd_info, u_int32_t min_rx, u_int32_t min_tx, + u_int8_t detect_mult, int defaults, int *command) +{ + if (!*bfd_info) + { + *bfd_info = bfd_info_create(); + *command = ZEBRA_BFD_DEST_REGISTER; + } + else + { + if (((*bfd_info)->required_min_rx != min_rx) || + ((*bfd_info)->desired_min_tx != min_tx) || + ((*bfd_info)->detect_mult != detect_mult)) + *command = ZEBRA_BFD_DEST_UPDATE; + } + + if (*command) + { + (*bfd_info)->required_min_rx = min_rx; + (*bfd_info)->desired_min_tx = min_tx; + (*bfd_info)->detect_mult = detect_mult; + } + + if (!defaults) + SET_FLAG ((*bfd_info)->flags, BFD_FLAG_PARAM_CFG); + else + UNSET_FLAG ((*bfd_info)->flags, BFD_FLAG_PARAM_CFG); +} + +/* + * bfd_peer_sendmsg - Format and send a peer register/Unregister + * command to Zebra to be forwarded to BFD + */ +void +bfd_peer_sendmsg (struct zclient *zclient, struct bfd_info *bfd_info, + int family, void *dst_ip, void *src_ip, char *if_name, + int ttl, int multihop, int command, int set_flag) +{ + struct stream *s; + int ret; + int len; + + /* Check socket. */ + if (!zclient || zclient->sock < 0) + { + zlog_debug("%s: Can't send BFD peer register, Zebra client not " + "established", __FUNCTION__); + return; + } + + s = zclient->obuf; + stream_reset (s); + zclient_create_header (s, command); + + stream_putw(s, family); + switch (family) + { + case AF_INET: + stream_put_in_addr (s, (struct in_addr *)dst_ip); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + stream_put(s, dst_ip, 16); + break; +#endif + default: + break; + } + + if (command != ZEBRA_BFD_DEST_DEREGISTER) + { + stream_putl(s, bfd_info->required_min_rx); + stream_putl(s, bfd_info->desired_min_tx); + stream_putc(s, bfd_info->detect_mult); + } + + if (multihop) + { + stream_putc(s, 1); + /* Multi-hop destination send the source IP address to BFD */ + if (src_ip) + { + stream_putw(s, family); + switch (family) + { + case AF_INET: + stream_put_in_addr (s, (struct in_addr *) src_ip); + break; + #ifdef HAVE_IPV6 + case AF_INET6: + stream_put(s, src_ip, 16); + break; + #endif + default: + break; + } + } + stream_putc(s, ttl); + } + else + { + stream_putc(s, 0); +#ifdef HAVE_IPV6 + if ((family == AF_INET6) && (src_ip)) + { + stream_putw(s, family); + stream_put(s, src_ip, 16); + } +#endif + if (if_name) + { + len = strlen(if_name); + stream_putc(s, len); + stream_put(s, if_name, len); + } + else + { + stream_putc(s, 0); + } + } + + stream_putw_at (s, 0, stream_get_endp (s)); + + ret = zclient_send_message(zclient); + + if (ret < 0) + { + zlog_warn("bfd_peer_sendmsg: zclient_send_message() failed"); + return; + } + + if (set_flag) + { + if (command == ZEBRA_BFD_DEST_REGISTER) + SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG); + else if (command == ZEBRA_BFD_DEST_DEREGISTER) + UNSET_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG); + } + + return; +} + +/* + * bfd_get_command_dbg_str - Convert command to a debug string. + */ +const char * +bfd_get_command_dbg_str(int command) +{ + switch (command) + { + case ZEBRA_BFD_DEST_REGISTER: + return "Register"; + case ZEBRA_BFD_DEST_DEREGISTER: + return "Deregister"; + case ZEBRA_BFD_DEST_UPDATE: + return "Update"; + default: + return "Unknown"; + } +} + +/* + * bfd_get_peer_info - Extract the Peer information for which the BFD session + * went down from the message sent from Zebra to clients. + */ +struct interface * +bfd_get_peer_info (struct stream *s, struct prefix *dp, struct prefix *sp) +{ + unsigned int ifindex; + struct interface *ifp = NULL; + int plen; + + /* Get interface index. */ + ifindex = stream_getl (s); + + /* Lookup index. */ + if (ifindex != 0) + { + ifp = if_lookup_by_index (ifindex); + if (ifp == NULL) + { + zlog_warn ("zebra_interface_bfd_read: " + "Can't find interface by ifindex: %d ", ifindex); + return NULL; + } + } + + /* Fetch destination address. */ + dp->family = stream_getc (s); + + plen = prefix_blen (dp); + stream_get (&dp->u.prefix, s, plen); + dp->prefixlen = stream_getc (s); + + if (sp) + { + sp->family = stream_getc (s); + + plen = prefix_blen (sp); + stream_get (&sp->u.prefix, s, plen); + sp->prefixlen = stream_getc (s); + } + return ifp; +} |
