#!/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) [tl_sg] 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' 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' ); #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"; print "p${port}.label Port $port Link speed\n"; print "p${port}.type GAUGE\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, 5 - 100Mbps full, 6 - 1Gbps # 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"; print "p${currentPort}.value $link\n"; } } # vim: ft=perl : ts=4 : expandtab