source: lib/format_dag25.c @ dd06159

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