Mailing List Archive

OSPF Multicast on FreeBSD.
Hi

Quagga no longer uses the correct interface for OSPF with a recent
( > June 12) FreeBSD-CURRENT. This is because the kernel multicast
support has been updated. I really don't know enough about multicast
to fix the problem. I can supply a test box though.

I'm guessing this problem will exist for any protocol trying to use
multicast on a specific interface for the routing information.

Ian

--
Ian Freislich

_______________________________________________
Quagga-users mailing list
Quagga-users@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-users
Re: OSPF Multicast on FreeBSD. [ In reply to ]
On Mon, 2 Jul 2007, Ian FREISLICH wrote:

> Hi
>
> Quagga no longer uses the correct interface for OSPF with a recent
> ( > June 12) FreeBSD-CURRENT. This is because the kernel multicast
> support has been updated.

Which change is that? There are no relevant changes this month.

regards,
--
Paul Jakma paul@clubi.ie paul@jakma.org Key ID: 64A2FF6A
Fortune:
I couldn't remember when I had been so disappointed. Except perhaps the
time I found out that M&Ms really DO melt in your hand.
-- Peter Oakley
_______________________________________________
Quagga-users mailing list
Quagga-users@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-users
Re: OSPF Multicast on FreeBSD. [ In reply to ]
Paul Jakma wrote:
> On Mon, 2 Jul 2007, Ian FREISLICH wrote:
>
> > Hi
> >
> > Quagga no longer uses the correct interface for OSPF with a recent
> > ( > June 12) FreeBSD-CURRENT. This is because the kernel multicast
> > support has been updated.
>
> Which change is that? There are no relevant changes this month.

This is not a change to quagga, it's a change to the OS. Since the
change which reworked FreeBSD's multicast support, quagga's multicast
group membership is bound to the interface with the default route.
The struct ip_mreqn now has an ifindex member.

netinet/in.h:
/*
* Modified argument structure for IP_MULTICAST_IF, obtained from Linux.
* This is used to specify an interface index for multicast sends, as
* the IPv4 legacy APIs do not support this (unless IP_SENDIF is available).
*/
struct ip_mreqn {
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_address; /* local IP address of interface */
int imr_ifindex; /* Interface index; cast to uint32_t */
};

Using the code selected by HAVE_STRUCT_IP_MREQN_IMR_IFINDEX and
always setting mreqn.imr_address = if_addr in setsockopt_multicast_ipv4()
seems to fix the problem.

Ian

--
Ian Freislich

_______________________________________________
Quagga-users mailing list
Quagga-users@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-users
Re: OSPF Multicast on FreeBSD. [ In reply to ]
On Tue, Jul 03, 2007 at 07:30:16AM +0200, Ian FREISLICH wrote:
> This is not a change to quagga, it's a change to the OS. Since the
> change which reworked FreeBSD's multicast support, quagga's multicast
> group membership is bound to the interface with the default route.
> The struct ip_mreqn now has an ifindex member.
>
> netinet/in.h:
> /*
> * Modified argument structure for IP_MULTICAST_IF, obtained from Linux.
> * This is used to specify an interface index for multicast sends, as
> * the IPv4 legacy APIs do not support this (unless IP_SENDIF is available).
> */
> struct ip_mreqn {
> struct in_addr imr_multiaddr; /* IP multicast address of group */
> struct in_addr imr_address; /* local IP address of interface */
> int imr_ifindex; /* Interface index; cast to uint32_t */
> };
>
> Using the code selected by HAVE_STRUCT_IP_MREQN_IMR_IFINDEX and

I would expect that the configure script defines this automatically,
based on this line:

AC_CHECK_MEMBERS([struct ip_mreqn.imr_ifindex], [], [], QUAGGA_INCLUDES)

Are you seeing otherwise?

> always setting mreqn.imr_address = if_addr in setsockopt_multicast_ipv4()
> seems to fix the problem.

So you're saying that freebsd needs imr_address to be populated
even though imr_ifindex is being set? i.e. the code should look
like this:

mreqn.imr_address = if_addr;
if (ifindex)
mreqn.imr_ifindex = ifindex;

I'm not sure whether that would cause problems for any other platforms
out there. Presumably most existing platforms that support imr_ifindex
would use that value (if available) and ignore imr_address. But you're
saying FreeBSD needs both to be set consistently in order for imr_ifindex
to be respected?

