source: tools/tracesplit/tracesplit.c @ a1935fa

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivendag_formatrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since a1935fa was a1935fa, checked in by Perry Lorier <git@…>, 5 years ago

Add -j# to jump to the next L3 header.

  • Property mode set to 100644
File size: 12.8 KB
Line 
1#include <libtrace.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <inttypes.h>
5#include <lt_inttypes.h>
6#include <stdbool.h>
7#include <getopt.h>
8#include <string.h>
9#include <assert.h>
10#include <signal.h>
11#include <time.h>
12
13/* Global variables */
14struct libtrace_out_t *output = NULL;
15uint64_t count=UINT64_MAX;
16uint64_t bytes=UINT64_MAX;
17uint64_t starttime=0;
18uint64_t endtime=UINT64_MAX;
19uint64_t interval=UINT64_MAX;
20double firsttime=0;
21uint64_t pktcount=0;
22uint64_t totbytes=0;
23uint64_t totbyteslast=0;
24uint64_t maxfiles = UINT64_MAX;
25uint64_t filescreated = 0;
26uint16_t snaplen = 0;
27int jump=0;
28int verbose=0;
29int compress_level=-1;
30trace_option_compresstype_t compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
31char *output_base = NULL;
32
33
34static char *strdupcat(char *str,char *app)
35{
36        str=realloc(str,strlen(str)+strlen(app)+1);
37        strncat(str,app,strlen(str) + strlen(app));
38        return str;
39}
40
41static char *strdupcati(char *str,uint64_t i)
42{
43        char buffer[64];
44        snprintf(buffer,sizeof(buffer),"%" PRIu64,i);
45        return strdupcat(str,buffer);
46}
47
48static int usage(char *argv0)
49{
50        printf("Usage:\n"
51        "%s flags inputuri [inputuri ... ] outputuri\n"
52        "-f --filter=bpf        only output packets that match filter\n"
53        "-c --count=n           split every n packets\n"
54        "-b --bytes=n           Split every n bytes received\n"
55        "-i --interval=n        Split every n seconds\n"
56        "-s --starttime=time    Start at time\n"
57        "-e --endtime=time      End at time\n"
58        "-m --maxfiles=n        Create a maximum of n trace files\n"
59        "-j --jump=n            Jump to the nth IP header\n"
60        "-H --libtrace-help     Print libtrace runtime documentation\n"
61        "-S --snaplen           Snap packets at the specified length\n"
62        "-v --verbose           Output statistics\n"
63        "-z --compress-level    Set compression level\n"
64        "-Z --compress-type     Set compression type\n"
65        ,argv0);
66        exit(1);
67}
68
69volatile int done=0;
70
71static void cleanup_signal(int sig)
72{
73        (void)sig;
74        done=1;
75        trace_interrupt();
76}
77
78
79static libtrace_packet_t *perform_jump(libtrace_packet_t *packet, int jump)
80{
81    uint16_t ethertype;
82    uint32_t remaining;
83    uint8_t ipproto;
84    void *offset = trace_get_layer3(packet, &ethertype, &remaining);
85    while(jump > 0 && offset) {
86        --jump;
87        switch (ethertype) {
88            case TRACE_ETHERTYPE_IP:
89                if (jump <= 0) {
90                    void *newpacket = trace_create_packet();
91                    trace_construct_packet(newpacket,
92                            TRACE_TYPE_NONE,
93                            offset,
94                            remaining);
95                    return newpacket;
96                }
97                offset = trace_get_payload_from_ip(offset,
98                        &ipproto,
99                        &remaining);
100                if (!offset)
101                    return NULL;
102                break;
103            case TRACE_ETHERTYPE_IPV6:
104                if (jump <= 0) {
105                    void *newpacket = trace_create_packet();
106                    trace_construct_packet(newpacket,
107                            TRACE_TYPE_NONE,
108                            offset,
109                            remaining);
110                    return newpacket;
111                }
112                offset = trace_get_payload_from_ip6(offset,
113                        &ipproto,
114                        &remaining);
115                if (!offset)
116                    return NULL;
117                break;
118            /* TODO: vlan, etc */
119            default:
120                return NULL;
121        }
122        if (!offset)
123            return false;
124        switch (ipproto) {
125            case TRACE_IPPROTO_IPV6:
126                ethertype = TRACE_ETHERTYPE_IPV6;
127                continue;
128            case TRACE_IPPROTO_IPIP:
129                ethertype = TRACE_ETHERTYPE_IP;
130                continue;
131            case TRACE_IPPROTO_GRE:
132                if (remaining < sizeof(libtrace_gre_t)) {
133                    return NULL;
134                }
135                ethertype = ((libtrace_gre_t *)offset)->ethertype;
136                offset = trace_get_payload_from_gre(offset, &remaining);
137                continue;
138            case TRACE_IPPROTO_UDP:
139                offset = trace_get_vxlan_from_udp(offset, &remaining);
140                if (!offset)
141                    return NULL;
142                offset = trace_get_payload_from_vxlan(offset, &remaining);
143                if (!offset)
144                    return NULL;
145                offset = trace_get_payload_from_layer2(offset,
146                        TRACE_TYPE_ETH,
147                        &ethertype,
148                        &remaining);
149                if (!offset)
150                    return NULL;
151                continue;
152        }
153        return NULL;
154    }
155    return NULL;
156}
157
158
159/* Return values:
160 *  1 = continue reading packets
161 *  0 = stop reading packets, cos we're done
162 *  -1 = stop reading packets, we've got an error
163 */
164static int per_packet(libtrace_packet_t **packet) {
165
166        if (trace_get_link_type(*packet) == -1) {
167                fprintf(stderr, "Halted due to being unable to determine linktype - input trace may be corrupt.\n");
168                return -1;
169        }
170
171        if (snaplen>0) {
172                trace_set_capture_length(*packet,snaplen);
173        }
174
175        if (trace_get_seconds(*packet)<starttime) {
176                return 1;
177        }
178
179        if (trace_get_seconds(*packet)>endtime) {
180                return 0;
181        }
182
183        if (firsttime==0) {
184                time_t now = trace_get_seconds(*packet);
185                if (starttime != 0) {
186                        firsttime=now-((now - starttime)%interval);
187                }
188                else {
189                        firsttime=now;
190                }
191        }
192
193        if (output && trace_get_seconds(*packet)>firsttime+interval) {
194                trace_destroy_output(output);
195                output=NULL;
196                firsttime+=interval;
197        }
198
199        if (output && pktcount%count==0) {
200                trace_destroy_output(output);
201                output=NULL;
202        }
203
204        pktcount++;
205        totbytes+=trace_get_capture_length(*packet);
206        if (output && totbytes-totbyteslast>=bytes) {
207                trace_destroy_output(output);
208                output=NULL;
209                totbyteslast=totbytes;
210        }
211        if (!output) {
212                char *buffer;
213                bool need_ext=false;
214                if (maxfiles <= filescreated) {
215                        return 0;
216                }
217                buffer=strdup(output_base);
218                if (interval!=UINT64_MAX && maxfiles>1) {
219                        buffer=strdupcat(buffer,"-");
220                        buffer=strdupcati(buffer,(uint64_t)firsttime);
221                        need_ext=true;
222                }
223                if (count!=UINT64_MAX && maxfiles>1) {
224                        buffer=strdupcat(buffer,"-");
225                        buffer=strdupcati(buffer,(uint64_t)pktcount);
226                        need_ext=true;
227                }
228                if (bytes!=UINT64_MAX && maxfiles>1) {
229                        static int filenum=0;
230                        buffer=strdupcat(buffer,"-");
231                        buffer=strdupcati(buffer,(uint64_t)++filenum);
232                        need_ext=true;
233                }
234                if (need_ext) {
235                        if (compress_level!=0)
236                                buffer=strdupcat(buffer,".gz");
237                }
238                if (verbose>1) {
239                        fprintf(stderr,"%s:",buffer);
240                        if (count!=UINT64_MAX)
241                                fprintf(stderr," count=%" PRIu64,pktcount);
242                        if (bytes!=UINT64_MAX)
243                                fprintf(stderr," bytes=%" PRIu64,bytes);
244                        if (interval!=UINT64_MAX) {
245                                time_t filetime = firsttime;
246                                fprintf(stderr," time=%s",ctime(&filetime));
247                        }
248                        else {
249                                fprintf(stderr,"\n");
250                        }
251                }
252                output=trace_create_output(buffer);
253                if (trace_is_err_output(output)) {
254                        trace_perror_output(output,"%s",buffer);
255                        free(buffer);
256                        return -1;
257                }
258                if (compress_level!=-1) {
259                        if (trace_config_output(output,
260                                                TRACE_OPTION_OUTPUT_COMPRESS,
261                                                &compress_level)==-1) {
262                                trace_perror_output(output,"Unable to set compression level");
263                        }
264                }
265
266                if (trace_config_output(output,
267                                        TRACE_OPTION_OUTPUT_COMPRESSTYPE,
268                                        &compress_type) == -1) {
269                        trace_perror_output(output, "Unable to set compression type");
270                }
271
272                trace_start_output(output);
273                if (trace_is_err_output(output)) {
274                        trace_perror_output(output,"%s",buffer);
275                        free(buffer);
276                        return -1;
277                }
278                free(buffer);
279                filescreated ++;
280        }
281
282        /* Some traces we have are padded (usually with 0x00), so
283         * lets sort that out now and truncate them properly
284         */
285
286        if (trace_get_capture_length(*packet)
287                        > trace_get_wire_length(*packet)) {
288                trace_set_capture_length(*packet,
289                        trace_get_wire_length(*packet));
290        }
291
292        /* Support "jump"ping to the nth IP header. */
293        if (jump) {
294            /* Skip headers */
295            void *newpacket = perform_jump(*packet, jump);
296            if (newpacket) {
297                trace_destroy_packet(*packet);
298                *packet = newpacket;
299            }
300            else /* Skip packet */
301                return 1;
302        }
303
304        if (trace_write_packet(output, *packet)==-1) {
305                trace_perror_output(output,"write_packet");
306                return -1;
307        }
308
309        return 1;
310
311}
312
313int main(int argc, char *argv[])
314{
315        char *compress_type_str=NULL;
316        struct libtrace_filter_t *filter=NULL;
317        struct libtrace_t *input = NULL;
318        struct libtrace_packet_t *packet = trace_create_packet();
319        struct sigaction sigact;
320        int i;
321
322        if (argc<2) {
323                usage(argv[0]);
324                return 1;
325        }
326
327        /* Parse command line options */
328        while(1) {
329                int option_index;
330                struct option long_options[] = {
331                        { "filter",        1, 0, 'f' },
332                        { "count",         1, 0, 'c' },
333                        { "bytes",         1, 0, 'b' },
334                        { "starttime",     1, 0, 's' },
335                        { "endtime",       1, 0, 'e' },
336                        { "interval",      1, 0, 'i' },
337                        { "jump",          1, 0, 'j' },
338                        { "libtrace-help", 0, 0, 'H' },
339                        { "maxfiles",      1, 0, 'm' },
340                        { "snaplen",       1, 0, 'S' },
341                        { "verbose",       0, 0, 'v' },
342                        { "compress-level", 1, 0, 'z' },
343                        { "compress-type", 1, 0, 'Z' },
344                        { NULL,            0, 0, 0   },
345                };
346
347                int c=getopt_long(argc, argv, "j:f:c:b:s:e:i:m:S:Hvz:Z:",
348                                long_options, &option_index);
349
350                if (c==-1)
351                        break;
352
353                switch (c) {
354                        case 'f': filter=trace_create_filter(optarg);
355                                break;
356                        case 'c': count=atoi(optarg);
357                                break;
358                        case 'b': bytes=atoi(optarg);
359                                break;
360                        case 's': starttime=atoi(optarg); /* FIXME: use getdate */
361                                  break;
362                        case 'e': endtime=atoi(optarg);
363                                  break;
364                        case 'i': interval=atoi(optarg);
365                                  break;
366                        case 'j': jump=atoi(optarg);
367                                  break;
368                        case 'm': maxfiles=atoi(optarg);
369                                  break;
370                        case 'S': snaplen=atoi(optarg);
371                                  break;
372                        case 'H':
373                                  trace_help();
374                                  exit(1);
375                                  break;
376                        case 'v':
377                                  verbose++;
378                                  break;
379                        case 'z':
380                                  compress_level=atoi(optarg);
381                                  if (compress_level<0 || compress_level>9) {
382                                        usage(argv[0]);
383                                        exit(1);
384                                  }
385                                  break;
386                        case 'Z':
387                                  compress_type_str=optarg;
388                                  break;
389                        default:
390                                fprintf(stderr,"Unknown option: %c\n",c);
391                                usage(argv[0]);
392                                return 1;
393                }
394        }
395
396        if (compress_type_str == NULL && compress_level >= 0) {
397                fprintf(stderr, "Compression level set, but no compression type was defined, setting to gzip\n");
398                compress_type = TRACE_OPTION_COMPRESSTYPE_ZLIB;
399        }
400
401        else if (compress_type_str == NULL) {
402                /* If a level or type is not specified, use the "none"
403                 * compression module */
404                compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
405        }
406
407        /* I decided to be fairly generous in what I accept for the
408         * compression type string */
409        else if (strncmp(compress_type_str, "gz", 2) == 0 ||
410                        strncmp(compress_type_str, "zlib", 4) == 0) {
411                compress_type = TRACE_OPTION_COMPRESSTYPE_ZLIB;
412        } else if (strncmp(compress_type_str, "bz", 2) == 0) {
413                compress_type = TRACE_OPTION_COMPRESSTYPE_BZ2;
414        } else if (strncmp(compress_type_str, "lzo", 3) == 0) {
415                compress_type = TRACE_OPTION_COMPRESSTYPE_LZO;
416        } else if (strncmp(compress_type_str, "xz", 2) == 0) {
417                compress_type = TRACE_OPTION_COMPRESSTYPE_LZMA;
418        } else if (strncmp(compress_type_str, "no", 2) == 0) {
419                compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
420        } else {
421                fprintf(stderr, "Unknown compression type: %s\n",
422                        compress_type_str);
423                return 1;
424        }
425
426        if (optind+2>argc) {
427                fprintf(stderr,"missing inputuri or outputuri\n");
428                usage(argv[0]);
429        }
430
431        output_base = argv[argc - 1];
432
433        sigact.sa_handler = cleanup_signal;
434        sigemptyset(&sigact.sa_mask);
435        sigact.sa_flags = SA_RESTART;
436
437        sigaction(SIGINT, &sigact, NULL);
438        sigaction(SIGTERM, &sigact, NULL);
439
440        output=NULL;
441
442        signal(SIGINT,&cleanup_signal);
443        signal(SIGTERM,&cleanup_signal);
444
445        for (i = optind; i < argc - 1; i++) {
446
447
448                input = trace_create(argv[i]);
449
450                if (trace_is_err(input)) {
451                        trace_perror(input,"%s",argv[i]);
452                        return 1;
453                }
454
455                if (filter && trace_config(input, TRACE_OPTION_FILTER, filter) == 1) {
456                        trace_perror(input, "Configuring filter for %s",
457                                        argv[i]);
458                        return 1;
459                }
460
461                if (trace_start(input)==-1) {
462                        trace_perror(input,"%s",argv[i]);
463                        return 1;
464                }
465
466                while (trace_read_packet(input,packet)>0) {
467                        if (per_packet(&packet) < 1)
468                                done = 1;
469                        if (done)
470                                break;
471                }
472
473                if (trace_is_err(input)) {
474                        trace_perror(input,"Reading packets");
475                        trace_destroy(input);
476                        break;
477                }
478
479                trace_destroy(input);
480               
481                if (done)
482                        break;
483               
484        }
485
486        if (verbose) {
487                uint64_t f;
488                f=trace_get_received_packets(input);
489                if (f!=UINT64_MAX)
490                        fprintf(stderr,"%" PRIu64 " packets on input\n",f);
491                f=trace_get_filtered_packets(input);
492                if (f!=UINT64_MAX)
493                        fprintf(stderr,"%" PRIu64 " packets filtered\n",f);
494                f=trace_get_dropped_packets(input);
495                if (f!=UINT64_MAX)
496                        fprintf(stderr,"%" PRIu64 " packets dropped\n",f);
497                f=trace_get_accepted_packets(input);
498                if (f!=UINT64_MAX)
499                        fprintf(stderr,"%" PRIu64 " packets accepted\n",f);
500        }
501       
502        if (output)
503                trace_destroy_output(output);
504
505        trace_destroy_packet(packet);
506
507        return 0;
508}
Note: See TracBrowser for help on using the repository browser.