-
Notifications
You must be signed in to change notification settings - Fork 209
Description
I have a use case where I have two network interfaces in the same subnet.
I am running two instances of the p-net stack, one for each interface.
For this use case, it is important to bind the udp socket to the device using the device name.
If I don't do this bind, the p-net stack will randomly use the wrong interface to send udp messages.
To fix this, I have added a reverse lookup loop to pnal_udp_open
in the linux port.
It searches for the network interface with the given ip and sets the SO_BINDTODEVICE
socket option to bind to the device by name.
For this to work, pf_udp_open
needs to be modified as well. Instead of handing PNAL_IPADDR_ANY
it should use the ip from net->fspm_cfg
.
As far as I know, binding to the device by name does not have any downsides and I would like you to include this feature in your next release.
Below is my proof of concept implementation:
int pf_udp_open (pnet_t * net, pnal_ipport_t port)
{
const uint32_t ip_addr =
(((uint32_t)net->fspm_cfg.if_cfg.ip_cfg.ip_addr.a) << 24) |
(((uint32_t)net->fspm_cfg.if_cfg.ip_cfg.ip_addr.b) << 16) |
(((uint32_t)net->fspm_cfg.if_cfg.ip_cfg.ip_addr.c) << 8) |
((uint32_t)net->fspm_cfg.if_cfg.ip_cfg.ip_addr.d);
return pnal_udp_open (ip_addr, port);
}
int pnal_udp_open (pnal_ipaddr_t addr, pnal_ipport_t port)
{
struct sockaddr_in local;
int id;
const int enable = 1;
id = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (id == -1)
{
return -1;
}
if (setsockopt(id, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) != 0)
{
goto error;
}
/* Find the network interface with the matching IP address */
struct ifaddrs *ifaddr, *ifa;
int found_interface = 0;
if (getifaddrs (&ifaddr) == 0)
{
/* Walk through linked list, looking for matching IP */
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL)
continue;
if (ifa->ifa_addr->sa_family == AF_INET)
{
struct sockaddr_in * ifaddr_in =
(struct sockaddr_in *)ifa->ifa_addr;
if (ntohl (ifaddr_in->sin_addr.s_addr) == addr)
{
/* Found matching interface, bind socket to it */
if (
setsockopt (
id,
SOL_SOCKET,
SO_BINDTODEVICE,
ifa->ifa_name,
strlen (ifa->ifa_name)) == 0)
{
printf ("Socket bound to interface: %s\n", ifa->ifa_name);
found_interface = 1;
break;
}
}
}
}
freeifaddrs (ifaddr);
if (!found_interface)
{
printf (
"Warning: Could not find interface with IP address 0x%08x\n",
addr);
}
}
/* set IP and port number */
local = (struct sockaddr_in){
.sin_family = AF_INET,
.sin_addr.s_addr = htonl (addr),
.sin_port = htons (port),
.sin_zero = {0},
};
if (bind (id, (struct sockaddr *)&local, sizeof (local)) != 0)
{
goto error;
}
return id;
error:
close (id);
return -1;
}