source: lib/format_erf.c @ a81d2fc

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since a81d2fc was 646aca1, checked in by Shane Alcock <salcock@…>, 14 years ago
  • Added a new config option for input traces which will specify whether the event framework should retain the time gaps between packets or not.
  • Updated erf and pcapfile to support the new option, other formats can be updated as required.
  • Renamed the TRACE_META_FREQ option to match the option naming scheme
  • Property mode set to 100644
File size: 17.1 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007 The University of Waikato, Hamilton, New Zealand.
5 * Authors: Daniel Lawson
6 *          Perry Lorier
7 *         
8 * All rights reserved.
9 *
10 * This code has been developed by the University of Waikato WAND
11 * research group. For further information please see http://www.wand.net.nz/
12 *
13 * libtrace is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * libtrace is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with libtrace; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 *
27 * $Id$
28 *
29 */
30#define _GNU_SOURCE
31
32#include "config.h"
33#include "common.h"
34#include "libtrace.h"
35#include "libtrace_int.h"
36#include "format_helper.h"
37#include "format_erf.h"
38
39#include <assert.h>
40#include <errno.h>
41#include <fcntl.h>
42#include <stdio.h>
43#include <string.h>
44#include <stdlib.h>
45
46#ifdef WIN32
47#  include <io.h>
48#  include <share.h>
49#  define PATH_MAX _MAX_PATH
50#else
51#  include <netdb.h>
52#  ifndef PATH_MAX
53#       define PATH_MAX 4096
54#  endif
55#  include <sys/ioctl.h>
56#endif
57
58
59#define COLLECTOR_PORT 3435
60
61static struct libtrace_format_t erfformat;
62
63#define DATA(x) ((struct erf_format_data_t *)x->format_data)
64#define DATAOUT(x) ((struct erf_format_data_out_t *)x->format_data)
65
66#define INPUT DATA(libtrace)->input
67#define IN_OPTIONS DATA(libtrace)->options
68#define OUTPUT DATAOUT(libtrace)->output
69#define OUT_OPTIONS DATAOUT(libtrace)->options
70struct erf_format_data_t {
71       
72        union {
73                int fd;
74                libtrace_io_t *file;
75        } input;
76
77       
78        struct {
79                enum { INDEX_UNKNOWN=0, INDEX_NONE, INDEX_EXISTS } exists;
80                libtrace_io_t *index;
81                off_t index_len;
82        } seek;
83
84        struct {
85                int real_time;
86        } options;
87};
88
89struct erf_format_data_out_t {
90        union {
91                struct {
92                        int level;
93                        int fileflag;
94                } erf;
95               
96        } options;
97       
98        union {
99                int fd;
100                struct rtserver_t * rtserver;
101                libtrace_io_t *file;
102        } output;
103};
104
105/** Structure holding status information for a packet */
106typedef struct libtrace_packet_status {
107        uint8_t type;
108        uint8_t reserved;
109        uint16_t message;
110} libtrace_packet_status_t;
111
112typedef struct erf_index_t {
113        uint64_t timestamp;
114        uint64_t offset; 
115} erf_index_t;
116
117
118/* Dag erf ether packets have a 2 byte padding before the packet
119 * so that the ip header is aligned on a 32 bit boundary.
120 */
121static int erf_get_padding(const libtrace_packet_t *packet)
122{
123        if (packet->trace->format->type==TRACE_FORMAT_ERF) {
124                dag_record_t *erfptr = (dag_record_t *)packet->header;
125                switch(erfptr->type) {
126                        case TYPE_ETH:          return 2;
127                        default:                return 0;
128                }
129        }
130        else {
131                switch(trace_get_link_type(packet)) {
132                        case TYPE_ETH:          return 2;
133                        default:                return 0;
134                }
135        }
136}
137
138int erf_get_framing_length(const libtrace_packet_t *packet)
139{
140        return dag_record_size + erf_get_padding(packet);
141}
142
143
144static int erf_init_input(libtrace_t *libtrace) 
145{
146        libtrace->format_data = malloc(sizeof(struct erf_format_data_t));
147       
148        INPUT.file = 0;
149        IN_OPTIONS.real_time = 0;
150       
151        return 0; /* success */
152}
153
154static int erf_config_input(libtrace_t *libtrace, trace_option_t option,
155                void *value) {
156
157        switch (option) {
158                case TRACE_OPTION_EVENT_REALTIME:
159                        IN_OPTIONS.real_time = *(int *)value;
160                        return 0;
161                default:
162                        /* Unknown option */
163                        trace_set_err(libtrace,TRACE_ERR_UNKNOWN_OPTION,
164                                        "Unknown option");
165                        return -1;
166        }
167}
168
169static int erf_start_input(libtrace_t *libtrace)
170{
171        if (INPUT.file)
172                return 0; /* success */
173
174        INPUT.file = trace_open_file(libtrace);
175
176        if (!INPUT.file)
177                return -1;
178
179        return 0; /* success */
180}
181
182/* Binary search through the index to find the closest point before
183 * the packet.  Consider in future having a btree index perhaps?
184 */
185static int erf_fast_seek_start(libtrace_t *libtrace,uint64_t erfts)
186{
187        size_t max_off = DATA(libtrace)->seek.index_len/sizeof(erf_index_t);
188        size_t min_off = 0;
189        off_t current;
190        erf_index_t record;
191        do {
192                current=(max_off+min_off)>>2;
193
194                libtrace_io_seek(DATA(libtrace)->seek.index,
195                                (int64_t)(current*sizeof(record)),
196                                SEEK_SET);
197                libtrace_io_read(DATA(libtrace)->seek.index,
198                                &record,sizeof(record));
199                if (record.timestamp < erfts) {
200                        min_off=current;
201                }
202                if (record.timestamp > erfts) {
203                        max_off=current;
204                }
205                if (record.timestamp == erfts)
206                        break;
207        } while(min_off<max_off);
208
209        /* If we've passed it, seek backwards.  This loop shouldn't
210         * execute more than twice.
211         */
212        do {
213                libtrace_io_seek(DATA(libtrace)->seek.index,
214                                (int64_t)(current*sizeof(record)),SEEK_SET);
215                libtrace_io_read(DATA(libtrace)->seek.index,
216                                &record,sizeof(record));
217                current--;
218        } while(record.timestamp>erfts);
219
220        /* We've found our location in the trace, now use it. */
221        libtrace_io_seek(INPUT.file,(int64_t) record.offset,SEEK_SET);
222
223        return 0; /* success */
224}
225
226/* There is no index.  Seek through the entire trace from the start, nice
227 * and slowly.
228 */
229static int erf_slow_seek_start(libtrace_t *libtrace,uint64_t erfts UNUSED)
230{
231        if (INPUT.file) {
232                libtrace_io_close(INPUT.file);
233        }
234        INPUT.file = trace_open_file(libtrace);
235        if (!INPUT.file)
236                return -1;
237        return 0;
238}
239
240static int erf_seek_erf(libtrace_t *libtrace,uint64_t erfts)
241{
242        libtrace_packet_t *packet;
243        off_t off = 0;
244
245        if (DATA(libtrace)->seek.exists==INDEX_UNKNOWN) {
246                char buffer[PATH_MAX];
247                snprintf(buffer,sizeof(buffer),"%s.idx",libtrace->uridata);
248                DATA(libtrace)->seek.index=libtrace_io_open(buffer,"rb");
249                if (DATA(libtrace)->seek.index) {
250                        DATA(libtrace)->seek.exists=INDEX_EXISTS;
251                }
252                else {
253                        DATA(libtrace)->seek.exists=INDEX_NONE;
254                }
255        }
256
257        /* If theres an index, use it to find the nearest packet that isn't
258         * after the time we're looking for.  If there is no index we need
259         * to seek slowly through the trace from the beginning.  Sigh.
260         */
261        switch(DATA(libtrace)->seek.exists) {
262                case INDEX_EXISTS:
263                        erf_fast_seek_start(libtrace,erfts);
264                        break;
265                case INDEX_NONE:
266                        erf_slow_seek_start(libtrace,erfts);
267                        break;
268                case INDEX_UNKNOWN:
269                        assert(0);
270                        break;
271        }
272
273        /* Now seek forward looking for the correct timestamp */
274        packet=trace_create_packet();
275        do {
276                trace_read_packet(libtrace,packet);
277                if (trace_get_erf_timestamp(packet)==erfts)
278                        break;
279                off=libtrace_io_tell(INPUT.file);
280        } while(trace_get_erf_timestamp(packet)<erfts);
281
282        libtrace_io_seek(INPUT.file,off,SEEK_SET);
283
284        return 0;
285}
286
287static int erf_init_output(libtrace_out_t *libtrace) {
288        libtrace->format_data = malloc(sizeof(struct erf_format_data_out_t));
289
290        OUT_OPTIONS.erf.level = 0;
291        OUT_OPTIONS.erf.fileflag = O_CREAT | O_WRONLY;
292        OUTPUT.file = 0;
293
294        return 0;
295}
296
297static int erf_config_output(libtrace_out_t *libtrace, trace_option_output_t option,
298                void *value) {
299
300        switch (option) {
301                case TRACE_OPTION_OUTPUT_COMPRESS:
302                        OUT_OPTIONS.erf.level = *(int*)value;
303                        return 0;
304                case TRACE_OPTION_OUTPUT_FILEFLAGS:
305                        OUT_OPTIONS.erf.fileflag = *(int*)value;
306                        return 0;
307                default:
308                        /* Unknown option */
309                        trace_set_err_out(libtrace,TRACE_ERR_UNKNOWN_OPTION,
310                                        "Unknown option");
311                        return -1;
312        }
313}
314
315
316
317static int erf_fin_input(libtrace_t *libtrace) {
318        if (INPUT.file)
319                libtrace_io_close(INPUT.file);
320        free(libtrace->format_data);
321        return 0;
322}
323
324static int erf_fin_output(libtrace_out_t *libtrace) {
325        if (OUTPUT.file)
326                libtrace_io_close(OUTPUT.file);
327        free(libtrace->format_data);
328        return 0;
329}
330 
331
332static int erf_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
333        int numbytes;
334        unsigned int size;
335        void *buffer2 = packet->buffer;
336        unsigned int rlen;
337
338        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
339                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
340                packet->buf_control = TRACE_CTRL_PACKET;
341                if (!packet->buffer) {
342                        trace_set_err(libtrace, errno, 
343                                        "Cannot allocate memory");
344                        return -1;
345                }
346        }
347
348       
349       
350        packet->header = packet->buffer;
351        packet->type = TRACE_RT_DATA_ERF;
352
353        if ((numbytes=libtrace_io_read(INPUT.file,
354                                        packet->buffer,
355                                        (size_t)dag_record_size)) == -1) {
356                trace_set_err(libtrace,errno,"read(%s)",
357                                libtrace->uridata);
358                return -1;
359        }
360        /* EOF */
361        if (numbytes == 0) {
362                return 0;
363        }
364
365        rlen = ntohs(((dag_record_t *)packet->buffer)->rlen);
366        buffer2 = (char*)packet->buffer + dag_record_size;
367        size = rlen - dag_record_size;
368
369        if (size >= LIBTRACE_PACKET_BUFSIZE) {
370                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Packet size %u larger than supported by libtrace - packet is probably corrupt", size);
371                return -1;
372        }
373
374        /* Unknown/corrupt */
375        if (((dag_record_t *)packet->buffer)->type >= 10) {
376                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Corrupt or Unknown ERF type");
377                return -1;
378        }
379       
380        /* read in the rest of the packet */
381        if ((numbytes=libtrace_io_read(INPUT.file,
382                                        buffer2,
383                                        (size_t)size)) != (int)size) {
384                if (numbytes==-1) {
385                        trace_set_err(libtrace,errno, "read(%s)", libtrace->uridata);
386                        return -1;
387                }
388                trace_set_err(libtrace,EIO,"Truncated packet (wanted %d, got %d)", size, numbytes);
389                /* Failed to read the full packet?  must be EOF */
390                return -1;
391        }
392        if (((dag_record_t *)packet->buffer)->flags.rxerror == 1) {
393                packet->payload = NULL;
394        } else {
395                packet->payload = (char*)packet->buffer + erf_get_framing_length(packet);
396        }
397        return rlen;
398}
399
400static int erf_dump_packet(libtrace_out_t *libtrace,
401                dag_record_t *erfptr, unsigned int pad, void *buffer) {
402        int numbytes = 0;
403        int size;
404
405        if ((numbytes = 
406                libtrace_io_write(OUTPUT.file, 
407                                erfptr,
408                                (size_t)(dag_record_size + pad))) 
409                        != (int)(dag_record_size+pad)) {
410                trace_set_err_out(libtrace,errno,
411                                "write(%s)",libtrace->uridata);
412                return -1;
413        }
414
415        size=ntohs(erfptr->rlen)-(dag_record_size+pad);
416        numbytes=libtrace_io_write(OUTPUT.file, buffer, (size_t)size);
417        if (numbytes != size) {
418                trace_set_err_out(libtrace,errno,
419                                "write(%s)",libtrace->uridata);
420                return -1;
421        }
422        return numbytes + pad + dag_record_size;
423}
424
425static int erf_start_output(libtrace_out_t *libtrace)
426{
427        OUTPUT.file = trace_open_file_out(libtrace,
428                        OUT_OPTIONS.erf.level,
429                        OUT_OPTIONS.erf.fileflag);
430        if (!OUTPUT.file) {
431                return -1;
432        }
433        return 0;
434}
435
436static bool find_compatible_linktype(libtrace_out_t *libtrace,
437                                libtrace_packet_t *packet)
438{
439        /* Keep trying to simplify the packet until we can find
440         * something we can do with it */
441        do {
442                char type=libtrace_to_erf_type(trace_get_link_type(packet));
443
444                /* Success */
445                if (type != (char)-1)
446                        return true;
447
448                if (!demote_packet(packet)) {
449                        trace_set_err_out(libtrace,
450                                        TRACE_ERR_NO_CONVERSION,
451                                        "No erf type for packet (%i)",
452                                        trace_get_link_type(packet));
453                        return false;
454                }
455
456        } while(1);
457
458        return true;
459}
460               
461static int erf_write_packet(libtrace_out_t *libtrace, 
462                libtrace_packet_t *packet) 
463{
464        int numbytes = 0;
465        unsigned int pad = 0;
466        dag_record_t *dag_hdr = (dag_record_t *)packet->header;
467        void *payload = packet->payload;
468
469        assert(OUTPUT.file);
470
471        if (!packet->header) {
472                /*trace_set_err_output(libtrace, TRACE_ERR_BAD_PACKET,
473                                "Packet has no header - probably an RT packet");
474                */
475                return -1;
476        }
477       
478        pad = erf_get_padding(packet);
479
480        /* If we've had an rxerror, we have no payload to write - fix
481         * rlen to be the correct length
482         */
483        /* I Think this is bogus, we should somehow figure out
484         * a way to write out the payload even if it is gibberish -- Perry */
485        if (payload == NULL) {
486                dag_hdr->rlen = htons(dag_record_size + pad);
487               
488        } 
489       
490        if (packet->type == TRACE_RT_DATA_ERF) {
491                        numbytes = erf_dump_packet(libtrace,
492                                (dag_record_t *)packet->header,
493                                pad,
494                                payload
495                                );
496        } else {
497                dag_record_t erfhdr;
498                /* convert format - build up a new erf header */
499                /* Timestamp */
500                erfhdr.ts = bswap_host_to_le64(trace_get_erf_timestamp(packet));
501
502                /* Flags. Can't do this */
503                memset(&erfhdr.flags,1,sizeof(erfhdr.flags));
504                if (trace_get_direction(packet)!=~0U)
505                        erfhdr.flags.iface = trace_get_direction(packet);
506
507                if (!find_compatible_linktype(libtrace,packet))
508                        return -1;
509
510                payload=packet->payload;
511                pad = erf_get_padding(packet);
512
513                erfhdr.type = libtrace_to_erf_type(trace_get_link_type(packet));
514
515                /* Packet length (rlen includes format overhead) */
516                assert(trace_get_capture_length(packet)>0 
517                                && trace_get_capture_length(packet)<=65536);
518                assert(erf_get_framing_length(packet)>0 
519                                && trace_get_framing_length(packet)<=65536);
520                assert(
521                        trace_get_capture_length(packet)+erf_get_framing_length(packet)>0
522                      &&trace_get_capture_length(packet)+erf_get_framing_length(packet)<=65536);
523                erfhdr.rlen = htons(trace_get_capture_length(packet) 
524                        + erf_get_framing_length(packet));
525                /* loss counter. Can't do this */
526                erfhdr.lctr = 0;
527                /* Wire length, does not include padding! */
528                erfhdr.wlen = htons(trace_get_wire_length(packet));
529
530                /* Write it out */
531                numbytes = erf_dump_packet(libtrace,
532                                &erfhdr,
533                                pad,
534                                payload);
535        }
536        return numbytes;
537}
538
539libtrace_linktype_t erf_get_link_type(const libtrace_packet_t *packet) {
540        dag_record_t *erfptr = 0;
541        erfptr = (dag_record_t *)packet->header;
542        if (erfptr->type != TYPE_LEGACY)
543                return erf_type_to_libtrace(erfptr->type);
544        else {
545                /* Sigh, lets start wildly guessing */
546                if (((char*)packet->payload)[4]==0x45)
547                        return TRACE_TYPE_PPP;
548                return ~0;
549        }
550}
551
552libtrace_direction_t erf_get_direction(const libtrace_packet_t *packet) {
553        dag_record_t *erfptr = 0;
554        erfptr = (dag_record_t *)packet->header;
555        return erfptr->flags.iface;
556}
557
558libtrace_direction_t erf_set_direction(libtrace_packet_t *packet, libtrace_direction_t direction) {
559        dag_record_t *erfptr = 0;
560        erfptr = (dag_record_t *)packet->header;
561        erfptr->flags.iface = direction;
562        return erfptr->flags.iface;
563}
564
565uint64_t erf_get_erf_timestamp(const libtrace_packet_t *packet) {
566        dag_record_t *erfptr = 0;
567        erfptr = (dag_record_t *)packet->header;
568        return bswap_le_to_host64(erfptr->ts);
569}
570
571int erf_get_capture_length(const libtrace_packet_t *packet) {
572        dag_record_t *erfptr = 0;
573        int caplen;
574        if (packet->payload == NULL)
575                return 0; 
576       
577        erfptr = (dag_record_t *)packet->header;
578        caplen = ntohs(erfptr->rlen) - erf_get_framing_length(packet);
579        if (ntohs(erfptr->wlen) < caplen)
580                return ntohs(erfptr->wlen);
581
582        return (ntohs(erfptr->rlen) - erf_get_framing_length(packet));
583}
584
585int erf_get_wire_length(const libtrace_packet_t *packet) {
586        dag_record_t *erfptr = 0;
587        erfptr = (dag_record_t *)packet->header;
588        return ntohs(erfptr->wlen);
589}
590
591size_t erf_set_capture_length(libtrace_packet_t *packet, size_t size) {
592        dag_record_t *erfptr = 0;
593        assert(packet);
594        if(size  > trace_get_capture_length(packet)) {
595                /* can't make a packet larger */
596                return trace_get_capture_length(packet);
597        }
598        erfptr = (dag_record_t *)packet->header;
599        erfptr->rlen = htons(size + erf_get_framing_length(packet));
600        return trace_get_capture_length(packet);
601}
602
603static struct libtrace_eventobj_t erf_event(struct libtrace_t *libtrace, struct libtrace_packet_t *packet) {
604        struct libtrace_eventobj_t event = {0,0,0.0,0};
605       
606        if (IN_OPTIONS.real_time) {
607                event.size = erf_read_packet(libtrace, packet);
608                if (event.size < 1)
609                        event.type = TRACE_EVENT_TERMINATE;
610                else
611                        event.type = TRACE_EVENT_PACKET;
612                return event;
613               
614        } else {
615                return trace_event_trace(libtrace, packet);
616        }
617       
618}
619
620static void erf_help(void) {
621        printf("erf format module: $Revision$\n");
622        printf("Supported input URIs:\n");
623        printf("\terf:/path/to/file\t(uncompressed)\n");
624        printf("\terf:/path/to/file.gz\t(gzip-compressed)\n");
625        printf("\terf:-\t(stdin, either compressed or not)\n");
626        printf("\terf:/path/to/socket\n");
627        printf("\n");
628        printf("\te.g.: erf:/tmp/trace\n");
629        printf("\n");
630        printf("Supported output URIs:\n");
631        printf("\terf:path/to/file\t(uncompressed)\n");
632        printf("\terf:/path/to/file.gz\t(gzip-compressed)\n");
633        printf("\terf:-\t(stdout, either compressed or not)\n");
634        printf("\n");
635        printf("\te.g.: erf:/tmp/trace\n");
636        printf("\n");
637        printf("Supported output options:\n");
638        printf("\t-z\tSpecify the gzip compression, ranging from 0 (uncompressed) to 9 - defaults to 1\n");
639        printf("\n");
640
641       
642}
643
644static struct libtrace_format_t erfformat = {
645        "erf",
646        "$Id$",
647        TRACE_FORMAT_ERF,
648        erf_init_input,                 /* init_input */       
649        erf_config_input,               /* config_input */
650        erf_start_input,                /* start_input */
651        NULL,                           /* pause_input */
652        erf_init_output,                /* init_output */
653        erf_config_output,              /* config_output */
654        erf_start_output,               /* start_output */
655        erf_fin_input,                  /* fin_input */
656        erf_fin_output,                 /* fin_output */
657        erf_read_packet,                /* read_packet */
658        NULL,                           /* fin_packet */
659        erf_write_packet,               /* write_packet */
660        erf_get_link_type,              /* get_link_type */
661        erf_get_direction,              /* get_direction */
662        erf_set_direction,              /* set_direction */
663        erf_get_erf_timestamp,          /* get_erf_timestamp */
664        NULL,                           /* get_timeval */
665        NULL,                           /* get_seconds */
666        erf_seek_erf,                   /* seek_erf */
667        NULL,                           /* seek_timeval */
668        NULL,                           /* seek_seconds */
669        erf_get_capture_length,         /* get_capture_length */
670        erf_get_wire_length,            /* get_wire_length */
671        erf_get_framing_length,         /* get_framing_length */
672        erf_set_capture_length,         /* set_capture_length */
673        NULL,                           /* get_fd */
674        erf_event,                      /* trace_event */
675        erf_help,                       /* help */
676        NULL                            /* next pointer */
677};
678
679
680void erf_constructor(void) {
681        register_format(&erfformat);
682}
Note: See TracBrowser for help on using the repository browser.