tcpconns plugin: Changed the plugin to collect all TCP states, nut just `established'.
authorFlorian Forster <octo@huhu.verplant.org>
Wed, 10 Oct 2007 14:13:28 +0000 (16:13 +0200)
committerFlorian Forster <octo@huhu.verplant.org>
Wed, 10 Oct 2007 14:13:28 +0000 (16:13 +0200)
Also the contrib/collection.cgi script has been updated.

contrib/collection.cgi
src/tcpconns.c

index 7919760..045b77b 100755 (executable)
@@ -2070,7 +2070,7 @@ sub load_graph_definitions
     'GPRINT:max:MAX:%6.2lf%sByte Max,',
     'GPRINT:avg:LAST:%6.2lf%sByte Last\l'
     ],
-    ols_swap => [
+    old_swap => [
     'DEF:used_avg={file}:used:AVERAGE',
     'DEF:used_min={file}:used:MIN',
     'DEF:used_max={file}:used:MAX',
@@ -2114,6 +2114,18 @@ sub load_graph_definitions
     'GPRINT:used_max:MAX:%5.1lf%s Max,',
     'GPRINT:used_avg:LAST:%5.1lf%s Last\l'
     ],
+    tcp_connections => ['-v', 'Connections',
+    'DEF:avg={file}:value:AVERAGE',
+    'DEF:min={file}:value:MIN',
+    'DEF:max={file}:value:MAX',
+    "AREA:max#$HalfBlue",
+    "AREA:min#$Canvas",
+    "LINE1:avg#$FullBlue:Connections",
+    'GPRINT:min:MIN:%4.1lf Min,',
+    'GPRINT:avg:AVERAGE:%4.1lf Avg,',
+    'GPRINT:max:MAX:%4.1lf Max,',
+    'GPRINT:avg:LAST:%4.1lf Last\l'
+    ],
     temperature => ['-v', 'Celsius',
     'DEF:temp_avg={file}:value:AVERAGE',
     'DEF:temp_min={file}:value:MIN',
@@ -2328,6 +2340,7 @@ sub load_graph_definitions
   $MetaGraphDefs->{'swap'} = \&meta_graph_swap;
   $MetaGraphDefs->{'mysql_commands'} = \&meta_graph_mysql_commands;
   $MetaGraphDefs->{'mysql_handler'} = \&meta_graph_mysql_commands;
+  $MetaGraphDefs->{'tcp_connections'} = \&meta_graph_tcp_connections;
 } # load_graph_definitions
 
 sub meta_graph_generic_stack
@@ -2801,4 +2814,70 @@ sub meta_graph_swap
   return (meta_graph_generic_stack ($opts, $sources));
 } # meta_graph_swap
 
+sub meta_graph_tcp_connections
+{
+  confess ("Wrong number of arguments") if (@_ != 5);
+
+  my $host = shift;
+  my $plugin = shift;
+  my $plugin_instance = shift;
+  my $type = shift;
+  my $type_instances = shift;
+
+  my $opts = {};
+  my $sources = [];
+
+  $opts->{'title'} = "$host/$plugin"
+  . (defined ($plugin_instance) ? "-$plugin_instance" : '') . "/$type";
+  $opts->{'number_format'} = '%6.2lf';
+
+  $opts->{'rrd_opts'} = ['-v', 'Connections'];
+
+  my @files = ();
+
+  $opts->{'colors'} =
+  {
+    ESTABLISHED          => '00e000',
+    SYN_SENT     => '00e0ff',
+    SYN_RECV     => '00e0a0',
+    FIN_WAIT1    => 'f000f0',
+    FIN_WAIT2    => 'f000a0',
+    TIME_WAIT    => 'ffb000',
+    CLOSE        => '0000f0',
+    CLOSE_WAIT   => '0000a0',
+    LAST_ACK     => '000080',
+    LISTEN       => 'ff0000',
+    CLOSING      => '000000'
+  };
+
+  _custom_sort_arrayref ($type_instances,
+    [qw(ESTABLISHED SYN_SENT SYN_RECV FIN_WAIT1 FIN_WAIT2 TIME_WAIT CLOSE
+    CLOSE_WAIT LAST_ACK CLOSING LISTEN)]);
+
+  for (@$type_instances)
+  {
+    my $inst = $_;
+    my $file = '';
+    my $title = $opts->{'title'};
+
+    for (@DataDirs)
+    {
+      if (-e "$_/$title-$inst.rrd")
+      {
+       $file = "$_/$title-$inst.rrd";
+       last;
+      }
+    }
+    confess ("No file found for $title") if ($file eq '');
+
+    push (@$sources,
+      {
+       name => $inst,
+       file => $file
+      }
+    );
+  } # for (@$type_instances)
+
+  return (meta_graph_generic_stack ($opts, $sources));
+} # meta_graph_tcp_connections
 # vim: shiftwidth=2:softtabstop=2:tabstop=8
index 7d6e799..108a4e8 100644 (file)
@@ -27,6 +27,9 @@
 # error "No applicable input method."
 #endif
 
+#define TCP_STATE_LISTEN 10
+#define TCP_STATE_MAX 11
+
 #define PORT_COLLECT_LOCAL  0x01
 #define PORT_COLLECT_REMOTE 0x02
 #define PORT_IS_LISTENING   0x04
@@ -35,8 +38,8 @@ typedef struct port_entry_s
 {
   uint16_t port;
   uint16_t flags;
-  uint32_t count_local;
-  uint32_t count_remote;
+  uint32_t count_local[TCP_STATE_MAX + 1];
+  uint32_t count_remote[TCP_STATE_MAX + 1];
   struct port_entry_s *next;
 } port_entry_t;
 
@@ -48,6 +51,22 @@ static const char *config_keys[] =
 };
 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 
+static const char *tcp_state[] =
+{
+  "", /* 0 */
+  "ESTABLISHED",
+  "SYN_SENT",
+  "SYN_RECV",
+  "FIN_WAIT1",
+  "FIN_WAIT2",
+  "TIME_WAIT",
+  "CLOSE",
+  "CLOSE_WAIT",
+  "LAST_ACK",
+  "LISTEN", /* 10 */
+  "CLOSING"
+};
+
 static int port_collect_listening = 0;
 static port_entry_t *port_list_head = NULL;
 
@@ -55,27 +74,47 @@ static void conn_submit_port_entry (port_entry_t *pe)
 {
   value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
+  int i;
 
   vl.values = values;
   vl.values_len = 1;
   vl.time = time (NULL);
   strcpy (vl.host, hostname_g);
   strcpy (vl.plugin, "tcpconns");
-  snprintf (vl.type_instance, sizeof (vl.type_instance), "%hu", pe->port);
-  vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
 
   if (((port_collect_listening != 0) && (pe->flags & PORT_IS_LISTENING))
       || (pe->flags & PORT_COLLECT_LOCAL))
   {
-    values[0].gauge = pe->count_local;
-    strcpy (vl.plugin_instance, "local");
-    plugin_dispatch_values ("tcp_connections", &vl);
+    snprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
+       "%hu-local", pe->port);
+    vl.plugin_instance[sizeof (vl.plugin_instance) - 1] = '\0';
+
+    for (i = 1; i <= TCP_STATE_MAX; i++)
+    {
+      vl.values[0].gauge = pe->count_local[i];
+
+      strncpy (vl.type_instance, tcp_state[i], sizeof (vl.type_instance));
+      vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+
+      plugin_dispatch_values ("tcp_connections", &vl);
+    }
   }
+
   if (pe->flags & PORT_COLLECT_REMOTE)
   {
-    values[0].gauge = pe->count_remote;
-    strcpy (vl.plugin_instance, "remote");
-    plugin_dispatch_values ("tcp_connections", &vl);
+    snprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
+       "%hu-remote", pe->port);
+    vl.plugin_instance[sizeof (vl.plugin_instance) - 1] = '\0';
+
+    for (i = 1; i <= TCP_STATE_MAX; i++)
+    {
+      vl.values[0].gauge = pe->count_remote[i];
+
+      strncpy (vl.type_instance, tcp_state[i], sizeof (vl.type_instance));
+      vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+
+      plugin_dispatch_values ("tcp_connections", &vl);
+    }
   }
 } /* void conn_submit */
 
@@ -114,6 +153,8 @@ static port_entry_t *conn_get_port_entry (uint16_t port, int create)
   return (ret);
 } /* port_entry_t *conn_get_port_entry */
 
+/* Removes ports that were added automatically due to the `ListeningPorts'
+ * setting but which are no longer listening. */
 static void conn_reset_port_entry (void)
 {
   port_entry_t *prev = NULL;
@@ -123,7 +164,9 @@ static void conn_reset_port_entry (void)
   {
     /* If this entry was created while reading the files (ant not when handling
      * the configuration) remove it now. */
-    if ((pe->flags & (PORT_COLLECT_LOCAL | PORT_COLLECT_REMOTE)) == 0)
+    if ((pe->flags & (PORT_COLLECT_LOCAL
+           | PORT_COLLECT_REMOTE
+           | PORT_IS_LISTENING)) == 0)
     {
       port_entry_t *next = pe->next;
 
@@ -141,9 +184,8 @@ static void conn_reset_port_entry (void)
       continue;
     }
 
-    pe->count_local = 0;
-    pe->count_remote = 0;
-
+    memset (pe->count_local, '\0', sizeof (pe->count_local));
+    memset (pe->count_remote, '\0', sizeof (pe->count_remote));
     pe->flags &= ~PORT_IS_LISTENING;
 
     pe = pe->next;
@@ -152,41 +194,34 @@ static void conn_reset_port_entry (void)
 
 static int conn_handle_ports (uint16_t port_local, uint16_t port_remote, uint8_t state)
 {
-  /* Listening sockets */
-  if ((state == 0x0a) && (port_collect_listening != 0))
-  {
-    port_entry_t *pe;
+  port_entry_t *pe = NULL;
 
-    DEBUG ("tcpconns plugin: Adding listening port %hu", port_local);
+  if ((state == 0) || (state > TCP_STATE_MAX))
+  {
+    NOTICE ("tcpconns plugin: Ignoring connection with unknown state 0x%02x.",
+       state);
+    return (-1);
+  }
 
+  /* Listening sockets */
+  if ((state == TCP_STATE_LISTEN) && (port_collect_listening != 0))
+  {
     pe = conn_get_port_entry (port_local, 1 /* create */);
     if (pe != NULL)
-    {
-      pe->count_local++;
       pe->flags |= PORT_IS_LISTENING;
-    }
-  }
-  /* Established connections */
-  else if (state == 0x01)
-  {
-    port_entry_t *pe;
-
-    DEBUG ("tcpconns plugin: Established connection %hu <-> %hu",
-       port_local, port_remote);
-    
-    pe = conn_get_port_entry (port_local, 0 /* no create */);
-    if ((pe != NULL) && (pe->flags & PORT_COLLECT_LOCAL))
-      pe->count_local++;
-
-    pe = conn_get_port_entry (port_remote, 0 /* no create */);
-    if ((pe != NULL) && (pe->flags & PORT_COLLECT_REMOTE))
-      pe->count_remote++;
-  }
-  else
-  {
-    DEBUG ("tcpconns plugin: Ignoring unknown state 0x%x", state);
   }
 
+  DEBUG ("tcpconns plugin: Connection %hu <-> %hu (%s)",
+      port_local, port_remote, tcp_state[state]);
+
+  pe = conn_get_port_entry (port_local, 0 /* no create */);
+  if (pe != NULL)
+    pe->count_local[state]++;
+
+  pe = conn_get_port_entry (port_remote, 0 /* no create */);
+  if (pe != NULL)
+    pe->count_remote[state]++;
+
   return (0);
 } /* int conn_handle_ports */