1 # Copyright (C) 2002 Stanislav Sinyagin
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
17 # $Id: CiscoIOS_MacAccounting.pm,v 1.1 2010-12-27 00:03:46 ivan Exp $
18 # Stanislav Sinyagin <ssinyagin@yahoo.com>
20 # Cisco IOS MAC accounting
22 package Torrus::DevDiscover::CiscoIOS_MacAccounting;
28 $Torrus::DevDiscover::registry{'CiscoIOS_MacAccounting'} = {
30 'checkdevtype' => \&checkdevtype,
31 'discover' => \&discover,
32 'buildConfig' => \&buildConfig
39 'cipMacHCSwitchedBytes' => '1.3.6.1.4.1.9.9.84.1.2.3.1.2',
46 my $devdetails = shift;
48 my $session = $dd->session();
50 if( $devdetails->isDevType('CiscoIOS') and
51 $dd->checkSnmpTable('cipMacHCSwitchedBytes') )
63 my $devdetails = shift;
65 my $session = $dd->session();
66 my $data = $devdetails->data();
68 my $table = $session->get_table( -baseoid =>
69 $dd->oiddef('cipMacHCSwitchedBytes'));
71 if( not defined( $table ) or scalar( %{$table} ) == 0 )
75 $devdetails->storeSnmpVars( $table );
77 # External storage serviceid assignment
79 $devdetails->param('CiscoIOS_MacAccounting::external-serviceid');
80 if( defined( $extSrv ) and length( $extSrv ) > 0 )
83 my $extStorageTrees = {};
85 foreach my $srvDef ( split( /\s*,\s*/, $extSrv ) )
87 my ( $serviceid, $peerName, $direction, $trees ) =
88 split( /\s*:\s*/, $srvDef );
90 if( defined( $trees ) )
92 # Trees are listed with '|' as separator,
93 # whereas compiler expects commas
95 $trees =~ s/\s*\|\s*/,/g;
98 if( $direction eq 'Both' )
100 $extStorage->{$peerName}{'In'} = $serviceid . '_IN';
101 $extStorageTrees->{$serviceid . '_IN'} = $trees;
103 $extStorage->{$peerName}{'Out'} = $serviceid . '_OUT';
104 $extStorageTrees->{$serviceid . '_OUT'} = $trees;
108 $extStorage->{$peerName}{$direction} = $serviceid;
109 $extStorageTrees->{$serviceid} = $trees;
112 $data->{'cipMacExtStorage'} = $extStorage;
113 $data->{'cipMacExtStoragetrees'} = $extStorageTrees;
118 # Format: tokenset:ASXXXX,ASXXXX; tokenset:ASXXXX,ASXXXX;
119 # Peer MAC or IP addresses could be used too
121 $devdetails->param('CiscoIOS_MacAccounting::tokenset-members');
122 if( defined( $tsetMembership ) and length( $tsetMembership ) > 0 )
125 foreach my $memList ( split( /\s*;\s*/, $tsetMembership ) )
127 my ($tset, $list) = split( /\s*:\s*/, $memList );
128 foreach my $peerName ( split( /\s*,\s*/, $list ) )
130 $tsetMember->{$peerName}{$tset} = 1;
133 $data->{'cipTokensetMember'} = $tsetMember;
136 Torrus::DevDiscover::RFC2011_IP_MIB::discover($dd, $devdetails);
137 Torrus::DevDiscover::RFC1657_BGP4_MIB::discover($dd, $devdetails);
141 getSnmpIndices( $dd->oiddef('cipMacHCSwitchedBytes') ) )
143 my( $ifIndex, $direction, @phyAddrOctets ) = split( '\.', $INDEX );
145 my $interface = $data->{'interfaces'}{$ifIndex};
146 next if not defined( $interface );
149 my $macAddrString = '';
150 foreach my $byte ( @phyAddrOctets )
152 $phyAddr .= sprintf('%.2x', $byte);
153 if( length( $macAddrString ) > 0 )
155 $macAddrString .= ':';
157 $macAddrString .= sprintf('%.2x', $byte);
160 next if ( $phyAddr eq '0xffffffffffff' );
162 my $peerIP = $interface->{'mediaToIpNet'}{$phyAddr};
163 if( not defined( $peerIP ) )
165 # Try in the global table, as the ARP is stored per subinterface,
166 # and MAC accounting is on main interface
167 $peerIP = $data->{'mediaToIpNet'}{$phyAddr};
170 if( not defined( $peerIP ) )
172 # high logging level, because who cares about staled entries?
173 Debug('Cannot determine IP address for MAC accounting ' .
174 'entry: ' . $macAddrString);
178 # There should be two entries per IP: in and out.
179 if( defined( $data->{'cipMac'}{$ifIndex . ':' . $phyAddr} ) )
181 $data->{'cipMac'}{$ifIndex . ':' . $phyAddr}{'nEntries'}++;
187 'phyAddr' => $phyAddr,
188 'macAddrString' => $macAddrString,
189 'ifIndex' => $ifIndex,
193 $peer->{'macAddrOID'} = join('.', @phyAddrOctets);
195 $peer->{'ifReferenceName'} =
196 $interface->{$data->{'nameref'}{'ifReferenceName'}};
198 $interface->{$data->{'nameref'}{'ifNick'}};
201 $devdetails->param('peer-ipaddr-description-' .
202 join('_', split('\.', $peerIP)));
203 if( length( $desc ) > 0 )
205 $peer->{'description'} = $desc;
208 if( $devdetails->hasCap('bgpPeerTable') )
210 my $peerAS = $data->{'bgpPeerAS'}{$peerIP};
211 if( defined( $peerAS ) )
213 $peer->{'peerAS'} = $data->{'bgpPeerAS'}{$peerIP};
216 $devdetails->param('bgp-as-description-' . $peerAS);
217 if( length( $desc ) > 0 )
219 if( defined( $peer->{'description'} ) )
221 Warn('Conflicting descriptions for peer ' .
224 $peer->{'description'} = $desc;
228 param('CiscoIOS_MacAccounting::bgponly') eq 'yes' )
234 if( defined( $peer->{'description'} ) )
236 $peer->{'description'} .= ' ';
238 $peer->{'description'} .= '[' . $peerIP . ']';
240 $data->{'cipMac'}{$ifIndex . ':' . $phyAddr} = $peer;
244 foreach my $INDEX ( keys %{$data->{'cipMac'}} )
246 my $peer = $data->{'cipMac'}{$INDEX};
248 if( $peer->{'nEntries'} != 2 )
250 delete $data->{'cipMac'}{$INDEX};
254 if( defined( $peer->{'peerAS'} ) )
256 $asNumbers{$peer->{'peerAS'}}++;
261 foreach my $INDEX ( keys %{$data->{'cipMac'}} )
263 my $peer = $data->{'cipMac'}{$INDEX};
265 my $subtreeName = $peer->{'peerIP'};
266 my $asNum = $peer->{'peerAS'};
267 if( defined( $asNum ) )
269 $subtreeName = 'AS' . $asNum;
270 if( $asNumbers{$asNum} > 1 )
272 $subtreeName .= '_' . $peer->{'peerIP'};
275 $peer->{'subtreeName'} = $subtreeName;
284 my $devdetails = shift;
288 my $data = $devdetails->data();
291 $cb->addSubtree( $devNode, 'MAC_Accounting',
292 {'node-display-name' => 'MAC Accounting'},
293 ['CiscoIOS_MacAccounting::cisco-macacc-subtree']);
295 foreach my $INDEX ( sort { $data->{'cipMac'}{$a}{'subtreeName'} <=>
296 $data->{'cipMac'}{$b}{'subtreeName'} }
297 keys %{$data->{'cipMac'}} )
299 my $peer = $data->{'cipMac'}{$INDEX};
302 'peer-macaddr' => $peer->{'phyAddr'},
303 'peer-macoid' => $peer->{'macAddrOID'},
304 'peer-ipaddr' => $peer->{'peerIP'},
305 'interface-name' => $peer->{'ifReferenceName'},
306 'interface-nick' => $peer->{'ifNick'},
307 'comment' => $peer->{'description'},
308 'descriptive-nickname' => $peer->{'subtreeName'},
309 'precedence' => 65000 - $peer->{'peerAS'},
310 'searchable' => 'yes'
313 my $peerNode = $cb->addSubtree
314 ( $countersNode, $peer->{'subtreeName'}, $param,
315 ['CiscoIOS_MacAccounting::cisco-macacc'] );
317 if( defined( $data->{'cipMacExtStorage'} ) or
318 defined( $data->{'cipTokensetMember'} ) )
320 my $extStorageApplied = 0;
321 my $tsetMemberApplied = 0;
323 foreach my $peerName ( 'AS'.$peer->{'peerAS'}, $peer->{'peerIP'},
326 if( defined( $peerName ) )
328 if( not $extStorageApplied and
329 defined( $data->{'cipMacExtStorage'}{$peerName} ) )
332 $data->{'cipMacExtStorage'}{$peerName};
333 foreach my $dir ( 'In', 'Out' )
335 if( defined( $extStorage->{$dir} ) )
337 my $serviceid = $extStorage->{$dir};
340 'storage-type' => 'rrd,ext',
341 'ext-service-units' => 'bytes',
342 'ext-service-id' => $serviceid };
344 if( defined( $data->{'cipMacExtStoragetrees'}{
346 length( $data->{'cipMacExtStoragetrees'}{
349 $params->{'ext-service-trees'} =
350 $data->{'cipMacExtStoragetrees'}{
355 ( $peerNode, 'Bytes_' . $dir,
359 $extStorageApplied = 1;
362 if( not $tsetMemberApplied and
363 defined( $data->{'cipTokensetMember'}{$peerName} ) )
367 %{$data->{'cipTokensetMember'}{$peerName}} );
370 ( $peerNode, 'InOut_bps',
371 { 'tokenset-member' => $tsetList } );
386 # indent-tabs-mode: nil
387 # perl-indent-level: 4