Skip to content

Commit

Permalink
Support of BFD status in Quagga
Browse files Browse the repository at this point in the history
Ticket:CM-6802, CM-6952
Reviewed By: Donald, Kanna
Testing Done:

Double commit of b76943235e09472ec174edcf7204fc82d27fe966 from br2.5. But, manually resolved all the compilation errors. Also, modified the shows to support the json format which was not supported in br2.5.

CM-6802 – Currently, BFD session status can be monitored only through ptmctl. There is no way to check the BFD status of a peer/neighbor through Quagga. Debugging becomes easier if BFD status is shown in Quagga too. BFD status is relevant when it is shown against the BGP peer/OSPF neighbor. For, this following code changes have been done:
   - Only down messages from PTM were being propagated from Zebra daemon to clients (bgpd, ospfd and ospf6d). Now, both up and down messages are redistributed to the clients from zebra. BFD status field has been added to the messaging. Handling of BFD session up messages has been added to the client code. BGP/OSPF neighbor is brought down only if the old BFD session status is ‘Up’ to handle extra/initial down messages.
   - BFD status and last update timestamp fields have been added to the common BFD info structure. Also, common show functions for showing BFD information have been added to BFD lib.
   - Modified the BGP neighbor show functions to call common BFD lib functions.
   - For ospf and ospf6, BFD information was maintained only at interface level. To show BFD status per neighbor, BFD information has been added at neighbor level too. “show ip ospf interface”, “show ip ospf neighbor detail”, “show ipv6 ospf6 interface” and “show ipv6 ospf6 neighbor detail” output have been modified to show BFD information.

CM-6952 - IBGP peers were always assumed to be multi-hop since there was no easy way to determine whether an IBGP peer was single hop or multihop unlike EBGP. But, this is causing problem with IBGP link local peers since BFD doesn't allow multihop BFD session with link local IP addresses. Link local peers were discovered when the interface peering was enabled. Interface peering is always singlehop. So, added checks to treat all interface based peers as single hop irrespective of whether the peer is IBGP or EBGP.
  • Loading branch information
RadhikaMahankali committed Aug 31, 2015
1 parent 89ca90f commit 68fe91d
Show file tree
Hide file tree
Showing 22 changed files with 497 additions and 140 deletions.
98 changes: 47 additions & 51 deletions bgpd/bgp_bfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ bgp_bfd_peer_group2peer_copy(struct peer *conf, struct peer *peer)
static int
bgp_bfd_is_peer_multihop(struct peer *peer)
{
if((peer->sort == BGP_PEER_IBGP) || is_ebgp_multihop_configured(peer))
if((peer->conf_if == NULL) && ((peer->sort == BGP_PEER_IBGP) ||
is_ebgp_multihop_configured(peer)))
return 1;
else
return 0;
Expand Down Expand Up @@ -191,34 +192,61 @@ bgp_bfd_dest_replay (int command, struct zclient *client, zebra_size_t length)
}

/*
* bgp_interface_bfd_dest_down - Find the peer for which the BFD status
* has changed and bring down the peer
* connectivity.
* bgp_bfd_peer_status_update - Update the BFD status if it has changed. Bring
* down the peer if the BFD session went down from * up.
*/
static void
bgp_bfd_peer_status_update (struct peer *peer, int status)
{
struct bfd_info *bfd_info;
int old_status;

bfd_info = (struct bfd_info *)peer->bfd_info;

if (bfd_info->status == status)
return;

old_status = bfd_info->status;
bfd_info->status = status;
bfd_info->last_update = bgp_clock();

if ((status == BFD_STATUS_DOWN) && (old_status == BFD_STATUS_UP))
{
peer->last_reset = PEER_DOWN_BFD_DOWN;
BGP_EVENT_ADD (peer, BGP_Stop);
}
}

