… | |
… | |
10 | |
10 | |
11 | This module was written for a single purpose only: sending ICMP ECHO |
11 | This module was written for a single purpose only: sending ICMP ECHO |
12 | REQUEST packets as quickly as possible to a large number of hosts |
12 | REQUEST packets as quickly as possible to a large number of hosts |
13 | (thousands to millions). |
13 | (thousands to millions). |
14 | |
14 | |
15 | It employs a sending thread and is fully event-driven (using AnyEvent), so |
15 | It employs a separate thread and is fully event-driven (using AnyEvent), |
16 | you have to run an event model supported by AnyEvent to use this module. |
16 | so you have to run an event model supported by AnyEvent to use this |
|
|
17 | module. |
17 | |
18 | |
18 | =head1 FUNCTIONS |
19 | =head1 FUNCTIONS |
19 | |
20 | |
20 | =over 4 |
21 | =over 4 |
21 | |
22 | |
… | |
… | |
26 | use common::sense; |
27 | use common::sense; |
27 | |
28 | |
28 | use AnyEvent; |
29 | use AnyEvent; |
29 | |
30 | |
30 | BEGIN { |
31 | BEGIN { |
31 | our $VERSION = '2.0'; |
32 | our $VERSION = 2.02; |
32 | our @ISA = qw(Exporter); |
33 | our @ISA = qw(Exporter); |
33 | |
34 | |
34 | require Exporter; |
35 | require Exporter; |
35 | #Exporter::export_ok_tags (keys %EXPORT_TAGS); |
36 | #Exporter::export_ok_tags (keys %EXPORT_TAGS); |
36 | |
37 | |
… | |
… | |
45 | our $ICMP4_FH; our $ICMP4_W = $ICMP4_FD >= 0 && (open $ICMP4_FH, "<&=$ICMP4_FD") && AE::io $ICMP4_FH, 0, \&_recv_icmp4; |
46 | our $ICMP4_FH; our $ICMP4_W = $ICMP4_FD >= 0 && (open $ICMP4_FH, "<&=$ICMP4_FD") && AE::io $ICMP4_FH, 0, \&_recv_icmp4; |
46 | our $ICMP6_FH; our $ICMP6_W = $ICMP6_FD >= 0 && (open $ICMP6_FH, "<&=$ICMP6_FD") && AE::io $ICMP6_FH, 0, \&_recv_icmp6; |
47 | our $ICMP6_FH; our $ICMP6_W = $ICMP6_FD >= 0 && (open $ICMP6_FH, "<&=$ICMP6_FD") && AE::io $ICMP6_FH, 0, \&_recv_icmp6; |
47 | |
48 | |
48 | =item AnyEvent::FastPing::ipv4_supported |
49 | =item AnyEvent::FastPing::ipv4_supported |
49 | |
50 | |
50 | Returns true if IPv4 is supported in this module and on this system. |
51 | Returns true iff IPv4 is supported in this module and on this system. |
51 | |
52 | |
52 | =item AnyEvent::FastPing::ipv6_supported |
53 | =item AnyEvent::FastPing::ipv6_supported |
53 | |
54 | |
54 | Returns true if IPv6 is supported in this module and on this system. |
55 | Returns true iff IPv6 is supported in this module and on this system. |
55 | |
56 | |
56 | =item AnyEvent::FastPing::icmp4_pktsize |
57 | =item AnyEvent::FastPing::icmp4_pktsize |
57 | |
58 | |
58 | Returns the number of bytes each IPv4 ping packet has. |
59 | Returns the number of octets per IPv4 ping packet (the whole IP packet |
|
|
60 | including headers, excluding lower-level headers or trailers such as |
|
|
61 | Ethernet). |
|
|
62 | |
|
|
63 | Can be used to calculate e.g. octets/s from rate ... |
|
|
64 | |
|
|
65 | my $octets_per_second = $packets_per_second * AnyEvent::FastPing::icmp4_pktsize; |
|
|
66 | |
|
|
67 | ... or convert kilobit/second to packet rate ... |
|
|
68 | |
|
|
69 | my $packets_per_second = $kilobit_per_second |
|
|
70 | * (1000 / 8 / AnyEvent::FastPing::icmp4_pktsize); |
|
|
71 | |
|
|
72 | etc. |
59 | |
73 | |
60 | =item AnyEvent::FastPing::icmp6_pktsize |
74 | =item AnyEvent::FastPing::icmp6_pktsize |
61 | |
75 | |
62 | Returns the number of bytes each IPv4 ping packet has. |
76 | Like AnyEvent::FastPing::icmp4_pktsize, but for IPv6. |
|
|
77 | |
|
|
78 | =back |
|
|
79 | |
|
|
80 | =head1 THE AnyEvent::FastPing CLASS |
|
|
81 | |
|
|
82 | The AnyEvent::FastPing class represents a single "pinger". A "pinger" |
|
|
83 | comes with its own thread to send packets in the background, a rate-limit |
|
|
84 | machinery and separate idle/receive callbacks. |
|
|
85 | |
|
|
86 | The recommended workflow (there are others) is this: 1. create a new |
|
|
87 | AnyEvent::FastPing object 2. configure the address lists and ranges to |
|
|
88 | ping, also configure an idle callback and optionally a receive callback |
|
|
89 | 3. C<start> the pinger. |
|
|
90 | |
|
|
91 | When the pinger has finished pinging all the configured addresses it will |
|
|
92 | call the idle callback. |
|
|
93 | |
|
|
94 | The pinging process works like this: every range has a minimum interval |
|
|
95 | between sends, which is used to limit the rate at which hosts in that |
|
|
96 | range are being pinged. Distinct ranges are independent of each other, |
|
|
97 | which is why there is a per-pinger "global" minimum interval as well. |
|
|
98 | |
|
|
99 | The pinger sends pings as fats as possible, while both obeying the pinger |
|
|
100 | rate limit as well as range limits. |
|
|
101 | |
|
|
102 | When a range is exhausted, it is removed. When all ranges are exhausted, |
|
|
103 | the pinger waits another C<max_rtt> seconds and then exits, causing the |
|
|
104 | idle callback to trigger. |
|
|
105 | |
|
|
106 | Performance: On my 2 GHz Opteron system with a pretty average nvidia |
|
|
107 | gigabit network card I can ping around 60k to 200k addresses per second, |
|
|
108 | depending on routing decisions. |
|
|
109 | |
|
|
110 | Example: ping 10.0.0.1-10.0.0.15 with at most 100 packets/s, and |
|
|
111 | 11.0.0.1-11.0.255.255 with at most 1000 packets/s. Also ping the IPv6 |
|
|
112 | loopback address 5 times as fast as possible. Do not, however, exceed 1000 |
|
|
113 | packets/s overall. Also dump each received reply. |
|
|
114 | |
|
|
115 | use AnyEvent::Socket; |
|
|
116 | use AnyEvent::FastPing; |
|
|
117 | |
|
|
118 | my $done = AnyEvent->condvar; |
|
|
119 | |
|
|
120 | my $pinger = new AnyEvent::FastPing; |
|
|
121 | |
|
|
122 | $pinger->interval (1/1000); |
|
|
123 | $pinger->max_rtt (0.1); # reasonably fast/reliable network |
|
|
124 | |
|
|
125 | $pinger->add_range (v10.0.0.1, v10.0.0.15, 1/100); |
|
|
126 | $pinger->add_range (v11.0.0.1, v11.0.255.255, 1/1000); |
|
|
127 | $pinger->add_hosts ([ (v0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1) x 5 ]); |
|
|
128 | |
|
|
129 | $pinger->on_recv (sub { |
|
|
130 | for (@{ $_[0] }) { |
|
|
131 | printf "%s %g\n", (AnyEvent::Socket::format_address $_->[0]), $_->[1]; |
|
|
132 | } |
|
|
133 | }); |
|
|
134 | |
|
|
135 | $pinger->on_idle (sub { |
|
|
136 | print "done\n"; |
|
|
137 | undef $pinger; |
|
|
138 | }); |
|
|
139 | |
|
|
140 | $pinger->start; |
|
|
141 | $done->wait; |
|
|
142 | |
|
|
143 | =head2 METHODS |
|
|
144 | |
|
|
145 | =over 4 |
|
|
146 | |
|
|
147 | =item $pinger = new AnyEvent::FastPing |
|
|
148 | |
|
|
149 | Creates a new pinger - right now there can be at most C<65536> pingers in |
|
|
150 | a process, although that limit might change to something drastically lower |
|
|
151 | - you should be stingy with your pinger objects. |
63 | |
152 | |
64 | =cut |
153 | =cut |
65 | |
154 | |
66 | sub new { |
155 | sub new { |
67 | my ($klass) = @_; |
156 | my ($klass) = @_; |
… | |
… | |
73 | |
162 | |
74 | sub DESTROY { |
163 | sub DESTROY { |
75 | undef $IDLE_CB[ &id ]; |
164 | undef $IDLE_CB[ &id ]; |
76 | &_free; |
165 | &_free; |
77 | } |
166 | } |
|
|
167 | |
|
|
168 | =item $pinger->on_recv ($callback->([[$host, $rtt], ...])) |
|
|
169 | |
|
|
170 | Registers a callback to be called for ping replies. If no callback has |
|
|
171 | been registered than ping replies will be ignored, otherwise this module |
|
|
172 | calculates the round trip time, in seconds, for each reply and calls this |
|
|
173 | callback. |
|
|
174 | |
|
|
175 | The callback receives a single argument, which is an array reference |
|
|
176 | with an entry for each reply packet (the replies will be batched for |
|
|
177 | efficiency). Each member in the array reference is again an array |
|
|
178 | reference with exactly two members: the binary host address (4 octets for |
|
|
179 | IPv4, 16 for IPv6) and the approximate round trip time, in seconds. |
|
|
180 | |
|
|
181 | The replies will be passed to the callback as soon as they arrive, and |
|
|
182 | this callback can be called many times with batches of replies. |
|
|
183 | |
|
|
184 | The receive callback will be called whenever a suitable reply arrives, |
|
|
185 | whether generated by this pinger or not, whether this pinger is started |
|
|
186 | or not. The packets will have a unique 64 bit ID to distinguish them from |
|
|
187 | other pinger objects and other generators, but this doesn't help against |
|
|
188 | malicious replies. |
|
|
189 | |
|
|
190 | Note that very high packet rates can overwhelm your process, causing |
|
|
191 | replies to be dropped (configure your kernel with long receive queues for |
|
|
192 | raw sockets if this is a problem). |
|
|
193 | |
|
|
194 | Example: register a callback which simply dumps the received data. |
|
|
195 | |
|
|
196 | use AnyEvent::Socket; |
|
|
197 | |
|
|
198 | $pinger->on_recv (sub { |
|
|
199 | for (@{ $_[0] }) { |
|
|
200 | printf "%s %g\n", (AnyEvent::Socket::format_address $_->[0]), $_->[1]; |
|
|
201 | } |
|
|
202 | }); |
|
|
203 | |
|
|
204 | Example: a single ping reply with payload of 1 from C<::1> gets passed |
|
|
205 | like this: |
|
|
206 | |
|
|
207 | [ |
|
|
208 | [ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", 0.000280141830444336 ] |
|
|
209 | ] |
|
|
210 | |
|
|
211 | Example: ping replies for C<127.0.0.1> and C<127.0.0.2>: |
|
|
212 | |
|
|
213 | [ |
|
|
214 | [ "\177\0\0\1", 0.00015711784362793 ], |
|
|
215 | [ "\177\0\0\2", 0.00090184211731 ] |
|
|
216 | ] |
|
|
217 | |
|
|
218 | =item $pinger->on_idle ($callback->()) |
|
|
219 | |
|
|
220 | Registers a callback to be called when the pinger becomes I<idle>, that |
|
|
221 | is, it has been started, has exhausted all ping ranges and waited for |
|
|
222 | the C<max_rtt> time. An idle pinger is also stopped, so the callback can |
|
|
223 | instantly add new ranges, if it so desires. |
|
|
224 | |
|
|
225 | =cut |
78 | |
226 | |
79 | sub on_idle { |
227 | sub on_idle { |
80 | $IDLE_CB[ &id ] = $_[1]; |
228 | $IDLE_CB[ &id ] = $_[1]; |
81 | } |
229 | } |
82 | |
230 | |
… | |
… | |
87 | _stop_id $id; |
235 | _stop_id $id; |
88 | ($IDLE_CB[$id] || sub { })->(); |
236 | ($IDLE_CB[$id] || sub { })->(); |
89 | } |
237 | } |
90 | }; |
238 | }; |
91 | |
239 | |
92 | for(1..10) { |
240 | =item $pinger->interval ($seconds) |
93 | my $p = new AnyEvent::FastPing;#d# |
|
|
94 | $p->interval (0); |
|
|
95 | $p->max_rtt (0.5); |
|
|
96 | #$p->add_range (v127.0.0.1, v127.255.255.254, 0); |
|
|
97 | $p->add_range (v1.0.0.1, v1.255.255.254, 0); |
|
|
98 | $p->on_idle (my $cv = AE::cv); |
|
|
99 | my $cnt; |
|
|
100 | $p->on_recv (sub { |
|
|
101 | $cnt++; |
|
|
102 | }); |
|
|
103 | $p->start; |
|
|
104 | $cv->recv; |
|
|
105 | warn $cnt; |
|
|
106 | } |
|
|
107 | |
241 | |
108 | =item AnyEvent::FastPing::icmp_ping [ranges...], $send_interval, $payload, \&callback |
242 | Configures the minimum interval between packet sends for this pinger - the |
|
|
243 | pinger will not send packets faster than this rate (or actually 1 / rate), |
|
|
244 | even if individual ranges have a lower interval. |
109 | |
245 | |
110 | Ping the given IPv4 address ranges. Each range is an arrayref of the |
246 | A value of C<0> selects the fastest possible speed (currently no faster |
111 | form C<[lo, hi, interval]>, where C<lo> and C<hi> are octet strings with |
247 | than 1_000_000 packets/s). |
112 | either 4 octets (for IPv4 addresses) or 16 octets (for IPV6 addresses), |
|
|
113 | representing the lowest and highest address to ping (you can convert a |
|
|
114 | dotted-quad IPv4 address to this format by using C<inet_aton $address>. The |
|
|
115 | range C<interval> is the minimum time in seconds between pings to the |
|
|
116 | given range. If omitted, defaults to C<$send_interval>. |
|
|
117 | |
248 | |
118 | The C<$send_interval> is the minimum interval between sending any two |
249 | =item $pinger->max_rtt ($seconds) |
119 | packets and is a way to make an overall rate limit. If omitted, pings will |
|
|
120 | be sent as fast as possible. |
|
|
121 | |
250 | |
122 | The C<$payload> is a 32 bit unsigned integer given as the ICMP ECHO |
251 | If your idle callback were called instantly after all ranges were |
123 | REQUEST ident and sequence numbers (in unspecified order :). |
252 | exhausted and you destroyed the object inside (which is common), then |
|
|
253 | there would be no chance to receive some replies, as there would be no |
|
|
254 | time of the packet to travel over the network. |
124 | |
255 | |
125 | The request will be queued and all requests will be served by a background |
256 | This can be fixed by starting a timer in the idle callback, or more simply |
126 | thread in order. When all ranges have been pinged, the C<callback> will be |
257 | by selecting a suitable C<max_rtt> value, which should be the maximum time |
127 | called. |
258 | you allow a ping packet to travel to its destination and back. |
128 | |
259 | |
129 | Algorithm: Each range has an associated "next time to send packet" |
260 | The pinger thread automatically waits for this amount of time before becoming idle. |
130 | time. The algorithm loops as long as there are ranges with hosts to be |
|
|
131 | pinged and always serves the range with the most urgent packet send |
|
|
132 | time. It will at most send one packet every C<$send_interval> seconds. |
|
|
133 | |
261 | |
134 | This will ensure that pings to the same range are nicely interleaved with |
262 | The default is currently C<0.5> seconds, which is usually plenty. |
135 | other ranges - this can help reduce per-subnet bandwidth while maintaining |
|
|
136 | an overall high packet rate. |
|
|
137 | |
263 | |
138 | The algorithm to send each packet is O(log n) on the number of ranges, so |
264 | =item $pinger->add_range ($lo, $hi[, $interval]) |
|
|
265 | |
|
|
266 | Ping the IPv4 (or IPv6, but see below) address range, starting at binary |
|
|
267 | address C<$lo> and ending at C<$hi> (both C<$lo> and C<$hi> will be |
|
|
268 | pinged), generating no more than one ping per C<$interval> seconds (or as |
|
|
269 | fast as possible if omitted). |
|
|
270 | |
|
|
271 | You can convert IP addresses from text to binary form by |
|
|
272 | using C<AnyEvent::Util::parse_address>, C<Socket::inet_aton>, |
|
|
273 | C<Socket6::inet_pton> or any other method that you like :) |
|
|
274 | |
|
|
275 | The algorithm to select the next address is O(log n) on the number of |
139 | even a large number of ranges (many thousands) is managable. |
276 | ranges, so even a large number of ranges (many thousands) is manageable. |
140 | |
277 | |
141 | No storage is allocated per address. |
278 | No storage is allocated per address. |
142 | |
279 | |
143 | Performance: On my 2 GHz Opteron system with a pretty average nvidia |
280 | Note that, while IPv6 addresses are currently supported, the usefulness of |
144 | gigabit network card I can ping around 60k to 200k adresses per second, |
281 | this option is extremely limited and might be gone in future versions - if |
145 | depending on routing decisions. |
282 | you want to ping a number of IPv6 hosts, better specify them individually |
|
|
283 | using the C<add_hosts> method. |
146 | |
284 | |
147 | Example: ping 10.0.0.1-10.0.0.15 with at most 100 packets/s, and |
285 | =item $pinger->add_hosts ([$host...], $interval, $interleave) |
148 | 11.0.0.1-11.0.255.255 with at most 1000 packets/s. Do not, however, exceed |
|
|
149 | 1000 packets/s overall: |
|
|
150 | |
286 | |
151 | my $done = AnyEvent->condvar; |
287 | Similar to C<add_range>, but uses a list of single addresses instead. The |
|
|
288 | list is specified as an array reference as first argument. Each entry in |
|
|
289 | the array should be a binary host address, either IPv4 or IPv6. If all |
|
|
290 | addresses are IPv4 addresses, then a compact IPv4-only format will be used |
|
|
291 | to store the list internally. |
152 | |
292 | |
153 | AnyEvent::FastPing::icmp_ping |
293 | Minimum C<$interval> is the same as for C<add_range> and can be left out. |
154 | [ |
|
|
155 | [v10.0.0.1, v10.0.0.15, .01], |
|
|
156 | [v11.0.0.1, v11.0.255.255, .001], |
|
|
157 | ], |
|
|
158 | .001, 0x12345678, |
|
|
159 | sub { |
|
|
160 | warn "all ranges pinged\n"; |
|
|
161 | $done->broadcast; |
|
|
162 | } |
|
|
163 | ; |
|
|
164 | |
294 | |
165 | $done->wait; |
295 | C<$interlave> specifies an increment between addresses: often address |
|
|
296 | lists are generated in a way that results in clustering - first all |
|
|
297 | addresses from one subnet, then from the next, and so on. To avoid this, |
|
|
298 | you can specify an interleave factor. If it is C<1> (the default), then |
|
|
299 | every address is pinged in the order specified. If it is C<2>, then only |
|
|
300 | every second address will be pinged in the first round, followed by a |
|
|
301 | second round with the others. Higher factors will create C<$interleave> |
|
|
302 | runs of addresses spaced C<$interleave> indices in the list. |
166 | |
303 | |
167 | =cut |
304 | The special value C<0> selects a (hopefully) suitable interleave factor |
|
|
305 | automatically - currently C<256> for lists with less than 65536 addresses, |
|
|
306 | and the square root of the list length otherwise. |
168 | |
307 | |
169 | sub icmp_ping($$$&) { |
308 | =item $pinger->start |
170 | # _send_req _req_icmp_ping @_; |
|
|
171 | } |
|
|
172 | |
309 | |
173 | =item AnyEvent::FastPing::register_cb \&cb |
310 | Start the pinger, unless it is running already. While a pinger is running |
|
|
311 | you must not modify the pinger. If you want to change a parameter, you |
|
|
312 | have to C<stop> the pinger first. |
174 | |
313 | |
175 | Register a callback that is called for every received ping reply |
314 | The pinger will automatically stop when destroyed. |
176 | (regardless of whether a ping is still in process or not and regardless of |
|
|
177 | whether the reply is actually a reply to a ping sent earlier). |
|
|
178 | |
315 | |
179 | The code reference gets a single parameter - an arrayref with an |
316 | =item $pinger->stop |
180 | entry for each received packet (replies are being batched for greater |
|
|
181 | efficiency). Each packet is represented by an arrayref with three members: |
|
|
182 | the source address (an octet string of either 4 (IPv4) or 16 (IPv6) octets |
|
|
183 | length), the payload as passed to C<icmp_ping> and the round trip time in |
|
|
184 | seconds. |
|
|
185 | |
317 | |
186 | Example: register a callback which simply dumps the received data. Since |
318 | Stop the pinger, if it is running. A pinger can be stopped at any time, |
187 | the coderef is created on the fly via sub, it would be hard to unregister |
319 | after which it's current state is preserved - starting it again will |
188 | this callback again :) |
320 | continue where it left off. |
189 | |
321 | |
190 | AnyEvent::FastPing::register_cb sub { |
|
|
191 | for (@{$_[0]}) { |
|
|
192 | printf "%s %d %g\n", |
|
|
193 | (4 == length $_->[0] ? inet_ntoa $_->[0] : Socket6::inet_ntop (&AF_INET6, $_->[0])), |
|
|
194 | $_->[2], |
|
|
195 | $_->[1]; |
|
|
196 | } |
|
|
197 | }; |
|
|
198 | |
|
|
199 | Example: a single ping reply with payload of 1 from C<::1> gets passed |
|
|
200 | like this: |
|
|
201 | |
|
|
202 | [ [ |
|
|
203 | "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", |
|
|
204 | "0.000280141830444336", |
|
|
205 | 1 |
|
|
206 | ] ] |
|
|
207 | |
|
|
208 | Example: ping replies for C<127.0.0.1> and C<127.0.0.2>, with a payload of |
|
|
209 | C<0x12345678>: |
|
|
210 | |
|
|
211 | [ |
|
|
212 | [ |
|
|
213 | "\177\0\0\1", |
|
|
214 | "0.00015711784362793", |
|
|
215 | 305419896 |
|
|
216 | ], |
|
|
217 | [ |
|
|
218 | "\177\0\0\2", |
|
|
219 | "0.00090184211731", |
|
|
220 | 305419896 |
|
|
221 | ] |
|
|
222 | ] |
|
|
223 | |
|
|
224 | =item AnyEvent::FastPing::unregister_cb \&cb |
|
|
225 | |
|
|
226 | Unregister the callback again (make sure you pass the same codereference |
|
|
227 | as to C<register_cb>). |
|
|
228 | |
|
|
229 | =cut |
322 | =cut |
230 | |
|
|
231 | our @CB; |
|
|
232 | |
|
|
233 | sub register_cb($) { |
|
|
234 | push @CB, $_[0]; |
|
|
235 | } |
|
|
236 | |
|
|
237 | sub unregister_cb($) { |
|
|
238 | @CB = grep $_ != $_[0], @CB; |
|
|
239 | } |
|
|
240 | |
323 | |
241 | 1; |
324 | 1; |
242 | |
325 | |
243 | =back |
326 | =back |
244 | |
327 | |