summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:25:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:25:49 +0000
commit04fc174d50fd19d6ae78fd2fd2faae221acff807 (patch)
tree23e5482ac4eb332df0fc69bf932118f0d4e42eb0 /src
parentAdding upstream version 2.1.9+dfsg. (diff)
downloadiperf-04fc174d50fd19d6ae78fd2fd2faae221acff807.tar.xz
iperf-04fc174d50fd19d6ae78fd2fd2faae221acff807.zip
Adding upstream version 2.2.0+dfsg.upstream/2.2.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src')
-rw-r--r--src/Client.cpp798
-rw-r--r--src/Launch.cpp101
-rw-r--r--src/Listener.cpp522
-rw-r--r--src/Locale.c328
-rw-r--r--src/Makefile.am3
-rw-r--r--src/Makefile.in23
-rw-r--r--src/PerfSocket.cpp234
-rw-r--r--src/ReportOutputs.c1057
-rw-r--r--src/Reporter.c466
-rw-r--r--src/Reports.c139
-rw-r--r--src/Server.cpp321
-rw-r--r--src/Settings.cpp429
-rw-r--r--src/SocketAddr.c31
-rw-r--r--src/active_hosts.cpp198
-rw-r--r--src/dscp.c10
-rw-r--r--src/histogram.c21
-rw-r--r--src/iperf_formattime.c82
-rw-r--r--src/iperf_multicast_api.c386
-rw-r--r--src/isochronous.cpp86
-rw-r--r--src/packet_ring.c21
-rw-r--r--src/pdfs.c7
-rw-r--r--src/socket_io.c16
-rw-r--r--src/stdio.c11
23 files changed, 3665 insertions, 1625 deletions
diff --git a/src/Client.cpp b/src/Client.cpp
index 89e47e2..d56ee1c 100644
--- a/src/Client.cpp
+++ b/src/Client.cpp
@@ -67,6 +67,7 @@
#include "payloads.h"
#include "active_hosts.h"
#include "gettcpinfo.h"
+#include "iperf_formattime.h"
// const double kSecs_to_usecs = 1e6;
const double kSecs_to_nsecs = 1e9;
@@ -74,6 +75,7 @@ const int kBytes_to_Bits = 8;
#define VARYLOAD_PERIOD 0.1 // recompute the variable load every n seconds
#define MAXUDPBUF 1470
+#define TCPDELAYDEFAULTQUANTUM 4000 // units usecs
Client::Client (thread_Settings *inSettings) {
#ifdef HAVE_THREAD_DEBUG
@@ -136,13 +138,7 @@ Client::~Client () {
void Client::mySockInit (void) {
// create an internet socket
int type = (isUDP(mSettings) ? SOCK_DGRAM : SOCK_STREAM);
- int domain = (SockAddr_isIPv6(&mSettings->peer) ?
-#if HAVE_IPV6
- AF_INET6
-#else
- AF_INET
-#endif
- : AF_INET);
+ int domain = SockAddr_getAFdomain(&mSettings->peer);
mySocket = socket(domain, type, 0);
WARN_errno(mySocket == INVALID_SOCKET, "socket");
@@ -151,20 +147,23 @@ void Client::mySockInit (void) {
SetSocketOptions(mSettings);
SockAddr_localAddr(mSettings);
SockAddr_remoteAddr(mSettings);
- if (mSettings->mLocalhost != NULL) {
- // bind socket to local address
- int rc = bind(mySocket, reinterpret_cast<sockaddr*>(&mSettings->local),
- SockAddr_get_sizeof_sockaddr(&mSettings->local));
- WARN_errno(rc == SOCKET_ERROR, "bind");
+ // do this bind to device after IP addr name lookups per above
+ SetSocketBindToDeviceIfNeeded(mSettings);
+ if (mSettings->mLocalhost != NULL) { // bind src ip if needed
+ // bind socket to local address
+ int rc = bind(mSettings->mSock, (struct sockaddr *)(&mSettings->local), \
+ SockAddr_get_sizeof_sockaddr(&mSettings->local));
+ WARN_errno(rc == SOCKET_ERROR, "bind");
}
- mysock_init_done = true;
- if (!isUDP(mSettings) && isReport(mSettings) && isSettingsReport(mSettings)) {
+ if (isSettingsReport(mSettings)) {
struct ReportHeader *tmp = InitSettingsReport(mSettings);
assert(tmp!=NULL);
PostReport(tmp);
- setNoSettReport(mSettings);
}
+ mysock_init_done = true;
}
+
+
/* -------------------------------------------------------------------
* Setup a socket connected to a server.
* If inLocalhost is not null, bind to that address, specifying
@@ -177,29 +176,69 @@ bool Client::my_connect (bool close_on_fail) {
}
// connect socket
connected = false;
+ int connect_errno = 0;
mSettings->tcpinitstats.connecttime = -1;
if (!isUDP(mSettings)) {
- int trycnt = mSettings->mConnectRetries + 1;
- while (trycnt > 0) {
+ Timestamp end_connect_retry;
+ end_connect_retry.add(mSettings->connect_retry_time);
+ do {
connect_start.setnow();
rc = connect(mySocket, reinterpret_cast<sockaddr*>(&mSettings->peer),
SockAddr_get_sizeof_sockaddr(&mSettings->peer));
- WARN_errno((rc == SOCKET_ERROR), "tcp connect");
+ connect_done.setnow();
if (rc == SOCKET_ERROR) {
- if ((--trycnt) <= 0) {
- if (close_on_fail) {
- close(mySocket);
- mySocket = INVALID_SOCKET;
- }
- } else {
- delay_loop(200000);
+ char timestr[120];
+ char tmpaddr[200];
+ char errtext[50];
+ connect_errno = errno_decode(errtext, sizeof(errtext));
+ unsigned short port = SockAddr_getPort(&mSettings->peer);
+ SockAddr_getHostAddress(&mSettings->peer, tmpaddr, sizeof(tmpaddr));
+ struct timeval t;
+ t.tv_sec = connect_done.getSecs();
+ t.tv_usec = connect_done.getUsecs();
+ iperf_formattime(timestr, sizeof(timestr), t, isEnhanced(mSettings), isUTC(mSettings), YearThruSecTZ);
+ int slen = snprintf(NULL, 0, "%stcp connect to %s port %d failed (%s) on %s", \
+ mSettings->mTransferIDStr, tmpaddr, port, errtext, timestr);
+ char *text = (char *) calloc((slen+1), sizeof(char));
+ if (text) {
+ snprintf(text, (slen+1), "%stcp connect to %s port %d failed (%s) on %s", \
+ mSettings->mTransferIDStr, tmpaddr, port, errtext, timestr);
+ PostReport(InitStringReport(text));
+ FREE_ARRAY(text);
+ }
+ bool need_open = false;
+ if (close_on_fail || FATALTCPCONNECTERR(errno)) { // MAC OS kicks out invalid argument at times, not sure why
+ close(mySocket);
+ mySockInit();
+ delay_loop(10000); // delay the minimum of 10ms
+ need_open = true;
+ }
+ if (!need_open && connect_done.before(end_connect_retry)) {
+ int delay = mSettings->connect_retry_timer - (connect_done.subUsec(connect_start));
+ delay_loop((delay < 10000) ? 10000 : delay); // minimum of 10ms
}
} else {
- connect_done.setnow();
mSettings->tcpinitstats.connecttime = 1e3 * connect_done.subSec(connect_start);
connected = true;
break;
}
+ } while (connect_done.before(end_connect_retry));
+ if (!connected && (mSettings->connect_retry_time > 0)) {
+ char timestr[120];
+ struct timeval t;
+ t.tv_sec = end_connect_retry.getSecs();
+ t.tv_usec = end_connect_retry.getUsecs();
+ iperf_formattime(timestr, sizeof(timestr), t, isEnhanced(mSettings), isUTC(mSettings), YearThruSecTZ);
+ int len = snprintf(NULL, 0, "%stcp connect attempt timer expired on %s\n", \
+ mSettings->mTransferIDStr, timestr);
+ char *text = (char *) calloc(len+1, sizeof(char));
+ if (text) {
+ snprintf(text, len, "%stcp connect attempt timer expried on %s\n", \
+ mSettings->mTransferIDStr, timestr);
+ PostReport(InitStringReport(text));
+ FREE_ARRAY(text);
+ return false;
+ }
}
} else {
rc = connect(mySocket, reinterpret_cast<sockaddr*>(&mSettings->peer),
@@ -217,8 +256,6 @@ bool Client::my_connect (bool close_on_fail) {
}
#endif
// Set the send timeout for the very first write which has the test exchange
- int sosndtimer = TESTEXCHANGETIMEOUT; // 4 sec in usecs
- SetSocketOptionsSendTimeout(mSettings, sosndtimer);
getsockname(mySocket, reinterpret_cast<sockaddr*>(&mSettings->local), &mSettings->size_local);
getpeername(mySocket, reinterpret_cast<sockaddr*>(&mSettings->peer), &mSettings->size_peer);
SockAddr_Ifrname(mSettings);
@@ -230,12 +267,6 @@ bool Client::my_connect (bool close_on_fail) {
if (isUDP(mSettings) && !isIsochronous(mSettings) && !isIPG(mSettings)) {
mSettings->mBurstIPG = get_delay_target() / 1e3; // this is being set for the settings report only
}
- if (isReport(mSettings) && isSettingsReport(mSettings)) {
- struct ReportHeader *tmp = InitSettingsReport(mSettings);
- assert(tmp!=NULL);
- PostReport(tmp);
- setNoSettReport(mSettings);
- }
} else {
if (mySocket != INVALID_SOCKET) {
int rc = close(mySocket);
@@ -252,7 +283,7 @@ bool Client::my_connect (bool close_on_fail) {
cr->connect_timestamp.tv_usec = connect_start.getUsecs();
assert(reporthdr);
PostReport(reporthdr);
- } else {
+ } else if (!connect_errno) {
PostReport(InitConnectionReport(mSettings));
}
}
@@ -277,6 +308,10 @@ inline void Client::myReportPacket (void) {
reportstruct->packetLen = 0;
}
+inline void Client::myReportPacket (struct ReportStruct *reportptr) {
+ ReportPacket(myReport, reportptr);
+}
+
// There are multiple startup synchronizations, this code
// handles them all. The caller decides to apply them
@@ -303,8 +338,8 @@ int Client::StartSynch () {
// o Second is a holdback, a relative amount of seconds between the connect and data xfers
// check for an epoch based start time
reportstruct->packetLen = 0;
- if (!isServerReverse(mSettings)) {
- if (!isCompat(mSettings) && !isBounceBack(mSettings)) {
+ if (!isServerReverse(mSettings) && !isCompat(mSettings)) {
+ if (!isBounceBack(mSettings)) {
reportstruct->packetLen = SendFirstPayload();
// Reverse UDP tests need to retry "first sends" a few times
// before going to server or read mode
@@ -336,14 +371,18 @@ int Client::StartSynch () {
} else if (isTripTime(mSettings) || isPeriodicBurst(mSettings)) {
reportstruct->packetLen = SendFirstPayload();
}
- if (isIsochronous(mSettings) || isPeriodicBurst(mSettings)) {
+ if (isIsochronous(mSettings) || isPeriodicBurst(mSettings) || isBounceBack(mSettings)) {
Timestamp tmp;
- tmp.set(mSettings->txstart_epoch.tv_sec, mSettings->txstart_epoch.tv_usec);
- framecounter = new Isochronous::FrameCounter(mSettings->mFPS, tmp);
- // set the mbuf valid for burst period ahead of time. The same value will be set for all burst writes
- if (!isUDP(mSettings) && framecounter) {
- struct TCP_burst_payload * mBuf_burst = reinterpret_cast<struct TCP_burst_payload *>(mSettings->mBuf);
- mBuf_burst->burst_period_us = htonl(framecounter->period_us());
+ if (isTxStartTime(mSettings)) {
+ tmp.set(mSettings->txstart_epoch.tv_sec, mSettings->txstart_epoch.tv_usec);
+ }
+ if (mSettings->mFPS > 0) {
+ framecounter = new Isochronous::FrameCounter(mSettings->mFPS, tmp);
+ // set the mbuf valid for burst period ahead of time. The same value will be set for all burst writes
+ if (!isUDP(mSettings) && framecounter) {
+ struct TCP_burst_payload * mBuf_burst = reinterpret_cast<struct TCP_burst_payload *>(mSettings->mBuf);
+ mBuf_burst->burst_period_us = htonl(framecounter->period_us());
+ }
}
}
int setfullduplexflag = 0;
@@ -355,12 +394,12 @@ int Client::StartSynch () {
SetReportStartTime();
#if HAVE_TCP_STATS
if (!isUDP(mSettings)) {
- // Near congestion and peridiodic need sampling on every report packet
+ // Near congestion and periodic need sampling on every report packet
if (isNearCongest(mSettings) || isPeriodicBurst(mSettings)) {
myReport->info.isEnableTcpInfo = true;
myReport->info.ts.nextTCPSampleTime.tv_sec = 0;
myReport->info.ts.nextTCPSampleTime.tv_usec = 0;
- } else if (isEnhanced(mSettings) || isBounceBack(mSettings)) {
+ } else if (isEnhanced(mSettings) || isBounceBack(mSettings) || isFQPacing(mSettings)) {
myReport->info.isEnableTcpInfo = true;
myReport->info.ts.nextTCPSampleTime = myReport->info.ts.nextTime;
}
@@ -368,6 +407,7 @@ int Client::StartSynch () {
#endif
if (reportstruct->packetLen > 0) {
+ reportstruct->err_readwrite = WriteSuccess;
reportstruct->packetTime = myReport->info.ts.startTime;
reportstruct->sentTime = reportstruct->packetTime;
reportstruct->prevSentTime = reportstruct->packetTime;
@@ -406,6 +446,9 @@ inline void Client::SetFullDuplexReportStartTime () {
inline void Client::SetReportStartTime () {
assert(myReport!=NULL);
now.setnow();
+ if (isUDP(mSettings) && (mSettings->sendfirst_pacing > 0)) {
+ now.add(static_cast<unsigned int>(mSettings->sendfirst_pacing));
+ }
myReport->info.ts.startTime.tv_sec = now.getSecs();
myReport->info.ts.startTime.tv_usec = now.getUsecs();
myReport->info.ts.IPGstart = myReport->info.ts.startTime;
@@ -491,11 +534,27 @@ void Client::InitTrafficLoop () {
if (isPeriodicBurst(mSettings) && (mSettings->mFPS > 0.0)) {
sosndtimer = static_cast<int>(round(250000.0 / mSettings->mFPS));
} else if (mSettings->mInterval > 0) {
- sosndtimer = static_cast<int>(round(0.5 * mSettings->mInterval));
+ sosndtimer = static_cast<int>(round(((mSettings->mThreads > 1) ? 0.25 : 0.5) * mSettings->mInterval));
} else {
sosndtimer = static_cast<int>(mSettings->mAmount * 5e3);
}
- SetSocketOptionsSendTimeout(mSettings, sosndtimer);
+ // set to 1 second for wraps or too large
+ if ((sosndtimer < 0) || (sosndtimer > 1000000)) {
+ sosndtimer = 1000000;
+ }
+ if (sosndtimer < 1000) {
+ sosndtimer = 1000; //lower bound of 1 ms
+ }
+ if ((mSettings->mInterval > 0) && (mSettings->mIntervalMode == kInterval_Time)) {
+ int interval_half = static_cast<int>(round(mSettings->mAmount * 10000) / 2);
+ if (sosndtimer > interval_half) {
+ sosndtimer = interval_half;
+ }
+ }
+ if (!isUDP(mSettings)) {
+ mSettings->sosndtimer = sosndtimer;
+ SetSocketOptionsSendTimeout(mSettings, sosndtimer);
+ }
// set the lower bounds delay based of the socket timeout timer
// units needs to be in nanoseconds
delay_lower_bounds = static_cast<double>(sosndtimer) * -1e3;
@@ -510,10 +569,18 @@ void Client::InitTrafficLoop () {
mEndTime.add(mSettings->mAmount / 100.0);
// now.setnow(); fprintf(stderr, "DEBUG: end time set to %ld.%ld now is %ld.%ld\n", mEndTime.getSecs(), mEndTime.getUsecs(), now.getSecs(), now.getUsecs());
}
+#if HAVE_DECL_TCP_TX_DELAY
+ current_state = NO_DELAY;
+ if (isTcpTxDelay(mSettings)) {
+ state_tokens[NO_DELAY] = (int) (mSettings->mTcpTxDelayMean * (1 - mSettings->mTcpTxDelayProb));
+ state_tokens[ADD_DELAY] = (int) (mSettings->mTcpTxDelayMean * mSettings->mTcpTxDelayProb);
+ TcpTxDelayQuantumEnd.setnow();
+ }
+#endif
readAt = mSettings->mBuf;
lastPacketTime.set(myReport->info.ts.startTime.tv_sec, myReport->info.ts.startTime.tv_usec);
- reportstruct->errwrite=WriteNoErr;
- reportstruct->emptyreport=0;
+ reportstruct->err_readwrite=WriteSuccess;
+ reportstruct->emptyreport = false;
reportstruct->packetLen = 0;
// Finally, post this thread's "job report" which the reporter thread
// will continuously process as long as there are packets flowing
@@ -576,6 +643,48 @@ void Client::Run () {
}
}
+#if HAVE_DECL_TCP_TX_DELAY
+inline void Client::apply_txdelay_func (void) {
+ now.setnow();
+ if (isTcpTxDelay(mSettings) && TcpTxDelayQuantumEnd.before(now)) {
+ // expense the tokens for the current state
+ state_tokens[current_state] -= now.subUsec(TcpTxDelayQuantumEnd);
+ // add tokens
+ do {
+ state_tokens[NO_DELAY] += (int) (mSettings->mTcpTxDelayMean * (1 - mSettings->mTcpTxDelayProb));
+ state_tokens[ADD_DELAY] += (int) (mSettings->mTcpTxDelayMean * mSettings->mTcpTxDelayProb);
+ } while ((state_tokens[NO_DELAY] < 0) && (state_tokens[ADD_DELAY] < 0));
+ // set the next quantum end
+ while (TcpTxDelayQuantumEnd.before(now))
+ TcpTxDelayQuantumEnd.add((unsigned int) TCPDELAYDEFAULTQUANTUM);
+ // do any state change
+ if ((state_tokens[NO_DELAY] < 0) && (current_state == NO_DELAY)) {
+// printf("**** f state change to 0->1 current=%d %d %d\n", current_state, state_tokens[NO_DELAY], state_tokens[ADD_DELAY]);
+ SetSocketTcpTxDelay(mSettings, (mSettings->mTcpTxDelayMean * 1000.0));
+ current_state = ADD_DELAY;
+ } else if ((state_tokens[ADD_DELAY] < 0) && (current_state == ADD_DELAY)) {
+// printf("**** f state change to 1->0 current=%d %d %d\n", current_state, state_tokens[NO_DELAY], state_tokens[ADD_DELAY]);
+ SetSocketTcpTxDelay(mSettings, 0.0);
+ current_state = NO_DELAY;
+ } else {
+ int rval = (random() % 2);
+ // printf("**** curr=%d rval=%d tokens 0:%d 1:%d\n", current_state, rval, state_tokens[NO_DELAY], state_tokens[ADD_DELAY]);
+ if (rval != current_state) {
+ if (rval && (state_tokens[ADD_DELAY] > 0)) {
+// printf("**** state change to 0->1 rval=%d current=%d %d %d\n", rval, current_state, state_tokens[NO_DELAY], state_tokens[ADD_DELAY]);
+ SetSocketTcpTxDelay(mSettings, (mSettings->mTcpTxDelayMean * 1000.0));
+ current_state = ADD_DELAY;
+ } else if ((rval != 1) && (state_tokens[NO_DELAY] > 0)) {
+// printf("**** state change to 1->0 rval=%d current=%d %d %d\n", rval, current_state, state_tokens[NO_DELAY], state_tokens[ADD_DELAY]);
+ SetSocketTcpTxDelay(mSettings, 0.0);
+ current_state = NO_DELAY;
+ }
+ }
+ }
+ }
+}
+#endif
+
/*
* TCP send loop
*/
@@ -588,6 +697,12 @@ void Client::RunTCP () {
reportstruct->packetTime.tv_sec = now.getSecs();
reportstruct->packetTime.tv_usec = now.getUsecs();
reportstruct->write_time = 0;
+#if (HAVE_DECL_SO_MAX_PACING_RATE)
+ if (isFQPacingStep(mSettings)) {
+ PacingStepTime = now;
+ PacingStepTime.add(mSettings->mFQPacingRateStepInterval);
+ }
+#endif
while (InProgress()) {
reportstruct->writecnt = 0;
reportstruct->scheduled = false;
@@ -598,7 +713,7 @@ void Client::RunTCP () {
if (isIsochronous(mSettings)) {
assert(mSettings->mMean);
burst_remaining = static_cast<int>(lognormal(mSettings->mMean,mSettings->mVariance)) / (mSettings->mFPS * 8);
- } else if (isPeriodicBurst(mSettings)){
+ } else if (isBurstSize(mSettings)){
assert(mSettings->mBurstSize);
burst_remaining = mSettings->mBurstSize;
} else {
@@ -609,7 +724,7 @@ void Client::RunTCP () {
burst_remaining = static_cast<int>(sizeof(struct TCP_burst_payload));
// apply scheduling if needed
if (framecounter) {
- burst_id = framecounter->wait_tick(&reportstruct->sched_err);
+ burst_id = framecounter->wait_tick(&reportstruct->sched_err, true);
reportstruct->scheduled = true;
if (isPeriodicBurst(mSettings)) {
// low duty cycle traffic needs special event handling
@@ -619,20 +734,17 @@ void Client::RunTCP () {
reportstruct->packetTime.tv_usec = now.getUsecs();
if (!InProgress()) {
reportstruct->packetLen = 0;
- reportstruct->emptyreport = 1;
+ reportstruct->emptyreport = true;
// wait may have crossed the termination boundry
break;
} else {
//time interval crossings may have occurred during the wait
//post a null event to cause the report to flush the packet ring
- PostNullEvent();
+ PostNullEvent(false, false);
}
}
-#if HAVE_DECL_TCP_NOTSENT_LOWAT
- if (isWritePrefetch(mSettings)) {
- AwaitWriteSelectEventTCP();
- }
-#endif
+ if (isWritePrefetch(mSettings) && !AwaitSelectWrite())
+ continue;
}
now.setnow();
reportstruct->packetTime.tv_sec = now.getSecs();
@@ -659,11 +771,8 @@ void Client::RunTCP () {
if (isTcpWriteTimes(mSettings)) {
write_start.setnow();
}
-#if HAVE_DECL_TCP_NOTSENT_LOWAT
- if (isWritePrefetch(mSettings)) {
- AwaitWriteSelectEventTCP();
- }
-#endif
+ if (isWritePrefetch(mSettings) && !AwaitSelectWrite())
+ continue;
reportstruct->packetLen = write(mySocket, mSettings->mBuf, writelen);
now.setnow();
reportstruct->writecnt++;
@@ -676,28 +785,33 @@ void Client::RunTCP () {
}
if (reportstruct->packetLen <= 0) {
if (reportstruct->packetLen == 0) {
+ reportstruct->err_readwrite=WriteErrFatal;
peerclose = true;
} else if (NONFATALTCPWRITERR(errno)) {
- reportstruct->errwrite=WriteErrAccount;
+ reportstruct->err_readwrite=WriteErrAccount;
} else if (FATALTCPWRITERR(errno)) {
- reportstruct->errwrite=WriteErrFatal;
- WARN_errno(1, "tcp write");
+ reportstruct->err_readwrite=WriteErrFatal;
+ now.setnow();
+ char warnbuf[WARNBUFSIZE];
+ snprintf(warnbuf, sizeof(warnbuf), "%stcp write (%ld.%ld)", mSettings->mTransferIDStr, now.getSecs(), now.getUsecs());
+ warnbuf[sizeof(warnbuf)-1] = '\0';
+ WARN(1, warnbuf);
break;
} else {
- reportstruct->errwrite=WriteErrNoAccount;
+ reportstruct->err_readwrite=WriteNoAccount;
}
reportstruct->packetLen = 0;
- reportstruct->emptyreport = 1;
+ reportstruct->emptyreport = true;
} else {
- reportstruct->emptyreport = 0;
+ reportstruct->emptyreport = false;
totLen += reportstruct->packetLen;
- reportstruct->errwrite=WriteNoErr;
+ reportstruct->err_readwrite=WriteSuccess;
if (isburst) {
burst_remaining -= reportstruct->packetLen;
if (burst_remaining > 0) {
- reportstruct->transit_ready = 0;
+ reportstruct->transit_ready = false;
} else {
- reportstruct->transit_ready = 1;
+ reportstruct->transit_ready = true;
reportstruct->prevSentTime = myReport->info.ts.prevsendTime;
}
}
@@ -711,7 +825,20 @@ void Client::RunTCP () {
}
}
if (!one_report) {
+#if (HAVE_DECL_SO_MAX_PACING_RATE)
+ if (isFQPacing(mSettings))
+ reportstruct->FQPacingRate = mSettings->mFQPacingRateCurrent;
+#endif
myReportPacket();
+#if (HAVE_DECL_SO_MAX_PACING_RATE)
+ if (isFQPacingStep(mSettings) && PacingStepTime.before(now)) {
+ mSettings->mFQPacingRateCurrent += mSettings->mFQPacingRateStep;
+ setsockopt(mSettings->mSock, SOL_SOCKET, SO_MAX_PACING_RATE, &mSettings->mFQPacingRateCurrent, sizeof(mSettings->mFQPacingRateCurrent));
+ PacingStepTime.add(mSettings->mFQPacingRateStepInterval);
+ socklen_t len = sizeof(reportstruct->FQPacingRate);
+ getsockopt(mSettings->mSock, SOL_SOCKET, SO_MAX_PACING_RATE, &reportstruct->FQPacingRate, &len);
+ }
+#endif
}
}
FinishTrafficActions();
@@ -761,26 +888,26 @@ void Client::RunNearCongestionTCP () {
reportstruct->packetTime.tv_usec = now.getUsecs();
reportstruct->sentTime = reportstruct->packetTime;
ReportNow:
- reportstruct->transit_ready = 0;
+ reportstruct->transit_ready = false;
if (reportstruct->packetLen < 0) {
if (NONFATALTCPWRITERR(errno)) {
- reportstruct->errwrite=WriteErrAccount;
+ reportstruct->err_readwrite=WriteErrAccount;
} else if (FATALTCPWRITERR(errno)) {
- reportstruct->errwrite=WriteErrFatal;
+ reportstruct->err_readwrite=WriteErrFatal;
WARN_errno(1, "tcp write");
break;
} else {
- reportstruct->errwrite=WriteErrNoAccount;
+ reportstruct->err_readwrite=WriteNoAccount;
}
reportstruct->packetLen = 0;
- reportstruct->emptyreport = 1;
+ reportstruct->emptyreport = true;
} else {
- reportstruct->emptyreport = 0;
+ reportstruct->emptyreport = false;
totLen += reportstruct->packetLen;
- reportstruct->errwrite=WriteNoErr;
+ reportstruct->err_readwrite=WriteSuccess;
burst_remaining -= reportstruct->packetLen;
if (burst_remaining <= 0) {
- reportstruct->transit_ready = 1;
+ reportstruct->transit_ready = true;
}
}
if (isModeAmount(mSettings) && !reportstruct->emptyreport) {
@@ -814,8 +941,7 @@ void Client::RunNearCongestionTCP () {
void Client::RunRateLimitedTCP () {
double tokens = 0;
Timestamp time1, time2;
- int burst_size = mSettings->mBufLen;
- int burst_remaining = 0;
+ int write_remaining = 0;
int burst_id = 1;
long var_rate = mSettings->mAppRate;
@@ -848,61 +974,79 @@ void Client::RunRateLimitedTCP () {
// perform write
int len = 0;
int len2 = 0;
- if (burst_remaining == 0) {
- burst_remaining = mSettings->mBufLen;
+
+ if (isburst && !(write_remaining > 0)) {
+ if (isWritePrefetch(mSettings) && !AwaitSelectWrite())
+ continue;
+ write_remaining = mSettings->mBufLen;
+ // check for TCP minimum payload
+ if (write_remaining < static_cast<int>(sizeof(struct TCP_burst_payload)))
+ write_remaining = static_cast<int>(sizeof(struct TCP_burst_payload));
now.setnow();
reportstruct->packetTime.tv_sec = now.getSecs();
reportstruct->packetTime.tv_usec = now.getUsecs();
reportstruct->sentTime = reportstruct->packetTime;
- WriteTcpTxHdr(reportstruct, burst_size, burst_id++);
+ WriteTcpTxHdr(reportstruct, write_remaining, burst_id++);
// perform write
- if (isTripTime(mSettings)) {
- len = writen(mySocket, mSettings->mBuf, mSettings->mBufLen, &reportstruct->writecnt);
- WARN(len != mSettings->mBufLen, "burst write failed");
- } else {
- len = writen(mySocket, mSettings->mBuf, sizeof(struct TCP_burst_payload), &reportstruct->writecnt);
- WARN(len != sizeof(struct TCP_burst_payload), "burst hdr write failed");
+ // perform write, full header must succeed
+ if (isTcpWriteTimes(mSettings)) {
+ write_start.setnow();
+ }
+ len = writen(mySocket, mSettings->mBuf, write_remaining, &reportstruct->writecnt);
+ WARN((len < static_cast<int> (sizeof(struct TCP_burst_payload))), "burst hdr write failed");
+ if (isTcpWriteTimes(mSettings)) {
+ now.setnow();
+ reportstruct->write_time = now.subUsec(write_start);
}
if (len < 0) {
len = 0;
if (NONFATALTCPWRITERR(errno)) {
- reportstruct->errwrite=WriteErrAccount;
+ reportstruct->err_readwrite=WriteErrAccount;
} else if (FATALTCPWRITERR(errno)) {
- reportstruct->errwrite=WriteErrFatal;
+ reportstruct->err_readwrite=WriteErrFatal;
WARN_errno(1, "write");
fatalwrite_err = 1;
break;
} else {
- reportstruct->errwrite=WriteErrNoAccount;
+ reportstruct->err_readwrite=WriteNoAccount;
}
} else {
- burst_remaining -= len;
+ write_remaining -= len;
}
// thread_debug("***write burst header %d id=%d", burst_size, (burst_id - 1));
- } else if (reportstruct->packetLen > burst_remaining) {
- reportstruct->packetLen = burst_remaining;
+ } else {
+ write_remaining = mSettings->mBufLen;
}
- if (burst_remaining > 0) {
- len2 = write(mySocket, mSettings->mBuf, reportstruct->packetLen);
+ if (write_remaining > 0) {
+ if (isTcpWriteTimes(mSettings)) {
+ write_start.setnow();
+ }
+ if (isWritePrefetch(mSettings) && !AwaitSelectWrite())
+ continue;
+ len2 = write(mySocket, mSettings->mBuf, write_remaining);
+ if (isTcpWriteTimes(mSettings)) {
+ now.setnow();
+ reportstruct->write_time = now.subUsec(write_start);
+ }
reportstruct->writecnt++;
}
if (len2 < 0) {
len2 = 0;
if (NONFATALTCPWRITERR(errno)) {
- reportstruct->errwrite=WriteErrAccount;
+ reportstruct->err_readwrite=WriteErrAccount;
} else if (FATALTCPWRITERR(errno)) {
- reportstruct->errwrite=WriteErrFatal;
+ reportstruct->err_readwrite=WriteErrFatal;
WARN_errno(1, "write");
fatalwrite_err = 1;
break;
} else {
- reportstruct->errwrite=WriteErrNoAccount;
+ reportstruct->err_readwrite=WriteNoAccount;
}
} else {
// Consume tokens per the transmit
tokens -= (len + len2);
- totLen += (len + len2);;
- reportstruct->errwrite=WriteNoErr;
+ totLen += (len + len2);
+ reportstruct->err_readwrite=WriteSuccess;
}
time2.setnow();
reportstruct->packetLen = len + len2;
@@ -922,51 +1066,60 @@ void Client::RunRateLimitedTCP () {
}
} else {
// Use a 4 usec delay to fill tokens
-#if HAVE_DECL_TCP_NOTSENT_LOWAT
- if (isWritePrefetch(mSettings)) {
- AwaitWriteSelectEventTCP();
- } else
-#endif
- {
- delay_loop(4);
+ delay_loop(4);
+ if (isWritePrefetch(mSettings) && !AwaitSelectWrite()) {
+ continue;
}
}
}
FinishTrafficActions();
}
+inline bool Client::AwaitSelectWrite (void) {
#if HAVE_DECL_TCP_NOTSENT_LOWAT
-inline bool Client::AwaitWriteSelectEventTCP (void) {
- int rc;
- struct timeval timeout;
- fd_set writeset;
- FD_ZERO(&writeset);
- FD_SET(mySocket, &writeset);
- if (isModeTime(mSettings)) {
- Timestamp write_event_timeout(0,0);
- if (mSettings->mInterval && (mSettings->mIntervalMode == kInterval_Time)) {
- write_event_timeout.add((double) mSettings->mInterval / 1e6 * 2.0);
+ do {
+ int rc;
+ struct timeval timeout;
+ fd_set writeset;
+ FD_ZERO(&writeset);
+ FD_SET(mySocket, &writeset);
+ if (isModeTime(mSettings)) {
+ Timestamp write_event_timeout(0,0);
+ if (mSettings->mInterval && (mSettings->mIntervalMode == kInterval_Time)) {
+ write_event_timeout.add((double) mSettings->mInterval / ((mSettings->mThreads > 1) ? 4e6 : 2e6));
+ } else {
+ write_event_timeout.add((double) mSettings->mAmount / 4e2);
+ }
+ timeout.tv_sec = write_event_timeout.getSecs();
+ timeout.tv_usec = write_event_timeout.getUsecs();
} else {
- write_event_timeout.add((double) mSettings->mAmount / 1e2 * 4.0);
+ timeout.tv_sec = 1; // longest is 1 seconds
+ timeout.tv_usec = 0;
}
- timeout.tv_sec = write_event_timeout.getSecs();
- timeout.tv_usec = write_event_timeout.getUsecs();
- } else {
- timeout.tv_sec = 10; // longest is 10 seconds
- timeout.tv_usec = 0;
- }
- if ((rc = select(mySocket + 1, NULL, &writeset, NULL, &timeout)) <= 0) {
- WARN_errno((rc < 0), "select");
-#ifdef HAVE_THREAD_DEBUG
- if (rc == 0)
- thread_debug("AwaitWrite timeout");
+ if ((rc = select(mySocket + 1, NULL, &writeset, NULL, &timeout)) <= 0) {
+ WARN_errno((rc < 0), "select");
+ if (rc <= 0)
+ PostNullEvent(false, true);
+#if HAVE_SUMMING_DEBUG
+ if (rc == 0) {
+ char warnbuf[WARNBUFSIZE];
+ snprintf(warnbuf, sizeof(warnbuf), "%sTimeout: write select", mSettings->mTransferIDStr);
+ warnbuf[sizeof(warnbuf)-1] = '\0';
+ WARN(1, warnbuf);
+ }
#endif
- return false;
- }
+ } else {
+ return true;
+ }
+ } while (InProgress());
+ return false;
+#else
return true;
+#endif
}
+#if HAVE_DECL_TCP_NOTSENT_LOWAT
void Client::RunWriteEventsTCP () {
int burst_id = 0;
int writelen = mSettings->mBufLen;
@@ -975,18 +1128,28 @@ void Client::RunWriteEventsTCP () {
now.setnow();
reportstruct->packetTime.tv_sec = now.getSecs();
reportstruct->packetTime.tv_usec = now.getUsecs();
+#if (HAVE_DECL_SO_MAX_PACING_RATE)
+ if (isFQPacingStep(mSettings)) {
+ PacingStepTime = now;
+ PacingStepTime.add(mSettings->mFQPacingRateStepInterval);
+ }
+#endif
while (InProgress()) {
+#if HAVE_DECL_TCP_TX_DELAY
+// apply_txdelay_func();
+#endif
if (isModeAmount(mSettings)) {
writelen = ((mSettings->mAmount < static_cast<unsigned>(mSettings->mBufLen)) ? mSettings->mAmount : mSettings->mBufLen);
}
now.setnow();
reportstruct->write_time = 0;
+ reportstruct->writecnt = 0;
if (isTcpWriteTimes(mSettings)) {
write_start = now;
}
- bool rc = AwaitWriteSelectEventTCP();
- reportstruct->emptyreport = (rc == false) ? 1 : 0;
- if (rc) {
+ if (isWritePrefetch(mSettings) && !AwaitSelectWrite())
+ continue;
+ if (!reportstruct->emptyreport) {
now.setnow();
reportstruct->packetTime.tv_sec = now.getSecs();
reportstruct->packetTime.tv_usec = now.getUsecs();
@@ -999,7 +1162,7 @@ void Client::RunWriteEventsTCP () {
peerclose = true;
}
reportstruct->packetLen = 0;
- reportstruct->emptyreport = 1;
+ reportstruct->emptyreport = true;
} else if (isTcpWriteTimes(mSettings)) {
write_end.setnow();
reportstruct->write_time = write_end.subUsec(write_start);
@@ -1014,7 +1177,20 @@ void Client::RunWriteEventsTCP () {
}
}
if (!one_report) {
+#if (HAVE_DECL_SO_MAX_PACING_RATE)
+ if (isFQPacing(mSettings))
+ reportstruct->FQPacingRate = mSettings->mFQPacingRateCurrent;
+#endif
myReportPacket();
+#if (HAVE_DECL_SO_MAX_PACING_RATE)
+ if (isFQPacingStep(mSettings) && PacingStepTime.before(now)) {
+ mSettings->mFQPacingRateCurrent += mSettings->mFQPacingRateStep;
+ setsockopt(mSettings->mSock, SOL_SOCKET, SO_MAX_PACING_RATE, &mSettings->mFQPacingRateCurrent, sizeof(mSettings->mFQPacingRateCurrent));
+ PacingStepTime.add(mSettings->mFQPacingRateStepInterval);
+ socklen_t len = sizeof(reportstruct->FQPacingRate);
+ getsockopt(mSettings->mSock, SOL_SOCKET, SO_MAX_PACING_RATE, &reportstruct->FQPacingRate, &len);
+ }
+#endif
}
}
FinishTrafficActions();
@@ -1022,7 +1198,7 @@ void Client::RunWriteEventsTCP () {
#endif
void Client::RunBounceBackTCP () {
int burst_id = 0;
- int writelen = mSettings->mBufLen;
+ int writelen = mSettings->mBounceBackBytes;
memset(mSettings->mBuf, 0x5A, sizeof(struct bounceback_hdr));
if (mSettings->mInterval && (mSettings->mIntervalMode == kInterval_Time)) {
int sotimer = static_cast<int>(round(mSettings->mInterval / 2.0));
@@ -1044,11 +1220,12 @@ void Client::RunBounceBackTCP () {
reportstruct->packetTime.tv_usec = now.getUsecs();
while (InProgress()) {
int n;
+ long remaining;
reportstruct->writecnt = 0;
bool isFirst;
if (framecounter) {
- burst_id = framecounter->wait_tick(&reportstruct->sched_err);
- PostNullEvent(true); // this will set the now timestamp
+ burst_id = framecounter->wait_tick(&reportstruct->sched_err, false);
+ PostNullEvent(true, false); // now is set in this call
reportstruct->sentTime.tv_sec = now.getSecs();
reportstruct->sentTime.tv_usec = now.getUsecs();
isFirst = true;
@@ -1057,7 +1234,7 @@ void Client::RunBounceBackTCP () {
isFirst = false;
}
int bb_burst = (mSettings->mBounceBackBurst > 0) ? mSettings->mBounceBackBurst : 1;
- while (bb_burst > 0) {
+ while ((bb_burst > 0) && InProgress() && (!framecounter || (framecounter->get(&remaining)) == (unsigned int) burst_id)) {
bb_burst--;
if (isFirst) {
isFirst = false;
@@ -1067,28 +1244,31 @@ void Client::RunBounceBackTCP () {
reportstruct->sentTime.tv_usec = now.getUsecs();
}
WriteTcpTxBBHdr(reportstruct, burst_id, 0);
- reportstruct->packetLen = writen(mySocket, mSettings->mBuf, writelen, &reportstruct->writecnt);
- if (reportstruct->packetLen <= 0) {
- if ((reportstruct->packetLen < 0) && FATALTCPWRITERR(errno)) {
- reportstruct->errwrite=WriteErrFatal;
+ int write_offset = 0;
+ reportstruct->writecnt = 0;
+ RETRY_WRITE:
+ n = writen(mySocket, (mSettings->mBuf + write_offset), (writelen - write_offset), &reportstruct->writecnt);
+ if (n < 0) {
+ if (FATALTCPWRITERR(errno)) {
+ reportstruct->err_readwrite=WriteErrFatal;
WARN_errno(1, "tcp bounceback write fatal error");
peerclose = true;
- } else if (reportstruct->packetLen == 0) {
- peerclose = true;
- } else if (reportstruct->packetLen != writelen) {
- WARN_errno(1, "tcp bounceback writen incomplete");
- peerclose = true;
- } else {
- // retry the write
- bb_burst++;
- continue;
+ break;
+ } else if (InProgress()) {
+ PostNullEvent(false,false);
+ goto RETRY_WRITE;
}
- break;
}
- if (reportstruct->packetLen == writelen) {
- reportstruct->emptyreport = 0;
- totLen += reportstruct->packetLen;
- reportstruct->errwrite=WriteNoErr;
+ write_offset += n;
+ if ((write_offset < writelen) && InProgress()) {
+ WARN_errno(1, "tcp bounceback writen incomplete");
+ PostNullEvent(false,false);
+ goto RETRY_WRITE;
+ }
+ if (write_offset == writelen) {
+ reportstruct->emptyreport = false;
+ totLen += writelen;
+ reportstruct->err_readwrite=WriteSuccess;
#if HAVE_DECL_TCP_QUICKACK
if (isTcpQuickAck(mSettings)) {
int opt = 1;
@@ -1098,43 +1278,50 @@ void Client::RunBounceBackTCP () {
WARN_errno(rc == SOCKET_ERROR, "setsockopt TCP_QUICKACK");
}
#endif
- if ((n = recvn(mySocket, mSettings->mBuf, mSettings->mBounceBackBytes, 0)) == mSettings->mBounceBackBytes) {
- struct bounceback_hdr *bbhdr = reinterpret_cast<struct bounceback_hdr *>(mSettings->mBuf);
- now.setnow();
- reportstruct->sentTimeRX.tv_sec = ntohl(bbhdr->bbserverRx_ts.sec);
- reportstruct->sentTimeRX.tv_usec = ntohl(bbhdr->bbserverRx_ts.usec);
- reportstruct->sentTimeTX.tv_sec = ntohl(bbhdr->bbserverTx_ts.sec);
- reportstruct->sentTimeTX.tv_usec = ntohl(bbhdr->bbserverTx_ts.usec);
- reportstruct->packetTime.tv_sec = now.getSecs();
- reportstruct->packetTime.tv_usec = now.getUsecs();
- reportstruct->packetLen += n;
- reportstruct->emptyreport = 0;
- myReportPacket();
+ int read_offset = 0;
+ RETRY_READ:
+ n = recvn(mySocket, (mSettings->mBuf + read_offset), (mSettings->mBounceBackReplyBytes - read_offset), 0);
+ if (n > 0) {
+ read_offset += n;
+ if (read_offset == mSettings->mBounceBackReplyBytes) {
+ struct bounceback_hdr *bbhdr = reinterpret_cast<struct bounceback_hdr *>(mSettings->mBuf);
+ now.setnow();
+ reportstruct->sentTimeRX.tv_sec = ntohl(bbhdr->bbserverRx_ts.sec);
+ reportstruct->sentTimeRX.tv_usec = ntohl(bbhdr->bbserverRx_ts.usec);
+ reportstruct->sentTimeTX.tv_sec = ntohl(bbhdr->bbserverTx_ts.sec);
+ reportstruct->sentTimeTX.tv_usec = ntohl(bbhdr->bbserverTx_ts.usec);
+ reportstruct->packetTime.tv_sec = now.getSecs();
+ reportstruct->packetTime.tv_usec = now.getUsecs();
+ reportstruct->packetLen += n;
+ reportstruct->emptyreport = false;
+ reportstruct->packetID = burst_id;
+ myReportPacket();
+ } else if (InProgress()) {
+ PostNullEvent(false,false);
+ goto RETRY_READ;
+ } else {
+ break;
+ }
} else if (n == 0) {
peerclose = true;
- } else if (n < 0) {
+ break;
+ } else {
if (FATALTCPREADERR(errno)) {
- WARN_errno(1, "bounceback read");
+ FAIL_errno(1, "fatal bounceback read", mSettings);
peerclose = true;
- n = 0;
+ break;
} else {
- WARN(1, "timeout: bounceback read");
+ WARN_errno(1, "timeout: bounceback read");
+ PostNullEvent(false,false);
+ if (InProgress())
+ goto RETRY_READ;
}
}
- } else if ((reportstruct->packetLen < 0 ) && NONFATALTCPWRITERR(errno)) {
- reportstruct->packetLen = 0;
- reportstruct->emptyreport = 1;
- reportstruct->errwrite=WriteErrNoAccount;
- myReportPacket();
- } else {
- reportstruct->errwrite=WriteErrFatal;
- reportstruct->packetLen = -1;
- FAIL_errno(1, "tcp bounce-back write", mSettings);
}
}
}
- WriteTcpTxBBHdr(reportstruct, 0x0, 1);
- disarm_itimer();
+ if (!peerclose)
+ WriteTcpTxBBHdr(reportstruct, 0x0, 1); // Signal end of BB test
FinishTrafficActions();
}
/*
@@ -1148,10 +1335,11 @@ double Client::get_delay_target () {
// compute delay target in units of nanoseconds
if (mSettings->mAppRateUnits == kRate_BW) {
// compute delay for bandwidth restriction, constrained to [0,1] seconds
- delay_target = (mSettings->mBufLen * ((kSecs_to_nsecs * kBytes_to_Bits)
- / mSettings->mAppRate));
+ delay_target = ((mSettings->mAppRate > 0) ? \
+ (mSettings->mBufLen * ((kSecs_to_nsecs * kBytes_to_Bits) / mSettings->mAppRate)) \
+ : 0);
} else {
- delay_target = 1e9 / mSettings->mAppRate;
+ delay_target = (mSettings->mAppRate > 0) ? (1e9 / mSettings->mAppRate) : 0;
}
}
return delay_target;
@@ -1202,53 +1390,77 @@ void Client::RunUDP () {
mBuf_UDP->tv_sec = htonl(reportstruct->packetTime.tv_sec);
mBuf_UDP->tv_usec = htonl(reportstruct->packetTime.tv_usec);
- // Adjustment for the running delay
- // o measure how long the last loop iteration took
- // o calculate the delay adjust
- // - If write succeeded, adjust = target IPG - the loop time
- // - If write failed, adjust = the loop time
- // o then adjust the overall running delay
- // Note: adjust units are nanoseconds,
- // packet timestamps are microseconds
- if (currLen > 0)
- adjust = delay_target + \
- (1000.0 * lastPacketTime.subUsec(reportstruct->packetTime));
- else
- adjust = 1000.0 * lastPacketTime.subUsec(reportstruct->packetTime);
-
- lastPacketTime.set(reportstruct->packetTime.tv_sec, reportstruct->packetTime.tv_usec);
- // Since linux nanosleep/busyloop can exceed delay
- // there are two possible equilibriums
- // 1) Try to perserve inter packet gap
- // 2) Try to perserve requested transmit rate
- // The latter seems preferred, hence use a running delay
- // that spans the life of the thread and constantly adjust.
- // A negative delay means the iperf app is behind.
- delay += adjust;
- // Don't let delay grow unbounded
- if (delay < delay_lower_bounds) {
- delay = delay_target;
- }
+ if (delay_target > 0) {
+ // Adjustment for the running delay
+ // o measure how long the last loop iteration took
+ // o calculate the delay adjust
+ // - If write succeeded, adjust = target IPG - the loop time
+ // - If write failed, adjust = the loop time
+ // o then adjust the overall running delay
+ // Note: adjust units are nanoseconds,
+ // packet timestamps are microseconds
+ if (currLen > 0)
+ adjust = delay_target + \
+ (1000.0 * lastPacketTime.subUsec(reportstruct->packetTime));
+ else
+ adjust = 1000.0 * lastPacketTime.subUsec(reportstruct->packetTime);
- reportstruct->errwrite = WriteNoErr;
- reportstruct->emptyreport = 0;
+ lastPacketTime.set(reportstruct->packetTime.tv_sec, reportstruct->packetTime.tv_usec);
+ // Since linux nanosleep/busyloop can exceed delay
+ // there are two possible equilibriums
+ // 1) Try to perserve inter packet gap
+ // 2) Try to perserve requested transmit rate
+ // The latter seems preferred, hence use a running delay
+ // that spans the life of the thread and constantly adjust.
+ // A negative delay means the iperf app is behind.
+ delay += adjust;
+ // Don't let delay grow unbounded
+ if (delay < delay_lower_bounds) {
+ delay = delay_target;
+ }
+ }
+ reportstruct->err_readwrite = WriteSuccess;
+ reportstruct->emptyreport = false;
// perform write
if (isModeAmount(mSettings)) {
currLen = write(mySocket, mSettings->mBuf, (mSettings->mAmount < static_cast<unsigned>(mSettings->mBufLen)) ? mSettings->mAmount : mSettings->mBufLen);
} else {
+ currLen = -1;
+#if (HAVE_USE_WRITE_SELECT) && (HAVE_SELECT)
+#if HAVE_DECL_MSG_DONTWAIT
+ currLen = send(mySocket, mSettings->mBuf, mSettings->mBufLen, MSG_DONTWAIT);
+ if ((currLen < 0) && !FATALUDPWRITERR(errno)) {
+ if (AwaitSelectWrite()) {
+ currLen = write(mySocket, mSettings->mBuf, mSettings->mBufLen);
+ reportstruct->err_readwrite = WriteSelectRetry;
+ } else {
+ reportstruct->err_readwrite = WriteTimeo;
+ }
+ }
+#else
+ if (AwaitSelectWrite()) {
+ currLen = write(mySocket, mSettings->mBuf, mSettings->mBufLen);
+ } else {
+ reportstruct->err_readwrite = WriteTimeo;
+ }
+#endif
+#else
currLen = write(mySocket, mSettings->mBuf, mSettings->mBufLen);
+#endif
}
if (currLen < 0) {
reportstruct->packetID--;
if (FATALUDPWRITERR(errno)) {
- reportstruct->errwrite = WriteErrFatal;
+ reportstruct->err_readwrite = WriteErrFatal;
WARN_errno(1, "write");
+ currLen = 0;
break;
} else {
- reportstruct->errwrite = WriteErrAccount;
+ //WARN_errno(1, "write n");
currLen = 0;
+ reportstruct->err_readwrite = WriteErrAccount;
}
- reportstruct->emptyreport = 1;
+ reportstruct->emptyreport = true;
}
if (isModeAmount(mSettings)) {
@@ -1310,7 +1522,7 @@ void Client::RunUDPIsochronous () {
udp_payload->isoch.burstsize = htonl(bytecnt);
udp_payload->isoch.prevframeid = htonl(frameid);
reportstruct->burstsize=bytecnt;
- frameid = framecounter->wait_tick(&reportstruct->sched_err);
+ frameid = framecounter->wait_tick(&reportstruct->sched_err, true);
reportstruct->scheduled = true;
udp_payload->isoch.frameid = htonl(frameid);
lastPacketTime.setnow();
@@ -1356,8 +1568,8 @@ void Client::RunUDPIsochronous () {
// delay = delay_target;
// }
- reportstruct->errwrite = WriteNoErr;
- reportstruct->emptyreport = 0;
+ reportstruct->err_readwrite = WriteSuccess;
+ reportstruct->emptyreport = false;
reportstruct->writecnt = 1;
// perform write
@@ -1373,21 +1585,22 @@ void Client::RunUDPIsochronous () {
if (currLen < 0) {
reportstruct->packetID--;
- reportstruct->emptyreport = 1;
- currLen = 0;
+ reportstruct->emptyreport = true;
if (FATALUDPWRITERR(errno)) {
- reportstruct->errwrite = WriteErrFatal;
+ reportstruct->err_readwrite = WriteErrFatal;
WARN_errno(1, "write");
fatalwrite_err = 1;
- } else {
- reportstruct->errwrite = WriteErrAccount;
+ currLen = 0;
+ } else {
+ currLen = 0;
+ reportstruct->err_readwrite = WriteErrAccount;
}
} else {
bytecnt -= currLen;
if (!bytecnt)
- reportstruct->transit_ready = 1;
+ reportstruct->transit_ready = true;
else
- reportstruct->transit_ready = 0;
+ reportstruct->transit_ready = false;
// adjust bytecnt so last packet of burst is greater or equal to min packet
if ((bytecnt > 0) && (bytecnt < udp_payload_minimum)) {
bytecnt = udp_payload_minimum;
@@ -1504,8 +1717,11 @@ void Client::WriteTcpTxBBHdr (struct ReportStruct *reportstruct, uint32_t bbid,
if (final) {
bbflags |= HEADER_BBSTOP;
}
+ if ((mSettings->mBounceBackReplyBytes > 0) && (mSettings->mBounceBackReplyBytes != mSettings->mBounceBackBytes)) {
+ bbflags |= HEADER_BBREPLYSIZE;
+ }
mBuf_bb->bbflags = htons(bbflags);
- mBuf_bb->bbsize = htonl(mSettings->mBufLen);
+ mBuf_bb->bbsize = htonl(mSettings->mBounceBackBytes);
mBuf_bb->bbid = htonl(bbid);
mBuf_bb->bbclientTx_ts.sec = htonl(reportstruct->packetTime.tv_sec);
mBuf_bb->bbclientTx_ts.usec = htonl(reportstruct->packetTime.tv_usec);
@@ -1514,6 +1730,7 @@ void Client::WriteTcpTxBBHdr (struct ReportStruct *reportstruct, uint32_t bbid,
mBuf_bb->bbserverTx_ts.sec = -1;
mBuf_bb->bbserverTx_ts.usec = -1;
mBuf_bb->bbhold = htonl(mSettings->mBounceBackHold);
+ mBuf_bb->bbreplysize = htonl(mSettings->mBounceBackReplyBytes);
}
inline bool Client::InProgress (void) {
@@ -1535,7 +1752,10 @@ inline void Client::tcp_shutdown (void) {
#ifdef HAVE_THREAD_DEBUG
thread_debug("Client calls shutdown() SHUTW_WR on tcp socket %d", mySocket);
#endif
- WARN_errno(rc == SOCKET_ERROR, "shutdown");
+ char warnbuf[256];
+ snprintf(warnbuf, sizeof(warnbuf), "%sshutdown", mSettings->mTransferIDStr);
+ warnbuf[sizeof(warnbuf)-1] = '\0';
+ WARN_errno(rc == SOCKET_ERROR, warnbuf);
if (!rc && !isFullDuplex(mSettings))
AwaitServerCloseEvent();
}
@@ -1557,7 +1777,9 @@ void Client::FinishTrafficActions () {
disarm_itimer();
// Shutdown the TCP socket's writes as the event for the server to end its traffic loop
if (!isUDP(mSettings)) {
- tcp_shutdown();
+ if (!isIgnoreShutdown(mSettings)) {
+ tcp_shutdown();
+ }
now.setnow();
reportstruct->packetTime.tv_sec = now.getSecs();
reportstruct->packetTime.tv_usec = now.getUsecs();
@@ -1568,6 +1790,8 @@ void Client::FinishTrafficActions () {
*
*/
reportstruct->packetLen = totLen;
+ reportstruct->err_readwrite = WriteSuccess;
+ myReportPacket();
}
} else {
// stop timing
@@ -1593,7 +1817,7 @@ void Client::FinishTrafficActions () {
}
reportstruct->packetLen = 0;
}
- int do_close = EndJob(myJob, reportstruct);
+ bool do_close = EndJob(myJob, reportstruct);
if (isIsochronous(mSettings) && (myReport->info.schedule_error.cnt > 2)) {
fprintf(stderr,"%sIsoch schedule errors (mean/min/max/stdev) = %0.3f/%0.3f/%0.3f/%0.3f ms\n",mSettings->mTransferIDStr, \
((myReport->info.schedule_error.sum / myReport->info.schedule_error.cnt) * 1e-3), (myReport->info.schedule_error.min * 1e-3), \
@@ -1632,6 +1856,7 @@ void Client::AwaitServerFinPacket () {
struct timeval timeout;
int ack_success = 0;
int count = RETRYCOUNT;
+ static int read_warn_rate_limiter = 3; // rate limit read warn msgs
while (--count >= 0) {
// wait until the socket is readable, or our timeout expires
FD_ZERO(&readSet);
@@ -1664,8 +1889,16 @@ void Client::AwaitServerFinPacket () {
continue;
}
}
-
- WARN_errno(rc < 0, "read");
+ // only warn when threads is small, too many warnings are too much outputs
+ if (rc < 0 && (--read_warn_rate_limiter > 0)) {
+ int len = snprintf(NULL, 0, "%sRead UDP fin", mSettings->mTransferIDStr);
+ char *tmpbuf = (char *)calloc(1, len + 2);
+ if (tmpbuf) {
+ len = snprintf(tmpbuf, len + 1, "%sRead UDP fin", mSettings->mTransferIDStr);
+ WARN_errno(1, tmpbuf);
+ free(tmpbuf);
+ }
+ }
if (rc > 0) {
ack_success = 1;
#ifdef HAVE_THREAD_DEBUG
@@ -1682,32 +1915,23 @@ void Client::AwaitServerFinPacket () {
fprintf(stderr, warn_no_ack, mySocket, (isModeTime(mSettings) ? 10 : 1));
}
-
-void Client::PostNullEvent (void) {
+// isFirst indicates first event occurred per wait_tick
+void Client::PostNullEvent (bool isFirst, bool select_retry) {
assert(myReport!=NULL);
// push a nonevent into the packet ring
// this will cause the reporter to process
// up to this event
- memset(reportstruct, 0, sizeof(struct ReportStruct));
+ struct ReportStruct report_nopacket;
+ memset(&report_nopacket, 0, sizeof(struct ReportStruct));
now.setnow();
- reportstruct->packetTime.tv_sec = now.getSecs();
- reportstruct->packetTime.tv_usec = now.getUsecs();
- reportstruct->emptyreport=1;
- myReportPacket();
-}
-
-void Client::PostNullEvent (bool isFirst) {
- assert(myReport!=NULL);
- // push a nonevent into the packet ring
- // this will cause the reporter to process
- // up to this event
- memset(reportstruct, 0, sizeof(struct ReportStruct));
- now.setnow();
- reportstruct->packetTime.tv_sec = now.getSecs();
- reportstruct->packetTime.tv_usec = now.getUsecs();
- reportstruct->emptyreport=1;
- reportstruct->scheduled = isFirst;
- myReportPacket();
+ report_nopacket.packetTime.tv_sec = now.getSecs();
+ report_nopacket.packetTime.tv_usec = now.getUsecs();
+ report_nopacket.emptyreport = true;
+ report_nopacket.scheduled = isFirst;
+ report_nopacket.packetID = 0;
+ report_nopacket.err_readwrite = (select_retry ? WriteSelectRetry : WriteNoAccount);
+ reportstruct->packetTime = report_nopacket.packetTime; // needed for the InProgress loop test
+ myReportPacket(&report_nopacket);
}
// The client end timer is based upon the final fin, fin-ack w/the server
@@ -1717,7 +1941,7 @@ void Client::PostNullEvent (bool isFirst) {
#define MINAWAITCLOSEUSECS 2000000
void Client::AwaitServerCloseEvent () {
// the await detection can take awhile so post a non event ahead of it
- PostNullEvent();
+ PostNullEvent(false,false);
unsigned int amount_usec = \
(isModeTime(mSettings) ? static_cast<int>(mSettings->mAmount * 10000) : MINAWAITCLOSEUSECS);
if (amount_usec < MINAWAITCLOSEUSECS)
@@ -1739,6 +1963,9 @@ void Client::AwaitServerCloseEvent () {
int Client::SendFirstPayload () {
int pktlen = 0;
if (!isConnectOnly(mSettings)) {
+ if (isUDP(mSettings) && (mSettings->sendfirst_pacing > 0)) {
+ delay_loop(mSettings->sendfirst_pacing);
+ }
if (myReport && !TimeZero(myReport->info.ts.startTime) && !(mSettings->mMode == kTest_TradeOff)) {
reportstruct->packetTime = myReport->info.ts.startTime;
} else {
@@ -1746,7 +1973,7 @@ int Client::SendFirstPayload () {
reportstruct->packetTime.tv_sec = now.getSecs();
reportstruct->packetTime.tv_usec = now.getUsecs();
}
- pattern(mSettings->mBuf, mSettings->mBufLen);
+
if (isTxStartTime(mSettings)) {
pktlen = Settings_GenerateClientHdr(mSettings, (void *) mSettings->mBuf, mSettings->txstart_epoch);
} else {
@@ -1766,6 +1993,9 @@ int Client::SendFirstPayload () {
#endif
apply_first_udppkt_delay = true;
} else {
+ // Set the send timeout for the very first write which has the test exchange
+ int sosndtimer = DEFAULT_TESTEXCHANGETIMEOUT; //in usecs
+ SetSocketOptionsSendTimeout(mSettings, sosndtimer);
#if HAVE_DECL_TCP_NODELAY
if (!isNoDelay(mSettings) && isPeerVerDetect(mSettings) && isTripTime(mSettings)) {
int optflag=1;
@@ -1781,9 +2011,19 @@ int Client::SendFirstPayload () {
#else
pktlen = send(mySocket, mSettings->mBuf, pktlen, 0);
#endif
+ SetSocketOptionsSendTimeout(mSettings, mSettings->sosndtimer);
if (isPeerVerDetect(mSettings) && !isServerReverse(mSettings)) {
PeerXchange();
}
+ if (!isFileInput(mSettings)) {
+ int buflen = (mSettings->mBufLen < (int) sizeof(struct client_tcp_testhdr)) ? mSettings->mBufLen \
+ : sizeof(struct client_tcp_testhdr);
+ if (isTripTime(mSettings)) {
+ memset(mSettings->mBuf, 0xA5, buflen);
+ } else {
+ pattern(mSettings->mBuf, buflen); // reset the pattern in the payload for future writes
+ }
+ }
#if HAVE_DECL_TCP_NODELAY
if (!isNoDelay(mSettings) && isPeerVerDetect(mSettings) && isTripTime(mSettings)) {
int optflag=0;
@@ -1833,22 +2073,15 @@ void Client::PeerXchange () {
/*
* BarrierClient allows for multiple stream clients to be syncronized
*/
-int Client::BarrierClient (struct BarrierMutex *barrier) {
- int last = 0;
+#define BARRIER_MIN 100 // units is seconds to inform the server
+bool Client::BarrierClient (struct BarrierMutex *barrier) {
+ bool last = false;
#ifdef HAVE_THREAD
assert(barrier != NULL);
+ Timestamp now;
Condition_Lock(barrier->await);
if (--barrier->count <= 0) {
- // store the barrier release timer
-#ifdef HAVE_CLOCK_GETTIME
- struct timespec t1;
- clock_gettime(CLOCK_REALTIME, &t1);
- barrier->release_time.tv_sec = t1.tv_sec;
- barrier->release_time.tv_usec = t1.tv_nsec / 1000;
-#else
- gettimeofday(&barrier->release_time, NULL);
-#endif
- last = 1;
+ last = true;
// last one wake's up everyone else
Condition_Broadcast(&barrier->await);
#ifdef HAVE_THREAD_DEBUG
@@ -1858,14 +2091,25 @@ int Client::BarrierClient (struct BarrierMutex *barrier) {
#ifdef HAVE_THREAD_DEBUG
thread_debug("Barrier WAIT on condition %p count=%d", (void *)&barrier->await, barrier->count);
#endif
- Condition_Wait(&barrier->await);
+ if (isModeTime(mSettings)) {
+ int barrier_wait_secs = int(mSettings->mAmount / 100); // convert from 10 ms to seconds
+ if (barrier_wait_secs <= 0)
+ barrier_wait_secs = 1;
+ Condition_TimedWait(&barrier->await, barrier_wait_secs);
+ } else {
+ Condition_Wait(&barrier->await);
+ }
}
Condition_Unlock(barrier->await);
#ifdef HAVE_THREAD_DEBUG
thread_debug("Barrier EXIT on condition %p", (void *)&barrier->await);
#endif
+ mSettings->barrier_time = now.delta_usec();
+ if (mSettings->barrier_time < BARRIER_MIN) {
+ mSettings->barrier_time = 0;
+ }
#else
- last = 1;
+ last = true;
#endif // HAVE_THREAD
return last;
}
diff --git a/src/Launch.cpp b/src/Launch.cpp
index 9f0c633..721f95e 100644
--- a/src/Launch.cpp
+++ b/src/Launch.cpp
@@ -167,7 +167,7 @@ void server_spawn(struct thread_Settings *thread) {
}
static void clientside_client_basic (struct thread_Settings *thread, Client *theClient) {
- setTransferID(thread, 0);
+ setTransferID(thread, NORMAL);
#ifdef HAVE_THREAD_DEBUG
if (isBounceBack(thread)) {
thread_debug("Launch: spawn client bounce-back mode, size = %d", thread->mBurstSize);
@@ -176,24 +176,12 @@ static void clientside_client_basic (struct thread_Settings *thread, Client *the
}
#endif
SockAddr_remoteAddr(thread);
- // Bounceback start delays the connect too
- if (isBounceBack(thread)) {
- if (isTxStartTime(thread)) {
- theClient->mySockInit();
- clock_usleep_abstime(&thread->txstart_epoch);
- } else if (isTxHoldback(thread)) {
- unsetTxHoldback(thread);
- theClient->mySockInit();
- clock_usleep(&thread->txholdback_timer);
- }
- }
- theClient->my_connect(true);
+ theClient->my_connect(false);
if ((thread->mThreads > 1) && !isNoConnectSync(thread) && !isCompat(thread))
// When -P > 1 then all threads finish connect before starting traffic
theClient->BarrierClient(thread->connects_done);
if (theClient->isConnected()) {
- if ((thread->mThreads > 1) || isSumOnly(thread))
- Iperf_push_host(thread);
+ Iperf_push_host(thread);
theClient->StartSynch();
theClient->Run();
}
@@ -201,9 +189,9 @@ static void clientside_client_basic (struct thread_Settings *thread, Client *the
static void clientside_client_reverse (struct thread_Settings *thread, \
struct thread_Settings *reverse_client, Client *theClient) {
- setTransferID(thread, 0);
+ setTransferID(thread, NORMAL);
SockAddr_remoteAddr(thread);
- theClient->my_connect(true);
+ theClient->my_connect(false);
#ifdef HAVE_THREAD_DEBUG
thread_debug("Launch: client spawn thread reverse (sock=%d)", thread->mSock);
#endif
@@ -212,7 +200,7 @@ static void clientside_client_reverse (struct thread_Settings *thread, \
theClient->BarrierClient(thread->connects_done);
if (theClient->isConnected()) {
FAIL((!reverse_client || !(thread->mSock > 0)), "Reverse test failed to start per thread settings or socket problem", thread);
- setTransferID(reverse_client, 1);
+ setTransferID(reverse_client, REVERSED);
theClient->StartSynch();
reverse_client->mSock = thread->mSock; // use the same socket for both directions
reverse_client->mThreadMode = kMode_Server;
@@ -220,8 +208,7 @@ static void clientside_client_reverse (struct thread_Settings *thread, \
setNoUDPfin(reverse_client); // disable the fin report - no need
reverse_client->size_local = sizeof(iperf_sockaddr);
getsockname(reverse_client->mSock, reinterpret_cast<sockaddr*>(&reverse_client->local), &reverse_client->size_local);
- if ((thread->mThreads > 1) || isSumOnly(thread))
- Iperf_push_host(reverse_client);
+ Iperf_push_host(reverse_client);
thread_start(reverse_client);
if (theClient->myJob)
FreeReport(theClient->myJob);
@@ -230,20 +217,17 @@ static void clientside_client_reverse (struct thread_Settings *thread, \
static void clientside_client_fullduplex (struct thread_Settings *thread, \
struct thread_Settings *reverse_client, Client *theClient) {
- setTransferID(thread, 0);
+ setTransferID(thread, NORMAL);
SockAddr_remoteAddr(thread);
if (!isBounceBack(thread)) {
- thread->mFullDuplexReport = InitSumReport(thread, -1, 1);
+ thread->mFullDuplexReport = InitSumReport(thread, -1, true);
}
Settings_Copy(thread, &reverse_client, SHALLOW_COPY);
- if ((thread->mThreads > 1) || isSumOnly(thread) || \
- (!(thread->mThreads > 1) && !isEnhanced(thread))) {
- Iperf_push_host(thread);
- Iperf_push_host(reverse_client);
- }
+ Iperf_push_host(thread);
+ Iperf_push_host(reverse_client);
assert(reverse_client != NULL);
- setTransferID(reverse_client, 1);
- theClient->my_connect(true);
+ setTransferID(reverse_client, REVERSED);
+ theClient->my_connect(false);
#ifdef HAVE_THREAD_DEBUG
thread_debug("Launch: client spawn thread fullduplex (sock=%d)", thread->mSock);
#endif
@@ -270,7 +254,7 @@ static void serverside_client_fullduplex (struct thread_Settings *thread, Client
#ifdef HAVE_THREAD_DEBUG
thread_debug("Launch: Listener spawn client thread (fd sock=%d)", thread->mSock);
#endif
- setTransferID(thread, 1);
+ setTransferID(thread, REVERSED);
if (theClient->StartSynch() != -1) {
theClient->Run();
}
@@ -280,7 +264,7 @@ static void serverside_client_bidir (struct thread_Settings *thread, Client *the
#ifdef HAVE_THREAD_DEBUG
thread_debug("Launch: Listener spawn client thread (bidir sock=%d)", thread->mSock);
#endif
- setTransferID(thread, 1);
+ setTransferID(thread, REVERSED);
SockAddr_zeroAddress(&thread->peer);
SockAddr_remoteAddr(thread);
if (thread->mReportMode == kReport_CSV) {
@@ -324,7 +308,7 @@ void client_spawn (struct thread_Settings *thread) {
thread_setscheduler(thread);
#endif
// start up the client
- setTransferID(thread, 0);
+ setTransferID(thread, NORMAL);
theClient = new Client(thread);
// let the reporter thread go first in the case of -P greater than 1
Condition_Lock(reporter_state.await);
@@ -400,10 +384,21 @@ void client_init(struct thread_Settings *clients) {
if (isIncrSrcIP(clients) && (clients->mLocalhost != NULL)) {
next->incrsrcip = i;
}
+ if (isTxStartTime(clients)) {
+ // break apart -P first pkt sends by some usecs
+ // this allows the listener thread to spawn a server, connect() and open
+ // a new socket for subsequent threads. This issue is most
+ // notable with --tx-starttime and -P > 1
+ // use max cores & a max aggregate delay to limit this so it's bounded
+#define MAXCORES 10
+#define MAXDELAY 20000 // 20 ms
+ next->sendfirst_pacing = (i % MAXCORES) * (MAXDELAY / MAXCORES);
+ }
if (isIncrDstIP(clients)) {
next->incrdstip = i;
// force a setHostname
SockAddr_zeroAddress(&next->peer);
+ setNoSettReport(next);
} else if (clients->mBindPort) {
// Increment the source port of none of the quintuple is being change or the user requests it
if ((!isIncrDstPort(clients) && !isIncrDstIP(clients) && !isIncrSrcIP(clients)) || isIncrSrcPort(clients)) {
@@ -419,11 +414,22 @@ void client_init(struct thread_Settings *clients) {
itr->runNow = next;
itr = next;
}
- if ((isBounceBack(clients) || isConnectOnly(clients) || isPeriodicBurst(clients)) \
- && (isWorkingLoadUp(clients) || isWorkingLoadDown(clients))) {
+ if (isWorkingLoadUp(clients) || isWorkingLoadDown(clients)) {
int working_load_threads = (clients->mWorkingLoadThreads == 0) ? 1 : clients->mWorkingLoadThreads;
while (working_load_threads--) {
Settings_Copy(clients, &next, DEEP_COPY);
+ if (isUDP(next)) {
+ unsetUDP(next);
+ unsetBWSet(next);
+ setNoSettReport(next);
+ next->mAppRate=0;
+ }
+ if (isLoadCCA(next)) {
+ unsetCongestionControl(next);
+ }
+ if (isIsochronous(next)) {
+ unsetIsochronous(next);
+ }
if (next != NULL) {
unsetBounceBack(next);
unsetConnectOnly(next);
@@ -439,15 +445,24 @@ void client_init(struct thread_Settings *clients) {
} else if (isWorkingLoadDown(clients)) {
setReverse(next);
}
- if (isBounceBack(clients) && (clients->mWorkingLoadThreads > 1)) {
- Iperf_push_host(clients);
- }
+ Iperf_push_host(clients);
// Bump the bounceback time to include the delay time
if (next->txholdback_timer.tv_sec || next->txholdback_timer.tv_usec) {
// mAmount units are 10 ms
next->mAmount += (next->txholdback_timer.tv_sec * 100);
next->mAmount += (next->txholdback_timer.tv_usec / 10000);
}
+ if (isLoadCCA(next)) {
+ char *tmp = new char[strlen(next->mLoadCCA) + 1];
+ if (tmp) {
+ if (next->mCongestion)
+ DELETE_ARRAY(next->mCongestion);
+ setCongestionControl(next);
+ strcpy(tmp, next->mLoadCCA);
+ tmp[strlen(next->mLoadCCA)] = '\0';
+ next->mCongestion = tmp;
+ }
+ }
itr->runNow = next;
itr = next;
}
@@ -475,4 +490,16 @@ void listeners_init(struct thread_Settings *listener) {
itr = next;
}
}
+ // See if a working load TCP listener is needed
+ if (isUDP(listener) && (isWorkingLoadUp(listener) || isWorkingLoadDown(listener))) {
+ Settings_Copy(listener, &next, DEEP_COPY);
+ if (next != NULL) {
+ unsetUDP(next);
+ next->mAppRate = 0;
+ unsetBWSet(next);
+ setNoSettReport(next);
+ itr->runNow = next;
+ itr = next;
+ }
+ }
}
diff --git a/src/Listener.cpp b/src/Listener.cpp
index a517cbc..c6ea969 100644
--- a/src/Listener.cpp
+++ b/src/Listener.cpp
@@ -1,16 +1,15 @@
/*---------------------------------------------------------------
- * Copyright (c) 1999,2000,2001,2002,2003
- * The Board of Trustees of the University of Illinois
- * All Rights Reserved.
- *---------------------------------------------------------------
+ * Copyright (c) 1999,2000,2001,2002,2003 The Board of Trustees of the
+ * University of Illinois All Rights Reserved.
+ * ---------------------------------------------------------------
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software (Iperf) and associated
* documentation files (the "Software"), to deal in the Software
- * without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute,
- * sublicense, and/or sell copies of the Software, and to permit
- * persons to whom the Software is furnished to do
- * so, subject to the following conditions:
+ * without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
*
*
* Redistributions of source code must retain the above
@@ -139,7 +138,8 @@ void Listener::Run () {
}
if (!isUDP(mSettings)) {
// TCP needs just one listen
- my_listen(); // This will set ListenSocket to a new sock fd
+ if (!my_listen()) // This will set ListenSocket to a new sock fd
+ return;
}
bool mMode_Time = isServerModeTime(mSettings) && !isDaemon(mSettings);
if (mMode_Time) {
@@ -150,7 +150,9 @@ void Listener::Run () {
mEndTime.add(mSettings->mListenerTimeout);
}
Timestamp now;
+ bool need_listen = true;
#define SINGLECLIENTDELAY_DURATION 50000 // units is microseconds
+
while (!sInterupted && mCount) {
#ifdef HAVE_THREAD_DEBUG
thread_debug("Listener main loop port %d ", mSettings->mPort);
@@ -163,8 +165,8 @@ void Listener::Run () {
break;
}
// Serialize in the event the -1 option or --singleclient is set
- int tc;
- if ((isSingleClient(mSettings) || isMulticast(mSettings)) && \
+ int tc = 0;
+ if ((isSingleClient(mSettings) || (isUDP(mSettings) && isMulticast(mSettings))) && \
mCount && (tc = (thread_numtrafficthreads()) > 0)) {
// Start with a delay in the event some traffic
// threads are pending to be scheduled and haven't
@@ -178,9 +180,14 @@ void Listener::Run () {
#endif
continue;
}
- if (isUDP(mSettings)) {
+ // This will set ListenSocket to a new sock fd
+ if (isUDP(mSettings) && need_listen) {
// UDP needs a new listen per every new socket
- my_listen(); // This will set ListenSocket to a new sock fd
+ if (!my_listen()) {
+ break;
+ } else {
+ need_listen = false;
+ }
}
// Use a select() with a timeout if -t is set or if this is a v1 -r or -d test
fd_set set;
@@ -195,12 +202,6 @@ void Listener::Run () {
timeout.tv_sec = static_cast<long>(mSettings->mListenerTimeout);
timeout.tv_usec = (static_cast<long>(mSettings->mListenerTimeout) * 1000000) % 1000000;
}
- if (isTxStartTime(mSettings)) {
- now.setnow();
- long adjsecs = (mSettings->txstart_epoch.tv_sec - now.getSecs());
- if (adjsecs > 0)
- timeout.tv_sec += adjsecs + 1;
- }
FD_ZERO(&set);
FD_SET(ListenSocket, &set);
if (!(select(ListenSocket + 1, &set, NULL, NULL, &timeout) > 0)) {
@@ -234,7 +235,7 @@ void Listener::Run () {
Settings_Destroy(server);
continue;
}
-
+ need_listen = true;
#ifdef HAVE_THREAD_DEBUG
thread_debug("Listener thread accepted server sock=%d transferID", server->mSock, server->mTransferID);
#endif
@@ -309,7 +310,7 @@ void Listener::Run () {
if (isUDP(server) && isCompat(mSettings)) {
setSeqNo64b(server);
}
- setTransferID(server, 0);
+ setTransferID(server, NORMAL);
if ((mSettings->mReportMode == kReport_CSV) && server->mSumReport && !server->mSumReport->sum_reverse_set) {
format_ips_port_string(&server->mSumReport->info, 1);
server->mSumReport->sum_reverse_set = true;
@@ -334,7 +335,7 @@ void Listener::Run () {
if (listener_client_settings) {
if (server->mMode != kTest_Normal)
listener_client_settings->mTransferID = 0;
- setTransferID(listener_client_settings, 1);
+ setTransferID(listener_client_settings, REVERSED);
if (isFullDuplex(listener_client_settings) || isReverse(listener_client_settings))
Iperf_push_host(listener_client_settings);
if (isFullDuplex(server)) {
@@ -344,9 +345,9 @@ void Listener::Run () {
// now that it's know to be full duplex. This wasn't known
// during accept()
SetSumHandlers(server, server->mSumReport);
- server->mSumReport->sum_fd_set = 1;
+ server->mSumReport->sum_fd_set = true;
}
- server->mFullDuplexReport = InitSumReport(server, server->mSock, 1);
+ server->mFullDuplexReport = InitSumReport(server, server->mSock, true);
listener_client_settings->mFullDuplexReport = server->mFullDuplexReport;
#if HAVE_THREAD_DEBUG
thread_debug("FullDuplex report client=%p/%p server=%p/%p", (void *) listener_client_settings, (void *) listener_client_settings->mFullDuplexReport, (void *) server, (void *) server->mFullDuplexReport);
@@ -368,7 +369,7 @@ void Listener::Run () {
}
}
}
- setTransferID(server, 0);
+ setTransferID(server, NORMAL);
if (isConnectionReport(server) && !isSumOnly(server)) {
struct ReportHeader *reporthdr = InitConnectionReport(server);
struct ConnectionInfo *cr = static_cast<struct ConnectionInfo *>(reporthdr->this_report);
@@ -393,7 +394,7 @@ void Listener::Run () {
* wildcard server address, specifying what incoming interface to
* accept connections on.
* ------------------------------------------------------------------- */
-void Listener::my_listen () {
+bool Listener::my_listen () {
int rc;
int type;
int domain;
@@ -414,20 +415,13 @@ void Listener::my_listen () {
// for the case of L2 testing and UDP, a new AF_PACKET
// will be created to supercede this one
type = (isUDP(mSettings) ? SOCK_DGRAM : SOCK_STREAM);
- domain = (SockAddr_isIPv6(&mSettings->local) ?
-#if HAVE_IPV6
- AF_INET6
-#else
- AF_INET
-#endif
- : AF_INET);
+ domain = SockAddr_getAFdomain(&mSettings->local);
#ifdef WIN32
- if (SockAddr_isMulticast(&mSettings->local)) {
+ if (SockAddr_isMulticast(&mSettings->multicast_group)) {
// Multicast on Win32 requires special handling
ListenSocket = WSASocket(domain, type, 0, 0, 0, WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF);
WARN_errno(ListenSocket == INVALID_SOCKET, "socket");
-
} else
#endif
{
@@ -436,31 +430,46 @@ void Listener::my_listen () {
}
mSettings->mSock = ListenSocket;
SetSocketOptions(mSettings);
- // reuse the address, so we can run if a former server was killed off
- int boolean = 1;
- Socklen_t len = sizeof(boolean);
- rc = setsockopt(ListenSocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&boolean), len);
- // bind socket to server address
+ SetSocketBindToDeviceIfNeeded(mSettings);
+ rc = SOCKET_ERROR;
+ if (isUDP(mSettings) && SockAddr_isMulticast(&mSettings->multicast_group)) {
+#if HAVE_MULTICAST
#ifdef WIN32
- if (SockAddr_isMulticast(&mSettings->local)) {
// Multicast on Win32 requires special handling
- rc = WSAJoinLeaf(ListenSocket, (sockaddr*) &mSettings->local, mSettings->size_local,0,0,0,0,JL_BOTH);
+ rc = WSAJoinLeaf(ListenSocket, reinterpret_cast<sockaddr*> (&mSettings->local), mSettings->size_local,0,0,0,0,JL_BOTH);
WARN_errno(rc == SOCKET_ERROR, "WSAJoinLeaf (aka bind)");
- } else
+#else
+#if 0 && (HAVE_DECL_IP_ADD_MEMBERSHIP || HAVE_DECL_MCAST_JOIN_GROUP) // possible future, bind to all including unicast
+ iperf_sockaddr tmp;
+ memcpy(&tmp, &mSettings->local, sizeof(tmp));
+ SockAddr_setAddressAny(&tmp); // the multicast join will take care of this
+ rc = bind(ListenSocket, reinterpret_cast<sockaddr*>(&tmp), mSettings->size_local);
+ printf("***** any bind\n");
+#else
+ rc = bind(ListenSocket, reinterpret_cast<sockaddr*> (&mSettings->local), mSettings->size_local);
+// printf("***** single bind\n");
#endif
- {
- rc = bind(ListenSocket, reinterpret_cast<sockaddr*>(&mSettings->local), mSettings->size_local);
- FAIL_errno(rc == SOCKET_ERROR, "listener bind", mSettings);
+ FAIL_errno(rc == SOCKET_ERROR, "listener bind", mSettings);
+ // if UDP and multicast, join the group
+ if (iperf_multicast_join(mSettings) != IPERF_MULTICAST_JOIN_SUCCESS) {
+ rc = SOCKET_ERROR;
}
+#endif
+#else
+ fprintf(stderr, "Multicast not supported");
+#endif // HAVE_MULTICAST
+ } else {
+ // bind socket for unicast
+ rc = bind(ListenSocket, reinterpret_cast<sockaddr*>(&mSettings->local), mSettings->size_local);
+ }
+ FAIL_errno(rc == SOCKET_ERROR, "listener bind", mSettings);
}
-
// update the reporter thread
- if (isReport(mSettings) && isSettingsReport(mSettings)) {
- struct ReportHeader *report_settings = InitSettingsReport(mSettings);
- assert(report_settings != NULL);
- // disable future settings reports, listener should only do it once
- unsetReport(mSettings);
- PostReport(report_settings);
+ if (isSettingsReport(mSettings)) {
+ struct ReportHeader *tmp = InitSettingsReport(mSettings);
+ setNoSettReport(mSettings);
+ assert(tmp!=NULL);
+ PostReport(tmp);
}
// listen for connections (TCP only).
@@ -472,253 +481,10 @@ void Listener::my_listen () {
rc = listen(ListenSocket, INT_MAX);
}
WARN_errno(rc == SOCKET_ERROR, "listen");
- } else {
-#ifndef WIN32
- // if UDP and multicast, join the group
- if (SockAddr_isMulticast(&mSettings->local)) {
-#ifdef HAVE_MULTICAST
- my_multicast_join();
-#else
- fprintf(stderr, "Multicast not supported");
-#endif // HAVE_MULTICAST
- }
-#endif
}
+ return true;
} // end my_listen()
-/* -------------------------------------------------------------------
- * Joins the multicast group or source and group (SSM S,G)
- *
- * taken from: https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.1.0/com.ibm.zos.v2r1.hale001/ipv6d0141001708.htm
- *
- * Multicast function IPv4 IPv6 Protocol-independent
- * ================== ==== ==== ====================
- * Level of specified option on setsockopt()/getsockopt() IPPROTO_IP IPPROTO_IPV6 IPPROTO_IP or IPPROTO_IPV6
- * Join a multicast group IP_ADD_MEMBERSHIP IPV6_JOIN_GROUP MCAST_JOIN_GROUP
- * Leave a multicast group or leave all sources of that
- * multicast group IP_DROP_MEMBERSHIP IPV6_LEAVE_GROUP MCAST_LEAVE_GROUP
- * Select outbound interface for sending multicast datagrams IP_MULTICAST_IF IPV6_MULTICAST_IF NA
- * Set maximum hop count IP_MULTICAST_TTL IPV6_MULTICAST_HOPS NA
- * Enable multicast loopback IP_MULTICAST_LOOP IPV6_MULTICAST_LOOP NA
- * Join a source multicast group IP_ADD_SOURCE_MEMBERSHIP NA MCAST_JOIN_SOURCE_GROUP
- * Leave a source multicast group IP_DROP_SOURCE_MEMBERSHIP NA MCAST_LEAVE_SOURCE_GROUP
- * Block data from a source to a multicast group IP_BLOCK_SOURCE NA MCAST_BLOCK_SOURCE
- * Unblock a previously blocked source for a multicast group IP_UNBLOCK_SOURCE NA MCAST_UNBLOCK_SOURCE
- *
- *
- * Reminder: The os will decide which version of IGMP or MLD to use. This may be controlled by system settings, e.g.:
- *
- * [rmcmahon@lvnvdb0987:~/Code/ssm/iperf2-code] $ sysctl -a | grep mld | grep force
- * net.ipv6.conf.all.force_mld_version = 0
- * net.ipv6.conf.default.force_mld_version = 0
- * net.ipv6.conf.lo.force_mld_version = 0
- * net.ipv6.conf.eth0.force_mld_version = 0
- *
- * [rmcmahon@lvnvdb0987:~/Code/ssm/iperf2-code] $ sysctl -a | grep igmp | grep force
- * net.ipv4.conf.all.force_igmp_version = 0
- * net.ipv4.conf.default.force_igmp_version = 0
- * net.ipv4.conf.lo.force_igmp_version = 0
- * net.ipv4.conf.eth0.force_igmp_version = 0
- *
- * ------------------------------------------------------------------- */
-void Listener::my_multicast_join () {
- // This is the older mulitcast join code. Both SSM and binding the
- // an interface requires the newer socket options. Using the older
- // code here will maintain compatiblity with previous iperf versions
- if (!isSSMMulticast(mSettings) && !mSettings->mIfrname) {
- if (!SockAddr_isIPv6(&mSettings->local)) {
- struct ip_mreq mreq;
- memcpy(&mreq.imr_multiaddr, SockAddr_get_in_addr(&mSettings->local), \
- sizeof(mreq.imr_multiaddr));
- mreq.imr_interface.s_addr = htonl(INADDR_ANY);
- int rc = setsockopt(ListenSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
- reinterpret_cast<char*>(&mreq), sizeof(mreq));
- WARN_errno(rc == SOCKET_ERROR, "multicast join");
-#if HAVE_DECL_IP_MULTICAST_ALL
- int mc_all = 0;
- rc = setsockopt(ListenSocket, IPPROTO_IP, IP_MULTICAST_ALL, (void*) &mc_all, sizeof(mc_all));
- WARN_errno(rc == SOCKET_ERROR, "ip_multicast_all");
-#endif
- } else {
-#if (HAVE_IPV6 && HAVE_IPV6_MULTICAST && (HAVE_DECL_IPV6_JOIN_GROUP || HAVE_DECL_IPV6_ADD_MEMBERSHIP))
- struct ipv6_mreq mreq;
- memcpy(&mreq.ipv6mr_multiaddr, SockAddr_get_in6_addr(&mSettings->local), sizeof(mreq.ipv6mr_multiaddr));
- mreq.ipv6mr_interface = 0;
-#if HAVE_DECL_IPV6_JOIN_GROUP
- int rc = setsockopt(ListenSocket, IPPROTO_IPV6, IPV6_JOIN_GROUP, \
- reinterpret_cast<char*>(&mreq), sizeof(mreq));
-#else
- int rc = setsockopt(ListenSocket, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, \
- reinterpret_cast<char*>(&mreq), sizeof(mreq));
-#endif
- FAIL_errno(rc == SOCKET_ERROR, "multicast v6 join", mSettings);
-#else
- fprintf(stderr, "IPv6 multicast is not supported on this platform\n");
-#endif
- }
- } else {
- int rc;
-#ifdef HAVE_SSM_MULTICAST
- // Here it's either an SSM S,G multicast join or a *,G with an interface specifier
- // Use the newer socket options when these are specified
- socklen_t socklen = sizeof(struct sockaddr_storage);
- int iface=0;
-#ifdef HAVE_NET_IF_H
- /* Set the interface or any */
- if (mSettings->mIfrname) {
- iface = if_nametoindex(mSettings->mIfrname);
- FAIL_errno(!iface, "mcast if_nametoindex",mSettings);
- } else {
- iface = 0;
- }
-#endif
-
- if (isIPV6(mSettings)) {
-#if HAVE_IPV6_MULTICAST
- if (mSettings->mSSMMulticastStr) {
- struct group_source_req group_source_req;
- struct sockaddr_in6 *group;
- struct sockaddr_in6 *source;
-
- memset(&group_source_req, 0, sizeof(struct group_source_req));
-
- group_source_req.gsr_interface = iface;
- group=reinterpret_cast<struct sockaddr_in6*>(&group_source_req.gsr_group);
- source=reinterpret_cast<struct sockaddr_in6*>(&group_source_req.gsr_source);
- source->sin6_family = AF_INET6;
- group->sin6_family = AF_INET6;
- /* Set the group */
- rc=getsockname(ListenSocket,reinterpret_cast<struct sockaddr *>(group), &socklen);
- FAIL_errno(rc == SOCKET_ERROR, "mcast join source group getsockname",mSettings);
- group->sin6_port = 0; /* Ignored */
-
- /* Set the source, apply the S,G */
- rc=inet_pton(AF_INET6, mSettings->mSSMMulticastStr,&source->sin6_addr);
- FAIL_errno(rc != 1, "mcast v6 join source group pton",mSettings);
- source->sin6_port = 0; /* Ignored */
-#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
- source->sin6_len = group->sin6_len;
-#endif
- rc = -1;
-#if HAVE_DECL_MCAST_JOIN_SOURCE_GROUP
- rc = setsockopt(ListenSocket,IPPROTO_IPV6,MCAST_JOIN_SOURCE_GROUP, reinterpret_cast<const char *>(&group_source_req),
- sizeof(group_source_req));
-#endif
- FAIL_errno(rc == SOCKET_ERROR, "mcast v6 join source group",mSettings);
- } else {
- struct group_req group_req;
- struct sockaddr_in6 *group;
-
- memset(&group_req, 0, sizeof(struct group_req));
-
- group_req.gr_interface = iface;
- group=reinterpret_cast<struct sockaddr_in6*>(&group_req.gr_group);
- group->sin6_family = AF_INET6;
- /* Set the group */
- rc=getsockname(ListenSocket,reinterpret_cast<struct sockaddr *>(group), &socklen);
- FAIL_errno(rc == SOCKET_ERROR, "mcast v6 join group getsockname",mSettings);
- group->sin6_port = 0; /* Ignored */
- rc = -1;
-#if HAVE_DECL_MCAST_JOIN_GROUP
- rc = setsockopt(ListenSocket,IPPROTO_IPV6,MCAST_JOIN_GROUP, reinterpret_cast<const char *>(&group_req),
- sizeof(group_source_req));
-#endif
- FAIL_errno(rc == SOCKET_ERROR, "mcast v6 join group",mSettings);
- }
-#else
- fprintf(stderr, "Unfortunately, IPv6 multicast is not supported on this platform\n");
-#endif
- } else {
- if (mSettings->mSSMMulticastStr) {
- struct sockaddr_in *group;
- struct sockaddr_in *source;
-
- // Fill out both structures because we don't which one will succeed
- // and both may need to be tried
-#ifdef HAVE_STRUCT_IP_MREQ_SOURCE
- struct ip_mreq_source imr;
- memset (&imr, 0, sizeof (imr));
-#endif
-#ifdef HAVE_STRUCT_GROUP_SOURCE_REQ
- struct group_source_req group_source_req;
- memset(&group_source_req, 0, sizeof(struct group_source_req));
- group_source_req.gsr_interface = iface;
- group=reinterpret_cast<struct sockaddr_in*>(&group_source_req.gsr_group);
- source=reinterpret_cast<struct sockaddr_in*>(&group_source_req.gsr_source);
-#else
- struct sockaddr_in imrgroup;
- struct sockaddr_in imrsource;
- group = &imrgroup;
- source = &imrsource;
-#endif
- source->sin_family = AF_INET;
- group->sin_family = AF_INET;
- /* Set the group */
- rc=getsockname(ListenSocket,reinterpret_cast<struct sockaddr *>(group), &socklen);
- FAIL_errno(rc == SOCKET_ERROR, "mcast join source group getsockname",mSettings);
- group->sin_port = 0; /* Ignored */
-
- /* Set the source, apply the S,G */
- rc=inet_pton(AF_INET,mSettings->mSSMMulticastStr,&source->sin_addr);
- FAIL_errno(rc != 1, "mcast join source pton",mSettings);
-#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
- source->sin_len = group->sin_len;
-#endif
- source->sin_port = 0; /* Ignored */
- rc = -1;
-
-#if HAVE_DECL_MCAST_JOIN_SOURCE_GROUP
- rc = setsockopt(ListenSocket,IPPROTO_IP,MCAST_JOIN_SOURCE_GROUP, reinterpret_cast<const char *>(&group_source_req),
- sizeof(group_source_req));
-#endif
-
-#if HAVE_DECL_IP_ADD_SOURCE_MEMBERSHIP
-#ifdef HAVE_STRUCT_IP_MREQ_SOURCE
- // Some operating systems will have MCAST_JOIN_SOURCE_GROUP but still fail
- // In those cases try the IP_ADD_SOURCE_MEMBERSHIP
- if (rc < 0) {
-#ifdef HAVE_STRUCT_IP_MREQ_SOURCE_IMR_MULTIADDR_S_ADDR
- imr.imr_multiaddr = ((const struct sockaddr_in *)group)->sin_addr;
- imr.imr_sourceaddr = ((const struct sockaddr_in *)source)->sin_addr;
-#else
- // Some Android versions declare mreq_source without an s_addr
- imr.imr_multiaddr = ((const struct sockaddr_in *)group)->sin_addr.s_addr;
- imr.imr_sourceaddr = ((const struct sockaddr_in *)source)->sin_addr.s_addr;
-#endif
- rc = setsockopt (ListenSocket, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, reinterpret_cast<char*>(&imr), sizeof (imr));
- }
-#endif
-#endif
- FAIL_errno(rc == SOCKET_ERROR, "mcast join source group",mSettings);
- } else {
- struct group_req group_req;
- struct sockaddr_in *group;
-
- memset(&group_req, 0, sizeof(struct group_req));
-
- group_req.gr_interface = iface;
- group=reinterpret_cast<struct sockaddr_in*>(&group_req.gr_group);
- group->sin_family = AF_INET;
- /* Set the group */
- rc=getsockname(ListenSocket,reinterpret_cast<struct sockaddr *>(group), &socklen);
- FAIL_errno(rc == SOCKET_ERROR, "mcast join group getsockname",mSettings);
- group->sin_port = 0; /* Ignored */
- rc = -1;
-#if HAVE_DECL_MCAST_JOIN_GROUP
- rc = setsockopt(ListenSocket,IPPROTO_IP,MCAST_JOIN_GROUP, reinterpret_cast<const char *>(&group_req),
- sizeof(group_source_req));
-#endif
- FAIL_errno(rc == SOCKET_ERROR, "mcast join group",mSettings);
- }
- }
-
-#else
- fprintf(stderr, "Unfortunately, SSM is not supported on this platform\n");
- exit(-1);
-#endif
- }
-}
-// end my_multicast_join()
bool Listener::L2_setup (thread_Settings *server, int sockfd) {
#if defined(HAVE_LINUX_FILTER_H) && defined(HAVE_AF_PACKET)
@@ -905,6 +671,7 @@ int Listener::udp_accept (thread_Settings *server) {
// most likely not a new client thread requiring a new server thread, but remnants of an
// old one that already ended. Hence, the Listener should ignore "first packets" when
// they have negative seq numbers.
+ RETRYREAD:
do {
packetID = 0;
nread = recvfrom(ListenSocket, server->mBuf, server->mBufLen, 0, \
@@ -925,22 +692,12 @@ int Listener::udp_accept (thread_Settings *server) {
Timestamp now;
server->accept_time.tv_sec = now.getSecs();
server->accept_time.tv_usec = now.getUsecs();
-#if HAVE_THREAD_DEBUG
- {
- char tmpaddr[200];
- size_t len=200;
- unsigned short port = SockAddr_getPort(&server->peer);
- SockAddr_getHostAddress(&server->peer, tmpaddr, len);
- thread_debug("rcvfrom peer: %s port %d len=%d", tmpaddr, port, nread);
- }
-#endif
- // Handle connection for UDP sockets
- int gid = Iperf_push_host_port_conditional(server);
-#if HAVE_THREAD_DEBUG
- if (gid < 0)
- thread_debug("rcvfrom peer: drop duplicate");
-#endif
- if (gid > 0) {
+ // Drop duplicates, may need to use a BPF drop for better performance
+ // or ebfs
+ if (!Iperf_push_host(server)) {
+ packetID = 0;
+ goto RETRYREAD;
+ } else {
int rc;
// We have a new UDP flow (based upon key of quintuple)
// so let's hand off this socket
@@ -953,11 +710,28 @@ int Listener::udp_accept (thread_Settings *server) {
// This connect() routing is only supported with AF_INET or AF_INET6 sockets,
// e.g. AF_PACKET sockets can't do this. We'll handle packet sockets later
// All UDP accepts here will use AF_INET. This is intentional and needed
- rc = connect(server->mSock, reinterpret_cast<struct sockaddr*>(&server->peer), server->size_peer);
- FAIL_errno(rc == SOCKET_ERROR, "connect UDP", mSettings);
- server->size_local = sizeof(iperf_sockaddr);
- getsockname(server->mSock, reinterpret_cast<sockaddr*>(&server->local), &server->size_local);
- SockAddr_Ifrname(server);
+ if (!isMulticast(server)) {
+ rc = connect(server->mSock, reinterpret_cast<struct sockaddr*>(&server->peer), server->size_peer);
+ FAIL_errno(rc == SOCKET_ERROR, "connect UDP", mSettings);
+ server->size_local = sizeof(iperf_sockaddr);
+ getsockname(server->mSock, reinterpret_cast<sockaddr*>(&server->local), &server->size_local);
+ SockAddr_Ifrname(server);
+ } else {
+ server->size_multicast_group = sizeof(iperf_sockaddr);
+ iperf_sockaddr sent_dstaddr;
+ getsockname(server->mSock, reinterpret_cast<sockaddr*>(&sent_dstaddr), &server->size_multicast_group);
+ int join_send_match = SockAddr_Hostare_Equal(&sent_dstaddr, &server->multicast_group);
+#if DEBUG_MCAST
+ char joinaddr[200];
+ char pktaddr[200];
+ size_t len=200;
+ SockAddr_getHostAddress(&sent_dstaddr, joinaddr, len);
+ SockAddr_getHostAddress(&server->multicast_group, pktaddr, len);
+ printf("mcast(%d): join addr %s pkt group addr %s\n", join_send_match, joinaddr, pktaddr);
+#endif
+ WARN(!join_send_match, "mcast join and packet group addr");
+ // RJM - use a cmesg to read the interface name
+ }
server->firstreadbytes = nread;
}
}
@@ -1046,8 +820,12 @@ bool Listener::apply_client_settings (thread_Settings *server) {
bool rc = false;
// Set the receive timeout for the very first read
- int sorcvtimer = TESTEXCHANGETIMEOUT; // 4 sec in usecs
- SetSocketOptionsReceiveTimeout(server, sorcvtimer);
+ if (mSettings->mListenerTimeout >= 0) {
+ SetSocketOptionsReceiveTimeout(server, (int) (mSettings->mListenerTimeout * 1000000));
+ } else {
+ int sorcvtimer = DEFAULT_TESTEXCHANGETIMEOUT; // in usecs
+ SetSocketOptionsReceiveTimeout(server, sorcvtimer);
+ }
server->peer_version_u = 0;
server->peer_version_l = 0;
server->mMode = kTest_Normal;
@@ -1111,26 +889,39 @@ bool Listener::apply_client_settings_udp (thread_Settings *server) {
#if HAVE_THREAD_DEBUG
thread_debug("UDP small header");
#endif
+ struct client_udpsmall_testhdr *smallhdr = reinterpret_cast<struct client_udpsmall_testhdr *>(server->mBuf + server->l4payloadoffset);
server->sent_time.tv_sec = ntohl(hdr->seqno_ts.tv_sec);
server->sent_time.tv_usec = ntohl(hdr->seqno_ts.tv_usec);
+ server->txstart_epoch.tv_sec = ntohl(smallhdr->start_tv_sec);
+ server->txstart_epoch.tv_usec = ntohl(smallhdr->start_tv_usec);
uint32_t seqno = ntohl(hdr->seqno_ts.id);
+ if (server->txstart_epoch.tv_sec > 0) {
+ setTxStartTime(server);
+ }
if (seqno != 1) {
fprintf(stderr, "WARN: first received packet (id=%d) was not first sent packet, report start time will be off\n", seqno);
}
Timestamp now;
if (!isTxStartTime(server) && ((abs(now.getSecs() - server->sent_time.tv_sec)) > (MAXDIFFTIMESTAMPSECS + 1))) {
- fprintf(stdout,"WARN: ignore --trip-times because client didn't provide valid start timestamp within %d seconds of now\n", MAXDIFFTIMESTAMPSECS);
+ fprintf(stdout,"WARN: ignore --trip-times because client didn't provide valid start timestamp within %d seconds of now (now=%ld send=%ld)\n", MAXDIFFTIMESTAMPSECS, now.getSecs(), server->sent_time.tv_sec);
unsetTripTime(server);
} else {
setTripTime(server);
}
setEnhanced(server);
} else if ((flags & HEADER_VERSION1) || (flags & HEADER_VERSION2) || (flags & HEADER_EXTEND)) {
- if ((flags & HEADER_VERSION1) && !(flags & HEADER_VERSION2)) {
- if (flags & RUN_NOW)
- server->mMode = kTest_DualTest;
- else
- server->mMode = kTest_TradeOff;
+ if (flags & HEADER_VERSION1) {
+ uint32_t tidthreads = ntohl(hdr->base.numThreads);
+ if (tidthreads & HEADER_HASTRANSFERID) {
+ tidthreads &= (~HEADER_HASTRANSFERID & HEADER_TRANSFERIDMASK);
+ server->mPeerTransferID = tidthreads >> HEADER_TRANSFERIDSHIFT;
+ setSyncTransferID(server);
+ } else if (!(flags & HEADER_VERSION2)) {
+ if (flags & RUN_NOW)
+ server->mMode = kTest_DualTest;
+ else
+ server->mMode = kTest_TradeOff;
+ }
}
if (flags & HEADER_EXTEND) {
upperflags = htons(hdr->extend.upperflags);
@@ -1234,6 +1025,18 @@ bool Listener::apply_client_settings_tcp (thread_Settings *server) {
}
readptr += nread;
server->mBounceBackBytes = ntohl(bbhdr->bbsize);
+ if (server->mBounceBackBytes > server->mBufLen) {
+ if (isBuflenSet(server)) {
+ WARN(1, "Buffer length (-l) too small for bounceback request. Increase -l size or don't set (for auto-adjust)");
+ rc = false;
+ goto DONE;
+ } else {
+ int read_offset = readptr - server->mBuf;
+ Settings_Grow_mBuf(server, server->mBounceBackBytes);
+ readptr = server->mBuf + read_offset;
+ bbhdr = reinterpret_cast<struct bounceback_hdr *>(server->mBuf);
+ }
+ }
server->mBounceBackHold = ntohl(bbhdr->bbhold);
uint16_t bbflags = ntohs(bbhdr->bbflags);
if (bbflags & HEADER_BBCLOCKSYNCED) {
@@ -1249,6 +1052,23 @@ bool Listener::apply_client_settings_tcp (thread_Settings *server) {
setTcpQuickAck(server);
}
#endif
+ if (bbflags & HEADER_BBREPLYSIZE) {
+ server->mBounceBackReplyBytes = ntohl(bbhdr->bbreplysize);
+ } else {
+ server->mBounceBackReplyBytes = server->mBounceBackBytes;
+ }
+ if (server->mBounceBackReplyBytes > server->mBufLen) {
+ if (isBuflenSet(server)) {
+ WARN(1, "Buffer length (-l) too small for bounceback reply. Increase -l size or don't set (for auto-adjust)");
+ rc = false;
+ goto DONE;
+ } else {
+ int read_offset = readptr - server->mBuf;
+ Settings_Grow_mBuf(server, server->mBounceBackReplyBytes);
+ readptr = server->mBuf + read_offset;
+ bbhdr = reinterpret_cast<struct bounceback_hdr *>(server->mBuf);
+ }
+ }
int remaining = server->mBounceBackBytes - (sizeof(struct bounceback_hdr) + sizeof(uint32_t));
if (remaining < 0) {
WARN(1, "bounce back bytes too small");
@@ -1267,9 +1087,15 @@ bool Listener::apply_client_settings_tcp (thread_Settings *server) {
bbhdr->bbserverRx_ts.usec = htonl(now.getUsecs());
} else {
uint16_t upperflags = 0;
+ uint16_t lowerflags = 0;
int readlen;
// figure out the length of the test header
if ((readlen = Settings_ClientTestHdrLen(flags, server)) > 0) {
+ if (readlen > (server->mBufLen - nread)) {
+ WARN(1, "read tcp header too large");
+ rc = false;
+ goto DONE;
+ }
// read the test settings passed to the server by the client
nread += recvn(server->mSock, readptr, (readlen - (int) sizeof(uint32_t)), 0);
FAIL_errno((nread < readlen), "read tcp test info", server);
@@ -1285,14 +1111,22 @@ bool Listener::apply_client_settings_tcp (thread_Settings *server) {
}
server->firstreadbytes = nread;
struct client_tcp_testhdr *hdr = reinterpret_cast<struct client_tcp_testhdr*>(server->mBuf);
- if ((flags & HEADER_VERSION1) && !(flags & HEADER_VERSION2)) {
- if (flags & RUN_NOW)
- server->mMode = kTest_DualTest;
- else
- server->mMode = kTest_TradeOff;
+ if (flags & HEADER_VERSION1) {
+ uint32_t tidthreads = ntohl(hdr->base.numThreads);
+ if (tidthreads & HEADER_HASTRANSFERID) {
+ tidthreads &= (~HEADER_HASTRANSFERID & HEADER_TRANSFERIDMASK);
+ server->mPeerTransferID = tidthreads >> HEADER_TRANSFERIDSHIFT;
+ setSyncTransferID(server);
+ } else if (!(flags & HEADER_VERSION2)) {
+ if (flags & RUN_NOW)
+ server->mMode = kTest_DualTest;
+ else
+ server->mMode = kTest_TradeOff;
+ }
}
if (flags & HEADER_EXTEND) {
upperflags = htons(hdr->extend.upperflags);
+ lowerflags = htons(hdr->extend.lowerflags);
server->mTOS = ntohs(hdr->extend.tos);
server->peer_version_u = ntohl(hdr->extend.version_u);
server->peer_version_l = ntohl(hdr->extend.version_l);
@@ -1335,6 +1169,30 @@ bool Listener::apply_client_settings_tcp (thread_Settings *server) {
server->mFPS = 1.0;
}
}
+ if ((lowerflags & HEADER_CCA) && !isCongestionControl(server)) {
+#if HAVE_DECL_TCP_CONGESTION
+ int ccalen = ntohs(hdr->cca.cca_length);
+ setCongestionControl(server);
+ setEnhanced(server);
+ server->mCongestion = new char[ccalen+1];
+ if (server->mCongestion) {
+ strncpy(server->mCongestion, hdr->cca.value, ccalen);
+ server->mCongestion[ccalen] = '\0';
+ Socklen_t len = strlen(server->mCongestion) + 1;
+ int rc = setsockopt(server->mSock, IPPROTO_TCP, TCP_CONGESTION,
+ server->mCongestion, len);
+ if (rc == SOCKET_ERROR) {
+ fprintf(stderr, "Attempt to set '%s' congestion control failed: %s\n",
+ server->mCongestion, strerror(errno));
+ unsetCongestionControl(server);
+ DELETE_ARRAY(server->mCongestion);
+ }
+ }
+#endif
+ }
+ if (lowerflags & HEADER_BARRIER_TIME) {
+ server->barrier_time = ntohl(hdr->extend.barrier_usecs);
+ }
if (flags & HEADER_VERSION2) {
if (upperflags & HEADER_FULLDUPLEX) {
setFullDuplex(server);
diff --git a/src/Locale.c b/src/Locale.c
index 09333b0..34c82dd 100644
--- a/src/Locale.c
+++ b/src/Locale.c
@@ -50,8 +50,25 @@
* -------------------------------------------------------------------
* Strings and other stuff that is locale specific.
* ------------------------------------------------------------------- */
+
+/* Format specifiers per inttypes.h
+ *
+ * macro description example
+ * PRIxMAX printf specifier for intmax_t PRIiMAX is the equivalent of i (in "%i") for intmax_t values
+ * PRIxN printf specifier for intN_t PRId16 is the equivalent of d (in "%d") for int16_t values
+ * PRIxLEASTN printf specifier for int_leastN_t PRIuLEAST32 is the equivalent of u (in "%u") for uint32_t values
+ * PRIxFASTN printf specifier for int_fastN_t PRIxFAST8 is the equivalent of x (in "%x") for uint8_t values
+ * PRIxPTR printf specifier for intptr_t PRIuPTR is the equivalent of u (in "%u") for uintptr_t values
+ *
+ Where:
+ * x is one of d, i, o,u or x (for the printf specifiers this can also be an uppercase X).*
+ * N is 8, 16, 32, 64, or any other type width supported by the library in <cstdint>.
+ * * The specifier assumes the type to be signed for i and d, and unsigned for o, u, x and X.
+ */
+
#include "headers.h"
#include "version.h"
+#include "gettcpinfo.h"
#ifdef __cplusplus
extern "C" {
@@ -73,12 +90,14 @@ Client/Server:\n\
-e, --enhanced use enhanced reporting giving more tcp/udp and traffic information\n\
-f, --format [kmgKMG] format to report: Kbits, Mbits, KBytes, MBytes\n\
--hide-ips hide ip addresses and host names within outputs\n\
+ --histograms enable histograms (see client or server for more)\n\
-i, --interval # seconds between periodic bandwidth reports\n\
-l, --len #[kmKM] length of buffer in bytes to read or write (Defaults: TCP=128K, v4 UDP=1470, v6 UDP=1450)\n\
-m, --print_mss print TCP maximum segment size\n\
-o, --output <filename> output the report or error message to this specified file\n\
-p, --port # client/server port to listen/send on and to connect\n\
--permit-key permit key to be used to verify client and server (TCP only)\n\
+ --tcp-tx-delay set transmit delay\n\
--sum-only output sum only reports\n\
-u, --udp use UDP rather than TCP\n\
--utc use coordinated universal time (UTC) with time output\n\
@@ -102,6 +121,7 @@ Server specific:\n\
--jitter-histograms enable jitter histograms\n\
--permit-key-timeout set the timeout for a permit key in seconds\n\
--tcp-rx-window-clamp set the TCP receive window clamp size in bytes\n\
+ --test-exchange-timeout set the timeout on the test exchange, use 0 for no timeout\n\
--tap-dev #[<dev>] use TAP device to receive at L2 layer\n\
-t, --time # time in seconds to listen for new connections as well as to receive traffic (default not set)\n\
-B, --bind <ip>[%<dev>] bind to multicast address and optional device\n\
@@ -119,25 +139,34 @@ const char usage_long2[] = "\
Client specific:\n\
--bounceback request a bounceback test (use -l for size, defaults to 100 bytes)\n\
--bounceback-hold request the server to insert a delay of n milliseconds between its read and write\n\
- --bounceback-period request the client schedule a send every n milliseconds\n\
--bounceback-no-quickack request the server not set the TCP_QUICKACK socket option (disabling TCP ACK delays) during a bounceback test\n\
+ --bounceback-period request the client schedule a send every n milliseconds\n \
+ --bounceback-reply set the bounceback reply message size (defaults to symmetric)\n \
+ --bounceback-txdelay request the bounceback server delay n seconds between the request and the reply\n \
-c, --client <host> run in client mode, connecting to <host>\n\
--connect-only run a connect only test\n\
- --connect-retries # number of times to retry tcp connect\n\
+ --connect-retry-timer minimum time interval in seconds between application level connect retries\n\
+ --connect-retry-time time interval in seconds to attempt application level connect retries \n\
+ --dscp set the DSCP field (masking ECN bits) in TOS byte\n\
-d, --dualtest Do a bidirectional test simultaneously (multiple sockets)\n\
--fq-rate #[kmgKMG] bandwidth to socket pacing\n\
+ --fq-rate-step #[kmgKMG] step value to socket pacing\n\
+ --fq-rate-step-interval #[kmgKMG] step interval (in seconds) for socket pacing\n\
--full-duplex run full duplex test using same socket\n\
- --ipg set the the interpacket gap (milliseconds) for packets within an isochronous frame\n\
- --isochronous <frames-per-second>:<mean>,<stddev> send traffic in bursts (frames - emulate video traffic)\n\
+ --histograms enable histograms for --tcp-write-times\n\
+ --ignore-shutdown don't wait on the TCP shutdown or close (fin & finack) rather use the final write as the ending event\n\
--incr-dstip Increment the destination ip with parallel (-P) traffic threads\n\
--incr-dstport Increment the destination port with parallel (-P) traffic threads\n\
--incr-srcip Increment the source ip with parallel (-P) traffic threads\n\
--incr-srcport Increment the source port with parallel (-P) traffic threads\n\
+ --ipg set the the interpacket gap (milliseconds) for packets within an isochronous frame\n\
+ --isochronous <frames-per-second>:<mean>,<stddev> send traffic in bursts (frames - emulate video traffic)\n\
--local-only Set don't route on socket\n\
--near-congestion=[w] Use a weighted write delay per the sampled TCP RTT (experimental)\n\
--no-connect-sync No sychronization after connect when -P or parallel traffic threads\n\
--no-udp-fin No final server to client stats at end of UDP test\n\
-n, --num #[kmgKMG] number of bytes to transmit (instead of -t)\n\
+ --sync-transfer-id pass the clients' transfer id(s) to the server so both will use the same id in their respective outputs\n\
-r, --tradeoff Do a fullduplexectional test individually\n\
--tcp-quickack set the socket's TCP_QUICKACK option (off by default)\n\
--tcp-write-prefetch set the socket's TCP_NOTSENT_LOWAT value in bytes and use event based writes\n\
@@ -160,7 +189,8 @@ Client specific:\n\
#endif
" -S, --tos IP DSCP or tos settings\n\
-T, --ttl # time-to-live, for multicast (default 1)\n\
- --working-load request a concurrent TCP stream\n\
+ --working-load request working load(s)\n\
+ --working-load-cca set working load CCA\n\
-V, --ipv6_domain Set the domain to IPv6 (send packets over IPv6)\n\
-X, --peer-detect perform server version detection and version exchange\n\
\n\
@@ -196,6 +226,8 @@ Report bugs to <iperf-users@lists.sourceforge.net>\n";
const char version[] =
"iperf version " IPERF_VERSION " (" IPERF_VERSION_DATE ") " IPERF_THREADS "\n";
+const char branch_version[] =
+"iperf (branch " IPERF_BRANCH ") (" IPERF_VERSION_DATE ") " IPERF_THREADS "\n";
/* -------------------------------------------------------------------
* settings
@@ -213,14 +245,17 @@ const char client_port[] =
const char server_pid_port[] =
"Server listening on %s port %d with pid %d\n";
+const char server_working_load_port[] =
+"Working load listening on %s port %d\n";
+
const char server_pid_portrange[] =
"Server listening on %s ports %d-%d with pid %d\n";
const char client_pid_port[] =
-"Client connecting to %s, %s port %d with pid %d (%d flows)\n";
+"Client connecting to %s, %s port %d with pid %d (%d/%d flows/load)\n";
const char client_pid_port_dev[] =
-"Client connecting to %s, %s port %d with pid %d via %s (%d flows)\n";
+"Client connecting to %s, %s port %d with pid %d via %s (%d/%d flows/load)\n";
const char bind_address[] =
"Binding to local address %s\n";
@@ -277,10 +312,13 @@ const char client_burstperiodcount[] =
"Bursting: %s writes %d times every %0.2f second(s)\n";
const char client_bounceback[] =
-"Bounce-back test (size=%s) (server hold req=%d usecs & tcp_quickack)\n";
+"Bounceback test (req/reply size =%s/%s) (server hold req=%d usecs & tcp_quickack)\n";
+
+const char client_bbburstperiodcount[] =
+"Bursting request %d times every %0.2f second(s)\n";
const char client_bounceback_noqack[] =
-"Bounce-back test (size=%s) (server hold req=%d usecs)\n";
+"Bounceback test (req/reply size =%s/%s) (server hold req=%d usecs)\n";
const char server_burstperiod[] =
"Burst wait timeout set to (2 * %0.2f) seconds (use --burst-period=<n secs> to change)\n";
@@ -288,6 +326,9 @@ const char server_burstperiod[] =
const char client_fq_pacing [] =
"fair-queue socket pacing set to %s/s\n";
+const char client_fq_pacing_step [] =
+"fair-queue socket pacing set to %s/s (stepping rate by %s/s)\n";
+
/* -------------------------------------------------------------------
* Legacy reports
* ------------------------------------------------------------------- */
@@ -296,28 +337,28 @@ const char report_bw_header[] =
"[ ID] Interval Transfer Bandwidth\n";
const char report_bw_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec%s\n";
const char report_sum_bw_format[] =
-"[SUM] " IPERFTimeFrmt " sec %ss %ss/sec\n";
+"[SUM] " IPERFTimeFrmt " sec %ss %ss/sec%s\n";
const char report_sumcnt_bw_format[] =
-"[SUM-%d] " IPERFTimeFrmt " sec %ss %ss/sec\n";
+"[SUM-%d] " IPERFTimeFrmt " sec %ss %ss/sec%s\n";
const char report_bw_jitter_loss_header[] =
"[ ID] Interval Transfer Bandwidth Jitter Lost/Total Datagrams\n";
const char report_bw_jitter_loss_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%)\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%)%s\n";
const char report_sum_bw_jitter_loss_format[] =
-"[SUM] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " (%.2g%%)\n";
+"[SUM] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " (%.2g%%)%s\n";
const char report_sumcnt_bw_jitter_loss_header[] =
"[SUM-cnt] Interval Transfer Bandwidth Lost/Total PPS\n";
const char report_sumcnt_bw_jitter_loss_format[] =
-"[SUM-%d] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %8.0f pps\n";
+"[SUM-%d] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %8.0f pps%s\n";
/* -------------------------------------------------------------------
* Enhanced reports (per -e)
@@ -335,172 +376,250 @@ const char server_read_size[] =
"Read buffer size";
const char report_bw_enhanced_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec%s\n";
const char report_sum_bw_enhanced_format[] =
-"[SUM] " IPERFTimeFrmt " sec %ss %ss/sec\n";
+"[SUM] " IPERFTimeFrmt " sec %ss %ss/sec%s\n";
const char report_bw_read_enhanced_header[] =
"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Reads=Dist\n";
const char report_bw_read_enhanced_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "=%d:%d:%d:%d:%d:%d:%d:%d\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "=%d:%d:%d:%d:%d:%d:%d:%d%s\n";
const char report_sumcnt_bw_read_enhanced_header[] =
"[SUM-cnt] Interval" IPERFTimeSpace "Transfer Bandwidth Reads=Dist\n";
const char report_sumcnt_bw_read_enhanced_format[] =
-"[SUM-%d] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "=%d:%d:%d:%d:%d:%d:%d:%d\n";
+"[SUM-%d] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "=%d:%d:%d:%d:%d:%d:%d:%d%s\n";
const char report_sumcnt_bw_read_triptime_header[] =
"[SUM-cnt] Interval" IPERFTimeSpace "Transfer Bandwidth InP Reads=Dist\n";
const char report_sumcnt_bw_read_triptime_format[] =
-"[SUM-%d] " IPERFTimeFrmt " sec %ss %ss/sec %s %" PRIdMAX "=%d:%d:%d:%d:%d:%d:%d:%d\n";
+"[SUM-%d] " IPERFTimeFrmt " sec %ss %ss/sec %s %" PRIdMAX "=%d:%d:%d:%d:%d:%d:%d:%d%s\n";
const char report_bw_read_enhanced_netpwr_header[] =
"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Burst Latency avg/min/max/stdev (cnt/size) inP NetPwr Reads=Dist\n";
const char report_bw_read_enhanced_netpwr_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %.3f/%.3f/%.3f/%.3f ms (%d/%d) %s %s %" PRIdMAX "=%d:%d:%d:%d:%d:%d:%d:%d\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %.3f/%.3f/%.3f/%.3f ms (%d/%d) %s %s %" PRIdMAX "=%d:%d:%d:%d:%d:%d:%d:%d%s\n";
const char report_bw_isoch_enhanced_netpwr_header[] =
"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Burst Latency avg/min/max/stdev (cnt/size) NetPwr Reads=Dist\n";
const char report_bw_isoch_enhanced_netpwr_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %.3f/%.3f/%.3f/%.3f ms (%d/%d) %s %" PRIdMAX "=%d:%d:%d:%d:%d:%d:%d:%d\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %.3f/%.3f/%.3f/%.3f ms (%d/%d) %s %" PRIdMAX "=%d:%d:%d:%d:%d:%d:%d:%d%s\n";
const char report_sum_bw_read_enhanced_format[] =
-"[SUM] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "=%d:%d:%d:%d:%d:%d:%d:%d\n";
+"[SUM] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "=%d:%d:%d:%d:%d:%d:%d:%d%s\n";
const char report_triptime_enhanced_format[] =
-"%s" IPERFTimeFrmt " trip-time (3WHS done->fin+finack) = %.4f sec\n";
+"%s" IPERFTimeFrmt " trip-time (3WHS done->fin+finack) = %.4f sec%s\n";
#if HAVE_TCP_STATS
+#if HAVE_TCP_INFLIGHT
+const char report_bw_write_enhanced_header[] =
+"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err Rtry InF(pkts)/Cwnd(pkts)/RTT(var) NetPwr\n";
+
+const char report_bw_write_enhanced_format[] =
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%10" PRIdMAX " %8" PRIdMAX "K(%" PRIuLEAST32 ")/%" PRIdMAX "K(%" PRIuLEAST32 ")/%" PRIuLEAST32 "(%" PRIuLEAST32 ") us %s\n";
+
+const char report_write_enhanced_nocwnd_write_format[] =
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %10" PRIdMAX " NA/%" PRIuLEAST32 "(%" PRIuLEAST32 ") us %s %.3f/%.3f/%.3f/%.3f ms (%" PRIdMAX ")%s\n";
+
+const char report_bw_write_enhanced_fq_header[] =
+"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err Rtry InF(pkts)/Cwnd(pkts)/RTT(var) fq-rate NetPwr\n";
+
+const char report_bw_write_enhanced_fq_format[] =
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%10" PRIdMAX " %8" PRIdMAX "K(%" PRIuLEAST32 ")/%" PRIdMAX "K(%" PRIuLEAST32 ")/%" PRIuLEAST32 "(%" PRIuLEAST32 ") us %s/sec %s%s\n";
+
const char report_client_bb_bw_header[] =
-"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth BB cnt=avg/min/max/stdev Rtry Cwnd/RTT RPS\n";
+"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth BB cnt=avg/min/max/stdev Rtry Cwnd(pkts)/RTT(var) RPS(avg)\n";
const char report_client_bb_bw_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "=%.3f/%.3f/%.3f/%.3f ms %4d %4dK/%u us %s rps\n";
-#else
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "=%.3f/%.3f/%.3f/%.3f ms %4" PRIuLEAST32 "%4" PRIdMAX "K/(%" PRIuLEAST32 ")/%" PRIuLEAST32 "(%" PRIuLEAST32 ") us %s rps%s\n";
+
+const char report_client_bb_bw_final_format[] =
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "=%.3f/%.3f/%.3f/%.3f ms %4" PRIuLEAST32 " -(-)/-(-) %s rps%s\n";
+
+const char report_write_enhanced_write_header[] =
+"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err Rtry InF(pkts)/Cwnd(pkts)/RTT(var) NetPwr write-times avg/min/max/stdev (cnt)\n";
+
+const char report_write_enhanced_write_format[] =
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %8" PRIuLEAST32 "%7" PRIdMAX "K(%" PRIuLEAST32 ")/%" PRIdMAX "K(%" PRIuLEAST32 ")/%" PRIuLEAST32 "(%" PRIuLEAST32 ") us %s %.3f/%.3f/%.3f/%.3f ms (%" PRIdMAX ")%s\n";
+
+#else // no inflight
+const char report_bw_write_enhanced_header[] =
+"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err Rtry Cwnd(pkts)/RTT(var) NetPwr\n";
+
+const char report_bw_write_enhanced_format[] =
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%10" PRIuLEAST32 " %8" PRIdMAX "K(%" PRIuLEAST32 ")/%" PRIuLEAST32 "(%" PRIuLEAST32 ") us %s\n";
+
+const char report_bw_write_enhanced_fq_header[] =
+"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err Rtry Cwnd(pkts)/RTT(var) fq-rate NetPwr\n";
+
+const char report_bw_write_enhanced_fq_format[] =
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%10" PRIuLEAST32 " %8" PRIdMAX "K(%" PRIuLEAST32 ")/%" PRIuLEAST32 "(%" PRIuLEAST32 ") us %s/sec %s%s\n";
+
const char report_client_bb_bw_header[] =
-"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth BB cnt=avg/min/max/stdev RPS\n";
+"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth BB cnt=avg/min/max/stdev Rtry Cwnd(pkts)/RTT(var) RPS(avg)\n";
const char report_client_bb_bw_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "=%.3f/%.3f/%.3f/%.3f ms %s rps\n";
-#endif
-const char report_client_bb_bw_triptime_format[] =
-"%s" IPERFTimeFrmt " sec OWD Delays (ms) Cnt=%" PRIdMAX " To=%.3f/%.3f/%.3f/%.3f From=%.3f/%.3f/%.3f/%.3f Asymmetry=%.3f/%.3f/%.3f/%.3f %s rps\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "=%.3f/%.3f/%.3f/%.3f ms %4" PRIuLEAST32 " %4" PRIdMAX "K(%" PRIuLEAST32 ")/%" PRIuLEAST32 "(%" PRIuLEAST32 ") us %s rps%s\n";
+
+const char report_client_bb_bw_final_format[] =
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "=%.3f/%.3f/%.3f/%.3f ms %4" PRIuLEAST32 " -(-)/-(-) %s rps%s\n";
const char report_write_enhanced_write_header[] =
-"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err Rtry Cwnd/RTT NetPwr write-times avg/min/max/stdev (cnt)\n";
+"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err Rtry Cwnd(pkts)/RTT(var) NetPwr write-times avg/min/max/stdev (cnt)\n";
const char report_write_enhanced_write_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %10" PRIdMAX "%8dK/%u us %s %.3f/%.3f/%.3f/%.3f ms (%" PRIdMAX ")\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %10" PRIuLEAST32 "%8" PRIdMAX "K(%" PRIuLEAST32 ")/%" PRIuLEAST32 "(%" PRIuLEAST32 ") us %s %.3f/%.3f/%.3f/%.3f ms (%" PRIdMAX ")%s\n";
const char report_write_enhanced_nocwnd_write_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %10" PRIdMAX " NA/%u us %s %.3f/%.3f/%.3f/%.3f ms (%" PRIdMAX ")\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %10" PRIuLEAST32 " NA/%" PRIuLEAST32 "(%" PRIuLEAST32 ") us %s %.3f/%.3f/%.3f/%.3f ms (%" PRIdMAX ")%s\n";
-
-#if HAVE_TCP_STATS
-const char report_bw_write_enhanced_header[] =
-"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err Rtry Cwnd/RTT(var) NetPwr\n";
+#endif //HAVE_TCP_INFLIGHT
const char report_sum_bw_write_enhanced_format[] =
-"[SUM] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%10" PRIdMAX "\n";
+"[SUM] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%10" PRIuLEAST32 " %s\n";
-const char report_bw_write_enhanced_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%10" PRIdMAX " %8dK/%u(%u) us %s\n";
+const char report_bw_write_enhanced_fq_final_format[] =
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%10" PRIuLEAST32 " %8dK/%u(%u) us %s%s\n";
const char report_bw_write_enhanced_nocwnd_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %10" PRIdMAX " NA/%u us %s\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %10" PRIuLEAST32 " NA/%" PRIuLEAST32 "(%" PRIuLEAST32 ")us %s\n";
const char report_write_enhanced_isoch_header[] =
-"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err Rtry Cwnd/RTT isoch:tx/miss/slip NetPwr\n";
+"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err Rtry Cwnd(pkts)/RTT(var) isoch:tx/miss/slip NetPwr\n";
const char report_write_enhanced_isoch_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %8d %8dK/%u us %9" PRIuMAX "/%" PRIuMAX "/%" PRIuMAX " %s\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %8" PRIuLEAST32 " %8" PRIdMAX "K(%" PRIuLEAST32 ")/%" PRIuLEAST32 "(%" PRIuLEAST32 ") us %9" PRIuMAX "/%" PRIuMAX "/%" PRIuMAX " %s%s\n";
const char report_write_enhanced_isoch_nocwnd_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %10" PRIdMAX " NA/%u us %9" PRIuMAX "/%" PRIuMAX "/%" PRIuMAX " %s\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %10" PRIuLEAST32 " NA/%" PRIuLEAST32 "(%" PRIuLEAST32 ") us %9" PRIuMAX "/%" PRIuMAX "/%" PRIuMAX " %s%s\n";
-#else
+#else //no tcpstat
+
+const char report_client_bb_bw_header[] =
+"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth BB cnt=avg/min/max/stdev RPS(avg)\n";
+
+const char report_client_bb_bw_format[] =
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "=%.3f/%.3f/%.3f/%.3f ms %s rps%s\n";
+
+const char report_bw_write_enhanced_fq_header[] =
+"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err fq-rate NetPwr\n";
+
+const char report_bw_write_enhanced_fq_format[] =
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%s/sec %s%s\n";
const char report_bw_write_enhanced_header[] =
"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err\n";
const char report_bw_write_enhanced_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%s\n";
const char report_sum_bw_write_enhanced_format[] =
-"[SUM] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "\n";
+"[SUM] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%s\n";
const char report_write_enhanced_isoch_header[] =
"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err isoch:tx/miss/slip\n";
const char report_write_enhanced_isoch_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%9" PRIuMAX "/%" PRIuMAX "/%" PRIuMAX "\n";
-#endif
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%9" PRIuMAX "/%" PRIuMAX "/%" PRIuMAX "%s\n";
+
+const char report_write_enhanced_write_header[] =
+"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err NetPwr write-times avg/min/max/stdev (cnt)\n";
+
+const char report_write_enhanced_write_format[] =
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%s %.3f/%.3f/%.3f/%.3f ms (%" PRIdMAX ")%s\n";
+
+const char report_bw_write_fq_header[] =
+"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err fq-rate\n";
+
+const char report_bw_write_fq_format[] =
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %s/sec%s\n";
+
+#endif //no tcp stat
+
+const char report_client_bb_bw_triptime_format[] =
+"%s" IPERFTimeFrmt " sec OWD (ms) Cnt=%" PRIdMAX " TX=%.3f/%.3f/%.3f/%.3f RX=%.3f/%.3f/%.3f/%.3f Asymmetry=%.3f/%.3f/%.3f/%.3f%s\n";
const char report_sumcnt_bw_write_enhanced_header[] =
"[SUM-cnt] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err Rtry\n";
const char report_sumcnt_bw_write_enhanced_format[] =
-"[SUM-%d] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%10" PRIdMAX "\n";
+"[SUM-%d] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%10" PRIdMAX "%s\n";
const char report_bw_pps_enhanced_header[] =
-"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err PPS\n";
+"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err/Timeo PPS\n";
const char report_bw_pps_enhanced_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %8.0f pps\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "/%" PRIdMAX "%8.0f pps%s\n";
const char report_sumcnt_bw_pps_enhanced_header[] =
"[SUM-cnt] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err PPS\n";
const char report_sumcnt_bw_pps_enhanced_format[] =
-"[SUM-%d] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %8.0f pps\n";
+"[SUM-%d] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %8.0f pps%s\n";
const char report_sumcnt_udp_enhanced_header[] =
"[SUM-cnt] Interval" IPERFTimeSpace "Transfer Bandwidth Lost/Total PPS\n";
const char report_sumcnt_udp_enhanced_format[] =
-"[SUM-%d] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %8.0f pps\n";
+"[SUM-%d] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %8.0f pps%s\n";
const char report_sumcnt_udp_triptime_header[] =
"[SUM-cnt] Interval" IPERFTimeSpace "Transfer Bandwidth Lost/Total Rx/inP PPS\n";
const char report_sumcnt_udp_triptime_format[] =
-"[SUM-%d] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %" PRIdMAX "/%.0f %8.0f pps\n";
+"[SUM-%d] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX " %" PRIdMAX "/%.0f %8.0f pps%s\n";
const char report_bw_pps_enhanced_isoch_header[] =
"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err PPS isoch:tx/miss/slip\n";
const char report_bw_pps_enhanced_isoch_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%8.0f pps %3" PRIuMAX "/%" PRIuMAX "/%" PRIuMAX "\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%8.0f pps %3" PRIuMAX "/%" PRIuMAX "/%" PRIuMAX "%s\n";
const char report_sum_bw_pps_enhanced_format[] =
-"[SUM] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%8.0f pps\n";
+"[SUM] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "/%" PRIdMAX "%8.0f pps%s\n";
const char report_bw_jitter_loss_pps_header[] =
"[ ID] Interval Transfer Bandwidth Jitter Lost/Total Datagrams PPS\n";
const char report_bw_jitter_loss_pps_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) %8.0f pps\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) %8.0f pps%s\n";
+#if HAVE_DECL_MSG_TRUNC
const char report_bw_jitter_loss_enhanced_header[] =
"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Jitter Lost/Total \
- Latency avg/min/max/stdev PPS NetPwr\n";
+ Latency avg/min/max/stdev PPS Read/Timeo/Trunc NetPwr\n";
const char report_bw_jitter_loss_enhanced_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) %.3f/%.3f/%.3f/%.3f ms %.0f pps %s\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) %.3f/%.3f/%.3f/%.3f ms %.0f pps %" PRIdMAX "/%" PRIdMAX "/%" PRIdMAX " %s%s\n";
const char report_bw_jitter_loss_enhanced_triptime_header[] =
"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Jitter Lost/Total \
- Latency avg/min/max/stdev PPS Rx/inP NetPwr\n";
+ Latency avg/min/max/stdev PPS Rx/inP Read/Timeo/Trunc NetPwr\n";
const char report_bw_jitter_loss_enhanced_triptime_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) %.3f/%.3f/%.3f/%.3f ms %.0f pps %" PRIdMAX "/%s %s\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) %.3f/%.3f/%.3f/%.3f ms %.0f pps %" PRIdMAX "/%s %" PRIdMAX "/%" PRIdMAX "/%" PRIdMAX " %s%s\n";
+#else
+const char report_bw_jitter_loss_enhanced_header[] =
+"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Jitter Lost/Total \
+ Latency avg/min/max/stdev PPS Read/Timeo NetPwr\n";
+
+const char report_bw_jitter_loss_enhanced_format[] =
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) %.3f/%.3f/%.3f/%.3f ms %.0f pps %" PRIdMAX "/%" PRIdMAX " %s%s\n";
+const char report_bw_jitter_loss_enhanced_triptime_header[] =
+"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Jitter Lost/Total \
+ Latency avg/min/max/stdev PPS Rx/inP Read/Timeo NetPwr\n";
+
+const char report_bw_jitter_loss_enhanced_triptime_format[] =
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) %.3f/%.3f/%.3f/%.3f ms %.0f pps %" PRIdMAX "/%s %" PRIdMAX "/%" PRIdMAX "%s%s\n";
+#endif //msgtrunc
const char report_bw_jitter_loss_enhanced_isoch_header[] =
"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Jitter Lost/Total \
Latency avg/min/max/stdev PPS NetPwr Isoch:rx/lost\n";
@@ -510,16 +629,16 @@ const char report_bw_jitter_loss_enhanced_isoch_triptime_header[] =
Latency avg/min/max/stdev PPS Frame:rx/lost Frame-latency avg/min/max/stdev NetPwr\n";
const char report_bw_jitter_loss_enhanced_isoch_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) %.3f/%.3f/%.3f/%.3f ms %.0f pps %3d/%d %.3f/%.3f/%.3f/%.3f ms %s\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) %.3f/%.3f/%.3f/%.3f ms %.0f pps %3" PRIdMAX " /% " PRIdMAX " %.3f/%.3f/%.3f/%.3f ms %s%s\n";
const char report_sum_bw_jitter_loss_enhanced_format[] =
-"[SUM] " IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) %.0f pps\n";
+"[SUM] " IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) %.0f pps%s\n";
const char report_sumcnt_bw_jitter_loss_enhanced_format[] =
-"[SUM-%d] " IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) %.0f pps\n";
+"[SUM-%d] " IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) %.0f pps%s\n";
const char report_bw_jitter_loss_suppress_enhanced_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) -/-/-/- ms %.0f pps\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) -/-/-/- ms %.0f pps %" PRIdMAX "/%" PRIdMAX "/%" PRIdMAX "%s\n";
/*
* Frame interval reports
@@ -531,10 +650,10 @@ const char report_frame_jitter_loss_enhanced_header[] =
Latency avg/min/max/stdev PPS inP NetPwr\n";
const char report_frame_jitter_loss_enhanced_format[] =
-"%s" IPERFFTimeFrmt "(%0.4f) sec %ss %ss/sec %" PRIdMAX " %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) %.3f/%.3f/%.3f/%.3f ms %.0f pps %2.0f pkts %s\n";
+"%s" IPERFFTimeFrmt "(%0.4f) sec %ss %ss/sec %" PRIdMAX " %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) %.3f/%.3f/%.3f/%.3f ms %.0f pps %2.0f pkts %s%s\n";
const char report_frame_jitter_loss_suppress_enhanced_format[] =
-"%s" IPERFTimeFrmt "(%0.4f) sec %" PRIdMAX " %ss %ss/sec %" PRIdMAX " %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) -/-/-/- ms %.0f pps\n";
+"%s" IPERFTimeFrmt "(%0.4f) sec %" PRIdMAX " %ss %ss/sec %" PRIdMAX " %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) -/-/-/- ms %.0f pps %s%s\n";
const char report_frame_tcp_enhanced_header[] =
"[ ID] Interval(f-transit)" IPERFFTimeSpace "Transfer Bandwidth FrameID\n";
@@ -543,7 +662,7 @@ const char report_burst_read_tcp_header[] =
"[ ID] Burst (start-end)" IPERFFTimeSpace "Transfer Bandwidth XferTime (DC%) Reads=Dist NetPwr\n";
const char report_burst_read_tcp_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms (%.2g%%) %" PRIdMAX "=%d:%d:%d:%d:%d:%d:%d:%d %s\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms (%.2g%%) %" PRIdMAX "=%d:%d:%d:%d:%d:%d:%d:%d %s%s\n";
const char report_burst_read_tcp_final_format[] =
"%s" IPERFTimeFrmt " sec %ss %ss/sec %.3f/%.3f/%.3f/%.3f ms %" PRIdMAX "=%d:%d:%d:%d:%d:%d:%d:%d\n";
@@ -552,63 +671,57 @@ const char report_burst_write_tcp_header[] =
"[ ID] Burst (start-end)" IPERFFTimeSpace "Transfer Bandwidth XferTime Write/Err Rtry Cwnd/RTT NetPwr\n";
const char report_burst_write_tcp_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX "%10" PRIdMAX "%8dK/%u %s\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX "%10" PRIdMAX "%8dK/%u %s%s\n";
#else
const char report_burst_write_tcp_header[] =
"[ ID] Burst (start-end)" IPERFFTimeSpace "Transfer Bandwidth XferTime Write/Err\n";
const char report_burst_write_tcp_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX"\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX"%s\n";
#endif
const char report_burst_write_tcp_nocwnd_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX "%10" PRIdMAX "NA/%u %s\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX "%10" PRIdMAX "NA/%"PRIuLEAST32 "(%" PRIuLEAST32 ")%s\n";
const char report_burst_write_tcp_final_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "=%d:%d:%d:%d:%d:%d:%d:%d\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "=%d:%d:%d:%d:%d:%d:%d:%d%s\n";
/* -------------------------------------------------------------------
* Fullduplex reports
* ------------------------------------------------------------------- */
const char report_bw_sum_fullduplex_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec%s\n";
const char report_bw_sum_fullduplex_enhanced_format[] =
-"[FD%d] " IPERFTimeFrmt " sec %ss %ss/sec\n";
+"[FD%d] " IPERFTimeFrmt " sec %ss %ss/sec%s\n";
const char report_udp_fullduplex_header[] =
"[ ID] Interval Transfer Bandwidth Datagrams PPS\n";
-const char report_sumcnt_udp_fullduplex_header[] =
-"[SUM-cnt] Interval Transfer Bandwidth Datagrams PPS\n";
-
-const char report_sumcnt_udp_fullduplex_format[] =
-"[SUM-%d] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "%8.0f pps\n";
-
const char report_udp_fullduplex_format[] =
-"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "%8.0f pps\n";
+"%s" IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "%8.0f pps%s\n";
const char report_udp_fullduplex_enhanced_format[] =
-"[FD%d] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "%8.0f pps\n";
+"[FD%d] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "%8.0f pps%s\n";
const char report_udp_fullduplex_sum_format[] =
-"[SUM] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "%8.0f pps\n";
+"[SUM] " IPERFTimeFrmt " sec %ss %ss/sec %" PRIdMAX "%8.0f pps%s\n";
/* -------------------------------------------------------------------
* Misc reports
* ------------------------------------------------------------------- */
const char report_outoforder[] =
-"%s" IPERFTimeFrmt " sec %d datagrams received out-of-order\n";
+"%s" IPERFTimeFrmt " sec %d datagrams received out-of-order%s\n";
const char report_sumcnt_outoforder[] =
-"[SUM-%d] " IPERFTimeFrmt " sec %d datagrams received out-of-order\n";
+"[SUM-%d] " IPERFTimeFrmt " sec %d datagrams received out-of-order%s\n";
const char report_l2statistics[] =
"%s" IPERFTimeFrmt " sec L2 processing detected errors, total(length/checksum/unknown) = %" PRIdMAX "(%" PRIdMAX "/%" PRIdMAX "/%" PRIdMAX ")\n";
const char report_sum_outoforder[] =
-"[SUM] " IPERFTimeFrmt " sec %d datagrams received out-of-order\n";
+"[SUM] " IPERFTimeFrmt " sec %d datagrams received out-of-order%s\n";
const char report_peer [] =
"%slocal %s port %u connected with %s port %u%s\n";
@@ -629,13 +742,13 @@ const char report_mss[] =
"MSS req size %d bytes (per TCP_MAXSEG)\n";
const char report_datagrams[] =
-"[%3d] Sent %d datagrams\n";
+"[%3d] Sent %" PRIdMAX " datagrams\n";
const char report_sumcnt_datagrams[] =
-"[SUM-%d] Sent %d datagrams\n";
+"[SUM-%d] Sent %" PRIdMAX " datagrams\n";
const char report_sum_datagrams[] =
-"[SUM] Sent %d datagrams\n";
+"[SUM] Sent %" PRIdMAX " datagrams\n";
const char server_reporting[] =
"[%3d] Server Report:\n";
@@ -644,7 +757,9 @@ const char reportCSV_peer[] =
"%s,%u,%s,%u";
const char report_l2length_error[] =
-"%s" IPERFTimeFrmt " sec %d datagrams received out-of-order\n";
+"%s" IPERFTimeFrmt " sec %" PRIdMAX " datagrams received out-of-order\n";
+
+const char report_client_bb_triptime_clocksync_error[] ="%s" IPERFTimeFrmt " sec Clock sync error count = %" PRIdMAX "\n";
/*-------------------------------------------------------------------
* CSV outputs
@@ -652,17 +767,32 @@ const char report_l2length_error[] =
const char reportCSV_bw_format[] =
"%s,%s,%d,%.1f-%.1f,%" PRIdMAX ",%" PRIdMAX "\n";
+const char reportCSV_bw_read_enhanced_header[] =
+"time,srcaddress,srcport,dstaddr,dstport,transferid,istart,iend,bytes,speed,readcnt,bin0,bin1,bin2,bin3,bin4,bin5,bin6,bin7\n";
+
const char reportCSV_bw_read_enhanced_format[] =
-"%s,%s,%d,%.1f-%.1f,%" PRIdMAX ",%" PRIdMAX ",%" PRIdMAX ",%d,%d,%d,%d,%d,%d,%d,%d\n";
+"%s,%s,%d,%.1f,%.1f,%" PRIdMAX ",%" PRIdMAX ",%" PRIdMAX ",%d,%d,%d,%d,%d,%d,%d,%d\n";
+
+const char reportCSV_bw_write_enhanced_header[] =
+"time,srcaddress,srcport,dstaddr,dstport,transferid,istart,iend,bytes,speed,writecnt,writeerr,tcpretry,tcpcwnd,tcppcwnd,tcprtt,tcprttvar\n";
const char reportCSV_bw_write_enhanced_format[] =
-"%s,%s,%d,%.1f-%.1f,%" PRIdMAX ",%" PRIdMAX ",%" PRIdMAX ",%" PRIdMAX ",%" PRIdMAX ",%d,%u,%u\n";
+"%s,%s,%d,%.1f,%.1f,%" PRIdMAX ",%" PRIdMAX ",%" PRIdMAX ",%" PRIdMAX ",%" PRIuLEAST32 ",%" PRIdMAX ",%" PRIuLEAST32 ",%" PRIuLEAST32 ",%" PRIuLEAST32 "\n";
const char reportCSV_bw_jitter_loss_format[] =
"%s,%s,%d,%.1f-%.1f,%" PRIdMAX ",%" PRIdMAX ",%.3f,%" PRIdMAX ",%" PRIdMAX ",%.3f,%" PRIdMAX "\n";
+const char reportCSV_bw_jitter_loss_pps_header[] =
+"time,srcaddress,srcport,dstaddr,dstport,transferid,istart,iend,bytes,speed,jitter,errors,datagrams,errpercent,outoforder,writecnt,writeerr,pps\n";
+
const char reportCSV_bw_jitter_loss_pps_format[] =
-"%s,%s,%d,%.1f-%.1f,%" PRIdMAX ",%" PRIdMAX ",%.3f,%" PRIdMAX ",%" PRIdMAX ",%.3f,%" PRIdMAX ",%" PRIdMAX ",%" PRIdMAX ",%f\n";
+"%s,%s,%d,%.1f,%.1f,%" PRIdMAX ",%" PRIdMAX ",%.3f,%" PRIdMAX ",%" PRIdMAX ",%.3f,%" PRIdMAX ",%" PRIdMAX ",%" PRIdMAX ",%f\n";
+
+const char reportCSV_client_bb_bw_tcp_header[] =
+"time,srcaddress,srcport,dstaddr,dstport,transferid,istart,iend,bytes,speed,bbcnt,bbavg,bbmin,bbmax,bbstdev,tcpretry,tcpcwnd,tcprtt,rps\n";
+
+const char reportCSV_client_bb_bw_tcp_format[] =
+"%s,%s,%d,%.1f,%.1f,%" PRIdMAX ",%" PRIdMAX ",%" PRIdMAX ",%.3f,%.3f,%.3f,%.3f,%" PRIuLEAST32 ",%" PRIdMAX ",%" PRIuLEAST32 ",%0.1f\n";
/* -------------------------------------------------------------------
* warnings
@@ -744,14 +874,16 @@ const char warn_compat_and_peer_exchange[] =
"WARNING: Options of '-C' '--compatibility' AND '-X' '--peerdetect' are mutually exclusive, --peerdetect ignored\n";
const char warn_start_before_now[] =
-"[%3d] WARNING: --txstart-time (%" PRIdMAX ".%" PRIdMAX ") %s is before now %s\n";
+"[%3d] WARNING: --txstart-time (%ld.%06ld) %s is before now %s\n";
const char error_starttime_exceeds[] =
-"ERROR: --txstart-time (%" PRIdMAX ".%" PRIdMAX ") %s exceeds max scheduled delay of %d secs\n";
+"ERROR: --txstart-time %ld.%06ld %s exceeds max scheduled delay of %d secs\n";
const char error_delaytime_exceeds[] =
"ERROR: --txdelay-time of %d seconds is more than the supported delay of %d seconds\n";
+const char report_omitted[] = " (omitted)";
+
#ifdef __cplusplus
} /* end extern "C" */
#endif
diff --git a/src/Makefile.am b/src/Makefile.am
index 37db611..e6c8f86 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -49,7 +49,8 @@ iperf_SOURCES = \
tcp_window_size.c \
pdfs.c \
dscp.c \
- iperf_formattime.c
+ iperf_formattime.c \
+ iperf_multicast_api.c
iperf_LDADD = $(LIBCOMPAT_LDADDS)
diff --git a/src/Makefile.in b/src/Makefile.in
index a8ab595..ea6ccc7 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.2 from Makefile.am.
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -138,7 +138,7 @@ am__iperf_SOURCES_DIST = Client.cpp Extractor.c isochronous.cpp \
Settings.cpp SocketAddr.c gnu_getopt.c gnu_getopt_long.c \
histogram.c main.cpp service.c socket_io.c stdio.c \
packet_ring.c tcp_window_size.c pdfs.c dscp.c \
- iperf_formattime.c checksums.c
+ iperf_formattime.c iperf_multicast_api.c checksums.c
@AF_PACKET_TRUE@am__objects_1 = checksums.$(OBJEXT)
am_iperf_OBJECTS = Client.$(OBJEXT) Extractor.$(OBJEXT) \
isochronous.$(OBJEXT) Launch.$(OBJEXT) active_hosts.$(OBJEXT) \
@@ -149,7 +149,8 @@ am_iperf_OBJECTS = Client.$(OBJEXT) Extractor.$(OBJEXT) \
histogram.$(OBJEXT) main.$(OBJEXT) service.$(OBJEXT) \
socket_io.$(OBJEXT) stdio.$(OBJEXT) packet_ring.$(OBJEXT) \
tcp_window_size.$(OBJEXT) pdfs.$(OBJEXT) dscp.$(OBJEXT) \
- iperf_formattime.$(OBJEXT) $(am__objects_1)
+ iperf_formattime.$(OBJEXT) iperf_multicast_api.$(OBJEXT) \
+ $(am__objects_1)
iperf_OBJECTS = $(am_iperf_OBJECTS)
iperf_DEPENDENCIES = $(am__DEPENDENCIES_1)
iperf_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(iperf_LDFLAGS) \
@@ -180,7 +181,8 @@ am__depfiles_remade = ./$(DEPDIR)/Client.Po ./$(DEPDIR)/Extractor.Po \
./$(DEPDIR)/checksums.Po ./$(DEPDIR)/dscp.Po \
./$(DEPDIR)/gnu_getopt.Po ./$(DEPDIR)/gnu_getopt_long.Po \
./$(DEPDIR)/histogram.Po ./$(DEPDIR)/igmp_querier.Po \
- ./$(DEPDIR)/iperf_formattime.Po ./$(DEPDIR)/isochronous.Po \
+ ./$(DEPDIR)/iperf_formattime.Po \
+ ./$(DEPDIR)/iperf_multicast_api.Po ./$(DEPDIR)/isochronous.Po \
./$(DEPDIR)/main.Po ./$(DEPDIR)/packet_ring.Po \
./$(DEPDIR)/pdfs.Po ./$(DEPDIR)/service.Po \
./$(DEPDIR)/socket_io.Po ./$(DEPDIR)/stdio.Po \
@@ -238,8 +240,6 @@ am__define_uniq_tagged_files = \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
@@ -254,6 +254,8 @@ CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
CXX = @CXX@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
@@ -264,6 +266,7 @@ ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
+ETAGS = @ETAGS@
EXEEXT = @EXEEXT@
GREP = @GREP@
INSTALL = @INSTALL@
@@ -373,7 +376,7 @@ iperf_SOURCES = Client.cpp Extractor.c isochronous.cpp Launch.cpp \
SocketAddr.c gnu_getopt.c gnu_getopt_long.c histogram.c \
main.cpp service.c socket_io.c stdio.c packet_ring.c \
tcp_window_size.c pdfs.c dscp.c iperf_formattime.c \
- $(am__append_5)
+ iperf_multicast_api.c $(am__append_5)
iperf_LDADD = $(LIBCOMPAT_LDADDS)
@CHECKPROGRAMS_TRUE@checkdelay_SOURCES = checkdelay.c
@CHECKPROGRAMS_TRUE@checkdelay_LDADD = $(LIBCOMPAT_LDADDS)
@@ -510,6 +513,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/histogram.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/igmp_querier.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf_formattime.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf_multicast_api.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isochronous.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet_ring.Po@am__quote@ # am--include-marker
@@ -604,7 +608,6 @@ cscopelist-am: $(am__tagged_files)
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
@@ -704,6 +707,7 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/histogram.Po
-rm -f ./$(DEPDIR)/igmp_querier.Po
-rm -f ./$(DEPDIR)/iperf_formattime.Po
+ -rm -f ./$(DEPDIR)/iperf_multicast_api.Po
-rm -f ./$(DEPDIR)/isochronous.Po
-rm -f ./$(DEPDIR)/main.Po
-rm -f ./$(DEPDIR)/packet_ring.Po
@@ -780,6 +784,7 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/histogram.Po
-rm -f ./$(DEPDIR)/igmp_querier.Po
-rm -f ./$(DEPDIR)/iperf_formattime.Po
+ -rm -f ./$(DEPDIR)/iperf_multicast_api.Po
-rm -f ./$(DEPDIR)/isochronous.Po
-rm -f ./$(DEPDIR)/main.Po
-rm -f ./$(DEPDIR)/packet_ring.Po
diff --git a/src/PerfSocket.cpp b/src/PerfSocket.cpp
index bad4074..363e8b1 100644
--- a/src/PerfSocket.cpp
+++ b/src/PerfSocket.cpp
@@ -74,6 +74,7 @@
#include "PerfSocket.hpp"
#include "SocketAddr.h"
#include "util.h"
+#include "iperf_multicast_api.h"
/* -------------------------------------------------------------------
* Set socket options before the listen() or connect() calls.
@@ -85,9 +86,8 @@ void SetSocketOptions (struct thread_Settings *inSettings) {
// must occur before call to accept() for large window sizes
setsock_tcp_windowsize(inSettings->mSock, inSettings->mTCPWin,
(inSettings->mThreadMode == kMode_Client ? 1 : 0));
-
+#if HAVE_DECL_TCP_CONGESTION
if (isCongestionControl(inSettings)) {
-#ifdef TCP_CONGESTION
Socklen_t len = strlen(inSettings->mCongestion) + 1;
int rc = setsockopt(inSettings->mSock, IPPROTO_TCP, TCP_CONGESTION,
inSettings->mCongestion, len);
@@ -95,12 +95,56 @@ void SetSocketOptions (struct thread_Settings *inSettings) {
fprintf(stderr, "Attempt to set '%s' congestion control failed: %s\n",
inSettings->mCongestion, strerror(errno));
unsetCongestionControl(inSettings);
+ thread_stop(inSettings);
+ }
+ char cca[TCP_CCA_NAME_MAX] = "";
+ len = sizeof(cca);
+ if (getsockopt(inSettings->mSock, IPPROTO_TCP, TCP_CONGESTION, &cca, &len) == 0) {
+ cca[TCP_CCA_NAME_MAX-1]='\0';
+ if (strcmp(cca, inSettings->mCongestion) != 0) {
+ fprintf(stderr, "Failed to set '%s' congestion control got '%s'\n", inSettings->mCongestion, cca);
+ thread_stop(inSettings);
+ }
}
+ } else if (isLoadCCA(inSettings)) {
+ Socklen_t len = strlen(inSettings->mLoadCCA) + 1;
+ int rc = setsockopt(inSettings->mSock, IPPROTO_TCP, TCP_CONGESTION,
+ inSettings->mLoadCCA, len);
+ if (rc == SOCKET_ERROR) {
+ fprintf(stderr, "Attempt to set '%s' load congestion control failed: %s\n",
+ inSettings->mLoadCCA, strerror(errno));
+ unsetLoadCCA(inSettings);
+ thread_stop(inSettings);
+ }
+ char cca[TCP_CCA_NAME_MAX] = "";
+ len = sizeof(cca);
+ if (getsockopt(inSettings->mSock, IPPROTO_TCP, TCP_CONGESTION, &cca, &len) == 0) {
+ cca[TCP_CCA_NAME_MAX-1]='\0';
+ if (strcmp(cca, inSettings->mLoadCCA) != 0) {
+ fprintf(stderr, "Failed to set '%s' load congestion control got '%s'\n", inSettings->mLoadCCA, cca);
+ thread_stop(inSettings);
+ }
+ }
+ }
#else
- fprintf(stderr, "The -Z option is not available on this operating system\n");
-#endif
+ if (isCongestionControl(inSettings) || isLoadCCA(inSettings)) {
+ fprintf(stderr, "TCP congestion control not supported\n");
+ thread_stop(inSettings);
}
+#endif
+ int boolean = 1;
+ int rc;
+ Socklen_t len = sizeof(boolean);
+#if HAVE_DECL_SO_REUSEADDR
+ // reuse the address, so we can run if a former server was killed off
+ rc = setsockopt(inSettings->mSock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&boolean), len);
+ WARN_errno(rc == SOCKET_ERROR, "SO_REUSEADDR");
+#endif
+#if HAVE_DECL_SO_REUSEPORT
+ setsockopt(inSettings->mSock, SOL_SOCKET, SO_REUSEPORT, (char*) &boolean, len);
+ WARN_errno(rc == SOCKET_ERROR, "SO_REUSEADDR");
+#endif
#if ((HAVE_TUNTAP_TAP) && (HAVE_TUNTAP_TUN))
if (isTunDev(inSettings) || isTapDev(inSettings)) {
@@ -140,28 +184,6 @@ void SetSocketOptions (struct thread_Settings *inSettings) {
#endif
} else
#endif
-#if (HAVE_DECL_SO_BINDTODEVICE)
- {
- char **device = (inSettings->mThreadMode == kMode_Client) ? &inSettings->mIfrnametx : &inSettings->mIfrname;
- if (*device) {
- struct ifreq ifr;
- memset(&ifr, 0, sizeof(ifr));
- snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", *device);
- if (setsockopt(inSettings->mSock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {
- char *buf;
- int len = snprintf(NULL, 0, "%s %s", "bind to device", *device);
- len++; // Trailing null byte + extra
- buf = static_cast<char *>(malloc(len));
- len = snprintf(buf, len, "%s %s", "bind to device", *device);
- WARN_errno(1, buf);
- free(buf);
- free(*device);
- *device = NULL;
- FAIL(1, "setsockopt() SO_BINDTODEVICE", inSettings);
- }
- }
- }
-#endif
// check if we're sending multicast
if (isMulticast(inSettings)) {
@@ -201,9 +223,7 @@ void SetSocketOptions (struct thread_Settings *inSettings) {
WARN_errno(rc == SOCKET_ERROR, "v4 ttl");
}
-#if HAVE_DECL_IP_TOS
SetSocketOptionsIPTos(inSettings, inSettings->mTOS);
-#endif
if (!isUDP(inSettings)) {
if (isTCPMSS(inSettings)) {
@@ -255,12 +275,18 @@ void SetSocketOptions (struct thread_Settings *inSettings) {
WARN_errno(rc == SOCKET_ERROR, "setsockopt TCP_NOTSENT_LOWAT");
}
#endif
+#if HAVE_DECL_TCP_TX_DELAY
+ if (isTcpTxDelay(inSettings) && (inSettings->mTcpTxDelayProb >= 1.0)) {
+ SetSocketTcpTxDelay(inSettings, inSettings->mTcpTxDelayMean * 1000);
+ }
+#endif
}
#if HAVE_DECL_SO_MAX_PACING_RATE
/* If socket pacing is specified try to enable it. */
if (isFQPacing(inSettings) && inSettings->mFQPacingRate > 0) {
int rc = setsockopt(inSettings->mSock, SOL_SOCKET, SO_MAX_PACING_RATE, &inSettings->mFQPacingRate, sizeof(inSettings->mFQPacingRate));
+ inSettings->mFQPacingRateCurrent = inSettings->mFQPacingRate;
WARN_errno(rc == SOCKET_ERROR, "setsockopt SO_MAX_PACING_RATE");
}
#endif /* HAVE_SO_MAX_PACING_RATE */
@@ -310,37 +336,149 @@ void SetSocketOptionsReceiveTimeout (struct thread_Settings *mSettings, int time
void SetSocketOptionsIPTos (struct thread_Settings *mSettings, int tos) {
-#if HAVE_DECL_IP_TOS
-#ifdef HAVE_THREAD_DEBUG
- thread_debug("Set socket IP_TOS to 0x%x", tos);
+ bool supported = true;
+ // set IP TOS (type-of-service) field
+ if (isOverrideTOS(mSettings) || isSetTOS(mSettings) || (tos > 0)) {
+ // IPV6_TCLASS is defined on Windows but not implemented.
+#if !HAVE_DECL_IPV6_TCLASS || HAVE_WINSOCK2_H
+ if (isIPV6(mSettings)) {
+ WARN(1, "WARN: IPV6_TCLASS not supported, setting --tos");
+ mSettings->mTOS = 0;
+ supported = false;
+ }
#endif
-#if HAVE_DECL_IPV6_TCLASS && ! defined HAVE_WINSOCK2_H
- // IPV6_TCLASS is defined on Windows but not implemented.
- if (isIPV6(mSettings)) {
- const int dscp = tos;
- int rc = setsockopt(mSettings->mSock, IPPROTO_IPV6, IPV6_TCLASS, (char*) &dscp, sizeof(dscp));
- WARN_errno(rc == SOCKET_ERROR, "setsockopt IPV6_TCLASS");
- } else
+#if !HAVE_DECL_IP_TOS
+ if (!isIPV6(mSettings)) {
+ WARN(1, "WARN: IP_TOS not supported, setting --tos");
+ mSettings->mTOS = 0;
+ supported = false;
+ }
#endif
- // set IP TOS (type-of-service) field
- if (isOverrideTOS(mSettings) || (tos > 0)) {
+ if (supported) {
int reqtos = tos;
Socklen_t len = sizeof(reqtos);
- int rc = setsockopt(mSettings->mSock, IPPROTO_IP, IP_TOS,
- reinterpret_cast<char*>(&reqtos), len);
- WARN_errno(rc == SOCKET_ERROR, "setsockopt IP_TOS");
- rc = getsockopt(mSettings->mSock, IPPROTO_IP, IP_TOS,
- reinterpret_cast<char*>(&reqtos), &len);
- WARN_errno(rc == SOCKET_ERROR, "getsockopt IP_TOS");
- WARN((reqtos != tos), "IP_TOS setting failed");
+ int rc = setsockopt(mSettings->mSock, (isIPV6(mSettings) ? IPPROTO_IPV6 : IPPROTO_IP), \
+ (isIPV6(mSettings) ? IPV6_TCLASS : IP_TOS), reinterpret_cast<char*>(&reqtos), len);
+ WARN_errno(rc == SOCKET_ERROR, (isIPV6(mSettings) ? "setsockopt IPV6_TCLASS" : "setsockopt IP_TOS"));
+ rc = getsockopt(mSettings->mSock, (isIPV6(mSettings) ? IPPROTO_IPV6 : IPPROTO_IP), \
+ (isIPV6(mSettings) ? IPV6_TCLASS : IP_TOS), reinterpret_cast<char*>(&reqtos), &len);
+ WARN_errno(rc == SOCKET_ERROR, (isIPV6(mSettings) ? "getsockopt IPV6_TCLASS" : "getsockopt IP_TOS"));
+ if (reqtos != tos) {
+ char warnbuf[256];
+ snprintf(warnbuf, sizeof(warnbuf), "Warning: IP_TOS set to 0x%x, request for setting to 0x%x", reqtos, tos);
+ warnbuf[sizeof(warnbuf)-1] = '\0';
+ WARN(1, warnbuf);
+ mSettings->mTOS = reqtos;
+ }
}
+ }
+}
+
+/*
+ * Networking tools can now establish thousands of flows, each of them
+ * with a different delay, simulating real world conditions.
+ *
+ * This requires FQ packet scheduler or a EDT-enabled NIC.
+ *
+ * TCP_TX_DELAY socket option, to set a delay in usec units.
+ * Note that FQ packet scheduler limits might need some tweaking :
+ *
+ * man tc-fq
+ *
+ * PARAMETERS
+ * limit
+ * Hard limit on the real queue size. When this limit is
+ * reached, new packets are dropped. If the value is lowered,
+ * packets are dropped so that the new limit is met. Default
+ * is 10000 packets.
+ *
+ * flow_limit
+ * Hard limit on the maximum number of packets queued per
+ * flow. Default value is 100.
+ *
+ * Use of TCP_TX_DELAY option will increase number of skbs in FQ qdisc,
+ * so packets would be dropped if any of the previous limit is hit.
+ * Using big delays might very well trigger
+ * old bugs in TSO auto defer logic and/or sndbuf limited detection.
+ ^
+ * [root@rjm-nas rjmcmahon]# tc qdisc replace dev enp4s0 root fq
+ * [root@rjm-nas rjmcmahon]# tc qdisc replace dev enp2s0 root fq
+ */
+void SetSocketTcpTxDelay(struct thread_Settings *mSettings, int delay) {
+#ifdef TCP_TX_DELAY
+#if HAVE_DECL_TCP_TX_DELAY
+ int rc = setsockopt(mSettings->mSock, IPPROTO_TCP, TCP_TX_DELAY, &delay, sizeof(delay));
+ if (rc == SOCKET_ERROR) {
+ fprintf(stderr, "Fail on TCP_TX_DELAY for sock %d\n", mSettings->mSock);
+ }
+#ifdef HAVE_THREAD_DEBUG
+ else {
+ Socklen_t len = sizeof(delay);
+ rc = getsockopt(mSettings->mSock, IPPROTO_TCP, TCP_TX_DELAY, reinterpret_cast<char*>(&delay), &len);
+ thread_debug("TCP_TX_DELAY set to %d for sock %d", (int) delay, mSettings->mSock);
+ }
+#endif
+#endif
#endif
}
+void sol_bindtodevice (struct thread_Settings *inSettings) {
+ char *device = (inSettings->mThreadMode == kMode_Client) ? inSettings->mIfrnametx : inSettings->mIfrname;
+ if (device) {
+#if (HAVE_DECL_SO_BINDTODEVICE)
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", device);
+ if (setsockopt(inSettings->mSock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {
+ char *buf;
+ int len = snprintf(NULL, 0, "%s %s", "bind to device", device);
+ len++; // Trailing null byte + extra
+ buf = static_cast<char *>(malloc(len));
+ len = snprintf(buf, len, "%s %s", "bind to device", device);
+ WARN_errno(1, buf);
+ free(buf);
+ }
+#else
+ fprintf(stderr, "bind to device not supported\n");
+#endif
+
+ }
+}
+
+void SetSocketBindToDeviceIfNeeded (struct thread_Settings *inSettings) {
+ if (!isMulticast(inSettings)) {
+ // typically requires root privileges for unicast bind to device
+ sol_bindtodevice(inSettings);
+ }
+#ifndef WIN32
+ else { // multicast bind below
+ if (inSettings->mThreadMode != kMode_Client) {
+ // multicast on the server uses iperf_multicast_join for device binding
+ // found in listener code, do nothing and return
+ return;
+ }
+ // Handle client side bind to device for multicast
+ if (!isIPV6(inSettings)) {
+ // v4 tries with the -B ip first, then legacy socket bind
+ if (!((inSettings->mLocalhost != NULL) && iperf_multicast_sendif_v4(inSettings))) {
+ if (inSettings->mIfrnametx != NULL) {
+ sol_bindtodevice(inSettings);
+ }
+ }
+ } else {
+ if (!((inSettings->mIfrnametx != NULL) && iperf_multicast_sendif_v6(inSettings))) {
+ if (inSettings->mIfrnametx != NULL) {
+ sol_bindtodevice(inSettings);
+ }
+ }
+ }
+ }
+#endif
+}
/*
* Set a socket to blocking or non-blocking
-*
+ *
* Returns true on success, or false if there was an error
*/
bool setsock_blocking (int fd, bool blocking) {
diff --git a/src/ReportOutputs.c b/src/ReportOutputs.c
index e977433..2e34cb5 100644
--- a/src/ReportOutputs.c
+++ b/src/ReportOutputs.c
@@ -51,6 +51,7 @@
#include "Locale.h"
#include "SocketAddr.h"
#include "iperf_formattime.h"
+#include "dscp.h"
// These static variables are not thread safe but ok to use becase only
// the repoter thread usses them
@@ -68,6 +69,8 @@ static int HEADING_FLAG(report_bw_jitter_loss) = 0;
static int HEADING_FLAG(report_bw_read_enhanced) = 0;
static int HEADING_FLAG(report_bw_read_enhanced_netpwr) = 0;
static int HEADING_FLAG(report_bw_write_enhanced) = 0;
+static int HEADING_FLAG(report_bw_write_enhanced_fq) = 0;
+static int HEADING_FLAG(report_bw_write_fq) = 0;
static int HEADING_FLAG(report_write_enhanced_write) = 0;
static int HEADING_FLAG(report_bw_write_enhanced_netpwr) = 0;
static int HEADING_FLAG(report_bw_pps_enhanced) = 0;
@@ -81,7 +84,6 @@ static int HEADING_FLAG(report_frame_tcp_enhanced) = 0;
static int HEADING_FLAG(report_frame_read_tcp_enhanced_triptime) = 0;
static int HEADING_FLAG(report_udp_fullduplex) = 0;
static int HEADING_FLAG(report_sumcnt_bw) = 0;
-static int HEADING_FLAG(report_sumcnt_udp_fullduplex) = 0;
static int HEADING_FLAG(report_sumcnt_bw_read_enhanced) = 0;
static int HEADING_FLAG(report_sumcnt_bw_read_triptime) = 0;
static int HEADING_FLAG(report_sumcnt_bw_write_enhanced) = 0;
@@ -94,16 +96,21 @@ static int HEADING_FLAG(report_burst_write_tcp) = 0;
static int HEADING_FLAG(report_bw_isoch_enhanced_netpwr) = 0;
static int HEADING_FLAG(report_sumcnt_udp_enhanced) = 0;
static int HEADING_FLAG(report_sumcnt_udp_triptime) = 0;
+static int HEADING_FLAG(reportCSV_bw_read_enhanced) = 0;
+static int HEADING_FLAG(reportCSV_bw_write_enhanced) = 0;
+static int HEADING_FLAG(reportCSV_bw_jitter_loss_pps) = 0;
+static int HEADING_FLAG(reportCSV_client_bb_bw_tcp) = 0;
void reporter_default_heading_flags (int flag) {
HEADING_FLAG(report_bw) = flag;
HEADING_FLAG(report_client_bb_bw) = flag;
HEADING_FLAG(report_sumcnt_bw) = flag;
- HEADING_FLAG(report_sumcnt_udp_fullduplex) = flag;
HEADING_FLAG(report_bw_jitter_loss) = flag;
HEADING_FLAG(report_bw_read_enhanced) = flag;
HEADING_FLAG(report_bw_read_enhanced_netpwr) = flag;
HEADING_FLAG(report_bw_write_enhanced) = flag;
+ HEADING_FLAG(report_bw_write_enhanced_fq) = flag;
+ HEADING_FLAG(report_bw_write_fq) = flag;
HEADING_FLAG(report_write_enhanced_write) = flag;
HEADING_FLAG(report_write_enhanced_isoch) = flag;
HEADING_FLAG(report_bw_write_enhanced_netpwr) = flag;
@@ -126,7 +133,30 @@ void reporter_default_heading_flags (int flag) {
HEADING_FLAG(report_bw_isoch_enhanced_netpwr) = flag;
HEADING_FLAG(report_sumcnt_udp_enhanced) = flag;
HEADING_FLAG(report_sumcnt_udp_triptime) = flag;
+ HEADING_FLAG(reportCSV_bw_read_enhanced) = 0;
+ HEADING_FLAG(reportCSV_bw_write_enhanced) = 0;
+ HEADING_FLAG(reportCSV_bw_jitter_loss_pps) = 0;
+ HEADING_FLAG(reportCSV_client_bb_bw_tcp) = 0;
}
+
+//
+// flush when
+//
+// o) it's a final report
+// o) this is the sum report (all preceding interval reports need flush)
+// o) below the flush rate limiter
+//
+#define FLUSH_RATE_LIMITER 1000 //units is microseconds
+static inline void cond_flush (struct TransferInfo *stats) {
+ static struct timeval prev={0,0};
+ struct timeval now;
+ TimeGetNow(now);
+ if (stats->final || (stats->type == SUM_REPORT) || !(TimeDifferenceUsec(now, prev) < FLUSH_RATE_LIMITER)) {
+ fflush(stdout);
+ prev = now;
+ }
+}
+
static inline void _print_stats_common (struct TransferInfo *stats) {
assert(stats!=NULL);
outbuffer[0] = '\0';
@@ -145,13 +175,13 @@ static inline void _output_outoforder(struct TransferInfo *stats) {
if (stats->cntOutofOrder > 0) {
printf(report_outoforder,
stats->common->transferIDStr, stats->ts.iStart,
- stats->ts.iEnd, stats->cntOutofOrder);
+ stats->ts.iEnd, stats->cntOutofOrder, (stats->common->Omit ? report_omitted : ""));
}
if (stats->l2counts.cnt) {
printf(report_l2statistics,
stats->common->transferIDStr, stats->ts.iStart,
stats->ts.iEnd, stats->l2counts.cnt, stats->l2counts.lengtherr,
- stats->l2counts.udpcsumerr, stats->l2counts.unknown);
+ stats->l2counts.udpcsumerr, stats->l2counts.unknown, (stats->common->Omit ? report_omitted : ""));
}
}
@@ -209,29 +239,29 @@ static inline void set_netpowerbuf(double meantransit, struct TransferInfo *stat
void tcp_output_fullduplex (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_bw);
_print_stats_common(stats);
- printf(report_bw_sum_fullduplex_format, stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd, outbuffer, outbufferext);
- fflush(stdout);
+ printf(report_bw_sum_fullduplex_format, stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd, outbuffer, outbufferext, (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void tcp_output_fullduplex_sum (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_bw);
_print_stats_common(stats);
- printf(report_sum_bw_format, stats->ts.iStart, stats->ts.iEnd, outbuffer, outbufferext);
- fflush(stdout);
+ printf(report_sum_bw_format, stats->ts.iStart, stats->ts.iEnd, outbuffer, outbufferext, (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void tcp_output_fullduplex_enhanced (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_bw);
_print_stats_common(stats);
- printf(report_bw_sum_fullduplex_enhanced_format, stats->common->transferID, stats->ts.iStart, stats->ts.iEnd, outbuffer, outbufferext);
- fflush(stdout);
+ printf(report_bw_sum_fullduplex_enhanced_format, stats->common->transferID, stats->ts.iStart, stats->ts.iEnd, outbuffer, outbufferext, (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void tcp_output_read (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_bw);
_print_stats_common(stats);
- printf(report_bw_format, stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd, outbuffer, outbufferext);
- fflush(stdout);
+ printf(report_bw_format, stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd, outbuffer, outbufferext, (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
//TCP read or server output
void tcp_output_read_enhanced (struct TransferInfo *stats) {
@@ -248,8 +278,9 @@ void tcp_output_read_enhanced (struct TransferInfo *stats) {
stats->sock_callstats.read.bins[4],
stats->sock_callstats.read.bins[5],
stats->sock_callstats.read.bins[6],
- stats->sock_callstats.read.bins[7]);
- fflush(stdout);
+ stats->sock_callstats.read.bins[7],
+ (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void tcp_output_read_triptime (struct TransferInfo *stats) {
double meantransit;
@@ -279,7 +310,8 @@ void tcp_output_read_triptime (struct TransferInfo *stats) {
stats->sock_callstats.read.bins[4],
stats->sock_callstats.read.bins[5],
stats->sock_callstats.read.bins[6],
- stats->sock_callstats.read.bins[7]);
+ stats->sock_callstats.read.bins[7],
+ (stats->common->Omit ? report_omitted : ""));
} else {
meantransit = (stats->transit.total.cnt > 0) ? (stats->transit.total.sum / stats->transit.total.cnt) : 0;
set_netpowerbuf(meantransit, stats);
@@ -302,12 +334,13 @@ void tcp_output_read_triptime (struct TransferInfo *stats) {
stats->sock_callstats.read.bins[4],
stats->sock_callstats.read.bins[5],
stats->sock_callstats.read.bins[6],
- stats->sock_callstats.read.bins[7]);
+ stats->sock_callstats.read.bins[7],
+ (stats->common->Omit ? report_omitted : ""));
}
if (stats->framelatency_histogram) {
histogram_print(stats->framelatency_histogram, stats->ts.iStart, stats->ts.iEnd);
}
- fflush(stdout);
+ cond_flush(stats);
}
void tcp_output_read_enhanced_isoch (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_bw_isoch_enhanced_netpwr);
@@ -334,7 +367,8 @@ void tcp_output_read_enhanced_isoch (struct TransferInfo *stats) {
stats->sock_callstats.read.bins[4],
stats->sock_callstats.read.bins[5],
stats->sock_callstats.read.bins[6],
- stats->sock_callstats.read.bins[7]);
+ stats->sock_callstats.read.bins[7],
+ (stats->common->Omit ? report_omitted : ""));
} else {
meantransit = (stats->isochstats.transit.total.cnt > 0) ? (stats->isochstats.transit.total.sum / stats->isochstats.transit.total.cnt) : 0;
set_netpowerbuf(meantransit, stats);
@@ -356,12 +390,13 @@ void tcp_output_read_enhanced_isoch (struct TransferInfo *stats) {
stats->sock_callstats.read.bins[4],
stats->sock_callstats.read.bins[5],
stats->sock_callstats.read.bins[6],
- stats->sock_callstats.read.bins[7]);
+ stats->sock_callstats.read.bins[7],
+ (stats->common->Omit ? report_omitted : ""));
}
if (stats->framelatency_histogram) {
histogram_print(stats->framelatency_histogram, stats->ts.iStart, stats->ts.iEnd);
}
- fflush(stdout);
+ cond_flush(stats);
}
void tcp_output_frame_read (struct TransferInfo *stats) {
@@ -378,8 +413,9 @@ void tcp_output_frame_read (struct TransferInfo *stats) {
stats->sock_callstats.read.bins[4],
stats->sock_callstats.read.bins[5],
stats->sock_callstats.read.bins[6],
- stats->sock_callstats.read.bins[7]);
- fflush(stdout);
+ stats->sock_callstats.read.bins[7],
+ (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void tcp_output_frame_read_triptime (struct TransferInfo *stats) {
fprintf(stderr, "FIXME\n");
@@ -403,7 +439,8 @@ void tcp_output_burst_read (struct TransferInfo *stats) {
stats->sock_callstats.read.bins[5],
stats->sock_callstats.read.bins[6],
stats->sock_callstats.read.bins[7],
- netpower_buf);
+ netpower_buf,
+ (stats->common->Omit ? report_omitted : ""));
} else {
printf(report_burst_read_tcp_final_format,
stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd,
@@ -420,9 +457,10 @@ void tcp_output_burst_read (struct TransferInfo *stats) {
stats->sock_callstats.read.bins[4],
stats->sock_callstats.read.bins[5],
stats->sock_callstats.read.bins[6],
- stats->sock_callstats.read.bins[7]);
+ stats->sock_callstats.read.bins[7],
+ (stats->common->Omit ? report_omitted : ""));
}
- fflush(stdout);
+ cond_flush(stats);
}
//TCP write or client output
@@ -431,8 +469,8 @@ void tcp_output_write (struct TransferInfo *stats) {
_print_stats_common(stats);
printf(report_bw_format, stats->common->transferIDStr,
stats->ts.iStart, stats->ts.iEnd,
- outbuffer, outbufferext);
- fflush(stdout);
+ outbuffer, outbufferext, (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void tcp_output_write_bb (struct TransferInfo *stats) {
@@ -448,18 +486,35 @@ void tcp_output_write_bb (struct TransferInfo *stats) {
rps_string[sizeof(rps_string) - 1] = '\0';
#if HAVE_TCP_STATS
- printf(report_client_bb_bw_format, stats->common->transferIDStr,
- stats->ts.iStart, stats->ts.iEnd,
- outbuffer, outbufferext,
- stats->bbrtt.total.cnt,
- (stats->bbrtt.total.mean * 1e3),
- (stats->bbrtt.total.cnt < 2) ? 0 : (stats->bbrtt.total.min * 1e3),
- (stats->bbrtt.total.cnt < 2) ? 0 : (stats->bbrtt.total.max * 1e3),
- (stats->bbrtt.total.cnt < 2) ? 0 : 1e3 * (sqrt(stats->bbrtt.total.m2 / (stats->bbrtt.total.cnt - 1))),
- stats->sock_callstats.write.tcpstats.retry,
- stats->sock_callstats.write.tcpstats.cwnd,
- stats->sock_callstats.write.tcpstats.rtt,
- rps_string);
+ if (!stats->final) {
+ printf(report_client_bb_bw_format, stats->common->transferIDStr,
+ stats->ts.iStart, stats->ts.iEnd,
+ outbuffer, outbufferext,
+ stats->bbrtt.total.cnt,
+ (stats->bbrtt.total.mean * 1e3),
+ (stats->bbrtt.total.cnt < 2) ? 0 : (stats->bbrtt.total.min * 1e3),
+ (stats->bbrtt.total.cnt < 2) ? 0 : (stats->bbrtt.total.max * 1e3),
+ (stats->bbrtt.total.cnt < 2) ? 0 : 1e3 * (sqrt(stats->bbrtt.total.m2 / (stats->bbrtt.total.cnt - 1))),
+ stats->sock_callstats.write.tcpstats.retry,
+ stats->sock_callstats.write.tcpstats.cwnd,
+ stats->sock_callstats.write.tcpstats.cwnd_packets,
+ stats->sock_callstats.write.tcpstats.rtt,
+ stats->sock_callstats.write.tcpstats.rttvar,
+ rps_string,
+ (stats->common->Omit ? report_omitted : ""));
+ } else {
+ printf(report_client_bb_bw_final_format, stats->common->transferIDStr,
+ stats->ts.iStart, stats->ts.iEnd,
+ outbuffer, outbufferext,
+ stats->bbrtt.total.cnt,
+ (stats->bbrtt.total.mean * 1e3),
+ (stats->bbrtt.total.cnt < 2) ? 0 : (stats->bbrtt.total.min * 1e3),
+ (stats->bbrtt.total.cnt < 2) ? 0 : (stats->bbrtt.total.max * 1e3),
+ (stats->bbrtt.total.cnt < 2) ? 0 : 1e3 * (sqrt(stats->bbrtt.total.m2 / (stats->bbrtt.total.cnt - 1))),
+ stats->sock_callstats.write.tcpstats.retry,
+ rps_string,
+ (stats->common->Omit ? report_omitted : ""));
+ }
#else
printf(report_client_bb_bw_format, stats->common->transferIDStr,
stats->ts.iStart, stats->ts.iEnd,
@@ -469,7 +524,8 @@ void tcp_output_write_bb (struct TransferInfo *stats) {
(stats->bbrtt.total.cnt < 2) ? 0 : (stats->bbrtt.total.min * 1e3),
(stats->bbrtt.total.cnt < 2) ? 0 : (stats->bbrtt.total.max * 1e3),
(stats->bbrtt.total.cnt < 2) ? 0 : 1e3 * (sqrt(stats->bbrtt.total.m2 / (stats->bbrtt.total.cnt - 1))),
- rps_string);
+ rps_string,
+ (stats->common->Omit ? report_omitted : ""));
#endif
if (isTripTime(stats->common)) {
printf(report_client_bb_bw_triptime_format, stats->common->transferIDStr,
@@ -487,11 +543,23 @@ void tcp_output_write_bb (struct TransferInfo *stats) {
(stats->bbasym.total.cnt < 2) ? 0 : (stats->bbasym.total.min * 1e3),
(stats->bbasym.total.cnt < 2) ? 0 : (stats->bbasym.total.max * 1e3),
(stats->bbasym.total.cnt < 2) ? 0 : 1e3 * (sqrt(stats->bbasym.total.m2 / (stats->bbasym.total.cnt - 1))),
- rps_string);
+ (stats->common->Omit ? report_omitted : ""));
+ }
+ if (stats->bbowdto_histogram) {
+ stats->bbowdto_histogram->final = 1;
+ histogram_print(stats->bbowdto_histogram, stats->ts.iStart, stats->ts.iEnd);
+ }
+ if (stats->bbowdfro_histogram) {
+ stats->bbowdfro_histogram->final = 1;
+ histogram_print(stats->bbowdfro_histogram, stats->ts.iStart, stats->ts.iEnd);
}
if (stats->bbrtt_histogram) {
+ stats->bbrtt_histogram->final = 1;
histogram_print(stats->bbrtt_histogram, stats->ts.iStart, stats->ts.iEnd);
}
+ if (isTripTime(stats->common) && (stats->bb_clocksync_error > 0)) {
+ printf(report_client_bb_triptime_clocksync_error, stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd, stats->bb_clocksync_error);
+ }
} else {
double rps = ((stats->bbrtt.current.cnt > 0) && (stats->iBBrunning > 0)) ? ((double) stats->bbrtt.current.cnt / stats->iBBrunning) : 0;
if (rps < 10)
@@ -511,8 +579,11 @@ void tcp_output_write_bb (struct TransferInfo *stats) {
(stats->bbrtt.current.cnt < 2) ? 0 : 1e3 * (sqrt(stats->bbrtt.current.m2 / (stats->bbrtt.current.cnt - 1))),
stats->sock_callstats.write.tcpstats.retry,
stats->sock_callstats.write.tcpstats.cwnd,
+ stats->sock_callstats.write.tcpstats.cwnd_packets,
stats->sock_callstats.write.tcpstats.rtt,
- rps_string);
+ stats->sock_callstats.write.tcpstats.rttvar,
+ rps_string,
+ (stats->common->Omit ? report_omitted : ""));
#else
printf(report_client_bb_bw_format, stats->common->transferIDStr,
stats->ts.iStart, stats->ts.iEnd,
@@ -522,10 +593,43 @@ void tcp_output_write_bb (struct TransferInfo *stats) {
(stats->bbrtt.current.cnt < 2) ? 0 : (stats->bbrtt.current.min * 1e3),
(stats->bbrtt.current.cnt < 2) ? 0 : (stats->bbrtt.current.max * 1e3),
(stats->bbrtt.current.cnt < 2) ? 0 : 1e3 * (sqrt(stats->bbrtt.current.m2 / (stats->bbrtt.current.cnt - 1))),
- rps_string);
+ rps_string,
+ (stats->common->Omit ? report_omitted : ""));
#endif
+ if (isTripTime(stats->common)) {
+ printf(report_client_bb_bw_triptime_format, stats->common->transferIDStr,
+ stats->ts.iStart, stats->ts.iEnd,
+ stats->bbowdto.current.cnt,
+ (stats->bbowdto.current.mean * 1e3),
+ (stats->bbowdto.current.cnt < 2) ? 0 : (stats->bbowdto.current.min * 1e3),
+ (stats->bbowdto.current.cnt < 2) ? 0 : (stats->bbowdto.current.max * 1e3),
+ (stats->bbowdto.current.cnt < 2) ? 0 : 1e3 * (sqrt(stats->bbowdto.current.m2 / (stats->bbowdto.current.cnt - 1))),
+ (stats->bbowdfro.current.mean * 1e3),
+ (stats->bbowdfro.current.cnt < 2) ? 0 : (stats->bbowdfro.current.min * 1e3),
+ (stats->bbowdfro.current.cnt < 2) ? 0 : (stats->bbowdfro.current.max * 1e3),
+ (stats->bbowdfro.current.cnt < 2) ? 0 : 1e3 * (sqrt(stats->bbowdfro.current.m2 / (stats->bbowdfro.current.cnt - 1))),
+ (stats->bbasym.current.mean * 1e3),
+ (stats->bbasym.current.cnt < 2) ? 0 : (stats->bbasym.current.min * 1e3),
+ (stats->bbasym.current.cnt < 2) ? 0 : (stats->bbasym.current.max * 1e3),
+ (stats->bbasym.current.cnt < 2) ? 0 : 1e3 * (sqrt(stats->bbasym.current.m2 / (stats->bbasym.current.cnt - 1))),
+ (stats->common->Omit ? report_omitted : ""));
+ }
+ if (isHistogram(stats->common)) {
+ if (stats->bbowdto_histogram) {
+ stats->bbowdto_histogram->final = 0;
+ histogram_print(stats->bbowdto_histogram, stats->ts.iStart, stats->ts.iEnd);
+ }
+ if (stats->bbowdfro_histogram) {
+ stats->bbowdfro_histogram->final = 0;
+ histogram_print(stats->bbowdfro_histogram, stats->ts.iStart, stats->ts.iEnd);
+ }
+ if (stats->bbrtt_histogram) {
+ stats->bbrtt_histogram->final = 0;
+ histogram_print(stats->bbrtt_histogram, stats->ts.iStart, stats->ts.iEnd);
+ }
+ }
}
- fflush(stdout);
+ cond_flush(stats);
}
void tcp_output_burst_write (struct TransferInfo *stats) {
@@ -542,16 +646,18 @@ void tcp_output_burst_write (struct TransferInfo *stats) {
stats->sock_callstats.write.tcpstats.retry,
stats->sock_callstats.write.tcpstats.cwnd,
stats->sock_callstats.write.tcpstats.rtt,
- netpower_buf);
+ netpower_buf,
+ (stats->common->Omit ? report_omitted : ""));
#else
printf(report_burst_write_tcp_format, stats->common->transferIDStr,
stats->ts.iStart, stats->ts.iEnd,
outbuffer, outbufferext,
stats->transit.current.mean,
stats->sock_callstats.write.WriteCnt,
- stats->sock_callstats.write.WriteErr);
+ stats->sock_callstats.write.WriteErr,
+ (stats->common->Omit ? report_omitted : ""));
#endif
- fflush(stdout);
+ cond_flush(stats);
}
void tcp_output_write_enhanced (struct TransferInfo *stats) {
@@ -562,37 +668,121 @@ void tcp_output_write_enhanced (struct TransferInfo *stats) {
stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd,
outbuffer, outbufferext,
stats->sock_callstats.write.WriteCnt,
- stats->sock_callstats.write.WriteErr);
+ stats->sock_callstats.write.WriteErr,
+ (stats->common->Omit ? report_omitted : ""));
#else
set_netpowerbuf(stats->sock_callstats.write.tcpstats.rtt * 1e-6, stats);
- if (stats->sock_callstats.write.tcpstats.cwnd > 0) {
- printf(report_bw_write_enhanced_format,
+#if HAVE_STRUCT_TCP_INFO_TCPI_SND_CWND
+ printf(report_bw_write_enhanced_format,
+ stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd,
+ outbuffer, outbufferext,
+ stats->sock_callstats.write.WriteCnt,
+ stats->sock_callstats.write.WriteErr,
+ stats->sock_callstats.write.tcpstats.retry,
+#if HAVE_TCP_INFLIGHT
+ stats->sock_callstats.write.tcpstats.bytes_in_flight,
+ stats->sock_callstats.write.tcpstats.packets_in_flight,
+#endif
+ stats->sock_callstats.write.tcpstats.cwnd,
+ stats->sock_callstats.write.tcpstats.cwnd_packets,
+ stats->sock_callstats.write.tcpstats.rtt,
+ stats->sock_callstats.write.tcpstats.rttvar,
+ netpower_buf,
+ (stats->common->Omit ? report_omitted : ""));
+#else
+ printf(report_bw_write_enhanced_nocwnd_format,
+ stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd,
+ outbuffer, outbufferext,
+ stats->sock_callstats.write.WriteCnt,
+ stats->sock_callstats.write.WriteErr,
+ stats->sock_callstats.write.tcpstats.retry,
+ stats->sock_callstats.write.tcpstats.rtt,
+ stats->sock_callstats.write.tcpstats.rttvar,
+ netpower_buf,
+ (stats->common->Omit ? report_omitted : ""));
+#endif
+#endif
+#if HAVE_DECL_TCP_NOTSENT_LOWAT
+ if (stats->latency_histogram) {
+ histogram_print(stats->latency_histogram, stats->ts.iStart, stats->ts.iEnd);
+ }
+#endif
+ cond_flush(stats);
+}
+
+void tcp_output_write_enhanced_fq (struct TransferInfo *stats) {
+#if (HAVE_DECL_SO_MAX_PACING_RATE)
+ _print_stats_common(stats);
+ char pacingrate[40];
+ if (!stats->final) {
+ byte_snprintf(pacingrate, sizeof(pacingrate), stats->FQPacingRateCurrent, 'a');
+ pacingrate[39] = '\0';
+ } else {
+ pacingrate[0] = '\0';
+ }
+#if !(HAVE_TCP_STATS)
+ HEADING_PRINT_COND(report_bw_write_fq);
+ printf(report_bw_write_fq_format,
+ stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd,
+ outbuffer, outbufferext,
+ stats->sock_callstats.write.WriteCnt,
+ stats->sock_callstats.write.WriteErr,
+ pacingrate,
+ (stats->common->Omit ? report_omitted : ""));
+#else
+ HEADING_PRINT_COND(report_bw_write_enhanced_fq);
+ set_netpowerbuf(stats->sock_callstats.write.tcpstats.rtt * 1e-6, stats);
+#if HAVE_STRUCT_TCP_INFO_TCPI_SND_CWND
+ if (!stats->final) {
+ printf(report_bw_write_enhanced_fq_format,
stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd,
outbuffer, outbufferext,
stats->sock_callstats.write.WriteCnt,
stats->sock_callstats.write.WriteErr,
stats->sock_callstats.write.tcpstats.retry,
+#if HAVE_TCP_INFLIGHT
+ stats->sock_callstats.write.tcpstats.bytes_in_flight,
+ stats->sock_callstats.write.tcpstats.packets_in_flight,
+#endif
stats->sock_callstats.write.tcpstats.cwnd,
+ stats->sock_callstats.write.tcpstats.cwnd_packets,
stats->sock_callstats.write.tcpstats.rtt,
stats->sock_callstats.write.tcpstats.rttvar,
- netpower_buf);
+ pacingrate, netpower_buf,
+ (stats->common->Omit ? report_omitted : ""));
} else {
- printf(report_bw_write_enhanced_nocwnd_format,
+ printf(report_bw_write_enhanced_fq_final_format,
stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd,
outbuffer, outbufferext,
stats->sock_callstats.write.WriteCnt,
stats->sock_callstats.write.WriteErr,
stats->sock_callstats.write.tcpstats.retry,
+ stats->sock_callstats.write.tcpstats.cwnd,
stats->sock_callstats.write.tcpstats.rtt,
- netpower_buf);
+ stats->sock_callstats.write.tcpstats.rttvar,
+ netpower_buf,
+ (stats->common->Omit ? report_omitted : ""));
}
+#else
+ printf(report_bw_write_enhanced_nocwnd_format,
+ stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd,
+ outbuffer, outbufferext,
+ stats->sock_callstats.write.WriteCnt,
+ stats->sock_callstats.write.WriteErr,
+ stats->sock_callstats.write.tcpstats.retry,
+ stats->sock_callstats.write.tcpstats.rtt,
+ stats->sock_callstats.write.tcpstats.rttvar,
+ netpower_buf,
+ (stats->common->Omit ? report_omitted : ""));
+#endif
#endif
#if HAVE_DECL_TCP_NOTSENT_LOWAT
if (stats->latency_histogram) {
histogram_print(stats->latency_histogram, stats->ts.iStart, stats->ts.iEnd);
}
#endif
- fflush(stdout);
+ cond_flush(stats);
+#endif
}
void tcp_output_write_enhanced_write (struct TransferInfo *stats) {
@@ -608,39 +798,48 @@ void tcp_output_write_enhanced_write (struct TransferInfo *stats) {
stats->write_mmm.current.min * 1e3,
stats->write_mmm.current.max * 1e3,
(stats->write_mmm.current.cnt < 2) ? 0 : (1e-3 * sqrt(stats->write_mmm.current.m2 / (stats->write_mmm.current.cnt - 1))),
- stats->write_mmm.current.cnt);
+ stats->write_mmm.current.cnt,
+ (stats->common->Omit ? report_omitted : ""));
#else
set_netpowerbuf(stats->sock_callstats.write.tcpstats.rtt * 1e-6, stats);
- if (stats->sock_callstats.write.tcpstats.cwnd > 0) {
- printf(report_write_enhanced_write_format,
- stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd,
- outbuffer, outbufferext,
- stats->sock_callstats.write.WriteCnt,
- stats->sock_callstats.write.WriteErr,
- stats->sock_callstats.write.tcpstats.retry,
- stats->sock_callstats.write.tcpstats.cwnd,
- stats->sock_callstats.write.tcpstats.rtt,
- netpower_buf,
- stats->write_mmm.current.mean * 1e-3,
- stats->write_mmm.current.min * 1e-3,
- stats->write_mmm.current.max * 1e-3,
- (stats->write_mmm.current.cnt < 2) ? 0 : (1e-3 * sqrt(stats->write_mmm.current.m2 / (stats->write_mmm.current.cnt - 1))),
- stats->write_mmm.current.cnt);
- } else {
- printf(report_write_enhanced_nocwnd_write_format,
- stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd,
- outbuffer, outbufferext,
- stats->sock_callstats.write.WriteCnt,
- stats->sock_callstats.write.WriteErr,
- stats->sock_callstats.write.tcpstats.retry,
- stats->sock_callstats.write.tcpstats.rtt,
- netpower_buf,
- stats->write_mmm.current.mean * 1e3,
- stats->write_mmm.current.min * 1e3,
- stats->write_mmm.current.max * 1e3,
- (stats->write_mmm.current.cnt < 2) ? 0 : (1e3 * sqrt(stats->write_mmm.current.m2 / (stats->write_mmm.current.cnt - 1))),
- stats->write_mmm.current.cnt);
- }
+#if HAVE_STRUCT_TCP_INFO_TCPI_SND_CWND
+ printf(report_write_enhanced_write_format,
+ stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd,
+ outbuffer, outbufferext,
+ stats->sock_callstats.write.WriteCnt,
+ stats->sock_callstats.write.WriteErr,
+ stats->sock_callstats.write.tcpstats.retry,
+#if HAVE_TCP_INFLIGHT
+ stats->sock_callstats.write.tcpstats.bytes_in_flight,
+ stats->sock_callstats.write.tcpstats.packets_in_flight,
+#endif
+ stats->sock_callstats.write.tcpstats.cwnd,
+ stats->sock_callstats.write.tcpstats.cwnd_packets,
+ stats->sock_callstats.write.tcpstats.rtt,
+ stats->sock_callstats.write.tcpstats.rttvar,
+ netpower_buf,
+ stats->write_mmm.current.mean * 1e-3,
+ stats->write_mmm.current.min * 1e-3,
+ stats->write_mmm.current.max * 1e-3,
+ (stats->write_mmm.current.cnt < 2) ? 0 : (1e-3 * sqrt(stats->write_mmm.current.m2 / (stats->write_mmm.current.cnt - 1))),
+ stats->write_mmm.current.cnt,
+ (stats->common->Omit ? report_omitted : ""));
+#else
+ printf(report_write_enhanced_nocwnd_write_format,
+ stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd,
+ outbuffer, outbufferext,
+ stats->sock_callstats.write.WriteCnt,
+ stats->sock_callstats.write.WriteErr,
+ stats->sock_callstats.write.tcpstats.retry,
+ stats->sock_callstats.write.tcpstats.rtt,
+ stats->sock_callstats.write.tcpstats.rttvar,
+ netpower_buf,
+ stats->write_mmm.current.mean * 1e3,
+ stats->write_mmm.current.min * 1e3,
+ stats->write_mmm.current.max * 1e3,
+ (stats->write_mmm.current.cnt < 2) ? 0 : (1e3 * sqrt(stats->write_mmm.current.m2 / (stats->write_mmm.current.cnt - 1))),
+ stats->write_mmm.current.cnt, (stats->common->Omit ? report_omitted : ""));
+#endif
#endif
if (stats->latency_histogram) {
histogram_print(stats->latency_histogram, stats->ts.iStart, stats->ts.iEnd);
@@ -648,7 +847,7 @@ void tcp_output_write_enhanced_write (struct TransferInfo *stats) {
if (stats->write_histogram) {
histogram_print(stats->write_histogram, stats->ts.iStart, stats->ts.iEnd);
}
- fflush(stdout);
+ cond_flush(stats);
}
void tcp_output_write_enhanced_isoch (struct TransferInfo *stats) {
@@ -660,38 +859,41 @@ void tcp_output_write_enhanced_isoch (struct TransferInfo *stats) {
outbuffer, outbufferext,
stats->sock_callstats.write.WriteCnt,
stats->sock_callstats.write.WriteErr,
- stats->isochstats.cntFrames, stats->isochstats.cntFramesMissed, stats->isochstats.cntSlips);
+ stats->isochstats.cntFrames, stats->isochstats.cntFramesMissed, stats->isochstats.cntSlips, (stats->common->Omit ? report_omitted : ""));
#else
set_netpowerbuf(stats->sock_callstats.write.tcpstats.rtt * 1e-6, stats);
- if (stats->sock_callstats.write.tcpstats.cwnd > 0) {
- printf(report_write_enhanced_isoch_format,
- stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd,
- outbuffer, outbufferext,
- stats->sock_callstats.write.WriteCnt,
- stats->sock_callstats.write.WriteErr,
- stats->sock_callstats.write.tcpstats.retry,
- stats->sock_callstats.write.tcpstats.cwnd,
- stats->sock_callstats.write.tcpstats.rtt,
- stats->isochstats.cntFrames, stats->isochstats.cntFramesMissed, stats->isochstats.cntSlips,
- netpower_buf);
- } else {
- printf(report_write_enhanced_isoch_nocwnd_format,
- stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd,
- outbuffer, outbufferext,
- stats->sock_callstats.write.WriteCnt,
- stats->sock_callstats.write.WriteErr,
- stats->sock_callstats.write.tcpstats.retry,
- stats->sock_callstats.write.tcpstats.rtt,
- stats->isochstats.cntFrames, stats->isochstats.cntFramesMissed, stats->isochstats.cntSlips,
- netpower_buf);
- }
+#if HAVE_STRUCT_TCP_INFO_TCPI_SND_CWND
+ printf(report_write_enhanced_isoch_format,
+ stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd,
+ outbuffer, outbufferext,
+ stats->sock_callstats.write.WriteCnt,
+ stats->sock_callstats.write.WriteErr,
+ stats->sock_callstats.write.tcpstats.retry,
+ stats->sock_callstats.write.tcpstats.cwnd,
+ stats->sock_callstats.write.tcpstats.cwnd_packets,
+ stats->sock_callstats.write.tcpstats.rtt,
+ stats->sock_callstats.write.tcpstats.rttvar,
+ stats->isochstats.cntFrames, stats->isochstats.cntFramesMissed, stats->isochstats.cntSlips,
+ netpower_buf,(stats->common->Omit ? report_omitted : ""));
+#else
+ printf(report_write_enhanced_isoch_nocwnd_format,
+ stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd,
+ outbuffer, outbufferext,
+ stats->sock_callstats.write.WriteCnt,
+ stats->sock_callstats.write.WriteErr,
+ stats->sock_callstats.write.tcpstats.retry,
+ stats->sock_callstats.write.tcpstats.rtt,
+ stats->sock_callstats.write.tcpstats.rttvar,
+ stats->isochstats.cntFrames, stats->isochstats.cntFramesMissed, stats->isochstats.cntSlips,
+ netpower_buf,(stats->common->Omit ? report_omitted : ""));
+#endif
#endif
#if HAVE_DECL_TCP_NOTSENT_LOWAT
if (stats->latency_histogram) {
histogram_print(stats->latency_histogram, stats->ts.iStart, stats->ts.iEnd);
}
#endif
- fflush(stdout);
+ cond_flush(stats);
}
@@ -700,50 +902,65 @@ void udp_output_fullduplex (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_udp_fullduplex);
_print_stats_common(stats);
printf(report_udp_fullduplex_format, stats->common->transferIDStr, stats->ts.iStart, stats->ts.iEnd, outbuffer, outbufferext, \
- stats->cntDatagrams, (stats->cntIPG && (stats->IPGsum > 0.0) ? (stats->cntIPG / stats->IPGsum) : 0.0));
- fflush(stdout);
+ stats->cntDatagrams, (stats->cntIPG && (stats->IPGsum > 0.0) ? (stats->cntIPG / stats->IPGsum) : 0.0),(stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void udp_output_fullduplex_enhanced (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_udp_fullduplex);
_print_stats_common(stats);
printf(report_udp_fullduplex_enhanced_format, stats->common->transferID, stats->ts.iStart, stats->ts.iEnd, outbuffer, outbufferext, \
- stats->cntDatagrams, (stats->cntIPG && (stats->IPGsum > 0.0) ? (stats->cntIPG / stats->IPGsum) : 0.0));
- fflush(stdout);
+ stats->cntDatagrams, (stats->cntIPG && (stats->IPGsum > 0.0) ? (stats->cntIPG / stats->IPGsum) : 0.0),(stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void udp_output_fullduplex_sum (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_udp_fullduplex);
_print_stats_common(stats);
printf(report_udp_fullduplex_sum_format, stats->ts.iStart, stats->ts.iEnd, outbuffer, outbufferext, \
- stats->cntDatagrams, (stats->cntIPG && (stats->IPGsum > 0.0) ? (stats->cntIPG / stats->IPGsum) : 0.0));
- fflush(stdout);
+ stats->cntDatagrams, (stats->cntIPG && (stats->IPGsum > 0.0) ? (stats->cntIPG / stats->IPGsum) : 0.0),(stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void udp_output_read (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_bw_jitter_loss);
_print_stats_common(stats);
- printf(report_bw_jitter_loss_format, stats->common->transferIDStr,
- stats->ts.iStart, stats->ts.iEnd,
- outbuffer, outbufferext,
- (stats->final) ? ((stats->inline_jitter.total.sum / (double) stats->inline_jitter.total.cnt) * 1e3) : (stats->jitter * 1e3), \
- stats->cntError, stats->cntDatagrams,
- (100.0 * stats->cntError) / stats->cntDatagrams);
+ if (!stats->cntIPG) {
+ printf(report_bw_jitter_loss_format, stats->common->transferIDStr,
+ stats->ts.iStart, stats->ts.iEnd,
+ outbuffer, outbufferext,
+ 0.0, stats->cntError,
+ stats->cntDatagrams,
+ 0.0,(stats->common->Omit ? report_omitted : ""));
+ } else {
+ printf(report_bw_jitter_loss_format, stats->common->transferIDStr,
+ stats->ts.iStart, stats->ts.iEnd,
+ outbuffer, outbufferext,
+ (stats->final) ? ((stats->inline_jitter.total.sum / (double) stats->inline_jitter.total.cnt) * 1e3) : (stats->jitter * 1e3), \
+ stats->cntError, stats->cntDatagrams,
+ (100.0 * stats->cntError) / stats->cntDatagrams, (stats->common->Omit ? report_omitted : ""));
+ }
_output_outoforder(stats);
- fflush(stdout);
+ cond_flush(stats);
}
void udp_output_read_triptime (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_bw_jitter_loss_enhanced_triptime);
_print_stats_common(stats);
+
if (!stats->cntIPG) {
printf(report_bw_jitter_loss_suppress_enhanced_format, stats->common->transferIDStr,
stats->ts.iStart, stats->ts.iEnd,
outbuffer, outbufferext,
0.0, stats->cntError,
stats->cntDatagrams,
- 0.0,0.0,0.0,0.0,0.0,0.0);
+ stats->sock_callstats.read.cntRead,
+ stats->sock_callstats.read.cntReadTimeo,
+#if HAVE_DECL_MSG_TRUNC
+ stats->sock_callstats.read.cntReadErrLen,
+#endif
+ 0.0,0.0,0.0,0.0,0.0,0.0,(stats->common->Omit ? report_omitted : ""));
} else {
if ((stats->transit.current.min > UNREALISTIC_LATENCYMINMAX) ||
(stats->transit.current.min < UNREALISTIC_LATENCYMINMIN)) {
@@ -753,7 +970,14 @@ void udp_output_read_triptime (struct TransferInfo *stats) {
(stats->final) ? ((stats->inline_jitter.total.sum / (double) stats->inline_jitter.total.cnt) * 1e3) : (stats->jitter * 1e3),
stats->cntError, stats->cntDatagrams,
(100.0 * stats->cntError) / stats->cntDatagrams,
- (stats->cntIPG / stats->IPGsum));
+ (stats->cntIPG / stats->IPGsum),
+ stats->sock_callstats.read.cntRead,
+#if HAVE_DECL_MSG_TRUNC
+ stats->sock_callstats.read.cntReadTimeo,
+ stats->sock_callstats.read.cntReadErrLen,(stats->common->Omit ? report_omitted : ""));
+#else
+ stats->sock_callstats.read.cntReadTimeo, (stats->common->Omit ? report_omitted : ""));
+#endif
} else {
double meantransit;
double variance;
@@ -785,7 +1009,12 @@ void udp_output_read_triptime (struct TransferInfo *stats) {
(stats->cntIPG / stats->IPGsum),
stats->cntIPG,
llaw_bufstr,
- netpower_buf);
+ stats->sock_callstats.read.cntRead,
+ stats->sock_callstats.read.cntReadTimeo,
+#if HAVE_DECL_MSG_TRUNC
+ stats->sock_callstats.read.cntReadErrLen,
+#endif
+ netpower_buf, (stats->common->Omit ? report_omitted : ""));
}
}
if (stats->latency_histogram) {
@@ -795,7 +1024,7 @@ void udp_output_read_triptime (struct TransferInfo *stats) {
histogram_print(stats->jitter_histogram, stats->ts.iStart, stats->ts.iEnd);
}
_output_outoforder(stats);
- fflush(stdout);
+ cond_flush(stats);
}
void udp_output_read_enhanced (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_bw_jitter_loss_enhanced);
@@ -806,7 +1035,12 @@ void udp_output_read_enhanced (struct TransferInfo *stats) {
outbuffer, outbufferext,
0.0, stats->cntError,
stats->cntDatagrams,
- 0.0,0.0,0.0,0.0,0.0,0.0);
+ stats->sock_callstats.read.cntRead,
+ stats->sock_callstats.read.cntReadTimeo,
+#if HAVE_DECL_MSG_TRUNC
+ stats->sock_callstats.read.cntReadErrLen,
+#endif
+ 0.0,0.0,0.0,0.0,0.0,0.0, (stats->common->Omit ? report_omitted : ""));
} else {
if ((stats->transit.current.min > UNREALISTIC_LATENCYMINMAX) ||
(stats->transit.current.min < UNREALISTIC_LATENCYMINMIN)) {
@@ -816,7 +1050,14 @@ void udp_output_read_enhanced (struct TransferInfo *stats) {
(stats->final) ? ((stats->inline_jitter.total.sum / (double) stats->inline_jitter.total.cnt) * 1e3) : (stats->jitter * 1e3),
stats->cntError, stats->cntDatagrams,
(100.0 * stats->cntError) / stats->cntDatagrams,
- (stats->cntIPG / stats->IPGsum));
+ (stats->cntIPG / stats->IPGsum),
+ stats->sock_callstats.read.cntRead,
+#if HAVE_DECL_MSG_TRUNC
+ stats->sock_callstats.read.cntReadTimeo,
+ stats->sock_callstats.read.cntReadErrLen, (stats->common->Omit ? report_omitted : ""));
+#else
+ stats->sock_callstats.read.cntReadTimeo, (stats->common->Omit ? report_omitted : ""));
+#endif
} else {
double meantransit;
double variance;
@@ -841,7 +1082,12 @@ void udp_output_read_enhanced (struct TransferInfo *stats) {
((stats->final ? stats->transit.total.max : stats->transit.current.max) * 1e3),
(stats->final ? (stats->transit.total.cnt < 2) : (stats->transit.current.cnt < 2)) ? 0 : (1e3 * variance), // convert from sec to ms
(stats->cntIPG / stats->IPGsum),
- netpower_buf);
+ stats->sock_callstats.read.cntRead,
+ stats->sock_callstats.read.cntReadTimeo,
+#if HAVE_DECL_MSG_TRUNC
+ stats->sock_callstats.read.cntReadErrLen,
+#endif
+ netpower_buf, (stats->common->Omit ? report_omitted : ""));
}
}
if (stats->latency_histogram) {
@@ -851,7 +1097,7 @@ void udp_output_read_enhanced (struct TransferInfo *stats) {
histogram_print(stats->jitter_histogram, stats->ts.iStart, stats->ts.iEnd);
}
_output_outoforder(stats);
- fflush(stdout);
+ cond_flush(stats);
}
void udp_output_read_triptime_isoch (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_bw_jitter_loss_enhanced_isoch_triptime);
@@ -876,7 +1122,7 @@ void udp_output_read_triptime_isoch (struct TransferInfo *stats) {
(stats->final) ? ((stats->inline_jitter.total.sum / (double) stats->inline_jitter.total.cnt) * 1e3) : (stats->jitter * 1e3),
stats->cntError, stats->cntDatagrams,
(100.0 * stats->cntError) / stats->cntDatagrams,
- (stats->cntIPG / stats->IPGsum));
+ (stats->cntIPG / stats->IPGsum), (stats->common->Omit ? report_omitted : ""));
} else {
double frame_meantransit = (stats->isochstats.transit.current.cnt > 0) ? (stats->isochstats.transit.current.sum / stats->isochstats.transit.current.cnt) : 0;
double meantransit = (stats->transit.current.cnt > 0) ? (stats->transit.current.sum / stats->transit.current.cnt) : 0;
@@ -897,7 +1143,7 @@ void udp_output_read_triptime_isoch (struct TransferInfo *stats) {
stats->isochstats.transit.current.min * 1e3,
stats->isochstats.transit.current.max * 1e3,
(stats->isochstats.transit.current.cnt < 2) ? 0 : 1e3 * (sqrt(stats->isochstats.transit.current.m2 / (stats->isochstats.transit.current.cnt - 1))),
- netpower_buf);
+ netpower_buf, (stats->common->Omit ? report_omitted : ""));
#if 0
if (stats->final) {
printf("***** Jitter MMM = %f/%f/%f\n",stats->inline_jitter.total.mean, stats->inline_jitter.total.min, stats->inline_jitter.total.max);
@@ -915,15 +1161,15 @@ void udp_output_read_triptime_isoch (struct TransferInfo *stats) {
histogram_print(stats->framelatency_histogram, stats->ts.iStart, stats->ts.iEnd);
}
_output_outoforder(stats);
- fflush(stdout);
+ cond_flush(stats);
}
void udp_output_write (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_bw);
_print_stats_common(stats);
printf(report_bw_format, stats->common->transferIDStr,
stats->ts.iStart, stats->ts.iEnd,
- outbuffer, outbufferext);
- fflush(stdout);
+ outbuffer, outbufferext, (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void udp_output_write_enhanced (struct TransferInfo *stats) {
@@ -934,8 +1180,9 @@ void udp_output_write_enhanced (struct TransferInfo *stats) {
outbuffer, outbufferext,
stats->sock_callstats.write.WriteCnt,
stats->sock_callstats.write.WriteErr,
- (stats->cntIPG ? (stats->cntIPG / stats->IPGsum) : 0.0));
- fflush(stdout);
+ stats->sock_callstats.write.WriteTimeo,
+ (stats->cntIPG ? (stats->cntIPG / stats->IPGsum) : 0.0), (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void udp_output_write_enhanced_isoch (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_bw_pps_enhanced_isoch);
@@ -946,8 +1193,8 @@ void udp_output_write_enhanced_isoch (struct TransferInfo *stats) {
stats->sock_callstats.write.WriteCnt,
stats->sock_callstats.write.WriteErr,
(stats->cntIPG ? (stats->cntIPG / stats->IPGsum) : 0.0),
- stats->isochstats.cntFrames, stats->isochstats.cntFramesMissed, stats->isochstats.cntSlips);
- fflush(stdout);
+ stats->isochstats.cntFrames, stats->isochstats.cntFramesMissed, stats->isochstats.cntSlips, (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
// Sum reports
@@ -958,121 +1205,123 @@ void udp_output_sum_read (struct TransferInfo *stats) {
stats->ts.iStart, stats->ts.iEnd,
outbuffer, outbufferext,
stats->cntError, stats->cntDatagrams,
- (100.0 * stats->cntError) / stats->cntDatagrams);
+ ((100.0 * stats->cntError) / stats->cntDatagrams),
+ (stats->common->Omit ? report_omitted : ""));
if ((stats->cntOutofOrder > 0) && stats->final) {
printf(report_sum_outoforder,
stats->ts.iStart,
- stats->ts.iEnd, stats->cntOutofOrder);
+ stats->ts.iEnd, stats->cntOutofOrder, (stats->common->Omit ? report_omitted : ""));
}
- fflush(stdout);
+ cond_flush(stats);
}
void udp_output_sumcnt (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_sumcnt_bw);
_print_stats_common(stats);
- printf(report_sumcnt_bw_format, stats->threadcnt,
+ printf(report_sumcnt_bw_format, stats->slot_thread_downcount,
stats->ts.iStart, stats->ts.iEnd,
- outbuffer, outbufferext);
- if ((stats->cntOutofOrder > 0) && stats->final) {
+ outbuffer, outbufferext, (stats->common->Omit ? report_omitted : ""));
+ if ((stats->cntOutofOrder > 0) && stats->final) {
if (isSumOnly(stats->common)) {
printf(report_sumcnt_outoforder,
- stats->threadcnt,
+ stats->threadcnt_final,
stats->ts.iStart,
- stats->ts.iEnd, stats->cntOutofOrder);
+ stats->ts.iEnd, stats->cntOutofOrder, (stats->common->Omit ? report_omitted : ""));
} else {
printf(report_outoforder,
stats->common->transferIDStr, stats->ts.iStart,
- stats->ts.iEnd, stats->cntOutofOrder);
+ stats->ts.iEnd, stats->cntOutofOrder, (stats->common->Omit ? report_omitted : ""));
}
}
- fflush(stdout);
+ cond_flush(stats);
}
void udp_output_sumcnt_enhanced (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_sumcnt_bw_jitter_loss);
_print_stats_common(stats);
- printf(report_sumcnt_bw_jitter_loss_format, stats->threadcnt, stats->ts.iStart, stats->ts.iEnd, outbuffer, outbufferext, \
- stats->cntError, stats->cntDatagrams, (stats->cntIPG && (stats->IPGsum > 0.0) ? (stats->cntIPG / stats->IPGsum) : 0.0));
+ printf(report_sumcnt_bw_jitter_loss_format, (stats->final ? stats->threadcnt_final: stats->slot_thread_downcount), stats->ts.iStart, stats->ts.iEnd, outbuffer, outbufferext, \
+ stats->cntError, stats->cntDatagrams, (stats->cntIPG && (stats->IPGsum > 0.0) ? (stats->cntIPG / stats->IPGsum) : 0.0), (stats->common->Omit ? report_omitted : ""));
if ((stats->cntOutofOrder > 0) && stats->final) {
if (isSumOnly(stats->common)) {
printf(report_sumcnt_outoforder,
- stats->threadcnt,
+ (stats->final ? stats->threadcnt_final: stats->slot_thread_downcount),
stats->ts.iStart,
- stats->ts.iEnd, stats->cntOutofOrder);
+ stats->ts.iEnd, stats->cntOutofOrder, (stats->common->Omit ? report_omitted : ""));
} else {
printf(report_sum_outoforder,
stats->ts.iStart,
- stats->ts.iEnd, stats->cntOutofOrder);
+ stats->ts.iEnd, stats->cntOutofOrder,(stats->common->Omit ? report_omitted : ""));
}
}
- fflush(stdout);
+ cond_flush(stats);
}
void udp_output_sumcnt_read_enhanced (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_sumcnt_bw_read_enhanced);
_print_stats_common(stats);
- printf(report_sumcnt_bw_read_enhanced_format, stats->threadcnt,
+ printf(report_sumcnt_bw_read_enhanced_format, (stats->final ? stats->threadcnt_final: stats->slot_thread_downcount),
stats->ts.iStart, stats->ts.iEnd,
outbuffer, outbufferext,
(stats->final) ? ((stats->inline_jitter.total.sum / (double) stats->inline_jitter.total.cnt) * 1e3) : (stats->jitter * 1e3), \
stats->cntError, stats->cntDatagrams,
- (100.0 * stats->cntError) / stats->cntDatagrams);
+ (100.0 * stats->cntError) / stats->cntDatagrams, (stats->common->Omit ? report_omitted : ""));
if ((stats->cntOutofOrder > 0) && stats->final) {
if (isSumOnly(stats->common)) {
printf(report_sumcnt_outoforder,
- stats->threadcnt,
+ (stats->final ? stats->threadcnt_final: stats->slot_thread_downcount),
stats->ts.iStart,
- stats->ts.iEnd, stats->cntOutofOrder);
+ stats->ts.iEnd, stats->cntOutofOrder, (stats->common->Omit ? report_omitted : ""));
} else {
printf(report_sum_outoforder,
stats->ts.iStart,
- stats->ts.iEnd, stats->cntOutofOrder);
+ stats->ts.iEnd, stats->cntOutofOrder, (stats->common->Omit ? report_omitted : ""));
}
}
- fflush(stdout);
+ cond_flush(stats);
}
void udp_output_sumcnt_read_triptime (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_sumcnt_udp_triptime);
_print_stats_common(stats);
- printf(report_sumcnt_udp_triptime_format, stats->threadcnt, stats->ts.iStart, stats->ts.iEnd, outbuffer, outbufferext, \
- stats->cntError, stats->cntDatagrams, stats->cntIPG, (stats->final ? stats->fInP : stats->iInP), (stats->cntIPG && (stats->IPGsum > 0.0) ? (stats->cntIPG / stats->IPGsum) : 0.0));
- if ((stats->cntOutofOrder > 0) && stats->final) {
+ printf(report_sumcnt_udp_triptime_format, (stats->final ? stats->threadcnt_final: stats->slot_thread_downcount), stats->ts.iStart, stats->ts.iEnd, outbuffer, outbufferext, \
+ stats->cntError, stats->cntDatagrams, stats->cntIPG, (stats->final ? stats->fInP : stats->iInP), \
+ (stats->cntIPG && (stats->IPGsum > 0.0) ? (stats->cntIPG / stats->IPGsum) : 0.0), (stats->common->Omit ? report_omitted : ""));
+ if ((stats->cntOutofOrder > 0) && stats->final) {
if (isSumOnly(stats->common)) {
printf(report_sumcnt_outoforder,
- stats->threadcnt,
+ stats->threadcnt_final,
stats->ts.iStart,
- stats->ts.iEnd, stats->cntOutofOrder);
+ stats->ts.iEnd, stats->cntOutofOrder, (stats->common->Omit ? report_omitted : ""));
} else {
printf(report_sum_outoforder,
stats->ts.iStart,
- stats->ts.iEnd, stats->cntOutofOrder);
+ stats->ts.iEnd, stats->cntOutofOrder, (stats->common->Omit ? report_omitted : ""));
}
}
- fflush(stdout);
+ cond_flush(stats);
}
void udp_output_sum_write (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_bw);
_print_stats_common(stats);
printf(report_sum_bw_format, stats->ts.iStart, stats->ts.iEnd,
- outbuffer, outbufferext);
- fflush(stdout);
+ outbuffer, outbufferext, (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void udp_output_sumcnt_write (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_sumcnt_bw);
_print_stats_common(stats);
- printf(report_sumcnt_bw_format, stats->threadcnt,
+ printf(report_sumcnt_bw_format, (stats->final ? stats->threadcnt_final: stats->slot_thread_downcount),
stats->ts.iStart, stats->ts.iEnd,
- outbuffer, outbufferext);
- fflush(stdout);
+ outbuffer, outbufferext, (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void udp_output_sum_read_enhanced (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_sumcnt_udp_enhanced);
_print_stats_common(stats);
- printf(report_sumcnt_udp_enhanced_format, stats->threadcnt,
+ printf(report_sumcnt_udp_enhanced_format, (stats->final ? stats->threadcnt_final: stats->slot_thread_downcount),
stats->ts.iStart, stats->ts.iEnd,
outbuffer, outbufferext,
stats->cntError, stats->cntDatagrams,
- (stats->cntIPG ? (stats->cntIPG / stats->IPGsum) : 0.0));
+ (stats->cntIPG ? (stats->cntIPG / stats->IPGsum) : 0.0), (stats->common->Omit ? report_omitted : ""));
if (stats->latency_histogram && stats->final) {
histogram_print(stats->latency_histogram, stats->ts.iStart, stats->ts.iEnd);
}
@@ -1082,16 +1331,16 @@ void udp_output_sum_read_enhanced (struct TransferInfo *stats) {
if ((stats->cntOutofOrder > 0) && stats->final) {
if (isSumOnly(stats->common)) {
printf(report_sumcnt_outoforder,
- stats->threadcnt,
+ stats->threadcnt_final,
stats->ts.iStart,
- stats->ts.iEnd, stats->cntOutofOrder);
+ stats->ts.iEnd, stats->cntOutofOrder, (stats->common->Omit ? report_omitted : ""));
} else {
printf(report_sum_outoforder,
stats->ts.iStart,
- stats->ts.iEnd, stats->cntOutofOrder);
+ stats->ts.iEnd, stats->cntOutofOrder, (stats->common->Omit ? report_omitted : ""));
}
}
- fflush(stdout);
+ cond_flush(stats);
}
void udp_output_sum_write_enhanced (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_bw_pps_enhanced);
@@ -1101,19 +1350,19 @@ void udp_output_sum_write_enhanced (struct TransferInfo *stats) {
outbuffer, outbufferext,
stats->sock_callstats.write.WriteCnt,
stats->sock_callstats.write.WriteErr,
- ((stats->cntIPG && (stats->IPGsum > 0.0)) ? (stats->cntIPG / stats->IPGsum) : 0.0));
- fflush(stdout);
+ ((stats->cntIPG && (stats->IPGsum > 0.0)) ? (stats->cntIPG / stats->IPGsum) : 0.0), (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void udp_output_sumcnt_write_enhanced (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_sumcnt_bw_pps_enhanced);
_print_stats_common(stats);
- printf(report_sumcnt_bw_pps_enhanced_format, stats->threadcnt,
+ printf(report_sumcnt_bw_pps_enhanced_format, (stats->final ? stats->threadcnt_final: stats->slot_thread_downcount),
stats->ts.iStart, stats->ts.iEnd,
outbuffer, outbufferext,
stats->sock_callstats.write.WriteCnt,
stats->sock_callstats.write.WriteErr,
- ((stats->cntIPG && (stats->IPGsum > 0.0)) ? (stats->cntIPG / stats->IPGsum) : 0.0));
- fflush(stdout);
+ ((stats->cntIPG && (stats->IPGsum > 0.0)) ? (stats->cntIPG / stats->IPGsum) : 0.0), (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void tcp_output_sum_read (struct TransferInfo *stats) {
@@ -1121,8 +1370,8 @@ void tcp_output_sum_read (struct TransferInfo *stats) {
_print_stats_common(stats);
printf(report_sum_bw_format,
stats->ts.iStart, stats->ts.iEnd,
- outbuffer, outbufferext);
- fflush(stdout);
+ outbuffer, outbufferext, (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void tcp_output_sum_read_enhanced (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_bw_read_enhanced);
@@ -1138,24 +1387,24 @@ void tcp_output_sum_read_enhanced (struct TransferInfo *stats) {
stats->sock_callstats.read.bins[4],
stats->sock_callstats.read.bins[5],
stats->sock_callstats.read.bins[6],
- stats->sock_callstats.read.bins[7]);
+ stats->sock_callstats.read.bins[7], (stats->common->Omit ? report_omitted : ""));
if (stats->framelatency_histogram && stats->final) {
histogram_print(stats->framelatency_histogram, stats->ts.iStart, stats->ts.iEnd);
}
- fflush(stdout);
+ cond_flush(stats);
}
void tcp_output_sumcnt_read (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_sumcnt_bw);
_print_stats_common(stats);
- printf(report_sumcnt_bw_format, stats->threadcnt,
+ printf(report_sumcnt_bw_format, (stats->final ? stats->threadcnt_final: stats->slot_thread_downcount),
stats->ts.iStart, stats->ts.iEnd,
- outbuffer, outbufferext);
- fflush(stdout);
+ outbuffer, outbufferext, (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void tcp_output_sumcnt_read_enhanced (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_sumcnt_bw_read_enhanced);
_print_stats_common(stats);
- printf(report_sumcnt_bw_read_enhanced_format, stats->threadcnt,
+ printf(report_sumcnt_bw_read_enhanced_format, (stats->final ? stats->threadcnt_final: stats->slot_thread_downcount),
stats->ts.iStart, stats->ts.iEnd,
outbuffer, outbufferext,
stats->sock_callstats.read.cntRead,
@@ -1166,15 +1415,15 @@ void tcp_output_sumcnt_read_enhanced (struct TransferInfo *stats) {
stats->sock_callstats.read.bins[4],
stats->sock_callstats.read.bins[5],
stats->sock_callstats.read.bins[6],
- stats->sock_callstats.read.bins[7]);
- fflush(stdout);
+ stats->sock_callstats.read.bins[7], (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void tcp_output_sumcnt_read_triptime (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_sumcnt_bw_read_triptime);
_print_stats_common(stats);
char llaw_bufstr[LLAWBUFSIZE];
human_format_llawbuf(llaw_bufstr, sizeof(llaw_bufstr), ((stats->final) ? stats->fInP : stats->iInP));
- printf(report_sumcnt_bw_read_triptime_format, stats->threadcnt,
+ printf(report_sumcnt_bw_read_triptime_format, (stats->final ? stats->threadcnt_final: stats->slot_thread_downcount),
stats->ts.iStart, stats->ts.iEnd,
outbuffer, outbufferext,
llaw_bufstr,
@@ -1186,8 +1435,8 @@ void tcp_output_sumcnt_read_triptime (struct TransferInfo *stats) {
stats->sock_callstats.read.bins[4],
stats->sock_callstats.read.bins[5],
stats->sock_callstats.read.bins[6],
- stats->sock_callstats.read.bins[7]);
- fflush(stdout);
+ stats->sock_callstats.read.bins[7], (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void tcp_output_sum_write (struct TransferInfo *stats) {
@@ -1195,16 +1444,16 @@ void tcp_output_sum_write (struct TransferInfo *stats) {
_print_stats_common(stats);
printf(report_sum_bw_format,
stats->ts.iStart, stats->ts.iEnd,
- outbuffer, outbufferext);
- fflush(stdout);
+ outbuffer, outbufferext, (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void tcp_output_sumcnt_write (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_sumcnt_bw);
_print_stats_common(stats);
- printf(report_sumcnt_bw_format, stats->threadcnt,
+ printf(report_sumcnt_bw_format, (stats->final ? stats->threadcnt_final: stats->slot_thread_downcount),
stats->ts.iStart, stats->ts.iEnd,
- outbuffer, outbufferext);
- fflush(stdout);
+ outbuffer, outbufferext, (stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void tcp_output_sum_write_enhanced (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_bw_write_enhanced);
@@ -1217,13 +1466,13 @@ void tcp_output_sum_write_enhanced (struct TransferInfo *stats) {
#if HAVE_TCP_STATS
,stats->sock_callstats.write.tcpstats.retry
#endif
- );
- fflush(stdout);
+ ,(stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
void tcp_output_sumcnt_write_enhanced (struct TransferInfo *stats) {
HEADING_PRINT_COND(report_sumcnt_bw_write_enhanced);
_print_stats_common(stats);
- printf(report_sumcnt_bw_write_enhanced_format, stats->threadcnt,
+ printf(report_sumcnt_bw_write_enhanced_format, (stats->final ? stats->threadcnt_final: stats->slot_thread_downcount),
stats->ts.iStart, stats->ts.iEnd,
outbuffer, outbufferext,
stats->sock_callstats.write.WriteCnt,
@@ -1231,8 +1480,8 @@ void tcp_output_sumcnt_write_enhanced (struct TransferInfo *stats) {
#if HAVE_TCP_STATS
,stats->sock_callstats.write.tcpstats.retry
#endif
- );
- fflush(stdout);
+ ,(stats->common->Omit ? report_omitted : ""));
+ cond_flush(stats);
}
// CSV outputs
@@ -1313,12 +1562,28 @@ void format_ips_port_string (struct TransferInfo *stats, bool sum) {
#endif
}
+static inline void _print_stats_csv_timestr(struct TransferInfo *stats,
+ char *timestr, int buflen)
+{
+ iperf_formattime(timestr,
+ buflen,
+ (!stats->final ? stats->ts.nextTime : stats->ts.packetTime),
+ isEnhanced(stats->common),
+ isUTC(stats->common),
+ (isEnhanced(stats->common) ? CSVTZ : CSV));
+}
+
+static inline intmax_t _print_stats_csv_speed(struct TransferInfo *stats)
+{
+ return (intmax_t) (((stats->cntBytes > 0) && (stats->ts.iEnd - stats->ts.iStart) > 0.0)
+ ? (((double)stats->cntBytes * 8.0) / (stats->ts.iEnd - stats->ts.iStart))
+ : 0);
+}
+
void udp_output_basic_csv (struct TransferInfo *stats) {
char timestr[120];
- iperf_formattime(timestr, sizeof(timestr), (!stats->final ? stats->ts.nextTime : stats->ts.packetTime), \
- isEnhanced(stats->common), isUTC(stats->common), (isEnhanced(stats->common) ? CSVTZ : CSV));
- intmax_t speed = (intmax_t) (((stats->cntBytes > 0) && (stats->ts.iEnd - stats->ts.iStart) > 0.0) ? \
- (((double)stats->cntBytes * 8.0) / (stats->ts.iEnd - stats->ts.iStart)) : 0);
+ _print_stats_csv_timestr(stats, timestr, sizeof(timestr));
+ intmax_t speed = _print_stats_csv_speed(stats);
printf(reportCSV_bw_jitter_loss_format,
timestr,
stats->csv_peer,
@@ -1331,15 +1596,14 @@ void udp_output_basic_csv (struct TransferInfo *stats) {
stats->cntError,
stats->cntDatagrams,
(100.0 * stats->cntError) / stats->cntDatagrams, stats->cntOutofOrder );
+ cond_flush(stats);
}
void udp_output_enhanced_csv (struct TransferInfo *stats) {
- char timestr[80];
- iperf_formattime(timestr, sizeof(timestr), (!stats->final ? stats->ts.nextTime : stats->ts.packetTime), \
- isEnhanced(stats->common), isUTC(stats->common),
- isEnhanced(stats->common) ? CSVTZ : CSV);
- intmax_t speed = (intmax_t) (((stats->cntBytes > 0) && (stats->ts.iEnd - stats->ts.iStart) > 0.0) ? \
- (((double)stats->cntBytes * 8.0) / (stats->ts.iEnd - stats->ts.iStart)) : 0);
+ HEADING_PRINT_COND(reportCSV_bw_jitter_loss_pps);
+ char timestr[120];
+ _print_stats_csv_timestr(stats, timestr, sizeof(timestr));
+ intmax_t speed = _print_stats_csv_speed(stats);
printf(reportCSV_bw_jitter_loss_pps_format,
timestr,
stats->csv_peer,
@@ -1356,14 +1620,13 @@ void udp_output_enhanced_csv (struct TransferInfo *stats) {
stats->sock_callstats.write.WriteCnt,
stats->sock_callstats.write.WriteErr,
(stats->cntIPG ? (stats->cntIPG / stats->IPGsum) : 0.0));
+ cond_flush(stats);
}
void tcp_output_basic_csv (struct TransferInfo *stats) {
- char timestr[80];
- iperf_formattime(timestr, sizeof(timestr), (!stats->final ? stats->ts.nextTime : stats->ts.packetTime), \
- isEnhanced(stats->common), isUTC(stats->common), (isEnhanced(stats->common) ? CSVTZ : CSV));
- intmax_t speed = (intmax_t) (((stats->cntBytes > 0) && (stats->ts.iEnd - stats->ts.iStart) > 0.0) ? \
- (((double)stats->cntBytes * 8.0) / (stats->ts.iEnd - stats->ts.iStart)) : 0);
+ char timestr[120];
+ _print_stats_csv_timestr(stats, timestr, sizeof(timestr));
+ intmax_t speed = _print_stats_csv_speed(stats);
printf(reportCSV_bw_format,
timestr,
stats->csv_peer,
@@ -1372,15 +1635,14 @@ void tcp_output_basic_csv (struct TransferInfo *stats) {
stats->ts.iEnd,
stats->cntBytes,
speed);
+ cond_flush(stats);
}
void tcp_output_read_enhanced_csv (struct TransferInfo *stats) {
+ HEADING_PRINT_COND(reportCSV_bw_read_enhanced);
char timestr[80];
- iperf_formattime(timestr, sizeof(timestr), (!stats->final ? stats->ts.nextTime : stats->ts.packetTime), \
- isEnhanced(stats->common), isUTC(stats->common),
- isEnhanced(stats->common) ? CSVTZ : CSV);
- intmax_t speed = (intmax_t) (((stats->cntBytes > 0) && (stats->ts.iEnd - stats->ts.iStart) > 0.0) ? \
- (((double)stats->cntBytes * 8.0) / (stats->ts.iEnd - stats->ts.iStart)) : 0);
+ _print_stats_csv_timestr(stats, timestr, sizeof(timestr));
+ intmax_t speed = _print_stats_csv_speed(stats);
printf(reportCSV_bw_read_enhanced_format,
timestr,
stats->csv_peer,
@@ -1398,15 +1660,14 @@ void tcp_output_read_enhanced_csv (struct TransferInfo *stats) {
stats->sock_callstats.read.bins[5],
stats->sock_callstats.read.bins[6],
stats->sock_callstats.read.bins[7]);
+ cond_flush(stats);
}
void tcp_output_write_enhanced_csv (struct TransferInfo *stats) {
- char timestr[80];
- iperf_formattime(timestr, sizeof(timestr), (!stats->final ? stats->ts.nextTime : stats->ts.packetTime), \
- isEnhanced(stats->common), isUTC(stats->common),
- isEnhanced(stats->common) ? CSVTZ : CSV);
- intmax_t speed = (intmax_t) (((stats->cntBytes > 0) && (stats->ts.iEnd - stats->ts.iStart) > 0.0) ? \
- (((double)stats->cntBytes * 8.0) / (stats->ts.iEnd - stats->ts.iStart)) : 0);
+ HEADING_PRINT_COND(reportCSV_bw_write_enhanced);
+ char timestr[120];
+ _print_stats_csv_timestr(stats, timestr, sizeof(timestr));
+ intmax_t speed = _print_stats_csv_speed(stats);
#if !(HAVE_TCP_STATS)
printf(reportCSV_bw_write_enhanced_format,
timestr,
@@ -1420,6 +1681,7 @@ void tcp_output_write_enhanced_csv (struct TransferInfo *stats) {
-1,
-1,
-1,
+ -1,
0,
0);
#else
@@ -1437,9 +1699,11 @@ void tcp_output_write_enhanced_csv (struct TransferInfo *stats) {
stats->sock_callstats.write.WriteErr,
stats->sock_callstats.write.tcpstats.retry,
-1,
+ -1,
0,
0);
- } else if (stats->sock_callstats.write.tcpstats.cwnd > 0) {
+ } else {
+#if HAVE_STRUCT_TCP_INFO_TCPI_SND_CWND
printf(reportCSV_bw_write_enhanced_format,
timestr,
stats->csv_peer,
@@ -1452,9 +1716,10 @@ void tcp_output_write_enhanced_csv (struct TransferInfo *stats) {
stats->sock_callstats.write.WriteErr,
stats->sock_callstats.write.tcpstats.retry,
stats->sock_callstats.write.tcpstats.cwnd,
+ stats->sock_callstats.write.tcpstats.cwnd_packets,
stats->sock_callstats.write.tcpstats.rtt,
stats->sock_callstats.write.tcpstats.rttvar);
- } else {
+#else
printf(reportCSV_bw_write_enhanced_format,
timestr,
stats->csv_peer,
@@ -1467,10 +1732,101 @@ void tcp_output_write_enhanced_csv (struct TransferInfo *stats) {
stats->sock_callstats.write.WriteErr,
stats->sock_callstats.write.tcpstats.retry,
-1,
+ -1,
stats->sock_callstats.write.tcpstats.rtt,
0);
+#endif
}
#endif
+ cond_flush(stats);
+}
+
+void tcp_output_write_bb_csv (struct TransferInfo *stats) {
+ HEADING_PRINT_COND(reportCSV_client_bb_bw_tcp);
+ char timestr[120];
+ _print_stats_csv_timestr(stats, timestr, sizeof(timestr));
+ intmax_t speed = _print_stats_csv_speed(stats);
+ if (stats->final) {
+ double rps = ((stats->fBBrunning > 0) && (stats->bbrtt.total.cnt > 0)) ? ((double) stats->bbrtt.total.cnt / stats->fBBrunning) : 0;
+
+#if HAVE_TCP_STATS
+ printf(reportCSV_client_bb_bw_tcp_format,
+ timestr,
+ stats->csv_peer,
+ stats->common->transferID,
+ stats->ts.iStart,
+ stats->ts.iEnd,
+ stats->cntBytes,
+ speed,
+ stats->bbrtt.total.cnt,
+ (stats->bbrtt.total.mean * 1e3),
+ (stats->bbrtt.total.cnt < 2) ? 0 : (stats->bbrtt.total.min * 1e3),
+ (stats->bbrtt.total.cnt < 2) ? 0 : (stats->bbrtt.total.max * 1e3),
+ (stats->bbrtt.total.cnt < 2) ? 0 : 1e3 * (sqrt(stats->bbrtt.total.m2 / (stats->bbrtt.total.cnt - 1))),
+ stats->sock_callstats.write.tcpstats.retry,
+ stats->sock_callstats.write.tcpstats.cwnd,
+ stats->sock_callstats.write.tcpstats.rtt,
+ rps);
+#else
+ printf(reportCSV_client_bb_bw_tcp_format,
+ timestr,
+ stats->csv_peer,
+ stats->common->transferID,
+ stats->ts.iStart,
+ stats->ts.iEnd,
+ stats->cntBytes,
+ speed,
+ stats->bbrtt.total.cnt,
+ (stats->bbrtt.total.mean * 1e3),
+ (stats->bbrtt.total.cnt < 2) ? 0 : (stats->bbrtt.total.min * 1e3),
+ (stats->bbrtt.total.cnt < 2) ? 0 : (stats->bbrtt.total.max * 1e3),
+ (stats->bbrtt.total.cnt < 2) ? 0 : 1e3 * (sqrt(stats->bbrtt.total.m2 / (stats->bbrtt.total.cnt - 1))),
+ -1,
+ -1,
+ -1,
+ rps);
+#endif
+ } else {
+ double rps = ((stats->bbrtt.current.cnt > 0) && (stats->iBBrunning > 0)) ? ((double) stats->bbrtt.current.cnt / stats->iBBrunning) : 0;
+#if HAVE_TCP_STATS
+ printf(reportCSV_client_bb_bw_tcp_format,
+ timestr,
+ stats->csv_peer,
+ stats->common->transferID,
+ stats->ts.iStart,
+ stats->ts.iEnd,
+ stats->cntBytes,
+ speed,
+ stats->bbrtt.current.cnt,
+ (stats->bbrtt.current.mean * 1e3),
+ (stats->bbrtt.current.cnt < 2) ? 0 : (stats->bbrtt.current.min * 1e3),
+ (stats->bbrtt.current.cnt < 2) ? 0 : (stats->bbrtt.current.max * 1e3),
+ (stats->bbrtt.current.cnt < 2) ? 0 : 1e3 * (sqrt(stats->bbrtt.current.m2 / (stats->bbrtt.current.cnt - 1))),
+ stats->sock_callstats.write.tcpstats.retry,
+ stats->sock_callstats.write.tcpstats.cwnd,
+ stats->sock_callstats.write.tcpstats.rtt,
+ rps);
+#else
+ printf(reportCSV_client_bb_bw_tcp_format,
+ timestr,
+ stats->csv_peer,
+ stats->common->transferID,
+ stats->ts.iStart,
+ stats->ts.iEnd,
+ stats->cntBytes,
+ speed,
+ stats->bbrtt.current.cnt,
+ (stats->bbrtt.current.mean * 1e3),
+ (stats->bbrtt.current.cnt < 2) ? 0 : (stats->bbrtt.current.min * 1e3),
+ (stats->bbrtt.current.cnt < 2) ? 0 : (stats->bbrtt.current.max * 1e3),
+ (stats->bbrtt.current.cnt < 2) ? 0 : 1e3 * (sqrt(stats->bbrtt.current.m2 / (stats->bbrtt.current.cnt - 1))),
+ -1,
+ -1,
+ -1,
+ rps);
+#endif
+ }
+ cond_flush(stats);
}
/*
@@ -1498,7 +1854,11 @@ static void reporter_output_listener_settings (struct ReportSettings *report) {
report->common->Port, report->common->PortLast, report->pid);
} else {
printf(isEnhanced(report->common) ? server_pid_port : server_port,
- (isUDP(report->common) ? "UDP" : "TCP"), report->common->Port, report->pid);
+ (isUDP(report->common) ? ((isIPV6(report->common) && isEnhanced(report->common)) ? "UDP (v6)" : "UDP") : \
+ ((isIPV6(report->common) && isEnhanced(report->common)) ? "TCP (v6)" : "TCP")), report->common->Port, report->pid);
+ }
+ if (isUDP(report->common) && isWorkingLoadUp(report->common) && isWorkingLoadDown(report->common)) {
+ printf(server_working_load_port, "TCP", report->common->Port);
}
if (report->common->Localhost != NULL) {
if (isEnhanced(report->common) && !SockAddr_isMulticast(&report->local)) {
@@ -1543,17 +1903,36 @@ static void reporter_output_listener_settings (struct ReportSettings *report) {
printf(bind_address_iface_taptun, report->common->Ifrname);
}
if (isEnhanced(report->common)) {
- byte_snprintf(outbuffer, sizeof(outbuffer), report->common->BufLen, toupper((int)report->common->Format));
- byte_snprintf(outbufferext, sizeof(outbufferext), report->common->BufLen / 8, 'A');
- outbuffer[(sizeof(outbuffer)-1)] = '\0';
- outbufferext[(sizeof(outbufferext)-1)] = '\0';
- printf("%s: %s (Dist bin width=%s)\n", server_read_size, outbuffer, outbufferext);
+ if (!(isUDP(report->common))) {
+ byte_snprintf(outbuffer, sizeof(outbuffer), report->common->BufLen, toupper((int)report->common->Format));
+ byte_snprintf(outbufferext, sizeof(outbufferext), report->common->BufLen / 8, 'A');
+ outbuffer[(sizeof(outbuffer)-1)] = '\0';
+ outbufferext[(sizeof(outbufferext)-1)] = '\0';
+ printf("%s: %s (Dist bin width=%s)\n", server_read_size, outbuffer, outbufferext);
+ } else {
+ byte_snprintf(outbuffer, sizeof(outbuffer), report->common->BufLen, 'B');
+ outbuffer[(sizeof(outbuffer)-1)] = '\0';
+ printf("%s: %s \n", server_read_size, outbuffer);
+ }
+
}
- if (isCongestionControl(report->common) && report->common->Congestion) {
- fprintf(stdout, "TCP congestion control set to %s\n", report->common->Congestion);
+#if HAVE_DECL_TCP_CONGESTION
+ if (isCongestionControl(report->common) || isEnhanced(report->common)) {
+ char cca[40] = "";
+ Socklen_t len = sizeof(cca);
+ if (getsockopt(report->common->socket, IPPROTO_TCP, TCP_CONGESTION, &cca, &len) == 0) {
+ cca[len]='\0';
+ }
+ if (report->common->Congestion) {
+ fprintf(stdout,"TCP congestion control default set to %s using %s\n", report->common->Congestion, cca);
+ } else if (strlen(cca)) {
+ fprintf(stdout,"TCP congestion control default %s\n", cca);
+ }
}
+#endif
if (isOverrideTOS(report->common)) {
- fprintf(stdout, "Reflected TOS will be set to 0x%x\n", report->common->RTOS);
+ fprintf(stdout, "Reflected TOS will be set to 0x%x (dscp=%d,ecn=%d)\n", report->common->RTOS, \
+ DSCP_VALUE(report->common->RTOS), ECN_VALUE(report->common->RTOS));
}
if (isPrintMSS(report->common)) {
if (isTCPMSS(report->common)) {
@@ -1563,7 +1942,8 @@ static void reporter_output_listener_settings (struct ReportSettings *report) {
}
}
if (report->common->TOS) {
- fprintf(stdout, "TOS will be set to 0x%x\n", report->common->TOS);
+ fprintf(stdout, "TOS will be set to 0x%x (dscp=%d,ecn=%d)\n", report->common->TOS, \
+ DSCP_VALUE(report->common->RTOS), ECN_VALUE(report->common->RTOS));
}
if (isUDP(report->common)) {
if (isSingleClient(report->common)) {
@@ -1574,7 +1954,7 @@ static void reporter_output_listener_settings (struct ReportSettings *report) {
} else if (isSingleClient(report->common)) {
fprintf(stdout, "Server set to single client traffic mode (serialize traffic tests)\n");
}
- if (isMulticast(report->common)) {
+ if (isMulticast(report->common) && (report->common->Port == report->common->PortLast)) {
fprintf(stdout, "Server set to single client traffic mode (per multicast receive)\n");
}
if (isHistogram(report->common)) {
@@ -1608,19 +1988,31 @@ static void reporter_output_client_settings (struct ReportSettings *report) {
if (!report->common->Ifrnametx) {
printf(isEnhanced(report->common) ? client_pid_port : client_port, hoststr,
(isUDP(report->common) ? "UDP" : "TCP"), report->common->Port, report->pid, \
- (!report->common->threads ? 1 : report->common->threads));
+ (!report->common->threads ? 1 : report->common->threads),
+ (!report->common->threads ? 1 : report->common->working_load_threads));
} else {
printf(client_pid_port_dev, hoststr,
(isUDP(report->common) ? "UDP" : "TCP"), report->common->Port, report->pid, \
- report->common->Ifrnametx, (!report->common->threads ? 1 : report->common->threads));
+ report->common->Ifrnametx, (!report->common->threads ? 1 : report->common->threads),
+ (!report->common->threads ? 1 : report->common->working_load_threads));
}
- if ((isEnhanced(report->common) || isNearCongest(report->common)) && !isUDP(report->common)) {
+ if ((isEnhanced(report->common) || isNearCongest(report->common)) && !isUDP(report->common) && !isBounceBack(report->common)) {
byte_snprintf(outbuffer, sizeof(outbuffer), report->common->BufLen, 'B');
outbuffer[(sizeof(outbuffer)-1)] = '\0';
- if (isTcpWriteTimes(report->common)) {
- printf("%s: %s (writetimer-enabled)\n", client_write_size, outbuffer);
+ if (!isBurstSize(report->common)) {
+ if (isTcpWriteTimes(report->common)) {
+ printf("%s: %s (write timer enabled)\n", client_write_size, outbuffer);
+ } else {
+ printf("%s: %s\n", client_write_size, outbuffer);
+ }
} else {
- printf("%s: %s\n", client_write_size, outbuffer);
+ byte_snprintf(outbufferext, sizeof(outbufferext), report->common->BurstSize, 'B');
+ outbufferext[(sizeof(outbufferext)-1)] = '\0';
+ if (isTcpWriteTimes(report->common)) {
+ printf("%s: %s Burst size: %s (write timer enabled)\n", client_write_size, outbuffer, outbufferext);
+ } else {
+ printf("%s: %s Burst size: %s\n", client_write_size, outbuffer, outbufferext);
+ }
}
}
if (isIsochronous(report->common)) {
@@ -1631,30 +2023,47 @@ static void reporter_output_client_settings (struct ReportSettings *report) {
meanbuf[39]='\0'; variancebuf[39]='\0';
printf(client_isochronous, report->isochstats.mFPS, meanbuf, variancebuf, (report->isochstats.mBurstInterval/1000.0), (report->isochstats.mBurstIPG/1000.0));
}
- if (isPeriodicBurst(report->common)) {
- char tmpbuf[40];
- byte_snprintf(tmpbuf, sizeof(tmpbuf), report->common->BurstSize, 'A');
- tmpbuf[39]='\0';
- if (report->common->bbcount) {
- printf(client_burstperiodcount, tmpbuf, report->common->bbcount, (1.0 / report->common->FPS));
- } else {
- printf(client_burstperiod, tmpbuf, (1.0 / report->common->FPS));
- }
- }
if (isBounceBack(report->common)) {
- char tmpbuf[40];
- byte_snprintf(tmpbuf, sizeof(tmpbuf), report->common->bbsize, 'A');
- tmpbuf[39]='\0';
+ char tmplbuf[40];
+ byte_snprintf(tmplbuf, sizeof(tmplbuf), report->common->bbsize, 'A');
+ tmplbuf[39]='\0';
+ char tmprbuf[40];
+ byte_snprintf(tmprbuf, sizeof(tmprbuf), report->common->bbreplysize, 'A');
+ tmprbuf[39]='\0';
if (isTcpQuickAck(report->common)) {
- printf(client_bounceback, tmpbuf, report->common->bbhold);
+ printf(client_bounceback, tmplbuf, tmprbuf, report->common->bbhold);
} else {
- printf(client_bounceback_noqack, tmpbuf, report->common->bbhold);
+ printf(client_bounceback_noqack, tmplbuf, tmprbuf, report->common->bbhold);
+ }
+ if (report->common->FPS > 0) {
+ printf(client_bbburstperiodcount, report->common->bbcount, (1.0 / report->common->FPS));
+ }
+ } else {
+ if (isPeriodicBurst(report->common) && (report->common->FPS > 0)) {
+ char tmpbuf[40];
+ byte_snprintf(tmpbuf, sizeof(tmpbuf), report->common->BurstSize, 'A');
+ tmpbuf[39]='\0';
+ if (report->common->bbcount) {
+ printf(client_burstperiodcount, tmpbuf, report->common->bbcount, (1.0 / report->common->FPS));
+ } else {
+ printf(client_burstperiod, tmpbuf, (1.0 / report->common->FPS));
+ }
}
}
if (isFQPacing(report->common)) {
- byte_snprintf(outbuffer, sizeof(outbuffer), report->common->FQPacingRate, 'a');
- outbuffer[(sizeof(outbuffer)-1)] = '\0';
- printf(client_fq_pacing,outbuffer);
+ char prate[40];
+ byte_snprintf(prate, sizeof(prate), report->common->FQPacingRate, 'a');
+ prate[39] = '\0';
+ if (isFQPacingStep(report->common)) {
+ char pratestep[40];
+ byte_snprintf(pratestep, sizeof(pratestep), report->common->FQPacingRateStep, 'a');
+ pratestep[39] = '\0';
+ printf(client_fq_pacing_step,prate, pratestep);
+ } else {
+ byte_snprintf(outbuffer, sizeof(outbuffer), report->common->FQPacingRate, 'a');
+ outbuffer[(sizeof(outbuffer)-1)] = '\0';
+ printf(client_fq_pacing,outbuffer);
+ }
}
if (isPrintMSS(report->common)) {
if (isTCPMSS(report->common)) {
@@ -1663,16 +2072,41 @@ static void reporter_output_client_settings (struct ReportSettings *report) {
printf(report_default_mss, report->sockmaxseg);
}
}
-
- if (isCongestionControl(report->common) && report->common->Congestion) {
- fprintf(stdout, "TCP congestion control set to %s\n", report->common->Congestion);
+#if HAVE_DECL_TCP_CONGESTION
+ if (isCongestionControl(report->common) || isEnhanced(report->common)) {
+ char cca[40] = "";
+ Socklen_t len = sizeof(cca);
+ if (getsockopt(report->common->socket, IPPROTO_TCP, TCP_CONGESTION, &cca, &len) == 0) {
+ cca[len]='\0';
+ }
+ if (report->common->Congestion) {
+ fprintf(stdout,"TCP congestion control set to %s using %s\n", report->common->Congestion, cca);
+ } else if (strlen(cca)) {
+ fprintf(stdout,"TCP congestion control using %s\n", cca);
+ }
+ }
+ if ((isWorkingLoadUp(report->common) || isWorkingLoadDown(report->common)) && isLoadCCA(report->common)) {
+ fprintf(stdout,"TCP working load congestion control set to %s\n", report->common->LoadCCA);
}
+#endif
if (isEnhanced(report->common)) {
+ char strtext[10];
+ if (isSetTOS(report->common)) {
+ strcpy(strtext, "set");
+ } else {
+ strcpy(strtext, "defaults");
+ }
+ fprintf(stdout, "TOS %s to 0x%x (dscp=%d,ecn=%d)", strtext, report->common->TOS, \
+ DSCP_VALUE(report->common->TOS), ECN_VALUE(report->common->TOS));
+ if (ECN_VALUE(report->common->TOS)) {
+ fprintf(stdout, " (warn ecn bits set)");
+ }
if (isNoDelay(report->common)) {
- fprintf(stdout, "TOS set to 0x%x and nodelay (Nagle off)\n", report->common->TOS);
+ fprintf(stdout," and nodelay (Nagle off)");
} else {
- fprintf(stdout, "TOS set to 0x%x (Nagle on)\n", report->common->TOS);
+ fprintf(stdout," (Nagle on)");
}
+ fprintf(stdout, "\n");
}
if (isNearCongest(report->common)) {
if (report->common->rtt_weight == NEARCONGEST_DEFAULT) {
@@ -1716,15 +2150,23 @@ static void reporter_output_client_settings (struct ReportSettings *report) {
fflush(stdout);
}
+#define MINSAMPLES_FORVARIANCE 25
void reporter_connect_printf_tcp_final (struct ConnectionInfo * report) {
- if (report->connect_times.cnt > 1) {
- double variance = (report->connect_times.cnt < 2) ? 0 : 1e3* (sqrt(report->connect_times.m2 / (report->connect_times.cnt - 1)));
+ if (report->connect_times.cnt >= MINSAMPLES_FORVARIANCE) {
+ double variance = (sqrt(report->connect_times.m2 / (report->connect_times.cnt - 1)));
fprintf(stdout, "[ CT] final connect times (min/avg/max/stdev) = %0.3f/%0.3f/%0.3f/%0.3f ms (tot/err) = %" PRIdMAX "/%" PRIdMAX "\n", \
report->connect_times.min, \
(report->connect_times.sum / report->connect_times.cnt), \
report->connect_times.max, variance, \
(report->connect_times.cnt + report->connect_times.err), \
report->connect_times.err);
+ } else if (report->connect_times.cnt > 2) {
+ fprintf(stdout, "[ CT] final connect times (min/avg/max) = %0.3f/%0.3f/%0.3f ms (tot/err) = %" PRIdMAX "/%" PRIdMAX "\n", \
+ report->connect_times.min, \
+ (report->connect_times.sum / report->connect_times.cnt), \
+ report->connect_times.max, \
+ (report->connect_times.cnt + report->connect_times.err), \
+ report->connect_times.err);
}
fflush(stdout);
}
@@ -1739,7 +2181,6 @@ void reporter_print_connection_report (struct ConnectionInfo *report) {
outbuffer[0]='\0';
outbufferext[0]='\0';
char *b = &outbuffer[0];
-
#if HAVE_DECL_TCP_WINDOW_CLAMP
if (!isUDP(report->common) && isRxClamp(report->common)) {
snprintf(b, SNBUFFERSIZE-strlen(b), " (%s%d)", "clamp=", report->common->ClampSize);
@@ -1781,9 +2222,11 @@ void reporter_print_connection_report (struct ConnectionInfo *report) {
}
if (isBounceBack(report->common)) {
if (isTcpQuickAck(report->common)) {
- snprintf(b, SNBUFFERSIZE-strlen(b), " (bb w/quickack len/hold=%d/%d)", report->common->bbsize, report->common->bbhold);
+ snprintf(b, SNBUFFERSIZE-strlen(b), " (bb w/quickack req/reply/hold=%d/%d/%d)", report->common->bbsize, \
+ report->common->bbreplysize, report->common->bbhold);
} else {
- snprintf(b, SNBUFFERSIZE-strlen(b), " (bb len/hold=%d/%d)", report->common->bbsize, report->common->bbhold);
+ snprintf(b, SNBUFFERSIZE-strlen(b), " (bb req/reply/hold=%d/%d/%d)", report->common->bbsize, \
+ report->common->bbreplysize, report->common->bbhold);
}
b += strlen(b);
}
@@ -1800,23 +2243,47 @@ void reporter_print_connection_report (struct ConnectionInfo *report) {
b += strlen(b);
}
if (isEnhanced(report->common)) {
- snprintf(b, SNBUFFERSIZE-strlen(b), " (sock=%d)", report->common->socket);;
- b += strlen(b);
+ if (isCongestionControl(report->common)) {
+#if HAVE_DECL_TCP_CONGESTION
+ char cca[40] = "";
+ Socklen_t len = sizeof(cca);
+ int rc;
+ if ((rc = getsockopt(report->common->socket, IPPROTO_TCP, TCP_CONGESTION, &cca, &len)) == 0) {
+ cca[len]='\0';
+ }
+ if (rc != SOCKET_ERROR) {
+ snprintf(b, SNBUFFERSIZE-strlen(b), " (sock=%d/%s)", report->common->socket, cca);
+ b += strlen(b);
+ }
+#endif
+ } else {
+ snprintf(b, SNBUFFERSIZE-strlen(b), " (sock=%d)", report->common->socket);
+ b += strlen(b);
+ }
}
if (isOverrideTOS(report->common)) {
if (isFullDuplex(report->common)) {
- snprintf(b, SNBUFFERSIZE-strlen(b), " (tos rx/tx=0x%x/0x%x)", report->common->TOS, report->common->RTOS);
+ snprintf(b, SNBUFFERSIZE-strlen(b), " (tos rx/tx=0x%x,dscp=%d,ecn=%d, /0x%x,dscp=%d,ecn=%d)", report->common->TOS, \
+ DSCP_VALUE(report->common->TOS), ECN_VALUE(report->common->TOS), \
+ report->common->RTOS, \
+ DSCP_VALUE(report->common->RTOS), ECN_VALUE(report->common->RTOS));
} else if (isReverse(report->common)) {
- snprintf(b, SNBUFFERSIZE-strlen(b), " (tos tx=0x%x)", report->common->TOS);
+ snprintf(b, SNBUFFERSIZE-strlen(b), " (tos rx=0x%x,dscp=%d,ecn=%d)", report->common->TOS, \
+ DSCP_VALUE(report->common->TOS), ECN_VALUE(report->common->TOS));
}
b += strlen(b);
} else if (report->common->TOS) {
if (isFullDuplex(report->common) || isBounceBack(report->common)) {
- snprintf(b, SNBUFFERSIZE-strlen(b), " (tos rx/tx=0x%x/0x%x)", report->common->TOS, report->common->TOS);
+ snprintf(b, SNBUFFERSIZE-strlen(b), " (tos rx/tx=0x%x,dscp=%d,ecn=%d/0x%x,dscp=%d,ecn=%d)", report->common->TOS, \
+ DSCP_VALUE(report->common->TOS), ECN_VALUE(report->common->TOS), \
+ report->common->TOS, \
+ DSCP_VALUE(report->common->TOS), ECN_VALUE(report->common->TOS));
} else if (isReverse(report->common)) {
- snprintf(b, SNBUFFERSIZE-strlen(b), " (tos tx=0x%x)", report->common->TOS);
+ snprintf(b, SNBUFFERSIZE-strlen(b), " (tos rx=0x%x,dscp=%d,ecn=%d)", report->common->TOS, \
+ DSCP_VALUE(report->common->TOS), ECN_VALUE(report->common->TOS));
} else {
- snprintf(b, SNBUFFERSIZE-strlen(b), " (tos rx=0x%x)", report->common->TOS);
+ snprintf(b, SNBUFFERSIZE-strlen(b), " (tos tx=0x%x,dscp=%d,ecn=%d)", report->common->TOS, \
+ DSCP_VALUE(report->common->TOS), ECN_VALUE(report->common->TOS));
}
b += strlen(b);
}
@@ -1833,13 +2300,12 @@ void reporter_print_connection_report (struct ConnectionInfo *report) {
}
#endif
#if HAVE_TCP_STATS
- if (!isUDP(report->common) && (report->tcpinitstats.isValid)) {
- snprintf(b, SNBUFFERSIZE-strlen(b), " (icwnd/mss/irtt=%u/%u/%u)", \
+ if (!isUDP(report->common) && (report->tcpinitstats.isValid) && isEnhanced(report->common)) {
+ snprintf(b, SNBUFFERSIZE-strlen(b), " (icwnd/mss/irtt=%" PRIdMAX "/%" PRIuLEAST32 "/%" PRIuLEAST32 ")", \
report->tcpinitstats.cwnd, report->tcpinitstats.mss_negotiated, report->tcpinitstats.rtt);
b += strlen(b);
}
#endif
-
if ((isFullDuplex(report->common) || !isServerReverse(report->common)) \
&& (isEnhanced(report->common) || isConnectOnly(report->common))) {
if (report->connect_timestamp.tv_sec > 0) {
@@ -1923,14 +2389,7 @@ void reporter_print_connection_report (struct ConnectionInfo *report) {
if ((report->common->ThreadMode == kMode_Client) && !isServerReverse(report->common)) {
if (isTxHoldback(report->common) || isTxStartTime(report->common)) {
struct timeval now;
-#ifdef HAVE_CLOCK_GETTIME
- struct timespec t1;
- clock_gettime(CLOCK_REALTIME, &t1);
- now.tv_sec = t1.tv_sec;
- now.tv_usec = t1.tv_nsec / 1000;
-#else
- gettimeofday(&now, NULL);
-#endif
+ TimeGetNow(now);
int seconds_from_now;
if (isTxHoldback(report->common)) {
seconds_from_now = report->txholdbacktime.tv_sec;
diff --git a/src/Reporter.c b/src/Reporter.c
index bbd6fd5..e200a80 100644
--- a/src/Reporter.c
+++ b/src/Reporter.c
@@ -82,12 +82,12 @@ static void reporter_reset_transfer_stats_client_tcp(struct TransferInfo *stats)
static void reporter_reset_transfer_stats_client_udp(struct TransferInfo *stats);
static void reporter_reset_transfer_stats_server_udp(struct TransferInfo *stats);
static void reporter_reset_transfer_stats_server_tcp(struct TransferInfo *stats);
+static void reporter_reset_transfer_stats_sum(struct TransferInfo *stats);
// code for welfornd's algorithm to produce running mean/min/max/var
static void reporter_update_mmm (struct MeanMinMaxStats *stats, double value);
static void reporter_reset_mmm (struct MeanMinMaxStats *stats);
-
// one way delay (OWD) calculations
static void reporter_handle_packet_oneway_transit(struct TransferInfo *stats, struct ReportStruct *packet);
static void reporter_handle_isoch_oneway_transit_tcp(struct TransferInfo *stats, struct ReportStruct *packet);
@@ -160,8 +160,10 @@ bool ReportPacket (struct ReporterData* data, struct ReportStruct *packet) {
if (!TimeZero(stats->ts.nextTCPSampleTime) && (TimeDifference(stats->ts.nextTCPSampleTime, packet->packetTime) < 0)) {
gettcpinfo(data->info.common->socket, &packet->tcpstats);
TimeAdd(stats->ts.nextTCPSampleTime, stats->ts.intervalTime);
+ rc = true;
} else {
gettcpinfo(data->info.common->socket, &packet->tcpstats);
+ rc = true;
}
}
#endif
@@ -194,14 +196,14 @@ bool ReportPacket (struct ReporterData* data, struct ReportStruct *packet) {
* thread to print a final report and to remove the data report from its jobq.
* It also handles the freeing reports and other closing actions
*/
-int EndJob (struct ReportHeader *reporthdr, struct ReportStruct *finalpacket) {
+bool EndJob (struct ReportHeader *reporthdr, struct ReportStruct *finalpacket) {
assert(reporthdr!=NULL);
assert(finalpacket!=NULL);
struct ReporterData *report = (struct ReporterData *) reporthdr->this_report;
struct ReportStruct packet;
memset(&packet, 0, sizeof(struct ReportStruct));
- int do_close = 1;
+ bool do_close = true;
/*
* Using PacketID of -1 ends reporting
* It pushes a "special packet" through
@@ -217,24 +219,25 @@ int EndJob (struct ReportHeader *reporthdr, struct ReportStruct *finalpacket) {
}
#endif
// clear the reporter done predicate
- report->packetring->consumerdone = 0;
+ report->packetring->consumerdone = false;
// the negative packetID is used to inform the report thread this traffic thread is done
packet.packetID = -1;
packet.packetLen = finalpacket->packetLen;
packet.packetTime = finalpacket->packetTime;
+ packet.err_readwrite = NullEvent; // this is not a real event
if (isSingleUDP(report->info.common)) {
packetring_enqueue(report->packetring, &packet);
reporter_process_transfer_report(report);
} else {
ReportPacket(report, &packet);
-#ifdef HAVE_THREAD_DEBUG
- thread_debug( "Traffic thread awaiting reporter to be done with %p and cond %p", (void *)report, (void *) report->packetring->awake_producer);
-#endif
Condition_Lock((*(report->packetring->awake_producer)));
while (!report->packetring->consumerdone) {
// This wait time is the lag between the reporter thread
// and the traffic thread, a reporter thread with lots of
// reports (e.g. fastsampling) can lag per the i/o
+#ifdef HAVE_THREAD_DEBUG
+ thread_debug( "Traffic thread awaiting reporter to be done with %p and cond %p", (void *)report, (void *) report->packetring->awake_producer);
+#endif
Condition_TimedWait(report->packetring->awake_producer, 1);
// printf("Consumer done may be stuck\n");
}
@@ -249,7 +252,7 @@ int EndJob (struct ReportHeader *reporthdr, struct ReportStruct *finalpacket) {
#endif
FreeSumReport(report->FullDuplexReport);
} else {
- do_close = 0;
+ do_close = false;
}
}
return do_close;
@@ -422,7 +425,7 @@ void reporter_spawn (struct thread_Settings *thread) {
#ifdef HAVE_THREAD_DEBUG
thread_debug( "Reporter thread started");
#endif
- if (isEnhanced(thread)) {
+ if (isEnhanced(thread) && (thread->mThreadMode == kMode_Client)) {
myConnectionReport = InitConnectOnlyReport(thread);
}
/*
@@ -480,8 +483,9 @@ void reporter_spawn (struct thread_Settings *thread) {
// Report process report returns true
// when a report needs to be removed
// from the jobq. Also, work item might
- // be removed as part of processing
- // Store a cached pointer for the linked list maitenance
+ // be free as part of its processing
+ // Store a cached pointer tmp
+ // for the next work item
struct ReportHeader *tmp = (*work_item)->next;
if (reporter_process_report(*work_item)) {
#ifdef HAVE_THREAD_DEBUG
@@ -510,11 +514,11 @@ void reporter_spawn (struct thread_Settings *thread) {
}
// The Transfer or Data report is by far the most complicated report
-int reporter_process_transfer_report (struct ReporterData *this_ireport) {
+bool reporter_process_transfer_report (struct ReporterData *this_ireport) {
assert(this_ireport != NULL);
struct TransferInfo *sumstats = (this_ireport->GroupSumReport ? &this_ireport->GroupSumReport->info : NULL);
struct TransferInfo *fullduplexstats = (this_ireport->FullDuplexReport ? &this_ireport->FullDuplexReport->info : NULL);
- int need_free = 0;
+ bool need_free = false;
// The consumption detector applies delay to the reporter
// thread when its consumption rate is too low. This allows
// the traffic threads to send aggregates vs thrash
@@ -530,7 +534,7 @@ int reporter_process_transfer_report (struct ReporterData *this_ireport) {
apply_consumption_detector();
// If there are more packets to process then handle them
struct ReportStruct *packet = NULL;
- int advance_jobq = 0;
+ bool advance_jobq = false;
while (!advance_jobq && (packet = packetring_dequeue(this_ireport->packetring))) {
// Increment the total packet count processed by this thread
// this will be used to make decisions on if the reporter
@@ -543,9 +547,21 @@ int reporter_process_transfer_report (struct ReporterData *this_ireport) {
reporter_handle_packet_tcpistats(this_ireport, packet);
}
#endif
+ if (this_ireport->transfer_interval_handler) {
+ if (sumstats && (this_ireport->packetring->uplevel != sumstats->uplevel) \
+ && (TimeDifference(sumstats->ts.nextTime, packet->packetTime) > 0)) {
+ sumstats->slot_thread_upcount++;
+#if HAVE_SUMMING_DEBUG
+ printf("**** %s upcnt (%p) pkt=%ld.%ld (up/down)=%d/%d uplevel (sum/pkt)=%d/%d\n", this_ireport->info.common->transferIDStr, (void *)this_ireport->packetring, \
+ (long) packet->packetTime.tv_sec, (long) packet->packetTime.tv_usec, sumstats->slot_thread_upcount, sumstats->slot_thread_downcount, \
+ sumstats->uplevel, this_ireport->packetring->uplevel);
+#endif
+ this_ireport->packetring->uplevel = toggleLevel(this_ireport->packetring->uplevel);
+ }
+ }
if (!(packet->packetID < 0)) {
// Check to output any interval reports,
- // bursts need to report the packet first
+ // bursts need to report the packet first
if (this_ireport->packet_handler_pre_report) {
(*this_ireport->packet_handler_pre_report)(this_ireport, packet);
}
@@ -564,8 +580,8 @@ int reporter_process_transfer_report (struct ReporterData *this_ireport) {
if (fullduplexstats)
fullduplexstats->ts.packetTime = packet->packetTime;
} else {
- need_free = 1;
- advance_jobq = 1;
+ need_free = true;
+ advance_jobq = true;
// A last packet event was detected
// printf("last packet event detected\n"); fflush(stdout);
this_ireport->reporter_thread_suspends = consumption_detector.reporter_thread_suspends;
@@ -577,7 +593,7 @@ int reporter_process_transfer_report (struct ReporterData *this_ireport) {
}
this_ireport->info.ts.packetTime = packet->packetTime;
assert(this_ireport->transfer_protocol_handler != NULL);
- (*this_ireport->transfer_protocol_handler)(this_ireport, 1);
+ (*this_ireport->transfer_protocol_handler)(this_ireport, true);
// This is a final report so set the sum report header's packet time
// Note, the thread with the max value will set this
if (fullduplexstats && isEnhanced(this_ireport->info.common)) {
@@ -587,20 +603,22 @@ int reporter_process_transfer_report (struct ReporterData *this_ireport) {
}
if (DecrSumReportRefCounter(this_ireport->FullDuplexReport) == 0) {
if (this_ireport->FullDuplexReport->transfer_protocol_sum_handler) {
- (*this_ireport->FullDuplexReport->transfer_protocol_sum_handler)(fullduplexstats, 1);
+ (*this_ireport->FullDuplexReport->transfer_protocol_sum_handler)(fullduplexstats, true);
}
// FullDuplex report gets freed by a traffic thread (per its barrier)
}
}
if (sumstats) {
- if (!this_ireport->GroupSumReport->threads_cntr_fsum)
- this_ireport->GroupSumReport->threads_cntr_fsum = this_ireport->GroupSumReport->reference.maxcount;
if (TimeDifference(sumstats->ts.packetTime, packet->packetTime) > 0) {
sumstats->ts.packetTime = packet->packetTime;
}
- if (this_ireport->GroupSumReport->transfer_protocol_sum_handler && \
- (--this_ireport->GroupSumReport->threads_cntr_fsum == 0) && (this_ireport->GroupSumReport->reference.maxcount > 1)) {
- (*this_ireport->GroupSumReport->transfer_protocol_sum_handler)(&this_ireport->GroupSumReport->info, 1);
+ if (this_ireport->GroupSumReport->transfer_protocol_sum_handler) {
+ Mutex_Lock(&this_ireport->GroupSumReport->reference.lock);
+ if ((++this_ireport->GroupSumReport->final_thread_upcount == this_ireport->GroupSumReport->reference.maxcount) && \
+ ((this_ireport->GroupSumReport->reference.maxcount > 1) || isSumOnly(this_ireport->info.common))) {
+ (*this_ireport->GroupSumReport->transfer_protocol_sum_handler)(&this_ireport->GroupSumReport->info, true);
+ }
+ Mutex_Unlock(&this_ireport->GroupSumReport->reference.lock);
}
}
}
@@ -614,17 +632,20 @@ int reporter_process_transfer_report (struct ReporterData *this_ireport) {
* can't use them anymore (except for the DATA REPORT);
*
*/
-inline int reporter_process_report (struct ReportHeader *reporthdr) {
+inline bool reporter_process_report (struct ReportHeader *reporthdr) {
assert(reporthdr != NULL);
- int done = 1;
+ bool done = true;
switch (reporthdr->type) {
case DATA_REPORT:
done = reporter_process_transfer_report((struct ReporterData *)reporthdr->this_report);
- fflush(stdout);
if (done) {
struct ReporterData *tmp = (struct ReporterData *)reporthdr->this_report;
struct PacketRing *pr = tmp->packetring;
- pr->consumerdone = 1;
+ pr->consumerdone = true;
+# ifdef HAVE_THREAD_DEBUG
+ struct ReporterData *report = (struct ReporterData *) reporthdr->this_report;
+ thread_debug( "Reporter thread signal traffic thread %p %p", (void *)report, (void *) report->packetring->awake_producer);
+#endif
// Data Reports are special because the traffic thread needs to free them, just signal
Condition_Signal(pr->awake_producer);
}
@@ -642,20 +663,23 @@ inline int reporter_process_report (struct ReportHeader *reporthdr) {
}
}
reporter_print_connection_report(creport);
- fflush(stdout);
FreeReport(reporthdr);
}
break;
case SETTINGS_REPORT:
reporter_print_settings_report((struct ReportSettings *)reporthdr->this_report);
- fflush(stdout);
FreeReport(reporthdr);
break;
case SERVER_RELAY_REPORT:
reporter_print_server_relay_report((struct ServerRelay *)reporthdr->this_report);
- fflush(stdout);
FreeReport(reporthdr);
break;
+ case STRING_REPORT:
+ if (reporthdr->this_report) {
+ printf("%s\n", (char *)reporthdr->this_report);
+ free((char *)reporthdr->this_report);
+ }
+ break;
default:
fprintf(stderr,"Invalid report type in process report %p\n", reporthdr->this_report);
assert(0);
@@ -675,7 +699,7 @@ inline int reporter_process_report (struct ReportHeader *reporthdr) {
// Reporter private routines
void reporter_handle_packet_null (struct ReporterData *data, struct ReportStruct *packet) {
}
-void reporter_transfer_protocol_null (struct ReporterData *data, int final){
+void reporter_transfer_protocol_null (struct ReporterData *data, bool final){
}
static inline void reporter_compute_packet_pps (struct TransferInfo *stats, struct ReportStruct *packet) {
@@ -694,7 +718,7 @@ static void reporter_handle_packet_oneway_transit (struct TransferInfo *stats, s
// Transit or latency updates done inline below
double transit = TimeDifference(packet->packetTime, packet->sentTime);
if (stats->latency_histogram) {
- histogram_insert(stats->latency_histogram, transit, NULL);
+ histogram_insert(stats->latency_histogram, transit, &packet->packetTime);
}
double deltaTransit;
deltaTransit = transit - stats->transit.current.last;
@@ -756,7 +780,6 @@ static void reporter_handle_packet_oneway_transit (struct TransferInfo *stats, s
}
}
-
static void reporter_handle_isoch_oneway_transit_tcp (struct TransferInfo *stats, struct ReportStruct *packet) {
// printf("fid=%lu bs=%lu remain=%lu\n", packet->frameID, packet->burstsize, packet->remaining);
if (packet->frameID && packet->transit_ready) {
@@ -908,12 +931,12 @@ static void reporter_handle_frame_isoch_oneway_transit (struct TransferInfo *sta
void reporter_handle_packet_client (struct ReporterData *data, struct ReportStruct *packet) {
struct TransferInfo *stats = &data->info;
stats->ts.packetTime = packet->packetTime;
- if (!packet->emptyreport) {
+ switch (packet->err_readwrite) {
+ case WriteSelectRetry :
+ stats->sock_callstats.write.WriteErr++;
+ stats->sock_callstats.write.totWriteErr++;
+ case WriteSuccess :
stats->total.Bytes.current += packet->packetLen;
- if (packet->errwrite && (packet->errwrite != WriteErrNoAccount)) {
- stats->sock_callstats.write.WriteErr++;
- stats->sock_callstats.write.totWriteErr++;
- }
// These are valid packets that need standard iperf accounting
stats->sock_callstats.write.WriteCnt += packet->writecnt;
stats->sock_callstats.write.totWriteCnt += packet->writecnt;
@@ -929,7 +952,20 @@ void reporter_handle_packet_client (struct ReporterData *data, struct ReportStru
histogram_insert(stats->write_histogram, (1e-6 * packet->write_time), NULL);
}
}
+ break;
+ case WriteTimeo:
+ stats->sock_callstats.write.WriteTimeo++;
+ stats->sock_callstats.write.totWriteTimeo++;
+ case WriteErrAccount :
+ stats->sock_callstats.write.WriteErr++;
+ stats->sock_callstats.write.totWriteErr++;
+ case WriteNoAccount:
+ case NullEvent:
+ break;
+ default :
+ fprintf(stderr, "Program error: invalid client packet->err_readwrite %d\n", packet->err_readwrite);
}
+
if (isUDP(stats->common)) {
stats->PacketID = packet->packetID;
reporter_compute_packet_pps(stats, packet);
@@ -945,25 +981,47 @@ void reporter_handle_packet_bb_client (struct ReporterData *data, struct ReportS
if (!packet->emptyreport && (packet->packetLen > 0)) {
stats->total.Bytes.current += packet->packetLen;
double bbrtt = TimeDifference(packet->packetTime, packet->sentTime);
- double bbowdto = TimeDifference(packet->sentTimeRX, packet->sentTime);
- double bbowdfro = TimeDifference(packet->packetTime, packet->sentTimeTX);
- double asym = bbowdfro - bbowdto;
- stats->ts.prevpacketTime = packet->packetTime;
-#if DEBUG_BB_TIMESTAMPS
- fprintf(stderr, "BB Debug: ctx=%lx.%lx srx=%lx.%lx stx=%lx.%lx crx=%lx.%lx (hex)\n", packet->sentTime.tv_sec, packet->sentTime.tv_usec, packet->sentTimeRX.tv_sec, packet->sentTimeRX.tv_usec, packet->sentTimeTX.tv_sec, packet->sentTimeTX.tv_usec, packet->packetTime.tv_sec, packet->packetTime.tv_usec);
- fprintf(stderr, "BB Debug: ctx=%ld.%ld srx=%ld.%ld stx=%ld.%ld crx=%ld.%ld\n", packet->sentTime.tv_sec, packet->sentTime.tv_usec, packet->sentTimeRX.tv_sec, packet->sentTimeRX.tv_usec, packet->sentTimeTX.tv_sec, packet->sentTimeTX.tv_usec, packet->packetTime.tv_sec, packet->packetTime.tv_usec);
- fprintf(stderr, "BB RTT=%f OWDTo=%f OWDFro=%f Asym=%f\n", bbrtt, bbowdto, bbowdfro, asym);
-#endif
stats->iBBrunning += bbrtt;
stats->fBBrunning += bbrtt;
reporter_update_mmm(&stats->bbrtt.current, bbrtt);
reporter_update_mmm(&stats->bbrtt.total, bbrtt);
- reporter_update_mmm(&stats->bbowdto.total, bbowdto);
- reporter_update_mmm(&stats->bbowdfro.total, bbowdfro);
- reporter_update_mmm(&stats->bbasym.total, fabs(asym));
if (stats->bbrtt_histogram) {
histogram_insert(stats->bbrtt_histogram, bbrtt, NULL);
}
+ if (isTripTime(stats->common)) {
+ double bbowdto = TimeDifference(packet->sentTimeRX, packet->sentTime);
+ double bbowdfro = TimeDifference(packet->packetTime, packet->sentTimeTX);
+ double asym = bbowdfro - bbowdto;
+ double bbturnaround = TimeDifference(packet->sentTimeTX, packet->sentTimeRX);
+ double bbadj = TimeDifference(packet->packetTime, packet->sentTimeRX);
+ // If you measure RTT, you can detect when clock are unsync.
+ // If you have the sent-time, rcv-time and return-time, you can check that
+ // sent-time < rcv-time < return-time. As sent-time and return-time use
+ // the same clock, you can detect any drift bigger than RTT. JT
+ //
+ // Adjust this clock A write < clock B read < Clock A read - (clock B write - clock B read)
+ if ((bbowdto < 0) || ((bbadj - bbturnaround) < 0)) {
+ stats->bb_clocksync_error++;
+ }
+ reporter_update_mmm(&stats->bbowdto.total, bbowdto);
+ reporter_update_mmm(&stats->bbowdfro.total, bbowdfro);
+ reporter_update_mmm(&stats->bbasym.total, fabs(asym));
+ reporter_update_mmm(&stats->bbowdto.current, bbowdto);
+ reporter_update_mmm(&stats->bbowdfro.current, bbowdfro);
+ reporter_update_mmm(&stats->bbasym.current, fabs(asym));
+ if (stats->bbowdto_histogram) {
+ histogram_insert(stats->bbowdto_histogram, bbowdto, NULL);
+ }
+ if (stats->bbowdfro_histogram) {
+ histogram_insert(stats->bbowdfro_histogram, bbowdfro, NULL);
+ }
+ }
+ stats->ts.prevpacketTime = packet->packetTime;
+#if DEBUG_BB_TIMESTAMPS
+ fprintf(stderr, "BB Debug: ctx=%lx.%lx srx=%lx.%lx stx=%lx.%lx crx=%lx.%lx (hex)\n", packet->sentTime.tv_sec, packet->sentTime.tv_usec, packet->sentTimeRX.tv_sec, packet->sentTimeRX.tv_usec, packet->sentTimeTX.tv_sec, packet->sentTimeTX.tv_usec, packet->packetTime.tv_sec, packet->packetTime.tv_usec);
+ fprintf(stderr, "BB Debug: ctx=%ld.%ld srx=%ld.%ld stx=%ld.%ld crx=%ld.%ld\n", packet->sentTime.tv_sec, packet->sentTime.tv_usec, packet->sentTimeRX.tv_sec, packet->sentTimeRX.tv_usec, packet->sentTimeTX.tv_sec, packet->sentTimeTX.tv_usec, packet->packetTime.tv_sec, packet->packetTime.tv_usec);
+ fprintf(stderr, "BB RTT=%f OWDTo=%f OWDFro=%f Asym=%f\n", bbrtt, bbowdto, bbowdfro, asym);
+#endif
}
}
@@ -981,8 +1039,7 @@ inline void reporter_handle_packet_server_tcp (struct ReporterData *data, struct
int bin;
stats->total.Bytes.current += packet->packetLen;
// mean min max tests
- stats->sock_callstats.read.cntRead++;
- stats->sock_callstats.read.totcntRead++;
+ stats->sock_callstats.read.ReadCnt.current++;
bin = (int)floor((packet->packetLen -1)/stats->sock_callstats.read.binsize);
if (bin < TCPREADBINCOUNT) {
stats->sock_callstats.read.bins[bin]++;
@@ -1007,8 +1064,21 @@ inline void reporter_handle_packet_server_udp (struct ReporterData *data, struct
// Hence, set the per interval min to infinity
// and the per interval max and sum to zero
reporter_reset_mmm(&stats->transit.current);
- } else if (packet->packetID > 0) {
- stats->total.Bytes.current += packet->packetLen;
+ } else if (!packet->emptyreport && (packet->packetID > 0)) {
+ bool ooo_packet = false;
+ // packet loss occured if the datagram numbers aren't sequential
+ if (packet->packetID != stats->PacketID + 1) {
+ if (packet->packetID < stats->PacketID + 1) {
+ stats->total.OutofOrder.current++;
+ ooo_packet = true;
+ } else {
+ stats->total.Lost.current += packet->packetID - stats->PacketID - 1;
+ }
+ }
+ // never decrease datagramID (e.g. if we get an out-of-order packet)
+ if (packet->packetID > stats->PacketID) {
+ stats->PacketID = packet->packetID;
+ }
// These are valid packets that need standard iperf accounting
// Do L2 accounting first (if needed)
if (packet->l2errors && (stats->total.Datagrams.current > L2DROPFILTERCOUNTER)) {
@@ -1027,20 +1097,17 @@ inline void reporter_handle_packet_server_udp (struct ReporterData *data, struct
stats->l2counts.tot_udpcsumerr++;
}
}
- // packet loss occured if the datagram numbers aren't sequential
- if (packet->packetID != stats->PacketID + 1) {
- if (packet->packetID < stats->PacketID + 1) {
- stats->total.OutofOrder.current++;
- } else {
- stats->total.Lost.current += packet->packetID - stats->PacketID - 1;
- }
+ if (packet->err_readwrite == ReadErrLen) {
+ stats->sock_callstats.read.ReadErrLenCnt.current++;
}
- // never decrease datagramID (e.g. if we get an out-of-order packet)
- if (packet->packetID > stats->PacketID) {
- stats->PacketID = packet->packetID;
+ if (!ooo_packet && \
+ ((packet->err_readwrite == ReadSuccess) ||
+ ((packet->err_readwrite == ReadErrLen) && (packet->packetLen >= sizeof(struct UDP_datagram))))) {
+ reporter_handle_packet_oneway_transit(stats, packet);
}
+ stats->total.Bytes.current += packet->packetLen;
reporter_compute_packet_pps(stats, packet);
- reporter_handle_packet_oneway_transit(stats, packet);
+
if (packet->transit_ready) {
if (isIsochronous(stats->common)) {
reporter_handle_isoch_oneway_transit_udp(stats, packet);
@@ -1049,9 +1116,14 @@ inline void reporter_handle_packet_server_udp (struct ReporterData *data, struct
}
}
}
+ if (packet->err_readwrite != ReadNoAccount) {
+ if (packet->emptyreport) {
+ stats->sock_callstats.read.ReadTimeoCnt.current++;
+ } else {
+ stats->sock_callstats.read.ReadCnt.current++;
+ }
+ }
}
-
-// This is done in reporter thread context
#if HAVE_TCP_STATS
static inline void reporter_handle_packet_tcpistats (struct ReporterData *data, struct ReportStruct *packet) {
assert(data!=NULL);
@@ -1060,12 +1132,22 @@ static inline void reporter_handle_packet_tcpistats (struct ReporterData *data,
stats->sock_callstats.write.tcpstats.retry_prev = packet->tcpstats.retry_tot;
stats->sock_callstats.write.tcpstats.retry_tot = packet->tcpstats.retry_tot;
stats->sock_callstats.write.tcpstats.cwnd = packet->tcpstats.cwnd;
+ stats->sock_callstats.write.tcpstats.cwnd_packets = packet->tcpstats.cwnd_packets;
stats->sock_callstats.write.tcpstats.rtt = packet->tcpstats.rtt;
stats->sock_callstats.write.tcpstats.rttvar = packet->tcpstats.rttvar;
+#if HAVE_TCP_INFLIGHT
+ stats->sock_callstats.write.tcpstats.packets_in_flight = packet->tcpstats.packets_in_flight;
+ stats->sock_callstats.write.tcpstats.bytes_in_flight = packet->tcpstats.bytes_in_flight;
+#else
+ stats->sock_callstats.write.tcpstats.bytes_in_flight = -1;
+ stats->sock_callstats.write.tcpstats.packets_in_flight = -1;
+#endif
+#if (HAVE_DECL_SO_MAX_PACING_RATE)
+ stats->FQPacingRateCurrent = packet->FQPacingRate;
+#endif
}
#endif
-
/*
* Report printing routines below
*/
@@ -1110,6 +1192,22 @@ static inline void reporter_set_timestamps_time (struct TransferInfo *stats, enu
}
}
+#if HAVE_SUMMING_DEBUG
+static void reporter_dump_timestamps (struct ReportStruct *packet, struct TransferInfo *stats, struct TransferInfo *sumstats) {
+ if (packet)
+ printf("**** %s pkt =%ld.%ld (up/down)=%d/%d\n", stats->common->transferIDStr, (long) packet->packetTime.tv_sec, \
+ (long) packet->packetTime.tv_usec, sumstats->slot_thread_upcount, sumstats->slot_thread_downcount);
+ else {
+ printf("**** %s pkt ts =%ld.%ld prev=%ld.%ld (up/down)=%d/%d\n", stats->common->transferIDStr, (long) stats->ts.packetTime.tv_sec, \
+ (long) stats->ts.packetTime.tv_usec, (long) stats->ts.prevpacketTime.tv_sec, (long) stats->ts.prevpacketTime.tv_usec, sumstats->slot_thread_upcount, sumstats->slot_thread_downcount);
+ }
+ printf("**** %s stats =%ld.%ld next=%ld.%ld prev=%ld.%ld\n", stats->common->transferIDStr, (long) stats->ts.packetTime.tv_sec, \
+ (long) stats->ts.packetTime.tv_usec, (long) stats->ts.nextTime.tv_sec, (long) stats->ts.nextTime.tv_usec, (long) stats->ts.prevpacketTime.tv_sec, (long) stats->ts.prevpacketTime.tv_usec);
+ printf("**** %s sum stats=%ld.%ld next=%ld.%ld prev=%ld.%ld \n", stats->common->transferIDStr, (long) sumstats->ts.packetTime.tv_sec, \
+ (long) sumstats->ts.packetTime.tv_usec, (long) sumstats->ts.nextTime.tv_sec, (long) sumstats->ts.nextTime.tv_usec, (long) sumstats->ts.prevTime.tv_sec, (long) sumstats->ts.prevTime.tv_usec);
+}
+#endif
+
// If reports were missed, catch up now
static inline void reporter_transfer_protocol_missed_reports (struct TransferInfo *stats, struct ReportStruct *packet) {
while (TimeDifference(packet->packetTime, stats->ts.nextTime) > TimeDouble(stats->ts.intervalTime)) {
@@ -1125,10 +1223,24 @@ static inline void reporter_transfer_protocol_missed_reports (struct TransferInf
}
}
+static inline void reporter_reset_transfer_stats_sum (struct TransferInfo *sumstats) {
+#if HAVE_SUMMING_DEBUG
+ printf("***** [SUM] RESET %ld.%ld nxt %ld.%ld down=%d up=%d\n", (long) sumstats->ts.prevTime.tv_sec, (long) sumstats->ts.prevTime.tv_usec, \
+ (long) sumstats->ts.nextTime.tv_sec, (long) sumstats->ts.nextTime.tv_usec, sumstats->slot_thread_downcount, sumstats->slot_thread_upcount);
+#endif
+ sumstats->slot_thread_upcount -= sumstats->slot_thread_downcount;
+ sumstats->slot_thread_downcount = 0;
+ sumstats->ts.prevTime = sumstats->ts.nextTime;
+ sumstats->iInP = 0;
+ sumstats->uplevel = toggleLevel(sumstats->uplevel);
+ sumstats->downlevel = toggleLevel(sumstats->downlevel);
+}
+
static inline void reporter_reset_transfer_stats_client_tcp (struct TransferInfo *stats) {
stats->total.Bytes.prev = stats->total.Bytes.current;
stats->sock_callstats.write.WriteCnt = 0;
stats->sock_callstats.write.WriteErr = 0;
+ stats->sock_callstats.write.WriteTimeo = 0;
stats->isochstats.framecnt.prev = stats->isochstats.framecnt.current;
stats->isochstats.framelostcnt.prev = stats->isochstats.framelostcnt.current;
stats->isochstats.slipcnt.prev = stats->isochstats.slipcnt.current;
@@ -1144,13 +1256,7 @@ static inline void reporter_reset_transfer_stats_client_tcp (struct TransferInfo
reporter_reset_mmm(&stats->bbasym.current);
}
if (isTcpWriteTimes(stats->common)) {
- stats->write_mmm.current.cnt = 0;
- stats->write_mmm.current.min = FLT_MAX;
- stats->write_mmm.current.max = FLT_MIN;
- stats->write_mmm.current.sum = 0;
- stats->write_mmm.current.vd = 0;
- stats->write_mmm.current.mean = 0;
- stats->write_mmm.current.m2 = 0;
+ reporter_reset_mmm(&stats->write_mmm.current);
}
}
@@ -1164,6 +1270,7 @@ static inline void reporter_reset_transfer_stats_client_udp (struct TransferInfo
stats->total.IPG.prev = stats->total.IPG.current;
stats->sock_callstats.write.WriteCnt = 0;
stats->sock_callstats.write.WriteErr = 0;
+ stats->sock_callstats.write.WriteTimeo = 0;
stats->isochstats.framecnt.prev = stats->isochstats.framecnt.current;
stats->isochstats.framelostcnt.prev = stats->isochstats.framelostcnt.current;
stats->isochstats.slipcnt.prev = stats->isochstats.slipcnt.current;
@@ -1174,7 +1281,7 @@ static inline void reporter_reset_transfer_stats_client_udp (struct TransferInfo
static inline void reporter_reset_transfer_stats_server_tcp (struct TransferInfo *stats) {
int ix;
stats->total.Bytes.prev = stats->total.Bytes.current;
- stats->sock_callstats.read.cntRead = 0;
+ stats->sock_callstats.read.ReadCnt.prev = stats->sock_callstats.read.ReadCnt.current;
for (ix = 0; ix < 8; ix++) {
stats->sock_callstats.read.bins[ix] = 0;
}
@@ -1198,8 +1305,10 @@ static inline void reporter_reset_transfer_stats_server_udp (struct TransferInfo
stats->l2counts.unknown = 0;
stats->l2counts.udpcsumerr = 0;
stats->l2counts.lengtherr = 0;
- stats->threadcnt = 0;
stats->iInP = 0;
+ stats->sock_callstats.read.ReadCnt.prev = stats->sock_callstats.read.ReadCnt.current;
+ stats->sock_callstats.read.ReadTimeoCnt.prev = stats->sock_callstats.read.ReadTimeoCnt.current;
+ stats->sock_callstats.read.ReadErrLenCnt.prev = stats->sock_callstats.read.ReadErrLenCnt.current;
if (stats->cntDatagrams)
stats->IPGsum = 0;
}
@@ -1209,7 +1318,7 @@ static inline void reporter_reset_transfer_stats_server_udp (struct TransferInfo
// o) set the TransferInfo struct and then calls the individual report output handler
// o) updates the sum and fullduplex reports
//
-void reporter_transfer_protocol_server_udp (struct ReporterData *data, int final) {
+void reporter_transfer_protocol_server_udp (struct ReporterData *data, bool final) {
struct TransferInfo *stats = &data->info;
struct TransferInfo *sumstats = (data->GroupSumReport != NULL) ? &data->GroupSumReport->info : NULL;
struct TransferInfo *fullduplexstats = (data->FullDuplexReport != NULL) ? &data->FullDuplexReport->info : NULL;
@@ -1223,6 +1332,9 @@ void reporter_transfer_protocol_server_udp (struct ReporterData *data, int final
stats->cntError = 0;
stats->cntDatagrams = stats->PacketID - stats->total.Datagrams.prev;
stats->cntIPG = stats->total.IPG.current - stats->total.IPG.prev;
+ stats->sock_callstats.read.cntRead = stats->sock_callstats.read.ReadCnt.current - stats->sock_callstats.read.ReadCnt.prev;
+ stats->sock_callstats.read.cntReadTimeo = stats->sock_callstats.read.ReadTimeoCnt.current - stats->sock_callstats.read.ReadTimeoCnt.prev;
+ stats->sock_callstats.read.cntReadErrLen = stats->sock_callstats.read.ReadErrLenCnt.current - stats->sock_callstats.read.ReadErrLenCnt.prev;
if (stats->latency_histogram) {
stats->latency_histogram->final = final;
@@ -1258,8 +1370,24 @@ void reporter_transfer_protocol_server_udp (struct ReporterData *data, int final
sumstats->total.IPG.current += stats->cntIPG;
if (sumstats->IPGsum < stats->IPGsum)
sumstats->IPGsum = stats->IPGsum;
- sumstats->threadcnt++;
sumstats->iInP += stats->iInP;
+ sumstats->sock_callstats.read.cntRead += stats->sock_callstats.read.cntRead;
+ sumstats->sock_callstats.read.cntReadTimeo += stats->sock_callstats.read.cntReadTimeo;
+ sumstats->sock_callstats.read.cntReadErrLen += stats->sock_callstats.read.cntReadErrLen;
+ if (final) {
+ sumstats->threadcnt_final++;
+ if (data->packetring->downlevel != sumstats->downlevel) {
+ sumstats->slot_thread_downcount++;
+ }
+ if (data->packetring->uplevel != sumstats->uplevel){
+ sumstats->slot_thread_upcount++;
+ }
+#if HAVE_SUMMING_DEBUG
+ printf("**** %s downcnt (%p) (up/down)=%d/%d final true uplevel (sum/pkt)=%d/%d\n", stats->common->transferIDStr, (void *)data->packetring, \
+ sumstats->slot_thread_upcount, sumstats->slot_thread_downcount, \
+ sumstats->uplevel, data->packetring->uplevel);
+#endif
+ }
}
if (fullduplexstats) {
fullduplexstats->total.Bytes.current += stats->cntBytes;
@@ -1321,20 +1449,23 @@ void reporter_transfer_protocol_server_udp (struct ReporterData *data, int final
if (stats->latency_histogram) {
if (sumstats && sumstats->latency_histogram) {
histogram_add(sumstats->latency_histogram, stats->latency_histogram);
- sumstats->latency_histogram->final = 1;
+ sumstats->latency_histogram->final = true;
}
- stats->latency_histogram->final = 1;
+ stats->latency_histogram->final = true;
}
if (stats->jitter_histogram) {
if (sumstats && sumstats->jitter_histogram) {
histogram_add(sumstats->jitter_histogram, stats->jitter_histogram);
- sumstats->jitter_histogram->final = 1;
+ sumstats->jitter_histogram->final = true;
}
- stats->jitter_histogram->final = 1;
+ stats->jitter_histogram->final = true;
}
if (stats->framelatency_histogram) {
- stats->framelatency_histogram->final = 1;
+ stats->framelatency_histogram->final = true;
}
+ stats->sock_callstats.read.cntRead = stats->sock_callstats.read.ReadCnt.current;
+ stats->sock_callstats.read.cntReadTimeo = stats->sock_callstats.read.ReadTimeoCnt.current;
+ stats->sock_callstats.read.cntReadErrLen = stats->sock_callstats.read.ReadErrLenCnt.current;
}
if ((stats->output_handler) && !(stats->isMaskOutput))
(*stats->output_handler)(stats);
@@ -1342,7 +1473,7 @@ void reporter_transfer_protocol_server_udp (struct ReporterData *data, int final
reporter_reset_transfer_stats_server_udp(stats);
}
-void reporter_transfer_protocol_sum_server_udp (struct TransferInfo *stats, int final) {
+void reporter_transfer_protocol_sum_server_udp (struct TransferInfo *stats, bool final) {
if (final) {
reporter_set_timestamps_time(stats, TOTAL);
stats->cntOutofOrder = stats->total.OutofOrder.current;
@@ -1368,15 +1499,16 @@ void reporter_transfer_protocol_sum_server_udp (struct TransferInfo *stats, int
stats->cntBytes = stats->total.Bytes.current - stats->total.Bytes.prev;
stats->cntIPG = stats->total.IPG.current - stats->total.IPG.prev;
}
- if ((stats->output_handler) && !(stats->isMaskOutput))
+ if ((stats->output_handler) && !(stats->isMaskOutput)) {
(*stats->output_handler)(stats);
+ }
if (!final) {
// there is no packet ID for sum server reports, set it to total cnt for calculation
stats->PacketID = stats->total.Datagrams.current;
reporter_reset_transfer_stats_server_udp(stats);
}
}
-void reporter_transfer_protocol_sum_client_udp (struct TransferInfo *stats, int final) {
+void reporter_transfer_protocol_sum_client_udp (struct TransferInfo *stats, bool final) {
if (final) {
reporter_set_timestamps_time(stats, TOTAL);
stats->sock_callstats.write.WriteErr = stats->sock_callstats.write.totWriteErr;
@@ -1390,19 +1522,18 @@ void reporter_transfer_protocol_sum_client_udp (struct TransferInfo *stats, int
stats->cntIPG = stats->total.IPG.current - stats->total.IPG.prev;
stats->cntDatagrams = stats->total.Datagrams.current - stats->total.Datagrams.prev;
}
- if ((stats->output_handler) && !(stats->isMaskOutput))
+ if ((stats->output_handler) && !(stats->isMaskOutput)) {
(*stats->output_handler)(stats);
-
+ }
if (!final) {
- stats->threadcnt = 0;
reporter_reset_transfer_stats_client_udp(stats);
} else if ((stats->common->ReportMode != kReport_CSV) && !(stats->isMaskOutput)) {
- printf(report_sumcnt_datagrams, stats->threadcnt, stats->total.Datagrams.current);
+ printf(report_sumcnt_datagrams, stats->threadcnt_final, stats->total.Datagrams.current);
fflush(stdout);
}
}
-void reporter_transfer_protocol_client_udp (struct ReporterData *data, int final) {
+void reporter_transfer_protocol_client_udp (struct ReporterData *data, bool final) {
struct TransferInfo *stats = &data->info;
struct TransferInfo *sumstats = (data->GroupSumReport != NULL) ? &data->GroupSumReport->info : NULL;
struct TransferInfo *fullduplexstats = (data->FullDuplexReport != NULL) ? &data->FullDuplexReport->info : NULL;
@@ -1418,13 +1549,28 @@ void reporter_transfer_protocol_client_udp (struct ReporterData *data, int final
sumstats->total.Bytes.current += stats->cntBytes;
sumstats->sock_callstats.write.WriteErr += stats->sock_callstats.write.WriteErr;
sumstats->sock_callstats.write.WriteCnt += stats->sock_callstats.write.WriteCnt;
+ sumstats->sock_callstats.write.WriteTimeo += stats->sock_callstats.write.WriteTimeo;
sumstats->sock_callstats.write.totWriteErr += stats->sock_callstats.write.WriteErr;
sumstats->sock_callstats.write.totWriteCnt += stats->sock_callstats.write.WriteCnt;
+ sumstats->sock_callstats.write.totWriteTimeo += stats->sock_callstats.write.WriteTimeo;
sumstats->total.Datagrams.current += stats->cntDatagrams;
if (sumstats->IPGsum < stats->IPGsum)
sumstats->IPGsum = stats->IPGsum;
sumstats->total.IPG.current += stats->cntIPG;
- sumstats->threadcnt++;
+ if (final) {
+ sumstats->threadcnt_final++;
+ if (data->packetring->downlevel != sumstats->downlevel) {
+ sumstats->slot_thread_downcount++;
+ }
+ if (data->packetring->uplevel != sumstats->uplevel){
+ sumstats->slot_thread_upcount++;
+ }
+#if HAVE_SUMMING_DEBUG
+ printf("**** %s downcnt (%p) (up/down)=%d/%d final true level (sum/pkt)=%d/%d\n", stats->common->transferIDStr, (void *)data->packetring, \
+ sumstats->slot_thread_upcount, sumstats->slot_thread_downcount, \
+ sumstats->uplevel, data->packetring->uplevel);
+#endif
+ }
}
if (fullduplexstats) {
fullduplexstats->total.Bytes.current += stats->cntBytes;
@@ -1438,6 +1584,7 @@ void reporter_transfer_protocol_client_udp (struct ReporterData *data, int final
stats->cntBytes = stats->total.Bytes.current;
stats->sock_callstats.write.WriteErr = stats->sock_callstats.write.totWriteErr;
stats->sock_callstats.write.WriteCnt = stats->sock_callstats.write.totWriteCnt;
+ stats->sock_callstats.write.WriteTimeo = stats->sock_callstats.write.totWriteTimeo;
stats->cntIPG = stats->total.IPG.current;
stats->cntDatagrams = stats->PacketID;
stats->IPGsum = TimeDifference(stats->ts.packetTime, stats->ts.startTime);
@@ -1463,14 +1610,14 @@ void reporter_transfer_protocol_client_udp (struct ReporterData *data, int final
reporter_reset_transfer_stats_client_udp(stats);
}
-void reporter_transfer_protocol_server_tcp (struct ReporterData *data, int final) {
+void reporter_transfer_protocol_server_tcp (struct ReporterData *data, bool final) {
struct TransferInfo *stats = &data->info;
struct TransferInfo *sumstats = (data->GroupSumReport != NULL) ? &data->GroupSumReport->info : NULL;
struct TransferInfo *fullduplexstats = (data->FullDuplexReport != NULL) ? &data->FullDuplexReport->info : NULL;
stats->cntBytes = stats->total.Bytes.current - stats->total.Bytes.prev;
int ix;
if (stats->framelatency_histogram) {
- stats->framelatency_histogram->final = 0;
+ stats->framelatency_histogram->final = false;
}
double thisInP;
if (!final) {
@@ -1479,18 +1626,18 @@ void reporter_transfer_protocol_server_tcp (struct ReporterData *data, int final
double meantransit = (double) ((stats->transit.current.cnt > 0) ? (stats->transit.current.sum / stats->transit.current.cnt) : 0.0);
thisInP = lambda * meantransit;
stats->iInP = thisInP;
+ stats->sock_callstats.read.cntRead = stats->sock_callstats.read.ReadCnt.current - stats->sock_callstats.read.ReadCnt.prev;
} else {
double bytecnt = (double) stats->cntBytes;
double lambda = (stats->IPGsum > 0.0) ? (bytecnt / stats->IPGsum) : 0.0;
double meantransit = (double) ((stats->transit.total.cnt > 0) ? (stats->transit.total.sum / stats->transit.total.cnt) : 0.0);
thisInP = lambda * meantransit;
stats->fInP = thisInP;
+ stats->sock_callstats.read.cntRead = stats->sock_callstats.read.ReadCnt.current;
}
if (sumstats) {
- sumstats->threadcnt++;
sumstats->total.Bytes.current += stats->cntBytes;
- sumstats->sock_callstats.read.cntRead += stats->sock_callstats.read.cntRead;
- sumstats->sock_callstats.read.totcntRead += stats->sock_callstats.read.cntRead;
+ sumstats->sock_callstats.read.ReadCnt.current += stats->sock_callstats.read.cntRead;
for (ix = 0; ix < TCPREADBINCOUNT; ix++) {
sumstats->sock_callstats.read.bins[ix] += stats->sock_callstats.read.bins[ix];
sumstats->sock_callstats.read.totbins[ix] += stats->sock_callstats.read.bins[ix];
@@ -1499,6 +1646,18 @@ void reporter_transfer_protocol_server_tcp (struct ReporterData *data, int final
sumstats->iInP += thisInP;
} else {
sumstats->fInP += thisInP;
+ sumstats->threadcnt_final++;
+ if (data->packetring->downlevel != sumstats->downlevel) {
+ sumstats->slot_thread_downcount++;
+ }
+ if (data->packetring->uplevel != sumstats->uplevel){
+ sumstats->slot_thread_upcount++;
+ }
+#if HAVE_SUMMING_DEBUG
+ printf("**** %s downcnt (%p) (up/down)=%d/%d final true level (sum/pkt)=%d/%d\n", stats->common->transferIDStr, (void *)data->packetring, \
+ sumstats->slot_thread_upcount, sumstats->slot_thread_downcount, \
+ sumstats->uplevel, data->packetring->uplevel);
+#endif
}
}
if (fullduplexstats) {
@@ -1520,12 +1679,12 @@ void reporter_transfer_protocol_server_tcp (struct ReporterData *data, int final
}
}
if (stats->framelatency_histogram) {
- stats->framelatency_histogram->final = 1;
+ stats->framelatency_histogram->final = true;
}
reporter_set_timestamps_time(stats, TOTAL);
stats->cntBytes = stats->total.Bytes.current;
stats->IPGsum = stats->ts.iEnd;
- stats->sock_callstats.read.cntRead = stats->sock_callstats.read.totcntRead;
+ stats->sock_callstats.read.cntRead = stats->sock_callstats.read.ReadCnt.current;
for (ix = 0; ix < TCPREADBINCOUNT; ix++) {
stats->sock_callstats.read.bins[ix] = stats->sock_callstats.read.totbins[ix];
}
@@ -1538,9 +1697,9 @@ void reporter_transfer_protocol_server_tcp (struct ReporterData *data, int final
if (stats->framelatency_histogram) {
if (sumstats && sumstats->framelatency_histogram) {
histogram_add(sumstats->framelatency_histogram, stats->framelatency_histogram);
- sumstats->framelatency_histogram->final = 1;
+ sumstats->framelatency_histogram->final = true;
}
- stats->framelatency_histogram->final = 1;
+ stats->framelatency_histogram->final = true;
}
} else if (isIsochronous(stats->common)) {
stats->isochstats.cntFrames = stats->isochstats.framecnt.current - stats->isochstats.framecnt.prev;
@@ -1557,7 +1716,7 @@ void reporter_transfer_protocol_server_tcp (struct ReporterData *data, int final
reporter_reset_transfer_stats_server_tcp(stats);
}
-void reporter_transfer_protocol_client_tcp (struct ReporterData *data, int final) {
+void reporter_transfer_protocol_client_tcp (struct ReporterData *data, bool final) {
struct TransferInfo *stats = &data->info;
struct TransferInfo *sumstats = (data->GroupSumReport != NULL) ? &data->GroupSumReport->info : NULL;
struct TransferInfo *fullduplexstats = (data->FullDuplexReport != NULL) ? &data->FullDuplexReport->info : NULL;
@@ -1585,7 +1744,24 @@ void reporter_transfer_protocol_client_tcp (struct ReporterData *data, int final
sumstats->sock_callstats.write.WriteCnt += stats->sock_callstats.write.WriteCnt;
sumstats->sock_callstats.write.totWriteErr += stats->sock_callstats.write.WriteErr;
sumstats->sock_callstats.write.totWriteCnt += stats->sock_callstats.write.WriteCnt;
- sumstats->threadcnt++;
+ if (final) {
+ sumstats->threadcnt_final++;
+ if (data->packetring->downlevel != sumstats->downlevel) {
+ sumstats->slot_thread_downcount++;
+ }
+ if (data->packetring->uplevel != sumstats->uplevel){
+ sumstats->slot_thread_upcount++;
+ }
+#if HAVE_SUMMING_DEBUG
+ printf("**** %s downcnt (%p) (up/down)=%d/%d final true level (sum/pkt)=%d/%d\n", stats->common->transferIDStr, (void *)data->packetring, \
+ sumstats->slot_thread_upcount, sumstats->slot_thread_downcount, \
+ sumstats->uplevel, data->packetring->uplevel);
+#endif
+ }
+#if HAVE_SUMMING_DEBUG
+ reporter_dump_timestamps(NULL, stats, sumstats);
+#endif
+
#if HAVE_TCP_STATS
sumstats->sock_callstats.write.tcpstats.retry += stats->sock_callstats.write.tcpstats.retry;
sumstats->sock_callstats.write.tcpstats.retry_tot += stats->sock_callstats.write.tcpstats.retry;
@@ -1596,10 +1772,10 @@ void reporter_transfer_protocol_client_tcp (struct ReporterData *data, int final
}
if (final) {
if (stats->latency_histogram) {
- stats->latency_histogram->final = 1;
+ stats->latency_histogram->final = true;
}
if (stats->write_histogram) {
- stats->write_histogram->final = 1;
+ stats->write_histogram->final = true;
}
if ((stats->cntBytes > 0) && stats->output_handler && !TimeZero(stats->ts.intervalTime)) {
// print a partial interval report if enable and this a final
@@ -1626,7 +1802,7 @@ void reporter_transfer_protocol_client_tcp (struct ReporterData *data, int final
stats->sock_callstats.write.tcpstats.retry = stats->sock_callstats.write.tcpstats.retry_tot;
#endif
if (stats->framelatency_histogram) {
- stats->framelatency_histogram->final = 1;
+ stats->framelatency_histogram->final = true;
}
stats->cntBytes = stats->total.Bytes.current;
stats->write_mmm.current = stats->write_mmm.total;
@@ -1646,19 +1822,20 @@ void reporter_transfer_protocol_client_tcp (struct ReporterData *data, int final
/*
* Handles summing of threads
*/
-void reporter_transfer_protocol_sum_client_tcp (struct TransferInfo *stats, int final) {
+void reporter_transfer_protocol_sum_client_tcp (struct TransferInfo *stats, bool final) {
if (!final || (final && (stats->cntBytes > 0) && !TimeZero(stats->ts.intervalTime))) {
stats->cntBytes = stats->total.Bytes.current - stats->total.Bytes.prev;
if (final) {
if ((stats->output_handler) && !(stats->isMaskOutput)) {
reporter_set_timestamps_time(stats, FINALPARTIAL);
- if ((stats->ts.iEnd - stats->ts.iStart) > stats->ts.significant_partial)
+ if ((stats->ts.iEnd - stats->ts.iStart) > stats->ts.significant_partial) {
(*stats->output_handler)(stats);
+ }
reporter_reset_transfer_stats_client_tcp(stats);
}
} else if ((stats->output_handler) && !(stats->isMaskOutput)) {
(*stats->output_handler)(stats);
- stats->threadcnt = 0;
+ reporter_reset_transfer_stats_sum(stats);
}
reporter_reset_transfer_stats_client_tcp(stats);
}
@@ -1675,7 +1852,7 @@ void reporter_transfer_protocol_sum_client_tcp (struct TransferInfo *stats, int
}
}
-void reporter_transfer_protocol_client_bb_tcp (struct ReporterData *data, int final) {
+void reporter_transfer_protocol_client_bb_tcp (struct ReporterData *data, bool final) {
struct TransferInfo *stats = &data->info;
if (final) {
@@ -1703,7 +1880,7 @@ void reporter_transfer_protocol_client_bb_tcp (struct ReporterData *data, int fi
}
}
-void reporter_transfer_protocol_server_bb_tcp (struct ReporterData *data, int final) {
+void reporter_transfer_protocol_server_bb_tcp (struct ReporterData *data, bool final) {
struct TransferInfo *stats = &data->info;
if (final) {
if ((stats->cntBytes > 0) && stats->output_handler && !TimeZero(stats->ts.intervalTime)) {
@@ -1716,7 +1893,6 @@ void reporter_transfer_protocol_server_bb_tcp (struct ReporterData *data, int fi
}
}
#if HAVE_TCP_STATS
-
stats->sock_callstats.write.tcpstats.retry = stats->sock_callstats.write.tcpstats.retry_tot;
#endif
stats->cntBytes = stats->total.Bytes.current;
@@ -1730,26 +1906,27 @@ void reporter_transfer_protocol_server_bb_tcp (struct ReporterData *data, int fi
reporter_reset_transfer_stats_client_tcp(stats);
}
-void reporter_transfer_protocol_sum_server_tcp (struct TransferInfo *stats, int final) {
+void reporter_transfer_protocol_sum_server_tcp (struct TransferInfo *stats, bool final) {
if (!final || (final && (stats->cntBytes > 0) && !TimeZero(stats->ts.intervalTime))) {
stats->cntBytes = stats->total.Bytes.current - stats->total.Bytes.prev;
+ stats->sock_callstats.read.cntRead = stats->sock_callstats.read.ReadCnt.current - stats->sock_callstats.read.ReadCnt.prev;
if (final) {
if ((stats->output_handler) && !(stats->isMaskOutput)) {
reporter_set_timestamps_time(stats, FINALPARTIAL);
- if ((stats->ts.iEnd - stats->ts.iStart) > stats->ts.significant_partial)
+ if ((stats->ts.iEnd - stats->ts.iStart) > stats->ts.significant_partial) {
(*stats->output_handler)(stats);
+ }
}
} else if ((stats->output_handler) && !(stats->isMaskOutput)) {
(*stats->output_handler)(stats);
- stats->threadcnt = 0;
- stats->iInP = 0;
+ reporter_reset_transfer_stats_sum(stats);
}
reporter_reset_transfer_stats_server_tcp(stats);
}
if (final) {
int ix;
stats->cntBytes = stats->total.Bytes.current;
- stats->sock_callstats.read.cntRead = stats->sock_callstats.read.totcntRead;
+ stats->sock_callstats.read.cntRead = stats->sock_callstats.read.ReadCnt.current;
for (ix = 0; ix < TCPREADBINCOUNT; ix++) {
stats->sock_callstats.read.bins[ix] = stats->sock_callstats.read.totbins[ix];
}
@@ -1759,7 +1936,7 @@ void reporter_transfer_protocol_sum_server_tcp (struct TransferInfo *stats, int
(*stats->output_handler)(stats);
}
}
-void reporter_transfer_protocol_fullduplex_tcp (struct TransferInfo *stats, int final) {
+void reporter_transfer_protocol_fullduplex_tcp (struct TransferInfo *stats, bool final) {
if (!final || (final && (stats->cntBytes > 0) && !TimeZero(stats->ts.intervalTime))) {
stats->cntBytes = stats->total.Bytes.current - stats->total.Bytes.prev;
if (final) {
@@ -1781,7 +1958,7 @@ void reporter_transfer_protocol_fullduplex_tcp (struct TransferInfo *stats, int
(*stats->output_handler)(stats);
}
-void reporter_transfer_protocol_fullduplex_udp (struct TransferInfo *stats, int final) {
+void reporter_transfer_protocol_fullduplex_udp (struct TransferInfo *stats, bool final) {
if (!final || (final && (stats->cntBytes > 0) && !TimeZero(stats->ts.intervalTime))) {
stats->cntBytes = stats->total.Bytes.current - stats->total.Bytes.prev;
stats->cntDatagrams = stats->total.Datagrams.current - stats->total.Datagrams.prev;
@@ -1814,11 +1991,11 @@ void reporter_transfer_protocol_fullduplex_udp (struct TransferInfo *stats, int
}
// Conditional print based on time
-int reporter_condprint_time_interval_report (struct ReporterData *data, struct ReportStruct *packet) {
+bool reporter_condprint_time_interval_report (struct ReporterData *data, struct ReportStruct *packet) {
struct TransferInfo *stats = &data->info;
assert(stats!=NULL);
// printf("***sum handler = %p\n", (void *) data->GroupSumReport->transfer_protocol_sum_handler);
- int advance_jobq = 0;
+ bool advance_jobq = false;
// Print a report if packet time exceeds the next report interval time,
// Also signal to the caller to move to the next report (or packet ring)
// if there was output. This will allow for more precise interval sum accounting.
@@ -1826,7 +2003,7 @@ int reporter_condprint_time_interval_report (struct ReporterData *data, struct R
// printf("***** nt %ld.%ld pt %ld.%ld pid=%lld empty=%d\n", stats->ts.nextTime.tv_sec, stats->ts.nextTime.tv_usec, packet->packetTime.tv_sec, packet->packetTime.tv_usec, packet->packetID, packet->emptyreport);
if (TimeDifference(stats->ts.nextTime, packet->packetTime) < 0) {
assert(data->transfer_protocol_handler!=NULL);
- advance_jobq = 1;
+ advance_jobq = true;
struct TransferInfo *sumstats = (data->GroupSumReport ? &data->GroupSumReport->info : NULL);
struct TransferInfo *fullduplexstats = (data->FullDuplexReport ? &data->FullDuplexReport->info : NULL);
stats->ts.packetTime = packet->packetTime;
@@ -1838,10 +2015,19 @@ int reporter_condprint_time_interval_report (struct ReporterData *data, struct R
if (fullduplexstats && ((++data->FullDuplexReport->threads) == 2) && isEnhanced(stats->common)) {
data->FullDuplexReport->threads = 0;
assert(data->FullDuplexReport->transfer_protocol_sum_handler != NULL);
- (*data->FullDuplexReport->transfer_protocol_sum_handler)(fullduplexstats, 0);
+ (*data->FullDuplexReport->transfer_protocol_sum_handler)(fullduplexstats, false);
}
if (sumstats) {
- if ((++data->GroupSumReport->threads) == data->GroupSumReport->reference.count) {
+ if (data->packetring->downlevel != sumstats->downlevel) {
+ sumstats->slot_thread_downcount++;
+ data->packetring->downlevel = toggleLevel(data->packetring->downlevel);
+#if HAVE_SUMMING_DEBUG
+ printf("**** %s downcnt (%p) pkt=%ld.%ld (up/down)=%d/%d final false level (sum/pkt)=%d/%d\n", stats->common->transferIDStr, (void *)data->packetring, \
+ (long) packet->packetTime.tv_sec, (long) packet->packetTime.tv_usec, sumstats->slot_thread_upcount, sumstats->slot_thread_downcount, \
+ sumstats->uplevel, data->packetring->uplevel);
+#endif
+ }
+ if ((sumstats->slot_thread_downcount) == sumstats->slot_thread_upcount) {
data->GroupSumReport->threads = 0;
if ((data->GroupSumReport->reference.count > (fullduplexstats ? 2 : 1)) || \
isSumOnly(data->info.common)) {
@@ -1849,9 +2035,12 @@ int reporter_condprint_time_interval_report (struct ReporterData *data, struct R
} else {
sumstats->isMaskOutput = true;
}
+#if HAVE_SUMMING_DEBUG
+ reporter_dump_timestamps(packet, stats, sumstats);
+#endif
reporter_set_timestamps_time(sumstats, INTERVAL);
assert(data->GroupSumReport->transfer_protocol_sum_handler != NULL);
- (*data->GroupSumReport->transfer_protocol_sum_handler)(sumstats, 0);
+ (*data->GroupSumReport->transfer_protocol_sum_handler)(sumstats, false);
}
}
// In the (hopefully unlikely event) the reporter fell behind
@@ -1863,9 +2052,9 @@ int reporter_condprint_time_interval_report (struct ReporterData *data, struct R
}
// Conditional print based on bursts or frames
-int reporter_condprint_frame_interval_report_server_udp (struct ReporterData *data, struct ReportStruct *packet) {
+bool reporter_condprint_frame_interval_report_server_udp (struct ReporterData *data, struct ReportStruct *packet) {
struct TransferInfo *stats = &data->info;
- int advance_jobq = 0;
+ bool advance_jobq = false;
// first packet of a burst and not a duplicate
if ((packet->burstsize == (packet->remaining + packet->packetLen)) && (stats->matchframeID != packet->frameID)) {
stats->matchframeID=packet->frameID;
@@ -1887,35 +2076,36 @@ int reporter_condprint_frame_interval_report_server_udp (struct ReporterData *da
if ((stats->output_handler) && !(stats->isMaskOutput))
(*stats->output_handler)(stats);
reporter_reset_transfer_stats_server_udp(stats);
- advance_jobq = 1;
+ advance_jobq = true;
}
return advance_jobq;
}
-int reporter_condprint_frame_interval_report_server_tcp (struct ReporterData *data, struct ReportStruct *packet) {
+bool reporter_condprint_frame_interval_report_server_tcp (struct ReporterData *data, struct ReportStruct *packet) {
fprintf(stderr, "FIX ME\n");
- return 1;
+ return true;
}
-int reporter_condprint_burst_interval_report_server_tcp (struct ReporterData *data, struct ReportStruct *packet) {
+bool reporter_condprint_burst_interval_report_server_tcp (struct ReporterData *data, struct ReportStruct *packet) {
struct TransferInfo *stats = &data->info;
- int advance_jobq = 0;
+ int advance_jobq = false;
if (packet->transit_ready) {
stats->ts.prevpacketTime = packet->sentTime;
stats->ts.packetTime = packet->packetTime;
reporter_set_timestamps_time(stats, INTERVALPARTIAL);
stats->cntBytes = stats->total.Bytes.current - stats->total.Bytes.prev;
+ stats->sock_callstats.read.cntRead = stats->sock_callstats.read.ReadCnt.current - stats->sock_callstats.read.ReadCnt.prev;
if ((stats->output_handler) && !(stats->isMaskOutput))
(*stats->output_handler)(stats);
reporter_reset_transfer_stats_server_tcp(stats);
- advance_jobq = 1;
+ advance_jobq = true;
}
return advance_jobq;
}
-int reporter_condprint_burst_interval_report_client_tcp (struct ReporterData *data, struct ReportStruct *packet) {
+bool reporter_condprint_burst_interval_report_client_tcp (struct ReporterData *data, struct ReportStruct *packet) {
struct TransferInfo *stats = &data->info;
- int advance_jobq = 0;
+ int advance_jobq = false;
// first packet of a burst and not a duplicate
if (packet->transit_ready) {
reporter_handle_packet_oneway_transit(stats, packet);
@@ -1927,7 +2117,7 @@ int reporter_condprint_burst_interval_report_client_tcp (struct ReporterData *da
if ((stats->output_handler) && !(stats->isMaskOutput))
(*stats->output_handler)(stats);
reporter_reset_transfer_stats_client_tcp(stats);
- advance_jobq = 1;
+ advance_jobq = true;
}
return advance_jobq;
}
diff --git a/src/Reports.c b/src/Reports.c
index 008f7f4..296078e 100644
--- a/src/Reports.c
+++ b/src/Reports.c
@@ -59,6 +59,7 @@
#include "Locale.h"
#include "active_hosts.h"
#include "payloads.h"
+
static int transferid_counter = 0;
static inline int my_str_copy(char **dst, char *src) {
@@ -90,6 +91,7 @@ static void common_copy (struct ReportCommon **common, struct thread_Settings *i
my_str_copy(&(*common)->Ifrnametx, inSettings->mIfrnametx);
my_str_copy(&(*common)->SSMMulticastStr, inSettings->mSSMMulticastStr);
my_str_copy(&(*common)->Congestion, inSettings->mCongestion);
+ my_str_copy(&(*common)->LoadCCA, inSettings->mLoadCCA);
my_str_copy(&(*common)->transferIDStr, inSettings->mTransferIDStr);
my_str_copy(&(*common)->PermitKey, inSettings->mPermitKey);
@@ -107,6 +109,9 @@ static void common_copy (struct ReportCommon **common, struct thread_Settings *i
(*common)->MSS = inSettings->mMSS;
(*common)->TCPWin = inSettings->mTCPWin;
(*common)->FQPacingRate = inSettings->mFQPacingRate;
+#if (HAVE_DECL_SO_MAX_PACING_RATE)
+ (*common)->FQPacingRateStep = inSettings->mFQPacingRateStep;
+#endif
(*common)->Port = inSettings->mPort;
(*common)->PortLast = inSettings->mPortLast;
(*common)->BindPort = inSettings->mBindPort;
@@ -116,7 +121,9 @@ static void common_copy (struct ReportCommon **common, struct thread_Settings *i
(*common)->AppRateUnits = inSettings->mAppRateUnits;
(*common)->socket = inSettings->mSock;
(*common)->transferID = inSettings->mTransferID;
+ (*common)->peertransferID = inSettings->mPeerTransferID;
(*common)->threads = inSettings->mThreads;
+ (*common)->working_load_threads = inSettings->mWorkingLoadThreads;
(*common)->winsize_requested = inSettings->mTCPWin;
#if defined(HAVE_LINUX_FILTER_H) && defined(HAVE_AF_PACKET)
(*common)->socketdrop = inSettings->mSockDrop;
@@ -126,18 +133,22 @@ static void common_copy (struct ReportCommon **common, struct thread_Settings *i
(*common)->jitter_binwidth = inSettings->jitter_binwidth;
(*common)->local = inSettings->local;
(*common)->size_local = inSettings->size_local;
+ (*common)->multicast_group = inSettings->multicast_group;
+ (*common)->size_multicast_group = inSettings->size_multicast_group;
(*common)->HistBins =inSettings->mHistBins;
(*common)->HistBinsize =inSettings->mHistBinsize;
(*common)->HistUnits =inSettings->mHistUnits;
(*common)->pktIPG =inSettings->mBurstIPG;
(*common)->rtt_weight = inSettings->rtt_nearcongest_weight_factor;
(*common)->ListenerTimeout =inSettings->mListenerTimeout;
- (*common)->FPS = inSettings->mFPS;
+ (*common)->FPS = (inSettings->mFPS > 0) ? inSettings->mFPS : 0;
(*common)->TOS = inSettings->mTOS;
(*common)->RTOS = inSettings->mRTOS;
(*common)->bbsize = inSettings->mBounceBackBytes;
+ (*common)->bbreplysize = inSettings->mBounceBackReplyBytes;
(*common)->bbhold = inSettings->mBounceBackHold;
(*common)->bbcount = inSettings->mBounceBackBurst;
+ (*common)->Omit = inSettings->mOmit;
#if HAVE_DECL_TCP_WINDOW_CLAMP
(*common)->ClampSize = inSettings->mClampSize;
#endif
@@ -169,6 +180,8 @@ static void free_common_copy (struct ReportCommon *common) {
free(common->SSMMulticastStr);
if (common->Congestion)
free(common->Congestion);
+ if (common->LoadCCA)
+ free(common->LoadCCA);
if (common->transferIDStr)
free(common->transferIDStr);
if (common->PermitKey)
@@ -180,7 +193,7 @@ static void free_common_copy (struct ReportCommon *common) {
// on the setting object. If the current id is zero
// this will get the next one. Otherwise it will use
// the value.
-void setTransferID (struct thread_Settings *inSettings, int role_reversal) {
+void setTransferID (struct thread_Settings *inSettings, enum TansferIDType traffic_direction) {
if (!inSettings->mTransferIDStr) {
if (!inSettings->mTransferID) {
Mutex_Lock(&transferid_mutex);
@@ -188,7 +201,7 @@ void setTransferID (struct thread_Settings *inSettings, int role_reversal) {
Mutex_Unlock(&transferid_mutex);
}
int len = 0;
- if (role_reversal) {
+ if (traffic_direction == REVERSED) {
#ifdef HAVE_ROLE_REVERSAL_ID
if (isPermitKey(inSettings) && (inSettings->mPermitKey[0] != '\0')) {
len = snprintf(NULL, 0, "[%s(*%d)] ", \
@@ -220,6 +233,17 @@ void setTransferID (struct thread_Settings *inSettings, int role_reversal) {
}
}
+void updateTransferIDPeer (struct thread_Settings *inSettings) {
+ if (inSettings->mPeerTransferID && (inSettings->mPeerTransferID != inSettings->mTransferID)) {
+ if (inSettings->mTransferIDStr)
+ FREE_ARRAY(inSettings->mTransferIDStr);
+ int len = snprintf(NULL, 0, "[%3d] ", inSettings->mPeerTransferID);
+ inSettings->mTransferIDStr = (char *) calloc(len+1, sizeof(char));
+ if (inSettings->mTransferIDStr) {
+ len = sprintf(inSettings->mTransferIDStr, "[%3d] ", inSettings->mPeerTransferID);
+ }
+ }
+}
void SetFullDuplexHandlers (struct thread_Settings *inSettings, struct SumReport* sumreport) {
if (isUDP(inSettings)) {
sumreport->transfer_protocol_sum_handler = reporter_transfer_protocol_fullduplex_udp;
@@ -252,7 +276,7 @@ void SetSumHandlers (struct thread_Settings *inSettings, struct SumReport* sumre
} else if (isFullDuplex(inSettings)) {
sumreport->info.output_handler = udp_output_fullduplex_sum;
} else {
- sumreport->info.output_handler = (isEnhanced(inSettings) ? udp_output_sum_read_enhanced : udp_output_sum_read);
+ sumreport->info.output_handler = (isEnhanced(inSettings) ? udp_output_sumcnt_read_enhanced : udp_output_sum_read);
}
}
} else {
@@ -270,7 +294,7 @@ void SetSumHandlers (struct thread_Settings *inSettings, struct SumReport* sumre
} else if (isFullDuplex(inSettings)) {
sumreport->info.output_handler = tcp_output_sum_read;
} else {
- sumreport->info.output_handler = (isEnhanced(inSettings) ? tcp_output_sum_read_enhanced : tcp_output_sum_read);
+ sumreport->info.output_handler = (isEnhanced(inSettings) ? tcp_output_sumcnt_read_enhanced : tcp_output_sum_read);
}
}
}
@@ -290,7 +314,7 @@ void SetSumHandlers (struct thread_Settings *inSettings, struct SumReport* sumre
} else if (isFullDuplex(inSettings)) {
sumreport->info.output_handler = udp_output_fullduplex_sum;
} else {
- sumreport->info.output_handler = (isEnhanced(inSettings) ? udp_output_sum_write_enhanced : udp_output_sum_write);
+ sumreport->info.output_handler = (isEnhanced(inSettings) ? udp_output_sumcnt_write_enhanced : udp_output_sum_write);
}
}
} else {
@@ -306,7 +330,7 @@ void SetSumHandlers (struct thread_Settings *inSettings, struct SumReport* sumre
} else if (isFullDuplex(inSettings)) {
sumreport->info.output_handler = tcp_output_fullduplex_sum;
} else {
- sumreport->info.output_handler = (isEnhanced(inSettings) ? tcp_output_sum_write_enhanced : tcp_output_sum_write);
+ sumreport->info.output_handler = (isEnhanced(inSettings) ? tcp_output_sumcnt_write_enhanced : tcp_output_sum_write);
}
}
}
@@ -316,7 +340,7 @@ void SetSumHandlers (struct thread_Settings *inSettings, struct SumReport* sumre
}
}
-struct SumReport* InitSumReport(struct thread_Settings *inSettings, int inID, int fullduplex_report) {
+struct SumReport* InitSumReport(struct thread_Settings *inSettings, int inID, bool fullduplex_report) {
struct SumReport *sumreport = (struct SumReport *) calloc(1, sizeof(struct SumReport));
if (sumreport == NULL) {
FAIL(1, "Out of Memory!!\n", inSettings);
@@ -324,11 +348,17 @@ struct SumReport* InitSumReport(struct thread_Settings *inSettings, int inID, in
sumreport->reference.count = 0;
sumreport->reference.maxcount = 0;
Mutex_Initialize(&sumreport->reference.lock);
- sumreport->threads = 0;
common_copy(&sumreport->info.common, inSettings);
// sumreport->info.common->transferID = inID; // this is now set in the active code
- sumreport->info.threadcnt = 0;
sumreport->info.isMaskOutput = false;
+ sumreport->info.sumreport = sumreport;
+ sumreport->info.type = SUM_REPORT;
+ sumreport->info.uplevel = LOW;
+ sumreport->info.downlevel = LOW;
+ sumreport->info.slot_thread_upcount = 0;
+ sumreport->info.slot_thread_downcount = 0;
+ sumreport->final_thread_upcount = 0;
+
if (inSettings->mReportMode == kReport_CSV) {
format_ips_port_string(&sumreport->info, 1);
}
@@ -348,18 +378,18 @@ struct SumReport* InitSumReport(struct thread_Settings *inSettings, int inID, in
char name[] = "SUMT8";
sumreport->info.latency_histogram = histogram_init(inSettings->mHistBins,inSettings->mHistBinsize,0,\
pow(10,inSettings->mHistUnits), \
- inSettings->mHistci_lower, inSettings->mHistci_upper, sumreport->info.common->transferID, name);
+ inSettings->mHistci_lower, inSettings->mHistci_upper, sumreport->info.common->transferID, name, false);
} else {
char name[] = "SUMF8";
sumreport->info.framelatency_histogram = histogram_init(inSettings->mHistBins,inSettings->mHistBinsize,0, \
pow(10,inSettings->mHistUnits), inSettings->mHistci_lower, \
- inSettings->mHistci_upper, sumreport->info.common->transferID, name);
+ inSettings->mHistci_upper, sumreport->info.common->transferID, name, false);
}
}
if (isJitterHistogram(inSettings) && isUDP(inSettings)) {
char name[] = "SUMJ8";
sumreport->info.jitter_histogram = histogram_init(JITTER_BINCNT,inSettings->jitter_binwidth,0,JITTER_UNITS, \
- JITTER_LCI, JITTER_UCI, sumreport->info.common->transferID, name);
+ JITTER_LCI, JITTER_UCI, sumreport->info.common->transferID, name, false);
}
}
if (fullduplex_report) {
@@ -417,6 +447,12 @@ void FreeSumReport (struct SumReport *sumreport) {
if (sumreport->info.bbrtt_histogram) {
histogram_delete(sumreport->info.bbrtt_histogram);
}
+ if (sumreport->info.bbowdto_histogram) {
+ histogram_delete(sumreport->info.bbowdto_histogram);
+ }
+ if (sumreport->info.bbowdfro_histogram) {
+ histogram_delete(sumreport->info.bbowdfro_histogram);
+ }
if (sumreport->info.jitter_histogram) {
histogram_delete(sumreport->info.jitter_histogram);
}
@@ -453,6 +489,12 @@ static void Free_iReport (struct ReporterData *ireport) {
if (ireport->info.bbrtt_histogram) {
histogram_delete(ireport->info.bbrtt_histogram);
}
+ if (ireport->info.bbowdto_histogram) {
+ histogram_delete(ireport->info.bbowdto_histogram);
+ }
+ if (ireport->info.bbowdfro_histogram) {
+ histogram_delete(ireport->info.bbowdfro_histogram);
+ }
free_common_copy(ireport->info.common);
free(ireport);
}
@@ -568,13 +610,18 @@ struct ReportHeader* InitIndividualReport (struct thread_Settings *inSettings) {
}
// Copy common settings into the transfer report section
common_copy(&ireport->info.common, inSettings);
+ ireport->info.sumreport = inSettings->mSumReport;
ireport->info.final = false;
ireport->info.burstid_transition = false;
ireport->info.isEnableTcpInfo = false;
+ ireport->info.type = DATA_REPORT;
// Create a new packet ring which is used to communicate
// packet stats from the traffic thread to the reporter
// thread. The reporter thread does all packet accounting
+ // ring events causes the packet ring to return a NULL on
+ // dequeue across a boundary, e.g. an interval report timestamp.
+ // This is needed so summing works properly
ireport->packetring = packetring_init((inSettings->numreportstructs ? inSettings->numreportstructs : (isSingleUDP(inSettings) ? 40 : NUM_REPORT_STRUCTS)), \
&ReportCond, (isSingleUDP(inSettings) ? NULL : &inSettings->awake_me));
#ifdef HAVE_THREAD_DEBUG
@@ -693,21 +740,28 @@ struct ReportHeader* InitIndividualReport (struct thread_Settings *inSettings) {
ireport->transfer_protocol_handler = reporter_transfer_protocol_client_tcp;
if (isSumOnly(inSettings)) {
ireport->info.output_handler = NULL;
+ } else if (isBounceBack(inSettings)) {
+ ireport->packet_handler_post_report = reporter_handle_packet_bb_client;
+ ireport->transfer_protocol_handler = reporter_transfer_protocol_client_bb_tcp;
+ if (inSettings->mReportMode == kReport_CSV)
+ ireport->info.output_handler = tcp_output_write_bb_csv;
+ else
+ ireport->info.output_handler = tcp_output_write_bb;
} else if ((inSettings->mReportMode == kReport_CSV) && !isSumOnly(inSettings)) {
if (isEnhanced(inSettings))
ireport->info.output_handler = tcp_output_write_enhanced_csv;
else
ireport->info.output_handler = tcp_output_basic_csv;
- } else if (isBounceBack(inSettings)) {
- ireport->packet_handler_post_report = reporter_handle_packet_bb_client;
- ireport->transfer_protocol_handler = reporter_transfer_protocol_client_bb_tcp;
- ireport->info.output_handler = tcp_output_write_bb;
} else if (isIsochronous(inSettings)) {
ireport->info.output_handler = tcp_output_write_enhanced_isoch;
} else if (isTcpWriteTimes(inSettings)) {
ireport->info.output_handler = tcp_output_write_enhanced_write;
} else if (isEnhanced(inSettings)) {
- ireport->info.output_handler = tcp_output_write_enhanced;
+ if (isFQPacing(inSettings))
+ ireport->info.output_handler = tcp_output_write_enhanced_fq;
+ else {
+ ireport->info.output_handler = tcp_output_write_enhanced;
+ }
} else if (isFullDuplex(inSettings)) {
ireport->info.output_handler = tcp_output_write;
} else {
@@ -729,13 +783,13 @@ struct ReportHeader* InitIndividualReport (struct thread_Settings *inSettings) {
if (isJitterHistogram(inSettings)) {
char name[] = "J8";
ireport->info.jitter_histogram = histogram_init(JITTER_BINCNT,inSettings->jitter_binwidth,0,JITTER_UNITS, \
- JITTER_LCI, JITTER_UCI, ireport->info.common->transferID, name);
+ JITTER_LCI, JITTER_UCI, ireport->info.common->transferID, name, false);
}
if (isTripTime(inSettings) && isHistogram(inSettings)) {
char name[] = "T8";
ireport->info.latency_histogram = histogram_init(inSettings->mHistBins,inSettings->mHistBinsize,0,\
pow(10,inSettings->mHistUnits), \
- inSettings->mHistci_lower, inSettings->mHistci_upper, ireport->info.common->transferID, name);
+ inSettings->mHistci_lower, inSettings->mHistci_upper, ireport->info.common->transferID, name, false);
}
}
if (isHistogram(inSettings) && (isIsochronous(inSettings) || (!isUDP(inSettings) && isTripTime(inSettings)))) {
@@ -743,7 +797,7 @@ struct ReportHeader* InitIndividualReport (struct thread_Settings *inSettings) {
// make sure frame bin size min is 100 microsecond
ireport->info.framelatency_histogram = histogram_init(inSettings->mHistBins,inSettings->mHistBinsize,0, \
pow(10,inSettings->mHistUnits), inSettings->mHistci_lower, \
- inSettings->mHistci_upper, ireport->info.common->transferID, name);
+ inSettings->mHistci_upper, ireport->info.common->transferID, name, false);
}
}
if ((inSettings->mThreadMode == kMode_Client) && !isUDP(inSettings) && isHistogram(inSettings)) {
@@ -751,16 +805,16 @@ struct ReportHeader* InitIndividualReport (struct thread_Settings *inSettings) {
char name[] = "W8";
ireport->info.write_histogram = histogram_init(inSettings->mHistBins,inSettings->mHistBinsize,0,\
pow(10,inSettings->mHistUnits), \
- inSettings->mHistci_lower, inSettings->mHistci_upper, ireport->info.common->transferID, name);
+ inSettings->mHistci_lower, inSettings->mHistci_upper, ireport->info.common->transferID, name, false);
} else if (isWritePrefetch(inSettings)) {
char name[] = "S8";
ireport->info.latency_histogram = histogram_init(inSettings->mHistBins,inSettings->mHistBinsize,0,\
pow(10,inSettings->mHistUnits), \
- inSettings->mHistci_lower, inSettings->mHistci_upper, ireport->info.common->transferID, name);
+ inSettings->mHistci_lower, inSettings->mHistci_upper, ireport->info.common->transferID, name, false);
}
}
if ((inSettings->mThreadMode == kMode_Client) && isBounceBack(inSettings)) {
- char name[] = "BB8";
+ char name[] = " BB8";
if (!isHistogram(inSettings)) {
inSettings->mHistBins = 100000; // 10 seconds wide
inSettings->mHistBinsize = 100; // 100 usec bins
@@ -769,8 +823,16 @@ struct ReportHeader* InitIndividualReport (struct thread_Settings *inSettings) {
inSettings->mHistci_upper = 95;
}
ireport->info.bbrtt_histogram = histogram_init(inSettings->mHistBins,inSettings->mHistBinsize,0, \
- pow(10,inSettings->mHistUnits), \
- inSettings->mHistci_lower, inSettings->mHistci_upper, ireport->info.common->transferID, name);
+ pow(10,inSettings->mHistUnits), \
+ inSettings->mHistci_lower, inSettings->mHistci_upper, ireport->info.common->transferID, name, false);
+ if (isTripTime(inSettings)) {
+ ireport->info.bbowdto_histogram = histogram_init(inSettings->mHistBins,inSettings->mHistBinsize,0, \
+ pow(10,inSettings->mHistUnits), \
+ inSettings->mHistci_lower, inSettings->mHistci_upper, ireport->info.common->transferID, " OWD-TX", false);
+ ireport->info.bbowdfro_histogram = histogram_init(inSettings->mHistBins,inSettings->mHistBinsize,0, \
+ pow(10,inSettings->mHistUnits), \
+ inSettings->mHistci_lower, inSettings->mHistci_upper, ireport->info.common->transferID, " OWD-RX", false);
+ }
}
return reporthdr;
}
@@ -838,8 +900,14 @@ struct ReportHeader* InitConnectionReport (struct thread_Settings *inSettings) {
creport->common->winsize_requested = inSettings->mTCPWin;
creport->txholdbacktime = inSettings->txholdback_timer;
if (isPeriodicBurst(inSettings)) {
- creport->common->FPS = inSettings->mFPS;
+ creport->common->FPS = (inSettings->mFPS > 0) ? inSettings->mFPS : 0;
+ }
+ if (isLoadCCA(inSettings) && (isWorkingLoadUp(inSettings) || isWorkingLoadDown(inSettings))) {
+ strncpy(creport->connected_cca, inSettings->mLoadCCA, TCP_CCA_NAME_MAX);
+ } else if (isCongestionControl(inSettings)) {
+ strncpy(creport->connected_cca, inSettings->mCongestion, TCP_CCA_NAME_MAX);
}
+ creport->connected_cca[TCP_CCA_NAME_MAX - 1] = '\0';
#ifdef HAVE_THREAD_DEBUG
char rs[REPORTTXTMAX];
reporttype_text(reporthdr, &rs[0]);
@@ -972,6 +1040,19 @@ struct ReportHeader* InitServerRelayUDPReport(struct thread_Settings *inSettings
return reporthdr;
}
+struct ReportHeader* InitStringReport (char *textoutput) {
+ struct ReportHeader *reporthdr = (struct ReportHeader *) calloc(1, sizeof(struct ReportHeader));
+ if (reporthdr == NULL) {
+ WARN_errno(1, "Out of Memory!!\n");
+ }
+ reporthdr->type = STRING_REPORT;
+
+ reporthdr->this_report = (void *) calloc((strlen(textoutput) + 1), sizeof(char));
+ char *dst = (char *)(reporthdr->this_report);
+ strcpy(dst, textoutput);
+ return reporthdr;
+}
+
/* -------------------------------------------------------------------
* Send an AckFIN (a datagram acknowledging a FIN) on the socket,
* then select on the socket for some time to check for silence.
@@ -985,7 +1066,7 @@ void write_UDP_AckFIN (struct TransferInfo *stats, int len) {
int ackpacket_length = (int) (sizeof(struct UDP_datagram) + sizeof(struct server_hdr));
int readlen = ((ackpacket_length * 2) > len * 2) ? (ackpacket_length * 2) : (len * 2);
char *ackPacket = (char *) calloc(1, readlen);
- int success = 0;
+ bool success = false;
assert(ackPacket);
fd_set readSet;
int rc = 1;
@@ -1068,7 +1149,7 @@ void write_UDP_AckFIN (struct TransferInfo *stats, int len) {
#ifdef HAVE_THREAD_DEBUG
thread_debug("UDP server detected silence - server stats assumed received by client");
#endif
- success = 1;
+ success = true;
break;
}
rc = read(stats->common->socket, ackPacket, readlen);
diff --git a/src/Server.cpp b/src/Server.cpp
index c271cd7..76eba40 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -70,7 +70,6 @@
#include "checksums.h"
#endif
-
/* -------------------------------------------------------------------
* Stores connected socket and socket info.
* ------------------------------------------------------------------- */
@@ -94,6 +93,9 @@ Server::Server (thread_Settings *inSettings) {
}
}
#endif
+#if HAVE_DECL_MSG_CTRUNC
+ ctrunc_warn_enable = true;
+#endif
// Enable kernel level timestamping if available
InitKernelTimeStamping();
int sorcvtimer = 0;
@@ -101,15 +103,24 @@ Server::Server (thread_Settings *inSettings) {
// minterval double, units seconds
// mAmount integer, units 10 milliseconds
// divide by two so timeout is 1/2 the interval
- if (mSettings->mInterval && (mSettings->mIntervalMode == kInterval_Time)) {
+ if ((mSettings->mInterval > 0) && (mSettings->mIntervalMode == kInterval_Time)) {
sorcvtimer = static_cast<int>(round(mSettings->mInterval / 2.0));
} else if (isServerModeTime(mSettings)) {
sorcvtimer = static_cast<int>(round(mSettings->mAmount * 10000) / 2);
}
- isburst = (isIsochronous(mSettings) || isPeriodicBurst(mSettings) || (isTripTime(mSettings) && !isUDP(mSettings)));
+ isburst = (isIsochronous(mSettings) || isPeriodicBurst(mSettings) || (isTripTime(mSettings)&& !isUDP(mSettings)));
if (isburst && (mSettings->mFPS > 0.0)) {
sorcvtimer = static_cast<int>(round(2000000.0 / mSettings->mFPS));
}
+ if ((mSettings->mInterval > 0) && (mSettings->mIntervalMode == kInterval_Time)) {
+ int interval_quarter = static_cast<int>(round(mSettings->mAmount * 10000) / 4);
+ if (sorcvtimer > interval_quarter) {
+ sorcvtimer = interval_quarter;
+ }
+ if (sorcvtimer < 1000) {
+ sorcvtimer = 1000; // lower bound of 1 ms
+ }
+ }
if (sorcvtimer > 0) {
SetSocketOptionsReceiveTimeout(mSettings, sorcvtimer);
}
@@ -162,7 +173,7 @@ void Server::RunTCP () {
reportstruct->packetTime.tv_usec = now.getUsecs();
while (InProgress()) {
// printf("***** bid expect = %u\n", burstid_expect);
- reportstruct->emptyreport=1;
+ reportstruct->emptyreport = true;
currLen = 0;
// perform read
if (isBWSet(mSettings)) {
@@ -170,13 +181,13 @@ void Server::RunTCP () {
tokens += time2.subSec(time1) * (mSettings->mAppRate / 8.0);
time1 = time2;
}
- reportstruct->transit_ready = 0;
+ reportstruct->transit_ready = false;
if (tokens >= 0.0) {
int n = 0;
int readLen = mSettings->mBufLen;
if (burst_nleft > 0)
readLen = (mSettings->mBufLen < burst_nleft) ? mSettings->mBufLen : burst_nleft;
- reportstruct->emptyreport=1;
+ reportstruct->emptyreport = true;
#if HAVE_DECL_TCP_QUICKACK
if (isTcpQuickAck(mSettings)) {
int opt = 1;
@@ -215,7 +226,7 @@ void Server::RunTCP () {
burst_nleft = burst_info.burst_size - n;
if (burst_nleft == 0) {
reportstruct->prevSentTime = myReport->info.ts.prevsendTime;
- reportstruct->transit_ready = 1;
+ reportstruct->transit_ready = true;
reportstruct->burstperiod = burst_info.burst_period_us;
}
currLen += n;
@@ -237,7 +248,7 @@ void Server::RunTCP () {
if (!reportstruct->transit_ready) {
n = recv(mSettings->mSock, mSettings->mBuf, readLen, 0);
if (n > 0) {
- reportstruct->emptyreport = 0;
+ reportstruct->emptyreport = false;
if (isburst) {
burst_nleft -= n;
if (burst_nleft == 0) {
@@ -247,7 +258,7 @@ void Server::RunTCP () {
reportstruct->isochStartTime.tv_usec = burst_info.send_tt.write_tv_usec;
reportstruct->burstperiod = burst_info.burst_period_us;
}
- reportstruct->transit_ready = 1;
+ reportstruct->transit_ready = true;
}
}
} else if (n == 0) {
@@ -256,9 +267,14 @@ void Server::RunTCP () {
thread_debug("Server thread detected EOF on socket %d", mSettings->mSock);
#endif
} else if ((n < 0) && (FATALTCPREADERR(errno))) {
- WARN_errno(1, "recv");
peerclose = true;
n = 0;
+ now.setnow();
+ char warnbuf[WARNBUFSIZE];
+ snprintf(warnbuf, sizeof(warnbuf), "%stcp recv (%ld.%ld)",\
+ mSettings->mTransferIDStr, now.getSecs(), now.getUsecs());
+ warnbuf[sizeof(warnbuf)-1] = '\0';
+ WARN_errno(1, warnbuf);
}
currLen += n;
}
@@ -305,44 +321,103 @@ void Server::PostNullEvent () {
// push a nonevent into the packet ring
// this will cause the reporter to process
// up to this event
- memset(reportstruct, 0, sizeof(struct ReportStruct));
+ struct ReportStruct report_nopacket;
+ memset(&report_nopacket, 0, sizeof(struct ReportStruct));
now.setnow();
- reportstruct->packetTime.tv_sec = now.getSecs();
- reportstruct->packetTime.tv_usec = now.getUsecs();
- reportstruct->emptyreport=1;
- ReportPacket(myReport, reportstruct);
+ report_nopacket.packetTime.tv_sec = now.getSecs();
+ report_nopacket.packetTime.tv_usec = now.getUsecs();
+ report_nopacket.emptyreport = true;
+ report_nopacket.err_readwrite = WriteNoAccount;
+ reportstruct->packetTime = report_nopacket.packetTime; // needed for the InProgress loop test
+ ReportPacket(myReport, &report_nopacket);
}
inline bool Server::ReadBBWithRXTimestamp () {
bool rc = false;
int n;
- while (1) {
- if ((n = recvn(mySocket, mSettings->mBuf, mSettings->mBounceBackBytes, 0)) == mSettings->mBounceBackBytes) {
- struct bounceback_hdr *bbhdr = reinterpret_cast<struct bounceback_hdr *>(mSettings->mBuf);
- uint16_t bbflags = ntohs(bbhdr->bbflags);
- if (!(bbflags & HEADER_BBSTOP)) {
+ while (InProgress()) {
+ int read_offset = 0;
+ RETRY_READ :
+ n = recvn(mySocket, (mSettings->mBuf + read_offset), (mSettings->mBounceBackBytes - read_offset), 0);
+ if (n > 0) {
+ read_offset += n;
+ if (read_offset == mSettings->mBounceBackBytes) {
+ struct bounceback_hdr *bbhdr = reinterpret_cast<struct bounceback_hdr *>(mSettings->mBuf);
+ uint16_t bbflags = ntohs(bbhdr->bbflags);
now.setnow();
reportstruct->packetTime.tv_sec = now.getSecs();
reportstruct->packetTime.tv_usec = now.getUsecs();
- reportstruct->emptyreport=0;
+ reportstruct->emptyreport = false;
reportstruct->packetLen = mSettings->mBounceBackBytes;
// write the rx timestamp back into the payload
bbhdr->bbserverRx_ts.sec = htonl(reportstruct->packetTime.tv_sec);
bbhdr->bbserverRx_ts.usec = htonl(reportstruct->packetTime.tv_usec);
ReportPacket(myReport, reportstruct);
- rc = true;
+ if (!(bbflags & HEADER_BBSTOP)) {
+ rc = true;
+ } else {
+ // last BB write received from client, false return code stops this side
+ }
+ break;
+ }
+ } else if (n == 0) {
+ peerclose = true;
+ } else if (n == IPERF_SOCKET_ERROR_NONFATAL) {
+ PostNullEvent();
+ if (InProgress())
+ goto RETRY_READ;
+ } else {
+ if (FATALTCPREADERR(errno)) {
+ WARN_errno(1, "fatal bounceback read");
+ peerclose = true;
+ break;
} else {
+ WARN(1, "timeout: bounceback read");
+ PostNullEvent();
+ if (InProgress())
+ goto RETRY_READ;
+ }
+ }
+ }
+ return rc;
+}
+
+inline bool Server::WriteBB () {
+ int n;
+ bool rc = false;
+ struct bounceback_hdr *bbhdr = reinterpret_cast<struct bounceback_hdr *>(mSettings->mBuf);
+ now.setnow();
+ bbhdr->bbserverTx_ts.sec = htonl(now.getSecs());
+ bbhdr->bbserverTx_ts.usec = htonl(now.getUsecs());
+ if (mSettings->mTOS) {
+ bbhdr->tos = htons((uint16_t)(mSettings->mTOS & 0xFF));
+ }
+ int write_offset = 0;
+ reportstruct->writecnt = 0;
+ int writelen = mSettings->mBounceBackReplyBytes;
+ while (InProgress()) {
+ n = writen(mySocket, (mSettings->mBuf + write_offset), (writelen - write_offset), &reportstruct->writecnt);
+ if (n < 0) {
+ if (FATALTCPWRITERR(errno)) {
+ reportstruct->err_readwrite=WriteErrFatal;
+ FAIL_errno(1, "tcp bounceback writen", mSettings);
peerclose = true;
+ break;
+ } else {
+ PostNullEvent();
+ continue;
}
- break;
- } else if (n==0) {
- peerclose = true;
- break;
- } else if (n == -2){
+ }
+ write_offset += n;
+ if (write_offset < writelen) {
+ WARN_errno(1, "tcp bounceback writen incomplete");
PostNullEvent();
- } else {
- break;
+ continue;
}
+ reportstruct->emptyreport = false;
+ reportstruct->err_readwrite=WriteSuccess;
+ reportstruct->packetLen = writelen;
+ return true;
}
return rc;
}
@@ -374,40 +449,21 @@ void Server::RunBounceBackTCP () {
reportstruct->packetTime.tv_sec = now.getSecs();
reportstruct->packetTime.tv_usec = now.getUsecs();
reportstruct->packetLen = mSettings->mBounceBackBytes;
- reportstruct->emptyreport=0;
+ reportstruct->emptyreport = false;
ReportPacket(myReport, reportstruct);
- while (InProgress()) {
- int n;
- reportstruct->emptyreport=1;
- do {
- struct bounceback_hdr *bbhdr = reinterpret_cast<struct bounceback_hdr *>(mSettings->mBuf);
- if (mSettings->mBounceBackHold) {
-#if HAVE_DECL_TCP_QUICKACK
- if (isTcpQuickAck(mSettings)) {
- int opt = 1;
- Socklen_t len = sizeof(opt);
- int rc = setsockopt(mySocket, IPPROTO_TCP, TCP_QUICKACK,
- reinterpret_cast<char*>(&opt), len);
- WARN_errno(rc == SOCKET_ERROR, "setsockopt TCP_QUICKACK");
- }
-#endif
- delay_loop(mSettings->mBounceBackHold);
- }
- now.setnow();
- bbhdr->bbserverTx_ts.sec = htonl(now.getSecs());
- bbhdr->bbserverTx_ts.usec = htonl(now.getUsecs());
- if (mSettings->mTOS) {
- bbhdr->tos = htons((uint16_t)(mSettings->mTOS & 0xFF));
- }
- if ((n = writen(mySocket, mSettings->mBuf, mSettings->mBounceBackBytes, &reportstruct->writecnt)) == mSettings->mBounceBackBytes) {
- reportstruct->emptyreport=0;
- reportstruct->packetLen = n;
- ReportPacket(myReport, reportstruct);
- } else {
+ int rc;
+ while (InProgress() && (rc = WriteBB())) {
+ if (rc) {
+ ReportPacket(myReport, reportstruct);
+ if (ReadBBWithRXTimestamp())
+ continue;
+ else {
break;
}
- } while (ReadBBWithRXTimestamp());
+ } else {
+ break;
+ }
}
disarm_itimer();
// stop timing
@@ -471,10 +527,17 @@ inline void Server::SetReportStartTime () {
// Servers that aren't full duplex use the accept timestamp for start
myReport->info.ts.startTime.tv_sec = mSettings->sent_time.tv_sec;
myReport->info.ts.startTime.tv_usec = mSettings->sent_time.tv_usec;
- } else if (!TimeZero(mSettings->accept_time) && !isTxStartTime(mSettings)) {
+ } else if (!TimeZero(mSettings->accept_time)) {
// Servers that aren't full duplex use the accept timestamp for start
myReport->info.ts.startTime.tv_sec = mSettings->accept_time.tv_sec;
myReport->info.ts.startTime.tv_usec = mSettings->accept_time.tv_usec;
+ // The client may have had a barrier between the connect and start of traffic, check and adjust
+ if (mSettings->barrier_time) {
+ now.setnow();
+ if (now.subUsec(mSettings->accept_time) >= mSettings->barrier_time) {
+ TimeAddIntUsec(myReport->info.ts.startTime, mSettings->barrier_time);
+ }
+ }
} else {
now.setnow();
myReport->info.ts.startTime.tv_sec = now.getSecs();
@@ -579,6 +642,20 @@ void Server::ClientReverseFirstRead (void) {
bool Server::InitTrafficLoop (void) {
bool UDPReady = true;
+ if (isSyncTransferID(mSettings)) {
+ if (mSettings->mPeerTransferID != mSettings->mTransferID) {
+ int len = snprintf(NULL, 0, "%sTransfer ID %d remapped to %d\n", \
+ mSettings->mTransferIDStr, mSettings->mTransferID, mSettings->mPeerTransferID);
+ char *text = (char *) calloc(len+1, sizeof(char));
+ if (text) {
+ snprintf(text, len, "%sTransfer ID %d remapped to %d\n", \
+ mSettings->mTransferIDStr, mSettings->mTransferID, mSettings->mPeerTransferID);
+ PostReport(InitStringReport(text));
+ FREE_ARRAY(text);
+ }
+ updateTransferIDPeer(mSettings);
+ }
+ }
myJob = InitIndividualReport(mSettings);
myReport = static_cast<struct ReporterData *>(myJob->this_report);
assert(myJob != NULL);
@@ -598,21 +675,42 @@ bool Server::InitTrafficLoop (void) {
reportstruct->l2errors = 0x0;
int setfullduplexflag = 0;
+ Timestamp now;
+
+ if ((mSettings->txstart_epoch.tv_sec > 0) && (mSettings->txstart_epoch.tv_sec - now.getSecs()) > 1) {
+ // Have the server thread wait on the client's epoch start
+ // unblocking one second ahead
+ struct timeval wait_until = mSettings->txstart_epoch;
+ wait_until.tv_sec -= 1;
+ clock_usleep_abstime(&wait_until);
+ }
if (isFullDuplex(mSettings) && !isServerReverse(mSettings)) {
assert(mSettings->mFullDuplexReport != NULL);
if ((setfullduplexflag = fullduplex_start_barrier(&mSettings->mFullDuplexReport->fullduplex_barrier)) < 0)
exit(-1);
}
- Timestamp now;
if (isReverse(mSettings)) {
mSettings->accept_time.tv_sec = now.getSecs();
mSettings->accept_time.tv_usec = now.getUsecs();
ClientReverseFirstRead();
}
if (isTripTime(mSettings)) {
- if ((abs(now.getSecs() - mSettings->sent_time.tv_sec)) > MAXDIFFTIMESTAMPSECS) {
+ int diff_tolerance;
+ if (mSettings->mInterval && (mSettings->mIntervalMode == kInterval_Time)) {
+ diff_tolerance = ceil(mSettings->mInterval / 1000000);
+ } else {
+ diff_tolerance = MAXDIFFTIMESTAMPSECS;
+ }
+ if (diff_tolerance < 2) {
+ diff_tolerance = 2; // min is 2 seconds
+ }
+ if (mSettings->txstart_epoch.tv_sec > 0) {
+ mSettings->accept_time.tv_sec = mSettings->txstart_epoch.tv_sec;
+ mSettings->accept_time.tv_usec = mSettings->txstart_epoch.tv_usec;
+ mSettings->sent_time = mSettings->accept_time; // the first sent time w/epoch starts uses now()
+ } else if ((abs(now.getSecs() - mSettings->sent_time.tv_sec)) > diff_tolerance) {
unsetTripTime(mSettings);
- fprintf(stdout,"WARN: ignore --trip-times because client didn't provide valid start timestamp within %d seconds of now\n", MAXDIFFTIMESTAMPSECS);
+ fprintf(stdout,"WARN: ignore --trip-times because client didn't provide valid start timestamp within %d seconds of now\n", diff_tolerance);
mSettings->accept_time.tv_sec = now.getSecs();
mSettings->accept_time.tv_usec = now.getUsecs();
}
@@ -643,8 +741,8 @@ bool Server::InitTrafficLoop (void) {
reportstruct->packetLen = mSettings->firstreadbytes;
if (isUDP(mSettings)) {
int offset = 0;
- UDPReady = !ReadPacketID(offset);
reportstruct->packetTime = mSettings->accept_time;
+ UDPReady = !ReadPacketID(offset);
} else {
reportstruct->sentTime.tv_sec = myReport->info.ts.startTime.tv_sec;
reportstruct->sentTime.tv_usec = myReport->info.ts.startTime.tv_usec;
@@ -656,21 +754,36 @@ bool Server::InitTrafficLoop (void) {
}
inline int Server::ReadWithRxTimestamp () {
- long currLen;
- int tsdone = 0;
+ int currLen;
+ int tsdone = false;
-#if HAVE_DECL_SO_TIMESTAMP
+ reportstruct->err_readwrite = ReadSuccess;
+
+#if (HAVE_DECL_SO_TIMESTAMP) && (HAVE_DECL_MSG_CTRUNC)
cmsg = reinterpret_cast<struct cmsghdr *>(&ctrl);
currLen = recvmsg(mSettings->mSock, &message, mSettings->recvflags);
if (currLen > 0) {
- for (cmsg = CMSG_FIRSTHDR(&message); cmsg != NULL;
- cmsg = CMSG_NXTHDR(&message, cmsg)) {
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_TIMESTAMP &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) {
- memcpy(&(reportstruct->packetTime), CMSG_DATA(cmsg), sizeof(struct timeval));
- tsdone = 1;
+#if HAVE_DECL_MSG_TRUNC
+ if (message.msg_flags & MSG_TRUNC) {
+ reportstruct->err_readwrite = ReadErrLen;
+ }
+#endif
+ if (!(message.msg_flags & MSG_CTRUNC)) {
+ for (cmsg = CMSG_FIRSTHDR(&message); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&message, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_TIMESTAMP &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) {
+ memcpy(&(reportstruct->packetTime), CMSG_DATA(cmsg), sizeof(struct timeval));
+ if (TimeZero(myReport->info.ts.prevpacketTime)) {
+ myReport->info.ts.prevpacketTime = reportstruct->packetTime;
+ }
+ tsdone = true;
+ }
}
+ } else if (ctrunc_warn_enable && mSettings->mTransferIDStr) {
+ fprintf(stderr, "%sWARN: recvmsg MSG_CTRUNC occured\n", mSettings->mTransferIDStr);
+ ctrunc_warn_enable = false;
}
}
#else
@@ -678,13 +791,15 @@ inline int Server::ReadWithRxTimestamp () {
#endif
if (currLen <=0) {
// Socket read timeout or read error
- reportstruct->emptyreport=1;
+ reportstruct->emptyreport = true;
if (currLen == 0) {
peerclose = true;
} else if (FATALUDPREADERR(errno)) {
WARN_errno(1, "recvmsg");
currLen = 0;
peerclose = true;
+ } else {
+ reportstruct->err_readwrite = ReadTimeo;
}
} else if (TimeZero(myReport->info.ts.prevpacketTime)) {
myReport->info.ts.prevpacketTime = reportstruct->packetTime;
@@ -704,29 +819,45 @@ inline bool Server::ReadPacketID (int offset_adjust) {
// terminate when datagram begins with negative index
// the datagram ID should be correct, just negated
+ // read the sent timestamp from the rx packet
+ reportstruct->sentTime.tv_sec = ntohl(mBuf_UDP->tv_sec);
+ reportstruct->sentTime.tv_usec = ntohl(mBuf_UDP->tv_usec);
if (isSeqNo64b(mSettings)) {
- // New client - Signed PacketID packed into unsigned id2,id
- reportstruct->packetID = (static_cast<uint32_t>(ntohl(mBuf_UDP->id))) | (static_cast<uintmax_t>(ntohl(mBuf_UDP->id2)) << 32);
+ // New client - Signed PacketID packed into unsigned id2,id
+ reportstruct->packetID = (static_cast<uint32_t>(ntohl(mBuf_UDP->id))) | (static_cast<uintmax_t>(ntohl(mBuf_UDP->id2)) << 32);
#ifdef HAVE_PACKET_DEBUG
- printf("id 0x%x, 0x%x -> %" PRIdMAX " (0x%" PRIxMAX ")\n",
- ntohl(mBuf_UDP->id), ntohl(mBuf_UDP->id2), reportstruct->packetID, reportstruct->packetID);
+ if (isTripTime(mSettings)) {
+ int len = snprintf(NULL,0,"%sPacket id 0x%x, 0x%x -> %" PRIdMAX " (0x%" PRIxMAX ") Sent: %ld.%ld6 Received: %ld.%ld6 Delay: %f\n", \
+ mSettings->mTransferIDStr,ntohl(mBuf_UDP->id), ntohl(mBuf_UDP->id2), reportstruct->packetID, reportstruct->packetID, \
+ reportstruct->sentTime.tv_sec, reportstruct->sentTime.tv_usec, \
+ reportstruct->packetTime.tv_sec, reportstruct->packetTime.tv_usec, TimeDifference(reportstruct->packetTime, reportstruct->sentTime));
+ char *text = (char *) calloc(len+1, sizeof(char));
+ if (text) {
+ snprintf(text, len,"%sPacket ID id 0x%x, 0x%x -> %" PRIdMAX " (0x%" PRIxMAX ") Sent: %ld.%ld Received: %ld.%ld Delay: %f\n", \
+ mSettings->mTransferIDStr,ntohl(mBuf_UDP->id), ntohl(mBuf_UDP->id2), reportstruct->packetID, reportstruct->packetID, \
+ reportstruct->sentTime.tv_sec, reportstruct->sentTime.tv_usec, \
+ reportstruct->packetTime.tv_sec, reportstruct->packetTime.tv_usec, TimeDifference(reportstruct->packetTime, reportstruct->sentTime));
+ PostReport(InitStringReport(text));
+ FREE_ARRAY(text);
+ }
+ } else {
+ printf("id 0x%x, 0x%x -> %" PRIdMAX " (0x%" PRIxMAX ")\n",
+ ntohl(mBuf_UDP->id), ntohl(mBuf_UDP->id2), reportstruct->packetID, reportstruct->packetID);
+ }
#endif
} else {
- // Old client - Signed PacketID in Signed id
- reportstruct->packetID = static_cast<int32_t>(ntohl(mBuf_UDP->id));
+ // Old client - Signed PacketID in Signed id
+ reportstruct->packetID = static_cast<int32_t>(ntohl(mBuf_UDP->id));
#ifdef HAVE_PACKET_DEBUG
- printf("id 0x%x -> %" PRIdMAX " (0x%" PRIxMAX ")\n",
- ntohl(mBuf_UDP->id), reportstruct->packetID, reportstruct->packetID);
+ printf("id 0x%x -> %" PRIdMAX " (0x%" PRIxMAX ")\n",
+ ntohl(mBuf_UDP->id), reportstruct->packetID, reportstruct->packetID);
#endif
}
if (reportstruct->packetID < 0) {
- reportstruct->packetID = - reportstruct->packetID;
- terminate = true;
+ reportstruct->packetID = -reportstruct->packetID;
+ terminate = true;
}
- // read the sent timestamp from the rx packet
- reportstruct->sentTime.tv_sec = ntohl(mBuf_UDP->tv_sec);
- reportstruct->sentTime.tv_usec = ntohl(mBuf_UDP->tv_usec);
return terminate;
}
@@ -749,7 +880,7 @@ void Server::L2_processing () {
if (L2_quintuple_filter() != 0) {
reportstruct->l2errors |= L2UNKNOWN;
reportstruct->l2errors |= L2CSUMERR;
- reportstruct->emptyreport = 1;
+ reportstruct->emptyreport = true;
}
}
if (!(reportstruct->l2errors & L2UNKNOWN)) {
@@ -759,7 +890,7 @@ void Server::L2_processing () {
if (rc) {
reportstruct->l2errors |= L2CSUMERR;
if ((!(reportstruct->l2errors & L2LENERR)) && (L2_quintuple_filter() != 0)) {
- reportstruct->emptyreport = 1;
+ reportstruct->emptyreport = true;
reportstruct->l2errors |= L2UNKNOWN;
}
}
@@ -848,7 +979,7 @@ int Server::L2_quintuple_filter () {
}
inline void Server::udp_isoch_processing (int rxlen) {
- reportstruct->transit_ready = 0;
+ reportstruct->transit_ready = false;
// Ignore runt sized isoch packets
if (rxlen < static_cast<int>(sizeof(struct UDP_datagram) + sizeof(struct client_hdr_v1) + sizeof(struct client_hdrext) + sizeof(struct isoch_payload))) {
reportstruct->burstsize = 0;
@@ -865,7 +996,7 @@ inline void Server::udp_isoch_processing (int rxlen) {
reportstruct->burstperiod = ntohl(udp_pkt->isoch.burstperiod);
reportstruct->remaining = ntohl(udp_pkt->isoch.remaining);
if ((reportstruct->remaining == (uint32_t) rxlen) && ((reportstruct->frameID - reportstruct->prevframeID) == 1)) {
- reportstruct->transit_ready = 1;
+ reportstruct->transit_ready = true;
}
}
}
@@ -891,13 +1022,13 @@ void Server::RunUDP () {
// bandwidth accounting, basically it's indicating
// that the reportstruct itself couldn't be
// completely filled out.
- reportstruct->emptyreport=1;
+ reportstruct->emptyreport = true;
reportstruct->packetLen=0;
// read the next packet with timestamp
// will also set empty report or not
rxlen=ReadWithRxTimestamp();
if (!peerclose && (rxlen > 0)) {
- reportstruct->emptyreport = 0;
+ reportstruct->emptyreport = false;
reportstruct->packetLen = rxlen;
if (isL2LengthCheck(mSettings)) {
reportstruct->l2len = rxlen;
@@ -924,7 +1055,7 @@ void Server::RunUDP () {
}
}
disarm_itimer();
- int do_close = EndJob(myJob, reportstruct);
+ bool do_close = EndJob(myJob, reportstruct);
if (!isMulticast(mSettings) && !isNoUDPfin(mSettings)) {
// send a UDP acknowledgement back except when:
// 1) we're NOT receiving multicast
diff --git a/src/Settings.cpp b/src/Settings.cpp
index 39229f5..246eddd 100644
--- a/src/Settings.cpp
+++ b/src/Settings.cpp
@@ -90,10 +90,13 @@ static int txstarttime = 0;
static int noconnectsync = 0;
static int txholdback = 0;
static int fqrate = 0;
+static int fqratestep = 0;
+static int fqratestepinterval = 0;
static int triptime = 0;
static int infinitetime = 0;
static int connectonly = 0;
-static int connectretry = 0;
+static int connectretrytime = 0;
+static int connectretryinterval = 0;
static int burstipg = 0;
static int burstsize = 0;
static int burstperiodic = 0;
@@ -113,7 +116,10 @@ static int hideips = 0;
static int bounceback = 0;
static int bouncebackhold = 0;
static int bouncebackperiod = 0;
+static int bouncebackrequest = 0;
+static int bouncebackreply = 0;
static int overridetos = 0;
+static int dscp = 0;
static int notcpbbquickack = 0;
static int tcpquickack = 0;
static int notcpbbquickack_cliset = 0;
@@ -121,6 +127,12 @@ static int workingload = 0;
static int utctimes = 0;
static int bouncebackdelaystart = 0;
static int tcpwritetimes = 0;
+static int primarycca = 0;
+static int loadcca = 0;
+static int tcptxdelay = 0;
+static int testxchangetimeout = 0;
+static int synctransferid = 0;
+static int ignoreshutdown = 0;
void Settings_Interpret(char option, const char *optarg, struct thread_Settings *mExtSettings);
// apply compound settings after the command line has been fully parsed
@@ -173,8 +185,11 @@ const struct option long_options[] =
{"bounceback-hold", required_argument, &bouncebackhold, 1},
{"bounceback-no-quickack", no_argument, &notcpbbquickack, 1},
{"bounceback-period", required_argument, &bouncebackperiod, 1},
+{"bounceback-request", required_argument, &bouncebackrequest, 1},
+{"bounceback-reply", required_argument, &bouncebackreply, 1},
{"compatibility", no_argument, NULL, 'C'},
{"daemon", no_argument, NULL, 'D'},
+{"dscp", required_argument, &dscp, 1},
{"file_input", required_argument, NULL, 'F'},
{"ssm-host", required_argument, NULL, 'H'},
{"stdin_input", no_argument, NULL, 'I'},
@@ -187,6 +202,7 @@ const struct option long_options[] =
#else
{"reverse", no_argument, NULL, 'R'},
#endif
+{"sync-transfer-id", no_argument, &synctransferid, 1},
{"tos", required_argument, NULL, 'S'},
{"ttl", required_argument, NULL, 'T'},
{"single_udp", no_argument, NULL, 'U'},
@@ -199,6 +215,7 @@ const struct option long_options[] =
{"jitter-histograms", optional_argument, &jitter_histogram, 1},
{"udp-histograms", optional_argument, &histogram, 1}, // keep support per 2.0.13 usage
{"l2checks", no_argument, &l2checks, 1},
+{"ignore-shutdown", no_argument, &ignoreshutdown, 1},
{"incr-dstip", no_argument, &incrdstip, 1},
{"incr-srcip", no_argument, &incrsrcip, 1},
{"incr-dstport", no_argument, &incrdstport, 1},
@@ -207,10 +224,13 @@ const struct option long_options[] =
{"txstart-time", required_argument, &txstarttime, 1},
{"txdelay-time", required_argument, &txholdback, 1},
{"fq-rate", required_argument, &fqrate, 1},
+{"fq-rate-step", required_argument, &fqratestep, 1},
+{"fq-rate-step-interval", required_argument, &fqratestepinterval, 1},
{"trip-times", no_argument, &triptime, 1},
{"no-udp-fin", no_argument, &noudpfin, 1},
{"connect-only", optional_argument, &connectonly, 1},
-{"connect-retries", required_argument, &connectretry, 1},
+{"connect-retry-time", required_argument, &connectretrytime, 1},
+{"connect-retry-timer", required_argument, &connectretryinterval, 1},
{"no-connect-sync", no_argument, &noconnectsync, 1},
{"full-duplex", no_argument, &fullduplextest, 1},
{"ipg", required_argument, &burstipg, 1},
@@ -225,11 +245,15 @@ const struct option long_options[] =
{"tos-override", required_argument, &overridetos, 1},
{"tcp-rx-window-clamp", required_argument, &rxwinclamp, 1},
{"tcp-quickack", no_argument, &tcpquickack, 1},
+{"tcp-tx-delay", required_argument, &tcptxdelay, 1},
{"tcp-write-prefetch", required_argument, &txnotsentlowwater, 1}, // see doc/DESIGN_NOTES
{"tcp-write-times", no_argument, &tcpwritetimes, 1},
+{"test-exchange-timeout", required_argument, &testxchangetimeout, 1},
{"tap-dev", optional_argument, &tapif, 1},
{"tun-dev", optional_argument, &tunif, 1},
{"working-load", optional_argument, &workingload, 1},
+{"working-load-cca", required_argument, &loadcca, 1},
+{"tcp-cca", required_argument, &primarycca, 1},
{"utc", no_argument, &utctimes, 1},
{"NUM_REPORT_STRUCTS", required_argument, &numreportstructs, 1},
#ifdef WIN32
@@ -294,8 +318,7 @@ const char short_options[] = "146b:c:def:hi:l:mn:o:p:rst:uvw:x:y:zAB:CDF:H:IL:M:
const long kDefault_UDPRate = 1024 * 1024; // -u if set, 1 Mbit/sec
const int kDefault_TCPBufLen = 128 * 1024; // TCP default read/write size
-const int kDefault_BBTCPBufLen = 100; // default bounce-back size in bytes
-
+const int kDefault_BBTCPReqLen = 100; // default bounce-back size in bytes
/* -------------------------------------------------------------------
* Initialize all settings to defaults.
@@ -414,6 +437,10 @@ void Settings_Copy (struct thread_Settings *from, struct thread_Settings **into,
(*into)->mCongestion = new char[strlen(from->mCongestion) + 1];
strcpy((*into)->mCongestion, from->mCongestion);
}
+ if (from->mLoadCCA != NULL) {
+ (*into)->mLoadCCA = new char[strlen(from->mLoadCCA) + 1];
+ strcpy((*into)->mLoadCCA, from->mLoadCCA);
+ }
} else {
(*into)->mHost = NULL;
(*into)->mOutputFileName = NULL;
@@ -458,6 +485,15 @@ void Settings_Copy (struct thread_Settings *from, struct thread_Settings **into,
unsetReport((*into));
}
+void Settings_Grow_mBuf (struct thread_Settings *mSettings, int newsize) {
+ char *tmp = new char[newsize];
+ pattern(tmp, newsize);
+ memcpy(tmp, mSettings->mBuf, mSettings->mBufLen);
+ DELETE_ARRAY(mSettings->mBuf);
+ mSettings->mBuf = tmp;
+ mSettings->mBufLen = newsize;
+}
+
/* -------------------------------------------------------------------
* Delete memory: Does not clean up open file pointers or ptr_parents
* ------------------------------------------------------------------- */
@@ -477,6 +513,7 @@ void Settings_Destroy (struct thread_Settings *mSettings) {
DELETE_ARRAY(mSettings->mHistogramStr);
DELETE_ARRAY(mSettings->mSSMMulticastStr);
DELETE_ARRAY(mSettings->mCongestion);
+ DELETE_ARRAY(mSettings->mLoadCCA);
FREE_ARRAY(mSettings->mIfrname);
FREE_ARRAY(mSettings->mIfrnametx);
FREE_ARRAY(mSettings->mTransferIDStr);
@@ -729,7 +766,10 @@ void Settings_Interpret (char option, const char *optarg, struct thread_Settings
break;
case 'v': // print version and exit
- fprintf(stdout, "%s", version);
+ if (strlen(IPERF_BRANCH))
+ fprintf(stdout, "%s", branch_version);
+ else
+ fprintf(stdout, "%s", version);
exit(0);
break;
@@ -888,9 +928,12 @@ void Settings_Interpret (char option, const char *optarg, struct thread_Settings
// TODO use a function that understands base-2
// the zero base here allows the user to specify
// "0x#" hex, "0#" octal, and "#" decimal numbers
- if ((mExtSettings->mTOS = parse_ipqos(optarg)) == -1) {
- fprintf(stderr, "Invalid --tos value of %s\n", optarg);
+ mExtSettings->mTOS = parse_ipqos(optarg);
+ if (mExtSettings->mTOS == -1) {
+ fprintf(stderr, "WARN: Invalid --tos value of %s ignored\n", optarg);
mExtSettings->mTOS = 0;
+ } else {
+ setSetTOS(mExtSettings);
}
break;
@@ -923,10 +966,14 @@ void Settings_Interpret (char option, const char *optarg, struct thread_Settings
break;
case 'Z':
-#ifdef TCP_CONGESTION
- setCongestionControl(mExtSettings);
- mExtSettings->mCongestion = new char[strlen(optarg)+1];
- strcpy(mExtSettings->mCongestion, optarg);
+#if HAVE_DECL_TCP_CONGESTION
+ if (isCongestionControl(mExtSettings)) {
+ fprintf(stderr, "Option --tcp-congestion or -Z ignored because --tcp-cca set\n");
+ } else {
+ setCongestionControl(mExtSettings);
+ mExtSettings->mCongestion = new char[strlen(optarg)+1];
+ strcpy(mExtSettings->mCongestion, optarg);
+ }
#else
fprintf(stderr, "The -Z option is not available on this operating system\n");
#endif
@@ -949,10 +996,18 @@ void Settings_Interpret (char option, const char *optarg, struct thread_Settings
incrsrcport = 0;
setIncrSrcPort(mExtSettings);
}
+ if (ignoreshutdown) {
+ ignoreshutdown = 0;
+ setIgnoreShutdown(mExtSettings);
+ }
if (sumdstip) {
sumdstip = 0;
setSumServerDstIP(mExtSettings);
}
+ if (synctransferid) {
+ synctransferid = 0;
+ setSyncTransferID(mExtSettings);
+ }
if (txstarttime) {
long seconds;
long usecs;
@@ -1013,9 +1068,36 @@ void Settings_Interpret (char option, const char *optarg, struct thread_Settings
mExtSettings->connectonly_count = -1;
}
}
- if (connectretry) {
- connectretry = 0;
- mExtSettings->mConnectRetries = atoi(optarg);
+ if (connectretryinterval) {
+ connectretryinterval = 0;
+ char *end;
+ double period = strtof(optarg, &end);
+ if ((*end != '\0') || (period < 0 )) {
+ fprintf (stderr, "Invalid value of '%s' for --connect-retry-timer\n", optarg);
+ exit(1);
+ }
+ if (period > (UINT_MAX / 1e6)) {
+ fprintf (stderr, "Too large value of '%s' for --connect-retry-timer, max is %f\n", optarg, (UINT_MAX / 1e6));
+ exit(1);
+ }
+ mExtSettings->connect_retry_timer = static_cast<unsigned int>(ceil(period * 1e6));
+ if (mExtSettings->connect_retry_timer == 0) {
+ mExtSettings->connect_retry_timer = 10000;
+ }
+ }
+ if (connectretrytime) {
+ connectretrytime = 0;
+ char *end;
+ double timer = strtof(optarg, &end);
+ if (*end != '\0') {
+ fprintf (stderr, "Invalid value of '%s' for --connect-retry-time\n", optarg);
+ exit(1);
+ }
+ if (timer > (UINT_MAX / 1e6)) {
+ fprintf (stderr, "Too large value of '%s' for --connect-retry-time, max is %f\n", optarg, (UINT_MAX / 1e6));
+ exit(1);
+ }
+ mExtSettings->connect_retry_time = timer;
}
if (sumonly) {
sumonly = 0;
@@ -1048,7 +1130,7 @@ void Settings_Interpret (char option, const char *optarg, struct thread_Settings
permitkey = 0;
if (optarg) {
strncpy(mExtSettings->mPermitKey, optarg, MAX_PERMITKEY_LEN);
- mExtSettings->mPermitKey[MAX_PERMITKEY_LEN] = '\0';
+ mExtSettings->mPermitKey[MAX_PERMITKEY_LEN-1] = '\0';
} else {
mExtSettings->mPermitKey[0] = '\0';
}
@@ -1056,7 +1138,12 @@ void Settings_Interpret (char option, const char *optarg, struct thread_Settings
}
if (permitkeytimeout) {
permitkeytimeout = 0;
- if (atof(optarg) >= 0.0)
+ if (atof(optarg) > mExtSettings->mListenerTimeout)
+ mExtSettings->mListenerTimeout = static_cast<size_t>(atof(optarg));
+ }
+ if (testxchangetimeout) {
+ testxchangetimeout = 0;
+ if (atof(optarg) > mExtSettings->mListenerTimeout)
mExtSettings->mListenerTimeout = static_cast<size_t>(atof(optarg));
}
if (histogram) {
@@ -1096,8 +1183,13 @@ void Settings_Interpret (char option, const char *optarg, struct thread_Settings
setOverrideTOS(mExtSettings);
}
}
+ if (dscp) {
+ dscp = 0;
+ // dscp needs to shifted by 2 and the ECN bits masked off to map to a TOS byte
+ mExtSettings->mTOS = (atoi(optarg) << DSCP_SHIFT) & DSCP_BITMASK; //2 & 0xFC
+ }
if (fqrate) {
-#if defined(HAVE_DECL_SO_MAX_PACING_RATE)
+#if (HAVE_DECL_SO_MAX_PACING_RATE)
fqrate=0;
setFQPacing(mExtSettings);
mExtSettings->mFQPacingRate = static_cast<uintmax_t>(bitorbyte_atoi(optarg) / 8);
@@ -1105,6 +1197,34 @@ void Settings_Interpret (char option, const char *optarg, struct thread_Settings
fprintf(stderr, "WARNING: The --fq-rate option is not supported\n");
#endif
}
+#if (HAVE_DECL_SO_MAX_PACING_RATE)
+ if (fqratestep) {
+ fqratestep=0;
+ setFQPacingStep(mExtSettings);
+ mExtSettings->mFQPacingRateStep = static_cast<uintmax_t>(bitorbyte_atoi(optarg) / 8);
+ setEnhanced(mExtSettings);
+ }
+ if (fqratestepinterval) {
+ fqratestepinterval=0;
+ double val;
+#if HAVE_STRTOD
+ char *end;
+ errno = 0;
+ val = strtod(optarg, &end);
+ if (errno || (*end != '\0')) {
+ fprintf(stderr, "ERROR: --fq-rate-step-interval value of '%s' not recognized\n", optarg);
+ exit(1);
+ }
+#else
+ val = atof(optarg);
+#endif
+ if (val > 0.0) {
+ mExtSettings->mFQPacingRateStepInterval = val;
+ setFQPacingStepInterval(mExtSettings);
+ setEnhanced(mExtSettings);
+ }
+ }
+#endif
if (isochronous) {
isochronous = 0;
setEnhanced(mExtSettings);
@@ -1153,14 +1273,59 @@ void Settings_Interpret (char option, const char *optarg, struct thread_Settings
setTcpQuickAck(mExtSettings);
#endif
}
+ if (tcptxdelay) {
+ tcptxdelay = 0;
+#if HAVE_DECL_TCP_TX_DELAY
+ char *tmp= new char [strlen(optarg) + 1];
+ char *results;
+ strcpy(tmp, optarg);
+ mExtSettings->mTcpTxDelayProb = 1.0;
+ if (((results = strtok(tmp, ",")) != NULL) && !strcmp(results,tmp)) {
+ mExtSettings->mTcpTxDelayMean = atof(results);
+ if ((results = strtok(NULL, ",")) != NULL) {
+ mExtSettings->mTcpTxDelayProb = atof(results);
+ }
+ }
+ if (mExtSettings->mTcpTxDelayMean > 0) {
+ setTcpTxDelay(mExtSettings);
+ }
+#else
+ fprintf(stderr, "The --tcp-tx-delay option is not available on this operating system\n");
+#endif
+ }
if (utctimes) {
setUTC(mExtSettings);
}
+ if (loadcca) {
+ loadcca = 0;
+#if HAVE_DECL_TCP_CONGESTION
+ setLoadCCA(mExtSettings);
+ mExtSettings->mLoadCCA = new char[strlen(optarg)+1];
+ strcpy(mExtSettings->mLoadCCA, optarg);
+#else
+ fprintf(stderr, "The --working-load-cca option is not available on this operating system\n");
+#endif
+ }
+ if (primarycca) {
+ primarycca = 0;
+#if HAVE_DECL_TCP_CONGESTION
+ if (isCongestionControl(mExtSettings)) {
+ fprintf(stderr, "Option --tcp-cca ignored because --tcp-congestion or -Z set\n");
+ } else {
+ setCongestionControl(mExtSettings);
+ mExtSettings->mCongestion = new char[strlen(optarg)+1];
+ strcpy(mExtSettings->mCongestion, optarg);
+ }
+#else
+ fprintf(stderr, "The --tcp-cca option is not available on this operating system\n");
+#endif
+ }
if (workingload) {
workingload = 0;
#ifdef HAVE_THREAD
setWorkingLoadUp(mExtSettings);
setWorkingLoadDown(mExtSettings);
+ setEnhanced(mExtSettings);
if (optarg) {
char *tmp= new char [strlen(optarg) + 1];
if (tmp) {
@@ -1224,7 +1389,7 @@ void Settings_Interpret (char option, const char *optarg, struct thread_Settings
}
if (burstsize) {
burstsize = 0;
- setPeriodicBurst(mExtSettings);
+ setBurstSize(mExtSettings);
if (optarg) {
mExtSettings->mBurstSize = byte_atoi(optarg);
}
@@ -1300,6 +1465,20 @@ void Settings_Interpret (char option, const char *optarg, struct thread_Settings
}
}
}
+ if (bouncebackrequest) {
+ bouncebackrequest = 0;
+ if (optarg)
+ mExtSettings->mBounceBackBytes = byte_atoi(optarg);
+ else
+ mExtSettings->mBounceBackBytes = 0;
+ }
+ if (bouncebackreply) {
+ bouncebackreply = 0;
+ if (optarg)
+ mExtSettings->mBounceBackReplyBytes = byte_atoi(optarg);
+ else
+ mExtSettings->mBounceBackReplyBytes = 0;
+ }
break;
default: // ignore unknown
break;
@@ -1383,7 +1562,7 @@ void Settings_ModalOptions (struct thread_Settings *mExtSettings) {
}
} else {
if (isBounceBack(mExtSettings))
- mExtSettings->mBufLen = kDefault_BBTCPBufLen;
+ mExtSettings->mBufLen = kDefault_TCPBufLen;
else
mExtSettings->mBufLen = kDefault_TCPBufLen;
}
@@ -1428,12 +1607,6 @@ void Settings_ModalOptions (struct thread_Settings *mExtSettings) {
fprintf(stderr, "ERROR: compatibility mode not supported with the requested with options\n");
bail = true;
}
-#if !(HAVE_DECL_IP_TOS)
- if (isOverrideTOS(mExtSettings) || mExtSettings->mTOS) {
- unsetOverrideTOS(mExtSettings);
- fprintf(stderr, "WARN: IP_TOS not supported\n");
- }
-#endif
if (isPermitKey(mExtSettings)) {
if (isUDP(mExtSettings)) {
fprintf(stderr, "ERROR: Option of --permit-key not supported with UDP\n");
@@ -1486,10 +1659,6 @@ void Settings_ModalOptions (struct thread_Settings *mExtSettings) {
fprintf(stderr, "WARN: option of --jitter-histogram not supported on the client\n");
unsetJitterHistogram(mExtSettings);
}
- if (isIncrSrcPort(mExtSettings) && !mExtSettings->mBindPort) {
- fprintf(stderr, "WARN: option of --incr-srcport requires -B bind option w/port to be set\n");
- unsetIncrSrcPort(mExtSettings);
- }
if (isPeriodicBurst(mExtSettings)) {
setEnhanced(mExtSettings);
setFrameInterval(mExtSettings);
@@ -1502,6 +1671,17 @@ void Settings_ModalOptions (struct thread_Settings *mExtSettings) {
fprintf(stderr, "ERROR: option of --permit-key requires a value on the client\n");
bail = true;
}
+#if (HAVE_DECL_SO_MAX_PACING_RATE)
+ if (isFQPacingStep(mExtSettings)) {
+ if (!isFQPacing(mExtSettings)) {
+ setFQPacing(mExtSettings);
+ mExtSettings->mFQPacingRate = mExtSettings->mFQPacingRateStep;
+ }
+ if (!isFQPacingStepInterval(mExtSettings)) {
+ mExtSettings->mFQPacingRateStepInterval = 1.0;
+ }
+ }
+#endif
if (!isUDP(mExtSettings) && isTxHoldback(mExtSettings) && isTxStartTime(mExtSettings)) {
fprintf(stderr,"ERROR: options of --txstart-time and --txdelay-time are mutually exclusive\n");
bail = true;
@@ -1527,11 +1707,40 @@ void Settings_ModalOptions (struct thread_Settings *mExtSettings) {
bail = true;
}
}
+ if (isTripTime(mExtSettings) && (mExtSettings->mBufLen < static_cast<int> (sizeof(struct TCP_burst_payload)))) {
+ fprintf(stderr, "ERROR: payload (-l) size of %d too small for --trip-times, must be %d or greater\n",\
+ mExtSettings->mBufLen, static_cast<int> (sizeof(struct TCP_burst_payload)));
+ bail = true;
+ }
if (isBounceBack(mExtSettings)) {
if (static_cast<int> (mExtSettings->mBurstSize) > 0) {
fprintf(stderr, "WARN: options of --burst-size for bounce-back ignored, use -l sets size\n");
}
- mExtSettings->mBounceBackBytes = mExtSettings->mBufLen;
+ if (mExtSettings->mBounceBackBytes <= 0) {
+ if (isBuflenSet(mExtSettings)) {
+ // Backward compatibility with older versions
+ mExtSettings->mBounceBackBytes = mExtSettings->mBufLen;
+ } else {
+ mExtSettings->mBounceBackBytes = kDefault_BBTCPReqLen;
+ }
+ } else if (mExtSettings->mBounceBackBytes > mExtSettings->mBufLen) {
+ if (isBuflenSet(mExtSettings)) {
+ mExtSettings->mBounceBackBytes = mExtSettings->mBufLen;
+ fprintf(stderr, "WARN: bounceback request will use -l length and not --bounceback-request value\n");
+ } else {
+ mExtSettings->mBufLen = mExtSettings->mBounceBackBytes;
+ }
+ }
+ if (mExtSettings->mBounceBackReplyBytes <= 0) {
+ mExtSettings->mBounceBackReplyBytes = mExtSettings->mBounceBackBytes;
+ } else if (mExtSettings->mBounceBackReplyBytes > mExtSettings->mBufLen) {
+ if (isBuflenSet(mExtSettings)) {
+ mExtSettings->mBounceBackReplyBytes = mExtSettings->mBufLen;
+ fprintf(stderr, "WARN: bounceback reply will use -l length and not --bounceback-reply value\n");
+ } else {
+ mExtSettings->mBufLen = mExtSettings->mBounceBackReplyBytes;
+ }
+ }
mExtSettings->mBurstSize = mExtSettings->mBufLen;
#if HAVE_DECL_TCP_QUICKACK
if (notcpbbquickack_cliset && isTcpQuickAck(mExtSettings)) {
@@ -1559,15 +1768,17 @@ void Settings_ModalOptions (struct thread_Settings *mExtSettings) {
}
}
#if HAVE_DECL_TCP_NOTSENT_LOWAT
- if (isTripTime(mExtSettings) && !isUDP(mExtSettings)) {
- if (isWritePrefetch(mExtSettings)) {
- if (mExtSettings->mWritePrefetch <= 0) {
- unsetWritePrefetch(mExtSettings);
+ if (!isUDP(mExtSettings)) {
+ if (isTcpWriteTimes(mExtSettings) || isTripTime(mExtSettings)) {
+ if (isWritePrefetch(mExtSettings)) {
+ if (mExtSettings->mWritePrefetch <= 0) {
+ unsetWritePrefetch(mExtSettings);
+ }
+ } else {
+ mExtSettings->mWritePrefetch = SMALL_WRITE_PREFETCH;
+ setWritePrefetch(mExtSettings);
+ setEnhanced(mExtSettings);
}
- } else {
- mExtSettings->mWritePrefetch = SMALL_WRITE_PREFETCH;
- setWritePrefetch(mExtSettings);
- setEnhanced(mExtSettings);
}
}
#endif
@@ -1585,10 +1796,14 @@ void Settings_ModalOptions (struct thread_Settings *mExtSettings) {
fprintf(stderr, "ERROR: option of --burst-size %d must be equal or larger to write length (-l) %d\n", mExtSettings->mBurstSize, mExtSettings->mBufLen);
bail = true;
}
- } else if (!isBounceBack(mExtSettings) && (static_cast<int> (mExtSettings->mBurstSize) > 0)) {
- setPeriodicBurst(mExtSettings);
- mExtSettings->mFPS = 1.0;
- fprintf(stderr, "WARN: option of --burst-size without --burst-period defaults --burst-period to 1 second\n");
+ }
+ if ((mExtSettings->connect_retry_time > 0) && !mExtSettings->connect_retry_timer) {
+ fprintf(stderr, "WARN: companion option of --connect-retry-timer not set - setting to default value of one second\n");
+ mExtSettings->connect_retry_timer = 1000000; // 1 sec in units usecs
+ }
+ if ((mExtSettings->connect_retry_timer > 0) && (mExtSettings->connect_retry_time <= 0)) {
+ fprintf(stderr, "WARN: companion option of --connect-retry-time not set - setting to default value of ten seconds\n");
+ mExtSettings->connect_retry_time = 10;
}
if (isUDP(mExtSettings)) {
if (isPeerVerDetect(mExtSettings)) {
@@ -1615,7 +1830,7 @@ void Settings_ModalOptions (struct thread_Settings *mExtSettings) {
fprintf(stderr, "ERROR: option --ipg must be a positive value\n");
bail = true;
}
- if (mExtSettings->mConnectRetries > 0) {
+ if (mExtSettings->connect_retry_timer > 0) {
fprintf(stderr, "ERROR: option --connect-retries not supported with -u UDP\n");
bail = true;
}
@@ -1627,18 +1842,22 @@ void Settings_ModalOptions (struct thread_Settings *mExtSettings) {
fprintf(stderr, "WARN: setting of option --tcp-quickack is not supported with -u UDP\n");
unsetWritePrefetch(mExtSettings);
}
+ if (isTcpTxDelay(mExtSettings)) {
+ fprintf(stderr, "WARN: setting of option --tcp-tx-delay is not supported with -u UDP\n");
+ unsetTcpTxDelay(mExtSettings);
+ }
{
double delay_target;
if (isIPG(mExtSettings)) {
- delay_target = mExtSettings->mBurstIPG * 1e9; // convert from seconds to nanoseconds
+ delay_target = ((mExtSettings->mBurstIPG > 0) ? mExtSettings->mBurstIPG * 1e9 : 0); // convert from seconds to nanoseconds
} else {
// compute delay target in units of nanoseconds
if (mExtSettings->mAppRateUnits == kRate_BW) {
// compute delay for bandwidth restriction, constrained to [0,max] seconds
- delay_target = (mExtSettings->mBufLen * 8e9) / mExtSettings->mAppRate;
+ delay_target = ((mExtSettings->mAppRate > 0) ? ((mExtSettings->mBufLen * 8e9) / mExtSettings->mAppRate) : 0);
} else {
- delay_target = 1e9 / mExtSettings->mAppRate;
+ delay_target = ((mExtSettings->mAppRate > 0) ? (1e9 / mExtSettings->mAppRate) : 0);
}
}
if (delay_target < 0 ||
@@ -1648,9 +1867,9 @@ void Settings_ModalOptions (struct thread_Settings *mExtSettings) {
}
}
if (isTripTime(mExtSettings)) {
- if (mExtSettings->mBufLen < MINTRIPTIMEPLAYOAD) {
+ if (mExtSettings->mBufLen < MINTRIPTIMEPAYLOAD) {
if (isReverse(mExtSettings) || isFullDuplex(mExtSettings) || (mExtSettings->mMode != kTest_Normal)) {
- fprintf(stderr, "ERROR: payload (-l) size of %d too small for --trip-times, must be %d or greater\n", mExtSettings->mBufLen, MINTRIPTIMEPLAYOAD);
+ fprintf(stderr, "ERROR: payload (-l) size of %d too small for --trip-times, must be %d or greater\n", mExtSettings->mBufLen, MINTRIPTIMEPAYLOAD);
bail = true;
} else {
setSmallTripTime(mExtSettings);
@@ -1731,6 +1950,11 @@ void Settings_ModalOptions (struct thread_Settings *mExtSettings) {
mExtSettings->mListenerTimeout = DEFAULT_PERMITKEY_LIFE;
}
}
+ if ((mExtSettings->mWorkingLoadThreads > 0) || (!isWorkingLoadUp(mExtSettings) && isWorkingLoadDown(mExtSettings)) \
+ || (isWorkingLoadUp(mExtSettings) && !isWorkingLoadDown(mExtSettings))) {
+ fprintf(stderr, "ERROR: setting of --working-load options is not supported on the server, just use --working-load\n");
+ bail = true;
+ }
if (isBounceBack(mExtSettings)) {
fprintf(stderr, "ERROR: setting of option --bounce-back is not supported on the server\n");
bail = true;
@@ -1769,6 +1993,9 @@ void Settings_ModalOptions (struct thread_Settings *mExtSettings) {
if (isIncrDstIP(mExtSettings)) {
fprintf(stderr, "WARN: option of --incr-dstip is not supported on the server\n");
}
+ if (isIgnoreShutdown(mExtSettings)) {
+ fprintf(stderr, "WARN: option of --ignore-shutdown is not supported on the server\n");
+ }
if (isFQPacing(mExtSettings)) {
fprintf(stderr, "WARN: option of --fq-rate is not supported on the server\n");
}
@@ -1778,12 +2005,15 @@ void Settings_ModalOptions (struct thread_Settings *mExtSettings) {
if (isPeerVerDetect(mExtSettings)) {
fprintf(stderr, "WARN: option of -X or --peer-detect not supported on the server\n");
}
- if (mExtSettings->mConnectRetries > 0) {
+ if (mExtSettings->connect_retry_timer > 0) {
fprintf(stderr, "WARN: option --connect-retries not supported on the server\n");
}
if (isNearCongest(mExtSettings)) {
fprintf(stderr, "WARN: option of --near-congestion not supported on the server\n");
}
+ if (isSyncTransferID(mExtSettings)) {
+ fprintf(stderr, "WARN: option of --sync-transfer-id is not supported on the server\n");
+ }
if (isPeriodicBurst(mExtSettings)) {
fprintf(stderr, "WARN: option of --burst-period can only be set on the client\n");
}
@@ -1802,15 +2032,15 @@ void Settings_ModalOptions (struct thread_Settings *mExtSettings) {
if (isHistogram(mExtSettings)) {
if (!mExtSettings->mHistogramStr) {
if (mExtSettings->mThreadMode == kMode_Server) {
- // set default rx histogram settings, milliseconds bins between 0 and 1 secs
- mExtSettings->mHistBins = 1000;
+ // set default rx histogram settings, milliseconds bins between 0 and 10 secs
+ mExtSettings->mHistBins = 10000;
mExtSettings->mHistBinsize = 1;
mExtSettings->mHistUnits = 3;
mExtSettings->mHistci_lower = 5;
mExtSettings->mHistci_upper = 95;
} else {
// set default tx histogram settings, microseconds with 100 us bins
- mExtSettings->mHistBins = 10000;
+ mExtSettings->mHistBins = 100000;
mExtSettings->mHistBinsize = 100;
mExtSettings->mHistUnits = 6;
mExtSettings->mHistci_lower = 5;
@@ -1910,7 +2140,6 @@ void Settings_ModalOptions (struct thread_Settings *mExtSettings) {
// Check for further mLocalhost (-B) and <dev> requests
// full addresses look like 192.168.1.1:6001%eth0 or [2001:e30:1401:2:d46e:b891:3082:b939]:6001%eth0
- iperf_sockaddr tmp;
// Parse -B addresses
if (mExtSettings->mLocalhost) {
if (((results = strtok(mExtSettings->mLocalhost, "%")) != NULL) && ((results = strtok(NULL, "%")) != NULL)) {
@@ -1934,17 +2163,26 @@ void Settings_ModalOptions (struct thread_Settings *mExtSettings) {
fprintf(stderr, "WARNING: port %s ignored - set receive port on server via -p or -L\n", results);
}
}
- // Check for multicast per the -B
- SockAddr_setHostname(mExtSettings->mLocalhost, &tmp,
- (isIPV6(mExtSettings) ? 1 : 0));
- if ((mExtSettings->mThreadMode != kMode_Client) && SockAddr_isMulticast(&tmp)) {
- setMulticast(mExtSettings);
- } else if (SockAddr_isMulticast(&tmp)) {
- if (mExtSettings->mIfrname) {
- free(mExtSettings->mIfrname);
- mExtSettings->mIfrname = NULL;
+ // Do multicast address checking and processing
+ SockAddr_setHostname(mExtSettings->mLocalhost, &mExtSettings->multicast_group, \
+ &mExtSettings->size_multicast_group, (isIPV6(mExtSettings) ? 1 : 0));
+ if (SockAddr_isMulticast(&mExtSettings->multicast_group)) {
+ if (mExtSettings->mThreadMode == kMode_Client) {
+ fprintf(stderr, "WARNING: Client src addr (per -B) must be ip unicast\n");
+ exit(1);
+ } else {
+ setMulticast(mExtSettings);
+ if (isSSMMulticast(mExtSettings)) {
+ SockAddr_setHostname(mExtSettings->mSSMMulticastStr, &mExtSettings->multicast_group_source, \
+ &mExtSettings->size_multicast_group, (isIPV6(mExtSettings) ? 1 : 0));
+ if (SockAddr_isMulticast(&mExtSettings->multicast_group_source)) {
+ fprintf(stderr, "WARNING: SSM host src address (-H or --ssm-host) must be ip unicast\n");
+ exit(1);
+ }
+ }
}
- fprintf(stderr, "WARNING: Client src addr (per -B) must be ip unicast\n");
+ } else {
+ SockAddr_zeroAddress(&mExtSettings->multicast_group); // Zero out multicast sockaddr
}
}
// Parse client (-c) addresses for multicast, link-local and bind to device, port incr
@@ -1987,25 +2225,22 @@ void Settings_ModalOptions (struct thread_Settings *mExtSettings) {
}
if (SockAddr_isMulticast(&mExtSettings->peer)) {
bail = false;
- if ((mExtSettings->mThreads > 1) && !isIncrDstIP(mExtSettings)) {
- fprintf(stderr, "ERROR: client option of -P greater than 1 not supported with multicast address\n");
- bail = true;
- } else if (isFullDuplex(mExtSettings) || isReverse(mExtSettings) || (mExtSettings->mMode != kTest_Normal)) {
+ if (isFullDuplex(mExtSettings) || isReverse(mExtSettings) || (mExtSettings->mMode != kTest_Normal)) {
fprintf(stderr, "ERROR: options of --full-duplex, --reverse, -d and -r not supported with multicast addresses\n");
bail = true;
+ } else if (isSyncTransferID(mExtSettings)) {
+ fprintf(stderr, "ERROR: option of --sync-transfer-id incompatibile with multicast\n");
+ bail = true;
}
if (bail)
exit(1);
else
setMulticast(mExtSettings);
}
-#ifndef HAVE_DECL_SO_BINDTODEVICE
- if (mExtSettings->mIfrnametx) {
- fprintf(stderr, "bind to device will be ignored because not supported\n");
- free(mExtSettings->mIfrnametx);
- mExtSettings->mIfrnametx=NULL;
- }
-#endif
+ }
+ if (isIncrSrcPort(mExtSettings) && !mExtSettings->mBindPort) {
+ fprintf(stderr, "WARN: option of --incr-srcport requires -B bind option w/port to be set\n");
+ unsetIncrSrcPort(mExtSettings);
}
if ((mExtSettings->mIntervalMode == kInterval_Time) && (mExtSettings->mIntervalMode <= 0)) {
mExtSettings->mIntervalMode = kInterval_None;
@@ -2151,7 +2386,7 @@ void Settings_GenerateClientSettings (struct thread_Settings *server, struct thr
thread_debug("header set for a version 1 test");
#endif
if (isFullDuplex(server) || isServerReverse(server))
- setTransferID(server, 1);
+ setTransferID(server, REVERSED);
if (isFullDuplex(server) || v1test) {
Settings_Copy(server, client, SHALLOW_COPY);
reversed_thread = *client;
@@ -2291,7 +2526,16 @@ int Settings_GenerateClientHdrV1 (struct thread_Settings *client, struct client_
} else {
hdr->mPort = htonl(client->mPort);
}
- hdr->numThreads = htonl(client->mThreads);
+ if (isSyncTransferID(client)) {
+ if (client->mTransferID & (HEADER_HASTRANSFERID | HEADER_TRANSFERIDMASK)) {
+ fprintf(stderr, "WARN: num threads too large for --sync-transfer-id\n");
+ } else {
+ uint32_t tidthreads = (HEADER_HASTRANSFERID | ((client->mTransferID << HEADER_TRANSFERIDSHIFT) & HEADER_TRANSFERIDMASK) | client->mThreads);
+ hdr->numThreads = htonl(tidthreads);
+ }
+ } else {
+ hdr->numThreads = htonl(client->mThreads);
+ }
if (isModeTime(client)) {
hdr->mAmount = htonl(-(long)client->mAmount);
} else {
@@ -2325,10 +2569,13 @@ int Settings_GenerateClientHdr (struct thread_Settings *client, void *testhdr, s
struct client_udpsmall_testhdr *hdr = static_cast<struct client_udpsmall_testhdr *>(testhdr);
memset(hdr, 0, buflen);
hdr->flags = htons(HEADER16_SMALL_TRIPTIMES);
+ if (isTxStartTime(client) && !TimeZero(startTime)) {
+ hdr->start_tv_sec = htonl(startTime.tv_sec);
+ }
#ifdef HAVE_THREAD_DEBUG
thread_debug("UDP small trip times flags = %X", ntohs(hdr->flags));
#endif
- return (MINIPERFPAYLOAD);
+ return buflen;
}
// flags common to both TCP and UDP
if (isReverse(client) && !isCompat(client)) {
@@ -2473,7 +2720,7 @@ int Settings_GenerateClientHdr (struct thread_Settings *client, void *testhdr, s
}
len += sizeof(struct client_hdrext);
len += Settings_GenerateClientHdrV1(client, &hdr->base);
- if (!isCompat(client) && (client->mMode != kTest_Normal)) {
+ if ((!isCompat(client) && (client->mMode != kTest_Normal)) || isSyncTransferID(client)) {
flags |= HEADER_VERSION1;
if (client->mMode == kTest_DualTest)
flags |= RUN_NOW;
@@ -2481,7 +2728,7 @@ int Settings_GenerateClientHdr (struct thread_Settings *client, void *testhdr, s
if (isPeerVerDetect(client)) {
flags |= (HEADER_V2PEERDETECT | HEADER_VERSION2);
}
- if (isTripTime(client) || isFQPacing(client) || isIsochronous(client) || isTxStartTime(client)) {
+ if (isTripTime(client) || isFQPacing(client) || isIsochronous(client) || isTxStartTime(client) || isLoadCCA(client) || isCongestionControl(client)) {
hdr->start_fq.start_tv_sec = htonl(startTime.tv_sec);
hdr->start_fq.start_tv_usec = htonl(startTime.tv_usec);
hdr->start_fq.fqratel = htonl((uint32_t) client->mFQPacingRate);
@@ -2503,6 +2750,10 @@ int Settings_GenerateClientHdr (struct thread_Settings *client, void *testhdr, s
hdr->extend.TCPWritePrefetch = htonl((long)client->mWritePrefetch);
}
#endif
+ if (client->barrier_time) {
+ lowerflags |= HEADER_BARRIER_TIME;
+ hdr->extend.barrier_usecs = htonl((long)client->barrier_time);
+ }
#if HAVE_DECL_TCP_QUICKACK
if (isTcpQuickAck(client) && (!isReverse(client) || isFullDuplex(client))) {
upperflags |= HEADER_TCPQUICKACK;
@@ -2529,6 +2780,26 @@ int Settings_GenerateClientHdr (struct thread_Settings *client, void *testhdr, s
}
len += sizeof(struct client_hdrext_isoch_settings);
}
+ } else if (isLoadCCA(client) || isCongestionControl(client)) {
+ // just jump the enclave hdr
+ len += sizeof(struct client_hdrext_isoch_settings);
+ }
+ if (isLoadCCA(client) && (isWorkingLoadUp(client) || isWorkingLoadDown(client))) {
+ uint16_t lenfield = ((client->mLoadCCA != NULL) ? (strlen(client->mLoadCCA)) : 0);
+ if (lenfield > 0) {
+ hdr->cca.cca_length = htons(lenfield);
+ lowerflags |= HEADER_CCA;
+ memcpy(hdr->cca.value, client->mLoadCCA, lenfield);
+ len += sizeof(uint16_t) + lenfield;
+ }
+ } else if (isCongestionControl(client)) {
+ uint16_t lenfield = ((client->mCongestion != NULL) ? (strlen(client->mCongestion)) : 0);
+ if (lenfield > 0) {
+ hdr->cca.cca_length = htons(lenfield);
+ lowerflags |= HEADER_CCA;
+ memcpy(hdr->cca.value, client->mCongestion, lenfield);
+ len += sizeof(uint16_t) + lenfield;
+ }
}
if (isReverse(client) || isFullDuplex(client)) {
flags |= HEADER_VERSION2;
diff --git a/src/SocketAddr.c b/src/SocketAddr.c
index 4322475..b42d272 100644
--- a/src/SocketAddr.c
+++ b/src/SocketAddr.c
@@ -62,6 +62,16 @@
extern "C" {
#endif
+int SockAddr_getAFdomain (iperf_sockaddr *inSockAddr) {
+ return (SockAddr_isIPv6(inSockAddr) ?
+#if HAVE_IPV6
+ AF_INET6
+#else
+ AF_INET
+#endif
+ : AF_INET);
+}
+
/* -------------------------------------------------------------------
* Create a socket address. If inHostname is not null, resolve that
* address and fill it in. Fill in the port number. Use IPv6 ADDR_ANY
@@ -70,7 +80,7 @@ extern "C" {
void SockAddr_remoteAddr (struct thread_Settings *inSettings) {
if (SockAddr_isZeroAddress(&inSettings->peer) == 0) {
if (inSettings->mHost != NULL) {
- SockAddr_setHostname(inSettings->mHost, &inSettings->peer, isIPV6(inSettings));
+ SockAddr_setHostname(inSettings->mHost, &inSettings->peer, &inSettings->size_peer, isIPV6(inSettings));
if (inSettings->incrdstip)
SockAddr_incrAddress(&inSettings->peer, inSettings->incrdstip);
} else {
@@ -100,11 +110,10 @@ void SockAddr_localAddr (struct thread_Settings *inSettings) {
SockAddr_zeroAddress(&inSettings->local);
if (inSettings->mLocalhost != NULL) {
- SockAddr_setHostname(inSettings->mLocalhost, &inSettings->local,
+ SockAddr_setHostname(inSettings->mLocalhost, &inSettings->local, &inSettings->size_local,
isIPV6(inSettings));
if (inSettings->incrsrcip)
SockAddr_incrAddress(&inSettings->local, inSettings->incrsrcip);
-
} else {
#if HAVE_IPV6
if (isIPV6(inSettings)) {
@@ -158,11 +167,6 @@ void SockAddr_localAddr (struct thread_Settings *inSettings) {
/*
* User specified port so use it
*/
-#if HAVE_DECL_SO_REUSEPORT
- int boolean = 1;
- Socklen_t len = sizeof(boolean);
- setsockopt(inSettings->mSock, SOL_SOCKET, SO_REUSEPORT, (char*) &boolean, len);
-#endif
SockAddr_setPort(&inSettings->local, (inSettings->mBindPort + inSettings->incrsrcport));
} else {
/*
@@ -179,12 +183,13 @@ void SockAddr_localAddr (struct thread_Settings *inSettings) {
}
}
}
+
// end SocketAddr
/* -------------------------------------------------------------------
* Resolve the hostname address and fill it in.
* ------------------------------------------------------------------- */
-void SockAddr_setHostname (const char* inHostname, iperf_sockaddr *inSockAddr, int isIPv6) {
+void SockAddr_setHostname (const char* inHostname, iperf_sockaddr *inSockAddr, Socklen_t *addr_size, int isIPv6) {
// ..I think this works for both ipv6 & ipv4... we'll see
bool found = false;
int ret_ga;
@@ -201,6 +206,7 @@ void SockAddr_setHostname (const char* inHostname, iperf_sockaddr *inSockAddr, i
while (itr != NULL) {
if (itr->ai_family == AF_INET) {
memcpy(inSockAddr, (itr->ai_addr), (itr->ai_addrlen));
+ *addr_size = (Socklen_t) sizeof(struct sockaddr_in);
freeaddrinfo(res);
found = true;
break;
@@ -223,6 +229,7 @@ void SockAddr_setHostname (const char* inHostname, iperf_sockaddr *inSockAddr, i
if (itr->ai_family == AF_INET6) {
memcpy(inSockAddr, (itr->ai_addr), (itr->ai_addrlen));
freeaddrinfo(res);
+ *addr_size = (Socklen_t) sizeof(struct sockaddr_in6);
found = true;
break;
} else {
@@ -271,7 +278,11 @@ void SockAddr_setHostname (const char* inHostname, iperf_sockaddr *inSockAddr, i
}
}
if (!found) {
- fprintf(stderr, "ERROR: failed to find an ip address for host '%s'\n", inHostname);
+ if (!isIPv6) {
+ fprintf(stderr, "ERROR: failed to find an ip address for host '%s'\n", inHostname);
+ } else {
+ fprintf(stderr, "ERROR: failed to find an ipv6 address for host '%s'\n", inHostname);
+ }
exit(1);
}
}
diff --git a/src/active_hosts.cpp b/src/active_hosts.cpp
index a3455ab..24358c3 100644
--- a/src/active_hosts.cpp
+++ b/src/active_hosts.cpp
@@ -61,10 +61,18 @@
* Global table with active hosts, their sum reports and active thread counts
*/
static struct Iperf_Table active_table;
-static bool Iperf_host_port_present (iperf_sockaddr *find);
static struct Iperf_ListEntry* Iperf_host_present (iperf_sockaddr *find);
+static struct Iperf_ListEntry* Iperf_flow_present (iperf_sockaddr *find);
#if HAVE_THREAD_DEBUG
+static void rcvfrom_peer_debug (thread_Settings *server, bool duplicate) {
+ char tmpaddr[200];
+ size_t len=200;
+ unsigned short port = SockAddr_getPort(&server->peer);
+ SockAddr_getHostAddress(&server->peer, tmpaddr, len);
+ thread_debug("rcvfrom peer: %s port %d dup=%s", tmpaddr, port, (duplicate ? "true" : "false"));
+}
+
static void active_table_show_entry(const char *action, Iperf_ListEntry *entry, int found) {
assert(action != NULL);
assert(entry != NULL);
@@ -72,9 +80,9 @@ static void active_table_show_entry(const char *action, Iperf_ListEntry *entry,
size_t len=200;
unsigned short port = SockAddr_getPort(&(entry->host));
SockAddr_getHostAddress(&(entry->host), tmpaddr, len);
- thread_debug("active table: %s %s port %d (flag=%d) rootp=%p entryp=%p totcnt/activecnt/hostcnt = %d/%d/%d", \
- action, tmpaddr, port, found, (void *) active_table.root, (void *) entry, active_table.total_count, \
- active_table.count, entry->thread_count);
+ thread_debug("active table: %s %s port %d (flag=%d) rootp=%p entryp=%p hostcnt/flowcnt/threadcnt = %d/%d/%d", \
+ action, tmpaddr, port, found, (void *) active_table.sum_root, (void *) entry->sumreport, active_table.sum_count, \
+ active_table.flow_count, entry->thread_count);
}
static void active_table_show_compare(const char *action, Iperf_ListEntry *entry, iperf_sockaddr *host, const char *type) {
assert(action != NULL);
@@ -92,79 +100,108 @@ static void active_table_show_compare(const char *action, Iperf_ListEntry *entry
void Iperf_initialize_active_table () {
Mutex_Initialize(&active_table.my_mutex);
- active_table.root = NULL;
+ active_table.flow_root = NULL;
+ active_table.sum_root = NULL;
active_table.groupid = 0;
+#if HAVE_THREAD_DEBUG
+ active_table.sum_count = 0;
+ active_table.flow_count = 0;
+#endif
}
/*
- * Add Entry add to the list or update thread count
+ * Add Entry add to the list or update thread count, return 0 on UDP tuple duplicate
*/
-static void active_table_update (iperf_sockaddr *host, struct thread_Settings *agent) {
- assert(host != NULL);
- assert(agent != NULL);
- Iperf_ListEntry *this_entry = Iperf_host_present(host);
- active_table.total_count++;
- if (this_entry == NULL) {
- this_entry = new Iperf_ListEntry();
- assert(this_entry != NULL);
- this_entry->host = *host;
- this_entry->next = active_table.root;
- this_entry->thread_count = 1;
- this_entry->socket = agent->mSock;
- active_table.count++;
- active_table.groupid++;
- active_table.root = this_entry;
- this_entry->sum_report = InitSumReport(agent, active_table.total_count, 0);
- IncrSumReportRefCounter(this_entry->sum_report);
- agent->mSumReport = this_entry->sum_report;
- this_entry->sum_report->info.common->transferID = -active_table.groupid; // sum ids are negative
+static inline struct Iperf_ListEntry *hostkey_insert (iperf_sockaddr *host) {
+ struct Iperf_ListEntry *this_key = new Iperf_ListEntry();
+ assert(this_key != NULL);
+ if (!this_key) {
+ fprintf(stderr, "Memory alloc failure in key insert\n");
+ exit(1);
+ }
+ this_key->next = active_table.sum_root;
+ active_table.sum_root = this_key;
+ this_key->host = *host;
+ this_key->thread_count = 0;
#if HAVE_THREAD_DEBUG
- active_table_show_entry("new entry", this_entry, ((SockAddr_are_Equal(&this_entry->host, host) && SockAddr_Hostare_Equal(&this_entry->host, host))));
+ active_table.sum_count++;
+ active_table_show_entry("new host entry", this_key, ((SockAddr_are_Equal(&this_key->host, host) && SockAddr_Hostare_Equal(&this_key->host, host))));
#endif
- } else {
- this_entry->thread_count++;
- agent->mSumReport = this_entry->sum_report;
- IncrSumReportRefCounter(this_entry->sum_report);
+ return this_key;
+}
+
+static inline struct Iperf_ListEntry *flowkey_insert (iperf_sockaddr *host) {
+ struct Iperf_ListEntry *this_key = new Iperf_ListEntry();
+ assert(this_key != NULL);
+ if (!this_key) {
+ fprintf(stderr, "Memory alloc failure in key insert\n");
+ exit(1);
+ }
+ this_key->next = active_table.flow_root;
+ active_table.flow_root = this_key;
+ this_key->host = *host;
#if HAVE_THREAD_DEBUG
- active_table_show_entry("incr entry", this_entry, 1);
+ active_table.flow_count++;
+// active_table_show_flow_entry("new flow entry", this_key, ((SockAddr_are_Equal(&this_key->host, host) && SockAddr_Hostare_Equal(&this_key->host, host))));
#endif
- }
+ return this_key;
}
static inline iperf_sockaddr *active_table_get_host_key (struct thread_Settings *agent) {
- iperf_sockaddr *key = (isSumServerDstIP(agent) ? &agent->local : &agent->peer);
+ iperf_sockaddr *key = ((isIncrDstIP(agent) || isSumServerDstIP(agent)) ? &agent->local : &agent->peer);
return key;
}
-// Thread access to store a host
-int Iperf_push_host (struct thread_Settings *agent) {
- iperf_sockaddr *host = active_table_get_host_key(agent);
- Mutex_Lock(&active_table.my_mutex);
- active_table_update(host, agent);
- int groupid = active_table.groupid;
- Mutex_Unlock(&active_table.my_mutex);
- return groupid;
+static bool Iperf_push_flow (iperf_sockaddr *host) {
+ bool rc;
+ if (Iperf_flow_present(host)) {
+ rc = false;
+ } else {
+ flowkey_insert(host);
+ rc = true;
+ }
+ return rc;
}
-// Used for UDP push of a new host, returns negative value if the host/port is already present
-// This is critical because UDP is connectionless and designed to be stateless
-int Iperf_push_host_port_conditional (struct thread_Settings *agent) {
- iperf_sockaddr *host = active_table_get_host_key(agent);
- int rc = -1;
+// Thread access to store a host
+bool Iperf_push_host (struct thread_Settings *agent) {
Mutex_Lock(&active_table.my_mutex);
- if (!Iperf_host_port_present(host)) {
- active_table_update(host, agent);
- rc = active_table.groupid;
+ if (isUDP(agent) && (agent->mThreadMode == kMode_Server)) {
+ if (!Iperf_push_flow(&agent->peer)) {
+ // this is a duplicate on UDP, should just ignore
+ Mutex_Unlock(&active_table.my_mutex);
+#if HAVE_THREAD_DEBUG
+ rcvfrom_peer_debug(agent, true);
+#endif
+ return false;
+ }
}
+ struct Iperf_ListEntry *this_host = Iperf_host_present(active_table_get_host_key(agent));
+ if (!this_host) {
+ this_host = hostkey_insert(active_table_get_host_key(agent));
+ active_table.groupid++;
+ this_host->sumreport = InitSumReport(agent, -active_table.groupid, false);
+ this_host->sumreport->info.common->transferID = -active_table.groupid;
+#if HAVE_THREAD_DEBUG
+ active_table_show_entry("new sum report", this_host , 0);
+#endif
+ }
+ agent->mSumReport = this_host->sumreport;
+ this_host->thread_count++;
+ IncrSumReportRefCounter(this_host->sumreport);
+ this_host->socket = agent->mSock;
+#if HAVE_THREAD_DEBUG
+ active_table_show_entry("bind sum report", this_host, 0);
+#endif
Mutex_Unlock(&active_table.my_mutex);
- return (rc);
+ return true;
}
/*
* Remove a host from the table
*/
void Iperf_remove_host (struct thread_Settings *agent) {
- iperf_sockaddr *del = active_table_get_host_key(agent);
+ iperf_sockaddr *del;
// remove_list_entry(entry) {
// indirect = &head;
// while ((*indirect) != entry) {
@@ -172,7 +209,25 @@ void Iperf_remove_host (struct thread_Settings *agent) {
// }
// *indirect = entry->next
Mutex_Lock(&active_table.my_mutex);
- Iperf_ListEntry **tmp = &active_table.root;
+ // Delete any flow entries first
+ if (isUDP(agent)) {
+ del = &agent->peer;
+ Iperf_ListEntry **tmp = &active_table.flow_root;
+ while ((*tmp) && !(SockAddr_are_Equal(&(*tmp)->host, del))) {
+ tmp = &(*tmp)->next;
+ }
+ if (*tmp) {
+ Iperf_ListEntry *remove = (*tmp);
+#if HAVE_THREAD_DEBUG
+ active_table.flow_count--;
+#endif
+ *tmp = remove->next;
+ delete remove;
+ }
+ }
+
+ del = active_table_get_host_key(agent);
+ Iperf_ListEntry **tmp = &active_table.sum_root;
while ((*tmp) && !(SockAddr_Hostare_Equal(&(*tmp)->host, del))) {
#if HAVE_THREAD_DEBUG
active_table_show_compare("miss", *tmp, del, "client ip");
@@ -182,16 +237,16 @@ void Iperf_remove_host (struct thread_Settings *agent) {
if (*tmp) {
if (--(*tmp)->thread_count == 0) {
Iperf_ListEntry *remove = (*tmp);
- active_table.count--;
agent->mSumReport = NULL;
#if HAVE_THREAD_DEBUG
+ active_table.sum_count--;
active_table_show_entry("delete", remove, 1);
#endif
*tmp = remove->next;
- FreeSumReport(remove->sum_report);
+ FreeSumReport(remove->sumreport);
delete remove;
} else {
- DecrSumReportRefCounter((*tmp)->sum_report);
+ DecrSumReportRefCounter((*tmp)->sumreport);
#if HAVE_THREAD_DEBUG
active_table_show_entry("decr", (*tmp), 1);
#endif
@@ -204,55 +259,60 @@ void Iperf_remove_host (struct thread_Settings *agent) {
* Destroy the table
*/
void Iperf_destroy_active_table () {
- Iperf_ListEntry *itr1 = active_table.root, *itr2;
+ Iperf_ListEntry *itr1 = active_table.sum_root, *itr2;
+ while (itr1 != NULL) {
+ itr2 = itr1->next;
+ delete itr1;
+ itr1 = itr2;
+ }
+ itr1 = active_table.flow_root;
while (itr1 != NULL) {
itr2 = itr1->next;
delete itr1;
itr1 = itr2;
}
Mutex_Destroy(&active_table.my_mutex);
- active_table.root = NULL;
- active_table.count = 0;
- active_table.total_count = 0;
+ active_table.sum_root = NULL;
+#if HAVE_THREAD_DEBUG
+ active_table.sum_count = 0;
+#endif
}
/*
* Check if the host and port are present in the active table
*/
-bool Iperf_host_port_present (iperf_sockaddr *find) {
- Iperf_ListEntry *itr = active_table.root;
- bool rc = false;
+struct Iperf_ListEntry* Iperf_flow_present (iperf_sockaddr *find) {
+ Iperf_ListEntry *itr = active_table.flow_root;
while (itr != NULL) {
if (SockAddr_are_Equal(&itr->host, find)) {
#if HAVE_THREAD_DEBUG
- active_table_show_compare("match", itr, find, "client ip/port");
+ active_table_show_compare("match host/port", itr, find, "client ip/port");
#endif
- rc = true;
break;
} else {
#if HAVE_THREAD_DEBUG
- active_table_show_compare("miss", itr, find, "client ip/port");
+ active_table_show_compare("miss host/port", itr, find, "client ip/port");
#endif
itr = itr->next;
}
}
- return rc;
+ return itr;
}
/*
* Check if the host is present in the active table
*/
static Iperf_ListEntry* Iperf_host_present (iperf_sockaddr *find) {
- Iperf_ListEntry *itr = active_table.root;
+ Iperf_ListEntry *itr = active_table.sum_root;
while (itr != NULL) {
if (SockAddr_Hostare_Equal(&itr->host, find)) {
#if HAVE_THREAD_DEBUG
- active_table_show_compare("match", itr, find, "client ip");
+ active_table_show_compare("match host", itr, find, "client ip");
#endif
break;
} else {
#if HAVE_THREAD_DEBUG
- active_table_show_compare("miss", itr, find, "client ip");
+ active_table_show_compare("miss host", itr, find, "client ip");
#endif
itr = itr->next;
}
diff --git a/src/dscp.c b/src/dscp.c
index de691a7..f7bae7a 100644
--- a/src/dscp.c
+++ b/src/dscp.c
@@ -23,6 +23,12 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 7 6 5 4 3 2 1 0
+ * +--+--+--+--+--+--+--+--+
+ * | DSCP | ECN |
+ * +--+--+--+--+--+--+--+--+
+ *
*/
#if HAVE_CONFIG_H
@@ -137,8 +143,8 @@ static const struct {
{ "nqb2", IPTOS_DSCP_NQB2 },
{ "ac_be", IPTOS_DSCP_CS0 },
{ "ac_bk", IPTOS_DSCP_CS1 },
- { "ac_vi", IPTOS_DSCP_CS4 },
- { "ac_vo", IPTOS_DSCP_EF },
+ { "ac_vi", IPTOS_DSCP_CS5 },
+ { "ac_vo", IPTOS_DSCP_CS6 },
{ "lowdelay", IPTOS_LOWDELAY },
{ "throughput", IPTOS_THROUGHPUT },
{ "reliability", IPTOS_RELIABILITY },
diff --git a/src/histogram.c b/src/histogram.c
index 3a9b82c..f00ffc7 100644
--- a/src/histogram.c
+++ b/src/histogram.c
@@ -47,17 +47,20 @@
*/
#include "headers.h"
#include "histogram.h"
+#include "Locale.h"
+#include "util.h"
#ifdef HAVE_THREAD_DEBUG
// needed for thread_debug
#include "Thread.h"
#endif
struct histogram *histogram_init(unsigned int bincount, unsigned int binwidth, float offset, float units,\
- double ci_lower, double ci_upper, unsigned int id, char *name) {
+ double ci_lower, double ci_upper, unsigned int id, char *name, bool Omit) {
struct histogram *this = (struct histogram *) malloc(sizeof(struct histogram));
if (!this) {
fprintf(stderr,"Malloc failure in histogram init\n");
return(NULL);
}
+ this->Omit = Omit;
if (!bincount)
bincount = 1000;
this->mybins = (unsigned int *) malloc(sizeof(unsigned int) * bincount);
@@ -196,7 +199,7 @@ void histogram_print(struct histogram *h, double start, double end) {
histogram_clear(h->prev);
}
if (!h->prev) {
- h->prev = histogram_init(h->bincount, h->binwidth, h->offset, h->units, h->ci_lower, h->ci_upper, h->id, h->myname);
+ h->prev = histogram_init(h->bincount, h->binwidth, h->offset, h->units, h->ci_lower, h->ci_upper, h->id, h->myname, h->Omit);
}
int n = 0, ix, delta, lowerci, upperci, outliercnt, fence_lower, fence_upper, upper3stdev;
int running=0;
@@ -258,12 +261,18 @@ void histogram_print(struct histogram *h, double start, double end) {
fprintf(stdout, "%s (%.2f/%.2f/99.7%%=%d/%d/%d,Outliers=%d,obl/obu=%d/%d)", \
h->outbuf, h->ci_lower, h->ci_upper, lowerci, upperci, upper3stdev, outliercnt, oob_l, oob_u);
if (!h->final && (h->maxval > 0) && ((h->maxts.tv_sec > 0) || h->maxts.tv_usec > 0)) {
- fprintf(stdout, " (%0.3f ms/%ld.%ld)\n", (h->maxval * 1e3), (long) h->maxts.tv_sec, (long) h->maxts.tv_usec);
+ fprintf(stdout, " (%0.3f ms/%ld.%ld)", (h->maxval * 1e3), (long) h->maxts.tv_sec, (long) h->maxts.tv_usec);
+ if (TimeDifference(h->prev->maxts, h->maxts) > 0) {
+ fprintf(stdout, "(clock_err)");
+ }
h->maxbin = -1;
h->maxval = 0;
+ h->prev->maxts.tv_sec = 0;
+ h->prev->maxts.tv_usec = 0;
+ h->maxts.tv_sec = 0;
+ h->maxts.tv_usec = 0;
} else if (h->final && (h->fmaxval > 0) && ((h->maxts.tv_sec > 0) || h->maxts.tv_usec > 0)) {
- fprintf(stdout, " (%0.3f ms/%ld.%ld)\n", (h->fmaxval * 1e3), (long) h->fmaxts.tv_sec, (long) h->fmaxts.tv_usec);
- } else {
- fprintf(stdout, "\n");
+ fprintf(stdout, " (%0.3f ms/%ld.%ld)", (h->fmaxval * 1e3), (long) h->fmaxts.tv_sec, (long) h->fmaxts.tv_usec);
}
+ fprintf(stdout, "%s\n", (h->Omit ? report_omitted : ""));
}
diff --git a/src/iperf_formattime.c b/src/iperf_formattime.c
index df65650..f0e8d1d 100644
--- a/src/iperf_formattime.c
+++ b/src/iperf_formattime.c
@@ -50,51 +50,53 @@
#include "iperf_formattime.h"
inline void iperf_formattime (char *timestr, int buflen, struct timeval timestamp, bool prec_ms, bool utc_time, enum TimeFormatType ftype) {
- struct tm ts ;
- ts = (utc_time ? *gmtime(&timestamp.tv_sec) : *localtime(&timestamp.tv_sec));
- switch (ftype) {
- case YearThruSec:
- strftime(timestr, buflen, "%Y-%m-%d %H:%M:%S", &ts);
- if (prec_ms) {
+ if (buflen > 0) {
+ struct tm ts ;
+ ts = (utc_time ? *gmtime(&timestamp.tv_sec) : *localtime(&timestamp.tv_sec));
+ switch (ftype) {
+ case YearThruSec:
+ strftime(timestr, buflen, "%Y-%m-%d %H:%M:%S", &ts);
+ if (prec_ms) {
+ int currlen = strlen(timestr);
+ if (currlen > 5) {
+ snprintf((timestr + currlen), 5, ".%.3d", (int) (timestamp.tv_usec/1000));
+ }
+ }
+ break;
+ case YearThruSecTZ:
+ strftime(timestr, buflen, "%Y-%m-%d %H:%M:%S", &ts);
int currlen = strlen(timestr);
- if (currlen > 5) {
- snprintf((timestr + currlen), 5, ".%.3d", (int) (timestamp.tv_usec/1000));
+ if (prec_ms) {
+ if (currlen > 5) {
+ snprintf((timestr + currlen), 5, ".%.3d", (int) (timestamp.tv_usec/1000));
+ currlen = strlen(timestr);
+ }
}
- }
- break;
- case YearThruSecTZ:
- strftime(timestr, buflen, "%Y-%m-%d %H:%M:%S", &ts);
- int currlen = strlen(timestr);
- if (prec_ms) {
- if (currlen > 5) {
- snprintf((timestr + currlen), 5, ".%.3d", (int) (timestamp.tv_usec/1000));
- currlen = strlen(timestr);
+ if ((buflen - currlen) > 5) {
+ strftime((timestr + currlen), (buflen - currlen), " (%Z)", &ts);
}
- }
- if ((buflen - currlen) > 5) {
- strftime((timestr + currlen), (buflen - currlen), " (%Z)", &ts);
- }
- break;
- case CSV:
- strftime(timestr, buflen, "%Y%m%d%H%M%S", &ts);
- if (prec_ms) {
- int currlen = strlen(timestr);
- if (currlen > 5) {
- snprintf((timestr + currlen), 5, ".%.3d", (int) (timestamp.tv_usec/1000));
+ break;
+ case CSV:
+ strftime(timestr, buflen, "%Y%m%d%H%M%S", &ts);
+ if (prec_ms) {
+ int currlen = strlen(timestr);
+ if (currlen > 5) {
+ snprintf((timestr + currlen), 5, ".%.3d", (int) (timestamp.tv_usec/1000));
+ }
}
- }
- break;
- case CSVTZ:
- strftime(timestr, buflen, "%z:%Y%m%d%H%M%S", &ts);
- if (prec_ms) {
- int currlen = strlen(timestr);
- if (currlen > 5) {
- snprintf((timestr + currlen), 5, ".%.3d", (int) (timestamp.tv_usec/1000));
+ break;
+ case CSVTZ:
+ strftime(timestr, buflen, "%z:%Y%m%d%H%M%S", &ts);
+ if (prec_ms) {
+ int currlen = strlen(timestr);
+ if (currlen > 5) {
+ snprintf((timestr + currlen), 5, ".%.3d", (int) (timestamp.tv_usec/1000));
+ }
}
+ break;
+ default:
+ FAIL_exit(1, "iperf_formattime program error");
}
- break;
- default:
- FAIL_exit(1, "iperf_formattime program error");
+ timestr[buflen - 1] = '\0'; // make sure string is null terminated
}
- timestr[buflen - 1] = '\0'; // make sure string is null terminated
}
diff --git a/src/iperf_multicast_api.c b/src/iperf_multicast_api.c
new file mode 100644
index 0000000..48c0184
--- /dev/null
+++ b/src/iperf_multicast_api.c
@@ -0,0 +1,386 @@
+/*---------------------------------------------------------------
+ * Copyright (c) 2023
+ * Broadcom Corporation
+ * All Rights Reserved.
+ *---------------------------------------------------------------
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software
+ * without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ *
+ * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and
+ * the following disclaimers.
+ *
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimers in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ *
+ * Neither the name of Broadcom Coporation,
+ * nor the names of its contributors may be used to endorse
+ * or promote products derived from this Software without
+ * specific prior written permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * ________________________________________________________________
+ *
+ * iperf_multicast_api.c
+ * pull iperf multicast code for maitainability
+ *
+ * by Robert J. McMahon (rjmcmahon@rjmcmahon.com, bob.mcmahon@broadcom.com)
+ *
+ *
+ * Joins the multicast group or source and group (SSM S,G)
+ *
+ * taken from: https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.1.0/com.ibm.zos.v2r1.hale001/ipv6d0141001708.htm
+ *
+ * Multicast function IPv4 IPv6 Protocol-independent
+ * ================== ==== ==== ====================
+ * Level of specified option on setsockopt()/getsockopt() IPPROTO_IP IPPROTO_IPV6 IPPROTO_IP or IPPROTO_IPV6
+ * Join a multicast group IP_ADD_MEMBERSHIP IPV6_JOIN_GROUP MCAST_JOIN_GROUP
+ * Leave a multicast group or leave all sources of that
+ * multicast group IP_DROP_MEMBERSHIP IPV6_LEAVE_GROUP MCAST_LEAVE_GROUP
+ * Select outbound interface for sending multicast datagrams IP_MULTICAST_IF IPV6_MULTICAST_IF NA
+ * Set maximum hop count IP_MULTICAST_TTL IPV6_MULTICAST_HOPS NA
+ * Enable multicast loopback IP_MULTICAST_LOOP IPV6_MULTICAST_LOOP NA
+ * Join a source multicast group IP_ADD_SOURCE_MEMBERSHIP NA MCAST_JOIN_SOURCE_GROUP
+ * Leave a source multicast group IP_DROP_SOURCE_MEMBERSHIP NA MCAST_LEAVE_SOURCE_GROUP
+ * Block data from a source to a multicast group IP_BLOCK_SOURCE NA MCAST_BLOCK_SOURCE
+ * Unblock a previously blocked source for a multicast group IP_UNBLOCK_SOURCE NA MCAST_UNBLOCK_SOURCE
+ *
+ *
+ * Reminder: The os will decide which version of IGMP or MLD to use. This may be controlled by system settings, e.g.:
+ *
+ * [rmcmahon@lvnvdb0987:~/Code/ssm/iperf2-code] $ sysctl -a | grep mld | grep force
+ * net.ipv6.conf.all.force_mld_version = 0
+ * net.ipv6.conf.default.force_mld_version = 0
+ * net.ipv6.conf.lo.force_mld_version = 0
+ * net.ipv6.conf.eth0.force_mld_version = 0
+ *
+ * [rmcmahon@lvnvdb0987:~/Code/ssm/iperf2-code] $ sysctl -a | grep igmp | grep force
+ * net.ipv4.conf.all.force_igmp_version = 0
+ * net.ipv4.conf.default.force_igmp_version = 0
+ * net.ipv4.conf.lo.force_igmp_version = 0
+ * net.ipv4.conf.eth0.force_igmp_version = 0
+ *
+ * ------------------------------------------------------------------- */
+#include "headers.h"
+#include "Settings.hpp"
+#include "iperf_multicast_api.h"
+#include "SocketAddr.h"
+#include "util.h"
+
+#ifdef HAVE_IFADDRS_H
+#include <ifaddrs.h>
+#endif
+
+static unsigned int mcast_iface (struct thread_Settings *inSettings) {
+ unsigned int iface=0;
+ /* Set the interface or any */
+ if (inSettings->mIfrname) {
+#if HAVE_NET_IF_H && !WIN32
+ iface = if_nametoindex(inSettings->mIfrname);
+ FAIL_errno(!iface, "mcast if_nametoindex", inSettings);
+#else
+ fprintf(stderr, "multicast bind to device not supported on this platform\n");
+#endif
+ }
+ return iface;
+}
+
+
+// IP_MULTICAST_ALL is on be default, disable it here.
+// If set to 1, the socket will receive messages from all the groups that have been joined
+// globally on the whole system. Otherwise, it will deliver messages only from the
+// groups that have been explicitly joined (for example via the IP_ADD_MEMBERSHIP option)
+// on this particular socket.
+#if HAVE_MULTICAST_ALL_DISABLE
+static int iperf_multicast_all_disable (struct thread_Settings *inSettings) {
+ int rc = 0;
+#if HAVE_DECL_IP_MULTICAST_ALL
+ int mc_all = 0;
+ rc = setsockopt(inSettings->mSock, IPPROTO_IP, IP_MULTICAST_ALL, (void*) &mc_all, sizeof(mc_all));
+ FAIL_errno(rc == SOCKET_ERROR, "ip_multicast_all", inSettings);
+#endif
+ return rc;
+}
+#endif
+
+// This is the older mulitcast join code. Both SSM and binding the
+// an interface requires the newer socket options. Using the older
+// code here will maintain compatiblity with previous iperf versions
+static int iperf_multicast_join_v4_legacy (struct thread_Settings *inSettings) {
+#if HAVE_DECL_IP_ADD_MEMBERSHIP
+#if (HAVE_STRUCT_IP_MREQ) || (HAVE_STRUCT_IP_MREQN)
+#if HAVE_STRUCT_IP_MREQ
+ struct ip_mreq mreq;
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ size_t len = sizeof(struct ip_mreq);
+#elif HAVE_STRUCT_IP_MREQN
+ // struct ip_mreqn {
+ // struct in_addr imr_multiaddr; /* IP multicast address of group */
+ // struct in_addr imr_interface; /* local IP address of interface */
+ // int imr_ifindex; /* interface index */
+ // }
+ struct ip_mreqn mreq;
+ size_t len = sizeof(struct ip_mreqn);
+ mreq.imr_address.s_addr = htonl(INADDR_ANY);
+ mreq.imr_ifindex = mcast_iface(inSettings);
+#endif
+ memcpy(&mreq.imr_multiaddr, SockAddr_get_in_addr(&inSettings->multicast_group), sizeof(mreq.imr_multiaddr));
+ int rc = setsockopt(inSettings->mSock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (char*)(&mreq), len);
+ FAIL_errno(rc == SOCKET_ERROR, "multicast join", inSettings);
+#if HAVE_MULTICAST_ALL_DISABLE
+ iperf_multicast_all_disable(inSettings);
+#endif
+ return ((rc == 0) ? IPERF_MULTICAST_JOIN_SUCCESS : IPERF_MULTICAST_JOIN_FAIL);
+#endif
+#endif
+ return IPERF_MULTICAST_JOIN_UNSUPPORTED;
+}
+
+static int iperf_multicast_join_v4_pi (struct thread_Settings *inSettings) {
+#if HAVE_DECL_MCAST_JOIN_GROUP
+ int rc = -1;
+ struct group_req group_req;
+
+ memset(&group_req, 0, sizeof(struct group_req));
+ memcpy(&group_req.gr_group, (struct sockaddr_in *)(&inSettings->multicast_group), sizeof(struct sockaddr_in));
+ group_req.gr_interface = mcast_iface(inSettings);
+ group_req.gr_group.ss_family = AF_INET;
+ rc = setsockopt(inSettings->mSock, IPPROTO_IP, MCAST_JOIN_GROUP, (const char *)(&group_req),
+ (socklen_t) sizeof(struct group_source_req));
+ FAIL_errno(rc == SOCKET_ERROR, "mcast v4 join group pi", inSettings);
+ return ((rc == 0) ? IPERF_MULTICAST_JOIN_SUCCESS : IPERF_MULTICAST_JOIN_FAIL);
+#else
+ return IPERF_MULTICAST_JOIN_UNSUPPORTED;
+#endif
+}
+
+
+static int iperf_multicast_join_v6 (struct thread_Settings *inSettings) {
+#if (HAVE_DECL_IPV6_JOIN_GROUP || HAVE_DECL_IPV6_ADD_MEMBERSHIP)
+#if HAVE_STRUCT_IPV6_MREQ
+ struct ipv6_mreq mreq;
+ memcpy(&mreq.ipv6mr_multiaddr, SockAddr_get_in6_addr(&inSettings->multicast_group), sizeof(mreq.ipv6mr_multiaddr));
+ mreq.ipv6mr_interface = mcast_iface(inSettings);
+#if HAVE_DECL_IPV6_JOIN_GROUP
+ int rc = setsockopt(inSettings->mSock, IPPROTO_IPV6, IPV6_JOIN_GROUP, \
+ (char*)(&mreq), sizeof(mreq));
+#else
+ int rc = setsockopt(inSettings->mSock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, \
+ (char*)(&mreq), sizeof(mreq));
+#endif
+ FAIL_errno(rc == SOCKET_ERROR, "multicast v6 join", inSettings);
+ return ((rc == 0) ? IPERF_MULTICAST_JOIN_SUCCESS : IPERF_MULTICAST_JOIN_FAIL);
+#endif
+#endif
+ return IPERF_MULTICAST_JOIN_UNSUPPORTED;
+
+}
+
+static int iperf_multicast_join_v6_pi (struct thread_Settings *inSettings) {
+#if HAVE_DECL_MCAST_JOIN_GROUP
+ int rc = -1;
+ struct group_req group_req;
+
+ memset(&group_req, 0, sizeof(struct group_req));
+ memcpy(&group_req.gr_group, (struct sockaddr_in6 *)(&inSettings->multicast_group), sizeof(struct sockaddr_in6));
+ group_req.gr_interface = mcast_iface(inSettings);
+ group_req.gr_group.ss_family = AF_INET6;
+ rc = setsockopt(inSettings->mSock, IPPROTO_IPV6, MCAST_JOIN_GROUP, (const char *)(&group_req),
+ (socklen_t) sizeof(struct group_source_req));
+ FAIL_errno(rc == SOCKET_ERROR, "mcast v6 join group", inSettings);
+ return ((rc == 0) ? IPERF_MULTICAST_JOIN_SUCCESS : IPERF_MULTICAST_JOIN_FAIL);
+#endif
+ return IPERF_MULTICAST_JOIN_UNSUPPORTED;
+}
+
+
+static int iperf_multicast_ssm_join_v4 (struct thread_Settings *inSettings) {
+#if HAVE_SSM_MULTICAST
+ int rc;
+ struct sockaddr_in *group;
+ struct sockaddr_in *source;
+
+ // Fill out both structures because we don't which one will succeed
+ // and both may need to be tried
+#if HAVE_STRUCT_IP_MREQ_SOURCE
+ struct ip_mreq_source imr;
+ memset (&imr, 0, sizeof (imr));
+#endif
+#if HAVE_STRUCT_GROUP_SOURCE_REQ
+ struct group_source_req group_source_req;
+ memset(&group_source_req, 0, sizeof(struct group_source_req));
+ group_source_req.gsr_interface = mcast_iface(inSettings);
+ group=(struct sockaddr_in *)(&group_source_req.gsr_group);
+ source=(struct sockaddr_in *)(&group_source_req.gsr_source);
+#else
+ struct sockaddr_in imrgroup;
+ struct sockaddr_in imrsource;
+ group = &imrgroup;
+ source = &imrsource;
+#endif
+ source->sin_family = AF_INET;
+ group->sin_family = AF_INET;
+ /* Set the group and SSM source*/
+ memcpy(group, (struct sockaddr_in *)(&inSettings->multicast_group), sizeof(struct sockaddr_in));
+ memcpy(source, (struct sockaddr_in *)(&inSettings->multicast_group_source), sizeof(struct sockaddr_in));
+#if HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+ source->sin_len = group->sin_len;
+#endif
+ source->sin_port = 0; /* Ignored */
+ rc = -1;
+
+#if HAVE_DECL_MCAST_JOIN_SOURCE_GROUP
+ rc = setsockopt(inSettings->mSock,IPPROTO_IP,MCAST_JOIN_SOURCE_GROUP, (const char *)(&group_source_req), \
+ sizeof(struct group_source_req));
+ WARN(rc == SOCKET_ERROR, "mcast v4 join ssm join_src");
+#endif
+
+#if (HAVE_DECL_IP_ADD_SOURCE_MEMBERSHIP && HAVE_STRUCT_IP_MREQ_SOURCE)
+ // Some operating systems will have MCAST_JOIN_SOURCE_GROUP but still fail
+ // In those cases try the IP_ADD_SOURCE_MEMBERSHIP
+ if (rc < 0) {
+#if HAVE_STRUCT_IP_MREQ_SOURCE_IMR_MULTIADDR_S_ADDR
+ imr.imr_multiaddr = ((const struct sockaddr_in *)group)->sin_addr;
+ imr.imr_sourceaddr = ((const struct sockaddr_in *)source)->sin_addr;
+#else
+ // Some Android versions declare mreq_source without an s_addr
+ imr.imr_multiaddr = ((const struct sockaddr_in *)group)->sin_addr.s_addr;
+ imr.imr_sourceaddr = ((const struct sockaddr_in *)source)->sin_addr.s_addr;
+#endif
+ rc = setsockopt (inSettings->mSock, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char*)(&imr), sizeof (imr));
+ FAIL_errno(rc == SOCKET_ERROR, "mcast v4 join ssm add_src", inSettings);
+ }
+#endif
+ return ((rc == 0) ? IPERF_MULTICAST_JOIN_SUCCESS : IPERF_MULTICAST_JOIN_FAIL);
+#endif
+ return IPERF_MULTICAST_JOIN_UNSUPPORTED;
+}
+
+static int iperf_multicast_ssm_join_v6 (struct thread_Settings *inSettings) {
+#if (HAVE_IPV6_MULTICAST && HAVE_SSM_MULTICAST && HAVE_DECL_MCAST_JOIN_SOURCE_GROUP)
+ int rc;
+
+ // Here it's either an SSM S,G multicast join or a *,G with an interface specifier
+ // Use the newer socket options when these are specified
+ struct group_source_req group_source_req;
+ struct sockaddr_in6 *group;
+ struct sockaddr_in6 *source;
+
+ memset(&group_source_req, 0, sizeof(struct group_source_req));
+
+ group_source_req.gsr_interface = mcast_iface(inSettings);
+ group=(struct sockaddr_in6*)(&group_source_req.gsr_group);
+ source=(struct sockaddr_in6*)(&group_source_req.gsr_source);
+ source->sin6_family = AF_INET6;
+ group->sin6_family = AF_INET6;
+ /* Set the group and SSM source*/
+ memcpy(group, (struct sockaddr_in *)(&inSettings->multicast_group), sizeof(struct sockaddr_in6));
+ memcpy(source, (struct sockaddr_in *)(&inSettings->multicast_group_source), sizeof(struct sockaddr_in6));
+ group->sin6_port = 0; /* Ignored */
+#if HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
+ source->sin6_len = group->sin6_len;
+#endif
+ rc = setsockopt(inSettings->mSock,IPPROTO_IPV6,MCAST_JOIN_SOURCE_GROUP, (const char *)(&group_source_req),
+ sizeof(struct group_source_req));
+ FAIL_errno(rc == SOCKET_ERROR, "mcast v6 join source group", inSettings);
+ return ((rc == 0) ? IPERF_MULTICAST_JOIN_SUCCESS : IPERF_MULTICAST_JOIN_FAIL);
+#endif
+ return IPERF_MULTICAST_JOIN_UNSUPPORTED;
+}
+
+enum McastJoinResponse iperf_multicast_join (struct thread_Settings *inSettings) {
+ int rc = IPERF_MULTICAST_JOIN_FAIL;
+ if (!isSSMMulticast(inSettings)) {
+ // *.G join
+ if (!SockAddr_isIPv6(&inSettings->multicast_group)) {
+ if (!mcast_iface(inSettings)) {
+ rc = iperf_multicast_join_v4_legacy(inSettings);
+ }
+ if (rc != IPERF_MULTICAST_JOIN_SUCCESS) {
+ rc = iperf_multicast_join_v4_pi(inSettings);
+ }
+ } else {
+ rc = iperf_multicast_join_v6(inSettings);
+ if (rc != IPERF_MULTICAST_JOIN_SUCCESS) {
+ rc = iperf_multicast_join_v6_pi(inSettings);
+ }
+ }
+ } else {
+ // SSM or S,G join
+ if (!SockAddr_isIPv6(&inSettings->multicast_group)) {
+ rc = iperf_multicast_ssm_join_v4(inSettings);
+ } else {
+ rc = iperf_multicast_ssm_join_v6(inSettings);
+ }
+ }
+ return rc;
+}
+
+static void iperf_multicast_sync_ifrname (struct thread_Settings *inSettings) {
+ if (inSettings->mIfrname && !inSettings->mIfrnametx) {
+ int len = strlen(inSettings->mIfrname);
+ inSettings->mIfrnametx = calloc((len + 1), sizeof(char));
+ if (inSettings->mIfrnametx) {
+ strncpy(inSettings->mIfrnametx, inSettings->mIfrname, len+1);
+ }
+ }
+ if (!inSettings->mIfrname && inSettings->mIfrnametx) {
+ int len = strlen(inSettings->mIfrnametx);
+ inSettings->mIfrname = calloc((len + 1), sizeof(char));
+ if (inSettings->mIfrname) {
+ strncpy(inSettings->mIfrname, inSettings->mIfrnametx, len+1);
+ }
+ }
+}
+
+bool iperf_multicast_sendif_v4 (struct thread_Settings *inSettings) {
+ bool result = false;
+#if HAVE_DECL_IP_MULTICAST_IF
+ struct in_addr interface_addr;
+ memcpy(&interface_addr, SockAddr_get_in_addr(&inSettings->local), sizeof(interface_addr));
+ int rc = setsockopt(inSettings->mSock, IPPROTO_IP, IP_MULTICAST_IF, \
+ (char*)(&interface_addr), sizeof(interface_addr));
+ if ((rc != SOCKET_ERROR) && SockAddr_Ifrname(inSettings)) {
+ iperf_multicast_sync_ifrname(inSettings);
+ }
+ FAIL_errno(rc == SOCKET_ERROR, "v4 multicast if", inSettings);
+ result = ((rc == 0) ? true : false);
+#endif
+ return result;
+}
+
+bool iperf_multicast_sendif_v6 (struct thread_Settings *inSettings) {
+ int result = false;
+#if HAVE_DECL_IPV6_MULTICAST_IF && HAVE_NET_IF_H && !WIN32
+ if (inSettings->mIfrnametx) {
+ unsigned int ifindex = if_nametoindex(inSettings->mIfrnametx);
+ if (ifindex) {
+ int rc = setsockopt(inSettings->mSock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex));
+ if (rc == 0) {
+ iperf_multicast_sync_ifrname(inSettings);
+ result = true;
+ }
+ }
+ }
+#endif
+ return result;
+}
diff --git a/src/isochronous.cpp b/src/isochronous.cpp
index 573f05a..62c9703 100644
--- a/src/isochronous.cpp
+++ b/src/isochronous.cpp
@@ -57,7 +57,7 @@ using namespace Isochronous;
FrameCounter::FrameCounter (double value, const Timestamp& start) : frequency(value) {
period = static_cast<unsigned int>(1000000 / frequency);
startTime = start;
- nextslotTime=start;
+ nextslotTime = start;
lastcounter = 0;
slot_counter = 0;
slip = 0;
@@ -69,6 +69,8 @@ FrameCounter::FrameCounter (double value) : frequency(value) {
if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL))
WARN_errno(1, "SetThreadPriority");
#endif
+ startTime.setnow();
+ nextslotTime = startTime;
period = static_cast<unsigned int>(1000000 / frequency); // unit us
lastcounter = 0;
slot_counter = 0;
@@ -119,23 +121,23 @@ int FrameCounter::mySetWaitableTimer (long delay_time) {
#endif
#if HAVE_CLOCK_NANOSLEEP
-unsigned int FrameCounter::wait_tick (long *sched_err) {
+unsigned int FrameCounter::wait_tick (long *sched_err, bool sync_strict) {
Timestamp now;
int rc = true;
if (!slot_counter) {
slot_counter = 1;
- now.setnow();
nextslotTime = now;
+ startTime = now;
} else {
- while (!now.before(nextslotTime)) {
- now.setnow();
+ nextslotTime.add(period);
+ slot_counter++;
+ while (now.subUsec(nextslotTime) > static_cast<long>(sync_strict ? 0 : period)) {
nextslotTime.add(period);
-// printf("***** next slot %ld.%ld\n",nextslotTime.getSecs(), nextslotTime.getUsecs());
slot_counter++;
}
- if (lastcounter && ((slot_counter - lastcounter) > 1)) {
+ if (lastcounter && ((slot_counter - lastcounter) > 1)) {
slip++;
- }
+ }
}
#ifndef WIN32
timespec txtime_ts;
@@ -179,42 +181,42 @@ unsigned int FrameCounter::wait_tick (long *sched_err) {
return(slot_counter);
}
#else
-unsigned int FrameCounter::wait_tick (long *sched_err) {
- long remaining;
- unsigned int framecounter;
-
- if (!lastcounter) {
- reset();
- framecounter = 1;
+unsigned int FrameCounter::wait_tick (long *sched_err, bool sync_strict) {
+ Timestamp now;
+ if (!slot_counter) {
+ slot_counter = 1;
+ startTime = now;
+ nextslotTime = now;
} else {
- framecounter = get(&remaining);
- if ((framecounter - lastcounter) > 1)
- slip++;
-// delay_loop(remaining);
- remaining *= 1000;
- struct timespec tv0={0,0}, tv1;
- tv0.tv_sec = (remaining / BILLION);
- tv0.tv_nsec += (remaining % BILLION);
- if (tv0.tv_nsec >= BILLION) {
- tv0.tv_sec++;
- tv0.tv_nsec -= BILLION;
+ long remaining;
+ nextslotTime.add(period);
+ slot_counter++;
+ while (now.subUsec(nextslotTime) > (sync_strict ? 0 : period)) {
+ nextslotTime.add(period);
+ slot_counter++;
}
- Timestamp slotstart = startTime;
- slot_counter = get();
- // period unit is in microseconds, convert to seconds
- slotstart.add(slot_counter * period * 1e-6);
- int rc = nanosleep(&tv0, &tv1);
- if (sched_err) {
- Timestamp actual;
- *sched_err = actual.subUsec(slotstart);
-// printf("**** slot %ld.%ld actual %ld.%ld %ld\n", slotstart.getSecs(), slotstart.getUsecs(), actual.getSecs(), actual.getUsecs(), *sched_err);
+// printf("**** sync strict %d now %ld.%ld next %ld.%ld\n", sync_strict, now.getSecs(), now.getUsecs(), nextslotTime.getSecs(), nextslotTime.getUsecs());
+ if (now.before(nextslotTime)) {
+ struct timespec tv0={0,0}, tv1;
+ get(&remaining);
+ remaining *= 1000; // convert to nano seconds
+ tv0.tv_sec = (remaining / BILLION);
+ tv0.tv_nsec += (remaining % BILLION);
+ if (tv0.tv_nsec >= BILLION) {
+ tv0.tv_sec++;
+ tv0.tv_nsec -= BILLION;
+ }
+// printf("**** wait: nanos %ld remain %ld.%ld\n", remaining, tv0.tv_sec, tv0.tv_nsec);
+ int rc = nanosleep(&tv0, &tv1);
+ if (sched_err) {
+ Timestamp actual;
+ *sched_err = actual.subUsec(nextslotTime);
+ // printf("**** slot %ld.%ld actual %ld.%ld %ld\n", slotstart.getSecs(), slotstart.getUsecs(), actual.getSecs(), actual.getUsecs(), *sched_err);
+ }
+ WARN_errno((rc != 0), "nanosleep wait_tick");
}
- WARN_errno((rc != 0), "nanosleep wait_tick"); ;
-// printf("****** rc = %d, remain %ld.%ld\n", rc, tv1.tv_sec, tv1.tv_nsec);
- framecounter ++;
}
- lastcounter = framecounter;
- return(framecounter);
+ return(slot_counter);
}
#endif
inline unsigned int FrameCounter::get () const {
@@ -226,7 +228,7 @@ inline unsigned int FrameCounter::get (const Timestamp& slot) const {
return(slot_counter + 1); // Frame counter for packets starts at 1
}
-inline unsigned int FrameCounter::get (long *ticks_remaining) {
+unsigned int FrameCounter::get (long *ticks_remaining) {
assert(ticks_remaining != NULL);
Timestamp sampleTime; // Constructor will initialize timestamp to now
long usecs = -startTime.subUsec(sampleTime);
@@ -234,7 +236,7 @@ inline unsigned int FrameCounter::get (long *ticks_remaining) {
// figure out how many usecs before the next frame counter tick
// the caller can use this to delay until the next tick
*ticks_remaining = (counter * period) - usecs;
- return(counter + 1); // Frame counter for packets starts at 1
+ return(counter); // Frame counter for packets starts at 1
}
inline Timestamp FrameCounter::next_slot () {
diff --git a/src/packet_ring.c b/src/packet_ring.c
index 93e7578..97a25a5 100644
--- a/src/packet_ring.c
+++ b/src/packet_ring.c
@@ -55,6 +55,11 @@ static int totalpacketringcount = 0;
Mutex packetringdebug_mutex;
#endif
+//
+// Initialize a packet ring between a traffic thread and the reporter thread
+// Note: enable dequeue events will have the dequeue return null on an event relevant to
+// the reporter thread moving to the next ring. This is needed for proper summing
+//
struct PacketRing * packetring_init (int count, struct Condition *awake_consumer, struct Condition *awake_producer) {
assert(awake_consumer != NULL);
struct PacketRing *pr = NULL;
@@ -78,6 +83,8 @@ struct PacketRing * packetring_init (int count, struct Condition *awake_consumer
pr->mutex_enable=1;
pr->consumerdone = 0;
pr->awaitcounter = 0;
+ pr->uplevel = HIGH;
+ pr->downlevel = HIGH;
#ifdef HAVE_THREAD_DEBUG
Mutex_Lock(&packetringdebug_mutex);
totalpacketringcount++;
@@ -103,7 +110,7 @@ inline void packetring_enqueue (struct PacketRing *pr, struct ReportStruct *meta
{
struct timeval now;
static struct timeval prev={0, 0};
- gettimeofday( &now, NULL );
+ TimeGetNow(now);
if (!prev.tv_sec || (TimeDifference(now, prev) > 1.0)) {
prev = now;
thread_debug( "Not good, traffic's packet ring %p stalled per %p", (void *)pr, (void *)&pr->awake_producer);
@@ -127,16 +134,18 @@ inline void packetring_enqueue (struct PacketRing *pr, struct ReportStruct *meta
inline struct ReportStruct *packetring_dequeue (struct PacketRing *pr) {
struct ReportStruct *packet = NULL;
- if (pr->producer == pr->consumer)
+ if (pr->producer == pr->consumer) {
return NULL;
-
+ }
int readindex;
if ((pr->consumer + 1) == pr->maxcount)
readindex = 0;
else
readindex = (pr->consumer + 1);
+
packet = (pr->data + readindex);
- // advance the consumer pointer last
+ // See if the dequeue needs to detect an event so the reporter
+ // can move to the next packet ring
pr->consumer = readindex;
if (pr->mutex_enable) {
// Signal the traffic thread assigned to this ring
@@ -152,6 +161,10 @@ inline struct ReportStruct *packetring_dequeue (struct PacketRing *pr) {
return packet;
}
+inline enum edgeLevel toggleLevel(enum edgeLevel level) {
+ return ((level == HIGH) ? LOW : HIGH);
+}
+
inline void enqueue_ackring (struct PacketRing *pr, struct ReportStruct *metapacket) {
packetring_enqueue(pr, metapacket);
// Keep the latency low by signaling the consumer thread
diff --git a/src/pdfs.c b/src/pdfs.c
index a1e0382..8110c8f 100644
--- a/src/pdfs.c
+++ b/src/pdfs.c
@@ -63,13 +63,16 @@
#define TRUE 1
float box_muller(void) {
float x1, x2, w, y1;
+#if 0
static float y2;
static int generate = FALSE;
/* Each iteration produces two values, if one exists use the value from previous call */
generate = !generate;
if (!generate) {
y1 = y2;
- } else {
+ } else
+#endif
+ {
int loopcontrol=100;
do {
x1 = 2.0 * (float)rand()/(float)(RAND_MAX) - 1.0;
@@ -82,7 +85,9 @@ float box_muller(void) {
} else {
w = sqrt( (-2.0 * logf( w ) ) / w );
y1 = x1 * w;
+#if 0
y2 = x2 * w;
+#endif
}
}
return(y1);
diff --git a/src/socket_io.c b/src/socket_io.c
index 0475310..0f83a6c 100644
--- a/src/socket_io.c
+++ b/src/socket_io.c
@@ -82,7 +82,7 @@ ssize_t readn (int inSock, void *outBuf, size_t inLen) {
if (errno == EINTR)
nread = 0; /* interupted, call read again */
else
- return -1; /* error */
+ return SOCKET_ERROR; /* error */
} else if (nread == 0)
break; /* EOF */
@@ -119,7 +119,7 @@ int recvn (int inSock, char *outBuf, int inLen, int flags) {
// Note: use TCP fatal error codes even for UDP
if (FATALTCPREADERR(errno)) {
WARN_errno(1, "recvn peek");
- nread = -1;
+ nread = SOCKET_ERROR;
sInterupted = 1;
goto DONE;
}
@@ -151,11 +151,11 @@ int recvn (int inSock, char *outBuf, int inLen, int flags) {
// Note: use TCP fatal error codes even for UDP
if (FATALTCPREADERR(errno)) {
WARN_errno(1, "recvn");
- nread = -1;
+ nread = SOCKET_ERROR;
sInterupted = 1;
goto DONE;
} else {
- nread = -2;
+ nread = IPERF_SOCKET_ERROR_NONFATAL;
goto DONE;
}
#ifdef HAVE_THREAD_DEBUG
@@ -179,7 +179,7 @@ int recvn (int inSock, char *outBuf, int inLen, int flags) {
}
DONE:
return(nread);
-} /* end readn */
+} /* end recvn */
/* -------------------------------------------------------------------
* Attempts to write n bytes to a socket.
@@ -202,7 +202,6 @@ int writen (int inSock, const void *inBuf, int inLen, int *count) {
ptr = (char*) inBuf;
nleft = inLen;
nwritten = 0;
- *count = 0;
while ((nleft > 0) && !sInterupted) {
nwritten = write(inSock, ptr, nleft);
@@ -212,9 +211,8 @@ int writen (int inSock, const void *inBuf, int inLen, int *count) {
// check for a fatal error vs an error that should retry
if ((errno != EINTR) && (errno != EAGAIN) && (errno != EWOULDBLOCK)) {
nwritten = inLen - nleft;
- fprintf(stdout, "FAIL: writen errno = %d\n", errno);
- WARN_errno(1, "writen fatal");
- sInterupted = 1;
+ fprintf(stdout, "FAIL: writen errno = %d (bytes=%d)\n", errno, nwritten);
+// sInterupted = 1;
goto DONE;
}
break;
diff --git a/src/stdio.c b/src/stdio.c
index 3bdf668..33e58ac 100644
--- a/src/stdio.c
+++ b/src/stdio.c
@@ -322,6 +322,17 @@ void byte_snprintf(char* outString, int inLen, double inNum, char inFormat) {
snprintf(outString, inLen, format, inNum, suffix);
} /* end byte_snprintf */
+
+void make_lower (char *s) {
+ if (s) {
+ int length = strlen(s);
+ for (int i = 0; i < length; i++) {
+ s[i] = tolower(s[i]);
+ }
+ }
+ return;
+}
+
/* -------------------------------------------------------------------
* redirect
*