/*
* bgp_bfd_dest_update - Find the peer for which the BFD status
* has changed and bring down the peer
* connectivity if the BFD session went down.
*/
static int
bgp_interface_bfd_dest_down (int command, struct zclient *zclient,
bgp_bfd_dest_update (int command, struct zclient *zclient,
zebra_size_t length)
{
struct interface *ifp;
struct prefix dp;
struct prefix sp;
int status;

ifp = bfd_get_peer_info (zclient->ibuf, &dp, &sp);
ifp = bfd_get_peer_info (zclient->ibuf, &dp, &sp, &status);

if (BGP_DEBUG (zebra, ZEBRA))
{
char buf[2][128];
prefix2str(&dp, buf[0], sizeof(buf[0]));
if (ifp)
{
zlog_debug("Zebra: interface %s bfd destination %s down",
ifp->name, buf[0]);
zlog_debug("Zebra: interface %s bfd destination %s %s",
ifp->name, buf[0], bfd_get_status_str(status));
}
else
{
prefix2str(&sp, buf[1], sizeof(buf[1]));
zlog_debug("Zebra: source %s bfd destination %s down",
buf[1], buf[0]);
zlog_debug("Zebra: source %s bfd destination %s %s",
buf[1], buf[0], bfd_get_status_str(status));
}
}

Expand Down Expand Up @@ -253,8 +281,7 @@ bgp_interface_bfd_dest_down (int command, struct zclient *zclient,

if (ifp && (ifp == peer->nexthop.ifp))
{
peer->last_reset = PEER_DOWN_BFD_DOWN;
BGP_EVENT_ADD (peer, BGP_Stop);
bgp_bfd_peer_status_update(peer, status);
}
else
{
Expand All @@ -279,8 +306,7 @@ bgp_interface_bfd_dest_down (int command, struct zclient *zclient,
else
continue;

peer->last_reset = PEER_DOWN_BFD_DOWN;
BGP_EVENT_ADD (peer, BGP_Stop);
bgp_bfd_peer_status_update(peer, status);
}
}
}
Expand All @@ -299,17 +325,17 @@ bgp_bfd_peer_param_set (struct peer *peer, u_int32_t min_rx, u_int32_t min_tx,
struct listnode *node, *nnode;
int command = 0;

bfd_set_param(&(peer->bfd_info), min_rx, min_tx, detect_mult,
defaults, &command);
bfd_set_param((struct bfd_info **)&(peer->bfd_info), min_rx, min_tx,
detect_mult, defaults, &command);

if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
{
command = 0;
bfd_set_param(&(peer->bfd_info), min_rx, min_tx, detect_mult,
defaults, &command);
bfd_set_param((struct bfd_info **)&(peer->bfd_info), min_rx, min_tx,
detect_mult, defaults, &command);

if ((peer->status == Established) &&
(command == ZEBRA_BFD_DEST_REGISTER))
Expand Down Expand Up @@ -386,38 +412,8 @@ bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer, char *addr)
void
bgp_bfd_show_info(struct vty *vty, struct peer *peer, u_char use_json, json_object *json_neigh)
{
struct bfd_info *bfd_info;
json_object *json_bfd = NULL;

if (!peer->bfd_info)
return;

if (use_json)
json_bfd = json_object_new_object();

bfd_info = (struct bfd_info *)peer->bfd_info;

if (use_json)
{
if (bgp_bfd_is_peer_multihop(peer))
json_object_string_add(json_bfd, "bfdMultiHop", "yes");
else
json_object_string_add(json_bfd, "bfdMultiHop", "no");
json_object_int_add(json_bfd, "detectMultiplier", bfd_info->detect_mult);
json_object_int_add(json_bfd, "rxMinInterval", bfd_info->required_min_rx);
json_object_int_add(json_bfd, "txMinInterval", bfd_info->desired_min_tx);
json_object_object_add(json_neigh, "peerBfdInfo", json_bfd);
}
else
{
vty_out (vty, " BFD: Multi-hop: %s%s",
(bgp_bfd_is_peer_multihop(peer)) ? "yes" : "no", VTY_NEWLINE);
vty_out (vty, " Detect Mul: %d, Min Rx interval: %d,"
" Min Tx interval: %d%s",
bfd_info->detect_mult, bfd_info->required_min_rx,
bfd_info->desired_min_tx, VTY_NEWLINE);
vty_out (vty, "%s", VTY_NEWLINE);
}
bfd_show_info(vty, (struct bfd_info *)peer->bfd_info,
bgp_bfd_is_peer_multihop(peer), 0, use_json, json_neigh);
}

DEFUN (neighbor_bfd,
Expand Down Expand Up @@ -501,7 +497,7 @@ void
bgp_bfd_init(void)
{
/* Initialize BFD client functions */
zclient->interface_bfd_dest_down = bgp_interface_bfd_dest_down;
zclient->interface_bfd_dest_update = bgp_bfd_dest_update;
zclient->bfd_dest_replay = bgp_bfd_dest_replay;

/* "neighbor bfd" commands. */
Expand Down
152 changes: 151 additions & 1 deletion lib/bfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ bfd_info_create(void)
bfd_info = XCALLOC (MTYPE_BFD_INFO, sizeof (struct bfd_info));
assert(bfd_info);

bfd_info->status = BFD_STATUS_UNKNOWN;
bfd_info->last_update = 0;
return bfd_info;
}

Expand Down Expand Up @@ -247,7 +249,8 @@ bfd_get_command_dbg_str(int command)
* 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)
bfd_get_peer_info (struct stream *s, struct prefix *dp, struct prefix *sp,
int *status)
{
unsigned int ifindex;
struct interface *ifp = NULL;
Expand Down Expand Up @@ -275,6 +278,9 @@ bfd_get_peer_info (struct stream *s, struct prefix *dp, struct prefix *sp)
stream_get (&dp->u.prefix, s, plen);
dp->prefixlen = stream_getc (s);

/* Get BFD status. */
*status = stream_getl (s);

if (sp)
{
sp->family = stream_getc (s);
Expand All @@ -285,3 +291,147 @@ bfd_get_peer_info (struct stream *s, struct prefix *dp, struct prefix *sp)
}
return ifp;
}

/*
* bfd_get_status_str - Convert BFD status to a display string.
*/
const char *
bfd_get_status_str(int status)
{
switch (status)
{
case BFD_STATUS_DOWN:
return "Down";
case BFD_STATUS_UP:
return "Up";
case BFD_STATUS_UNKNOWN:
default:
return "Unknown";
}
}

/*
* bfd_last_update - Calculate the last BFD update time and convert it
* into a dd:hh:mm:ss display format.
*/
static void
bfd_last_update (time_t last_update, char *buf, size_t len)
{
time_t curr;
time_t diff;
struct tm *tm;
struct timeval tv;

/* If no BFD satatus update has ever been received, print `never'. */
if (last_update == 0)
{
snprintf (buf, len, "never");
return;
}

/* Get current time. */
quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv);
curr = tv.tv_sec;
diff = curr - last_update;
tm = gmtime (&diff);

snprintf (buf, len, "%d:%02d:%02d:%02d",
tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec);
}

/*
* bfd_show_param - Show the BFD parameter information.
*/
void
bfd_show_param(struct vty *vty, struct bfd_info *bfd_info, int bfd_tag,
int extra_space, u_char use_json, json_object *json_obj)
{
json_object *json_bfd = NULL;

if (!bfd_info)
return;

if (use_json)
{
if (bfd_tag)
json_bfd = json_object_new_object();
else
json_bfd = json_obj;

json_object_int_add(json_bfd, "detectMultiplier", bfd_info->detect_mult);
json_object_int_add(json_bfd, "rxMinInterval", bfd_info->required_min_rx);
json_object_int_add(json_bfd, "txMinInterval", bfd_info->desired_min_tx);
if (bfd_tag)
json_object_object_add(json_obj, "peerBfdInfo", json_bfd);
}
else
{
vty_out (vty, " %s%sDetect Mul: %d, Min Rx interval: %d,"
" Min Tx interval: %d%s",
(extra_space) ? " ": "", (bfd_tag) ? "BFD: " : " ",
bfd_info->detect_mult, bfd_info->required_min_rx,
bfd_info->desired_min_tx, VTY_NEWLINE);
}
}

/*
* bfd_show_status - Show the BFD status information.
*/
static void
bfd_show_status(struct vty *vty, struct bfd_info *bfd_info, int bfd_tag,
int extra_space, u_char use_json, json_object *json_bfd)
{
char time_buf[32];

if (!bfd_info)
return;

bfd_last_update(bfd_info->last_update, time_buf, 32);
if (use_json)
{
json_object_string_add(json_bfd, "status",
bfd_get_status_str(bfd_info->status));
json_object_string_add(json_bfd, "lastUpdate", time_buf);
}
else
{
vty_out (vty, " %s%sStatus: %s, Last update: %s%s",
(extra_space) ? " ": "", (bfd_tag) ? "BFD: " : " ",
bfd_get_status_str(bfd_info->status), time_buf, VTY_NEWLINE);
}
}

/*
* bfd_show_info - Show the BFD information.
*/
void
bfd_show_info(struct vty *vty, struct bfd_info *bfd_info, int multihop,
int extra_space, u_char use_json, json_object *json_obj)
{
json_object *json_bfd = NULL;

if (!bfd_info)
return;

if (use_json)
{
json_bfd = json_object_new_object();
if (multihop)
json_object_string_add(json_bfd, "type", "multi hop");
else
json_object_string_add(json_bfd, "type", "single hop");
}
else
{
vty_out (vty, " %sBFD: Type: %s%s", (extra_space) ? " " : "",
(multihop) ? "multi hop" : "single hop", VTY_NEWLINE);
}

bfd_show_param(vty, bfd_info, 0, extra_space, use_json, json_bfd);
bfd_show_status(vty, bfd_info, 0, extra_space, use_json, json_bfd);

if (use_json)
json_object_object_add(json_obj, "peerBfdInfo", json_bfd);
else
vty_out (vty, "%s", VTY_NEWLINE);
}
22 changes: 21 additions & 1 deletion lib/bfd.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#ifndef _ZEBRA_BFD_H
#define _ZEBRA_BFD_H

#include "lib/json.h"

#define BFD_CMD_DETECT_MULT_RANGE "<2-255> "
#define BFD_CMD_MIN_RX_RANGE "<50-60000> "
#define BFD_CMD_MIN_TX_RANGE "<50-60000>"
Expand All @@ -41,12 +43,18 @@
#define BFD_FLAG_PARAM_CFG (1 << 0) /* parameters have been configured */
#define BFD_FLAG_BFD_REG (1 << 1) /* Peer registered with BFD */

#define BFD_STATUS_UNKNOWN (1 << 0) /* BFD session status never received */
#define BFD_STATUS_DOWN (1 << 1) /* BFD session status is down */
#define BFD_STATUS_UP (1 << 2) /* BFD session status is up */

struct bfd_info
{
u_int16_t flags;
u_int8_t detect_mult;
u_int32_t desired_min_tx;
u_int32_t required_min_rx;
time_t last_update;
u_int8_t status;
};

extern struct bfd_info *
Expand All @@ -72,6 +80,18 @@ extern const char *
bfd_get_command_dbg_str(int command);

extern struct interface *
bfd_get_peer_info (struct stream *s, struct prefix *dp, struct prefix *sp);
bfd_get_peer_info (struct stream *s, struct prefix *dp, struct prefix *sp,
int *status);

const char *
bfd_get_status_str(int status);

extern void
bfd_show_param(struct vty *vty, struct bfd_info *bfd_info, int bfd_tag,
int extra_space, u_char use_json, json_object *json_obj);

extern void
bfd_show_info(struct vty *vty, struct bfd_info *bfd_info, int multihop,
int extra_space, u_char use_json, json_object *json_obj);

#endif /* _ZEBRA_BFD_H */
Loading

0 comments on commit 68fe91d

Please sign in to comment.