source: lib/format_dag25.c @ 2faa57e

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 2faa57e was 2faa57e, checked in by Shane Alcock <salcock@…>, 14 years ago
  • Added a separate .h file for the various ERF types as newer ERF types aren't specified in the DAG 2.4 drivers
  • ERF traces should now return a Option Unavailable error for any unsupported cconfig options, rather than Unknown Option
  • Added a bit of extra documentation to the new thread/mutex related code added to format_dag25.c
  • Property mode set to 100644
File size: 16.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/* XXX: Windows doesn't have pthreads, but this code doesn't compile under
49 * Windows anyway so we'll worry about this more later :] */
50#include <pthread.h>
51
52
53#ifdef WIN32
54#  include <io.h>
55#  include <share.h>
56#  define PATH_MAX _MAX_PATH
57#  define snprintf sprintf_s
58#else
59#  include <netdb.h>
60#  ifndef PATH_MAX
61#       define PATH_MAX 4096
62#  endif
63#  include <sys/ioctl.h>
64#endif
65
66
67#define DATA(x) ((struct dag_format_data_t *)x->format_data)
68#define FORMAT_DATA DATA(libtrace)
69#define DUCK FORMAT_DATA->duck
70static struct libtrace_format_t dag;
71
72struct dag_dev_t {
73        //pthread_mutex_t dag_mutex;
74        char * dev_name;
75        int fd;
76        uint16_t ref_count;
77        struct dag_dev_t *prev;
78        struct dag_dev_t *next;
79};     
80
81struct dag_format_data_t {
82        struct {
83                uint32_t last_duck;
84                uint32_t duck_freq;
85                uint32_t last_pkt;
86                libtrace_t *dummy_duck;
87        } duck;
88
89        struct dag_dev_t *device;
90        unsigned int dagstream;
91        int stream_attached;
92        uint8_t *bottom;
93        uint8_t *top;
94        uint32_t processed;
95        uint64_t drops;
96};
97
98pthread_mutex_t open_dag_mutex;
99struct dag_dev_t *open_dags = NULL;
100
101/* NOTE: This function assumes the open_dag_mutex is held by the caller */
102static struct dag_dev_t *dag_find_open_device(char *dev_name) {
103        struct dag_dev_t *dag_dev;
104       
105        dag_dev = open_dags;
106
107        /* XXX: Not exactly zippy, but how often are we going to be dealing
108         * with multiple dag cards? */
109        while (dag_dev != NULL) {
110                if (strcmp(dag_dev->dev_name, dev_name) == 0) {
111                        dag_dev->ref_count ++;
112                        return dag_dev;
113                       
114                }
115                dag_dev = dag_dev->next;
116        }
117        return NULL;
118               
119       
120}
121
122/* NOTE: This function assumes the open_dag_mutex is held by the caller */
123static void dag_close_device(struct dag_dev_t *dev) {
124        /* Need to remove from the device list */
125       
126        assert(dev->ref_count == 0);
127       
128        if (dev->prev == NULL) {
129                open_dags = dev->next;
130                if (dev->next)
131                        dev->next->prev = NULL;
132        } else {
133                dev->prev->next = dev->next;
134                if (dev->next)
135                        dev->next->prev = dev->prev;
136        }
137
138        dag_close(dev->fd);
139        free(dev->dev_name);
140        free(dev);
141               
142}
143
144/* NOTE: This function assumes the open_dag_mutex is held by the caller */
145static struct dag_dev_t *dag_open_device(libtrace_t *libtrace, char *dev_name) {
146        struct stat buf;
147        int fd;
148        struct dag_dev_t *new_dev;
149       
150        if (stat(dev_name, &buf) == -1) {
151                trace_set_err(libtrace,errno,"stat(%s)",dev_name);
152                return NULL;
153        }
154       
155        if (S_ISCHR(buf.st_mode)) {
156                if((fd = dag_open(dev_name)) < 0) {
157                        trace_set_err(libtrace,errno,"Cannot open DAG %s",
158                                        dev_name);
159                        return NULL;
160                }
161        } else {
162                trace_set_err(libtrace,errno,"Not a valid dag device: %s",
163                                dev_name);
164                return NULL;
165        }
166       
167        new_dev = (struct dag_dev_t *)malloc(sizeof(struct dag_dev_t));
168        new_dev->fd = fd;
169        new_dev->dev_name = dev_name;
170        new_dev->ref_count = 1;
171       
172        new_dev->prev = NULL;
173        new_dev->next = open_dags;
174        if (open_dags)
175                open_dags->prev = new_dev;
176       
177        open_dags = new_dev;
178       
179        return new_dev;
180}
181       
182
183static int dag_init_input(libtrace_t *libtrace) {
184        char *dag_dev_name = NULL;
185        char *scan = NULL;
186        int stream = 0;
187        struct dag_dev_t *dag_device = NULL;
188       
189        pthread_mutex_lock(&open_dag_mutex);
190        if ((scan = strchr(libtrace->uridata,',')) == NULL) {
191                dag_dev_name = strdup(libtrace->uridata);
192        } else {
193                dag_dev_name = (char *)strndup(libtrace->uridata,
194                                (size_t)(scan - libtrace->uridata));
195                stream = atoi(++scan);
196        }
197       
198       
199        libtrace->format_data = (struct dag_format_data_t *)
200                malloc(sizeof(struct dag_format_data_t));
201
202        /* For now, we don't offer the ability to select the stream */
203        FORMAT_DATA->dagstream = stream;
204
205        dag_device = dag_find_open_device(dag_dev_name);
206
207        if (dag_device == NULL) {
208                /* Device not yet opened - open it ourselves */
209                dag_device = dag_open_device(libtrace, dag_dev_name);
210        } else {
211                free(dag_dev_name);
212                dag_dev_name = NULL;
213        }
214
215        if (dag_device == NULL) {
216                if (dag_dev_name)
217                        free(dag_dev_name);
218                return -1;
219        }
220
221
222
223        DUCK.last_duck = 0;
224        DUCK.duck_freq = 0;
225        DUCK.last_pkt = 0;
226        DUCK.dummy_duck = NULL;
227        FORMAT_DATA->device = dag_device;
228        FORMAT_DATA->stream_attached = 0;
229        FORMAT_DATA->drops = 0;
230       
231        pthread_mutex_unlock(&open_dag_mutex);
232        return 0;
233}
234       
235static int dag_config_input(libtrace_t *libtrace, trace_option_t option,
236                                void *data) {
237        char conf_str[4096];
238        switch(option) {
239                case TRACE_OPTION_META_FREQ:
240                        DUCK.duck_freq = *(int *)data;
241                        return 0;
242                case TRACE_OPTION_SNAPLEN:
243                        snprintf(conf_str, 4096, "varlen slen=%i", *(int *)data);
244                        if (dag_configure(FORMAT_DATA->device->fd, 
245                                                conf_str) != 0) {
246                                trace_set_err(libtrace, errno, "Failed to configure snaplen on DAG card: %s", libtrace->uridata);
247                                return -1;
248                        }
249                        return 0;
250                case TRACE_OPTION_PROMISC:
251                        /* DAG already operates in a promisc fashion */
252                        return -1;
253                case TRACE_OPTION_FILTER:
254                        return -1;
255                case TRACE_OPTION_EVENT_REALTIME:
256                        return -1;
257        }
258        return -1;
259}
260
261static int dag_start_input(libtrace_t *libtrace) {
262        struct timeval zero, nopoll;
263        uint8_t *top, *bottom;
264        uint8_t diff = 0;
265        top = bottom = NULL;
266
267        zero.tv_sec = 0;
268        zero.tv_usec = 0;
269        nopoll = zero;
270
271
272       
273        if (dag_attach_stream(FORMAT_DATA->device->fd, 
274                                FORMAT_DATA->dagstream, 0, 0) < 0) {
275                trace_set_err(libtrace, errno, "Cannot attach DAG stream");
276                return -1;
277        }
278
279        if (dag_start_stream(FORMAT_DATA->device->fd, 
280                                FORMAT_DATA->dagstream) < 0) {
281                trace_set_err(libtrace, errno, "Cannot start DAG stream");
282                return -1;
283        }
284        FORMAT_DATA->stream_attached = 1;
285        /* We don't want the dag card to do any sleeping */
286        dag_set_stream_poll(FORMAT_DATA->device->fd, 
287                                FORMAT_DATA->dagstream, 0, &zero, 
288                                &nopoll);
289       
290        /* Should probably flush the memory hole now */
291       
292        do {
293                top = dag_advance_stream(FORMAT_DATA->device->fd,
294                                        FORMAT_DATA->dagstream,
295                                        &bottom);
296                assert(top && bottom);
297                diff = top - bottom;
298                bottom -= diff;
299        } while (diff != 0);
300        FORMAT_DATA->top = NULL;
301        FORMAT_DATA->bottom = NULL;
302        FORMAT_DATA->processed = 0;
303        FORMAT_DATA->drops = 0;
304       
305        return 0;
306}
307
308static int dag_pause_input(libtrace_t *libtrace) {
309        if (dag_stop_stream(FORMAT_DATA->device->fd, 
310                                FORMAT_DATA->dagstream) < 0) {
311                trace_set_err(libtrace, errno, "Could not stop DAG stream");
312                return -1;
313        }
314        if (dag_detach_stream(FORMAT_DATA->device->fd, 
315                                FORMAT_DATA->dagstream) < 0) {
316                trace_set_err(libtrace, errno, "Could not detach DAG stream");
317                return -1;
318        }
319        FORMAT_DATA->stream_attached = 0;
320        return 0;
321}
322
323static int dag_fin_input(libtrace_t *libtrace) {
324        pthread_mutex_lock(&open_dag_mutex);
325        if (FORMAT_DATA->stream_attached)
326                dag_pause_input(libtrace);
327        FORMAT_DATA->device->ref_count --;
328       
329        if (FORMAT_DATA->device->ref_count == 0)
330                dag_close_device(FORMAT_DATA->device);
331        if (DUCK.dummy_duck)
332                trace_destroy_dead(DUCK.dummy_duck);
333        free(libtrace->format_data);
334        pthread_mutex_unlock(&open_dag_mutex);
335        return 0; /* success */
336}
337
338static int dag_get_duckinfo(libtrace_t *libtrace,
339                                libtrace_packet_t *packet) {
340        if (packet->buf_control == TRACE_CTRL_EXTERNAL ||
341                        !packet->buffer) {
342                packet->buffer = malloc(LIBTRACE_PACKET_BUFSIZE);
343                packet->buf_control = TRACE_CTRL_PACKET;
344                if (!packet->buffer) {
345                        trace_set_err(libtrace, errno,
346                                        "Cannot allocate packet buffer");
347                        return -1;
348                }
349        }
350
351        packet->header = 0;
352        packet->payload = packet->buffer;
353
354        /* No need to check if we can get DUCK or not - we're modern
355         * enough */
356        if ((ioctl(FORMAT_DATA->device->fd, DAGIOCDUCK, 
357                                        (duckinf_t *)packet->payload) < 0)) {
358                trace_set_err(libtrace, errno, "Error using DAGIOCDUCK");
359                return -1;
360        }
361
362        packet->type = TRACE_RT_DUCK_2_5;
363        if (!DUCK.dummy_duck)
364                DUCK.dummy_duck = trace_create_dead("rt:localhost:3434");
365        packet->trace = DUCK.dummy_duck;
366        return sizeof(duckinf_t);
367}
368
369static int dag_available(libtrace_t *libtrace) {
370        uint32_t diff = FORMAT_DATA->top - FORMAT_DATA->bottom;
371        /* If we've processed more than 4MB of data since we last called
372         * dag_advance_stream, then we should call it again to allow the
373         * space occupied by that 4MB to be released */
374        if (diff >= dag_record_size && FORMAT_DATA->processed < 4 * 1024 * 1024)
375                return diff;
376        FORMAT_DATA->top = dag_advance_stream(FORMAT_DATA->device->fd, 
377                        FORMAT_DATA->dagstream, 
378                        &(FORMAT_DATA->bottom));
379        if (FORMAT_DATA->top == NULL) {
380                trace_set_err(libtrace, errno, "dag_advance_stream failed!");
381                return -1;
382        }
383        FORMAT_DATA->processed = 0;
384        diff = FORMAT_DATA->top - FORMAT_DATA->bottom;
385        return diff;
386}
387
388static dag_record_t *dag_get_record(libtrace_t *libtrace) {
389        dag_record_t *erfptr = NULL;
390        uint16_t size;
391        erfptr = (dag_record_t *)FORMAT_DATA->bottom;
392        if (!erfptr)
393                return NULL;
394        size = ntohs(erfptr->rlen);
395        assert( size >= dag_record_size );
396        /* Make certain we have the full packet available */
397        if (size > (FORMAT_DATA->top - FORMAT_DATA->bottom))
398                return NULL;
399        FORMAT_DATA->bottom += size;
400        FORMAT_DATA->processed += size;
401        return erfptr;
402}
403
404static void dag_form_packet(dag_record_t *erfptr, libtrace_packet_t *packet) {
405        packet->buffer = erfptr;
406        packet->header = erfptr;
407        packet->type = TRACE_RT_DATA_ERF;
408        if (erfptr->flags.rxerror == 1) {
409                /* rxerror means the payload is corrupt - drop it
410                 * by tweaking rlen */
411                packet->payload = NULL;
412                erfptr->rlen = htons(erf_get_framing_length(packet));
413        } else {
414                packet->payload = (char*)packet->buffer
415                        + erf_get_framing_length(packet);
416        }
417
418}
419
420
421static int dag_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
422        int size = 0;
423        struct timeval tv;
424        dag_record_t *erfptr = NULL;
425        int numbytes = 0;
426       
427        if (DUCK.last_pkt - DUCK.last_duck > DUCK.duck_freq &&
428                        DUCK.duck_freq != 0) {
429                size = dag_get_duckinfo(libtrace, packet);
430                DUCK.last_duck = DUCK.last_pkt;
431                if (size != 0) {
432                        return size;
433                }
434                /* No DUCK support, so don't waste our time anymore */
435                DUCK.duck_freq = 0;
436        }
437
438        if (packet->buf_control == TRACE_CTRL_PACKET) {
439                packet->buf_control = TRACE_CTRL_EXTERNAL;
440                free(packet->buffer);
441                packet->buffer = 0;
442        }
443
444        do {
445                numbytes = dag_available(libtrace);
446                if (numbytes < 0)
447                        return numbytes;
448                if (numbytes < dag_record_size)
449                        /* Block until we see a packet */
450                        continue;
451                erfptr = dag_get_record(libtrace);
452        } while (erfptr == NULL);
453
454        dag_form_packet(erfptr, packet);
455        tv = trace_get_timeval(packet);
456        DUCK.last_pkt = tv.tv_sec;
457       
458        /* No loss counter for DSM coloured records - have to use
459         * some other API */
460        if (erfptr->type == TYPE_DSM_COLOR_ETH) {
461               
462        } else {
463                DATA(libtrace)->drops += ntohs(erfptr->lctr);
464        }
465        return packet->payload ? htons(erfptr->rlen) : 
466                                erf_get_framing_length(packet);
467}
468
469static libtrace_eventobj_t trace_event_dag(libtrace_t *trace,
470                                        libtrace_packet_t *packet) {
471        libtrace_eventobj_t event = {0,0,0.0,0};
472        dag_record_t *erfptr = NULL;
473        int numbytes;
474       
475        /* Need to call dag_available so that the top pointer will get
476         * updated, otherwise we'll never see any data! */
477        numbytes = dag_available(trace);
478
479        /* May as well not bother calling dag_get_record if dag_available
480         * suggests that there's no data */
481        if (numbytes != 0)
482                erfptr = dag_get_record(trace);
483        if (erfptr == NULL) {
484                /* No packet available */
485                event.type = TRACE_EVENT_SLEEP;
486                event.seconds = 0.0001;
487                return event;
488        }
489        dag_form_packet(erfptr, packet);
490        event.size = trace_get_capture_length(packet) + trace_get_framing_length(packet);
491        if (trace->filter) {
492                if (trace_apply_filter(trace->filter, packet)) {
493                        event.type = TRACE_EVENT_PACKET;
494                } else {
495                        event.type = TRACE_EVENT_SLEEP;
496                        event.seconds = 0.000001;
497                        return event;
498                }
499        } else {
500                event.type = TRACE_EVENT_PACKET;
501        }
502
503        if (trace->snaplen > 0) {
504                trace_set_capture_length(packet, trace->snaplen);
505        }
506
507        return event;
508}
509
510static uint64_t dag_get_dropped_packets(libtrace_t *trace) {
511        return DATA(trace)->drops;
512}
513
514static void dag_help(void) {
515        printf("dag format module: $Revision$\n");
516        printf("Supported input URIs:\n");
517        printf("\tdag:/dev/dagn\n");
518        printf("\n");
519        printf("\te.g.: dag:/dev/dag0\n");
520        printf("\n");
521        printf("Supported output URIs:\n");
522        printf("\tnone\n");
523        printf("\n");
524}
525
526static struct libtrace_format_t dag = {
527        "dag",
528        "$Id$",
529        TRACE_FORMAT_ERF,
530        dag_init_input,                 /* init_input */
531        dag_config_input,               /* config_input */
532        dag_start_input,                /* start_input */
533        dag_pause_input,                /* pause_input */
534        NULL,                           /* init_output */
535        NULL,                           /* config_output */
536        NULL,                           /* start_output */
537        dag_fin_input,                  /* fin_input */
538        NULL,                           /* fin_output */
539        dag_read_packet,                /* read_packet */
540        NULL,                           /* fin_packet */
541        NULL,                           /* write_packet */
542        erf_get_link_type,              /* get_link_type */
543        erf_get_direction,              /* get_direction */
544        erf_set_direction,              /* set_direction */
545        erf_get_erf_timestamp,          /* get_erf_timestamp */
546        NULL,                           /* get_timeval */
547        NULL,                           /* get_seconds */
548        NULL,                           /* seek_erf */
549        NULL,                           /* seek_timeval */
550        NULL,                           /* seek_seconds */
551        erf_get_capture_length,         /* get_capture_length */
552        erf_get_wire_length,            /* get_wire_length */
553        erf_get_framing_length,         /* get_framing_length */
554        erf_set_capture_length,         /* set_capture_length */
555        NULL,                           /* get_received_packets */
556        NULL,                           /* get_filtered_packets */
557        dag_get_dropped_packets,        /* get_dropped_packets */
558        NULL,                           /* get_captured_packets */
559        NULL,                           /* get_fd */
560        trace_event_dag,                /* trace_event */
561        dag_help,                       /* help */
562        NULL                            /* next pointer */
563};
564
565void dag_constructor(void) {
566        register_format(&dag);
567}
Note: See TracBrowser for help on using the repository browser.