source: lib/format_dag24.c @ f625817

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

Deprecate trace_get_filtered/accepted/recevied/dropped() in favour of a single function

Adds the single trace_get_statistics function. This allows the structure to be filled
at a point in time, rather than making multiple calls to the library during which state
might have changed.

This has been designed such that the structure can be added to in the future without
breaking old code.

The old internal get_captured_packets was removed from the formats as it was never used.
Eventually we should completely remove get_filtered and received from the formats and replace
them with get_statistics.

In additon some extra fields have added, such as error and captured and the pre-existing
fields are better defined.

The linux formats have been updated to use this new API, which combined with reading
/proc/net/dev returns a full set of statistics.

  • Property mode set to 100644
File size: 18.7 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#include <sys/stat.h>
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
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 */
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
81/* "Global" data that is stored for each DAG input trace */
82struct dag_format_data_t {
83
84        /* Data required for regular DUCK reporting */
85        struct {
86                /* Timestamp of the last DUCK report */
87                uint32_t last_duck;
88                /* The number of seconds between each DUCK report */
89                uint32_t duck_freq;
90                /* Timestamp of the last packet read from the DAG card */
91                uint32_t last_pkt;
92                /* Dummy trace to ensure DUCK packets are dealt with using
93                 * the DUCK format functions */
94                libtrace_t *dummy_duck;
95        } duck; 
96       
97        /* File descriptor for the DAG card */
98        int fd;
99        /* Pointer to DAG memory hole */
100        void *buf;
101        /* Difference between the top and bottom pointers in the DAG memory
102         * hole, i.e. the amount of available data to read */
103        uint32_t diff;
104        /* The amount of data read thus far from the start of the bottom
105         * pointer */
106        uint32_t offset;
107        /* The offset for the first unread byte in the DAG memory hole */
108        uint32_t bottom;
109        /* The offset for the last unread byte in the DAG memory hole */
110        uint32_t top;
111        /* The number of packets that have been dropped */
112        uint64_t drops;
113};
114
115/* Determines if a given filename refers to a DAG device */
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
131/* Initialises the DAG "global" variables */
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
149/* Determines how much data is available for reading on the DAG card and
150 * updates the various offsets accordingly */
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
166/* Initialises a DAG input trace */
167static int dag_init_input(libtrace_t *libtrace) {
168        struct stat buf;
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
182
183        /* Make sure a DAG device with the right name exists */ 
184        if (stat(dag_dev_name, &buf) == -1) {
185                trace_set_err(libtrace,errno,"stat(%s)",dag_dev_name);
186                free(dag_dev_name);
187                return -1;
188        }
189       
190        dag_init_format_data(libtrace);
191        if (S_ISCHR(buf.st_mode)) {
192                /* DEVICE */
193                if((FORMAT_DATA->fd = dag_open(dag_dev_name)) < 0) {
194                        trace_set_err(libtrace,errno,"Cannot open DAG %s",
195                                        dag_dev_name);
196                        free(dag_dev_name);
197                        return -1;
198                }
199
200                /* Memory-map ourselves a pointer to the DAG memory hole */
201                if((FORMAT_DATA->buf = (void *)dag_mmap(FORMAT_DATA->fd)) == MAP_FAILED) {
202                        trace_set_err(libtrace,errno,"Cannot mmap DAG %s",
203                                        dag_dev_name);
204                        free(dag_dev_name);
205                        return -1;
206                }
207        } else {
208                trace_set_err(libtrace,errno,"Not a valid dag device: %s",
209                                dag_dev_name);
210                free(dag_dev_name);
211                return -1;
212        }
213
214        free(dag_dev_name);
215
216        return 0;
217}
218
219/* Configures a DAG input trace */
220static int dag_config_input(libtrace_t *libtrace, trace_option_t option,
221                                void *data) {
222        switch(option) {
223                case TRACE_OPTION_META_FREQ:
224                        /* We use this option to specify the frequency of
225                         * DUCK updates */
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:
235                        /* Cards that use the older drivers don't do
236                         * filtering */
237                        return -1;
238                case TRACE_OPTION_EVENT_REALTIME:
239                        /* Live capture is always going to be realtime */
240                        return -1;
241        }
242        return -1;
243}
244
245/* Starts a DAG input trace */
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;
256        FORMAT_DATA->drops = 0;
257        return 0;
258}
259
260/* Pauses a DAG input trace */
261static int dag_pause_input(libtrace_t *libtrace) {
262        dag_stop(FORMAT_DATA->fd);
263        return 0;
264}
265
266/* Destroys a DAG input trace */
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
275/* Extracts DUCK information from the DAG card and produces a DUCK packet */
276static int dag_get_duckinfo(libtrace_t *libtrace,
277                                libtrace_packet_t *packet) {
278        dag_inf lt_dag_inf;
279
280        /* Allocate memory for the DUCK data */
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
292        /* DUCK doesn't actually have a format header, as such */
293        packet->header = 0;
294        packet->payload = packet->buffer;
295
296        /* Check that the DAG card supports DUCK */
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
307        /* Get the DUCK information from the card */
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
314        /* Set the type */
315        packet->type = TRACE_RT_DUCK_2_4;
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 */
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
326/* Reads the next ERF record from the DAG memory hole */
327static dag_record_t *dag_get_record(libtrace_t *libtrace) {
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
342/* Converts a buffer containing a recently read DAG packet record into a
343 * libtrace packet */
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;
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 */
351        if (packet->buffer != buffer &&
352                        packet->buf_control == TRACE_CTRL_PACKET) {
353                free(packet->buffer);
354        }
355
356        /* Set the buffer owner appropriately */
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       
362        /* Update packet pointers and type appropriately */
363        erfptr = (dag_record_t *)buffer;
364        packet->buffer = erfptr;
365        packet->header = erfptr;
366        packet->type = rt_type;
367
368        if (erfptr->flags.rxerror == 1) {
369                /* rxerror means the payload is corrupt - drop the payload
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
378        if (libtrace->format_data == NULL) {
379                dag_init_format_data(libtrace);
380        }
381
382        /* Update the dropped packets counter, using the value of the ERF
383         * loss counter */
384        DATA(libtrace)->drops += ntohs(erfptr->lctr);
385
386        return 0;
387
388}
389
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 */
393static int dag_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
394        int numbytes;
395        int size = 0;
396        uint32_t flags = 0;
397        struct timeval tv;
398        dag_record_t *erfptr = NULL;
399
400        /* Check if we're due for a DUCK report */
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
412        /* Don't let anyone try to free our DAG memory hole */
413        flags |= TRACE_PREP_DO_NOT_OWN_BUFFER;
414       
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) {
418                packet->buf_control = TRACE_CTRL_EXTERNAL;
419                free(packet->buffer);
420                packet->buffer = 0;
421        }
422
423        /* Grab a full ERF record */
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);
432       
433        /* Prepare the libtrace packet */
434        if (dag_prepare_packet(libtrace, packet, erfptr, TRACE_RT_DATA_ERF, 
435                                flags))
436                return -1;
437       
438        /* Update the DUCK timer */
439        tv = trace_get_timeval(packet);
440        DUCK.last_pkt = tv.tv_sec;
441        return packet->payload ? htons(erfptr->rlen) : erf_get_framing_length(packet);
442}
443
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 */
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
453        do {
454                data = dag_available(trace);
455
456                /* If no data is available, drop out and return a sleep event */
457                if (data <= 0)
458                        break;
459
460                /* Data is available, so we can call the blocking read because
461                 * we know that we will get a packet straight away */
462                event.size = dag_read_packet(trace,packet);
463                //DATA(trace)->dag.diff -= event.size;
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 */
470                if (trace->filter) {
471                        if (trace_apply_filter(trace->filter, packet)) {
472                                event.type = TRACE_EVENT_PACKET;
473                        } else {
474                                /* Do not sleep - try to read another packet */
475                                trace->filtered_packets ++;
476                                continue;
477                        }
478                } else {
479                        event.type = TRACE_EVENT_PACKET;
480                }
481
482                /* If the user has specified a snap length, apply that too */
483                if (trace->snaplen > 0) {
484                        trace_set_capture_length(packet, trace->snaplen);
485                }
486                trace->accepted_packets ++;
487                return event;
488        } while (1);
489
490
491        /* We only want to sleep for a very short time */
492        assert(data == 0);
493        event.type = TRACE_EVENT_SLEEP;
494        event.seconds = 0.0001;
495        event.size = 0;
496        return event;
497}
498
499/* Gets the number of dropped packets */
500static uint64_t dag_get_dropped_packets(libtrace_t *trace)
501{
502        if (!trace->format_data)
503                return (uint64_t)-1;
504        return DATA(trace)->drops;
505}
506
507/* Prints some semi-useful help text about the DAG format module */
508static void dag_help(void) {
509        printf("dag format module: $Revision: 1715 $\n");
510        printf("Supported input URIs:\n");
511        printf("\tdag:/dev/dagn\n");
512        printf("\n");
513        printf("\te.g.: dag:/dev/dag0\n");
514        printf("\n");
515        printf("Supported output URIs:\n");
516        printf("\tnone\n");
517        printf("\n");
518}
519
520static struct libtrace_format_t dag = {
521        "dag",
522        "$Id$",
523        TRACE_FORMAT_ERF,
524        dag_probe_filename,             /* probe filename */
525        NULL,                           /* probe magic */
526        dag_init_input,                 /* init_input */
527        dag_config_input,               /* config_input */
528        dag_start_input,                /* start_input */
529        dag_pause_input,                /* pause_input */
530        NULL,                           /* init_output */
531        NULL,                           /* config_output */
532        NULL,                           /* start_output */
533        dag_fin_input,                  /* fin_input */
534        NULL,                           /* fin_output */
535        dag_read_packet,                /* read_packet */
536        dag_prepare_packet,             /* prepare_packet */
537        NULL,                           /* fin_packet */
538        NULL,                           /* write_packet */
539        erf_get_link_type,              /* get_link_type */
540        erf_get_direction,              /* get_direction */
541        erf_set_direction,              /* set_direction */
542        erf_get_erf_timestamp,          /* get_erf_timestamp */
543        NULL,                           /* get_timeval */
544        NULL,                           /* get_timespec */
545        NULL,                           /* get_seconds */
546        NULL,                           /* seek_erf */
547        NULL,                           /* seek_timeval */
548        NULL,                           /* seek_seconds */
549        erf_get_capture_length,         /* get_capture_length */
550        erf_get_wire_length,            /* get_wire_length */
551        erf_get_framing_length,         /* get_framing_length */
552        erf_set_capture_length,         /* set_capture_length */
553        NULL,                           /* get_received_packets */
554        NULL,                           /* get_filtered_packets */
555        dag_get_dropped_packets,        /* get_dropped_packets */
556        NULL,                           /* get_statistics */
557        NULL,                           /* get_fd */
558        trace_event_dag,                /* trace_event */
559        dag_help,                       /* help */
560        NULL,                            /* next pointer */
561    NON_PARALLEL(true)
562};
563
564void dag_constructor(void) {
565        register_format(&dag);
566}
Note: See TracBrowser for help on using the repository browser.