# Copyright (C) 2003 Shawn Ferry # # 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; either version 2 of the License, or # (at your option) any later version. # # 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. # $Id: F5BigIp.pm,v 1.2 2011-12-16 22:43:52 ivan Exp $ # Shawn Ferry # F5 BigIp Load Balancer package Torrus::DevDiscover::F5BigIp; use strict; use Torrus::Log; $Torrus::DevDiscover::registry{'F5BigIp'} = { 'sequence' => 500, 'checkdevtype' => \&checkdevtype, 'discover' => \&discover, 'buildConfig' => \&buildConfig }; our %oiddef = ( # F5 'f5' => '1.3.6.1.4.1.3375', '4.x_globalStatUptime' => '1.3.6.1.4.1.3375.1.1.1.2.1.0', '3.x_uptime' => '1.3.6.1.4.1.3375.1.1.50.0', '4.x_globalAttrProductCode' => '1.3.6.1.4.1.3375.1.1.1.1.5.0', '4.x_virtualServer' => '1.3.6.1.4.1.3375.1.1.3', '4.x_virtualServerNumber' => '1.3.6.1.4.1.3375.1.1.3.1.0', '4.x_virtualServerTable' => '1.3.6.1.4.1.3375.1.1.3.2', '4.x_virtualServerIp' => '1.3.6.1.4.1.3375.1.1.3.2.1.1', '4.x_virtualServerPort' => '1.3.6.1.4.1.3375.1.1.3.2.1.2', '4.x_virtualServerPool' => '1.3.6.1.4.1.3375.1.1.3.2.1.30', '4.x_poolTable' => '1.3.6.1.4.1.3375.1.1.7.2', '4.x_poolName' => '1.3.6.1.4.1.3375.1.1.7.2.1.1', '4.x_poolMemberTable' => '1.3.6.1.4.1.3375.1.1.8.2', '4.x_poolMemberPoolName' => '1.3.6.1.4.1.3375.1.1.8.2.1.1', '4.x_poolMemberIpAddress' => '1.3.6.1.4.1.3375.1.1.8.2.1.2', '4.x_poolMemberPort' => '1.3.6.1.4.1.3375.1.1.8.2.1.3', '4.x_sslProxyTable' => '1.3.6.1.4.1.3375.1.1.9.2.1', '4.x_sslProxyOrigIpAddress' => '1.3.6.1.4.1.3375.1.1.9.2.1.1', '4.x_sslProxyOrigPort' => '1.3.6.1.4.1.3375.1.1.9.2.1.2', '4.x_sslProxyDestIpAddress' => '1.3.6.1.4.1.3375.1.1.9.2.1.3', '4.x_sslProxyDestPort' => '1.3.6.1.4.1.3375.1.1.9.2.1.4', '4.x_sslProxyConnLimit' => '1.3.6.1.4.1.3375.1.1.9.2.1.23', ); # from https://secure.f5.com/validate/help.jsp #HA (BIG-IP high availability software) #3DNS (3-DNS software) #LC (BIG-IP Link Controller software) #LB (BIG-IP Load Balancer 520) #FLB (BIG-IP FireGuard 520) #CLB (BIG-IP Cache Load Balancer 520) #SSL (BIG-IP eCommerce Load Balancer 520) #XLB (BIG-IP user-defined special purpose product for 520 platforms) #ISMAN (iControl Services Manager) our %f5_product = ( '1' => { 'product' => 'indeterminate', 'supported' => 0, }, '2' => { 'product' => 'ha', 'supported' => 1, }, '3' => { 'product' => 'lb', 'supported' => 1, }, '4' => { 'product' => 'threedns', 'supported' => 0, }, '5' => { 'product' => 'flb', 'supported' => 0, }, '6' => { 'product' => 'clb', 'supported' => 0, }, '7' => { 'product' => 'xlb', 'supported' => 0, }, '8' => { 'product' => 'ssl', 'supported' => 1, }, '10' => { 'product' => 'test', 'supported' => 0, }, '99' => { 'product' => 'unsupported', 'supported' => 0, }, ); our %f5_sslGatewayLevel = ( '1' => 'none', '3' => 'tps200', '4' => 'tps400', '5' => 'tps600', '6' => 'tps800', '7' => 'tps1000', '9' => 'tps500', '10' => 'tps1500', '11' => 'tps2000', '99' => 'unsupported', ); sub checkdevtype { my $dd = shift; my $devdetails = shift; my $data = $devdetails->data(); # You would think globalAttrProductCode would work well # I need more examples to see if ha(2) is specific to # BipIP HA or any ha f5 product if( not $dd->checkSnmpTable( 'f5' ) ) { return 0; } return 1; } sub discover { my $dd = shift; my $devdetails = shift; my $session = $dd->session(); my $data = $devdetails->data(); # SNMP on F5 boxes will become unresponsive over time with large # enough oids-per-pdu values. 10 appears to work for everything however # no exhaustive testing has been done to determine if a higer number # could be used. if( not defined( $data->{'param'}{'snmp-oids-per-pdu'} ) ) { my $oidsPerPDU = $devdetails->param('F5BigIp::snmp-oids-per-pdu'); if( $oidsPerPDU == 0 ) { $oidsPerPDU = 10; } $data->{'param'}{'snmp-oids-per-pdu'} = $oidsPerPDU; } # this is rather basic, per-capability checking # may be required in the future if( $dd->checkSnmpOID('4.x_globalStatUptime') ) { $devdetails->setCap('BigIp_4.x'); } elsif( $dd->checkSnmpOID('3.x_uptime') ) { # for v3.x we are not supporting detailed stats, so don't check # anything else $devdetails->setCap('BigIp_3.x'); return 1; } my $product_name; my $product_name; my $result = $dd->retrieveSnmpOIDs( '4.x_globalAttrProductCode' ); my $product_code = $result->{'4.x_globalAttrProductCode'}; $product_name = $f5_product{$product_code}->{'product'}; if( $f5_product{$product_code}->{'supported'} ) { $devdetails->setCap( 'BigIp_' . $product_name ); } else { if( defined($product_name) ) { Debug("Found an unsupported F5 product '$product_name'"); } else { Debug("Found an unknown F5 product"); } return 0; } my $poolTable = $session->get_table( -baseoid => $dd->oiddef('4.x_poolTable') ); if( defined( $poolTable ) ) { $devdetails->storeSnmpVars( $poolTable ); $devdetails->setCap('BigIp_4.x_PoolTable'); my $ref = {}; $ref->{'indices'} = []; $data->{'poolTable'} = $ref; foreach my $INDEX ( $devdetails-> getSnmpIndices( $dd->oiddef('4.x_poolName') ) ) { push( @{$ref->{'indices'}}, $INDEX ); my $pool = $devdetails->snmpVar($dd->oiddef('4.x_poolName') . '.' . $INDEX ); my $nick = $pool; $nick =~ s/\W/_/g; $nick =~ s/_+/_/g; my $param = {}; $ref->{$INDEX}->{'param'} = $param; $param->{'nick'} = $nick; $param->{'pool'} = $pool; $param->{'descr'} = "Stats for Pool $pool"; $param->{'INDEX'} = $INDEX; } } my $poolMemberTable = $session->get_table( -baseoid => $dd->oiddef('4.x_poolMemberTable') ); if( defined( $poolMemberTable ) ) { $devdetails->storeSnmpVars( $poolMemberTable ); $devdetails->setCap('BigIp_4.x_PoolMemberTable'); my $ref = {}; $data->{'poolMemberTable'} = $ref; foreach my $INDEX ( $devdetails-> getSnmpIndices( $dd->oiddef('4.x_poolMemberPoolName') ) ) { push( @{ $ref->{'indices'} }, $INDEX ); my $pool = $devdetails->snmpVar($dd->oiddef('4.x_poolMemberPoolName') . '.' . $INDEX ); my $ip = $devdetails->snmpVar($dd->oiddef('4.x_poolMemberIpAddress') . '.' . $INDEX ); my $port = $devdetails->snmpVar($dd->oiddef('4.x_poolMemberPort') . '.' . $INDEX ); my $nick = "MEMBER_${pool}_${ip}_${port}"; $nick =~ s/\W/_/g; $nick =~ s/_+/_/g; my $param = {}; $ref->{$INDEX}->{'param'} = $param; $param->{'nick'} = $nick; $param->{'pool'} = $pool; $param->{'descr'} = "Member of Pool $pool IP: $ip Port: $port"; $param->{'INDEX'} = $INDEX; } } my $virtServerNumber = $dd->retrieveSnmpOIDs( '4.x_virtualServerNumber' ); if( $virtServerNumber->{'4.x_virtualServerNumber'} > 0 ) { my $virtServer = $session->get_table( -baseoid => $dd->oiddef('4.x_virtualServer') ); if( defined( $virtServer ) ) { $devdetails->storeSnmpVars( $virtServer ); $devdetails->setCap('BigIp_4.x_VirtualServer'); my $ref = {}; $data->{'virtualServer'} = $ref; foreach my $INDEX ( $devdetails-> getSnmpIndices( $dd->oiddef('4.x_virtualServerIp') ) ) { push( @{ $ref->{'indices'} }, $INDEX); my $pool = $devdetails->snmpVar( $dd->oiddef('4.x_virtualServerPool') . '.' . $INDEX ); my $ip = $devdetails->snmpVar( $dd->oiddef('4.x_virtualServerIp') . '.' . $INDEX ); my $port = $devdetails->snmpVar( $dd->oiddef('4.x_virtualServerPort') . '.' . $INDEX ); my $param = {}; $ref->{$INDEX}->{'param'} = $param; my $descr = "Virtual Server Pool: $pool IP: $ip Port: $port"; my $nick = "VIP_${pool}_${ip}_${port}"; $nick =~ s/\W/_/g; $nick =~ s/_+/_/g; $param->{'INDEX'} = $INDEX; $param->{'descr'} = $descr; $param->{'nick'} = $nick; $param->{'pool'} = $pool; } } else { Debug("Virtual Servers Defined but not able to be configured"); } } my $sslProxyTable = $session->get_table( -baseoid => $dd->oiddef('4.x_sslProxyTable') ); if( defined( $sslProxyTable ) ) { $devdetails->storeSnmpVars( $sslProxyTable ); $devdetails->setCap('BigIp_4.x_sslProxyTable'); my $ref = {}; $ref->{'indices'} = []; $data->{'sslProxyTable'} = $ref; foreach my $INDEX ( $devdetails-> getSnmpIndices( $dd->oiddef('4.x_sslProxyOrigIpAddress') ) ) { push( @{$ref->{'indices'}}, $INDEX ); my $origIp = $devdetails->snmpVar( $dd->oiddef('4.x_sslProxyOrigIpAddress') . '.' . $INDEX ); my $origPort = $devdetails->snmpVar( $dd->oiddef('4.x_sslProxyOrigPort') . '.' . $INDEX ); my $destIp = $devdetails->snmpVar( $dd->oiddef('4.x_sslProxyDestIpAddress') . '.' . $INDEX ); my $destPort = $devdetails->snmpVar( $dd->oiddef('4.x_sslProxyDestPort') . '.' . $INDEX ); my $connLimit = $devdetails->snmpVar( $dd->oiddef('4.x_sslProxyConnLimit') . '.' . $INDEX ); my $nick = $origIp . '_' . $origPort . '_' . $destIp . '_' . $destPort; my $param = {}; $ref->{$INDEX}->{'param'} = $param; $param->{'nick'} = $nick; $param->{'descr'} = "Stats for SSL Proxy Address: " . "${origIp}:${origPort} -> ${destIp}:${destPort}"; $param->{'INDEX'} = $INDEX; $param->{'connLimit'} = $connLimit; } } return 1; } sub buildConfig { my $devdetails = shift; my $cb = shift; my $devNode = shift; my $data = $devdetails->data(); my $bigIpName = 'BigIp_Global_Stats'; my $bigIpParam = { 'precedence' => '-100', 'comment' => 'BigIp Global Stats', 'rrd-create-dstype' => 'GAUGE', }; if( $devdetails->hasCap('BigIp_4.x') ) { my $bigIpStatsNode = $cb->addSubtree( $devNode, $bigIpName, $bigIpParam, [ 'F5BigIp::BigIp_4.x' ]); if( $devdetails->hasCap('BigIp_ssl') ) { $cb->addTemplateApplication ( $bigIpStatsNode , 'F5BigIp::BigIp_4.x_sslProxy_Global' ); } } elsif( $devdetails->hasCap('BigIp_3.x') ) { $cb->addSubtree( $devNode, $bigIpName, $bigIpParam, [ 'F5BigIp::BigIp_3.x' ]); } my $virtName = 'BigIp_VirtualServers'; my $virtParam = { 'precedence' => '-200', 'comment' => 'Virtual Server(VIP) Stats', }; my $virtTree; if( $devdetails->hasCap('BigIp_4.x_VirtualServer') ) { my @templates = ( 'F5BigIp::BigIp_4.x_virtualServer-actvconn-overview' ); # 'F5BigIp::BigIp_4.x_virtualServer-connrate-overview'); $virtTree = $cb->addSubtree( $devNode, $virtName, $virtParam, \@templates ); my $ref = $data->{'virtualServer'}; foreach my $INDEX ( @{ $ref->{'indices'} } ) { my $server = $ref->{$INDEX}->{'param'}; $server->{'precedence'} = '-100'; $cb->addSubtree( $virtTree, $server->{'nick'}, $server, [ 'F5BigIp::BigIp_4.x_virtualServer' ] ); } } my $poolName = 'BigIp_Pools'; my $poolParam = { 'precedence' => '-300', 'comment' => 'Pool Stats', }; my $poolTree; if( $devdetails->hasCap('BigIp_4.x_PoolTable') ) { $poolTree = $cb->addSubtree( $devNode, $poolName, $poolParam, ['F5BigIp::BigIp_4.x_pool-actvconn-overview']); my $ref = $data->{'poolTable'}; foreach my $INDEX ( @{ $ref->{'indices'} } ) { my $pool = $ref->{$INDEX}->{'param'}; $pool->{'precedence'} = '-100'; $cb->addSubtree( $poolTree, $pool->{'pool'}, $pool, [ 'F5BigIp::BigIp_4.x_pool' ] ); } } my $poolMemberName = 'BigIp_Pool_Members'; my $poolMemberParam = { 'precedence' => '-400', 'comment' => 'Pool Member Stats', }; my $poolMemberTree; if( $devdetails->hasCap('BigIp_4.x_PoolMemberTable') ) { $poolMemberTree = $cb->addSubtree( $devNode, $poolMemberName, $poolMemberParam ); my $ref = $data->{'poolMemberTable'}; foreach my $INDEX ( @{ $ref->{'indices'} } ) { my $poolMemberPoolTree; my $lastPoolTree; my $server = $ref->{$INDEX}->{'param'}; my $poolMemberPoolName = $server->{'pool'}; my $poolMemberPoolParam = { 'precidence' => '-100', 'comment' => "Members of the $server->{'pool'} Pool", }; if( not defined( $lastPoolTree ) or $poolMemberPoolName !~ /\b$lastPoolTree\b/ ) { my @templates = ( 'F5BigIp::BigIp_4.x_poolMember-actvconn-overview' ); $poolMemberPoolTree = $cb->addSubtree( $poolMemberTree, $poolMemberPoolName, $poolMemberPoolParam, \@templates ); $lastPoolTree = $poolMemberPoolName; $server->{'precedence'} = '-100'; $cb->addSubtree( $poolMemberPoolTree, $server->{'nick'}, $server, [ 'F5BigIp::BigIp_4.x_poolMember' ] ); } } } # BigIP SSL Product Support if( $devdetails->hasCap('BigIp_4.x_sslProxyTable') ) { my $bigIpSSLProxies = 'BigIp_SSL_Proxies'; my $bigIpSSLParam = { 'comment' => 'BigIp SSL Proxies', 'rrd-create-dstype' => 'COUNTER', }; my $sslProxyTree = $cb->addSubtree( $devNode, $bigIpSSLProxies, $bigIpSSLParam, [ 'F5BigIp::BigIp_4.x_sslProxy-currconn-overview' ]); my $ref = $data->{'sslProxyTable'}; foreach my $INDEX ( @{ $ref->{'indices'} } ) { my $proxy = $ref->{$INDEX}->{'param'}; $cb->addSubtree( $sslProxyTree, $proxy->{'nick'}, $proxy, [ 'F5BigIp::BigIp_4.x_sslProxy' ] ); } } } 1; # Local Variables: # mode: perl # indent-tabs-mode: nil # perl-indent-level: 4 # End: