source: tools/tracesplit/tracesplit.c @ 92cf299

cachetimestampsdevelopdpdk-ndagetsiliverc-4.0.3rc-4.0.4ringdecrementfixringperformance
Last change on this file since 92cf299 was 92cf299, checked in by Shane Alcock <salcock@…>, 3 years ago

tracesplit: don't bother setting compression type to "none".

Setting a compression type on a output format that does not
support compression (e.g. dpdk) tends to not work so well.

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