Commit 95e08d42 authored by Dan Melnic's avatar Dan Melnic Committed by Facebook GitHub Bot

AsyncUDPSocket: multi release pacing for UDP GSO

Summary:
AsyncUDPSocket: multi release pacing for UDP GSO

(Note: this ignores all push blocking failures!)

Reviewed By: mjoras

Differential Revision: D25451694

fbshipit-source-id: 3550a3744b407cbc40efebe759f472ee9f40a5b8
parent 9a83e424
...@@ -474,20 +474,40 @@ ssize_t AsyncUDPSocket::writeChain( ...@@ -474,20 +474,40 @@ ssize_t AsyncUDPSocket::writeChain(
msg.msg_flags = 0; msg.msg_flags = 0;
#ifdef FOLLY_HAVE_MSG_ERRQUEUE #ifdef FOLLY_HAVE_MSG_ERRQUEUE
char control[CMSG_SPACE(sizeof(uint16_t))]; char control
[CMSG_SPACE(sizeof(uint16_t)) + /*gro*/
CMSG_SPACE(sizeof(uint64_t)) /*txtime*/
] = {};
struct cmsghdr* cm = CMSG_FIRSTHDR(&msg);
if (options.gso > 0) { if (options.gso > 0) {
msg.msg_control = control; msg.msg_control = control;
msg.msg_controllen = sizeof(control); msg.msg_controllen = CMSG_SPACE(sizeof(uint16_t));
struct cmsghdr* cm = CMSG_FIRSTHDR(&msg);
cm->cmsg_level = SOL_UDP; cm->cmsg_level = SOL_UDP;
cm->cmsg_type = UDP_SEGMENT; cm->cmsg_type = UDP_SEGMENT;
cm->cmsg_len = CMSG_LEN(sizeof(uint16_t)); cm->cmsg_len = CMSG_LEN(sizeof(uint16_t));
auto gso_len = static_cast<uint16_t>(options.gso); auto gso_len = static_cast<uint16_t>(options.gso);
memcpy(CMSG_DATA(cm), &gso_len, sizeof(gso_len)); memcpy(CMSG_DATA(cm), &gso_len, sizeof(gso_len));
cm = CMSG_NXTHDR(&msg, cm);
}
if (options.txTime.count() > 0 && txTime_.has_value() &&
(txTime_.value().clockid >= 0)) {
msg.msg_control = control;
msg.msg_controllen += CMSG_SPACE(sizeof(uint64_t));
cm->cmsg_level = SOL_SOCKET;
cm->cmsg_type = SCM_TXTIME;
cm->cmsg_len = CMSG_LEN(sizeof(uint64_t));
struct timespec ts;
clock_gettime(txTime_.value().clockid, &ts);
uint64_t txtime = ts.tv_sec * 1000000000ULL + ts.tv_nsec +
std::chrono::nanoseconds(options.txTime).count();
memcpy(CMSG_DATA(cm), &txtime, sizeof(txtime));
} }
#else #else
CHECK_LT(options.gso, 1) << "GSO not supported"; CHECK_LT(options.gso, 1) << "GSO not supported";
CHECK_LT(options.txTime.count(), 1) << "TX_TIME not supported";
#endif #endif
auto ret = sendmsg(fd_, &msg, msg_flags); auto ret = sendmsg(fd_, &msg, msg_flags);
...@@ -1147,6 +1167,41 @@ int AsyncUDPSocket::getGRO() { ...@@ -1147,6 +1167,41 @@ int AsyncUDPSocket::getGRO() {
return gro_.value(); return gro_.value();
} }
AsyncUDPSocket::TXTime AsyncUDPSocket::getTXTime() {
// check if we can return the cached value
if (FOLLY_UNLIKELY(!txTime_.has_value())) {
TXTime txTime;
#ifdef FOLLY_HAVE_MSG_ERRQUEUE
struct sock_txtime val = {};
socklen_t optlen = sizeof(val);
if (!netops::getsockopt(fd_, SOL_SOCKET, SO_TXTIME, &val, &optlen)) {
txTime.clockid = val.clockid;
txTime.deadline = (val.flags & SOF_TXTIME_DEADLINE_MODE);
}
#endif
txTime_ = txTime;
}
return txTime_.value();
}
bool AsyncUDPSocket::setTXTime(TXTime txTime) {
#ifdef FOLLY_HAVE_MSG_ERRQUEUE
struct sock_txtime val;
val.clockid = txTime.clockid;
val.flags = txTime.deadline ? SOF_TXTIME_DEADLINE_MODE : 0;
int ret =
netops::setsockopt(fd_, SOL_SOCKET, SO_TIMESTAMPING, &val, sizeof(val));
txTime_ = ret ? TXTime() : txTime;
return !ret;
#else
(void)txTime;
return false;
#endif
}
bool AsyncUDPSocket::setRxZeroChksum6(FOLLY_MAYBE_UNUSED bool bVal) { bool AsyncUDPSocket::setRxZeroChksum6(FOLLY_MAYBE_UNUSED bool bVal) {
#ifdef FOLLY_HAVE_MSG_ERRQUEUE #ifdef FOLLY_HAVE_MSG_ERRQUEUE
if (address().getFamily() != AF_INET6) { if (address().getFamily() != AF_INET6) {
......
...@@ -143,6 +143,12 @@ class AsyncUDPSocket : public EventHandler { ...@@ -143,6 +143,12 @@ class AsyncUDPSocket : public EventHandler {
: gso(gsoVal), zerocopy(zerocopyVal) {} : gso(gsoVal), zerocopy(zerocopyVal) {}
int gso{0}; int gso{0};
bool zerocopy{false}; bool zerocopy{false};
std::chrono::microseconds txTime{0};
};
struct TXTime {
int clockid{-1};
bool deadline{false};
}; };
/** /**
...@@ -418,6 +424,11 @@ class AsyncUDPSocket : public EventHandler { ...@@ -418,6 +424,11 @@ class AsyncUDPSocket : public EventHandler {
bool setGRO(bool bVal); bool setGRO(bool bVal);
// TX time
TXTime getTXTime();
bool setTXTime(TXTime txTime);
// packet timestamping // packet timestamping
int getTimestamping(); int getTimestamping();
bool setTimestamping(int val); bool setTimestamping(int val);
...@@ -521,6 +532,10 @@ class AsyncUDPSocket : public EventHandler { ...@@ -521,6 +532,10 @@ class AsyncUDPSocket : public EventHandler {
// See https://lwn.net/Articles/770978/ for more details // See https://lwn.net/Articles/770978/ for more details
folly::Optional<int> gro_; folly::Optional<int> gro_;
// multi release pacing for UDP GSO
// See https://lwn.net/Articles/822726/ for more details
folly::Optional<TXTime> txTime_;
// packet timestamping // packet timestamping
folly::Optional<int> ts_; folly::Optional<int> ts_;
......
...@@ -54,6 +54,26 @@ ...@@ -54,6 +54,26 @@
#define SO_ZEROCOPY 60 #define SO_ZEROCOPY 60
#endif #endif
#ifndef SO_TXTIME
#define SO_TXTIME 61
#define SCM_TXTIME SO_TXTIME
#endif
#ifdef FOLLY_HAVE_MSG_ERRQUEUE
enum txtime_flags {
SOF_TXTIME_DEADLINE_MODE = (1 << 0),
SOF_TXTIME_REPORT_ERRORS = (1 << 1),
SOF_TXTIME_FLAGS_LAST = SOF_TXTIME_REPORT_ERRORS,
SOF_TXTIME_FLAGS_MASK = (SOF_TXTIME_FLAGS_LAST - 1) | SOF_TXTIME_FLAGS_LAST
};
struct sock_txtime {
__kernel_clockid_t clockid; /* reference clockid */
__u32 flags; /* as defined by enum txtime_flags */
};
#endif
#ifndef MSG_ZEROCOPY #ifndef MSG_ZEROCOPY
#define MSG_ZEROCOPY 0x4000000 #define MSG_ZEROCOPY 0x4000000
#endif #endif
...@@ -106,6 +126,7 @@ using sa_family_t = ADDRESS_FAMILY; ...@@ -106,6 +126,7 @@ using sa_family_t = ADDRESS_FAMILY;
// these are not supported // these are not supported
#define SO_EE_ORIGIN_ZEROCOPY 0 #define SO_EE_ORIGIN_ZEROCOPY 0
#define SO_ZEROCOPY 0 #define SO_ZEROCOPY 0
#define SO_TXTIME 0
#define MSG_ZEROCOPY 0x0 #define MSG_ZEROCOPY 0x0
#define SOL_UDP 0x0 #define SOL_UDP 0x0
#define UDP_SEGMENT 0x0 #define UDP_SEGMENT 0x0
......
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