source: lib/format_dag24.c @ bcfe4ea

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivelibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since bcfe4ea was b13b939, checked in by Richard Sanger <rsangerarj@…>, 7 years ago

Adds a configuration option for the tick messages.
Adds the trace_information structure which contains information about traces.
Updates trace_rt_stats to use both of these.

Replaced libtrace_t->joined internally with a state

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