source: lib/format_dag25.c @ a9a91d1

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