per-agent configuration of batch processors, #71837
[freeside.git] / torrus / perllib / Torrus / DevDiscover / CiscoIOS_MacAccounting.pm
1 #  Copyright (C) 2002  Stanislav Sinyagin
2 #
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.
7 #
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.
12 #
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.
16
17 # $Id: CiscoIOS_MacAccounting.pm,v 1.1 2010-12-27 00:03:46 ivan Exp $
18 # Stanislav Sinyagin <ssinyagin@yahoo.com>
19
20 # Cisco IOS MAC accounting
21
22 package Torrus::DevDiscover::CiscoIOS_MacAccounting;
23
24 use strict;
25 use Torrus::Log;
26
27
28 $Torrus::DevDiscover::registry{'CiscoIOS_MacAccounting'} = {
29     'sequence'     => 510,
30     'checkdevtype' => \&checkdevtype,
31     'discover'     => \&discover,
32     'buildConfig'  => \&buildConfig
33     };
34
35
36 our %oiddef =
37     (
38      # CISCO-IP-STAT-MIB
39      'cipMacHCSwitchedBytes'        => '1.3.6.1.4.1.9.9.84.1.2.3.1.2',
40      
41      );
42
43 sub checkdevtype
44 {
45     my $dd = shift;
46     my $devdetails = shift;
47
48     my $session = $dd->session();
49
50     if( $devdetails->isDevType('CiscoIOS') and
51         $dd->checkSnmpTable('cipMacHCSwitchedBytes') )
52     {
53         return 1;
54     }
55     
56     return 0;
57 }
58
59
60 sub discover
61 {
62     my $dd = shift;
63     my $devdetails = shift;
64
65     my $session = $dd->session();
66     my $data = $devdetails->data();
67
68     my $table = $session->get_table( -baseoid =>
69                                      $dd->oiddef('cipMacHCSwitchedBytes'));
70     
71     if( not defined( $table ) or scalar( %{$table} ) == 0 )
72     {
73         return 0;
74     }
75     $devdetails->storeSnmpVars( $table );
76
77     # External storage serviceid assignment
78     my $extSrv =
79         $devdetails->param('CiscoIOS_MacAccounting::external-serviceid');
80     if( defined( $extSrv ) and length( $extSrv ) > 0 )
81     {
82         my $extStorage = {};
83         my $extStorageTrees = {};
84
85         foreach my $srvDef ( split( /\s*,\s*/, $extSrv ) )
86         {
87             my ( $serviceid, $peerName, $direction, $trees ) =
88                 split( /\s*:\s*/, $srvDef );
89
90             if( defined( $trees ) )
91             {
92                 # Trees are listed with '|' as separator,
93                 # whereas compiler expects commas
94                 
95                 $trees =~ s/\s*\|\s*/,/g;
96             }
97             
98             if( $direction eq 'Both' )
99             {
100                 $extStorage->{$peerName}{'In'} = $serviceid . '_IN';
101                 $extStorageTrees->{$serviceid . '_IN'} = $trees;
102                 
103                 $extStorage->{$peerName}{'Out'} = $serviceid . '_OUT';
104                 $extStorageTrees->{$serviceid . '_OUT'} = $trees;
105             }
106             else
107             {
108                 $extStorage->{$peerName}{$direction} = $serviceid;
109                 $extStorageTrees->{$serviceid} = $trees;
110             }
111         }
112         $data->{'cipMacExtStorage'} = $extStorage;
113         $data->{'cipMacExtStoragetrees'} = $extStorageTrees;
114     }
115
116
117     # tokenset members
118     # Format: tokenset:ASXXXX,ASXXXX; tokenset:ASXXXX,ASXXXX;
119     # Peer MAC or IP addresses could be used too
120     my $tsetMembership =
121         $devdetails->param('CiscoIOS_MacAccounting::tokenset-members');
122     if( defined( $tsetMembership ) and length( $tsetMembership ) > 0 )
123     {
124         my $tsetMember = {};
125         foreach my $memList ( split( /\s*;\s*/, $tsetMembership ) )
126         {
127             my ($tset, $list) = split( /\s*:\s*/, $memList );
128             foreach my $peerName ( split( /\s*,\s*/, $list ) )
129             {
130                 $tsetMember->{$peerName}{$tset} = 1;
131             }
132         }
133         $data->{'cipTokensetMember'} = $tsetMember;
134     }
135     
136     Torrus::DevDiscover::RFC2011_IP_MIB::discover($dd, $devdetails);
137     Torrus::DevDiscover::RFC1657_BGP4_MIB::discover($dd, $devdetails);
138     
139     foreach my $INDEX
140         ( $devdetails->
141           getSnmpIndices( $dd->oiddef('cipMacHCSwitchedBytes') ) )
142     {
143         my( $ifIndex, $direction, @phyAddrOctets ) = split( '\.', $INDEX );
144
145         my $interface = $data->{'interfaces'}{$ifIndex};
146         next if not defined( $interface );
147
148         my $phyAddr = '0x';
149         my $macAddrString = '';
150         foreach my $byte ( @phyAddrOctets )
151         {
152             $phyAddr .= sprintf('%.2x', $byte);
153             if( length( $macAddrString ) > 0 )
154             {
155                 $macAddrString .= ':';
156             }
157             $macAddrString .= sprintf('%.2x', $byte);
158         }
159
160         next if ( $phyAddr eq '0xffffffffffff' );
161         
162         my $peerIP = $interface->{'mediaToIpNet'}{$phyAddr};
163         if( not defined( $peerIP ) )
164         {
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};
168         }
169         
170         if( not defined( $peerIP ) )
171         {
172             # high logging level, because who cares about staled entries?
173             Debug('Cannot determine IP address for MAC accounting ' .
174                   'entry: ' . $macAddrString);            
175             next;
176         }
177
178         # There should be two entries per IP: in and out.
179         if( defined( $data->{'cipMac'}{$ifIndex . ':' . $phyAddr} ) )
180         {
181             $data->{'cipMac'}{$ifIndex . ':' . $phyAddr}{'nEntries'}++;
182             next;
183         }
184         
185         my $peer = {
186             'peerIP' => $peerIP,
187             'phyAddr' => $phyAddr,
188             'macAddrString' => $macAddrString,
189             'ifIndex' => $ifIndex,
190             'nEntries' => 1
191         };
192
193         $peer->{'macAddrOID'} = join('.', @phyAddrOctets);
194
195         $peer->{'ifReferenceName'} =
196             $interface->{$data->{'nameref'}{'ifReferenceName'}};
197         $peer->{'ifNick'} =
198             $interface->{$data->{'nameref'}{'ifNick'}};
199         
200         my $desc =
201             $devdetails->param('peer-ipaddr-description-' .
202                                join('_', split('\.', $peerIP)));
203         if( length( $desc ) > 0 )
204         {
205             $peer->{'description'} = $desc;
206         }        
207         
208         if( $devdetails->hasCap('bgpPeerTable') )
209         {
210             my $peerAS = $data->{'bgpPeerAS'}{$peerIP};
211             if( defined( $peerAS ) )
212             {
213                 $peer->{'peerAS'} = $data->{'bgpPeerAS'}{$peerIP};
214                 
215                 my $desc =
216                     $devdetails->param('bgp-as-description-' . $peerAS);
217                 if( length( $desc ) > 0 )
218                 {
219                     if( defined( $peer->{'description'} ) )
220                     {
221                         Warn('Conflicting descriptions for peer ' .
222                              $peerIP);
223                     }
224                     $peer->{'description'} = $desc;
225                 }
226             }
227             elsif( $devdetails->
228                     param('CiscoIOS_MacAccounting::bgponly') eq 'yes' )
229             {
230                 next;
231             }
232         }
233
234         if( defined( $peer->{'description'} ) )
235         {
236             $peer->{'description'} .= ' ';
237         }
238         $peer->{'description'} .= '[' . $peerIP . ']';
239                     
240         $data->{'cipMac'}{$ifIndex . ':' . $phyAddr} = $peer;
241     }
242
243     my %asNumbers;    
244     foreach my $INDEX ( keys %{$data->{'cipMac'}} )
245     {        
246         my $peer = $data->{'cipMac'}{$INDEX};
247
248         if( $peer->{'nEntries'} != 2 )
249         {
250             delete $data->{'cipMac'}{$INDEX};
251         }
252         else
253         {
254             if( defined( $peer->{'peerAS'} ) )
255             {
256                 $asNumbers{$peer->{'peerAS'}}++;
257             }
258         }
259     }
260     
261     foreach my $INDEX ( keys %{$data->{'cipMac'}} )
262     {
263         my $peer = $data->{'cipMac'}{$INDEX};
264         
265         my $subtreeName = $peer->{'peerIP'};
266         my $asNum = $peer->{'peerAS'};
267         if( defined( $asNum ) )
268         {
269             $subtreeName = 'AS' . $asNum; 
270             if( $asNumbers{$asNum} > 1 )
271             {
272                 $subtreeName .= '_' . $peer->{'peerIP'};
273             }
274         }
275         $peer->{'subtreeName'} = $subtreeName;
276     }
277     
278     return 1;
279 }
280
281
282 sub buildConfig
283 {
284     my $devdetails = shift;
285     my $cb = shift;
286     my $devNode = shift;
287
288     my $data = $devdetails->data();
289
290     my $countersNode =
291         $cb->addSubtree( $devNode, 'MAC_Accounting',
292                          {'node-display-name' => 'MAC Accounting'},
293                          ['CiscoIOS_MacAccounting::cisco-macacc-subtree']);
294     
295     foreach my $INDEX ( sort { $data->{'cipMac'}{$a}{'subtreeName'} <=>
296                                    $data->{'cipMac'}{$b}{'subtreeName'} }
297                         keys %{$data->{'cipMac'}} )
298     {
299         my $peer = $data->{'cipMac'}{$INDEX};
300     
301         my $param = {
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'
311             };
312
313         my $peerNode = $cb->addSubtree
314             ( $countersNode, $peer->{'subtreeName'}, $param,
315               ['CiscoIOS_MacAccounting::cisco-macacc'] );
316
317         if( defined( $data->{'cipMacExtStorage'} ) or
318             defined( $data->{'cipTokensetMember'} ) )
319         {
320             my $extStorageApplied = 0;
321             my $tsetMemberApplied = 0;
322             
323             foreach my $peerName ( 'AS'.$peer->{'peerAS'}, $peer->{'peerIP'},
324                                    $peer->{'phyAddr'} )
325             {
326                 if( defined( $peerName ) )
327                 {
328                     if( not $extStorageApplied and
329                         defined( $data->{'cipMacExtStorage'}{$peerName} ) )
330                     {
331                         my $extStorage =
332                             $data->{'cipMacExtStorage'}{$peerName};
333                         foreach my $dir ( 'In', 'Out' )
334                         {
335                             if( defined( $extStorage->{$dir} ) )
336                             {
337                                 my $serviceid = $extStorage->{$dir};
338                                 
339                                 my $params = {
340                                     'storage-type' => 'rrd,ext',
341                                     'ext-service-units' => 'bytes',
342                                     'ext-service-id' => $serviceid };
343                                 
344                                 if( defined( $data->{'cipMacExtStoragetrees'}{
345                                     $serviceid}) and
346                                     length( $data->{'cipMacExtStoragetrees'}{
347                                         $serviceid}) > 0 )
348                                 {
349                                     $params->{'ext-service-trees'} =
350                                         $data->{'cipMacExtStoragetrees'}{
351                                             $serviceid};
352                                 }
353                                 
354                                 $cb->addLeaf
355                                     ( $peerNode, 'Bytes_' . $dir,
356                                       $params );
357                             }
358                         }
359                         $extStorageApplied = 1;
360                     }
361
362                     if( not $tsetMemberApplied and
363                         defined( $data->{'cipTokensetMember'}{$peerName} ) )
364                     {
365                         my $tsetList =
366                             join( ',', sort keys
367                                   %{$data->{'cipTokensetMember'}{$peerName}} );
368
369                         $cb->addLeaf
370                             ( $peerNode, 'InOut_bps',
371                               { 'tokenset-member' => $tsetList } );
372                     }                        
373                 }
374             }
375         }
376     }
377 }
378
379
380
381 1;
382
383
384 # Local Variables:
385 # mode: perl
386 # indent-tabs-mode: nil
387 # perl-indent-level: 4
388 # End: