net: zperf: Define a public upload API for the library

This commit defines a public API for zperf upload functionality. The
UDP/TCP uploader modules are decoupled from shell, allowing to perform
uploads directly from the application code. The shell submodule makes
use of this new public API.

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
Robert Lubos 2022-11-18 13:46:25 +01:00 committed by Carles Cufí
commit 812a1bc152
11 changed files with 368 additions and 368 deletions

View file

@ -4,6 +4,7 @@ zephyr_library_named(zperf)
zephyr_library_sources(
shell_utils.c
zperf_common.c
zperf_session.c
zperf_shell.c
zperf_udp_receiver.c

View file

@ -1,29 +0,0 @@
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ZPERF_H
#define __ZPERF_H
#define VERSION "1.1"
struct zperf_results {
uint32_t nb_packets_sent;
uint32_t nb_packets_rcvd;
uint32_t nb_packets_lost;
uint32_t nb_packets_outorder;
uint32_t nb_bytes_sent;
uint32_t time_in_us;
uint32_t jitter_in_us;
uint32_t client_time_in_us;
uint32_t packet_size;
uint32_t nb_packets_errors;
};
typedef void (*zperf_callback)(int status, struct zperf_results *);
#define IPV4_STR_LEN_MAX 15
#define IPV4_STR_LEN_MIN 7
#endif /* __ZPERF_H */

View file

@ -0,0 +1,89 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/logging/log.h>
#include <zephyr/net/socket.h>
LOG_MODULE_DECLARE(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL);
int zperf_prepare_upload_sock(const struct sockaddr *peer_addr, int tos,
int proto)
{
socklen_t addrlen = peer_addr->sa_family == AF_INET6 ?
sizeof(struct sockaddr_in6) :
sizeof(struct sockaddr_in);
int type = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
int sock = -1;
int ret;
switch (peer_addr->sa_family) {
case AF_INET:
if (!IS_ENABLED(CONFIG_NET_IPV4)) {
NET_ERR("IPv4 not available.");
return -EINVAL;
}
sock = zsock_socket(AF_INET, type, proto);
if (sock < 0) {
NET_ERR("Cannot create IPv4 network socket (%d)",
errno);
return -errno;
}
if (tos > 0) {
if (zsock_setsockopt(sock, IPPROTO_IP, IP_TOS,
&tos, sizeof(tos)) != 0) {
NET_WARN("Failed to set IP_TOS socket option. "
"Please enable CONFIG_NET_CONTEXT_DSCP_ECN.");
}
}
break;
case AF_INET6:
if (!IS_ENABLED(CONFIG_NET_IPV6)) {
NET_ERR("IPv6 not available.");
return -EINVAL;
}
sock = zsock_socket(AF_INET6, type, proto);
if (sock < 0) {
NET_ERR("Cannot create IPv6 network socket (%d)",
errno);
return -errno;
}
if (tos >= 0) {
if (zsock_setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS,
&tos, sizeof(tos)) != 0) {
NET_WARN("Failed to set IPV6_TCLASS socket option. "
"Please enable CONFIG_NET_CONTEXT_DSCP_ECN.");
}
}
break;
default:
LOG_ERR("Invalid address family (%d)", peer_addr->sa_family);
return -EINVAL;
}
ret = zsock_connect(sock, peer_addr, addrlen);
if (ret < 0) {
NET_ERR("Connect failed (%d)", errno);
ret = -errno;
zsock_close(sock);
return ret;
}
return sock;
}
uint32_t zperf_packet_duration(uint32_t packet_size, uint32_t rate_in_kbps)
{
return (uint32_t)(((uint64_t)packet_size * 8U * USEC_PER_SEC) /
(rate_in_kbps * 1024U));
}

View file

@ -8,6 +8,7 @@
#include <limits.h>
#include <zephyr/net/net_ip.h>
#include <zephyr/net/zperf.h>
#include <zephyr/shell/shell.h>
#include <zephyr/sys/__assert.h>
@ -81,23 +82,9 @@ int zperf_get_ipv4_addr(const struct shell *sh, char *host,
struct in_addr *addr);
struct sockaddr_in *zperf_get_sin(void);
extern void zperf_udp_upload(const struct shell *sh,
int sock,
int port,
unsigned int duration_in_ms,
unsigned int packet_size,
unsigned int rate_in_kbps,
struct zperf_results *results);
extern void zperf_udp_receiver_init(const struct shell *sh, int port);
extern void zperf_tcp_receiver_init(const struct shell *sh, int port);
extern void zperf_tcp_uploader_init(struct k_fifo *tx_queue);
extern void zperf_tcp_upload(const struct shell *sh,
int sock,
unsigned int duration_in_ms,
unsigned int packet_size,
struct zperf_results *results);
extern void connect_ap(char *ssid);
@ -107,4 +94,9 @@ const struct in6_addr *zperf_get_default_if_in6_addr(void);
void zperf_tcp_stopped(void);
void zperf_tcp_started(void);
int zperf_prepare_upload_sock(const struct sockaddr *peer_addr, int tos,
int proto);
uint32_t zperf_packet_duration(uint32_t packet_size, uint32_t rate_in_kbps);
#endif /* __ZPERF_INTERNAL_H */

