tcpreplay.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /*
  2. tcpreplay.c
  3. Matt Undy <mundy@anzen.com>
  4. Copyright (c) 1999 Anzen Computing. All rights reserved.
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions
  7. are met:
  8. 1. Redistributions of source code must retain the above copyright
  9. notice, this list of conditions and the following disclaimer.
  10. 2. Redistributions in binary form must reproduce the above copyright
  11. notice, this list of conditions and the following disclaimer in the
  12. documentation and/or other materials provided with the distribution.
  13. 3. All advertising materials mentioning features or use of this software
  14. must display the following acknowledgement:
  15. This product includes software developed by Anzen Computing, Inc.
  16. 4. Neither the name of Anzen Computing, Inc. nor the names of its
  17. contributors may be used to endorse or promote products derived
  18. from this software without specific prior written permission.
  19. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  20. WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  21. MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  23. DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24. DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  25. GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  26. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  27. IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  28. OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  29. ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. Notes:
  31. The performance of paced modes could be increased somewhat by
  32. estimating sleep time and only checking against the RTC ocasionally,
  33. although this would also result in a less precise data rate,
  34. especially on machines with an imprecise usleep().
  35. */
  36. #ifdef HAVE_CONFIG_H
  37. #include "config.h"
  38. #endif /* HAVE_CONFIG_H */
  39. #include <stdio.h>
  40. #include <stdlib.h>
  41. #if TIME_WITH_SYS_TIME
  42. # include <sys/time.h>
  43. # include <time.h>
  44. #else
  45. # if HAVE_SYS_TIME_H
  46. # include <sys/time.h>
  47. # else
  48. # include <time.h>
  49. # endif
  50. #endif
  51. #include <pcap.h>
  52. #include <libnet.h>
  53. #define TCPREPLAY_VERSION "1.0.1"
  54. #define PACE 1 /*0b01*/
  55. #define RATE 2 /*0b10*/
  56. #define TIME_GT(x,y) (x tv_sec>y tv_sec||(x tv_sec==y tv_sec&&x tv_usec>y tv_usec))
  57. #define TIME_LT(x,y) (x tv_sec<y tv_sec||(x tv_sec==y tv_sec&&x tv_usec<y tv_usec))
  58. #define TIME_ASSIGN(x,y) x tv_sec=y tv_sec; x tv_usec=y tv_usec;
  59. #define PRINT_TIMEVAL(x) fprintf(stderr, " tv_sec=%li tv_usec=%li\n",x tv_sec, x tv_usec);
  60. typedef struct timeval time_struct;
  61. extern int errno;
  62. int failed_writes, first_pkt,older_pkts;
  63. int pkts_sent;
  64. long long bytes_sent;
  65. int iterrations;
  66. int mode;
  67. int rate;
  68. int debug;
  69. float multiplier;
  70. struct timeval lasttime, lastpkt, behind_time, starttime_struc,
  71. startpkt_struct, last_dpkt, starttime, pkttime_struct;
  72. int caplen;
  73. int iterations;
  74. char * interface;
  75. void usage(){
  76. fprintf(stderr, "Version: " TCPREPLAY_VERSION "\nUsage: tcpreplay "
  77. "[-i interface] [-l loops] [-m multiplier] [-r rate] <file>\n");
  78. exit (1);
  79. }
  80. /* we aren't checking for overflow here. if it happens we have run
  81. into the 2038 problem and the whole time handling is broken (or a bug). */
  82. void addtime(time_struct * op1,time_struct * op2,time_struct * result)
  83. {
  84. result->tv_usec = op1->tv_usec+op2->tv_usec;
  85. if (result->tv_usec > 999999) {
  86. result->tv_usec -= 1000000;
  87. op1->tv_sec++;
  88. }
  89. result->tv_sec = op1->tv_sec+op2->tv_sec;
  90. }
  91. /*
  92. if op1>op2, return op1-op2 and 0
  93. if op1<op2, return |op1-op2| and 1
  94. (return a negative # with the sign bit in the return int)
  95. if op2>op1, subtract op2 from op1 and set return int
  96. */
  97. int subtime(time_struct * op1, time_struct * op2, time_struct * result)
  98. {
  99. int borrow=0;
  100. int sign=0;
  101. time_struct * temp_time;
  102. if (TIME_LT(op1->, op2->)) {
  103. sign = 1;
  104. temp_time = op1;
  105. op1 = op2;
  106. op2 = temp_time;
  107. }
  108. if (op1->tv_usec >= op2->tv_usec) {
  109. result->tv_usec = op1->tv_usec-op2->tv_usec;
  110. }
  111. else {
  112. result->tv_usec = (op1->tv_usec+1000000)-op2->tv_usec;
  113. borrow = 1;
  114. }
  115. result->tv_sec = (op1->tv_sec-op2->tv_sec)-borrow;
  116. return sign;
  117. }
  118. void divtime(time_struct * num, float denom) {
  119. num->tv_sec = num->tv_sec/denom;
  120. num->tv_usec = num->tv_usec/denom;
  121. }
  122. void write_packet(u_char * user,struct pcap_pkthdr* pcap_hdr, u_char * data)
  123. {
  124. int write_status = -1;
  125. float sec;
  126. struct timeval now, dtime, dpkt, sleeptime;
  127. if (mode) {
  128. #if HAVE_GETTIMEOFDAY
  129. gettimeofday(&now,NULL);
  130. #endif
  131. iterations++;
  132. #ifdef DEBUG
  133. if ((!(iterations %99))&&debug>0) {
  134. fprintf(stderr, "\nELAPSED TIME %lu sec %li usec\n\n",
  135. now.tv_sec-starttime_struc.tv_sec,
  136. now.tv_usec - starttime_struc.tv_usec);
  137. fprintf(stderr, "\nELAPSED PACKET TIME %lu sec %li usec\n\n",
  138. pcap_hdr->ts.tv_sec - startpkt_struct.tv_sec,
  139. pcap_hdr->ts.tv_usec - startpkt_struct.tv_usec);
  140. }
  141. #endif
  142. if (first_pkt) {
  143. first_pkt = 0;
  144. TIME_ASSIGN(starttime_struc., now.);
  145. TIME_ASSIGN(lastpkt., pcap_hdr->ts.);
  146. TIME_ASSIGN(startpkt_struct., pcap_hdr->ts.);
  147. }
  148. if (subtime(&now, &starttime_struc, &dtime)) {
  149. fprintf(stderr, "The RTC has decreased since last read (or someone multithreaded this wrong)\n");
  150. /*if it is earlier than the last time we executed this loop,
  151. something is very wrong*/
  152. abort();
  153. }
  154. if (mode & PACE) {
  155. if (subtime(&pcap_hdr->ts, &lastpkt, &dpkt)) {
  156. /*Uncomment this if you want to stop on out of order packets
  157. in the dump file*/
  158. /*fprintf(stderr, "packets in pcap file not in increasing time of arrival\n");
  159. abort();*/
  160. older_pkts++;
  161. }
  162. else {
  163. divtime(&dpkt, multiplier);
  164. addtime(&dpkt, &pkttime_struct, &pkttime_struct);
  165. }
  166. #ifdef DEBUG
  167. if (debug > 2) {
  168. fprintf(stderr, "dtime: ");
  169. PRINT_TIMEVAL(dtime.);
  170. fprintf(stderr, "pkttime_struct: ");
  171. PRINT_TIMEVAL(pkttime_struct.);
  172. }
  173. #endif
  174. }
  175. if (mode & RATE) {
  176. /*calculate time packet should take, add to total packet time. */
  177. sec = (float)pcap_hdr->caplen / (float)rate;
  178. dpkt.tv_sec = sec;
  179. dpkt.tv_usec = (sec - dpkt.tv_sec) * 1000000;
  180. #ifdef DEBUG
  181. if (debug > 2) {
  182. fprintf(stderr, "dpkt:");
  183. PRINT_TIMEVAL(dpkt.);
  184. }
  185. #endif
  186. addtime(&dpkt, &pkttime_struct, &pkttime_struct);
  187. #ifdef DEBUG
  188. if (debug > 2) {
  189. fprintf(stderr, "pkttime_struct: ");
  190. PRINT_TIMEVAL(pkttime_struct.);
  191. }
  192. #endif
  193. }
  194. if (subtime(&dtime, &pkttime_struct, &sleeptime)) {
  195. /*we are ahead by pkttime if true*/
  196. #ifdef DEBUG
  197. if (debug > 2) {
  198. fprintf(stderr, "sleeptime: ");
  199. PRINT_TIMEVAL(sleeptime.);
  200. }
  201. #endif
  202. sleep(sleeptime.tv_sec);
  203. usleep(sleeptime.tv_usec);
  204. }
  205. TIME_ASSIGN(lastpkt., pcap_hdr->ts.);
  206. }
  207. while (write_status < 0) {
  208. write_status = write_link_layer((struct link_int *)user, interface,
  209. data,pcap_hdr->caplen);
  210. #ifdef DEBUG
  211. if (debug > 1) {
  212. fprintf(stderr, "write_status = %i\n", write_status);
  213. }
  214. #endif
  215. if (write_status < 0) {
  216. /*if errno = = 55(ENOBUFS) loop, otherwise break*/
  217. if (errno != ENOBUFS) {
  218. fprintf(stderr, "errno = %i\n", errno);
  219. perror("pcap_inject");
  220. exit(1);
  221. }
  222. else {
  223. failed_writes++;
  224. }
  225. }
  226. }
  227. bytes_sent += write_status;
  228. pkts_sent++;
  229. }
  230. int main(int argc, char * argv[])
  231. {
  232. pcap_t * in_file;
  233. struct link_int * write_if;
  234. float Mrate = 0;
  235. double starttime_local, startusec;
  236. char ebuf[256];
  237. struct timeval tp;
  238. extern char *optarg;
  239. extern int optind;
  240. int ch, iterrated,files = 0;
  241. char * name = NULL;
  242. int stdinput = 0;
  243. debug = 0;
  244. iterrations = 1;
  245. mode = 0;
  246. interface = NULL;
  247. while ((ch = getopt(argc, argv, "i:l:r:m:h")) != -1)
  248. switch(ch) {
  249. case 'd':
  250. debug++;
  251. break;
  252. case 'm':
  253. multiplier = atof(optarg);
  254. mode = mode | PACE;
  255. break;
  256. case 'r':
  257. mode = mode | RATE;
  258. Mrate = atof(optarg);
  259. rate = (Mrate * (1024 * 1024)) / 8;
  260. break;
  261. case 'l':
  262. iterrations = atoi(optarg);
  263. break;
  264. case 'i':
  265. interface = optarg;
  266. break;
  267. case 'h':
  268. usage();
  269. break;
  270. default:
  271. usage();
  272. }
  273. if ((mode & PACE) && (mode & RATE)) {
  274. usage();
  275. }
  276. if ((mode & PACE) && multiplier == 0) {
  277. fprintf(stderr, "invalid pace multiplier - use a nonzero multiplier\n");
  278. usage();
  279. }
  280. if ((mode & RATE) && (Mrate == 0)) {
  281. fprintf(stderr, "invalid sending rate - use a nonzero rate\n");
  282. usage();
  283. }
  284. if (interface == NULL) {
  285. if (!(interface = pcap_lookupdev(ebuf))) {
  286. fprintf(stderr, "can't determine default interface: %s\n", ebuf);
  287. exit(1);
  288. }
  289. }
  290. iterations = 0;
  291. older_pkts = 0;
  292. #if HAVE_GETTIMEOFDAY
  293. gettimeofday(&tp,NULL);
  294. #endif
  295. /*if you don't have gettimeofday, you will have to add the appropriate
  296. syscall for your system*/
  297. starttime_local = tp.tv_sec;
  298. startusec = tp.tv_usec;
  299. failed_writes = 0;
  300. pkts_sent = 0;
  301. bytes_sent = 0;
  302. write_if = open_link_interface(interface,ebuf);
  303. if (write_if <= 0) {
  304. fprintf(stderr, "output i/f: %s\n",ebuf);
  305. exit(1);
  306. }
  307. /*need to account for no args*/
  308. if (argc == optind) {
  309. stdinput = 1;
  310. }
  311. for (files=0;files < argc-optind || stdinput;files++) {
  312. if (stdinput) {
  313. name = malloc(4);
  314. strcpy(name,"-");
  315. }
  316. else {
  317. name = argv[files+optind];
  318. }
  319. for (iterrated = 0; iterrated < iterrations; iterrated++){
  320. first_pkt = 1;
  321. #if HAVE_GETTIMEOFDAY
  322. gettimeofday(&tp,NULL);
  323. #endif
  324. pkttime_struct.tv_sec = 0;
  325. pkttime_struct.tv_usec = 0;
  326. lasttime.tv_sec = tp.tv_sec;
  327. lasttime.tv_usec = tp.tv_usec;
  328. in_file = pcap_open_offline(name, ebuf);
  329. if (!in_file) {
  330. fprintf(stderr, "Error opening %s for reading\n",argv[1]);
  331. fprintf(stderr, "in_file: %s\n",ebuf);
  332. exit (1);
  333. }
  334. if (pcap_dispatch(in_file, 0,(void *)&write_packet,
  335. (u_char *) write_if) == -1) {
  336. pcap_perror(in_file, argv[1]);
  337. }
  338. pcap_close(in_file);
  339. }
  340. stdinput = 0;
  341. }
  342. if (failed_writes) {
  343. fprintf(stderr, "%i write attempts failed from full buffers and were repeated\n", failed_writes);
  344. }
  345. if (older_pkts) {
  346. fprintf(stderr, "%i packet delays removed because they were out of order\n", older_pkts);
  347. }
  348. fprintf(stderr, "%i packets sucessfully sent", pkts_sent);
  349. #if HAVE_GETTIMEOFDAY
  350. gettimeofday(&tp, NULL);
  351. #endif
  352. fprintf(stderr, " in %f seconds(%f packets per second)\n",
  353. (tp.tv_sec - starttime_local + ((tp.tv_usec - startusec) / 1000000)),
  354. (pkts_sent / ((tp.tv_sec - starttime_local) * 1000000 +
  355. ((tp.tv_usec - startusec)))) * 1000000);
  356. fprintf(stderr, "%lld bytes sucessfully sent", bytes_sent);
  357. fprintf(stderr, "(%f bytes per second\n",
  358. (bytes_sent / ((tp.tv_sec - starttime_local) * 1000000 +
  359. ((tp.tv_usec - startusec)))) * 1000000);
  360. fprintf(stderr, "%f megabits per second)\n",
  361. (((bytes_sent / ((tp.tv_sec - starttime_local) * 1000000 +
  362. ((tp.tv_usec-startusec)))) * 1000000) * 8) /
  363. (1024 * 1024));
  364. exit(0);
  365. }