source: tools/tracesplit/tracesplit.c @ ee6e802

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivendag_formatrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since ee6e802 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: 14.0 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
193        if (trace_get_link_type(*packet) == -1) {
194                fprintf(stderr, "Halted due to being unable to determine linktype - input trace may be corrupt.\n");
195                return -1;
196        }
197
198        if (snaplen>0) {
199                trace_set_capture_length(*packet,snaplen);
200        }
201
202        if (trace_get_seconds(*packet)<starttime) {
203                return 1;
204        }
205
206        if (trace_get_seconds(*packet)>endtime) {
207                return 0;
208        }
209
210        if (firsttime==0) {
211                time_t now = trace_get_seconds(*packet);
212                if (starttime != 0) {
213                        firsttime=now-((now - starttime)%interval);
214                }
215                else {
216                        firsttime=now;
217                }
218        }
219
220        if (output && trace_get_seconds(*packet)>firsttime+interval) {
221                trace_destroy_output(output);
222                output=NULL;
223                firsttime+=interval;
224        }
225
226        if (output && pktcount%count==0) {
227                trace_destroy_output(output);
228                output=NULL;
229        }
230
231        pktcount++;
232        totbytes+=trace_get_capture_length(*packet);
233        if (output && totbytes-totbyteslast>=bytes) {
234                trace_destroy_output(output);
235                output=NULL;
236                totbyteslast=totbytes;
237        }
238        if (!output) {
239                char *buffer;
240                bool need_ext=false;
241                if (maxfiles <= filescreated) {
242                        return 0;
243                }
244                buffer=strdup(output_base);
245                if (interval!=UINT64_MAX && maxfiles>1) {
246                        buffer=strdupcat(buffer,"-");
247                        buffer=strdupcati(buffer,(uint64_t)firsttime);
248                        need_ext=true;
249                }
250                if (count!=UINT64_MAX && maxfiles>1) {
251                        buffer=strdupcat(buffer,"-");
252                        buffer=strdupcati(buffer,(uint64_t)pktcount);
253                        need_ext=true;
254                }
255                if (bytes!=UINT64_MAX && maxfiles>1) {
256                        static int filenum=0;
257                        buffer=strdupcat(buffer,"-");
258                        buffer=strdupcati(buffer,(uint64_t)++filenum);
259                        need_ext=true;
260                }
261                if (need_ext) {
262                        if (compress_level!=0)
263                                buffer=strdupcat(buffer,".gz");
264                }
265                if (verbose>1) {
266                        fprintf(stderr,"%s:",buffer);
267                        if (count!=UINT64_MAX)
268                                fprintf(stderr," count=%" PRIu64,pktcount);
269                        if (bytes!=UINT64_MAX)
270                                fprintf(stderr," bytes=%" PRIu64,bytes);
271                        if (interval!=UINT64_MAX) {
272                                time_t filetime = firsttime;
273                                fprintf(stderr," time=%s",ctime(&filetime));
274                        }
275                        else {
276                                fprintf(stderr,"\n");
277                        }
278                }
279                output=trace_create_output(buffer);
280                if (trace_is_err_output(output)) {
281                        trace_perror_output(output,"%s",buffer);
282                        free(buffer);
283                        return -1;
284                }
285                if (compress_level!=-1) {
286                        if (trace_config_output(output,
287                                                TRACE_OPTION_OUTPUT_COMPRESS,
288                                                &compress_level)==-1) {
289                                trace_perror_output(output,"Unable to set compression level");
290                        }
291                }
292
293                if (trace_config_output(output,
294                                        TRACE_OPTION_OUTPUT_COMPRESSTYPE,
295                                        &compress_type) == -1) {
296                        trace_perror_output(output, "Unable to set compression type");
297                }
298
299                trace_start_output(output);
300                if (trace_is_err_output(output)) {
301                        trace_perror_output(output,"%s",buffer);
302                        free(buffer);
303                        return -1;
304                }
305                free(buffer);
306                filescreated ++;
307        }
308
309        /* Some traces we have are padded (usually with 0x00), so
310         * lets sort that out now and truncate them properly
311         */
312
313        if (trace_get_capture_length(*packet)
314                        > trace_get_wire_length(*packet)) {
315                trace_set_capture_length(*packet,
316                        trace_get_wire_length(*packet));
317        }
318
319        /* Support "jump"ping to the nth IP header. */
320        if (jump) {
321            /* Skip headers */
322            void *newpacket = perform_jump(*packet, jump);
323            if (newpacket) {
324                trace_destroy_packet(*packet);
325                *packet = newpacket;
326            }
327            else /* Skip packet */
328                return 1;
329        }
330
331        if (trace_write_packet(output, *packet)==-1) {
332                trace_perror_output(output,"write_packet");
333                return -1;
334        }
335
336        return 1;
337
338}
339
340int main(int argc, char *argv[])
341{
342        char *compress_type_str=NULL;
343        struct libtrace_filter_t *filter=NULL;
344        struct libtrace_t *input = NULL;
345        struct libtrace_packet_t *packet = trace_create_packet();
346        struct sigaction sigact;
347        int i;
348
349        if (argc<2) {
350                usage(argv[0]);
351                return 1;
352        }
353
354        /* Parse command line options */
355        while(1) {
356                int option_index;
357                struct option long_options[] = {
358                        { "filter",        1, 0, 'f' },
359                        { "count",         1, 0, 'c' },
360                        { "bytes",         1, 0, 'b' },
361                        { "starttime",     1, 0, 's' },
362                        { "endtime",       1, 0, 'e' },
363                        { "interval",      1, 0, 'i' },
364                        { "jump",          1, 0, 'j' },
365                        { "libtrace-help", 0, 0, 'H' },
366                        { "maxfiles",      1, 0, 'm' },
367                        { "snaplen",       1, 0, 'S' },
368                        { "verbose",       0, 0, 'v' },
369                        { "compress-level", 1, 0, 'z' },
370                        { "compress-type", 1, 0, 'Z' },
371                        { NULL,            0, 0, 0   },
372                };
373
374                int c=getopt_long(argc, argv, "j:f:c:b:s:e:i:m:S:Hvz:Z:",
375                                long_options, &option_index);
376
377                if (c==-1)
378                        break;
379
380                switch (c) {
381                        case 'f': filter=trace_create_filter(optarg);
382                                break;
383                        case 'c': count=atoi(optarg);
384                                break;
385                        case 'b': bytes=atoi(optarg);
386                                break;
387                        case 's': starttime=atoi(optarg); /* FIXME: use getdate */
388                                  break;
389                        case 'e': endtime=atoi(optarg);
390                                  break;
391                        case 'i': interval=atoi(optarg);
392                                  break;
393                        case 'j': jump=atoi(optarg);
394                                  break;
395                        case 'm': maxfiles=atoi(optarg);
396                                  break;
397                        case 'S': snaplen=atoi(optarg);
398                                  break;
399                        case 'H':
400                                  trace_help();
401                                  exit(1);
402                                  break;
403                        case 'v':
404                                  verbose++;
405                                  break;
406                        case 'z':
407                                  compress_level=atoi(optarg);
408                                  if (compress_level<0 || compress_level>9) {
409                                        usage(argv[0]);
410                                        exit(1);
411                                  }
412                                  break;
413                        case 'Z':
414                                  compress_type_str=optarg;
415                                  break;
416                        default:
417                                fprintf(stderr,"Unknown option: %c\n",c);
418                                usage(argv[0]);
419                                return 1;
420                }
421        }
422
423        if (compress_type_str == NULL && compress_level >= 0) {
424                fprintf(stderr, "Compression level set, but no compression type was defined, setting to gzip\n");
425                compress_type = TRACE_OPTION_COMPRESSTYPE_ZLIB;
426        }
427
428        else if (compress_type_str == NULL) {
429                /* If a level or type is not specified, use the "none"
430                 * compression module */
431                compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
432        }
433
434        /* I decided to be fairly generous in what I accept for the
435         * compression type string */
436        else if (strncmp(compress_type_str, "gz", 2) == 0 ||
437                        strncmp(compress_type_str, "zlib", 4) == 0) {
438                compress_type = TRACE_OPTION_COMPRESSTYPE_ZLIB;
439        } else if (strncmp(compress_type_str, "bz", 2) == 0) {
440                compress_type = TRACE_OPTION_COMPRESSTYPE_BZ2;
441        } else if (strncmp(compress_type_str, "lzo", 3) == 0) {
442                compress_type = TRACE_OPTION_COMPRESSTYPE_LZO;
443        } else if (strncmp(compress_type_str, "xz", 2) == 0) {
444                compress_type = TRACE_OPTION_COMPRESSTYPE_LZMA;
445        } else if (strncmp(compress_type_str, "no", 2) == 0) {
446                compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
447        } else {
448                fprintf(stderr, "Unknown compression type: %s\n",
449                        compress_type_str);
450                return 1;
451        }
452
453        if (optind+2>argc) {
454                fprintf(stderr,"missing inputuri or outputuri\n");
455                usage(argv[0]);
456        }
457
458        output_base = argv[argc - 1];
459
460        sigact.sa_handler = cleanup_signal;
461        sigemptyset(&sigact.sa_mask);
462        sigact.sa_flags = SA_RESTART;
463
464        sigaction(SIGINT, &sigact, NULL);
465        sigaction(SIGTERM, &sigact, NULL);
466
467        output=NULL;
468
469        signal(SIGINT,&cleanup_signal);
470        signal(SIGTERM,&cleanup_signal);
471
472        for (i = optind; i < argc - 1; i++) {
473
474
475                input = trace_create(argv[i]);
476
477                if (trace_is_err(input)) {
478                        trace_perror(input,"%s",argv[i]);
479                        return 1;
480                }
481
482                if (filter && trace_config(input, TRACE_OPTION_FILTER, filter) == 1) {
483                        trace_perror(input, "Configuring filter for %s",
484                                        argv[i]);
485                        return 1;
486                }
487
488                if (trace_start(input)==-1) {
489                        trace_perror(input,"%s",argv[i]);
490                        return 1;
491                }
492
493                while (trace_read_packet(input,packet)>0) {
494                        if (per_packet(&packet) < 1)
495                                done = 1;
496                        if (done)
497                                break;
498                }
499
500                if (trace_is_err(input)) {
501                        trace_perror(input,"Reading packets");
502                        trace_destroy(input);
503                        break;
504                }
505
506                trace_destroy(input);
507               
508                if (done)
509                        break;
510               
511        }
512
513        if (verbose) {
514                libtrace_stat_t *stat;
515               
516                stat = trace_create_statistics();
517                trace_get_statistics(input, stat);
518
519                if (stat->received_valid)
520                        fprintf(stderr,"%" PRIu64 " packets on input\n",
521                                        stat->received);
522                if (stat->filtered_valid)
523                        fprintf(stderr,"%" PRIu64 " packets filtered\n",
524                                        stat->filtered);
525                if (stat->dropped_valid)
526                        fprintf(stderr,"%" PRIu64 " packets dropped\n",
527                                        stat->dropped);
528                if (stat->accepted_valid)
529                        fprintf(stderr,"%" PRIu64 " packets accepted\n",
530                                        stat->accepted);
531                free(stat);
532        }
533       
534        if (output)
535                trace_destroy_output(output);
536
537        trace_destroy_packet(packet);
538
539        return 0;
540}
Note: See TracBrowser for help on using the repository browser.