source: lib/format_erf.c @ 32ee9b2

cachetimestampsdeveloprc-4.0.4ringdecrementfixringperformance
Last change on this file since 32ee9b2 was 32ee9b2, checked in by Shane Alcock <salcock@…>, 2 years ago

Add new trace_flush_output() to public API

Can be used to force a libtrace output to dump any buffered output
to disk immediately.

Note that if the file is compressed or the output trace format
requires a trailer, the flushed file will still not be properly
readable afterwards as this will not result in any trailers
being written. You'll still have to close the file for that.

Mainly this is useful for ensuring that output file sizes grow
over time in situations where the amount of output is relatively
small, rather than staying stuck at 0 bytes until we either reach
1MB of output or the file is closed. For instance, you could have
a timer that calls trace_flush_output() every 30 seconds so that
the output file size will grow if any packets were written in the
last 30 seconds.

  • Property mode set to 100644
File size: 24.9 KB
Line 
1/*
2 *
3 * Copyright (c) 2007-2016 The University of Waikato, Hamilton, New Zealand.
4 * All rights reserved.
5 *
6 * This file is part of libtrace.
7 *
8 * This code has been developed by the University of Waikato WAND
9 * research group. For further information please see http://www.wand.net.nz/
10 *
11 * libtrace is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * libtrace is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 *
24 *
25 */
26
27#define _GNU_SOURCE
28
29#include "config.h"
30#include "common.h"
31#include "libtrace.h"
32#include "libtrace_int.h"
33#include "format_helper.h"
34#include "format_erf.h"
35#include "wandio.h"
36
37#include <assert.h>
38#include <errno.h>
39#include <fcntl.h>
40#include <stdio.h>
41#include <string.h>
42#include <stdlib.h>
43
44
45#ifdef WIN32
46#  include <io.h>
47#  include <share.h>
48#  define PATH_MAX _MAX_PATH
49#else
50#  include <netdb.h>
51#  ifndef PATH_MAX
52#       define PATH_MAX 4096
53#  endif
54#  include <sys/ioctl.h>
55#endif
56
57/* This format module deals with reading and writing ERF traces. ERF is the
58 * trace format developed by Endace for use by DAG hardware capture cards.
59 *
60 * ERF is not a live capture format.
61 *
62 */
63
64
65static struct libtrace_format_t erfformat;
66
67#define DATA(x) ((struct erf_format_data_t *)x->format_data)
68#define DATAOUT(x) ((struct erf_format_data_out_t *)x->format_data)
69
70#define IN_OPTIONS DATA(libtrace)->options
71#define OUTPUT DATAOUT(libtrace)
72#define OUT_OPTIONS DATAOUT(libtrace)->options
73
74/* "Global" data that is stored for each ERF input trace */
75struct erf_format_data_t {
76       
77        /* Index used for seeking within a trace */
78        struct {
79                /* The index itself */
80                io_t *index;
81                /* The offset of the index */
82                off_t index_len;
83                /* Indicates the existence of an index */
84                enum { INDEX_UNKNOWN=0, INDEX_NONE, INDEX_EXISTS } exists;
85        } seek;
86
87        /* Number of packets that were dropped during the capture */
88        uint64_t drops;
89
90        /* Config options for the input trace */
91        struct {
92                /* Flag indicating whether the event API should replicate the
93                 * time gaps between each packet or return a PACKET event for
94                 * each packet */
95                int real_time;
96        } options;
97};
98
99/* "Global" data that is stored for each ERF output trace */
100struct erf_format_data_out_t {
101
102        /* Config options for the output trace */
103        struct {
104                /* Compression level for the output file */
105                int level;
106                /* Compression type */
107                int compress_type;
108                /* File flags used to open the file, e.g. O_CREATE */
109                int fileflag;
110        } options;
111
112        /* The output file itself */
113        iow_t *file;
114       
115};
116
117typedef struct erf_index_t {
118        uint64_t timestamp;
119        uint64_t offset; 
120} erf_index_t;
121
122/* Ethernet packets have a 2 byte padding before the packet
123 * so that the IP header is aligned on a 32 bit boundary.
124 */
125static inline int erf_get_padding(const libtrace_packet_t *packet)
126{
127        if (packet->trace->format->type==TRACE_FORMAT_ERF ||
128                        packet->trace->format->type == TRACE_FORMAT_NDAG ||
129                        packet->trace->format->type == TRACE_FORMAT_RAWERF ||
130                        packet->trace->format->type == TRACE_FORMAT_DPDK_NDAG) {
131                dag_record_t *erfptr = (dag_record_t *)packet->header;
132                switch((erfptr->type & 0x7f)) {
133                        case TYPE_ETH:
134                        case TYPE_COLOR_ETH:
135                        case TYPE_DSM_COLOR_ETH:
136                        case TYPE_COLOR_HASH_ETH:
137                                return 2;
138                        default:                return 0;
139                }
140        }
141        else {
142                switch(trace_get_link_type(packet)) {
143                        case TRACE_TYPE_ETH:    return 2;
144                        default:                return 0;
145                }
146        }
147}
148
149int erf_is_color_type(uint8_t erf_type)
150{
151        switch(erf_type & 0x7f) {
152                case TYPE_COLOR_HDLC_POS:
153                case TYPE_DSM_COLOR_HDLC_POS:
154                case TYPE_COLOR_ETH:
155                case TYPE_DSM_COLOR_ETH:
156                case TYPE_COLOR_HASH_POS:
157                case TYPE_COLOR_HASH_ETH:
158                        return 1;
159        }
160
161        return 0;
162}
163
164int erf_get_framing_length(const libtrace_packet_t *packet)
165{
166        uint16_t extsize = 0;
167        dag_record_t *erfptr = NULL;
168        uint64_t *exthdr = NULL;
169        uint8_t *firstbyte;
170
171        erfptr = (dag_record_t *)packet->header;
172        if ((erfptr->type & 0x80) == 0x80) {
173                /* Extension headers are present */
174                exthdr = (uint64_t *)((char *)packet->header + dag_record_size);
175                extsize += 8;
176
177                firstbyte = (uint8_t *)exthdr;
178                while ((*firstbyte & 0x80) == 0x80) {
179                        extsize += 8;
180                        exthdr ++;
181                        firstbyte = (uint8_t *)exthdr;
182                        assert(extsize <= ntohs(erfptr->rlen));
183                }
184        }
185        return dag_record_size + extsize + erf_get_padding(packet);
186}
187
188/* Attempts to determine whether a given trace file is using the ERF format
189 *
190 * Returns 1 if the trace is probably ERF, 0 otherwise
191 */
192static int erf_probe_magic(io_t *io)
193{
194        char buffer[4096];
195        int len;
196        dag_record_t *erf;
197        len = wandio_peek(io, buffer, sizeof(buffer));
198        if (len < (int)dag_record_size) {
199                return 0; /* False */
200        }
201        erf = (dag_record_t *) buffer;
202        /* If the record is too short */
203        if (ntohs(erf->rlen) < dag_record_size) {
204                return 0;
205        }
206        /* There aren't any erf traces before 1995-01-01 */
207        if (bswap_le_to_host64(erf->ts) < 0x2f0539b000000000ULL) {
208                return 0;
209        }
210        /* And not pcap! */
211        if (bswap_le_to_host64(erf->ts) >>32 == 0xa1b2c3d4) {
212                return 0;
213        }
214        /* And not the other pcap! */
215        if (bswap_le_to_host64(erf->ts) >>32 == 0xd4c3b2a1) {
216                return 0;
217        }
218        /* Is this a proper typed packet */
219        if ((erf->type & 0x7f) > ERF_TYPE_MAX) {
220                return 0;
221        }
222        /* We should put some more tests in here. */
223        /* Yeah, this is probably ERF */
224        return 1;
225}
226
227static int erf_init_input(libtrace_t *libtrace) 
228{
229        libtrace->format_data = malloc(sizeof(struct erf_format_data_t));
230       
231        IN_OPTIONS.real_time = 0;
232        DATA(libtrace)->drops = 0;
233       
234        return 0; /* success */
235}
236
237static int erf_config_input(libtrace_t *libtrace, trace_option_t option,
238                void *value) {
239
240        switch (option) {
241                case TRACE_OPTION_EVENT_REALTIME:
242                        IN_OPTIONS.real_time = *(int *)value;
243                        return 0;
244                case TRACE_OPTION_SNAPLEN:
245                case TRACE_OPTION_PROMISC:
246                case TRACE_OPTION_FILTER:
247                case TRACE_OPTION_META_FREQ:
248                        trace_set_err(libtrace, TRACE_ERR_OPTION_UNAVAIL,
249                                        "Unsupported option");
250                        return -1;
251                default:
252                        /* Unknown option */
253                        trace_set_err(libtrace,TRACE_ERR_UNKNOWN_OPTION,
254                                        "Unknown option");
255                        return -1;
256        }
257}
258
259static int erf_start_input(libtrace_t *libtrace) 
260{
261        if (libtrace->io)
262                return 0; /* Success -- already done. */
263
264        libtrace->io = trace_open_file(libtrace);
265
266        if (!libtrace->io)
267                return -1;
268
269        DATA(libtrace)->drops = 0;
270        return 0; /* success */
271}
272
273/* Raw ERF is a special case -- we want to force libwandio to treat the file
274 * as uncompressed so we can't just use trace_open_file() */
275static int rawerf_start_input(libtrace_t *libtrace)
276{
277        if (libtrace->io)
278                return 0; 
279
280        libtrace->io = wandio_create_uncompressed(libtrace->uridata);
281
282        if (!libtrace->io) {
283                if (errno != 0) {
284                        trace_set_err(libtrace, errno, "Unable to open raw ERF file %s", libtrace->uridata);
285                }
286                return -1;
287        }
288
289        DATA(libtrace)->drops = 0;
290
291        return 0; /* success */
292}
293
294/* Binary search through the index to find the closest point before
295 * the packet.  Consider in future having a btree index perhaps?
296 */
297static int erf_fast_seek_start(libtrace_t *libtrace,uint64_t erfts)
298{
299        size_t max_off = DATA(libtrace)->seek.index_len/sizeof(erf_index_t);
300        size_t min_off = 0;
301        off_t current;
302        erf_index_t record;
303        do {
304                current=(max_off+min_off)>>2;
305
306                wandio_seek(DATA(libtrace)->seek.index,
307                                (int64_t)(current*sizeof(record)),
308                                SEEK_SET);
309                wandio_read(DATA(libtrace)->seek.index,
310                                &record,sizeof(record));
311                if (record.timestamp < erfts) {
312                        min_off=current;
313                }
314                if (record.timestamp > erfts) {
315                        max_off=current;
316                }
317                if (record.timestamp == erfts)
318                        break;
319        } while(min_off<max_off);
320
321        /* If we've passed it, seek backwards.  This loop shouldn't
322         * execute more than twice.
323         */
324        do {
325                wandio_seek(DATA(libtrace)->seek.index,
326                                (int64_t)(current*sizeof(record)),SEEK_SET);
327                wandio_read(DATA(libtrace)->seek.index,
328                                &record,sizeof(record));
329                current--;
330        } while(record.timestamp>erfts);
331
332        /* We've found our location in the trace, now use it. */
333        wandio_seek(libtrace->io,(int64_t) record.offset,SEEK_SET);
334
335        return 0; /* success */
336}
337
338/* There is no index.  Seek through the entire trace from the start, nice
339 * and slowly.
340 */
341static int erf_slow_seek_start(libtrace_t *libtrace,uint64_t erfts UNUSED)
342{
343        if (libtrace->io) {
344                wandio_destroy(libtrace->io);
345        }
346        libtrace->io = trace_open_file(libtrace);
347        if (!libtrace->io)
348                return -1;
349        return 0;
350}
351
352/* Seek within an ERF trace based on an ERF timestamp */
353static int erf_seek_erf(libtrace_t *libtrace,uint64_t erfts)
354{
355        libtrace_packet_t *packet;
356        off_t off = 0;
357
358        if (DATA(libtrace)->seek.exists==INDEX_UNKNOWN) {
359                char buffer[PATH_MAX];
360                snprintf(buffer,sizeof(buffer),"%s.idx",libtrace->uridata);
361                DATA(libtrace)->seek.index=wandio_create(buffer);
362                if (DATA(libtrace)->seek.index) {
363                        DATA(libtrace)->seek.exists=INDEX_EXISTS;
364                }
365                else {
366                        DATA(libtrace)->seek.exists=INDEX_NONE;
367                }
368        }
369
370        /* If theres an index, use it to find the nearest packet that isn't
371         * after the time we're looking for.  If there is no index we need
372         * to seek slowly through the trace from the beginning.  Sigh.
373         */
374        switch(DATA(libtrace)->seek.exists) {
375                case INDEX_EXISTS:
376                        erf_fast_seek_start(libtrace,erfts);
377                        break;
378                case INDEX_NONE:
379                        erf_slow_seek_start(libtrace,erfts);
380                        break;
381                case INDEX_UNKNOWN:
382                        assert(0);
383                        break;
384        }
385
386        /* Now seek forward looking for the correct timestamp */
387        packet=trace_create_packet();
388        do {
389                trace_read_packet(libtrace,packet);
390                if (trace_get_erf_timestamp(packet)==erfts)
391                        break;
392                off=wandio_tell(libtrace->io);
393        } while(trace_get_erf_timestamp(packet)<erfts);
394
395        wandio_seek(libtrace->io,off,SEEK_SET);
396
397        return 0;
398}
399
400static int erf_init_output(libtrace_out_t *libtrace) {
401        libtrace->format_data = malloc(sizeof(struct erf_format_data_out_t));
402
403        OUT_OPTIONS.level = 0;
404        OUT_OPTIONS.compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
405        OUT_OPTIONS.fileflag = O_CREAT | O_WRONLY;
406        OUTPUT->file = 0;
407
408        return 0;
409}
410
411static int erf_config_output(libtrace_out_t *libtrace, 
412                trace_option_output_t option, void *value) {
413
414        switch (option) {
415                case TRACE_OPTION_OUTPUT_COMPRESS:
416                        OUT_OPTIONS.level = *(int*)value;
417                        return 0;
418                case TRACE_OPTION_OUTPUT_COMPRESSTYPE:
419                        OUT_OPTIONS.compress_type = *(int*)value;
420                        return 0;
421                case TRACE_OPTION_OUTPUT_FILEFLAGS:
422                        OUT_OPTIONS.fileflag = *(int*)value;
423                        return 0;
424                default:
425                        /* Unknown option */
426                        trace_set_err_out(libtrace,TRACE_ERR_UNKNOWN_OPTION,
427                                        "Unknown option");
428                        return -1;
429        }
430}
431
432
433
434static int erf_fin_input(libtrace_t *libtrace) {
435        if (libtrace->io)
436                wandio_destroy(libtrace->io);
437        free(libtrace->format_data);
438        return 0;
439}
440
441static int erf_fin_output(libtrace_out_t *libtrace) {
442        if (OUTPUT->file)
443                wandio_wdestroy(OUTPUT->file);
444        free(libtrace->format_data);
445        return 0;
446}
447 
448static int erf_prepare_packet(libtrace_t *libtrace, libtrace_packet_t *packet,
449                void *buffer, libtrace_rt_types_t rt_type, uint32_t flags) {
450       
451        dag_record_t *erfptr;
452
453        if (packet->buffer != buffer && 
454                packet->buf_control == TRACE_CTRL_PACKET) {
455                free(packet->buffer);
456        }
457
458        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
459                packet->buf_control = TRACE_CTRL_PACKET;
460        } else
461                packet->buf_control = TRACE_CTRL_EXTERNAL;
462       
463       
464        packet->type = rt_type;
465        packet->buffer = buffer;
466        packet->header = buffer;
467        erfptr = (dag_record_t *)packet->buffer;
468        if (erfptr->flags.rxerror == 1) {
469                packet->payload = NULL;
470        } else {
471                packet->payload = (char*)packet->buffer + erf_get_framing_length(packet);
472        }
473
474        assert(erfptr->rlen != 0);
475       
476        if (libtrace->format_data == NULL) {
477                /* Allocates the format_data structure */
478                if (erf_init_input(libtrace)) 
479                        return -1;
480        }
481
482        /* Check for loss */
483        if (erf_is_color_type(erfptr->type)) {
484                /* No idea how we get this yet */
485
486        } else if (erfptr->lctr) {
487                DATA(libtrace)->drops += ntohs(erfptr->lctr);
488        }
489
490        return 0;
491}
492
493static int erf_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
494        int numbytes;
495        unsigned int size;
496        void *buffer2 = packet->buffer;
497        unsigned int rlen;
498        uint32_t flags = 0;
499       
500       
501        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
502                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
503                if (!packet->buffer) {
504                        trace_set_err(libtrace, errno, 
505                                        "Cannot allocate memory");
506                        return -1;
507                }
508        }
509
510        flags |= TRACE_PREP_OWN_BUFFER; 
511       
512        if ((numbytes=wandio_read(libtrace->io,
513                                        packet->buffer,
514                                        (size_t)dag_record_size)) == -1) {
515                trace_set_err(libtrace,errno,"reading ERF file");
516                return -1;
517        }
518        /* EOF */
519        if (numbytes == 0) {
520                return 0;
521        }
522
523        if (numbytes < (int)dag_record_size) {
524                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Incomplete ERF header");
525                return -1;
526        }
527
528        rlen = ntohs(((dag_record_t *)packet->buffer)->rlen);
529        buffer2 = (char*)packet->buffer + dag_record_size;
530        size = rlen - dag_record_size;
531
532        if (size >= LIBTRACE_PACKET_BUFSIZE) {
533                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, 
534                                "Packet size %u larger than supported by libtrace - packet is probably corrupt", 
535                                size);
536                return -1;
537        }
538
539        /* Unknown/corrupt */
540        if ((((dag_record_t *)packet->buffer)->type & 0x7f) > ERF_TYPE_MAX) {
541                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, 
542                                "Corrupt or Unknown ERF type");
543                return -1;
544        }
545       
546        /* read in the rest of the packet */
547        if ((numbytes=wandio_read(libtrace->io,
548                                        buffer2,
549                                        (size_t)size)) != (int)size) {
550                if (numbytes==-1) {
551                        trace_set_err(libtrace,errno, "read(%s)", 
552                                        libtrace->uridata);
553                        return -1;
554                }
555                trace_set_err(libtrace,EIO,
556                                "Truncated packet (wanted %d, got %d)", 
557                                size, numbytes);
558                /* Failed to read the full packet?  must be EOF */
559                return -1;
560        }
561
562        if (numbytes < (int)size) {
563                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Incomplete ERF record");
564                return -1;
565        }
566       
567        if (erf_prepare_packet(libtrace, packet, packet->buffer, 
568                                TRACE_RT_DATA_ERF, flags))
569                return -1;
570       
571        return rlen;
572}
573
574static int erf_dump_packet(libtrace_out_t *libtrace,
575                dag_record_t *erfptr, int framinglen, void *buffer,
576                int caplen) {
577        int numbytes = 0;
578
579        if (caplen + framinglen != ntohs(erfptr->rlen))
580                erfptr->rlen = htons(caplen + framinglen);
581
582        if ((numbytes = 
583                wandio_wwrite(OUTPUT->file, 
584                                erfptr,
585                                (size_t)(framinglen))) 
586                        != (int)(framinglen)) {
587                trace_set_err_out(libtrace,errno,
588                                "write(%s)",libtrace->uridata);
589                return -1;
590        }
591
592        numbytes=wandio_wwrite(OUTPUT->file, buffer, (size_t)caplen);
593        if (numbytes != caplen) {
594                trace_set_err_out(libtrace,errno,
595                                "write(%s)",libtrace->uridata);
596                return -1;
597        }
598        return numbytes + framinglen;
599}
600
601static int erf_flush_output(libtrace_out_t *libtrace) {
602        return wandio_wflush(OUTPUT->file);
603}
604
605static int erf_start_output(libtrace_out_t *libtrace)
606{
607        OUTPUT->file = trace_open_file_out(libtrace,
608                        OUT_OPTIONS.compress_type,
609                        OUT_OPTIONS.level,
610                        OUT_OPTIONS.fileflag);
611
612        if (!OUTPUT->file) {
613                return -1;
614        }
615        return 0;
616}
617
618static bool find_compatible_linktype(libtrace_out_t *libtrace,
619                                libtrace_packet_t *packet)
620{
621        /* Keep trying to simplify the packet until we can find
622         * something we can do with it */
623        do {
624                char type=libtrace_to_erf_type(trace_get_link_type(packet));
625
626                /* Success */
627                if (type != (char)-1)
628                        return true;
629
630                if (!demote_packet(packet)) {
631                        trace_set_err_out(libtrace,
632                                        TRACE_ERR_NO_CONVERSION,
633                                        "No erf type for packet (%i)",
634                                        trace_get_link_type(packet));
635                        return false;
636                }
637
638        } while(1);
639
640        return true;
641}
642               
643static int erf_write_packet(libtrace_out_t *libtrace, 
644                libtrace_packet_t *packet) 
645{
646        int numbytes = 0;
647        unsigned int pad = 0;
648        dag_record_t *dag_hdr = (dag_record_t *)packet->header;
649        void *payload = packet->payload;
650
651        assert(OUTPUT->file);
652
653        if (trace_get_link_type(packet) == TRACE_TYPE_NONDATA)
654                return 0;
655
656        if (!packet->header) {
657                return -1;
658        }
659       
660        pad = erf_get_padding(packet);
661
662        /* If we've had an rxerror, we have no payload to write - fix
663         * rlen to be the correct length
664         */
665        /* I Think this is bogus, we should somehow figure out
666         * a way to write out the payload even if it is gibberish -- Perry */
667        if (payload == NULL) {
668                dag_hdr->rlen = htons(dag_record_size + pad);
669               
670        } 
671       
672        if (packet->type == TRACE_RT_DATA_ERF) {
673                        numbytes = erf_dump_packet(libtrace,
674                                (dag_record_t *)packet->header,
675                                trace_get_framing_length(packet),
676                                payload,
677                                trace_get_capture_length(packet)
678                                );
679        } else {
680                dag_record_t erfhdr;
681                int rlen;
682                int framing;
683                /* convert format - build up a new erf header */
684                /* Timestamp */
685                erfhdr.ts = bswap_host_to_le64(trace_get_erf_timestamp(packet));
686
687                /* Flags. Can't do this */
688                memset(&erfhdr.flags,1,sizeof(erfhdr.flags));
689                if (trace_get_direction(packet)!=TRACE_DIR_UNKNOWN)
690                        erfhdr.flags.iface = trace_get_direction(packet);
691
692                if (!find_compatible_linktype(libtrace,packet))
693                        return -1;
694
695                payload=packet->payload;
696                pad = erf_get_padding(packet);
697
698                erfhdr.type = libtrace_to_erf_type(trace_get_link_type(packet));
699
700                /* Packet length (rlen includes format overhead) */
701                assert(trace_get_capture_length(packet)>0 
702                                && trace_get_capture_length(packet)<=65536);
703                assert(trace_get_framing_length(packet)<=65536);
704               
705                if (erfhdr.type == TYPE_ETH)
706                        framing = dag_record_size + 2;
707                else
708                        framing = dag_record_size;
709               
710                rlen = trace_get_capture_length(packet) + framing;
711                assert(rlen > 0 && rlen <= 65536);
712                erfhdr.rlen = htons(rlen);
713                /* loss counter. Can't do this */
714                erfhdr.lctr = 0;
715                /* Wire length, does not include padding! */
716                erfhdr.wlen = htons(trace_get_wire_length(packet));
717
718                /* Write it out */
719                numbytes = erf_dump_packet(libtrace,
720                                &erfhdr,
721                                framing,
722                                payload,
723                                trace_get_capture_length(packet));
724        }
725        return numbytes;
726}
727
728libtrace_linktype_t erf_get_link_type(const libtrace_packet_t *packet) {
729        dag_record_t *erfptr = 0;
730        erfptr = (dag_record_t *)packet->header;
731        uint8_t type = (erfptr->type & 0x7f);
732        if (type != TYPE_LEGACY) {
733                /* The top-most bit is now used to indicate the presence of
734                 * extension headers :/ */
735                return erf_type_to_libtrace(type);
736        }
737        else {
738                /* Sigh, lets start wildly guessing */
739                if (((char*)packet->payload)[4]==0x45)
740                        return TRACE_TYPE_PPP;
741                return ~0;
742        }
743}
744
745libtrace_direction_t erf_get_direction(const libtrace_packet_t *packet) {
746        dag_record_t *erfptr = 0;
747        erfptr = (dag_record_t *)packet->header;
748        return erfptr->flags.iface;
749}
750
751libtrace_direction_t erf_set_direction(libtrace_packet_t *packet, libtrace_direction_t direction) {
752        dag_record_t *erfptr = 0;
753        erfptr = (dag_record_t *)packet->header;
754        erfptr->flags.iface = direction;
755        return erfptr->flags.iface;
756}
757
758uint64_t erf_get_erf_timestamp(const libtrace_packet_t *packet) {
759        dag_record_t *erfptr = 0;
760        erfptr = (dag_record_t *)packet->header;
761        return bswap_le_to_host64(erfptr->ts);
762}
763
764int erf_get_capture_length(const libtrace_packet_t *packet) {
765        dag_record_t *erfptr = 0;
766        int caplen;
767        if (packet->payload == NULL)
768                return 0; 
769       
770        erfptr = (dag_record_t *)packet->header;
771        caplen = ntohs(erfptr->rlen) - erf_get_framing_length(packet);
772        if (ntohs(erfptr->wlen) < caplen)
773                return ntohs(erfptr->wlen);
774
775        return (ntohs(erfptr->rlen) - erf_get_framing_length(packet));
776}
777
778int erf_get_wire_length(const libtrace_packet_t *packet) {
779        dag_record_t *erfptr = 0;
780        erfptr = (dag_record_t *)packet->header;
781
782        if ((erfptr->type & 0x7f) == TYPE_META)
783                return 0;
784
785        return ntohs(erfptr->wlen);
786}
787
788size_t erf_set_capture_length(libtrace_packet_t *packet, size_t size) {
789        dag_record_t *erfptr = 0;
790        assert(packet);
791        erfptr = (dag_record_t *)packet->header;
792
793        if(size > trace_get_capture_length(packet) || (erfptr->type & 0x7f) == TYPE_META) {
794                /* Can't make a packet larger */
795                return trace_get_capture_length(packet);
796        }
797
798        /* Reset cached capture length - otherwise we will both return the
799         * wrong value here and subsequent get_capture_length() calls will
800         * return the wrong value. */
801        packet->capture_length = -1;
802        erfptr->rlen = htons(size + erf_get_framing_length(packet));
803        return trace_get_capture_length(packet);
804}
805
806static struct libtrace_eventobj_t erf_event(struct libtrace_t *libtrace, struct libtrace_packet_t *packet) {
807        struct libtrace_eventobj_t event = {0,0,0.0,0};
808       
809        /* If we are being told to replay packets as fast as possible, then
810         * we just need to read and return the next packet in the trace */
811        if (IN_OPTIONS.real_time) {
812                event.size = trace_read_packet(libtrace, packet);
813                if (event.size < 1)
814                        event.type = TRACE_EVENT_TERMINATE;
815                else
816                        event.type = TRACE_EVENT_PACKET;
817                return event;
818               
819        } else {
820                /* Otherwise, use the generic event function */
821                return trace_event_trace(libtrace, packet);
822        }
823       
824}
825
826static void erf_get_statistics(libtrace_t *trace, libtrace_stat_t *stat) {
827
828        if (trace->format_data) {
829                stat->dropped_valid = 1;
830                stat->dropped = DATA(trace)->drops;
831        }
832}
833
834static void erf_help(void) {
835        printf("erf format module: $Revision: 1752 $\n");
836        printf("Supported input URIs:\n");
837        printf("\terf:/path/to/file\t(uncompressed)\n");
838        printf("\terf:/path/to/file.gz\t(gzip-compressed)\n");
839        printf("\terf:-\t(stdin, either compressed or not)\n");
840        printf("\terf:/path/to/socket\n");
841        printf("\n");
842        printf("\te.g.: erf:/tmp/trace\n");
843        printf("\n");
844        printf("Supported output URIs:\n");
845        printf("\terf:path/to/file\t(uncompressed)\n");
846        printf("\terf:/path/to/file.gz\t(gzip-compressed)\n");
847        printf("\terf:-\t(stdout, either compressed or not)\n");
848        printf("\n");
849        printf("\te.g.: erf:/tmp/trace\n");
850        printf("\n");
851
852       
853}
854
855static struct libtrace_format_t erfformat = {
856        "erf",
857        "$Id$",
858        TRACE_FORMAT_ERF,
859        NULL,                           /* probe filename */
860        erf_probe_magic,                /* probe magic */
861        erf_init_input,                 /* init_input */       
862        erf_config_input,               /* config_input */
863        erf_start_input,                /* start_input */
864        NULL,                           /* pause_input */
865        erf_init_output,                /* init_output */
866        erf_config_output,              /* config_output */
867        erf_start_output,               /* start_output */
868        erf_fin_input,                  /* fin_input */
869        erf_fin_output,                 /* fin_output */
870        erf_read_packet,                /* read_packet */
871        erf_prepare_packet,             /* prepare_packet */
872        NULL,                           /* fin_packet */
873        erf_write_packet,               /* write_packet */
874        erf_flush_output,               /* flush_output */
875        erf_get_link_type,              /* get_link_type */
876        erf_get_direction,              /* get_direction */
877        erf_set_direction,              /* set_direction */
878        erf_get_erf_timestamp,          /* get_erf_timestamp */
879        NULL,                           /* get_timeval */
880        NULL,                           /* get_timespec */
881        NULL,                           /* get_seconds */
882        erf_seek_erf,                   /* seek_erf */
883        NULL,                           /* seek_timeval */
884        NULL,                           /* seek_seconds */
885        erf_get_capture_length,         /* get_capture_length */
886        erf_get_wire_length,            /* get_wire_length */
887        erf_get_framing_length,         /* get_framing_length */
888        erf_set_capture_length,         /* set_capture_length */
889        NULL,                           /* get_received_packets */
890        NULL,                           /* get_filtered_packets */
891        NULL,                           /* get_dropped_packets */
892        erf_get_statistics,             /* get_statistics */
893        NULL,                           /* get_fd */
894        erf_event,                      /* trace_event */
895        erf_help,                       /* help */
896        NULL,                           /* next pointer */
897        NON_PARALLEL(false)
898};
899
900static struct libtrace_format_t rawerfformat = {
901        "rawerf",
902        "$Id$",
903        TRACE_FORMAT_RAWERF,
904        NULL,                           /* probe filename */
905        NULL,           /* probe magic */
906        erf_init_input,                 /* init_input */       
907        erf_config_input,               /* config_input */
908        rawerf_start_input,             /* start_input */
909        NULL,                           /* pause_input */
910        erf_init_output,                /* init_output */
911        erf_config_output,              /* config_output */
912        erf_start_output,               /* start_output */
913        erf_fin_input,                  /* fin_input */
914        erf_fin_output,                 /* fin_output */
915        erf_read_packet,                /* read_packet */
916        erf_prepare_packet,             /* prepare_packet */
917        NULL,                           /* fin_packet */
918        erf_write_packet,               /* write_packet */
919        erf_flush_output,               /* flush_output */
920        erf_get_link_type,              /* get_link_type */
921        erf_get_direction,              /* get_direction */
922        erf_set_direction,              /* set_direction */
923        erf_get_erf_timestamp,          /* get_erf_timestamp */
924        NULL,                           /* get_timeval */
925        NULL,                           /* get_timespec */
926        NULL,                           /* get_seconds */
927        erf_seek_erf,                   /* seek_erf */
928        NULL,                           /* seek_timeval */
929        NULL,                           /* seek_seconds */
930        erf_get_capture_length,         /* get_capture_length */
931        erf_get_wire_length,            /* get_wire_length */
932        erf_get_framing_length,         /* get_framing_length */
933        erf_set_capture_length,         /* set_capture_length */
934        NULL,                           /* get_received_packets */
935        NULL,                           /* get_filtered_packets */
936        NULL,                           /* get_dropped_packets */
937        erf_get_statistics,             /* get_statistics */
938        NULL,                           /* get_fd */
939        erf_event,                      /* trace_event */
940        erf_help,                       /* help */
941        NULL,                           /* next pointer */
942        NON_PARALLEL(false)
943};
944
945
946
947void erf_constructor(void) {
948        register_format(&erfformat);
949        register_format(&rawerfformat);
950}
Note: See TracBrowser for help on using the repository browser.