339 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			339 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/perl -w
 | |
| 
 | |
| # $Id$
 | |
| 
 | |
| $DevMatrix = '../DeviceMatrix.txt';
 | |
| $DevHTML   = 'DeviceMatrix.html';
 | |
| $DevPNG    = 'DeviceMatrix.png';
 | |
| $Attributes= {};
 | |
| 
 | |
| # Parse Data File
 | |
| $matrix = parse_data($DevMatrix);
 | |
| 
 | |
| # Graph it for fun
 | |
| eval "use GraphViz::Data::Structure;";
 | |
| if ($@) {
 | |
|     print "GraphViz::Data::Structure not installed. $@\n";
 | |
| } else {
 | |
|     my %graph = ();
 | |
|     foreach my $vendor (sort sort_nocase keys %$matrix){
 | |
|         $graph{$vendor} = {};
 | |
|         foreach my $family  (sort sort_nocase keys %{$matrix->{$vendor}->{families}} ){
 | |
|             my @models;
 | |
|             foreach my $mod (keys %{$matrix->{$vendor}->{families}->{$family}->{models}}){
 | |
|                 push(@models,split(/\s*,\s*/,$mod));
 | |
|             }
 | |
|             if (scalar @models){
 | |
|                 $graph{$vendor}->{$family}=\@models;
 | |
|             } else {
 | |
|                 $graph{$vendor}->{$family}=[];
 | |
|             }
 | |
| 
 | |
|         }
 | |
|     }
 | |
|     my $now = scalar localtime;
 | |
|     my $gvds = GraphViz::Data::Structure->new(\%graph,Orientation=>'vertical',
 | |
|         Colors=> 'Deep',
 | |
|         graph => {label=>"SNMP::Info and Netdisco Supported Devices \n $now",'fontpath'=>'/usr/local/netdisco','fontname'=>'lucon',concentrate=>'true','overlap'=>'false',spline=>'true',bgcolor=>'wheat'},
 | |
|         node  => {fontname=>'lucon'},
 | |
|         );
 | |
|     $gvds->graph()->as_png($DevPNG);
 | |
| }
 | |
| 
 | |
| print "Creating $DevHTML\n";
 | |
| open (HTML, "> $DevHTML") or die "Can't open $DevHTML. $!\n";
 | |
| $old_fh = select(HTML);
 | |
| &html_head;
 | |
| print_vendors($matrix);
 | |
| foreach my $vendor (sort sort_nocase keys %$matrix){
 | |
|     print "<A NAME=\"$vendor\"><SPAN CLASS=\"vendor\"><B>$vendor</B></SPAN></A>\n";
 | |
|     print "<DL>\n";
 | |
| 
 | |
|     my $vendor_defaults = $matrix->{$vendor}->{defaults};
 | |
|     print_notes($vendor_defaults,1);
 | |
| 
 | |
|     my $families = $matrix->{$vendor}->{families};
 | |
|     foreach my $family (sort sort_nocase keys %$families ) {
 | |
|         print "<DT>$family Family\n";
 | |
| 
 | |
|         my $family_defaults = $families->{$family}->{defaults};
 | |
|         print_notes($family_defaults,2);
 | |
| 
 | |
|         my $models = $families->{$family}->{models};
 | |
|         foreach my $model (sort sort_nocase keys %$models ){
 | |
|             my $model_defaults = $models->{$model}->{defaults};
 | |
|             print "<DD>$model\n";
 | |
|             print "<DL>\n";
 | |
|             print_notes($model_defaults,3);
 | |
| 
 | |
|             print "<DT><DD><TABLE BORDER=1>\n";
 | |
|             print_headers();
 | |
|             print "<TR>\n";
 | |
|             foreach my $a (sort sort_nocase keys %$Attributes) {
 | |
|                 my $val;
 | |
|                 next if $a eq 'note';
 | |
|                 $val = ['-'];
 | |
|                 $class = 'none';
 | |
|                 if (defined $model_defaults->{$a}) {
 | |
|                     $val = $model_defaults->{$a};
 | |
|                     $class = 'model';
 | |
|                 } elsif (defined $family_defaults->{$a}){
 | |
|                     $val = $family_defaults->{$a};
 | |
|                     $class = 'family';
 | |
|                 } elsif (defined $vendor_defaults->{$a}){
 | |
|                     $val = $vendor_defaults->{$a};
 | |
|                     $class = 'vendor';
 | |
|                 }
 | |
|                 print "  <TD CLASS='$class'>",join("<BR>\n",@$val),"</TD>\n";
 | |
|             }
 | |
|             print "</TR></TABLE>\n";
 | |
|             print "</DL>\n";
 | |
|         }
 | |
|     }
 | |
|     print "</DL>\n";
 | |
| }
 | |
