Compare commits

...

87 Commits

Author SHA1 Message Date
Bruce A. Mah
a7a4ec7f9c
Fix a heap corruption issue leading to a server-side crash. (#564)
Commit 5ab2132c (PR #551) fixed, among other things, a memory
leak.  The solution, however, causes a hazard where a free() of
an invalid pointer can corrupt the heap.  We've observed this
fairly repeatably while running the test_commands.sh script on
CentOS 7.

To remedy this, we NULL out a pointer after the object it
pointed to has been free-d, just like a number of other similar
objects.

(cherry picked from commit 103d4318e85783b99d6984c091ea878fc0d844b2)
2017-05-04 14:33:53 -07:00
Bruce A. Mah
30d8c2828a Fix possible integer overflow in tera prefix conversions.
Follow-on commit for #402, possible fix for #561.

(cherry picked from commit c8531ca31fab4be1a02d4d3bf86fa555048e9805)
2017-05-02 11:56:04 -07:00
Bruce A. Mah
6d95a4daab
Fix bug introduced in 03224c9 where we fail on default UDP blocksize.
Fixes #559, follow up to #390..

(cherry picked from commit 65ed04deb540809ec204e22f9c18675be6247e79)
2017-05-01 09:19:34 -07:00
Bruce A. Mah
c7801f85ff
Fix a problem when getting snd_cwnd on FreeBSD.
On FreeBSD, unlike Linux (and NetBSD?) snd_cwnd is expressed in
octets instead of segments.  Hilarity ensued when we erroneously
multiplied by snd_mss and integer overflows occureed.

Possible fix for #465, #475, #338.  Testing from FreeBSD users
appreciated.

(cherry picked from commit b9478db94730c7bf1f4aa02091fbc425b9149a86)
2017-04-25 10:52:11 -07:00
Bruce A. Mah
d0ab9a43cf
Merge branch 'dmdailey-master'.
This merges pull request #446.

(cherry picked from commit 92a2498edc14262f726279c15357f9fce0173d27)
2017-04-20 17:54:16 -07:00
Gabriel Ganne
f0e0c5b211
warning fixes (#551)
* fix Wstrict-prototypes warnings found by clang

also fix usage_long() call

Signed-off-by: Gabriel Ganne <gabriel.ganne@enea.com>

* fix Wunreachable-code-break warnings found by clang

Signed-off-by: Gabriel Ganne <gabriel.ganne@enea.com>

* fix Wshadow warnings found by clang

Signed-off-by: Gabriel Ganne <gabriel.ganne@enea.com>

* fix Wmissing-noreturn warning found by clang

Signed-off-by: Gabriel Ganne <gabriel.ganne@enea.com>

* ix memory leak found by clang

Signed-off-by: Gabriel Ganne <gabriel.ganne@enea.com>

* fix Wmisleading-indentation warnings raised by gcc-6

Signed-off-by: Gabriel Ganne <gabriel.ganne@enea.com>

* fix warning: Value stored to 'ptr' during its initialization is never read found by clang

Signed-off-by: Gabriel Ganne <gabriel.ganne@enea.com>

* fix warning: The left operand of '>' is a garbage value found by clang

Signed-off-by: Gabriel Ganne <gabriel.ganne@enea.com>

* fix memory leak in global cleanup

Signed-off-by: Gabriel Ganne <gabriel.ganne@enea.com>

(cherry picked from commit 5ab2132ce390da77ac35a6aadfc740db6ebe2b0d)
2017-04-20 17:53:43 -07:00
Bruce A. Mah
3b492fee4b
Minor follow-ups to #508.
Change the internal command-line option code for --dscp from the literal
'5' to a constant defined as OPT_DSCP.

Add manpage text for --dscp option.

Tweak help text for --dscp (while here, fix problem in --tos text).

(cherry picked from commit 05600c201ac47d02c33e8ccfb2f17f1bcc977c4b)
2017-04-14 14:31:32 -07:00
Bruce A. Mah
b1d6d30c86
Regen, follow-up to #508. 2017-04-14 14:31:15 -07:00
Dave Täht
4d28dc570f
add support for specifying --dscp symbolically and numerically (#508)
Using a command line adding dscp (instead of tos) you can:

--dscp EF,CS1,etc.
--dscp 0x08
--dscp 63

These will provide the correct shifted left 2 tos value for these, and
for people that think in terms of dscp values, this is a goodness.

Having this option available lets an enduser clearly distinguish between
an old version of iperf with a non-working --tos facility, vs a
version where it works, with something saner that lets just specify
the dscp.

I did not come up with a good -? option for it, and used -5 internally.
(cherry picked from commit 97c95c3be2542894db7d58578b2734d00ec6d63f)
2017-04-14 14:30:47 -07:00
Bruce A. Mah
7a1953a5ec
Add support for tera- prefix [Tt] in input and output.
Also add some more unit tests for this and prune unused code
from unit test program.

Fixes #402.

(cherry picked from commit e9e2d6d19c713f9a849609eb32a6cc06d7cc211a)
2017-04-14 13:17:57 -07:00
Bruce A. Mah
b69347cad8
Make explicitly requested usage output (--help) go to stdout.
Also in this case make the process exit code 0.

Fixes #405.

(cherry picked from commit d51501ef8345e056b45c7ee4ef5a5bd8ba7d22b7)
2017-04-14 12:49:24 -07:00
Bruce A. Mah
3a536dc68e
Be more explicit about the direction of data during tests.
Documentation change only, no functional change.
Fixes #384.

(cherry picked from commit b07ed14dae4ce117c5cc7d455258283db4917f76)
2017-04-14 12:39:12 -07:00
Bruce A. Mah
c73f0ab736 Ignore SIGPIPE signals to simplify error handling.
This is an attempt to avoid server-side crashes/exits when the
client abruptly closes its control connection, as found in some
testing for #549.

Fixes #550.

(cherry picked from commit 6f414a040842b240db4a40a33059e8dab8e0d175)
2017-04-11 16:00:02 -07:00
Bruce A. Mah
68ac5fcf11 More gracefully handle the case where a congestion control
algorithm isn't available on the server.  This can happen
if the client and server machines have different sets of
congestion control algorithms loaded in kernel modules, etc.
If the requested algorithm isn't available on the server, then
print a warning on the server side, but otherwise continue to
run the test.

Towards #549.

(cherry picked from commit 08758a16d226f47e772891d27e8cb19c3eed6c87)
2017-04-11 15:59:39 -07:00
Bruce A. Mah
32c0a802a3 Prevent specifying a UDP send size that's too small.
We need at least 16 bytes to hold counters and timestamps.
Avoids a problem noted in issue #390.

(cherry picked from commit 03224c9f56cd59f7375db10c59cb09233f36f392)
2017-04-11 09:54:59 -07:00
Tran Viet Hoang
5b6553910b add tcp rttvar to stream info (#534)
Fixes #525.
(cherry picked from commit 5d14d10697d146055dc59b0e0cc3dd58510bd504)
2017-03-30 16:35:13 -07:00
Bruce A. Mah
5bf55ed9d2 Fix divide-by-zero / weird output with -F and a zero-length file.
Fixes #361.

(cherry picked from commit 8066a1d2226f9675c2ce7d7fec18b3d53dc197a2)
2017-03-30 16:34:12 -07:00
f1rebird
17e6dbf3d6
Fix header includes and build failures on musl (#518)
* Include stdint.h in files where its types are used

Signed-off-by: Moritz Kick <f1rebird@users.noreply.github.com>

* Fix type of len parameter passed to getsockopt

getsockopt expects socklen_t instead of int as its fifth argument

Signed-off-by: Moritz Kick <f1rebird@users.noreply.github.com>

* Remove unnecassary includes of netinet/tcp.h

also cleanup the second include of stdint.h in main.c

This commit fixes #331 and is a replacement for #344.

Signed-off-by: Moritz Kick <f1rebird@users.noreply.github.com>

(cherry picked from commit a8ee9c650b3efe4453a69ceebe4d71c3cb4bcadf)
2017-03-30 10:01:34 -07:00
ShaunCurrier
097994fb37
Remove unused hstrerror(), bad nanosleep() message in configure.ac (#503) (#523)
* Remove unused hstrerror(), bad nanosleep() message in configure.ac (#503)

* Remove dead code involving h_errno and hstrerror()

h_errno was formerly set as a side effect of a failed
gethostbyname(3) call, but this function has been
deprecated.

(cherry picked from commit 9f28b247ba689d15d09c9c09eb5b18b7cebfc0e0)
2017-03-20 17:37:45 -07:00
Bruce A. Mah
1a128e5b3d
Change "iperf" to "iperf3" in usage strings. Fixes #529.
(cherry picked from commit b3828fed23c419da395eeb468acecd7eddd4c221)
2017-03-20 17:34:58 -07:00
Bruce A. Mah
454ca162cd
Add missing word. Fixes #527.
(cherry picked from commit 59a11c6236c533aa4ca11b13aa12c225f3fa8e91)
2017-03-14 14:59:51 -07:00
Bruce A. Mah
761ea92c30
Fix a bug where specifying --title leaked into server JSON in future runs.
Fixes #500, based on pull request in #501 submitted by @slankes.

(cherry picked from commit 7c79294b5b2b3499fdf1dcd42969971909a740e3)
2017-03-09 19:37:40 -08:00
Bruce A. Mah
58180eafe2
Regen. 2017-03-03 16:20:07 -08:00
Bruce A. Mah
decc63269a
Prepare for iperf-3.1.7. 2017-03-03 16:19:40 -08:00
Bruce A. Mah
4a08c88794
Replace "known issues" section with a pointer to Web content.
This will make it easier to update the known issues independently
from a software release.

(cherry picked from commit 0dafb3b2aa54b8f7b8e09eee1b00ef6823009c67)
2017-02-24 15:58:02 -08:00
Bruce A. Mah
0869aed3fc
Revise package description in RPM spec file.
(The original had a few typos and errors in it, and I just lifted
the first paragraph of README.md and tweaked it a bit.)
2017-02-16 15:08:17 -08:00
Bruce A. Mah
6e51a5ce7d
Regen. 2017-02-02 10:54:30 -08:00
Bruce A. Mah
2126a64cf7
Update release notes and version number bump for iperf-3.1.6. 2017-02-02 10:53:28 -08:00
Bruce A. Mah
8e77cf0612 Prevent two recently added messages from spamming JSON output on UDP tests.
Stumbled on by:	@daldoyle

(cherry picked from commit f46e2e3edc3cefd3c451bac6d621092f0d71c087)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2017-02-02 09:29:33 -08:00
Bruce A. Mah
1bf39b8e50 Revert "Try to disambiguate / localize the three occurrences of IESTREAMREAD."
This reverts commit 2827766e0233e2913393eb5ebe78e398d8d10213.
2017-01-31 12:27:25 -08:00
Bruce A. Mah
2827766e02 Try to disambiguate / localize the three occurrences of IESTREAMREAD.
For debugging a possible pScheduler issue.
2017-01-31 12:19:52 -08:00
Bruce A. Mah
74f1595322 Revert "Fail gracefully if --fq-rate or --no-fq-socket-pacing are specified on"
This reverts commit 9d9b77dbbd410d66be23d0b7cfff33a983cf5f12.

Fixes #504.
2017-01-25 13:57:00 -08:00
Bruce A. Mah
a46d5aec97
Regen. 2017-01-12 08:42:27 -08:00
Bruce A. Mah
ec1bd83b78
Version number and manpage date bump for iperf 3.1.5. 2017-01-12 08:41:25 -08:00
Bruce A. Mah
76fbb2c8ee
Minor edits to release notes for the upcoming iperf 3.1.5. 2017-01-12 08:01:39 -08:00
Bruce A. Mah
6c8b53f577 Add 1KB to default UDP socket buffer sizes under certain circumstances.
This fixes a problem observed on FreeBSD and macOS where the MTU on
the loopback interface is larger than the default socket buffer size.
We adjusted the socket buffer size upwards to match the UDP payload
size, but that's apparently not enough and we ended up dropping packets.
This is bad.  Add a 1KB fudge factor, which seesm to avoid this problem.
Affects UDP tests only, not TCP or SCTP.

Part of #496.

(cherry picked from commit d76198944d210e8a575747d3ddbee41a886a10c9)
Signed-off-by: Bruce A. Mah <bmah@es.net>
(cherry picked from commit 1ff12f4c3e9969b9652dd1963a97e08f7dcf0e61)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2017-01-11 11:53:35 -08:00
Bruce A. Mah
bab17044fa
Draft release notes for the upcoming iperf 3.1.5 release. 2017-01-10 15:26:56 -08:00
Bruce A. Mah
183bfc4156 Happy 2017.
(cherry picked from commit 69ba4e58318b75181821ef53abb84bc6304f44ff)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2017-01-06 22:45:00 -08:00
Bruce A. Mah
e1002192fe
Issue 496 (#498)
* Dynamically determine an appropriate default UDP send size.

We use the TCP MSS for the control connection as the default UDP
sending length, if the --length parameter is not specified for a
UDP test.  This computation replaces the former hard-coded 8K
default, which was way too large for non-jumbo-frame Ethernet
networks.

The concept for this solution was adapted from nuttcp.  The
iperf3 implementation is pretty easy since we already were
getting the MSS for the control connection anyway (although we
needed to get it slightly earlier in the setup process to be
useful).

Towards issue #496.

While here, s/int/socklen_t/ in one place to fix a compile warning,
and bump a few copyright dates.

* Warn if doing a UDP test and the socket buffer isn't big enough.

This is surprisingly an issue on FreeBSD and macOS, where the MTU
over the loopback interface is actually larger than the default
UDP socket buffer size.  In these cases, doing a UDP test over the
loopback interface (with the new UDP defaults) will fail unless a
smaller --length or a larger --window size is set explicitly.

Linux has larger UDP socket buffers by default (much larger than the
largest possible MTU), but even in the case that the socket buffers
are too small to hold an MTU-sized send, the kernel seems to do the
send correctly anyway.

Still working towards a good solution for issue #496.

* Further refinement on UDP buffer size settings.

If the default buffer size on a UDP test can't hold a packet,
then increase the buffer size to be large enough to hold one
packet payload.  (If the buffer size was explicitly set, but too
small to hold a packet payload, then warn but don't change the
buffer size.)

Minor code refactoring to...factor out some common code into
a new iperf_udp_buffercheck() function.

Still working towards issue #496.

(cherry picked from commit 0fd60a36862d0cd9c50ec522aa376b3223f835a2)
Signed-off-by: Bruce A. Mah <bmah@es.net>

Conflicts:
	src/iperf_api.c
2017-01-06 22:41:52 -08:00
Bruce A. Mah
d873190e73 Fix socket buffer size checks. Clearly this wasn't tested well.
On Linux it's possible to set the socket buffer to one size but
(correctly it seems) get back some larger size up to 2x what you
asked for (see tcp(7)).

While here, make related debugging output more useful.

Fixes (again) #356.

(cherry picked from commit 55598a072f681fbaeaa25a7cc884640bac8a3813)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2017-01-06 22:28:36 -08:00
Bruce A. Mah
66f89829e4 After setting socket buffer sizes, verify they were set correctly.
Do this for both TCP and UDP, but not SCTP (which strangely doesn't
support --window, that's probably a bug).  Fixes #356.

(cherry picked from commit d2202ee3be6007324eb98f60d6fcd3eb8b51c838)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2017-01-06 22:28:05 -08:00
Bruce A. Mah
9d9b77dbbd Fail gracefully if --fq-rate or --no-fq-socket-pacing are specified on
platforms where they aren't supported.

Requested by:	@bltierney

(cherry picked from commit 9c83a707eb0454994a7d42356981ff3ccd93c7a9)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2017-01-06 22:25:13 -08:00
Bruce A. Mah
27f6691270
Separate out application-level and fair-queueing-based pacing (#488)
* First try to fix pacing issues.  Code compiles, lightly run-tested.

Make --bandwidth only control application-level pacing, refecting
behavior of iperf 3.1.2 and earlier.

Add a new --fq-rate that controls only FQ-based per-socket pacing.
A given test can use application-level pacing, FQ pacing, both,
or neither.

Deprecate the --no-fq-socket-pacing option; specifying this generates
a warning and is equivalent to --fq-rate=0.

Towards issue #467 and related to issue #325.

* Move --fq-rate in the help text to be just below --b, tweak wording.

* Sigh.  One more tweak on help text.

Some day I probably need to review and rewrite the whole thing.

Still working towards #467.

(cherry picked from commit a094d9feeff01354ccb1d7f2df7c225837a81fea)
Signed-off-by: Bruce A. Mah <bmah@es.net>

Conflicts:
	src/iperf_tcp.c
	src/iperf_udp.c
2016-12-12 14:53:56 -08:00
Bruce A. Mah
3f11925f24 Improvements to systemd service file as per #430.
Submitted by @rpodgorny.

(cherry picked from commit c4a56a3c49cf6fe5a6621eb0c148613ab5dcbed1)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2016-11-21 14:19:55 -08:00
Sascha Spreitzer
3243d0584d Add systemd service file (#340)
To be modified by some code changes in #430.

(cherry picked from commit b56d154cda622f731f3ef16048ca532b25ffc996)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2016-11-21 14:19:37 -08:00
Bruce A. Mah
69e675101e Fix executable name and date in the manpage heading.
(cherry picked from commit 6aff679e96202b726334f926bf8fcdcb134bd538)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2016-11-10 13:51:10 -08:00
Bruce A. Mah
72ab7033ca
Merge pull request #377 from quasoft/forceflush
Add option `--forceflush` to force flushing of output at the end of each interval
(cherry picked from commit 4fbdab392caf6fcd77c538b6712b721a56ff31b8)

Signed-off-by: Bruce A. Mah <bmah@es.net>

Conflicts:
	src/iperf.h
	src/iperf_api.h
2016-11-10 10:01:26 -08:00
Bruce A. Mah
7b96c08f82
Regen. 2016-10-31 12:39:34 -07:00
Bruce A. Mah
a393f41d60
Frob release notes, bump version number in configure. 2016-10-31 12:36:34 -07:00
Bruce A. Mah
6bd93f6b01
Start working on release notes for iperf-3.1.4. 2016-10-14 11:44:26 -07:00
Bruce A. Mah
3ad5127014 Fix a buffer overflow in upstream cJSON.
This is DaveGamble/cJSON#30, and fixes issue #466.

Signed-off-by: Bruce A. Mah <bmah@es.net>
2016-10-05 14:52:44 -07:00
woody77
ad60eeeb28
Properly setting the no_fq_socket_pacing option when support for it is not compiled in. (#459) 2016-09-27 15:56:29 -07:00
Bruce A. Mah
6694f65fe8
Prevent a double-close on the server side in some cases.
Alternate solution to a problem pointed out by @g-coder in pull request #429.
2016-09-27 15:52:13 -07:00
Bruce A. Mah
4a9d74f9e9
Fix divide-by-zero problem that can occur with a zero-length interval
(this can happen at the end of a test under certain circumstances).
Fixes #388, alternate solution from pull request in #389.
2016-09-27 15:40:47 -07:00
Bruce A. Mah
873dcaf082
Fix whitespace errors in .travis.yml. 2016-09-27 15:21:43 -07:00
g-coder
c2c31a8013
Created .travis.yml for build automation (#424)
This enhancement will automatic check and test the changes done. It will improve the testing capability of component as build can be tested at every pull request before commit.

To enable this feature , you will have to login in https://travis-ci.org/. using github account 
and enable the travis feature for the iperf library.

Many other github projects use this feature. Hope it will help iperf too.
2016-09-27 15:21:43 -07:00
Bruce A. Mah
0429a987ac
Only print congestion control algorithm for a TCP test.
Properly (I think) label the two TCP instsances as "sender"
and "receiver".
2016-09-27 15:17:32 -07:00
Bruce A. Mah
49b8af11f2
Fix build on FreeBSD. 2016-09-27 15:17:32 -07:00
Bruce A. Mah
5291825b3f
First try at issue #461.
First, realize that we've been setting the congestion control (CC)
algorithm unnecessarily; rather than doing it for all listening or
connecting sockets, do it just for those sockets that are being used
for TCP test streams.

Record the CC algorithm in use (this handles the case where a CC algorithm
hasn't been specified), and have the client and server exchange this
information.

Report the CC algorithms that were used (note that it's theoretically
possible for the two ends of the test to be using different algorithms,
if no algorithm was explicitly specified and the two end hosts have
different defaults, or if one side allows setting the CC algorithm and
the other doesn't).

Committing to a branch to make it easier to test this code on a
wider combination of systems.
2016-09-27 15:17:25 -07:00
Bruce A. Mah
274eaed5b1
Regen. 2016-06-06 11:18:49 -07:00
Bruce A. Mah
4d57f63dff
Version number bump for iperf-3.1.3 release. 2016-06-06 11:18:15 -07:00
Bruce A. Mah
09cf7bd9dc
Edit / update release notes. 2016-06-06 07:33:26 -07:00
Bruce A. Mah
093a8fc719
Initial draft of 3.1.3 release notes. 2016-06-03 10:11:59 -07:00
Bruce A. Mah
5a73bf9dc5
Regen. 2016-06-03 09:34:35 -07:00
Bruce A. Mah
d3be2dfb7c
Make the server more tolerant of most types of errors encountered
during tests.

We used to exit if 5 consecutive errors were encountered.  Instead,
only exit if certain types of fatal errors happen.

(cherry picked from commit b7ab2b4b25ab47b937afb631380ef207cb68854c)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2016-06-03 09:34:11 -07:00
Bruce A. Mah
35c38b3c38
Make error handling on the control channel more robust.
(cherry picked from commit 4dcb275b5b4ab2edbcccba1affaf9a3a089a1a96)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2016-06-03 09:33:16 -07:00
Bruce A. Mah
f01a9ca8f7
Fix a buffer overflow / heap corruption issue that could occur if a
malformed JSON string was passed on the control channel.  This issue,
present in the cJSON library, was already fixed upstream, so was
addressed here in iperf3 by importing a newer version of cJSON (plus
local ESnet modifications).

Discovered and reported by Dave McDaniel, Cisco Talos.

Based on a patch by @dopheide-esnet, with input from @DaveGamble.

Cross-references:  TALOS-CAN-0164, ESNET-SECADV-2016-0001,
CVE-2016-4303

(cherry picked from commit ed94082be27d971a5e1b08b666e2c217cf470a40)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2016-06-03 09:32:30 -07:00
Bruce A. Mah
908409a608
Regen. 2016-05-26 17:40:28 -07:00
Bruce A. Mah
7bb4cf12c9 Squashed commit of the following:
commit 2dc03630a736be2ae9f64823aabb5776e7074c2a
Merge: 61e325c 0da552c
Author: Bruce A. Mah <bmah@es.net>
Date:   Thu May 26 09:40:58 2016 -0700

    Merge branch 'master' into issue-325

commit 61e325c5d0a4e7a9823221ce507db0f478fc98b5
Merge: 227992f ccbcee6
Author: Bruce A. Mah <bmah@es.net>
Date:   Thu May 26 11:09:54 2016 -0400

    Merge branch 'issue-325' of github.com:esnet/iperf into issue-325

    Conflicts:
    	src/iperf3.1

commit 227992f366e7f4895b6762011576ba22a42a752e
Author: Bruce A. Mah <bmah@es.net>
Date:   Thu May 26 11:07:01 2016 -0400

    Don't set SO_MAX_PACING_RATE if the rate is 0.  Also tweak some help text.

    Towards #325, in response to feedback from @bltierney.

commit ccbcee6366d50ec632fc00eb11fde8a886f8febe
Author: Bruce A. Mah <bmah@es.net>
Date:   Tue May 24 09:19:41 2016 -0700

    Fix manpage formatting for consistency.

commit 90ac5a9ce09bd746ca5f943a8226ab864da3ebf8
Author: Bruce A. Mah <bmah@es.net>
Date:   Tue May 24 12:14:16 2016 -0400

    Add some documentation for fair-queueing per-socket pacing.

    For #325.

commit 5571059870f7aefefb574816de70b6406848888f
Author: Bruce A. Mah <bmah@es.net>
Date:   Tue May 24 11:55:44 2016 -0400

    Change the fair-queueing socket pacing logic in response to feedback.

    By default, on platforms where per-socket pacing is available, it
    will be used.  If not available, iperf3 will fall back to application-
    level pacing.

    The --no-fq-socket-pacing option can be used to forcibly disable
    fair-queueing per-socket pacing.  (The earlier --socket-pacing option
    has been removed.)

    Tested on CentOS 7, more testing on other platforms is required to
    be sure it didn't break the old application-level pacing behavior.

    For #325.

commit 3e3f506fe9f375a5771c9e3ddfe8677c1a7146e7
Merge: 50a379e 3b23112
Author: Bruce A. Mah <bmah@es.net>
Date:   Tue May 24 09:54:39 2016 -0400

    Merge branch 'master' into issue-325

commit 50a379eddfa89d1313d2aeeb62a6fbc82f00ea17
Author: Bruce A. Mah <bmah@es.net>
Date:   Sat Apr 16 02:55:42 2016 -0400

    Regen.

commit 200d3fe3917b3d298bdf52a0bde32c47cf2727b0
Author: Bruce A. Mah <bmah@es.net>
Date:   Sat Apr 16 02:41:32 2016 -0400

    Checkpoint for initial work on #325 to add socket pacing.

    This works only on Linux and depends on the availability of
    the SO_MAX_PACING_RATE socket option and the fq queue discipline.
    Use --socket-pacing to use SO_MAX_PACING_RATE instead of the
    default iperf3 user-level rate limiting; in either case, the
    --bandwidth parameter controls the desired rate.

    Lightly tested with both --tcp and --udp, normal and --reverse.
    Real testing requires analysis of packet timestamps between
    multiple hosts.

(cherry picked from commit 9915746a8bf88050cd4cfee4295d063c1154e9a0)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2016-05-26 16:23:52 -07:00
Joe McEachern
69b8efa424
Add fix for #412 (#414)
* Add fix for #412
This prevents negative loss counters with UDP when omit is used

* Track the original start time and bytes omitted. This allows the
throttle function to work after the omit timer fires. This is
a fix for issue #419.

* Remove changes to switch the bandwidth to received instead of sent bandwidth

* Roll back bandwidth sent vs received changes

(cherry picked from commit 3b2311263aca633fba76b4baef8de78420214fcf)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2016-05-26 15:58:59 -07:00
Bruce A. Mah
997968349d
Fix build on FreeBSD 11-CURRENT, as described in issue #413.
This caused by a combination of the iperf3 build somehow using
the system queue.h on FreeBSD 11 (possibly only on this platform)
and TAILQ_END not being defined in the system queue.h.

Expanding the TAILQ_END macro to NULL seems to solve the problem.

Submitted by:	@rbgarga

(cherry picked from commit f88486443ca91417ac3b47d69368b7d1db40eba6)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2016-05-26 15:57:44 -07:00
g-coder
876e9b85ee
DEREF_AFTER_NULL in src/iperf_error.c (#423)
DEREF_AFTER_NULL: pointer ‘test’ at line:77 is passed as an argument to function iperf_delete_pidfile(), in which it is dereferenced at iperf_api.c:2832.
Pointer ‘test’ can be NULL and dereferencing a NULL pointer causes seg-fault.

Applied Fix: pointer ‘test’ is checked for NULL before passing it to function iperf_delete_pidfile().
(cherry picked from commit 8fcfc2479f8072c00798fcbea93309d41af5ef2a)

Signed-off-by: Bruce A. Mah <bmah@es.net>
2016-05-26 15:51:35 -07:00
g-coder
870f55cad1 Safe programming practice. Added va_end. (#425)
In file iperf_util.c:
Function 'va_start' is called at line:327. But, 'va_end' is not called before returning from function 'iperf_json_printf()' at line:352 and line:355.
The va_end performs cleanup for the argp object initialized by a call to va_start. If va_end is not called before a function that calls va_start returns, the behavior is undefined.

Applied Fix: added va_end before returning from the function.
(cherry picked from commit 0da552c390c8332a53b5a39cdfbe6ffccd749189)

Signed-off-by: Bruce A. Mah <bmah@es.net>
2016-05-26 15:46:37 -07:00
Bruce A. Mah
117e458639
Regen. 2016-02-01 15:48:54 -08:00
Bruce A. Mah
23767e2d06
Bump version numbers for upcoming 3.1.2 release. 2016-02-01 15:48:09 -08:00
Brian Tierney
7eb521f644 added additional project
(cherry picked from commit 3cf50d9856182a5e89abbe899be915382c165137)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2016-02-01 15:45:01 -08:00
Brian Tierney
f6ba16590e adding scripts to generate gnuplots from iperf3 data
(cherry picked from commit c50b5ea849ca07ca3d27d46dcb200f67ba7e6b81)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2016-02-01 15:44:48 -08:00
Bruce A. Mah
9d1b9cfe13 Update copyright dates in a couple of places.
(cherry picked from commit cb25dfe687806788ec6c66b1d30726f561884130)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2016-02-01 14:04:26 -08:00
Bruce A. Mah
ecd0521820 Get rid of nan values when there were no packets in a UDP interval.
This was causing some headaches for code trying to parse JSON.
Also revise a prior partial fix that hard-coded 100% loss for the
case of zero packets.

Partially fixes #278.

Merge candidate for 3.0 and 3.1 bugfix branches.

(cherry picked from commit 670c18584bcf7a285f3561eb7ea38cc53600d0ab)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2016-01-29 09:08:40 -08:00
Bruce A. Mah
3f857c5ea8 Fix a bug where we printed the incorrect value for out-of-order UDP packets.
Fixes #329, submitted by @bhegardt.

While here, add this value to the JSON output.

(cherry picked from commit 224ae8c764cb9ff86a55d9a7ad8612b3644d42b1)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2015-11-20 08:34:32 -08:00
Bruce A. Mah
d9ed428411
Regen. 2015-11-19 09:23:48 -08:00
Bruce A. Mah
45388f9d3b
Release notes, version number bumps for iperf 3.1.1. 2015-11-19 09:21:46 -08:00
Bruce A. Mah
c3a346b6dc Update README.
Reflect current support/maintenance status, add a few new known issues,
bump copyright date.

(cherry picked from commit ccec14eb5138d22059e2475da035c2d74627e417)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2015-11-18 13:28:38 -08:00
Bruce A. Mah
7351625c61 Improve command error handling.
Exit with non-zero exit code if server mode has too many errors.

Properly detect complain about non-numeric arguments to -A, -L, and -S.

Implement range checks for argument to -S.

Fixes #316.

(cherry picked from commit 956d115851755390bb59ad93a6d501be444b9f73)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2015-11-18 13:28:28 -08:00
Bruce A. Mah
3c58372bbc Fix a bug where the -T title option was not being output correctly
in JSON output.

Fixes #292.

Patch from:	@SLX-WI

(cherry picked from commit 44485b5b88089065ba03eadc0b9fe1907d01e976)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2015-11-18 13:28:14 -08:00
Bruce A. Mah
9048da7a1e Markup fixes in manpages for Debian compatibility.
Fixes #291.

Merge candidate for 3.1 stable release if applicable.

(cherry picked from commit 6e48bb2a5da13cdc2dcf069c1d4750ff99c15191)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2015-11-18 13:28:05 -08:00
Bruce A. Mah
e5e38d9da0 Rename the recently-added template member in the iperf_test structure
to improve C++ compatibility.

Fixes #323.

(cherry picked from commit 7b2abbc59a92d4f834c29e62ef9ec6375164f7e9)
Signed-off-by: Bruce A. Mah <bmah@es.net>
2015-11-18 13:27:42 -08:00
37 changed files with 2215 additions and 1258 deletions

7
.travis.yml Normal file
View File

@ -0,0 +1,7 @@
language: c
compiler:
- gcc
- clang
os: linux
script: ./configure && make && make check

View File

@ -1,6 +1,6 @@
"iperf, Copyright (c) 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."
"iperf, Copyright (c) 2014-2017, 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."
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

View File

@ -13,7 +13,7 @@ This version, sometimes referred to as iperf3, is a redesign of an
original version developed at NLANR/DAST. iperf3 is a new
implementation from scratch, with the goal of a smaller, simpler code
base, and a library version of the functionality that can be used in
other programs. iperf3 also a number of features found in other tools
other programs. iperf3 also has a number of features found in other tools
such as nuttcp and netperf, but were missing from the original iperf.
These include, for example, a zero-copy mode and optional JSON output.
Note that iperf3 is *not* backwards compatible with the original iperf.
@ -26,6 +26,13 @@ OpenBSD, NetBSD, Android, Solaris, and other Linux distributions.
iperf3 is principally developed by ESnet / Lawrence Berkeley National
Laboratory. It is released under a three-clause BSD license.
Note that at this point, ESnet plans to support iperf3 in "maintenance
mode". At this point, there are no definite plans for further iperf3
releases, and ESnet will be providing a very limited amount of
resources for support and development, going forward. However, ESnet
could issue new iperf3 releases to deal with security issues or
high-impact bug fixes.
For more information see: http://software.es.net/iperf
Source code and issue tracker: https://github.com/esnet/iperf
@ -137,26 +144,9 @@ variables.
Known Issues
------------
* UDP performance: Some problems have been noticed with iperf3 on the
ESnet 100G testbed at high UDP rates (above 10Gbps). The symptom is
that on any particular run of iperf3 the receiver reports a loss rate
of about 20%, regardless of the -b option used on the client side.
This problem appears not to be iperf3-specific, and may be due to the
placement of the iperf3 process on a CPU and its relation to the
inbound NIC. In some cases this problem can be mitigated by an
appropriate use of the CPU affinity (-A) option. (Issue #55)
A set of known issues is maintained on the iperf3 Web pages:
* The -Z flag sometimes causes the iperf3 client to hang on OSX.
(Issue #129)
* When specifying the TCP buffer size using the "-w" flag on Linux, Linux
doubles the value you pass in. (You can see this using iperf3's debug flag).
But then the CWND does not actually ramp up to the doubled value, but only
to about 75% of the doubled value. This appears to be by design.
* On some platforms, it might be necessary to invoke "ldconfig"
manually after doing a "make install" before the iperf3 executable can
find its shared library. (Issue #153)
http://software.es.net/iperf/dev.html#known-issues
Links
-----
@ -173,7 +163,7 @@ responsibility for the content of these pages.
Copyright
---------
iperf, Copyright (c) 2014, The Regents of the University of
iperf, Copyright (c) 2014-2017, 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.

View File

@ -1,3 +1,181 @@
== iperf 3.1.7 2017-03-06 ==
iperf 3.1.7 is functionally identical to iperf 3.1.6. Its only
changes consist of updated documentation files and text in the RPM
spec file.
== iperf 3.1.6 2017-02-02 ==
The release notes for iperf 3.1.6 describe changes, including bug
fixes and new functionality, made since iperf 3.1.5.
* User-visible changes
* Specifying --fq-rate or --no-fq-socket-pacing on a system where
these options are not supported now generate an error instead of a
warning. This change makes diagnosing issues related to pacing
more apparent.
* Fixed a bug where two recently-added diagnostic messages spammed
the JSON output on UDP tests.
== iperf 3.1.5 2017-01-12 ==
The release notes for iperf 3.1.5 describe changes, including bug
fixes and new functionality, made since iperf 3.1.4.
Compatibility note: Fair-queueing is now specified differently in
iperf 3.1.5 than in prior versions (which include 3.1.3 and 3.1.4).
Compatibility note: UDP tests may yield different results from all
prior versions of iperf3 (through 3.1.4) due to the new default UDP
sending size.
* User-visible changes
* The fair-queueing per-socket based pacing available on recent
Linux systems has been reimplemented with a different user
interface (#325, #467, #488). The --bandwidth command-line flag
now controls only the application-level pacing, as was the case in
iperf 3.1.2 and all earlier versions. Fair-queueing per-socket
based pacing is now controlled via a new --fq-rate command-line
flag. Note that TCP and UDP tests may use --bandwidth, --fq-rate,
both flags, or neither flag. SCTP tests currently support
--bandwidth only. The --no-fq-socket-pacing flag, which was
introduced in iperf 3.1.3, has now been deprecated, and is
equivalent to --fq-rate=0. iperf3 now reacts more gracefully if
--no-fq-socket-pacing or --fq-rate are specified on platforms that
don't support these options.
For UDP tests, note that the default --bandwidth is 1 Mbps. Using
the fair-queueing-based pacing will probably require explicitly
setting both --bandwidth and --fq-rate, preferably to the same
value. (While setting different values for --bandwidth and
--fq-rate can certainly be done, the results can range from
entertaining to perplexing.)
* iperf3 now chooses a more sane default UDP send size (#496, #498).
The former default (8KB) caused IP packet fragmentation on paths
having smaller MTUs (including any Ethernet network not configured
for jumbo frames). This could have effects ranging from increased
burstiness, to packet loss, to complete failure of the test.
iperf3 now attempts to use the MSS of the control connection to
determine a default UDP send size if no sending length was
explicitly specified with --length.
* Several checks are now made when setting the socket buffer sizes
with the -w option, to verify that the settings have been applied
correctly. The results of these checks can been seen when the
--debug flag is specified. (#356)
* A --forceflush flag has been added to flush the output stream
after every statistics reporting interval.
* Developer-visible changes
* A systemd service file has been added (#340, #430).
== iperf 3.1.4 2016-10-31 ==
The release notes for iperf 3.1.4 describe changes, including bug
fixes and new functionality, made since iperf 3.1.3.
* User-visible changes
* On systems that support setting the congestion control algorithm,
iperf3 now keeps track of the congestion control algorithm and
print it in the JSON output in the members sender_tcp_congestion
and receiver_tcp_congestion (issue #461). A few bugs (probably
not user-visible) with setting the congestion control algorithm
were also fixed.
* Developer-visible changes
* Fixed a buffer overflow in the cJSON library (issue #466). It is
not believed that this bug created any security vulnerabilities in
the context of iperf3.
* Travis CI builds are now enabled on this codeline (pull request #424).
* Various bug fixes (issue #459, pull request #429, issue #388).
== iperf 3.1.3 2016-06-08 ==
The release notes for iperf 3.1.3 describe changes, including bug
fixes and new functionality, made since iperf 3.1.2.
* Security
* Fixed a buffer overflow / heap corruption issue that could occur
if a malformed JSON string was passed on the control channel. In
theory, this vulnerability could be leveraged to create a heap
exploit. This issue, present in the cJSON library, was already
fixed upstream, so was addressed in iperf3 by importing a newer
version of cJSON (plus local ESnet modifications). Discovered and
reported by Dave McDaniel, Cisco Talos. Cross-references:
TALOS-CAN-0164, ESNET-SECADV-2016-0001, CVE-2016-4303.
* User-visible changes
* On supported platforms (recent Linux), iperf3 can use
fair-queueing-based per-socket pacing instead of its own
application-level pacing for the --bandwidth option.
Application-level pacing can be forced with the
-no-fq-socket-pacing flag.
* A bug that could show negative loss counters with --udp and --omit
has been fixed (issue #412, pull request #414).
* Error handling has been made slightly more robust. Also, the
iperf3 server will no longer exit after five consecutive errors,
but will only exit for certain types of errors that prevent it
from participating in any tests at all.
* Developer-visible changes
* Fixed the build on FreeBSD 11-CURRENT (issue #413).
* Fixed various coding errors (issue #423, issue #425).
== iperf 3.1.2 2016-02-01 ==
The release notes for iperf 3.1.2 describe changes, including bug
fixes and new functionality, made since iperf 3.1.1.
* User-visible changes
* Fixed a bug that caused nan values to be emitted (incorrectly)
into JSON, particularly at the end of UDP tests (issue #278).
* Fixed a bug that caused the wrong value to be printed for
out-of-order UDP packets (issue #329).
* Added a contrib/ directory containing a few submitted graphing
scripts.
* Developer-visible changes
== iperf 3.1.1 2015-11-19 ==
The release notes for iperf 3.1.1 describe changes and new
functionality in iperf 3.1.1, but not present in 3.1.
* User-visible changes
* Some markup fixes have been made in the manpages for Debian
compatibility (issue #291).
* A bug where the -T title option was not being output correctly
in JSON output has been fixed (issue #292).
* Argument handling for some command-line options has been improved
(issue #316).
* Developer-visible changes
* A regression with C++ compatibility in one of the iperf header
files has been fixed (issue #323).
== iperf 3.1 2015-10-16 ==
The release notes for iperf 3.1 describe changes and new

178
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for iperf 3.1.
# Generated by GNU Autoconf 2.69 for iperf 3.1.7.
#
# Report bugs to <https://github.com/esnet/iperf>.
#
@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='iperf'
PACKAGE_TARNAME='iperf'
PACKAGE_VERSION='3.1'
PACKAGE_STRING='iperf 3.1'
PACKAGE_VERSION='3.1.7'
PACKAGE_STRING='iperf 3.1.7'
PACKAGE_BUGREPORT='https://github.com/esnet/iperf'
PACKAGE_URL='http://software.es.net/iperf/'
@ -1316,7 +1316,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures iperf 3.1 to adapt to many kinds of systems.
\`configure' configures iperf 3.1.7 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1386,7 +1386,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of iperf 3.1:";;
short | recursive ) echo "Configuration of iperf 3.1.7:";;
esac
cat <<\_ACEOF
@ -1500,7 +1500,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
iperf configure 3.1
iperf configure 3.1.7
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@ -1869,7 +1869,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by iperf $as_me 3.1, which was
It was created by iperf $as_me 3.1.7, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@ -2744,7 +2744,7 @@ fi
# Define the identity of the package.
PACKAGE='iperf'
VERSION='3.1'
VERSION='3.1.7'
cat >>confdefs.h <<_ACEOF
@ -12185,6 +12185,69 @@ fi
# Check for systems which need -lsocket and -lnsl
#AX_LIB_SOCKET_NSL
# Check for the math library (needed by cjson on some platforms)
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing floor" >&5
$as_echo_n "checking for library containing floor... " >&6; }
if ${ac_cv_search_floor+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char floor ();
int
main ()
{
return floor ();
;
return 0;
}
_ACEOF
for ac_lib in '' m; do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_search_floor=$ac_res
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
if ${ac_cv_search_floor+:} false; then :
break
fi
done
if ${ac_cv_search_floor+:} false; then :
else
ac_cv_search_floor=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_floor" >&5
$as_echo "$ac_cv_search_floor" >&6; }
ac_res=$ac_cv_search_floor
if test "$ac_res" != no; then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
else
echo "floor()"
exit 1
fi
# Solaris puts nanosleep in -lrt
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing nanosleep" >&5
$as_echo_n "checking for library containing nanosleep... " >&6; }
@ -12248,69 +12311,6 @@ exit 1
fi
# Solaris puts hstrerror in -lresolv
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing hstrerror" >&5
$as_echo_n "checking for library containing hstrerror... " >&6; }
if ${ac_cv_search_hstrerror+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char hstrerror ();
int
main ()
{
return hstrerror ();
;
return 0;
}
_ACEOF
for ac_lib in '' resolv; do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_search_hstrerror=$ac_res
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
if ${ac_cv_search_hstrerror+:} false; then :
break
fi
done
if ${ac_cv_search_hstrerror+:} false; then :
else
ac_cv_search_hstrerror=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_hstrerror" >&5
$as_echo "$ac_cv_search_hstrerror" >&6; }
ac_res=$ac_cv_search_hstrerror
if test "$ac_res" != no; then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
else
echo "nanosleep() required for timing operations."
exit 1
fi
# On illumos we need -lsocket
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing socket" >&5
$as_echo_n "checking for library containing socket... " >&6; }
@ -12774,6 +12774,38 @@ fi
done
# Check for packet pacing socket option (Linux only for now).
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking SO_MAX_PACING_RATE socket option" >&5
$as_echo_n "checking SO_MAX_PACING_RATE socket option... " >&6; }
if ${iperf3_cv_header_so_max_pacing_rate+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/socket.h>
#ifdef SO_MAX_PACING_RATE
yes
#endif
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
$EGREP "yes" >/dev/null 2>&1; then :
iperf3_cv_header_so_max_pacing_rate=yes
else
iperf3_cv_header_so_max_pacing_rate=no
fi
rm -f conftest*
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $iperf3_cv_header_so_max_pacing_rate" >&5
$as_echo "$iperf3_cv_header_so_max_pacing_rate" >&6; }
if test "x$iperf3_cv_header_so_max_pacing_rate" = "xyes"; then
$as_echo "#define HAVE_SO_MAX_PACING_RATE 1" >>confdefs.h
fi
ac_config_files="$ac_config_files Makefile src/Makefile src/version.h examples/Makefile iperf3.spec"
cat >confcache <<\_ACEOF
@ -13309,7 +13341,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by iperf $as_me 3.1, which was
This file was extended by iperf $as_me 3.1.7, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -13376,7 +13408,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
iperf config.status 3.1
iperf config.status 3.1.7
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"

View File

@ -1,4 +1,4 @@
# iperf, Copyright (c) 2014, 2015, The Regents of the University of
# iperf, Copyright (c) 2014, 2015, 2016, 2017, 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.
@ -24,7 +24,7 @@
# file for complete information.
# Initialize the autoconf system for the specified tool, version and mailing list
AC_INIT(iperf, 3.1, https://github.com/esnet/iperf, iperf, http://software.es.net/iperf/)
AC_INIT(iperf, 3.1.7, https://github.com/esnet/iperf, iperf, http://software.es.net/iperf/)
AC_LANG(C)
# Specify where the auxiliary files created by configure should go. The config
@ -57,14 +57,14 @@ AC_HEADER_STDC
# Check for systems which need -lsocket and -lnsl
#AX_LIB_SOCKET_NSL
# Solaris puts nanosleep in -lrt
AC_SEARCH_LIBS(nanosleep, [rt], [], [
echo "nanosleep() required for timing operations."
# Check for the math library (needed by cjson on some platforms)
AC_SEARCH_LIBS(floor, [m], [], [
echo "floor()"
exit 1
])
# Solaris puts hstrerror in -lresolv
AC_SEARCH_LIBS(hstrerror, [resolv], [], [
# Solaris puts nanosleep in -lrt
AC_SEARCH_LIBS(nanosleep, [rt], [], [
echo "nanosleep() required for timing operations."
exit 1
])
@ -141,4 +141,18 @@ AC_CHECK_FUNCS([cpuset_setaffinity sched_setaffinity],
# it needs and what arguments it expects.
AC_CHECK_FUNCS([sendfile])
# Check for packet pacing socket option (Linux only for now).
AC_CACHE_CHECK([SO_MAX_PACING_RATE socket option],
[iperf3_cv_header_so_max_pacing_rate],
AC_EGREP_CPP(yes,
[#include <sys/socket.h>
#ifdef SO_MAX_PACING_RATE
yes
#endif
],iperf3_cv_header_so_max_pacing_rate=yes,iperf3_cv_header_so_max_pacing_rate=no))
if test "x$iperf3_cv_header_so_max_pacing_rate" = "xyes"; then
AC_DEFINE([HAVE_SO_MAX_PACING_RATE], [1], [Have SO_MAX_PACING_RATE sockopt.])
fi
AC_OUTPUT([Makefile src/Makefile src/version.h examples/Makefile iperf3.spec])

12
contrib/README.txt Normal file
View File

@ -0,0 +1,12 @@
This directory contains files that might be useful to analyze iperf3 results
iperf3_to_gnuplot.py: converts iperf3 JSON output to format easy to plot in gnuplot
iperf3.gp: sample gnuplot commands to plot throught and retransmits
Other iperf3 related projects that might be of interest:
https://github.com/kaihendry/iperf3chart

37
contrib/iperf3.gp Normal file
View File

@ -0,0 +1,37 @@
#
# sample Gnuplot command file for iperf3 results
set term x11
#set term png
#set term postscript landscape color
set key width -12
# iperf3 data fields
#start bytes bits_per_second retransmits snd_cwnd
set output "iperf3.png"
#set output "iperf3.eps"
#set nokey
set grid xtics
set grid ytics
set grid linewidth 1
set title "TCP performance: 40G to 10G host"
set xlabel "time (seconds)"
set ylabel "Bandwidth (Gbits/second)"
set xrange [0:60]
set yrange [0:15]
set ytics nomirror
set y2tics
set y2range [0:2500]
# dont plot when retransmits = 0
set datafile missing '0'
set pointsize 1.6
plot "40Gto10G.old.dat" using 1:3 title '3.10 kernel' with linespoints lw 3 pt 5, \
"40Gto10G.new.dat" using 1:3 title '4.2 kernel' with linespoints lw 3 pt 7, \
"40Gto10G.old.dat" using 1:4 title 'retransmits' with points pt 7 axes x1y2
#plot "iperf3.old.dat" using 1:3 title '3.10 kernel' with linespoints lw 3 pt 5, \
# "iperf3.new.dat" using 1:3 title '4.2 kernel' with linespoints lw 3 pt 7

10
contrib/iperf3.service Normal file
View File

@ -0,0 +1,10 @@
[Unit]
Description=iperf3
Requires=network.target
[Service]
ExecStart=/usr/bin/iperf3 -s
Restart=on-failure
[Install]
WantedBy=multi-user.target

77
contrib/iperf3_to_gnuplot.py Executable file
View File

@ -0,0 +1,77 @@
#!/usr/bin/env python
"""
Extract iperf data from json blob and format for gnuplot.
"""
import json
import os
import sys
import os.path
from optparse import OptionParser
import pprint
# for debugging, so output to stderr to keep verbose
# output out of any redirected stdout.
pp = pprint.PrettyPrinter(indent=4, stream=sys.stderr)
def generate_output(iperf, options):
for i in iperf.get('intervals'):
for ii in i.get('streams'):
if options.verbose: pp.pprint(ii)
row = '{0} {1} {2} {3} {4}\n'.format(
round(float(ii.get('start')), 4),
ii.get('bytes'),
# to Gbits/sec
round(float(ii.get('bits_per_second')) / (1000*1000*1000), 3),
ii.get('retransmits'),
round(float(ii.get('snd_cwnd')) / (1000*1000), 2)
)
yield row
def main():
usage = '%prog [ -f FILE | -o OUT | -v ]'
parser = OptionParser(usage=usage)
parser.add_option('-f', '--file', metavar='FILE',
type='string', dest='filename',
help='Input filename.')
parser.add_option('-o', '--output', metavar='OUT',
type='string', dest='output',
help='Optional file to append output to.')
parser.add_option('-v', '--verbose',
dest='verbose', action='store_true', default=False,
help='Verbose debug output to stderr.')
options, args = parser.parse_args()
if not options.filename:
parser.error('Filename is required.')
file_path = os.path.normpath(options.filename)
if not os.path.exists(file_path):
parser.error('{f} does not exist'.format(f=file_path))
with open(file_path,'r') as fh:
data = fh.read()
try:
iperf = json.loads(data)
except Exception as e:
parser.error('Could not parse JSON from file (ex): {0}'.format(str(e)))
if options.output:
absp = os.path.abspath(options.output)
d,f = os.path.split(absp)
if not os.path.exists(d):
parser.error('Output file directory path {0} does not exist'.format(d))
fh = open(absp, 'a')
else:
fh = sys.stdout
for i in generate_output(iperf, options):
fh.write(i)
if __name__ == '__main__':
main()

View File

@ -82,6 +82,10 @@ the executable.
logfile file
send output to a log file.
--forceflush
force flushing output at every interval. Used to avoid buffering when sending
output to pipe.
d, debug
emit debugging output. Primarily (perhaps exclusively) of use
to developers.

View File

@ -14,9 +14,10 @@ BuildRequires: e2fsprogs-devel
%endif
%description
Iperf is a tool to measure maximum TCP bandwidth, allowing the tuning of
various parameters and UDP characteristics. Iperf reports bandwidth, delay
jitter, data-gram loss.
iperf3 is a tool for active measurements of the maximum achievable
bandwidth between two IP hosts. It supports tuning of various
parameters related to timing, protocols, and buffers. For each test,
it reports the bandwidth, loss, and other parameters.
%package devel
Summary: Development files for %{name}

View File

@ -25,6 +25,7 @@ libiperf_la_SOURCES = \
iperf_sctp.h \
iperf_util.c \
iperf_util.h \
dscp.c \
net.c \
net.h \
portable_endian.h \

View File

@ -139,8 +139,8 @@ LTLIBRARIES = $(lib_LTLIBRARIES)
libiperf_la_LIBADD =
am_libiperf_la_OBJECTS = cjson.lo iperf_api.lo iperf_error.lo \
iperf_client_api.lo iperf_locale.lo iperf_server_api.lo \
iperf_tcp.lo iperf_udp.lo iperf_sctp.lo iperf_util.lo net.lo \
tcp_info.lo tcp_window_size.lo timer.lo units.lo
iperf_tcp.lo iperf_udp.lo iperf_sctp.lo iperf_util.lo dscp.lo \
net.lo tcp_info.lo tcp_window_size.lo timer.lo units.lo
libiperf_la_OBJECTS = $(am_libiperf_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@ -163,7 +163,8 @@ am__objects_1 = iperf3_profile-cjson.$(OBJEXT) \
iperf3_profile-iperf_udp.$(OBJEXT) \
iperf3_profile-iperf_sctp.$(OBJEXT) \
iperf3_profile-iperf_util.$(OBJEXT) \
iperf3_profile-net.$(OBJEXT) iperf3_profile-tcp_info.$(OBJEXT) \
iperf3_profile-dscp.$(OBJEXT) iperf3_profile-net.$(OBJEXT) \
iperf3_profile-tcp_info.$(OBJEXT) \
iperf3_profile-tcp_window_size.$(OBJEXT) \
iperf3_profile-timer.$(OBJEXT) iperf3_profile-units.$(OBJEXT)
am_iperf3_profile_OBJECTS = iperf3_profile-main.$(OBJEXT) \
@ -585,6 +586,7 @@ libiperf_la_SOURCES = \
iperf_sctp.h \
iperf_util.c \
iperf_util.h \
dscp.c \
net.c \
net.h \
portable_endian.h \
@ -803,8 +805,10 @@ distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cjson.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dscp.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf3-main.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf3_profile-cjson.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf3_profile-dscp.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf3_profile-iperf_api.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf3_profile-iperf_client_api.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf3_profile-iperf_error.Po@am__quote@
@ -1027,6 +1031,20 @@ iperf3_profile-iperf_util.obj: iperf_util.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(iperf3_profile_CFLAGS) $(CFLAGS) -c -o iperf3_profile-iperf_util.obj `if test -f 'iperf_util.c'; then $(CYGPATH_W) 'iperf_util.c'; else $(CYGPATH_W) '$(srcdir)/iperf_util.c'; fi`
iperf3_profile-dscp.o: dscp.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(iperf3_profile_CFLAGS) $(CFLAGS) -MT iperf3_profile-dscp.o -MD -MP -MF $(DEPDIR)/iperf3_profile-dscp.Tpo -c -o iperf3_profile-dscp.o `test -f 'dscp.c' || echo '$(srcdir)/'`dscp.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/iperf3_profile-dscp.Tpo $(DEPDIR)/iperf3_profile-dscp.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dscp.c' object='iperf3_profile-dscp.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(iperf3_profile_CFLAGS) $(CFLAGS) -c -o iperf3_profile-dscp.o `test -f 'dscp.c' || echo '$(srcdir)/'`dscp.c
iperf3_profile-dscp.obj: dscp.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(iperf3_profile_CFLAGS) $(CFLAGS) -MT iperf3_profile-dscp.obj -MD -MP -MF $(DEPDIR)/iperf3_profile-dscp.Tpo -c -o iperf3_profile-dscp.obj `if test -f 'dscp.c'; then $(CYGPATH_W) 'dscp.c'; else $(CYGPATH_W) '$(srcdir)/dscp.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/iperf3_profile-dscp.Tpo $(DEPDIR)/iperf3_profile-dscp.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dscp.c' object='iperf3_profile-dscp.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(iperf3_profile_CFLAGS) $(CFLAGS) -c -o iperf3_profile-dscp.obj `if test -f 'dscp.c'; then $(CYGPATH_W) 'dscp.c'; else $(CYGPATH_W) '$(srcdir)/dscp.c'; fi`
iperf3_profile-net.o: net.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(iperf3_profile_CFLAGS) $(CFLAGS) -MT iperf3_profile-net.o -MD -MP -MF $(DEPDIR)/iperf3_profile-net.Tpo -c -o iperf3_profile-net.o `test -f 'net.c' || echo '$(srcdir)/'`net.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/iperf3_profile-net.Tpo $(DEPDIR)/iperf3_profile-net.Po

File diff suppressed because it is too large Load Diff

View File

@ -19,107 +19,137 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "iperf_config.h"
#ifndef cJSON__h
#define cJSON__h
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
/* cJSON Types: */
#define cJSON_False 0
#define cJSON_True 1
#define cJSON_NULL 2
#define cJSON_Number 3
#define cJSON_String 4
#define cJSON_Array 5
#define cJSON_Object 6
#define cJSON_False (1 << 0)
#define cJSON_True (1 << 1)
#define cJSON_NULL (1 << 2)
#define cJSON_Number (1 << 3)
#define cJSON_String (1 << 4)
#define cJSON_Array (1 << 5)
#define cJSON_Object (1 << 6)
#define cJSON_IsReference 256
#define cJSON_StringIsConst 512
/* The cJSON structure: */
typedef struct cJSON {
struct cJSON *next, *prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
int type; /* The type of the item, as above. */
int type; /* The type of the item, as above. */
char *valuestring; /* The item's string, if type==cJSON_String */
int64_t valueint; /* The item's number, if type==cJSON_Number */
double valuefloat; /* The item's number, if type==cJSON_Number */
char *valuestring; /* The item's string, if type==cJSON_String */
int64_t valueint; /* The item's number, if type==cJSON_Number */
double valuedouble; /* The item's number, if type==cJSON_Number */
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
} cJSON;
typedef struct cJSON_Hooks {
void *(*malloc_fn)(size_t sz );
void (*free_fn)( void *ptr );
void *(*malloc_fn)(size_t sz);
void (*free_fn)(void *ptr);
} cJSON_Hooks;
/* Supply malloc, realloc and free functions to cJSON */
extern void cJSON_InitHooks( cJSON_Hooks* hooks );
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
extern cJSON *cJSON_Parse( const char *value );
extern cJSON *cJSON_Parse(const char *value);
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
extern char *cJSON_Print( cJSON *item );
extern char *cJSON_Print(cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
extern char *cJSON_PrintUnformatted( cJSON *item );
extern char *cJSON_PrintUnformatted(cJSON *item);
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt);
/* Delete a cJSON entity and all subentities. */
extern void cJSON_Delete( cJSON *c );
extern void cJSON_Delete(cJSON *c);
/* Returns the number of items in an array (or object). */
extern int cJSON_GetArraySize( cJSON *array );
extern int cJSON_GetArraySize(cJSON *array);
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
extern cJSON *cJSON_GetArrayItem( cJSON *array, int item );
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
/* Get item "string" from object. Case insensitive. */
extern cJSON *cJSON_GetObjectItem( cJSON *object, const char *string );
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
extern int cJSON_HasObjectItem(cJSON *object,const char *string);
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
extern const char *cJSON_GetErrorPtr( void );
extern const char *cJSON_GetErrorPtr(void);
/* These calls create a cJSON item of the appropriate type. */
extern cJSON *cJSON_CreateNull( void );
extern cJSON *cJSON_CreateTrue( void );
extern cJSON *cJSON_CreateFalse( void );
extern cJSON *cJSON_CreateBool( int b );
extern cJSON *cJSON_CreateInt( int64_t num );
extern cJSON *cJSON_CreateFloat( double num );
extern cJSON *cJSON_CreateString( const char *string );
extern cJSON *cJSON_CreateArray( void );
extern cJSON *cJSON_CreateObject( void );
extern cJSON *cJSON_CreateNull(void);
extern cJSON *cJSON_CreateTrue(void);
extern cJSON *cJSON_CreateFalse(void);
extern cJSON *cJSON_CreateBool(int b);
extern cJSON *cJSON_CreateNumber(double num);
extern cJSON *cJSON_CreateString(const char *string);
extern cJSON *cJSON_CreateArray(void);
extern cJSON *cJSON_CreateObject(void);
/* These utilities create an Array of count items. */
extern cJSON *cJSON_CreateIntArray( int64_t *numbers, int count );
extern cJSON *cJSON_CreateFloatArray( double *numbers, int count );
extern cJSON *cJSON_CreateStringArray( const char **strings, int count );
extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
/* Append item to the specified array/object. */
extern void cJSON_AddItemToArray( cJSON *array, cJSON *item );
extern void cJSON_AddItemToObject( cJSON *object, const char *string, cJSON *item );
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
extern void cJSON_AddItemReferenceToArray( cJSON *array, cJSON *item );
extern void cJSON_AddItemReferenceToObject( cJSON *object, const char *string, cJSON *item );
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
/* Remove/Detatch items from Arrays/Objects. */
extern cJSON *cJSON_DetachItemFromArray( cJSON *array, int which );
extern void cJSON_DeleteItemFromArray( cJSON *array, int which );
extern cJSON *cJSON_DetachItemFromObject( cJSON *object, const char *string );
extern void cJSON_DeleteItemFromObject( cJSON *object, const char *string );
extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
/* Update array items. */
extern void cJSON_ReplaceItemInArray( cJSON *array, int which, cJSON *newitem );
extern void cJSON_ReplaceItemInObject( cJSON *object, const char *string, cJSON *newitem );
extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* Shifts pre-existing items to the right. */
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
#define cJSON_AddNullToObject( object, name ) cJSON_AddItemToObject( object, name, cJSON_CreateNull() )
#define cJSON_AddTrueToObject( object, name ) cJSON_AddItemToObject( object, name, cJSON_CreateTrue() )
#define cJSON_AddFalseToObject( object, name ) cJSON_AddItemToObject( object, name, cJSON_CreateFalse() )
#define cJSON_AddIntToObject( object, name, n ) cJSON_AddItemToObject( object, name, cJSON_CreateInt( n ) )
#define cJSON_AddFloatToObject( object, name, n ) cJSON_AddItemToObject( object, name, cJSON_CreateFloat( n ) )
#define cJSON_AddStringToObject( object, name, s ) cJSON_AddItemToObject( object, name, cJSON_CreateString( s ) )
/* Duplicate a cJSON item */
extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
need to be released. With recurse!=0, it will duplicate any children connected to the item.
The item->next and ->prev pointers are always zero on return from Duplicate. */
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error. If not, then cJSON_GetErrorPtr() does the job. */
extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
extern void cJSON_Minify(char *json);
/* Macros for creating things quickly. */
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
#define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
/* Macro for iterating over an array */
#define cJSON_ArrayForEach(pos, head) for(pos = (head)->child; pos != NULL; pos = pos->next)
#ifdef __cplusplus
}

156
src/dscp.c Normal file
View File

@ -0,0 +1,156 @@
/* dscp lookup routines lifted wholesale from openssh */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2005,2006 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* 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.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#ifdef WIN32
#define strcasecmp(a,b) _stricmp(a,b)
#define snprintf _snprintf
#endif
int parse_qos(const char *cp);
const char * iptos2str(int iptos);
/*
* Definitions for IP type of service (ip_tos)
*/
#if HAVE_NETINET_IN_SYSTM_H
#include <netinet/in_systm.h>
#endif
#if HAVE_NETINET_IP_H
#include <netinet/ip.h>
#endif
#ifndef IPTOS_LOWDELAY
# define IPTOS_LOWDELAY 0x10
# define IPTOS_THROUGHPUT 0x08
# define IPTOS_RELIABILITY 0x04
# define IPTOS_LOWCOST 0x02
# define IPTOS_MINCOST IPTOS_LOWCOST
#endif /* IPTOS_LOWDELAY */
/*
* Definitions for DiffServ Codepoints as per RFC2474
*/
#ifndef IPTOS_DSCP_AF11
# define IPTOS_DSCP_AF11 0x28
# define IPTOS_DSCP_AF12 0x30
# define IPTOS_DSCP_AF13 0x38
# define IPTOS_DSCP_AF21 0x48
# define IPTOS_DSCP_AF22 0x50
# define IPTOS_DSCP_AF23 0x58
# define IPTOS_DSCP_AF31 0x68
# define IPTOS_DSCP_AF32 0x70
# define IPTOS_DSCP_AF33 0x78
# define IPTOS_DSCP_AF41 0x88
# define IPTOS_DSCP_AF42 0x90
# define IPTOS_DSCP_AF43 0x98
# define IPTOS_DSCP_EF 0xb8
#endif /* IPTOS_DSCP_AF11 */
#ifndef IPTOS_DSCP_CS0
# define IPTOS_DSCP_CS0 0x00
# define IPTOS_DSCP_CS1 0x20
# define IPTOS_DSCP_CS2 0x40
# define IPTOS_DSCP_CS3 0x60
# define IPTOS_DSCP_CS4 0x80
# define IPTOS_DSCP_CS5 0xa0
# define IPTOS_DSCP_CS6 0xc0
# define IPTOS_DSCP_CS7 0xe0
#endif /* IPTOS_DSCP_CS0 */
#ifndef IPTOS_DSCP_EF
# define IPTOS_DSCP_EF 0xb8
#endif /* IPTOS_DSCP_EF */
static const struct {
const char *name;
int value;
} ipqos[] = {
{ "af11", IPTOS_DSCP_AF11 },
{ "af12", IPTOS_DSCP_AF12 },
{ "af13", IPTOS_DSCP_AF13 },
{ "af21", IPTOS_DSCP_AF21 },
{ "af22", IPTOS_DSCP_AF22 },
{ "af23", IPTOS_DSCP_AF23 },
{ "af31", IPTOS_DSCP_AF31 },
{ "af32", IPTOS_DSCP_AF32 },
{ "af33", IPTOS_DSCP_AF33 },
{ "af41", IPTOS_DSCP_AF41 },
{ "af42", IPTOS_DSCP_AF42 },
{ "af43", IPTOS_DSCP_AF43 },
{ "cs0", IPTOS_DSCP_CS0 },
{ "cs1", IPTOS_DSCP_CS1 },
{ "cs2", IPTOS_DSCP_CS2 },
{ "cs3", IPTOS_DSCP_CS3 },
{ "cs4", IPTOS_DSCP_CS4 },
{ "cs5", IPTOS_DSCP_CS5 },
{ "cs6", IPTOS_DSCP_CS6 },
{ "cs7", IPTOS_DSCP_CS7 },
{ "ef", IPTOS_DSCP_EF },
{ "lowdelay", IPTOS_LOWDELAY },
{ "throughput", IPTOS_THROUGHPUT },
{ "reliability", IPTOS_RELIABILITY },
{ NULL, -1 }
};
int
parse_qos(const char *cp)
{
unsigned int i;
char *ep = NULL;
long val;
if (cp == NULL)
return -1;
for (i = 0; ipqos[i].name != NULL; i++) {
if (strcasecmp(cp, ipqos[i].name) == 0)
return ipqos[i].value;
}
/* Try parsing as an integer */
val = strtol(cp, &ep, 0);
if (*cp == '\0' || *ep != '\0' || val < 0 || val > 255)
return -1;
return val;
}
const char *
iptos2str(int iptos)
{
int i;
static char iptos_str[sizeof "0xff"];
if (iptos < 0 || iptos > 64) iptos = 0;
for (i = 0; ipqos[i].name != NULL; i++) {
if (ipqos[i].value == iptos)
return ipqos[i].name;
}
snprintf(iptos_str, sizeof iptos_str, "0x%02x", iptos);
return iptos_str;
}

View File

@ -1,5 +1,5 @@
/*
* iperf, Copyright (c) 2014, The Regents of the University of
* iperf, Copyright (c) 2014, 2015, 2016, 2017, 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.
@ -36,6 +36,7 @@
#endif
#include <sys/select.h>
#include <sys/socket.h>
#define _GNU_SOURCE
#include <netinet/tcp.h>
#if defined(HAVE_CPUSET_SETAFFINITY)
@ -79,6 +80,7 @@ struct iperf_interval_results
TAILQ_ENTRY(iperf_interval_results) irlistentries;
void *custom_data;
int rtt;
int rttvar;
};
struct iperf_stream_result
@ -87,6 +89,7 @@ struct iperf_stream_result
iperf_size_t bytes_sent;
iperf_size_t bytes_received_this_interval;
iperf_size_t bytes_sent_this_interval;
iperf_size_t bytes_sent_omit;
int stream_prev_total_retrans;
int stream_retrans;
int stream_prev_total_sacks;
@ -98,6 +101,7 @@ struct iperf_stream_result
int stream_max_snd_cwnd;
struct timeval start_time;
struct timeval end_time;
struct timeval start_time_fixed;
TAILQ_HEAD(irlisthead, iperf_interval_results) interval_results;
void *data;
};
@ -108,7 +112,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) */
uint64_t rate; /* target data rate */
uint64_t rate; /* target data rate for application pacing*/
uint64_t fqrate; /* target data rate for FQ pacing*/
int burst; /* packets per burst */
int mss; /* for TCP MSS */
int ttl; /* IP TTL option */
@ -152,7 +157,9 @@ struct iperf_stream
double jitter;
double prev_transit;
int outoforder_packets;
int omitted_outoforder_packets;
int cnt_error;
int omitted_cnt_error;
uint64_t target;
struct sockaddr_storage local_addr;
@ -202,7 +209,7 @@ struct iperf_test
struct protocol *protocol;
signed char state;
char *server_hostname; /* -c option */
char *template; /* -c option */
char *tmp_template;
char *bind_address; /* first -B option */
TAILQ_HEAD(xbind_addrhead, xbind_entry) xbind_addrs; /* all -X opts */
int bind_port; /* --cport option */
@ -216,6 +223,8 @@ struct iperf_test
#endif /* HAVE_CPUSET_SETAFFINITY */
char *title; /* -T option */
char *congestion; /* -C option */
char *congestion_used; /* what was actually used */
char *remote_congestion_used; /* what the other side used */
char *pidfile; /* -P option */
char *logfile; /* --logfile option */
@ -225,6 +234,8 @@ struct iperf_test
int listener;
int prot_listener;
int ctrl_sck_mss; /* MSS for the control channel */
/* boolean variables for Options */
int daemon; /* -D option */
int one_off; /* -1 option */
@ -236,7 +247,7 @@ struct iperf_test
int debug; /* -d option - enable debug */
int get_server_output; /* --get-server-output */
int udp_counters_64bit; /* --use-64-bit-udp-counters */
int forceflush; /* --forceflush - flushing output at every interval */
int multisend;
char *json_output_string; /* rendered JSON output if json_output is set */
@ -304,10 +315,14 @@ struct iperf_test
#define SEC_TO_NS 1000000000LL /* too big for enum/const on some platforms */
#define MAX_RESULT_STRING 4096
#define UDP_BUFFER_EXTRA 1024
/* constants for command line arg sanity checks */
#define MB (1024 * 1024)
#define MAX_TCP_BUFFER (512 * MB)
#define MAX_BLOCKSIZE MB
/* Minimum size UDP send is the size of two 32-bit ints followed by a 64-bit int */
#define MIN_UDP_BLOCKSIZE (4 + 4 + 8)
/* Maximum size UDP send is (64K - 1) - IP and UDP header sizes */
#define MAX_UDP_BLOCKSIZE (65535 - 8 - 20)
#define MIN_INTERVAL 0.1

View File

@ -1,4 +1,4 @@
.TH IPERF 1 "October 2015" ESnet "User Manuals"
.TH IPERF3 1 "April 2017" ESnet "User Manuals"
.SH NAME
iperf3 \- perform network throughput tests
.SH SYNOPSIS
@ -58,6 +58,10 @@ output in JSON format
.BR --logfile " \fIfile\fR"
send output to a log file.
.TP
.BR --forceflush " "
force flushing output at every interval.
Used to avoid buffering when sending output to pipe.
.TP
.BR -d ", " --debug " "
emit debugging output.
Primarily (perhaps exclusively) of use to developers.
@ -85,7 +89,9 @@ handle one client connection, then exit.
.SH "CLIENT SPECIFIC OPTIONS"
.TP
.BR -c ", " --client " \fIhost\fR"
run in client mode, connecting to the specified server
run in client mode, connecting to the specified server.
By default, a test consists of sending data from the client to the
server, unless the \-R flag is specified.
.TP
.BR --sctp
use SCTP rather than TCP (FreeBSD and Linux)
@ -95,7 +101,7 @@ use UDP rather than TCP
.TP
.BR -b ", " --bandwidth " \fIn\fR[KM]"
set target bandwidth to \fIn\fR bits/sec (default 1 Mbit/sec for UDP, unlimited for TCP).
If there are multiple streams (-P flag), the bandwidth limit is applied
If there are multiple streams (\-P flag), the bandwidth limit is applied
separately to each stream.
You can also add a '/' and a number to the bandwidth specifier.
This is called "burst mode".
@ -103,18 +109,40 @@ It will send the given number of packets without pausing, even if that
temporarily exceeds the specified bandwidth limit.
Setting the target bandwidth to 0 will disable bandwidth limits
(particularly useful for UDP tests).
This bandwidth limit is implemented internally inside iperf3, and is
available on all platforms.
Compare with the \--fq-rate flag.
.TP
.BR --fq-rate " \fIn\fR[KM]"
Set a rate to be used with fair-queueing based socket-level pacing,
in bits per second.
This pacing (if specified) will be in addition to any pacing due to
iperf3's internal bandwidth pacing (\-b flag), and both can be
specified for the same test.
Only available on platforms supporting the
\fCSO_MAX_PACING_RATE\fR socket option (currently only Linux).
The default is no fair-queueing based pacing.
.TP
.BR --no-fq-socket-pacing
This option is deprecated and will be removed.
It is equivalent to specifying --fq-rate=0.
.TP
.BR -t ", " --time " \fIn\fR"
time in seconds to transmit for (default 10 secs)
.TP
.BR -n ", " --bytes " \fIn\fR[KM]"
number of bytes to transmit (instead of -t)
number of bytes to transmit (instead of \-t)
.TP
.BR -k ", " --blockcount " \fIn\fR[KM]"
number of blocks (packets) to transmit (instead of -t or -n)
number of blocks (packets) to transmit (instead of \-t or \-n)
.TP
.BR -l ", " --length " \fIn\fR[KM]"
length of buffer to read or write (default 128 KB for TCP, 8KB for UDP)
length of buffer to read or write. For TCP tests, the default value
is 128KB.
In the case of UDP, iperf3 tries to dynamically determine a reasonable
sending size based on the path MTU; if that cannot be determined it
uses 1460 bytes as a sending size.
For SCTP tests, the default size is 64KB.
.TP
.BR --cport " \fIport\fR"
bind data streams to a specific client port (for TCP and UDP only,
@ -124,7 +152,8 @@ default is to use an ephemeral port)
number of parallel client streams to run
.TP
.BR -R ", " --reverse
run in reverse mode (server sends, client receives)
reverse the direction of a test, so that the server sends data to the
client
.TP
.BR -w ", " --window " \fIn\fR[KM]"
window size / socket buffer size (this gets sent to the server and used on that side too)
@ -142,7 +171,10 @@ only use IPv4
only use IPv6
.TP
.BR -S ", " --tos " \fIn\fR"
set the IP 'type of service'
set the IP type of service
.TP
.BR "--dscp " \fIdscp\fR
set the IP DSCP bits. Both numeric and symbolic values are accepted.
.TP
.BR -L ", " --flowlabel " \fIn\fR"
set the IPv6 flow label (currently only supported on Linux)

View File

@ -1,5 +1,5 @@
/*
* iperf, Copyright (c) 2014, 2015, The Regents of the University of
* iperf, Copyright (c) 2014-2017, 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.
@ -100,9 +100,9 @@ usage()
void
usage_long()
usage_long(FILE *f)
{
fprintf(stderr, usage_longstr, UDP_RATE / (1024*1024), DURATION, DEFAULT_TCP_BLKSIZE / 1024, DEFAULT_UDP_BLKSIZE / 1024);
fprintf(f, usage_longstr, UDP_RATE / (1024*1024), DURATION, DEFAULT_TCP_BLKSIZE / 1024, DEFAULT_UDP_BLKSIZE / 1024);
}
@ -126,6 +126,12 @@ iperf_get_control_socket(struct iperf_test *ipt)
return ipt->ctrl_sck;
}
int
iperf_get_control_socket_mss(struct iperf_test *ipt)
{
return ipt->ctrl_sck_mss;
}
int
iperf_get_test_omit(struct iperf_test *ipt)
{
@ -144,6 +150,12 @@ iperf_get_test_rate(struct iperf_test *ipt)
return ipt->settings->rate;
}
uint64_t
iperf_get_test_fqrate(struct iperf_test *ipt)
{
return ipt->settings->fqrate;
}
int
iperf_get_test_burst(struct iperf_test *ipt)
{
@ -213,7 +225,7 @@ iperf_get_test_server_hostname(struct iperf_test *ipt)
char*
iperf_get_test_template(struct iperf_test *ipt)
{
return ipt->template;
return ipt->tmp_template;
}
int
@ -326,6 +338,12 @@ iperf_set_test_rate(struct iperf_test *ipt, uint64_t rate)
ipt->settings->rate = rate;
}
void
iperf_set_test_fqrate(struct iperf_test *ipt, uint64_t fqrate)
{
ipt->settings->fqrate = fqrate;
}
void
iperf_set_test_burst(struct iperf_test *ipt, int burst)
{
@ -333,9 +351,9 @@ iperf_set_test_burst(struct iperf_test *ipt, int burst)
}
void
iperf_set_test_server_port(struct iperf_test *ipt, int server_port)
iperf_set_test_server_port(struct iperf_test *ipt, int srv_port)
{
ipt->server_port = server_port;
ipt->server_port = srv_port;
}
void
@ -379,9 +397,9 @@ iperf_set_test_server_hostname(struct iperf_test *ipt, char *server_hostname)
}
void
iperf_set_test_template(struct iperf_test *ipt, char *template)
iperf_set_test_template(struct iperf_test *ipt, char *tmp_template)
{
ipt->template = strdup(template);
ipt->tmp_template = strdup(tmp_template);
}
void
@ -424,9 +442,9 @@ iperf_set_test_unit_format(struct iperf_test *ipt, char unit_format)
}
void
iperf_set_test_bind_address(struct iperf_test *ipt, char *bind_address)
iperf_set_test_bind_address(struct iperf_test *ipt, char *bnd_address)
{
ipt->bind_address = strdup(bind_address);
ipt->bind_address = strdup(bnd_address);
}
void
@ -532,7 +550,6 @@ iperf_on_connect(struct iperf_test *test)
struct sockaddr_in *sa_inP;
struct sockaddr_in6 *sa_in6P;
socklen_t len;
int opt;
now_secs = time((time_t*) 0);
(void) strftime(now_str, sizeof(now_str), rfc1123_fmt, gmtime(&now_secs));
@ -571,11 +588,9 @@ iperf_on_connect(struct iperf_test *test)
cJSON_AddStringToObject(test->json_start, "cookie", test->cookie);
if (test->protocol->id == SOCK_STREAM) {
if (test->settings->mss)
cJSON_AddIntToObject(test->json_start, "tcp_mss", test->settings->mss);
cJSON_AddNumberToObject(test->json_start, "tcp_mss", test->settings->mss);
else {
len = sizeof(opt);
getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len);
cJSON_AddIntToObject(test->json_start, "tcp_mss_default", opt);
cJSON_AddNumberToObject(test->json_start, "tcp_mss_default", test->ctrl_sck_mss);
}
}
} else if (test->verbose) {
@ -584,9 +599,7 @@ iperf_on_connect(struct iperf_test *test)
if (test->settings->mss)
iprintf(test, " TCP MSS: %d\n", test->settings->mss);
else {
len = sizeof(opt);
getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len);
iprintf(test, " TCP MSS: %d (default)\n", opt);
iprintf(test, " TCP MSS: %d (default)\n", test->ctrl_sck_mss);
}
}
@ -632,6 +645,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
{"version4", no_argument, NULL, '4'},
{"version6", no_argument, NULL, '6'},
{"tos", required_argument, NULL, 'S'},
{"dscp", required_argument, NULL, OPT_DSCP},
#if defined(HAVE_FLOWLABEL)
{"flowlabel", required_argument, NULL, 'L'},
#endif /* HAVE_FLOWLABEL */
@ -653,8 +667,11 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
#endif
{"pidfile", required_argument, NULL, 'I'},
{"logfile", required_argument, NULL, OPT_LOGFILE},
{"forceflush", no_argument, NULL, OPT_FORCEFLUSH},
{"get-server-output", no_argument, NULL, OPT_GET_SERVER_OUTPUT},
{"udp-counters-64bit", no_argument, NULL, OPT_UDP_COUNTERS_64BIT},
{"no-fq-socket-pacing", no_argument, NULL, OPT_NO_FQ_SOCKET_PACING},
{"fq-rate", required_argument, NULL, OPT_FQ_RATE},
{"debug", no_argument, NULL, 'd'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
@ -662,6 +679,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
int flag;
int blksize;
int server_flag, client_flag, rate_flag, duration_flag;
char *endptr;
#if defined(HAVE_CPU_AFFINITY)
char* comma;
#endif /* HAVE_CPU_AFFINITY */
@ -728,11 +746,11 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
#if defined(HAVE_SCTP)
set_protocol(test, Psctp);
client_flag = 1;
break;
#else /* HAVE_SCTP */
i_errno = IEUNIMP;
return -1;
#endif /* HAVE_SCTP */
break;
case OPT_NUMSTREAMS:
#if defined(linux) || defined(__FreeBSD__)
@ -825,13 +843,28 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
test->settings->domain = AF_INET6;
break;
case 'S':
test->settings->tos = strtol(optarg, NULL, 0);
test->settings->tos = strtol(optarg, &endptr, 0);
if (endptr == optarg ||
test->settings->tos < 0 ||
test->settings->tos > 255) {
i_errno = IEBADTOS;
return -1;
}
client_flag = 1;
break;
case OPT_DSCP:
test->settings->tos = parse_qos(optarg);
if(test->settings->tos < 0) {
i_errno = IEBADTOS;
return -1;
}
client_flag = 1;
break;
case 'L':
#if defined(HAVE_FLOWLABEL)
test->settings->flowlabel = strtol(optarg, NULL, 0);
if (test->settings->flowlabel < 1 || test->settings->flowlabel > 0xfffff) {
test->settings->flowlabel = strtol(optarg, &endptr, 0);
if (endptr == optarg ||
test->settings->flowlabel < 1 || test->settings->flowlabel > 0xfffff) {
i_errno = IESETFLOW;
return -1;
}
@ -876,8 +909,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
break;
case 'A':
#if defined(HAVE_CPU_AFFINITY)
test->affinity = atoi(optarg);
if (test->affinity < 0 || test->affinity > 1024) {
test->affinity = strtol(optarg, &endptr, 0);
if (endptr == optarg ||
test->affinity < 0 || test->affinity > 1024) {
i_errno = IEAFFINITY;
return -1;
}
@ -918,6 +952,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
case OPT_LOGFILE:
test->logfile = strdup(optarg);
break;
case OPT_FORCEFLUSH:
test->forceflush = 1;
break;
case OPT_GET_SERVER_OUTPUT:
test->get_server_output = 1;
client_flag = 1;
@ -925,9 +962,30 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
case OPT_UDP_COUNTERS_64BIT:
test->udp_counters_64bit = 1;
break;
case OPT_NO_FQ_SOCKET_PACING:
#if defined(HAVE_SO_MAX_PACING_RATE)
printf("Warning: --no-fq-socket-pacing is deprecated\n");
test->settings->fqrate = 0;
client_flag = 1;
#else /* HAVE_SO_MAX_PACING_RATE */
i_errno = IEUNIMP;
return -1;
#endif
break;
case OPT_FQ_RATE:
#if defined(HAVE_SO_MAX_PACING_RATE)
test->settings->fqrate = unit_atof_rate(optarg);
client_flag = 1;
#else /* HAVE_SO_MAX_PACING_RATE */
i_errno = IEUNIMP;
return -1;
#endif
break;
case 'h':
usage_long(stdout);
exit(0);
default:
usage_long();
usage_long(stderr);
exit(1);
}
}
@ -957,18 +1015,20 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
}
if (blksize == 0) {
if (test->protocol->id == Pudp)
blksize = DEFAULT_UDP_BLKSIZE;
blksize = 0; /* try to dynamically determine from MSS */
else if (test->protocol->id == Psctp)
blksize = DEFAULT_SCTP_BLKSIZE;
else
blksize = DEFAULT_TCP_BLKSIZE;
}
if (blksize <= 0 || blksize > MAX_BLOCKSIZE) {
if ((test->protocol->id != Pudp && blksize <= 0)
|| blksize > MAX_BLOCKSIZE) {
i_errno = IEBLOCKSIZE;
return -1;
}
if (test->protocol->id == Pudp &&
blksize > MAX_UDP_BLOCKSIZE) {
(blksize > 0 &&
(blksize < MIN_UDP_BLOCKSIZE || blksize > MAX_UDP_BLOCKSIZE))) {
i_errno = IEUDPBLOCKSIZE;
return -1;
}
@ -1025,7 +1085,7 @@ iperf_check_throttle(struct iperf_stream *sp, struct timeval *nowP)
if (sp->test->done)
return;
seconds = timeval_diff(&sp->result->start_time, nowP);
seconds = timeval_diff(&sp->result->start_time_fixed, nowP);
bits_per_second = sp->result->bytes_sent * 8 / seconds;
if (bits_per_second < sp->test->settings->rate) {
sp->green_light = 1;
@ -1056,8 +1116,8 @@ iperf_send(struct iperf_test *test, fd_set *write_setP)
gettimeofday(&now, NULL);
streams_active = 0;
SLIST_FOREACH(sp, &test->streams, streams) {
if (sp->green_light &&
(write_setP == NULL || FD_ISSET(sp->socket, write_setP))) {
if ((sp->green_light &&
(write_setP == NULL || FD_ISSET(sp->socket, write_setP)))) {
if ((r = sp->snd(sp)) < 0) {
if (r == NET_SOFTERROR)
break;
@ -1129,7 +1189,7 @@ iperf_init_test(struct iperf_test *test)
return -1;
}
SLIST_FOREACH(sp, &test->streams, streams) {
sp->result->start_time = now;
sp->result->start_time = sp->result->start_time_fixed = now;
}
if (test->on_test_start)
@ -1267,42 +1327,46 @@ send_parameters(struct iperf_test *test)
cJSON_AddTrueToObject(j, "udp");
else if (test->protocol->id == Psctp)
cJSON_AddTrueToObject(j, "sctp");
cJSON_AddIntToObject(j, "omit", test->omit);
cJSON_AddNumberToObject(j, "omit", test->omit);
if (test->server_affinity != -1)
cJSON_AddIntToObject(j, "server_affinity", test->server_affinity);
cJSON_AddNumberToObject(j, "server_affinity", test->server_affinity);
if (test->duration)
cJSON_AddIntToObject(j, "time", test->duration);
cJSON_AddNumberToObject(j, "time", test->duration);
if (test->settings->bytes)
cJSON_AddIntToObject(j, "num", test->settings->bytes);
cJSON_AddNumberToObject(j, "num", test->settings->bytes);
if (test->settings->blocks)
cJSON_AddIntToObject(j, "blockcount", test->settings->blocks);
cJSON_AddNumberToObject(j, "blockcount", test->settings->blocks);
if (test->settings->mss)
cJSON_AddIntToObject(j, "MSS", test->settings->mss);
cJSON_AddNumberToObject(j, "MSS", test->settings->mss);
if (test->no_delay)
cJSON_AddTrueToObject(j, "nodelay");
cJSON_AddIntToObject(j, "parallel", test->num_streams);
cJSON_AddNumberToObject(j, "parallel", test->num_streams);
if (test->reverse)
cJSON_AddTrueToObject(j, "reverse");
if (test->settings->socket_bufsize)
cJSON_AddIntToObject(j, "window", test->settings->socket_bufsize);
cJSON_AddNumberToObject(j, "window", test->settings->socket_bufsize);
if (test->settings->blksize)
cJSON_AddIntToObject(j, "len", test->settings->blksize);
cJSON_AddNumberToObject(j, "len", test->settings->blksize);
if (test->settings->rate)
cJSON_AddIntToObject(j, "bandwidth", test->settings->rate);
cJSON_AddNumberToObject(j, "bandwidth", test->settings->rate);
if (test->settings->fqrate)
cJSON_AddNumberToObject(j, "fqrate", test->settings->fqrate);
if (test->settings->burst)
cJSON_AddIntToObject(j, "burst", test->settings->burst);
cJSON_AddNumberToObject(j, "burst", test->settings->burst);
if (test->settings->tos)
cJSON_AddIntToObject(j, "TOS", test->settings->tos);
cJSON_AddNumberToObject(j, "TOS", test->settings->tos);
if (test->settings->flowlabel)
cJSON_AddIntToObject(j, "flowlabel", test->settings->flowlabel);
cJSON_AddNumberToObject(j, "flowlabel", test->settings->flowlabel);
if (test->title)
cJSON_AddStringToObject(j, "title", test->title);
if (test->congestion)
cJSON_AddStringToObject(j, "congestion", test->congestion);
if (test->congestion_used)
cJSON_AddStringToObject(j, "congestion_used", test->congestion_used);
if (test->get_server_output)
cJSON_AddIntToObject(j, "get_server_output", iperf_get_test_get_server_output(test));
cJSON_AddNumberToObject(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_AddNumberToObject(j, "udp_counters_64bit", iperf_get_test_udp_counters_64bit(test));
cJSON_AddStringToObject(j, "client_version", IPERF_VERSION);
@ -1367,6 +1431,8 @@ get_parameters(struct iperf_test *test)
test->settings->blksize = j_p->valueint;
if ((j_p = cJSON_GetObjectItem(j, "bandwidth")) != NULL)
test->settings->rate = j_p->valueint;
if ((j_p = cJSON_GetObjectItem(j, "fqrate")) != NULL)
test->settings->fqrate = j_p->valueint;
if ((j_p = cJSON_GetObjectItem(j, "burst")) != NULL)
test->settings->burst = j_p->valueint;
if ((j_p = cJSON_GetObjectItem(j, "TOS")) != NULL)
@ -1377,10 +1443,13 @@ get_parameters(struct iperf_test *test)
test->title = strdup(j_p->valuestring);
if ((j_p = cJSON_GetObjectItem(j, "congestion")) != NULL)
test->congestion = strdup(j_p->valuestring);
if ((j_p = cJSON_GetObjectItem(j, "congestion_used")) != NULL)
test->congestion_used = 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);
@ -1407,14 +1476,17 @@ send_results(struct iperf_test *test)
i_errno = IEPACKAGERESULTS;
r = -1;
} else {
cJSON_AddFloatToObject(j, "cpu_util_total", test->cpu_util[0]);
cJSON_AddFloatToObject(j, "cpu_util_user", test->cpu_util[1]);
cJSON_AddFloatToObject(j, "cpu_util_system", test->cpu_util[2]);
cJSON_AddNumberToObject(j, "cpu_util_total", test->cpu_util[0]);
cJSON_AddNumberToObject(j, "cpu_util_user", test->cpu_util[1]);
cJSON_AddNumberToObject(j, "cpu_util_system", test->cpu_util[2]);
if ( ! test->sender )
sender_has_retransmits = -1;
else
sender_has_retransmits = test->sender_has_retransmits;
cJSON_AddIntToObject(j, "sender_has_retransmits", sender_has_retransmits);
cJSON_AddNumberToObject(j, "sender_has_retransmits", sender_has_retransmits);
if ( test->congestion_used ) {
cJSON_AddStringToObject(j, "congestion_used", test->congestion_used);
}
/* If on the server and sending server output, then do this */
if (test->role == 's' && test->get_server_output) {
@ -1440,6 +1512,7 @@ send_results(struct iperf_test *test)
}
cJSON_AddStringToObject(j, "server_output_text", output);
free(output);
}
}
@ -1456,14 +1529,14 @@ send_results(struct iperf_test *test)
r = -1;
} else {
cJSON_AddItemToArray(j_streams, j_stream);
bytes_transferred = test->sender ? sp->result->bytes_sent : sp->result->bytes_received;
bytes_transferred = test->sender ? (sp->result->bytes_sent - sp->result->bytes_sent_omit) : sp->result->bytes_received;
retransmits = (test->sender && test->sender_has_retransmits) ? sp->result->stream_retrans : -1;
cJSON_AddIntToObject(j_stream, "id", sp->id);
cJSON_AddIntToObject(j_stream, "bytes", bytes_transferred);
cJSON_AddIntToObject(j_stream, "retransmits", retransmits);
cJSON_AddFloatToObject(j_stream, "jitter", sp->jitter);
cJSON_AddIntToObject(j_stream, "errors", sp->cnt_error);
cJSON_AddIntToObject(j_stream, "packets", sp->packet_count);
cJSON_AddNumberToObject(j_stream, "id", sp->id);
cJSON_AddNumberToObject(j_stream, "bytes", bytes_transferred);
cJSON_AddNumberToObject(j_stream, "retransmits", retransmits);
cJSON_AddNumberToObject(j_stream, "jitter", sp->jitter);
cJSON_AddNumberToObject(j_stream, "errors", sp->cnt_error);
cJSON_AddNumberToObject(j_stream, "packets", sp->packet_count);
}
}
if (r == 0 && test->debug) {
@ -1489,6 +1562,7 @@ get_results(struct iperf_test *test)
cJSON *j_cpu_util_total;
cJSON *j_cpu_util_user;
cJSON *j_cpu_util_system;
cJSON *j_remote_congestion_used;
cJSON *j_sender_has_retransmits;
int result_has_retransmits;
cJSON *j_streams;
@ -1524,9 +1598,9 @@ get_results(struct iperf_test *test)
printf("get_results\n%s\n", cJSON_Print(j));
}
test->remote_cpu_util[0] = j_cpu_util_total->valuefloat;
test->remote_cpu_util[1] = j_cpu_util_user->valuefloat;
test->remote_cpu_util[2] = j_cpu_util_system->valuefloat;
test->remote_cpu_util[0] = j_cpu_util_total->valuedouble;
test->remote_cpu_util[1] = j_cpu_util_user->valuedouble;
test->remote_cpu_util[2] = j_cpu_util_system->valuedouble;
result_has_retransmits = j_sender_has_retransmits->valueint;
if (! test->sender)
test->sender_has_retransmits = result_has_retransmits;
@ -1555,7 +1629,7 @@ get_results(struct iperf_test *test)
sid = j_id->valueint;
bytes_transferred = j_bytes->valueint;
retransmits = j_retransmits->valueint;
jitter = j_jitter->valuefloat;
jitter = j_jitter->valuedouble;
cerror = j_errors->valueint;
pcount = j_packets->valueint;
SLIST_FOREACH(sp, &test->streams, streams)
@ -1597,6 +1671,12 @@ get_results(struct iperf_test *test)
}
}
}
j_remote_congestion_used = cJSON_GetObjectItem(j, "congestion_used");
if (j_remote_congestion_used != NULL) {
test->remote_congestion_used = strdup(j_remote_congestion_used->valuestring);
}
cJSON_Delete(j);
}
return r;
@ -1636,14 +1716,32 @@ JSON_read(int fd)
uint32_t hsize, nsize;
char *str;
cJSON *json = NULL;
int rc;
/*
* Read a four-byte integer, which is the length of the JSON to follow.
* Then read the JSON into a buffer and parse it. Return a parsed JSON
* structure, NULL if there was an error.
*/
if (Nread(fd, (char*) &nsize, sizeof(nsize), Ptcp) >= 0) {
hsize = ntohl(nsize);
str = (char *) malloc(hsize+1); /* +1 for EOS */
/* Allocate a buffer to hold the JSON */
str = (char *) calloc(sizeof(char), hsize+1); /* +1 for trailing null */
if (str != NULL) {
if (Nread(fd, str, hsize, Ptcp) >= 0) {
str[hsize] = '\0'; /* add the EOS */
json = cJSON_Parse(str);
rc = Nread(fd, str, hsize, Ptcp);
if (rc >= 0) {
/*
* We should be reading in the number of bytes corresponding to the
* length in that 4-byte integer. If we don't the socket might have
* prematurely closed. Only do the JSON parsing if we got the
* correct number of bytes.
*/
if (rc == hsize) {
json = cJSON_Parse(str);
}
else {
printf("WARNING: Size of data read does not correspond to offered length\n");
}
}
}
free(str);
@ -1775,6 +1873,8 @@ iperf_defaults(struct iperf_test *testp)
#endif /* HAVE_CPUSET_SETAFFINITY */
testp->title = NULL;
testp->congestion = NULL;
testp->congestion_used = NULL;
testp->remote_congestion_used = NULL;
testp->server_port = PORT;
testp->ctrl_sck = -1;
testp->prot_listener = -1;
@ -1790,6 +1890,7 @@ iperf_defaults(struct iperf_test *testp)
testp->settings->socket_bufsize = 0; /* use autotuning */
testp->settings->blksize = DEFAULT_TCP_BLKSIZE;
testp->settings->rate = 0;
testp->settings->fqrate = 0;
testp->settings->burst = 0;
testp->settings->mss = 0;
testp->settings->bytes = 0;
@ -1881,8 +1982,8 @@ iperf_free_test(struct iperf_test *test)
if (test->server_hostname)
free(test->server_hostname);
if (test->template)
free(test->template);
if (test->tmp_template)
free(test->tmp_template);
if (test->bind_address)
free(test->bind_address);
if (!TAILQ_EMPTY(&test->xbind_addrs)) {
@ -1903,6 +2004,10 @@ iperf_free_test(struct iperf_test *test)
free(test->title);
if (test->congestion)
free(test->congestion);
if (test->congestion_used)
free(test->congestion_used);
if (test->remote_congestion_used)
free(test->remote_congestion_used);
if (test->omit_timer != NULL)
tmr_cancel(test->omit_timer);
if (test->timer != NULL)
@ -2022,6 +2127,10 @@ iperf_reset_test(struct iperf_test *test)
memset(test->cookie, 0, COOKIE_SIZE);
test->multisend = 10; /* arbitrary */
test->udp_counters_64bit = 0;
if (test->title) {
free(test->title);
test->title = NULL;
}
/* Free output line buffers, if any (on the server only) */
struct iperf_textline *t;
@ -2049,11 +2158,12 @@ iperf_reset_stats(struct iperf_test *test)
gettimeofday(&now, NULL);
SLIST_FOREACH(sp, &test->streams, streams) {
sp->omitted_packet_count = sp->packet_count;
sp->omitted_cnt_error = sp->cnt_error;
sp->omitted_outoforder_packets = sp->outoforder_packets;
sp->jitter = 0;
sp->outoforder_packets = 0;
sp->cnt_error = 0;
rp = sp->result;
rp->bytes_sent = rp->bytes_received = 0;
rp->bytes_sent_omit = rp->bytes_sent;
rp->bytes_received = 0;
rp->bytes_sent_this_interval = rp->bytes_received_this_interval = 0;
if (test->sender && test->sender_has_retransmits) {
struct iperf_interval_results ir; /* temporary results structure */
@ -2120,6 +2230,8 @@ iperf_stats_callback(struct iperf_test *test)
}
rp->stream_sum_rtt += temp.rtt;
rp->stream_count_rtt++;
temp.rttvar = get_rttvar(&temp);
}
}
} else {
@ -2234,7 +2346,12 @@ iperf_print_intermediate(struct iperf_test *test)
iprintf(test, report_sum_bw_udp_sender_format, start_time, end_time, ubuf, nbuf, total_packets, test->omitting?report_omitted:"");
} else {
avg_jitter /= test->num_streams;
lost_percent = 100.0 * lost_packets / total_packets;
if (total_packets > 0) {
lost_percent = 100.0 * lost_packets / total_packets;
}
else {
lost_percent = 0.0;
}
if (test->json_output)
cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f lost_packets: %d packets: %d lost_percent: %f omitted: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (double) avg_jitter * 1000.0, (int64_t) lost_packets, (int64_t) total_packets, (double) lost_percent, test->omitting));
else
@ -2263,7 +2380,7 @@ iperf_print_results(struct iperf_test *test)
struct iperf_stream *sp = NULL;
iperf_size_t bytes_sent, total_sent = 0;
iperf_size_t bytes_received, total_received = 0;
double start_time, end_time, avg_jitter = 0.0, lost_percent;
double start_time, end_time = 0.0, avg_jitter = 0.0, lost_percent;
double bandwidth;
/* print final summary for all intervals */
@ -2304,7 +2421,7 @@ iperf_print_results(struct iperf_test *test)
cJSON_AddItemToArray(json_summary_streams, json_summary_stream);
}
bytes_sent = sp->result->bytes_sent;
bytes_sent = sp->result->bytes_sent - sp->result->bytes_sent_omit;
bytes_received = sp->result->bytes_received;
total_sent += bytes_sent;
total_received += bytes_received;
@ -2315,7 +2432,7 @@ iperf_print_results(struct iperf_test *test)
}
} else {
total_packets += (sp->packet_count - sp->omitted_packet_count);
lost_packets += sp->cnt_error;
lost_packets += (sp->cnt_error - sp->omitted_cnt_error);
avg_jitter += sp->jitter;
}
@ -2338,21 +2455,30 @@ iperf_print_results(struct iperf_test *test)
}
} else {
/* Summary, UDP. */
lost_percent = 100.0 * sp->cnt_error / (sp->packet_count - sp->omitted_packet_count);
if (test->json_output)
cJSON_AddItemToObject(json_summary_stream, "udp", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f lost_packets: %d packets: %d lost_percent: %f", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8, (double) sp->jitter * 1000.0, (int64_t) sp->cnt_error, (int64_t) (sp->packet_count - sp->omitted_packet_count), (double) lost_percent));
if (sp->packet_count - sp->omitted_packet_count > 0) {
lost_percent = 100.0 * (sp->cnt_error - sp->omitted_cnt_error) / (sp->packet_count - sp->omitted_packet_count);
}
else {
iprintf(test, report_bw_udp_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->jitter * 1000.0, sp->cnt_error, (sp->packet_count - sp->omitted_packet_count), lost_percent, "");
lost_percent = 0.0;
}
if (test->json_output)
cJSON_AddItemToObject(json_summary_stream, "udp", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f lost_packets: %d packets: %d lost_percent: %f out_of_order: %d", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8, (double) sp->jitter * 1000.0, (int64_t) (sp->cnt_error - sp->omitted_cnt_error), (int64_t) (sp->packet_count - sp->omitted_packet_count), (double) lost_percent, (int64_t) (sp->outoforder_packets - sp->omitted_outoforder_packets)));
else {
iprintf(test, report_bw_udp_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->jitter * 1000.0, (sp->cnt_error - sp->omitted_cnt_error), (sp->packet_count - sp->omitted_packet_count), lost_percent, "");
if (test->role == 'c')
iprintf(test, report_datagrams, sp->socket, (sp->packet_count - sp->omitted_packet_count));
if (sp->outoforder_packets > 0)
iprintf(test, report_sum_outoforder, start_time, end_time, sp->cnt_error);
if ((sp->outoforder_packets - sp->omitted_outoforder_packets) > 0)
iprintf(test, report_sum_outoforder, start_time, end_time, (sp->outoforder_packets - sp->omitted_outoforder_packets));
}
}
if (sp->diskfile_fd >= 0) {
if (fstat(sp->diskfile_fd, &sb) == 0) {
int percent = (int) ( ( (double) bytes_sent / (double) sb.st_size ) * 100.0 );
/* In the odd case that it's a zero-sized file, say it was all transferred. */
int percent = 100;
if (sb.st_size > 0) {
percent = (int) ( ( (double) bytes_sent / (double) sb.st_size ) * 100.0 );
}
unit_snprintf(sbuf, UNIT_LEN, (double) sb.st_size, 'A');
if (test->json_output)
cJSON_AddItemToObject(json_summary_stream, "diskfile", iperf_json_printf("sent: %d size: %d percent: %d filename: %s", (int64_t) bytes_sent, (int64_t) sb.st_size, (int64_t) percent, test->diskfile_name));
@ -2413,12 +2539,12 @@ iperf_print_results(struct iperf_test *test)
} else {
/* Summary sum, UDP. */
avg_jitter /= test->num_streams;
/* If no packets were sent, arbitrarily set loss percentage to 100. */
/* If no packets were sent, arbitrarily set loss percentage to 0. */
if (total_packets > 0) {
lost_percent = 100.0 * lost_packets / total_packets;
}
else {
lost_percent = 100.0;
lost_percent = 0.0;
}
if (test->json_output)
cJSON_AddItemToObject(test->json_end, "sum", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f lost_packets: %d packets: %d lost_percent: %f", (double) start_time, (double) end_time, (double) end_time, (int64_t) total_sent, bandwidth * 8, (double) avg_jitter * 1000.0, (int64_t) lost_packets, (int64_t) total_packets, (double) lost_percent));
@ -2427,11 +2553,47 @@ iperf_print_results(struct iperf_test *test)
}
}
if (test->json_output)
if (test->json_output) {
cJSON_AddItemToObject(test->json_end, "cpu_utilization_percent", iperf_json_printf("host_total: %f host_user: %f host_system: %f remote_total: %f remote_user: %f remote_system: %f", (double) test->cpu_util[0], (double) test->cpu_util[1], (double) test->cpu_util[2], (double) test->remote_cpu_util[0], (double) test->remote_cpu_util[1], (double) test->remote_cpu_util[2]));
if (test->protocol->id == Ptcp) {
char *snd_congestion = NULL, *rcv_congestion = NULL;
if (test->sender) {
snd_congestion = test->congestion_used;
rcv_congestion = test->remote_congestion_used;
}
else {
snd_congestion = test->remote_congestion_used;
rcv_congestion = test->congestion_used;
}
if (snd_congestion) {
cJSON_AddStringToObject(test->json_end, "sender_tcp_congestion", snd_congestion);
}
if (rcv_congestion) {
cJSON_AddStringToObject(test->json_end, "receiver_tcp_congestion", rcv_congestion);
}
}
}
else {
if (test->verbose) {
iprintf(test, report_cpu, report_local, test->sender?report_sender:report_receiver, test->cpu_util[0], test->cpu_util[1], test->cpu_util[2], report_remote, test->sender?report_receiver:report_sender, test->remote_cpu_util[0], test->remote_cpu_util[1], test->remote_cpu_util[2]);
if (test->protocol->id == Ptcp) {
char *snd_congestion = NULL, *rcv_congestion = NULL;
if (test->sender) {
snd_congestion = test->congestion_used;
rcv_congestion = test->remote_congestion_used;
}
else {
snd_congestion = test->remote_congestion_used;
rcv_congestion = test->congestion_used;
}
if (snd_congestion) {
iprintf(test, "snd_tcp_congestion %s\n", snd_congestion);
}
if (rcv_congestion) {
iprintf(test, "rcv_tcp_congestion %s\n", rcv_congestion);
}
}
}
/* Print server output if we're on the client and it was requested/provided */
@ -2520,7 +2682,12 @@ print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON *
}
unit_snprintf(ubuf, UNIT_LEN, (double) (irp->bytes_transferred), 'A');
bandwidth = (double) irp->bytes_transferred / (double) irp->interval_duration;
if (irp->interval_duration > 0.0) {
bandwidth = (double) irp->bytes_transferred / (double) irp->interval_duration;
}
else {
bandwidth = 0.0;
}
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
st = timeval_diff(&sp->result->start_time, &irp->interval_start_time);
@ -2530,7 +2697,7 @@ print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON *
if (test->sender && test->sender_has_retransmits) {
/* Interval, TCP with retransmits. */
if (test->json_output)
cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d snd_cwnd: %d rtt: %d omitted: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (int64_t) irp->interval_retrans, (int64_t) irp->snd_cwnd, (int64_t) irp->rtt, irp->omitted));
cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d snd_cwnd: %d rtt: %d rttvar: %d omitted: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (int64_t) irp->interval_retrans, (int64_t) irp->snd_cwnd, (int64_t) irp->rtt, (int64_t) irp->rttvar, irp->omitted));
else {
unit_snprintf(cbuf, UNIT_LEN, irp->snd_cwnd, 'A');
iprintf(test, report_bw_retrans_cwnd_format, sp->socket, st, et, ubuf, nbuf, irp->interval_retrans, cbuf, irp->omitted?report_omitted:"");
@ -2550,7 +2717,12 @@ print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON *
else
iprintf(test, report_bw_udp_sender_format, sp->socket, st, et, ubuf, nbuf, irp->interval_packet_count, irp->omitted?report_omitted:"");
} else {
lost_percent = 100.0 * irp->interval_cnt_error / irp->interval_packet_count;
if (irp->interval_packet_count > 0) {
lost_percent = 100.0 * irp->interval_cnt_error / irp->interval_packet_count;
}
else {
lost_percent = 0.0;
}
if (test->json_output)
cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f lost_packets: %d packets: %d lost_percent: %f omitted: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (double) irp->jitter * 1000.0, (int64_t) irp->interval_cnt_error, (int64_t) irp->interval_packet_count, (double) lost_percent, irp->omitted));
else
@ -2558,7 +2730,7 @@ print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON *
}
}
if (test->logfile)
if (test->logfile || test->forceflush)
iflush(test);
}
@ -2573,7 +2745,7 @@ iperf_free_stream(struct iperf_stream *sp)
close(sp->buffer_fd);
if (sp->diskfile_fd >= 0)
close(sp->diskfile_fd);
for (irp = TAILQ_FIRST(&sp->result->interval_results); irp != TAILQ_END(sp->result->interval_results); irp = nirp) {
for (irp = TAILQ_FIRST(&sp->result->interval_results); irp != NULL; irp = nirp) {
nirp = TAILQ_NEXT(irp, irlistentries);
free(irp);
}
@ -2591,15 +2763,13 @@ iperf_new_stream(struct iperf_test *test, int s)
struct iperf_stream *sp;
char template[1024];
if (test->template) {
snprintf(template, sizeof(template) / sizeof(char), "%s", test->template);
if (test->tmp_template) {
snprintf(template, sizeof(template) / sizeof(char), "%s", test->tmp_template);
} else {
char buf[] = "/tmp/iperf3.XXXXXX";
snprintf(template, sizeof(template) / sizeof(char), "%s", buf);
}
h_errno = 0;
sp = (struct iperf_stream *) malloc(sizeof(struct iperf_stream));
if (!sp) {
i_errno = IECREATESTREAM;
@ -2865,8 +3035,6 @@ iperf_json_start(struct iperf_test *test)
test->json_top = cJSON_CreateObject();
if (test->json_top == NULL)
return -1;
if (test->title)
cJSON_AddStringToObject(test->json_top, "title", test->title);
test->json_start = cJSON_CreateObject();
if (test->json_start == NULL)
return -1;
@ -2889,6 +3057,8 @@ iperf_json_start(struct iperf_test *test)
int
iperf_json_finish(struct iperf_test *test)
{
if (test->title)
cJSON_AddStringToObject(test->json_top, "title", test->title);
/* Include server output */
if (test->json_server_output) {
cJSON_AddItemToObject(test->json_top, "server_output_json", test->json_server_output);

View File

@ -1,5 +1,5 @@
/*
* iperf, Copyright (c) 2014, The Regents of the University of
* iperf, Copyright (c) 2014-2017, 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.
@ -39,7 +39,7 @@ struct iperf_stream;
#define Ptcp SOCK_STREAM
#define Pudp SOCK_DGRAM
#define Psctp 12
#define DEFAULT_UDP_BLKSIZE 8192
#define DEFAULT_UDP_BLKSIZE 1460 /* default is dynamically set, else this */
#define DEFAULT_TCP_BLKSIZE (128 * 1024) /* default read/write block size */
#define DEFAULT_SCTP_BLKSIZE (64 * 1024)
@ -50,6 +50,10 @@ struct iperf_stream;
#define OPT_UDP_COUNTERS_64BIT 4
#define OPT_CLIENT_PORT 5
#define OPT_NUMSTREAMS 6
#define OPT_FORCEFLUSH 7
#define OPT_NO_FQ_SOCKET_PACING 9 /* UNUSED */
#define OPT_FQ_RATE 10
#define OPT_DSCP 11
/* states */
#define TEST_START 1
@ -114,7 +118,7 @@ void iperf_set_test_socket_bufsize( struct iperf_test* ipt, int socket_bufsize )
void iperf_set_test_num_streams( struct iperf_test* ipt, int num_streams );
void iperf_set_test_role( struct iperf_test* ipt, char role );
void iperf_set_test_server_hostname( struct iperf_test* ipt, char* server_hostname );
void iperf_set_test_template( struct iperf_test *ipt, char *template );
void iperf_set_test_template( struct iperf_test *ipt, char *tmp_template );
void iperf_set_test_reverse( struct iperf_test* ipt, int reverse );
void iperf_set_test_json_output( struct iperf_test* ipt, int json_output );
int iperf_has_zerocopy( void );
@ -161,7 +165,7 @@ void iperf_reporter_callback(struct iperf_test * test);
* returns NULL on failure
*
*/
struct iperf_test *iperf_new_test();
struct iperf_test *iperf_new_test(void);
int iperf_defaults(struct iperf_test * testp);
@ -204,6 +208,7 @@ void save_tcpinfo(struct iperf_stream *sp, struct iperf_interval_results *irp);
long get_total_retransmits(struct iperf_interval_results *irp);
long get_snd_cwnd(struct iperf_interval_results *irp);
long get_rtt(struct iperf_interval_results *irp);
long get_rttvar(struct iperf_interval_results *irp);
void print_tcpinfo(struct iperf_test *test);
void build_tcpinfo_message(struct iperf_interval_results *r, char *message);
@ -213,8 +218,8 @@ int iperf_send(struct iperf_test *, fd_set *) /* __attribute__((hot)) */;
int iperf_recv(struct iperf_test *, fd_set *);
void iperf_catch_sigend(void (*handler)(int));
void iperf_got_sigend(struct iperf_test *test) __attribute__ ((noreturn));
void usage();
void usage_long();
void usage(void);
void usage_long(FILE * f);
void warning(char *);
int iperf_exchange_results(struct iperf_test *);
int iperf_init_test(struct iperf_test *);
@ -288,7 +293,8 @@ enum {
IELOGFILE = 17, // Can't open log file
IENOSCTP = 18, // No SCTP support available
IEBIND = 19, // Local port specified with no local bind option
IEUDPBLOCKSIZE = 20, // Block size too large. Maximum value = %dMAX_UDP_BLOCKSIZE
IEUDPBLOCKSIZE = 20, // Block size invalid
IEBADTOS = 21, // Bad TOS value
/* Test errors */
IENEWTEST = 100, // Unable to create a new test (check perror)
IEINITTEST = 101, // Test initialization failed (check perror)
@ -330,6 +336,8 @@ enum {
IESETSCTPDISABLEFRAG = 137, // Unable to set SCTP Fragmentation (check perror)
IESETSCTPNSTREAM= 138, // Unable to set SCTP number of streams (check perror)
IESETSCTPBINDX= 139, // Unable to process sctp_bindx() parameters
IESETPACING= 140, // Unable to set socket pacing rate
IESETBUF2= 141, // Socket buffer size incorrect (written value != read value)
/* Stream errors */
IECREATESTREAM = 200, // Unable to create a new stream (check herror/perror)
IEINITSTREAM = 201, // Unable to initialize stream (check herror/perror)

View File

@ -1,5 +1,5 @@
/*
* iperf, Copyright (c) 2014, 2015, The Regents of the University of
* iperf, Copyright (c) 2014-2017, 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.
@ -32,6 +32,7 @@
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/uio.h>
#include <arpa/inet.h>
@ -43,6 +44,11 @@
#include "net.h"
#include "timer.h"
#if defined(HAVE_TCP_CONGESTION)
#if !defined(TCP_CA_NAME_MAX)
#define TCP_CA_NAME_MAX 16
#endif /* TCP_CA_NAME_MAX */
#endif /* HAVE_TCP_CONGESTION */
int
iperf_create_streams(struct iperf_test *test)
@ -59,6 +65,31 @@ iperf_create_streams(struct iperf_test *test)
if ((s = test->protocol->connect(test)) < 0)
return -1;
#if defined(HAVE_TCP_CONGESTION)
if (test->protocol->id == Ptcp) {
if (test->congestion) {
if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {
close(s);
i_errno = IESETCONGESTION;
return -1;
}
}
{
socklen_t len = TCP_CA_NAME_MAX;
char ca[TCP_CA_NAME_MAX + 1];
if (getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len) < 0) {
close(s);
i_errno = IESETCONGESTION;
return -1;
}
test->congestion_used = strdup(ca);
if (test->debug) {
printf("Congestion algorithm is %s\n", test->congestion_used);
}
}
}
#endif /* HAVE_TCP_CONGESTION */
if (test->sender)
FD_SET(s, &test->write_set);
else
@ -304,6 +335,61 @@ iperf_connect(struct iperf_test *test)
FD_SET(test->ctrl_sck, &test->read_set);
if (test->ctrl_sck > test->max_fd) test->max_fd = test->ctrl_sck;
int opt;
socklen_t len;
len = sizeof(opt);
if (getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len) < 0) {
test->ctrl_sck_mss = 0;
}
else {
test->ctrl_sck_mss = opt;
}
if (test->verbose) {
printf("Control connection MSS %d\n", test->ctrl_sck_mss);
}
/*
* If we're doing a UDP test and the block size wasn't explicitly
* set, then use the known MSS of the control connection to pick
* an appropriate default. If we weren't able to get the
* MSS for some reason, then default to something that should
* work on non-jumbo-frame Ethernet networks. The goal is to
* pick a reasonable default that is large but should get from
* sender to receiver without any IP fragmentation.
*
* We assume that the control connection is routed the same as the
* data packets (thus has the same PMTU). Also in the case of
* --reverse tests, we assume that the MTU is the same in both
* directions. Note that even if the algorithm guesses wrong,
* the user always has the option to override.
*/
if (test->protocol->id == Pudp) {
if (test->settings->blksize == 0) {
if (test->ctrl_sck_mss) {
test->settings->blksize = test->ctrl_sck_mss;
}
else {
test->settings->blksize = DEFAULT_UDP_BLKSIZE;
}
if (test->verbose) {
printf("Setting UDP block size to %d\n", test->settings->blksize);
}
}
/*
* Regardless of whether explicitly or implicitly set, if the
* block size is larger than the MSS, print a warning.
*/
if (test->settings->blksize > test->ctrl_sck_mss) {
char str[128];
snprintf(str, sizeof(str),
"Warning: UDP block size %d exceeds TCP MSS %d, may result in fragmentation / drops", test->settings->blksize, test->ctrl_sck_mss);
warning(str);
}
}
return 0;
}

View File

@ -30,6 +30,9 @@
/* Define to 1 if you have the `sendfile' function. */
#undef HAVE_SENDFILE
/* Have SO_MAX_PACING_RATE sockopt. */
#undef HAVE_SO_MAX_PACING_RATE
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H

View File

@ -1,5 +1,5 @@
/*
* iperf, Copyright (c) 2014, The Regents of the University of
* iperf, Copyright (c) 2014, 2015, 2016, 2017, 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.
@ -74,14 +74,15 @@ iperf_errexit(struct iperf_test *test, const char *format, ...)
fprintf(stderr, "iperf3: %s\n", str);
}
va_end(argp);
iperf_delete_pidfile(test);
if (test)
iperf_delete_pidfile(test);
exit(1);
}
int i_errno;
char *
iperf_strerror(int i_errno)
iperf_strerror(int int_errno)
{
static char errstr[256];
int len, perr, herr;
@ -90,7 +91,7 @@ iperf_strerror(int i_errno)
len = sizeof(errstr);
memset(errstr, 0, len);
switch (i_errno) {
switch (int_errno) {
case IENONE:
snprintf(errstr, len, "no error");
break;
@ -125,8 +126,11 @@ iperf_strerror(int i_errno)
snprintf(errstr, len, "--bind must be specified to use --cport");
break;
case IEUDPBLOCKSIZE:
snprintf(errstr, len, "block size too large (maximum = %d bytes)", MAX_UDP_BLOCKSIZE);
snprintf(errstr, len, "block size invalid (minimum = %d bytes, maximum = %d bytes)", MIN_UDP_BLOCKSIZE, MAX_UDP_BLOCKSIZE);
break;
case IEBADTOS:
snprintf(errstr, len, "bad TOS value (must be between 0 and 255 inclusive)");
break;
case IEMSS:
snprintf(errstr, len, "TCP MSS too large (maximum = %d bytes)", MAX_MSS);
break;
@ -351,15 +355,20 @@ iperf_strerror(int i_errno)
snprintf(errstr, len, "unable to set SCTP_INIT num of SCTP streams\n");
perr = 1;
break;
case IESETPACING:
snprintf(errstr, len, "unable to set socket pacing");
perr = 1;
break;
case IESETBUF2:
snprintf(errstr, len, "socket buffer size not set correctly");
break;
}
if (herr || perr)
strncat(errstr, ": ", len - strlen(errstr) - 1);
if (h_errno && herr) {
strncat(errstr, hstrerror(h_errno), len - strlen(errstr) - 1);
} else if (errno && perr) {
if (errno && perr)
strncat(errstr, strerror(errno), len - strlen(errstr) - 1);
}
return errstr;
}

View File

@ -1,5 +1,5 @@
/*---------------------------------------------------------------
* iperf, Copyright (c) 2014, The Regents of the University of
* iperf, Copyright (c) 2014, 2016, 2017, 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.
@ -91,11 +91,11 @@ extern "C"
* usage
* ------------------------------------------------------------------- */
const char usage_shortstr[] = "Usage: iperf [-s|-c host] [options]\n"
"Try `iperf --help' for more information.\n";
const char usage_shortstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
"Try `iperf3 --help' for more information.\n";
const char usage_longstr[] = "Usage: iperf [-s|-c host] [options]\n"
" iperf [-h|--help] [-v|--version]\n\n"
const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
" iperf3 [-h|--help] [-v|--version]\n\n"
"Server or Client:\n"
" -p, --port # server port to listen on/connect to\n"
" -f, --format [kmgKMG] format to report: Kbits, Mbits, KBytes, MBytes\n"
@ -108,6 +108,7 @@ const char usage_longstr[] = "Usage: iperf [-s|-c host] [options]\n"
" -V, --verbose more detailed output\n"
" -J, --json output in JSON format\n"
" --logfile f send output to a log file\n"
" --forceflush force flushing output at every interval\n"
" -d, --debug emit debugging output\n"
" -v, --version show version information and quit\n"
" -h, --help show this message and quit\n"
@ -127,11 +128,15 @@ const char usage_longstr[] = "Usage: iperf [-s|-c host] [options]\n"
" -b, --bandwidth #[KMG][/#] target bandwidth in bits/sec (0 for unlimited)\n"
" (default %d Mbit/sec for UDP, unlimited for TCP)\n"
" (optional slash and packet count for burst mode)\n"
#if defined(HAVE_SO_MAX_PACING_RATE)
" --fq-rate #[KMG] enable fair-queuing based socket pacing in\n"
" bits/sec (Linux only)\n"
#endif
" -t, --time # time in seconds to transmit for (default %d secs)\n"
" -n, --bytes #[KMG] number of bytes to transmit (instead of -t)\n"
" -k, --blockcount #[KMG] number of blocks (packets) to transmit (instead of -t or -n)\n"
" -l, --len #[KMG] length of buffer to read or write\n"
" (default %d KB for TCP, %d KB for UDP)\n"
" (default %d KB for TCP, dynamic or %d for UDP)\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"
@ -143,7 +148,8 @@ const char usage_longstr[] = "Usage: iperf [-s|-c host] [options]\n"
" -N, --no-delay set TCP/SCTP no delay, disabling Nagle's Algorithm\n"
" -4, --version4 only use IPv4\n"
" -6, --version6 only use IPv6\n"
" -S, --tos N set the IP 'type of service'\n"
" -S, --tos N set the IP type of service, 0-255\n"
" --dscp N or --dscp val set the IP dscp value, either 0-63 or symbolic\n"
#if defined(HAVE_FLOWLABEL)
" -L, --flowlabel N set the IPv6 flow label (only supported on Linux)\n"
#endif /* HAVE_FLOWLABEL */

View File

@ -35,7 +35,6 @@
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <sys/time.h>
#include <sys/select.h>

View File

@ -1,5 +1,5 @@
/*
* iperf, Copyright (c) 2014, 2015, The Regents of the University of
* iperf, Copyright (c) 2014, 2015, 2016, 2017, 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.
@ -44,7 +44,6 @@
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <netinet/tcp.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sched.h>
@ -62,6 +61,11 @@
#include "iperf_util.h"
#include "iperf_locale.h"
#if defined(HAVE_TCP_CONGESTION)
#if !defined(TCP_CA_NAME_MAX)
#define TCP_CA_NAME_MAX 16
#endif /* TCP_CA_NAME_MAX */
#endif /* HAVE_TCP_CONGESTION */
int
iperf_server_listen(struct iperf_test *test)
@ -311,6 +315,26 @@ iperf_test_reset(struct iperf_test *test)
memset(test->cookie, 0, COOKIE_SIZE);
}
static void
server_timer_proc(TimerClientData client_data, struct timeval *nowP)
{
struct iperf_test *test = client_data.p;
struct iperf_stream *sp;
test->timer = NULL;
if (test->done)
return;
test->done = 1;
/* Free streams */
while (!SLIST_EMPTY(&test->streams)) {
sp = SLIST_FIRST(&test->streams);
SLIST_REMOVE_HEAD(&test->streams, streams);
close(sp->socket);
iperf_free_stream(sp);
}
close(test->ctrl_sck);
}
static void
server_stats_timer_proc(TimerClientData client_data, struct timeval *nowP)
{
@ -344,6 +368,16 @@ create_server_timers(struct iperf_test * test)
return -1;
}
cd.p = test;
test->timer = test->stats_timer = test->reporter_timer = NULL;
if (test->duration != 0 ) {
test->done = 0;
test->timer = tmr_create(&now, server_timer_proc, cd, (test->duration + test->omit + 5) * SEC_TO_US, 0);
if (test->timer == NULL) {
i_errno = IEINITTEST;
return -1;
}
}
test->stats_timer = test->reporter_timer = NULL;
if (test->stats_interval != 0) {
test->stats_timer = tmr_create(&now, server_stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1);
@ -410,8 +444,12 @@ static void
cleanup_server(struct iperf_test *test)
{
/* Close open test sockets */
close(test->ctrl_sck);
close(test->listener);
if (test->ctrl_sck) {
close(test->ctrl_sck);
}
if (test->listener) {
close(test->listener);
}
/* Cancel any remaining timers. */
if (test->stats_timer != NULL) {
@ -426,6 +464,14 @@ cleanup_server(struct iperf_test *test)
tmr_cancel(test->omit_timer);
test->omit_timer = NULL;
}
if (test->congestion_used != NULL) {
free(test->congestion_used);
test->congestion_used = NULL;
}
if (test->timer != NULL) {
tmr_cancel(test->timer);
test->timer = NULL;
}
}
@ -440,11 +486,11 @@ iperf_run_server(struct iperf_test *test)
if (test->affinity != -1)
if (iperf_setaffinity(test, test->affinity) != 0)
return -1;
return -2;
if (test->json_output)
if (iperf_json_start(test) < 0)
return -1;
return -2;
if (test->json_output) {
cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version));
@ -458,7 +504,7 @@ iperf_run_server(struct iperf_test *test)
// Open socket and listen
if (iperf_server_listen(test) < 0) {
return -1;
return -2;
}
// Begin calculating CPU utilization
@ -506,6 +552,47 @@ iperf_run_server(struct iperf_test *test)
return -1;
}
#if defined(HAVE_TCP_CONGESTION)
if (test->protocol->id == Ptcp) {
if (test->congestion) {
if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {
/*
* ENOENT means we tried to set the
* congestion algorithm but the algorithm
* specified doesn't exist. This can happen
* if the client and server have different
* congestion algorithms available. In this
* case, print a warning, but otherwise
* continue.
*/
if (errno == ENOENT) {
warning("TCP congestion control algorithm not supported");
}
else {
close(s);
cleanup_server(test);
i_errno = IESETCONGESTION;
return -1;
}
}
}
{
socklen_t len = TCP_CA_NAME_MAX;
char ca[TCP_CA_NAME_MAX + 1];
if (getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len) < 0) {
close(s);
cleanup_server(test);
i_errno = IESETCONGESTION;
return -1;
}
test->congestion_used = strdup(ca);
if (test->debug) {
printf("Congestion algorithm is %s\n", test->congestion_used);
}
}
}
#endif /* HAVE_TCP_CONGESTION */
if (!is_closed(s)) {
sp = iperf_new_stream(test, s);
if (!sp) {
@ -545,6 +632,7 @@ iperf_run_server(struct iperf_test *test)
if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
FD_CLR(test->listener, &test->read_set);
close(test->listener);
test->listener = 0;
if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {
cleanup_server(test);
i_errno = IELISTEN;

View File

@ -1,5 +1,5 @@
/*
* iperf, Copyright (c) 2014, The Regents of the University of
* iperf, Copyright (c) 2014, 2016, 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.
@ -35,7 +35,6 @@
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <sys/time.h>
#include <sys/select.h>
@ -235,16 +234,29 @@ iperf_tcp_listen(struct iperf_test *test)
}
printf("SO_SNDBUF is %u\n", opt);
}
#if defined(HAVE_TCP_CONGESTION)
if (test->congestion) {
if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {
close(s);
freeaddrinfo(res);
i_errno = IESETCONGESTION;
return -1;
}
#if defined(HAVE_SO_MAX_PACING_RATE)
/* If fq socket pacing is specified, enable it. */
if (test->settings->fqrate) {
/* Convert bits per second to bytes per second */
unsigned int fqrate = test->settings->fqrate / 8;
if (fqrate > 0) {
if (test->debug) {
printf("Setting fair-queue socket pacing to %u\n", fqrate);
}
if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) {
warning("Unable to set socket pacing");
}
}
#endif /* HAVE_TCP_CONGESTION */
}
#endif /* HAVE_SO_MAX_PACING_RATE */
{
unsigned int rate = test->settings->rate / 8;
if (rate > 0) {
if (test->debug) {
printf("Setting application pacing to %u\n", rate);
}
}
}
opt = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
saved_errno = errno;
@ -311,6 +323,7 @@ iperf_tcp_connect(struct iperf_test *test)
struct addrinfo hints, *local_res, *server_res;
char portstr[6];
int s, opt;
socklen_t optlen;
int saved_errno;
if (test->bind_address) {
@ -400,18 +413,43 @@ iperf_tcp_connect(struct iperf_test *test)
return -1;
}
}
if (test->debug) {
socklen_t optlen = sizeof(opt);
if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, &optlen) < 0) {
saved_errno = errno;
close(s);
freeaddrinfo(server_res);
errno = saved_errno;
i_errno = IESETBUF;
return -1;
}
printf("SO_SNDBUF is %u\n", opt);
/* Read back and verify the sender socket buffer size */
optlen = sizeof(opt);
if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, &optlen) < 0) {
saved_errno = errno;
close(s);
freeaddrinfo(server_res);
errno = saved_errno;
i_errno = IESETBUF;
return -1;
}
if (test->debug) {
printf("SNDBUF is %u, expecting %u\n", opt, test->settings->socket_bufsize);
}
if (test->settings->socket_bufsize && test->settings->socket_bufsize > opt) {
i_errno = IESETBUF2;
return -1;
}
/* Read back and verify the receiver socket buffer size */
optlen = sizeof(opt);
if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, &optlen) < 0) {
saved_errno = errno;
close(s);
freeaddrinfo(server_res);
errno = saved_errno;
i_errno = IESETBUF;
return -1;
}
if (test->debug) {
printf("RCVBUF is %u, expecting %u\n", opt, test->settings->socket_bufsize);
}
if (test->settings->socket_bufsize && test->settings->socket_bufsize > opt) {
i_errno = IESETBUF2;
return -1;
}
#if defined(HAVE_FLOWLABEL)
if (test->settings->flowlabel) {
if (server_res->ai_addr->sa_family != AF_INET6) {
@ -457,16 +495,29 @@ iperf_tcp_connect(struct iperf_test *test)
}
#endif /* HAVE_FLOWLABEL */
#if defined(HAVE_TCP_CONGESTION)
if (test->congestion) {
if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {
close(s);
freeaddrinfo(server_res);
i_errno = IESETCONGESTION;
return -1;
#if defined(HAVE_SO_MAX_PACING_RATE)
/* If socket pacing is specified try to enable it. */
if (test->settings->fqrate) {
/* Convert bits per second to bytes per second */
unsigned int fqrate = test->settings->fqrate / 8;
if (fqrate > 0) {
if (test->debug) {
printf("Setting fair-queue socket pacing to %u\n", fqrate);
}
if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) {
warning("Unable to set socket pacing");
}
}
}
#endif /* HAVE_SO_MAX_PACING_RATE */
{
unsigned int rate = test->settings->rate / 8;
if (rate > 0) {
if (test->debug) {
printf("Setting application pacing to %u\n", rate);
}
}
}
#endif /* HAVE_TCP_CONGESTION */
if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) {
saved_errno = errno;

View File

@ -1,5 +1,5 @@
/*
* iperf, Copyright (c) 2014, The Regents of the University of
* iperf, Copyright (c) 2014, 2016, 2017, 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.
@ -193,6 +193,80 @@ iperf_udp_send(struct iperf_stream *sp)
* connection knows about each other before the real data transfers begin.
*/
/*
* Set and verify socket buffer sizes.
* Return 0 if no error, -1 if an error, +1 if socket buffers are
* potentially too small to hold a message.
*/
int
iperf_udp_buffercheck(struct iperf_test *test, int s)
{
int rc = 0;
/*
* Set socket buffer size if requested. Do this for both sending and
* receiving so that we can cover both normal and --reverse operation.
*/
int opt;
socklen_t optlen;
if ((opt = test->settings->socket_bufsize)) {
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
i_errno = IESETBUF;
return -1;
}
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
i_errno = IESETBUF;
return -1;
}
}
/* Read back and verify the sender socket buffer size */
optlen = sizeof(opt);
if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, &optlen) < 0) {
i_errno = IESETBUF;
return -1;
}
if (test->debug) {
printf("SNDBUF is %u, expecting %u\n", opt, test->settings->socket_bufsize);
}
if (test->settings->socket_bufsize && test->settings->socket_bufsize > opt) {
i_errno = IESETBUF2;
return -1;
}
if (test->settings->blksize > opt) {
char str[80];
snprintf(str, sizeof(str),
"Block size %d > sending socket buffer size %d",
test->settings->blksize, opt);
warning(str);
rc = 1;
}
/* Read back and verify the receiver socket buffer size */
optlen = sizeof(opt);
if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, &optlen) < 0) {
i_errno = IESETBUF;
return -1;
}
if (test->debug) {
printf("RCVBUF is %u, expecting %u\n", opt, test->settings->socket_bufsize);
}
if (test->settings->socket_bufsize && test->settings->socket_bufsize > opt) {
i_errno = IESETBUF2;
return -1;
}
if (test->settings->blksize > opt) {
char str[80];
snprintf(str, sizeof(str),
"Block size %d > receiving socket buffer size %d",
test->settings->blksize, opt);
warning(str);
rc = 1;
}
return rc;
}
/*
* iperf_udp_accept
*
@ -205,6 +279,7 @@ iperf_udp_accept(struct iperf_test *test)
int buf;
socklen_t len;
int sz, s;
int rc;
/*
* Get the current outstanding socket. This socket will be used to handle
@ -228,20 +303,49 @@ iperf_udp_accept(struct iperf_test *test)
return -1;
}
/* Check and set socket buffer sizes */
rc = iperf_udp_buffercheck(test, s);
if (rc < 0)
/* error */
return rc;
/*
* Set socket buffer size if requested. Do this for both sending and
* receiving so that we can cover both normal and --reverse operation.
* If the socket buffer was too small, but it was the default
* size, then try explicitly setting it to something larger.
*/
int opt;
if ((opt = test->settings->socket_bufsize)) {
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
i_errno = IESETBUF;
return -1;
}
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
i_errno = IESETBUF;
return -1;
}
if (rc > 0) {
if (test->settings->socket_bufsize == 0) {
int bufsize = test->settings->blksize + UDP_BUFFER_EXTRA;
printf("Increasing socket buffer size to %d\n",
bufsize);
test->settings->socket_bufsize = bufsize;
rc = iperf_udp_buffercheck(test, s);
if (rc < 0)
return rc;
}
}
#if defined(HAVE_SO_MAX_PACING_RATE)
/* If socket pacing is specified, try it. */
if (test->settings->fqrate) {
/* Convert bits per second to bytes per second */
unsigned int fqrate = test->settings->fqrate / 8;
if (fqrate > 0) {
if (test->debug) {
printf("Setting fair-queue socket pacing to %u\n", fqrate);
}
if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) {
warning("Unable to set socket pacing");
}
}
}
#endif /* HAVE_SO_MAX_PACING_RATE */
{
unsigned int rate = test->settings->rate / 8;
if (rate > 0) {
if (test->debug) {
printf("Setting application pacing to %u\n", rate);
}
}
}
/*
@ -303,6 +407,7 @@ iperf_udp_connect(struct iperf_test *test)
#ifdef SO_RCVTIMEO
struct timeval tv;
#endif
int rc;
/* Create and bind our local socket. */
if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->bind_port, test->server_hostname, test->server_port)) < 0) {
@ -310,20 +415,49 @@ iperf_udp_connect(struct iperf_test *test)
return -1;
}
/* Check and set socket buffer sizes */
rc = iperf_udp_buffercheck(test, s);
if (rc < 0)
/* error */
return rc;
/*
* Set socket buffer size if requested. Do this for both sending and
* receiving so that we can cover both normal and --reverse operation.
* If the socket buffer was too small, but it was the default
* size, then try explicitly setting it to something larger.
*/
int opt;
if ((opt = test->settings->socket_bufsize)) {
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
i_errno = IESETBUF;
return -1;
}
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
i_errno = IESETBUF;
return -1;
}
if (rc > 0) {
if (test->settings->socket_bufsize == 0) {
int bufsize = test->settings->blksize + UDP_BUFFER_EXTRA;
printf("Increasing socket buffer size to %d\n",
bufsize);
test->settings->socket_bufsize = bufsize;
rc = iperf_udp_buffercheck(test, s);
if (rc < 0)
return rc;
}
}
#if defined(HAVE_SO_MAX_PACING_RATE)
/* If socket pacing is available and not disabled, try it. */
if (test->settings->fqrate) {
/* Convert bits per second to bytes per second */
unsigned int fqrate = test->settings->fqrate / 8;
if (fqrate > 0) {
if (test->debug) {
printf("Setting fair-queue socket pacing to %u\n", fqrate);
}
if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) {
warning("Unable to set socket pacing");
}
}
}
#endif /* HAVE_SO_MAX_PACING_RATE */
{
unsigned int rate = test->settings->rate / 8;
if (rate > 0) {
if (test->debug) {
printf("Setting application pacing to %u\n", rate);
}
}
}
#ifdef SO_RCVTIMEO

View File

@ -1,5 +1,5 @@
/*
* iperf, Copyright (c) 2014, The Regents of the University of
* iperf, Copyright (c) 2014, 2016, 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.
@ -285,6 +285,16 @@ get_optional_features(void)
numfeatures++;
#endif /* HAVE_SENDFILE */
#if defined(HAVE_SO_MAX_PACING_RATE)
if (numfeatures > 0) {
strncat(features, ", ",
sizeof(features) - strlen(features) - 1);
}
strncat(features, "socket pacing",
sizeof(features) - strlen(features) - 1);
numfeatures++;
#endif /* HAVE_SO_MAX_PACING_RATE */
if (numfeatures == 0) {
strncat(features, "None",
sizeof(features) - strlen(features) - 1);
@ -340,19 +350,22 @@ iperf_json_printf(const char *format, ...)
j = cJSON_CreateBool(va_arg(argp, int));
break;
case 'd':
j = cJSON_CreateInt(va_arg(argp, int64_t));
j = cJSON_CreateNumber(va_arg(argp, int64_t));
break;
case 'f':
j = cJSON_CreateFloat(va_arg(argp, double));
j = cJSON_CreateNumber(va_arg(argp, double));
break;
case 's':
j = cJSON_CreateString(va_arg(argp, char *));
break;
default:
va_end(argp);
return NULL;
}
if (j == NULL)
return NULL;
if (j == NULL) {
va_end(argp);
return NULL;
}
cJSON_AddItemToObject(o, name, j);
np = name;
break;

View File

@ -5,7 +5,7 @@ libiperf \- API for iperf3 network throughput tester
.SH SYNOPSIS
#include <iperf_api.h>
.br
-liperf
\-liperf
.SH DESCRIPTION
.PP

View File

@ -1,5 +1,5 @@
/*
* iperf, Copyright (c) 2014, The Regents of the University of
* iperf, Copyright (c) 2014, 2015, 2017, 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.
@ -41,10 +41,6 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <netinet/tcp.h>
#include "iperf.h"
#include "iperf_api.h"
@ -104,7 +100,7 @@ main(int argc, char **argv)
if (iperf_parse_arguments(test, argc, argv) < 0) {
iperf_err(test, "parameter error - %s", iperf_strerror(i_errno));
fprintf(stderr, "\n");
usage_long();
usage_long(stdout);
exit(1);
}
@ -119,7 +115,7 @@ main(int argc, char **argv)
static jmp_buf sigend_jmp_buf;
static void
static void __attribute__ ((noreturn))
sigend_handler(int sig)
{
longjmp(sigend_jmp_buf, 1);
@ -129,13 +125,14 @@ sigend_handler(int sig)
static int
run(struct iperf_test *test)
{
int consecutive_errors;
/* Termination signals. */
iperf_catch_sigend(sigend_handler);
if (setjmp(sigend_jmp_buf))
iperf_got_sigend(test);
/* Ignore SIGPIPE to simplify error handling */
signal(SIGPIPE, SIG_IGN);
switch (test->role) {
case 's':
if (test->daemon) {
@ -145,22 +142,19 @@ run(struct iperf_test *test)
iperf_errexit(test, "error - %s", iperf_strerror(i_errno));
}
}
consecutive_errors = 0;
if (iperf_create_pidfile(test) < 0) {
i_errno = IEPIDFILE;
iperf_errexit(test, "error - %s", iperf_strerror(i_errno));
}
for (;;) {
if (iperf_run_server(test) < 0) {
int rc;
rc = iperf_run_server(test);
if (rc < 0) {
iperf_err(test, "error - %s", iperf_strerror(i_errno));
fprintf(stderr, "\n");
++consecutive_errors;
if (consecutive_errors >= 5) {
fprintf(stderr, "too many errors, exiting\n");
break;
if (rc < -1) {
iperf_errexit(test, "exiting");
}
} else
consecutive_errors = 0;
}
iperf_reset_test(test);
if (iperf_get_test_one_off(test))
break;
@ -177,6 +171,7 @@ run(struct iperf_test *test)
}
iperf_catch_sigend(SIG_DFL);
signal(SIGPIPE, SIG_DFL);
return 0;
}

View File

@ -37,6 +37,7 @@ int getsock_tcp_mss(int inSock);
int set_tcp_options(int sock, int no_delay, int mss);
int setnonblocking(int fd, int nonblocking);
int getsockdomain(int sock);
int parse_qos(const char *tos);
#define NET_SOFTERROR -1
#define NET_HARDERROR -2

View File

@ -24,6 +24,11 @@
* This code is distributed under a BSD style license, see the LICENSE
* file for complete information.
*/
#include "iperf_config.h"
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

View File

@ -1,5 +1,5 @@
/*
* iperf, Copyright (c) 2014, The Regents of the University of
* iperf, Copyright (c) 2014, 2017, 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.
@ -45,20 +45,13 @@ main(int argc, char **argv)
assert(1024.0 == unit_atof("1K"));
assert(1024.0 * 1024.0 == unit_atof("1M"));
assert(4.0 * 1024.0 * 1024.0 * 1024.0 == unit_atof("4G"));
assert(3.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 == unit_atof("3T"));
#ifdef notdef
/* Obsolete - we no longer make a distinction between upper and lower
** case.
*/
assert(1000.0 * 0.5 == unit_atof("0.5k"));
assert(1000.0 == unit_atof("1k"));
assert(1000.0 * 1000.0 == unit_atof("1m"));
assert(4.0 * 1000.0 * 1000.0 * 1000.0 == unit_atof("4g"));
#endif
assert(1024.0 * 0.5 == unit_atof("0.5k"));
assert(1024.0 == unit_atof("1k"));
assert(1024.0 * 1024.0 == unit_atof("1m"));
assert(4.0 * 1024.0 * 1024.0 * 1024.0 == unit_atof("4g"));
assert(3.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 == unit_atof("3t"));
assert(1024 * 0.5 == unit_atoi("0.5K"));
assert(1024 == unit_atoi("1K"));
@ -66,22 +59,19 @@ main(int argc, char **argv)
d = 4.0 * 1024 * 1024 * 1024;
llu = (iperf_size_t) d;
assert(llu == unit_atoi("4G"));
#ifdef notdef
/* Also obsolete. */
assert(1000 * 0.5 == unit_atoi("0.5k"));
assert(1000 == unit_atoi("1k"));
assert(1000 * 1000 == unit_atoi("1m"));
d = 4.0 * 1000 * 1000 * 1000;
d = 3.0 * 1024 * 1024 * 1024 * 1024;
llu = (iperf_size_t) d;
assert(llu == unit_atoi("4g"));
#endif
assert(llu == unit_atoi("3T"));
assert(1024 * 0.5 == unit_atoi("0.5k"));
assert(1024 == unit_atoi("1k"));
assert(1024 * 1024 == unit_atoi("1m"));
d = 4.0 * 1024 * 1024 * 1024;
llu = (iperf_size_t) d;
assert(llu == unit_atoi("4g"));
d = 3.0 * 1024 * 1024 * 1024 * 1024;
llu = (iperf_size_t) d;
assert(llu == unit_atoi("3t"));
unit_snprintf(s, 11, 1024.0, 'A');
assert(strncmp(s, "1.00 KByte", 11) == 0);
@ -102,5 +92,12 @@ main(int argc, char **argv)
unit_snprintf(s, 11, d, 'a');
assert(strncmp(s, "34.4 Gbit", 11) == 0);
d = 4.0 * 1024 * 1024 * 1024 * 1024;
unit_snprintf(s, 11, d, 'A');
assert(strncmp(s, "4.00 TByte", 11) == 0);
unit_snprintf(s, 11, d, 'a');
assert(strncmp(s, "35.2 Tbit", 11) == 0);
return 0;
}

View File

@ -48,7 +48,6 @@
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>
@ -136,7 +135,7 @@ get_snd_cwnd(struct iperf_interval_results *irp)
#if defined(linux) && defined(TCP_MD5SIG)
return irp->tcpInfo.tcpi_snd_cwnd * irp->tcpInfo.tcpi_snd_mss;
#elif defined(__FreeBSD__) && __FreeBSD_version >= 600000
return irp->tcpInfo.tcpi_snd_cwnd * irp->tcpInfo.tcpi_snd_mss;
return irp->tcpInfo.tcpi_snd_cwnd;
#elif defined(__NetBSD__) && defined(TCP_INFO)
return irp->tcpInfo.tcpi_snd_cwnd * irp->tcpInfo.tcpi_snd_mss;
#else
@ -162,6 +161,24 @@ get_rtt(struct iperf_interval_results *irp)
#endif
}
/*************************************************************/
/*
* Return rttvar in usec.
*/
long
get_rttvar(struct iperf_interval_results *irp)
{
#if defined(linux) && defined(TCP_MD5SIG)
return irp->tcpInfo.tcpi_rttvar;
#elif defined(__FreeBSD__) && __FreeBSD_version >= 600000
return irp->tcpInfo.tcpi_rttvar;
#elif defined(__NetBSD__) && defined(TCP_INFO)
return irp->tcpInfo.tcpi_rttvar;
#else
return -1;
#endif
}
/*************************************************************/
void
build_tcpinfo_message(struct iperf_interval_results *r, char *message)

View File

@ -48,7 +48,7 @@
* by Mark Gates <mgates@nlanr.net>
* and Ajay Tirumalla <tirumala@ncsa.uiuc.edu>
* -------------------------------------------------------------------
* input and output numbers, converting with kilo, mega, giga
* input and output numbers, converting with kilo, mega, giga, tera
* ------------------------------------------------------------------- */
#include <stdio.h>
@ -60,7 +60,6 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/tcp.h>
#include "iperf.h"
@ -70,13 +69,15 @@ extern "C"
{
#endif
const long KILO_UNIT = 1024;
const long MEGA_UNIT = 1024 * 1024;
const long GIGA_UNIT = 1024 * 1024 * 1024;
const double KILO_UNIT = 1024.0;
const double MEGA_UNIT = 1024.0 * 1024.0;
const double GIGA_UNIT = 1024.0 * 1024.0 * 1024.0;
const double TERA_UNIT = 1024.0 * 1024.0 * 1024.0 * 1024.0;
const long KILO_RATE_UNIT = 1000;
const long MEGA_RATE_UNIT = 1000 * 1000;
const long GIGA_RATE_UNIT = 1000 * 1000 * 1000;
const double KILO_RATE_UNIT = 1000.0;
const double MEGA_RATE_UNIT = 1000.0 * 1000.0;
const double GIGA_RATE_UNIT = 1000.0 * 1000.0 * 1000.0;
const double TERA_RATE_UNIT = 1000.0 * 1000.0 * 1000.0 * 1000.0;
/* -------------------------------------------------------------------
* unit_atof
@ -96,9 +97,12 @@ extern "C"
/* scan the number and any suffices */
sscanf(s, "%lf%c", &n, &suffix);
/* convert according to [Gg Mm Kk] */
/* convert according to [Tt Gg Mm Kk] */
switch (suffix)
{
case 't': case 'T':
n *= TERA_UNIT;
break;
case 'g': case 'G':
n *= GIGA_UNIT;
break;
@ -132,9 +136,12 @@ extern "C"
/* scan the number and any suffices */
sscanf(s, "%lf%c", &n, &suffix);
/* convert according to [Gg Mm Kk] */
/* convert according to [Tt Gg Mm Kk] */
switch (suffix)
{
case 't': case 'T':
n *= TERA_RATE_UNIT;
break;
case 'g': case 'G':
n *= GIGA_RATE_UNIT;
break;
@ -157,7 +164,7 @@ extern "C"
*
* Given a string of form #x where # is a number and x is a format
* character listed below, this returns the interpreted integer.
* Gg, Mm, Kk are giga, mega, kilo respectively
* Tt, Gg, Mm, Kk are tera, giga, mega, kilo respectively
* ------------------------------------------------------------------- */
iperf_size_t unit_atoi(const char *s)
@ -170,9 +177,12 @@ extern "C"
/* scan the number and any suffices */
sscanf(s, "%lf%c", &n, &suffix);
/* convert according to [Gg Mm Kk] */
/* convert according to [Tt Gg Mm Kk] */
switch (suffix)
{
case 't': case 'T':
n *= TERA_UNIT;
break;
case 'g': case 'G':
n *= GIGA_UNIT;
break;
@ -198,7 +208,8 @@ extern "C"
UNIT_CONV,
KILO_CONV,
MEGA_CONV,
GIGA_CONV
GIGA_CONV,
TERA_CONV
};
/* factor to multiply the number by */
@ -207,7 +218,8 @@ extern "C"
1.0, /* unit */
1.0 / 1024, /* kilo */
1.0 / 1024 / 1024, /* mega */
1.0 / 1024 / 1024 / 1024/* giga */
1.0 / 1024 / 1024 / 1024, /* giga */
1.0 / 1024 / 1024 / 1024 / 1024 /* tera */
};
/* factor to multiply the number by for bits*/
@ -216,26 +228,29 @@ extern "C"
1.0, /* unit */
1.0 / 1000, /* kilo */
1.0 / 1000 / 1000, /* mega */
1.0 / 1000 / 1000 / 1000/* giga */
1.0 / 1000 / 1000 / 1000, /* giga */
1.0 / 1000 / 1000 / 1000 / 1000 /* tera */
};
/* labels for Byte formats [KMG] */
/* labels for Byte formats [KMGT] */
const char *label_byte[] =
{
"Byte",
"KByte",
"MByte",
"GByte"
"GByte",
"TByte"
};
/* labels for bit formats [kmg] */
/* labels for bit formats [kmgt] */
const char *label_bit[] =
{
"bit",
"Kbit",
"Mbit",
"Gbit"
"Gbit",
"Tbit"
};
/* -------------------------------------------------------------------
@ -276,6 +291,9 @@ extern "C"
case 'G':
conv = GIGA_CONV;
break;
case 'T':
conv = TERA_CONV;
break;
default:
case 'A':
@ -285,14 +303,14 @@ extern "C"
if (isupper((int) inFormat))
{
while (tmpNum >= 1024.0 && conv <= GIGA_CONV)
while (tmpNum >= 1024.0 && conv <= TERA_CONV)
{
tmpNum /= 1024.0;
conv++;
}
} else
{
while (tmpNum >= 1000.0 && conv <= GIGA_CONV)
while (tmpNum >= 1000.0 && conv <= TERA_CONV)
{
tmpNum /= 1000.0;
conv++;