source: lib/format_dag25.c @ 6033b99

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 6033b99 was 6033b99, checked in by Shane Alcock <salcock@…>, 14 years ago
  • Fixed bug where DAG 2.5 was never seeing any packets when using the event framework, because the internal pointers were never being updated!
  • Property mode set to 100644
File size: 13.6 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
49#ifdef WIN32
50#  include <io.h>
51#  include <share.h>
52#  define PATH_MAX _MAX_PATH
53#  define snprintf sprintf_s
54#else
55#  include <netdb.h>
56#  ifndef PATH_MAX
57#       define PATH_MAX 4096
58#  endif
59#  include <sys/ioctl.h>
60#endif
61
62#define DATA(x) ((struct dag_format_data_t *)x->format_data)
63#define FORMAT_DATA DATA(libtrace)
64#define DUCK FORMAT_DATA->duck
65static struct libtrace_format_t dag;
66
67struct dag_format_data_t {
68        struct {
69                uint32_t last_duck;
70                uint32_t duck_freq;
71                uint32_t last_pkt;
72                libtrace_t *dummy_duck;
73        } duck;
74
75        int fd;
76        unsigned int dagstream;
77        int stream_attached;
78        uint8_t *bottom;
79        uint8_t *top;
80        uint32_t processed;
81        uint64_t drops;
82};
83
84static int dag_init_input(libtrace_t *libtrace) {
85        struct stat buf;
86        libtrace->format_data = (struct dag_format_data_t *)
87                malloc(sizeof(struct dag_format_data_t));
88        if (stat(libtrace->uridata, &buf) == -1) {
89                trace_set_err(libtrace,errno,"stat(%s)",libtrace->uridata);
90                return -1;
91        }
92
93        /* For now, we don't offer the ability to select the stream */
94        FORMAT_DATA->dagstream = 0;
95
96        if (S_ISCHR(buf.st_mode)) {
97                if((FORMAT_DATA->fd = dag_open(libtrace->uridata)) < 0) {
98                        trace_set_err(libtrace,errno,"Cannot open DAG %s",
99                                        libtrace->uridata);
100                        return -1;
101                }
102        } else {
103                trace_set_err(libtrace,errno,"Not a valid dag device: %s",
104                                libtrace->uridata);
105                return -1;
106        }
107
108        DUCK.last_duck = 0;
109        DUCK.duck_freq = 0;
110        DUCK.last_pkt = 0;
111        DUCK.dummy_duck = NULL;
112        FORMAT_DATA->stream_attached = 0;
113        FORMAT_DATA->drops = 0;
114       
115        return 0;
116}
117       
118static int dag_config_input(libtrace_t *libtrace, trace_option_t option,
119                                void *data) {
120        char conf_str[4096];
121        switch(option) {
122                case TRACE_OPTION_META_FREQ:
123                        DUCK.duck_freq = *(int *)data;
124                        return 0;
125                case TRACE_OPTION_SNAPLEN:
126                        snprintf(conf_str, 4096, "varlen slen=%i", *(int *)data);
127                        if (dag_configure(FORMAT_DATA->fd, conf_str) != 0) {
128                                trace_set_err(libtrace, errno, "Failed to configure snaplen on DAG card: %s", libtrace->uridata);
129                                return -1;
130                        }
131                        return 0;
132                case TRACE_OPTION_PROMISC:
133                        /* DAG already operates in a promisc fashion */
134                        return -1;
135                case TRACE_OPTION_FILTER:
136                        return -1;
137                case TRACE_OPTION_EVENT_REALTIME:
138                        return -1;
139        }
140        return -1;
141}
142
143static int dag_start_input(libtrace_t *libtrace) {
144        struct timeval zero, nopoll;
145        uint8_t *top, *bottom;
146        uint8_t diff = 0;
147        top = bottom = NULL;
148
149        zero.tv_sec = 0;
150        zero.tv_usec = 0;
151        nopoll = zero;
152
153
154       
155        if (dag_attach_stream(FORMAT_DATA->fd, 
156                                FORMAT_DATA->dagstream, 0, 0) < 0) {
157                trace_set_err(libtrace, errno, "Cannot attach DAG stream");
158                return -1;
159        }
160
161        if (dag_start_stream(FORMAT_DATA->fd, 
162                                FORMAT_DATA->dagstream) < 0) {
163                trace_set_err(libtrace, errno, "Cannot start DAG stream");
164                return -1;
165        }
166        FORMAT_DATA->stream_attached = 1;
167        /* We don't want the dag card to do any sleeping */
168        dag_set_stream_poll(FORMAT_DATA->fd, 
169                                FORMAT_DATA->dagstream, 0, &zero, 
170                                &nopoll);
171       
172        /* Should probably flush the memory hole now */
173       
174        do {
175                top = dag_advance_stream(FORMAT_DATA->fd,
176                                        FORMAT_DATA->dagstream,
177                                        &bottom);
178                assert(top && bottom);
179                diff = top - bottom;
180                bottom -= diff;
181        } while (diff != 0);
182        FORMAT_DATA->top = NULL;
183        FORMAT_DATA->bottom = NULL;
184        FORMAT_DATA->processed = 0;
185        FORMAT_DATA->drops = 0;
186       
187        return 0;
188}
189
190static int dag_pause_input(libtrace_t *libtrace) {
191        if (dag_stop_stream(FORMAT_DATA->fd, 
192                                FORMAT_DATA->dagstream) < 0) {
193                trace_set_err(libtrace, errno, "Could not stop DAG stream");
194                return -1;
195        }
196        if (dag_detach_stream(FORMAT_DATA->fd, 
197                                FORMAT_DATA->dagstream) < 0) {
198                trace_set_err(libtrace, errno, "Could not detach DAG stream");
199                return -1;
200        }
201        FORMAT_DATA->stream_attached = 0;
202        return 0;
203}
204
205static int dag_fin_input(libtrace_t *libtrace) {
206        if (FORMAT_DATA->stream_attached)
207                dag_pause_input(libtrace);
208        dag_close(FORMAT_DATA->fd);
209        if (DUCK.dummy_duck)
210                trace_destroy_dead(DUCK.dummy_duck);
211        free(libtrace->format_data);
212        return 0; /* success */
213}
214
215static int dag_get_duckinfo(libtrace_t *libtrace,
216                                libtrace_packet_t *packet) {
217        if (packet->buf_control == TRACE_CTRL_EXTERNAL ||
218                        !packet->buffer) {
219                packet->buffer = malloc(LIBTRACE_PACKET_BUFSIZE);
220                packet->buf_control = TRACE_CTRL_PACKET;
221                if (!packet->buffer) {
222                        trace_set_err(libtrace, errno,
223                                        "Cannot allocate packet buffer");
224                        return -1;
225                }
226        }
227
228        packet->header = 0;
229        packet->payload = packet->buffer;
230
231        /* No need to check if we can get DUCK or not - we're modern
232         * enough */
233        if ((ioctl(FORMAT_DATA->fd, DAGIOCDUCK, (duckinf_t *)packet->payload)
234                                < 0)) {
235                trace_set_err(libtrace, errno, "Error using DAGIOCDUCK");
236                return -1;
237        }
238
239        packet->type = TRACE_RT_DUCK_2_5;
240        if (!DUCK.dummy_duck)
241                DUCK.dummy_duck = trace_create_dead("rt:localhost:3434");
242        packet->trace = DUCK.dummy_duck;
243        return sizeof(duckinf_t);
244}
245
246static int dag_available(libtrace_t *libtrace) {
247        uint32_t diff = FORMAT_DATA->top - FORMAT_DATA->bottom;
248        /* If we've processed more than 4MB of data since we last called
249         * dag_advance_stream, then we should call it again to allow the
250         * space occupied by that 4MB to be released */
251        if (diff >= dag_record_size && FORMAT_DATA->processed < 4 * 1024 * 1024)
252                return diff;
253        FORMAT_DATA->top = dag_advance_stream(FORMAT_DATA->fd, 
254                        FORMAT_DATA->dagstream, 
255                        &(FORMAT_DATA->bottom));
256        if (FORMAT_DATA->top == NULL) {
257                trace_set_err(libtrace, errno, "dag_advance_stream failed!");
258                return -1;
259        }
260        FORMAT_DATA->processed = 0;
261        diff = FORMAT_DATA->top - FORMAT_DATA->bottom;
262        return diff;
263}
264
265static dag_record_t *dag_get_record(libtrace_t *libtrace) {
266        dag_record_t *erfptr = NULL;
267        uint16_t size;
268        erfptr = (dag_record_t *)FORMAT_DATA->bottom;
269        if (!erfptr)
270                return NULL;
271        size = ntohs(erfptr->rlen);
272        assert( size >= dag_record_size );
273        /* Make certain we have the full packet available */
274        if (size > (FORMAT_DATA->top - FORMAT_DATA->bottom))
275                return NULL;
276        FORMAT_DATA->bottom += size;
277        FORMAT_DATA->processed += size;
278        return erfptr;
279}
280
281static void dag_form_packet(dag_record_t *erfptr, libtrace_packet_t *packet) {
282        packet->buffer = erfptr;
283        packet->header = erfptr;
284        packet->type = TRACE_RT_DATA_ERF;
285        if (erfptr->flags.rxerror == 1) {
286                /* rxerror means the payload is corrupt - drop it
287                 * by tweaking rlen */
288                packet->payload = NULL;
289                erfptr->rlen = htons(erf_get_framing_length(packet));
290        } else {
291                packet->payload = (char*)packet->buffer
292                        + erf_get_framing_length(packet);
293        }
294
295}
296
297
298static int dag_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
299        int size = 0;
300        struct timeval tv;
301        dag_record_t *erfptr = NULL;
302        int numbytes = 0;
303       
304        if (DUCK.last_pkt - DUCK.last_duck > DUCK.duck_freq &&
305                        DUCK.duck_freq != 0) {
306                size = dag_get_duckinfo(libtrace, packet);
307                DUCK.last_duck = DUCK.last_pkt;
308                if (size != 0) {
309                        return size;
310                }
311                /* No DUCK support, so don't waste our time anymore */
312                DUCK.duck_freq = 0;
313        }
314
315        if (packet->buf_control == TRACE_CTRL_PACKET) {
316                packet->buf_control = TRACE_CTRL_EXTERNAL;
317                free(packet->buffer);
318                packet->buffer = 0;
319        }
320
321        do {
322                numbytes = dag_available(libtrace);
323                if (numbytes < 0)
324                        return numbytes;
325                if (numbytes < dag_record_size)
326                        /* Block until we see a packet */
327                        continue;
328                erfptr = dag_get_record(libtrace);
329        } while (erfptr == NULL);
330
331        dag_form_packet(erfptr, packet);
332        tv = trace_get_timeval(packet);
333        DUCK.last_pkt = tv.tv_sec;
334        DATA(libtrace)->drops += ntohs(erfptr->lctr);
335        return packet->payload ? htons(erfptr->rlen) : 
336                                erf_get_framing_length(packet);
337}
338
339static libtrace_eventobj_t trace_event_dag(libtrace_t *trace,
340                                        libtrace_packet_t *packet) {
341        libtrace_eventobj_t event = {0,0,0.0,0};
342        dag_record_t *erfptr = NULL;
343        int numbytes;
344       
345        /* Need to call dag_available so that the top pointer will get
346         * updated, otherwise we'll never see any data! */
347        numbytes = dag_available(trace);
348
349        /* May as well not bother calling dag_get_record if dag_available
350         * suggests that there's no data */
351        if (numbytes != 0)
352                erfptr = dag_get_record(trace);
353        if (erfptr == NULL) {
354                /* No packet available */
355                event.type = TRACE_EVENT_SLEEP;
356                event.seconds = 0.0001;
357                return event;
358        }
359        dag_form_packet(erfptr, packet);
360        event.size = trace_get_capture_length(packet) + trace_get_framing_length(packet);
361        if (trace->filter) {
362                if (trace_apply_filter(trace->filter, packet)) {
363                        event.type = TRACE_EVENT_PACKET;
364                } else {
365                        event.type = TRACE_EVENT_SLEEP;
366                        event.seconds = 0.000001;
367                        return event;
368                }
369        } else {
370                event.type = TRACE_EVENT_PACKET;
371        }
372
373        if (trace->snaplen > 0) {
374                trace_set_capture_length(packet, trace->snaplen);
375        }
376
377        return event;
378}
379
380static uint64_t dag_get_dropped_packets(libtrace_t *trace) {
381        return DATA(trace)->drops;
382}
383
384static void dag_help(void) {
385        printf("dag format module: $Revision$\n");
386        printf("Supported input URIs:\n");
387        printf("\tdag:/dev/dagn\n");
388        printf("\n");
389        printf("\te.g.: dag:/dev/dag0\n");
390        printf("\n");
391        printf("Supported output URIs:\n");
392        printf("\tnone\n");
393        printf("\n");
394}
395
396static struct libtrace_format_t dag = {
397        "dag",
398        "$Id$",
399        TRACE_FORMAT_ERF,
400        dag_init_input,                 /* init_input */
401        dag_config_input,               /* config_input */
402        dag_start_input,                /* start_input */
403        dag_pause_input,                /* pause_input */
404        NULL,                           /* init_output */
405        NULL,                           /* config_output */
406        NULL,                           /* start_output */
407        dag_fin_input,                  /* fin_input */
408        NULL,                           /* fin_output */
409        dag_read_packet,                /* read_packet */
410        NULL,                           /* fin_packet */
411        NULL,                           /* write_packet */
412        erf_get_link_type,              /* get_link_type */
413        erf_get_direction,              /* get_direction */
414        erf_set_direction,              /* set_direction */
415        erf_get_erf_timestamp,          /* get_erf_timestamp */
416        NULL,                           /* get_timeval */
417        NULL,                           /* get_seconds */
418        NULL,                           /* seek_erf */
419        NULL,                           /* seek_timeval */
420        NULL,                           /* seek_seconds */
421        erf_get_capture_length,         /* get_capture_length */
422        erf_get_wire_length,            /* get_wire_length */
423        erf_get_framing_length,         /* get_framing_length */
424        erf_set_capture_length,         /* set_capture_length */
425        NULL,                           /* get_received_packets */
426        NULL,                           /* get_filtered_packets */
427        dag_get_dropped_packets,        /* get_dropped_packets */
428        NULL,                           /* get_captured_packets */
429        NULL,                           /* get_fd */
430        trace_event_dag,                /* trace_event */
431        dag_help,                       /* help */
432        NULL                            /* next pointer */
433};
434
435void dag_constructor(void) {
436        register_format(&dag);
437}
Note: See TracBrowser for help on using the repository browser.