net: zperf: Add support for bind to host option for tcp/udp download

The current zperf tcp/udp download command doesn't provide the option
to bind the server to a specific host address. If there is more than
one interface, it will not be possible to test each interface with zperf
tcp/udp download command without building the Zpehyr.

This patch will add support for zperf tcp/udp download command to bind
server to host interface address.

Signed-off-by: Rahul Singh <rahul.singh@arm.com>
This commit is contained in:
Rahul Singh 2023-07-17 09:45:39 +01:00 committed by Carles Cufí
commit 6ef75a26ea
4 changed files with 84 additions and 20 deletions

View file

@ -43,6 +43,7 @@ struct zperf_upload_params {
struct zperf_download_params {
uint16_t port;
struct sockaddr addr;
};
struct zperf_results {

View file

@ -178,6 +178,39 @@ static int parse_ipv4_addr(const struct shell *sh, char *host, char *port,
return 0;
}
static int zperf_bind_host(const struct shell *sh,
size_t argc, char *argv[],
struct zperf_download_params *param)
{
int ret;
/* Parse options */
if (argc >= 2) {
param->port = strtoul(argv[1], NULL, 10);
} else {
param->port = DEF_PORT;
}
if (argc >= 3) {
char *addr_str = argv[2];
struct sockaddr addr;
memset(&addr, 0, sizeof(addr));
ret = net_ipaddr_parse(addr_str, strlen(addr_str), &addr);
if (ret < 0) {
shell_fprintf(sh, SHELL_WARNING,
"Cannot parse address \"%s\"\n",
addr_str);
return ret;
}
memcpy(&param->addr, &addr, sizeof(struct sockaddr));
}
return 0;
}
static int cmd_setip(const struct shell *sh, size_t argc, char *argv[])
{
int start = 0;
@ -333,10 +366,12 @@ static int cmd_udp_download(const struct shell *sh, size_t argc,
struct zperf_download_params param = { 0 };
int ret;
if (argc >= 2) {
param.port = strtoul(argv[1], NULL, 10);
} else {
param.port = DEF_PORT;
ret = zperf_bind_host(sh, argc, argv, &param);
if (ret < 0) {
shell_fprintf(sh, SHELL_WARNING,
"Unable to bind host.\n");
shell_help(sh);
return -ENOEXEC;
}
ret = zperf_udp_download(&param, udp_session_cb, (void *)sh);
@ -1120,10 +1155,12 @@ static int cmd_tcp_download(const struct shell *sh, size_t argc,
struct zperf_download_params param = { 0 };
int ret;
if (argc >= 2) {
param.port = strtoul(argv[1], NULL, 10);
} else {
param.port = DEF_PORT;
ret = zperf_bind_host(sh, argc, argv, &param);
if (ret < 0) {
shell_fprintf(sh, SHELL_WARNING,
"Unable to bind host.\n");
shell_help(sh);
return -ENOEXEC;
}
ret = zperf_tcp_download(&param, tcp_session_cb, (void *)sh);
@ -1254,8 +1291,9 @@ SHELL_STATIC_SUBCMD_SET_CREATE(zperf_cmd_tcp,
,
cmd_tcp_upload2),
SHELL_CMD(download, &zperf_cmd_tcp_download,
"[<port>]\n"
"Example: tcp download 5001\n",
"[<port>]: Server port to listen on/connect to\n"
"[<host>]: Bind to <host>, an interface address\n"
"Example: tcp download 5001 192.168.0.1\n",
cmd_tcp_download),
SHELL_SUBCMD_SET_END
);
@ -1312,8 +1350,9 @@ SHELL_STATIC_SUBCMD_SET_CREATE(zperf_cmd_udp,
,
cmd_udp_upload2),
SHELL_CMD(download, &zperf_cmd_udp_download,
"[<port>]\n"
"Example: udp download 5001\n",
"[<port>]: Server port to listen on/connect to\n"
"[<host>]: Bind to <host>, an interface address\n"
"Example: udp download 5001 192.168.0.1\n",
cmd_udp_download),
SHELL_SUBCMD_SET_END
);

View file

@ -46,6 +46,7 @@ static void *tcp_user_data;
static bool tcp_server_running;
static bool tcp_server_stop;
static uint16_t tcp_server_port;
static struct sockaddr tcp_server_addr;
static K_SEM_DEFINE(tcp_server_run, 0, 1);
static void tcp_received(const struct sockaddr *addr, size_t datalen)
@ -150,6 +151,7 @@ static void tcp_server_session(void)
if (IS_ENABLED(CONFIG_NET_IPV4)) {
struct sockaddr_in *in4_addr = zperf_get_sin();
const struct in_addr *addr = NULL;
fds[SOCK_ID_IPV4_LISTEN].fd = zsock_socket(AF_INET, SOCK_STREAM,
IPPROTO_TCP);
@ -158,7 +160,12 @@ static void tcp_server_session(void)
goto error;
}
if (MY_IP4ADDR && strlen(MY_IP4ADDR)) {
addr = &net_sin(&tcp_server_addr)->sin_addr;
if (!net_ipv4_is_addr_unspecified(addr)) {
memcpy(&in4_addr->sin_addr, addr,
sizeof(struct in_addr));
} else if (MY_IP4ADDR && strlen(MY_IP4ADDR)) {
/* Use Setting IP */
ret = zperf_get_ipv4_addr(MY_IP4ADDR,
&in4_addr->sin_addr);
@ -167,9 +174,8 @@ static void tcp_server_session(void)
goto use_existing_ipv4;
}
} else {
/* Use existing IP */
const struct in_addr *addr;
use_existing_ipv4:
/* Use existing IP */
addr = zperf_get_default_if_in4_addr();
if (!addr) {
NET_ERR("Unable to get IPv4 by default");
@ -197,6 +203,7 @@ use_existing_ipv4:
if (IS_ENABLED(CONFIG_NET_IPV6)) {
struct sockaddr_in6 *in6_addr = zperf_get_sin6();
const struct in6_addr *addr = NULL;
fds[SOCK_ID_IPV6_LISTEN].fd = zsock_socket(AF_INET6, SOCK_STREAM,
IPPROTO_TCP);
@ -205,7 +212,12 @@ use_existing_ipv4:
goto error;
}
if (MY_IP6ADDR && strlen(MY_IP6ADDR)) {
addr = &net_sin6(&tcp_server_addr)->sin6_addr;
if (!net_ipv6_is_addr_unspecified(addr)) {
memcpy(&in6_addr->sin6_addr, addr,
sizeof(struct in6_addr));
} else if (MY_IP6ADDR && strlen(MY_IP6ADDR)) {
/* Use Setting IP */
ret = zperf_get_ipv6_addr(MY_IP6ADDR,
MY_PREFIX_LEN_STR,
@ -215,9 +227,8 @@ use_existing_ipv4:
goto use_existing_ipv6;
}
} else {
/* Use existing IP */
const struct in6_addr *addr;
use_existing_ipv6:
/* Use existing IP */
addr = zperf_get_default_if_in6_addr();
if (!addr) {
NET_ERR("Unable to get IPv6 by default");
@ -387,6 +398,7 @@ int zperf_tcp_download(const struct zperf_download_params *param,
tcp_server_port = param->port;
tcp_server_running = true;
tcp_server_stop = false;
memcpy(&tcp_server_addr, &param->addr, sizeof(struct sockaddr));
k_sem_give(&tcp_server_run);

View file

@ -48,6 +48,7 @@ static void *udp_user_data;
static bool udp_server_running;
static bool udp_server_stop;
static uint16_t udp_server_port;
static struct sockaddr udp_server_addr;
static K_SEM_DEFINE(udp_server_run, 0, 1);
static inline void build_reply(struct zperf_udp_datagram *hdr,
@ -251,7 +252,12 @@ static void udp_server_session(void)
goto error;
}
if (MY_IP4ADDR && strlen(MY_IP4ADDR)) {
in4_addr = &net_sin(&udp_server_addr)->sin_addr;
if (!net_ipv4_is_addr_unspecified(in4_addr)) {
memcpy(&in4_addr_my->sin_addr, in4_addr,
sizeof(struct in_addr));
} else if (MY_IP4ADDR && strlen(MY_IP4ADDR)) {
/* Use setting IP */
ret = zperf_get_ipv4_addr(MY_IP4ADDR,
&in4_addr_my->sin_addr);
@ -301,7 +307,12 @@ static void udp_server_session(void)
goto error;
}
if (MY_IP6ADDR && strlen(MY_IP6ADDR)) {
in6_addr = &net_sin6(&udp_server_addr)->sin6_addr;
if (!net_ipv6_is_addr_unspecified(in6_addr)) {
memcpy(&in6_addr_my->sin6_addr, in6_addr,
sizeof(struct in6_addr));
} else if (MY_IP6ADDR && strlen(MY_IP6ADDR)) {
/* Use setting IP */
ret = zperf_get_ipv6_addr(MY_IP6ADDR,
MY_PREFIX_LEN_STR,
@ -441,6 +452,7 @@ int zperf_udp_download(const struct zperf_download_params *param,
udp_server_port = param->port;
udp_server_running = true;
udp_server_stop = false;
memcpy(&udp_server_addr, &param->addr, sizeof(struct sockaddr));
k_sem_give(&udp_server_run);