1

I have a machine with 4 Ethernet Interfaces (ensf1s1, ensf1s2, ensf1s3, ensf1f4) and using GNAT.Sockets I need to be able to send/recieve data over each interface.

The code I am using is

Create_Socket(SendFrom1, Family_Inet, Socket_Datagram);
Create_Socket(SendFrom2, Family_Inet, Socket_Datagram);
...
Bind_Socket(SendFrom1, SendFrom1Address);
Bind_Socket(SendFrom2, SendFrom2Address);
...
Channel1 := Stream(SendFrom1, SendToAddress1);
Channel2 := Stream(SendFrom2, SendToAddress2);
...

With IP addresses configured as 192.168.1.(101/102/103/104) I am getting all messages sent over a single interface with the correctly specified Source and Destination IPs in the packet.

I read in another question that having multiple NICs on the same subnet could cause a problem to some OS's so I changed to 192.168.1.101, 192.168.2.102 etc with a Subnet mask of 255.255.0.0. Using the same code with Addresses corrected this only sent data intended for the interface which previously sent all messages but nothing on the other 3.

Have I missed something in my Socket configuration to ensure a Socket is binded to the adaptor with the SendFromAddress specified? The OS is RHEL 7 if that's relevant.

MattP
  • 2,798
  • 2
  • 31
  • 42

1 Answers1

0

Your question is related to how sockets are working.

If you bind your socket to a specific address, you will receive packets only for that destination address. To receive packets from any of your four interfaces, you may bind to the INADDR_ANY address. You will do this as follows:

Address     : GNAT.Sockets.Sock_Addr_Type;
SendFromAll : GNAT.Sockets.Socket_Type;
   ...
   Address.Port := 0; --  Or whatever fixed port you like
   Address.Addr := GNAT.Sockets.Any_Inet_Addr;
   GNAT.Sockets.Bind_Socket (SendFromAll, Address);

Using this implementation, the SendFromAll socket will receive data from any interface. With Receive_Socket, you can get the sender address. Then when you send data back to the client using the SendFromAll socket, the system will pick an interface depending on the destination address and the network routing tables. On Linux, it will depend on the routing policy (ip rule) and on the routing tables (ip route).

Client  : GNAT.Sockets.Sock_Addr_Type;
Buffer  : Ada.Streams.Stream_Element_Array (0 .. 8192);
Last    : Ada.Streams.Stream_Element_Offset;
....
   GNAT.Sockets.Receive_Socket (SendFromAll, Buffer, Last, Client);
   GNAT.Sockets.Send_Socket (SendFromAll, Buffer (Buffer'First .. Last), Last, Client);

Now if you really need to bind a socket to an interface, you must get the IP address of that interface. If you have several interfaces, you have to get their own IP addresses. There is no easy way with GNAT.Sockets to do this. You can use the Get_Host_By_Name function but you must setup different names for each interface (otherwise you'll get the same IP for each socket).

Another way which is not possible with GNAT.Sockets is to use the SO_BINDTODEVICE socket option. You bind the socket to the interface name (you don't need to get the IP).

What may happen to you is that you are using the same IP address for each Bind_Socket call.

ciceron
  • 586
  • 5
  • 10