summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Mares <mj@ucw.cz>1999-12-16 13:06:13 +0000
committerMartin Mares <mj@ucw.cz>1999-12-16 13:06:13 +0000
commit67ece6df42b20ecc524cf3e5c14e8b541afec860 (patch)
tree4922b7aa50265895ac195ba59af184b7808533b9
parentccdc33975648647270bf33511ec5bbab4d634634 (diff)
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.
-rw-r--r--TODO7
-rw-r--r--sysdep/cf/README8
-rw-r--r--sysdep/cf/linux-20.h5
-rw-r--r--sysdep/cf/linux-21.h5
-rw-r--r--sysdep/cf/linux-22.h3
-rw-r--r--sysdep/linux/Modules1
-rw-r--r--sysdep/linux/sysio.h118
-rw-r--r--sysdep/unix/io.c68
-rw-r--r--sysdep/unix/krt-iface.c7
9 files changed, 150 insertions, 72 deletions
diff --git a/TODO b/TODO
index 105f7e1f..2c0a0227 100644
--- a/TODO
+++ b/TODO
@@ -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
diff --git a/sysdep/cf/README b/sysdep/cf/README
index b1ed8683..a3442752 100644
--- a/sysdep/cf/README
+++ b/sysdep/cf/README
@@ -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
diff --git a/sysdep/cf/linux-20.h b/sysdep/cf/linux-20.h
index 5fc440c9..5c6a2377 100644
--- a/sysdep/cf/linux-20.h
+++ b/sysdep/cf/linux-20.h
@@ -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
diff --git a/sysdep/cf/linux-21.h b/sysdep/cf/linux-21.h
index 34e81830..17882c81 100644
--- a/sysdep/cf/linux-21.h
+++ b/sysdep/cf/linux-21.h
@@ -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
diff --git a/sysdep/cf/linux-22.h b/sysdep/cf/linux-22.h
index cd5090f6..52a4681a 100644
--- a/sysdep/cf/linux-22.h
+++ b/sysdep/cf/linux-22.h
@@ -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
diff --git a/sysdep/linux/Modules b/sysdep/linux/Modules
index 4a99916a..1b867d81 100644
--- a/sysdep/linux/Modules
+++ b/sysdep/linux/Modules
@@ -2,3 +2,4 @@
krt-scan.c
krt-scan.h
#endif
+sysio.h
diff --git a/sysdep/linux/sysio.h b/sysdep/linux/sysio.h
new file mode 100644
index 00000000..bef8a612
--- /dev/null
+++ b/sysdep/linux/sysio.h
@@ -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
diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c
index 7e71d20d..af630f5e 100644
--- a/sysdep/unix/io.c
+++ b/sysdep/unix/io.c
@@ -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;
}
diff --git a/sysdep/unix/krt-iface.c b/sysdep/unix/krt-iface.c
index a41b5ae9..3a50e8b2 100644
--- a/sysdep/unix/krt-iface.c
+++ b/sysdep/unix/krt-iface.c
@@ -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));