Merge branch 'ph/ipmi'
authorFlorian Forster <octo@huhu.verplant.org>
Tue, 19 Aug 2008 09:19:08 +0000 (11:19 +0200)
committerFlorian Forster <octo@huhu.verplant.org>
Tue, 19 Aug 2008 09:19:08 +0000 (11:19 +0200)
AUTHORS
configure.in
contrib/collection.cgi
src/Makefile.am
src/collectd.conf.pod
src/postgresql.c
src/postgresql_default.conf
src/tcpconns.c
src/types.db

diff --git a/AUTHORS b/AUTHORS
index 35cbec6..d924a91 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -47,6 +47,9 @@ tape plugin by:
 teamspeak2 plugin by:
   Stefan Hacker <stefan.hacker at web.de>
 
+tcpconns plugin:
+  Michael Stapelberg <michael+git@stapelberg.de> (OpenBSD port)
+
 users plugin by:
   Sebastian Harl <sh at tokkee.org>
 
index 02e06fe..314ad1d 100644 (file)
@@ -45,6 +45,9 @@ case $host_os in
        *darwin*)
        ac_system="Darwin"
        ;;
+       *openbsd*)
+       ac_system="OpenBSD"
+       ;;
        *)
        ac_system="unknown"
 esac
@@ -1232,11 +1235,13 @@ then
   AC_SUBST(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
 fi
 
+with_libkvm="no"
 AC_CHECK_LIB(kvm, kvm_getprocs, [with_kvm_getprocs="yes"], [with_kvm_getprocs="no"])
 if test "x$with_kvm_getprocs" = "xyes"
 then
        AC_DEFINE(HAVE_LIBKVM_GETPROCS, 1,
                  [Define to 1 if you have the 'kvm' library with the 'kvm_getprocs' symbol (-lkvm)])
+       with_libkvm="yes"
 fi
 AM_CONDITIONAL(BUILD_WITH_LIBKVM_GETPROCS, test "x$with_kvm_getprocs" = "xyes")
 
@@ -1245,9 +1250,19 @@ if test "x$with_kvm_getswapinfo" = "xyes"
 then
        AC_DEFINE(HAVE_LIBKVM_GETSWAPINFO, 1,
                  [Define to 1 if you have the 'kvm' library with the 'kvm_getswapinfo' symbol (-lkvm)])
+       with_libkvm="yes"
 fi
 AM_CONDITIONAL(BUILD_WITH_LIBKVM_GETSWAPINFO, test "x$with_kvm_getswapinfo" = "xyes")
 
+AC_CHECK_LIB(kvm, kvm_nlist, [with_kvm_nlist="yes"], [with_kvm_nlist="no"])
+if test "x$with_kvm_nlist" = "xyes"
+then
+       AC_DEFINE(HAVE_LIBKVM_NLIST, 1,
+                 [Define to 1 if you have the 'kvm' library with the 'kvm_nlist' symbol (-lkvm)])
+       with_libkvm="yes"
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBKVM_NLIST, test "x$with_kvm_nlist" = "xyes")
+
 with_sensors_cflags=""
 with_sensors_ldflags=""
 AC_ARG_WITH(lm-sensors, [AS_HELP_STRING([--with-lm-sensors@<:@=PREFIX@:>@], [Path to lm_sensors.])],
@@ -2529,6 +2544,11 @@ then
        fi
 fi
 
+if test "x$ac_system" = "xOpenBSD"
+then
+       plugin_tcpconns="yes"
+fi
+
 # Mac OS X devices
 if test "x$with_libiokit" = "xyes"
 then
@@ -2625,12 +2645,21 @@ then
        plugin_processes="yes"
 fi
 
-if test "x$with_libkvm" = "xyes"
+if test "x$with_kvm_getprocs" = "xyes"
 then
        plugin_processes="yes"
+fi
+
+if test "x$with_kvm_getswapinfo" = "xyes"
+then
        plugin_swap="yes"
 fi
 
+if test "x$with_kvm_nlist" = "xyes"
+then
+       plugin_tcpconns="yes"
+fi
+
 if test "x$have_getutent" = "xyes"
 then
        plugin_users="yes"
index cab7543..d3e5ccf 100755 (executable)
@@ -1963,6 +1963,16 @@ sub load_graph_definitions
     'GPRINT:pg_blks_avg:AVERAGE:%4.1lf%s Avg,',
     'GPRINT:pg_blks_max:MAX:%4.1lf%s Max,',
     'GPRINT:pg_blks_avg:LAST:%4.1lf%s Last'],
