Hi,
becasue reading from /proc/net/tcp[6] takes a LOT of time, especially
when there are thousands of connections. I've adopted a patch on netstat
that uses netlink interface:
http://www.ducksong.com/misc/netstat-netlink-diag-patch.txt
as described in:
http://amailbox.org/mailarchive/linux-netdev/2008/8/26/3086024
The difference is like night and day. (netstat -n -t vs ss -a -n t)
Maybe someone is interested in making it pretty so it could be added to
the tree.
Thank you for collectd,
Jack.
diff -rupN collectd-4.4.2.orig/src/tcpconns.c collectd-4.4.2/src/tcpconns.c
--- collectd-4.4.2.orig/src/tcpconns.c 2008-07-15 16:31:47.000000000 +0200
+++ collectd-4.4.2/src/tcpconns.c 2010-08-24 21:13:47.000000000 +0200
@@ -23,6 +23,8 @@
#include "common.h"
#include "plugin.h"
+#define HAVE_NETLINK 1
+
#if !KERNEL_LINUX && !HAVE_SYSCTLBYNAME
# error "No applicable input method."
#endif
@@ -46,6 +48,7 @@
# include <net/if.h>
#endif
+
# include <net/route.h>
# include <netinet/in.h>
# include <netinet/in_systm.h>
@@ -59,6 +62,13 @@
# include <netinet/tcp_var.h>
#endif /* HAVE_SYSCTLBYNAME */
+#ifdef HAVE_NETLINK
+# include <netinet/in.h>
+# include <asm/types.h>
+# include <linux/netlink.h>
+# include <linux/inet_diag.h>
+#endif /* HAVE_NETLINK */
+
#if KERNEL_LINUX
static const char *tcp_state[] =
{
@@ -285,7 +295,117 @@ static int conn_handle_ports (uint16_t p
return (0);
} /* int conn_handle_ports */
-#if KERNEL_LINUX
+#if KERNEL_LINUX && HAVE_NETLINK
+
+static int conn_read_netlink ()
+{
+ int fd;
+ struct sockaddr_nl nladdr;
+ struct {
+ struct nlmsghdr nlh;
+ struct inet_diag_req r;
+ } req;
+ struct msghdr msg;
+ char buf[8192];
+ struct iovec iov;
+ struct inet_diag_msg *r;
+
+ if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG)) < 0)
+ return -1;
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+
+ req.nlh.nlmsg_len = sizeof(req);
+ req.nlh.nlmsg_type = TCPDIAG_GETSOCK;
+ req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+ req.nlh.nlmsg_pid = 0;
+ req.nlh.nlmsg_seq = 123456;
+ memset(&req.r, 0, sizeof(req.r));
+ req.r.idiag_family = AF_INET;
+ req.r.idiag_states = 0xfff;
+ req.r.idiag_ext = 0;
+
+ iov.iov_base = &req;
+ iov.iov_len = sizeof(req);
+
+ msg = (struct msghdr) {
+ .msg_name = (void*)&nladdr,
+ .msg_namelen = sizeof(nladdr),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ };
+
+ if (sendmsg(fd, &msg, 0) < 0)
+ {
+ close(fd);
+ return -1;
+ }
+
+ iov.iov_base = buf;
+ iov.iov_len = sizeof(buf);
+
+ while (1)
+ {
+ int status;
+ struct nlmsghdr *h;
+
+ msg = (struct msghdr) {
+ (void*) &nladdr,
+ sizeof(nladdr),
+ &iov,1,NULL,0,0
+ };
+
+ status = recvmsg(fd, &msg, 0);
+
+ if (status < 0)
+ {
+ if (errno == EINTR) continue;
+ close(fd);
+ return -2;
+ }
+
+ if (status == 0)
+ {
+ close(fd);
+ return 0;
+ }
+
+ h = (struct nlmsghdr*)buf;
+ while (NLMSG_OK(h, status))
+ {
+ if (h->nlmsg_seq == 123456)
+ {
+ if (h->nlmsg_type == NLMSG_DONE)
+ {
+ close(fd);
+ return 0;
+ }
+
+ if (h->nlmsg_type == NLMSG_ERROR)
+ {
+ close(fd);
+ return -2;
+ }
+
+ r = NLMSG_DATA(h);
+
+ conn_handle_ports(
+ ntohs(r->id.idiag_sport),
+ ntohs(r->id.idiag_dport),
+ (uint8_t) r->idiag_state
+ );
+ }
+ h = NLMSG_NEXT(h, status);
+ }
+ }
+
+ close(fd);
+ return 0;
+}
+
+#elif KERNEL_LINUX
+
static int conn_handle_line (char *buffer)
{
char *fields[32];
@@ -423,10 +543,15 @@ static int conn_read (void)
conn_reset_port_entry ();
- if (conn_read_file ("/proc/net/tcp") != 0)
- errors_num++;
- if (conn_read_file ("/proc/net/tcp6") != 0)
- errors_num++;
+#if HAVE_NETLINK
+ if (conn_read_netlink() != 0)
+ errors_num++;
+#else
+ if (conn_read_file ("/proc/net/tcp") != 0)
+ errors_num++;
+ if (conn_read_file ("/proc/net/tcp6") != 0)
+ errors_num++;
+#endif
if (errors_num < 2)
{
_______________________________________________
collectd mailing list
[email protected]
http://mailman.verplant.org/listinfo/collectd