Skip to content

Commit ab08bb2

Browse files
committed
Rebase using version 3.20+
1 parent 6b76500 commit ab08bb2

File tree

5 files changed

+285
-49
lines changed

5 files changed

+285
-49
lines changed

configure.ac

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,10 @@ AC_CHECK_FUNCS([sendfile])
253253
# connections.
254254
AC_CHECK_FUNCS([getline])
255255

256+
# Check for sendmmsg/recvmmsg support for better throughput.
257+
AC_CHECK_FUNCS([sendmmsg recvmmsg],
258+
AC_DEFINE([HAVE_SEND_RECVMMSG], [1], [Have sendmmsg/recvmmsg functions.]))
259+
256260
# Check for packet pacing socket option (Linux only for now).
257261
AC_CACHE_CHECK([SO_MAX_PACING_RATE socket option],
258262
[iperf3_cv_header_so_max_pacing_rate],

src/iperf.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@ struct iperf_sctp_info
9191
uint32_t cwnd;
9292
};
9393

94+
#ifndef HAVE_SENDMMSG
95+
struct dummy_mmsghdr {
96+
struct msghdr msg_hdr; /* Message header */
97+
unsigned int msg_len; /* Number of received bytes for header */
98+
};
99+
#endif /* HAVE_SENDMMSG */
100+
101+
/* macro to calculate buffer sizes used for a stream (to support hse of send/recvmmsg) */
102+
#define STREAM_BUFSIZE(prefix) (((prefix)->settings->blksize) * (((prefix)->settings->send_recvmmsg == 0 || (prefix)->settings->burst == 0)? 1 : (prefix)->settings->burst))
103+
94104
struct iperf_interval_results
95105
{
96106
atomic_iperf_size_t bytes_transferred; /* bytes transferred in this interval */
@@ -186,6 +196,7 @@ struct iperf_settings
186196
int connect_timeout; /* socket connection timeout, in ms */
187197
int idle_timeout; /* server idle time timeout */
188198
unsigned int snd_timeout; /* Timeout for sending tcp messages in active mode, in us */
199+
int send_recvmmsg; /* whether sendmmsg/recvmmsg should be used - mainly per the -Z option */
189200
struct iperf_time rcv_timeout; /* Timeout for receiving messages in active mode, in us */
190201
int cntl_ka; /* Use Control TCP connection Keepalive */
191202
int cntl_ka_keepidle; /* Control TCP connection Keepalive idle time (TCP_KEEPIDLE) */
@@ -237,6 +248,16 @@ struct iperf_stream
237248
int64_t omitted_outoforder_packets;
238249
int64_t cnt_error;
239250
int64_t omitted_cnt_error;
251+
252+
#ifdef HAVE_SENDMMSG
253+
struct mmsghdr *msg; /* For some reason, just struct and not a pointer failes on "field ‘msg’ has incomplete type" */
254+
#else
255+
struct dummy_mmsghdr *msg;
256+
#endif /* HAVE_SENDMMSG */
257+
struct iovec *pmsg_iov; /* Pointer to the array of iov_msg per mmsg message */
258+
int sendmmsg_buffered_packets_count; /* number of buffered packets for sendmmsg */
259+
char *pbuf; /* Pointer to current vailable space in buffer */
260+
240261
uint64_t target;
241262

242263
struct sockaddr_storage local_addr;

src/iperf_api.c

Lines changed: 95 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include <fcntl.h>
4444
#include <sys/socket.h>
4545
#include <sys/types.h>
46+
#include <sys/uio.h>
4647
#include <netinet/in.h>
4748
#include <arpa/inet.h>
4849
#include <netdb.h>
@@ -101,6 +102,7 @@ static int JSON_write(int fd, cJSON *json);
101102
static void print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON *json_interval_streams);
102103
static cJSON *JSON_read(int fd, int max_size);
103104
static int JSONStream_Output(struct iperf_test *test, const char* event_name, cJSON* obj);
105+
void iperf_init_send_recvmmsg(struct iperf_test *test);
104106

105107

