Bugzilla – Bug 136
Sockets bound to specific interfaces receive broadcasts arriving on other interfaces
Last modified: 2008-02-26 05:28:49 UTC
here's a simple diagram <----- broadcast / 10.0.0.1 --------------------- 10.0.0.2 / \ N1 N2 \ \ 10.0.1.1 Suppose N1 has two sockets, one bound to one interface, another bound to another interface (Bind (interface-ipv4-address)). When N2 sends a broadcast packet to N1, currently both sockets in N1 are receiving a copy, which is wrong. That should only happen when using sockets bound to the "any" address, not like this. Yes, this is partly my fault (bug 51) but there is a subtle distinction between multiple sockets receiving a broadcast packet when they are bound to the "any" address and the case where all sockets are bound to specific interface addresses. Both scenarios have their uses and should be supported.
Created attachment 105 [details] patch to exercise the problem in the unit tests
Created attachment 106 [details] patch to fix issue (including unit test) Phew! It has been a challenge to get both cases working together :P The rationale for this change is (besides the usual "Linux does it") that in the OLSR agent I am now trying to create several sockets, each bound to its own interface, because I need to know on which interface OLSR HELLO messages arrive, in order to properly follow the RFC algorithm, which states that "link sensing" uses real interface addresses, unlike everything else that uses "main addresses". As far as I know, this is the only way using sockets to discover on which interface a packet arrived.
OK, I have finally finished debugging OLSR, and I have a big patch to cleanup OLSR and fix a ton of bugs. But it needs this patch to go in first. So, can someone please review this, or give a suggestion of how to get information of interface by which UDP packets are received. I suppose we could make something else up to solve the problem, by using packet tags for example, but since there is a standard way of doing it with sockets I think it is best to use it -> less learning for users that know socket programming -> less difficulty in porting daemons between NS-3 and real world. Eagerly awaiting a reply; this is kind of blocking my research into OSLR for large wireless networks... :P
I support the patch; just had a couple of nits: + ipv4_api->FindInterfaceForAddr (ipv4); // check if address matches a local interface I would change the above comment to // asserts if requested address is not found I was looking at this function for a while and wondering "why is the return value ignored?" Also, + Ipv4Address m_localInterface; // local interface (optional) In what sense is this optional? I see it as a mandatory parameter everywhere. Does "(optional)" mean optional in the sense that the user calling Bind is optional?
(In reply to comment #4) > I support the patch; just had a couple of nits: > > + ipv4_api->FindInterfaceForAddr (ipv4); // check if address matches a > local interface > > I would change the above comment to // asserts if requested address is not > found Agree; will change it. > > I was looking at this function for a while and wondering "why is the return > value ignored?" I'll change to NS_ASSERT (ipv4_api->FindInterfaceForAddr (ipv4) != 0), to make the code clearer. (the outer assert will never be invoked, but it doesn't hurt). > > Also, > + Ipv4Address m_localInterface; // local interface (optional) > > In what sense is this optional? I see it as a mandatory parameter everywhere. > Does "(optional)" mean optional in the sense that the user calling Bind is > optional? + Ipv4Address m_localInterface; // local interface (optional) It is optional in the sense that localInterface can be Ipv4Address::GetAny (), which means the end point is not associated with any particular interface. I will clarify this comment.
committed -> http://code.nsnam.org/ns-3-dev/rev/eec07777d1a2
With these changes, several UDP and TCP APIs have an additional localInterface parameter passed in. Can we use a default parameter, or have overloaded versions that assume the parameter is Ipv4Address::GetAny() ? It will simplify the user API for simple cases. I noticed this because these changes broke the API I was using when I wrote the TCP server forking code, and I'm now revisiting that.
I'm fine in principle with a default parameter version, but I remember I intentionally made the parameter mandatory precisely to catch code that needed to adapt to new API requirements. If the parameter had a default a lot of code would silently compile but fail in subtle ways in runtime...