+    pg_db_size => ['DEF:pg_db_size_avg={file}:value:AVERAGE',
+    'DEF:pg_db_size_min={file}:value:MIN',
+    'DEF:pg_db_size_max={file}:value:MAX',
+    "AREA:pg_db_size_max#$HalfBlue",
+    "AREA:pg_db_size_min#$Canvas",
+    "LINE1:pg_db_size_avg#$FullBlue:Bytes",
+    'GPRINT:pg_db_size_min:MIN:%4.1lf%s Min,',
+    'GPRINT:pg_db_size_avg:AVERAGE:%4.1lf%s Avg,',
+    'GPRINT:pg_db_size_max:MAX:%4.1lf%s Max,',
+    'GPRINT:pg_db_size_avg:LAST:%4.1lf%s Last'],
     pg_n_tup_c => ['DEF:pg_n_tup_avg={file}:value:AVERAGE',
     'DEF:pg_n_tup_min={file}:value:MIN',
     'DEF:pg_n_tup_max={file}:value:MAX',
index 789f7f8..f0ad3cb 100644 (file)
@@ -683,8 +683,12 @@ if BUILD_PLUGIN_TCPCONNS
 pkglib_LTLIBRARIES += tcpconns.la
 tcpconns_la_SOURCES = tcpconns.c
 tcpconns_la_LDFLAGS = -module -avoid-version
+tcpconns_la_LIBADD =
 collectd_LDADD += "-dlopen" tcpconns.la
 collectd_DEPENDENCIES += tcpconns.la
+if BUILD_WITH_LIBKVM_NLIST
+tcpconns_la_LIBADD += -lkvm
+endif
 endif
 
 if BUILD_PLUGIN_TEAMSPEAK2
@@ -789,10 +793,20 @@ EXTRA_DIST += collectd-email.pod collectd-exec.pod collectd-nagios.pod \
        postgresql_default.conf
 
 .pod.1:
-       pod2man --release=$(VERSION) --center=$(PACKAGE) $< >.pod2man.tmp 2>/dev/null && mv -f .pod2man.tmp $@ || true
+       pod2man --release=$(VERSION) --center=$(PACKAGE) $< \
+               >.pod2man.tmp 2>/dev/null && mv -f .pod2man.tmp $@ || true
+       if grep '\<POD ERRORS\>' $@ >/dev/null 2>&1; \
+       then \
+               echo "$@ has some POD errors!"; false; \
+       fi
 
 .pod.5:
-       pod2man --section=5 --release=$(VERSION) --center=$(PACKAGE) $< >.pod2man.tmp 2>/dev/null && mv -f .pod2man.tmp $@ || true
+       pod2man --section=5 --release=$(VERSION) --center=$(PACKAGE) $< \
+               >.pod2man.tmp 2>/dev/null && mv -f .pod2man.tmp $@ || true
+       if grep '\<POD ERRORS\>' $@ >/dev/null 2>&1; \
+       then \
+               echo "$@ has some POD errors!"; false; \
+       fi
 
 install-exec-hook:
        $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
index c8d9a12..11a4192 100644 (file)
@@ -1110,6 +1110,9 @@ The username used to connect to the database.
 
 =back
 
+Please note that parameters are only supported by PostgreSQL's protocol
+version 3 and above which was introduced in version 7.4 of PostgreSQL.
+
 =item B<Column> I<type> [I<type instance>]
 
 Specify the I<type> and optional I<type instance> used to dispatch the value
@@ -1119,23 +1122,43 @@ B<Column> options has to match the columns of the query result.
 
 =back
 
-The following predefined queries are available:
+The following predefined queries are available (the definitions can be found
+in the F<postgresql_default.conf> file which, by default, is available at
+C<I<prefix>/share/collectd/>):
 
 =over 4
 
-=item B<database>
+=item B<backends>
+
+This query collects the number of backends, i.E<nbsp>e. the number of
+connected clients.
+
+=item B<transactions>
+
+This query collects the numbers of committed and rolled-back transactions of
+the user tables.
+
+=item B<queries>
+
+This query collects the numbers of various table modifications (i.E<nbsp>e.
+insertions, updates, deletions) of the user tables.
+
+=item B<query_plans>
+
+This query collects the numbers of various table scans and returned tuples of
+the user tables.
+
+=item B<table_states>
 
-This query collects general database statistics, i.E<nbsp>e. the number of
-backends and committed and rolled-back transactions.
+This query collects the numbers of live and dead rows in the user tables.
 
-=item B<user_tables>
+=item B<disk_io>
 
-This query collects user-table usage statistics, i.E<nbsp>e. the numbers of
-various table scans and the numbers of various table modifications.
+This query collects disk block access counts for user tables.
 
-=item B<io_user_tables>
+=item B<disk_usage>
 
-This query collects block access counts for user-tables.
+This query collects the on-disk size of the database in bytes.
 
 =back
 
@@ -1216,8 +1239,9 @@ B<PostgreSQL Documentation> for details.
 
 Specify a I<query> which should be executed for the database connection. This
 may be any of the predefined or user-defined queries. If no such option is
-given, it defaults to "database", "user_tables" and "io_user_tables". Else,
-the specified queries are used only.
+given, it defaults to "backends", "transactions", "queries", "query_plans",
+"table_states", "disk_io" and "disk_usage". Else, the specified queries are
+used only.
 
 =back
 
index 5bf0614..fbc117b 100644 (file)
@@ -103,6 +103,8 @@ typedef struct {
        PGconn      *conn;
        c_complain_t conn_complaint;
 
+       int proto_version;
+
        int max_params_num;
 
        /* user configuration */
@@ -123,9 +125,13 @@ typedef struct {
 } c_psql_database_t;
 
 static char *def_queries[] = {
-       "database",
-       "user_tables",
-       "io_user_tables"
+       "backends",
+       "transactions",
+       "queries",
+       "query_plans",
+       "table_states",
+       "disk_io",
+       "disk_usage"
 };
 static int def_queries_num = STATIC_ARRAY_SIZE (def_queries);
 
@@ -205,6 +211,8 @@ static c_psql_database_t *c_psql_database_new (const char *name)
        db->conn_complaint.last     = 0;
        db->conn_complaint.interval = 0;
 
+       db->proto_version = 0;
+
        db->max_params_num = 0;
 
        db->queries     = NULL;
@@ -319,6 +327,11 @@ static int c_psql_check_connection (c_psql_database_t *db)
                                        db->database, PQerrorMessage (db->conn));
                        return -1;
                }
