Я сделал приложение для Linux для получения многоадресного трафика.Это работает, когда я подключаюсь к одному интерфейсу.Когда я подключаюсь к потоку, в Wireshark я вижу соединение IGMP, и когда коммутатор отправляет запросы IGMP, Linux отвечает с отчетом IGMP для потока.
Однако мне нужна большая пропускная способность, чем мой единственный интерфейсможет обеспечить.Для большей пропускной способности у меня есть несколько интерфейсов в одной сети.Поэтому я продублировал свой код, чтобы два интерфейса подключались к потоку.В этом случае в Wireshark я вижу соединение IGMP на обоих интерфейсах, но когда коммутатор отправляет запросы IGMP, Linux отвечает только отчетом IGMP на одном интерфейсе.Таким образом происходит тайм-аут переключения, и я теряю поток на интерфейсе, который не сообщает.
Вот воспроизводимый пример.Он не получает никаких данных, но достаточно увидеть, что проблема возникает в Wireshark:
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
// Create and fill internet socket address structure for both sockets.
struct sockaddr_in internetSocketAdressStructure;
bzero(&internetSocketAdressStructure, sizeof(internetSocketAdressStructure));
internetSocketAdressStructure.sin_family = AF_INET;
internetSocketAdressStructure.sin_addr.s_addr=htonl(INADDR_ANY);
internetSocketAdressStructure.sin_port = htons(10000);
// Create first socket.
int firstSocketToUse;
if ((firstSocketToUse = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("First socket failed");
exit(1);
}
// Set first socket for address reuse.
int reuseAddressForFirstSocket;
reuseAddressForFirstSocket = 1;
if (setsockopt(firstSocketToUse, SOL_SOCKET, SO_REUSEADDR, ( char* )&reuseAddressForFirstSocket, sizeof(reuseAddressForFirstSocket) ) == -1 ) {
perror("Error setting first socket for address reuse");
exit(1);
}
// Bind first socket.
if (bind(firstSocketToUse, (struct sockaddr *)&internetSocketAdressStructure, sizeof(internetSocketAdressStructure))==-1) {
perror("First bind failed");
exit(1);
}
// Join stream on first socket.
struct ip_mreq multicastRequestOnFirstInterface;
multicastRequestOnFirstInterface.imr_multiaddr.s_addr = inet_addr("239.120.15.2");
multicastRequestOnFirstInterface.imr_interface.s_addr = inet_addr("25.25.40.116");
if (setsockopt(firstSocketToUse, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&multicastRequestOnFirstInterface, sizeof(multicastRequestOnFirstInterface)) == -1) {
perror("Error joining multicast group on Interface 1");
exit(1);
}
// Create second socket.
int secondSocketToUse;
if ((secondSocketToUse = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Second socket failed");
exit(1);
}
// Set second socket for address reuse.
int reuseAddressForSecondSocket;
reuseAddressForSecondSocket = 1;
if (setsockopt(secondSocketToUse, SOL_SOCKET, SO_REUSEADDR, ( char* )&reuseAddressForSecondSocket, sizeof(reuseAddressForSecondSocket) ) == -1 ) {
perror("Error setting second socket for address reuse");
exit(1);
}
// Bind second socket.
if (bind(secondSocketToUse, (struct sockaddr *)&internetSocketAdressStructure, sizeof(internetSocketAdressStructure))==-1) {
perror("Second bind failed");
exit(1);
}
// Join stream on second socket.
struct ip_mreq multicastRequestOnSecondInterface;
multicastRequestOnSecondInterface.imr_multiaddr.s_addr = inet_addr("239.120.15.2");
multicastRequestOnSecondInterface.imr_interface.s_addr = inet_addr("25.25.40.134");
if (setsockopt(secondSocketToUse, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&multicastRequestOnSecondInterface, sizeof(multicastRequestOnSecondInterface)) == -1) {
perror("Error joining multicast group on Interface 2");
exit(1);
}
// Wait forever.
while(1) {}
}
Я видел сообщение в Stackoverflow, предлагающее сделать это только с одним сокетом,так что я попробовал, но возникает та же проблема.Вот код для этого:
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
// Create and fill internet socket address structure for the socket.
struct sockaddr_in internetSocketAdressStructure;
bzero(&internetSocketAdressStructure, sizeof(internetSocketAdressStructure));
internetSocketAdressStructure.sin_family = AF_INET;
internetSocketAdressStructure.sin_addr.s_addr=htonl(INADDR_ANY);
internetSocketAdressStructure.sin_port = htons(10000);
// Create socket.
int socketToUse;
if ((socketToUse = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket failed");
exit(1);
}
// Bind socket.
if (bind(socketToUse, (struct sockaddr *)&internetSocketAdressStructure, sizeof(internetSocketAdressStructure))==-1) {
perror("bind failed");
exit(1);
}
// Set first socket for address reuse.
int reuseAddress;
reuseAddress = 1;
if (setsockopt(socketToUse, SOL_SOCKET, SO_REUSEADDR, ( char* )&reuseAddress, sizeof(int) ) == -1 ) {
perror("Error setting socket for address reuse");
exit(1);
}
// Join stream on first interface.
struct ip_mreq multicastRequestOnFirstInterface;
multicastRequestOnFirstInterface.imr_multiaddr.s_addr = inet_addr("239.120.15.2");
multicastRequestOnFirstInterface.imr_interface.s_addr = inet_addr("25.25.40.116");
if (setsockopt(socketToUse, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&multicastRequestOnFirstInterface, sizeof(multicastRequestOnFirstInterface)) == -1)
{
perror("Error joining multicast group on first interface");
exit(1);
}
// Join stream on second interface.
struct ip_mreq multicastRequestOnSecondInterface;
multicastRequestOnSecondInterface.imr_multiaddr.s_addr = inet_addr("239.120.15.2");
multicastRequestOnSecondInterface.imr_interface.s_addr = inet_addr("25.25.40.134");
if (setsockopt(socketToUse, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&multicastRequestOnSecondInterface, sizeof(multicastRequestOnSecondInterface)) == -1)
{
perror("Error joining multicast group on second interface");
exit(1);
}
// Wait forever.
while(1) {}
}
Я также пытался перевести интерфейсы в беспорядочный режим:
sudo ip link set interface1 promisc on
sudo ip link set interface2 promisc on
и добавить опцию noprefixroute для каждого интерфейса:
sudo ip addr change 25.25.40.134 dev interface1 noprefixroute
sudo ip addr change 25.25.40.116 dev interface2 noprefixroute
Обе эти проблемы не смогли решить мою проблему.
При этом я нашел источники ( 1 , 2 ), которые могут указывать на то, чтоЯ пытаюсь сделать это невозможно, хотя эти источники кажутся несколько старыми.
Мне удалось решить проблему, поместив оба порта на коммутаторе в разные vlans, хотя это неуклюжее / ужасное решение, которое можетнеприемлемо.
Возможно ли подключение к многоадресным потокам в одной сети через два интерфейса и настроить сеть для ответа на запросы IGMP на обоих интерфейсах?