📜 ⬆️ ⬇️

Unicast multicast traffic routing

Foreword


Recently, I noticed that when watching multicast IPTV over Wi-Fi, some of the traffic is lost. After a detailed study of the problem, it was found out that this behavior is explained by the nature of multicast traffic, namely, the MAC address of the packet recipient. It does not depend on the recipient and is formed from the address of the multicast group. Accordingly, all clients connected to a wireless access point claim to such packets. As a result, we get only a part of the packages and we see a steep picture.

By standard means, the problem is solved either by creating a separate access point for the client, or by creating a static route for certain multicast groups, or by moving the client to a separate VLAN. All the “power” of such decisions will manifest itself when there are several IPTV set-top boxes on the network wishing to watch the same channel, plus the need for them on the Internet will add complexity to the configuration of the router. I propose a solution to this problem below.

Programs like udpxy are not suitable here, as they change the complete package structure. And we just need to set the required MAC address, while maintaining the network and transport parts so that the client software does not notice any changes.

This solution, let's call it MUT ( M ulticast to U nicast T ranslation), is as follows:
  1. Find out the IP address of the client who wants to connect to the group
  2. Report this to the OS kernel
  3. Learn by IP address the client’s MAC address
  4. Create and send a copy of the package to the appropriate interface.

The execution of steps 1 and 2 lies on the multicast routing program, 3 and 4 - on the core. Both require little change in their work. All work will take place in the GNU / Linux OS.
')

Some theory


Network routing IP version 4 in Linux is based on the following structures:

In Linux, multicast traffic routing is completely controlled from the user's area, namely the router program. The key element in multicast routing is the mfc_cache structure. This is a linked list that stores all the information about each route: the source address of the stream, statistics, further route, etc. Adding and removing mfc_cache structures is done by a user program.

Schematic representation of the mfc_cache list:

image
Image taken from the book “Linux Networking Architecture”

Development


It was based on the Linux 3.18 kernel. To store client IP addresses for each multicast group, expand the mfc_cache with a linked list:

struct mut_dst { struct list_head list; __be32 ip; struct rcu_head rcu; }; 

We introduce the new function ipmr_unicast_xmit . A unicast rtable will be generated in it , but at the same time we will transmit multicast sk_buff . Thus, we select the necessary interface for future dispatch.

Now, in order to further create a neighbor for our recipient, and not for a multicast group, we specify the gateway in the rtable . The rt_gateway field is responsible for this:

 struct rtable *rt; rt = ip_route_output_ports(net, &fl4, NULL, m_dst->ip, 0, 0, 0, IPPROTO_IPIP, RT_TOS(iph->tos), 0); if (IS_ERR(rt)) goto out_free; rt->rt_gateway = m_dst->ip; dev = rt->dst.dev; 

Enter the sysctl variable / proc / sys / net / ipv4 / mut . It will give the opportunity to change the operating mode of the kernel on the fly.

reference
sysctl net.ipv4.mut = 1 - Enables new mode
sysctl net.ipv4.mut = 0 - Returns standard routing mode

As before, you can see the list of routes, now also unicast:

root@multicast:~# cat /proc/net/ip_mr_cache
Group Origin Iif Pkts Bytes Wrong Dsts
0520C3EF 2 18842 25323648 0 01000A0A

More details with all the changes can be found in the repository. Link at the end of the article.

Visual representation of the work (changes in the column with the MAC address):



Router


Based on the program IGMPProxy . You could take any other, the same mrouted . It is very important that all IGMP messages are sent from the IP address of the requesting interface, and nothing prevents us from using it. Details of the changes describe it makes no sense, they can also be found in the corresponding repository. The main thing is that in the management of the kernel there are two new commands that the program should support:


Together with them is passed the structure of the form:

 struct <name> { struct in_addr group; //   struct in_addr origin; //   struct in_addr destination; //   } 

A warning


It is worth noting that such an approach does not allow disconnecting clients from groups for the absence of Membership Report requests, since, based on IGMP, a client who received such a request from another client with the same group does not send a similar one. Therefore, disabling is possible only after receiving an explicit Leave Group-package.

Using


To enable a new feature, you must compile the kernel with the CONFIG_IP_MUT = y option
For the full work of the modified IGMPProxy, you also need to enable CONFIG_SYSCTL_SYSCALL = y

Links


Modified core
Modified IGMPProxy

References


Rami Rosen “Linux Kernel Networking. Implementation and Theory »
Christian Benvenuti "Understanding Linux Network Internals"
Klaus Wehrle and Frank Pahlke "Linux Networking Architecture"

If anyone has a different way to solve the problem, please share in the comments.

Source: https://habr.com/ru/post/302956/


All Articles