Iptables' counters: Number of bytes that were matched by a certain
iptables rule.
+ - ipmi
+ IPMI (Intelligent Platform Management Interface) sensors information.
+
- ipvs
IPVS connection statistics (number of connections, octets and packets
for each service and destination).
PostgreSQL database statistics: active server connections, transaction
numbers, block IO, table row manipulations.
+ - powerdns
+ PowerDNS name server statistics.
+
- processes
Process counts: Number of running, sleeping, zombie, ... processes.
+ - rrdcached
+ RRDtool caching daemon (RRDcacheD) statistics.
+
- sensors
System sensors, accessed using lm_sensors: Voltages, temperatures and
fan rotation speeds.
- tcpconns
Number of TCP connections to specific local and remote ports.
+ - teamspeak2
+ TeamSpeak2 server statistics.
+
+ - thermal
+ Linux ACPI thermal zone information.
+
- users
Users currently logged in.
you can easily do weird stuff with the plugins we didn't dare think of
;) See collectd-perl(5).
+ - rrdcached
+ Output to round-robin-database (RRD) files using the RRDtool caching
+ daemon (RRDcacheD) - see rrdcached(1). That daemon provides a general
+ implementation of the caching done by the `rrdtool' plugin.
+
- rrdtool
Output to round-robin-database (RRD) files using librrd. See rrdtool(1).
This is likely the most popular destination for such values. Since
since collectd is programmed multithreaded it benefits from hyperthreading
and multicore processors and makes sure that the daemon isn't idle if only
one plugins waits for an IO-operation to complete.
-
+
* Once set up, hardly any maintenance is necessary. Setup is kept as easy
as possible and the default values should be okay for most users.
* libhal (optional)
If present, the uuid plugin will check for UUID from HAL.
- * libiptc (optional)
+ * libiptc (optional, if not found a version shipped with this distribution
+ can be used if the Linux kernel headers are available)
For querying iptables counters.
* libmysqlclient (optional)
* libpq (optional)
The PostgreSQL C client library used by the `postgresql' plugin.
- * librrd (optional; headers and library; rrdtool 1.0 and 1.2 both work fine)
- If built without `librrd' the resulting binary will be `client only', i.e.
- will send its values via multicast and not create any RRD files itself.
- Alternatively you can chose to write CSV-files (Comma Separated Values)
- instead.
+ * librrd (optional)
+ Used by the `rrdtool' and `rrdcached' plugins. The latter requires RRDtool
+ client support which was added after version 1.3 of RRDtool. Versions 1.0,
+ 1.2 and 1.3 are known to work with the `rrdtool' plugin.
* librt, libsocket, libkstat, libdevinfo (optional)
Various standard Solaris libraries which provide system functions.
* libsensors (optional)
To read from `lm_sensors', see the `sensors' plugin.
- * libstatgrab (optional) may be used to collect statistics on systems other
- than Linux and/or Solaris. Note that CPU- and disk-statistics, while being
- provided by this library, are not supported in collectd right now..
- <http://www.i-scream.org/libstatgrab/>
+ * libstatgrab (optional)
+ Used by various plugins to collect statistics on systems other than Linux
+ and/or Solaris.
+ <http://www.i-scream.org/libstatgrab/>
* libupsclient/nut (optional)
For the `nut' plugin which queries nut's `upsd'.
`./configure && make && make install'. For detailed, generic instructions
see INSTALL. For a complete list of configure options and their description,
run `./configure --help'.
-
+
By default, the configure script will check for all build dependencies and
disable all plugins whose requirements cannot be fulfilled (any other plugin
will be enabled). To enable a plugin, install missing dependencies (see
librrd_cflags=""
librrd_ldflags=""
librrd_threadsafe="yes"
+librrd_rrdc_update="no"
AC_ARG_WITH(rrdtool, [AS_HELP_STRING([--with-rrdtool@<:@=PREFIX@:>@], [Path to rrdtool.])],
[ if test "x$withval" != "xno" && test "x$withval" != "xyes"
then
],
[-lm])
+ if test "x$librrd_threadsafe" = "xyes"
+ then
+ AC_CHECK_LIB(rrd_th, rrdc_update, [librrd_rrdc_update="yes"], [librrd_rrdc_update="no"])
+ else
+ AC_CHECK_LIB(rrd, rrdc_update, [librrd_rrdc_update="yes"], [librrd_rrdc_update="no"])
+ fi
+
CPPFLAGS="$SAVE_CPPFLAGS"
LDFLAGS="$SAVE_LDFLAGS"
fi
AC_PLUGIN([powerdns], [yes], [PowerDNS statistics])
AC_PLUGIN([processes], [$plugin_processes], [Process statistics])
AC_PLUGIN([rrdtool], [$with_rrdtool], [RRDTool output plugin])
+AC_PLUGIN([rrdcached], [$librrd_rrdc_update], [RRDTool output plugin])
AC_PLUGIN([sensors], [$with_lm_sensors], [lm_sensors statistics])
AC_PLUGIN([serial], [$plugin_serial], [serial port traffic])
AC_PLUGIN([snmp], [$with_libnetsnmp], [SNMP querying plugin])
powerdns . . . . . . $enable_powerdns
processes . . . . . . $enable_processes
rrdtool . . . . . . . $enable_rrdtool
+ rrdcached . . . . . . $enable_rrdcached
sensors . . . . . . . $enable_sensors
serial . . . . . . . $enable_serial
snmp . . . . . . . . $enable_snmp
endif
endif
+if BUILD_PLUGIN_RRDCACHED
+pkglib_LTLIBRARIES += rrdcached.la
+rrdcached_la_SOURCES = rrdcached.c utils_rrdcreate.c utils_rrdcreate.h
+rrdcached_la_LDFLAGS = -module -avoid-version
+rrdcached_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBRRD_CFLAGS)
+rrdcached_la_LIBADD = $(BUILD_WITH_LIBRRD_LDFLAGS)
+collectd_LDADD += "-dlopen" rrdcached.la
+collectd_DEPENDENCIES += rrdcached.la
+endif
+
if BUILD_PLUGIN_RRDTOOL
pkglib_LTLIBRARIES += rrdtool.la
-rrdtool_la_SOURCES = rrdtool.c
+rrdtool_la_SOURCES = rrdtool.c utils_rrdcreate.c utils_rrdcreate.h
rrdtool_la_LDFLAGS = -module -avoid-version
rrdtool_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBRRD_CFLAGS)
rrdtool_la_LIBADD = $(BUILD_WITH_LIBRRD_LDFLAGS)
@BUILD_PLUGIN_POSTGRESQL_TRUE@LoadPlugin postgresql
@BUILD_PLUGIN_POWERDNS_TRUE@LoadPlugin powerdns
@BUILD_PLUGIN_PROCESSES_TRUE@LoadPlugin processes
+@BUILD_PLUGIN_RRDCACHED_TRUE@LoadPlugin rrdcached
@BUILD_PLUGIN_RRDTOOL_TRUE@LoadPlugin rrdtool
@BUILD_PLUGIN_SENSORS_TRUE@LoadPlugin sensors
@BUILD_PLUGIN_SERIAL_TRUE@LoadPlugin serial
# Process "name"
#</Plugin>
+#<Plugin rrdcached>
+# DaemonAddress "unix:/tmp/rrdcached.sock"
+# DataDir "@prefix@/var/lib/@PACKAGE_NAME@/rrd"
+# CreateFiles true
+# CollectStatistics true
+#</Plugin>
+
#<Plugin rrdtool>
# DataDir "@prefix@/var/lib/@PACKAGE_NAME@/rrd"
# CacheTimeout 120
=back
+=head2 Plugin C<rrdcached>
+
+The C<rrdcached> plugin uses the RRDTool accelerator daemon, L<rrdcached(1)>,
+to store values to RRD files in an efficient manner. The combination of the
+C<rrdcached> B<plugin> and the C<rrdcached> B<daemon> is very similar to the
+way the C<rrdtool> plugin works (see below). The added abstraction layer
+provides a number of benefits, though: Because the cache is not within
+C<collectd> anymore, it does not need to be flushed when C<collectd> is to be
+restarted. This results in much shorter (if any) gaps in graphs, especially
+under heavy load. Also, the C<rrdtool> command line utility is aware of the
+daemon so that it can flush values to disk automatically when needed. This
+allows to integrate automated flushing of values into graphing solutions much
+more easily.
+
+There are disadvantages, though: The daemon may reside on a different host, so
+it may not be possible for C<collectd> to create the appropriate RRD files
+anymore. And even if C<rrdcached> runs on the same host, it may run in a
+different base directory, so relative paths may do weird stuff if you're not
+careful.
+
+So the B<recommended configuration> is to let C<collectd> and C<rrdcached> run
+on the same host, communicating via a UNIX domain socket. The B<DataDir>
+setting should be set to an absolute path, so that a changed base directory
+does not result in RRD files being createdE<nbsp>/ expected in the wrong place.
+
+=over 4
+
+=item B<DaemonAddress> I<Address>
+
+Address of the daemon as understood by the C<rrdc_connect> function of the RRD
+library. See L<rrdcached(1)> for details. Example:
+
+ <Plugin "rrdcached">
+ DaemonAddress "unix:/var/run/rrdcached.sock"
+ </Plugin>
+
+=item B<DataDir> I<Directory>
+
+Set the base directory in which the RRD files reside. If this is a relative
+path, it is relative to the working base directory of the C<rrdcached> daemon!
+Use of an absolute path is recommended.
+
+=item B<CreateFiles> B<true>|B<false>
+
+Enables or disables the creation of RRD files. If the daemon is not running
+locally, or B<DataDir> is set to a relative path, this will not work as
+expected. Default is B<true>.
+
+=back
+
=head2 Plugin C<rrdtool>
You can use the settings B<StepSize>, B<HeartBeat>, B<RRARows>, and B<XFF> to
#include "common.h"
#include "plugin.h"
#include "configfile.h"
+#include "utils_ignorelist.h"
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
};
static int config_keys_num = 2;
-static char **if_list = NULL;
-static int if_list_num = 0;
-/*
- * if_list_action:
- * 0 => default is to collect selected interface
- * 1 => ignore selcted interfaces
- */
-static int if_list_action = 0;
+static ignorelist_t *ignorelist = NULL;
#ifdef HAVE_LIBKSTAT
#define MAX_NUMIF 256
static int interface_config (const char *key, const char *value)
{
- char **temp;
+ if (ignorelist == NULL)
+ ignorelist = ignorelist_create (/* invert = */ 1);
if (strcasecmp (key, "Interface") == 0)
{
- temp = (char **) realloc (if_list, (if_list_num + 1) * sizeof (char *));
- if (temp == NULL)
- {
- ERROR ("Cannot allocate more memory.");
- return (1);
- }
- if_list = temp;
-
- if ((if_list[if_list_num] = strdup (value)) == NULL)
- {
- ERROR ("Cannot allocate memory.");
- return (1);
- }
- if_list_num++;
+ ignorelist_add (ignorelist, value);
}
else if (strcasecmp (key, "IgnoreSelected") == 0)
{
+ int invert = 1;
if ((strcasecmp (value, "True") == 0)
|| (strcasecmp (value, "Yes") == 0)
|| (strcasecmp (value, "On") == 0))
- if_list_action = 1;
- else
- if_list_action = 0;
+ invert = 0;
+ ignorelist_set_invert (ignorelist, invert);
}
else
{
} /* int interface_init */
#endif /* HAVE_LIBKSTAT */
-/*
- * Check if this interface/instance should be ignored. This is called from
- * both, `submit' and `write' to give client and server the ability to
- * ignore certain stuff..
- */
-static int check_ignore_if (const char *interface)
-{
- int i;
-
- /* If no interfaces are given collect all interfaces. Mostly to be
- * backwards compatible, but also because this is much easier. */
- if (if_list_num < 1)
- return (0);
-
- for (i = 0; i < if_list_num; i++)
- if (strcasecmp (interface, if_list[i]) == 0)
- return (if_list_action);
- return (1 - if_list_action);
-} /* int check_ignore_if */
-
static void if_submit (const char *dev, const char *type,
unsigned long long rx,
unsigned long long tx)
value_t values[2];
value_list_t vl = VALUE_LIST_INIT;
- if (check_ignore_if (dev))
+ if (ignorelist_match (ignorelist, dev) != 0)
return;
values[0].counter = rx;
AUTOMAKE_OPTIONS = foreign no-dependencies
-EXTRA_DIST = libiptc.c
+EXTRA_DIST = libiptc.c README.collectd
if COMPILER_IS_GCC
AM_CFLAGS = -Wall -Werror
noinst_LTLIBRARIES = libiptc.la
-libiptc_la_CFLAGS = -DIPTABLES_VERSION=\"1.4.0\" -I$(KERNEL_DIR)/include
+libiptc_la_CFLAGS = -I$(KERNEL_DIR)/include
libiptc_la_SOURCES = libip4tc.c libip6tc.c \
ipt_kernel_headers.h libip6tc.h libiptc.h linux_list.h
--- /dev/null
+ libiptc (IPTables Chains) in collectd
+=======================================
+http://netfilter.org/
+http://collectd.org/
+
+About
+-----
+
+ This is libiptc taken from the iptables source distribution. As it is not
+ meant to be a public interface by upstream it is not shipped in some binary
+ distributions. Thus, collectd ships its own copy as a fall-back.
+
+ The presently available version was imported from iptables 1.4.1.1.
+
+Changes to the iptables upstream sources:
+-----------------------------------------
+
+ * Added copyright headers mentioning the "Netfilter Core Team" as copyright
+ holder.
+
+ * Changed "libiptc/*" includes to "*".
+
+ * Use the shipped copy of "xtables.h" instead of the one possibly available
+ on the system.
+
#include "libiptc.c"
#define BIT6(a, l) \
- ((ntohl(a->in6_u.u6_addr32[(l) / 32]) >> (31 - ((l) & 31))) & 1)
+ ((ntohl(a->s6_addr32[(l) / 32]) >> (31 - ((l) & 31))) & 1)
int
ipv6_prefix_length(const struct in6_addr *a)
int ip6tc_commit(ip6tc_handle_t *handle);
/* Get raw socket. */
-int ip6tc_get_raw_socket();
+int ip6tc_get_raw_socket(void);
/* Translates errno numbers into more human-readable form than strerror. */
const char *ip6tc_strerror(int err);
/* Return prefix length, or -1 if not contiguous */
int ipv6_prefix_length(const struct in6_addr *a);
+extern void dump_entries6(const ip6tc_handle_t);
+
#endif /* _LIBIP6TC_H */
*/
#include <sys/types.h>
#include <sys/socket.h>
+#include "xtables.h"
#include "linux_list.h"
#define DEBUGP_C(x, args...)
#endif
-#ifndef IPT_LIB_DIR
-#define IPT_LIB_DIR "/usr/local/lib/iptables"
+#ifdef DEBUG
+#define debug(x, args...) fprintf(stderr, x, ## args)
+#else
+#define debug(x, args...)
#endif
static int sockfd = -1;
struct chain_head *chain_iterator_cur;
struct rule_head *rule_iterator_cur;
+ unsigned int num_chains; /* number of user defined chains */
+
+ struct chain_head **chain_index; /* array for fast chain list access*/
+ unsigned int chain_index_sz;/* size of chain index array */
+
STRUCT_GETINFO info;
STRUCT_GET_ENTRIES *entries;
};
}
/* notify us that the ruleset has been modified by the user */
-static void
+static inline void
set_changed(TC_HANDLE_T h)
{
h->changed = 1;
/**********************************************************************
+ * Chain index (cache utility) functions
+ **********************************************************************
+ * The chain index is an array with pointers into the chain list, with
+ * CHAIN_INDEX_BUCKET_LEN spacing. This facilitates the ability to
+ * speedup chain list searching, by find a more optimal starting
+ * points when searching the linked list.
+ *
+ * The starting point can be found fast by using a binary search of
+ * the chain index. Thus, reducing the previous search complexity of
+ * O(n) to O(log(n/k) + k) where k is CHAIN_INDEX_BUCKET_LEN.
+ *
+ * A nice property of the chain index, is that the "bucket" list
+ * length is max CHAIN_INDEX_BUCKET_LEN (when just build, inserts will
+ * change this). Oppose to hashing, where the "bucket" list length can
+ * vary a lot.
+ */
+#ifndef CHAIN_INDEX_BUCKET_LEN
+#define CHAIN_INDEX_BUCKET_LEN 40
+#endif
+
+/* Another nice property of the chain index is that inserting/creating
+ * chains in chain list don't change the correctness of the chain
+ * index, it only causes longer lists in the buckets.
+ *
+ * To mitigate the performance penalty of longer bucket lists and the
+ * penalty of rebuilding, the chain index is rebuild only when
+ * CHAIN_INDEX_INSERT_MAX chains has been added.
+ */
+#ifndef CHAIN_INDEX_INSERT_MAX
+#define CHAIN_INDEX_INSERT_MAX 355
+#endif
+
+static inline unsigned int iptcc_is_builtin(struct chain_head *c);
+
+
+/* Use binary search in the chain index array, to find a chain_head
+ * pointer closest to the place of the searched name element.
+ *
+ * Notes that, binary search (obviously) requires that the chain list
+ * is sorted by name.
+ */
+static struct list_head *
+iptcc_bsearch_chain_index(const char *name, unsigned int *idx, TC_HANDLE_T handle)
+{
+ unsigned int pos, end;
+ int res;
+
+ struct list_head *list_pos;
+ list_pos=&handle->chains;
+
+ /* Check for empty array, e.g. no user defined chains */
+ if (handle->chain_index_sz == 0) {
+ debug("WARNING: handle->chain_index_sz == 0\n");
+ return list_pos;
+ }
+
+ /* Init */
+ end = handle->chain_index_sz;
+ pos = end / 2;
+
+ debug("bsearch Find chain:%s (pos:%d end:%d)\n", name, pos, end);
+
+ /* Loop */
+ loop:
+ if (!handle->chain_index[pos]) {
+ fprintf(stderr, "ERROR: NULL pointer chain_index[%d]\n", pos);
+ return &handle->chains; /* Be safe, return orig start pos */
+ }
+
+ res = strcmp(name, handle->chain_index[pos]->name);
+ list_pos = &handle->chain_index[pos]->list;
+ *idx = pos;
+
+ debug("bsearch Index[%d] name:%s res:%d ",
+ pos, handle->chain_index[pos]->name, res);
+
+ if (res == 0) { /* Found element, by direct hit */
+ debug("[found] Direct hit pos:%d end:%d\n", pos, end);
+ return list_pos;
+ } else if (res < 0) { /* Too far, jump back */
+ end = pos;
+ pos = pos / 2;
+
+ /* Exit case: First element of array */
+ if (end == 0) {
+ debug("[found] Reached first array elem (end%d)\n",end);
+ return list_pos;
+ }
+ debug("jump back to pos:%d (end:%d)\n", pos, end);
+ goto loop;
+ } else if (res > 0 ){ /* Not far enough, jump forward */
+
+ /* Exit case: Last element of array */
+ if (pos == handle->chain_index_sz-1) {
+ debug("[found] Last array elem (end:%d)\n", end);
+ return list_pos;
+ }
+
+ /* Exit case: Next index less, thus elem in this list section */
+ res = strcmp(name, handle->chain_index[pos+1]->name);
+ if (res < 0) {
+ debug("[found] closest list (end:%d)\n", end);
+ return list_pos;
+ }
+
+ pos = (pos+end)/2;
+ debug("jump forward to pos:%d (end:%d)\n", pos, end);
+ goto loop;
+ }
+
+ return list_pos;
+}
+
+#ifdef DEBUG
+/* Trivial linear search of chain index. Function used for verifying
+ the output of bsearch function */
+static struct list_head *
+iptcc_linearly_search_chain_index(const char *name, TC_HANDLE_T handle)
+{
+ unsigned int i=0;
+ int res=0;
+
+ struct list_head *list_pos;
+ list_pos = &handle->chains;
+
+ if (handle->chain_index_sz)
+ list_pos = &handle->chain_index[0]->list;
+
+ /* Linearly walk of chain index array */
+
+ for (i=0; i < handle->chain_index_sz; i++) {
+ if (handle->chain_index[i]) {
+ res = strcmp(handle->chain_index[i]->name, name);
+ if (res > 0)
+ break; // One step too far
+ list_pos = &handle->chain_index[i]->list;
+ if (res == 0)
+ break; // Direct hit
+ }
+ }
+
+ return list_pos;
+}
+#endif
+
+static int iptcc_chain_index_alloc(TC_HANDLE_T h)
+{
+ unsigned int list_length = CHAIN_INDEX_BUCKET_LEN;
+ unsigned int array_elems;
+ unsigned int array_mem;
+
+ /* Allocate memory for the chain index array */
+ array_elems = (h->num_chains / list_length) +
+ (h->num_chains % list_length ? 1 : 0);
+ array_mem = sizeof(h->chain_index) * array_elems;
+
+ debug("Alloc Chain index, elems:%d mem:%d bytes\n",
+ array_elems, array_mem);
+
+ h->chain_index = malloc(array_mem);
+ if (!h->chain_index) {
+ h->chain_index_sz = 0;
+ return -ENOMEM;
+ }
+ memset(h->chain_index, 0, array_mem);
+ h->chain_index_sz = array_elems;
+
+ return 1;
+}
+
+static void iptcc_chain_index_free(TC_HANDLE_T h)
+{
+ h->chain_index_sz = 0;
+ free(h->chain_index);
+}
+
+
+#ifdef DEBUG
+static void iptcc_chain_index_dump(TC_HANDLE_T h)
+{
+ unsigned int i = 0;
+
+ /* Dump: contents of chain index array */
+ for (i=0; i < h->chain_index_sz; i++) {
+ if (h->chain_index[i]) {
+ fprintf(stderr, "Chain index[%d].name: %s\n",
+ i, h->chain_index[i]->name);
+ }
+ }
+}
+#endif
+
+/* Build the chain index */
+static int iptcc_chain_index_build(TC_HANDLE_T h)
+{
+ unsigned int list_length = CHAIN_INDEX_BUCKET_LEN;
+ unsigned int chains = 0;
+ unsigned int cindex = 0;
+ struct chain_head *c;
+
+ /* Build up the chain index array here */
+ debug("Building chain index\n");
+
+ debug("Number of user defined chains:%d bucket_sz:%d array_sz:%d\n",
+ h->num_chains, list_length, h->chain_index_sz);
+
+ if (h->chain_index_sz == 0)
+ return 0;
+
+ list_for_each_entry(c, &h->chains, list) {
+
+ /* Issue: The index array needs to start after the
+ * builtin chains, as they are not sorted */
+ if (!iptcc_is_builtin(c)) {
+ cindex=chains / list_length;
+
+ /* Safe guard, break out on array limit, this
+ * is useful if chains are added and array is
+ * rebuild, without realloc of memory. */
+ if (cindex >= h->chain_index_sz)
+ break;
+
+ if ((chains % list_length)== 0) {
+ debug("\nIndex[%d] Chains:", cindex);
+ h->chain_index[cindex] = c;
+ }
+ chains++;
+ }
+ debug("%s, ", c->name);
+ }
+ debug("\n");
+
+ return 1;
+}
+
+static int iptcc_chain_index_rebuild(TC_HANDLE_T h)
+{
+ debug("REBUILD chain index array\n");
+ iptcc_chain_index_free(h);
+ if ((iptcc_chain_index_alloc(h)) < 0)
+ return -ENOMEM;
+ iptcc_chain_index_build(h);
+ return 1;
+}
+
+/* Delete chain (pointer) from index array. Removing an element from
+ * the chain list only affects the chain index array, if the chain
+ * index points-to/uses that list pointer.
+ *
+ * There are different strategies, the simple and safe is to rebuild
+ * the chain index every time. The more advanced is to update the
+ * array index to point to the next element, but that requires some
+ * house keeping and boundry checks. The advanced is implemented, as
+ * the simple approach behaves badly when all chains are deleted
+ * because list_for_each processing will always hit the first chain
+ * index, thus causing a rebuild for every chain.
+ */
+static int iptcc_chain_index_delete_chain(struct chain_head *c, TC_HANDLE_T h)
+{
+ struct list_head *index_ptr, *index_ptr2, *next;
+ struct chain_head *c2;
+ unsigned int idx, idx2;
+
+ index_ptr = iptcc_bsearch_chain_index(c->name, &idx, h);
+
+ debug("Del chain[%s] c->list:%p index_ptr:%p\n",
+ c->name, &c->list, index_ptr);
+
+ /* Save the next pointer */
+ next = c->list.next;
+ list_del(&c->list);
+
+ if (index_ptr == &c->list) { /* Chain used as index ptr */
+
+ /* See if its possible to avoid a rebuild, by shifting
+ * to next pointer. Its possible if the next pointer
+ * is located in the same index bucket.
+ */
+ c2 = list_entry(next, struct chain_head, list);
+ index_ptr2 = iptcc_bsearch_chain_index(c2->name, &idx2, h);
+ if (idx != idx2) {
+ /* Rebuild needed */
+ return iptcc_chain_index_rebuild(h);
+ } else {
+ /* Avoiding rebuild */
+ debug("Update cindex[%d] with next ptr name:[%s]\n",
+ idx, c2->name);
+ h->chain_index[idx]=c2;
+ return 0;
+ }
+ }
+ return 0;
+}
+
+
+/**********************************************************************
* iptc cache utility functions (iptcc_*)
**********************************************************************/
/* Is the given chain builtin (1) or user-defined (0) */
-static unsigned int iptcc_is_builtin(struct chain_head *c)
+static inline unsigned int iptcc_is_builtin(struct chain_head *c)
{
return (c->hooknum ? 1 : 0);
}
return NULL;
}
+
/* Returns chain head if found, otherwise NULL. */
static struct chain_head *
iptcc_find_label(const char *name, TC_HANDLE_T handle)
{
struct list_head *pos;
+ struct list_head *list_start_pos;
+ unsigned int i=0;
+ int res;
if (list_empty(&handle->chains))
return NULL;
+ /* First look at builtin chains */
list_for_each(pos, &handle->chains) {
struct chain_head *c = list_entry(pos, struct chain_head, list);
+ if (!iptcc_is_builtin(c))
+ break;
if (!strcmp(c->name, name))
return c;
}
+ /* Find a smart place to start the search via chain index */
+ //list_start_pos = iptcc_linearly_search_chain_index(name, handle);
+ list_start_pos = iptcc_bsearch_chain_index(name, &i, handle);
+
+ /* Handel if bsearch bails out early */
+ if (list_start_pos == &handle->chains) {
+ list_start_pos = pos;
+ }
+#ifdef DEBUG
+ else {
+ /* Verify result of bsearch against linearly index search */
+ struct list_head *test_pos;
+ struct chain_head *test_c, *tmp_c;
+ test_pos = iptcc_linearly_search_chain_index(name, handle);
+ if (list_start_pos != test_pos) {
+ debug("BUG in chain_index search\n");
+ test_c=list_entry(test_pos, struct chain_head,list);
+ tmp_c =list_entry(list_start_pos,struct chain_head,list);
+ debug("Verify search found:\n");
+ debug(" Chain:%s\n", test_c->name);
+ debug("BSearch found:\n");
+ debug(" Chain:%s\n", tmp_c->name);
+ exit(42);
+ }
+ }
+#endif
+
+ /* Initial/special case, no user defined chains */
+ if (handle->num_chains == 0)
+ return NULL;
+
+ /* Start searching through the chain list */
+ list_for_each(pos, list_start_pos->prev) {
+ struct chain_head *c = list_entry(pos, struct chain_head, list);
+ res = strcmp(c->name, name);
+ debug("List search name:%s == %s res:%d\n", name, c->name, res);
+ if (res==0)
+ return c;
+
+ /* We can stop earlier as we know list is sorted */
+ if (res>0 && !iptcc_is_builtin(c)) { /* Walked too far*/
+ debug(" Not in list, walked too far, sorted list\n");
+ return NULL;
+ }
+
+ /* Stop on wrap around, if list head is reached */
+ if (pos == &handle->chains) {
+ debug("Stop, list head reached\n");
+ return NULL;
+ }
+ }
+
+ debug("List search NOT found name:%s\n", name);
return NULL;
}
static inline void iptc_insert_chain(TC_HANDLE_T h, struct chain_head *c)
{
struct chain_head *tmp;
+ struct list_head *list_start_pos;
+ unsigned int i=1;
+
+ /* Find a smart place to start the insert search */
+ list_start_pos = iptcc_bsearch_chain_index(c->name, &i, h);
+
+ /* Handle the case, where chain.name is smaller than index[0] */
+ if (i==0 && strcmp(c->name, h->chain_index[0]->name) <= 0) {
+ h->chain_index[0] = c; /* Update chain index head */
+ list_start_pos = h->chains.next;
+ debug("Update chain_index[0] with %s\n", c->name);
+ }
+
+ /* Handel if bsearch bails out early */
+ if (list_start_pos == &h->chains) {
+ list_start_pos = h->chains.next;
+ }
/* sort only user defined chains */
if (!c->hooknum) {
- list_for_each_entry(tmp, &h->chains, list) {
+ list_for_each_entry(tmp, list_start_pos->prev, list) {
if (!tmp->hooknum && strcmp(c->name, tmp->name) <= 0) {
list_add(&c->list, tmp->list.prev);
return;
}
+
+ /* Stop if list head is reached */
+ if (&tmp->list == &h->chains) {
+ debug("Insert, list head reached add to tail\n");
+ break;
+ }
}
}
errno = -ENOMEM;
return -1;
}
+ h->num_chains++; /* New user defined chain */
__iptcc_p_add_chain(h, c, offset, num);
ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
cache_add_entry, h, &prev, &num);
+ /* Build the chain index, used for chain list search speedup */
+ if ((iptcc_chain_index_alloc(h)) < 0)
+ return -ENOMEM;
+ iptcc_chain_index_build(h);
+
/* Second pass: fixup parsed data from first pass */
list_for_each_entry(c, &h->chains, list) {
struct rule_head *r;
list_for_each_entry(r, &c->rules, list) {
- struct chain_head *c;
+ struct chain_head *lc;
STRUCT_STANDARD_TARGET *t;
if (r->type != IPTCC_R_JUMP)
continue;
t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
- c = iptcc_find_chain_by_offset(h, t->verdict);
- if (!c)
+ lc = iptcc_find_chain_by_offset(h, t->verdict);
+ if (!lc)
return -1;
- r->jump = c;
- c->references++;
+ r->jump = lc;
+ lc->references++;
}
}
return NULL;
}
sockfd_use++;
-
+retry:
s = sizeof(info);
strcpy(info.name, tablename);
return h;
error:
TC_FREE(&h);
+ /* A different process changed the ruleset size, retry */
+ if (errno == EAGAIN)
+ goto retry;
return NULL;
}
free(c);
}
+ iptcc_chain_index_free(*h);
+
free((*h)->entries);
free(*h);
CHECK(handle);
printf("libiptc v%s. %u bytes.\n",
- IPTABLES_VERSION, handle->entries->size);
+ XTABLES_VERSION, handle->entries->size);
printf("Table `%s'\n", handle->info.name);
printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
handle->info.hook_entry[HOOK_PRE_ROUTING],
}
/* How many rules in this chain? */
-unsigned int
+static unsigned int
TC_NUM_RULES(const char *chain, TC_HANDLE_T *handle)
{
struct chain_head *c;
return c->num_rules;
}
-const STRUCT_ENTRY *TC_GET_RULE(const char *chain,
- unsigned int n,
- TC_HANDLE_T *handle)
+static const STRUCT_ENTRY *
+TC_GET_RULE(const char *chain, unsigned int n, TC_HANDLE_T *handle)
{
struct chain_head *c;
struct rule_head *r;
TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
{
static struct chain_head *c;
+ int capacity;
+ int exceeded;
iptc_fn = TC_CREATE_CHAIN;
return 0;
}
+ (*handle)->num_chains++; /* New user defined chain */
DEBUGP("Creating chain `%s'\n", chain);
iptc_insert_chain(*handle, c); /* Insert sorted */
+ /* Inserting chains don't change the correctness of the chain
+ * index (except if its smaller than index[0], but that
+ * handled by iptc_insert_chain). It only causes longer lists
+ * in the buckets. Thus, only rebuild chain index when the
+ * capacity is exceed with CHAIN_INDEX_INSERT_MAX chains.
+ */
+ capacity = (*handle)->chain_index_sz * CHAIN_INDEX_BUCKET_LEN;
+ exceeded = ((((*handle)->num_chains)-capacity));
+ if (exceeded > CHAIN_INDEX_INSERT_MAX) {
+ debug("Capacity(%d) exceeded(%d) rebuild (chains:%d)\n",
+ capacity, exceeded, (*handle)->num_chains);
+ iptcc_chain_index_rebuild(*handle);
+ }
+
set_changed(*handle);
return 1;
}
/* If we are about to delete the chain that is the current
- * iterator, move chain iterator firward. */
+ * iterator, move chain iterator forward. */
if (c == (*handle)->chain_iterator_cur)
iptcc_chain_iterator_advance(*handle);
- list_del(&c->list);
+ (*handle)->num_chains--; /* One user defined chain deleted */
+
+ //list_del(&c->list); /* Done in iptcc_chain_index_delete_chain() */
+ iptcc_chain_index_delete_chain(c, *handle);
free(c);
DEBUGP("chain `%s' deleted\n", chain);
}
-static void counters_nomap(STRUCT_COUNTERS_INFO *newcounters,
- unsigned int index)
+static void counters_nomap(STRUCT_COUNTERS_INFO *newcounters, unsigned int idx)
{
- newcounters->counters[index] = ((STRUCT_COUNTERS) { 0, 0});
+ newcounters->counters[idx] = ((STRUCT_COUNTERS) { 0, 0});
DEBUGP_C("NOMAP => zero\n");
}
static void counters_normal_map(STRUCT_COUNTERS_INFO *newcounters,
- STRUCT_REPLACE *repl,
- unsigned int index,
+ STRUCT_REPLACE *repl, unsigned int idx,
unsigned int mappos)
{
/* Original read: X.
* => Add in X + Y
* => Add in replacement read.
*/
- newcounters->counters[index] = repl->counters[mappos];
+ newcounters->counters[idx] = repl->counters[mappos];
DEBUGP_C("NORMAL_MAP => mappos %u \n", mappos);
}
static void counters_map_zeroed(STRUCT_COUNTERS_INFO *newcounters,
- STRUCT_REPLACE *repl,
- unsigned int index,
- unsigned int mappos,
- STRUCT_COUNTERS *counters)
+ STRUCT_REPLACE *repl, unsigned int idx,
+ unsigned int mappos, STRUCT_COUNTERS *counters)
{
/* Original read: X.
* Atomic read on replacement: X + Y.
* => Add in Y.
* => Add in (replacement read - original read).
*/
- subtract_counters(&newcounters->counters[index],
+ subtract_counters(&newcounters->counters[idx],
&repl->counters[mappos],
counters);
DEBUGP_C("ZEROED => mappos %u\n", mappos);
}
static void counters_map_set(STRUCT_COUNTERS_INFO *newcounters,
- unsigned int index,
- STRUCT_COUNTERS *counters)
+ unsigned int idx, STRUCT_COUNTERS *counters)
{
/* Want to set counter (iptables-restore) */
- memcpy(&newcounters->counters[index], counters,
+ memcpy(&newcounters->counters[idx], counters,
sizeof(STRUCT_COUNTERS));
DEBUGP_C("SET\n");
int iptc_commit(iptc_handle_t *handle);
/* Get raw socket. */
-int iptc_get_raw_socket();
+int iptc_get_raw_socket(void);
/* Translates errno numbers into more human-readable form than strerror. */
const char *iptc_strerror(int err);
+extern void dump_entries(const iptc_handle_t);
+
#ifdef __cplusplus
}
#endif
--- /dev/null
+/**
+ * This file was imported from the iptables sources.
+ * Copyright (C) 1999-2008 Netfilter Core Team
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBXTC_H
+#define _LIBXTC_H
+/* Library which manipulates filtering rules. */
+
+#include "ipt_kernel_headers.h"
+#include <linux/netfilter/x_tables.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef XT_MIN_ALIGN
+/* xt_entry has pointers and u_int64_t's in it, so if you align to
+ it, you'll also align to any crazy matches and targets someone
+ might write */
+#define XT_MIN_ALIGN (__alignof__(struct xt_entry))
+#endif
+
+#ifndef XT_ALIGN
+#define XT_ALIGN(s) (((s) + ((XT_MIN_ALIGN)-1)) & ~((XT_MIN_ALIGN)-1))
+#endif
+
+typedef char xt_chainlabel[32];
+
+#define XTC_LABEL_ACCEPT "ACCEPT"
+#define XTC_LABEL_DROP "DROP"
+#define XTC_LABEL_QUEUE "QUEUE"
+#define XTC_LABEL_RETURN "RETURN"
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBXTC_H */
--- /dev/null
+/**
+ * This file was imported from the iptables sources.
+ * Copyright (C) 1999-2008 Netfilter Core Team
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _XTABLES_H
+#define _XTABLES_H
+
+#include <sys/types.h>
+#include <linux/types.h>
+#include <linux/netfilter/x_tables.h>
+#include "libxtc.h"
+#include <stdbool.h>
+
+#ifndef IPPROTO_SCTP
+#define IPPROTO_SCTP 132
+#endif
+#ifndef IPPROTO_DCCP
+#define IPPROTO_DCCP 33
+#endif
+#ifndef IPPROTO_UDPLITE
+#define IPPROTO_UDPLITE 136
+#endif
+
+#define XTABLES_VERSION "1.4.1.1"
+#define XTABLES_VERSION_CODE (0x10000 * 1 + 0x100 * 4 + 1)
+
+#define XTABLES_API_VERSION(x,y,z) (0x10000*(x) + 0x100*(y) + z)
+
+/* Include file for additions: new matches and targets. */
+struct xtables_match
+{
+ struct xtables_match *next;
+
+ xt_chainlabel name;
+
+ /* Revision of match (0 by default). */
+ u_int8_t revision;
+
+ u_int16_t family;
+
+ const char *version;
+
+ /* Size of match data. */
+ size_t size;
+
+ /* Size of match data relevent for userspace comparison purposes */
+ size_t userspacesize;
+
+ /* Function which prints out usage message. */
+ void (*help)(void);
+
+ /* Initialize the match. */
+ void (*init)(struct xt_entry_match *m);
+
+ /* Function which parses command options; returns true if it
+ ate an option */
+ /* entry is struct ipt_entry for example */
+ int (*parse)(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry,
+ struct xt_entry_match **match);
+
+ /* Final check; exit if not ok. */
+ void (*final_check)(unsigned int flags);
+
+ /* Prints out the match iff non-NULL: put space at end */
+ /* ip is struct ipt_ip * for example */
+ void (*print)(const void *ip,
+ const struct xt_entry_match *match, int numeric);
+
+ /* Saves the match info in parsable form to stdout. */
+ /* ip is struct ipt_ip * for example */
+ void (*save)(const void *ip, const struct xt_entry_match *match);
+
+ /* Pointer to list of extra command-line options */
+ const struct option *extra_opts;
+
+ /* Ignore these men behind the curtain: */
+ unsigned int option_offset;
+ struct xt_entry_match *m;
+ unsigned int mflags;
+#ifdef NO_SHARED_LIBS
+ unsigned int loaded; /* simulate loading so options are merged properly */
+#endif
+};
+
+struct xtables_target
+{
+ struct xtables_target *next;
+
+ xt_chainlabel name;
+
+ /* Revision of target (0 by default). */
+ u_int8_t revision;
+
+ u_int16_t family;
+
+ const char *version;
+
+ /* Size of target data. */
+ size_t size;
+
+ /* Size of target data relevent for userspace comparison purposes */
+ size_t userspacesize;
+
+ /* Function which prints out usage message. */
+ void (*help)(void);
+
+ /* Initialize the target. */
+ void (*init)(struct xt_entry_target *t);
+
+ /* Function which parses command options; returns true if it
+ ate an option */
+ /* entry is struct ipt_entry for example */
+ int (*parse)(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry,
+ struct xt_entry_target **targetinfo);
+
+ /* Final check; exit if not ok. */
+ void (*final_check)(unsigned int flags);
+
+ /* Prints out the target iff non-NULL: put space at end */
+ void (*print)(const void *ip,
+ const struct xt_entry_target *target, int numeric);
+
+ /* Saves the targinfo in parsable form to stdout. */
+ void (*save)(const void *ip,
+ const struct xt_entry_target *target);
+
+ /* Pointer to list of extra command-line options */
+ const struct option *extra_opts;
+
+ /* Ignore these men behind the curtain: */
+ unsigned int option_offset;
+ struct xt_entry_target *t;
+ unsigned int tflags;
+ unsigned int used;
+#ifdef NO_SHARED_LIBS
+ unsigned int loaded; /* simulate loading so options are merged properly */
+#endif
+};
+
+/* Your shared library should call one of these. */
+extern void xtables_register_match(struct xtables_match *me);
+extern void xtables_register_target(struct xtables_target *me);
+
+extern int string_to_number_ll(const char *s,
+ unsigned long long min,
+ unsigned long long max,
+ unsigned long long *ret);
+extern int string_to_number_l(const char *s,
+ unsigned long min,
+ unsigned long max,
+ unsigned long *ret);
+extern int string_to_number(const char *s,
+ unsigned int min,
+ unsigned int max,
+ unsigned int *ret);
+extern bool strtonuml(const char *, char **, unsigned long *,
+ unsigned long, unsigned long);
+extern bool strtonum(const char *, char **, unsigned int *,
+ unsigned int, unsigned int);
+extern int service_to_port(const char *name, const char *proto);
+extern u_int16_t parse_port(const char *port, const char *proto);
+extern void
+parse_interface(const char *arg, char *vianame, unsigned char *mask);
+
+enum exittype {
+ OTHER_PROBLEM = 1,
+ PARAMETER_PROBLEM,
+ VERSION_PROBLEM,
+ RESOURCE_PROBLEM,
+ P_ONLY_ONCE,
+ P_NO_INVERT,
+ P_BAD_VALUE,
+ P_ONE_ACTION,
+};
+
+/* this is a special 64bit data type that is 8-byte aligned */
+#define aligned_u64 u_int64_t __attribute__((aligned(8)))
+
+int check_inverse(const char option[], int *invert, int *my_optind, int argc);
+void exit_error(enum exittype, const char *, ...)__attribute__((noreturn,
+ format(printf,2,3)));
+extern void param_act(unsigned int, const char *, ...);
+extern const char *program_name, *program_version;
+
+extern const char *ipaddr_to_numeric(const struct in_addr *);
+extern const char *ipaddr_to_anyname(const struct in_addr *);
+extern const char *ipmask_to_numeric(const struct in_addr *);
+extern struct in_addr *numeric_to_ipaddr(const char *);
+extern struct in_addr *numeric_to_ipmask(const char *);
+extern void ipparse_hostnetworkmask(const char *, struct in_addr **,
+ struct in_addr *, unsigned int *);
+
+extern struct in6_addr *numeric_to_ip6addr(const char *);
+extern const char *ip6addr_to_numeric(const struct in6_addr *);
+extern const char *ip6addr_to_anyname(const struct in6_addr *);
+extern const char *ip6mask_to_numeric(const struct in6_addr *);
+extern void ip6parse_hostnetworkmask(const char *, struct in6_addr **,
+ struct in6_addr *, unsigned int *);
+
+/**
+ * Print the specified value to standard output, quoting dangerous
+ * characters if required.
+ */
+extern void save_string(const char *value);
+
+#ifdef NO_SHARED_LIBS
+# ifdef _INIT
+# undef _init
+# define _init _INIT
+# endif
+ extern void init_extensions(void);
+#else
+# define _init __attribute__((constructor)) _INIT
+#endif
+
+/* Present in both iptables.c and ip6tables.c */
+extern u_int16_t parse_protocol(const char *s);
+
+#ifdef XTABLES_INTERNAL
+# include <xtables/internal.h>
+#endif
+
+#endif /* _XTABLES_H */
int plugin_dispatch_values (value_list_t *vl)
{
- static c_complain_t no_write_complaint = C_COMPLAIN_INIT;
+ static c_complain_t no_write_complaint = C_COMPLAIN_INIT_STATIC;
int (*callback) (const data_set_t *, const value_list_t *);
data_set_t *ds;
db->conn = NULL;
- db->conn_complaint.last = 0;
- db->conn_complaint.interval = 0;
+ C_COMPLAIN_INIT (&db->conn_complaint);
db->proto_version = 0;
--- /dev/null
+/**
+ * collectd - src/rrdcached.c
+ * Copyright (C) 2008 Florian octo Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "common.h"
+#include "utils_rrdcreate.h"
+
+#include <rrd_client.h>
+
+/*
+ * Private variables
+ */
+static const char *config_keys[] =
+{
+ "DaemonAddress",
+ "DataDir",
+ "CreateFiles",
+ "CollectStatistics"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static char *datadir = NULL;
+static char *daemon_address = NULL;
+static int config_create_files = 1;
+static int config_collect_stats = 1;
+static rrdcreate_config_t rrdcreate_config =
+{
+ /* stepsize = */ 0,
+ /* heartbeat = */ 0,
+ /* rrarows = */ 1200,
+ /* xff = */ 0.1,
+
+ /* timespans = */ NULL,
+ /* timespans_num = */ 0,
+
+ /* consolidation_functions = */ NULL,
+ /* consolidation_functions_num = */ 0
+};
+
+static int value_list_to_string (char *buffer, int buffer_len,
+ const data_set_t *ds, const value_list_t *vl)
+{
+ int offset;
+ int status;
+ int i;
+
+ assert (0 == strcmp (ds->type, vl->type));
+
+ memset (buffer, '\0', buffer_len);
+
+ status = ssnprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
+ if ((status < 1) || (status >= buffer_len))
+ return (-1);
+ offset = status;
+
+ for (i = 0; i < ds->ds_num; i++)
+ {
+ if ((ds->ds[i].type != DS_TYPE_COUNTER)
+ && (ds->ds[i].type != DS_TYPE_GAUGE))
+ return (-1);
+
+ if (ds->ds[i].type == DS_TYPE_COUNTER)
+ {
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ ":%llu", vl->values[i].counter);
+ }
+ else /* if (ds->ds[i].type == DS_TYPE_GAUGE) */
+ {
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ ":%lf", vl->values[i].gauge);
+ }
+
+ if ((status < 1) || (status >= (buffer_len - offset)))
+ return (-1);
+
+ offset += status;
+ } /* for ds->ds_num */
+
+ return (0);
+} /* int value_list_to_string */
+
+static int value_list_to_filename (char *buffer, int buffer_len,
+ const data_set_t *ds, const value_list_t *vl)
+{
+ int offset = 0;
+ int status;
+
+ assert (0 == strcmp (ds->type, vl->type));
+
+ if (datadir != NULL)
+ {
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ "%s/", datadir);
+ if ((status < 1) || (status >= buffer_len - offset))
+ return (-1);
+ offset += status;
+ }
+
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ "%s/", vl->host);
+ if ((status < 1) || (status >= buffer_len - offset))
+ return (-1);
+ offset += status;
+
+ if (strlen (vl->plugin_instance) > 0)
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ "%s-%s/", vl->plugin, vl->plugin_instance);
+ else
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ "%s/", vl->plugin);
+ if ((status < 1) || (status >= buffer_len - offset))
+ return (-1);
+ offset += status;
+
+ if (strlen (vl->type_instance) > 0)
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ "%s-%s", vl->type, vl->type_instance);
+ else
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ "%s", vl->type);
+ if ((status < 1) || (status >= buffer_len - offset))
+ return (-1);
+ offset += status;
+
+ strncpy (buffer + offset, ".rrd", buffer_len - offset);
+ buffer[buffer_len - 1] = 0;
+
+ return (0);
+} /* int value_list_to_filename */
+
+static int rc_config (const char *key, const char *value)
+{
+ if (strcasecmp ("DataDir", key) == 0)
+ {
+ if (datadir != NULL)
+ free (datadir);
+ datadir = strdup (value);
+ if (datadir != NULL)
+ {
+ int len = strlen (datadir);
+ while ((len > 0) && (datadir[len - 1] == '/'))
+ {
+ len--;
+ datadir[len] = '\0';
+ }
+ if (len <= 0)
+ {
+ free (datadir);
+ datadir = NULL;
+ }
+ }
+ }
+ else if (strcasecmp ("DaemonAddress", key) == 0)
+ {
+ sfree (daemon_address);
+ daemon_address = strdup (value);
+ if (daemon_address == NULL)
+ {
+ ERROR ("rrdcached plugin: strdup failed.");
+ return (1);
+ }
+ }
+ else if (strcasecmp ("CreateFiles", key) == 0)
+ {
+ if ((strcasecmp ("false", value) == 0)
+ || (strcasecmp ("no", value) == 0)
+ || (strcasecmp ("off", value) == 0))
+ config_create_files = 0;
+ else
+ config_create_files = 1;
+ }
+ else if (strcasecmp ("CollectStatistics", key) == 0)
+ {
+ if ((strcasecmp ("false", value) == 0)
+ || (strcasecmp ("no", value) == 0)
+ || (strcasecmp ("off", value) == 0))
+ config_collect_stats = 0;
+ else
+ config_collect_stats = 1;
+ }
+ else
+ {
+ return (-1);
+ }
+ return (0);
+} /* int rc_config */
+
+static int rc_read (void)
+{
+ int status;
+ rrdc_stats_t *head;
+ rrdc_stats_t *ptr;
+
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ if (daemon_address == NULL)
+ return (-1);
+
+ if (config_collect_stats == 0)
+ return (-1);
+
+ vl.values = values;
+ vl.values_len = 1;
+ vl.time = time (NULL);
+
+ if ((strncmp ("unix:", daemon_address, strlen ("unix:")) == 0)
+ || (daemon_address[0] == '/'))
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ else
+ sstrncpy (vl.host, daemon_address, sizeof (vl.host));
+ sstrncpy (vl.plugin, "rrdcached", sizeof (vl.plugin));
+
+ head = NULL;
+ status = rrdc_stats_get (&head);
+ if (status != 0)
+ {
+ ERROR ("rrdcached plugin: rrdc_stats_get failed with status %i.", status);
+ return (-1);
+ }
+
+ for (ptr = head; ptr != NULL; ptr = ptr->next)
+ {
+ if (ptr->type == RRDC_STATS_TYPE_GAUGE)
+ values[0].gauge = (gauge_t) ptr->value.gauge;
+ else if (ptr->type == RRDC_STATS_TYPE_COUNTER)
+ values[0].counter = (counter_t) ptr->value.counter;
+ else
+ continue;
+
+ if (strcasecmp ("QueueLength", ptr->name) == 0)
+ {
+ sstrncpy (vl.type, "queue_length", sizeof (vl.type));
+ sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
+ }
+ else if (strcasecmp ("UpdatesWritten", ptr->name) == 0)
+ {
+ sstrncpy (vl.type, "operations", sizeof (vl.type));
+ sstrncpy (vl.type_instance, "write-updates", sizeof (vl.type_instance));
+ }
+ else if (strcasecmp ("DataSetsWritten", ptr->name) == 0)
+ {
+ sstrncpy (vl.type, "operations", sizeof (vl.type));
+ sstrncpy (vl.type_instance, "write-data_sets",
+ sizeof (vl.type_instance));
+ }
+ else if (strcasecmp ("TreeNodesNumber", ptr->name) == 0)
+ {
+ sstrncpy (vl.type, "gauge", sizeof (vl.type));
+ sstrncpy (vl.type_instance, "tree_nodes", sizeof (vl.type_instance));
+ }
+ else if (strcasecmp ("TreeDepth", ptr->name) == 0)
+ {
+ sstrncpy (vl.type, "gauge", sizeof (vl.type));
+ sstrncpy (vl.type_instance, "tree_depth", sizeof (vl.type_instance));
+ }
+ else if (strcasecmp ("FlushesReceived", ptr->name) == 0)
+ {
+ sstrncpy (vl.type, "operations", sizeof (vl.type));
+ sstrncpy (vl.type_instance, "receive-flush", sizeof (vl.type_instance));
+ }
+ else if (strcasecmp ("JournalBytes", ptr->name) == 0)
+ {
+ sstrncpy (vl.type, "counter", sizeof (vl.type));
+ sstrncpy (vl.type_instance, "journal-bytes", sizeof (vl.type_instance));
+ }
+ else if (strcasecmp ("JournalRotate", ptr->name) == 0)
+ {
+ sstrncpy (vl.type, "counter", sizeof (vl.type));
+ sstrncpy (vl.type_instance, "journal-rotates", sizeof (vl.type_instance));
+ }
+ else if (strcasecmp ("UpdatesReceived", ptr->name) == 0)
+ {
+ sstrncpy (vl.type, "operations", sizeof (vl.type));
+ sstrncpy (vl.type_instance, "receive-update", sizeof (vl.type_instance));
+ }
+ else
+ {
+ DEBUG ("rrdcached plugin: rc_read: Unknown statistic `%s'.", ptr->name);
+ continue;
+ }
+
+ plugin_dispatch_values (&vl);
+ } /* for (ptr = head; ptr != NULL; ptr = ptr->next) */
+
+ rrdc_stats_free (head);
+
+ return (0);
+} /* int rc_read */
+
+static int rc_init (void)
+{
+ if (config_collect_stats != 0)
+ plugin_register_read ("rrdcached", rc_read);
+
+ return (0);
+} /* int rc_init */
+
+static int rc_write (const data_set_t *ds, const value_list_t *vl)
+{
+ char filename[512];
+ char values[512];
+ char *values_array[2];
+ int status;
+
+ if (daemon_address == NULL)
+ {
+ ERROR ("rrdcached plugin: daemon_address == NULL.");
+ plugin_unregister_write ("rrdcached");
+ return (-1);
+ }
+
+ if (strcmp (ds->type, vl->type) != 0)
+ {
+ ERROR ("rrdcached plugin: DS type does not match value list type");
+ return (-1);
+ }
+
+ if (value_list_to_filename (filename, sizeof (filename), ds, vl) != 0)
+ {
+ ERROR ("rrdcached plugin: value_list_to_filename failed.");
+ return (-1);
+ }
+
+ if (value_list_to_string (values, sizeof (values), ds, vl) != 0)
+ {
+ ERROR ("rrdcached plugin: value_list_to_string failed.");
+ return (-1);
+ }
+
+ values_array[0] = values;
+ values_array[1] = NULL;
+
+ if (config_create_files != 0)
+ {
+ struct stat statbuf;
+
+ status = stat (filename, &statbuf);
+ if (status != 0)
+ {
+ if (errno != ENOENT)
+ {
+ char errbuf[1024];
+ ERROR ("rrdcached plugin: stat (%s) failed: %s",
+ filename, sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+
+ status = cu_rrd_create_file (filename, ds, vl, &rrdcreate_config);
+ if (status != 0)
+ {
+ ERROR ("rrdcached plugin: cu_rrd_create_file (%s) failed.",
+ filename);
+ return (-1);
+ }
+ }
+ }
+
+ status = rrdc_connect (daemon_address);
+ if (status != 0)
+ {
+ ERROR ("rrdcached plugin: rrdc_connect (%s) failed with status %i.",
+ daemon_address, status);
+ return (-1);
+ }
+
+ status = rrdc_update (filename, /* values_num = */ 1, (void *) values_array);
+ if (status != 0)
+ {
+ ERROR ("rrdcached plugin: rrdc_update (%s, [%s], 1) failed with "
+ "status %i.",
+ filename, values_array[0], status);
+ return (-1);
+ }
+
+ return (0);
+} /* int rc_write */
+
+static int rc_shutdown (void)
+{
+ rrdc_disconnect ();
+ return (0);
+} /* int rc_shutdown */
+
+void module_register (void)
+{
+ plugin_register_config ("rrdcached", rc_config,
+ config_keys, config_keys_num);
+ plugin_register_init ("rrdcached", rc_init);
+ plugin_register_write ("rrdcached", rc_write);
+ plugin_register_shutdown ("rrdcached", rc_shutdown);
+} /* void module_register */
+
+/*
+ * vim: set sw=2 sts=2 et :
+ */
#include "plugin.h"
#include "common.h"
#include "utils_avltree.h"
+#include "utils_rrdcreate.h"
#include <rrd.h>
/*
* Private variables
*/
-static int rra_timespans[] =
-{
- 3600,
- 86400,
- 604800,
- 2678400,
- 31622400
-};
-static int rra_timespans_num = STATIC_ARRAY_SIZE (rra_timespans);
-
-static int *rra_timespans_custom = NULL;
-static int rra_timespans_custom_num = 0;
-
-static char *rra_types[] =
-{
- "AVERAGE",
- "MIN",
- "MAX"
-};
-static int rra_types_num = STATIC_ARRAY_SIZE (rra_types);
-
static const char *config_keys[] =
{
"CacheTimeout",
/* If datadir is zero, the daemon's basedir is used. If stepsize or heartbeat
* is zero a default, depending on the `interval' member of the value list is
* being used. */
-static char *datadir = NULL;
-static int stepsize = 0;
-static int heartbeat = 0;
-static int rrarows = 1200;
-static double xff = 0.1;
-static double write_rate = 0.0;
+static char *datadir = NULL;
+static double write_rate = 0.0;
+static rrdcreate_config_t rrdcreate_config =
+{
+ /* stepsize = */ 0,
+ /* heartbeat = */ 0,
+ /* rrarows = */ 1200,
+ /* xff = */ 0.1,
+
+ /* timespans = */ NULL,
+ /* timespans_num = */ 0,
+
+ /* consolidation_functions = */ NULL,
+ /* consolidation_functions_num = */ 0
+};
/* XXX: If you need to lock both, cache_lock and queue_lock, at the same time,
* ALWAYS lock `cache_lock' first! */
static int do_shutdown = 0;
-/* * * * * * * * * *
- * WARNING: Magic *
- * * * * * * * * * */
-
-static void rra_free (int rra_num, char **rra_def)
-{
- int i;
-
- for (i = 0; i < rra_num; i++)
- {
- sfree (rra_def[i]);
- }
- sfree (rra_def);
-} /* void rra_free */
-
-static int rra_get (char ***ret, const value_list_t *vl)
-{
- char **rra_def;
- int rra_num;
-
- int *rts;
- int rts_num;
-
- int rra_max;
-
- int span;
-
- int cdp_num;
- int cdp_len;
- int i, j;
-
- char buffer[64];
-
- /* The stepsize we use here: If it is user-set, use it. If not, use the
- * interval of the value-list. */
- int ss;
-
- if (rrarows <= 0)
- {
- *ret = NULL;
- return (-1);
- }
-
- ss = (stepsize > 0) ? stepsize : vl->interval;
- if (ss <= 0)
- {
- *ret = NULL;
- return (-1);
- }
-
- /* Use the configured timespans or fall back to the built-in defaults */
- if (rra_timespans_custom_num != 0)
- {
- rts = rra_timespans_custom;
- rts_num = rra_timespans_custom_num;
- }
- else
- {
- rts = rra_timespans;
- rts_num = rra_timespans_num;
- }
-
- rra_max = rts_num * rra_types_num;
-
- if ((rra_def = (char **) malloc ((rra_max + 1) * sizeof (char *))) == NULL)
- return (-1);
- memset (rra_def, '\0', (rra_max + 1) * sizeof (char *));
- rra_num = 0;
-
- cdp_len = 0;
- for (i = 0; i < rts_num; i++)
- {
- span = rts[i];
-
- if ((span / ss) < rrarows)
- span = ss * rrarows;
-
- if (cdp_len == 0)
- cdp_len = 1;
- else
- cdp_len = (int) floor (((double) span)
- / ((double) (rrarows * ss)));
-
- cdp_num = (int) ceil (((double) span)
- / ((double) (cdp_len * ss)));
-
- for (j = 0; j < rra_types_num; j++)
- {
- if (rra_num >= rra_max)
- break;
-
- if (ssnprintf (buffer, sizeof (buffer), "RRA:%s:%3.1f:%u:%u",
- rra_types[j], xff,
- cdp_len, cdp_num) >= sizeof (buffer))
- {
- ERROR ("rra_get: Buffer would have been truncated.");
- continue;
- }
-
- rra_def[rra_num++] = sstrdup (buffer);
- }
- }
-
-#if COLLECT_DEBUG
- DEBUG ("rra_num = %i", rra_num);
- for (i = 0; i < rra_num; i++)
- DEBUG (" %s", rra_def[i]);
-#endif
-
- *ret = rra_def;
- return (rra_num);
-} /* int rra_get */
-
-static void ds_free (int ds_num, char **ds_def)
-{
- int i;
-
- for (i = 0; i < ds_num; i++)
- if (ds_def[i] != NULL)
- free (ds_def[i]);
- free (ds_def);
-}
-
-static int ds_get (char ***ret, const data_set_t *ds, const value_list_t *vl)
-{
- char **ds_def;
- int ds_num;
-
- char min[32];
- char max[32];
- char buffer[128];
-
- DEBUG ("ds->ds_num = %i", ds->ds_num);
-
- ds_def = (char **) malloc (ds->ds_num * sizeof (char *));
- if (ds_def == NULL)
- {
- char errbuf[1024];
- ERROR ("rrdtool plugin: malloc failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (-1);
- }
- memset (ds_def, '\0', ds->ds_num * sizeof (char *));
-
- for (ds_num = 0; ds_num < ds->ds_num; ds_num++)
- {
- data_source_t *d = ds->ds + ds_num;
- char *type;
- int status;
-
- ds_def[ds_num] = NULL;
-
- if (d->type == DS_TYPE_COUNTER)
- type = "COUNTER";
- else if (d->type == DS_TYPE_GAUGE)
- type = "GAUGE";
- else
- {
- ERROR ("rrdtool plugin: Unknown DS type: %i",
- d->type);
- break;
- }
-
- if (isnan (d->min))
- {
- sstrncpy (min, "U", sizeof (min));
- }
- else
- ssnprintf (min, sizeof (min), "%lf", d->min);
-
- if (isnan (d->max))
- {
- sstrncpy (max, "U", sizeof (max));
- }
- else
- ssnprintf (max, sizeof (max), "%lf", d->max);
-
- status = ssnprintf (buffer, sizeof (buffer),
- "DS:%s:%s:%i:%s:%s",
- d->name, type,
- (heartbeat > 0) ? heartbeat : (2 * vl->interval),
- min, max);
- if ((status < 1) || (status >= sizeof (buffer)))
- break;
-
- ds_def[ds_num] = sstrdup (buffer);
- } /* for ds_num = 0 .. ds->ds_num */
-
-#if COLLECT_DEBUG
-{
- int i;
- DEBUG ("ds_num = %i", ds_num);
- for (i = 0; i < ds_num; i++)
- DEBUG (" %s", ds_def[i]);
-}
-#endif
-
- if (ds_num != ds->ds_num)
- {
- ds_free (ds_num, ds_def);
- return (-1);
- }
-
- *ret = ds_def;
- return (ds_num);
-}
-
#if HAVE_THREADSAFE_LIBRRD
-static int srrd_create (char *filename, unsigned long pdp_step, time_t last_up,
- int argc, const char **argv)
-{
- int status;
-
- optind = 0; /* bug in librrd? */
- rrd_clear_error ();
-
- status = rrd_create_r (filename, pdp_step, last_up, argc, (void *) argv);
-
- if (status != 0)
- {
- WARNING ("rrdtool plugin: rrd_create_r (%s) failed: %s",
- filename, rrd_get_error ());
- }
-
- return (status);
-} /* int srrd_create */
-
static int srrd_update (char *filename, char *template,
int argc, const char **argv)
{
/* #endif HAVE_THREADSAFE_LIBRRD */
#else /* !HAVE_THREADSAFE_LIBRRD */
-static int srrd_create (char *filename, unsigned long pdp_step, time_t last_up,
- int argc, const char **argv)
-{
- int status;
-
- int new_argc;
- char **new_argv;
-
- char pdp_step_str[16];
- char last_up_str[16];
-
- new_argc = 6 + argc;
- new_argv = (char **) malloc ((new_argc + 1) * sizeof (char *));
- if (new_argv == NULL)
- {
- ERROR ("rrdtool plugin: malloc failed.");
- return (-1);
- }
-
- if (last_up == 0)
- last_up = time (NULL) - 10;
-
- ssnprintf (pdp_step_str, sizeof (pdp_step_str), "%lu", pdp_step);
- ssnprintf (last_up_str, sizeof (last_up_str), "%u", (unsigned int) last_up);
-
- new_argv[0] = "create";
- new_argv[1] = filename;
- new_argv[2] = "-s";
- new_argv[3] = pdp_step_str;
- new_argv[4] = "-b";
- new_argv[5] = last_up_str;
-
- memcpy (new_argv + 6, argv, argc * sizeof (char *));
- new_argv[new_argc] = NULL;
-
- pthread_mutex_lock (&librrd_lock);
- optind = 0; /* bug in librrd? */
- rrd_clear_error ();
-
- status = rrd_create (new_argc, new_argv);
- pthread_mutex_unlock (&librrd_lock);
-
- if (status != 0)
- {
- WARNING ("rrdtool plugin: rrd_create (%s) failed: %s",
- filename, rrd_get_error ());
- }
-
- sfree (new_argv);
-
- return (status);
-} /* int srrd_create */
-
static int srrd_update (char *filename, char *template,
int argc, const char **argv)
{
} /* int srrd_update */
#endif /* !HAVE_THREADSAFE_LIBRRD */
-static int rrd_create_file (char *filename, const data_set_t *ds, const value_list_t *vl)
-{
- char **argv;
- int argc;
- char **rra_def;
- int rra_num;
- char **ds_def;
- int ds_num;
- int status = 0;
-
- if (check_create_dir (filename))
- return (-1);
-
- if ((rra_num = rra_get (&rra_def, vl)) < 1)
- {
- ERROR ("rrd_create_file failed: Could not calculate RRAs");
- return (-1);
- }
-
- if ((ds_num = ds_get (&ds_def, ds, vl)) < 1)
- {
- ERROR ("rrd_create_file failed: Could not calculate DSes");
- return (-1);
- }
-
- argc = ds_num + rra_num;
-
- if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL)
- {
- char errbuf[1024];
- ERROR ("rrd_create failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (-1);
- }
-
- memcpy (argv, ds_def, ds_num * sizeof (char *));
- memcpy (argv + ds_num, rra_def, rra_num * sizeof (char *));
- argv[ds_num + rra_num] = NULL;
-
- assert (vl->time > 10);
- status = srrd_create (filename,
- (stepsize > 0) ? stepsize : vl->interval,
- vl->time - 10,
- argc, (const char **)argv);
-
- free (argv);
- ds_free (ds_num, ds_def);
- rra_free (rra_num, rra_def);
-
- return (status);
-}
-
static int value_list_to_string (char *buffer, int buffer_len,
const data_set_t *ds, const value_list_t *vl)
{
{
if (errno == ENOENT)
{
- if (rrd_create_file (filename, ds, vl))
+ status = cu_rrd_create_file (filename,
+ ds, vl, &rrdcreate_config);
+ if (status != 0)
return (-1);
}
else
}
else if (strcasecmp ("StepSize", key) == 0)
{
- stepsize = atoi (value);
- if (stepsize < 0)
- stepsize = 0;
+ int temp = atoi (value);
+ if (temp > 0)
+ rrdcreate_config.stepsize = temp;
}
else if (strcasecmp ("HeartBeat", key) == 0)
{
- heartbeat = atoi (value);
- if (heartbeat < 0)
- heartbeat = 0;
+ int temp = atoi (value);
+ if (temp > 0)
+ rrdcreate_config.heartbeat = temp;
}
else if (strcasecmp ("RRARows", key) == 0)
{
"be greater than 0.\n");
return (1);
}
- rrarows = tmp;
+ rrdcreate_config.rrarows = tmp;
}
else if (strcasecmp ("RRATimespan", key) == 0)
{
{
dummy = NULL;
- tmp_alloc = realloc (rra_timespans_custom,
- sizeof (int) * (rra_timespans_custom_num + 1));
+ tmp_alloc = realloc (rrdcreate_config.timespans,
+ sizeof (int) * (rrdcreate_config.timespans_num + 1));
if (tmp_alloc == NULL)
{
fprintf (stderr, "rrdtool: realloc failed.\n");
free (value_copy);
return (1);
}
- rra_timespans_custom = tmp_alloc;
- rra_timespans_custom[rra_timespans_custom_num] = atoi (ptr);
- if (rra_timespans_custom[rra_timespans_custom_num] != 0)
- rra_timespans_custom_num++;
+ rrdcreate_config.timespans = tmp_alloc;
+ rrdcreate_config.timespans[rrdcreate_config.timespans_num] = atoi (ptr);
+ if (rrdcreate_config.timespans[rrdcreate_config.timespans_num] != 0)
+ rrdcreate_config.timespans_num++;
} /* while (strtok_r) */
- qsort (/* base = */ rra_timespans_custom,
- /* nmemb = */ rra_timespans_custom_num,
- /* size = */ sizeof (rra_timespans_custom[0]),
+ qsort (/* base = */ rrdcreate_config.timespans,
+ /* nmemb = */ rrdcreate_config.timespans_num,
+ /* size = */ sizeof (rrdcreate_config.timespans[0]),
/* compar = */ rrd_compare_numeric);
free (value_copy);
"be in the range 0 to 1 (exclusive).");
return (1);
}
- xff = tmp;
+ rrdcreate_config.xff = tmp;
}
else if (strcasecmp ("WritesPerSecond", key) == 0)
{
{
int status;
- if (stepsize < 0)
- stepsize = 0;
- if (heartbeat <= 0)
- heartbeat = 2 * stepsize;
+ if (rrdcreate_config.stepsize < 0)
+ rrdcreate_config.stepsize = 0;
+ if (rrdcreate_config.heartbeat <= 0)
+ rrdcreate_config.heartbeat = 2 * rrdcreate_config.stepsize;
- if ((heartbeat > 0) && (heartbeat < interval_g))
+ if ((rrdcreate_config.heartbeat > 0)
+ && (rrdcreate_config.heartbeat < interval_g))
WARNING ("rrdtool plugin: Your `heartbeat' is "
"smaller than your `interval'. This will "
"likely cause problems.");
- else if ((stepsize > 0) && (stepsize < interval_g))
+ else if ((rrdcreate_config.stepsize > 0)
+ && (rrdcreate_config.stepsize < interval_g))
WARNING ("rrdtool plugin: Your `stepsize' is "
"smaller than your `interval'. This will "
"create needlessly big RRD-files.");
DEBUG ("rrdtool plugin: rrd_init: datadir = %s; stepsize = %i;"
" heartbeat = %i; rrarows = %i; xff = %lf;",
(datadir == NULL) ? "(null)" : datadir,
- stepsize, heartbeat, rrarows, xff);
+ rrdcreate_config.stepsize,
+ rrdcreate_config.heartbeat,
+ rrdcreate_config.rrarows,
+ rrdcreate_config.xff);
return (0);
} /* int rrd_init */
#include "collectd.h"
#include "common.h"
#include "plugin.h"
+#include "utils_complain.h"
#include <pthread.h>
char *community;
int version;
void *sess_handle;
+ c_complain_t complaint;
uint32_t interval;
time_t next_update;
data_definition_t **data_list;
return (-1);
memset (hd, '\0', sizeof (host_definition_t));
hd->version = 2;
+ C_COMPLAIN_INIT (&hd->complaint);
hd->name = strdup (ci->values[0].value.string);
if (hd->name == NULL)
char *errstr = NULL;
snmp_sess_error (host->sess_handle, NULL, NULL, &errstr);
- ERROR ("snmp plugin: host %s: snmp_sess_synch_response failed: %s",
+
+ c_complain (LOG_ERR, &host->complaint,
+ "snmp plugin: host %s: snmp_sess_synch_response failed: %s",
host->name, (errstr == NULL) ? "Unknown problem" : errstr);
if (res != NULL)
}
status = 0;
assert (res != NULL);
+ c_release (LOG_INFO, &host->complaint,
+ "snmp plugin: host %s: snmp_sess_synch_response successful.",
+ host->name);
vb = res->variables;
if (vb == NULL)
nfs_procedure value:COUNTER:0:4294967295
nginx_connections value:GAUGE:0:U
nginx_requests value:COUNTER:0:134217728
+operations value:COUNTER:0:4294967295
percent percent:GAUGE:0:100.1
pg_blks value:COUNTER:0:U
pg_db_size value:GAUGE:0:U
ps_pagefaults minflt:COUNTER:0:9223372036854775807, majflt:COUNTER:0:9223372036854775807
ps_rss value:GAUGE:0:9223372036854775807
ps_state value:GAUGE:0:65535
+queue_length value:GAUGE:0:U
serial_octets rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
signal_noise value:GAUGE:U:0
signal_power value:GAUGE:U:0
int interval;
} c_complain_t;
-#define C_COMPLAIN_INIT { 0, 0 }
+#define C_COMPLAIN_INIT_STATIC { 0, 0 }
+#define C_COMPLAIN_INIT(c) do { (c)->last = 0; (c)->interval = 0; } while (0)
/*
* NAME
--- /dev/null
+/**
+ * collectd - src/utils_rrdcreate.c
+ * Copyright (C) 2006-2008 Florian octo Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "utils_rrdcreate.h"
+
+#include <rrd.h>
+
+/*
+ * Private variables
+ */
+static int rra_timespans[] =
+{
+ 3600,
+ 86400,
+ 604800,
+ 2678400,
+ 31622400
+};
+static int rra_timespans_num = STATIC_ARRAY_SIZE (rra_timespans);
+
+static char *rra_types[] =
+{
+ "AVERAGE",
+ "MIN",
+ "MAX"
+};
+static int rra_types_num = STATIC_ARRAY_SIZE (rra_types);
+
+/*
+ * Private functions
+ */
+static void rra_free (int rra_num, char **rra_def) /* {{{ */
+{
+ int i;
+
+ for (i = 0; i < rra_num; i++)
+ {
+ sfree (rra_def[i]);
+ }
+ sfree (rra_def);
+} /* }}} void rra_free */
+
+/* * * * * * * * * *
+ * WARNING: Magic *
+ * * * * * * * * * */
+static int rra_get (char ***ret, const value_list_t *vl, /* {{{ */
+ const rrdcreate_config_t *cfg)
+{
+ char **rra_def;
+ int rra_num;
+
+ int *rts;
+ int rts_num;
+
+ int rra_max;
+
+ int span;
+
+ int cdp_num;
+ int cdp_len;
+ int i, j;
+
+ char buffer[128];
+
+ /* The stepsize we use here: If it is user-set, use it. If not, use the
+ * interval of the value-list. */
+ int ss;
+
+ if (cfg->rrarows <= 0)
+ {
+ *ret = NULL;
+ return (-1);
+ }
+
+ if ((cfg->xff < 0) || (cfg->xff >= 1.0))
+ {
+ *ret = NULL;
+ return (-1);
+ }
+
+ ss = (cfg->stepsize > 0) ? cfg->stepsize : vl->interval;
+ if (ss <= 0)
+ {
+ *ret = NULL;
+ return (-1);
+ }
+
+ /* Use the configured timespans or fall back to the built-in defaults */
+ if (cfg->timespans_num != 0)
+ {
+ rts = cfg->timespans;
+ rts_num = cfg->timespans_num;
+ }
+ else
+ {
+ rts = rra_timespans;
+ rts_num = rra_timespans_num;
+ }
+
+ rra_max = rts_num * rra_types_num;
+
+ if ((rra_def = (char **) malloc ((rra_max + 1) * sizeof (char *))) == NULL)
+ return (-1);
+ memset (rra_def, '\0', (rra_max + 1) * sizeof (char *));
+ rra_num = 0;
+
+ cdp_len = 0;
+ for (i = 0; i < rts_num; i++)
+ {
+ span = rts[i];
+
+ if ((span / ss) < cfg->rrarows)
+ span = ss * cfg->rrarows;
+
+ if (cdp_len == 0)
+ cdp_len = 1;
+ else
+ cdp_len = (int) floor (((double) span)
+ / ((double) (cfg->rrarows * ss)));
+
+ cdp_num = (int) ceil (((double) span)
+ / ((double) (cdp_len * ss)));
+
+ for (j = 0; j < rra_types_num; j++)
+ {
+ if (rra_num >= rra_max)
+ break;
+
+ if (ssnprintf (buffer, sizeof (buffer), "RRA:%s:%3.1f:%u:%u",
+ rra_types[j], cfg->xff,
+ cdp_len, cdp_num) >= sizeof (buffer))
+ {
+ ERROR ("rra_get: Buffer would have been truncated.");
+ continue;
+ }
+
+ rra_def[rra_num++] = sstrdup (buffer);
+ }
+ }
+
+ *ret = rra_def;
+ return (rra_num);
+} /* }}} int rra_get */
+
+static void ds_free (int ds_num, char **ds_def) /* {{{ */
+{
+ int i;
+
+ for (i = 0; i < ds_num; i++)
+ if (ds_def[i] != NULL)
+ free (ds_def[i]);
+ free (ds_def);
+} /* }}} void ds_free */
+
+static int ds_get (char ***ret, /* {{{ */
+ const data_set_t *ds, const value_list_t *vl,
+ const rrdcreate_config_t *cfg)
+{
+ char **ds_def;
+ int ds_num;
+
+ char min[32];
+ char max[32];
+ char buffer[128];
+
+ ds_def = (char **) malloc (ds->ds_num * sizeof (char *));
+ if (ds_def == NULL)
+ {
+ char errbuf[1024];
+ ERROR ("rrdtool plugin: malloc failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+ memset (ds_def, '\0', ds->ds_num * sizeof (char *));
+
+ for (ds_num = 0; ds_num < ds->ds_num; ds_num++)
+ {
+ data_source_t *d = ds->ds + ds_num;
+ char *type;
+ int status;
+
+ ds_def[ds_num] = NULL;
+
+ if (d->type == DS_TYPE_COUNTER)
+ type = "COUNTER";
+ else if (d->type == DS_TYPE_GAUGE)
+ type = "GAUGE";
+ else
+ {
+ ERROR ("rrdtool plugin: Unknown DS type: %i",
+ d->type);
+ break;
+ }
+
+ if (isnan (d->min))
+ {
+ sstrncpy (min, "U", sizeof (min));
+ }
+ else
+ ssnprintf (min, sizeof (min), "%lf", d->min);
+
+ if (isnan (d->max))
+ {
+ sstrncpy (max, "U", sizeof (max));
+ }
+ else
+ ssnprintf (max, sizeof (max), "%lf", d->max);
+
+ status = ssnprintf (buffer, sizeof (buffer),
+ "DS:%s:%s:%i:%s:%s",
+ d->name, type,
+ (cfg->heartbeat > 0) ? cfg->heartbeat : (2 * vl->interval),
+ min, max);
+ if ((status < 1) || (status >= sizeof (buffer)))
+ break;
+
+ ds_def[ds_num] = sstrdup (buffer);
+ } /* for ds_num = 0 .. ds->ds_num */
+
+ if (ds_num != ds->ds_num)
+ {
+ ds_free (ds_num, ds_def);
+ return (-1);
+ }
+
+ *ret = ds_def;
+ return (ds_num);
+} /* }}} int ds_get */
+
+#if HAVE_THREADSAFE_LIBRRD
+static int srrd_create (const char *filename, /* {{{ */
+ unsigned long pdp_step, time_t last_up,
+ int argc, const char **argv)
+{
+ int status;
+
+ optind = 0; /* bug in librrd? */
+ rrd_clear_error ();
+
+ status = rrd_create_r (filename, pdp_step, last_up, argc, (void *) argv);
+
+ if (status != 0)
+ {
+ WARNING ("rrdtool plugin: rrd_create_r (%s) failed: %s",
+ filename, rrd_get_error ());
+ }
+
+ return (status);
+} /* }}} int srrd_create */
+/* #endif HAVE_THREADSAFE_LIBRRD */
+
+#else /* !HAVE_THREADSAFE_LIBRRD */
+static int srrd_create (const char *filename, /* {{{ */
+ unsigned long pdp_step, time_t last_up,
+ int argc, const char **argv)
+{
+ int status;
+
+ int new_argc;
+ char **new_argv;
+
+ char pdp_step_str[16];
+ char last_up_str[16];
+
+ new_argc = 6 + argc;
+ new_argv = (char **) malloc ((new_argc + 1) * sizeof (char *));
+ if (new_argv == NULL)
+ {
+ ERROR ("rrdtool plugin: malloc failed.");
+ return (-1);
+ }
+
+ if (last_up == 0)
+ last_up = time (NULL) - 10;
+
+ ssnprintf (pdp_step_str, sizeof (pdp_step_str), "%lu", pdp_step);
+ ssnprintf (last_up_str, sizeof (last_up_str), "%u", (unsigned int) last_up);
+
+ new_argv[0] = "create";
+ new_argv[1] = filename;
+ new_argv[2] = "-s";
+ new_argv[3] = pdp_step_str;
+ new_argv[4] = "-b";
+ new_argv[5] = last_up_str;
+
+ memcpy (new_argv + 6, argv, argc * sizeof (char *));
+ new_argv[new_argc] = NULL;
+
+ pthread_mutex_lock (&librrd_lock);
+ optind = 0; /* bug in librrd? */
+ rrd_clear_error ();
+
+ status = rrd_create (new_argc, new_argv);
+ pthread_mutex_unlock (&librrd_lock);
+
+ if (status != 0)
+ {
+ WARNING ("rrdtool plugin: rrd_create (%s) failed: %s",
+ filename, rrd_get_error ());
+ }
+
+ sfree (new_argv);
+
+ return (status);
+} /* }}} int srrd_create */
+#endif /* !HAVE_THREADSAFE_LIBRRD */
+
+/*
+ * Public functions
+ */
+int cu_rrd_create_file (const char *filename, /* {{{ */
+ const data_set_t *ds, const value_list_t *vl,
+ const rrdcreate_config_t *cfg)
+{
+ char **argv;
+ int argc;
+ char **rra_def;
+ int rra_num;
+ char **ds_def;
+ int ds_num;
+ int status = 0;
+
+ if (check_create_dir (filename))
+ return (-1);
+
+ if ((rra_num = rra_get (&rra_def, vl, cfg)) < 1)
+ {
+ ERROR ("cu_rrd_create_file failed: Could not calculate RRAs");
+ return (-1);
+ }
+
+ if ((ds_num = ds_get (&ds_def, ds, vl, cfg)) < 1)
+ {
+ ERROR ("cu_rrd_create_file failed: Could not calculate DSes");
+ return (-1);
+ }
+
+ argc = ds_num + rra_num;
+
+ if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL)
+ {
+ char errbuf[1024];
+ ERROR ("cu_rrd_create_file failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+
+ memcpy (argv, ds_def, ds_num * sizeof (char *));
+ memcpy (argv + ds_num, rra_def, rra_num * sizeof (char *));
+ argv[ds_num + rra_num] = NULL;
+
+ assert (vl->time > 10);
+ status = srrd_create (filename,
+ (cfg->stepsize > 0) ? cfg->stepsize : vl->interval,
+ vl->time - 10,
+ argc, (const char **) argv);
+
+ free (argv);
+ ds_free (ds_num, ds_def);
+ rra_free (rra_num, rra_def);
+
+ if (status != 0)
+ {
+ WARNING ("cu_rrd_create_file: srrd_create (%s) returned status %i.",
+ filename, status);
+ }
+ else
+ {
+ DEBUG ("cu_rrd_create_file: Successfully created RRD file \"%s\".",
+ filename);
+ }
+
+ return (status);
+} /* }}} int cu_rrd_create_file */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
--- /dev/null
+/**
+ * collectd - src/utils_rrdcreate.h
+ * Copyright (C) 2008 Florian octo Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Florian octo Forster <octo at verplant.org>
+ **/
+
+#ifndef UTILS_RRDCREATE_H
+#define UTILS_RRDCREATE_H 1
+
+struct rrdcreate_config_s
+{
+ int stepsize;
+ int heartbeat;
+ int rrarows;
+ double xff;
+
+ int *timespans;
+ size_t timespans_num;
+
+ char **consolidation_functions;
+ size_t consolidation_functions_num;
+};
+typedef struct rrdcreate_config_s rrdcreate_config_t;
+
+int cu_rrd_create_file (const char *filename,
+ const data_set_t *ds, const value_list_t *vl,
+ const rrdcreate_config_t *cfg);
+
+#endif /* UTILS_RRDCREATE_H */
+
+/* vim: set sw=2 sts=2 et : */