source: lib/format_dag24.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: 18.6 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#define _GNU_SOURCE
27
28#include "config.h"
29#include "common.h"
30#include "libtrace.h"
31#include "libtrace_int.h"
32#include "format_helper.h"
33#include "format_erf.h"
34
35#include <assert.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <stdio.h>
39#include <string.h>
40#include <stdlib.h>
41#include <sys/stat.h>
42
43#include <sys/mman.h>
44#ifdef WIN32
45#  include <io.h>
46#  include <share.h>
47#  define PATH_MAX _MAX_PATH
48#  define snprintf sprintf_s
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 deals with DAG cards that are using drivers from the 2.4.X
58 * versions.
59 *
60 * DAG is a LIVE capture format.
61 *
62 * We do not support writing using this format, as transmit support was not
63 * added until a subsequent version of the DAG software (see format_dag25.c).
64 * Instead, you should write the packets read using this format as ERF traces.
65 */
66
67static struct libtrace_format_t dag;
68
69#define DATA(x) ((struct dag_format_data_t *)x->format_data)
70#define DUCK DATA(libtrace)->duck
71#define FORMAT_DATA DATA(libtrace)
72
73/* "Global" data that is stored for each DAG input trace */
74struct dag_format_data_t {
75
76        /* Data required for regular DUCK reporting */
77        struct {
78                /* Timestamp of the last DUCK report */
79                uint32_t last_duck;
80                /* The number of seconds between each DUCK report */
81                uint32_t duck_freq;
82                /* Timestamp of the last packet read from the DAG card */
83                uint32_t last_pkt;
84                /* Dummy trace to ensure DUCK packets are dealt with using
85                 * the DUCK format functions */
86                libtrace_t *dummy_duck;
87        } duck; 
88       
89        /* File descriptor for the DAG card */
90        int fd;
91        /* Pointer to DAG memory hole */
92        void *buf;
93        /* Difference between the top and bottom pointers in the DAG memory
94         * hole, i.e. the amount of available data to read */
95        uint32_t diff;
96        /* The amount of data read thus far from the start of the bottom
97         * pointer */
98        uint32_t offset;
99        /* The offset for the first unread byte in the DAG memory hole */
100        uint32_t bottom;
101        /* The offset for the last unread byte in the DAG memory hole */
102        uint32_t top;
103        /* The number of packets that have been dropped */
104        uint64_t drops;
105};
106
107/* Determines if a given filename refers to a DAG device */
108static void dag_probe_filename(const char *filename) 
109{
110        struct stat statbuf;
111        /* Can we stat the file? */
112        if (stat(filename, &statbuf) != 0) {
113                return 0;
114        }
115        /* Is it a character device? */
116        if (!S_ISCHR(statbuf.st_mode)) {
117                return 0;
118        }
119        /* Yeah, it's probably us. */
120        return 1;
121}
122
123/* Initialises the DAG "global" variables */
124static void dag_init_format_data(libtrace_t *libtrace) {
125        libtrace->format_data = (struct dag_format_data_t *)
126                malloc(sizeof(struct dag_format_data_t));
127
128        DUCK.last_duck = 0;
129        DUCK.duck_freq = 0;
130        DUCK.last_pkt = 0;
131        DUCK.dummy_duck = NULL;
132        FORMAT_DATA->drops = 0;
133        FORMAT_DATA->top = 0;
134        FORMAT_DATA->bottom = 0;
135        FORMAT_DATA->buf = NULL;
136        FORMAT_DATA->fd = -1;
137        FORMAT_DATA->offset = 0;
138        FORMAT_DATA->diff = 0;
139}
140
141/* Determines how much data is available for reading on the DAG card and
142 * updates the various offsets accordingly */
143static int dag_available(libtrace_t *libtrace) {
144
145        if (FORMAT_DATA->diff > 0)
146                return FORMAT_DATA->diff;
147
148        FORMAT_DATA->bottom = FORMAT_DATA->top;
149        FORMAT_DATA->top = dag_offset(
150                        FORMAT_DATA->fd,
151                        &(FORMAT_DATA->bottom),
152                        DAGF_NONBLOCK);
153        FORMAT_DATA->diff = FORMAT_DATA->top - FORMAT_DATA->bottom;
154        FORMAT_DATA->offset = 0;
155        return FORMAT_DATA->diff;
156}
157
158/* Initialises a DAG input trace */
159static int dag_init_input(libtrace_t *libtrace) {
160        struct stat buf;
161        char *dag_dev_name = NULL;
162        char *scan = NULL;
163
164        /* Since DAG 2.5 has been changed to support a slightly different URI
165         * format, it's probably a good idea to deal with URIs specified in
166         * such a fashion even if we just end up ignoring the stream number */
167        if ((scan = strchr(libtrace->uridata,',')) == NULL) {
168                dag_dev_name = strdup(libtrace->uridata);
169        } else {
170                dag_dev_name = (char *)strndup(libtrace->uridata,
171                                (size_t)(scan - libtrace->uridata));
172        }
173
174
175        /* Make sure a DAG device with the right name exists */ 
176        if (stat(dag_dev_name, &buf) == -1) {
177                trace_set_err(libtrace,errno,"stat(%s)",dag_dev_name);
178                free(dag_dev_name);
179                return -1;
180        }
181       
182        dag_init_format_data(libtrace);
183        if (S_ISCHR(buf.st_mode)) {
184                /* DEVICE */
185                if((FORMAT_DATA->fd = dag_open(dag_dev_name)) < 0) {
186                        trace_set_err(libtrace,errno,"Cannot open DAG %s",
187                                        dag_dev_name);
188                        free(dag_dev_name);
189                        return -1;
190                }
191
192                /* Memory-map ourselves a pointer to the DAG memory hole */
193                if((FORMAT_DATA->buf = (void *)dag_mmap(FORMAT_DATA->fd)) == MAP_FAILED) {
194                        trace_set_err(libtrace,errno,"Cannot mmap DAG %s",
195                                        dag_dev_name);
196                        free(dag_dev_name);
197                        return -1;
198                }
199        } else {
200                trace_set_err(libtrace,errno,"Not a valid dag device: %s",
201                                dag_dev_name);
202                free(dag_dev_name);
203                return -1;
204        }
205
206        free(dag_dev_name);
207
208        return 0;
209}
210
211/* Configures a DAG input trace */
212static int dag_config_input(libtrace_t *libtrace, trace_option_t option,
213                                void *data) {
214        switch(option) {
215                case TRACE_OPTION_META_FREQ:
216                        /* We use this option to specify the frequency of
217                         * DUCK updates */
218                        DUCK.duck_freq = *(int *)data;
219                        return 0;
220                case TRACE_OPTION_SNAPLEN:
221                        /* Surely we can set this?? Fall through for now*/
222                        return -1;
223                case TRACE_OPTION_PROMISC:
224                        /* DAG already operates in a promisc fashion */
225                        return -1;
226                case TRACE_OPTION_FILTER:
227                        /* Cards that use the older drivers don't do
228                         * filtering */
229                        return -1;
230                case TRACE_OPTION_EVENT_REALTIME:
231                        /* Live capture is always going to be realtime */
232                        return -1;
233        }
234        return -1;
235}
236
237/* Starts a DAG input trace */
238static int dag_start_input(libtrace_t *libtrace) {     
239        if(dag_start(FORMAT_DATA->fd) < 0) {
240                trace_set_err(libtrace,errno,"Cannot start DAG %s",
241                                libtrace->uridata);
242                return -1;
243        }
244
245        /* Flush the memory hole */
246        while(dag_available(libtrace) != 0)
247                FORMAT_DATA->diff = 0;
248        FORMAT_DATA->drops = 0;
249        return 0;
250}
251
252/* Pauses a DAG input trace */
253static int dag_pause_input(libtrace_t *libtrace) {
254        dag_stop(FORMAT_DATA->fd);
255        return 0;
256}
257
258/* Destroys a DAG input trace */
259static int dag_fin_input(libtrace_t *libtrace) {
260        dag_close(FORMAT_DATA->fd);
261        if (DUCK.dummy_duck)
262                trace_destroy_dead(DUCK.dummy_duck);
263        free(libtrace->format_data);
264        return 0; /* success */
265}
266
267/* Extracts DUCK information from the DAG card and produces a DUCK packet */
268static int dag_get_duckinfo(libtrace_t *libtrace,
269                                libtrace_packet_t *packet) {
270        dag_inf lt_dag_inf;
271
272        /* Allocate memory for the DUCK data */
273        if (packet->buf_control == TRACE_CTRL_EXTERNAL ||
274                        !packet->buffer) {
275                packet->buffer = malloc(LIBTRACE_PACKET_BUFSIZE);
276                packet->buf_control = TRACE_CTRL_PACKET;
277                if (!packet->buffer) {
278                        trace_set_err(libtrace, errno,
279                                        "Cannot allocate packet buffer");
280                        return -1;
281                }
282        }
283
284        /* DUCK doesn't actually have a format header, as such */
285        packet->header = 0;
286        packet->payload = packet->buffer;
287
288        /* Check that the DAG card supports DUCK */
289        if ((ioctl(FORMAT_DATA->fd, DAG_IOINF, &lt_dag_inf) < 0)) {
290                trace_set_err(libtrace, errno,
291                                "Error using DAG_IOINF");
292                return -1;
293        }
294        if (!IsDUCK(&lt_dag_inf)) {
295                printf("WARNING: %s does not have modern clock support - No DUCK information will be gathered\n", libtrace->uridata);
296                return 0;
297        }
298
299        /* Get the DUCK information from the card */
300        if ((ioctl(FORMAT_DATA->fd, DAG_IOGETDUCK, (duck_inf *)packet->payload)
301                                < 0)) {
302                trace_set_err(libtrace, errno, "Error using DAG_IOGETDUCK");
303                return -1;
304        }
305
306        /* Set the type */
307        packet->type = TRACE_RT_DUCK_2_4;
308
309        /* Set the packet's trace to point at a DUCK trace, so that the
310         * DUCK format functions will be called on the packet rather than the
311         * DAG ones */
312        if (!DUCK.dummy_duck)
313                DUCK.dummy_duck = trace_create_dead("duck:dummy");
314        packet->trace = DUCK.dummy_duck;
315        return sizeof(duck_inf);
316}
317
318/* Reads the next ERF record from the DAG memory hole */
319static dag_record_t *dag_get_record(libtrace_t *libtrace) {
320        dag_record_t *erfptr = NULL;
321        uint16_t size;
322        erfptr = (dag_record_t *) ((char *)FORMAT_DATA->buf + 
323                        (FORMAT_DATA->bottom + FORMAT_DATA->offset));
324
325        if (!erfptr)
326                return NULL;
327        size = ntohs(erfptr->rlen);
328        assert( size >= dag_record_size );
329        FORMAT_DATA->offset += size;
330        FORMAT_DATA->diff -= size;
331        return erfptr;
332}
333
334/* Converts a buffer containing a recently read DAG packet record into a
335 * libtrace packet */
336static int dag_prepare_packet(libtrace_t *libtrace, libtrace_packet_t *packet,
337                void *buffer, libtrace_rt_types_t rt_type, uint32_t flags) {
338
339        dag_record_t *erfptr;
340        /* If the packet previously owned a buffer that is not the buffer
341         * that contains the new packet data, we're going to need to free the
342         * old one to avoid memory leaks */
343        if (packet->buffer != buffer &&
344                        packet->buf_control == TRACE_CTRL_PACKET) {
345                free(packet->buffer);
346        }
347
348        /* Set the buffer owner appropriately */
349        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
350                packet->buf_control = TRACE_CTRL_PACKET;
351        } else 
352                packet->buf_control = TRACE_CTRL_EXTERNAL;
353       
354        /* Update packet pointers and type appropriately */
355        erfptr = (dag_record_t *)buffer;
356        packet->buffer = erfptr;
357        packet->header = erfptr;
358        packet->type = rt_type;
359
360        if (erfptr->flags.rxerror == 1) {
361                /* rxerror means the payload is corrupt - drop the payload
362                 * by tweaking rlen */
363                packet->payload = NULL;
364                erfptr->rlen = htons(erf_get_framing_length(packet));
365        } else {
366                packet->payload = (char*)packet->buffer
367                        + erf_get_framing_length(packet);
368        }
369
370        if (libtrace->format_data == NULL) {
371                dag_init_format_data(libtrace);
372        }
373
374        /* Update the dropped packets counter, using the value of the ERF
375         * loss counter */
376        DATA(libtrace)->drops += ntohs(erfptr->lctr);
377
378        return 0;
379
380}
381
382/* Reads the next available packet from a DAG card, in a BLOCKING fashion
383 *
384 * If DUCK reporting is enabled, the packet returned may be a DUCK update */
385static int dag_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
386        int numbytes;
387        int size = 0;
388        uint32_t flags = 0;
389        struct timeval tv;
390        dag_record_t *erfptr = NULL;
391
392        /* Check if we're due for a DUCK report */
393        if (DUCK.last_pkt - DUCK.last_duck > DUCK.duck_freq &&
394                        DUCK.duck_freq != 0) {
395                size = dag_get_duckinfo(libtrace, packet);
396                DUCK.last_duck = DUCK.last_pkt;
397                if (size != 0) {
398                        return size;
399                }
400                /* No DUCK support, so don't waste our time anymore */
401                DUCK.duck_freq = 0;
402        }
403
404        /* Don't let anyone try to free our DAG memory hole */
405        flags |= TRACE_PREP_DO_NOT_OWN_BUFFER;
406       
407        /* If the packet buffer is currently owned by libtrace, free it so
408         * that we can set the packet to point into the DAG memory hole */
409        if (packet->buf_control == TRACE_CTRL_PACKET) {
410                packet->buf_control = TRACE_CTRL_EXTERNAL;
411                free(packet->buffer);
412                packet->buffer = 0;
413        }
414
415        /* Grab a full ERF record */
416        do {
417                numbytes = dag_available(libtrace);
418                if (numbytes < 0)
419                        return numbytes;
420                if (numbytes == 0)
421                        continue;
422                erfptr = dag_get_record(libtrace);
423        } while (erfptr == NULL);
424       
425        /* Prepare the libtrace packet */
426        if (dag_prepare_packet(libtrace, packet, erfptr, TRACE_RT_DATA_ERF, 
427                                flags))
428                return -1;
429       
430        /* Update the DUCK timer */
431        tv = trace_get_timeval(packet);
432        DUCK.last_pkt = tv.tv_sec;
433        return packet->payload ? htons(erfptr->rlen) : erf_get_framing_length(packet);
434}
435
436/* Attempts to read a packet from a DAG card in a NON-BLOCKING fashion. If
437 * a packet is available, we will return a packet event. Otherwise we will
438 * return a SLEEP event (as we cannot select on the DAG file descriptor).
439 */
440static libtrace_eventobj_t trace_event_dag(libtrace_t *trace,
441                                        libtrace_packet_t *packet) {
442        libtrace_eventobj_t event = {0,0,0.0,0};
443        int data;
444
445        do {
446                data = dag_available(trace);
447
448                /* If no data is available, drop out and return a sleep event */
449                if (data <= 0)
450                        break;
451
452                /* Data is available, so we can call the blocking read because
453                 * we know that we will get a packet straight away */
454                event.size = dag_read_packet(trace,packet);
455                //DATA(trace)->dag.diff -= event.size;
456               
457                /* XXX trace_read_packet() normally applies the following
458                 * config options for us, but this function is called via
459                 * trace_event() so we have to do it ourselves */
460
461                /* Check that the packet matches any pre-existing filter */
462                if (trace->filter) {
463                        if (trace_apply_filter(trace->filter, packet)) {
464                                event.type = TRACE_EVENT_PACKET;
465                        } else {
466                                /* Do not sleep - try to read another packet */
467                                trace->filtered_packets ++;
468                                continue;
469                        }
470                } else {
471                        event.type = TRACE_EVENT_PACKET;
472                }
473
474                /* If the user has specified a snap length, apply that too */
475                if (trace->snaplen > 0) {
476                        trace_set_capture_length(packet, trace->snaplen);
477                }
478                trace->accepted_packets ++;
479                return event;
480        } while (1);
481
482
483        /* We only want to sleep for a very short time */
484        assert(data == 0);
485        event.type = TRACE_EVENT_SLEEP;
486        event.seconds = 0.0001;
487        event.size = 0;
488        return event;
489}
490
491/* Gets the number of dropped packets */
492static uint64_t dag_get_dropped_packets(libtrace_t *trace)
493{
494        if (!trace->format_data)
495                return (uint64_t)-1;
496        return DATA(trace)->drops;
497}
498
499/* Prints some semi-useful help text about the DAG format module */
500static void dag_help(void) {
501        printf("dag format module: $Revision: 1715 $\n");
502        printf("Supported input URIs:\n");
503        printf("\tdag:/dev/dagn\n");
504        printf("\n");
505        printf("\te.g.: dag:/dev/dag0\n");
506        printf("\n");
507        printf("Supported output URIs:\n");
508        printf("\tnone\n");
509        printf("\n");
510}
511
512static struct libtrace_format_t dag = {
513        "dag",
514        "$Id$",
515        TRACE_FORMAT_ERF,
516        dag_probe_filename,             /* probe filename */
517        NULL,                           /* probe magic */
518        dag_init_input,                 /* init_input */
519        dag_config_input,               /* config_input */
520        dag_start_input,                /* start_input */
521        dag_pause_input,                /* pause_input */
522        NULL,                           /* init_output */
523        NULL,                           /* config_output */
524        NULL,                           /* start_output */
525        dag_fin_input,                  /* fin_input */
526        NULL,                           /* fin_output */
527        dag_read_packet,                /* read_packet */
528        dag_prepare_packet,             /* prepare_packet */
529        NULL,                           /* fin_packet */
530        NULL,                           /* write_packet */
531        NULL,                           /* flush_output */
532        erf_get_link_type,              /* get_link_type */
533        erf_get_direction,              /* get_direction */
534        erf_set_direction,              /* set_direction */
535        erf_get_erf_timestamp,          /* get_erf_timestamp */
536        NULL,                           /* get_timeval */
537        NULL,                           /* get_timespec */
538        NULL,                           /* get_seconds */
539        NULL,                           /* seek_erf */
540        NULL,                           /* seek_timeval */
541        NULL,                           /* seek_seconds */
542        erf_get_capture_length,         /* get_capture_length */
543        erf_get_wire_length,            /* get_wire_length */
544        erf_get_framing_length,         /* get_framing_length */
545        erf_set_capture_length,         /* set_capture_length */
546        NULL,                           /* get_received_packets */
547        NULL,                           /* get_filtered_packets */
548        dag_get_dropped_packets,        /* get_dropped_packets */
549        NULL,                           /* get_statistics */
550        NULL,                           /* get_fd */
551        trace_event_dag,                /* trace_event */
552        dag_help,                       /* help */
553        NULL,                            /* next pointer */
554    NON_PARALLEL(true)
555};
556
557void dag_constructor(void) {
558        register_format(&dag);
559}
Note: See TracBrowser for help on using the repository browser.