Regards,
Andy
_______________________________________________
Quagga-users mailing list
Quagga-users@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-users
Re: OSPF Multicast on FreeBSD. [ In reply to ]
"Andrew J. Schorr" wrote:
> On Tue, Jul 03, 2007 at 07:30:16AM +0200, Ian FREISLICH wrote:
> > This is not a change to quagga, it's a change to the OS. Since the
> > change which reworked FreeBSD's multicast support, quagga's multicast
> > group membership is bound to the interface with the default route.
> > The struct ip_mreqn now has an ifindex member.
> >
> > netinet/in.h:
> > /*
> > * Modified argument structure for IP_MULTICAST_IF, obtained from Linux.
> > * This is used to specify an interface index for multicast sends, as
> > * the IPv4 legacy APIs do not support this (unless IP_SENDIF is available)
_______________________________________________
Quagga-users mailing list
Quagga-users@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-users
Re: OSPF Multicast on FreeBSD. [ In reply to ]
This seems odd. Historically the address has been either an address or
an ifindex. Having an explicit index makes sense, but if so I would
think that either the old behavior should work or specifying an address
should be an error.

Did FreeBSD version the ioctl to provide backwards binary compatibility?
_______________________________________________
Quagga-users mailing list
Quagga-users@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-users
Re: OSPF Multicast on FreeBSD. [ In reply to ]
Greg Troxel wrote:
> This seems odd. Historically the address has been either an address or
> an ifindex. Having an explicit index makes sense, but if so I would
> think that either the old behavior should work or specifying an address
> should be an error.
>
> Did FreeBSD version the ioctl to provide backwards binary compatibility?

Apparently not. Here's a message from the maintainer of the multicast
support.

---x---
Warning: long technical answer to explain horrible kludge, and why
kludge was removed.

imr_ifindex is never used for IP_ADD_MEMBERSHIP as it is not part of the
original IPv4 any-source multicast API. It is part of the ip_mreqn
structure defined in Linux, where it is used for the IP_MULTICAST_IF ioctl.

FreeBSD previously supported a hack derived from RFC 1724 which allowed
an interface index to be specified in the imr_interface field when using
IP_ADD_MEMBERSHIP which is totally non standard and only allows 24 bits
of a quantity which is 32 bits in modern APIs.

It is however part of MCAST_JOIN_GROUP in the new SSM API, which accepts
the ifindex in the field gsr_interface of the group_source_req structure.

In the case of OSPF, 224.0.0.5 lies within 224.0.0.0/8. It therefore has
link-local scope and SHOULD NOT be forwarded by an IGMP enabled router,
so IGMP announcements don't matter here.

It looks like in your situation the old API is insufficient to capture
the semantics of what Quagga needs to do without the RFC 1724 hack, and
simply passing ip_mreqn isn't enough as the receive filters won't change
-- IP_MULTICAST_IF only changes the source interface for transmission,
not the interface where the join has been made.

The correct fix is for applications to use the new API if they need to
explicitly join a multicast group on an interface index i.e. to support
an unnumbered interface, because that was one of the motivations behind
the new API in the first place.

I see now that Linux also supports ip_mreqn in its IP_ADD_MEMBERSHIP
path. I could potentially change the ASM API ioctl paths
(IP_ADD_MEMBERSHIP, IP_DEL_MEMBERSHIP) to detect and support the
ip_mreqn structure -- however -- I am loathe to do this as it introduces
another bunch of nested conditionals, as the same code now has to
support IP_ADD_SOURCE_MEMBERSHIP in FreeBSD, which has the same
structure size. It is also a retrograde change.

Regards,
BMS
---x---

Ian

--
Ian Freislich

_______________________________________________
Quagga-users mailing list
Quagga-users@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-users
Re: OSPF Multicast on FreeBSD. [ In reply to ]
On Fri, Jul 06, 2007 at 06:44:24AM +0200, Ian FREISLICH wrote:
...
> imr_ifindex is never used for IP_ADD_MEMBERSHIP as it is not part of the
> original IPv4 any-source multicast API. It is part of the ip_mreqn
> structure defined in Linux, where it is used for the IP_MULTICAST_IF ioctl.
>
> FreeBSD previously supported a hack derived from RFC 1724 which allowed
> an interface index to be specified in the imr_interface field when using
> IP_ADD_MEMBERSHIP which is totally non standard and only allows 24 bits
> of a quantity which is 32 bits in modern APIs.
>
> It is however part of MCAST_JOIN_GROUP in the new SSM API, which accepts
> the ifindex in the field gsr_interface of the group_source_req structure.

Seems to me like the only way to fix this properly is to use the
new MCAST_JOIN_GROUP API, since the old IP_ADD_MEMBERSHIP no longer has
any way to identify the interface by ifindex.

Regards,
Andy
_______________________________________________
Quagga-users mailing list
Quagga-users@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-users
Re: OSPF Multicast on FreeBSD. [ In reply to ]
FreeBSD previously supported a hack derived from RFC 1724 which allowed
an interface index to be specified in the imr_interface field when using
IP_ADD_MEMBERSHIP which is totally non standard and only allows 24 bits
of a quantity which is 32 bits in modern APIs.

This is a longstanding feature, and the notion that interface indexes,
while techincally 32 bit quantities, don't fit in 24 bits is not
compelling to me. On NetBSD (which I think dates from Deering's
original modifications to support multicasting in 4.2BSD), netinet/in.h
has:

/*
* Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP.
*/
struct ip_mreq {
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_interface; /* local IP address of interface */
};

