import torrus 1.0.9
[freeside.git] / torrus / perllib / Torrus / DevDiscover / ALU_Timetra.pm
1 #
2 #  Discovery module for Alcatel-Lucent ESS and SR routers
3 #
4 #  Copyright (C) 2009 Stanislav Sinyagin
5 #
6 #  This program is free software; you can redistribute it and/or modify
7 #  it under the terms of the GNU General Public License as published by
8 #  the Free Software Foundation; either version 2 of the License, or
9 #  (at your option) any later version.
10 #
11 #  This program is distributed in the hope that it will be useful,
12 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 #  GNU General Public License for more details.
15 #
16 #  You should have received a copy of the GNU General Public License
17 #  along with this program; if not, write to the Free Software
18 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19
20 # $Id: ALU_Timetra.pm,v 1.1 2010-12-27 00:03:49 ivan Exp $
21 # Stanislav Sinyagin <ssinyagin@yahoo.com>
22 #
23
24 # Currently tested with following Alcatel-Lucent devices:
25 #  * ESS 7450
26
27
28 package Torrus::DevDiscover::ALU_Timetra;
29
30 use strict;
31 use Torrus::Log;
32
33
34 $Torrus::DevDiscover::registry{'ALU_Timetra'} = {
35     'sequence'     => 500,
36     'checkdevtype' => \&checkdevtype,
37     'discover'     => \&discover,
38     'buildConfig'  => \&buildConfig
39     };
40
41
42
43 our %oiddef =
44     (
45      # TIMETRA-CHASSIS-MIB
46      'tmnxChassisTotalNumber'     => '1.3.6.1.4.1.6527.3.1.2.2.1.1.0',
47      
48      # TIMETRA-GLOBAL-MIB
49      'timetraReg'                 => '1.3.6.1.4.1.6527.1',
50      'timetraServiceRouters'      => '1.3.6.1.4.1.6527.1.3',
51      'timetraServiceSwitches'     => '1.3.6.1.4.1.6527.1.6',
52      'alcatel7710ServiceRouters'  => '1.3.6.1.4.1.6527.1.9',
53
54      # TIMETRA-SERV-MIB
55      'custDescription'  => '1.3.6.1.4.1.6527.3.1.2.4.1.3.1.3',
56      'svcCustId'        => '1.3.6.1.4.1.6527.3.1.2.4.2.2.1.4',
57      'svcDescription'   => '1.3.6.1.4.1.6527.3.1.2.4.2.2.1.6',
58      'sapDescription'   => '1.3.6.1.4.1.6527.3.1.2.4.3.2.1.5',
59
60      # TIMETRA-PORT-MIB (chassis ID hardcoded to 1)
61      'tmnxPortDescription' => '1.3.6.1.4.1.6527.3.1.2.2.4.2.1.5.1',
62      'tmnxPortEncapType'   => '1.3.6.1.4.1.6527.3.1.2.2.4.2.1.12.1',     
63      );
64
65
66 my %essInterfaceFilter =
67     (
68      'system'  => {
69          'ifType'  => 24,                     # softwareLoopback
70          'ifName' => '^system'
71          },
72      );
73
74
75
76 sub checkdevtype
77 {
78     my $dd = shift;
79     my $devdetails = shift;
80
81     my $objectID = $devdetails->snmpVar( $dd->oiddef('sysObjectID') );
82     
83     if( $dd->oidBaseMatch( 'timetraReg', $objectID ) )
84     {
85         my $session = $dd->session();
86         my $oid = $dd->oiddef('tmnxChassisTotalNumber');
87         my $result = $session->get_request( $oid );
88         if( $result->{$oid} != 1 )
89         {
90             Error('Multi-chassis ALU 7x50 equipment is not yet supported');
91             return 0;
92         }
93             
94         if( $dd->oidBaseMatch( 'timetraServiceSwitches', $objectID ) )
95         {
96             $devdetails->setCap('ALU_ESS7450');
97             
98             $devdetails->setCap('interfaceIndexingManaged');
99             $devdetails->setCap('interfaceIndexingPersistent');
100             
101             &Torrus::DevDiscover::RFC2863_IF_MIB::addInterfaceFilter
102                 ($devdetails, \%essInterfaceFilter);
103
104             $dd->setMaxMsgSize($devdetails, 65535, {'only_v1_and_v2' => 1});
105             
106             return 1;
107         }
108         else
109         {
110             # placeholder for future developments
111             Error('This model of Alcatel-Lucent equipment ' .
112                   'is not yet supported');
113             return 0;
114         }
115     }
116     
117     return 0;
118 }
119
120
121
122
123 sub discover
124 {
125     my $dd = shift;
126     my $devdetails = shift;
127
128     my $session = $dd->session();
129     my $data = $devdetails->data();
130
131     # WARNING: This code is tested only with ESS7450
132
133     # Get port descriptions
134     {
135         my $oid = $dd->oiddef('tmnxPortDescription');
136         
137         my $portDescrTable = $session->get_table( -baseoid => $oid );        
138         my $prefixLen = length( $oid ) + 1;
139
140         while( my( $oid, $descr ) = each %{$portDescrTable} )
141         {
142             my $ifIndex = substr( $oid, $prefixLen );
143             if( defined( $data->{'interfaces'}{$ifIndex} ) )
144             {
145                 $data->{'interfaces'}{$ifIndex}{'tmnxPortDescription'} =
146                     $descr;
147             }
148         }
149     }
150     
151     # Amend RFC2863_IF_MIB references
152     $data->{'nameref'}{'ifSubtreeName'}    = 'ifNameT';
153     $data->{'nameref'}{'ifReferenceName'}  = 'ifName';
154     $data->{'nameref'}{'ifNick'} = 'ifNameT';
155     $data->{'nameref'}{'ifComment'} = 'tmnxPortDescription';
156     
157     # Get customers
158     {
159         my $oid = $dd->oiddef('custDescription');
160         my $custDescrTable = $session->get_table( -baseoid => $oid );        
161         my $prefixLen = length( $oid ) + 1;
162         
163         while( my( $oid, $descr ) = each %{$custDescrTable} )
164         {
165             my $custId = substr( $oid, $prefixLen );
166             $data->{'timetraCustDescr'}{$custId} = $descr;
167         }
168     }
169         
170     
171     # Get Service Descriptions
172     {
173         my $oid = $dd->oiddef('svcDescription');
174         my $svcDescrTable = $session->get_table( -baseoid => $oid );        
175         my $prefixLen = length( $oid ) + 1;
176
177         while( my( $oid, $descr ) = each %{$svcDescrTable} )
178         {
179             my $svcId = substr( $oid, $prefixLen );
180             $data->{'timetraSvc'}{$svcId} = {
181                 'description' => $descr,
182                 'sap' => [],
183             };
184         }
185     }
186
187     # Get mapping of Services to Customers
188     {
189         my $oid = $dd->oiddef('svcCustId');
190         my $svcCustIdTable = $session->get_table( -baseoid => $oid );        
191         my $prefixLen = length( $oid ) + 1;
192         
193         while( my( $oid, $custId ) = each %{$svcCustIdTable} )
194         {
195             my $svcId = substr( $oid, $prefixLen );
196             
197             $data->{'timetraCustSvc'}{$custId}{$svcId} = 1;
198             $data->{'timetraSvcCust'}{$svcId} = $custId;
199         }
200     }
201
202     
203     # Get port encapsulations
204     {
205         my $oid = $dd->oiddef('tmnxPortEncapType');
206         
207         my $portEncapTable = $session->get_table( -baseoid => $oid );        
208         my $prefixLen = length( $oid ) + 1;
209
210         while( my( $oid, $encap ) = each %{$portEncapTable} )
211         {
212             my $ifIndex = substr( $oid, $prefixLen );
213             if( defined( $data->{'interfaces'}{$ifIndex} ) )
214             {
215                 $data->{'interfaces'}{$ifIndex}{'tmnxPortEncapType'} = $encap;
216             }
217         }
218     }
219
220     
221     # Get SAP information
222     {
223         my $oid = $dd->oiddef('sapDescription');
224         
225         my $sapDescrTable = $session->get_table( -baseoid => $oid );        
226         my $prefixLen = length( $oid ) + 1;
227
228         while( my( $oid, $descr ) = each %{$sapDescrTable} )
229         {
230             my $sapFullID = substr( $oid, $prefixLen );
231
232             my ($svcId, $ifIndex, $sapEncapValue) =
233                 split(/\./o, $sapFullID);
234
235             my $svcSaps = $data->{'timetraSvc'}{$svcId}{'sap'};
236             if( not defined( $svcSaps ) )
237             {
238                 Error('Cannot find Service ID ' . $svcId);
239                 next;
240             }
241
242             if( not defined( $data->{'interfaces'}{$ifIndex} ) )
243             {
244                 Warn('IfIndex ' . $ifIndex . ' is not in interfaces table, ' .
245                      'skipping SAP');
246                 next;
247             }
248             
249             my $encap = $data->{'interfaces'}{$ifIndex}{'tmnxPortEncapType'};
250
251             # Compose the SAP name depending on port encapsulation.
252             
253             my $sapName = $data->{'interfaces'}{$ifIndex}{'ifName'};
254
255             if( $encap == 1 )  # nullEncap
256             {
257                 # do nothing
258             }
259             elsif( $encap == 2 )  # qEncap
260             {
261                 # sapEncapValue is equal to VLAN ID
262                 $sapName .= ':' . $sapEncapValue;
263             }
264             elsif( $encap == 10 )  # qinqEncap
265             {
266                 # sapEncapValue contains inner and outer VLAN IDs
267                 
268                 my $outer = $sapEncapValue & 0xffff;
269                 my $inner = $sapEncapValue >> 16;
270                 if( $inner == 4095 )
271                 {
272                     # default SAP
273                     $inner = '*';
274                 }
275
276                 $sapName .= ':' . $outer . '.' . $inner;
277             }
278             elsif( $encap == 3 ) # mplsEncap
279             {
280                 # sapEncapValue contains the 20-bit LSP ID
281                 # we should probably do something more here
282                 $sapName .= ':' . $sapEncapValue;
283             }
284             else
285             {
286                 Warn('Encapsulation type ' . $encap . ' is not supported yet');
287                 $sapName .= ':' . $sapEncapValue;
288             }
289
290             $data->{'timetraSap'}{$sapFullID} =  {
291                 'description' => $descr,
292                 'port' => $ifIndex,
293                 'name' => $sapName,
294                 'encval' => $sapEncapValue,
295                 'svc' => $svcId,
296             };
297
298             push( @{$svcSaps}, $sapFullID );
299         }
300     }
301     
302     return 1;
303 }
304
305
306 sub buildConfig
307 {
308     my $devdetails = shift;
309     my $cb = shift;
310     my $devNode = shift;
311     my $data = $devdetails->data();
312
313
314     if( defined( $data->{'timetraSvc'} ) )
315     {
316         my $customersNode = $cb->addSubtree( $devNode, 'Customers' );
317
318         foreach my $custId (sort {$a <=> $b} keys %{$data->{'timetraCustSvc'}})
319         {
320             # count the number of SAPs
321             my $nSaps = 0;
322             foreach my $svcId ( keys %{$data->{'timetraCustSvc'}{$custId}} )
323             {
324                 my $svcSaps = $data->{'timetraSvc'}{$svcId}{'sap'};
325                 if( defined( $svcSaps ) )
326                 {
327                     foreach my $sapID ( @{$svcSaps} )
328                     {
329                         if( not $data->{'timetraSap'}{$sapID}{'excluded'} )
330                         {               
331                             $nSaps++;
332                         }
333                     }
334                 }
335             }
336
337             if( $nSaps == 0 )
338             {
339                 next;
340             }
341             
342             my $param = {
343                 'precedence' => 100000 - $custId,
344                 'comment'    => $data->{'timetraCustDescr'}{$custId},
345                 'timetra-customer-id' => $custId,
346             };
347             
348             my $custNode =
349                 $cb->addSubtree( $customersNode, $custId, $param,
350                                  ['ALU_Timetra::alu-timetra-customer']);
351             
352             my $precedence = 10000;
353             
354             foreach my $svcId
355                 ( keys %{$data->{'timetraCustSvc'}{$custId}} )
356             {
357                 my $svcSaps = $data->{'timetraSvc'}{$svcId}{'sap'};
358                 
359                 if( defined($svcSaps ) )
360                 {                    
361                     foreach my $sapID
362                         ( sort {sapCompare($data->{'timetraSap'}{$a},
363                                            $data->{'timetraSap'}{$b})}
364                           @{$svcSaps} )
365                     {
366                         my $sap = $data->{'timetraSap'}{$sapID};
367
368                         if( $sap->{'excluded'} )
369                         {
370                             next;
371                         }
372                         
373                         my $sapDescr = $sap->{'description'};
374                         if( length( $sapDescr ) == 0 )
375                         {
376                             $sapDescr = $data->{'timetraSvc'}{$svcId}->{
377                                 'description'};
378                         }
379
380                         my $subtreeName = $sap->{'name'};
381                         $subtreeName =~ s/\W/_/go;
382
383                         my $comment = '';
384                         if( length( $sapDescr ) > 0 )
385                         {
386                             $comment = $sapDescr;
387                         }
388
389                         my $legend = '';                        
390                         
391                         if( length($data->{'timetraCustDescr'}{$custId}) > 0 )
392                         {
393                             $legend .= 'Customer:' .
394                                 $devdetails->screenSpecialChars
395                                 ( $data->{'timetraCustDescr'}{$custId} ) . ';';
396                         }
397                         
398                         if( length($data->{'timetraSvc'}{$svcId}->{
399                             'description'}) > 0 )
400                         {
401                             $legend .= 'Service:' .
402                                 $devdetails->screenSpecialChars
403                                 ( $data->{'timetraSvc'}{$svcId}->{
404                                     'description'} ) . ';';
405                         }
406                         
407                         $legend .= 'SAP: ' .
408                             $devdetails->screenSpecialChars( $sap->{'name'} );
409                         
410                         
411                         my $param = {
412                             'comment'          => $comment,
413                             'timetra-sap-id'   => $sapID,
414                             'timetra-sap-name' => $sap->{'name'},
415                             'node-display-name' => $sap->{'name'},
416                             'precedence'       => $precedence--,
417                             'legend'           => $legend,
418                         };
419
420                         $cb->addSubtree( $custNode, $subtreeName, $param,
421                                          ['ALU_Timetra::alu-timetra-sap']);
422                     }
423                 }
424             }                            
425         }
426     }    
427 }
428
429
430 sub sapCompare
431 {
432     my $a = shift;
433     my $b = shift;
434
435     if( $a->{'port'} == $b->{'port'} )
436     {
437         return ( $a->{'encval'} <=> $b->{'encval'} );
438     }
439     else
440     {
441         return ( $a->{'port'} <=> $b->{'port'} );
442     }
443 }
444       
445
446
447 #######################################
448 # Selectors interface
449 #
450
451
452 $Torrus::DevDiscover::selectorsRegistry{'ALU_SAP'} = {
453     'getObjects'      => \&getSelectorObjects,
454     'getObjectName'   => \&getSelectorObjectName,
455     'checkAttribute'  => \&checkSelectorAttribute,
456     'applyAction'     => \&applySelectorAction,
457 };
458
459 ## Objects are full SAP indexes: svcId.sapPortId.sapEncapValue
460
461 sub getSelectorObjects
462 {
463     my $devdetails = shift;
464     my $objType = shift;
465
466     my $data = $devdetails->data();
467     my @ret = keys %{$data->{'timetraSap'}};
468
469     return( sort {$a<=>$b} @ret );
470 }
471
472
473 sub checkSelectorAttribute
474 {
475     my $devdetails = shift;
476     my $object = shift;
477     my $objType = shift;
478     my $attr = shift;
479     my $checkval = shift;
480
481     my $data = $devdetails->data();
482     
483     my $value;
484     my $operator = '=~';
485     
486     my $sap = $data->{'timetraSap'}{$object};
487     
488     if( $attr eq 'sapDescr' )
489     {
490         $value = $sap->{'description'};
491     }
492     elsif( $attr eq 'custDescr' )
493     {
494         my $svcId = $sap->{'svc'};
495         my $custId = $data->{'timetraSvcCust'}{$svcId};
496         $value = $data->{'timetraCustDescr'}{$custId};
497     }
498     elsif( $attr eq 'sapName' )
499     {
500         $value = $sap->{'name'};
501         $operator = 'eq';
502     }
503     elsif( $attr eq 'sapPort' )
504     {
505         my $ifIndex = $sap->{'port'};
506         $value = $data->{'interfaces'}{$ifIndex}{'ifName'};
507         $operator = 'eq';
508     }    
509     else
510     {
511         Error('Unknown ALU_SAP selector attribute: ' . $attr);
512         $value = '';
513     }        
514         
515     
516     return eval( '$value' . ' ' . $operator . '$checkval' ) ? 1:0;
517 }
518
519
520 sub getSelectorObjectName
521 {
522     my $devdetails = shift;
523     my $object = shift;
524     my $objType = shift;
525     
526     my $data = $devdetails->data();
527
528     return $data->{'timetraSap'}{$object}{'name'};
529 }
530
531
532 my %knownSelectorActions =
533     (
534      'RemoveSAP' => 1,
535      );
536
537                             
538 sub applySelectorAction
539 {
540     my $devdetails = shift;
541     my $object = shift;
542     my $objType = shift;
543     my $action = shift;
544     my $arg = shift;
545
546     my $data = $devdetails->data();
547     my $objref;
548     
549     if( not $knownSelectorActions{$action} )
550     {
551         Error('Unknown ALU_SAP selector action: ' . $action);
552         return;
553     }
554
555     if( $action eq 'RemoveSAP' )
556     {
557         $data->{'timetraSap'}{$object}{'excluded'} = 1;
558     }
559 }   
560
561 1;
562
563 # Local Variables:
564 # mode: perl
565 # indent-tabs-mode: nil
566 # perl-indent-level: 4
567 # End: