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