Dear collectd-developers, users and fans!

Please excuse my possible double-post, but I've just found out that
the email was sent in a similar way as Fabian Linzbergers one in
July 2009. Thus I'm expecting that it also got lost at least in some
of your mailboxes.

I'm very impressed by the features and the idea of collectd.
It's very useful for the operation on embedded devices like the
OpenWRT-supported ones, because of its efficient operation and the
small memory footprint. During my tests I've considered the following
as a nice improvement.

The default behaviour of collectd to let the kernel choose the
default outgoing/incoming interface for multicast traffic is not
always a good choice, since the Linux kernel let's you only specify
one default route for multicast traffic or the system has to be
configured as a multicast router (which can be an overkill). To have
the opportunity to express the desired interface explicitly I've
created a patch against the current master.

The patch tries to follow the coding standard, the idea of the
configuration file and the structure of the network plugin as close
as possible. Furthermore I've tried to accomplish it with
interoperability in mind. Nonetheless there might be some (many ;-)
unconsidered issues from my side and thus:

  Suggestions and feedback is _greatly_ appreciated. :-)

Maybe it will help somebody or it gets collect(e)d for inclusion ;-)

Thank you for this nice piece of software!

Best regards,

Max
-- 
< henkel at gmx dot at >
---
 src/collectd.conf.pod |    7 ++++
 src/network.c         |   93 +++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 98 insertions(+), 2 deletions(-)

diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod
index 3a6f9a2..d8ad4ab 100644
--- a/src/collectd.conf.pod
+++ b/src/collectd.conf.pod
@@ -2438,6 +2438,13 @@ multicast, and IPv4 and IPv6 packets. The default is to not change this value.
 That means that multicast packets will be sent with a TTL of C<1> (one) on most
 operating systems.
 
+=item B<Interface> I<Interface name>
+
+Set the outgoing or incoming interface for multicast packets. This applies
+at least to IPv6 packets and if possible to IPv4. If it is not applicable or
+defined, the default behaviour is to let the kernel choose the appropriate
+interface.
+
 =item B<MaxPacketSize> I<1024-65535>
 
 Set the maximum size for datagrams received over the network. Packets larger
diff --git a/src/network.c b/src/network.c
index 8615753..b6e21b9 100644
--- a/src/network.c
+++ b/src/network.c
@@ -52,6 +52,9 @@
 #if HAVE_POLL_H
 # include <poll.h>
 #endif
+#if HAVE_NET_IF_H
+# include <net/if.h>
+#endif
 
 #if HAVE_LIBGCRYPT
 # include <gcrypt.h>
@@ -254,6 +257,7 @@ typedef struct receive_list_entry_s receive_list_entry_t;
  * Private variables
  */
 static int network_config_ttl = 0;
+static int network_config_interface_idx = 0;
 static size_t network_config_packet_size = 1024;
 static int network_config_forward = 0;
 static int network_config_stats = 0;
@@ -1583,6 +1587,64 @@ static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai)
 	return (0);
 } /* int network_set_ttl */
 