I had thought that using the interface as ifindex was a long standing
practice, but quagga seems to enable this only on some systems,
e.g. NetBSD newer than 1.6.1.

All that said, I can see the merit in changing the API. Has FreeBSD
withdraw struct mreq, and only has struct mreqn now?

Well, to deal with this, someone will need to read the new documentation
for FreeBSD about how to join/leave, and figure out how to write an
autoconf test to turn on this behavior being extremely careful not to
break any other platforms.

It really seems broken that the current quagga code doesn't work - it
seems to leave the address at 0 and store the index. Can you post which
of the relevant configure tests fire? In particular, is the following
defined?

HAVE_STRUCT_IP_MREQN_IMR_IFINDEX

If so, could you post the relevant FreeBSD man page that says what one
is supposed to set. If there isn't one, perhaps you could ask Bruce to
write one.
_______________________________________________
Quagga-users mailing list
Quagga-users@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-users
Re: OSPF Multicast on FreeBSD. [ In reply to ]
"Andrew J. Schorr" <aschorr@telemetry-investments.com> writes:

> On Fri, Jul 06, 2007 at 06:44:24AM +0200, Ian FREISLICH wrote:
> ...
>> imr_ifindex is never used for IP_ADD_MEMBERSHIP as it is not part of the
>> original IPv4 any-source multicast API. It is part of the ip_mreqn
>> structure defined in Linux, where it is used for the IP_MULTICAST_IF ioctl.
>>
>> FreeBSD previously supported a hack derived from RFC 1724 which allowed
>> an interface index to be specified in the imr_interface field when using
>> IP_ADD_MEMBERSHIP which is totally non standard and only allows 24 bits
>> of a quantity which is 32 bits in modern APIs.
>>
>> It is however part of MCAST_JOIN_GROUP in the new SSM API, which accepts
>> the ifindex in the field gsr_interface of the group_source_req structure.
>
> Seems to me like the only way to fix this properly is to use the
> new MCAST_JOIN_GROUP API, since the old IP_ADD_MEMBERSHIP no longer has
> any way to identify the interface by ifindex.

Ah - I misunderstood. I had thought that IP_ADD_MEMBERSHIP used mreqn.
But it seems that still uses mreq, and MCAST_JOIN_GROUP uses mreqn, and
FreeBSD has silently (from the header file viewpoint) withdrawn support
for using ifindex in the address field. That's really too bad - it
seems like a gratuitous incompatibility with historical practice. But,
it seems the thing to do is to write a configure test for
MCAST_JOIN_GROUP and to change lib/sockopt.c to use MCAST_JOIN_GROUP
first, and then mreqn with IP_ADD_MEMBERSHIP, and then regular mreq.

While at it, the multicast function probably should assert that either
ifindex is 0 or the address is some non-interface value - the current
code more or less relies on that and it isn't tested.
Re: OSPF Multicast on FreeBSD. [ In reply to ]
On Fri, Jul 06, 2007 at 09:04:27AM -0400, Greg Troxel wrote:
> Ah - I misunderstood. I had thought that IP_ADD_MEMBERSHIP used mreqn.
> But it seems that still uses mreq, and MCAST_JOIN_GROUP uses mreqn, and
> FreeBSD has silently (from the header file viewpoint) withdrawn support
> for using ifindex in the address field. That's really too bad - it
> seems like a gratuitous incompatibility with historical practice. But,
> it seems the thing to do is to write a configure test for
> MCAST_JOIN_GROUP and to change lib/sockopt.c to use MCAST_JOIN_GROUP
> first, and then mreqn with IP_ADD_MEMBERSHIP, and then regular mreq.

Agreed. The current confusion is because freebsd now defines the ip_mreqn
structure, but does not actually use it with the IP_ADD_MEMBERSHIP call.
We'll need to use MCAST_JOIN_GROUP with the new 'struct group_req' to
get this working again.

http://www.faqs.org/rfcs/rfc3678.html

> While at it, the multicast function probably should assert that either
> ifindex is 0 or the address is some non-interface value - the current
> code more or less relies on that and it isn't tested.

I don't understand the problem here, the current code in
setsockopt_multicast_ipv4 looks fine to me (it uses ifindex if it is non-zero
and the platform supports it, otherwise it falls back to using the if_addr
interface address). Can you please explain the problem in more detail?

Regards,
Andy
_______________________________________________
Quagga-users mailing list
Quagga-users@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-users
Re: OSPF Multicast on FreeBSD. [ In reply to ]
Greg Troxel wrote:
> All that said, I can see the merit in changing the API. Has FreeBSD
> withdraw struct mreq, and only has struct mreqn now?

ip_mreq still exists:

struct ip_mreq {
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_interface; /* local IP address of interface */
};

> Well, to deal with this, someone will need to read the new documentation
> for FreeBSD about how to join/leave, and figure out how to write an
> autoconf test to turn on this behavior being extremely careful not to
> break any other platforms.

It appears that the manual was updated following this change:

