Commit 67ece6df authored by Martin Mareš's avatar Martin Mareš

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.
parent ccdc3397
......@@ -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
......
......@@ -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
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -2,3 +2,4 @@
krt-scan.c
krt-scan.h
#endif
sysio.h
/*
* 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
......@@ -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;
}
......
......@@ -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));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment