net: zperf: multicast support on multi interfaces

Zperf upload multicast always use default interface.
Zperf download multicast cannot receive packets from other than
224.0.0.1 which is default multicast group.

Add zperf upload/download option -I <interface name> for multicast.
So that user can select interface for multicast.
Add join multicast group for zperf download.

Use the "device list" command to get the interface name as
follows:
 "- ua (READY)"  #uAP interface name
 "- ml (READY)"  #STA interface name

Multicast traffic commands:
zperf udp upload -a -I ua 224.0.0.2 5001 10 1470 1M
zperf udp download -I ua 5001 224.0.0.3

Signed-off-by: Fengming Ye <frank.ye@nxp.com>
This commit is contained in:
Fengming Ye 2024-03-12 11:12:05 +09:00 committed by Henrik Brix Andersen
commit 10670b7515
4 changed files with 196 additions and 2 deletions

View file

@ -23,6 +23,10 @@ LOG_MODULE_DECLARE(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL);
#define NET_LOG_ENABLED 1
#include "net_private.h"
/* To support multicast */
#include "ipv6.h"
#include "zephyr/net/igmp.h"
static struct sockaddr_in6 *in6_addr_my;
static struct sockaddr_in *in4_addr_my;
@ -45,6 +49,7 @@ static void udp_svc_handler(struct k_work *work);
NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(svc_udp, NULL, udp_svc_handler,
SOCK_ID_MAX);
static char udp_server_iface_name[IFNAMSIZ];
static inline void build_reply(struct zperf_udp_datagram *hdr,
struct zperf_server_hdr *stat,
@ -225,6 +230,63 @@ static void udp_received(int sock, const struct sockaddr *addr, uint8_t *data,
}
}
static void zperf_udp_join_mcast_ipv4(char *if_name, struct in_addr *addr)
{
struct net_if *iface = NULL;
if (if_name[0]) {
iface = net_if_get_by_index(net_if_get_by_name(if_name));
if (iface == NULL)
iface = net_if_get_default();
} else {
iface = net_if_get_default();
}
if (iface != NULL) {
net_ipv4_igmp_join(iface, addr, NULL);
}
}
static void zperf_udp_join_mcast_ipv6(char *if_name, struct in6_addr *addr)
{
struct net_if *iface = NULL;
if (if_name[0]) {
iface = net_if_get_by_index(net_if_get_by_name(if_name));
if (iface == NULL)
iface = net_if_get_default();
} else {
iface = net_if_get_default();
}
if (iface != NULL) {
net_ipv6_mld_join(iface, addr);
}
}
static void zperf_udp_leave_mcast(int sock)
{
struct net_if *iface = NULL;
struct sockaddr addr = {0};
socklen_t addr_len = NET_IPV6_ADDR_SIZE;
zsock_getsockname(sock, &addr, &addr_len);
if (IS_ENABLED(CONFIG_NET_IPV4) && addr.sa_family == AF_INET) {
struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
if (net_ipv4_is_addr_mcast(&addr4->sin_addr))
net_ipv4_igmp_leave(iface, &addr4->sin_addr);
}
if (IS_ENABLED(CONFIG_NET_IPV6) && addr.sa_family == AF_INET6) {
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
if (net_ipv6_is_addr_mcast(&addr6->sin6_addr))
net_ipv6_mld_leave(iface, &addr6->sin6_addr);
}
}
static void udp_receiver_cleanup(void)
{
int i;
@ -233,6 +295,7 @@ static void udp_receiver_cleanup(void)
for (i = 0; i < ARRAY_SIZE(fds); i++) {
if (fds[i].fd >= 0) {
zperf_udp_leave_mcast(fds[i].fd);
zsock_close(fds[i].fd);
fds[i].fd = -1;
}
@ -350,6 +413,11 @@ use_any_ipv4:
in4_addr_my->sin_addr.s_addr = INADDR_ANY;
}
if (net_ipv4_is_addr_mcast(&in4_addr_my->sin_addr)) {
zperf_udp_join_mcast_ipv4(udp_server_iface_name,
&in4_addr_my->sin_addr);
}
NET_INFO("Binding to %s",
net_sprint_ipv4_addr(&in4_addr_my->sin_addr));
@ -402,6 +470,11 @@ use_any_ipv6:
sizeof(struct in6_addr));
}
if (net_ipv6_is_addr_mcast(&in6_addr_my->sin6_addr)) {
zperf_udp_join_mcast_ipv6(udp_server_iface_name,
&in6_addr_my->sin6_addr);
}
NET_INFO("Binding to %s",
net_sprint_ipv6_addr(&in6_addr_my->sin6_addr));
@ -451,6 +524,18 @@ int zperf_udp_download(const struct zperf_download_params *param,
udp_server_port = param->port;
memcpy(&udp_server_addr, &param->addr, sizeof(struct sockaddr));
if (param->if_name[0]) {
/*
* IFNAMSIZ by default CONFIG_NET_INTERFACE_NAME_LEN
* is at least 1 so no overflow risk here
*/
(void)memset(udp_server_iface_name, 0, IFNAMSIZ);
strncpy(udp_server_iface_name, param->if_name, IFNAMSIZ);
udp_server_iface_name[IFNAMSIZ - 1] = 0;
} else {
udp_server_iface_name[0] = 0;
}
ret = zperf_udp_receiver_init();
if (ret < 0) {
udp_receiver_cleanup();