Ошибка «Нет такого устройства» при вызове setsockopt IPV6_ADD_MEMBERSHIP

Связано: Ошибка Нет такого устройства в вызове setsockopt

при отслеживании одного из процессов модульного тестирования (я не являюсь автором модульного теста) я сталкиваюсь

socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP) = 8
setsockopt(8, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
setsockopt(8, SOL_IPV6, IPV6_ADD_MEMBERSHIP, "\377\2\0\0\0\0\0\0\0\0\0\0\0\0\0\373\2\0\0\0", 20) = -1 ENODEV (No such device)
close(8)                                = 0

По связанному с этим вопросу предполагается, что MULTICAST не включен на машине.

Тем не менее, я считаю, что в моей среде он включен, поскольку я вижу MULTICAST.

eth0      Link encap:Ethernet  HWaddr 02:42:AC:12:00:02  
          inet addr:172.18.0.2  Bcast:172.18.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:15 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:1518 (1.4 KiB)  TX bytes:0 (0.0 b)

eth1      Link encap:Ethernet  HWaddr 02:42:0A:3C:73:A9  
          inet addr:10.60.115.169  Bcast:10.60.115.255  Mask:255.255.254.0
          inet6 addr: fd20:8b1e:b255:8136:42:aff:fe3c:73a9/64 Scope:Global
          inet6 addr: 2002:3984:3989::2/80 Scope:Global
          inet6 addr: fe80::42:aff:fe3c:73a9/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:9000  Metric:1
          RX packets:2797166513 errors:0 dropped:5 overruns:0 frame:0
          TX packets:1847378326 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:5442226175566 (4.9 TiB)  TX bytes:4392851979876 (3.9 TiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:861782 errors:0 dropped:0 overruns:0 frame:0
          TX packets:861782 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1 
          RX bytes:363667068 (346.8 MiB)  TX bytes:363667068 (346.8 MiB)

а также

$ netstat -g
IPv6/IPv4 Group Memberships
Interface       RefCnt Group
--------------- ------ ---------------------
lo              1      all-systems.mcast.net
eth0            1      all-systems.mcast.net
eth1            1      all-systems.mcast.net
lo              1      ff02::1
lo              1      ff01::1
eth0            1      ff02::1
eth0            1      ff01::1
eth1            1      ff02::202
eth1            2      ff02::1:ff3c:73a9
eth1            1      ff02::1:ff00:2
eth1            1      ff02::1
eth1            1      ff01::1

Любая идея, почему я получаю «Нет такого устройства» в вызове setsockopt?

мне не хватает некоторых опций в /etc/sysctl.conf? Я работаю на RHEL7.4.

Я верю коду, из которого я это вижу

static int
create_ipv6_listener_socket(ifi_info* ifi)
{
    struct ipv6_mreq imr6;
    int err = 0;
    static const int kOn = 1;
    int skt = -1;

    std::string addr_str = sock_addr_to_string(ifi->ifi_ipv6_addr);
    TLOG_INFO(plogger, "Creating listener socket on addr %s", addr_str.c_str());

    skt = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
    if (skt < 0) {
        TLOG_ERROR(plogger,
                   "Failed to create listener socket on addr %s: %d",
                   addr_str.c_str(),
                   errno);
        return -1;
    }

    err = setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
    if (err < 0) {
        TLOG_ERROR(plogger,
                   "For listener socket on %s, failed to set SO_REUSEADDR: %d",
                   addr_str.c_str(),
                   errno);
        close(skt);
        return -1;
    }

    imr6.ipv6mr_interface = ifi->ifi_index;
    err = inet_pton(AF_INET6, "FF02::FB", &imr6.ipv6mr_multiaddr);
    if (err < 1) { 
        TLOG_ERROR(plogger,
                   "For listener socket on %s, failed to assign dns-sd "
                   "multicast address: %d",
                   addr_str.c_str(),
                   errno);
        close(skt);
        return -1;
    }    

    err = setsockopt(skt, IPPROTO_IPV6, IPV6_JOIN_GROUP, &imr6, sizeof(imr6));
    if (err < 0) { 
        TLOG_ERROR(
            plogger,
            "For listener socket on %s, failed to join multicast group: %d",
            addr_str.c_str(),
            errno);
        close(skt);
        return -1;
    }  


static int
create_listener_socket(ifi_info* ifi)
{
    if (ifi->ifi_family == AF_INET) {
        return create_ipv4_listener_socket(ifi);
    } else if (ifi->ifi_family == AF_INET6) {
        return create_ipv6_listener_socket(ifi);
    } else {
        assert(false);
    }

    return -1;
}

static void
create_sockets()
{
    int skt = -1;
    std::vector<struct ifi_info*> interfaces;

    ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
    assert(ifi);
    strcpy(ifi->ifi_name, "fake_ipv6_ifi_info");
    ifi->ifi_family = AF_INET6;
    ifi->ifi_index = 2;
    interfaces.push_back(ifi);

    for (uint32_t ii = 0; ii < interfaces.size(); ++ii) {
        struct ifi_info* ifi = interfaces[ii];

        while ((skt = create_listener_socket(ifi)) == -1) {
            TLOG_ERROR(plogger,
                   "Failed to create a listener socket for interface %s; "
                   "will try again in 5 seconds",
                   ifi->ifi_name);
            sleep(5);
        }
        listener_sockets.push_back(skt);

Я получаю сообщение об ошибке «Для сокета прослушивателя на INADDR_ANY не удалось присоединиться к группе многоадресной рассылки: 19»


person ealeon    schedule 24.07.2018    source источник
comment
Последний аргумент для IPV6_ADD_MEMBERSHIP не является указателем на строку с завершающим нулем, но если это не ваш код и вы не можете его исправить, вопрос не по теме.   -  person user207421    schedule 25.07.2018
comment
@EJP IPV6_ADD_MEMBERSHIP не принимает строку в качестве входных данных, он принимает указатель на структуру ipv6_mreq. Журнал просто отображает необработанные байты этой структуры в строковом формате.   -  person Remy Lebeau    schedule 25.07.2018
comment
@ealeon Второй параметр setsockopt() должен быть IPPROTO_IPV6. Но что более важно, вы пытаетесь присоединиться к многоадресной группе FF02::FB (Multicast DNS) на интерфейсе индекс 2. Какой из ваших интерфейсов на самом деле имеет индекс 2? Это случайно не lo (локальная петля)? Вы пытались использовать индекс 0 или 1 для доступа к eth0/eth1?   -  person Remy Lebeau    schedule 25.07.2018
comment
@RemyLebeau спасибо за ответ. Как вы выяснили, что он пытается присоединиться к IP-адресу многоадресной группы FF02::FB (Multicast DNS) на индексе интерфейса 2   -  person ealeon    schedule 25.07.2018
comment
@RemyLebeau Вот что я сказал. Я не знаю, почему ты повторяешь это и мне. Если это не код, вопрос не по теме.   -  person user207421    schedule 25.07.2018
comment
@EJP кажется, я нашел код   -  person ealeon    schedule 25.07.2018
comment
@ealeon Как вы выяснили ... - прочитав документацию IPV6_ADD_MEMBERSHIP и просмотрев байты, которые вы показали в своем журнале strace (которые записываются в восьмеричном формате). IPV6_ADD_MEMBERSHIP принимает в качестве входных данных структуру ipv6_mreq, которая составляет 20 байтов и содержит 2 поля: 16-байтовый in6_addr для группового IPv6-адреса и 4-байтовый индекс интерфейса. Таким образом, \377\2\0\0\0\0\0\0\0\0\0\0\0\0\0\373 — это байты FF 02 00 00 00 00 00 00 00 00 00 00 00 00 00 FB в шестнадцатеричном формате, также известные как FF02::FB в краткой нотации IPv6, а \2\0\0\0 — это байты 02 00 00 00 в шестнадцатеричном виде, также известные как десятичные 2 в целочисленной форме.   -  person Remy Lebeau    schedule 25.07.2018
comment
@RemyLebeauah, спасибо. Я все еще не следую 100%. FF — это 16-байтовый адрес in6_addr, а 02 — 4-байтовый индекс интерфейса? так что попробуйте использовать FF01::FB или FF00:FB вместо FF02:FB?   -  person ealeon    schedule 26.07.2018
comment
@RemyLebeau я пробовал FF00::FB и FF01:FB, но не повезло   -  person ealeon    schedule 26.07.2018
comment
@RemyLebeau Также я думаю, что сузил код и постоянно вижу, что сообщение об ошибке не удалось присоединиться к группе многоадресной рассылки 19.   -  person ealeon    schedule 26.07.2018
comment
@ealeon, вы игнорируете другой аспект моего предыдущего комментария. Вы сосредотачиваетесь только на ipv6mr_multiaddr, к которому нужно присоединиться, но как насчет ipv6mr_interface, из которого происходит присоединение? Какой из ваших интерфейсов представляет ifi? Например, вы не можете присоединиться из lo. Вы проверили, что ifi указывает на eth0 или eth1? И есть ли у этого интерфейса сетевой маршрут к многоадресному вещателю, к которому вы пытаетесь присоединиться?   -  person Remy Lebeau    schedule 26.07.2018
comment
@RemyLebeau спасибо за терпение. я действительно пытаюсь понять. Как мне проверить, указывает ли ifi на eth0 или eth1, я предполагаю, что это основано на индексе. Я поиграл с индексом 0,1,2 и 3. Я предполагаю, что это означает, что я пробовал со всеми интерфейсами. и как вы можете видеть из netstat -g, разве это не показывает, что lo, eth0 и eth1 имеют включенный многоадресный вещатель, отмеченный MULTICAST?   -  person ealeon    schedule 26.07.2018
comment
@ealeon, ваша регистрация оставляет желать лучшего. Вы должны зарегистрировать имя интерфейса и индекс, который говорит ifi. Кроме того, вы не можете присоединиться из INADDR_ANY, как говорится в вашем предыдущем сообщении об ошибке. Вы должны bind() подключить свой сокет к определенному интерфейсу, чтобы он мог получать пакеты, прежде чем присоединиться к группе, используя этот интерфейс. Вы вообще не звоните bind().   -  person Remy Lebeau    schedule 26.07.2018
comment
@RemyLebeau просто для большего контекста. этот код работает без проблем на производственной машине. Я пытаюсь запустить его на своей личной тестовой машине, которая терпит неудачу. следовательно, я предполагаю, что код в порядке. должны быть некоторые конфигурации с многоадресной рассылкой и интерфейсами, которых нет на моей тестовой машине, но я понятия не имею   -  person ealeon    schedule 26.07.2018
comment
@RemyLebeau Я нашел больше кода, и похоже, что он определяет имя интерфейса?   -  person ealeon    schedule 26.07.2018