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";
|
|
}
|