macsuck_unsupported setting to allow node gathering on delinquent switches
This commit is contained in:
@@ -4,6 +4,7 @@ use Dancer qw/:syntax :script/;
|
||||
use Dancer::Plugin::DBIC 'schema';
|
||||
|
||||
use App::Netdisco::Util::PortMAC 'get_port_macs';
|
||||
use App::Netdisco::Util::Device qw/check_device_no match_devicetype/;
|
||||
use App::Netdisco::Util::Node 'check_mac';
|
||||
use App::Netdisco::Util::SNMP 'snmp_comm_reindex';
|
||||
use Time::HiRes 'gettimeofday';
|
||||
@@ -67,7 +68,7 @@ sub do_macsuck {
|
||||
|
||||
# cache the device ports to save hitting the database for many single rows
|
||||
my $device_ports = {map {($_->port => $_)}
|
||||
$device->ports(undef, {prefetch => 'neighbor_alias'})->all};
|
||||
$device->ports(undef, {prefetch => {neighbor_alias => 'device'}})->all};
|
||||
my $port_macs = get_port_macs();
|
||||
my $interfaces = $snmp->interfaces;
|
||||
|
||||
@@ -151,7 +152,8 @@ sub store_node {
|
||||
|
||||
my $old = $nodes->search(
|
||||
{ mac => $mac,
|
||||
vlan => $vlan,
|
||||
# where vlan is unknown, need to archive on all other vlans
|
||||
($vlan ? (vlan => $vlan) : ()),
|
||||
-bool => 'active',
|
||||
-not => {
|
||||
switch => $ip,
|
||||
@@ -361,8 +363,21 @@ sub _walk_fwtable {
|
||||
# * a mac addr is seen which belongs to any device port/interface
|
||||
# * (TODO) admin sets is_uplink_admin on the device_port
|
||||
|
||||
# allow to gather MACs on upstream port for some kinds of device that
|
||||
# do not expose MAC address tables via SNMP. relies on prefetched
|
||||
# neighbors otherwise it would kill the DB with device lookups.
|
||||
my $neigh_cannot_macsuck = eval { # can fail
|
||||
check_device_no($device_port->neighbor, 'macsuck_unsupported') ||
|
||||
match_devicetype($device_port->remote_type, 'macsuck_unsupported_type') };
|
||||
|
||||
if ($device_port->is_uplink) {
|
||||
if (my $neighbor = $device_port->neighbor) {
|
||||
if ($neigh_cannot_macsuck) {
|
||||
debug sprintf
|
||||
' [%s] macsuck %s - port %s neighbor %s without macsuck support',
|
||||
$device->ip, $mac, $port, $device_port->neighbor->ip;
|
||||
# continue!!
|
||||
}
|
||||
elsif (my $neighbor = $device_port->neighbor) {
|
||||
debug sprintf
|
||||
' [%s] macsuck %s - port %s has neighbor %s - skipping.',
|
||||
$device->ip, $mac, $port, $neighbor->ip;
|
||||
@@ -398,6 +413,11 @@ sub _walk_fwtable {
|
||||
$device->ip, $mac, $port;
|
||||
$device_port->update({is_uplink => \'true'});
|
||||
|
||||
# neighbor exists and Netdisco can speak to it, so we don't want
|
||||
# its MAC address. however don't add to skiplist as that would
|
||||
# clear all other MACs on the port.
|
||||
next if $neigh_cannot_macsuck;
|
||||
|
||||
# when there's no CDP/LLDP, we only want to gather macs at the
|
||||
# topology edge, hence skip ports with known device macs.
|
||||
if (not setting('macsuck_bleed')) {
|
||||
|
||||
@@ -237,8 +237,16 @@ database.
|
||||
|
||||
=cut
|
||||
|
||||
__PACKAGE__->has_many( neighbor_alias => 'App::Netdisco::DB::Result::DeviceIp',
|
||||
{ 'foreign.alias' => 'self.remote_ip' },
|
||||
__PACKAGE__->belongs_to( neighbor_alias => 'App::Netdisco::DB::Result::DeviceIp',
|
||||
sub {
|
||||
my $args = shift;
|
||||
return {
|
||||
"$args->{foreign_alias}.ip" => { '=' =>
|
||||
$args->{self_resultsource}->schema->resultset('DeviceIp')
|
||||
->search({alias => { -ident => "$args->{self_alias}.remote_ip"}},
|
||||
{rows => 1, columns => 'ip', alias => 'devipsub'})->as_query }
|
||||
};
|
||||
},
|
||||
{ join_type => 'LEFT' },
|
||||
);
|
||||
|
||||
@@ -289,7 +297,7 @@ the database.
|
||||
|
||||
sub neighbor {
|
||||
my $row = shift;
|
||||
return eval { $row->neighbor_alias->first->device || undef };
|
||||
return eval { $row->neighbor_alias->device || undef };
|
||||
}
|
||||
|
||||
=head1 ADDITIONAL COLUMNS
|
||||
|
||||
@@ -737,6 +737,27 @@ Value: List of "IP:vlan-number" or "IP:vlan-name". Default: Empty List.
|
||||
Similar to C<macsuck_no_vlan>, but allows specifying the device root
|
||||
(canonical) IP, in order to restrict VLAN skipping only to some devices.
|
||||
|
||||
=head3 C<macsuck_unsupported>
|
||||
|
||||
Value: List of Network Identifiers or Device Properties. Default: Empty List.
|
||||
|
||||
Similar to C<macsuck_no>, but instead of skipping nodes on this device, they
|
||||
are allowed to gather on the upstream device port. Useful for devices which
|
||||
can be discovered by Netdisco but do not provide a MAC address table via SNMP.
|
||||
|
||||
=head3 C<macsuck_unsupported_type>
|
||||
|
||||
Value: List of Strings. Default: None.
|
||||
|
||||
Place regular expression patterns here to skip macsuck of certain devices
|
||||
based on the CDP/LLDP device type information they advertise. MAC addresses
|
||||
will be allowed to gather on the upstream device port, as in the
|
||||
C<macscuk_unsupported> setting. For example:
|
||||
|
||||
macsuck_unsupported_type:
|
||||
- 'cisco\s+AIR-LAP'
|
||||
- '(?i)Cisco\s+IP\s+Phone'
|
||||
|
||||
=head3 C<macsuck_bleed>
|
||||
|
||||
Value: Boolean. Default: C<false>.
|
||||
|
||||
@@ -10,6 +10,7 @@ our @EXPORT_OK = qw/
|
||||
get_device
|
||||
delete_device
|
||||
renumber_device
|
||||
match_devicetype
|
||||
check_device_no
|
||||
check_device_only
|
||||
is_discoverable
|
||||
@@ -126,6 +127,21 @@ sub renumber_device {
|
||||
return $happy;
|
||||
}
|
||||
|
||||
=head2 match_devicetype( $type, $setting_name )
|
||||
|
||||
Given a C<$type> (which may be any text value), returns true if any of the
|
||||
list of regular expressions in C<$setting_name> is matched, otherwise returns
|
||||
false.
|
||||
|
||||
=cut
|
||||
|
||||
sub match_devicetype {
|
||||
my ($type, $setting_name) = @_;
|
||||
return 0 unless $type and $setting_name;
|
||||
return (scalar grep {$type =~ m/$_/}
|
||||
@{setting($setting_name) || []});
|
||||
}
|
||||
|
||||
=head2 check_device_no( $ip, $setting_name )
|
||||
|
||||
Given the IP address of a device, returns true if the configuration setting
|
||||
@@ -170,6 +186,8 @@ To match no devices we recommend an entry of "C<localhost>" in the setting.
|
||||
|
||||
sub check_device_no {
|
||||
my ($ip, $setting_name) = @_;
|
||||
|
||||
return 0 unless $ip and $setting_name;
|
||||
my $device = get_device($ip) or return 0;
|
||||
|
||||
my $config = setting($setting_name) || [];
|
||||
@@ -251,10 +269,8 @@ sub is_discoverable {
|
||||
my ($ip, $remote_type) = @_;
|
||||
my $device = get_device($ip) or return 0;
|
||||
|
||||
if ($remote_type) {
|
||||
return _bail_msg("is_discoverable: device matched discover_no_type")
|
||||
if scalar grep {$remote_type =~ m/$_/}
|
||||
@{setting('discover_no_type') || []};
|
||||
if (match_devicetype($remote_type, 'discover_no_type')) {
|
||||
return _bail_msg("is_discoverable: device matched discover_no_type");
|
||||
}
|
||||
|
||||
return _bail_msg("is_discoverable: device matched discover_no")
|
||||
|
||||
Reference in New Issue
Block a user