From 6c30c9ac47eaef4ac0e89d23747b8e07af755c5c Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 1 Jun 2022 15:10:26 +0200 Subject: [PATCH] samples: net: zperf: Rewrite upload part to use sockets Rewrite TCP/UDP upload part of the zperf sample to use socket API instead of net_context. This has a negligible impact on the upload throughputs (< 1 Mbps). Signed-off-by: Robert Lubos --- samples/net/zperf/prj.conf | 8 +- samples/net/zperf/src/zperf_internal.h | 4 +- samples/net/zperf/src/zperf_shell.c | 183 ++++++++------------- samples/net/zperf/src/zperf_tcp_uploader.c | 18 +- samples/net/zperf/src/zperf_udp_uploader.c | 114 ++++++------- 5 files changed, 134 insertions(+), 193 deletions(-) diff --git a/samples/net/zperf/prj.conf b/samples/net/zperf/prj.conf index 1a82973d582..a2cd41ad847 100644 --- a/samples/net/zperf/prj.conf +++ b/samples/net/zperf/prj.conf @@ -11,11 +11,17 @@ CONFIG_NET_PKT_RX_COUNT=14 CONFIG_NET_PKT_TX_COUNT=14 CONFIG_NET_BUF_RX_COUNT=28 CONFIG_NET_BUF_TX_COUNT=28 +CONFIG_NET_BUF_DATA_SIZE=1500 CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=4 CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=5 CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=1 CONFIG_NET_MAX_CONTEXTS=5 -CONFIG_NET_CONTEXT_SYNC_RECV=y +CONFIG_NET_CONTEXT_RCVTIMEO=y +CONFIG_NET_TC_TX_COUNT=1 +CONFIG_NET_SOCKETS=y +CONFIG_NET_SOCKETS_POSIX_NAMES=y +CONFIG_NET_SOCKETS_POLL_MAX=4 +CONFIG_POSIX_MAX_FDS=8 CONFIG_INIT_STACKS=y CONFIG_TEST_RANDOM_GENERATOR=y diff --git a/samples/net/zperf/src/zperf_internal.h b/samples/net/zperf/src/zperf_internal.h index d91760aba1c..434de29f70a 100644 --- a/samples/net/zperf/src/zperf_internal.h +++ b/samples/net/zperf/src/zperf_internal.h @@ -79,7 +79,7 @@ int zperf_get_ipv4_addr(const struct shell *shell, char *host, struct sockaddr_in *zperf_get_sin(void); extern void zperf_udp_upload(const struct shell *shell, - struct net_context *context, + int sock, int port, unsigned int duration_in_ms, unsigned int packet_size, @@ -91,7 +91,7 @@ extern void zperf_udp_receiver_init(const struct shell *shell, int port); extern void zperf_tcp_receiver_init(const struct shell *shell, int port); extern void zperf_tcp_uploader_init(struct k_fifo *tx_queue); extern void zperf_tcp_upload(const struct shell *shell, - struct net_context *net_context, + int sock, unsigned int duration_in_ms, unsigned int packet_size, struct zperf_results *results); diff --git a/samples/net/zperf/src/zperf_shell.c b/samples/net/zperf/src/zperf_shell.c index 400fadcb623..fcd41adbff2 100644 --- a/samples/net/zperf/src/zperf_shell.c +++ b/samples/net/zperf/src/zperf_shell.c @@ -17,6 +17,7 @@ LOG_MODULE_REGISTER(net_zperf_sample, LOG_LEVEL_DBG); #include #include +#include #include "zperf.h" #include "zperf_internal.h" @@ -52,7 +53,6 @@ static const char *CONFIG = #define MY_SRC_PORT 50000 #define DEF_PORT 5001 #define DEF_PORT_STR STRINGIFY(DEF_PORT) -#define WAIT_CONNECT K_SECONDS(2) /* in ms */ static struct in6_addr ipv6; @@ -451,27 +451,24 @@ static void shell_tcp_upload_print_stats(const struct shell *shell, } } -static int setup_contexts(const struct shell *shell, - struct net_context **context6, - struct net_context **context4, - sa_family_t family, - struct sockaddr_in6 *ipv6, - struct sockaddr_in *ipv4, - int port, - bool is_udp, - char *argv0) +static int setup_upload_sockets(const struct shell *shell, + int *sock6, + int *sock4, + sa_family_t family, + struct sockaddr_in6 *ipv6, + struct sockaddr_in *ipv4, + int port, + bool is_udp, + char *argv0) { - int ret; - if (IS_ENABLED(CONFIG_NET_IPV6)) { - ret = net_context_get(AF_INET6, - is_udp ? SOCK_DGRAM : SOCK_STREAM, - is_udp ? IPPROTO_UDP : IPPROTO_TCP, - context6); - if (ret < 0) { + *sock6 = socket(AF_INET6, + is_udp ? SOCK_DGRAM : SOCK_STREAM, + is_udp ? IPPROTO_UDP : IPPROTO_TCP); + if (*sock6 < 0) { shell_fprintf(shell, SHELL_WARNING, - "Cannot get IPv6 network context (%d)\n", - ret); + "Cannot create IPv6 network socket (%d)\n", + errno); return -ENOEXEC; } @@ -480,14 +477,13 @@ static int setup_contexts(const struct shell *shell, } if (IS_ENABLED(CONFIG_NET_IPV4)) { - ret = net_context_get(AF_INET, - is_udp ? SOCK_DGRAM : SOCK_STREAM, - is_udp ? IPPROTO_UDP : IPPROTO_TCP, - context4); - if (ret < 0) { + *sock4 = socket(AF_INET, + is_udp ? SOCK_DGRAM : SOCK_STREAM, + is_udp ? IPPROTO_UDP : IPPROTO_TCP); + if (*sock4 < 0) { shell_fprintf(shell, SHELL_WARNING, - "Cannot get IPv4 network context (%d)\n", - ret); + "Cannot create IPv4 network socket (%d)\n", + errno); return -ENOEXEC; } @@ -495,33 +491,9 @@ static int setup_contexts(const struct shell *shell, ipv4->sin_family = AF_INET; } - if (family == AF_INET6 && *context6) { - ret = net_context_bind(*context6, - (struct sockaddr *)ipv6, - sizeof(struct sockaddr_in6)); - if (ret < 0) { - shell_fprintf(shell, SHELL_NORMAL, - "Cannot bind IPv6 port %d (%d)", - ntohs(ipv6->sin6_port), ret); - return -ENOEXEC; - } - } - - if (family == AF_INET && *context4) { - ret = net_context_bind(*context4, - (struct sockaddr *)ipv4, - sizeof(struct sockaddr_in)); - if (ret < 0) { - shell_fprintf(shell, SHELL_WARNING, - "Cannot bind IPv4 port %d (%d)", - ntohs(ipv4->sin_port), ret); - return -ENOEXEC; - } - } - - if (!(*context6) && !(*context4)) { + if ((*sock6 < 0) && (*sock4 < 0)) { shell_fprintf(shell, SHELL_WARNING, - "Fail to retrieve network context(s)\n"); + "Fail to create network socket(s)\n"); return -ENOEXEC; } @@ -529,8 +501,8 @@ static int setup_contexts(const struct shell *shell, } static int execute_upload(const struct shell *shell, - struct net_context *context6, - struct net_context *context4, + int sock6, + int sock4, sa_family_t family, struct sockaddr_in6 *ipv6, struct sockaddr_in *ipv4, @@ -554,7 +526,7 @@ static int execute_upload(const struct shell *shell, rate_in_kbps); shell_fprintf(shell, SHELL_NORMAL, "Starting...\n"); - if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6 && context6) { + if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6 && sock6 >= 0) { /* 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. @@ -570,40 +542,34 @@ static int execute_upload(const struct shell *shell, print_number(shell, rate_in_kbps, KBPS, KBPS_UNIT); shell_fprintf(shell, SHELL_NORMAL, "\n"); - if (family == AF_INET6 && context6) { - ret = net_context_connect(context6, - (struct sockaddr *)ipv6, - sizeof(*ipv6), - NULL, - K_NO_WAIT, - NULL); + if (family == AF_INET6 && sock6 >= 0) { + ret = connect(sock6, + (struct sockaddr *)ipv6, + sizeof(*ipv6)); if (ret < 0) { shell_fprintf(shell, SHELL_WARNING, "IPv6 connect failed (%d)\n", - ret); + errno); goto out; } - zperf_udp_upload(shell, context6, port, duration_in_ms, + zperf_udp_upload(shell, sock6, port, duration_in_ms, packet_size, rate_in_kbps, &results); shell_udp_upload_print_stats(shell, &results); } - if (family == AF_INET && context4) { - ret = net_context_connect(context4, - (struct sockaddr *)ipv4, - sizeof(*ipv4), - NULL, - K_NO_WAIT, - NULL); + if (family == AF_INET && sock4 >= 0) { + ret = connect(sock4, + (struct sockaddr *)ipv4, + sizeof(*ipv4)); if (ret < 0) { shell_fprintf(shell, SHELL_NORMAL, "IPv4 connect failed (%d)\n", - ret); + errno); goto out; } - zperf_udp_upload(shell, context4, port, duration_in_ms, + zperf_udp_upload(shell, sock4, port, duration_in_ms, packet_size, rate_in_kbps, &results); shell_udp_upload_print_stats(shell, &results); } @@ -615,59 +581,51 @@ static int execute_upload(const struct shell *shell, } if (!is_udp && IS_ENABLED(CONFIG_NET_TCP)) { - if (family == AF_INET6 && context6) { - ret = net_context_connect(context6, - (struct sockaddr *)ipv6, - sizeof(*ipv6), - NULL, - WAIT_CONNECT, - NULL); + if (family == AF_INET6 && sock6 >= 0) { + ret = connect(sock6, + (struct sockaddr *)ipv6, + sizeof(*ipv6)); if (ret < 0) { shell_fprintf(shell, SHELL_WARNING, "IPv6 connect failed (%d)\n", - ret); + errno); goto out; } /* We either upload using IPv4 or IPv6, not both at * the same time. */ - if (IS_ENABLED(CONFIG_NET_IPV4)) { - net_context_put(context4); + if (IS_ENABLED(CONFIG_NET_IPV4) && sock4 >= 0) { + (void)close(sock4); + sock4 = -1; } - zperf_tcp_upload(shell, context6, duration_in_ms, + zperf_tcp_upload(shell, sock6, duration_in_ms, packet_size, &results); shell_tcp_upload_print_stats(shell, &results); - - return 0; } - if (family == AF_INET && context4) { - ret = net_context_connect(context4, - (struct sockaddr *)ipv4, - sizeof(*ipv4), - NULL, - WAIT_CONNECT, - NULL); + if (family == AF_INET && sock4 >= 0) { + ret = connect(sock4, + (struct sockaddr *)ipv4, + sizeof(*ipv4)); if (ret < 0) { shell_fprintf(shell, SHELL_WARNING, "IPv4 connect failed (%d)\n", - ret); + errno); goto out; } - if (IS_ENABLED(CONFIG_NET_IPV6)) { - net_context_put(context6); + if (IS_ENABLED(CONFIG_NET_IPV6) && sock6 >= 0) { + (void)close(sock6); + sock6 = -1; } - zperf_tcp_upload(shell, context4, duration_in_ms, + zperf_tcp_upload(shell, sock4, duration_in_ms, packet_size, &results); shell_tcp_upload_print_stats(shell, &results); - - return 0; } } else { if (!IS_ENABLED(CONFIG_NET_TCP)) { @@ -677,11 +635,14 @@ static int execute_upload(const struct shell *shell, } out: - if (IS_ENABLED(CONFIG_NET_IPV6)) { - net_context_put(context6); + if (IS_ENABLED(CONFIG_NET_IPV6) && sock6 >= 0) { + (void)close(sock6); + sock6 = -1; } - if (IS_ENABLED(CONFIG_NET_IPV4)) { - net_context_put(context4); + + if (IS_ENABLED(CONFIG_NET_IPV4) && sock4 >= 0) { + (void)close(sock4); + sock4 = -1; } return 0; @@ -692,7 +653,7 @@ static int shell_cmd_upload(const struct shell *shell, size_t argc, { struct sockaddr_in6 ipv6 = { .sin6_family = AF_INET6 }; struct sockaddr_in ipv4 = { .sin_family = AF_INET }; - struct net_context *context6 = NULL, *context4 = NULL; + int sock6 = -1, sock4 = -1; sa_family_t family = AF_UNSPEC; unsigned int duration_in_ms, packet_size, rate_in_kbps; char *port_str; @@ -786,8 +747,8 @@ static int shell_cmd_upload(const struct shell *shell, size_t argc, } } - if (setup_contexts(shell, &context6, &context4, family, &in6_addr_my, - &in4_addr_my, port, is_udp, argv[start]) < 0) { + if (setup_upload_sockets(shell, &sock6, &sock4, family, &in6_addr_my, + &in4_addr_my, port, is_udp, argv[start]) < 0) { return -ENOEXEC; } @@ -812,7 +773,7 @@ static int shell_cmd_upload(const struct shell *shell, size_t argc, rate_in_kbps = 10U; } - return execute_upload(shell, context6, context4, family, &ipv6, &ipv4, + return execute_upload(shell, sock6, sock4, family, &ipv6, &ipv4, is_udp, port, argv[start], duration_in_ms, packet_size, rate_in_kbps); } @@ -834,7 +795,7 @@ static int cmd_udp_upload(const struct shell *shell, size_t argc, char *argv[]) static int shell_cmd_upload2(const struct shell *shell, size_t argc, char *argv[], enum net_ip_protocol proto) { - struct net_context *context6 = NULL, *context4 = NULL; + int sock6 = -1, sock4 = -1; uint16_t port = DEF_PORT; unsigned int duration_in_ms, packet_size, rate_in_kbps; sa_family_t family; @@ -906,8 +867,8 @@ static int shell_cmd_upload2(const struct shell *shell, size_t argc, net_sprint_ipv4_addr(&in4_addr_dst.sin_addr)); } - if (setup_contexts(shell, &context6, &context4, family, &in6_addr_my, - &in4_addr_my, port, is_udp, argv[start]) < 0) { + if (setup_upload_sockets(shell, &sock6, &sock4, family, &in6_addr_my, + &in4_addr_my, port, is_udp, argv[start]) < 0) { return -ENOEXEC; } @@ -932,7 +893,7 @@ static int shell_cmd_upload2(const struct shell *shell, size_t argc, rate_in_kbps = 10U; } - return execute_upload(shell, context6, context4, family, &in6_addr_dst, + return execute_upload(shell, sock6, sock4, family, &in6_addr_dst, &in4_addr_dst, is_udp, port, argv[start], duration_in_ms, packet_size, rate_in_kbps); } diff --git a/samples/net/zperf/src/zperf_tcp_uploader.c b/samples/net/zperf/src/zperf_tcp_uploader.c index 2ba19752655..d9ba6073a16 100644 --- a/samples/net/zperf/src/zperf_tcp_uploader.c +++ b/samples/net/zperf/src/zperf_tcp_uploader.c @@ -12,9 +12,7 @@ LOG_MODULE_DECLARE(net_zperf_sample, LOG_LEVEL_DBG); #include #include -#include -#include -#include +#include #include "zperf.h" #include "zperf_internal.h" @@ -22,7 +20,7 @@ LOG_MODULE_DECLARE(net_zperf_sample, LOG_LEVEL_DBG); static char sample_packet[PACKET_SIZE_MAX]; void zperf_tcp_upload(const struct shell *shell, - struct net_context *ctx, + int sock, unsigned int duration_in_ms, unsigned int packet_size, struct zperf_results *results) @@ -58,19 +56,17 @@ void zperf_tcp_upload(const struct shell *shell, int ret = 0; /* Send the packet */ - ret = net_context_send(ctx, sample_packet, - packet_size, NULL, - K_NO_WAIT, NULL); + ret = send(sock, sample_packet, packet_size, 0); if (ret < 0) { if (nb_errors == 0 && ret != -ENOMEM) { shell_fprintf(shell, SHELL_WARNING, - "Failed to send the packet (%d)\n", - ret); + "Failed to send the packet (%d)\n", + errno); } nb_errors++; - if (ret == -ENOMEM) { + if (errno == -ENOMEM) { /* Ignore memory errors as we just run out of * buffers which is kind of expected if the * buffer count is not optimized for the test @@ -111,6 +107,4 @@ void zperf_tcp_upload(const struct shell *shell, "options.\n", alloc_errors); } - - net_context_put(ctx); } diff --git a/samples/net/zperf/src/zperf_udp_uploader.c b/samples/net/zperf/src/zperf_udp_uploader.c index 06757f4579d..c256795438e 100644 --- a/samples/net/zperf/src/zperf_udp_uploader.c +++ b/samples/net/zperf/src/zperf_udp_uploader.c @@ -11,43 +11,30 @@ LOG_MODULE_DECLARE(net_zperf_sample, LOG_LEVEL_DBG); #include -#include -#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]; + sizeof(struct zperf_client_hdr_v1) + + PACKET_SIZE_MAX]; static inline void zperf_upload_decode_stat(const struct shell *shell, - struct net_pkt *pkt, + const uint8_t *data, + size_t datalen, struct zperf_results *results) { - NET_PKT_DATA_ACCESS_DEFINE(zperf_udp, struct zperf_udp_datagram); - NET_PKT_DATA_ACCESS_DEFINE(zperf_stat, struct zperf_server_hdr); - struct zperf_udp_datagram *hdr; struct zperf_server_hdr *stat; - hdr = (struct zperf_udp_datagram *) - net_pkt_get_data(pkt, &zperf_udp); - if (!hdr) { + if (datalen < sizeof(struct zperf_udp_datagram) + + sizeof(struct zperf_server_hdr)) { shell_fprintf(shell, SHELL_WARNING, "Network packet too short\n"); - return; } - net_pkt_acknowledge_data(pkt, &zperf_udp); - stat = (struct zperf_server_hdr *) - net_pkt_get_data(pkt, &zperf_stat); - if (!stat) { - shell_fprintf(shell, SHELL_WARNING, - "Network packet too short\n"); - return; - } + (data + sizeof(struct zperf_udp_datagram)); results->nb_packets_rcvd = ntohl(UNALIGNED_GET(&stat->datagrams)); results->nb_packets_lost = ntohl(UNALIGNED_GET(&stat->error_cnt)); @@ -60,34 +47,27 @@ static inline void zperf_upload_decode_stat(const struct shell *shell, ntohl(UNALIGNED_GET(&stat->jitter1)) * USEC_PER_SEC; } -static void stat_received(struct net_context *context, - struct net_pkt *pkt, - union net_ip_header *ip_hdr, - union net_proto_header *proto_hdr, - int status, - void *user_data) -{ - struct net_pkt **stat = user_data; - - *stat = pkt; -} - static inline void zperf_upload_fin(const struct shell *shell, - struct net_context *context, + int sock, uint32_t nb_packets, uint64_t end_time, uint32_t packet_size, struct zperf_results *results) { - struct net_pkt *stat = NULL; + uint8_t stats[sizeof(struct zperf_udp_datagram) + + sizeof(struct zperf_server_hdr)] = { 0 }; struct zperf_udp_datagram *datagram; struct zperf_client_hdr_v1 *hdr; uint32_t secs = k_ticks_to_ms_ceil32(end_time) / 1000U; uint32_t usecs = k_ticks_to_us_ceil32(end_time) - secs * USEC_PER_SEC; int loop = 2; - int ret; + int ret = 0; + struct timeval rcvtimeo = { + .tv_sec = 2, + .tv_usec = 0, + }; - while (!stat && loop-- > 0) { + while (ret <= 0 && loop-- > 0) { datagram = (struct zperf_udp_datagram *)sample_packet; /* Fill the packet header */ @@ -112,60 +92,61 @@ static inline void zperf_upload_fin(const struct shell *shell, hdr->num_of_bytes = htonl(packet_size); /* Send the packet */ - ret = net_context_send(context, sample_packet, packet_size, - NULL, K_NO_WAIT, NULL); + ret = send(sock, sample_packet, packet_size, 0); if (ret < 0) { shell_fprintf(shell, SHELL_WARNING, "Failed to send the packet (%d)\n", - ret); + errno); continue; } /* Receive statistics */ - stat = NULL; + ret = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &rcvtimeo, + sizeof(rcvtimeo)); + if (ret < 0) { + shell_fprintf(shell, SHELL_WARNING, + "setsockopt error (%d)\n", + errno); + continue; + } - ret = net_context_recv(context, stat_received, - K_SECONDS(2), &stat); - if (ret == -ETIMEDOUT) { - break; + ret = recv(sock, stats, sizeof(stats), 0); + if (ret == -EAGAIN) { + shell_fprintf(shell, SHELL_WARNING, + "Stats receive timeout\n"); + } else if (ret < 0) { + shell_fprintf(shell, SHELL_WARNING, + "Failed to receive packet (%d)\n", + errno); } } /* Decode statistics */ - if (stat) { - zperf_upload_decode_stat(shell, stat, results); - - net_pkt_unref(stat); + if (ret > 0) { + zperf_upload_decode_stat(shell, stats, ret, results); } /* Drain RX */ - while (stat) { - stat = NULL; - - ret = net_context_recv(context, stat_received, - K_NO_WAIT, &stat); - if (ret == -ETIMEDOUT) { + while (true) { + ret = recv(sock, stats, sizeof(stats), MSG_DONTWAIT); + if (ret < 0) { break; } - if (stat) { - shell_fprintf(shell, SHELL_WARNING, - "Drain one spurious stat packet!\n"); - - net_pkt_unref(stat); - } + shell_fprintf(shell, SHELL_WARNING, + "Drain one spurious stat packet!\n"); } } void zperf_udp_upload(const struct shell *shell, - struct net_context *context, + 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 = ((uint32_t)packet_size * 8U * USEC_PER_SEC) / + uint32_t packet_duration = ((uint64_t)packet_size * 8U * USEC_PER_SEC) / (rate_in_kbps * 1024U); uint64_t duration = sys_clock_timeout_end_calc(K_MSEC(duration_in_ms)); int64_t print_interval = sys_clock_timeout_end_calc(K_SECONDS(1)); @@ -257,12 +238,11 @@ void zperf_udp_upload(const struct shell *shell, hdr->num_of_bytes = htonl(packet_size); /* Send the packet */ - ret = net_context_send(context, sample_packet, packet_size, - NULL, K_NO_WAIT, NULL); + ret = send(sock, sample_packet, packet_size, 0); if (ret < 0) { shell_fprintf(shell, SHELL_WARNING, "Failed to send the packet (%d)\n", - ret); + errno); break; } else { nb_packets++; @@ -296,7 +276,7 @@ void zperf_udp_upload(const struct shell *shell, end_time = k_uptime_ticks(); - zperf_upload_fin(shell, context, nb_packets, end_time, packet_size, + zperf_upload_fin(shell, sock, nb_packets, end_time, packet_size, results); /* Add result coming from the client */