source: tools/tracereplay/tracereplay.c @ cc9c9de

cachetimestampsdevelopetsiliverc-4.0.4ringdecrementfixringperformance
Last change on this file since cc9c9de was cc9c9de, checked in by Shane Alcock <salcock@…>, 4 years ago

Add new config option for trace_event() -- REPLAY_SPEEDUP

This allows users to specify a "speedup factor" when using
trace_event() to replay trace files, i.e. all inter-packet
gaps will be divided by the speedup factor. This allows traces
to be replayed faster, while still preserving the same relative
gaps between packets.

  • Property mode set to 100644
File size: 7.6 KB
Line 
1/*
2 *
3 * Copyright (c) 2007-2016 The University of Waikato, Hamilton, New Zealand.
4 * All rights reserved.
5 *
6 * This file is part of libtrace.
7 *
8 * This code has been developed by the University of Waikato WAND
9 * research group. For further information please see http://www.wand.net.nz/
10 *
11 * libtrace is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * libtrace is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 *
24 *
25 */
26
27
28
29/*
30
31   Tracereplay is a simple utility that takes a trace and replays it to a
32   specified interface.
33   It pads packets with zeroes to reach the original length of the packet
34   and recalculates checksums in ip/tcp/udp headers.
35
36Authors: Andreas Loef and Yuwei Wang
37
38
39 */
40
41
42#include <stdio.h>
43#include <stdlib.h>
44#include <assert.h>
45#include <sys/types.h>
46#include <unistd.h>
47#include <string.h>
48#include <libtrace.h>
49#include <getopt.h>
50#include <arpa/inet.h>
51
52#define FCS_SIZE 4
53
54int broadcast = 0;
55
56static void replace_ip_checksum(libtrace_packet_t *packet) {
57
58        uint16_t *ip_csm_ptr = NULL;
59        uint16_t calc_csum;
60
61        ip_csm_ptr = trace_checksum_layer3(packet, &calc_csum);
62
63        if (ip_csm_ptr == NULL)
64                return;
65        *ip_csm_ptr = htons(calc_csum);
66
67}
68
69static void replace_transport_checksum(libtrace_packet_t *packet) {
70
71        uint16_t *csm_ptr = NULL;
72        uint16_t calc_csum;
73       
74        csm_ptr = trace_checksum_transport(packet, &calc_csum);
75
76        if (csm_ptr == NULL)
77                return;
78        *csm_ptr = htons(calc_csum);
79
80}
81
82/*
83   Create a copy of the packet that can be written to the output URI.
84   if the packet is IPv4 the checksum will be recalculated to account for
85   cryptopan. Same for TCP and UDP. No other protocols are supported at the
86   moment.
87 */
88static libtrace_packet_t * per_packet(libtrace_packet_t *packet) {
89        uint32_t remaining = 0; 
90        libtrace_linktype_t linktype = 0;
91        libtrace_packet_t *new_packet;
92        size_t wire_length;
93        void * pkt_buffer;
94        void * l2_header;
95        libtrace_ether_t * ether_header;
96        int i;
97
98        if (IS_LIBTRACE_META_PACKET(packet))
99                return NULL;
100        if (trace_get_wire_length(packet) == 0)
101                return NULL;
102
103        pkt_buffer = trace_get_packet_buffer(packet,&linktype,&remaining);
104        remaining = 0;
105        new_packet = trace_create_packet();
106
107        wire_length = trace_get_wire_length(packet);
108
109        /* if it's ehternet we don't want to add space for the FCS that will
110           be appended. */
111        if(linktype == TRACE_TYPE_ETH || linktype == TRACE_TYPE_80211) {
112                wire_length -= FCS_SIZE;
113        }
114
115        trace_construct_packet(new_packet,linktype,pkt_buffer,wire_length);
116
117
118        if(broadcast) {
119                l2_header = trace_get_layer2(new_packet,&linktype,&remaining);
120                if(linktype == TRACE_TYPE_ETH){
121                        ether_header = (libtrace_ether_t *) l2_header;
122                        for(i = 0; i < 6; i++) {
123                                ether_header -> ether_dhost[i] = 0xFF;
124                        }
125                }
126
127        }
128
129        replace_ip_checksum(new_packet);
130        replace_transport_checksum(new_packet);
131
132        return new_packet;
133
134}
135
136
137
138static uint32_t event_read_packet(libtrace_t *trace, libtrace_packet_t *packet) 
139{
140        libtrace_eventobj_t obj;
141        fd_set rfds;
142        struct timeval sleep_tv;
143
144        FD_ZERO(&rfds);
145
146        for (;;) {
147                obj = trace_event(trace, packet);
148
149                switch(obj.type) {
150
151                        /* Device has no packets at present - lets wait until
152                         * it does get something */
153                        case TRACE_EVENT_IOWAIT:
154                                FD_ZERO(&rfds);
155                                FD_SET(obj.fd, &rfds);
156                                select(obj.fd + 1, &rfds, NULL, NULL, 0);
157                                continue;
158
159                                /* Replaying a trace in tracetime and the next packet
160                                 * is not due yet */
161                        case TRACE_EVENT_SLEEP:
162                                /* select offers good precision for sleeping */
163                                sleep_tv.tv_sec = (int)obj.seconds;
164                                sleep_tv.tv_usec = (int) ((obj.seconds - sleep_tv.tv_sec) * 1000000.0);
165                                select(0, NULL, NULL, NULL, &sleep_tv);
166                                continue;
167
168                                /* We've got a packet! */
169                        case TRACE_EVENT_PACKET:
170                                /* Check for error first */
171                                if (obj.size == -1)
172                                        return -1;
173                                return 1;
174
175                                /* End of trace has been reached */
176                        case TRACE_EVENT_TERMINATE:
177                                return -1;
178
179                                /* An event we don't know about has occured */
180                        default:
181                                fprintf(stderr, "Unknown event type occured\n");
182                                return -1;
183                }
184        }
185}
186
187static void usage(char * argv) {
188        fprintf(stderr, "usage: %s [options] inputuri outputuri...\n", argv);
189        fprintf(stderr, " --filter bpfexpr\n");
190        fprintf(stderr, " -f bpfexpr\n");
191        fprintf(stderr, "\t\tApply a bpf filter expression\n");
192        fprintf(stderr, " -s snaplength\n");
193        fprintf(stderr, " --snaplength snaplength\n");
194        fprintf(stderr, "\t\tTruncate the packets read from inputuri to <snaplength>\n");
195        fprintf(stderr, " -b\n");
196        fprintf(stderr, " --broadcast\n");
197        fprintf(stderr, "\t\tSend ethernet frames to broadcast address\n");
198
199}
200
201int main(int argc, char *argv[]) {
202
203        libtrace_t *trace;
204        libtrace_out_t *output;
205        libtrace_packet_t *packet;
206        libtrace_filter_t *filter=NULL;
207        int psize = 0;
208        char *uri = 0;
209        libtrace_packet_t * new;
210        int snaplen = 0;
211        int speedup = 1;
212
213
214        while(1) {
215                int option_index;
216                struct option long_options[] = {
217                        { "filter",     1, 0, 'f'},
218                        { "help",       0, 0, 'h'},
219                        { "snaplen",    1, 0, 's'},
220                        { "broadcast",  0, 0, 'b'},
221                        { NULL,         0, 0, 0}
222                };
223
224                int c = getopt_long(argc, argv, "bhs:f:",
225                                long_options, &option_index);
226
227                if(c == -1)
228                        break;
229
230                switch (c) {
231                        case 'f':
232                                filter = trace_create_filter(optarg);
233                                break;
234                        case 's':
235                                snaplen = atoi(optarg);
236                                break;
237
238                        case 'b':
239                                broadcast = 1;
240                                break;
241
242                        case 'h':
243
244                                usage(argv[0]);
245                                return 1;
246                        default:
247                                fprintf(stderr, "Unknown option: %c\n", c);
248                }
249        }
250
251        if(optind>=argc) {
252                fprintf(stderr, "Missing input uri\n");
253                usage(argv[0]);
254                return 1;
255        }
256        if(optind+1>=argc) {
257                fprintf(stderr, "Missing output uri\n");
258                usage(argv[0]);
259                return 1;
260        }
261
262        uri = strdup(argv[optind]);
263
264        /* Create the trace */
265        trace = trace_create(uri);
266        if (trace_is_err(trace)) {
267                trace_perror(trace, "trace_create");
268                return 1;
269        }
270
271        /*apply snaplength */
272        if(snaplen) {
273                if(trace_config(trace,TRACE_OPTION_SNAPLEN,&snaplen)) {
274                        trace_perror(trace,"error setting snaplength, proceeding anyway");
275                }
276        }
277
278        /* apply filter */
279        if(filter) {
280                if(trace_config(trace, TRACE_OPTION_FILTER, filter)) {
281                        trace_perror(trace, "ignoring: ");
282                }
283        }
284
285        /* Starting the trace */
286        if (trace_start(trace) != 0) {
287                trace_perror(trace, "trace_start");
288                return 1;
289        }
290
291        /* Creating output trace */
292        output = trace_create_output(argv[optind+1]);
293
294        if (trace_is_err_output(output)) {
295                trace_perror_output(output, "Opening output trace: ");
296                return 1;
297        }
298        if (trace_start_output(output)) {
299                trace_perror_output(output, "Starting output trace: ");
300                trace_destroy_output(output);
301                trace_destroy(trace);
302                return 1;
303        }
304
305        packet = trace_create_packet();
306
307        for (;;) {
308                if ((psize = event_read_packet(trace, packet)) <= 0) {
309                        break;
310                }
311
312                /* Got a packet - let's do something with it */
313                new = per_packet(packet);
314
315                if (!new)
316                        continue;
317
318                if (trace_write_packet(output, new) < 0) {
319                        trace_perror_output(output, "Writing packet");
320                        trace_destroy(trace);
321                        trace_destroy_output(output);
322                        trace_destroy_packet(packet);
323                        return 1;
324                }
325                trace_destroy_packet(new);
326        }
327        if (trace_is_err(trace)) {
328                trace_perror(trace,"%s",uri);
329        }
330        free(uri);
331        trace_destroy(trace);
332        if(filter != NULL) {
333                trace_destroy_filter(filter);
334        }
335        trace_destroy_output(output);
336        trace_destroy_packet(packet);
337        return 0;
338
339}
340
Note: See TracBrowser for help on using the repository browser.