source: tools/tracereplay/tracereplay.c @ cb075c5

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivendag_formatrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since cb075c5 was ee6e802, checked in by Shane Alcock <salcock@…>, 5 years ago

Updated copyright blurb on all source files

In some cases, this meant adding copyright blurbs to files that
had never had them before.

  • Property mode set to 100644
File size: 7.4 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        pkt_buffer = trace_get_packet_buffer(packet,&linktype,&remaining);
99        remaining = 0;
100        new_packet = trace_create_packet();
101
102        wire_length = trace_get_wire_length(packet);
103
104        /* if it's ehternet we don't want to add space for the FCS that will
105           be appended. */
106        if(linktype == TRACE_TYPE_ETH || linktype == TRACE_TYPE_80211) {
107                wire_length -= FCS_SIZE;
108        }
109
110        trace_construct_packet(new_packet,linktype,pkt_buffer,wire_length);
111
112
113        if(broadcast) {
114                l2_header = trace_get_layer2(new_packet,&linktype,&remaining);
115                if(linktype == TRACE_TYPE_ETH){
116                        ether_header = (libtrace_ether_t *) l2_header;
117                        for(i = 0; i < 6; i++) {
118                                ether_header -> ether_dhost[i] = 0xFF;
119                        }
120                }
121
122        }
123
124        replace_ip_checksum(new_packet);
125        replace_transport_checksum(new_packet);
126
127        return new_packet;
128
129}
130
131
132
133static uint32_t event_read_packet(libtrace_t *trace, libtrace_packet_t *packet) 
134{
135        libtrace_eventobj_t obj;
136        fd_set rfds;
137        struct timeval sleep_tv;
138
139        FD_ZERO(&rfds);
140
141        for (;;) {
142                obj = trace_event(trace, packet);
143
144                switch(obj.type) {
145
146                        /* Device has no packets at present - lets wait until
147                         * it does get something */
148                        case TRACE_EVENT_IOWAIT:
149                                FD_ZERO(&rfds);
150                                FD_SET(obj.fd, &rfds);
151                                select(obj.fd + 1, &rfds, NULL, NULL, 0);
152                                continue;
153
154                                /* Replaying a trace in tracetime and the next packet
155                                 * is not due yet */
156                        case TRACE_EVENT_SLEEP:
157                                /* select offers good precision for sleeping */
158                                sleep_tv.tv_sec = (int)obj.seconds;
159                                sleep_tv.tv_usec = (int) ((obj.seconds - sleep_tv.tv_sec) * 1000000.0);
160                                select(0, NULL, NULL, NULL, &sleep_tv);
161                                continue;
162
163                                /* We've got a packet! */
164                        case TRACE_EVENT_PACKET:
165                                /* Check for error first */
166                                if (obj.size == -1)
167                                        return -1;
168                                return 1;
169
170                                /* End of trace has been reached */
171                        case TRACE_EVENT_TERMINATE:
172                                return -1;
173
174                                /* An event we don't know about has occured */
175                        default:
176                                fprintf(stderr, "Unknown event type occured\n");
177                                return -1;
178                }
179        }
180}
181
182static void usage(char * argv) {
183        fprintf(stderr, "usage: %s [options] inputuri outputuri...\n", argv);
184        fprintf(stderr, " --filter bpfexpr\n");
185        fprintf(stderr, " -f bpfexpr\n");
186        fprintf(stderr, "\t\tApply a bpf filter expression\n");
187        fprintf(stderr, " -s snaplength\n");
188        fprintf(stderr, " --snaplength snaplength\n");
189        fprintf(stderr, "\t\tTruncate the packets read from inputuri to <snaplength>\n");
190        fprintf(stderr, " -b\n");
191        fprintf(stderr, " --broadcast\n");
192        fprintf(stderr, "\t\tSend ethernet frames to broadcast address\n");
193
194}
195
196int main(int argc, char *argv[]) {
197
198        libtrace_t *trace;
199        libtrace_out_t *output;
200        libtrace_packet_t *packet;
201        libtrace_filter_t *filter=NULL;
202        int psize = 0;
203        char *uri = 0;
204        libtrace_packet_t * new;
205        int snaplen = 0;
206
207
208        while(1) {
209                int option_index;
210                struct option long_options[] = {
211                        { "filter",     1, 0, 'f'},
212                        { "help",       0, 0, 'h'},
213                        { "snaplen",    1, 0, 's'},
214                        { "broadcast",  0, 0, 'b'},
215                        { NULL,         0, 0, 0}
216                };
217
218                int c = getopt_long(argc, argv, "bhs:f:",
219                                long_options, &option_index);
220
221                if(c == -1)
222                        break;
223
224                switch (c) {
225                        case 'f':
226                                filter = trace_create_filter(optarg);
227                                break;
228                        case 's':
229                                snaplen = atoi(optarg);
230                                break;
231
232                        case 'b':
233                                broadcast = 1;
234                                break;
235
236                        case 'h':
237
238                                usage(argv[0]);
239                                return 1;
240                        default:
241                                fprintf(stderr, "Unknown option: %c\n", c);
242                }
243        }
244
245        if(optind>=argc) {
246                fprintf(stderr, "Missing input uri\n");
247                usage(argv[0]);
248                return 1;
249        }
250        if(optind+1>=argc) {
251                fprintf(stderr, "Missing output uri\n");
252                usage(argv[0]);
253                return 1;
254        }
255
256        uri = strdup(argv[optind]);
257
258        /* Create the trace */
259        trace = trace_create(uri);
260        if (trace_is_err(trace)) {
261                trace_perror(trace, "trace_create");
262                return 1;
263        }
264
265        /*apply snaplength */
266        if(snaplen) {
267                if(trace_config(trace,TRACE_OPTION_SNAPLEN,&snaplen)) {
268                        trace_perror(trace,"error setting snaplength, proceeding anyway");
269                }
270        }
271
272        /* apply filter */
273        if(filter) {
274                if(trace_config(trace, TRACE_OPTION_FILTER, filter)) {
275                        trace_perror(trace, "ignoring: ");
276                }
277        }
278
279        /* Starting the trace */
280        if (trace_start(trace) != 0) {
281                trace_perror(trace, "trace_start");
282                return 1;
283        }
284
285        /* Creating output trace */
286        output = trace_create_output(argv[optind+1]);
287
288        if (trace_is_err_output(output)) {
289                trace_perror_output(output, "Opening output trace: ");
290                return 1;
291        }
292        if (trace_start_output(output)) {
293                trace_perror_output(output, "Starting output trace: ");
294                trace_destroy_output(output);
295                trace_destroy(trace);
296                return 1;
297        }
298
299        packet = trace_create_packet();
300
301        for (;;) {
302                if ((psize = event_read_packet(trace, packet)) <= 0) {
303                        break;
304                }
305
306                /* Got a packet - let's do something with it */
307                new = per_packet(packet);
308
309                if (trace_write_packet(output, new) < 0) {
310                        trace_perror_output(output, "Writing packet");
311                        trace_destroy(trace);
312                        trace_destroy_output(output);
313                        trace_destroy_packet(packet);
314                        return 1;
315                }
316                trace_destroy_packet(new);
317        }
318        if (trace_is_err(trace)) {
319                trace_perror(trace,"%s",uri);
320        }
321        free(uri);
322        trace_destroy(trace);
323        if(filter != NULL) {
324                trace_destroy_filter(filter);
325        }
326        trace_destroy_output(output);
327        trace_destroy_packet(packet);
328        return 0;
329
330}
331
Note: See TracBrowser for help on using the repository browser.