View file

@ -15,7 +15,6 @@
#include <zephyr/net/net_ip.h>
#include <zephyr/net/net_core.h>
#include "zperf.h"
#include "zperf_internal.h"
#include "shell_utils.h"

View file

@ -17,8 +17,8 @@ LOG_MODULE_REGISTER(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL);
#include <zephyr/net/net_ip.h>
#include <zephyr/net/net_core.h>
#include <zephyr/net/socket.h>
#include <zephyr/net/zperf.h>
#include "zperf.h"
#include "zperf_internal.h"
#include "shell_utils.h"
#include "zperf_session.h"
@ -53,6 +53,8 @@ static const char *CONFIG =
#define DEF_PORT 5001
#define DEF_PORT_STR STRINGIFY(DEF_PORT)
#define ZPERF_VERSION "1.1"
static struct in6_addr ipv6;
static struct sockaddr_in6 in6_addr_my = {
@ -362,7 +364,7 @@ static void shell_udp_upload_print_stats(const struct shell *sh,
if (results->time_in_us != 0U) {
rate_in_kbps = (uint32_t)
(((uint64_t)results->nb_bytes_sent *
(((uint64_t)results->total_len *
(uint64_t)8 * (uint64_t)USEC_PER_SEC) /
((uint64_t)results->time_in_us * 1024U));
} else {
@ -450,101 +452,26 @@ static void shell_tcp_upload_print_stats(const struct shell *sh,
}
}
static int setup_upload_sockets(const struct shell *sh,
int *sock6,
int *sock4,
sa_family_t family,
struct sockaddr_in6 *ipv6,
struct sockaddr_in *ipv4,
int port,
int tos,
bool is_udp)
{
if (IS_ENABLED(CONFIG_NET_IPV6)) {
*sock6 = zsock_socket(AF_INET6,
is_udp ? SOCK_DGRAM : SOCK_STREAM,
is_udp ? IPPROTO_UDP : IPPROTO_TCP);
if (*sock6 < 0) {
shell_fprintf(sh, SHELL_WARNING,
"Cannot create IPv6 network socket (%d)\n",
errno);
return -ENOEXEC;
}
if (tos >= 0) {
if (zsock_setsockopt(*sock6, IPPROTO_IPV6, IPV6_TCLASS,
&tos, sizeof(tos)) != 0) {
shell_fprintf(
sh, SHELL_WARNING,
"Failed to set IPV6_TCLASS socket option. "
"Please enable CONFIG_NET_CONTEXT_DSCP_ECN.\n");
}
}
ipv6->sin6_port = htons(port);
ipv6->sin6_family = AF_INET6;
}
if (IS_ENABLED(CONFIG_NET_IPV4)) {
*sock4 = zsock_socket(AF_INET,
is_udp ? SOCK_DGRAM : SOCK_STREAM,
is_udp ? IPPROTO_UDP : IPPROTO_TCP);
if (*sock4 < 0) {
shell_fprintf(sh, SHELL_WARNING,
"Cannot create IPv4 network socket (%d)\n",
errno);
return -ENOEXEC;
}
if (tos >= 0) {
if (zsock_setsockopt(*sock4, IPPROTO_IP, IP_TOS,
&tos, sizeof(tos)) != 0) {
shell_fprintf(
sh, SHELL_WARNING,
"Failed to set IP_TOS socket option. "
"Please enable CONFIG_NET_CONTEXT_DSCP_ECN.\n");
}
}
ipv4->sin_port = htons(port);
ipv4->sin_family = AF_INET;
}
if ((*sock6 < 0) && (*sock4 < 0)) {
shell_fprintf(sh, SHELL_WARNING,
"Fail to create network socket(s)\n");
return -ENOEXEC;
}
return 0;
}
static int execute_upload(const struct shell *sh,
int sock6,
int sock4,
sa_family_t family,
struct sockaddr_in6 *ipv6,
struct sockaddr_in *ipv4,
bool is_udp,
int port,
unsigned int duration_in_ms,
unsigned int packet_size,
unsigned int rate_in_kbps)
const struct zperf_upload_params *param,
bool is_udp)
{
struct zperf_results results = { };
struct zperf_results results = { 0 };
int ret;
shell_fprintf(sh, SHELL_NORMAL, "Duration:\t");
print_number(sh, duration_in_ms * USEC_PER_MSEC, TIME_US,
print_number(sh, param->duration_ms * USEC_PER_MSEC, TIME_US,
TIME_US_UNIT);
shell_fprintf(sh, SHELL_NORMAL, "\n");
shell_fprintf(sh, SHELL_NORMAL, "Packet size:\t%u bytes\n",
packet_size);
param->packet_size);
shell_fprintf(sh, SHELL_NORMAL, "Rate:\t\t%u kbps\n",
rate_in_kbps);
param->rate_kbps);
shell_fprintf(sh, SHELL_NORMAL, "Starting...\n");
if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6 && sock6 >= 0) {
if (IS_ENABLED(CONFIG_NET_IPV6) && param->peer_addr.sa_family == AF_INET6) {
struct sockaddr_in6 *ipv6 =
(struct sockaddr_in6 *)&param->peer_addr;
/* For IPv6, we should make sure that neighbor discovery
* has been done for the peer. So send ping here, wait
* some time and start the test after that.
@ -556,41 +483,29 @@ static int execute_upload(const struct shell *sh,
}
if (is_udp && IS_ENABLED(CONFIG_NET_UDP)) {
uint32_t packet_duration =
zperf_packet_duration(param->packet_size, param->rate_kbps);
shell_fprintf(sh, SHELL_NORMAL, "Rate:\t\t");
print_number(sh, rate_in_kbps, KBPS, KBPS_UNIT);
print_number(sh, param->rate_kbps, KBPS, KBPS_UNIT);
shell_fprintf(sh, SHELL_NORMAL, "\n");
if (family == AF_INET6 && sock6 >= 0) {
ret = zsock_connect(sock6,
(struct sockaddr *)ipv6,
sizeof(*ipv6));
if (ret < 0) {
shell_fprintf(sh, SHELL_WARNING,
"IPv6 connect failed (%d)\n",
errno);
goto out;
}
zperf_udp_upload(sh, sock6, port, duration_in_ms,
packet_size, rate_in_kbps, &results);
shell_udp_upload_print_stats(sh, &results);
if (packet_duration > 1000U) {
shell_fprintf(sh, SHELL_NORMAL, "Packet duration %u ms\n",
(unsigned int)(packet_duration / 1000U));
} else {
shell_fprintf(sh, SHELL_NORMAL, "Packet duration %u us\n",
(unsigned int)packet_duration);
}
if (family == AF_INET && sock4 >= 0) {
ret = zsock_connect(sock4,
(struct sockaddr *)ipv4,
sizeof(*ipv4));
if (ret < 0) {
shell_fprintf(sh, SHELL_NORMAL,
"IPv4 connect failed (%d)\n",
errno);
goto out;
}
zperf_udp_upload(sh, sock4, port, duration_in_ms,
packet_size, rate_in_kbps, &results);
shell_udp_upload_print_stats(sh, &results);
ret = zperf_udp_upload(param, &results);
if (ret < 0) {
shell_fprintf(sh, SHELL_ERROR,
"UDP upload failed (%d)\n", ret);
return ret;
}
shell_udp_upload_print_stats(sh, &results);
} else {
if (!IS_ENABLED(CONFIG_NET_UDP)) {
shell_fprintf(sh, SHELL_INFO,
@ -599,52 +514,14 @@ static int execute_upload(const struct shell *sh,
}
if (!is_udp && IS_ENABLED(CONFIG_NET_TCP)) {
if (family == AF_INET6 && sock6 >= 0) {
ret = zsock_connect(sock6,
(struct sockaddr *)ipv6,
sizeof(*ipv6));
if (ret < 0) {
shell_fprintf(sh, SHELL_WARNING,
"IPv6 connect failed (%d)\n",
errno);
goto out;
}
/* We either upload using IPv4 or IPv6, not both at
* the same time.
*/
if (IS_ENABLED(CONFIG_NET_IPV4) && sock4 >= 0) {
(void)zsock_close(sock4);
sock4 = -1;
}
zperf_tcp_upload(sh, sock6, duration_in_ms,
packet_size, &results);
shell_tcp_upload_print_stats(sh, &results);
ret = zperf_tcp_upload(param, &results);
if (ret < 0) {
shell_fprintf(sh, SHELL_ERROR,
"TCP upload failed (%d)\n", ret);
return ret;
}
if (family == AF_INET && sock4 >= 0) {
ret = zsock_connect(sock4,
(struct sockaddr *)ipv4,
sizeof(*ipv4));
if (ret < 0) {
shell_fprintf(sh, SHELL_WARNING,
"IPv4 connect failed (%d)\n",
errno);
goto out;
}
if (IS_ENABLED(CONFIG_NET_IPV6) && sock6 >= 0) {
(void)zsock_close(sock6);
sock6 = -1;
}
zperf_tcp_upload(sh, sock4, duration_in_ms,
packet_size, &results);
shell_tcp_upload_print_stats(sh, &results);
}
shell_tcp_upload_print_stats(sh, &results);
} else {
if (!IS_ENABLED(CONFIG_NET_TCP)) {
shell_fprintf(sh, SHELL_INFO,
@ -652,17 +529,6 @@ static int execute_upload(const struct shell *sh,
}
}
out:
if (IS_ENABLED(CONFIG_NET_IPV6) && sock6 >= 0) {
(void)zsock_close(sock6);
sock6 = -1;
}
if (IS_ENABLED(CONFIG_NET_IPV4) && sock4 >= 0) {
(void)zsock_close(sock4);
sock4 = -1;
}
return 0;
}
@ -698,17 +564,13 @@ static int parse_arg(size_t *i, size_t argc, char *argv[])
static int shell_cmd_upload(const struct shell *sh, size_t argc,
char *argv[], enum net_ip_protocol proto)
{
struct zperf_upload_params param = { 0 };
struct sockaddr_in6 ipv6 = { .sin6_family = AF_INET6 };
struct sockaddr_in ipv4 = { .sin_family = AF_INET };
int sock6 = -1, sock4 = -1;
sa_family_t family = AF_UNSPEC;
unsigned int duration_in_ms, packet_size, rate_in_kbps;
char *port_str;
uint16_t port;
bool is_udp;
int start = 0;
size_t opt_cnt = 0;
int tos = 0;
is_udp = proto == IPPROTO_UDP;
@ -720,13 +582,16 @@ static int shell_cmd_upload(const struct shell *sh, size_t argc,
switch (argv[i][1]) {
case 'S':
tos = parse_arg(&i, argc, argv);
int tos = parse_arg(&i, argc, argv);
if (tos < 0 || tos > UINT8_MAX) {
shell_fprintf(sh, SHELL_WARNING,
"Parse error: %s\n", argv[i]);
return -ENOEXEC;
}
param.options.tos = tos;
break;
default:
shell_fprintf(sh, SHELL_WARNING,
@ -760,12 +625,10 @@ static int shell_cmd_upload(const struct shell *sh, size_t argc,
}
if (argc > 2) {
port = strtoul(argv[start + 2], NULL, 10);
shell_fprintf(sh, SHELL_NORMAL,
"Remote port is %u\n", port);
port_str = argv[start + 2];
shell_fprintf(sh, SHELL_NORMAL,
"Remote port is %s\n", port_str);
} else {
port = DEF_PORT;
port_str = DEF_PORT_STR;
}
@ -781,7 +644,7 @@ static int shell_cmd_upload(const struct shell *sh, size_t argc,
shell_fprintf(sh, SHELL_WARNING, "Connecting to %s\n",
net_sprint_ipv6_addr(&ipv6.sin6_addr));
family = AF_INET6;
memcpy(&param.peer_addr, &ipv6, sizeof(ipv6));
}
if (IS_ENABLED(CONFIG_NET_IPV4) && !IS_ENABLED(CONFIG_NET_IPV6)) {
@ -796,7 +659,7 @@ static int shell_cmd_upload(const struct shell *sh, size_t argc,
shell_fprintf(sh, SHELL_NORMAL, "Connecting to %s\n",
net_sprint_ipv4_addr(&ipv4.sin_addr));
family = AF_INET;
memcpy(&param.peer_addr, &ipv4, sizeof(ipv4));
}
if (IS_ENABLED(CONFIG_NET_IPV6) && IS_ENABLED(CONFIG_NET_IPV4)) {
@ -814,45 +677,37 @@ static int shell_cmd_upload(const struct shell *sh, size_t argc,
"Connecting to %s\n",
net_sprint_ipv4_addr(&ipv4.sin_addr));
family = AF_INET;
memcpy(&param.peer_addr, &ipv4, sizeof(ipv4));
} else {
shell_fprintf(sh, SHELL_NORMAL,
"Connecting to %s\n",
net_sprint_ipv6_addr(&ipv6.sin6_addr));
family = AF_INET6;
memcpy(&param.peer_addr, &ipv6, sizeof(ipv6));
}
}
if (setup_upload_sockets(sh, &sock6, &sock4, family, &in6_addr_my,
&in4_addr_my, port, tos, is_udp) < 0) {
return -ENOEXEC;
}
if (argc > 3) {
duration_in_ms = MSEC_PER_SEC * strtoul(argv[start + 3],
NULL, 10);
param.duration_ms = MSEC_PER_SEC * strtoul(argv[start + 3],
NULL, 10);
} else {
duration_in_ms = MSEC_PER_SEC * 1;
param.duration_ms = MSEC_PER_SEC * 1;
}
if (argc > 4) {
packet_size = parse_number(argv[start + 4], K, K_UNIT);
param.packet_size = parse_number(argv[start + 4], K, K_UNIT);
} else {
packet_size = 256U;
param.packet_size = 256U;
}
if (argc > 5) {
rate_in_kbps =
(parse_number(argv[start + 5], K, K_UNIT) +
1023) / 1024;
param.rate_kbps =
(parse_number(argv[start + 5], K, K_UNIT) + 1023) / 1024;
} else {
rate_in_kbps = 10U;
param.rate_kbps = 10U;
}
return execute_upload(sh, sock6, sock4, family, &ipv6, &ipv4,
is_udp, port, duration_in_ms,
packet_size, rate_in_kbps);
return execute_upload(sh, &param, is_udp);
}
static int cmd_tcp_upload(const struct shell *sh, size_t argc, char *argv[])
@ -872,14 +727,11 @@ static int cmd_udp_upload(const struct shell *sh, size_t argc, char *argv[])
static int shell_cmd_upload2(const struct shell *sh, size_t argc,
char *argv[], enum net_ip_protocol proto)
{
int sock6 = -1, sock4 = -1;
uint16_t port = DEF_PORT;
unsigned int duration_in_ms, packet_size, rate_in_kbps;
struct zperf_upload_params param = { 0 };
sa_family_t family;
uint8_t is_udp;
int start = 0;
size_t opt_cnt = 0;
int tos = -1;
is_udp = proto == IPPROTO_UDP;
@ -891,13 +743,16 @@ static int shell_cmd_upload2(const struct shell *sh, size_t argc,
switch (argv[i][1]) {
case 'S':
tos = parse_arg(&i, argc, argv);
int tos = parse_arg(&i, argc, argv);
if (tos < 0 || tos > UINT8_MAX) {
shell_fprintf(sh, SHELL_WARNING,
"Parse error: %s\n", argv[i]);
return -ENOEXEC;
}
param.options.tos = tos;
break;
default:
shell_fprintf(sh, SHELL_WARNING,
@ -932,21 +787,7 @@ static int shell_cmd_upload2(const struct shell *sh, size_t argc,
family = !strcmp(argv[start + 1], "v4") ? AF_INET : AF_INET6;
if (IS_ENABLED(CONFIG_NET_IPV6)) {
in6_addr_my.sin6_port = htons(port);
}
if (IS_ENABLED(CONFIG_NET_IPV4)) {
in4_addr_my.sin_port = htons(port);
}
if (family == AF_INET6) {
if (net_ipv6_is_addr_unspecified(&in6_addr_my.sin6_addr)) {
shell_fprintf(sh, SHELL_WARNING,
"Invalid local IPv6 address.\n");
return -ENOEXEC;
}
if (net_ipv6_is_addr_unspecified(&in6_addr_dst.sin6_addr)) {
shell_fprintf(sh, SHELL_WARNING,
"Invalid destination IPv6 address.\n");
@ -956,13 +797,9 @@ static int shell_cmd_upload2(const struct shell *sh, size_t argc,
shell_fprintf(sh, SHELL_NORMAL,
"Connecting to %s\n",
net_sprint_ipv6_addr(&in6_addr_dst.sin6_addr));
} else {
if (net_ipv4_is_addr_unspecified(&in4_addr_my.sin_addr)) {
shell_fprintf(sh, SHELL_WARNING,
"Invalid local IPv4 address.\n");
return -ENOEXEC;
}
memcpy(&param.peer_addr, &in6_addr_dst, sizeof(in6_addr_dst));
} else {
if (net_ipv4_is_addr_unspecified(&in4_addr_dst.sin_addr)) {
shell_fprintf(sh, SHELL_WARNING,
"Invalid destination IPv4 address.\n");
@ -972,37 +809,31 @@ static int shell_cmd_upload2(const struct shell *sh, size_t argc,
shell_fprintf(sh, SHELL_NORMAL,
"Connecting to %s\n",
net_sprint_ipv4_addr(&in4_addr_dst.sin_addr));
}
if (setup_upload_sockets(sh, &sock6, &sock4, family, &in6_addr_my,
&in4_addr_my, port, tos, is_udp) < 0) {
return -ENOEXEC;
memcpy(&param.peer_addr, &in4_addr_dst, sizeof(in4_addr_dst));
}
if (argc > 2) {
duration_in_ms = MSEC_PER_SEC * strtoul(argv[start + 2],
NULL, 10);
param.duration_ms = MSEC_PER_SEC * strtoul(argv[start + 2],
NULL, 10);
} else {
duration_in_ms = MSEC_PER_SEC * 1;
param.duration_ms = MSEC_PER_SEC * 1;
}
if (argc > 3) {
packet_size = parse_number(argv[start + 3], K, K_UNIT);
param.packet_size = parse_number(argv[start + 3], K, K_UNIT);
} else {
packet_size = 256U;
param.packet_size = 256U;
}
if (argc > 4) {
rate_in_kbps =
(parse_number(argv[start + 4], K, K_UNIT) + 1023) /
1024;
param.rate_kbps =
(parse_number(argv[start + 4], K, K_UNIT) + 1023) / 1024;
} else {
rate_in_kbps = 10U;
param.rate_kbps = 10U;
}
return execute_upload(sh, sock6, sock4, family, &in6_addr_dst,
&in4_addr_dst, is_udp, port,
duration_in_ms, packet_size, rate_in_kbps);
return execute_upload(sh, &param, is_udp);
}
static int cmd_tcp_upload2(const struct shell *sh, size_t argc,
@ -1105,7 +936,7 @@ static int cmd_tcp_download(const struct shell *sh, size_t argc,
static int cmd_version(const struct shell *sh, size_t argc, char *argv[])
{
shell_fprintf(sh, SHELL_NORMAL, "Version: %s\nConfig: %s\n",
VERSION, CONFIG);
ZPERF_VERSION, CONFIG);
return 0;
}

View file

@ -13,8 +13,8 @@ LOG_MODULE_DECLARE(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL);
#include <zephyr/toolchain.h>
#include <zephyr/net/socket.h>
#include <zephyr/net/zperf.h>
#include "zperf.h"
#include "zperf_internal.h"
#include "shell_utils.h"
#include "zperf_session.h"

View file

@ -12,14 +12,13 @@ LOG_MODULE_DECLARE(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL);
#include <errno.h>
#include <zephyr/net/socket.h>
#include <zephyr/net/zperf.h>
#include "zperf.h"
#include "zperf_internal.h"
static char sample_packet[PACKET_SIZE_MAX];
void zperf_tcp_upload(const struct shell *sh,
int sock,
static int tcp_upload(int sock,
unsigned int duration_in_ms,
unsigned int packet_size,
struct zperf_results *results)
@ -28,11 +27,11 @@ void zperf_tcp_upload(const struct shell *sh,
int64_t start_time, last_print_time, end_time, remaining;
uint32_t nb_packets = 0U, nb_errors = 0U;
uint32_t alloc_errors = 0U;
int ret = 0;
if (packet_size > PACKET_SIZE_MAX) {
shell_fprintf(sh, SHELL_WARNING,
"Packet size too large! max size: %u\n",
PACKET_SIZE_MAX);
NET_WARN("Packet size too large! max size: %u\n",
PACKET_SIZE_MAX);
packet_size = PACKET_SIZE_MAX;
}
@ -40,9 +39,6 @@ void zperf_tcp_upload(const struct shell *sh,
start_time = k_uptime_ticks();
last_print_time = start_time;
shell_fprintf(sh, SHELL_NORMAL,
"New session started\n");
(void)memset(sample_packet, 'z', sizeof(sample_packet));
/* Set the "flags" field in start of the packet to be 0.
@ -52,15 +48,11 @@ void zperf_tcp_upload(const struct shell *sh,
(void)memset(sample_packet, 0, sizeof(uint32_t));
do {
int ret = 0;
/* Send the packet */
ret = zsock_send(sock, sample_packet, packet_size, 0);
if (ret < 0) {
if (nb_errors == 0 && ret != -ENOMEM) {
shell_fprintf(sh, SHELL_WARNING,
"Failed to send the packet (%d)\n",
errno);
NET_ERR("Failed to send the packet (%d)", errno);
}
nb_errors++;
@ -73,6 +65,7 @@ void zperf_tcp_upload(const struct shell *sh,
*/
alloc_errors++;
} else {
ret = -errno;
break;
}
} else {
@ -98,12 +91,40 @@ void zperf_tcp_upload(const struct shell *sh,
results->nb_packets_errors = nb_errors;
if (alloc_errors > 0) {
shell_fprintf(sh, SHELL_WARNING,
"There was %u network buffer allocation "
"errors during send.\nConsider increasing the "
"value of CONFIG_NET_BUF_TX_COUNT and\n"
"optionally CONFIG_NET_PKT_TX_COUNT Kconfig "
"options.\n",
alloc_errors);
NET_WARN("There was %u network buffer allocation "
"errors during send.\nConsider increasing the "
"value of CONFIG_NET_BUF_TX_COUNT and\n"
"optionally CONFIG_NET_PKT_TX_COUNT Kconfig "
"options.",
alloc_errors);
}
if (ret < 0) {
return ret;
}
return 0;
}
int zperf_tcp_upload(const struct zperf_upload_params *param,
struct zperf_results *result)
{
int sock;
int ret;
if (param == NULL || result == NULL) {
return -EINVAL;
}
sock = zperf_prepare_upload_sock(&param->peer_addr, param->options.tos,
IPPROTO_TCP);
if (sock < 0) {
return sock;
}
ret = tcp_upload(sock, param->duration_ms, param->packet_size, result);
zsock_close(sock);
return ret;
}

View file

@ -13,8 +13,8 @@ LOG_MODULE_DECLARE(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL);
#include <zephyr/kernel.h>
#include <zephyr/net/socket.h>
#include <zephyr/net/zperf.h>
#include "zperf.h"
#include "zperf_internal.h"
#include "shell_utils.h"
#include "zperf_session.h"

View file

@ -10,16 +10,15 @@ LOG_MODULE_DECLARE(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL);
#include <zephyr/kernel.h>
#include <zephyr/net/socket.h>
#include <zephyr/net/zperf.h>
#include "zperf.h"
#include "zperf_internal.h"
static uint8_t sample_packet[sizeof(struct zperf_udp_datagram) +
sizeof(struct zperf_client_hdr_v1) +
PACKET_SIZE_MAX];
static inline void zperf_upload_decode_stat(const struct shell *sh,
const uint8_t *data,
static inline void zperf_upload_decode_stat(const uint8_t *data,
size_t datalen,
struct zperf_results *results)
{
@ -27,8 +26,7 @@ static inline void zperf_upload_decode_stat(const struct shell *sh,
if (datalen < sizeof(struct zperf_udp_datagram) +
sizeof(struct zperf_server_hdr)) {
shell_fprintf(sh, SHELL_WARNING,
"Network packet too short\n");
NET_WARN("Network packet too short");
}
stat = (struct zperf_server_hdr *)
@ -38,19 +36,18 @@ static inline void zperf_upload_decode_stat(const struct shell *sh,
results->nb_packets_lost = ntohl(UNALIGNED_GET(&stat->error_cnt));
results->nb_packets_outorder =
ntohl(UNALIGNED_GET(&stat->outorder_cnt));
results->nb_bytes_sent = ntohl(UNALIGNED_GET(&stat->total_len2));
results->total_len = ntohl(UNALIGNED_GET(&stat->total_len2));
results->time_in_us = ntohl(UNALIGNED_GET(&stat->stop_usec)) +
ntohl(UNALIGNED_GET(&stat->stop_sec)) * USEC_PER_SEC;
results->jitter_in_us = ntohl(UNALIGNED_GET(&stat->jitter2)) +
ntohl(UNALIGNED_GET(&stat->jitter1)) * USEC_PER_SEC;
}
static inline void zperf_upload_fin(const struct shell *sh,
int sock,
uint32_t nb_packets,
uint64_t end_time,
uint32_t packet_size,
struct zperf_results *results)
static inline int zperf_upload_fin(int sock,
uint32_t nb_packets,
uint64_t end_time,
uint32_t packet_size,
struct zperf_results *results)
{
uint8_t stats[sizeof(struct zperf_udp_datagram) +
sizeof(struct zperf_server_hdr)] = { 0 };
@ -92,9 +89,7 @@ static inline void zperf_upload_fin(const struct shell *sh,
/* Send the packet */
ret = zsock_send(sock, sample_packet, packet_size, 0);
if (ret < 0) {
shell_fprintf(sh, SHELL_WARNING,
"Failed to send the packet (%d)\n",
errno);
NET_ERR("Failed to send the packet (%d)", errno);
continue;
}
@ -102,26 +97,23 @@ static inline void zperf_upload_fin(const struct shell *sh,
ret = zsock_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &rcvtimeo,
sizeof(rcvtimeo));
if (ret < 0) {
shell_fprintf(sh, SHELL_WARNING,
"setsockopt error (%d)\n",
errno);
NET_ERR("setsockopt error (%d)", errno);
continue;
}
ret = zsock_recv(sock, stats, sizeof(stats), 0);
if (ret == -EAGAIN) {
shell_fprintf(sh, SHELL_WARNING,
"Stats receive timeout\n");
NET_WARN("Stats receive timeout");
} else if (ret < 0) {
shell_fprintf(sh, SHELL_WARNING,
"Failed to receive packet (%d)\n",
errno);
NET_ERR("Failed to receive packet (%d)", errno);
}
}
/* Decode statistics */
if (ret > 0) {
zperf_upload_decode_stat(sh, stats, ret, results);
zperf_upload_decode_stat(stats, ret, results);
} else {
return ret;
}
/* Drain RX */
@ -131,50 +123,37 @@ static inline void zperf_upload_fin(const struct shell *sh,
break;
}
shell_fprintf(sh, SHELL_WARNING,
"Drain one spurious stat packet!\n");
NET_WARN("Drain one spurious stat packet!");
}
return 0;
}
void zperf_udp_upload(const struct shell *sh,
int sock,
int port,
static int udp_upload(int sock, int port,
unsigned int duration_in_ms,
unsigned int packet_size,
unsigned int rate_in_kbps,
struct zperf_results *results)
{
uint32_t packet_duration = ((uint64_t)packet_size * 8U * USEC_PER_SEC) /
(rate_in_kbps * 1024U);
uint32_t packet_duration = zperf_packet_duration(packet_size, rate_in_kbps);
uint64_t duration = sys_clock_timeout_end_calc(K_MSEC(duration_in_ms));
uint64_t delay = packet_duration;
uint32_t nb_packets = 0U;
int64_t start_time, end_time;
int64_t last_print_time, last_loop_time;
int64_t remaining;
int ret;
if (packet_size > PACKET_SIZE_MAX) {
shell_fprintf(sh, SHELL_WARNING,
"Packet size too large! max size: %u\n",
PACKET_SIZE_MAX);
NET_WARN("Packet size too large! max size: %u",
PACKET_SIZE_MAX);
packet_size = PACKET_SIZE_MAX;
} else if (packet_size < sizeof(struct zperf_udp_datagram)) {
shell_fprintf(sh, SHELL_WARNING,
"Packet size set to the min size: %zu\n",
sizeof(struct zperf_udp_datagram));
NET_WARN("Packet size set to the min size: %zu",
sizeof(struct zperf_udp_datagram));
packet_size = sizeof(struct zperf_udp_datagram);
}
if (packet_duration > 1000U) {
shell_fprintf(sh, SHELL_NORMAL,
"Packet duration %u ms\n",
(unsigned int)(packet_duration / 1000U));
} else {
shell_fprintf(sh, SHELL_NORMAL,
"Packet duration %u us\n",
(unsigned int)packet_duration);
}
/* Start the loop */
start_time = k_uptime_ticks();
last_print_time = start_time;
@ -188,7 +167,6 @@ void zperf_udp_upload(const struct shell *sh,
uint32_t secs, usecs;
int64_t loop_time;
int32_t adjust;
int ret;
/* Timestamp */
loop_time = k_uptime_ticks();
@ -237,10 +215,8 @@ void zperf_udp_upload(const struct shell *sh,
/* Send the packet */
ret = zsock_send(sock, sample_packet, packet_size, 0);
if (ret < 0) {
shell_fprintf(sh, SHELL_WARNING,
"Failed to send the packet (%d)\n",
errno);
break;
NET_ERR("Failed to send the packet (%d)", errno);
return -errno;
} else {
nb_packets++;
}
@ -251,10 +227,9 @@ void zperf_udp_upload(const struct shell *sh,
int64_t print_info = print_interval - k_uptime_ticks();
if (print_info <= 0) {
shell_fprintf(sh, SHELL_WARNING,
"nb_packets=%u\tdelay=%u\tadjust=%d\n",
nb_packets, (unsigned int)delay,
(int)adjust);
NET_DBG("nb_packets=%u\tdelay=%u\tadjust=%d",
nb_packets, (unsigned int)delay,
(int)adjust);
print_interval = sys_clock_timeout_end_calc(K_SECONDS(1));
}
}
@ -277,12 +252,52 @@ void zperf_udp_upload(const struct shell *sh,
end_time = k_uptime_ticks();
zperf_upload_fin(sh, sock, nb_packets, end_time, packet_size,
results);
ret = zperf_upload_fin(sock, nb_packets, end_time, packet_size,
results);
if (ret < 0) {
return ret;
}
/* Add result coming from the client */
results->nb_packets_sent = nb_packets;
results->client_time_in_us =
k_ticks_to_us_ceil32(end_time - start_time);
results->packet_size = packet_size;
return 0;
}
int zperf_udp_upload(const struct zperf_upload_params *param,
struct zperf_results *result)
{
int port = 0;
int sock;
int ret;
if (param == NULL || result == NULL) {
return -EINVAL;
}
if (param->peer_addr.sa_family == AF_INET) {
port = ntohs(net_sin(&param->peer_addr)->sin_port);
} else if (param->peer_addr.sa_family == AF_INET6) {
port = ntohs(net_sin6(&param->peer_addr)->sin6_port);
} else {
NET_ERR("Invalid address family (%d)",
param->peer_addr.sa_family);
return -EINVAL;
}
sock = zperf_prepare_upload_sock(&param->peer_addr, param->options.tos,
IPPROTO_UDP);
if (sock < 0) {
return sock;
}
ret = udp_upload(sock, port, param->duration_ms, param->packet_size,
param->rate_kbps, result);
zsock_close(sock);
return ret;
}