| 
 | |
| 
 | |
| &html_tail;
 | |
| 
 | |
| select ($old_fh);
 | |
| close (HTML) or die "Can't write $DevHTML. $!\n";
 | |
| 
 | |
| # Data Structures
 | |
| 
 | |
| # Matrix =
 | |
| #   ( vendor => { families  => { family => family_hash },
 | |
| #                  defaults => { cmd    => [values]    },
 | |
| #               }
 | |
| #   )
 | |
| 
 | |
| # Family Hash
 | |
| #   ( models   => { model => model_hash },
 | |
| #     defaults => { cmd   => [values]   }
 | |
| #   )
 | |
| 
 | |
| # Model Hash
 | |
| #   ( defaults => { cmd => [values] } )
 | |
| sub parse_data {
 | |
|     my $file = shift;
 | |
|     my %ignore = map { $_ => 1  }  @_;
 | |
|     my $Matrix;
 | |
| 
 | |
|     my @Lines;
 | |
|     open (DM, "< $file") or die "Can't open $file. $!\n";
 | |
|     {
 | |
|         @Lines = <DM>;
 | |
|     }
 | |
|     close (DM);
 | |
| 
 | |
|     my ($device,$family,$vendor,$class);
 | |
|     foreach my $line (@Lines){
 | |
|         chomp($line);
 | |
|         # Comments
 | |
|         $line =~ s/#.*//;
 | |
| 
 | |
|         # Blank Lines
 | |
|         next if $line =~ /^\s*$/;
 | |
| 
 | |
|         # Trim whitespace
 | |
|         $line =~ s/^\s+//;
 | |
|         $line =~ s/\s+$//;
 | |
| 
 | |
|         my ($cmd,$value);
 | |
|         if ($line =~ /^([a-z-_]+)\s*:\s*(.*)$/) {
 | |
|             $cmd = $1;  $value = $2;
 | |
|         } else {
 | |
|             print "What do i do with this line : $line \n";
 | |
|             next;
 | |
|         }
 | |
| 
 | |
|         if (exists $ignore{$cmd}){
 | |
|             print "Ignoring $cmd\n";
 | |
|         }
 | |
|         # Set Class {vendor,family,device}
 | |
|         if ($cmd eq 'device-vendor'){
 | |
|             $vendor = $value;
 | |
|             $family = $model = undef;
 | |
|             $Matrix->{$vendor} = {} unless defined $Matrix->{$vendor};
 | |
|             $class = $Matrix->{$vendor};
 | |
|             $class->{defaults}->{type}='vendor';
 | |
|             next;
 | |
|         }
 | |
| 
 | |
|         if ($cmd eq 'device-family'){
 | |
|             $family = $value;
 | |
|             $model = undef;
 | |
|             print "$family has no vendor.\n" unless defined $vendor;
 | |
|             $Matrix->{$vendor}->{families}->{$family} = {}
 | |
|                 unless defined $Matrix->{$vendor}->{families}->{$family};
 | |
|             $class = $Matrix->{$vendor}->{families}->{$family};
 | |
|             $class->{defaults}->{type}='family';
 | |
|             next;
 | |
|         }
 | |
| 
 | |
|         if ($cmd eq 'device') {
 | |
|             $model = $value;
 | |
|             print "$model has no family.\n" unless defined $family;
 | |
|             print "$model has no vendor.\n" unless defined $vendor;
 | |
|             $Matrix->{$vendor}->{families}->{$family}->{models}->{$model} = {}
 | |
|                 unless defined $Matrix->{$vendor}->{families}->{$family}->{models}->{$model};
 | |
|             $class = $Matrix->{$vendor}->{families}->{$family}->{models}->{$model};
 | |
|             $class->{defaults}->{type}='device';
 | |
|             next;
 | |
|         }
 | |
| 
 | |
|         # Store attribute
 | |
|         push (@{$class->{defaults}->{$cmd}} , $value);
 | |
|         $Attributes->{$cmd}++;
 | |
|     }
 | |
| 
 | |
|     return $Matrix;
 | |
| }
 | |
