source: lib/format_erf.c @ f3f3558

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since f3f3558 was f3f3558, checked in by Perry Lorier <perry@…>, 14 years ago

Ready for release

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