Tried to clean up multicast handling. Now we don't try to guess

multicast abilities depending on definedness of symbols and use hard-wired
system-dependent configuration defines instead.

Please test whereever you can.
This commit is contained in:
Martin Mares 1999-12-16 13:06:13 +00:00
parent ccdc339756
commit 67ece6df42
9 changed files with 150 additions and 72 deletions

7
TODO
View file

@ -2,8 +2,6 @@ Core
~~~~
- IPv6 support
- io.c: refuse old-style multicasts for unnumbered interfaces?
- counters (according to SNMP MIB?)
- better memory allocators
- real attribute cache
@ -21,12 +19,8 @@ Core
- iface: SIOCGIFINDEX exists on glibc systems, but it doesn't work on 2.0.x kernels!
* glibc problems with struct mreqn
- socket: Use IP_RECVERR for BGP TCP sockets?
- OSPF: refuse running on non-multicast devices
- config: executable config files
- config: when parsing prefix, check zero bits
- config: reconfiguration
@ -82,6 +76,7 @@ RIP
OSPF
~~~~
- refuse running on non-multicast devices
- importing of device routes for networks where we don't run OSPF
- check incoming packets using neighbor cache
- RFC2328 appendix E: Use a better algorithm

View file

@ -2,7 +2,6 @@ Available configuration variables:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CONFIG_AUTO_ROUTES Device routes are added automagically by the kernel
CONFIG_ALL_MULTICAST All devices support multicasting (i.e., ignore IFF_MULTICAST)
CONFIG_SELF_CONSCIOUS We're able to recognize whether route was installed by us
CONFIG_MULTIPLE_TABLES The kernel supports multiple routing tables
CONFIG_ALL_TABLES_AT_ONCE Kernel scanner wants to process all tables at once
@ -10,3 +9,10 @@ CONFIG_ALL_TABLES_AT_ONCE Kernel scanner wants to process all tables at once
CONFIG_UNIX_IFACE Use Unix interface scanner
CONFIG_UNIX_SET Use Unix route setting
CONFIG_LINUX_SCAN Use Linux /proc/net/route scanner
CONFIG_ALL_MULTICAST krt-iface: All devices support multicasting (i.e., ignore IFF_MULTICAST)
CONFIG_UNNUM_MULTICAST krt-iface: We support multicasts on unnumbered PtP devices
CONFIG_LINUX_MC_MREQN Linux: Use struct mreqn for multicasting
CONFIG_LINUX_MC_MREQ Linux: Use struct mreq
CONFIG_LINUX_MC_MREQ_BIND Linux: Use struct mreq and SO_BINDTODEVICE

View file