--x--
IP(4)
Multicast Options
IP multicasting is supported only on AF_INET sockets of type SOCK_DGRAM
and SOCK_RAW, and only on networks where the interface driver supports
multicasting.

The IP_MULTICAST_TTL option changes the time-to-live (TTL) for outgoing
multicast datagrams in order to control the scope of the multicasts:

u_char ttl; /* range: 0 to 255, default = 1 */
setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));

Datagrams with a TTL of 1 are not forwarded beyond the local network.
Multicast datagrams with a TTL of 0 will not be transmitted on any net-
work, but may be delivered locally if the sending host belongs to the
destination group and if multicast loopback has not been disabled on the
sending socket (see below). Multicast datagrams with TTL greater than 1
may be forwarded to other networks if a multicast router is attached to
the local network.

For hosts with multiple interfaces, each multicast transmission is sent
from the primary network interface. The IP_MULTICAST_IF option overrides
the default for subsequent transmissions from a given socket:

struct in_addr addr;
setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr));

where "addr" is the local IP address of the desired interface or
INADDR_ANY to specify the default interface.

To specify an interface by index, an instance of ip_mreqn should be
passed instead. The imr_ifindex member should be set to the index of the
desired interface, or 0 to specify the default interface. The kernel
differentiates between these two structures by their size. An inter-
face's local IP address and multicast capability can be obtained via the
SIOCGIFCONF and SIOCGIFFLAGS ioctls. Normal applications should not need
to use this option.

If a multicast datagram is sent to a group to which the sending host
itself belongs (on the outgoing interface), a copy of the datagram is, by
default, looped back by the IP layer for local delivery. The
IP_MULTICAST_LOOP option gives the sender explicit control over whether
or not subsequent datagrams are looped back:

u_char loop; /* 0 = disable, 1 = enable (default) */
setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));

This option improves performance for applications that may have no more
than one instance on a single host (such as a router daemon), by elimi-
nating the overhead of receiving their own transmissions. It should gen-
erally not be used by applications for which there may be more than one
instance on a single host (such as a conferencing program) or for which
the sender does not belong to the destination group (such as a time
querying program).

A multicast datagram sent with an initial TTL greater than 1 may be
delivered to the sending host on a different interface from that on which
it was sent, if the host belongs to the destination group on that other
interface. The loopback control option has no effect on such delivery.

A host must become a member of a multicast group before it can receive
datagrams sent to the group. To join a multicast group, use the
IP_ADD_MEMBERSHIP option:

struct ip_mreq mreq;
setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));

where mreq is the following structure:

struct ip_mreq {
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_interface; /* local IP address of interface */
}

imr_interface should be set to INADDR_ANY to choose the default multicast
interface, or the IP address of a particular multicast-capable interface
if the host is multihomed. Since FreeBSD 4.4, if the imr_interface mem-
ber is within the network range 0.0.0.0/8, it is treated as an interface
index in the system interface MIB, as per the RIP Version 2 MIB Extension
(RFC-1724).

Up to IP_MAX_MEMBERSHIPS memberships may be added on a single socket.
Membership is associated with a single interface; programs running on
multihomed hosts may need to join the same group on more than one inter-
face.

The IGMP protocol uses the primary IP address of the interface as its
identifier for group membership. If multiple IP aliases are configured
on the same interface, they will be ignored. This shortcoming was
addressed in IPv6; MLDv2 requires that the unique link-local address for
an interface is used to identify an MLDv2 listener.

To drop a membership, use:

struct ip_mreq mreq;
setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));

where mreq contains the same values as used to add the membership. Mem-
berships are dropped when the socket is closed or the process exits.
--x--

> It really seems broken that the current quagga code doesn't work - it
> seems to leave the address at 0 and store the index. Can you post which
> of the relevant configure tests fire? In particular, is the following
> defined?
>
> HAVE_STRUCT_IP_MREQN_IMR_IFINDEX

#define HAVE_STRUCT_IP_MREQN_IMR_IFINDEX 1

For some reason this still triggers.
#define HAVE_BSD_STRUCT_IP_MREQ_HACK

Ian

--
Ian Freislich

_______________________________________________
Quagga-users mailing list
Quagga-users@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-users
Re: OSPF Multicast on FreeBSD. [ In reply to ]
"Andrew J. Schorr" <aschorr@telemetry-investments.com> writes:

>> While at it, the multicast function probably should assert that either
>> ifindex is 0 or the address is some non-interface value - the current
>> code more or less relies on that and it isn't tested.
>
> I don't understand the problem here, the current code in
> setsockopt_multicast_ipv4 looks fine to me (it uses ifindex if it is non-zero
> and the platform supports it, otherwise it falls back to using the if_addr
> interface address). Can you please explain the problem in more detail?

The call could have

address null, ifindex 0
address null, ifindex valid
address non-null, ifindex 0
address non-null, ifindex valid

