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:
parent
8c19142278
commit
10670b7515
4 changed files with 196 additions and 2 deletions
|
@ -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, ¶m->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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue