'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',
'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',
$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
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
# 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
{
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;
};
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;
{
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 */
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;
{
/* 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;
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;
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 */