+
+               db->proto_version = PQprotocolVersion (db->conn);
+               if (3 > db->proto_version)
+                       log_warn ("Protocol version %d does not support parameters.",
+                                       db->proto_version);
        }
 
        c_release (LOG_INFO, &db->conn_complaint,
@@ -326,20 +339,11 @@ static int c_psql_check_connection (c_psql_database_t *db)
        return 0;
 } /* c_psql_check_connection */
 
-static int c_psql_exec_query (c_psql_database_t *db, int idx)
+static PGresult *c_psql_exec_query_params (c_psql_database_t *db,
+               c_psql_query_t *query)
 {
-       c_psql_query_t *query;
-       PGresult       *res;
-
        char *params[db->max_params_num];
-
-       int rows, cols;
-       int i;
-
-       if (idx >= db->queries_num)
-               return -1;
-
-       query = db->queries[idx];
+       int   i;
 
        assert (db->max_params_num >= query->params_num);
 
@@ -360,9 +364,40 @@ static int c_psql_exec_query (c_psql_database_t *db, int idx)
                }
        }
 
-       res = PQexecParams (db->conn, query->query, query->params_num, NULL,
+       return PQexecParams (db->conn, query->query, query->params_num, NULL,
                        (const char *const *)((0 == query->params_num) ? NULL : params),
                        NULL, NULL, /* return text data */ 0);
+} /* c_psql_exec_query_params */
+
+static PGresult *c_psql_exec_query_noparams (c_psql_database_t *db,
+               c_psql_query_t *query)
+{
+       return PQexec (db->conn, query->query);
+} /* c_psql_exec_query_noparams */
+
+static int c_psql_exec_query (c_psql_database_t *db, int idx)
+{
+       c_psql_query_t *query;
+       PGresult       *res;
+
+       int rows, cols;
+       int i;
+
+       if (idx >= db->queries_num)
+               return -1;
+
+       query = db->queries[idx];
+
+       if (3 <= db->proto_version)
+               res = c_psql_exec_query_params (db, query);
+       else if (0 == query->params_num)
+               res = c_psql_exec_query_noparams (db, query);
+       else {
+               log_err ("Connection to database \"%s\" does not support parameters "
+                               "(protocol version %d) - cannot execute query \"%s\".",
+                               db->database, db->proto_version, query->name);
+               return -1;
+       }
 
        if (PGRES_TUPLES_OK != PQresultStatus (res)) {
                log_err ("Failed to execute SQL query: %s",
@@ -518,6 +553,8 @@ static int c_psql_init (void)
                if (0 != c_psql_check_connection (db))
                        continue;
 
+               db->proto_version = PQprotocolVersion (db->conn);
+
                server_host    = PQhost (db->conn);
                server_version = PQserverVersion (db->conn);
                log_info ("Sucessfully connected to database %s (user %s) "
@@ -526,7 +563,11 @@ static int c_psql_init (void)
                                PQdb (db->conn), PQuser (db->conn),
                                C_PSQL_SOCKET3 (server_host, PQport (db->conn)),
                                C_PSQL_SERVER_VERSION3 (server_version),
-                               PQprotocolVersion (db->conn), PQbackendPID (db->conn));
+                               db->proto_version, PQbackendPID (db->conn));
+
+               if (3 > db->proto_version)
+                       log_warn ("Protocol version %d does not support parameters.",
+                                       db->proto_version);
        }
 
        plugin_register_read ("postgresql", c_psql_read);
@@ -617,20 +658,14 @@ static int config_set_column (c_psql_query_t *query, const oconfig_item_t *ci)
        return 0;
 } /* config_set_column */
 
