+// SPDX-License-Identifier: GPL-2.0-or-later
/*********************************************************************
* Copyright 2017 Cumulus Networks, Inc. All rights reserved.
*
- * This program 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 of the License, or (at your option)
- * any later version.
- *
- * This program 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 this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
* bfd_packet.c: implements the BFD protocol packet handling.
*
* Authors
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 */
memcpy(&ttlval, CMSG_DATA(cm), sizeof(ttlval));
if (ttlval > 255) {
if (bglobal.debug_network)
- zlog_debug("ipv4-recv: invalid TTL: %u",
- ttlval);
+ zlog_debug("%s: invalid TTL: %u",
+ __func__, ttlval);
return -1;
}
*ttl = ttlval;
memcpy(&ttlval, CMSG_DATA(cm), sizeof(ttlval));
if (ttlval > 255) {
if (bglobal.debug_network)
- zlog_debug("ipv6-recv: invalid TTL: %u",
- ttlval);
+ zlog_debug("%s: invalid TTL: %u",
+ __func__, ttlval);
return -1;
}
}
}
+PRINTFRR(6, 7)
static void cp_debug(bool mhop, struct sockaddr_any *peer,
struct sockaddr_any *local, ifindex_t ifindex,
vrf_id_t vrfid, const char *fmt, ...)
/* Implement RFC 5880 6.8.6 */
if (mlen < BFD_PKT_LEN) {
cp_debug(is_mhop, &peer, &local, ifindex, vrfid,
- "too small (%ld bytes)", mlen);
+ "too small (%zd bytes)", mlen);
return;
}
*
* 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);
if (wlen <= 0) {
if (bglobal.debug_network)
- zlog_debug("udp-send: loopback failure: (%d) %s", errno,
- strerror(errno));
+ zlog_debug("%s: loopback failure: (%d) %s", __func__,
+ errno, strerror(errno));
return -1;
} else if (wlen < (ssize_t)datalen) {
if (bglobal.debug_network)
- zlog_debug("udp-send: partial send: %zd expected %zu",
- wlen, datalen);
+ zlog_debug("%s: partial send: %zd expected %zu",
+ __func__, wlen, datalen);
return -1;
}
wlen = sendmsg(sd, &msg, 0);
if (wlen <= 0) {
if (bglobal.debug_network)
- zlog_debug("udp-send: loopback failure: (%d) %s", errno,
- strerror(errno));
+ zlog_debug("%s: loopback failure: (%d) %s", __func__,
+ errno, strerror(errno));
return -1;
} else if (wlen < (ssize_t)datalen) {
if (bglobal.debug_network)
- zlog_debug("udp-send: partial send: %zd expected %zu",
- wlen, datalen);
+ zlog_debug("%s: partial send: %zd expected %zu",
+ __func__, wlen, datalen);
return -1;
}
int ttl = value;
if (setsockopt(sd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) == -1) {
- zlog_warn("set-ttl: setsockopt(IP_TTL, %d): %s", value,
+ zlog_warn("%s: setsockopt(IP_TTL, %d): %s", __func__, value,
strerror(errno));
return -1;
}
int tos = value;
if (setsockopt(sd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1) {
- zlog_warn("set-tos: setsockopt(IP_TOS, %d): %s", value,
+ zlog_warn("%s: setsockopt(IP_TOS, %d): %s", __func__, value,
strerror(errno));
return -1;
}
int one = 1;
if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
- zlog_warn("set-reuse-addr: setsockopt(SO_REUSEADDR, %d): %s",
- one, strerror(errno));
+ zlog_warn("%s: setsockopt(SO_REUSEADDR, %d): %s", __func__, one,
+ strerror(errno));
return false;
}
return true;
int one = 1;
if (setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) == -1) {
- zlog_warn("set-reuse-port: setsockopt(SO_REUSEPORT, %d): %s",
- one, strerror(errno));
+ zlog_warn("%s: setsockopt(SO_REUSEPORT, %d): %s", __func__, one,
+ strerror(errno));
return false;
}
return true;
sin.sin_len = sizeof(sin);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
memcpy(&sin.sin_addr, &bs->key.local, sizeof(sin.sin_addr));
- if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
- sin.sin_addr.s_addr = INADDR_ANY;
pcount = 0;
do {
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;
if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET))
return;
+ if (ifp->flags & IFF_NOARP)
+ return;
if (peer->sa_sin.sin_family == AF_INET) {
/* IPV4 */
strlcpy(arpreq_.arp_dev, ifp->name, sizeof(arpreq_.arp_dev));
if (ioctl(sd, SIOCGARP, &arpreq_) < 0) {
- zlog_warn("BFD: getting peer's mac failed error %s",
- strerror(errno));
+ zlog_warn(
+ "BFD: getting peer's mac on %s failed error %s",
+ ifp->name, strerror(errno));
UNSET_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET);
memset(bfd->peer_hw_addr, 0, sizeof(bfd->peer_hw_addr));