diff --git a/plugins/tplink/tl_sg b/plugins/tplink/tl_sg new file mode 100755 index 00000000..f164c517 --- /dev/null +++ b/plugins/tplink/tl_sg @@ -0,0 +1,239 @@ +#!/usr/bin/perl +# -*- perl -*- +# +# 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; version 2 dated June, +# 1991. +# +# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Magic markers (used by munin-node-configure and some installation scripts): +#%# family=auto +#%# capabilities=autoconf + +use strict; +use warnings; +use WWW::Mechanize; + +=pod + +=encoding UTF-8 + +=head1 NAME + +tl_sg - Plugin to monitor packets per second and link speed for TP-Link SG108E/SG1016E switches + +=head1 APPLICABLE SYSTEMS + +TP-Link SG108E/SG1016E switches with web management (http). Tested with software version 1.0.2 Build 20160526 Rel.34615 on TL SG108E + +=head1 CONFIGURATION + +Add this to the relevant munin-node config file. You can specify switch address, username, password and description for each port +(the switch management doesn't allow port descriptions). You should also create a fake host for the switch and attach the graphs to it. +Details here: https://cweiske.de/tagebuch/munin-multiple-hosts.htm + +In /etc/munin/munin.conf add a new host called tl-sg108e (or whatever you want): + [tl-sg108e] + address 127.0.0.1 + use_node_name no + +In /etc/munin/plugin-conf.d/munin-node add the following entry: + + [tl_sg] + host_name tl-sg108e + env.host 192.168.1.12 + env.port 80 + env.numberOfPorts 8 + env.username admin + env.password mySecretPassword + env.p1 'Link to PC1' + env.p2 'Link to server1' + env.p3 'Not used' + env.p4 'Link to AP' + env.p5 'Link to PC2' + env.p6 'Link to PC3' + env.p7 'Not used' + env.p8 'Uplink' + +The name in host_name must match the name defined in munin.conf, and the tl_sg name must match the plugin instance name (symlink). + +If you're monitoring multiple switches, create different symlinks in /etc/munin/plugins pointing to this plugin and use the symlink +name as a configuration section as described above. + +Requires WWW:Mechanize module: + sudo apt-get install libwww-mechanize-perl + +=head1 BUGS/GOTCHAS + +The link speed is represented as a number: + 0 - down + 5 - 100Mbps full + 6 - 1Gbps + +=head1 AUTHOR + +Adrian Popa (https://github.com/mad-ady) + +=head1 COPYRIGHT + +Copyright (c) 2018, Adrian Popa + +All rights reserved. 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; version 2 +dated June, 1991. + +=head1 VERSION + + 1.1 + +=cut + +# read parameters from munin +my $host = ( $ENV{host} || '192.168.1.1' ); +my $tcpport = ( $ENV{port} || '80' ); +my $username = ( $ENV{username} || 'admin' ); +my $password = ( $ENV{password} || 'admin' ); +my $numberOfPorts = ( $ENV{numberOfPorts} || '8' ); + +my %speedMapping = ( + 0 => "down", + 1 => "auto", + 2 => "10M half-duplex", + 3 => "10M full-duplex", + 4 => "100M half-duplex", + 5 => "100M full-duplex", + 6 => "1G full-duplex", +); + + +#populate the ports and descriptions based on ENV +my %ports = (); +for ( 1 .. $numberOfPorts ) { + my $i = $_; + if ( defined $ENV{"p$i"} ) { + $ports{$i} = $ENV{"p$i"}; + } + else { + #no description + $ports{$i} = "Port $i"; + } +} + +if ( $ARGV[0] and $ARGV[0] eq 'autoconf' ) { + print "no (manual configuration needed)\n"; + exit 0; +} + +if ( $ARGV[0] and $ARGV[0] eq "config" ) { + foreach my $graphType (qw/Packets Speed/) { + foreach my $port ( sort keys %ports ) { + print "multigraph ${graphType}_if_$port\n", + "graph_title $graphType for $host port $port $ports{$port}\n", + "graph_info $graphType graph for port $port $ports{$port}\n", + "graph_args --base 1000 -l 0\n", + "graph_scale yes\n", + "graph_category network\n"; + if ( $graphType eq 'Speed' ) { + print "graph_vlabel speed\n"; + foreach my $value (sort keys %speedMapping){ + print "p${port}_$value.label $speedMapping{$value}\n"; + print "p${port}_$value.type GAUGE\n"; + print "p${port}_$value.draw AREA\n"; + } + } + else { + print "graph_vlabel packets\n"; + foreach my $gb (qw/good bad/) { + foreach my $direction (qw/tx rx/) { + print "p${port}${direction}${gb}.label Port $port $direction ($gb)\n"; + print "p${port}${direction}${gb}.type COUNTER\n"; + } + } + } + } + } + exit 0; +} + +# extract data from the switch - uses web scraping (tested with 1.0.2 Build 20160526 Rel.34615) + +# print STDERR "Connecting to $host with user $username"; +my $mech = WWW::Mechanize->new( + autocheck => 0, + requests_redirectable => [ 'GET', 'HEAD', 'POST' ] +); +my $result = $mech->post( + "http://$host:$tcpport/logon.cgi", + [ username => $username, password => $password, logon => 'Login' ], + "Referer" => "http://$host:$tcpport/" +); +my $response = $mech->response(); + +# navigate to the page with the network stats +$result = $mech->get("http://$host:$tcpport/PortStatisticsRpm.htm"); +$response = $mech->response(); + +#print STDERR $response->code()."\n"; + +# get the data +my $data = $mech->content( raw => 1 ); + +#print STDERR "$data\n"; + +# The page stores the data in a table, but internally it is stored in 3 javascript arrays: +# state:[1,1,1,1,1,1,1,1,0,0], +# link_status:[0,5,0,0,5,5,5,6,0,0], +# pkts:[0,0,0,0,14141090,0,10461386,0,14226,0,12252,0,0,0,0,0,2872063,0,1402200,0,59764503,0,34619246,0,4913873,0,4393574,0,44170456,0,68499653,0,0,0] + +# state: 1 - Enabled, 0 - Disabled (administratively) +# link_status: 0 - down, 1 - auto, 2 - 10Mbps half, 3 - 10Mbps full, 4 - 100Mbps half, 5 - 100Mbps full, 6 - 1Gbps full +# pkts: every group of 4 values represent txGoodPkt, txBadPkt, rxGoodPkt, rxBadPkt + +# parse good/bad packets +if ( $data =~ /pkts:\[([0-9,]+)\]/ ) { + + my $packetString = $1; + my @packets = split( /,/, $packetString ); + + for ( 1 .. $numberOfPorts ) { + my $currentPort = $_; + my $txGoodPkt = $packets[ ( $currentPort - 1 ) * 4 ]; + my $txBadPkt = $packets[ ( $currentPort - 1 ) * 4 + 1 ]; + my $rxGoodPkt = $packets[ ( $currentPort - 1 ) * 4 + 2 ]; + my $rxBadPkt = $packets[ ( $currentPort - 1 ) * 4 + 3 ]; + print "multigraph Packets_if_$currentPort\n"; + + print "p${currentPort}txgood.value $txGoodPkt\n"; + print "p${currentPort}rxgood.value $rxGoodPkt\n"; + print "p${currentPort}txbad.value $txBadPkt\n"; + print "p${currentPort}rxbad.value $rxBadPkt\n"; + } +} + +# parse link speed +if ( $data =~ /link_status:\[([0-9,]+)\]/ ) { + + my $linkString = $1; + my @links = split( /,/, $linkString ); + for ( 1 .. $numberOfPorts ) { + my $currentPort = $_; + my $link = $links[ $currentPort - 1 ]; + print "multigraph Speed_if_$currentPort\n"; + foreach my $value (sort keys %speedMapping){ + print "p${currentPort}_$value.value ".(($value eq $link)?1:0)."\n"; + } + } + +} + +# vim: ft=perl : ts=4 : expandtab diff --git a/plugins/tplink/tl_sg-day.png b/plugins/tplink/tl_sg-day.png new file mode 100644 index 00000000..5567089c Binary files /dev/null and b/plugins/tplink/tl_sg-day.png differ