source: tools/tracereplay/tracereplay.c @ 706cd57

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 706cd57 was 0f2e206, checked in by Andreas Löf <andreas.lof@…>, 12 years ago

initialising the broadcast flag to 0

  • Property mode set to 100644
File size: 8.2 KB
Line 
1
2/*
3
4  Tracereplay is a simple utility that takes a trace and replays it to a
5  specified interface.
6  It pads packets with zeroes to reach the original length of the packet
7  and recalculates checksums in ip/tcp/udp headers.
8
9  Authors: Andreas Loef and Yuwei Wang
10
11
12 */
13
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <assert.h>
18#include <sys/types.h>
19#include <unistd.h>
20#include <string.h>
21#include <libtrace.h>
22#include <getopt.h>
23#include <arpa/inet.h>
24
25#define FCS_SIZE 4
26
27int broadcast = 0;
28
29/* This function assumes that the relevant fields have been zeroed out.
30   RFC 1071 describes the method and provides a code example*/
31static uint16_t checksum(void * buffer, uint16_t length) {
32  uint32_t sum = 0;
33  uint16_t * buff = (uint16_t *) buffer;
34  uint16_t count = length;
35
36  while(count > 1 ) {
37    sum += *buff++;
38    count = count -2;
39  }
40
41  if(count > 0) {
42    sum += *buff;
43  }
44 
45  while (sum>>16)
46    sum = (sum & 0xffff) + (sum >> 16);
47
48  return ~sum;
49}
50
51/*
52  This function calculates and fills in the correct checksum on
53  a transport protocol header.
54  Currently only UDP and TCP are supported.
55*/
56
57static void udp_tcp_checksum(libtrace_ip_t *ip, uint32_t length) {
58
59  uint32_t sum = 0;
60  uint16_t protocol = ip->ip_p;
61  uint16_t temp = 0;
62  uint16_t * check = NULL;
63  uint16_t tsum = 0;
64  void * transportheader = NULL;
65
66  sum += (uint16_t) ~checksum(&ip->ip_src.s_addr,sizeof(uint32_t));
67  sum += (uint16_t) ~checksum(&ip->ip_dst.s_addr,sizeof(uint32_t));
68
69
70  /*this will be in host order whereas everything else is in network order*/
71  temp = htons(protocol);
72  sum += (uint16_t) ~checksum(&temp,sizeof(uint16_t));
73
74  /*this will be in host order whereas everything else is in network order*/
75  temp = htons(length);
76  sum += (uint16_t) ~checksum(&temp,sizeof(uint16_t));
77
78  transportheader = trace_get_payload_from_ip(ip,NULL,NULL);
79
80  /* UDP */
81  if(protocol == 17 ) {
82    libtrace_udp_t * udp_header = transportheader;
83    check = &udp_header -> check;
84    *check = 0;
85    tsum = checksum(transportheader, length);
86  }
87  /* TCP */
88  else if(protocol == 6) {
89    libtrace_tcp_t * tcp_header = transportheader;
90    tcp_header -> check = 0;
91    check = &tcp_header -> check;
92    *check = 0;
93    tsum = checksum(transportheader,length);
94  }
95
96  sum += (uint16_t) ~tsum;
97
98  while (sum>>16)
99    sum = (sum & 0xffff) + (sum >> 16);
100
101  if(check != NULL) {
102    *check = (uint16_t)~sum;
103  }
104 
105
106
107}
108
109/*
110  Create a copy of the packet that can be written to the output URI.
111  if the packet is IPv4 the checksum will be recalculated to account for
112  cryptopan. Same for TCP and UDP. No other protocols are supported at the
113  moment.
114 */
115static libtrace_packet_t * per_packet(libtrace_packet_t *packet) {
116  uint32_t remaining = 0; 
117  libtrace_linktype_t linktype = 0;
118  libtrace_ip_t * header = NULL;
119  uint16_t sum = 0;
120  libtrace_packet_t *new_packet;
121  size_t wire_length;
122  void * pkt_buffer;
123  void * l2_header;
124  libtrace_ether_t * ether_header;
125  int i;
126
127  pkt_buffer = trace_get_packet_buffer(packet,&linktype,&remaining);
128  remaining = 0;
129  new_packet = trace_create_packet();
130 
131  wire_length = trace_get_wire_length(packet);
132
133  /* if it's ehternet we don't want to add space for the FCS that will
134     be appended. */
135  if(linktype == TRACE_TYPE_ETH || linktype == TRACE_TYPE_80211) {
136    wire_length -= FCS_SIZE;
137  }
138
139  trace_construct_packet(new_packet,linktype,pkt_buffer,wire_length);
140
141
142  if(broadcast) {
143    l2_header = trace_get_layer2(new_packet,&linktype,&remaining);
144    if(linktype == TRACE_TYPE_ETH){
145      ether_header = (libtrace_ether_t *) l2_header;
146      for(i = 0; i < 6; i++) {
147        ether_header -> ether_dhost[i] = 0xFF;
148      }
149    }
150   
151  }
152
153 
154 
155  header = trace_get_ip(new_packet);
156  if(header != NULL) {
157    /* update ip checksum */
158    wire_length -= sizeof(uint32_t)*header->ip_hl;
159    header -> ip_sum = 0;
160    sum = checksum(header,header->ip_hl*sizeof(uint32_t));
161    header -> ip_sum = sum;
162    /* update transport layer checksums */
163    udp_tcp_checksum(header,ntohs(header->ip_len)-sizeof(uint32_t)*header->ip_hl);
164  }
165
166  return new_packet;
167 
168}
169
170
171
172static uint32_t event_read_packet(libtrace_t *trace, libtrace_packet_t *packet) 
173{
174        libtrace_eventobj_t obj;
175        fd_set rfds;
176        struct timeval sleep_tv;
177       
178        FD_ZERO(&rfds);
179       
180        for (;;) {
181                obj = trace_event(trace, packet);
182
183                switch(obj.type) {
184                       
185                        /* Device has no packets at present - lets wait until
186                         * it does get something */
187                        case TRACE_EVENT_IOWAIT:
188                                FD_ZERO(&rfds);
189                                FD_SET(obj.fd, &rfds);
190                                select(obj.fd + 1, &rfds, NULL, NULL, 0);
191                                continue;
192                               
193                        /* Replaying a trace in tracetime and the next packet
194                         * is not due yet */
195                        case TRACE_EVENT_SLEEP:
196                                /* select offers good precision for sleeping */
197                                sleep_tv.tv_sec = (int)obj.seconds;
198                                sleep_tv.tv_usec = (int) ((obj.seconds - sleep_tv.tv_sec) * 1000000.0);
199                                select(0, NULL, NULL, NULL, &sleep_tv);
200                                continue;
201                               
202                        /* We've got a packet! */
203                        case TRACE_EVENT_PACKET:
204                                /* Check for error first */
205                                if (obj.size == -1)
206                                        return -1;
207                                return 1;
208                               
209                        /* End of trace has been reached */
210                        case TRACE_EVENT_TERMINATE:
211                                return -1;
212                               
213                        /* An event we don't know about has occured */
214                        default:
215                                fprintf(stderr, "Unknown event type occured\n");
216                                return -1;
217                }
218        }
219}
220
221static void usage(char * argv) {
222        fprintf(stderr, "usage: %s [options] inputuri outputuri...\n", argv);
223        fprintf(stderr, " --filter bpfexpr\n");
224        fprintf(stderr, " -f bpfexpr\n");
225        fprintf(stderr, "\t\tApply a bpf filter expression\n");
226        fprintf(stderr, " -s snaplength\n");
227        fprintf(stderr, " --snaplength snaplength\n");
228        fprintf(stderr, "\t\tTruncate the packets read from inputuri to <snaplength>\n");
229        fprintf(stderr, " -b\n");
230        fprintf(stderr, " --broadcast\n");
231        fprintf(stderr, "\t\tSend ethernet frames to broadcast address\n");
232
233}
234
235int main(int argc, char *argv[]) {
236       
237        libtrace_t *trace;
238        libtrace_out_t *output;
239        libtrace_packet_t *packet;
240        libtrace_filter_t *filter=NULL;
241        int psize = 0;
242        char *uri = 0;
243        libtrace_packet_t * new;
244        int snaplen = 0;
245       
246
247        while(1) {
248                int option_index;
249                struct option long_options[] = {
250                        { "filter",     1, 0, 'f'},
251                        { "help",       0, 0, 'h'},
252                        { "snaplen",    1, 0, 's'},
253                        { "broadcast",  0, 0, 'b'},
254                        { NULL,         0, 0, 0}
255                };
256
257                int c = getopt_long(argc, argv, "bhs:f:",
258                                long_options, &option_index);
259
260                if(c == -1)
261                        break;
262
263                switch (c) {
264                case 'f':
265                  filter = trace_create_filter(optarg);
266                  break;
267                case 's':
268                  snaplen = atoi(optarg);
269                  break;
270
271                case 'b':
272                  broadcast = 1;
273                  break;
274                 
275                case 'h':
276                 
277                  usage(argv[0]);
278                  return 1;
279                default:
280                  fprintf(stderr, "Unknown option: %c\n", c);
281                }
282        }
283
284        if(optind>=argc) {
285                fprintf(stderr, "Missing input uri\n");
286                usage(argv[0]);
287                return 1;
288        }
289        if(optind+1>=argc) {
290                fprintf(stderr, "Missing output uri\n");
291                usage(argv[0]);
292                return 1;
293        }
294
295        uri = strdup(argv[optind]);
296
297        /* Create the trace */
298        trace = trace_create(uri);
299        if (trace_is_err(trace)) {
300                trace_perror(trace, "trace_create");
301                return 1;
302        }
303
304        /*apply snaplength */
305        if(snaplen) {
306          if(trace_config(trace,TRACE_OPTION_SNAPLEN,&snaplen)) {
307            trace_perror(trace,"error setting snaplength, proceeding anyway");
308          }
309        }
310
311        /* apply filter */
312        if(filter) {
313                if(trace_config(trace, TRACE_OPTION_FILTER, filter)) {
314                        trace_perror(trace, "ignoring: ");
315                }
316        }
317
318        /* Starting the trace */
319        if (trace_start(trace) != 0) {
320                trace_perror(trace, "trace_start");
321                return 1;
322        }
323
324        /* Creating output trace */
325        output = trace_create_output(argv[optind+1]);
326       
327        if (trace_is_err_output(output)) {
328                trace_perror_output(output, "Opening output trace: ");
329                return 1;
330        }
331        if (trace_start_output(output)) {
332                trace_perror_output(output, "Starting output trace: ");
333                trace_destroy_output(output);
334                trace_destroy(trace);
335                return 1;
336        }
337
338        packet = trace_create_packet();
339
340        for (;;) {
341                if ((psize = event_read_packet(trace, packet)) <= 0) {
342                        break;
343                }
344
345                /* Got a packet - let's do something with it */
346                new = per_packet(packet);
347
348                if (trace_write_packet(output, new) < 0) {
349                        trace_perror_output(output, "Writing packet");
350                        trace_destroy(trace);
351                        trace_destroy_output(output);
352                        trace_destroy_packet(packet);
353                        return 1;
354                }
355                trace_destroy_packet(new);
356        }
357        free(uri);
358        trace_destroy(trace);
359        if(filter != NULL) {
360          trace_destroy_filter(filter);
361        }
362        trace_destroy_output(output);
363        trace_destroy_packet(packet);
364        return 0;
365
366}
367
Note: See TracBrowser for help on using the repository browser.