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.
18 # Stanislav Sinyagin <ssinyagin@yahoo.com>
20 # Cisco IOS MAC accounting
22 package Torrus
::DevDiscover
::CiscoIOS_MacAccounting
;
30 $Torrus::DevDiscover
::registry
{'CiscoIOS_MacAccounting'} = {
32 'checkdevtype' => \
&checkdevtype
,
33 'discover' => \
&discover
,
34 'buildConfig' => \
&buildConfig
41 'cipMacHCSwitchedBytes' => '1.3.6.1.4.1.9.9.84.1.2.3.1.2',
48 my $devdetails = shift;
50 my $session = $dd->session();
52 if( $devdetails->isDevType('CiscoIOS') and
53 $dd->checkSnmpTable('cipMacHCSwitchedBytes') )
65 my $devdetails = shift;
67 my $session = $dd->session();
68 my $data = $devdetails->data();
70 my $table = $session->get_table( -baseoid
=>
71 $dd->oiddef('cipMacHCSwitchedBytes'));
73 if( not defined($table) or scalar(keys %{$table}) == 0 )
77 $devdetails->storeSnmpVars( $table );
79 # External storage serviceid assignment
81 $devdetails->paramString('CiscoIOS_MacAccounting::external-serviceid');
85 my $extStorageTrees = {};
87 for my $srvDef ( split( /\s*,\s*/, $extSrv ) )
89 my ( $serviceid, $peerName, $direction, $trees ) =
90 split( /\s*:\s*/, $srvDef );
92 if( defined( $trees ) )
94 # Trees are listed with '|' as separator,
95 # whereas compiler expects commas
97 $trees =~ s/\s*\|\s*/,/g;
100 if( $direction eq 'Both' )
102 $extStorage->{$peerName}{'In'} = $serviceid . '_IN';
103 $extStorageTrees->{$serviceid . '_IN'} = $trees;
105 $extStorage->{$peerName}{'Out'} = $serviceid . '_OUT';
106 $extStorageTrees->{$serviceid . '_OUT'} = $trees;
110 $extStorage->{$peerName}{$direction} = $serviceid;
111 $extStorageTrees->{$serviceid} = $trees;
114 $data->{'cipMacExtStorage'} = $extStorage;
115 $data->{'cipMacExtStoragetrees'} = $extStorageTrees;
120 # Format: tokenset:ASXXXX,ASXXXX; tokenset:ASXXXX,ASXXXX;
121 # Peer MAC or IP addresses could be used too
122 $data->{'cipTokensetMember'} = {};
125 $devdetails->paramString
126 ('CiscoIOS_MacAccounting::tokenset-members') ) )
128 my ($tset, $list) = split( /\s*:\s*/, $memList );
129 for my $peerName ( split( /\s*,\s*/, $list ) )
131 $data->{'cipTokensetMember'}->{$peerName}{$tset} = 1;
135 Torrus
::DevDiscover
::RFC2011_IP_MIB
::discover
($dd, $devdetails);
136 Torrus
::DevDiscover
::RFC1657_BGP4_MIB
::discover
($dd, $devdetails);
140 getSnmpIndices
( $dd->oiddef('cipMacHCSwitchedBytes') ) )
142 my( $ifIndex, $direction, @phyAddrOctets ) = split( '\.', $INDEX );
144 my $interface = $data->{'interfaces'}{$ifIndex};
145 next if not defined( $interface );
148 my $macAddrString = '';
149 for my $byte ( @phyAddrOctets )
151 $phyAddr .= sprintf('%.2x', $byte);
152 if( length( $macAddrString ) > 0 )
154 $macAddrString .= ':';
156 $macAddrString .= sprintf('%.2x', $byte);
159 next if ( $phyAddr eq '0xffffffffffff' );
161 my $peerIP = $interface->{'mediaToIpNet'}{$phyAddr};
162 if( not defined( $peerIP ) )
164 # Try in the global table, as the ARP is stored per subinterface,
165 # and MAC accounting is on main interface
166 $peerIP = $data->{'mediaToIpNet'}{$phyAddr};
169 if( not defined( $peerIP ) )
171 # high logging level, because who cares about staled entries?
172 Debug
('Cannot determine IP address for MAC accounting ' .
173 'entry: ' . $macAddrString);
177 # There should be two entries per IP: in and out.
178 if( defined( $data->{'cipMac'}{$ifIndex . ':' . $phyAddr} ) )
180 $data->{'cipMac'}{$ifIndex . ':' . $phyAddr}{'nEntries'}++;
186 'phyAddr' => $phyAddr,
187 'macAddrString' => $macAddrString,
188 'ifIndex' => $ifIndex,
192 $peer->{'macAddrOID'} = join('.', @phyAddrOctets);
194 $peer->{'ifReferenceName'} =
195 $interface->{$data->{'nameref'}{'ifReferenceName'}};
197 $interface->{$data->{'nameref'}{'ifNick'}};
201 $devdetails->paramString('peer-ipaddr-description-' .
202 join('_', split('\.', $peerIP)));
205 $peer->{'description'} = $desc;
209 if( $devdetails->hasCap('bgpPeerTable') )
211 my $peerAS = $data->{'bgpPeerAS'}{$peerIP};
212 if( defined( $peerAS ) )
214 $peer->{'peerAS'} = $data->{'bgpPeerAS'}{$peerIP};
217 $devdetails->paramString('bgp-as-description-' . $peerAS);
220 if( defined( $peer->{'description'} ) )
222 Warn
('Conflicting descriptions for peer ' .
225 $peer->{'description'} = $desc;
228 elsif( $devdetails->paramEnabled
229 ('CiscoIOS_MacAccounting::bgponly') )
235 if( defined( $peer->{'description'} ) )
237 $peer->{'description'} .= ' ';
239 $peer->{'description'} .= '[' . $peerIP . ']';
241 $data->{'cipMac'}{$ifIndex . ':' . $phyAddr} = $peer;
245 for my $INDEX ( keys %{$data->{'cipMac'}} )
247 my $peer = $data->{'cipMac'}{$INDEX};
249 if( $peer->{'nEntries'} != 2 )
251 delete $data->{'cipMac'}{$INDEX};
255 if( defined( $peer->{'peerAS'} ) )
257 $asNumbers{$peer->{'peerAS'}}++;
262 for my $INDEX ( keys %{$data->{'cipMac'}} )
264 my $peer = $data->{'cipMac'}{$INDEX};
266 my $subtreeName = $peer->{'peerIP'};
267 my $asNum = $peer->{'peerAS'};
268 if( defined( $asNum ) )
270 $subtreeName = 'AS' . $asNum;
271 if( $asNumbers{$asNum} > 1 )
273 $subtreeName .= '_' . $peer->{'peerIP'};
276 $peer->{'subtreeName'} = $subtreeName;
285 my $devdetails = shift;
289 my $data = $devdetails->data();
292 $cb->addSubtree( $devNode, 'MAC_Accounting',
293 {'node-display-name' => 'MAC Accounting'},
294 ['CiscoIOS_MacAccounting::cisco-macacc-subtree']);
296 for my $INDEX ( sort { $data->{'cipMac'}{$a}{'subtreeName'} <=>
297 $data->{'cipMac'}{$b}{'subtreeName'} }
298 keys %{$data->{'cipMac'}} )
300 my $peer = $data->{'cipMac'}{$INDEX};
303 'peer-macaddr' => $peer->{'phyAddr'},
304 'peer-macoid' => $peer->{'macAddrOID'},
305 'peer-ipaddr' => $peer->{'peerIP'},
306 'interface-name' => $peer->{'ifReferenceName'},
307 'interface-nick' => $peer->{'ifNick'},
308 'comment' => $peer->{'description'},
309 'descriptive-nickname' => $peer->{'subtreeName'},
310 'precedence' => 65000 - $peer->{'peerAS'},
311 'searchable' => 'yes'
314 my $peerNode = $cb->addSubtree
315 ( $countersNode, $peer->{'subtreeName'}, $param,
316 ['CiscoIOS_MacAccounting::cisco-macacc'] );
318 if( defined( $data->{'cipMacExtStorage'} ) or
319 defined( $data->{'cipTokensetMember'} ) )
321 my $extStorageApplied = 0;
322 my $tsetMemberApplied = 0;
324 for my $peerName ( 'AS'.$peer->{'peerAS'}, $peer->{'peerIP'},
327 if( defined( $peerName ) )
329 if( not $extStorageApplied and
330 defined( $data->{'cipMacExtStorage'}{$peerName} ) )
333 $data->{'cipMacExtStorage'}{$peerName};
334 for my $dir ( 'In', 'Out' )
336 if( defined( $extStorage->{$dir} ) )
338 my $serviceid = $extStorage->{$dir};
341 'storage-type' => 'rrd,ext',
342 'ext-service-units' => 'bytes',
343 'ext-service-id' => $serviceid };
345 if( defined( $data->{'cipMacExtStoragetrees'}{
347 length( $data->{'cipMacExtStoragetrees'}{
350 $params->{'ext-service-trees'} =
351 $data->{'cipMacExtStoragetrees'}{
356 ( $peerNode, 'Bytes_' . $dir,
360 $extStorageApplied = 1;
363 if( not $tsetMemberApplied and
364 defined( $data->{'cipTokensetMember'}{$peerName} ) )
368 %{$data->{'cipTokensetMember'}{$peerName}} );
371 ( $peerNode, 'InOut_bps',
372 { 'tokenset-member' => $tsetList } );
389 # indent-tabs-mode: nil
390 # perl-indent-level: 4