@ -7,7 +7,6 @@
*/
#undef CONFIG_AUTO_ROUTES
#define CONFIG_ALL_MULTICAST
#undef CONFIG_SELF_CONSCIOUS
#undef CONFIG_MULTIPLE_TABLES
@ -15,6 +14,10 @@
#define CONFIG_UNIX_SET
#define CONFIG_LINUX_SCAN
#define CONFIG_LINUX_MC_MREQ_BIND
#define CONFIG_ALL_MULTICAST
#define CONFIG_UNNUM_MULTICAST
/*
Link: sysdep/linux
Link: sysdep/unix

View file

@ -7,7 +7,6 @@
*/
#define CONFIG_AUTO_ROUTES
#define CONFIG_ALL_MULTICAST
#undef CONFIG_SELF_CONSCIOUS
#undef CONFIG_MULTIPLE_TABLES
@ -15,6 +14,10 @@
#define CONFIG_UNIX_SET
#define CONFIG_LINUX_SCAN
#define CONFIG_LINUX_MC_MREQN
#define CONFIG_ALL_MULTICAST
#define CONFIG_UNNUM_MULTICAST
/*
Link: sysdep/linux
Link: sysdep/unix

View file

@ -7,11 +7,12 @@
*/
#define CONFIG_AUTO_ROUTES
#define CONFIG_ALL_MULTICAST
#define CONFIG_SELF_CONSCIOUS
#define CONFIG_MULTIPLE_TABLES
#define CONFIG_ALL_TABLES_AT_ONCE
#define CONFIG_LINUX_MC_MREQN
/*
Link: sysdep/linux/netlink
Link: sysdep/linux

View file

@ -2,3 +2,4 @@
krt-scan.c
krt-scan.h
#endif
sysio.h

118
sysdep/linux/sysio.h Normal file
View file

@ -0,0 +1,118 @@
/*
* BIRD Internet Routing Daemon -- Linux Multicasting and Network Includes
*
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#ifdef IPV6
#include <linux/in6.h> /* FIXMEv6: glibc variant? */
#else
/*
* Multicasting in Linux systems is a real mess. Not only different kernels
* have different interfaces, but also different libc's export it in different
* ways. Horrible.
*/
static inline char *sysio_mcast_setup(sock *s)
{
int zero = 0;
if (ipa_nonzero(s->daddr))
{
if (
#ifdef IP_DEFAULT_MULTICAST_TTL
s->ttl != IP_DEFAULT_MULTICAST_TTL &&
#endif
setsockopt(s->fd, SOL_IP, IP_MULTICAST_TTL, &s->ttl, sizeof(s->ttl)) < 0)
return "IP_MULTICAST_TTL";
if (
#ifdef IP_DEFAULT_MULTICAST_LOOP
IP_DEFAULT_MULTICAST_LOOP &&
#endif
setsockopt(s->fd, SOL_IP, IP_MULTICAST_LOOP, &zero, sizeof(zero)) < 0)
return "IP_MULTICAST_LOOP";
}
return NULL;
}
#ifdef CONFIG_LINUX_MC_MREQN
/*
* 2.1 and newer kernels use struct mreqn which passes ifindex, so no
* problems with unnumbered devices.
*/
#ifndef HAVE_STRUCT_IP_MREQN
/* Several versions of glibc don't define this structure, so we have to do it ourselves */
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 */
};
#endif
static inline char *sysio_mcast_join(sock *s)
{
struct ip_mreqn mreq;
char *err;
if (err = sysio_mcast_setup(s))
return err;
mreq.imr_ifindex = s->iface->index;
set_inaddr(&mreq.imr_address, s->iface->addr->ip);
set_inaddr(&mreq.imr_multiaddr, s->daddr);
/* This defines where should we send _outgoing_ multicasts */
if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_IF, &mreq, sizeof(mreq)) < 0)
return "IP_MULTICAST_IF";
/* And this one sets interface for _receiving_ multicasts from */
if (ipa_nonzero(s->saddr) && setsockopt(s->fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
return "IP_ADD_MEMBERSHIP";
return NULL;
}
#endif
#if defined(CONFIG_LINUX_MC_MREQ) || defined(CONFIG_LINUX_MC_MREQ_BIND)
/*
* Older kernels support only struct mreq which matches interfaces by their
* addresses and thus fails on unnumbered devices. On newer 2.0 kernels
* we can use SO_BINDTODEVICE to circumvent this problem.
*/
#include <net/if.h>
static inline char *sysio_mcast_join(sock *s)
{
struct in_addr mreq;
struct ip_mreq mreq_add;
char *err;
if (err = sysio_mcast_setup(s))
return err;
set_inaddr(&mreq, s->iface->addr->ip);
#ifdef CONFIG_LINUX_MC_MREQ_BIND
{
struct ifreq ifr;
strcpy(ifr.ifr_name, s->iface->name);
if (setsockopt(s->fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0)
return "SO_BINDTODEVICE";
mreq_add.imr_interface.s_addr = INADDR_ANY;
}
#else
mreq_add.imr_interface = mreq;
#endif
set_inaddr(&mreq_add.imr_multiaddr, s->daddr);
/* This defines where should we send _outgoing_ multicasts */
if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_IF, &mreq, sizeof(mreq)) < 0)
return "IP_MULTICAST_IF";
/* And this one sets interface for _receiving_ multicasts from */
if (ipa_nonzero(s->saddr) && setsockopt(s->fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq_add, sizeof(mreq_add)) < 0)
return "IP_ADD_MEMBERSHIP";
return NULL;
}
#endif
#endif

View file

