]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Tried to clean up multicast handling. Now we don't try to guess
authorMartin Mares <mj@ucw.cz>
Thu, 16 Dec 1999 13:06:13 +0000 (13:06 +0000)
committerMartin Mares <mj@ucw.cz>
Thu, 16 Dec 1999 13:06:13 +0000 (13:06 +0000)
multicast abilities depending on definedness of symbols and use hard-wired
system-dependent configuration defines instead.

Please test whereever you can.

TODO
sysdep/cf/README
sysdep/cf/linux-20.h
sysdep/cf/linux-21.h
sysdep/cf/linux-22.h
sysdep/linux/Modules
sysdep/linux/sysio.h [new file with mode: 0644]
sysdep/unix/io.c
sysdep/unix/krt-iface.c

diff --git a/TODO b/TODO
index 105f7e1f9a2e0c1cb8d68dbce06a10e0c2d1c4b6..2c0a02275e77ce463386a7b53b4131b8b74f31e7 100644 (file)
--- 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
index b1ed8683b1e701e18766728fada3b539737d4c25..a34427527da82ca6294688660fcace04dfb6b5d6 100644 (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
index 5fc440c9f063507fbdc8be3ad4ea2998d394abc6..5c6a2377756b95f7bdc9f587d245ff23b8785e73 100644 (file)
@@ -7,7 +7,6 @@
  */
 
 #undef CONFIG_AUTO_ROUTES
-#define CONFIG_ALL_MULTICAST
 #undef CONFIG_SELF_CONSCIOUS
 #undef CONFIG_MULTIPLE_TABLES
 
 #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
index 34e81830efa661e9c9ed2089ef563fd2143ac429..17882c81c346f958058f747c728a72c16dd69ce9 100644 (file)
@@ -7,7 +7,6 @@
  */
 
 #define CONFIG_AUTO_ROUTES
-#define CONFIG_ALL_MULTICAST
 #undef CONFIG_SELF_CONSCIOUS
 #undef CONFIG_MULTIPLE_TABLES
 
 #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
index cd5090f67c4cebc891f17ebc13ec025a60d36372..52a4681af58d17e409f18bd556beda67ab3593b3 100644 (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
index 4a99916a048e0545e3d05df23825c2e7357943fc..1b867d819fe34ece5a345c236ab29cce2878466b 100644 (file)
@@ -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 (file)
index 0000000..bef8a61
--- /dev/null
@@ -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
index 7e71d20d08b1a4bd71d6f8d3266a1bcb2079b9b9..af630f5e7978ad641305b5c2f6d060abba76c796 100644 (file)
 #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"
 #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;
       }
index a41b5ae9420833b543b9c9fb0185f3254de538e6..3a50e8b213837e411980342fe503a022f8f12823 100644 (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));