Of these, the first case is an error, the second two as expected, and
the third is probably ok, but I'm not sure. So I was suggesting that
this be documented and whatever preconditions are required be validated.
This is going to get more complex over time as more systems have
different calling conventions.
Re: OSPF Multicast on FreeBSD. [ In reply to ]
Ian FREISLICH <ianf@clue.co.za> writes:

Thanks - this is very helpful.

> IP(4)
> Multicast Options
> IP multicasting is supported only on AF_INET sockets of type SOCK_DGRAM
> and SOCK_RAW, and only on networks where the interface driver supports
> multicasting.
>
> The IP_MULTICAST_TTL option changes the time-to-live (TTL) for outgoing
> multicast datagrams in order to control the scope of the multicasts:
>
> u_char ttl; /* range: 0 to 255, default = 1 */
> setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
>
> Datagrams with a TTL of 1 are not forwarded beyond the local network.
> Multicast datagrams with a TTL of 0 will not be transmitted on any net-
> work, but may be delivered locally if the sending host belongs to the
> destination group and if multicast loopback has not been disabled on the
> sending socket (see below). Multicast datagrams with TTL greater than 1
> may be forwarded to other networks if a multicast router is attached to
> the local network.
>
> For hosts with multiple interfaces, each multicast transmission is sent
> from the primary network interface. The IP_MULTICAST_IF option overrides
> the default for subsequent transmissions from a given socket:
>
> struct in_addr addr;
> setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr));
>
> where "addr" is the local IP address of the desired interface or
> INADDR_ANY to specify the default interface.
>
> To specify an interface by index, an instance of ip_mreqn should be
> passed instead. The imr_ifindex member should be set to the index of the
> desired interface, or 0 to specify the default interface. The kernel
> differentiates between these two structures by their size. An inter-
> face's local IP address and multicast capability can be obtained via the
> SIOCGIFCONF and SIOCGIFFLAGS ioctls. Normal applications should not need
> to use this option.
>
> If a multicast datagram is sent to a group to which the sending host
> itself belongs (on the outgoing interface), a copy of the datagram is, by
> default, looped back by the IP layer for local delivery. The
> IP_MULTICAST_LOOP option gives the sender explicit control over whether
> or not subsequent datagrams are looped back:
>
> u_char loop; /* 0 = disable, 1 = enable (default) */
> setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
>
> This option improves performance for applications that may have no more
> than one instance on a single host (such as a router daemon), by elimi-
> nating the overhead of receiving their own transmissions. It should gen-
> erally not be used by applications for which there may be more than one
> instance on a single host (such as a conferencing program) or for which
> the sender does not belong to the destination group (such as a time
> querying program).
>
> A multicast datagram sent with an initial TTL greater than 1 may be
> delivered to the sending host on a different interface from that on which
> it was sent, if the host belongs to the destination group on that other
> interface. The loopback control option has no effect on such delivery.
>
> A host must become a member of a multicast group before it can receive
> datagrams sent to the group. To join a multicast group, use the
> IP_ADD_MEMBERSHIP option:
>
> struct ip_mreq mreq;
> setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
>
> where mreq is the following structure:
>
> struct ip_mreq {
> struct in_addr imr_multiaddr; /* IP multicast address of group */
> struct in_addr imr_interface; /* local IP address of interface */
> }
>
> imr_interface should be set to INADDR_ANY to choose the default multicast
> interface, or the IP address of a particular multicast-capable interface
> if the host is multihomed. Since FreeBSD 4.4, if the imr_interface mem-
> ber is within the network range 0.0.0.0/8, it is treated as an interface
> index in the system interface MIB, as per the RIP Version 2 MIB Extension
> (RFC-1724).
>
> Up to IP_MAX_MEMBERSHIPS memberships may be added on a single socket.
> Membership is associated with a single interface; programs running on
> multihomed hosts may need to join the same group on more than one inter-
> face.
>
> The IGMP protocol uses the primary IP address of the interface as its
> identifier for group membership. If multiple IP aliases are configured
> on the same interface, they will be ignored. This shortcoming was
> addressed in IPv6; MLDv2 requires that the unique link-local address for
> an interface is used to identify an MLDv2 listener.
>
> To drop a membership, use:
>
> struct ip_mreq mreq;
> setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
>
> where mreq contains the same values as used to add the membership. Mem-
> berships are dropped when the socket is closed or the process exits.

Are you sure this documentation is up to date? It looks the same as NetBSD.

> #define HAVE_STRUCT_IP_MREQN_IMR_IFINDEX 1
>
> For some reason this still triggers.
> #define HAVE_BSD_STRUCT_IP_MREQ_HACK

The problem is that there is struct mreqn, but that IP_ADD_MEMBERSHIP
uses the traditional structure.

What is mreqn used for?