@ -17,10 +17,6 @@
#include <unistd.h>
#include <errno.h>
#ifndef HAVE_STRUCT_IP_MREQN
#include <net/if.h>
#endif
#include "nest/bird.h"
#include "lib/lists.h"
#include "lib/resource.h"
@ -30,10 +26,6 @@
#include "lib/string.h"
#include "nest/iface.h"
#ifdef IPV6
#include <linux/in6.h> /* FIXMEv6: glibc variant? */
#endif
#include "lib/unix.h"
/*
@ -383,7 +375,7 @@ sk_new(pool *p)
}
#define ERR(x) do { err = x; goto bad; } while(0)
#define WARN(x) log(L_WARN "sk_setup: " x)
#define WARN(x) log(L_WARN "sk_setup: %s: %m", x)
#ifdef IPV6
@ -444,6 +436,8 @@ get_sockaddr(sockaddr *sa, ip_addr *a, unsigned *port)
#endif
#include "lib/sysio.h"
static char *
sk_setup(sock *s)
{
@ -530,11 +524,9 @@ sk_open(sock *s)
{
int fd, e;
sockaddr sa;
int zero = 0;
int one = 1;
int type = s->type;
int has_src = ipa_nonzero(s->saddr) || s->sport;
int has_dest = ipa_nonzero(s->daddr);
char *err;
switch (type)
@ -581,9 +573,10 @@ sk_open(sock *s)
#ifdef IPV6
/* Fortunately, IPv6 socket interface is recent enough and therefore standardized */
ASSERT(s->iface && s->iface->addr);
if (has_dest)
if (ipa_nonzero(s->daddr))
{
int t = s->iface->index;
int zero = 0;
if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0)
ERR("IPV6_MULTICAST_HOPS");
if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero)) < 0)
@ -601,56 +594,9 @@ sk_open(sock *s)
}
#else
/* With IPv4 there are zillions of different socket interface variants. Ugh. */
#ifdef HAVE_STRUCT_IP_MREQN
struct ip_mreqn mreq;
#define mreq_add mreq
ASSERT(s->iface && s->iface->addr);
mreq.imr_ifindex = s->iface->index;
set_inaddr(&mreq.imr_address, s->iface->addr->ip);
#else
struct in_addr mreq;
struct ip_mreq mreq_add;
ASSERT(s->iface && s->iface->addr);
set_inaddr(&mreq, s->iface->addr->ip);
#ifdef SO_BINDTODEVICE
{
struct ifreq ifr;
strcpy(ifr.ifr_name, s->iface->name);
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0)
ERR("SO_BINDTODEVICE");
#if 0 /* FIXME */
mreq_add.imr_interface.s_addr = INADDR_ANY;
#else
mreq_add.imr_interface = mreq;
#endif
}
#else
#error Multicasts not supported on PtP devices /* FIXME: Solve it somehow? */
mreq_add.imr_interface = mreq;
#endif
#endif
set_inaddr(&mreq_add.imr_multiaddr, s->daddr);
if (has_dest)
{
if (
#ifdef IP_DEFAULT_MULTICAST_TTL
s->ttl != IP_DEFAULT_MULTICAST_TTL &&
#endif
setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &s->ttl, sizeof(s->ttl)) < 0)
ERR("IP_MULTICAST_TTL");
if (
#ifdef IP_DEFAULT_MULTICAST_LOOP
IP_DEFAULT_MULTICAST_LOOP &&
#endif
setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &zero, sizeof(zero)) < 0)
ERR("IP_MULTICAST_LOOP");
/* This defines where should we send _outgoing_ multicasts */
if (setsockopt(fd, SOL_IP, IP_MULTICAST_IF, &mreq, sizeof(mreq)) < 0)
ERR("IP_MULTICAST_IF");
}
/* And this one sets interface for _receiving_ multicasts from */
if (has_src && setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq_add, sizeof(mreq_add)) < 0)
ERR("IP_ADD_MEMBERSHIP");
if (err = sysio_mcast_join(s))
goto bad;
#endif
break;
}

View file

@ -102,9 +102,14 @@ scan_ifs(struct ifreq *r, int cnt)
}
if (fl & IFF_LOOPBACK)
i.flags |= IF_LOOPBACK | IF_IGNORE;
if (1
#ifndef CONFIG_ALL_MULTICAST
if (fl & IFF_MULTICAST)
&& (fl & IFF_MULTICAST)
#endif
#ifndef CONFIG_UNNUM_MULTICAST
&& !(i.flags & IF_UNNUMBERED)
#endif
)
i.flags |= IF_MULTICAST;
a.prefix = ipa_and(a.ip, ipa_mkmask(a.pxlen));