samples: zperf: Use native IP stack for TCP support
Enable zperf code to support TCP using the native IP stack when testing the network throughput. Change-Id: I3e58754cfff65525ad15e63adf57f1ea22e4559d Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
parent
56afb1065a
commit
48b9b96d3f
6 changed files with 338 additions and 143 deletions
|
@ -45,6 +45,12 @@ For example, the following command line must be used for UDP testing:
|
|||
|
||||
$ iperf -s -l 1K -u -V -B 2001:db8::2
|
||||
|
||||
For TCP testing, the command line would look like this:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ iperf -s -l 1K -V -B 2001:db8::2
|
||||
|
||||
|
||||
In the Zephyr console, zperf can be executed as follows:
|
||||
|
||||
|
@ -53,6 +59,13 @@ In the Zephyr console, zperf can be executed as follows:
|
|||
zperf> udp.upload 2001:db8::2 5001 10 1K 1M
|
||||
|
||||
|
||||
For TCP the zperf command would look like this:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
zperf> tcp.upload 2001:db8::2 5001 10 1K 1M
|
||||
|
||||
|
||||
If the IP addresses of Zephyr and the host machine are specified in the
|
||||
config file, zperf can be started as follows:
|
||||
|
||||
|
@ -61,20 +74,41 @@ config file, zperf can be started as follows:
|
|||
zperf> udp.upload2 v6 10 1K 1M
|
||||
|
||||
|
||||
If Zephyr is acting as a server, set the download mode as follows:
|
||||
or like this if you want to test TCP:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
zperf> tcp.upload2 v6 10 1K 1M
|
||||
|
||||
|
||||
If Zephyr is acting as a server, set the download mode as follows for UDP:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
zperf> udp.download 5001
|
||||
|
||||
|
||||
or like this for TCP:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
zperf> tcp.download 5001
|
||||
|
||||
|
||||
and in the host side, iPerf must be executed with the following
|
||||
command line:
|
||||
command line if you are testing UDP:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ iperf -l 1K -u -V -c 2001:db8::1 -p 5001
|
||||
|
||||
|
||||
and this if you are testing TCP:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ iperf -l 1K -V -c 2001:db8::1 -p 5001
|
||||
|
||||
|
||||
iPerf output can be limited by using the -b option if Zephyr is not
|
||||
able to receive all the packets in orderly manner.
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define CMD_STR_UDP_UPLOAD2 "udp.upload2"
|
||||
#define CMD_STR_UDP_DOWNLOAD "udp.download"
|
||||
#define CMD_STR_TCP_UPLOAD "tcp.upload"
|
||||
#define CMD_STR_TCP_UPLOAD2 "tcp.upload2"
|
||||
#define CMD_STR_TCP_DOWNLOAD "tcp.download"
|
||||
|
||||
struct zperf_results {
|
||||
|
|
|
@ -99,6 +99,7 @@ extern void zperf_receiver_init(int port);
|
|||
|
||||
#if defined(CONFIG_NET_TCP)
|
||||
extern void zperf_tcp_receiver_init(int port);
|
||||
extern void zperf_tcp_uploader_init(struct k_fifo *tx_queue);
|
||||
extern void zperf_tcp_upload(struct net_context *net_context,
|
||||
unsigned int duration_in_ms,
|
||||
unsigned int packet_size,
|
||||
|
|
|
@ -59,6 +59,7 @@ static const char *CONFIG =
|
|||
|
||||
#define MY_SRC_PORT 50000
|
||||
#define DEF_PORT 5001
|
||||
#define WAIT_CONNECT (2 * 1000) /* in ms */
|
||||
|
||||
#if defined(CONFIG_NET_IPV6)
|
||||
static struct in6_addr ipv6;
|
||||
|
@ -328,7 +329,7 @@ static void shell_udp_upload2_usage(void)
|
|||
printk("\t<baud rate>:\tBaudrate in kilobyte or megabyte\n");
|
||||
printk("\nExample %s v6 1 1K 1M\n",
|
||||
CMD_STR_UDP_UPLOAD2);
|
||||
#if defined(CONFIG_NET_IPV6) && defined(MY_IPV6ADDR)
|
||||
#if defined(CONFIG_NET_IPV6) && defined(MY_IP6ADDR)
|
||||
printk("\nDefault IPv6 address is %s, destination [%s]:%d\n",
|
||||
MY_IP6ADDR, DST_IP6ADDR, DEF_PORT);
|
||||
#endif
|
||||
|
@ -354,6 +355,29 @@ static void shell_tcp_upload_usage(void)
|
|||
printk("\nExample %s 10.237.164.178 1111 1 1K 1M\n",
|
||||
CMD_STR_TCP_UPLOAD);
|
||||
}
|
||||
|
||||
static void shell_tcp_upload2_usage(void)
|
||||
{
|
||||
/* Print usage */
|
||||
printk("\n%s:\n", CMD_STR_TCP_UPLOAD2);
|
||||
printk("Usage:\t%s v6|v4 <duration> <packet "
|
||||
"size>[K] <baud rate>[K|M]\n", CMD_STR_TCP_UPLOAD2);
|
||||
printk("\t<v6|v4>:\tUse either IPv6 or IPv4\n");
|
||||
printk("\t<duration>:\tDuration of the test in seconds\n");
|
||||
printk("\t<packet size>:\tSize of the packet in byte or kilobyte "
|
||||
"(with suffix K)\n");
|
||||
printk("\t<baud rate>:\tBaudrate in kilobyte or megabyte\n");
|
||||
printk("\nExample %s v6 1 1K 1M\n",
|
||||
CMD_STR_TCP_UPLOAD2);
|
||||
#if defined(CONFIG_NET_IPV6) && defined(MY_IP6ADDR)
|
||||
printk("\nDefault IPv6 address is %s, destination [%s]:%d\n",
|
||||
MY_IP6ADDR, DST_IP6ADDR, DEF_PORT);
|
||||
#endif
|
||||
#if defined(CONFIG_NET_IPV4) && defined(MY_IP4ADDR)
|
||||
printk("\nDefault IPv4 address is %s, destination %s:%d\n",
|
||||
MY_IP4ADDR, DST_IP4ADDR, DEF_PORT);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NET_UDP)
|
||||
|
@ -435,11 +459,11 @@ static void shell_tcp_upload_print_stats(struct zperf_results *results)
|
|||
printk("[%s] duration:\t", CMD_STR_TCP_UPLOAD);
|
||||
print_number(results->client_time_in_us, TIME_US, TIME_US_UNIT);
|
||||
printk("\n");
|
||||
printk("[%s] nb packets:\t%u\n", CMD_STR_UDP_UPLOAD,
|
||||
printk("[%s] nb packets:\t%u\n", CMD_STR_TCP_UPLOAD,
|
||||
results->nb_packets_sent);
|
||||
printk("[%s] nb sending errors (retry or fail):\t%u\n",
|
||||
CMD_STR_UDP_UPLOAD, results->nb_packets_errors);
|
||||
printk("[%s] rate:\t", CMD_STR_UDP_UPLOAD);
|
||||
CMD_STR_TCP_UPLOAD, results->nb_packets_errors);
|
||||
printk("[%s] rate:\t", CMD_STR_TCP_UPLOAD);
|
||||
print_number(client_rate_in_kbps, KBPS, KBPS_UNIT);
|
||||
printk("\n");
|
||||
}
|
||||
|
@ -596,38 +620,53 @@ static int execute_upload(struct net_context *context6,
|
|||
#endif
|
||||
} else {
|
||||
#if defined(CONFIG_NET_TCP)
|
||||
if (context6) {
|
||||
if (family == AF_INET6 && context6) {
|
||||
ret = net_context_connect(context6,
|
||||
(struct sockaddr *)ipv6,
|
||||
sizeof(*ipv6),
|
||||
NULL,
|
||||
K_NO_WAIT,
|
||||
WAIT_CONNECT,
|
||||
NULL);
|
||||
if (ret < 0) {
|
||||
printk("[%s] IPv6 connect failed\n", argv0);
|
||||
printk("[%s] IPv6 connect failed (%d)\n",
|
||||
argv0, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* We either upload using IPv4 or IPv6, not both at
|
||||
* the same time.
|
||||
*/
|
||||
net_context_put(context4);
|
||||
|
||||
zperf_tcp_upload(context6, duration_in_ms,
|
||||
packet_size, &results);
|
||||
|
||||
shell_tcp_upload_print_stats(&results);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (context4) {
|
||||
if (family == AF_INET && context4) {
|
||||
ret = net_context_connect(context4,
|
||||
(struct sockaddr *)ipv4,
|
||||
sizeof(*ipv4),
|
||||
NULL,
|
||||
K_NO_WAIT,
|
||||
WAIT_CONNECT,
|
||||
NULL);
|
||||
if (ret < 0) {
|
||||
printk("[%s] IPv4 connect failed\n", argv0);
|
||||
printk("[%s] IPv4 connect failed (%d)\n",
|
||||
argv0, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
net_context_put(context6);
|
||||
|
||||
zperf_tcp_upload(context4, duration_in_ms,
|
||||
packet_size, &results);
|
||||
|
||||
shell_tcp_upload_print_stats(&results);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
printk("[%s] TCP not supported\n", argv0);
|
||||
|
@ -983,6 +1022,8 @@ struct shell_cmd commands[] = {
|
|||
{ CMD_STR_UDP_DOWNLOAD, shell_cmd_udp_download },
|
||||
#endif
|
||||
#if defined(CONFIG_NET_TCP)
|
||||
{ CMD_STR_TCP_UPLOAD, shell_cmd_upload },
|
||||
{ CMD_STR_TCP_UPLOAD2, shell_cmd_upload2 },
|
||||
{ CMD_STR_TCP_DOWNLOAD, shell_cmd_tcp_download },
|
||||
#endif
|
||||
#if defined(PROFILER)
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#error "FIXME - TCP not supported yet"
|
||||
|
||||
#include <zephyr.h>
|
||||
|
||||
#include <sections.h>
|
||||
|
@ -22,110 +20,219 @@
|
|||
#include "shell_utils.h"
|
||||
#include "zperf_session.h"
|
||||
|
||||
/* To get net_sprint_ipv{4|6}_addr() */
|
||||
#define NET_LOG_ENABLED 1
|
||||
#include "net_private.h"
|
||||
|
||||
#define TAG CMD_STR_TCP_DOWNLOAD" "
|
||||
|
||||
#define TCP_RX_FIBER_STACK_SIZE 1024
|
||||
|
||||
/* Static data */
|
||||
static char __noinit __stack zperf_tcp_rx_fiber_stack[TCP_RX_FIBER_STACK_SIZE];
|
||||
static char __noinit __stack zperf_tcp_rx_stack[TCP_RX_FIBER_STACK_SIZE];
|
||||
|
||||
static struct net_addr in_addr_any = {
|
||||
#if defined(CONFIG_NETWORKING_WITH_IPV6)
|
||||
.family = AF_INET6,
|
||||
.in6_addr = IN6ADDR_ANY_INIT
|
||||
#else
|
||||
.family = AF_INET, .in_addr = { { { 0 } } }
|
||||
#endif
|
||||
};
|
||||
static struct sockaddr_in6 *in6_addr_my;
|
||||
static struct sockaddr_in *in4_addr_my;
|
||||
|
||||
static struct net_addr in_addr_my = {
|
||||
#if defined(CONFIG_NETWORKING_WITH_IPV6)
|
||||
.family = AF_INET6,
|
||||
.in6_addr = IN6ADDR_ANY_INIT
|
||||
#else
|
||||
.family = AF_INET, .in_addr = { { { 0 } } }
|
||||
#endif
|
||||
};
|
||||
|
||||
/* TCP RX fiber entry point */
|
||||
static void zperf_tcp_rx_fiber(int port)
|
||||
static void tcp_received(struct net_context *context,
|
||||
struct net_buf *buf,
|
||||
int status,
|
||||
void *user_data)
|
||||
{
|
||||
struct net_context *net_context = net_context_get(IPPROTO_TCP, &in_addr_any,
|
||||
0, &in_addr_my, port);
|
||||
struct session *session;
|
||||
uint32_t time;
|
||||
|
||||
if (!net_context) {
|
||||
printk(TAG "ERROR! Cannot get network context.\n");
|
||||
if (!buf) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
struct net_buf *buf = net_receive(net_context, K_FOREVER);
|
||||
struct session *session = NULL;
|
||||
uint32_t time = k_cycle_get_32();
|
||||
time = k_cycle_get_32();
|
||||
|
||||
if (buf == NULL) {
|
||||
printk(TAG "buf is null\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
session = get_session(buf, SESSION_UDP);
|
||||
if (session == NULL) {
|
||||
printk(TAG "ERROR! cannot get a session!\n");
|
||||
/* free buffer */
|
||||
ip_buf_unref(buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (session->state) {
|
||||
case STATE_NULL:
|
||||
case STATE_COMPLETED:
|
||||
printk(TAG "New session started\n");
|
||||
zperf_reset_session_stats(session);
|
||||
session->start_time = k_cycle_get_32();
|
||||
session->state = STATE_ONGOING;
|
||||
case STATE_ONGOING:
|
||||
session->counter++;
|
||||
session->length += ip_buf_appdatalen(buf);
|
||||
|
||||
if (uip_closed(buf)) {
|
||||
session->state = STATE_COMPLETED;
|
||||
uint32_t rate_in_kbps;
|
||||
uint32_t duration = HW_CYCLES_TO_USEC(
|
||||
time_delta(session->start_time, time));
|
||||
|
||||
/* Compute baud rate */
|
||||
if (duration != 0) {
|
||||
rate_in_kbps = (uint32_t) ((
|
||||
(uint64_t) session->length
|
||||
* (uint64_t) 8
|
||||
* (uint64_t) USEC_PER_SEC)
|
||||
/ ((uint64_t) duration * 1024));
|
||||
} else {
|
||||
rate_in_kbps = 0;
|
||||
}
|
||||
|
||||
printk(TAG "TCP session ended\n");
|
||||
printk(TAG " duration:\t\t");
|
||||
print_number(duration, TIME_US, TIME_US_UNIT);
|
||||
printk("\n");
|
||||
printk(TAG " rate:\t\t\t");
|
||||
print_number(rate_in_kbps, KBPS, KBPS_UNIT);
|
||||
printk("\n");
|
||||
}
|
||||
break;
|
||||
case STATE_LAST_PACKET_RECEIVED:
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(TAG "Error! Unsupported case\n");
|
||||
}
|
||||
|
||||
/* free buffer */
|
||||
ip_buf_unref(buf);
|
||||
session = get_session(buf, SESSION_TCP);
|
||||
if (!session) {
|
||||
printk(TAG "ERROR! cannot get a session!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (session->state) {
|
||||
case STATE_NULL:
|
||||
case STATE_COMPLETED:
|
||||
printk(TAG "New session started\n");
|
||||
zperf_reset_session_stats(session);
|
||||
session->start_time = sys_cycle_get_32();
|
||||
session->state = STATE_ONGOING;
|
||||
/* fall through */
|
||||
case STATE_ONGOING:
|
||||
session->counter++;
|
||||
|
||||
if (buf) {
|
||||
session->length += net_nbuf_appdatalen(buf);
|
||||
}
|
||||
|
||||
if (!buf && status == 0) { /* EOF */
|
||||
uint32_t rate_in_kbps;
|
||||
uint32_t duration = HW_CYCLES_TO_USEC(
|
||||
time_delta(session->start_time, time));
|
||||
|
||||
session->state = STATE_COMPLETED;
|
||||
|
||||
/* Compute baud rate */
|
||||
if (duration != 0) {
|
||||
rate_in_kbps = (uint32_t)
|
||||
(((uint64_t)session->length *
|
||||
(uint64_t)8 *
|
||||
(uint64_t)USEC_PER_SEC) /
|
||||
((uint64_t)duration * 1024));
|
||||
} else {
|
||||
rate_in_kbps = 0;
|
||||
}
|
||||
|
||||
printk(TAG "TCP session ended\n");
|
||||
|
||||
printk(TAG " duration:\t\t");
|
||||
print_number(duration, TIME_US, TIME_US_UNIT);
|
||||
printk("\n");
|
||||
|
||||
printk(TAG " rate:\t\t\t");
|
||||
print_number(rate_in_kbps, KBPS, KBPS_UNIT);
|
||||
printk("\n");
|
||||
}
|
||||
break;
|
||||
case STATE_LAST_PACKET_RECEIVED:
|
||||
break;
|
||||
default:
|
||||
printk(TAG "Error! Unsupported case\n");
|
||||
}
|
||||
|
||||
net_nbuf_unref(buf);
|
||||
}
|
||||
|
||||
static void tcp_accepted(struct net_context *context,
|
||||
struct sockaddr *addr,
|
||||
socklen_t addrlen,
|
||||
int error,
|
||||
void *user_data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = net_context_recv(context, tcp_received, K_NO_WAIT, user_data);
|
||||
if (ret < 0) {
|
||||
printk(TAG "Cannot receive TCP packet (family %d)",
|
||||
net_context_get_family(context));
|
||||
}
|
||||
}
|
||||
|
||||
static void zperf_tcp_rx_thread(int port)
|
||||
{
|
||||
struct net_context *context4 = NULL, *context6 = NULL;
|
||||
int ret, fail = 0;
|
||||
|
||||
#if defined(CONFIG_NET_IPV4) && defined(MY_IP4ADDR)
|
||||
ret = net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, &context4);
|
||||
if (ret < 0) {
|
||||
printk(TAG "ERROR! Cannot get IPv4 TCP network context.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = zperf_get_ipv4_addr(MY_IP4ADDR, &in4_addr_my->sin_addr, TAG);
|
||||
if (ret < 0) {
|
||||
printk(TAG "ERROR! Unable to set IPv4\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printk(TAG "Binding to %s\n",
|
||||
net_sprint_ipv4_addr(&in4_addr_my->sin_addr));
|
||||
|
||||
in4_addr_my->sin_port = htons(port);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NET_IPV6) && defined(MY_IP6ADDR)
|
||||
ret = net_context_get(AF_INET6, SOCK_STREAM, IPPROTO_TCP, &context6);
|
||||
if (ret < 0) {
|
||||
printk(TAG "ERROR! Cannot get IPv6 TCP network context.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = zperf_get_ipv6_addr(MY_IP6ADDR, MY_PREFIX_LEN_STR,
|
||||
&in6_addr_my->sin6_addr, TAG);
|
||||
if (ret < 0) {
|
||||
printk(TAG "ERROR! Unable to set IPv6\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printk(TAG "Binding to %s\n",
|
||||
net_sprint_ipv6_addr(&in6_addr_my->sin6_addr));
|
||||
|
||||
in6_addr_my->sin6_port = htons(port);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NET_IPV6)
|
||||
if (context6) {
|
||||
ret = net_context_bind(context6,
|
||||
(struct sockaddr *)in6_addr_my,
|
||||
sizeof(struct sockaddr_in6));
|
||||
if (ret < 0) {
|
||||
printk(TAG "Cannot bind IPv6 TCP port %d (%d)\n",
|
||||
ntohs(in6_addr_my->sin6_port), ret);
|
||||
fail++;
|
||||
}
|
||||
|
||||
ret = net_context_listen(context6, 0);
|
||||
if (ret < 0) {
|
||||
printk(TAG "Cannot listen IPv6 TCP (%d)", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = net_context_accept(context6, tcp_accepted, 0, NULL);
|
||||
if (ret < 0) {
|
||||
printk(TAG "Cannot receive IPv6 TCP packets (%d)", ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NET_IPV4)
|
||||
if (context4) {
|
||||
ret = net_context_bind(context4,
|
||||
(struct sockaddr *)in4_addr_my,
|
||||
sizeof(struct sockaddr_in));
|
||||
if (ret < 0) {
|
||||
printk(TAG "Cannot bind IPv4 TCP port %d (%d)\n",
|
||||
ntohs(in4_addr_my->sin_port), ret);
|
||||
fail++;
|
||||
}
|
||||
|
||||
ret = net_context_listen(context4, 0);
|
||||
if (ret < 0) {
|
||||
printk(TAG "Cannot listen IPv4 TCP (%d)", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = net_context_accept(context4, tcp_accepted, 0, NULL);
|
||||
if (ret < 0) {
|
||||
printk(TAG "Cannot receive IPv4 TCP packets (%d)", ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fail > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
k_sleep(K_FOREVER);
|
||||
}
|
||||
|
||||
void zperf_tcp_receiver_init(int port)
|
||||
{
|
||||
fiber_start(zperf_tcp_rx_fiber_stack, sizeof(zperf_tcp_rx_fiber_stack),
|
||||
(nano_fiber_entry_t) zperf_tcp_rx_fiber, port, 0, 7, 0);
|
||||
#if defined(CONFIG_NET_IPV6)
|
||||
in6_addr_my = zperf_get_sin6();
|
||||
#endif
|
||||
#if defined(CONFIG_NET_IPV4)
|
||||
in4_addr_my = zperf_get_sin();
|
||||
#endif
|
||||
|
||||
k_thread_spawn(zperf_tcp_rx_stack, sizeof(zperf_tcp_rx_stack),
|
||||
(k_thread_entry_t)zperf_tcp_rx_thread,
|
||||
INT_TO_POINTER(port), 0, 0,
|
||||
K_PRIO_COOP(7), 0, K_NO_WAIT);
|
||||
}
|
||||
|
|
|
@ -4,23 +4,26 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <misc/printk.h>
|
||||
#include <net/ip_buf.h>
|
||||
|
||||
#include <net/nbuf.h>
|
||||
#include <net/net_ip.h>
|
||||
#include <net/net_core.h>
|
||||
#include <net/net_socket.h>
|
||||
#include <zephyr.h>
|
||||
|
||||
#include "zperf.h"
|
||||
#include "zperf_internal.h"
|
||||
|
||||
#define TAG CMD_STR_TCP_UPLOAD" "
|
||||
|
||||
void zperf_tcp_upload(struct net_context *net_context,
|
||||
unsigned int duration_in_ms,
|
||||
unsigned int packet_size,
|
||||
zperf_results *results)
|
||||
static char sample_packet[PACKET_SIZE_MAX];
|
||||
|
||||
void zperf_tcp_upload(struct net_context *ctx,
|
||||
unsigned int duration_in_ms,
|
||||
unsigned int packet_size,
|
||||
struct zperf_results *results)
|
||||
{
|
||||
uint32_t duration = MSEC_TO_HW_CYCLES(duration_in_ms);
|
||||
uint32_t nb_packets = 0, nb_errors = 0;
|
||||
|
@ -29,7 +32,7 @@ void zperf_tcp_upload(struct net_context *net_context,
|
|||
|
||||
if (packet_size > PACKET_SIZE_MAX) {
|
||||
printk(TAG "WARNING! packet size too large! max size: %u\n",
|
||||
PACKET_SIZE_MAX);
|
||||
PACKET_SIZE_MAX);
|
||||
packet_size = PACKET_SIZE_MAX;
|
||||
}
|
||||
|
||||
|
@ -38,69 +41,77 @@ void zperf_tcp_upload(struct net_context *net_context,
|
|||
last_print_time = start_time;
|
||||
last_loop_time = start_time;
|
||||
printk(TAG "New session started\n");
|
||||
|
||||
memset(sample_packet, 'z', sizeof(sample_packet));
|
||||
|
||||
do {
|
||||
uint32_t loop_time;
|
||||
uint8_t *ptr = NULL;
|
||||
int ret = 0;
|
||||
struct net_buf *buf, *frag;
|
||||
uint32_t loop_time;
|
||||
bool st;
|
||||
|
||||
/* Timestamps */
|
||||
loop_time = k_cycle_get_32();
|
||||
last_loop_time = loop_time;
|
||||
|
||||
/* Get a new TX buffer */
|
||||
struct net_buf *buf = ip_buf_get_tx(net_context);
|
||||
|
||||
buf = net_nbuf_get_tx(ctx);
|
||||
if (!buf) {
|
||||
printk(TAG "ERROR! Failed to retrieve a buffer\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Fill in the TCP payload */
|
||||
ptr = net_buf_add(buf, packet_size);
|
||||
memset(ptr, 'z', packet_size);
|
||||
frag = net_nbuf_get_data(ctx);
|
||||
if (!frag) {
|
||||
printk(TAG "ERROR! Failed to retrieve a fragment\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If test time is elapsed, send a last packet with specific flag
|
||||
* to request uIP to close the TCP connection
|
||||
*/
|
||||
if (time_elapsed) {
|
||||
uip_flags(buf) |= UIP_CLOSE;
|
||||
net_buf_frag_add(buf, frag);
|
||||
|
||||
/* Fill in the TCP payload */
|
||||
st = net_nbuf_append(buf, sizeof(sample_packet),
|
||||
sample_packet);
|
||||
if (!st) {
|
||||
printk(TAG "ERROR! Failed to fill packet\n");
|
||||
|
||||
net_nbuf_unref(buf);
|
||||
nb_errors++;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Send the packet */
|
||||
again:
|
||||
ret = net_send(buf);
|
||||
ret = net_context_send(buf, NULL, K_NO_WAIT, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
if (ret == -EINPROGRESS || ret == -EAGAIN) {
|
||||
nb_errors++;
|
||||
fiber_sleep(100);
|
||||
goto again;
|
||||
} else {
|
||||
printk("ERROR! Failed to send the buffer\n");
|
||||
nb_errors++;
|
||||
}
|
||||
printk(TAG "ERROR! Failed to send the buffer (%d)\n",
|
||||
ret);
|
||||
|
||||
net_nbuf_unref(buf);
|
||||
nb_errors++;
|
||||
break;
|
||||
} else {
|
||||
nb_packets++;
|
||||
/* if test time is elapsed and are here, that means TCP connection
|
||||
* has been closed by uIP as requested. So exit the loop.
|
||||
*/
|
||||
|
||||
if (time_elapsed) {
|
||||
finished = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!time_elapsed && time_delta(start_time, last_loop_time) > duration)
|
||||
if (!time_elapsed && time_delta(start_time,
|
||||
last_loop_time) > duration) {
|
||||
time_elapsed = 1;
|
||||
}
|
||||
|
||||
ip_buf_unref(buf);
|
||||
fiber_yield();
|
||||
k_yield();
|
||||
} while (!finished);
|
||||
|
||||
end_time = k_cycle_get_32();
|
||||
|
||||
/* Add result coming from the client */
|
||||
results->nb_packets_sent = nb_packets;
|
||||
results->client_time_in_us = HW_CYCLES_TO_USEC(
|
||||
time_delta(start_time, end_time));
|
||||
results->client_time_in_us =
|
||||
HW_CYCLES_TO_USEC(time_delta(start_time, end_time));
|
||||
results->packet_size = packet_size;
|
||||
results->nb_packets_errors = nb_errors;
|
||||
|
||||
net_context_put(ctx);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue