aboutsummaryrefslogtreecommitdiffstats
path: root/extras/tools/lldp
diff options
context:
space:
mode:
Diffstat (limited to 'extras/tools/lldp')
-rwxr-xr-xextras/tools/lldp/lolwhat.pl126
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);