detect UDP RX buffer overflows

On Linux, use SO_RXQ_OVFL to snoop on the OS dropped packet
counter for our socket buffer.  Does not detect drops on
ingress, or internal to, to OS IP stack.
This commit is contained in:
Michael Davidsaver
2021-01-26 21:43:35 -08:00
parent 84ef355a4a
commit a064677e36
5 changed files with 73 additions and 2 deletions
+51
View File
@@ -15,6 +15,7 @@
#include <ctype.h>
#include <pvxs/log.h>
#include <pvxs/util.h>
#include <pvxs/sharedArray.h>
#include <pvxs/data.h>
@@ -25,6 +26,8 @@
namespace pvxs {
DEFINE_LOGGER(log, "pvxs.util");
#define stringifyX(X) #X
#define stringify(X) stringifyX(X)
@@ -286,6 +289,54 @@ SigInt::~SigInt()
#endif // !defined(__rtems__) && !defined(vxWorks)
void enable_SO_RXQ_OVFL(SOCKET sock)
{
#ifdef SO_RXQ_OVFL
// Linux specific feature exposes OS dropped packet count
{
int val = 1;
if(setsockopt(sock, SOL_SOCKET, SO_RXQ_OVFL, (char*)&val, sizeof(val)))
log_warn_printf(log, "Unable to set SO_RXQ_OVFL: %d\n", SOCKERRNO);
}
#endif
}
int recvfromx(SOCKET sock, void *buf, size_t buflen, sockaddr* peer, osiSocklen_t* peerlen, uint32_t *ndrop)
{
#ifdef SO_RXQ_OVFL
alignas (alignof (msghdr)) char cbuf[CMSG_SPACE(4u)];
iovec iov = {buf, buflen};
msghdr msg = {};
msg.msg_iov = &iov;
msg.msg_iovlen = 1u;
msg.msg_name = peer;
msg.msg_namelen = peerlen ? *peerlen : 0;
msg.msg_control = cbuf;
msg.msg_controllen = sizeof(cbuf);
int ret = recvmsg(sock, &msg, 0);
if(ret>=0 && peerlen)
*peerlen = msg.msg_namelen;
if(msg.msg_flags & MSG_CTRUNC)
log_debug_printf(log, "MSG_CTRUNC %zu, %zu\n", msg.msg_controllen, sizeof(cbuf));
if(ndrop) {
for(cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr ; hdr = CMSG_NXTHDR(&msg, hdr)) {
if(hdr->cmsg_level==SOL_SOCKET && hdr->cmsg_type==SO_RXQ_OVFL && hdr->cmsg_len>=CMSG_LEN(4u)) {
memcpy(ndrop, CMSG_DATA(hdr), 4u);
}
}
}
return ret;
#else
return recvfrom(sock, (char*)buf, buflen, 0, peer, peerlen);
#endif
}
SockAddr::SockAddr(int af)
{
memset(&store, 0, sizeof(store));