Does struct mreqn exist on other than Linux? Perhaps the problem lies
in assuming Linux behavior if mreqn is declared, and that should be
ifdef linux. or is it in solaris too?
Re: OSPF Multicast on FreeBSD. [ In reply to ]
On Fri, Jul 06, 2007 at 09:52:41AM -0400, Greg Troxel wrote:
> The call could have
>
> address null, ifindex 0
> address null, ifindex valid
> address non-null, ifindex 0
> address non-null, ifindex valid
>
> Of these, the first case is an error, the second two as expected, and
> the third is probably ok, but I'm not sure. So I was suggesting that
> this be documented and whatever preconditions are required be validated.
> This is going to get more complex over time as more systems have
> different calling conventions.

My (perhaps flawed) understanding is that the if_addr address must
always be provided correctly (note that this is a 'struct in_addr'
passed by value, not a pointer to an in_addr, so I'm not sure how
"null" would be represented -- by INADDR_ANY?). I believe
the ifindex is optional (i.e. we test for a non-zero value before using
it). So, in other words, I think the first 2 cases you list
are not allowed.

And in fact, this must be the case, since some platforms may not support
using ifindex to join multicast groups, right? For example, on my
Solaris 8 system, neither HAVE_STRUCT_IP_MREQN_IMR_IFINDEX nor
HAVE_BSD_STRUCT_IP_MREQ_HACK is defined, so it must rely on the
interface address.

Regards,
Andy
_______________________________________________
Quagga-users mailing list
Quagga-users@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-users
Re: OSPF Multicast on FreeBSD. [ In reply to ]
On Fri, Jul 06, 2007 at 03:30:24PM +0200, Ian FREISLICH wrote:
> For some reason this still triggers.
> #define HAVE_BSD_STRUCT_IP_MREQ_HACK

That's because configure.ac says:

AC_MSG_CHECKING([for BSD struct ip_mreq hack])
AC_TRY_COMPILE([#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif],[.#if (defined(__FreeBSD__) && (__FreeBSD_version >= 500022 || (__FreeBSD_version < 500000 && __FreeBSD_version >= 440000))) || (defined(__NetBSD__) && defined(__NetBSD_Version__) && __NetBSD_Version__ >= 106010000)
return (0);
#else
#error No support for BSD struct ip_mreq hack detected
#endif],[AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_BSD_STRUCT_IP_MREQ_HACK,,[Can pass ifindex in struct ip_mreq])],
AC_MSG_RESULT(no))

So it's basically just checking the value of __FreeBSD_version.

Regards,
Andy
_______________________________________________
Quagga-users mailing list
Quagga-users@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-users
Re: OSPF Multicast on FreeBSD. [ In reply to ]
On Fri, Jul 06, 2007 at 09:56:42AM -0400, Greg Troxel wrote:
>
> The problem is that there is struct mreqn, but that IP_ADD_MEMBERSHIP
> uses the traditional structure.
>
> What is mreqn used for?

In a previous message in this thread, it was mentioned that FreeBSD
is using struct ip_mreqn only for the IP_MULTICAST_IF call.

> Does struct mreqn exist on other than Linux? Perhaps the problem lies
> in assuming Linux behavior if mreqn is declared, and that should be
> ifdef linux. or is it in solaris too?

I suspect only linux. ip_mreqn was not in solaris 8, and I just
searched for ip_mreqn on docs.sun.com and found no matches.

I guess we need to upgrade to the new multicast APIs.

Regards,
Andy
_______________________________________________
Quagga-users mailing list
Quagga-users@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-users
Re: OSPF Multicast on FreeBSD. [ In reply to ]
Greg Troxel wrote:
> Are you sure this documentation is up to date? It looks the same as NetBSD.

Yes, Here's the diff of the original mdoc:

RCS file: /home/ncvs/src/share/man/man4/ip.4,v
retrieving revision 1.48
retrieving revision 1.49
diff -u -d -r1.48 -r1.49
--- ip.4 18 Mar 2007 15:31:06 -0000 1.48
+++ ip.4 12 Jun 2007 16:24:55 -0000 1.49
@@ -30,9 +30,9 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)ip.4 8.2 (Berkeley) 11/30/93
-.\" $FreeBSD: src/share/man/man4/ip.4,v 1.48 2007/03/18 15:31:06 bms Exp $
+.\" $FreeBSD: src/share/man/man4/ip.4,v 1.49 2007/06/12 16:24:55 bms Exp $
.\"
-.Dd March 18, 2007
+.Dd April 9, 2007
.Dt IP 4
.Os
.Sh NAME
@@ -420,6 +420,16 @@
address of the desired interface or
.Dv INADDR_ANY
to specify the default interface.
+.Pp
+To specify an interface by index, an instance of
+.Vt ip_mreqn
+should be passed instead.
+The
+.Vt imr_ifindex
+member should be set to the index of the desired interface,
+or 0 to specify the default interface.
+The kernel differentiates between these two structures by their size.
+.\"
An interface's local IP address and multicast capability can
be obtained via the
.Dv SIOCGIFCONF
@@ -672,3 +682,7 @@
.Nm
protocol appeared in
.Bx 4.2 .
+The
+.Vt ip_mreqn
+structure appeared in
+.Tn Linux 2.4 .

