Linux Multicast-пакеты запускаются dry через 4 минуты - PullRequest
2 голосов
/ 25 февраля 2020

Я пытаюсь обработать поток многоадресных пакетов в Linux. В течение 266 - 278 с (это не всегда одинаковый период времени) прием работает нормально, но после этого пакеты больше не принимаются.

Вот как я инициализирую многоадресную рассылку:

int arg = 1;
int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(fd == -1) {
    fprintf(stderr, "Error creating socket, %s\n", strerror(errno));
    return;
}

if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) < 0) {
    fprintf(stderr, "Failed to set `SO_REUSEADDR`, %s\n", strerror(errno));
    return;
}

fcntl(fd, F_SETFL, O_NONBLOCK);

static struct ifreq intf;
strncpy(intf.ifr_name, cfg->ifname_buf, IF_NAMESIZE);

if(setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (char*)&intf, sizeof(intf)) < 0) {
    fprintf(stderr, "Failed to set `SO_BINDTODEVICE`, %s\n", strerror(errno));
    return;
}


struct sockaddr_in sin;
memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_port = htons(xxxxx);
sin.sin_addr.s_addr = inet_addr("xxx.xxx.xxx.xxx");

if(bind(fd, (struct sockaddr*)&sin, sizeof(struct sockaddr)) < 0) {
    fprintf(stderr, "Error on binding socket, %s\n", strerror(errno));
    return;
}

ioctl(fd, SIOCGIFADDR, &intf);

struct ip_mreqn igmpv2_req;
memset(&igmpv2_req, 0, sizeof(struct ip_mreqn));

if(inet_pton(AF_INET, "xxx.xxx.xxx.xxx", &igmpv2_req.imr_multiaddr.s_addr)) {

    memcpy(&igmpv2_req.imr_address, &cfg->ifaddr.sin_addr, sizeof(struct in_addr));
    igmpv2_req.imr_ifindex = cfg->ifindex;

    printf("Multiaddr: %s\n", inet_ntoa(igmpv2_req.imr_multiaddr));
    printf("Interfaceaddr: %s\n", inet_ntoa(igmpv2_req.imr_address));
    printf("Ifindex: %d\n", igmpv2_req.imr_ifindex);

    if(setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &igmpv2_req, sizeof(struct ip_mreqn)) < 0) {
        fprintf(stderr, "Failed to set `IP_ADD_MEMBERSHIP`: %s\n", strerror(errno));
        return;
    } else {
        printf("Saved FD for igmp socket!\n");
        cfg->socket_fd_igmp = fd;
    }
} else {
    fprintf(stderr, "Failed `inet_pton` igmp-multiaddr, %s\n", strerror(errno));
    return;
}

Как я уже сказал, он отлично работает в течение 266 - 280 с. После этого пакеты не принимаются. Я не знаю, связано ли это с тем, как я добавляю интерфейс в группу многоадресной рассылки, или из-за переполнения некоторой очереди ядра (я получаю до 200 тыс. Пакетов в секунду).

1 Ответ

1 голос
/ 25 февраля 2020

Multicast - это не тривиальная вещь. Из того, что вы описываете, происходит следующее:

Когда вы выполняете

setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &igmpv2_req, sizeof(struct ip_mreqn))

, тогда клиент отправляет сообщение присоединения igmp для этой группы. На вашем коммутаторе igmp snooping включен и теперь он знает, что нужно перенаправить многоадресные пакеты для этой группы на порт вашего хоста.

Теперь, после того времени, которое вы наблюдали (4-5 минут, 260 секунд действительно является значением по умолчанию для многих коммутаторов) эта информация в коммутаторе истекает, потому что хост не отправляет эти сообщения регулярно / незапрошенно.

Вам необходим многоадресный маршрутизатор в вашей сети, который регулярно запрашивает хосты, которые отвечают отчетами igmp о группах многоадресной рассылки, которые они слушают, чтобы поддерживать таблицы отслеживания igmp на коммутационном оборудовании в актуальном состоянии.

В качестве альтернативы можно также попытаться отключить отслеживание igmp на всех устройствах между отправителем и получателем многоадресной рассылки, чтобы все многоадресные сообщения были перенесены на все порты (делая их широковещательными с уровня -2 точка зрения). Это может создать довольно большую нагрузку на сегмент уровня 2, поэтому предпочтителен первый метод.

Уродливый обходной путь (который я еще не тестировал) может состоять в удалении и повторном добавлении членства с * 1026. * каждые 2-3 минуты. Это должно заставить пакет igmp и, следовательно, поддерживать многоадресное соединение, но это не то, как он должен работать.

...