source: lib/format_dag25.c @ f3f3558

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since f3f3558 was f3f3558, checked in by Perry Lorier <perry@…>, 14 years ago

Ready for release

  • Property mode set to 100644
File size: 13.2 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       
344        erfptr = dag_get_record(trace);
345        if (erfptr == NULL) {
346                /* No packet available */
347                event.type = TRACE_EVENT_SLEEP;
348                event.seconds = 0.0001;
349                return event;
350        }
351        dag_form_packet(erfptr, packet);
352        event.size = trace_get_capture_length(packet) + trace_get_framing_length(packet);
353        if (trace->filter) {
354                if (trace_apply_filter(trace->filter, packet)) {
355                        event.type = TRACE_EVENT_PACKET;
356                } else {
357                        event.type = TRACE_EVENT_SLEEP;
358                        event.seconds = 0.000001;
359                        return event;
360                }
361        } else {
362                event.type = TRACE_EVENT_PACKET;
363        }
364
365        if (trace->snaplen > 0) {
366                trace_set_capture_length(packet, trace->snaplen);
367        }
368
369        return event;
370}
371
372
373static void dag_help(void) {
374        printf("dag format module: $Revision$\n");
375        printf("Supported input URIs:\n");
376        printf("\tdag:/dev/dagn\n");
377        printf("\n");
378        printf("\te.g.: dag:/dev/dag0\n");
379        printf("\n");
380        printf("Supported output URIs:\n");
381        printf("\tnone\n");
382        printf("\n");
383}
384
385static struct libtrace_format_t dag = {
386        "dag",
387        "$Id$",
388        TRACE_FORMAT_ERF,
389        dag_init_input,                 /* init_input */
390        dag_config_input,               /* config_input */
391        dag_start_input,                /* start_input */
392        dag_pause_input,                /* pause_input */
393        NULL,                           /* init_output */
394        NULL,                           /* config_output */
395        NULL,                           /* start_output */
396        dag_fin_input,                  /* fin_input */
397        NULL,                           /* fin_output */
398        dag_read_packet,                /* read_packet */
399        NULL,                           /* fin_packet */
400        NULL,                           /* write_packet */
401        erf_get_link_type,              /* get_link_type */
402        erf_get_direction,              /* get_direction */
403        erf_set_direction,              /* set_direction */
404        erf_get_erf_timestamp,          /* get_erf_timestamp */
405        NULL,                           /* get_timeval */
406        NULL,                           /* get_seconds */
407        NULL,                           /* seek_erf */
408        NULL,                           /* seek_timeval */
409        NULL,                           /* seek_seconds */
410        erf_get_capture_length,         /* get_capture_length */
411        erf_get_wire_length,            /* get_wire_length */
412        erf_get_framing_length,         /* get_framing_length */
413        erf_set_capture_length,         /* set_capture_length */
414        NULL,                           /* get_received_packets */
415        NULL,                           /* get_filtered_packets */
416        dag25_get_dropped_packets,      /* get_dropped_packets */
417        NULL,                           /* get_captured_packets */
418        NULL,                           /* get_fd */
419        trace_event_dag,                /* trace_event */
420        dag_help,                       /* help */
421        NULL                            /* next pointer */
422};
423
424void dag_constructor(void) {
425        register_format(&dag);
426}
Note: See TracBrowser for help on using the repository browser.