diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm index 5fa1dd8d1c..00f778e9e4 100644 --- a/pandora_server/lib/PandoraFMS/Recon/Base.pm +++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm @@ -42,7 +42,7 @@ use constant { DISCOVERY_DEPLOY_AGENTS => 9, DISCOVERY_APP_SAP => 10, DISCOVERY_APP_DB2 => 11, - DISCOVERY_APP_MICROSOFT_SQL_SERVER => 12, + DISCOVERY_APP_MICROSOFT_SQL_SERVER => 12, DISCOVERY_REVIEW => 0, DISCOVERY_STANDARD => 1, DISCOVERY_RESULTS => 2, @@ -151,6 +151,9 @@ sub new { # Found parents. parents => {}, + # Port counts for each switch. + ports => {}, + # Route cache. routes => [], default_gw => undef, @@ -366,14 +369,17 @@ sub add_iface($$$) { ################################################################################ # Discover connectivity from address forwarding tables. ################################################################################ -sub aft_connectivity($$) { - my ($self, $switch) = @_; +sub aft_connectivity($$$) { + my ($self, $switch, $single_port) = @_; my (%mac_temp, @aft_temp); return unless ($self->is_snmp_discovered($switch)); $self->enable_vlan_cache(); + # Fill port counts if needed. + $self->fill_port_counts($switch); + # Get the address forwarding table (AFT) of each switch. my @aft; foreach my $mac ($self->snmp_get_value_array($switch, $DOT1DTPFDBADDRESS)) { @@ -392,7 +398,7 @@ sub aft_connectivity($$) { $host_if_name = defined($host_if_name) ? $host_if_name : 'Host Alive'; # Get the interface associated to the port were we found the MAC address. - my $switch_if_name = $self->get_if_from_aft($switch, $aft_mac); + my $switch_if_name = $self->get_if_from_aft($switch, $aft_mac, $single_port); next unless defined($switch_if_name) and ($switch_if_name ne ''); # Do not connect a host to a switch twice using the same interface. @@ -771,13 +777,29 @@ sub get_iface($$) { ################################################################################ # Get an interface name from an AFT entry. Returns undef on error. ################################################################################ -sub get_if_from_aft($$$) { - my ($self, $switch, $mac) = @_; +sub get_if_from_aft($$$$) { + my ($self, $switch, $mac, $single_port) = @_; # Get the port associated to the MAC. my $port = $self->snmp_get_value($switch, "$DOT1DTPFDBPORT." . mac_to_dec($mac)); return '' unless defined($port); + # Are we looking for interfaces with a single port entry? + if ($single_port == 1 && + defined($self->{'ports'}->{$switch}) && + defined($self->{'ports'}->{$switch}->{$port}) && + $self->{'ports'}->{$switch}->{$port} > 1) { + return ''; + } + + # Are we looking for interfaces with multiple port entries? + if ($single_port == 0 && + defined($self->{'ports'}->{$switch}) && + defined($self->{'ports'}->{$switch}->{$port}) && + $self->{'ports'}->{$switch}->{$port} <= 1) { + return ''; + } + # Get the interface index associated to the port. my $if_index = $self->snmp_get_value($switch, "$DOT1DBASEPORTIFINDEX.$port"); return '' unless defined($if_index); @@ -936,6 +958,24 @@ sub get_mac_from_ip($$) { $self->call('message', "Found MAC $mac for host $host in the local ARP cache.", 5); } +################################################################################ +# Find out the number of entries for each port on the given switch. +################################################################################ +sub fill_port_counts($$) { + my ($self, $switch) = @_; + + return if (defined($self->{'ports'}->{$switch})); + + # List all the ports. + foreach my $port ($self->snmp_get_value_array($switch, $DOT1DTPFDBPORT)) { + if (!defined($self->{'ports'}->{$switch}->{$port})) { + $self->{'ports'}->{$switch}->{$port} = 1; + } else { + $self->{'ports'}->{$switch}->{$port} += 1; + } + } +} + ################################################################################ # Get a port number from an AFT entry. Returns undef on error. ################################################################################ @@ -1992,11 +2032,20 @@ sub scan($) { $self->call('message', "[2/6] Finding address forwarding table connectivity...", 3); $self->{'c_network_name'} = ''; $self->{'step'} = STEP_AFT; - ($progress, $step) = (50, 10.0 / scalar(@hosts)); # From 50% to 60%. + ($progress, $step) = (50, (10.0 / scalar(@hosts)) / 2.0); # From 50% to 60%. + + # Connect hosts on ports where there are no other hosts. for (my $i = 0; defined($hosts[$i]); $i++) { $self->call('update_progress', $progress); $progress += $step; - $self->aft_connectivity($hosts[$i]); + $self->aft_connectivity($hosts[$i], 1); + } + + # Connect hosts on ports even if they're shared by other hosts. + for (my $i = 0; defined($hosts[$i]); $i++) { + $self->call('update_progress', $progress); + $progress += $step; + $self->aft_connectivity($hosts[$i], 0); } # Connect hosts that are still unconnected using traceroute.