-static int config_set_query (c_psql_database_t *db, const oconfig_item_t *ci)
+static int set_query (c_psql_database_t *db, const char *name)
 {
        c_psql_query_t *query;
 
-       if ((0 != ci->children_num) || (1 != ci->values_num)
-                       || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
-               log_err ("Query expects a single string argument.");
-               return 1;
-       }
-
-       query = c_psql_query_get (ci->values[0].value.string);
+       query = c_psql_query_get (name);
        if (NULL == query) {
                log_err ("Query \"%s\" not found - please check your configuration.",
-                               ci->values[0].value.string);
+                               name);
                return 1;
        }
 
@@ -646,6 +681,16 @@ static int config_set_query (c_psql_database_t *db, const oconfig_item_t *ci)
 
        db->queries[db->queries_num - 1] = query;
        return 0;
+} /* set_query */
+
+static int config_set_query (c_psql_database_t *db, const oconfig_item_t *ci)
+{
+       if ((0 != ci->children_num) || (1 != ci->values_num)
+                       || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
+               log_err ("Query expects a single string argument.");
+               return 1;
+       }
+       return set_query (db, ci->values[0].value.string);
 } /* config_set_query */
 
 static int c_psql_config_query (oconfig_item_t *ci)
@@ -715,18 +760,8 @@ static int c_psql_config_database (oconfig_item_t *ci)
        }
 
        if (NULL == db->queries) {
-               db->queries = (c_psql_query_t **)malloc (def_queries_num
-                               * sizeof (*db->queries));
-
-               for (i = 0; i < def_queries_num; ++i) {
-                       db->queries[i] = c_psql_query_get (def_queries[i]);
-                       if (NULL == db->queries[i])
-                               log_err ("Query \"%s\" not found - "
-                                               "please check your installation.",
-                                               def_queries[i]);
-                       else
-                               ++db->queries_num;
-               }
+               for (i = 0; i < def_queries_num; ++i)
+                       set_query (db, def_queries[i]);
        }
        return 0;
 }
