better ports layout, now by default
[dell-switch] / snmp-topology.pl
index 744cf20..751dc1d 100755 (executable)
@@ -53,9 +53,22 @@ foreach my $file ( @dumps ) {
 
 open(my $fh, '>', '/dev/shm/mac2sw');
 foreach my $mac ( keys %{ $stat->{_mac2sw} } ) {
-       print $fh $mac, " ", macfmt( $stat->{_mac2sw}->{$mac} ), "\n";
+       print $fh macfmt($mac), " ", $stat->{_mac2sw}->{$mac}, "\n";
 };
 
+# XXX inject additional mac in filter to include wap devices
+my $mac_include = '/dev/shm/mac.wap';
+if ( -e $mac_include ) {
+       open(my $fh, '<', $mac_include);
+       while(<$fh>) {
+               chomp;
+               my ($mac,$host) = split(/\s+/,$_,2);
+               $mac =~ s/^0//; $mac =~ s/:0/:/g; # mungle mac to snmp format without leading zeros
+               $stat->{_mac2sw}->{$mac} = $host;
+       }
+       warn "# $mac_include added to _mac2sw = ",dump($stat->{_mac2sw}),$/;
+}
+
 my $s = $stat->{_sw_mac_port_vlan};
 foreach my $sw ( keys %$s ) {
        foreach my $mac ( keys %{ $s->{$sw} } ) {
@@ -71,8 +84,6 @@ foreach my $sw ( keys %$s ) {
 
 warn "# _sw_port_sw = ",dump($stat->{_sw_port_sw});
 
-open(my $dot, '>', '/tmp/snmp-topology.dot');
-print $dot "digraph topology {\n";
 
 my $s = $stat->{_sw_port_sw};
 our $later;
@@ -111,6 +122,7 @@ foreach my $sw ( sort keys %$s ) {
        foreach my $port ( @ports ) {
                warn "## $sw $port => ",join(' ', @{$s->{$sw}->{$port}}),$/;
        }
+
        if ( $#ports == 0 ) {
                my $port = $ports[0];
                #print "$sw $port TRUNK\n";
@@ -118,8 +130,10 @@ foreach my $sw ( sort keys %$s ) {
                #warn "## _trunk = ",dump( $stat->{_trunk} ).$/;
 
                my @visible = uniq_visible( @{ $s->{$sw}->{$port} } );
-               to_later( $sw, $port, @visible );
-               next;
+               if ( $#visible > 0 ) {
+                       to_later( $sw, $port, @visible );
+                       next;
+               }
        }
 
        foreach my $port ( @ports ) {
@@ -129,7 +143,6 @@ foreach my $sw ( sort keys %$s ) {
                if ( $#visible == 0 ) {
                        warn "++++ $sw $port $visible[0]\n";
                        #print "$sw $port $visible[0]\n";
-                       print $dot qq{ "$sw" -> "$visible[0]" [ label="$port" ];\n};
                        $stat->{_found}->{$visible[0]} = "$sw $port";
                
                } elsif ( @visible ) {
@@ -143,9 +156,17 @@ foreach my $sw ( sort keys %$s ) {
 }
 
 warn "NEXT later = ",dump($later),$/;
-$s = $later;
+#$s = $later;
+
+# remove all found
+$s = {};
+foreach my $sw ( keys %$later ) {
+       foreach my $port ( keys %{ $later->{$sw} } ) {
+               $s->{$sw}->{$port} = [ uniq_visible( @{ $later->{$sw}->{$port} } ) ];
+       }
+}
 
-my $d = dump($later);
+my $d = dump($s);
 if ( $d eq $last_later ) {
        warn "FIXME later didn't change, last\n";
        last;
@@ -156,11 +177,58 @@ $later = undef;
 
 } # while
 
-print $dot "}\n";
-
 warn "FINAL _found = ",dump( $stat->{_found} ),$/;
 warn "FINAL _trunk = ",dump( $stat->{_trunk} ),$/;
 
-foreach my $sw ( keys %{ $stat->{_found} } ) {
-       printf "%s -> %s %s\n", $stat->{_found}->{$sw}, $sw, uniq(@{ $stat->{_trunk}->{$sw} });
+
+my $node;
+my @edges;
+
+my $ports = $ENV{PORTS} || 1; # FIXME
+
+
+open(my $dot, '>', '/tmp/snmp-topology.dot');
+
+my $shape = $ports ? 'record' : 'ellipse';
+my $rankdir = 'LR'; #$ports ? 'TB' : 'LR';
+print $dot <<"__DOT__";
+digraph topology {
+graph [ rankdir = $rankdir ]
+node [ shape = $shape ]
+edge [ color = "gray" ]
+__DOT__
+
+foreach my $to_sw ( keys %{ $stat->{_found} } ) {
+       my ($from_sw, $from_port) = split(/ /,$stat->{_found}->{$to_sw},2);
+       my @to_port = uniq(@{ $stat->{_trunk}->{$to_sw} });
+       my $to_port = $to_port[0];
+       warn "ERROR: $to_sw has ",dump(\@to_port), " ports instead of just one!" if $#to_port > 0;
+       printf "%s %s -> %s %s\n", $from_sw, $from_port, $to_sw, $to_port;
+       push @edges, [ $from_sw, $to_sw, $from_port, $to_port ];
+       push @{ $node->{$from_sw} }, [ $from_port, $to_sw ];
+       push @{ $node->{$to_sw} }, [ $to_port, $from_sw ]
 }
+
+warn "# edges = ",dump(\@edges);
+warn "# node = ",dump($node);
+
+if ( $ports ) {
+       foreach my $n ( keys %$node ) {
+               my @port_sw =
+                       sort { $a->[0] <=> $b->[0] }
+                       @{ $node->{$n} };
+#warn "XXX $n ",dump( \@port_sw );
+               print $dot qq!"$n" [ label="!.uc($n).'|' . join('|', map { sprintf "<%d>%2d %s", $_->[0], $_->[0], $_->[1] } @port_sw ) . qq!" ];\n!;
+       }
+}
+
+foreach my $e ( @edges ) {
+       if (! $ports) {
+               print $dot sprintf qq{ "%s" -> "%s" [ taillabel="%s" ; headlabel="%s" ]\n}, @$e;
+       } else {
+               print $dot sprintf qq{ "%s":%d -> "%s":%d\n}, $e->[0], $e->[2], $e->[1], $e->[3];
+       }
+}
+
+print $dot "}\n";
+