pimd
pimd copied to clipboard
Translation PIM Join/Prune to IGMP Report/Leave
Hi,
Not really a problem or bug but more like a feature request. I have a network topology where there are some routers that are not pim-aware, but can deliver multicast to the network if some client issue an IGMP report. The problem is, those routers do not talk PIM and I have no control over them, so it would be great if pimd could just send an IGMP report/leave upstream upon receipt of a PIM join/prune for specific groups that it is RP of.
Detailing a bit more, below is a drawing of my network topology (hopefully you can understand!) where:
- R1 is the main router and interconnects four networks, one locally attached (192.168.10.0/24) and three via OpenVPN TAP tunnels (192.168.20.0/24, 192.168.30.0/24 and 192.168.40.0/24). It is also a PIM neighbor of R2, R3 and R4
- R2, R3 and R4 are OpenVPN clients that connect to R1 and RPs for multicast groups 239.230.0.0/24, 239.250.0.0/24, 239.240.0.0/24, respectively
- R5, R6 and R7 are routers that I have no control of and are not PIM-aware, but work as IGMP proxies to their upstream multicast networks
What I want to achieve is have all the multicast groups available on every network segment, where a client issues an IGMP report for a group, it traverses through PIM domain and, reaching the RP to the specific group, it sends an IGMP report to the upstream non-pim-aware router, and forwards the traffic back to the client. This behavior could be enabled/disabled by config, for example.
A similar scenario is described in the following two documents by Cisco and Juniper:
- pim-to-igmp-proxy - TechLibrary - Juniper Networks
- IP Multicast: IGMP Configuration Guide, Cisco IOS XE Release 3SE (Cisco WLC 5700 Series) - IGMP Proxy [Support] - Cisco
I have explored a bit your code, and found that maybe the correct point to insert that logic is somewhere in pim_proto.c inside method receive_pim_join_prune()
, but I can obviously be wrong.
If you need more info, or want to discuss a bit more please feel free to ask.
Regards, Tiago
I must say, compared to just about everything else here, this was a perfectly written feature request. Thank you! :smiley:
I understand what you want to achieve, and it also looks a lot like what I've been asked about over email by others as well. It shouldn't be too difficult to add support for it either. Unfortunately I've just entered release mode (about five years later than planned), so I won't be able to work on this for the upcoming v3.0, unless you're interested in pitching in yourself?
From what I can see, we need:
- A neato syntax, e.g. an
igmp-proxy
option to thephyint
setting, perhaps? - A new
passive
mode tophyint
's, such that we don't send PIM messages on your upstream links, e.g. from R2 to R5 - Support for (periodically) sending IGMP v2/v3 reports on
igmp-proxy
phyints for (*,G) we have in the MFC - A "hook point" for our new feature, possibly
receivve_pim_join_prune()
as you mention
For now I can only help out from the sidelines, cheering on, providing pointers and auditing code. Hope that's OK?
Thank you for your interest in the feature!
Yesterday, after your response, I have navigated a bit more over the code, to try to define a possible implementation for this, but I may confess that too many questions arose, so I kindly ask you to give me some directions on how to structure this new interaction.
Regarding your points:
A neato syntax, e.g. an igmp-proxy option to the phyint setting, perhaps?
Seems OK, something like phyint _iface_ igmp-proxy
A new passive mode to phyint's, such that we don't send PIM messages on your upstream links, e.g. from R2 to R5
Found on vif.h the following definition
#define VIFF_ONEWAY 0x000800 /* Maybe one way interface */
Seems like a good mode to place the interface into
Support for (periodically) sending IGMP v2/v3 reports on igmp-proxy phyints for (*,G) we have in the MFC
This includes sending our reports/leaves upstream and answering to general queries, right ? Also, do we need two separate sockets, so we do not send reports/leaves back to PIM neighbors ?
A "hook point" for our new feature, possibly receivve_pim_join_prune() as you mention
Can you please guide me on what part of this method the code knows exacly "I am the RP of this group" ?
Apart from this, I don't mind waiting for your next release, if you prefer to develop yourself and have things structured your way.
Thanks!
Hi again, sorry for the late reply! Been quite busy at $DAYJOB the last couple of weeks.
Huh, had forgotten about VIFF_ONEWAY
, yup we could definitely reuse that. Not sure of the naming though, I think it may have been intended for declaring one-way of bidirectional distribution trees. I think renaming that define to VIFF_PASSIVE
would be the best option. The code base is old, I'm just the current maintainer :)
Yes, sending IGMP reports upstream and answering general, or group-specific, queries. You're right about the socket, we should go with a separate socket for interfaces that have the VIFF_IGMP_PROXY
flag.
Figuring out if I'm the RP is trickier. I'll have to dig in to the code a bit more for that, but one example of how to do it is in receive_pim_register()
. Grep for "I am the RP"
https://github.com/troglobit/pimd/blob/da6f4c363709c1379271f6e7eabcb6594335ad4e/src/pim_proto.c#L737
Hi Joachim, hope your health is doing fine!
Regarding this feature, I have been digging around through the code to try to understand things and start some writing. Here is what I have done so far:
-
config.c
--> added config file parsing to acceptphyint if_name igmp-proxy
and added the flagVIFF_IGMP_PROXY
to the interface (should we limit to just one interface of this type ??) - excluded interfaces with
VIFF_IGMP_PROXY
from interface-related activities ininit_reg_vif(), update_reg_vif(), check_vif_state(), find_vif_direct(), local_address(), find_vif_direct_local(), max_local_address()
- prevented packet processing of PIM/IGMP packets received on interfaces with
VIFF_IGMP_PROXY
flag inreceive_pim_hello(), receive_pim_join_prune(), receive_pim_assert(), receive_pim_bootstrap(), send_pim_bootstrap(), accept_group_report(), accept_leave_message(),
-
vif.c
--> created a new methodinit_igmp_proxy()
that creates a separate socketint igmp_proxy_socket
specific to our igmp-proxy interface and registers theigmp_read()
handler on it. Also created another methodstart_igmp_proxy_vif()
that callsk_add_vif()
with our new socket
What I am trying to achieve:
-
I have figured that we may have to add some processing in
receive_pim_register(), receive_pim_join_prune()
and also inaccept_group_report()
andaccept_leave_message()
to deal with messages received from neighbor routers or from directly attached clients, respectively. BUT, I am stuck finding a reliable way to determine if "I am the RP for this group" becausecheck_mrtentry_rp()
never matches. Obviously I'm doing it wrong, for example inaccept_group_report()
:mrtentry = find_route(igmp_src, group, MRTF_SG | MRTF_WC | MRTF_PMBR, DONT_CREATE); if (local_address(group) == NO_VIF && check_mrtentry_rp(mrtentry, group)) { IF_DEBUG(DEBUG_PIM_REGISTER) logit(LOG_DEBUG, 0, "------------------------ I AM THE RP ------------------------------"); }
Where
igmp_src
is the address of the client sending a JOIN andgroup
is the MC group being joined. I think the problem might be infind_route()
where a subsequential call torp_grp_match()
always enters the following ckeck:if ((group_h & ntohl(mask_ptr->group_mask)) != ntohl(mask_ptr->group_mask & mask_ptr->group_addr)) continue;
Could not figure exactly what this check is doing and why if fails.
Ok, so this is where I am, and kindly ask for a bit of help from you. Also, sorry for the long post and the not-so-good code debugging method :)
Regards, Tiago