index d304de5..9d21217 100644 (file)
@@ -1,37 +1,57 @@
 # Pre-defined queries of collectd's postgresql plugin.
 
-<Query database>
-       Query "SELECT numbackends, xact_commit, xact_rollback \
-               FROM pg_stat_database \
+<Query backends>
+       Query "SELECT count(*) \
+               FROM pg_stat_activity \
                WHERE datname = $1;"
 
        Param database
 
        Column pg_numbackends
+</Query>
+
+<Query transactions>
+       Query "SELECT xact_commit, xact_rollback \
+               FROM pg_stat_database \
+               WHERE datname = $1;"
+
+       Param database
+
        Column pg_xact commit
        Column pg_xact rollback
 </Query>
 
-<Query user_tables>
-       Query "SELECT sum(seq_scan), sum(seq_tup_read), \
-                       sum(idx_scan), sum(idx_tup_fetch), \
-                       sum(n_tup_ins), sum(n_tup_upd), sum(n_tup_del), \
-                       sum(n_tup_hot_upd), sum(n_live_tup), sum(n_dead_tup) \
-               FROM pg_stat_user_tables"
-
-       Column pg_scan    seq
-       Column pg_scan    seq_tup_read
-       Column pg_scan    idx
-       Column pg_scan    idx_tup_fetch
+<Query queries>
+       Query "SELECT sum(n_tup_ins), sum(n_tup_upd), sum(n_tup_del), \
+                       sum(n_tup_hot_upd) \
+               FROM pg_stat_user_tables;"
+
        Column pg_n_tup_c ins
        Column pg_n_tup_c upd
        Column pg_n_tup_c del
        Column pg_n_tup_c hot_upd
+</Query>
+
+<Query query_plans>
+       Query "SELECT sum(seq_scan), sum(seq_tup_read), \
+                       sum(idx_scan), sum(idx_tup_fetch) \
+               FROM pg_stat_user_tables;"
+
+       Column pg_scan seq
+       Column pg_scan seq_tup_read
+       Column pg_scan idx
+       Column pg_scan idx_tup_fetch
+</Query>
+
+<Query table_states>
+       Query "SELECT sum(n_live_tup), sum(n_dead_tup) \
+               FROM pg_stat_user_tables;"
+
        Column pg_n_tup_g live
        Column pg_n_tup_g dead
 </Query>
 
-<Query io_user_tables>
+<Query disk_io>
        Query "SELECT sum(heap_blks_read), sum(heap_blks_hit), \
                        sum(idx_blks_read), sum(idx_blks_hit), \
                        sum(toast_blks_read), sum(toast_blks_hit), \
        Column pg_blks tidx_hit
 </Query>
 
+<Query disk_usage>
+       Query "SELECT pg_database_size($1);"
+
+       Param database
+
+       Column pg_db_size
+</Query>
+
index fac6a18..d39a6c3 100644 (file)
  *   Florian octo Forster <octo at verplant.org>
  **/
 
