1 /* $Id$ */
2
3
4 /*
5 * Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
6 * Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
7 *
8 * The Tcpreplay Suite of tools is free software: you can redistribute it
9 * and/or modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation, either version 3 of the
11 * License, or with the authors permission any later version.
12 *
13 * The Tcpreplay Suite is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with the Tcpreplay Suite. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "config.h"
23 #include "defines.h"
24 #include "common.h"
25
26 #include <sys/time.h>
27 #include <sys/types.h>
28 #include <signal.h>
29 #include <string.h>
30 #include <netinet/in.h>
31 #include <errno.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35
36 #include "tcpreplay_api.h"
37 #include "timestamp_trace.h"
38 #include "../lib/sll.h"
39
40 #ifdef HAVE_NETMAP
41 #ifdef HAVE_SYS_POLL_H
42 #include <sys/poll.h>
43 #endif
44 #include <sys/ioctl.h>
45 #include <net/netmap.h>
46 #include <net/netmap_user.h>
47 #endif /* HAVE_NETMAP */
48
49 #ifdef TCPREPLAY
50
51 #ifdef TCPREPLAY_EDIT
52 #include "tcpreplay_edit_opts.h"
53 #include "tcpedit/tcpedit.h"
54 extern tcpedit_t *tcpedit;
55 #else
56 #include "tcpreplay_opts.h"
57 #endif /* TCPREPLAY_EDIT */
58
59 #endif /* TCPREPLAY */
60
61 #include "send_packets.h"
62 #include "sleep.h"
63
64 #ifdef DEBUG
65 extern int debug;
66 #endif
67
68 static void calc_sleep_time(tcpreplay_t *ctx, struct timeval *pkt_time,
69 struct timeval *last, COUNTER len,
70 sendpacket_t *sp, COUNTER counter, timestamp_t *sent_timestamp,
71 COUNTER start_us, COUNTER *skip_length);
72 static void tcpr_sleep(tcpreplay_t *ctx, sendpacket_t *sp _U_,
73 struct timespec *nap_this_time, struct timeval *now);
74 static u_char *get_next_packet(tcpreplay_t *ctx, pcap_t *pcap,
75 struct pcap_pkthdr *pkthdr,
76 int file_idx,
77 packet_cache_t **prev_packet);
78 static uint32_t get_user_count(tcpreplay_t *ctx, sendpacket_t *sp, COUNTER counter);
79
wake_send_queues(sendpacket_t * sp _U_,tcpreplay_opt_t * options _U_)80 static inline void wake_send_queues(sendpacket_t *sp _U_,
81 tcpreplay_opt_t *options _U_)
82 {
83 #ifdef HAVE_NETMAP
84 if (options->netmap)
85 ioctl(sp->handle.fd, NIOCTXSYNC, NULL); /* flush TX buffer */
86 #endif
87 }
88
89 static inline int
fast_edit_packet(struct pcap_pkthdr * pkthdr,u_char ** pktdata,COUNTER iteration,bool cached,int datalink)90 fast_edit_packet(struct pcap_pkthdr *pkthdr, u_char **pktdata,
91 COUNTER iteration, bool cached, int datalink)
92 {
93 uint16_t ether_type;
94 ipv4_hdr_t *ip_hdr = NULL;
95 ipv6_hdr_t *ip6_hdr = NULL;
96 uint32_t src_ip, dst_ip;
97 uint32_t src_ip_orig, dst_ip_orig;
98 int l2_len;
99 u_char *packet = *pktdata;
100
101 l2_len = get_l2len(packet, pkthdr->caplen, datalink);
102 if (l2_len < 0)
103 return -1;
104
105 ether_type = get_l2protocol(packet, pkthdr->caplen, datalink);
106 switch (ether_type) {
107 case ETHERTYPE_IP:
108 if (pkthdr->caplen < (bpf_u_int32)(l2_len + sizeof(ipv4_hdr_t))) {
109 dbgx(1, "IP packet too short for Unique IP feature: %u", pkthdr->caplen);
110 return -1;
111 }
112 ip_hdr = (ipv4_hdr_t *)(packet + l2_len);
113 src_ip_orig = src_ip = ntohl(ip_hdr->ip_src.s_addr);
114 dst_ip_orig = dst_ip = ntohl(ip_hdr->ip_dst.s_addr);
115 break;
116
117 case ETHERTYPE_IP6:
118 if (pkthdr->caplen < (bpf_u_int32)(l2_len + sizeof(ipv6_hdr_t))) {
119 dbgx(1, "IP6 packet too short for Unique IP feature: %u", pkthdr->caplen);
120 return -1;
121 }
122 ip6_hdr = (ipv6_hdr_t *)(packet + l2_len);
123 src_ip_orig = src_ip = ntohl(ip6_hdr->ip_src.__u6_addr.__u6_addr32[3]);
124 dst_ip_orig = dst_ip = ntohl(ip6_hdr->ip_dst.__u6_addr.__u6_addr32[3]);
125 break;
126
127 default:
128 return -1; /* non-IP or packet too short */
129 }
130
131 dbgx(2, "Layer 3 protocol type is: 0x%04x", ether_type);
132
133 /* swap src/dst IP's in a manner that does not affect CRC */
134 if ((!cached && dst_ip > src_ip) ||
135 (cached && (dst_ip - iteration) > (src_ip - 1 - iteration))) {
136 if (cached) {
137 --src_ip;
138 ++dst_ip;
139 } else {
140 src_ip -= iteration;
141 dst_ip += iteration;
142 }
143
144 /* CRC compensations for wrap conditions */
145 if (src_ip > src_ip_orig && dst_ip > dst_ip_orig) {
146 dbgx(1, "dst_ip > src_ip(" COUNTER_SPEC "): before(1) src_ip=0x%08x dst_ip=0x%08x", iteration, src_ip, dst_ip);
147 --src_ip;
148 dbgx(1, "dst_ip > src_ip(" COUNTER_SPEC "): after(1) src_ip=0x%08x dst_ip=0x%08x", iteration, src_ip, dst_ip);
149 } else if (dst_ip < dst_ip_orig && src_ip < src_ip_orig) {
150 dbgx(1, "dst_ip > src_ip(" COUNTER_SPEC "): before(2) src_ip=0x%08x dst_ip=0x%08x", iteration, src_ip, dst_ip);
151 ++dst_ip;
152 dbgx(1, "dst_ip > src_ip(" COUNTER_SPEC "): after(2) src_ip=0x%08x dst_ip=0x%08x", iteration, src_ip, dst_ip);
153 }
154 } else {
155 if (cached) {
156 ++src_ip;
157 --dst_ip;
158 } else {
159 src_ip += iteration;
160 dst_ip -= iteration;
161 }
162
163 /* CRC compensations for wrap conditions */
164 if (dst_ip > dst_ip_orig && src_ip > src_ip_orig) {
165 dbgx(1, "src_ip > dst_ip(" COUNTER_SPEC "): before(1) dst_ip=0x%08x src_ip=0x%08x", iteration, dst_ip, src_ip);
166 --dst_ip;
167 dbgx(1, "src_ip > dst_ip(" COUNTER_SPEC "): after(1) dst_ip=0x%08x src_ip=0x%08x", iteration, dst_ip, src_ip);
168 } else if (src_ip < src_ip_orig && dst_ip < dst_ip_orig) {
169 dbgx(1, "src_ip > dst_ip(" COUNTER_SPEC "): before(2) dst_ip=0x%08x src_ip=0x%08x", iteration, dst_ip, src_ip);
170 ++src_ip;
171 dbgx(1, "src_ip > dst_ip(" COUNTER_SPEC "): after(2) dst_ip=0x%08x src_ip=0x%08x", iteration, dst_ip, src_ip);
172 }
173 }
174
175 dbgx(1, "(" COUNTER_SPEC "): final src_ip=0x%08x dst_ip=0x%08x", iteration, src_ip, dst_ip);
176
177 switch (ether_type) {
178 case ETHERTYPE_IP:
179 ip_hdr->ip_src.s_addr = htonl(src_ip);
180 ip_hdr->ip_dst.s_addr = htonl(dst_ip);
181 break;
182
183 case ETHERTYPE_IP6:
184 ip6_hdr->ip_src.__u6_addr.__u6_addr32[3] = htonl(src_ip);
185 ip6_hdr->ip_dst.__u6_addr.__u6_addr32[3] = htonl(dst_ip);
186 break;
187 }
188
189 return 0;
190 }
191
192 /**
193 * \brief Update flow stats
194 *
195 * Finds out if flow is unique and updates stats.
196 */
update_flow_stats(tcpreplay_t * ctx,sendpacket_t * sp,const struct pcap_pkthdr * pkthdr,const u_char * pktdata,int datalink)197 static inline void update_flow_stats(tcpreplay_t *ctx, sendpacket_t *sp,
198 const struct pcap_pkthdr *pkthdr, const u_char *pktdata, int datalink)
199 {
200 flow_entry_type_t res = flow_decode(ctx->flow_hash_table,
201 pkthdr, pktdata, datalink, ctx->options->flow_expiry);
202
203 switch (res) {
204 case FLOW_ENTRY_NEW:
205 ++ctx->stats.flows;
206 ++ctx->stats.flows_unique;
207 ++ctx->stats.flow_packets;
208 if (sp) {
209 ++sp->flows;
210 ++sp->flows_unique;
211 ++sp->flow_packets;
212 }
213 break;
214
215 case FLOW_ENTRY_EXISTING:
216 ++ctx->stats.flow_packets;
217 if (sp)
218 ++sp->flow_packets;
219 break;
220
221 case FLOW_ENTRY_EXPIRED:
222 ++ctx->stats.flows_expired;
223 ++ctx->stats.flows;
224 ++ctx->stats.flow_packets;
225 if (sp) {
226 ++sp->flows_expired;
227 ++sp->flows;
228 ++sp->flow_packets;
229 }
230 break;
231
232 case FLOW_ENTRY_NON_IP:
233 ++ctx->stats.flow_non_flow_packets;
234 if (sp)
235 ++sp->flow_non_flow_packets;
236 break;
237
238 case FLOW_ENTRY_INVALID:
239 ++ctx->stats.flows_invalid_packets;
240 if (sp)
241 ++sp->flows_invalid_packets;
242 break;
243 }
244 }
245 /**
246 * \brief Preloads the memory cache for the given pcap file_idx
247 *
248 * Preloading can be used with or without --loop
249 */
250 void
preload_pcap_file(tcpreplay_t * ctx,int idx)251 preload_pcap_file(tcpreplay_t *ctx, int idx)
252 {
253 tcpreplay_opt_t *options = ctx->options;
254 char *path = options->sources[idx].filename;
255 pcap_t *pcap = NULL;
256 char ebuf[PCAP_ERRBUF_SIZE];
257 const u_char *pktdata = NULL;
258 struct pcap_pkthdr pkthdr;
259 packet_cache_t *cached_packet = NULL;
260 packet_cache_t **prev_packet = &cached_packet;
261 COUNTER packetnum = 0;
262 int dlt;
263
264 /* close stdin if reading from it (needed for some OS's) */
265 if (strncmp(path, "-", 1) == 0)
266 if (close(1) == -1)
267 warnx("unable to close stdin: %s", strerror(errno));
268
269 if ((pcap = pcap_open_offline(path, ebuf)) == NULL)
270 errx(-1, "Error opening pcap file: %s", ebuf);
271
272 dlt = pcap_datalink(pcap);
273 /* loop through the pcap. get_next_packet() builds the cache for us! */
274 while ((pktdata = get_next_packet(ctx, pcap, &pkthdr, idx, prev_packet)) != NULL) {
275 packetnum++;
276 if (options->flow_stats)
277 update_flow_stats(ctx, NULL, &pkthdr, pktdata, dlt);
278 }
279
280 /* mark this file as cached */
281 options->file_cache[idx].cached = TRUE;
282 options->file_cache[idx].dlt = dlt;
283 pcap_close(pcap);
284 }
285
increment_iteration(tcpreplay_t * ctx)286 static void increment_iteration(tcpreplay_t *ctx)
287 {
288 tcpreplay_opt_t *options = ctx->options;
289
290 ctx->last_unique_iteration = ctx->unique_iteration;
291 ++ctx->iteration;
292 if (options->unique_ip) {
293 assert(options->unique_loops > 0.0);
294 ctx->unique_iteration =
295 ((ctx->iteration * 1000) / (COUNTER)(options->unique_loops * 1000.0))
296 + 1;
297 }
298 }
299
300 /**
301 * the main loop function for tcpreplay. This is where we figure out
302 * what to do with each packet
303 */
304 void
send_packets(tcpreplay_t * ctx,pcap_t * pcap,int idx)305 send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
306 {
307
308 struct timeval print_delta, now, last_pkt_ts;
309 tcpreplay_opt_t *options = ctx->options;
310 tcpreplay_stats_t *stats = &ctx->stats;
311 COUNTER packetnum = 0;
312 COUNTER limit_send = options->limit_send;
313 struct pcap_pkthdr pkthdr;
314 u_char *pktdata = NULL;
315 sendpacket_t *sp = ctx->intf1;
316 COUNTER pktlen;
317 packet_cache_t *cached_packet = NULL;
318 packet_cache_t **prev_packet = NULL;
319 #if defined TCPREPLAY && defined TCPREPLAY_EDIT
320 struct pcap_pkthdr *pkthdr_ptr;
321 #endif
322 int datalink = options->file_cache[idx].dlt;
323 COUNTER skip_length = 0;
324 COUNTER end_us;
325 bool preload = options->file_cache[idx].cached;
326 bool top_speed = (options->speed.mode == speed_topspeed ||
327 (options->speed.mode == speed_mbpsrate && options->speed.speed == 0));
328 bool now_is_now = true;
329
330 gettimeofday(&now, NULL);
331 if (!timerisset(&stats->start_time)) {
332 TIMEVAL_SET(&stats->start_time, &now);
333 if (ctx->options->stats >= 0) {
334 char buf[64];
335 if (format_date_time(&stats->start_time, buf, sizeof(buf)) > 0)
336 printf("Test start: %s ...\n", buf);
337 }
338 }
339
340 ctx->skip_packets = 0;
341 timerclear(&last_pkt_ts);
342 timerclear(&stats->first_packet_sent_wall_time);
343 if (options->limit_time > 0)
344 end_us = TIMEVAL_TO_MICROSEC(&stats->start_time) +
345 SEC_TO_MICROSEC(options->limit_time);
346 else
347 end_us = 0;
348
349 if (options->preload_pcap) {
350 prev_packet = &cached_packet;
351 } else {
352 prev_packet = NULL;
353 }
354
355 /* MAIN LOOP
356 * Keep sending while we have packets or until
357 * we've sent enough packets
358 */
359 while (!ctx->abort &&
360 (pktdata = get_next_packet(ctx, pcap, &pkthdr, idx, prev_packet)) != NULL) {
361
362 now_is_now = false;
363 packetnum++;
364 #if defined TCPREPLAY || defined TCPREPLAY_EDIT
365 /* do we use the snaplen (caplen) or the "actual" packet len? */
366 pktlen = options->use_pkthdr_len ? (COUNTER)pkthdr.len : (COUNTER)pkthdr.caplen;
367 #elif TCPBRIDGE
368 pktlen = (COUNTER)pkthdr.caplen;
369 #else
370 #error WTF??? We should not be here!
371 #endif
372
373 dbgx(2, "packet " COUNTER_SPEC " caplen " COUNTER_SPEC, packetnum, pktlen);
374
375 /* Dual nic processing */
376 if (ctx->intf2 != NULL) {
377 sp = (sendpacket_t *)cache_mode(ctx, options->cachedata, packetnum);
378
379 /* sometimes we should not send the packet */
380 if (sp == TCPR_DIR_NOSEND)
381 continue;
382 }
383
384 #if defined TCPREPLAY && defined TCPREPLAY_EDIT
385 pkthdr_ptr = &pkthdr;
386 if (tcpedit_packet(tcpedit, &pkthdr_ptr, &pktdata, sp->cache_dir) == -1) {
387 errx(-1, "Error editing packet #" COUNTER_SPEC ": %s", packetnum, tcpedit_geterr(tcpedit));
388 }
389 pktlen = options->use_pkthdr_len ? (COUNTER)pkthdr_ptr->len : (COUNTER)pkthdr_ptr->caplen;
390 #endif
391
392 if (ctx->options->unique_ip && ctx->unique_iteration &&
393 ctx->unique_iteration > ctx->last_unique_iteration) {
394 /* edit packet to ensure every pass has unique IP addresses */
395 if (fast_edit_packet(&pkthdr, &pktdata, ctx->unique_iteration - 1,
396 preload, datalink) == -1) {
397 ++stats->failed;
398 continue;
399 }
400 }
401
402 /* update flow stats */
403 if (options->flow_stats && !preload)
404 update_flow_stats(ctx,
405 options->cache_packets ? sp : NULL, &pkthdr, pktdata, datalink);
406
407 /*
408 * this accelerator improves performance by avoiding expensive
409 * time stamps during periods where we have fallen behind in our
410 * sending
411 */
412 if (skip_length && pktlen < skip_length) {
413 skip_length -= pktlen;
414 } else if (ctx->skip_packets) {
415 --ctx->skip_packets;
416 } else {
417 /*
418 * time stamping is expensive, but now is the
419 * time to do it.
420 */
421 dbgx(4, "This packet time: " TIMEVAL_FORMAT, pkthdr.ts.tv_sec,
422 pkthdr.ts.tv_usec);
423 skip_length = 0;
424 ctx->skip_packets = 0;
425
426 if (options->speed.mode == speed_multiplier) {
427 if(!timerisset(&stats->first_packet_sent_wall_time)) {
428 /* We're sending the first packet, so we have an absolute time reference. */
429 TIMEVAL_SET(&stats->first_packet_sent_wall_time, &now);
430 TIMEVAL_SET(&stats->first_packet_pcap_timestamp, &pkthdr.ts);
431 }
432
433 if (!timerisset(&last_pkt_ts)) {
434 TIMEVAL_SET(&last_pkt_ts, &pkthdr.ts);
435 } else if (timercmp(&pkthdr.ts, &last_pkt_ts, >)) {
436 /* pkt_ts_delta is the packet time stamp difference since the first packet */
437 timersub(&pkthdr.ts, &stats->first_packet_pcap_timestamp, &stats->pkt_ts_delta);
438
439 /* time_delta is the wall time difference since sending the first packet */
440 timersub(&now, &stats->first_packet_sent_wall_time, &stats->time_delta);
441
442 TIMEVAL_SET(&last_pkt_ts, &pkthdr.ts);
443 }
444 }
445
446 if (!top_speed) {
447 now_is_now = true;
448 gettimeofday(&now, NULL);
449 }
450
451 /*
452 * Only if the current packet is not late.
453 *
454 * This also sets skip_length and skip_packets which will avoid
455 * timestamping for a given number of packets.
456 */
457 calc_sleep_time(ctx, &stats->pkt_ts_delta, &stats->time_delta,
458 pktlen, sp, packetnum, &stats->end_time,
459 TIMEVAL_TO_MICROSEC(&stats->start_time), &skip_length);
460
461 /*
462 * Track the time of the "last packet sent".
463 *
464 * A number of 3rd party tools generate bad timestamps which go backwards
465 * in time. Hence, don't update the "last" unless pkthdr.ts > last
466 */
467 if (timercmp(&stats->time_delta, &stats->pkt_ts_delta, <))
468 TIMEVAL_SET(&stats->time_delta, &stats->pkt_ts_delta);
469
470 /*
471 * we know how long to sleep between sends, now do it.
472 */
473 if (!top_speed)
474 tcpr_sleep(ctx, sp, &ctx->nap, &now);
475 }
476
477 #ifdef ENABLE_VERBOSE
478 /* do we need to print the packet via tcpdump? */
479 if (options->verbose)
480 tcpdump_print(options->tcpdump, &pkthdr, pktdata);
481 #endif
482
483 dbgx(2, "Sending packet #" COUNTER_SPEC, packetnum);
484 /* write packet out on network */
485 if (sendpacket(sp, pktdata, pktlen, &pkthdr) < (int)pktlen) {
486 warnx("Unable to send packet: %s", sendpacket_geterr(sp));
487 break;
488 }
489
490 /*
491 * Mark the time when we sent the last packet
492 */
493 TIMEVAL_SET(&stats->end_time, &now);
494
495 #ifdef TIMESTAMP_TRACE
496 add_timestamp_trace_entry(pktlen, &stats->end_time, skip_length);
497 #endif
498
499 stats->pkts_sent++;
500 stats->bytes_sent += pktlen;
501
502 /* print stats during the run? */
503 if (options->stats > 0) {
504 if (! timerisset(&stats->last_print)) {
505 TIMEVAL_SET(&stats->last_print, &now);
506 } else {
507 timersub(&now, &stats->last_print, &print_delta);
508 if (print_delta.tv_sec >= options->stats) {
509 TIMEVAL_SET(&stats->end_time, &now);
510 packet_stats(stats);
511 TIMEVAL_SET(&stats->last_print, &now);
512 }
513 }
514 }
515
516 #if defined HAVE_NETMAP
517 if (sp->first_packet || timesisset(&ctx->nap)) {
518 wake_send_queues(sp, options);
519 sp->first_packet = false;
520 }
521 #endif
522 /* stop sending based on the duration limit... */
523 if ((end_us > 0 && (COUNTER)TIMEVAL_TO_MICROSEC(&now) > end_us) ||
524 /* ... or stop sending based on the limit -L? */
525 (limit_send > 0 && stats->pkts_sent >= limit_send)) {
526 ctx->abort = true;
527 }
528 } /* while */
529
530
531 #ifdef HAVE_NETMAP
532 /* when completing test, wait until the last packet is sent */
533 if (options->netmap && (ctx->abort || options->loop == 1)) {
534 while (ctx->intf1 && !netmap_tx_queues_empty(ctx->intf1)) {
535 now_is_now = true;
536 gettimeofday(&now, NULL);
537 }
538
539 while (ctx->intf2 && !netmap_tx_queues_empty(ctx->intf2)) {
540 now_is_now = true;
541 gettimeofday(&now, NULL);
542 }
543 }
544 #endif /* HAVE_NETMAP */
545
546 if (!now_is_now)
547 gettimeofday(&now, NULL);
548
549 TIMEVAL_SET(&stats->end_time, &now);
550
551 increment_iteration(ctx);
552 }
553
554 /**
555 * the alternate main loop function for tcpreplay. This is where we figure out
556 * what to do with each packet when processing two files a the same time
557 */
558 void
send_dual_packets(tcpreplay_t * ctx,pcap_t * pcap1,int cache_file_idx1,pcap_t * pcap2,int cache_file_idx2)559 send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t *pcap2, int cache_file_idx2)
560 {
561 struct timeval print_delta, now, last_pkt_ts;
562 tcpreplay_opt_t *options = ctx->options;
563 tcpreplay_stats_t *stats = &ctx->stats;
564 COUNTER packetnum = 0;
565 COUNTER limit_send = options->limit_send;
566 int cache_file_idx;
567 struct pcap_pkthdr pkthdr1, pkthdr2;
568 u_char *pktdata1 = NULL, *pktdata2 = NULL, *pktdata = NULL;
569 sendpacket_t *sp;
570 COUNTER pktlen;
571 packet_cache_t *cached_packet1 = NULL, *cached_packet2 = NULL;
572 packet_cache_t **prev_packet1 = NULL, **prev_packet2 = NULL;
573 struct pcap_pkthdr *pkthdr_ptr;
574 int datalink;
575 COUNTER end_us;
576 COUNTER skip_length = 0;
577 bool top_speed = (options->speed.mode == speed_topspeed ||
578 (options->speed.mode == speed_mbpsrate && options->speed.speed == 0));
579 bool now_is_now = true;
580
581 gettimeofday(&now, NULL);
582 if (!timerisset(&stats->start_time)) {
583 TIMEVAL_SET(&stats->start_time, &now);
584 if (ctx->options->stats >= 0) {
585 char buf[64];
586 if (format_date_time(&stats->start_time, buf, sizeof(buf)) > 0)
587 printf("Dual test start: %s ...\n", buf);
588 }
589 }
590
591 ctx->skip_packets = 0;
592 timerclear(&last_pkt_ts);
593 timerclear(&stats->first_packet_sent_wall_time);
594 if (options->limit_time > 0)
595 end_us = TIMEVAL_TO_MICROSEC(&stats->start_time) +
596 SEC_TO_MICROSEC(options->limit_time);
597 else
598 end_us = 0;
599
600 if (options->preload_pcap) {
601 prev_packet1 = &cached_packet1;
602 prev_packet2 = &cached_packet2;
603 } else {
604 prev_packet1 = NULL;
605 prev_packet2 = NULL;
606 }
607
608 pktdata1 = get_next_packet(ctx, pcap1, &pkthdr1, cache_file_idx1, prev_packet1);
609 pktdata2 = get_next_packet(ctx, pcap2, &pkthdr2, cache_file_idx2, prev_packet2);
610
611 /* MAIN LOOP
612 * Keep sending while we have packets or until
613 * we've sent enough packets
614 */
615 while (!ctx->abort &&
616 !(pktdata1 == NULL && pktdata2 == NULL)) {
617
618 now_is_now = false;
619 packetnum++;
620
621 /* figure out which pcap file we need to process next
622 * when get_next_packet() returns null for pktdata, the pkthdr
623 * will still have the old values from the previous call. This
624 * means we can't always trust the timestamps to tell us which
625 * file to process.
626 */
627 if (pktdata1 == NULL) {
628 /* file 2 is next */
629 sp = ctx->intf2;
630 datalink = options->file_cache[cache_file_idx2].dlt;
631 pkthdr_ptr = &pkthdr2;
632 cache_file_idx = cache_file_idx2;
633 pktdata = pktdata2;
634 } else if (pktdata2 == NULL) {
635 /* file 1 is next */
636 sp = ctx->intf1;
637 datalink = options->file_cache[cache_file_idx1].dlt;
638 pkthdr_ptr = &pkthdr1;
639 cache_file_idx = cache_file_idx1;
640 pktdata = pktdata1;
641 } else if (timercmp(&pkthdr1.ts, &pkthdr2.ts, <=)) {
642 /* file 1 is next */
643 sp = ctx->intf1;
644 datalink = options->file_cache[cache_file_idx1].dlt;
645 pkthdr_ptr = &pkthdr1;
646 cache_file_idx = cache_file_idx1;
647 pktdata = pktdata1;
648 } else {
649 /* file 2 is next */
650 sp = ctx->intf2;
651 datalink = options->file_cache[cache_file_idx2].dlt;
652 pkthdr_ptr = &pkthdr2;
653 cache_file_idx = cache_file_idx2;
654 pktdata = pktdata2;
655 }
656
657 #if defined TCPREPLAY || defined TCPREPLAY_EDIT
658 /* do we use the snaplen (caplen) or the "actual" packet len? */
659 pktlen = options->use_pkthdr_len ? (COUNTER)pkthdr_ptr->len : (COUNTER)pkthdr_ptr->caplen;
660 #elif TCPBRIDGE
661 pktlen = (COUNTER)pkthdr_ptr->caplen;
662 #else
663 #error WTF??? We should not be here!
664 #endif
665
666 dbgx(2, "packet " COUNTER_SPEC " caplen " COUNTER_SPEC, packetnum, pktlen);
667
668 #if defined TCPREPLAY && defined TCPREPLAY_EDIT
669 if (tcpedit_packet(tcpedit, &pkthdr_ptr, &pktdata, sp->cache_dir) == -1) {
670 errx(-1, "Error editing packet #" COUNTER_SPEC ": %s", packetnum, tcpedit_geterr(tcpedit));
671 }
672 pktlen = options->use_pkthdr_len ? (COUNTER)pkthdr_ptr->len : (COUNTER)pkthdr_ptr->caplen;
673 #endif
674
675 if (ctx->options->unique_ip && ctx->unique_iteration &&
676 ctx->unique_iteration > ctx->last_unique_iteration) {
677 /* edit packet to ensure every pass is unique */
678 if (fast_edit_packet(pkthdr_ptr, &pktdata, ctx->unique_iteration - 1,
679 options->file_cache[cache_file_idx].cached, datalink) == -1) {
680 ++stats->failed;
681 continue;
682 }
683 }
684
685 /* update flow stats */
686 if (options->flow_stats && !options->file_cache[cache_file_idx].cached)
687 update_flow_stats(ctx, sp, pkthdr_ptr, pktdata, datalink);
688
689 /*
690 * this accelerator improves performance by avoiding expensive
691 * time stamps during periods where we have fallen behind in our
692 * sending
693 */
694 if (skip_length && pktlen < skip_length) {
695 skip_length -= pktlen;
696 } else if (ctx->skip_packets) {
697 --ctx->skip_packets;
698 } else {
699 /*
700 * time stamping is expensive, but now is the
701 * time to do it.
702 */
703 dbgx(4, "This packet time: " TIMEVAL_FORMAT, pkthdr_ptr->ts.tv_sec,
704 pkthdr_ptr->ts.tv_usec);
705 skip_length = 0;
706 ctx->skip_packets = 0;
707
708 if (options->speed.mode == speed_multiplier) {
709 if(!timerisset(&stats->first_packet_sent_wall_time)) {
710 /* We're sending the first packet, so we have an absolute time reference. */
711 TIMEVAL_SET(&stats->first_packet_sent_wall_time, &now);
712 TIMEVAL_SET(&stats->first_packet_pcap_timestamp, &pkthdr_ptr->ts);
713 }
714
715 if (!timerisset(&last_pkt_ts)) {
716 TIMEVAL_SET(&last_pkt_ts, &pkthdr_ptr->ts);
717 } else if (timercmp(&pkthdr_ptr->ts, &last_pkt_ts, >)) {
718 /* pkt_ts_delta is the packet time stamp difference since the first packet */
719 timersub(&pkthdr_ptr->ts, &stats->first_packet_pcap_timestamp, &stats->pkt_ts_delta);
720
721 /* time_delta is the wall time difference since sending the first packet */
722 timersub(&now, &stats->first_packet_sent_wall_time, &stats->time_delta);
723
724 TIMEVAL_SET(&last_pkt_ts, &pkthdr_ptr->ts);
725 }
726 }
727
728 if (!top_speed) {
729 gettimeofday(&now, NULL);
730 now_is_now = true;
731 }
732
733 /*
734 * Only if the current packet is not late.
735 *
736 * This also sets skip_length and skip_packets which will avoid
737 * timestamping for a given number of packets.
738 */
739 calc_sleep_time(ctx, &stats->pkt_ts_delta, &stats->time_delta,
740 pktlen, sp, packetnum, &stats->end_time,
741 TIMEVAL_TO_MICROSEC(&stats->start_time), &skip_length);
742
743 /*
744 * Track the time of the "last packet sent".
745 *
746 * A number of 3rd party tools generate bad timestamps which go backwards
747 * in time. Hence, don't update the "last" unless pkthdr_ptr->ts > last
748 */
749 if (timercmp(&stats->time_delta, &stats->pkt_ts_delta, <))
750 TIMEVAL_SET(&stats->time_delta, &stats->pkt_ts_delta);
751
752 /*
753 * we know how long to sleep between sends, now do it.
754 */
755 if (!top_speed)
756 tcpr_sleep(ctx, sp, &ctx->nap, &now);
757 }
758
759 #ifdef ENABLE_VERBOSE
760 /* do we need to print the packet via tcpdump? */
761 if (options->verbose)
762 tcpdump_print(options->tcpdump, pkthdr_ptr, pktdata);
763 #endif
764
765 dbgx(2, "Sending packet #" COUNTER_SPEC, packetnum);
766 /* write packet out on network */
767 if (sendpacket(sp, pktdata, pktlen, pkthdr_ptr) < (int)pktlen) {
768 warnx("Unable to send packet: %s", sendpacket_geterr(sp));
769 break;
770 }
771
772 /*
773 * Mark the time when we sent the last packet
774 */
775 TIMEVAL_SET(&stats->end_time, &now);
776
777 ++stats->pkts_sent;
778 stats->bytes_sent += pktlen;
779
780 /* print stats during the run? */
781 if (options->stats > 0) {
782 if (! timerisset(&stats->last_print)) {
783 TIMEVAL_SET(&stats->last_print, &now);
784 } else {
785 timersub(&now, &stats->last_print, &print_delta);
786 if (print_delta.tv_sec >= options->stats) {
787 TIMEVAL_SET(&stats->end_time, &now);
788 packet_stats(stats);
789 TIMEVAL_SET(&stats->last_print, &now);
790 }
791 }
792 }
793
794 #if defined HAVE_NETMAP
795 if (sp->first_packet || timesisset(&ctx->nap)) {
796 wake_send_queues(sp, options);
797 sp->first_packet = false;
798 }
799 #endif
800
801 /* get the next packet for this file handle depending on which we last used */
802 if (sp == ctx->intf2) {
803 pktdata2 = get_next_packet(ctx, pcap2, &pkthdr2, cache_file_idx2, prev_packet2);
804 } else {
805 pktdata1 = get_next_packet(ctx, pcap1, &pkthdr1, cache_file_idx1, prev_packet1);
806 }
807
808 /* stop sending based on the duration limit... */
809 if ((end_us > 0 && (COUNTER)TIMEVAL_TO_MICROSEC(&now) > end_us) ||
810 /* ... or stop sending based on the limit -L? */
811 (limit_send > 0 && stats->pkts_sent >= limit_send)) {
812 ctx->abort = true;
813 }
814 } /* while */
815
816 #ifdef HAVE_NETMAP
817 /* when completing test, wait until the last packet is sent */
818 if (options->netmap && (ctx->abort || options->loop == 1)) {
819 while (ctx->intf1 && !netmap_tx_queues_empty(ctx->intf1)) {
820 gettimeofday(&now, NULL);
821 now_is_now = true;
822 }
823
824 while (ctx->intf2 && !netmap_tx_queues_empty(ctx->intf2)) {
825 gettimeofday(&now, NULL);
826 now_is_now = true;
827 }
828 }
829 #endif /* HAVE_NETMAP */
830
831 if (!now_is_now)
832 gettimeofday(&now, NULL);
833
834 TIMEVAL_SET(&stats->end_time, &now);
835
836 increment_iteration(ctx);
837 }
838
839
840
841 /**
842 * Gets the next packet to be sent out. This will either read from the pcap file
843 * or will retrieve the packet from the internal cache.
844 *
845 * The parameter prev_packet is used as the parent of the new entry in the cache list.
846 * This should be NULL on the first call to this function for each file and
847 * will be updated as new entries are added (or retrieved) from the cache list.
848 */
849 u_char *
get_next_packet(tcpreplay_t * ctx,pcap_t * pcap,struct pcap_pkthdr * pkthdr,int idx,packet_cache_t ** prev_packet)850 get_next_packet(tcpreplay_t *ctx, pcap_t *pcap, struct pcap_pkthdr *pkthdr, int idx,
851 packet_cache_t **prev_packet)
852 {
853 tcpreplay_opt_t *options = ctx->options;
854 u_char *pktdata = NULL;
855 uint32_t pktlen;
856
857 /* pcap may be null in cache mode! */
858 /* packet_cache_t may be null in file read mode! */
859 assert(pkthdr);
860
861 /*
862 * Check if we're caching files
863 */
864 if (options->preload_pcap && (prev_packet != NULL)) {
865 /*
866 * Yes we are caching files - has this one been cached?
867 */
868 if (options->file_cache[idx].cached) {
869 if (*prev_packet == NULL) {
870 /*
871 * Get the first packet in the cache list directly from the file
872 */
873 *prev_packet = options->file_cache[idx].packet_cache;
874 } else {
875 /*
876 * Get the next packet in the cache list
877 */
878 *prev_packet = (*prev_packet)->next;
879 }
880
881 if (*prev_packet != NULL) {
882 pktdata = (*prev_packet)->pktdata;
883 memcpy(pkthdr, &((*prev_packet)->pkthdr), sizeof(struct pcap_pkthdr));
884 }
885 } else {
886 /*
887 * We should read the pcap file, and cache the results
888 */
889 pktdata = safe_pcap_next(pcap, pkthdr);
890 if (pktdata != NULL) {
891 if (*prev_packet == NULL) {
892 /*
893 * Create the first packet in the list
894 */
895 *prev_packet = safe_malloc(sizeof(packet_cache_t));
896 options->file_cache[idx].packet_cache = *prev_packet;
897 } else {
898 /*
899 * Add a packet to the end of the list
900 */
901 (*prev_packet)->next = safe_malloc(sizeof(packet_cache_t));
902 *prev_packet = (*prev_packet)->next;
903 }
904
905 if (*prev_packet != NULL) {
906 (*prev_packet)->next = NULL;
907 pktlen = pkthdr->caplen;
908
909 (*prev_packet)->pktdata = safe_malloc(pktlen + PACKET_HEADROOM);
910 memcpy((*prev_packet)->pktdata, pktdata, pktlen);
911 memcpy(&((*prev_packet)->pkthdr), pkthdr, sizeof(struct pcap_pkthdr));
912 }
913 }
914 }
915 } else {
916 /*
917 * Read pcap file as normal
918 */
919 pktdata = safe_pcap_next(pcap, pkthdr);
920 }
921
922 /* this gets casted to a const on the way out */
923 return pktdata;
924 }
925
926 /**
927 * determines based upon the cachedata which interface the given packet
928 * should go out. Also rewrites any layer 2 data we might need to adjust.
929 * Returns a void cased pointer to the ctx->intfX of the corresponding
930 * interface or NULL on error
931 */
932 void *
cache_mode(tcpreplay_t * ctx,char * cachedata,COUNTER packet_num)933 cache_mode(tcpreplay_t *ctx, char *cachedata, COUNTER packet_num)
934 {
935 tcpreplay_opt_t *options = ctx->options;
936 void *sp = NULL;
937 int result;
938
939 if (packet_num > options->cache_packets) {
940 tcpreplay_seterr(ctx, "%s", "Exceeded number of packets in cache file.");
941 return NULL;
942 }
943
944 result = check_cache(cachedata, packet_num);
945 if (result == TCPR_DIR_NOSEND) {
946 dbgx(2, "Cache: Not sending packet " COUNTER_SPEC ".", packet_num);
947 return NULL;
948 }
949 else if (result == TCPR_DIR_C2S) {
950 dbgx(2, "Cache: Sending packet " COUNTER_SPEC " out primary interface.", packet_num);
951 sp = ctx->intf1;
952 }
953 else if (result == TCPR_DIR_S2C) {
954 dbgx(2, "Cache: Sending packet " COUNTER_SPEC " out secondary interface.", packet_num);
955 sp = ctx->intf2;
956 }
957 else {
958 tcpreplay_seterr(ctx, "Invalid cache value: %i", result);
959 return NULL;
960 }
961
962 return sp;
963 }
964
965
966 /**
967 * Given the timestamp on the current packet and the last packet sent,
968 * calculate the appropriate amount of time to sleep. Sleep time
969 * will be in ctx->nap.
970 */
calc_sleep_time(tcpreplay_t * ctx,struct timeval * pkt_ts_delta,struct timeval * time_delta,COUNTER len,sendpacket_t * sp,COUNTER counter,timestamp_t * sent_timestamp,COUNTER start_us,COUNTER * skip_length)971 static void calc_sleep_time(tcpreplay_t *ctx, struct timeval *pkt_ts_delta,
972 struct timeval *time_delta, COUNTER len,
973 sendpacket_t *sp, COUNTER counter, timestamp_t *sent_timestamp,
974 COUNTER start_us, COUNTER *skip_length)
975 {
976 tcpreplay_opt_t *options = ctx->options;
977 struct timeval nap_for;
978 COUNTER now_us;
979
980 timesclear(&ctx->nap);
981
982 /*
983 * pps_multi accelerator. This uses the existing send accelerator
984 * and hence requires the funky math to get the expected timings.
985 */
986 if (options->speed.mode == speed_packetrate && options->speed.pps_multi) {
987 ctx->skip_packets = options->speed.pps_multi - 1;
988 }
989
990 /* no last packet sent, just leave */
991 if (ctx->first_time) {
992 ctx->first_time = false;
993 return;
994 }
995
996 switch(options->speed.mode) {
997 case speed_multiplier:
998 /*
999 * Replay packets a factor of the time they were originally sent.
1000 * Make sure the packet is not late.
1001 */
1002 if (timercmp(pkt_ts_delta, time_delta, >)) {
1003 /* pkt_time_delta has increased, so handle normally */
1004 timersub(pkt_ts_delta, time_delta, &nap_for);
1005 TIMEVAL_TO_TIMESPEC(&nap_for, &ctx->nap);
1006 dbgx(3, "original packet delta time: " TIMESPEC_FORMAT,
1007 ctx->nap.tv_sec, ctx->nap.tv_nsec);
1008 timesdiv_float(&ctx->nap, options->speed.multiplier);
1009 dbgx(3, "original packet delta/div: " TIMESPEC_FORMAT,
1010 ctx->nap.tv_sec, ctx->nap.tv_nsec);
1011 }
1012 break;
1013
1014 case speed_mbpsrate:
1015 /*
1016 * Ignore the time supplied by the capture file and send data at
1017 * a constant 'rate' (bytes per second).
1018 */
1019 now_us = TIMSTAMP_TO_MICROSEC(sent_timestamp);
1020 if (now_us) {
1021 COUNTER next_tx_us;
1022 COUNTER bps = options->speed.speed;
1023 COUNTER bits_sent = ((ctx->stats.bytes_sent + len) * 8);
1024 COUNTER tx_us = now_us - start_us;
1025
1026 /*
1027 * bits * 1000000 divided by bps = microseconds
1028 *
1029 * ensure there is no overflow in cases where bits_sent is very high
1030 */
1031 if (bits_sent > COUNTER_OVERFLOW_RISK && bps > 500000)
1032 next_tx_us = (bits_sent * 1000) / bps * 1000;
1033 else
1034 next_tx_us = (bits_sent * 1000000) / bps;
1035
1036 if (next_tx_us > tx_us) {
1037 NANOSEC_TO_TIMESPEC((next_tx_us - tx_us) * 1000, &ctx->nap);
1038 } else if (tx_us > next_tx_us) {
1039 tx_us = now_us - start_us;
1040 *skip_length = ((tx_us - next_tx_us) * bps) / 8000000;
1041 }
1042
1043 update_current_timestamp_trace_entry(ctx->stats.bytes_sent +
1044 (COUNTER)len, now_us, tx_us, next_tx_us);
1045 }
1046
1047 dbgx(3, "packet size=" COUNTER_SPEC "\t\tnap=" TIMESPEC_FORMAT, len,
1048 ctx->nap.tv_sec, ctx->nap.tv_nsec);
1049 break;
1050
1051 case speed_packetrate:
1052 /*
1053 * Ignore the time supplied by the capture file and send data at
1054 * a constant rate (packets per second).
1055 */
1056 now_us = TIMSTAMP_TO_MICROSEC(sent_timestamp);
1057 if (now_us) {
1058 COUNTER next_tx_us;
1059 COUNTER pph = ctx->options->speed.speed;
1060 COUNTER pkts_sent = ctx->stats.pkts_sent;
1061 COUNTER tx_us = now_us - start_us;
1062 /*
1063 * packets * 1000000 divided by pps = microseconds
1064 * packets per sec (pps) = packets per hour / (60 * 60)
1065 *
1066 * Adjust for long running tests with high PPS to prevent overflow.
1067 * When active, adjusted calculation may add a bit of jitter.
1068 */
1069 if ((pkts_sent < COUNTER_OVERFLOW_RISK))
1070 next_tx_us = (pkts_sent * 1000000) * (60 * 60) / pph;
1071 else
1072 next_tx_us = (pkts_sent * 1000000) / pph / (60 * 60);
1073
1074 if (next_tx_us > tx_us)
1075 NANOSEC_TO_TIMESPEC((next_tx_us - tx_us) * 1000, &ctx->nap);
1076 else
1077 ctx->skip_packets = options->speed.pps_multi;
1078
1079 update_current_timestamp_trace_entry(ctx->stats.bytes_sent +
1080 (COUNTER)len, now_us, tx_us, next_tx_us);
1081 }
1082
1083 dbgx(3, "packet count=" COUNTER_SPEC "\t\tnap=" TIMESPEC_FORMAT,
1084 ctx->stats.pkts_sent, ctx->nap.tv_sec, ctx->nap.tv_nsec);
1085 break;
1086
1087 case speed_oneatatime:
1088 /* do we skip prompting for a key press? */
1089 if (ctx->skip_packets == 0) {
1090 ctx->skip_packets = get_user_count(ctx, sp, counter);
1091 }
1092
1093 /* decrement our send counter */
1094 printf("Sending packet " COUNTER_SPEC " out: %s\n", counter,
1095 sp == ctx->intf1 ? options->intf1_name : options->intf2_name);
1096 ctx->skip_packets--;
1097
1098 /* leave */
1099 break;
1100
1101 case speed_topspeed:
1102 break;
1103
1104 default:
1105 errx(-1, "Unknown/supported speed mode: %d", options->speed.mode);
1106 break;
1107 }
1108 }
1109
tcpr_sleep(tcpreplay_t * ctx,sendpacket_t * sp,struct timespec * nap_this_time,struct timeval * now)1110 static void tcpr_sleep(tcpreplay_t *ctx, sendpacket_t *sp,
1111 struct timespec *nap_this_time, struct timeval *now)
1112 {
1113 tcpreplay_opt_t *options = ctx->options;
1114 bool flush =
1115 #ifdef HAVE_NETMAP
1116 true;
1117 #else
1118 false;
1119 #endif
1120
1121
1122 /* don't sleep if nap = {0, 0} */
1123 if (!timesisset(nap_this_time))
1124 return;
1125
1126 /* do we need to limit the total time we sleep? */
1127 if (timesisset(&(options->maxsleep)) && (timescmp(nap_this_time, &(options->maxsleep), >))) {
1128 dbgx(2, "Was going to sleep for " TIMESPEC_FORMAT " but maxsleeping for " TIMESPEC_FORMAT,
1129 nap_this_time->tv_sec, nap_this_time->tv_nsec, options->maxsleep.tv_sec,
1130 options->maxsleep.tv_nsec);
1131 TIMESPEC_SET(nap_this_time, &options->maxsleep);
1132 }
1133
1134 if (flush)
1135 wake_send_queues(sp, options);
1136
1137 dbgx(2, "Sleeping: " TIMESPEC_FORMAT,
1138 nap_this_time->tv_sec, nap_this_time->tv_nsec);
1139
1140 /*
1141 * Depending on the accurate method & packet rate computation method
1142 * We have multiple methods of sleeping, pick the right one...
1143 */
1144 switch (options->accurate) {
1145 #ifdef HAVE_SELECT
1146 case accurate_select:
1147 select_sleep(sp, nap_this_time, now, flush);
1148 break;
1149 #endif
1150
1151 #if defined HAVE_IOPORT_SLEEP
1152 case accurate_ioport:
1153 ioport_sleep(sp, nap_this_time, now, flush);
1154 break;
1155 #endif
1156
1157 case accurate_gtod:
1158 gettimeofday_sleep(sp, nap_this_time, now, flush);
1159 break;
1160
1161 case accurate_nanosleep:
1162 nanosleep_sleep(sp, nap_this_time, now, flush);
1163 break;
1164
1165 default:
1166 errx(-1, "Unknown timer mode %d", options->accurate);
1167 }
1168 }
1169
1170 /**
1171 * Ask the user how many packets they want to send.
1172 */
1173 static uint32_t
get_user_count(tcpreplay_t * ctx,sendpacket_t * sp,COUNTER counter)1174 get_user_count(tcpreplay_t *ctx, sendpacket_t *sp, COUNTER counter)
1175 {
1176 tcpreplay_opt_t *options = ctx->options;
1177 struct pollfd poller[1]; /* use poll to read from the keyboard */
1178 char input[EBUF_SIZE];
1179 unsigned long send = 0;
1180
1181 printf("**** Next packet #" COUNTER_SPEC " out %s. How many packets do you wish to send? ",
1182 counter, (sp == ctx->intf1 ? options->intf1_name : options->intf2_name));
1183 fflush(NULL);
1184 poller[0].fd = STDIN_FILENO;
1185 poller[0].events = POLLIN | POLLPRI | POLLNVAL;
1186 poller[0].revents = 0;
1187
1188 if (fcntl(0, F_SETFL, fcntl(0, F_GETFL) & ~O_NONBLOCK))
1189 errx(-1, "Unable to clear non-blocking flag on stdin: %s", strerror(errno));
1190
1191 /* wait for the input */
1192 if (poll(poller, 1, -1) < 0)
1193 errx(-1, "Error reading user input from stdin: %s", strerror(errno));
1194
1195 /*
1196 * read to the end of the line or EBUF_SIZE,
1197 * Note, if people are stupid, and type in more text then EBUF_SIZE
1198 * then the next fgets() will pull in that data, which will have poor
1199 * results. fuck them.
1200 */
1201 if (fgets(input, sizeof(input), stdin) == NULL) {
1202 errx(-1, "Unable to process user input for fd %d: %s", fileno(stdin), strerror(errno));
1203 } else if (strlen(input) > 1) {
1204 send = strtoul(input, NULL, 0);
1205 }
1206
1207 /* how many packets should we send? */
1208 if (send == 0) {
1209 dbg(1, "Input was less then 1 or non-numeric, assuming 1");
1210
1211 /* assume send only one packet */
1212 send = 1;
1213 }
1214
1215 return(uint32_t)send;
1216 }
1217