+static int network_set_interface (const sockent_t *se, const struct addrinfo *ai) /* {{{ */
+{
+	DEBUG ("network plugin: network_set_interface: interface index = %i;",
+			network_config_interface_idx);
+
+        assert (se->type == SOCKENT_TYPE_CLIENT);
+
+	if (ai->ai_family == AF_INET)
+	{
+		struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr;
+#if KERNEL_LINUX
+		struct ip_mreqn mreq;
+#else
+		struct ip_mreq mreq;
+#endif
+
+		if (! IN_MULTICAST (ntohl (addr->sin_addr.s_addr)))
+			return (0);
+
+		mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr;
+#if KERNEL_LINUX
+		mreq.imr_address.s_addr = ntohl (INADDR_ANY);
+		mreq.imr_ifindex = network_config_interface_idx;
+#else
+		mreq.imr_interface.s_addr = ntohl (INADDR_ANY);
+#endif
+
+		if (setsockopt (se->data.client.fd, IPPROTO_IP, IP_MULTICAST_IF,
+					&mreq, sizeof (mreq)) == -1)
+		{
+			char errbuf[1024];
+			ERROR ("setsockopt: %s",
+					sstrerror (errno, errbuf, sizeof (errbuf)));
+			return (-1);
+		}
+	}
+	else if (ai->ai_family == AF_INET6)
+	{
+		struct sockaddr_in6 *addr = (struct sockaddr_in6 *) ai->ai_addr;
+
+		if (! IN6_IS_ADDR_MULTICAST (&addr->sin6_addr))
+			return (0);
+
+		if (setsockopt (se->data.client.fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+					&network_config_interface_idx,
+					sizeof (network_config_interface_idx)) == -1)
+		{
+			char errbuf[1024];
+			ERROR ("setsockopt: %s",
+					sstrerror (errno, errbuf,
+						sizeof (errbuf)));
+			return (-1);
+		}
+	}
+
+	return (0);
+} /* }}} network_set_interface */
+
 static int network_bind_socket (int fd, const struct addrinfo *ai)
 {
 	int loop = 0;
@@ -1612,12 +1674,21 @@ static int network_bind_socket (int fd, const struct addrinfo *ai)
 		struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr;
 		if (IN_MULTICAST (ntohl (addr->sin_addr.s_addr)))
 		{
+#if KERNEL_LINUX
+			struct ip_mreqn mreq;
+#else
 			struct ip_mreq mreq;
+#endif
 
 			DEBUG ("fd = %i; IPv4 multicast address found", fd);
 
 			mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr;
-			mreq.imr_interface.s_addr = htonl (INADDR_ANY);
+#if KERNEL_LINUX
+			mreq.imr_address.s_addr = ntohl (INADDR_ANY);
+			mreq.imr_ifindex = network_config_interface_idx;
+#else
+			mreq.imr_interface.s_addr = ntohl (INADDR_ANY);
+#endif
 
 			if (setsockopt (fd, IPPROTO_IP, IP_MULTICAST_LOOP,
 						&loop, sizeof (loop)) == -1)
@@ -1663,7 +1734,7 @@ static int network_bind_socket (int fd, const struct addrinfo *ai)
 			 * single interface; programs running on
 			 * multihomed hosts may need to join the same
 			 * group on more than one interface.*/
-			mreq.ipv6mr_interface = 0;
+			mreq.ipv6mr_interface = network_config_interface_idx;
 
 			if (setsockopt (fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
 						&loop, sizeof (loop)) == -1)
@@ -1890,6 +1961,7 @@ static int sockent_open (sockent_t *se) /* {{{ */
 			se->data.client.addrlen = ai_ptr->ai_addrlen;
 
 			network_set_ttl (se, ai_ptr);
+			network_set_interface (se, ai_ptr);
 
 			/* We don't open more than one write-socket per
 			 * node/service pair.. */
@@ -2601,6 +2673,21 @@ static int network_config_set_ttl (const oconfig_item_t *ci) /* {{{ */
   return (0);
 } /* }}} int network_config_set_ttl */
 
+static int network_config_set_interface (const oconfig_item_t *ci) /* {{{ */
+{
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_STRING))
+  {
+    WARNING ("network plugin: The `Interface' config option needs exactly "
+        "one string argument.");
+    return (-1);
+  }
+
+  network_config_interface_idx = if_nametoindex (ci->values[0].value.string);
+
+  return (0);
+} /* }}} int network_config_set_interface */
+
 static int network_config_set_buffer_size (const oconfig_item_t *ci) /* {{{ */
 {
   int tmp;
@@ -2842,6 +2929,8 @@ static int network_config (oconfig_item_t *ci) /* {{{ */
       network_config_add_server (child);
     else if (strcasecmp ("TimeToLive", child->key) == 0)
       network_config_set_ttl (child);
+    else if (strcasecmp ("Interface", child->key) == 0)
+      network_config_set_interface (child);
     else if (strcasecmp ("MaxPacketSize", child->key) == 0)
       network_config_set_buffer_size (child);
     else if (strcasecmp ("Forward", child->key) == 0)
-- 
1.6.3.3

_______________________________________________
collectd mailing list
collectd@verplant.org
http://mailman.verplant.org/listinfo/collectd

Reply via email to