> > #define HAVE_STRUCT_IP_MREQN_IMR_IFINDEX 1
> >
> > For some reason this still triggers.
> > #define HAVE_BSD_STRUCT_IP_MREQ_HACK
>
> The problem is that there is struct mreqn, but that IP_ADD_MEMBERSHIP
> uses the traditional structure.
>
> What is mreqn used for?

According to sys/netinet/in_mcast.c, the code that handles the
setsockopt system call for the IP_MULTICAST_IF option takes a struct
ip_mreqn or a struct in_addr as its argument. In the case of the
struct in_addr argument, it looks up the interface ifp (struct
ifnet) by address and in the case of the struct ip_mreqn it looks
up the interface ifp by if_index.

> Does struct mreqn exist on other than Linux? Perhaps the problem lies
> in assuming Linux behavior if mreqn is declared, and that should be
> ifdef linux. or is it in solaris too?

I don't think it assumes linux behaviour. At least that's not what
the kernel source suggests.

Hope this helps.
Ian

--
Ian Freislich

_______________________________________________
Quagga-users mailing list
Quagga-users@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-users
Re: OSPF Multicast on FreeBSD. [ In reply to ]
"Andrew J. Schorr" <aschorr@telemetry-investments.com> writes:

> On Fri, Jul 06, 2007 at 09:52:41AM -0400, Greg Troxel wrote:
>> The call could have
>>
>> address null, ifindex 0
>> address null, ifindex valid
>> address non-null, ifindex 0
>> address non-null, ifindex valid
>>
>> Of these, the first case is an error, the second two as expected, and
>> the third is probably ok, but I'm not sure. So I was suggesting that
>> this be documented and whatever preconditions are required be validated.
>> This is going to get more complex over time as more systems have
>> different calling conventions.
>
> My (perhaps flawed) understanding is that the if_addr address must
> always be provided correctly (note that this is a 'struct in_addr'
> passed by value, not a pointer to an in_addr, so I'm not sure how
> "null" would be represented -- by INADDR_ANY?). I believe
> the ifindex is optional (i.e. we test for a non-zero value before using
> it). So, in other words, I think the first 2 cases you list
> are not allowed.

There has been discussion of unnumbered interfaces, so I wasn't sure.

> And in fact, this must be the case, since some platforms may not support
> using ifindex to join multicast groups, right? For example, on my
> Solaris 8 system, neither HAVE_STRUCT_IP_MREQN_IMR_IFINDEX nor
> HAVE_BSD_STRUCT_IP_MREQ_HACK is defined, so it must rely on the
> interface address.

That all makes sense. I was just suggesting that it be documented and
that the funtion check that the preconditions are satisfied.

I wonder if Solaris 8 supports passing ifindex in the address field. I
would expect it to do so.


_______________________________________________
Quagga-users mailing list
Quagga-users@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-users
Re: OSPF Multicast on FreeBSD. [ In reply to ]
"Andrew J. Schorr" <aschorr@telemetry-investments.com> writes:

> On Fri, Jul 06, 2007 at 03:30:24PM +0200, Ian FREISLICH wrote:
>> For some reason this still triggers.
>> #define HAVE_BSD_STRUCT_IP_MREQ_HACK
>
> That's because configure.ac says:
>
> AC_MSG_CHECKING([for BSD struct ip_mreq hack])
> AC_TRY_COMPILE([#ifdef HAVE_SYS_PARAM_H
> #include <sys/param.h>
> #endif],[.#if (defined(__FreeBSD__) && (__FreeBSD_version >= 500022 || (__FreeBSD_version < 500000 && __FreeBSD_version >= 440000))) || (defined(__NetBSD__) && defined(__NetBSD_Version__) && __NetBSD_Version__ >= 106010000)
> return (0);
> #else
> #error No support for BSD struct ip_mreq hack detected
> #endif],[AC_MSG_RESULT(yes)
> AC_DEFINE(HAVE_BSD_STRUCT_IP_MREQ_HACK,,[Can pass ifindex in struct ip_mreq])],
> AC_MSG_RESULT(no))
>
> So it's basically just checking the value of __FreeBSD_version.

>From reading the man page HAVE_BSD_STRUCT_IP_MREQ_HACK should be
defined still.
_______________________________________________
Quagga-users mailing list
Quagga-users@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-users
Re: OSPF Multicast on FreeBSD. [ In reply to ]
"Andrew J. Schorr" <aschorr@telemetry-investments.com> writes:

> On Fri, Jul 06, 2007 at 09:56:42AM -0400, Greg Troxel wrote:
>>
>> The problem is that there is struct mreqn, but that IP_ADD_MEMBERSHIP
>> uses the traditional structure.
>>
>> What is mreqn used for?
>
> In a previous message in this thread, it was mentioned that FreeBSD
> is using struct ip_mreqn only for the IP_MULTICAST_IF call.

OK - and I see that in the docs. Sorry for coming in late, but BSD and
multicast woke me up :-)

