Closed troglobit closed 1 year ago
+1 for this request, this would be very handy for my use case.
I am running a firewall/router based on OpenBSD (7.2) and am routing multicast traffic between two routing domains via a set of pair(4) interfaces. Each routing domain has a pair interface attached and the interconnect is acting as a nexus between them. I have an mrouted instance configured to run in each routing domain and the mrouted daemons route multicast traffic back and forth over the pair interfaces.
Here is a copy of the mrouted configuration for the primary routing domain (rd0):
cache-lifetime 86400
no phyint
phyint aggr0 enable
static-group 239.255.255.250
force-leaf
phyint vlan55 enable
static-group 239.255.255.250
force-leaf
phyint pair1 enable
Here is a copy of the mrouted configuration for the secondary routing domain (rd1):
cache-lifetime 86400
no phyint
phyint vlan35 enable
static-group 239.255.255.250
force-leaf
phyint pair0 enable
If I understand this correctly, this feature would eliminate the need for the mrouted daemon I am running in the secondary routing domain - I could just force the pair/vlan interface in the secondary routing domain to join the group I need.
I will give a try to it this week. At least explore.
Should be pretty straightforward, let me know if you get stock or have any questions.
For the moment I have only reproduced the network setup above (6 VMs, 3 private networks, 1 GRE tunnel). I still need to add e.g. a video source and a video client to make it more realistic - otherwise I will try with mcjoin
.
Thanks for the help offer. I have sent an email to you last week, but I suspect it went to spam :smile_cat: .
I have checked my spam folder, don't seem to have gotten anything from you, sorry. Maybe we can keep communication about this feature here? Easier for me to track and orders to help out.
Just an update. Nothing spectacular:
a2:~ # mroutectl show status
Interface Table
Address Interface State Cost TTL Uptime Flags
172.16.200.15 eth0 Up 1 1 0:00:00 QL
10.20.30.40 gre1 Up 1 1 0:00:00 Q
Neighbor Table
Neighbor Interface Version Flags Uptime Expire
10.20.30.41 gre1 3.255 G 0:05:52 30s
DVMRP Routing Table
Origin Neighbor Interface
172.16.216.0/27 10.20.30.41 gre1
172.16.200.0/27 Local eth0
10.20.30/24 Local gre1
Multicast Forwarding Cache Table
Origin Group Inbound Outbound
172.16.200.0/27 226.94.1.1 eth0 gre1
172.16.200.0/27 239.255.255.250 eth0 gre1
b2:~ # mroutectl show status
Interface Table
Address Interface State Cost TTL Uptime Flags
172.16.216.8 eth0 Up 1 1 0:00:00 QL
10.20.30.41 gre1 Up 1 1 0:00:00
Neighbor Table
Neighbor Interface Version Flags Uptime Expire
10.20.30.40 gre1 3.255 G 0:08:50 20s
DVMRP Routing Table
Origin Neighbor Interface
172.16.216.0/27 Local eth0
172.16.200.0/27 10.20.30.40 gre1
10.20.30/24 Local gre1
Multicast Forwarding Cache Table
Origin Group Inbound Outbound
172.16.216.0/27 239.255.255.250 eth0 gre1
I had to use 172.16
instead of 10.0
that was already used. 10.20.30
is the prefix for the GRE tunnel. The rest of the addresses should match your diagram.
The multicast group 226.94.1.1
comes from a mcjoin -s
running on A1
. I do not see its packets forwarded on B2
, which is the other side of the GRE tunnel. That's probably normal?
DVMRP is a flood-and-prune type protocol, so if you managed to join the group on A2, it will start to flood the traffic on its interface (provided the TTL is > ttl-threshold, which by default is 1). You also have to set up static-group 225.1.2.3
on B2's interface.
But my guess is that you forgot to raise the TTL of the generated multicast traffic.
It was indeed the TTL. Now I see traffic on B2
. I did not need to set up the static group, not sure why it works without.
I even receive on B1
.
I have to stop for today. More tomorrow.
But I will have to re-read the issue, because everything seems to work out of the box, and now I am puzzled about what remains to be done :smile_cat: .
The issue that this issue addresses is when you have switches with IGMP snooping enabled that do not properly recognize mrouted as a dynamic multicast router port, so they will block traffic from the sender on LAN A to reach any of the mrouted routers there. If one of the routers act a s "proxy receiver" by joining the group to be routed, these lazy switches will open up the flow from the sender (attached to the switch) towards that router.
The traffic will be pruned eventually by B2 ("I have no local joins for this, I can tell A2 to stop forwarding it now.", so you need the static-group
.
I have a first draft code. Here is how it works.
All modified mrouted
code runs on A2
, there's no need to patch B2
.
In src/igmp.c
, in function accept_igmp()
, right after we call add_table_entry()
to store a new kernel multicast route received from a peer, I call a new function become_member_of()
to become a member of the same new group. This is done only if some new mrouted configuration option is set, the default being the old behaviour of not becoming a member of any group besides DVMRP routers etc.
In src/vif.c
, I implemented the new function become_member_of()
. It loops over all the virtual interfaces to enroll to the new group using k_join()
.
It seems to work. On A1
, I see the IGMP membership report that A2
joined 226.94.1.1
(from mcjoin
running on B1
) and 239.255.255.250
(from somewhere else on my local network):
a1:~ # tcpdump -nv -i eth0 multicast and host 224.0.0.22
(...)
15:53:01.722054 IP (tos 0xc0, ttl 1, id 0, offset 0, flags [DF], proto IGMP (2), length 72, options (RA))
172.16.200.15 > 224.0.0.22: igmp v3 report, 5 group record(s) [gaddr 239.255.255.250 is_ex, 0 source(s)]
[gaddr 226.94.1.1 is_ex, 0 source(s)] [gaddr 224.0.0.22 is_ex, 0 source(s)]
[gaddr 224.0.0.2 is_ex, 0 source(s)] [gaddr 224.0.0.4 is_ex, 0 source(s)]
It might not be the solution you would have preferred. Shoot the criticism :smiley_cat: .
OK, just to be crystal clear, a hack that "works for me" is not what we're after here. I want something that mimics what the phyint
option static-group
does, but in reverse. Like the static-group setting, it has to be per-phyint since it is be up to the administrator to know where to apply this static configuration.
Most options in mrouted (and the extended family including pimd et al) are modeled on Cisco. Here's a hint:
ip igmp join-group GROUP [source SENDER]
The latter part cannot be implemented yet using the k_join()
API, since it only supports IGMPv2, but since mrouted supports IGMPv3 we should plan syntax and the other APIs for that.
So, I'd like to see exactly this:
phyint eth1
join-group 226.94.1.1
But preparing data structures and APIs to be able to do this:
phyint eth1
join-group 226.94.1.1 source 10.0.200.13
I'm sorry, but the PR in #53 is a real mess and you'll have to clean up and squash it properly to meet the above syntax, and coding style, before I do a proper review of that.
I indeed just thought during this night exactlty the same thing: the new setting has to be per-int.
join-group
sounds nice.
However, I see a problem with your suggested syntax: we might not know in advance which groups might be wanted, as we have no control neither on the emitter nor on the receiver. I therefore suggest to make a all-received
variant:
phyint eth1
join-group 226.94.1.1 source 10.0.200.13
phyint eth1
join-group all-received
I'm sorry, but the PR in #53 is a real mess and you'll have to clean up and squash it properly to meet the above syntax, and coding style, before I do a proper review of that.
I was not asking a code review from you yet, and my PR is #58, not #53. My PR does not need being squashed as it has only one commit.
You might have mixed me with @ericb-summit . It is a pure coincidence that we are both named Eric B.
Even if it were my PR, you are being rude to someone who voluntarily offers to help. I clearly said #58 was a "first draft" and asked for criticism - which I expected to be respectful.
I'll have a look at #53 for comparaison, there might be some inspiration to take from it.
I don't see how an all-received
option would work with the DVMRP protocol. Please explain what you mean by that, which feature of multicast or DVMRP would you piggy-back that function on? The problem is that you don't see the multicast from the sender, hence the join, and from the DVMRP side you will not get any information either about the group. It's a workaround for misbehaving switches, not detailed anywhere in the DVMRP spec.
Yeah, I obviously typed in the wrong PR#, was more of a mixup of 3 and 8 with my font and bad eyesight. Regardless of the PR#, or the draft status, it does not live up to a reasonable standard for a code submission, that's just my being honest with you.
Please explain what you mean by that, which feature of multicast or DVMRP would you piggy-back that function on?
As already explained:
In src/igmp.c, in function accept_igmp(), right after we call add_table_entry() to store a new kernel multicast route received from a peer, I call a new function become_member_of() to become a member of the same new group.
The new group is indeed obtained from DVMRP. The variant could also be named join-group dynamic
.
Maybe I am going too far. We could go YAGNI and implement the dynamic
variant only if requested from some user.
Regardless of the PR#, or the draft status, it does not live up to a reasonable standard for a code submission,
I tried to conform as much as possible to the coding conventions of this project in #58. For example, despite it was only a very rough first experiment, I tried to respect the mixture of tabulations and spaces and the placement of braces { }. Could you give me a hint at what should be made better?
That won't work. The call to add_table_entry()
in accept_igmp()
is the kernel upcall for incoming unknown multicast data that we should flood. It is not the DVMRP call from LAN B.
The problem we are trying to solve is that we don't get this multicast data since the switch on LAN A, where the router and sender are connected, is blocking the multicast from reaching the router. So an administrator has to workaround that switch by performing an explicit join of that group on the router(s) on LAN A to open up that switch. If you don't have a malfunctioning IGMP snooping switch on LAN A you will not trigger this problem.
Yes, indeed, accept_igmp()
is, as its name suggests, triggered by an IGMP message, not by DVMRP. I receive 226.94.1.1 on A2
from A1
on both interfaces:
mrouted: 10:43:19.059 Accepting group membership report: src 10.20.30.40, dst 0.0.0.0, grp 226.94.1.1
mrouted: 10:59:28.588 Accepting group membership report: src 172.16.200.15, dst 0.0.0.0, grp 226.94.1.1
which should not be cut by IGMP snooping but I am not 100 % sure.
In any case, let's go with the static approach for now. If the need arises someday for dynamic joining, we can still re-think it later.
The code should be ready in not too long, I hope.
OK, I implemented the static join you requested. #58 is ready for a first code review.
Thanks for the merge.
In setups like #52, where you don't have access to the router(s), and you want to forward multicast between networks that are separated by an intranet/Internet without support for multicast, you may need to join the multicast groups you want to forward on the sender side.
In the picture below, A2 wants to route 226.94.1.1 to B2.
If A2 can join 226.94.1.1 it could forward the traffic to B2, which in turn can use the
phyint
sub-optionstatic-group 226.94.1.1
to fake it has heard the IGMP join message on LAN B. (Which it likely won't if you don't have access to the switch on LAN B (serving 10.0.216/27) and it has IGMP snooping enabled.This feature would perfectly complement
static-group
, which only serves the receiver side.