From 812a1bc1524f40810e9d07be8914eb2e988bc3ec Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 18 Nov 2022 13:46:25 +0100 Subject: [PATCH] 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 --- include/zephyr/net/zperf.h | 81 ++++++ subsys/net/lib/zperf/CMakeLists.txt | 1 + subsys/net/lib/zperf/zperf.h | 29 -- subsys/net/lib/zperf/zperf_common.c | 89 ++++++ subsys/net/lib/zperf/zperf_internal.h | 20 +- subsys/net/lib/zperf/zperf_session.h | 1 - subsys/net/lib/zperf/zperf_shell.c | 317 +++++----------------- subsys/net/lib/zperf/zperf_tcp_receiver.c | 2 +- subsys/net/lib/zperf/zperf_tcp_uploader.c | 63 +++-- subsys/net/lib/zperf/zperf_udp_receiver.c | 2 +- subsys/net/lib/zperf/zperf_udp_uploader.c | 131 +++++---- 11 files changed, 368 insertions(+), 368 deletions(-) create mode 100644 include/zephyr/net/zperf.h delete mode 100644 subsys/net/lib/zperf/zperf.h create mode 100644 subsys/net/lib/zperf/zperf_common.c diff --git a/include/zephyr/net/zperf.h b/include/zephyr/net/zperf.h new file mode 100644 index 00000000000..f09719dd18d --- /dev/null +++ b/include/zephyr/net/zperf.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file zperf.h + * + * @brief Zperf API + * @defgroup zperf Zperf API + * @ingroup networking + * @{ + */ + +#ifndef ZEPHYR_INCLUDE_NET_ZPERF_H_ +#define ZEPHYR_INCLUDE_NET_ZPERF_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct zperf_upload_params { + struct sockaddr peer_addr; + uint32_t duration_ms; + uint32_t rate_kbps; + uint16_t packet_size; + struct { + uint8_t tos; + } options; +}; + +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 total_len; + 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; +}; + +/** + * @brief Synchronous UDP upload operation. The function blocks until the upload + * is complete. + * + * @param param Upload parameters. + * @param result Session results. + * + * @return 0 if session completed successfully, a negative error code otherwise. + */ +int zperf_udp_upload(const struct zperf_upload_params *param, + struct zperf_results *result); + +/** + * @brief Synchronous TCP upload operation. The function blocks until the upload + * is complete. + * + * @param param Upload parameters. + * @param result Session results. + * + * @return 0 if session completed successfully, a negative error code otherwise. + */ +int zperf_tcp_upload(const struct zperf_upload_params *param, + struct zperf_results *result); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_NET_ZPERF_H_ */ diff --git a/subsys/net/lib/zperf/CMakeLists.txt b/subsys/net/lib/zperf/CMakeLists.txt index 9994c617b2f..3db391f2a71 100644 --- a/subsys/net/lib/zperf/CMakeLists.txt +++ b/subsys/net/lib/zperf/CMakeLists.txt @@ -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 diff --git a/subsys/net/lib/zperf/zperf.h b/subsys/net/lib/zperf/zperf.h deleted file mode 100644 index f47f55177cf..00000000000 --- a/subsys/net/lib/zperf/zperf.h +++ /dev/null @@ -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 */ diff --git a/subsys/net/lib/zperf/zperf_common.c b/subsys/net/lib/zperf/zperf_common.c new file mode 100644 index 00000000000..044fdd1cef7 --- /dev/null +++ b/subsys/net/lib/zperf/zperf_common.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +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)); +} diff --git a/subsys/net/lib/zperf/zperf_internal.h b/subsys/net/lib/zperf/zperf_internal.h index 11de948995c..2fa10385c44 100644 --- a/subsys/net/lib/zperf/zperf_internal.h +++ b/subsys/net/lib/zperf/zperf_internal.h @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -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 */ diff --git a/subsys/net/lib/zperf/zperf_session.h b/subsys/net/lib/zperf/zperf_session.h index 112c55631dc..be0560e195c 100644 --- a/subsys/net/lib/zperf/zperf_session.h +++ b/subsys/net/lib/zperf/zperf_session.h @@ -15,7 +15,6 @@ #include #include -#include "zperf.h" #include "zperf_internal.h" #include "shell_utils.h" diff --git a/subsys/net/lib/zperf/zperf_shell.c b/subsys/net/lib/zperf/zperf_shell.c index 2705c37a706..62ed74dbf99 100644 --- a/subsys/net/lib/zperf/zperf_shell.c +++ b/subsys/net/lib/zperf/zperf_shell.c @@ -17,8 +17,8 @@ LOG_MODULE_REGISTER(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL); #include #include #include +#include -#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 *)¶m->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(¶m.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(¶m.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(¶m.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(¶m.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, ¶m, 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(¶m.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(¶m.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, ¶m, 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; } diff --git a/subsys/net/lib/zperf/zperf_tcp_receiver.c b/subsys/net/lib/zperf/zperf_tcp_receiver.c index 618a71baf17..da4c0b13af7 100644 --- a/subsys/net/lib/zperf/zperf_tcp_receiver.c +++ b/subsys/net/lib/zperf/zperf_tcp_receiver.c @@ -13,8 +13,8 @@ LOG_MODULE_DECLARE(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL); #include #include +#include -#include "zperf.h" #include "zperf_internal.h" #include "shell_utils.h" #include "zperf_session.h" diff --git a/subsys/net/lib/zperf/zperf_tcp_uploader.c b/subsys/net/lib/zperf/zperf_tcp_uploader.c index 1c4b463e4ec..2fb5234f030 100644 --- a/subsys/net/lib/zperf/zperf_tcp_uploader.c +++ b/subsys/net/lib/zperf/zperf_tcp_uploader.c @@ -12,14 +12,13 @@ LOG_MODULE_DECLARE(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL); #include #include +#include -#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(¶m->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; } diff --git a/subsys/net/lib/zperf/zperf_udp_receiver.c b/subsys/net/lib/zperf/zperf_udp_receiver.c index 6d45c32a893..705eb5bef4f 100644 --- a/subsys/net/lib/zperf/zperf_udp_receiver.c +++ b/subsys/net/lib/zperf/zperf_udp_receiver.c @@ -13,8 +13,8 @@ LOG_MODULE_DECLARE(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL); #include #include +#include -#include "zperf.h" #include "zperf_internal.h" #include "shell_utils.h" #include "zperf_session.h" diff --git a/subsys/net/lib/zperf/zperf_udp_uploader.c b/subsys/net/lib/zperf/zperf_udp_uploader.c index bd127d5181e..f83ae2ba533 100644 --- a/subsys/net/lib/zperf/zperf_udp_uploader.c +++ b/subsys/net/lib/zperf/zperf_udp_uploader.c @@ -10,16 +10,15 @@ LOG_MODULE_DECLARE(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL); #include #include +#include -#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(¶m->peer_addr)->sin_port); + } else if (param->peer_addr.sa_family == AF_INET6) { + port = ntohs(net_sin6(¶m->peer_addr)->sin6_port); + } else { + NET_ERR("Invalid address family (%d)", + param->peer_addr.sa_family); + return -EINVAL; + } + + sock = zperf_prepare_upload_sock(¶m->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; }