3

I try to process a multicast packet stream in Linux. For 266s - 278s (it is not always exactly the same time period) the receiving works fine, but after that, no packets are received anymore.

This is how I initialize the multicast:

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;
}

As I said, it works fine for 266 - 280s. After that, no packets are received. I don't know if this is because of the way I add an interface to the multicast group or because of some Kernel queue being full (I receive up to 200k packets per second).

binaryBigInt
  • 1,526
  • 2
  • 18
  • 44
  • Please [edit] your question and add more details: How do you detect that "no packets are received"? Does your program block waiting for a packet? Does it show an error message? Does a packet sniffer (e.g. Wireshark) show packets? Maybe you should show the code that receives the packets. – Bodo Feb 25 '20 at 13:31

1 Answers1

3

Multicast is not a trivial thing. From what you are describing, the following happens:

When you perform

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

then the client sends out an igmp join message for this group. Your switch has igmp snooping enabled and now knows to forward the multicast packets for this group to the port of your host.

Now, after the time you observed (4-5 minutes, 260 seconds is indeed the default with many switches) this information in the switch times out, because the host does not send these messages regularly/unsolicited.

You need a multicast router on your network, that regularly queries the hosts, which respond with igmp reports for the multicast groups they are listening to, to keep the igmp snooping tables on the switching hardware up to date.

Alternatively, you can also try to disable igmp snooping on all devices between multicast sender and receiver, so that all multicast message are flooded to all ports (making them broadcast from a layer-2 point of view). This can put quite a high load on the layer-2 segment, so the first method is preferred.

An ugly workaround (that I have not tested yet) could be to drop and re-add membership with setsockopt() every 2-3 minutes. This should force an igmp packet and thus maintain multicast connectivity, but this is not how it is supposed to work.

Ctx
  • 18,090
  • 24
  • 36
  • 51
  • Do you know if Linux takes care of the responses to the switch? As far as I know the network I am working in already has all of these multicast routers / switches. – binaryBigInt Feb 25 '20 at 15:18
  • 1
    @binaryBigInt "_Do you know if Linux takes care of the responses to the switch?_" The switch does not query (_some_ switch models can be configured as a querier, but that is not a guarantee), that would be an mcast router. You simply need to fix the network configuration. Disabling IGMP snooping on the switches is generally a bad idea. If IGMP is properly configured on the host, then it should respond to the quesries. – Ron Maupin Feb 25 '20 at 15:26
  • @RonMaupin `Ctx` just wrote that I need a multicast router which queries the hosts which subscribed to the multicast stream. In case they don't reply, they get removed from the switch / router. If I understood correctly, this is contrary to your statement: `The switch does not query`. Because I am not responsible for the networking configuration, I have to assume that everything in the network is working as it should and that somehow my application doesn't reply to the queries of the rooter – binaryBigInt Feb 25 '20 at 15:31
  • @binaryBigInt, normally, switches do not query. IGMP sooping is the switch passively listening to the IGMP conversation between the hosts and router. IGMP is a protocol for the hosts and router to communicate with each other to detemine which multicast group traffic should be on the LAN. There are _some_ models of switches that can be configured as a querier, but it is not universal. A router will query for the IGMP groups that are configured on the router interface. – Ron Maupin Feb 25 '20 at 16:26
  • @RonMaupin I am sorry but this does not solve my problem. To be honest, I don't care if it is the router or the switch who queries the Host for IGMP responses. I don't even have the privilege to change anything regarding the network configuration – binaryBigInt Feb 26 '20 at 07:43
  • @binaryBigInt Well, if you do not have a multicast-capable environment, then you cannot/should not use multicast. But you can still try the "ugly workaround" I proposed above. – Ctx Feb 26 '20 at 08:53
  • @Ctx The "ugly workaround" indeed works. But I still ask my question again: Do I have to implement the replies to the IGMP queries myself or does Linux do that for me as soon as I call `setsockopt(..., IP_ADD_MEMBERSHIP, ...)`? – binaryBigInt Feb 26 '20 at 09:01
  • @binaryBigInt Linux cares about the answers, the problem is, that you _do not have someone who queries_. – Ctx Feb 26 '20 at 09:03
  • @Ctx Okay, thank you! But I have to trust my colleagues on that. – binaryBigInt Feb 26 '20 at 09:17