| 
 | |
| sub sort_nocase {
 | |
|     return lc($a) cmp lc($b);
 | |
| }
 | |
| 
 | |
| sub print_notes {
 | |
|     my $defaults = shift;
 | |
|     my $level    = shift;
 | |
|     my $notes    = $defaults->{note} || [];
 | |
|     foreach my $note (@$notes){
 | |
|         if ($note =~ s/^!//){
 | |
|             $note = '<SPAN CLASS="note">' . $note . '</SPAN>';
 | |
|         }
 | |
|     }
 | |
|     if (scalar @$notes){
 | |
|         print "<DT>\n";
 | |
|         my $print_note = join("\n<LI>",@$notes);
 | |
|         print "<UL TYPE='square'><LI>$print_note</UL>\n";
 | |
|     }
 | |
| }
 | |
| 
 | |
| sub print_vendors {
 | |
|     my $matrix=shift;
 | |
|     print "<h1>Device Vendors</h1>\n";
 | |
|     foreach my $vendor (sort sort_nocase keys %$matrix){
 | |
|         print "[<A HREF=\"#$vendor\">$vendor</A>]\n";
 | |
|     }
 | |
|     print "<HR>\n";
 | |
| }
 | |
| 
 | |
| sub html_head {
 | |
|     print <<"end_head";
 | |
| <HTML>
 | |
| <HEAD>
 | |
| <TITLE>SNMP::Info - Device Compatibility Matrix</TITLE>
 | |
| <STYLE TYPE="text/css" MEDIA="screen">
 | |
| <!--
 | |
|     BODY    { font-family:arial,helvetica,sans-serif; font-size:12pt; }
 | |
|     TD      { font-family:arial,helvetica,sans-serif; font-size:10pt; }
 | |
|     TH      { font-family:arial,helvetica,sans-serif; font-size:10pt; background:#F0F0F0; }
 | |
|     H1      { font-family:arial,helvetica,sans-serif; font-size:14pt; }
 | |
|     .vendor { font-size:12pt; color:#777777; }
 | |
|     .family { font-size:12pt; color:blue; }
 | |
|     .model  { font-size:12pt; color:red; }
 | |
|     .note   { color:red; }
 | |
| //-->
 | |
| </STYLE>
 | |
| </HEAD>
 | |
| <BODY>
 | |
| <h1>SNMP::Info - Device Compatibility Matrix</h1>
 | |
| <P>
 | |
| end_head
 | |
| }
 | |
| 
 | |
| sub html_tail {
 | |
|     print <<'end_tail';
 | |
| <HR>
 | |
| <h1>Color Key</h1>
 | |
| [<SPAN CLASS="model">Model Attribute</SPAN>]
 | |
| [<SPAN CLASS="family">Family Attribute</SPAN>]
 | |
| [<SPAN CLASS="vendor">Vendor Attribute</SPAN>]
 | |
| <h1>Attribute Key</h1>
 | |
| A value of <B>-</B> signifies the information is not specified and can not
 | |
| be assumed working.
 | |
| <TABLE BORDER=1>
 | |
| <TR>
 | |
|     <TD>Arpnip</TD>
 | |
|     <TD>Ability to collect ARP tables for MAC to IP translation.</TD>
 | |
| </TR>
 | |
| <TR>
 | |
|     <TD>Class</TD>
 | |
|     <TD>SNMP::Info Class the the device currently uses.  Devices using more generic
 | |
|         interfaces like <tt>Layer2</tt> or <tt>Layer3</tt> may eventually get their
 | |
|         own subclass.
 | |
|     </TD>
 | |
| </TR>
 | |
| <TR>
 | |
|     <TD>Duplex</TD>
 | |
|     <TD>Ability to cull duplex settings from device.<BR>
 | |
|         <UL>
 | |
|             <LI><tt>no</tt> - Can't recover current or admin setting.
 | |
|             <LI><tt>link</tt> - Can get current setting only.
 | |
|             <LI><tt>both</tt> - Can get admin and link setting.
 | |
|             <LI><tt>write</tt> - Can get admin and link setting and perform sets.
 | |
|         </UL>
 | |
|     </TD>
 | |
| </TR>
 | |
| <TR>
 | |
|     <TD>Macsuck</TD>
 | |
|     <TD>Ability to get CAM tables for MAC to switch port mapping.<BR>
 | |
|         <UL>
 | |
|             <LI><TT>no</TT> - Have not found an SNMP method to get data yet.
 | |
|             <LI><TT>yes</TT> - Can get through normal SWITCH-MIB method.
 | |
|             <LI><TT>vlan</TT> - Have to re-connect to each VLAN and then fetch with normal
 | |
|         method.
 | |
|         </UL>
 | |
|     </TD>
 | |
| </TR>
 | |
| <TR>
 | |
|     <TD>Modules</TD>
 | |
|     <TD>Ability to gather hardware module information.</TD>
 | |
| </TR>
 | |
| <TR>
 | |
|     <TD>Portmac</TD>
 | |
|     <TD>Whether the device will list the MAC address of the switch port on each
 | |
|         switch port when doing a Macsuck.
 | |
|     </TD>
 | |
| </TR>
 | |
| <TR>
 | |
|     <TD>Topo</TD>
 | |
|     <TD>Ability to get Layer 2 Topology Information from device if the
 | |
|         protocol is enabled.  SNMP::Info supports querying Link Layer
 | |
|         Discovery Protocol (LLDP), Cisco Discovery Protocol (CDP),
 | |
|         SynOptics/Bay/Nortel/Avaya Network Management Protocol (SONMP),
 | |
|         Foundry/Brocade Discovery Protocol (FDP), Extreme Discovery
 | |
|         Protocol (EDP), and Alcatel Mapping Adjacency Protocol (AMAP).
 | |
|     </TD>
 | |
| </TR>
 | |
| <TR>
 | |
|     <TD>Ver</TD>
 | |
|     <TD>SNMP Protocol Version the device has to use.</TD>
 | |
| </TR>
 | |
| <TR>
 | |
|     <TD>Vlan</TD>
 | |
|     <TD>Ability to get VLAN port assignments.<BR>
 | |
|         <UL>
 | |
|             <LI><TT>no</TT> - Have not found an SNMP method to get data yet.
 | |
|             <LI><TT>yes</TT> - Can read information.
 | |
|             <LI><TT>write</TT> - Can read and write (set).
 | |
|         </UL>
 | |
|     </TD>
 | |
| </TR>
 | |
| </TABLE>
 | |
| </BODY>
 | |
| </HTML>
 | |
| end_tail
 | |
| 
 | |
| }
 | |
| 
 | |
| sub print_headers {
 | |
|     print "<TR>\n";
 | |
|     foreach my $a (sort sort_nocase keys %$Attributes) {
 | |
|         next if $a eq 'note';
 | |
|         print "  <TH>$a</TH>\n";
 | |
|     }
 | |
|     print "</TR>\n";
 | |
| }
 |