rename upgrade file to include switch model N1148T-ON
[dell-switch] / neighbours.pl
1 #!/usr/bin/perl
2 use warnings;
3 use strict;
4 use autodie;
5
6 # ./sw-name-mac.sh
7 # ./sw-names | xargs -i ./dell-switch.pl {} 'show lldp neighbors'
8 # /home/dpavlin/mikrotik-switch/m-neighbour
9
10 use Data::Dump qw(dump);
11
12 my $debug = $ENV{DEBUG} || 0;
13
14 my $mac2name;
15
16 open(my $f, '<'. '/dev/shm/sw-name-mac');
17 while(<$f>) {
18         chomp;
19         #my ( $ip, $name, $mac ) = split(/ /,$_);
20         my ( $name, $mac ) = split(/ /,$_);
21         $mac = lc($mac);
22         if ( defined $mac2name->{$mac} ) {
23                 if ( $mac2name->{$mac} ne $name ) {
24                         warn "ERROR: GOT $mac with $mac2name->{$mac} and now trying to overwrite it with $name\n";
25                 }
26         } else {
27                 $mac2name->{$mac} = $name;
28         }
29 }
30
31 sub mac2name {
32         my ( $mac, $name ) = @_;
33
34         $mac = lc($mac);
35
36         if ( exists $mac2name->{$mac} ) {
37                 my $mac_name = $mac2name->{$mac};
38                 warn "ERROR: name different $name != $mac_name" if $name && $name ne $mac_name;
39                 return ( $mac, $mac_name );
40         }
41         return ( $mac, $name );
42 }
43
44 warn "# mac2name = ",dump($mac2name) if $debug;
45
46 open(my $n_fh, '>', '/dev/shm/neighbors.tab');
47 open(my $html_fh, '>', '/var/www/neighbors.html');
48 print $html_fh qq{<table>\n};
49
50 # parse Dell switch lldp neighbors output
51
52 foreach my $file ( glob('log/*lldp*') ) {
53         my ( undef, $name, undef ) = split(/_/, $file);
54         print "# $name $file\n" if $debug;
55
56         my $line_regex;
57         my @ports;
58
59         open(my $f, '<', $file);
60         while(<$f>) {
61                 chomp;
62                 #print "## $_<--\n";
63                 next if ( /^$/ || /^\s+Port/ );
64                 if ( /^--+/ ) {
65                         $line_regex = $_;
66                         $line_regex =~ s/\s+$//;
67                         $line_regex =~ s/-/./g;
68                         $line_regex =~ s/^/(/g;
69                         $line_regex =~ s/ /) (/g;
70                         $line_regex =~ s/$/)/g;
71
72                         if ( $file =~ m/remote-device/ ) {
73                                 $line_regex =~ s{\) \(}{.)(}g;
74                                 $line_regex =~ s{\(\.+\)$}{(.+)}g;
75                         }
76
77                         print "## line_regex = $line_regex\n" if $debug;
78                         next;
79                 }
80
81                 s{^\s+}{} if $file =~ m/remote-device/; # remote left-over from pager
82
83                 my @v;
84
85                 if ( defined($line_regex) &&  /$line_regex/ ) {
86                         # port, mac, remote_port, system_name, capabilities
87                         @v = ( $1, $2, $3, $4, $5 );
88
89                         if ( $file =~ m/neighbors/ ) {
90
91                                 # show lldp neighbours
92                                 # Port       Device ID          Port ID          System Name     Capabilities 
93
94                         } elsif ( $file =~ m/remote-device/ ) {
95
96                                 # show lldp remote-device all
97                                 # Interface RemID   Chassis ID          Port ID           System Name
98
99                                 @v = ( $v[0], $v[2], $v[3], $v[4], '' );
100
101                                 # move overflow numbers from system name to port id
102                                 if ( $v[3] =~ s{^(\d+)}{} ) {
103                                         $v[2] .= $1;
104                                 }
105
106                         } else {
107                                 die "don't know how to parse $file";
108                         }
109                 } elsif ( defined($line_regex) && $file =~ m/remote-device/ ) {
110                         # if we don't have system name, line_regex is too long
111                         my @s = split(/\s+/,$_);
112                         @v = ( $s[0], $s[2], $s[3], '', '' ) if $#s == 3;
113                 } elsif ( $debug ) {
114                         my $l = $line_regex;
115                         $l =~ s{[\(\)]}{}g;
116                         print "# [$_]<-- LINE IGNORED\n# [$l]\n",dump($_);
117                 }
118
119                 if (@v) {
120                         print "# [$_] ",join('|',@v),$/ if $debug;
121
122                         @v = map { s/^\s+//; s/\s+$//; $_ } @v;
123
124                         if ( length($v[1]) == 6 ) { # decode text mac
125                                 $v[1] = unpack('H*', $v[1]);
126                                 $v[1] =~ s/(..)/$1:/g;
127                                 $v[1] =~ s/:$//;
128                         }
129
130                         ( $v[1], $v[3] ) = mac2name( $v[1], $v[3] );
131
132
133                         #my ( $port, $device_id, $port_id, $system_name, $cap ) = @v;
134                         if ( @ports && $v[0] =~ m/^$/ ) {
135                                 my @old = @{ pop @ports };
136                                 foreach my $i ( 0 .. $#old ) {
137                                         $old[$i] .= $v[$i];
138                                 }
139                                 push @ports, [ @old ];
140                         } else {
141                                 push @ports, [ @v ];
142                         }
143                 } else {
144                         if ( $debug ) {
145                                 my $l = $line_regex;
146                                 $l =~ s{[\(\)]}{}g;
147                                 print "# [$_]<-- IGNORED no v\n# [$l]\n";
148                         }
149                 }
150         }
151
152         foreach my $p ( @ports ) {
153                 next if ( $p->[1] eq lc($p->[2]) && $p->[3] eq '' ); # FIXME hosts?
154                 print "$name ", join(' | ', @$p ), "\n";
155                 print $n_fh "$name\t", join("\t", @$p ), "\n";
156                 print $html_fh "<tr><td>$name</td><td>", join("</td><td>", @$p ), "</td></tr>\n";
157         }
158 }
159
160 # prase MikroTik /ip neighbor print detail terse
161
162 foreach my $file ( glob('../mikrotik-switch/out/*neighbor*'), glob('../tilera/out/*neighbor*') ) {
163         my $name = $1 if $file =~ m{out/([\w\-]+)\.ip neighbor};
164         print "## [$name] file $file\n" if $debug;
165         open(my $f, '<', $file);
166         while(<$f>) {
167                 chomp;
168                 next if m/^\s*$/;
169                 s{^\s*\d+\s+}{}; # remote ordinal number
170                 print "# $_\n" if $debug;
171                 my $l;
172                 foreach my $kv ( split(/ /, $_) ) {
173                         my ($k,$v) = split(/=/, $kv);
174                         $l->{$k} = $v if ( defined($v) && $v ne '""' );
175                 }
176
177                 no warnings 'uninitialized';
178
179                 #warn "## l=",dump($l),$/;
180                 # Port       Device ID          Port ID          System Name     Capabilities 
181                 my @v = (
182                         $l->{interface},
183                         $l->{'mac-address'},
184                         $l->{'interface-name'},
185                         $l->{'identity'},
186                         #$l->{caps},
187                         join(' ', $l->{address}, $l->{platform}, $l->{board}, $l->{version} ),
188                 );
189
190                 ( $v[1], $v[3] ) = mac2name( $v[1], $v[3] );
191
192                 print "$name ", join(' | ', @v), $/;
193                 print $n_fh "$name\t", join("\t", @v ), "\n";
194                 print $html_fh "<tr><td>$name</td><td>", join("</td><td>", @v ), "</td></tr>\n";
195         }
196 }
197
198 print $html_fh qq{</table>\n};