File Coverage

blib/lib/Cisco/SNMP/ProxyPing.pm
Criterion Covered Total %
statement 21 120 17.5
branch 0 46 0.0
condition 0 19 0.0
subroutine 7 14 50.0
pod 6 6 100.0
total 34 205 16.5


line stmt bran cond sub pod time code
1             package Cisco::SNMP::ProxyPing;
2              
3             ##################################################
4             # AUTHOR = Michael Vincent
5             # www.VinsWorld.com
6             ##################################################
7              
8 1     1   50083 use strict;
  1         14  
  1         29  
9 1     1   4 use warnings;
  1         2  
  1         23  
10              
11 1     1   497 use Net::SNMP qw(:asn1);
  1         71317  
  1         195  
12 1     1   304 use Cisco::SNMP;
  1         2  
  1         52  
13              
14             our $VERSION = $Cisco::SNMP::VERSION;
15              
16             our @ISA = qw(Cisco::SNMP);
17              
18 1     1   6 use Sys::Hostname;
  1         1  
  1         41  
19 1     1   5 use Socket qw(AF_INET);
  1         1  
  1         1020  
20              
21             # use Net::IPv6Addr;
22             my $HAVE_Net_IPv6Addr = 0;
23             if ( $Socket::VERSION >= 1.94 ) {
24 1     1   246 eval "use Net::IPv6Addr 0.2";
  1         31733  
  1         44  
25             if ( !$@ ) {
26             $HAVE_Net_IPv6Addr = 1;
27             }
28             }
29              
30             my $AF_INET6 = eval { Socket::AF_INET6() };
31              
32             ##################################################
33             # Start Public Module
34             ##################################################
35              
36             sub _ppOID {
37 0     0     return '1.3.6.1.4.1.9.9.16.1.1.1';
38             }
39              
40             sub proxy_ping {
41 0     0 1   my $self = shift;
42 0   0       my $class = ref($self) || $self;
43              
44 0           my $session = $self->{_SESSION_};
45              
46 0           my %params = (
47             count => 1,
48             size => 64,
49             wait => 1
50             );
51              
52 0           my %args;
53 0 0         if ( @_ == 1 ) {
54 0           ( $params{host} ) = @_;
55             } else {
56 0           %args = @_;
57 0           for ( keys(%args) ) {
58 0 0 0       if ( (/^-?host(?:name)?$/i) || (/^-?dest(?:ination)?$/i) ) {
    0 0        
    0          
    0          
    0          
    0          
59 0           $params{host} = $args{$_};
60             } elsif (/^-?size$/i) {
61 0 0         if ( $args{$_} =~ /^\d+$/ ) {
62 0           $params{size} = $args{$_};
63             } else {
64 0           $Cisco::SNMP::LASTERROR = "Invalid size `$args{$_}'";
65 0           return undef;
66             }
67             } elsif (/^-?family$/i) {
68 0 0         if ( $args{$_}
69 0           =~ /^(?:(?:(:?ip)?v?(?:4|6))|${\AF_INET}|$AF_INET6)$/ ) {
70 0 0         if ( $args{$_} =~ /^(?:(?:(:?ip)?v?4)|${\AF_INET})$/ ) {
  0            
71 0           $params{family} = AF_INET;
72             } else {
73 0           $params{family} = $AF_INET6;
74             }
75             } else {
76 0           $Cisco::SNMP::LASTERROR = "Invalid family `$args{$_}'";
77 0           return undef;
78             }
79             } elsif (/^-?count$/i) {
80 0 0         if ( $args{$_} =~ /^\d+$/ ) {
81 0           $params{count} = $args{$_};
82             } else {
83 0           $Cisco::SNMP::LASTERROR = "Invalid count `$args{$_}'";
84 0           return undef;
85             }
86             } elsif ( (/^-?wait$/i) || (/^-?timeout$/i) ) {
87 0 0         if ( $args{$_} =~ /^\d+$/ ) {
88 0           $params{wait} = $args{$_};
89             } else {
90 0           $Cisco::SNMP::LASTERROR = "Invalid wait time `$args{$_}'";
91 0           return undef;
92             }
93             } elsif (/^-?vrf(?:name)?$/i) {
94 0           $params{vrf} = $args{$_};
95             }
96             }
97             }
98 0           my $pp;
99 0           $pp->{_params_} = \%params;
100              
101             # host must be defined
102 0 0         if ( not defined $params{host} ) {
103 0           $params{host} = hostname;
104             }
105              
106             # inherit from new()
107 0 0         if ( not defined $params{family} ) {
108 0           $params{family} = $self->{family};
109             }
110              
111             # resolve host our way
112 0 0         if (defined(
113             my $ret = Cisco::SNMP::_resolv( $params{host}, $params{family} )
114             )
115             ) {
116 0           $params{host} = $ret->{addr};
117 0           $params{family} = $ret->{family};
118             } else {
119 0           return undef;
120             }
121              
122 0           my $instance = int( rand(1024) + 1024 );
123              
124             # Prepare object by clearing row
125 0           my $response
126             = $session->set_request( _ppOID() . '.16.' . $instance, INTEGER, 6 );
127 0 0         if ( not defined $response ) {
128 0           $Cisco::SNMP::LASTERROR = "proxy ping NOT SUPPORTED";
129 0           return undef;
130             }
131              
132             # Convert destination to Hex equivalent
133 0           my $dest;
134 0 0         if ( $params{family} == AF_INET ) {
135 0           for ( split( /\./, $params{host} ) ) {
136 0           $dest .= sprintf( "%02x", $_ );
137             }
138             } else {
139 0 0         if ($HAVE_Net_IPv6Addr) {
140 0           my $addr = Net::IPv6Addr->new( $params{host} );
141 0           my @dest = $addr->to_array;
142 0           $dest .= join '', $_ for (@dest);
143             } else {
144 0           $Cisco::SNMP::LASTERROR
145             = "Socket > 1.94 and Net::IPv6Addr required";
146 0           return undef;
147             }
148             }
149              
150             # ciscoPingEntryStatus (5 = createAndWait, 6 = destroy)
151 0           $response
152             = $session->set_request( _ppOID() . '.16.' . $instance, INTEGER, 6 );
153 0           $response
154             = $session->set_request( _ppOID() . '.16.' . $instance, INTEGER, 5 );
155              
156             # ciscoPingEntryOwner ()
157 0           $response = $session->set_request( _ppOID() . '.15.' . $instance,
158             OCTET_STRING, __PACKAGE__ );
159              
160             # ciscoPingProtocol (1 = IP, 20 = IPv6)
161             $response = $session->set_request( _ppOID() . '.2.' . $instance,
162 0 0         INTEGER, ( $params{family} == AF_INET ) ? 1 : 20 );
163 0 0         if ( not defined $response ) {
164 0           $Cisco::SNMP::LASTERROR
165             = "Device does not support ciscoPingProtocol 20 (IPv6)";
166 0           return undef;
167             }
168              
169             # ciscoPingAddress (NOTE: hex string, not regular IP)
170 0           $response = $session->set_request( _ppOID() . '.3.' . $instance,
171             OCTET_STRING, pack( 'H*', $dest ) );
172              
173             # ciscoPingPacketTimeout (in ms)
174             $response = $session->set_request( _ppOID() . '.6.' . $instance,
175 0           INTEGER32, $params{wait} * 100 );
176              
177             # ciscoPingDelay (Set gaps (in ms) between successive pings)
178             $response = $session->set_request( _ppOID() . '.7.' . $instance,
179 0           INTEGER32, $params{wait} * 100 );
180              
181             # ciscoPingPacketCount
182             $response = $session->set_request( _ppOID() . '.4.' . $instance,
183 0           INTEGER, $params{count} );
184              
185             # ciscoPingPacketSize (protocol dependent)
186             $response = $session->set_request( _ppOID() . '.5.' . $instance,
187 0           INTEGER, $params{size} );
188              
189 0 0         if ( exists $params{vrf} ) {
190              
191             # ciscoPingVrfName ()
192             $response = $session->set_request( _ppOID() . '.17.' . $instance,
193 0           OCTET_STRING, $params{vrf} );
194             }
195              
196             # Verify ping is ready (ciscoPingEntryStatus = 2)
197 0           $response = $session->get_request( _ppOID() . '.16.' . $instance );
198 0 0         if ( defined $response->{_ppOID() . '.16.' . $instance} ) {
199 0 0         if ( $response->{_ppOID() . '.16.' . $instance} != 2 ) {
200 0           $Cisco::SNMP::LASTERROR = "Ping not ready";
201 0           return undef;
202             }
203             } else {
204 0           $Cisco::SNMP::LASTERROR = "proxy ping NOT SUPPORTED (after setup)";
205 0           return undef;
206             }
207              
208             # ciscoPingEntryStatus (1 = activate)
209 0           $response
210             = $session->set_request( _ppOID() . '.16.' . $instance, INTEGER, 1 );
211              
212             # Wait sample interval
213 0           sleep $params{wait};
214              
215             # Get results
216 0           $response = $session->get_table( _ppOID() );
217 0   0       $pp->{Sent} = $response->{_ppOID() . '.9.' . $instance} || 0;
218 0   0       $pp->{Received} = $response->{_ppOID() . '.10.' . $instance} || 0;
219 0   0       $pp->{Minimum} = $response->{_ppOID() . '.11.' . $instance} || 0;
220 0   0       $pp->{Average} = $response->{_ppOID() . '.12.' . $instance} || 0;
221 0   0       $pp->{Maximum} = $response->{_ppOID() . '.13.' . $instance} || 0;
222              
223             # destroy entry
224 0           $response
225             = $session->set_request( _ppOID() . '.16.' . $instance, INTEGER, 6 );
226 0           return bless $pp, $class;
227             }
228              
229             sub ppSent {
230 0     0 1   my $self = shift;
231 0           return $self->{Sent};
232             }
233              
234             sub ppReceived {
235 0     0 1   my $self = shift;
236 0           return $self->{Received};
237             }
238              
239             sub ppMinimum {
240 0     0 1   my $self = shift;
241 0           return $self->{Minimum};
242             }
243              
244             sub ppAverage {
245 0     0 1   my $self = shift;
246 0           return $self->{Average};
247             }
248              
249             sub ppMaximum {
250 0     0 1   my $self = shift;
251 0           return $self->{Maximum};
252             }
253              
254             ##################################################
255             # End Public Module
256             ##################################################
257              
258             1;
259              
260             __END__