1package App::Netdisco::SSHCollector::Platform::VOSS; 2 3=head1 NAME 4 5App::Netdisco::SSHCollector::Platform::VOSS 6 7=head1 DESCRIPTION 8 9Collect ARP entries from Extreme VSP devices running the VOSS operating system. 10 11This is useful if running multiple VRFs as the built-in SNMP ARP collection will only fetch from the default GlobalRouter VRF. 12 13By default this module gets ARP entries from all VRFs (0-512). To specify only certain VRFs in the config: 14 15 device_auth: 16 - tag: sshvsp 17 driver: cli 18 platform: VOSS 19 only: 20 - 10.1.1.1 21 - 192.168.0.1 22 username: oliver 23 password: letmein 24 vrfs: 1,5,100 25 26The VRFs can be specified in any format that the "show ip arp vrfids" command will take. For example: 27 28 1,2,3,4,5,10 29 1-5,10 30 1-100 31 99 32 33=cut 34 35use strict; 36use warnings; 37 38use Dancer ':script'; 39use Expect; 40use Moo; 41 42=head1 PUBLIC METHODS 43 44=over 4 45 46=item B<arpnip($host, $ssh)> 47 48Retrieve ARP entries from device. C<$host> is the hostname or IP address 49of the device. C<$ssh> is a Net::OpenSSH connection to the device. 50 51Returns a list of hashrefs in the format C<{ mac =E<gt> MACADDR, ip =E<gt> IPADDR }>. 52 53=back 54 55=cut 56 57sub arpnip { 58 my ($self, $hostlabel, $ssh, $args) = @_; 59 60 debug "$hostlabel $$ arpnip()"; 61 62 # default to entire range of VRFs 63 my $vrflist = "0-512"; 64 # if specified in config, only get ARP from certain VRFs 65 if ($args->{vrfs}) { 66 if ($args->{vrfs} =~ m/^[0-9,\-]+$/) { 67 $vrflist = $args->{vrfs}; 68 } 69 } 70 71 my ($pty, $pid) = $ssh->open2pty; 72 unless ($pty) { 73 debug "unable to run remote command [$hostlabel] " . $ssh->error; 74 return (); 75 } 76 my $expect = Expect->init($pty); 77 78 my ($pos, $error, $match, $before, $after); 79 my $prompt; 80 81 $prompt = qr/>/; 82 ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt); 83 84 $expect->send("terminal more disable\n"); 85 ($pos, $error, $match, $before, $after) = $expect->expect(5, -re, $prompt); 86 87 if ($before =~ m/% Invalid input detected/) { 88 debug "invalid command [$hostlabel]"; 89 return (); 90 } 91 92 $expect->send("show ip arp vrfids $vrflist\n"); 93 ($pos, $error, $match, $before, $after) = $expect->expect(60, -re, $prompt); 94 my @lines = split(m/\n/, $before); 95 96 if ($before =~ m/% Invalid input detected/) { 97 debug "invalid command [$hostlabel]"; 98 return (); 99 } 100 101 if ($before =~ m/Error : ([^\n]+)/) { 102 my $errormsg = $1; 103 if ($errormsg =~ m/Invalid VRF ID/ || $errormsg =~ m/vrfId should be/) { 104 debug "incorrect VRF specified [$hostlabel] : $vrflist : $errormsg"; 105 return (); 106 } 107 else { 108 debug "general error fetching ARP [$hostlabel] : $errormsg"; 109 return (); 110 } 111 } 112 113 my @arpentries; 114 115 my $ipregex = '(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'; 116 my $macregex = '([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}'; 117 118 # IP Address MAC Address VLAN Port Type TTL Tunnel 119 # 172.16.20.15 0024.b269.867d 100 1/1 DYNAMIC 999 device-name 120 foreach my $line (@lines) { 121 next unless $line =~ m/^\s*$ipregex\s+$macregex/; 122 my @fields = split m/\s+/, $line; 123 124 debug "[$hostlabel] arpnip - mac $fields[1] ip $fields[0]"; 125 push @arpentries, { mac => $fields[1], ip => $fields[0] }; 126 } 127 128 $expect->send("exit\n"); 129 $expect->soft_close(); 130 131 return @arpentries; 132} 133 1341; 135