>> Does struct mreqn exist on other than Linux? Perhaps the problem lies
>> in assuming Linux behavior if mreqn is declared, and that should be
>> ifdef linux. or is it in solaris too?
>
> I suspect only linux. ip_mreqn was not in solaris 8, and I just
> searched for ip_mreqn on docs.sun.com and found no matches.

Then perhaps the ip_mreqn branch of the ifdef needs to be taken only on
linux. It's clearly an incorrect assumption that if ip_mreqn exists it
should be used for IP_ADD_MEMBERSHIP. One can argue that it was wrong
of Linux to change the structure, or of FreeBSD to reuse the name with
different rules, but we have to tell the cases apart.

> I guess we need to upgrade to the new multicast APIs.

That too, but they aren't many places yet, and I think that's a separate
issue. NetBSD doesn't have the SSM API, and I had the (fuzzy)
impression that the whole SSM multicast bit was still somewhat
fringe/controversial.
Re: OSPF Multicast on FreeBSD. [ In reply to ]
Ian FREISLICH <ianf@clue.co.za> writes:

Thanks for the diff - now this all makes sense.
>> The problem is that there is struct mreqn, but that IP_ADD_MEMBERSHIP
>> uses the traditional structure.

So what I should have said is that mreqn exists, but FreeBSD and Linux
use it for different calls.

>> What is mreqn used for?
>
> According to sys/netinet/in_mcast.c, the code that handles the
> setsockopt system call for the IP_MULTICAST_IF option takes a struct
> ip_mreqn or a struct in_addr as its argument. In the case of the
> struct in_addr argument, it looks up the interface ifp (struct
> ifnet) by address and in the case of the struct ip_mreqn it looks
> up the interface ifp by if_index.

I think we need to add into configure knowledge of the mapping between
os types and struct definitions to desired behavior. It's too bad this
isn't standardized.

>> Does struct mreqn exist on other than Linux? Perhaps the problem lies
>> in assuming Linux behavior if mreqn is declared, and that should be
>> ifdef linux. or is it in solaris too?
>
> I don't think it assumes linux behaviour. At least that's not what
> the kernel source suggests.

I meant that the quagga code checks for the existence of mreqn at
configure time, and if present assumes that IP_ADD_MEMBERSHIP uses
mreqn, which is what linux does. So quagga is assuming linux behavior,
and that's an incorrect assumption on freebsd post mreqn.
Re: OSPF Multicast on FreeBSD. [ In reply to ]
On Fri, Jul 06, 2007 at 11:06:04AM -0400, Greg Troxel wrote:
> "Andrew J. Schorr" <aschorr@telemetry-investments.com> writes:
> > And in fact, this must be the case, since some platforms may not support
> > using ifindex to join multicast groups, right? For example, on my
> > Solaris 8 system, neither HAVE_STRUCT_IP_MREQN_IMR_IFINDEX nor
> > HAVE_BSD_STRUCT_IP_MREQ_HACK is defined, so it must rely on the
> > interface address.
>
> That all makes sense. I was just suggesting that it be documented and
> that the funtion check that the preconditions are satisfied.

Does the attached patch do the trick?

> I wonder if Solaris 8 supports passing ifindex in the address field. I
> would expect it to do so.

That could well be the case, but I don't think the existing code takes
advantage of this. And I doubt it's very important to improve this
on Solaris 8. I'm not sure what happens in Solaris 10...

Regards,
Andy
Re: OSPF Multicast on FreeBSD. [ In reply to ]
On Fri, Jul 06, 2007 at 11:06:51AM -0400, Greg Troxel wrote:
> From reading the man page HAVE_BSD_STRUCT_IP_MREQ_HACK should be
> defined still.

True, but the explanation from BMS that Ian forwarded indicated that this
behavior is no longer supported...

"FreeBSD previously supported a hack derived from RFC 1724 which allowed
an interface index to be specified in the imr_interface field when using
IP_ADD_MEMBERSHIP which is totally non standard and only allows 24 bits
of a quantity which is 32 bits in modern APIs."

Note the word "previously".

Regards,
Andy
_______________________________________________
Quagga-users mailing list
Quagga-users@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-users
Re: OSPF Multicast on FreeBSD. [ In reply to ]
"Andrew J. Schorr" <aschorr@telemetry-investments.com> writes:

>> That all makes sense. I was just suggesting that it be documented and
>> that the funtion check that the preconditions are satisfied.
>
> Does the attached patch do the trick?

Yes, looks fine.

>> I wonder if Solaris 8 supports passing ifindex in the address field. I
>> would expect it to do so.
>
> That could well be the case, but I don't think the existing code takes
> advantage of this. And I doubt it's very important to improve this
> on Solaris 8. I'm not sure what happens in Solaris 10...

I was thinking more of using the BSD ifindex convention unless there's a
reason to think it won't work, since I suspect most systems other than
Linux have 4.2BSD-derived networking code. But that might be too
dangerous an assumption.

_______________________________________________
Quagga-users mailing list
Quagga-users@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-users