tcpconns plugin: add support for AIX
authorManuel Luis SanmartĂ­n Rozada <manuel.luis@gmail.com>
Mon, 6 Jun 2011 12:14:27 +0000 (14:14 +0200)
committerFlorian Forster <octo@collectd.org>
Mon, 22 Aug 2011 17:01:38 +0000 (19:01 +0200)
Hi.

In AIX there is a undocumented function/syscall in libc: netinfo
returns a structure with the state of the tcp connections.

I didn't found the description or info abut this syscall,  I guess is
something like this:

int netinfo (int proto, void *data, int *size,  int n);

and the struct something like this: (with some work we can guess the
unknow remaining bytes)

struct netinfo_header {
        unsigned int proto;
        unsigned int size;
        struct netinfo_entry e[];
};
struct netinfo_entry {
        uint32_t unknow1;
        uint32_t unknow2;
        uint16_t dstport;
        uint16_t unknow3;
        struct in6_addr dstaddr;
        uint16_t srcport;
        uint16_t unknow4;
        struct in6_addr srcaddr;
        uint32_t unknow01[4];
        uint32_t unknow02[2];
        uint16_t so_options;
        uint16_t unknow02a;
        uint16_t so_q0len;
        uint16_t so_qlen;
        uint16_t so_qlimit;
        uint16_t so_dqlen;
        uint32_t unknow03[4];
        struct {
                uint32_t sb_hiwat;
                uint32_t unknow01;
                uint32_t unknow02;
                uint32_t unknow03;
                uint32_t sb_mbmax;
                uint32_t unknow04;
                uint32_t sb_lowat;
                uint16_t sb_flags;
                uint16_t unknow05;
        } rcvbuf;
        uint32_t unknow07;
        uint32_t unknow08[2];
        uint32_t unknow09;
        struct {
                uint32_t sb_hiwat;
                uint32_t unknow01;
                uint32_t unknow02;
                uint32_t unknow03;
                uint32_t sb_mbmax;
                uint32_t unknow04;
                uint32_t sb_lowat;
                uint16_t sb_flags;
                uint16_t unknow05;
        } sndbuf;
        uint32_t unknow11;
        uint32_t so_uid;
        uint16_t so_special;
        uint16_t so_special2;
        uint16_t tcp_state;
        uint16_t unknow12;
        uint32_t tcp_flags;
        uint32_t tcp_mss;
        uint32_t unknow15;
};

Signed-off-by: Florian Forster <octo@collectd.org>
configure.in
src/tcpconns.c

index 3b641d1..9b6397f 100644 (file)
@@ -4358,6 +4358,12 @@ then
 fi
 
 # AIX
+
+if test "x$ac_system" = "xAIX"
+then
+        plugin_tcpconns="yes"
+fi
+
 if test "x$with_perfstat" = "xyes"
 then
        plugin_cpu="yes"
index d68cd09..6a7e32d 100644 (file)
@@ -65,7 +65,7 @@
 #undef HAVE_SYSCTLBYNAME /* force HAVE_LIBKVM_NLIST path */
 #endif
 
-#if !KERNEL_LINUX && !HAVE_SYSCTLBYNAME && !HAVE_LIBKVM_NLIST
+#if !KERNEL_LINUX && !HAVE_SYSCTLBYNAME && !HAVE_LIBKVM_NLIST && !KERNEL_AIX
 # error "No applicable input method."
 #endif
 
 # include <arpa/inet.h>
 # include <nlist.h>
 # include <kvm.h>
-#endif /* HAVE_LIBKVM_NLIST */
+/* #endif HAVE_LIBKVM_NLIST */
+
+#elif KERNEL_AIX
+# include <arpa/inet.h>
+# include <sys/socketvar.h>
+#endif /* KERNEL_AIX */
 
 #if KERNEL_LINUX
 static const char *tcp_state[] =
@@ -186,7 +191,49 @@ struct inpcbtable *inpcbtable_ptr = NULL;
 # define TCP_STATE_LISTEN 1
 # define TCP_STATE_MIN 1
 # define TCP_STATE_MAX 10
-#endif /* HAVE_LIBKVM_NLIST */
+/* #endif HAVE_LIBKVM_NLIST */
+
+#elif KERNEL_AIX
+static const char *tcp_state[] =
+{
+  "CLOSED",
+  "LISTEN",
+  "SYN_SENT",
+  "SYN_RCVD",
+  "ESTABLISHED",
+  "CLOSE_WAIT",
+  "FIN_WAIT_1",
+  "CLOSING",
+  "LAST_ACK",
+  "FIN_WAIT_2",
+  "TIME_WAIT"
+};
+
+# define TCP_STATE_LISTEN 1
+# define TCP_STATE_MIN 0
+# define TCP_STATE_MAX 10
+
+struct netinfo_conn {
+  uint32_t unknow1[2];
+  uint16_t dstport;
+  uint16_t unknow2;
+  struct in6_addr dstaddr;
+  uint16_t srcport;
+  uint16_t unknow3;
+  struct in6_addr srcaddr;
+  uint32_t unknow4[36];
+  uint16_t tcp_state;
+  uint16_t unknow5[7];
+};
+
+struct netinfo_header {
+  unsigned int proto;
+  unsigned int size;
+};
+
+# define NETINFO_TCP 3
+extern int netinfo (int proto, void *data, int *size,  int n);
+#endif /* KERNEL_AIX */
 
 #define PORT_COLLECT_LOCAL  0x01
 #define PORT_COLLECT_REMOTE 0x02
@@ -706,7 +753,67 @@ static int conn_read (void)
 
   return (0);
 }
-#endif /* HAVE_LIBKVM_NLIST */
+/* #endif HAVE_LIBKVM_NLIST */
+
+#elif KERNEL_AIX
+
+static int conn_read (void)
+{
+  int size;
+  int i;
+  int nconn;
+  void *data;
+  struct netinfo_header *header;
+  struct netinfo_conn *conn;
+
+  conn_reset_port_entry ();
+
+  size = netinfo(NETINFO_TCP, 0, 0, 0);
+  if (size < 0)
+  {
+    ERROR ("tcpconns plugin: netinfo failed return: %i", size);
+    return (-1);
+  }
+
+  if (size == 0)
+    return (0);
+
+  if ((size - sizeof (struct netinfo_header)) % sizeof (struct netinfo_conn))
+  {
+    ERROR ("tcpconns plugin: invalid buffer size");
+    return (-1);
+  }
+
+  data = malloc(size);
+  if (data == NULL)
+  {
+    ERROR ("tcpconns plugin: malloc failed");
+    return (-1);
+  }
+
+  if (netinfo(NETINFO_TCP, data, &size, 0) < 0)
+  {
+    ERROR ("tcpconns plugin: netinfo failed");
+    free(data);
+    return (-1);
+  }
+
+  header = (struct netinfo_header *)data;
+  nconn = header->size;
+  conn = (struct netinfo_conn *)(data + sizeof(struct netinfo_header));
+
+  for (i=0; i < nconn; conn++, i++)
+  {
+    conn_handle_ports (conn->srcport, conn->dstport, conn->tcp_state);
+  }
+
+  free(data);
+
+  conn_submit_all ();
+
+  return (0);
+}
+#endif /* KERNEL_AIX */
 
 void module_register (void)
 {
@@ -718,6 +825,8 @@ void module_register (void)
        /* no initialization */
 #elif HAVE_LIBKVM_NLIST
        plugin_register_init ("tcpconns", conn_init);
+#elif KERNEL_AIX
+       /* no initialization */
 #endif
        plugin_register_read ("tcpconns", conn_read);
 } /* void module_register */