diff options
Diffstat (limited to 'extras/tools/lldp/lolwhat.pl')
-rwxr-xr-x | extras/tools/lldp/lolwhat.pl | 126 |
1 files changed, 123 insertions, 3 deletions
diff --git a/extras/tools/lldp/lolwhat.pl b/extras/tools/lldp/lolwhat.pl index 86a5880..64e0140 100755 --- a/extras/tools/lldp/lolwhat.pl +++ b/extras/tools/lldp/lolwhat.pl @@ -38,6 +38,7 @@ my %lldpnamemap = (); my %lldpresolver = (); my %ipmap = (); my %peermap = (); +my %claimedips = (); # tracking for log indentation my $mylogindent = ""; @@ -89,6 +90,35 @@ mylog("Done. Outputting JSON."); print JSON::XS::encode_json(\%result); exit; +sub compare_targets_depth { + my ($t1, $t2) = @_; + my $res = 0; + my $matches = 0; + while (my ($port, $data) = each %{$snmpresults{$t1}{interfaces}}) { + my $one = $data->{ifPhysAddress}; + my $two = $snmpresults{$t2}{interfaces}{$port}{ifPhysAddress}; + if (!defined($one) and !defined($two)) { + next; + } + if ($one ne $two) { + $res++; + } else { + if ($one ne "" and $two ne "") { + if ($one ne "00:00:00:00:00:00") { + $matches++; + } + } + } + } + if ($matches > 10 and $res == 0) { + mylog("$matches interfaces share MAC address. Calling it OK."); + return $res; + } else { + mylog("$res mismatched interfaces versus $matches matched. Not enough for confidence."); + $res++; + } + return $res; +} sub compare_targets { my ($t1, $t2) = @_; my $res = 0; @@ -118,6 +148,19 @@ sub compare_targets { if ($res == 1) { mylog("... So there are two systems that look 50% similar. $bad (But not the other way around)"); } + if ($res != 2) { + mylog("Lacking confidence. Doing in-depth comparison instead"); + logindent(1); + $res = compare_targets_depth($t1, $t2); + if ($res == 0) { + $res = 2; + mylog("Gained confidence. Injecting missing IPs to both canidates."); + logindent(1); + inject_ips($t1, $t2); + logindent(-1); + } + logindent(-1); + } return $res; } # Get raw SNMP data for an ip/community. @@ -145,6 +188,9 @@ sub get_snmp_data { mylog($tmp); return undef; } + if (!defined($ret{sysName})) { + return undef; + } return \%ret; } @@ -201,6 +247,37 @@ sub deduplicate my %remmap = (); my %syscollisions = (); my %locmap = (); + my %okips = (); + mylog("Building inventory of decent results/ips"); + logindent(1); + while (my ($target, $value) = each %snmpresults) { + if (defined($value->{fakeSnmp}) and $value->{fakeSnmp} eq "yes") { + next; + } + if (defined($value->{sysName}) and defined($value->{ips})) { + mylog("Ok: $target"); + foreach my $ip (@{$value->{ips}}) { + $okips{$ip} = 1; + } + } + } + logindent(-1); + mylog("Checking for empty SNMP results that are covered by other results"); + logindent(1); + my @removals = (); + while (my ($target, $value) = each %snmpresults) { + if (defined($value->{fakeSnmp}) and $value->{fakeSnmp} eq "yes") { + if (defined($okips{$target})) { + push @removals,$target; + } + } + } + mylog("Removing " . join(", ", @removals)); + foreach my $removal (@removals) { + delete $snmpresults{$removal}; + } + logindent(-1); + mylog("Checking for duplicated/corrupt chassis ids"); logindent(1); mylog("Building sysname -> chassis id table where possible"); @@ -259,6 +336,7 @@ sub deduplicate next; } elsif (compare_targets($test, $test2) != 2) { mylog("Collision between $test and $test2. Adding to fixlist."); + mylog("a: " . $snmpresults{$test}{sysName} . " b: ". $snmpresults{$test2}{sysName}); $tested{$test}{$test2} = 1; $tested{$test2}{$test} = 1; $fixlist{$test} = 1; @@ -310,6 +388,7 @@ sub deduplicate sub parse_snmp { my $snmp = $_[0]; + my $targetip = $_[1]; my %result = (); my %lol = (); if (!defined($snmp)) { @@ -345,6 +424,9 @@ sub parse_snmp my %caps = (); nms::convert_lldp_caps($value->{'lldpRemSysCapEnabled'}, \%caps); $lol{$idx}{'lldpRemSysCapEnabled'} = \%caps; + my %caps2 = (); + nms::convert_lldp_caps($value->{'lldpRemSysCapSupported'}, \%caps2); + $lol{$idx}{'lldpRemSysCapSupported'} = \%caps2; } logindent(-1); mylog("Parsing lldp neighbors management interfaces"); @@ -444,10 +526,35 @@ sub parse_snmp @{$result{peers}} = sort @{$result{peers}}; @{$result{ips}} = sort @{$result{ips}}; $result{interfaces} = \%lol; + mylog("Ensuring some sanity: Checking if the $targetip is among claimed IPs for the SNMP results"); + logindent(1); + my $sanitytest = 0; + foreach my $ip (@{$result{ips}}) { + if ($ip eq $targetip) { + mylog("Phew, it is..."); + $sanitytest = 1; + } + } + if ($sanitytest == 0) { + mylog("Didn't find myself. Hoping deduplication will take care of it?"); + $result{badSelf} = 1; + } logindent(-1); + mylog("Registering known ips for " . ($sysname || "?" )); + foreach my $ip (@{$result{ips}}) { + $claimedips{$ip} = $sysname || "?"; + } + logindent(-1); + return \%result; } - +sub inject_ips { + my ($t1, $t2) = @_; + push @{$snmpresults{$t1}{ips}}, $t1; + push @{$snmpresults{$t1}{ips}}, $t2; + push @{$snmpresults{$t2}{ips}}, $t1; + push @{$snmpresults{$t2}{ips}}, $t2; +} sub logindent { my $change = $_[0]; if ($change > 0) { @@ -470,8 +577,18 @@ sub probe_sys mylog("Already probed $target. Skipping."); return; } + if (defined($claimedips{$target})) { + mylog("IP claimed by $claimedips{$target}. Skipping."); + return; + } my $snmp = get_snmp_data($target, $community); - my $parsed = parse_snmp($snmp); + if (!defined($snmp)) { + return; + } + my $parsed = parse_snmp($snmp,$target); + if (!defined($parsed)) { + return; + } $snmpresults{$target} = $parsed; } sub populate_lldpmap @@ -484,7 +601,9 @@ sub populate_lldpmap if (!defined($data->{lldpRemSysName})) { next; } else { - $lldpmap{$id}{$data->{lldpRemChassisId}} = 1; + if (defined($id)) { + $lldpmap{$id}{$data->{lldpRemChassisId}} = 1; + } $lldpnamemap{$sysname}{$data->{lldpRemSysName}} = 1; } } @@ -530,6 +649,7 @@ sub pad_snmp_results mylog("Adding basic info for $value->{ip} / $value->{name} to snmp results"); $snmpresults{$value->{ip}}{sysName} = $value->{name}; $snmpresults{$value->{ip}}{lldpLocChassisId} = $value->{id}; + $snmpresults{$value->{ip}}{fakeSnmp} = "yes"; push @{$snmpresults{$value->{ip}}{ips}}, $value->{ip}; } logindent(-1); |