]> git.puffer.fish Git - matthieu/frr.git/commitdiff
BFDD: Add RTT to BFD IPV4 Echo packet processing
authorlynnemorrison <lynne.morrison@ibm.com>
Mon, 25 Jul 2022 23:02:46 +0000 (19:02 -0400)
committerlynnemorrison <lynne.morrison@ibm.com>
Tue, 2 Aug 2022 14:09:01 +0000 (10:09 -0400)
Add a send time into the BFD Echo packet. When the BFD Echo
packet is received back store time it took in usec. When
user issues a show bfd peer(s) command calculate and display
minimum, average, and max time it took for the BFD Echo packet
to be looped back.

Signed-off-by: Lynne Morrison <lynne.morrison@ibm.com>
bfdd/bfd.c
bfdd/bfd.h
bfdd/bfd_packet.c
bfdd/bfdd_vty.c

index 483beb1b17ceeca46dbd06f065e6f807f98c78c2..7311c4228931265c577720ac00a0a4ace7f4bbe3 100644 (file)
@@ -381,6 +381,9 @@ int bfd_session_enable(struct bfd_session *bs)
                ptm_bfd_start_xmt_timer(bs, false);
        }
 
+       /* initialize RTT */
+       bfd_rtt_init(bs);
+
        return 0;
 }
 
@@ -574,6 +577,9 @@ void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag)
        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,
@@ -2065,3 +2071,14 @@ unsigned long bfd_get_session_count(void)
 {
        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;
+}
index 48a1e0bc3169c90c64c99c6b47e1b9e82f8903d0..a5881cddb0ec5d7f641b71e2e4ccd4a111435c7e 100644 (file)
@@ -86,7 +86,8 @@ struct bfd_echo_pkt {
                };
        };
        uint32_t my_discr;
-       uint8_t pad[16];
+       uint64_t time_sent_sec;
+       uint64_t time_sent_usec;
 };
 
 
@@ -249,6 +250,8 @@ struct bfd_config_timers {
        uint32_t required_min_echo_rx;
 };
 
+#define BFD_RTT_SAMPLE 8
+
 /*
  * Session state information
  */
@@ -311,6 +314,10 @@ struct bfd_session {
        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 {
@@ -635,6 +642,7 @@ const struct bfd_session *bfd_session_next(const struct bfd_session *bs,
                                           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.
index 26c7174f635d35019df33c3d3c5667a5df43e6eb..a61419ecc522986515b48d9fa3c9f577c3a65490 100644 (file)
@@ -55,8 +55,8 @@ ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
                      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,
@@ -207,6 +207,7 @@ void ptm_bfd_echo_fp_snd(struct bfd_session *bfd)
        struct iphdr *iph;
        struct bfd_echo_pkt *beph;
        static char sendbuff[100];
+       struct timeval time_sent;
 
        if (!bvrf)
                return;
@@ -259,6 +260,11 @@ void ptm_bfd_echo_fp_snd(struct bfd_session *bfd)
        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));
@@ -338,10 +344,11 @@ static int ptm_bfd_process_echo_pkt(struct bfd_vrf_global *bvrf, int s)
 {
        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 */
@@ -360,6 +367,16 @@ static int ptm_bfd_process_echo_pkt(struct bfd_vrf_global *bvrf, int s)
                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 */
@@ -995,8 +1012,8 @@ void bfd_recv_cb(struct thread *t)
  *
  * 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;
@@ -1054,6 +1071,17 @@ int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd,
                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;
 }
 
@@ -1066,11 +1094,10 @@ int bp_udp_send_fp(int sd, uint8_t *data, size_t datalen,
                   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;
@@ -1081,7 +1108,6 @@ int bp_udp_send_fp(int sd, uint8_t *data, size_t datalen,
        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);
@@ -1560,7 +1586,7 @@ int bp_echo_socket(const struct vrf *vrf)
                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;
index a9fc716177d6b78d51e12cbd5baf56822ee3522b..21429f06cfbf269c4630bd38d4c527a80089d794 100644 (file)
@@ -66,6 +66,9 @@ static void _display_peer_counters_json(struct vty *vty, struct bfd_session *bs)
 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,
@@ -106,6 +109,9 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs)
 {
        char buf[256];
        time_t now;
+       uint32_t min = 0;
+       uint32_t avg = 0;
+       uint32_t max = 0;
 
        _display_peer_header(vty, bs);
 
@@ -150,6 +156,8 @@ static void _display_peer(struct vty *vty, struct bfd_session *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",
@@ -217,6 +225,9 @@ static struct json_object *_peer_json_header(struct bfd_session *bs)
 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);
@@ -275,6 +286,11 @@ static struct json_object *__display_peer_json(struct bfd_session *bs)
        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;
 }
 
@@ -608,6 +624,31 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
        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.