=back
+=head2 Plugin C<protocols>
+
+Collects a lot of information about various network protocols, such as I<IP>,
+I<TCP>, I<UDP>, etc.
+
+Available configuration options:
+
+=over 4
+
+=item B<Value> I<Selector>
+
+Selects whether or not to select a specific value. The string being matched is
+of the form "I<Protocol>:I<ValueName>", where I<Protocol> will be used as the
+plugin instance and I<ValueName> will be used as type instance. An example of
+the string being used would be C<Tcp:RetransSegs>.
+
+You can use regular expressions to match a large number of values with just one
+configuration option. To select all "extended" I<TCP> values, you could use the
+following statement:
+
+ Value "/^TcpExt:/"
+
+Whether only matched values are selected or all matched values are ignored
+depends on the B<IgnoreSelected>. By default, only matched values are selected.
+If no value is configured at all, all values will be selected.
+
+=item B<IgnoreSelected> B<true>|B<false>
+
+If set to B<true>, inverts the selection made by B<Value>, i.E<nbsp>e. all
+matching values will be ignored.
+
+=back
+
=head2 Plugin C<rrdcached>
The C<rrdcached> plugin uses the RRDTool accelerator daemon, L<rrdcached(1)>,
--- /dev/null
+/**
+ * collectd - src/protocols.c
+ * Copyright (C) 2009 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 "plugin.h"
+#include "utils_ignorelist.h"
+
+#if !KERNEL_LINUX
+# error "No applicable input method."
+#endif
+
+#define SNMP_FILE "/proc/net/snmp"
+#define NETSTAT_FILE "/proc/net/netstat"
+
+/*
+ * Global variables
+ */
+static const char *config_keys[] =
+{
+ "Value",
+ "IgnoreSelected",
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static ignorelist_t *values_list = NULL;
+
+/*
+ * Functions
+ */
+static void submit (const char *protocol_name,
+ const char *str_key, const char *str_value)
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ char *tmp_ptr;
+
+ errno = 0;
+ tmp_ptr = NULL;
+ values[0].counter = (counter_t) strtoll (str_value, &tmp_ptr,
+ /* base = */ 0);
+ if ((errno != 0) || (tmp_ptr == str_value))
+ {
+ ERROR ("protocols plugin: Parsing string as integer failed: %s",
+ str_value);
+ return;
+ }
+
+ vl.values = values;
+ vl.values_len = 1;
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.plugin, "protocols", sizeof (vl.plugin));
+ sstrncpy (vl.plugin_instance, protocol_name, sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, "protocol_counter", sizeof (vl.type));
+ sstrncpy (vl.type_instance, str_key, sizeof (vl.type_instance));
+
+ plugin_dispatch_values (&vl);
+} /* void submit */
+
+static int read_file (const char *path)
+{
+ FILE *fh;
+ char key_buffer[4096];
+ char value_buffer[4096];
+ char *key_ptr;
+ char *value_ptr;
+ char *key_fields[256];
+ char *value_fields[256];
+ int key_fields_num;
+ int value_fields_num;
+ int status;
+ int i;
+
+ fh = fopen (path, "r");
+ if (fh == NULL)
+ {
+ ERROR ("protocols plugin: fopen (%s) failed: %s.",
+ path, sstrerror (errno, key_buffer, sizeof (key_buffer)));
+ return (-1);
+ }
+
+ status = -1;
+ while (42)
+ {
+ clearerr (fh);
+ key_ptr = fgets (key_buffer, sizeof (key_buffer), fh);
+ if (key_ptr == NULL)
+ {
+ if (feof (fh) != 0)
+ {
+ status = 0;
+ break;
+ }
+ else if (ferror (fh) != 0)
+ {
+ ERROR ("protocols plugin: Reading from %s failed.", path);
+ break;
+ }
+ else
+ {
+ ERROR ("protocols plugin: fgets failed for an unknown reason.");
+ break;
+ }
+ } /* if (key_ptr == NULL) */
+
+ value_ptr = fgets (value_buffer, sizeof (value_buffer), fh);
+ if (value_ptr == NULL)
+ {
+ ERROR ("protocols plugin: read_file (%s): Could not read values line.",
+ path);
+ break;
+ }
+
+ key_ptr = strchr (key_buffer, ':');
+ if (key_ptr == NULL)
+ {
+ ERROR ("protocols plugin: Could not find protocol name in keys line.");
+ break;
+ }
+ *key_ptr = 0;
+ key_ptr++;
+
+ value_ptr = strchr (value_buffer, ':');
+ if (value_ptr == NULL)
+ {
+ ERROR ("protocols plugin: Could not find protocol name "
+ "in values line.");
+ break;
+ }
+ *value_ptr = 0;
+ value_ptr++;
+
+ if (strcmp (key_buffer, value_buffer) != 0)
+ {
+ ERROR ("protocols plugin: Protocol names in keys and values lines "
+ "don't match: `%s' vs. `%s'.",
+ key_buffer, value_buffer);
+ break;
+ }
+
+
+ key_fields_num = strsplit (key_ptr,
+ key_fields, STATIC_ARRAY_SIZE (key_fields));
+ value_fields_num = strsplit (value_ptr,
+ value_fields, STATIC_ARRAY_SIZE (value_fields));
+
+ if (key_fields_num != value_fields_num)
+ {
+ ERROR ("protocols plugin: Number of fields in keys and values lines "
+ "dont match: %i vs %i.",
+ key_fields_num, value_fields_num);
+ break;
+ }
+
+ for (i = 0; i < key_fields_num; i++)
+ {
+ if (values_list != NULL)
+ {
+ char match_name[2 * DATA_MAX_NAME_LEN];
+
+ ssnprintf (match_name, sizeof (match_name), "%s:%s",
+ key_buffer, key_fields[i]);
+
+ if (ignorelist_match (values_list, match_name))
+ continue;
+ } /* if (values_list != NULL) */
+
+ submit (key_buffer, key_fields[i], value_fields[i]);
+ } /* for (i = 0; i < key_fields_num; i++) */
+ } /* while (42) */
+
+ fclose (fh);
+
+ return (status);
+} /* int read_file */
+
+static int protocols_read (void)
+{
+ int status;
+ int success = 0;
+
+ status = read_file (SNMP_FILE);
+ if (status == 0)
+ success++;
+
+ status = read_file (NETSTAT_FILE);
+ if (status == 0)
+ success++;
+
+ if (success == 0)
+ return (-1);
+
+ return (0);
+} /* int protocols_read */
+
+static int protocols_config (const char *key, const char *value)
+{
+ if (values_list == NULL)
+ values_list = ignorelist_create (/* invert = */ 1);
+
+ if (strcasecmp (key, "Value") == 0)
+ {
+ ignorelist_add (values_list, value);
+ }
+ else if (strcasecmp (key, "IgnoreSelected") == 0)
+ {
+ int invert = 1;
+ if ((strcasecmp (value, "True") == 0)
+ || (strcasecmp (value, "Yes") == 0)
+ || (strcasecmp (value, "On") == 0))
+ invert = 0;
+ ignorelist_set_invert (values_list, invert);
+ }
+ else
+ {
+ return (-1);
+ }
+
+ return (0);
+} /* int protocols_config */
+
+void module_register (void)
+{
+ plugin_register_config ("protocols", protocols_config,
+ config_keys, config_keys_num);
+ plugin_register_read ("protocols", protocols_read);
+} /* void module_register */
+
+/* vim: set sw=2 sts=2 et : */