TLDR: Is there a way to use "ip route" to add multicast routes for multiple NICs?
We have software that uses two multicast groups to communicate with two different groups of devices on two separate physical networks. With the exception of this application, devices on one network do not need to communicate across our device to communicate with devices on the other network.
To do this the software creates two sockets. Each one is bound to the one of the ip addresses of the separate NICS. That socket is then joined to the multicast group that exists on that network, eg socket 1 is bound to 192.168.0.2 and joined to multicast group 233.255.10.1 while socket 2 is bound to 10.57.31.2 and joined to multicast group 239.255.100.1.
We are currently using a bash script (Linux kernel 3.14.39) to set multicast routes on the two network interfaces using route, eg
route add -net 224.0.0.0 netmask 240.0.0.0 eth0
route add -net 224.0.0.0 netmask 240.0.0.0 eth1
and verified via route -n
Destination Gateway Genmask Flags Metric Ref Use Iface
224.0.0.0 0.0.0.0 240.0.0.0 U 0 0 0 eth0
224.0.0.0 0.0.0.0 240.0.0.0 U 0 0 0 eth1
I recently read that route was deprecated/obsolete and that we should be using ip route instead, eg
ip route add 224.0.0.0/4 dev eth0
ip route add 224.0.0.0/4 dev eth1
Unfortunately, the second call fails with "RTNETLINK answers: File exists" and of course the second route doesn't show up after these calls.
Is there a way to use ip route to add multicast routes to multiple NICs?
I can use /8 as a netmask? eg
ip route add 233.0.0.0/8 dev eth0
and
ip route add 239.0.0.0/8 dev eth1
but this is problematic as the script that does this is not aware of what multicast address is associated with which device and its not always guaranteed to be the same depending on system configuration. Using my first example of route add makes this a non issue.
UPDATES Thanks to an extended discussion with @Ron Maupin, I realized the error was in our code. We were not setting the interface to use for multicasting with IP_MULTICAST_IF. Once I added the setsockopt call to set IP_MULTICAST_IF, I no longer needed to add the routing tables.
struct in_addr multicastInterface = {};
multicastInterface.s_addr = interfaceAddressNetworkOrder;
// Set which outgoing interface to use
int result = setsockopt(m_socket, IPPROTO_IP, IP_MULTICAST_IF, (char*)&multicastInterface, sizeof(struct in_addr));
That you have multicast going through your Linux box by using unicast routing is a combination of a couple of lucky circumstances.
Multicast routing is not the same as unicast routing. Unicast routing is based on the face that traffic is sent to a single address, but multicast traffic is sent to a group address that represents hosts which want to subscribe to the multicast group.
Hosts use IGMP to tell a multicast router that they want to join a multicast group, and the multicast router will then start sending multicast traffic for that group to the network of the hosts requesting this.
Modern switches will use IGMP Snooping to determine which switch ports have hosts requesting to join a particular multicast group, and they will only send traffic for that multicast group to the switch ports where the hosts have requested to join the multicast group.
Linux, by itself, doesn't support multicast routing, and you need to add something to the Linux device to support multicast routing. Refer to the diagram below:
When the multicast source starts to send multicast traffic for a multicast group, the switch probably has not seen any IGMP requests to join the multicast group, so the multicast traffic for that group goes nowhere.
When one of the PCs on the same switch wants to join the multicast group, it will send an IGMP Join message, and the switch will snoop on that and send the multicast traffic to the port where the requesting PC is connected.
If a PC on the other side of the Linux router wants to join the multicast group, it is out of luck because the multicast traffic is not flowing to that side of the Linux Router. The Linux Router has not even joined the multicast group, so the switch never sends the multicast traffic to it.
When you run multicast routing on a router, the router will respond to the host IGMP request, and the switch will know that it is a multicast router, and it will send multicast traffic to the switch port where the multicast router is connected. Simplistically, the router will not send the multicast traffic to another interface unless there is an active receiver on another interface (this depends on the multicast version, for instance, PIM-DM will start sending, but back off if no IGMP requests are seen).
With multicast routing enabled on the router, a PC connected to the other interface will send an IGMP Join message, and the Linux Router will begin sending the multicast traffic for the requested group to the interface. The switch will snoop on the request, and it will send multicast traffic to the switch port where the PC that requested to join the multicast group is connected.
It gets more complicated if you need to route throgh multiple routers. IGMP is used between the hosts and the local multicast router. PIM (or some other multicast routing protocol) is used between multicast routers.
This all prevents multicast traffic from going where it is not wanted.
There are add-ons to Linux to aid it in properly handling IGMP and multicast routing.
To add multiple routes for a target, you can add the first as you have done, by using
ip route add <address> dev <interface>
. To add the second you then useip route append <address> dev <interface2>
.For ipv4 you will need something to manage the IGMP or whichever multicast management protocol you are using. For ipv6 this is baked into the icmpv6 protocol so my understanding is that linux should handle this out of the box for you.