source: lib/format_erf.c @ 2faa57e

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