diff --git a/src/iperf.h b/src/iperf.h index 61ba696..0fb0846 100644 --- a/src/iperf.h +++ b/src/iperf.h @@ -69,7 +69,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, UDP only */ + uint64_t rate; /* target data rate */ + int burst; /* packets per burst */ int mss; /* for TCP MSS */ int ttl; /* IP TTL option */ int tos; /* type of service bit */ @@ -234,6 +235,7 @@ struct iperf_test #define MIN_INTERVAL 0.1 #define MAX_INTERVAL 60.0 #define MAX_TIME 3600 +#define MAX_BURST 1000 #define MAX_MSS (9 * 1024) #define MAX_STREAMS 128 diff --git a/src/iperf3.1 b/src/iperf3.1 index 8ac0e8a..e867cf5 100644 --- a/src/iperf3.1 +++ b/src/iperf3.1 @@ -73,6 +73,10 @@ use UDP rather than TCP 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 separately to each stream. +You can also add a '/' and a number to the bandwidth specifier. +This is called "burst mode". +It will send the given number of packets without pausing, even if that +temporarily exceeds the specified bandwidth limit. .TP .BR -t ", " --time " \fIn\fR" time in seconds to transmit for (default 10 secs) diff --git a/src/iperf_api.c b/src/iperf_api.c index dab066c..5d4c3c7 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -115,6 +115,12 @@ iperf_get_test_rate(struct iperf_test *ipt) return ipt->settings->rate; } +int +iperf_get_test_burst(struct iperf_test *ipt) +{ + return ipt->settings->burst; +} + char iperf_get_test_role(struct iperf_test *ipt) { @@ -249,6 +255,12 @@ iperf_set_test_rate(struct iperf_test *ipt, uint64_t rate) ipt->settings->rate = rate; } +void +iperf_set_test_burst(struct iperf_test *ipt, int burst) +{ + ipt->settings->burst = burst; +} + void iperf_set_test_server_port(struct iperf_test *ipt, int server_port) { @@ -529,6 +541,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) int blksize; int server_flag, client_flag, rate_flag; char* comma; + char* slash; blksize = 0; server_flag = client_flag = rate_flag = 0; @@ -583,6 +596,17 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) client_flag = 1; break; case 'b': + slash = strchr(optarg, '/'); + if (slash) { + *slash = '\0'; + ++slash; + test->settings->burst = atoi(slash); + if (test->settings->burst <= 0 || + test->settings->burst > MAX_BURST) { + i_errno = IEBURST; + return -1; + } + } test->settings->rate = unit_atof(optarg); rate_flag = 1; client_flag = 1; @@ -795,13 +819,15 @@ iperf_send(struct iperf_test *test, fd_set *write_setP) struct timeval now; /* Can we do multisend mode? */ - if (test->settings->rate != 0) - multisend = 1; /* nope */ - else + if (test->settings->burst != 0) + multisend = test->settings->burst; + else if (test->settings->rate == 0) multisend = test->multisend; + else + multisend = 1; /* nope */ for (; multisend > 0; --multisend) { - if (test->settings->rate != 0) + if (test->settings->rate != 0 && test->settings->burst == 0) gettimeofday(&now, NULL); SLIST_FOREACH(sp, &test->streams, streams) { if (sp->green_light && @@ -813,13 +839,18 @@ iperf_send(struct iperf_test *test, fd_set *write_setP) return r; } test->bytes_sent += r; - if (test->settings->rate != 0) + if (test->settings->rate != 0 && test->settings->burst == 0) iperf_check_throttle(sp, &now); if (multisend > 1 && test->settings->bytes != 0 && test->bytes_sent >= test->settings->bytes) break; } } } + if (test->settings->burst != 0) { + gettimeofday(&now, NULL); + SLIST_FOREACH(sp, &test->streams, streams) + iperf_check_throttle(sp, &now); + } if (write_setP != NULL) SLIST_FOREACH(sp, &test->streams, streams) if (FD_ISSET(sp->socket, write_setP)) @@ -1021,6 +1052,8 @@ send_parameters(struct iperf_test *test) cJSON_AddIntToObject(j, "len", test->settings->blksize); if (test->settings->rate) cJSON_AddIntToObject(j, "bandwidth", test->settings->rate); + if (test->settings->burst) + cJSON_AddIntToObject(j, "burst", test->settings->burst); if (test->settings->tos) cJSON_AddIntToObject(j, "TOS", test->settings->tos); if (test->settings->flowlabel) @@ -1078,6 +1111,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, "burst")) != NULL) + test->settings->burst = j_p->valueint; if ((j_p = cJSON_GetObjectItem(j, "TOS")) != NULL) test->settings->tos = j_p->valueint; if ((j_p = cJSON_GetObjectItem(j, "flowlabel")) != NULL) @@ -1409,6 +1444,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->burst = 0; testp->settings->mss = 0; testp->settings->bytes = 0; memset(testp->cookie, 0, COOKIE_SIZE); @@ -1566,6 +1602,7 @@ iperf_reset_test(struct iperf_test *test) test->settings->socket_bufsize = 0; test->settings->blksize = DEFAULT_TCP_BLKSIZE; test->settings->rate = 0; + test->settings->burst = 0; test->settings->mss = 0; memset(test->cookie, 0, COOKIE_SIZE); test->multisend = 10; /* arbitrary */ diff --git a/src/iperf_api.h b/src/iperf_api.h index 033d1bb..59b73ef 100644 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -52,6 +52,7 @@ char iperf_get_test_role( struct iperf_test* ipt ); int iperf_get_test_reverse( struct iperf_test* ipt ); int iperf_get_test_blksize( struct iperf_test* ipt ); uint64_t iperf_get_test_rate( struct iperf_test* ipt ); +int iperf_get_test_burst( struct iperf_test* ipt ); int iperf_get_test_socket_bufsize( struct iperf_test* ipt ); double iperf_get_test_reporter_interval( struct iperf_test* ipt ); double iperf_get_test_stats_interval( struct iperf_test* ipt ); @@ -73,6 +74,7 @@ void iperf_set_test_stats_interval( struct iperf_test* ipt, double stats_interva void iperf_set_test_state( struct iperf_test* ipt, signed char state ); void iperf_set_test_blksize( struct iperf_test* ipt, int blksize ); void iperf_set_test_rate( struct iperf_test* ipt, uint64_t rate ); +void iperf_set_test_burst( struct iperf_test* ipt, int burst ); void iperf_set_test_server_port( struct iperf_test* ipt, int server_port ); 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 ); @@ -239,6 +241,7 @@ enum { IEOMIT = 12, // Bogus value for --omit IEUNIMP = 13, // Not implemented yet IEFILE = 14, // -F file couldn't be opened + IEBURST = 15, // Invalid burst count. Maximum value = %dMAX_BURST /* Test errors */ IENEWTEST = 100, // Unable to create a new test (check perror) IEINITTEST = 101, // Test initialization failed (check perror) diff --git a/src/iperf_error.c b/src/iperf_error.c index 0066257..df903ec 100644 --- a/src/iperf_error.c +++ b/src/iperf_error.c @@ -109,6 +109,9 @@ iperf_strerror(int i_errno) snprintf(errstr, len, "unable to open -F file"); perr = 1; break; + case IEBURST: + snprintf(errstr, len, "invalid burst count (maximum = %d)", MAX_BURST); + break; case IENEWTEST: snprintf(errstr, len, "unable to create a new test"); perr = 1;