source: lib/format_dag24.c @ 5952ff0

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