source: lib/format_dag24.c @ 5778738

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 5778738 was 5778738, checked in by Shane Alcock <salcock@…>, 12 years ago
  • Fixed major bug where we were sleeping whenever a packet did not match a specified BPF filter when reading from a DAG card, rather than immediately checking if there was another suitable packet available. This was causing libtrace to get massively behind in reading packets from the DAG card so the DAG buffer would overflow and packets would be dropped.
  • NOTE: the dag2.4 version of this fix has not been fully tested (or even compiled) because we upgraded the box that used to have the old DAG cards in
  • Property mode set to 100644
File size: 14.4 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007,2008 The University of Waikato, Hamilton, New Zealand.
5 * Authors: Daniel Lawson
6 *          Perry Lorier
7 *          Shane Alcock
8 *
9 * All rights reserved.
10 *
11 * This code has been developed by the University of Waikato WAND
12 * research group. For further information please see http://www.wand.net.nz/
13 *
14 * libtrace is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * libtrace is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with libtrace; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27 *
28 * $Id$
29 *
30 */
31#define _GNU_SOURCE
32
33#include "config.h"
34#include "common.h"
35#include "libtrace.h"
36#include "libtrace_int.h"
37#include "format_helper.h"
38#include "format_erf.h"
39
40#include <assert.h>
41#include <errno.h>
42#include <fcntl.h>
43#include <stdio.h>
44#include <string.h>
45#include <stdlib.h>
46
47#include <sys/mman.h>
48#ifdef WIN32
49#  include <io.h>
50#  include <share.h>
51#  define PATH_MAX _MAX_PATH
52#  define snprintf sprintf_s
53#else
54#  include <netdb.h>
55#  ifndef PATH_MAX
56#       define PATH_MAX 4096
57#  endif
58#  include <sys/ioctl.h>
59#endif
60
61
62static struct libtrace_format_t dag;
63
64#define DATA(x) ((struct dag_format_data_t *)x->format_data)
65#define DUCK DATA(libtrace)->duck
66#define FORMAT_DATA DATA(libtrace)
67
68struct dag_format_data_t {
69        struct {
70                uint32_t last_duck;
71                uint32_t duck_freq;
72                uint32_t last_pkt;
73                libtrace_t *dummy_duck;
74        } duck; 
75       
76        int fd;
77        void *buf;
78        uint32_t diff;
79        uint32_t offset;
80        uint32_t bottom;
81        uint32_t top;
82        uint64_t drops;
83};
84
85static void dag_probe_filename(const char *filename) 
86{
87        struct stat statbuf;
88        /* Can we stat the file? */
89        if (stat(filename, &statbuf) != 0) {
90                return 0;
91        }
92        /* Is it a character device? */
93        if (!S_ISCHR(statbuf.st_mode)) {
94                return 0;
95        }
96        /* Yeah, it's probably us. */
97        return 1;
98}
99
100static void dag_init_format_data(libtrace_t *libtrace) {
101        libtrace->format_data = (struct dag_format_data_t *)
102                malloc(sizeof(struct dag_format_data_t));
103
104        DUCK.last_duck = 0;
105        DUCK.duck_freq = 0;
106        DUCK.last_pkt = 0;
107        DUCK.dummy_duck = NULL;
108        FORMAT_DATA->drops = 0;
109        FORMAT_DATA->top = 0;
110        FORMAT_DATA->bottom = 0;
111        FORMAT_DATA->buf = NULL;
112        FORMAT_DATA->fd = -1;
113        FORMAT_DATA->offset = 0;
114        FORMAT_DATA->diff = 0;
115}
116
117static int dag_available(libtrace_t *libtrace) {
118
119        if (FORMAT_DATA->diff > 0)
120                return FORMAT_DATA->diff;
121
122        FORMAT_DATA->bottom = FORMAT_DATA->top;
123        FORMAT_DATA->top = dag_offset(
124                        FORMAT_DATA->fd,
125                        &(FORMAT_DATA->bottom),
126                        DAGF_NONBLOCK);
127        FORMAT_DATA->diff = FORMAT_DATA->top - FORMAT_DATA->bottom;
128        FORMAT_DATA->offset = 0;
129        return FORMAT_DATA->diff;
130}
131
132static int dag_init_input(libtrace_t *libtrace) {
133        struct stat buf;
134        char *dag_dev_name = NULL;
135        char *scan = NULL;
136
137        /* Since DAG 2.5 has been changed to support a slightly different URI
138         * format, it's probably a good idea to deal with URIs specified in
139         * such a fashion even if we just end up ignoring the stream number */
140        if ((scan = strchr(libtrace->uridata,',')) == NULL) {
141                dag_dev_name = strdup(libtrace->uridata);
142        } else {
143                dag_dev_name = (char *)strndup(libtrace->uridata,
144                                (size_t)(scan - libtrace->uridata));
145        }
146
147       
148        if (stat(dag_dev_name, &buf) == -1) {
149                trace_set_err(libtrace,errno,"stat(%s)",dag_dev_name);
150                free(dag_dev_name);
151                return -1;
152        }
153       
154        dag_init_format_data(libtrace);
155        if (S_ISCHR(buf.st_mode)) {
156                /* DEVICE */
157                if((FORMAT_DATA->fd = dag_open(dag_dev_name)) < 0) {
158                        trace_set_err(libtrace,errno,"Cannot open DAG %s",
159                                        dag_dev_name);
160                        free(dag_dev_name);
161                        return -1;
162                }
163                if((FORMAT_DATA->buf = (void *)dag_mmap(FORMAT_DATA->fd)) == MAP_FAILED) {
164                        trace_set_err(libtrace,errno,"Cannot mmap DAG %s",
165                                        dag_dev_name);
166                        free(dag_dev_name);
167                        return -1;
168                }
169        } else {
170                trace_set_err(libtrace,errno,"Not a valid dag device: %s",
171                                dag_dev_name);
172                free(dag_dev_name);
173                return -1;
174        }
175
176        free(dag_dev_name);
177
178        return 0;
179}
180
181static int dag_config_input(libtrace_t *libtrace, trace_option_t option,
182                                void *data) {
183        switch(option) {
184                case TRACE_OPTION_META_FREQ:
185                        DUCK.duck_freq = *(int *)data;
186                        return 0;
187                case TRACE_OPTION_SNAPLEN:
188                        /* Surely we can set this?? Fall through for now*/
189                        return -1;
190                case TRACE_OPTION_PROMISC:
191                        /* DAG already operates in a promisc fashion */
192                        return -1;
193                case TRACE_OPTION_FILTER:
194                        return -1;
195                case TRACE_OPTION_EVENT_REALTIME:
196                        return -1;
197        }
198        return -1;
199}
200
201static int dag_start_input(libtrace_t *libtrace) {     
202        if(dag_start(FORMAT_DATA->fd) < 0) {
203                trace_set_err(libtrace,errno,"Cannot start DAG %s",
204                                libtrace->uridata);
205                return -1;
206        }
207
208        /* Flush the memory hole */
209        while(dag_available(libtrace) != 0)
210                FORMAT_DATA->diff = 0;
211        FORMAT_DATA->drops = 0;
212        return 0;
213}
214
215static int dag_pause_input(libtrace_t *libtrace) {
216        dag_stop(FORMAT_DATA->fd);
217        return 0;
218}
219
220static int dag_fin_input(libtrace_t *libtrace) {
221        dag_close(FORMAT_DATA->fd);
222        if (DUCK.dummy_duck)
223                trace_destroy_dead(DUCK.dummy_duck);
224        free(libtrace->format_data);
225        return 0; /* success */
226}
227
228static int dag_get_duckinfo(libtrace_t *libtrace,
229                                libtrace_packet_t *packet) {
230        dag_inf lt_dag_inf;
231
232        if (packet->buf_control == TRACE_CTRL_EXTERNAL ||
233                        !packet->buffer) {
234                packet->buffer = malloc(LIBTRACE_PACKET_BUFSIZE);
235                packet->buf_control = TRACE_CTRL_PACKET;
236                if (!packet->buffer) {
237                        trace_set_err(libtrace, errno,
238                                        "Cannot allocate packet buffer");
239                        return -1;
240                }
241        }
242
243        packet->header = 0;
244        packet->payload = packet->buffer;
245
246        if ((ioctl(FORMAT_DATA->fd, DAG_IOINF, &lt_dag_inf) < 0)) {
247                trace_set_err(libtrace, errno,
248                                "Error using DAG_IOINF");
249                return -1;
250        }
251        if (!IsDUCK(&lt_dag_inf)) {
252                printf("WARNING: %s does not have modern clock support - No DUCK information will be gathered\n", libtrace->uridata);
253                return 0;
254        }
255
256        if ((ioctl(FORMAT_DATA->fd, DAG_IOGETDUCK, (duck_inf *)packet->payload)
257                                < 0)) {
258                trace_set_err(libtrace, errno, "Error using DAG_IOGETDUCK");
259                return -1;
260        }
261
262        packet->type = TRACE_RT_DUCK_2_4;
263        if (!DUCK.dummy_duck)
264                DUCK.dummy_duck = trace_create_dead("duck:dummy");
265        packet->trace = DUCK.dummy_duck;
266        return sizeof(duck_inf);
267}
268
269
270static dag_record_t *dag_get_record(libtrace_t *libtrace) {
271        dag_record_t *erfptr = NULL;
272        uint16_t size;
273        erfptr = (dag_record_t *) ((char *)FORMAT_DATA->buf + 
274                        (FORMAT_DATA->bottom + FORMAT_DATA->offset));
275
276        if (!erfptr)
277                return NULL;
278        size = ntohs(erfptr->rlen);
279        assert( size >= dag_record_size );
280        FORMAT_DATA->offset += size;
281        FORMAT_DATA->diff -= size;
282        return erfptr;
283}
284
285static int dag_prepare_packet(libtrace_t *libtrace, libtrace_packet_t *packet,
286                void *buffer, libtrace_rt_types_t rt_type, uint32_t flags) {
287
288        dag_record_t *erfptr;
289        if (packet->buffer != buffer &&
290                        packet->buf_control == TRACE_CTRL_PACKET) {
291                free(packet->buffer);
292        }
293
294        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
295                packet->buf_control = TRACE_CTRL_PACKET;
296        } else 
297                packet->buf_control = TRACE_CTRL_EXTERNAL;
298       
299        erfptr = (dag_record_t *)buffer;
300        packet->buffer = erfptr;
301        packet->header = erfptr;
302        packet->type = rt_type;
303
304        if (erfptr->flags.rxerror == 1) {
305                /* rxerror means the payload is corrupt - drop it
306                 * by tweaking rlen */
307                packet->payload = NULL;
308                erfptr->rlen = htons(erf_get_framing_length(packet));
309        } else {
310                packet->payload = (char*)packet->buffer
311                        + erf_get_framing_length(packet);
312        }
313
314        if (libtrace->format_data == NULL) {
315                dag_init_format_data(libtrace);
316        }
317
318        DATA(libtrace)->drops += ntohs(erfptr->lctr);
319
320        return 0;
321
322}
323
324static int dag_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
325        int numbytes;
326        int size = 0;
327        uint32_t flags = 0;
328        struct timeval tv;
329        dag_record_t *erfptr = NULL;
330
331        if (DUCK.last_pkt - DUCK.last_duck > DUCK.duck_freq &&
332                        DUCK.duck_freq != 0) {
333                size = dag_get_duckinfo(libtrace, packet);
334                DUCK.last_duck = DUCK.last_pkt;
335                if (size != 0) {
336                        return size;
337                }
338                /* No DUCK support, so don't waste our time anymore */
339                DUCK.duck_freq = 0;
340        }
341
342        flags |= TRACE_PREP_DO_NOT_OWN_BUFFER;
343       
344        if (packet->buf_control == TRACE_CTRL_PACKET) {
345                packet->buf_control = TRACE_CTRL_EXTERNAL;
346                free(packet->buffer);
347                packet->buffer = 0;
348        }
349
350
351        do {
352                numbytes = dag_available(libtrace);
353                if (numbytes < 0)
354                        return numbytes;
355                if (numbytes == 0)
356                        continue;
357                erfptr = dag_get_record(libtrace);
358        } while (erfptr == NULL);
359       
360       
361        if (dag_prepare_packet(libtrace, packet, erfptr, TRACE_RT_DATA_ERF, 
362                                flags))
363                return -1;
364        tv = trace_get_timeval(packet);
365        DUCK.last_pkt = tv.tv_sec;
366        return packet->payload ? htons(erfptr->rlen) : erf_get_framing_length(packet);
367}
368
369static libtrace_eventobj_t trace_event_dag(libtrace_t *trace,
370                                        libtrace_packet_t *packet) {
371        libtrace_eventobj_t event = {0,0,0.0,0};
372        int data;
373
374        do {
375                data = dag_available(trace);
376
377                if (data <= 0)
378                        break;
379
380                event.size = dag_read_packet(trace,packet);
381                //DATA(trace)->dag.diff -= event.size;
382                if (trace->filter) {
383                        if (trace_apply_filter(trace->filter, packet)) {
384                                event.type = TRACE_EVENT_PACKET;
385                        } else {
386                                /* Do not sleep - try to read another packet */
387                                continue;
388                        }
389                } else {
390                        event.type = TRACE_EVENT_PACKET;
391                }
392                if (trace->snaplen > 0) {
393                        trace_set_capture_length(packet, trace->snaplen);
394                }
395
396                return event;
397        } while (1);
398
399        assert(data == 0);
400        event.type = TRACE_EVENT_SLEEP;
401        event.seconds = 0.0001;
402        event.size = 0;
403        return event;
404}
405
406static uint64_t dag_get_dropped_packets(libtrace_t *trace)
407{
408        if (!trace->format_data)
409                return (uint64_t)-1;
410        return DATA(trace)->drops;
411}
412
413static void dag_help(void) {
414        printf("dag format module: $Revision$\n");
415        printf("Supported input URIs:\n");
416        printf("\tdag:/dev/dagn\n");
417        printf("\n");
418        printf("\te.g.: dag:/dev/dag0\n");
419        printf("\n");
420        printf("Supported output URIs:\n");
421        printf("\tnone\n");
422        printf("\n");
423}
424
425static struct libtrace_format_t dag = {
426        "dag",
427        "$Id$",
428        TRACE_FORMAT_ERF,
429        dag_probe_filename,             /* probe filename */
430        NULL,                           /* probe magic */
431        dag_init_input,                 /* init_input */
432        dag_config_input,               /* config_input */
433        dag_start_input,                /* start_input */
434        dag_pause_input,                /* pause_input */
435        NULL,                           /* init_output */
436        NULL,                           /* config_output */
437        NULL,                           /* start_output */
438        dag_fin_input,                  /* fin_input */
439        NULL,                           /* fin_output */
440        dag_read_packet,                /* read_packet */
441        dag_prepare_packet,             /* prepare_packet */
442        NULL,                           /* fin_packet */
443        NULL,                           /* write_packet */
444        erf_get_link_type,              /* get_link_type */
445        erf_get_direction,              /* get_direction */
446        erf_set_direction,              /* set_direction */
447        erf_get_erf_timestamp,          /* get_erf_timestamp */
448        NULL,                           /* get_timeval */
449        NULL,                           /* get_timespec */
450        NULL,                           /* get_seconds */
451        NULL,                           /* seek_erf */
452        NULL,                           /* seek_timeval */
453        NULL,                           /* seek_seconds */
454        erf_get_capture_length,         /* get_capture_length */
455        erf_get_wire_length,            /* get_wire_length */
456        erf_get_framing_length,         /* get_framing_length */
457        erf_set_capture_length,         /* set_capture_length */
458        NULL,                           /* get_received_packets */
459        NULL,                           /* get_filtered_packets */
460        dag_get_dropped_packets,        /* get_dropped_packets */
461        NULL,                           /* get_captured_packets */
462        NULL,                           /* get_fd */
463        trace_event_dag,                /* trace_event */
464        dag_help,                       /* help */
465        NULL                            /* next pointer */
466};
467
468void dag_constructor(void) {
469        register_format(&dag);
470}
Note: See TracBrowser for help on using the repository browser.