106108
/*************************** Print usage functions ****************************/
@@ -1971,6 +1973,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
19711973
1 : round(test->settings->bitrate_limit_interval/test->stats_interval) );
19721974
}
19731975

1976+
/* Set whether send/recvmmsg is supported along with related settings */
1977+
iperf_init_send_recvmmsg(test);
1978+
19741979
/* Show warning if JSON output is used with explicit report format */
19751980
if ((test->json_output) && (test->settings->unit_format != 'a')) {
19761981
warning("Report format (-f) flag ignored with JSON output (-J)");
@@ -2335,6 +2340,9 @@ iperf_exchange_parameters(struct iperf_test *test)
23352340
}
23362341
return -1;
23372342
}
2343+
2344+
/* Set whether send/recvmmsg is supported along with related settings */
2345+
iperf_init_send_recvmmsg(test);
23382346

23392347
#if defined(HAVE_SSL)
23402348
if (test_is_authorized(test) < 0){
@@ -3255,6 +3263,8 @@ iperf_defaults(struct iperf_test *testp)
32553263
testp->json_callback = NULL;
32563264

32573265

3266+
testp->zerocopy = 0;
3267+
testp->settings->send_recvmmsg = 0;
32583268
memset(testp->cookie, 0, COOKIE_SIZE);
32593269

32603270
testp->multisend = 10; /* arbitrary */
@@ -3555,6 +3565,7 @@ iperf_reset_test(struct iperf_test *test)
35553565
test->settings->dont_fragment = 0;
35563566
test->zerocopy = 0;
35573567
test->settings->skip_rx_copy = 0;
3568+
test->settings->send_recvmmsg = 0;
35583569

35593570
#if defined(HAVE_SSL)
35603571
if (test->settings->authtoken) {
@@ -3616,6 +3627,8 @@ iperf_reset_stats(struct iperf_test *test)
36163627
sp->omitted_cnt_error = sp->cnt_error;
36173628
sp->omitted_outoforder_packets = sp->outoforder_packets;
36183629
sp->jitter = 0;
3630+
sp->sendmmsg_buffered_packets_count = 0;
3631+
sp->pbuf = sp->buffer;
36193632
rp = sp->result;
36203633
rp->bytes_sent_omit = rp->bytes_sent;
36213634
rp->bytes_received = 0;
@@ -4694,9 +4707,15 @@ void
46944707
iperf_free_stream(struct iperf_stream *sp)
46954708
{
46964709
struct iperf_interval_results *irp, *nirp;
4710+
int r;
46974711

46984712
/* XXX: need to free interval list too! */
4699-
munmap(sp->buffer, sp->test->settings->blksize);
4713+
r = munmap(sp->buffer, STREAM_BUFSIZE(sp->test));
4714+
if (r < 0)
4715+
printf("Failed to release stream buffer at %p with size %d - errno=%d: %s)\n", sp->buffer, STREAM_BUFSIZE(sp->test), errno, strerror(errno));
4716+
else if (sp->test->debug)
4717+
printf("Successfully released stream buffer at %p with size %d\n", sp->buffer, STREAM_BUFSIZE(sp->test));
4718+
47004719
close(sp->buffer_fd);
47014720
if (sp->diskfile_fd >= 0)
47024721
close(sp->diskfile_fd);
@@ -4707,6 +4726,11 @@ iperf_free_stream(struct iperf_stream *sp)
47074726
free(sp->result);
47084727
if (sp->send_timer != NULL)
47094728
tmr_cancel(sp->send_timer);
4729+
4730+
if (sp->pmsg_iov != NULL)
4731+
free(sp->pmsg_iov);
4732+
if (sp->msg != NULL)
4733+
free(sp->msg);
47104734
free(sp);
47114735
}
47124736

@@ -4716,6 +4740,9 @@ iperf_new_stream(struct iperf_test *test, int s, int sender)
47164740
{
47174741
struct iperf_stream *sp;
47184742
int ret = 0;
4743+
int burst;
4744+
int i;
4745+
char *pbuf;
47194746

47204747
char template[1024];
47214748
if (test->tmp_template) {
@@ -4774,19 +4801,50 @@ iperf_new_stream(struct iperf_test *test, int s, int sender)
47744801
free(sp);
47754802
return NULL;
47764803
}
4777-
if (ftruncate(sp->buffer_fd, test->settings->blksize) < 0) {
4804+
if (ftruncate(sp->buffer_fd, STREAM_BUFSIZE(sp)) < 0) {
47784805
i_errno = IECREATESTREAM;
47794806
free(sp->result);
47804807
free(sp);
47814808
return NULL;
47824809
}
4783-
sp->buffer = (char *) mmap(NULL, test->settings->blksize, PROT_READ|PROT_WRITE, MAP_SHARED, sp->buffer_fd, 0);
4810+
4811+
sp->buffer = (char *) mmap(NULL, STREAM_BUFSIZE(sp), PROT_READ|PROT_WRITE, MAP_PRIVATE, sp->buffer_fd, 0);
47844812
if (sp->buffer == MAP_FAILED) {
47854813
i_errno = IECREATESTREAM;
47864814
free(sp->result);
47874815
free(sp);
47884816
return NULL;
47894817
}
4818+
else if (sp->test->debug)
4819+
printf("Successfully allocated stream buffer at addr %p with length %d\n", sp->buffer, STREAM_BUFSIZE(sp));
4820+
4821+
/* Allocate and initialize pointers for the messages in the buffer for UDP multi-msg send/receive */
4822+
if (test->protocol->id == Pudp) {
4823+
burst = (sp->settings->send_recvmmsg == 0)? 1 : sp->settings->burst;
4824+
sp->msg = malloc(burst * sizeof(*sp->msg));
4825+
if (sp->msg == NULL) {
4826+
i_errno = IECREATESTREAM;
4827+
iperf_free_stream(sp);
4828+
return NULL;
4829+
}
4830+
memset(sp->msg, 0, burst * sizeof(*sp->msg));
4831+
4832+
sp->pmsg_iov = malloc(burst * sizeof(struct iovec));
4833+
if (sp->pmsg_iov == NULL) {
4834+
i_errno = IECREATESTREAM;
4835+
iperf_free_stream(sp);
4836+
return NULL;
4837+
}
4838+
memset(sp->pmsg_iov, 0, burst * sizeof(struct iovec));
4839+
4840+
for (i = 0, pbuf = sp->buffer; i < burst; i++, pbuf += sp->settings->blksize) {
4841+
sp->msg[i].msg_hdr.msg_iov = &sp->pmsg_iov[i];
4842+
sp->msg[i].msg_hdr.msg_iov->iov_base = pbuf;
4843+
sp->msg[i].msg_hdr.msg_iov->iov_len = sp->settings->blksize;
4844+
sp->msg[i].msg_hdr.msg_iovlen = 1;
4845+
}
4846+
}
4847+
47904848
sp->pending_size = 0;
47914849

47924850
/* Set socket */
@@ -4795,11 +4853,14 @@ iperf_new_stream(struct iperf_test *test, int s, int sender)
47954853
sp->snd = test->protocol->send;
47964854
sp->rcv = test->protocol->recv;
47974855

4856+
sp->sendmmsg_buffered_packets_count = 0;
4857+
sp->pbuf = sp->buffer;
4858+
47984859
if (test->diskfile_name != (char*) 0) {
47994860
sp->diskfile_fd = open(test->diskfile_name, sender ? O_RDONLY : (O_WRONLY|O_CREAT|O_TRUNC), S_IRUSR|S_IWUSR);
48004861
if (sp->diskfile_fd == -1) {
48014862
i_errno = IEFILE;
4802-
munmap(sp->buffer, sp->test->settings->blksize);
4863+
munmap(sp->buffer, STREAM_BUFSIZE(sp));
48034864
free(sp->result);
48044865
free(sp);
48054866
return NULL;
@@ -4813,13 +4874,13 @@ iperf_new_stream(struct iperf_test *test, int s, int sender)
48134874

48144875
/* Initialize stream */
48154876
if (test->repeating_payload)
4816-
fill_with_repeating_pattern(sp->buffer, test->settings->blksize);
4877+
fill_with_repeating_pattern(sp->buffer, STREAM_BUFSIZE(sp));
48174878
else
4818-
ret = readentropy(sp->buffer, test->settings->blksize);
4879+
ret = readentropy(sp->buffer, STREAM_BUFSIZE(sp));
48194880

48204881
if ((ret < 0) || (iperf_init_stream(sp, test) < 0)) {
48214882
close(sp->buffer_fd);
4822-
munmap(sp->buffer, sp->test->settings->blksize);
4883+
munmap(sp->buffer, STREAM_BUFSIZE(sp));
48234884
free(sp->result);
48244885
free(sp);
48254886
return NULL;
@@ -4972,7 +5033,7 @@ diskfile_send(struct iperf_stream *sp)
49725033

49735034
/* if needed, read enough data from the disk to fill up the buffer */
49745035
if (sp->diskfile_left < sp->test->settings->blksize && !sp->test->done) {
4975-
r = read(sp->diskfile_fd, sp->buffer, sp->test->settings->blksize -
5036+
r = read(sp->diskfile_fd, sp->buffer, STREAM_BUFSIZE(sp) -
49765037
sp->diskfile_left);
49775038
buffer_left += r;
49785039
rtot += r;
@@ -4982,8 +5043,8 @@ diskfile_send(struct iperf_stream *sp)
49825043

49835044
// If the buffer doesn't contain a full buffer at this point,
49845045
// adjust the size of the data to send.
4985-
if (buffer_left != sp->test->settings->blksize) {
4986-
if (sp->test->debug)
5046+
if (buffer_left != STREAM_BUFSIZE(sp)) {
5047+
if (sp->test->debug)
49875048
printf("possible eof\n");
49885049
// setting data size to be sent,
49895050
// which is less than full block/buffer size
@@ -5572,3 +5633,27 @@ iperf_set_control_keepalive(struct iperf_test *test)
55725633
return 0;
55735634
}
55745635
#endif //HAVE_TCP_KEEPALIVE
5636+
5637+
/*
5638+
* Initialize whether sed/recvmmsg is supported for the test,
5639+
* along with initializing other related settings.
5640+
*/
5641+
void
5642+
iperf_init_send_recvmmsg(struct iperf_test *test)
5643+
{
5644+
#ifdef HAVE_SENDMMSG
5645+
/* Set UDP `send_recvmmsg` from `zerocopy` settings (not used for disk file) */
5646+
if (test->protocol->id == Pudp && test->zerocopy && test->diskfile_name == (char *)0) {
5647+
test->settings->send_recvmmsg = 1;
5648+
/* Ensure non-zero burst number of packets when sendmmsg/recvmmsg are used */
5649+
if (test->settings->burst == 0)
5650+
test->settings->burst = 1;
5651+
#ifdef UIO_MAXIOV
5652+
/* Ensure burst size is appropriate for sendmmsg() */
5653+
else if (test->settings->burst > UIO_MAXIOV)
5654+
test->settings->burst = UIO_MAXIOV;
5655+
#endif /* UIO_MAXIOV */
5656+
}
5657+
#endif /* HAVE_SENDMMSG */
5658+
return;
5659+
}

src/iperf_locale.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,10 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
211211
" -L, --flowlabel N set the IPv6 flow label (only supported on Linux)\n"
212212
#endif /* HAVE_FLOWLABEL */
213213
" -Z, --zerocopy use a 'zero copy' method of sending data\n"
214+
#if defined(HAVE_SENDMMSG)
215+
" UDP: use `sendmmsg` to send `-b` bust number of messages;\n"
216+
" (not supported when reading from a file).\n"
217+
#endif /* HAVE_SENDMMSG */
214218
#if defined(HAVE_MSG_TRUNC)
215219
" --skip-rx-copy ignore received messages using MSG_TRUNC option\n"
216220
#endif /* HAVE_MSG_TRUNC */

0 commit comments

Comments
 (0)