show all roots, use log git repository
[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 use lib 'lib';
21 use name2mac;
22 my $mac2name = $name2mac::mac2name;
23 warn "# mac2name = ",dump($mac2name); # if $debug;
24
25 sub mac2name {
26         my ( $mac, $name ) = @_;
27         return unless defined $mac;
28
29
30         $mac = lc($mac);
31
32         if ( exists $mac2name->{$mac} ) {
33                 my $mac_name = $mac2name->{$mac};
34                 warn "ERROR: name different $name != $mac_name" if $name && $name ne $mac_name;
35                 return ( $mac, $mac_name );
36         }
37         return ( $mac, $name );
38 }
39
40 open(my $n_fh, '>', '/dev/shm/neighbors.tab');
41 open(my $html_fh, '>', '/var/www/neighbors.html');
42 print $html_fh qq{<table>\n};
43
44 # parse Dell switch lldp neighbors output
45
46 foreach my $file ( glob('log/*lldp*') ) {
47         my ( undef, $name, undef ) = split(/_/, $file);
48         print "# $name $file\n" if $debug;
49
50         my $line_regex;
51         my @ports;
52
53         open(my $f, '<', $file);
54         while(<$f>) {
55                 chomp;
56                 #print "## $_<--\n";
57                 next if ( /^$/ || /^\s+Port/ );
58                 if ( /^--+/ ) {
59                         $line_regex = $_;
60                         $line_regex =~ s/\s+$//;
61                         $line_regex =~ s/-/./g;
62                         $line_regex =~ s/^/(/g;
63                         $line_regex =~ s/ /) (/g;
64                         $line_regex =~ s/$/)/g;
65
66                         if ( $file =~ m/remote-device/ ) {
67                                 $line_regex =~ s{\) \(}{.)(}g;
68                                 $line_regex =~ s{\(\.+\)$}{(.+)}g;
69                         }
70
71                         print "## line_regex = $line_regex\n" if $debug;
72                         next;
73                 }
74
75                 s{^\s+}{} if $file =~ m/remote-device/; # remote left-over from pager
76
77                 my @v;
78
79                 if ( defined($line_regex) &&  /$line_regex/ ) {
80                         # port, mac, remote_port, system_name, capabilities
81                         @v = ( $1, $2, $3, $4, $5 );
82
83                         if ( $file =~ m/neighbors/ ) {
84
85                                 # show lldp neighbours
86                                 # Port       Device ID          Port ID          System Name     Capabilities 
87
88                         } elsif ( $file =~ m/remote-device/ ) {
89
90                                 # show lldp remote-device all
91                                 # Interface RemID   Chassis ID          Port ID           System Name
92
93                                 @v = ( $v[0], $v[2], $v[3], $v[4], '' );
94
95                                 # move overflow numbers from system name to port id
96                                 if ( $v[3] =~ s{^(\d+)}{} ) {
97                                         $v[2] .= $1;
98                                 }
99
100                         } else {
101                                 die "don't know how to parse $file";
102                         }
103                 } elsif ( defined($line_regex) && $file =~ m/remote-device/ ) {
104                         # if we don't have system name, line_regex is too long
105                         my @s = split(/\s+/,$_);
106                         @v = ( $s[0], $s[2], $s[3], '', '' ) if $#s == 3;
107                 } elsif ( $debug ) {
108                         my $l = $line_regex;
109                         $l =~ s{[\(\)]}{}g;
110                         print "# [$_]<-- LINE IGNORED\n# [$l]\n",dump($_);
111                 }
112
113                 if (@v) {
114                         print "# [$_] ",join('|',@v),$/ if $debug;
115
116                         @v = map { s/^\s+//; s/\s+$//; $_ } @v;
117
118                         if ( length($v[1]) == 6 ) { # decode text mac
119                                 $v[1] = unpack('H*', $v[1]);
120                                 $v[1] =~ s/(..)/$1:/g;
121                                 $v[1] =~ s/:$//;
122                         }
123
124                         ( $v[1], $v[3] ) = mac2name( $v[1], $v[3] );
125
126
127                         #my ( $port, $device_id, $port_id, $system_name, $cap ) = @v;
128                         if ( @ports && $v[0] =~ m/^$/ ) {
129                                 my @old = @{ pop @ports };
130                                 foreach my $i ( 0 .. $#old ) {
131                                         $old[$i] .= $v[$i];
132                                 }
133                                 push @ports, [ @old ];
134                         } else {
135                                 push @ports, [ @v ];
136                         }
137                 } else {
138                         if ( $debug ) {
139                                 my $l = $line_regex;
140                                 $l =~ s{[\(\)]}{}g;
141                                 print "# [$_]<-- IGNORED no v\n# [$l]\n";
142                         }
143                 }
144         }
145
146         foreach my $p ( @ports ) {
147                 next if ( $p->[1] eq lc($p->[2]) && $p->[3] eq '' ); # FIXME hosts?
148                 print "$name ", join(' | ', @$p ), "\n";
149                 print $n_fh "$name\t", join("\t", @$p ), "\n";
150                 print $html_fh "<tr><td>$name</td><td>", join("</td><td>", @$p ), "</td></tr>\n";
151         }
152 }
153
154 # prase MikroTik /ip neighbor print detail terse
155
156 my $patt = 'ip neighbor print detail terse';
157 $patt =~ s{\s}{\\ }g; # escape spaces
158 my @files = ( map { $_ . '/*' . $patt } qw( ../mikrotik-switch/out/ ../tilera/out/ ));
159 @files = map { glob $_ } @files;
160 warn "XXX $patt files=",dump(\@files) if $debug;
161
162 foreach my $file ( @files ) {
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};
199
200 close($n_fh);
201 #system "git -C /dev/shm/ commit -m neighbors.tab neighbors.tab";