+/**
+ * Code within `HAVE_LIBKVM_NLIST' blocks is provided under the following
+ * license:
+ *
+ * $collectd: parts of tcpconns.c, 2008/08/08 03:48:30 Michael Stapelberg $
+ * $OpenBSD: inet.c,v 1.100 2007/06/19 05:28:30 ray Exp $
+ * $NetBSD: inet.c,v 1.14 1995/10/03 21:42:37 thorpej Exp $
+ *
+ * Copyright (c) 1983, 1988, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
 #include "collectd.h"
 #include "common.h"
 #include "plugin.h"
 
-#if !KERNEL_LINUX && !HAVE_SYSCTLBYNAME
+#if !KERNEL_LINUX && !HAVE_SYSCTLBYNAME && !HAVE_LIBKVM_NLIST
 # error "No applicable input method."
 #endif
 
 # include <netinet/tcpip.h>
 # include <netinet/tcp_seq.h>
 # include <netinet/tcp_var.h>
-#endif /* HAVE_SYSCTLBYNAME */
+/* #endif HAVE_SYSCTLBYNAME */
+
+/* This is for OpenBSD and possibly NetBSD. */
+#elif HAVE_LIBKVM_NLIST
+# include <sys/queue.h>
+# include <sys/socket.h>
+# include <net/route.h>
+# include <netinet/in.h>
+# include <netinet/in_systm.h>
+# include <netinet/ip.h>
+# include <netinet/in_pcb.h>
+# include <netinet/tcp.h>
+# include <netinet/tcp_timer.h>
+# include <netinet/tcp_var.h>
+# include <netdb.h>
+# include <arpa/inet.h>
+# include <nlist.h>
+# include <kvm.h>
+#endif /* HAVE_LIBKVM_NLIST */
 
 #if KERNEL_LINUX
 static const char *tcp_state[] =
@@ -100,7 +154,32 @@ static const char *tcp_state[] =
 # define TCP_STATE_LISTEN 1
 # define TCP_STATE_MIN 0
 # define TCP_STATE_MAX 10
-#endif /* HAVE_SYSCTLBYNAME */
+/* #endif HAVE_SYSCTLBYNAME */
+
+#elif HAVE_LIBKVM_NLIST
+static const char *tcp_state[] =
+{
+  "CLOSED",
+  "LISTEN",
+  "SYN_SENT",
+  "SYN_RECV",
+  "ESTABLISHED",
+  "CLOSE_WAIT",
+  "FIN_WAIT1",
+  "CLOSING",
+  "LAST_ACK",
+  "FIN_WAIT2",
+  "TIME_WAIT"
+};
+
+static kvm_t *kvmd;
+static u_long      inpcbtable_off = 0;
+struct inpcbtable *inpcbtable_ptr = NULL;
+
+# define TCP_STATE_LISTEN 1
+# define TCP_STATE_MIN 1
+# define TCP_STATE_MAX 10
+#endif /* HAVE_LIBKVM_NLIST */
 
 #define PORT_COLLECT_LOCAL  0x01
 #define PORT_COLLECT_REMOTE 0x02
@@ -360,7 +439,10 @@ static int conn_read_file (const char *file)
 /* #endif KERNEL_LINUX */
 
 #elif HAVE_SYSCTLBYNAME
-#endif /* HAVE_SYSCTLBYNAME */
+/* #endif HAVE_SYSCTLBYNAME */
+
+#elif HAVE_LIBKVM_NLIST
+#endif /* HAVE_LIBKVM_NLIST */
 
 static int conn_config (const char *key, const char *value)
 {
@@ -514,7 +596,107 @@ static int conn_read (void)
 
   return (0);
 } /* int conn_read */
