Add a --udp-counters-64bit feature to support very long UDP tests.
UDP tests store a packet sequence number in the packets to detect loss and ordering issues. This sequence number is a 32-bit signed integer, which can wrap during very long-running UDP tests. This change adds an option (defaulting to off) which uses a 64-bit unsigned integer to store this quantity in the packet. The option is specified on the client side; the server must support this feature for proper functioning (older servers will interoperate with newer clients, as long as --udp-counters-64-bit is not used). The default might be changed in a future version of iperf3. As a part of this change, the client sends its version string to the server in the parameter block. Uses a public-domain compatibility shim for 64-bit byte order conversions. There are probably some additional platforms that need to be supported, in particular Solaris. We might add some configure-time checks to only enable this feature on platforms where we can support the byte-order conversions. This change is not well-tested. Towards issue #191.
Этот коммит содержится в:
родитель
d30a2c8d04
Коммит
329523a557
12
LICENSE
12
LICENSE
@ -255,3 +255,15 @@ This software contains source code (src/units.{c.h}) that is:
|
||||
* -------------------------------------------------------------------
|
||||
* input and output numbers, converting with kilo, mega, giga
|
||||
* ------------------------------------------------------------------- */
|
||||
|
||||
=====
|
||||
|
||||
This software contains source code (src/portable_endian.h) that is:
|
||||
|
||||
// "License": Public Domain
|
||||
// I, Mathias Panzenböck, place this file hereby into the public domain. Use it at your own risk for whatever you like.
|
||||
|
||||
=====
|
||||
|
||||
|
||||
|
||||
|
@ -91,7 +91,7 @@ struct iperf_settings
|
||||
int tos; /* type of service bit */
|
||||
int flowlabel; /* IPv6 flow label */
|
||||
iperf_size_t bytes; /* number of bytes to send */
|
||||
int blocks; /* number of blocks (packets) to send */
|
||||
iperf_size_t blocks; /* number of blocks (packets) to send */
|
||||
char unit_format; /* -f */
|
||||
};
|
||||
|
||||
@ -200,6 +200,7 @@ struct iperf_test
|
||||
int zerocopy; /* -Z option - use sendfile */
|
||||
int debug; /* -d option - enable debug */
|
||||
int get_server_output; /* --get-server-output */
|
||||
int udp_counters_64bit; /* --use-64-bit-udp-counters */
|
||||
|
||||
int multisend;
|
||||
|
||||
@ -227,7 +228,7 @@ struct iperf_test
|
||||
int num_streams; /* total streams in the test (-P) */
|
||||
|
||||
iperf_size_t bytes_sent;
|
||||
int blocks_sent;
|
||||
iperf_size_t blocks_sent;
|
||||
char cookie[COOKIE_SIZE];
|
||||
// struct iperf_stream *streams; /* pointer to list of struct stream */
|
||||
SLIST_HEAD(slisthead, iperf_stream) streams;
|
||||
|
@ -59,7 +59,7 @@
|
||||
#include "tcp_window_size.h"
|
||||
#include "iperf_util.h"
|
||||
#include "locale.h"
|
||||
|
||||
#include "version.h"
|
||||
|
||||
/* Forwards. */
|
||||
static int send_parameters(struct iperf_test *test);
|
||||
@ -235,6 +235,12 @@ iperf_get_test_bind_address(struct iperf_test *ipt)
|
||||
return ipt->bind_address;
|
||||
}
|
||||
|
||||
int
|
||||
iperf_get_test_udp_counters_64bit(struct iperf_test *ipt)
|
||||
{
|
||||
return ipt->udp_counters_64bit;
|
||||
}
|
||||
|
||||
/************** Setter routines for some fields inside iperf_test *************/
|
||||
|
||||
void
|
||||
@ -388,6 +394,12 @@ iperf_set_test_bind_address(struct iperf_test *ipt, char *bind_address)
|
||||
ipt->bind_address = strdup(bind_address);
|
||||
}
|
||||
|
||||
void
|
||||
iperf_set_test_udp_counters_64bit(struct iperf_test *ipt, int udp_counters_64bit)
|
||||
{
|
||||
ipt->udp_counters_64bit = udp_counters_64bit;
|
||||
}
|
||||
|
||||
/********************** Get/set test protocol structure ***********************/
|
||||
|
||||
struct protocol *
|
||||
@ -597,6 +609,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
|
||||
{"pidfile", required_argument, NULL, 'I'},
|
||||
{"logfile", required_argument, NULL, OPT_LOGFILE},
|
||||
{"get-server-output", no_argument, NULL, OPT_GET_SERVER_OUTPUT},
|
||||
{"udp-counters-64bit", no_argument, NULL, OPT_UDP_COUNTERS_64BIT},
|
||||
{"debug", no_argument, NULL, 'd'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{NULL, 0, NULL, 0}
|
||||
@ -834,6 +847,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
|
||||
test->get_server_output = 1;
|
||||
client_flag = 1;
|
||||
break;
|
||||
case OPT_UDP_COUNTERS_64BIT:
|
||||
test->udp_counters_64bit = 1;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
usage_long();
|
||||
@ -1197,6 +1213,10 @@ send_parameters(struct iperf_test *test)
|
||||
cJSON_AddStringToObject(j, "congestion", test->congestion);
|
||||
if (test->get_server_output)
|
||||
cJSON_AddIntToObject(j, "get_server_output", iperf_get_test_get_server_output(test));
|
||||
if (test->udp_counters_64bit)
|
||||
cJSON_AddIntToObject(j, "udp_counters_64bit", iperf_get_test_udp_counters_64bit(test));
|
||||
|
||||
cJSON_AddStringToObject(j, "client_version", IPERF_VERSION);
|
||||
|
||||
if (test->debug) {
|
||||
printf("send_parameters:\n%s\n", cJSON_Print(j));
|
||||
@ -1271,6 +1291,8 @@ get_parameters(struct iperf_test *test)
|
||||
test->congestion = strdup(j_p->valuestring);
|
||||
if ((j_p = cJSON_GetObjectItem(j, "get_server_output")) != NULL)
|
||||
iperf_set_test_get_server_output(test, 1);
|
||||
if ((j_p = cJSON_GetObjectItem(j, "udp_counters_64bit")) != NULL)
|
||||
iperf_set_test_udp_counters_64bit(test, 1);
|
||||
if (test->sender && test->protocol->id == Ptcp && has_tcpinfo_retransmits())
|
||||
test->sender_has_retransmits = 1;
|
||||
cJSON_Delete(j);
|
||||
@ -1883,6 +1905,7 @@ iperf_reset_test(struct iperf_test *test)
|
||||
test->settings->mss = 0;
|
||||
memset(test->cookie, 0, COOKIE_SIZE);
|
||||
test->multisend = 10; /* arbitrary */
|
||||
test->udp_counters_64bit = 0;
|
||||
|
||||
/* Free output line buffers, if any (on the server only) */
|
||||
struct iperf_textline *t;
|
||||
|
@ -29,6 +29,7 @@ struct iperf_stream;
|
||||
#define OPT_SCTP 1
|
||||
#define OPT_LOGFILE 2
|
||||
#define OPT_GET_SERVER_OUTPUT 3
|
||||
#define OPT_UDP_COUNTERS_64BIT 4
|
||||
|
||||
/* states */
|
||||
#define TEST_START 1
|
||||
@ -73,6 +74,7 @@ char* iperf_get_test_json_output_string ( struct iperf_test* ipt );
|
||||
int iperf_get_test_zerocopy( struct iperf_test* ipt );
|
||||
int iperf_get_test_get_server_output( struct iperf_test* ipt );
|
||||
char* iperf_get_test_bind_address ( struct iperf_test* ipt );
|
||||
int iperf_get_test_udp_counters_64bit( struct iperf_test* ipt );
|
||||
|
||||
/* Setter routines for some fields inside iperf_test. */
|
||||
void iperf_set_verbose( struct iperf_test* ipt, int verbose );
|
||||
@ -96,6 +98,7 @@ int iperf_has_zerocopy( void );
|
||||
void iperf_set_test_zerocopy( struct iperf_test* ipt, int zerocopy );
|
||||
void iperf_set_test_get_server_output( struct iperf_test* ipt, int get_server_output );
|
||||
void iperf_set_test_bind_address( struct iperf_test* ipt, char *bind_address );
|
||||
void iperf_set_test_udp_counters_64bit( struct iperf_test* ipt, int udp_counters_64bit );
|
||||
|
||||
/**
|
||||
* exchange_parameters - handles the param_Exchange part for client
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, The Regents of the University of California,
|
||||
* Copyright (c) 2009-2011, 2014, The Regents of the University of California,
|
||||
* through Lawrence Berkeley National Laboratory (subject to receipt of any
|
||||
* required approvals from the U.S. Dept. of Energy). All rights reserved.
|
||||
*
|
||||
@ -28,7 +28,7 @@
|
||||
#include "iperf_udp.h"
|
||||
#include "timer.h"
|
||||
#include "net.h"
|
||||
|
||||
#include "portable_endian.h"
|
||||
|
||||
/* iperf_udp_recv
|
||||
*
|
||||
@ -37,9 +37,10 @@
|
||||
int
|
||||
iperf_udp_recv(struct iperf_stream *sp)
|
||||
{
|
||||
uint32_t sec, usec;
|
||||
uint64_t pcount;
|
||||
int r;
|
||||
int size = sp->settings->blksize;
|
||||
uint32_t sec, usec, pcount;
|
||||
double transit = 0, d = 0;
|
||||
struct timeval sent_time, arrival_time;
|
||||
|
||||
@ -51,14 +52,27 @@ iperf_udp_recv(struct iperf_stream *sp)
|
||||
sp->result->bytes_received += r;
|
||||
sp->result->bytes_received_this_interval += r;
|
||||
|
||||
memcpy(&sec, sp->buffer, sizeof(sec));
|
||||
memcpy(&usec, sp->buffer+4, sizeof(usec));
|
||||
memcpy(&pcount, sp->buffer+8, sizeof(pcount));
|
||||
sec = ntohl(sec);
|
||||
usec = ntohl(usec);
|
||||
pcount = ntohl(pcount);
|
||||
sent_time.tv_sec = sec;
|
||||
sent_time.tv_usec = usec;
|
||||
if (sp->test->udp_counters_64bit) {
|
||||
memcpy(&sec, sp->buffer, sizeof(sec));
|
||||
memcpy(&usec, sp->buffer+4, sizeof(usec));
|
||||
memcpy(&pcount, sp->buffer+8, sizeof(pcount));
|
||||
sec = ntohl(sec);
|
||||
usec = ntohl(usec);
|
||||
pcount = be64toh(pcount);
|
||||
sent_time.tv_sec = sec;
|
||||
sent_time.tv_usec = usec;
|
||||
}
|
||||
else {
|
||||
uint32_t pc;
|
||||
memcpy(&sec, sp->buffer, sizeof(sec));
|
||||
memcpy(&usec, sp->buffer+4, sizeof(usec));
|
||||
memcpy(&pc, sp->buffer+8, sizeof(pc));
|
||||
sec = ntohl(sec);
|
||||
usec = ntohl(usec);
|
||||
pcount = ntohl(pc);
|
||||
sent_time.tv_sec = sec;
|
||||
sent_time.tv_usec = usec;
|
||||
}
|
||||
|
||||
/* Out of order packets */
|
||||
if (pcount >= sp->packet_count + 1) {
|
||||
@ -68,7 +82,7 @@ iperf_udp_recv(struct iperf_stream *sp)
|
||||
sp->packet_count = pcount;
|
||||
} else {
|
||||
sp->outoforder_packets++;
|
||||
iperf_err(sp->test, "OUT OF ORDER - incoming packet = %d and received packet = %d AND SP = %d", pcount, sp->packet_count, sp->socket);
|
||||
iperf_err(sp->test, "OUT OF ORDER - incoming packet = %llu and received packet = %d AND SP = %d", pcount, sp->packet_count, sp->socket);
|
||||
}
|
||||
|
||||
/* jitter measurement */
|
||||
@ -83,6 +97,10 @@ iperf_udp_recv(struct iperf_stream *sp)
|
||||
// J = |(R1 - S1) - (R0 - S0)| [/ number of packets, for average]
|
||||
sp->jitter += (d - sp->jitter) / 16.0;
|
||||
|
||||
if (sp->test->debug) {
|
||||
fprintf(stderr, "packet_count %llu\n", sp->packet_count);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -95,20 +113,40 @@ int
|
||||
iperf_udp_send(struct iperf_stream *sp)
|
||||
{
|
||||
int r;
|
||||
uint32_t sec, usec, pcount;
|
||||
int size = sp->settings->blksize;
|
||||
struct timeval before;
|
||||
|
||||
gettimeofday(&before, 0);
|
||||
|
||||
++sp->packet_count;
|
||||
sec = htonl(before.tv_sec);
|
||||
usec = htonl(before.tv_usec);
|
||||
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));
|
||||
if (sp->test->udp_counters_64bit) {
|
||||
|
||||
uint32_t sec, usec;
|
||||
uint64_t pcount;
|
||||
|
||||
sec = htonl(before.tv_sec);
|
||||
usec = htonl(before.tv_usec);
|
||||
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));
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
uint32_t sec, usec, pcount;
|
||||
|
||||
sec = htonl(before.tv_sec);
|
||||
usec = htonl(before.tv_usec);
|
||||
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));
|
||||
|
||||
}
|
||||
|
||||
r = Nwrite(sp->socket, sp->buffer, size, Pudp);
|
||||
|
||||
|
@ -126,6 +126,7 @@ const char usage_longstr[] = "Usage: iperf [-s|-c host] [options]\n"
|
||||
" -O, --omit N omit the first n seconds\n"
|
||||
" -T, --title str prefix every output line with this string\n"
|
||||
" --get-server-output get results from server\n"
|
||||
" --udp-counters-64bit use 64-bit counters in UDP test packets\n"
|
||||
|
||||
#ifdef NOT_YET_SUPPORTED /* still working on these */
|
||||
#endif
|
||||
|
115
src/portable_endian.h
Обычный файл
115
src/portable_endian.h
Обычный файл
@ -0,0 +1,115 @@
|
||||
// "License": Public Domain
|
||||
// I, Mathias Panzenböck, place this file hereby into the public domain. Use it at your own risk for whatever you like.
|
||||
|
||||
#ifndef PORTABLE_ENDIAN_H__
|
||||
#define PORTABLE_ENDIAN_H__
|
||||
|
||||
#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__)
|
||||
|
||||
# define __WINDOWS__
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__CYGWIN__)
|
||||
|
||||
# include <endian.h>
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
# include <libkern/OSByteOrder.h>
|
||||
|
||||
# define htobe16(x) OSSwapHostToBigInt16(x)
|
||||
# define htole16(x) OSSwapHostToLittleInt16(x)
|
||||
# define be16toh(x) OSSwapBigToHostInt16(x)
|
||||
# define le16toh(x) OSSwapLittleToHostInt16(x)
|
||||
|
||||
# define htobe32(x) OSSwapHostToBigInt32(x)
|
||||
# define htole32(x) OSSwapHostToLittleInt32(x)
|
||||
# define be32toh(x) OSSwapBigToHostInt32(x)
|
||||
# define le32toh(x) OSSwapLittleToHostInt32(x)
|
||||
|
||||
# define htobe64(x) OSSwapHostToBigInt64(x)
|
||||
# define htole64(x) OSSwapHostToLittleInt64(x)
|
||||
# define be64toh(x) OSSwapBigToHostInt64(x)
|
||||
# define le64toh(x) OSSwapLittleToHostInt64(x)
|
||||
|
||||
# define __BYTE_ORDER BYTE_ORDER
|
||||
# define __BIG_ENDIAN BIG_ENDIAN
|
||||
# define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
# define __PDP_ENDIAN PDP_ENDIAN
|
||||
|
||||
#elif defined(__OpenBSD__)
|
||||
|
||||
# include <sys/endian.h>
|
||||
|
||||
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
|
||||
# include <sys/endian.h>
|
||||
|
||||
# define be16toh(x) betoh16(x)
|
||||
# define le16toh(x) letoh16(x)
|
||||
|
||||
# define be32toh(x) betoh32(x)
|
||||
# define le32toh(x) letoh32(x)
|
||||
|
||||
# define be64toh(x) betoh64(x)
|
||||
# define le64toh(x) letoh64(x)
|
||||
|
||||
#elif defined(__WINDOWS__)
|
||||
|
||||
# include <winsock2.h>
|
||||
# include <sys/param.h>
|
||||
|
||||
# if BYTE_ORDER == LITTLE_ENDIAN
|
||||
|
||||
# define htobe16(x) htons(x)
|
||||
# define htole16(x) (x)
|
||||
# define be16toh(x) ntohs(x)
|
||||
# define le16toh(x) (x)
|
||||
|
||||
# define htobe32(x) htonl(x)
|
||||
# define htole32(x) (x)
|
||||
# define be32toh(x) ntohl(x)
|
||||
# define le32toh(x) (x)
|
||||
|
||||
# define htobe64(x) htonll(x)
|
||||
# define htole64(x) (x)
|
||||
# define be64toh(x) ntohll(x)
|
||||
# define le64toh(x) (x)
|
||||
|
||||
# elif BYTE_ORDER == BIG_ENDIAN
|
||||
|
||||
/* that would be xbox 360 */
|
||||
# define htobe16(x) (x)
|
||||
# define htole16(x) __builtin_bswap16(x)
|
||||
# define be16toh(x) (x)
|
||||
# define le16toh(x) __builtin_bswap16(x)
|
||||
|
||||
# define htobe32(x) (x)
|
||||
# define htole32(x) __builtin_bswap32(x)
|
||||
# define be32toh(x) (x)
|
||||
# define le32toh(x) __builtin_bswap32(x)
|
||||
|
||||
# define htobe64(x) (x)
|
||||
# define htole64(x) __builtin_bswap64(x)
|
||||
# define be64toh(x) (x)
|
||||
# define le64toh(x) __builtin_bswap64(x)
|
||||
|
||||
# else
|
||||
|
||||
# error byte order not supported
|
||||
|
||||
# endif
|
||||
|
||||
# define __BYTE_ORDER BYTE_ORDER
|
||||
# define __BIG_ENDIAN BIG_ENDIAN
|
||||
# define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
# define __PDP_ENDIAN PDP_ENDIAN
|
||||
|
||||
#else
|
||||
|
||||
# error platform not supported
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
Загрузка…
x
Ссылка в новой задаче
Block a user