Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/iperf.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ struct iperf_settings
int domain; /* AF_INET or AF_INET6 */
int socket_bufsize; /* window size for TCP */
int blksize; /* size of read/writes (-l) */
int num_of_blocks; /* number of different (mainly for randomized) blocks to send (-l) */
int last_block_sent; /* last block sent from the `num_of_blocks` */
iperf_size_t rate; /* target data rate for application pacing*/
iperf_size_t bitrate_limit; /* server's maximum allowed total data rate for all streams*/
double bitrate_limit_interval; /* interval for averaging total data rate */
Expand Down Expand Up @@ -219,6 +221,7 @@ struct iperf_stream
int green_light;
int buffer_fd; /* data to send, file descriptor */
char *buffer; /* data to send, mmapped */
size_t buffer_size; /* size of the buffer */
int pending_size; /* pending data to send */
int diskfile_fd; /* file to send, file descriptor */
int diskfile_left; /* remaining file data on disk */
Expand Down
50 changes: 39 additions & 11 deletions src/iperf_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -1357,7 +1357,19 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
client_flag = 1;
break;
case 'l':
blksize = unit_atoi(optarg);
slash = strchr(optarg, '/');
if (slash) {
*slash = '\0';
++slash;
test->settings->num_of_blocks = atof(slash);
if (test->settings->num_of_blocks < 1) {
i_errno = IETNUMOFBLOCKS;
return -1;
}
}
if (strlen(optarg) > 0) {
blksize = unit_atoi(optarg);
}
client_flag = 1;
break;
case 'P':
Expand Down Expand Up @@ -1835,6 +1847,10 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
i_errno = IEUDPBLOCKSIZE;
return -1;
}
if (blksize * test->settings->num_of_blocks > MAX_BLOCKSIZE) {
i_errno = IETNUMOFBLOCKS;
return -1;
}
test->settings->blksize = blksize;

if (!rate_flag)
Expand Down Expand Up @@ -2357,6 +2373,7 @@ send_parameters(struct iperf_test *test)
cJSON_AddNumberToObject(j, "window", test->settings->socket_bufsize);
if (test->settings->blksize)
cJSON_AddNumberToObject(j, "len", test->settings->blksize);
cJSON_AddNumberToObject(j, "numblocks", test->settings->num_of_blocks);
if (test->settings->rate)
cJSON_AddNumberToObject(j, "bandwidth", test->settings->rate);
if (test->settings->fqrate)
Expand Down Expand Up @@ -2479,6 +2496,8 @@ get_parameters(struct iperf_test *test)
test->settings->socket_bufsize = j_p->valueint;
if ((j_p = iperf_cJSON_GetObjectItemType(j, "len", cJSON_Number)) != NULL)
test->settings->blksize = j_p->valueint;
if ((j_p = iperf_cJSON_GetObjectItemType(j, "numblocks", cJSON_Number)) != NULL)
test->settings->num_of_blocks = j_p->valueint;
if ((j_p = iperf_cJSON_GetObjectItemType(j, "bandwidth", cJSON_Number)) != NULL)
test->settings->rate = j_p->valueint;
if ((j_p = iperf_cJSON_GetObjectItemType(j, "fqrate", cJSON_Number)) != NULL)
Expand Down Expand Up @@ -3125,6 +3144,8 @@ iperf_defaults(struct iperf_test *testp)
testp->settings->unit_format = 'a';
testp->settings->socket_bufsize = 0; /* use autotuning */
testp->settings->blksize = DEFAULT_TCP_BLKSIZE;
testp->settings->num_of_blocks = 1;
testp->settings->last_block_sent = 0;
testp->settings->rate = 0;
testp->settings->bitrate_limit = 0;
testp->settings->bitrate_limit_interval = 5;
Expand Down Expand Up @@ -3440,6 +3461,8 @@ iperf_reset_test(struct iperf_test *test)
test->num_streams = 1;
test->settings->socket_bufsize = 0;
test->settings->blksize = DEFAULT_TCP_BLKSIZE;
test->settings->num_of_blocks = 1;
test->settings->last_block_sent = 0;
test->settings->rate = 0;
test->settings->fqrate = 0;
test->settings->burst = 0;
Expand Down Expand Up @@ -4584,7 +4607,7 @@ iperf_free_stream(struct iperf_stream *sp)
struct iperf_interval_results *irp, *nirp;

/* XXX: need to free interval list too! */
munmap(sp->buffer, sp->test->settings->blksize);
munmap(sp->buffer, sp->buffer_size);
close(sp->buffer_fd);
if (sp->diskfile_fd >= 0)
close(sp->diskfile_fd);
Expand All @@ -4604,6 +4627,7 @@ iperf_new_stream(struct iperf_test *test, int s, int sender)
{
struct iperf_stream *sp;
int ret = 0;
size_t buffer_size = test->settings->blksize * test->settings->num_of_blocks;

char template[1024];
if (test->tmp_template) {
Expand Down Expand Up @@ -4662,19 +4686,20 @@ iperf_new_stream(struct iperf_test *test, int s, int sender)
free(sp);
return NULL;
}
if (ftruncate(sp->buffer_fd, test->settings->blksize) < 0) {
if (ftruncate(sp->buffer_fd, buffer_size) < 0) {
i_errno = IECREATESTREAM;
free(sp->result);
free(sp);
return NULL;
}
sp->buffer = (char *) mmap(NULL, test->settings->blksize, PROT_READ|PROT_WRITE, MAP_PRIVATE, sp->buffer_fd, 0);
sp->buffer = (char *) mmap(NULL, buffer_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, sp->buffer_fd, 0);
if (sp->buffer == MAP_FAILED) {
i_errno = IECREATESTREAM;
free(sp->result);
free(sp);
return NULL;
}
sp->buffer_size = buffer_size;
sp->pending_size = 0;

/* Set socket */
Expand All @@ -4687,7 +4712,7 @@ iperf_new_stream(struct iperf_test *test, int s, int sender)
sp->diskfile_fd = open(test->diskfile_name, sender ? O_RDONLY : (O_WRONLY|O_CREAT|O_TRUNC), S_IRUSR|S_IWUSR);
if (sp->diskfile_fd == -1) {
i_errno = IEFILE;
munmap(sp->buffer, sp->test->settings->blksize);
munmap(sp->buffer, sp->buffer_size);
free(sp->result);
free(sp);
return NULL;
Expand All @@ -4699,15 +4724,18 @@ iperf_new_stream(struct iperf_test *test, int s, int sender)
} else
sp->diskfile_fd = -1;

/* Initialize stream */
if (test->repeating_payload)
fill_with_repeating_pattern(sp->buffer, test->settings->blksize);
else
ret = readentropy(sp->buffer, test->settings->blksize);
/* Initialize stream send buffer */
if (sender) {
if (test->repeating_payload)
fill_with_repeating_pattern(sp->buffer, sp->buffer_size);
else {
ret = readentropy(sp->buffer, sp->buffer_size);
}
}

if ((ret < 0) || (iperf_init_stream(sp, test) < 0)) {
close(sp->buffer_fd);
munmap(sp->buffer, sp->test->settings->blksize);
munmap(sp->buffer, sp->buffer_size);
free(sp->result);
free(sp);
return NULL;
Expand Down
1 change: 1 addition & 0 deletions src/iperf_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ enum {
IEUDPFILETRANSFER = 34, // Cannot transfer file using UDP
IESERVERAUTHUSERS = 35, // Cannot access authorized users file
IECNTLKA = 36, // Control connection Keepalive period should be larger than the full retry period (interval * count)
IETNUMOFBLOCKS = 37, // Invalid number of different (randomized) blocks to send
/* Test errors */
IENEWTEST = 100, // Unable to create a new test (check perror)
IEINITTEST = 101, // Test initialization failed (check perror)
Expand Down
3 changes: 3 additions & 0 deletions src/iperf_error.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ iperf_strerror(int int_errno)
case IEUDPBLOCKSIZE:
snprintf(errstr, len, "block size invalid (minimum = %d bytes, maximum = %d bytes)", MIN_UDP_BLOCKSIZE, MAX_UDP_BLOCKSIZE);
break;
case IETNUMOFBLOCKS:
snprintf(errstr, len, "number of different (randomized) blocks to send invalid (minimum = 1, max total size of all blocks = %d)", MAX_BLOCKSIZE);
break;
case IEBADTOS:
snprintf(errstr, len, "bad TOS value (must be between 0 and 255 inclusive)");
break;
Expand Down
5 changes: 3 additions & 2 deletions src/iperf_locale.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,9 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
" (per direction) at least this number of bytes (instead of -t or -k)\n"
" -k, --blockcount #[KMG] transmit until the end of the interval when the client sent or received\n"
" (per direction) at least this number of blocks (instead of -t or -n)\n"
" -l, --length #[KMG] length of buffer to read or write\n"
" (default %d KB for TCP, dynamic or %d for UDP)\n"
" -l, --length #[KMG]/[/#] length of buffer to read or write\n"
" (default %d KB for TCP, dynamic or %d for UDP)\n"
" (optional slash and number of different (randomized) blocks to send)\n"
" --cport <port> bind to a specific client port (TCP and UDP, default: ephemeral port)\n"
" -P, --parallel # number of parallel client streams to run\n"
" -R, --reverse run in reverse mode (server sends, client receives)\n"
Expand Down
15 changes: 14 additions & 1 deletion src/iperf_sctp.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,21 @@ iperf_sctp_send(struct iperf_stream *sp)
{
#if defined(HAVE_SCTP_H)
int r;
int size = sp->settings->blksize;
char *buffer = sp->buffer;
int num_of_blocks = sp->settings->num_of_blocks;
int block_to_send;

if (num_of_blocks > 1) { // Send the next buffered block (mainly used for randomized blocks)
block_to_send = sp->settings->last_block_sent + 1;
if (block_to_send >= num_of_blocks) {
block_to_send = 0;
}
sp->settings->last_block_sent = block_to_send;
buffer += (size * block_to_send);
}

r = Nwrite(sp->socket, sp->buffer, sp->settings->blksize, Psctp);
r = Nwrite(sp->socket, buffer, size, Psctp);
if (r < 0)
return r;

Expand Down
27 changes: 22 additions & 5 deletions src/iperf_tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,31 @@ int
iperf_tcp_send(struct iperf_stream *sp)
{
int r;

if (!sp->pending_size)
sp->pending_size = sp->settings->blksize;
int size = sp->settings->blksize;
char *buffer = sp->buffer;
int num_of_blocks = sp->settings->num_of_blocks;
int block_to_send;

if (!sp->pending_size) {
sp->pending_size = size;
if (num_of_blocks > 1) { // Send the next buffered block (mainly used for randomized blocks)
block_to_send = sp->settings->last_block_sent + 1;
if (block_to_send >= num_of_blocks) {
block_to_send = 0;
}
sp->settings->last_block_sent = block_to_send;
buffer += (size * block_to_send);
}
} else {
if (num_of_blocks > 1) { // Send the next buffered block (mainly used for randomized blocks)
buffer += (size * sp->settings->last_block_sent) - sp->pending_size;
}
}

if (sp->test->zerocopy)
r = Nsendfile(sp->buffer_fd, sp->socket, sp->buffer, sp->pending_size);
r = Nsendfile(sp->buffer_fd, sp->socket, buffer, sp->pending_size);
else
r = Nwrite(sp->socket, sp->buffer, sp->pending_size, Ptcp);
r = Nwrite(sp->socket, buffer, sp->pending_size, Ptcp);

if (r < 0)
return r;
Expand Down
26 changes: 19 additions & 7 deletions src/iperf_udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,22 @@ iperf_udp_send(struct iperf_stream *sp)
{
int r;
int size = sp->settings->blksize;
char *buffer = sp->buffer;
int num_of_blocks = sp->settings->num_of_blocks;
int block_to_send;
struct iperf_time before;

iperf_time_now(&before);

if (num_of_blocks > 1) { // Send the next buffered block (mainly used for randomized blocks)
block_to_send = sp->settings->last_block_sent + 1;
if (block_to_send >= num_of_blocks) {
block_to_send = 0;
}
sp->settings->last_block_sent = block_to_send;
buffer += (size * block_to_send);
}

++sp->packet_count;

if (sp->test->udp_counters_64bit) {
Expand All @@ -227,9 +239,9 @@ iperf_udp_send(struct iperf_stream *sp)
usec = htonl(before.usecs);
pcount = htobe64(sp->packet_count);

memcpy(sp->buffer, &sec, sizeof(sec));
memcpy(sp->buffer+4, &usec, sizeof(usec));
memcpy(sp->buffer+8, &pcount, sizeof(pcount));
memcpy(buffer, &sec, sizeof(sec));
memcpy(buffer+4, &usec, sizeof(usec));
memcpy(buffer+8, &pcount, sizeof(pcount));

}
else {
Expand All @@ -240,13 +252,13 @@ iperf_udp_send(struct iperf_stream *sp)
usec = htonl(before.usecs);
pcount = htonl(sp->packet_count);

memcpy(sp->buffer, &sec, sizeof(sec));
memcpy(sp->buffer+4, &usec, sizeof(usec));
memcpy(sp->buffer+8, &pcount, sizeof(pcount));
memcpy(buffer, &sec, sizeof(sec));
memcpy(buffer+4, &usec, sizeof(usec));
memcpy(buffer+8, &pcount, sizeof(pcount));

}

r = Nwrite(sp->socket, sp->buffer, size, Pudp);
r = Nwrite(sp->socket, buffer, size, Pudp);

if (r <= 0) {
--sp->packet_count; /* Don't count messages that no data was sent from them.
Expand Down
1 change: 0 additions & 1 deletion src/iperf_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ int readentropy(void *out, size_t outsize)
{
static FILE *frandom;
static const char rndfile[] = "/dev/urandom";

if (!outsize) return 0;

if (frandom == NULL) {
Expand Down