source: tools/tracereplay/tracereplay.c @ 1e0a804

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

Update tracereplay to allow users to specify a speed up factor.

  • Property mode set to 100644
File size: 8.2 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        fprintf(stderr, " -X\n");
199        fprintf(stderr, " --speedup\n");
200        fprintf(stderr, "\t\tSpeed up replay by a factor of <speedup>\n");
201
202}
203
204int main(int argc, char *argv[]) {
205
206        libtrace_t *trace;
207        libtrace_out_t *output;
208        libtrace_packet_t *packet;
209        libtrace_filter_t *filter=NULL;
210        int psize = 0;
211        char *uri = 0;
212        libtrace_packet_t * new;
213        int snaplen = 0;
214        int speedup = 1;
215
216
217        while(1) {
218                int option_index;
219                struct option long_options[] = {
220                        { "filter",     1, 0, 'f'},
221                        { "help",       0, 0, 'h'},
222                        { "snaplen",    1, 0, 's'},
223                        { "broadcast",  0, 0, 'b'},
224                        { "speedup",    1, 0, 'X'},
225                        { NULL,         0, 0, 0}
226                };
227
228                int c = getopt_long(argc, argv, "bhs:f:X:",
229                                long_options, &option_index);
230
231                if(c == -1)
232                        break;
233
234                switch (c) {
235                        case 'f':
236                                filter = trace_create_filter(optarg);
237                                break;
238                        case 's':
239                                snaplen = atoi(optarg);
240                                break;
241                        case 'X':
242                                speedup = atoi(optarg);
243                                break;
244                        case 'b':
245                                broadcast = 1;
246                                break;
247
248                        case 'h':
249
250                                usage(argv[0]);
251                                return 1;
252                        default:
253                                fprintf(stderr, "Unknown option: %c\n", c);
254                }
255        }
256
257        if(optind>=argc) {
258                fprintf(stderr, "Missing input uri\n");
259                usage(argv[0]);
260                return 1;
261        }
262        if(optind+1>=argc) {
263                fprintf(stderr, "Missing output uri\n");
264                usage(argv[0]);
265                return 1;
266        }
267
268        if (speedup < 1) {
269                speedup = 1;
270        }
271
272        uri = strdup(argv[optind]);
273
274        /* Create the trace */
275        trace = trace_create(uri);
276        if (trace_is_err(trace)) {
277                trace_perror(trace, "trace_create");
278                return 1;
279        }
280
281        /*apply snaplength */
282        if(snaplen) {
283                if(trace_config(trace,TRACE_OPTION_SNAPLEN,&snaplen)) {
284                        trace_perror(trace,"error setting snaplength, proceeding anyway");
285                }
286        }
287
288        /* apply filter */
289        if(filter) {
290                if(trace_config(trace, TRACE_OPTION_FILTER, filter)) {
291                        trace_perror(trace, "ignoring: ");
292                }
293        }
294
295        if (trace_config(trace, TRACE_OPTION_REPLAY_SPEEDUP, &speedup)) {
296                trace_perror(trace, "error setting replay speedup factor");
297                return 1;
298        }
299
300        /* Starting the trace */
301        if (trace_start(trace) != 0) {
302                trace_perror(trace, "trace_start");
303                return 1;
304        }
305
306        /* Creating output trace */
307        output = trace_create_output(argv[optind+1]);
308
309        if (trace_is_err_output(output)) {
310                trace_perror_output(output, "Opening output trace: ");
311                return 1;
312        }
313        if (trace_start_output(output)) {
314                trace_perror_output(output, "Starting output trace: ");
315                trace_destroy_output(output);
316                trace_destroy(trace);
317                return 1;
318        }
319
320        packet = trace_create_packet();
321
322        for (;;) {
323                if ((psize = event_read_packet(trace, packet)) <= 0) {
324                        break;
325                }
326
327                /* Got a packet - let's do something with it */
328                new = per_packet(packet);
329
330                if (!new)
331                        continue;
332
333                if (trace_write_packet(output, new) < 0) {
334                        trace_perror_output(output, "Writing packet");
335                        trace_destroy(trace);
336                        trace_destroy_output(output);
337                        trace_destroy_packet(packet);
338                        return 1;
339                }
340                trace_destroy_packet(new);
341        }
342        if (trace_is_err(trace)) {
343                trace_perror(trace,"%s",uri);
344        }
345        free(uri);
346        trace_destroy(trace);
347        if(filter != NULL) {
348                trace_destroy_filter(filter);
349        }
350        trace_destroy_output(output);
351        trace_destroy_packet(packet);
352        return 0;
353
354}
355
Note: See TracBrowser for help on using the repository browser.