Commit 1902d0ff authored by Dan Melnic's avatar Dan Melnic Committed by Facebook GitHub Bot

Add support for UDP RX timestamps

Summary: Add support for UDP RX timestamps

Reviewed By: mjoras

Differential Revision: D24146914

fbshipit-source-id: 381839fc5402f13e428364c47c5752473acda6af
parent 343a70ae
......@@ -737,8 +737,21 @@ void AsyncUDPSocket::handleRead() noexcept {
ReadCallback::OnDataAvailableParams params;
#ifdef FOLLY_HAVE_MSG_ERRQUEUE
if (gro_.has_value() && (gro_.value() > 0)) {
char control[CMSG_SPACE(sizeof(uint16_t))] = {};
bool use_gro = gro_.has_value() && (gro_.value() > 0);
bool use_ts = ts_.has_value() && (ts_.value() > 0);
if (use_gro || use_ts) {
char control
[CMSG_SPACE(sizeof(uint16_t)) +
CMSG_SPACE(sizeof(ReadCallback::OnDataAvailableParams::Timestamp))];
::memset(
control,
0,
(use_gro ? CMSG_SPACE(sizeof(uint16_t)) : 0) +
(use_ts ? CMSG_SPACE(sizeof(
ReadCallback::OnDataAvailableParams::Timestamp))
: 0));
struct msghdr msg = {};
struct iovec iov = {};
struct cmsghdr* cmsg;
......@@ -762,10 +775,23 @@ void AsyncUDPSocket::handleRead() noexcept {
addrLen = msg.msg_namelen;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level == SOL_UDP && cmsg->cmsg_type == UDP_GRO) {
grosizeptr = (uint16_t*)CMSG_DATA(cmsg);
params.gro_ = *grosizeptr;
break;
if (cmsg->cmsg_level == SOL_UDP) {
if (cmsg->cmsg_type == UDP_GRO) {
grosizeptr = (uint16_t*)CMSG_DATA(cmsg);
params.gro_ = *grosizeptr;
}
} else {
if (cmsg->cmsg_level == SOL_SOCKET) {
if (cmsg->cmsg_type == SO_TIMESTAMPING ||
cmsg->cmsg_type == SO_TIMESTAMPNS) {
ReadCallback::OnDataAvailableParams::Timestamp ts;
memcpy(
&ts,
reinterpret_cast<struct timespec*>(CMSG_DATA(cmsg)),
sizeof(ts));
params.ts_ = ts;
}
}
}
}
}
......@@ -867,6 +893,40 @@ bool AsyncUDPSocket::setGRO(bool bVal) {
#endif
}
// packet timestamping
int AsyncUDPSocket::getTimestamping() {
// check if we can return the cached value
if (FOLLY_UNLIKELY(!ts_.has_value())) {
#ifdef FOLLY_HAVE_MSG_ERRQUEUE
int ts = -1;
socklen_t optlen = sizeof(ts);
if (!netops::getsockopt(fd_, SOL_SOCKET, SO_TIMESTAMPING, &ts, &optlen)) {
ts_ = ts;
} else {
ts_ = -1;
}
#else
ts_ = -1;
#endif
}
return ts_.value();
}
bool AsyncUDPSocket::setTimestamping(int val) {
#ifdef FOLLY_HAVE_MSG_ERRQUEUE
int ret =
netops::setsockopt(fd_, SOL_SOCKET, SO_TIMESTAMPING, &val, sizeof(val));
ts_ = ret ? -1 : val;
return !ret;
#else
(void)val;
return false;
#endif
}
int AsyncUDPSocket::getGRO() {
// check if we can return the cached value
if (FOLLY_UNLIKELY(!gro_.has_value())) {
......
......@@ -42,6 +42,18 @@ class AsyncUDPSocket : public EventHandler {
public:
struct OnDataAvailableParams {
int gro_ = -1;
#ifdef FOLLY_HAVE_MSG_ERRQUEUE
// RX timestamp if available
using Timestamp = std::array<struct timespec, 3>;
folly::Optional<Timestamp> ts_;
static std::chrono::nanoseconds to(const struct timespec& ts) {
auto duration = std::chrono::seconds(ts.tv_sec) +
std::chrono::nanoseconds(ts.tv_nsec);
return std::chrono::duration_cast<std::chrono::nanoseconds>(duration);
}
#endif
};
/**
* Invoked when the socket becomes readable and we want buffer
......@@ -383,6 +395,10 @@ class AsyncUDPSocket : public EventHandler {
bool setGRO(bool bVal);
// packet timestamping
int getTimestamping();
bool setTimestamping(int val);
// disable/enable RX zero checksum check for UDP over IPv6
bool setRxZeroChksum6(bool bVal);
......@@ -482,6 +498,9 @@ class AsyncUDPSocket : public EventHandler {
// See https://lwn.net/Articles/770978/ for more details
folly::Optional<int> gro_;
// packet timestamping
folly::Optional<int> ts_;
ErrMessageCallback* errMessageCallback_{nullptr};
};
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment