source: lib/format_erf.c @ 121b7e2

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