-#endif /* HAVE_SYSCTLBYNAME */
+/* #endif HAVE_SYSCTLBYNAME */
+
+#elif HAVE_LIBKVM_NLIST
+static int kread (u_long addr, void *buf, int size)
+{
+  int status;
+
+  status = kvm_read (kvmd, addr, buf, size);
+  if (status != size)
+  {
+    ERROR ("tcpconns plugin: kvm_read failed (got %i, expected %i): %s\n",
+       status, size, kvm_geterr (kvmd));
+    return (-1);
+  }
+  return (0);
+} /* int kread */
+
+static int conn_init (void)
+{
+  char buf[_POSIX2_LINE_MAX];
+  struct nlist nl[] =
+  {
+#define N_TCBTABLE 0
+    { "_tcbtable" },
+    { "" }
+  };
+  int status;
+
+  kvmd = kvm_openfiles (NULL, NULL, NULL, O_RDONLY, buf);
+  if (kvmd == NULL)
+  {
+    ERROR ("tcpconns plugin: kvm_openfiles failed: %s", buf);
+    return (-1);
+  }
+
+  status = kvm_nlist (kvmd, nl);
+  if (status < 0)
+  {
+    ERROR ("tcpconns plugin: kvm_nlist failed with status %i.", status);
+    return (-1);
+  }
+
+  if (nl[N_TCBTABLE].n_type == 0)
+  {
+    ERROR ("tcpconns plugin: Error looking up kernel's namelist: "
+       "N_TCBTABLE is invalid.");
+    return (-1);
+  }
+
+  inpcbtable_off = (u_long) nl[N_TCBTABLE].n_value;
+  inpcbtable_ptr = (struct inpcbtable *) nl[N_TCBTABLE].n_value;
+
+  return (0);
+} /* int conn_init */
+
+static int conn_read (void)
+{
+  struct inpcbtable table;
+  struct inpcb *head;
+  struct inpcb *next;
+  struct inpcb inpcb;
+  struct tcpcb tcpcb;
+  int status;
+
+  conn_reset_port_entry ();
+
+  /* Read the pcbtable from the kernel */
+  status = kread (inpcbtable_off, &table, sizeof (table));
+  if (status != 0)
+    return (-1);
+
+  /* Get the `head' pcb */
+  head = (struct inpcb *) &(inpcbtable_ptr->inpt_queue);
+  /* Get the first pcb */
+  next = CIRCLEQ_FIRST (&table.inpt_queue);
+
+  while (next != head)
+  {
+    /* Read the pcb pointed to by `next' into `inpcb' */
+    kread ((u_long) next, &inpcb, sizeof (inpcb));
+
+    /* Advance `next' */
+    next = CIRCLEQ_NEXT (&inpcb, inp_queue);
+
+    /* Ignore sockets, that are not connected. */
+    if (!(inpcb.inp_flags & INP_IPV6)
+       && (inet_lnaof(inpcb.inp_laddr) == INADDR_ANY))
+      continue;
+    if ((inpcb.inp_flags & INP_IPV6)
+       && IN6_IS_ADDR_UNSPECIFIED (&inpcb.inp_laddr6))
+      continue;
+
+    kread ((u_long) inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb));
+    conn_handle_ports (ntohs(inpcb.inp_lport), ntohs(inpcb.inp_fport), tcpcb.t_state);
+  } /* while (next != head) */
+
+  conn_submit_all ();
+
+  return (0);
+}
+#endif /* HAVE_LIBKVM_NLIST */
 
 void module_register (void)
 {
@@ -522,10 +704,14 @@ void module_register (void)
                        config_keys, config_keys_num);
 #if KERNEL_LINUX
        plugin_register_init ("tcpconns", conn_init);
+#elif HAVE_SYSCTLBYNAME
+       /* no initialization */
+#elif HAVE_LIBKVM_NLIST
+       plugin_register_init ("tcpconns", conn_init);
 #endif
        plugin_register_read ("tcpconns", conn_read);
 } /* void module_register */
 
 /*
- * vim: set shiftwidth=2 softtabstop=2 tabstop=8 :
+ * vim: set shiftwidth=2 softtabstop=2 tabstop=8 fdm=marker :
  */
index fabae12..a31809d 100644 (file)
@@ -64,6 +64,7 @@ nginx_connections     value:GAUGE:0:U
 nginx_requests         value:COUNTER:0:134217728
 percent                        percent:GAUGE:0:100.1
 pg_blks                        value:COUNTER:0:U
+pg_db_size             value:GAUGE:0:U
 pg_n_tup_c             value:COUNTER:0:U
 pg_n_tup_g             value:GAUGE:0:U
 pg_numbackends         value:GAUGE:0:U