ptm_bfd_start_xmt_timer(bs, false);
}
+ /* initialize RTT */
+ bfd_rtt_init(bs);
+
return 0;
}
memset(bfd->peer_hw_addr, 0, sizeof(bfd->peer_hw_addr));
/* reset local address ,it might has been be changed after bfd is up*/
memset(&bfd->local_address, 0, sizeof(bfd->local_address));
+
+ /* reset RTT */
+ bfd_rtt_init(bfd);
}
static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa,
{
return bfd_key_hash->count;
}
+
+void bfd_rtt_init(struct bfd_session *bfd)
+{
+ uint8_t i;
+
+ /* initialize RTT */
+ bfd->rtt_valid = 0;
+ bfd->rtt_index = 0;
+ for (i = 0; i < BFD_RTT_SAMPLE; i++)
+ bfd->rtt[i] = 0;
+}
};
};
uint32_t my_discr;
- uint8_t pad[16];
+ uint64_t time_sent_sec;
+ uint64_t time_sent_usec;
};
uint32_t required_min_echo_rx;
};
+#define BFD_RTT_SAMPLE 8
+
/*
* Session state information
*/
struct bfd_timers remote_timers;
uint64_t refcount; /* number of pointers referencing this. */
+
+ uint8_t rtt_valid; /* number of valid samples */
+ uint8_t rtt_index; /* last index added */
+ uint64_t rtt[BFD_RTT_SAMPLE]; /* RRT in usec for echo to be looped */
};
struct peer_label {
bool mhop);
void bfd_sessions_remove_manual(void);
void bfd_profiles_remove(void);
+void bfd_rtt_init(struct bfd_session *bfd);
/**
* Set the BFD session echo state.
struct sockaddr_any *peer);
int bp_udp_send(int sd, uint8_t ttl, uint8_t *data, size_t datalen,
struct sockaddr *to, socklen_t tolen);
-int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd,
- uint8_t *ttl, uint32_t *my_discr);
+int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd, uint8_t *ttl,
+ uint32_t *my_discr, uint64_t *my_rtt);
#ifdef BFD_LINUX
ssize_t bfd_recv_ipv4_fp(int sd, uint8_t *msgbuf, size_t msgbuflen,
uint8_t *ttl, ifindex_t *ifindex,
struct iphdr *iph;
struct bfd_echo_pkt *beph;
static char sendbuff[100];
+ struct timeval time_sent;
if (!bvrf)
return;
beph->len = BFD_ECHO_PKT_LEN;
beph->my_discr = htonl(bfd->discrs.my_discr);
+ /* RTT calculation: add starting time in packet */
+ monotime(&time_sent);
+ beph->time_sent_sec = htobe64(time_sent.tv_sec);
+ beph->time_sent_usec = htobe64(time_sent.tv_usec);
+
total_len += sizeof(struct bfd_echo_pkt);
uh->len =
htons(total_len - sizeof(struct iphdr) - sizeof(struct ethhdr));
{
struct bfd_session *bfd;
uint32_t my_discr = 0;
+ uint64_t my_rtt = 0;
uint8_t ttl = 0;
/* Receive and parse echo packet. */
- if (bp_bfd_echo_in(bvrf, s, &ttl, &my_discr) == -1)
+ if (bp_bfd_echo_in(bvrf, s, &ttl, &my_discr, &my_rtt) == -1)
return 0;
/* Your discriminator not zero - use it to find session */
return -1;
}
+ /* RTT Calculation: add current RTT to samples */
+ if (my_rtt != 0) {
+ bfd->rtt[bfd->rtt_index] = my_rtt;
+ bfd->rtt_index++;
+ if (bfd->rtt_index >= BFD_RTT_SAMPLE)
+ bfd->rtt_index = 0;
+ if (bfd->rtt_valid < BFD_RTT_SAMPLE)
+ bfd->rtt_valid++;
+ }
+
bfd->stats.rx_echo_pkt++;
/* Compute detect time */
*
* Returns -1 on error or loopback or 0 on success.
*/
-int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd,
- uint8_t *ttl, uint32_t *my_discr)
+int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd, uint8_t *ttl,
+ uint32_t *my_discr, uint64_t *my_rtt)
{
struct bfd_echo_pkt *bep;
ssize_t rlen;
return -1;
}
+#ifdef BFD_LINUX
+ /* RTT Calculation: determine RTT time of IPv4 echo pkt */
+ if (sd == bvrf->bg_echo) {
+ struct timeval time_sent = {0, 0};
+
+ time_sent.tv_sec = be64toh(bep->time_sent_sec);
+ time_sent.tv_usec = be64toh(bep->time_sent_usec);
+ *my_rtt = monotime_since(&time_sent, NULL);
+ }
+#endif
+
return 0;
}
struct bfd_session *bfd)
{
ssize_t wlen;
- struct msghdr msg;
+ struct msghdr msg = {0};
struct iovec iov[1];
uint8_t msgctl[255];
- struct sockaddr_ll sadr_ll;
-
+ struct sockaddr_ll sadr_ll = {0};
sadr_ll.sll_ifindex = bfd->ifp->ifindex;
sadr_ll.sll_halen = ETH_ALEN;
iov[0].iov_base = data;
iov[0].iov_len = datalen;
- memset(&msg, 0, sizeof(msg));
memset(msgctl, 0, sizeof(msgctl));
msg.msg_name = &sadr_ll;
msg.msg_namelen = sizeof(sadr_ll);
zlog_fatal("echo-socket: socket: %s", strerror(errno));
struct sock_fprog pf;
- struct sockaddr_ll sll;
+ struct sockaddr_ll sll = {0};
/* adjust filter for socket to only receive ECHO packets */
pf.filter = my_filterudp;
static void _display_peer_counter_iter(struct hash_bucket *hb, void *arg);
static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg);
static void _display_peers_counter(struct vty *vty, char *vrfname, bool use_json);
+static void _display_rtt(uint32_t *min, uint32_t *avg, uint32_t *max,
+ struct bfd_session *bs);
+
static struct bfd_session *
_find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
const char *label, const char *peer_str,
{
char buf[256];
time_t now;
+ uint32_t min = 0;
+ uint32_t avg = 0;
+ uint32_t max = 0;
_display_peer_header(vty, bs);
vty_out(vty, "\t\tRemote diagnostics: %s\n", diag2str(bs->remote_diag));
vty_out(vty, "\t\tPeer Type: %s\n",
CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG) ? "configured" : "dynamic");
+ _display_rtt(&min, &avg, &max, bs);
+ vty_out(vty, "\t\tRTT min/avg/max: %u/%u/%u usec\n", min, avg, max);
vty_out(vty, "\t\tLocal timers:\n");
vty_out(vty, "\t\t\tDetect-multiplier: %u\n",
static struct json_object *__display_peer_json(struct bfd_session *bs)
{
struct json_object *jo = _peer_json_header(bs);
+ uint32_t min = 0;
+ uint32_t avg = 0;
+ uint32_t max = 0;
json_object_int_add(jo, "id", bs->discrs.my_discr);
json_object_int_add(jo, "remote-id", bs->discrs.remote_discr);
json_object_int_add(jo, "remote-detect-multiplier",
bs->remote_detect_mult);
+ _display_rtt(&min, &avg, &max, bs);
+ json_object_int_add(jo, "rtt-min", min);
+ json_object_int_add(jo, "rtt-avg", avg);
+ json_object_int_add(jo, "rtt-max", max);
+
return jo;
}
return bs;
}
+void _display_rtt(uint32_t *min, uint32_t *avg, uint32_t *max,
+ struct bfd_session *bs)
+{
+#ifdef BFD_LINUX
+ uint8_t i;
+ uint32_t average = 0;
+
+ if (bs->rtt_valid == 0)
+ return;
+
+ *max = bs->rtt[0];
+ *min = 1000;
+ *avg = 0;
+
+ for (i = 0; i < bs->rtt_valid; i++) {
+ if (bs->rtt[i] < *min)
+ *min = bs->rtt[i];
+ if (bs->rtt[i] > *max)
+ *max = bs->rtt[i];
+ average += bs->rtt[i];
+ }
+ *avg = average / bs->rtt_valid;
+
+#endif
+}
/*
* Show commands.