diff --git a/Build.PL b/Build.PL index d80d5b32..5e4abb29 100644 --- a/Build.PL +++ b/Build.PL @@ -66,7 +66,7 @@ Module::Build->new( 'Starman' => '0.4008', 'Storable' => '0', 'Sys::SigAction' => '0', - 'SNMP::Info' => '3.40', + 'SNMP::Info' => '3.42', 'SQL::Translator' => '0.11018', 'Template' => '2.24', 'Template::Plugin::CSV' => '0.04', diff --git a/Changes b/Changes index 4d63c064..1c032c92 100644 --- a/Changes +++ b/Changes @@ -1,3 +1,9 @@ +2.039001 - 2018-02-02 + + [ENHANCEMENTS] + + * #47 gather IPv6 Interface Addresses + 2.039000 - 2018-02-02 [NEW FEATURES] diff --git a/lib/App/Netdisco/Worker/Plugin/Discover/Properties.pm b/lib/App/Netdisco/Worker/Plugin/Discover/Properties.pm index f1b9384b..d71807a7 100644 --- a/lib/App/Netdisco/Worker/Plugin/Discover/Properties.pm +++ b/lib/App/Netdisco/Worker/Plugin/Discover/Properties.pm @@ -21,47 +21,9 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub { my $snmp = App::Netdisco::Transport::SNMP->reader_for($device) or return Status->defer("discover failed: could not SNMP connect to $device"); - my $ip_index = $snmp->ip_index; - my $interfaces = $snmp->interfaces; - my $ip_netmask = $snmp->ip_netmask; - - # Get IP Table per VRF if supported - my @vrf_list = _get_vrf_list($device, $snmp); - if (scalar @vrf_list) { - my $guard = guard { snmp_comm_reindex($snmp, $device, 0) }; - foreach my $vrf (@vrf_list) { - snmp_comm_reindex($snmp, $device, $vrf); - $ip_index = { %$ip_index, %{$snmp->ip_index} }; - $interfaces = { %$interfaces, %{$snmp->interfaces} }; - $ip_netmask = { %$ip_netmask, %{$snmp->ip_netmask} }; - } - } - - # build device aliases suitable for DBIC - my @aliases; - foreach my $entry (keys %$ip_index) { - my $ip = NetAddr::IP::Lite->new($entry) - or next; - my $addr = $ip->addr; - - next if $addr eq '0.0.0.0'; - next if check_acl_no($ip, 'group:__LOCAL_ADDRESSES__'); - next if setting('ignore_private_nets') and $ip->is_rfc1918; - - my $iid = $ip_index->{$addr}; - my $port = $interfaces->{$iid}; - my $subnet = $ip_netmask->{$addr} - ? NetAddr::IP::Lite->new($addr, $ip_netmask->{$addr})->network->cidr - : undef; - - debug sprintf ' [%s] device - aliased as %s', $device->ip, $addr; - push @aliases, { - alias => $addr, - port => $port, - subnet => $subnet, - dns => undef, - }; - } + my @aliases = (); + push @aliases, _get_ipv4_aliases($device, $snmp); + push @aliases, _get_ipv6_aliases($device, $snmp); debug sprintf ' resolving %d aliases with max %d outstanding requests', scalar @aliases, $ENV{'PERL_ANYEVENT_MAX_OUTSTANDING_DNS'}; @@ -276,4 +238,103 @@ sub _get_vrf_list { return @ok_vrfs; } +sub _get_ipv4_aliases { + my ($device, $snmp) = @_; + my @aliases; + + my $ip_index = $snmp->ip_index; + my $interfaces = $snmp->interfaces; + my $ip_netmask = $snmp->ip_netmask; + + # Get IP Table per VRF if supported + my @vrf_list = _get_vrf_list($device, $snmp); + if (scalar @vrf_list) { + my $guard = guard { snmp_comm_reindex($snmp, $device, 0) }; + foreach my $vrf (@vrf_list) { + snmp_comm_reindex($snmp, $device, $vrf); + $ip_index = { %$ip_index, %{$snmp->ip_index} }; + $interfaces = { %$interfaces, %{$snmp->interfaces} }; + $ip_netmask = { %$ip_netmask, %{$snmp->ip_netmask} }; + } + } + + # build device aliases suitable for DBIC + foreach my $entry (keys %$ip_index) { + my $ip = NetAddr::IP::Lite->new($entry) + or next; + my $addr = $ip->addr; + + next if $addr eq '0.0.0.0'; + next if check_acl_no($ip, 'group:__LOCAL_ADDRESSES__'); + next if setting('ignore_private_nets') and $ip->is_rfc1918; + + my $iid = $ip_index->{$addr}; + my $port = $interfaces->{$iid}; + my $subnet = $ip_netmask->{$addr} + ? NetAddr::IP::Lite->new($addr, $ip_netmask->{$addr})->network->cidr + : undef; + + debug sprintf ' [%s] device - aliased as %s', $device->ip, $addr; + push @aliases, { + alias => $addr, + port => $port, + subnet => $subnet, + dns => undef, + }; + } + + return @aliases; +} + +sub _get_ipv6_aliases { + my ($device, $snmp) = @_; + my @aliases; + + my $ipv6_index = $snmp->ipv6_index; + my $ipv6_addr = $snmp->ipv6_addr; + my $ipv6_type = $snmp->ipv6_type; + my $ipv6_pfxlen = $snmp->ipv6_addr_prefixlength; + my $interfaces = $snmp->interfaces; + + # Get IP Table per VRF if supported + my @vrf_list = _get_vrf_list($device, $snmp); + if (scalar @vrf_list) { + my $guard = guard { snmp_comm_reindex($snmp, $device, 0) }; + foreach my $vrf (@vrf_list) { + snmp_comm_reindex($snmp, $device, $vrf); + $ipv6_index = { %$ipv6_index, %{$snmp->ipv6_index} }; + $ipv6_addr = { %$ipv6_addr, %{$snmp->ipv6_addr} }; + $ipv6_type = { %$ipv6_type, %{$snmp->ipv6_type} }; + $ipv6_pfxlen = { %$ipv6_pfxlen, %{$snmp->ipv6_addr_prefixlength} }; + $interfaces = { %$interfaces, %{$snmp->interfaces} }; + } + } + + # build device aliases suitable for DBIC + foreach my $iid (keys %$ipv6_index) { + next unless $ipv6_type->{$iid} and $ipv6_type->{$iid} eq 'unicast'; + my $entry = $ipv6_addr->{$iid} or next; + my $ip = NetAddr::IP::Lite->new($entry) or next; + my $addr = $ip->addr; + + next if $addr eq '::0'; + next if check_acl_no($ip, 'group:__LOCAL_ADDRESSES__'); + + my $port = $interfaces->{ $ipv6_index->{$iid} }; + my $subnet = $ipv6_pfxlen->{$iid} + ? NetAddr::IP::Lite->new($addr .'/'. $ipv6_pfxlen->{$iid})->network->cidr + : undef; + + debug sprintf ' [%s] device - aliased as %s', $device->ip, $addr; + push @aliases, { + alias => $addr, + port => $port, + subnet => $subnet, + dns => undef, + }; + } + + return @aliases; +} + true;