source: lib/format_bpf.c @ f0fb38f

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since f0fb38f was f0fb38f, checked in by Shane Alcock <salcock@…>, 13 years ago
  • Added prepare_packet functions to all formats, primarily to support translating RT packets into the appropriate format. These functions are all used internally as well, as most formats still need to "prepare" packets that have been read by setting pointers, updating loss counters etc.
  • Also added a trace_prepare_packet function, but this is not made available externally at this stage
  • Added init_format_data functions to some formats to initialise format data structures in cases where the init_trace function does more than just that
  • Refactored rt packet reading code to use the new trace_prepare_packet functionality - also did a lot of tidying of the code
  • Added missing RT type for BPF format
  • Property mode set to 100644
File size: 12.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: Perry Lorier
6 *         
7 * All rights reserved.
8 *
9 * This code has been developed by the University of Waikato WAND
10 * research group. For further information please see http://www.wand.net.nz/
11 *
12 * libtrace is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * libtrace is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with libtrace; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25 *
26 * $Id$
27 *
28 */
29
30#include "libtrace.h"
31#include "libtrace_int.h"
32#include "format_helper.h"
33#include "config.h"
34#include "stdlib.h"
35
36#ifdef HAVE_INTTYPES_H
37#  include <inttypes.h>
38#else
39# error "Can't find inttypes.h"
40#endif
41
42#include <sys/socket.h>
43
44#include <sys/types.h>
45#include <sys/time.h>
46#include <sys/ioctl.h>
47
48#include <string.h>
49#include <net/if.h>
50#include <sys/ioctl.h>
51#include <errno.h>
52#include <fcntl.h>
53
54
55struct libtrace_format_data_t {
56        int fd;
57        int snaplen;
58        int promisc;
59        void *buffer;
60        void *bufptr;
61        unsigned int buffersize;
62        int remaining;
63        unsigned int linktype;
64        struct bpf_stat stats;
65        int stats_valid;
66};
67
68#define FORMATIN(x) ((struct libtrace_format_data_t*)((x->format_data)))
69
70#define BPFHDR(x) ((struct bpf_hdr *)((x)->header))
71
72static int bpf_init_input(libtrace_t *libtrace) 
73{
74        libtrace->format_data = (struct libtrace_format_data_t *)
75                malloc(sizeof(struct libtrace_format_data_t));
76        FORMATIN(libtrace)->fd = -1;
77        FORMATIN(libtrace)->promisc = 0;
78        FORMATIN(libtrace)->snaplen = 65536;
79        FORMATIN(libtrace)->stats_valid = 0;
80
81        return 0;
82}
83
84static int bpf_start_input(libtrace_t *libtrace)
85{
86        int bpfid=0;
87        struct bpf_version bv;
88        struct ifreq ifr;
89        unsigned int v;
90
91        /* Find and open a bpf device */
92        do {
93                char buffer[64];
94                snprintf(buffer,sizeof(buffer),"/dev/bpf%d", bpfid);
95                bpfid++;
96               
97                FORMATIN(libtrace)->fd = open(buffer, O_RDONLY);
98        } while(FORMATIN(libtrace)->fd == -1 && errno == EBUSY);
99
100        if (FORMATIN(libtrace)->fd == -1) {
101                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,
102                                "No free bpf devices");
103                return -1;
104        }
105
106        /* Check the BPF Version is ok */
107        if (ioctl(FORMATIN(libtrace)->fd, BIOCVERSION, &bv) == -1) {
108                trace_set_err(libtrace,errno,
109                                "Failed to read the bpf version");
110                close(FORMATIN(libtrace)->fd);
111                return -1;
112        }
113
114        if (bv.bv_major != BPF_MAJOR_VERSION) {
115                trace_set_err(libtrace,errno, 
116                        "Unknown kernel BPF version (%d.%d, libtrace requires at least %d.%d)",
117                        bv.bv_major,
118                        bv.bv_minor,
119                        BPF_MAJOR_VERSION,
120                        BPF_MINOR_VERSION);
121                close(FORMATIN(libtrace)->fd);
122                return -1;
123        }
124
125        if (bv.bv_minor < BPF_MINOR_VERSION) {
126                trace_set_err(libtrace,errno, "Kernel version too old (%d.%d, libtrace requires at least %d.%d)",
127                        bv.bv_major,
128                        bv.bv_minor,
129                        BPF_MAJOR_VERSION,
130                        BPF_MINOR_VERSION);
131                close(FORMATIN(libtrace)->fd);
132                return -1;
133        }
134
135        /* We assume the default kernel buffer size is sufficient. */
136        if (ioctl(FORMATIN(libtrace)->fd, BIOCGBLEN,
137                        &FORMATIN(libtrace)->buffersize)==-1) {
138                trace_set_err(libtrace,errno,"Failed to find buffer length");
139                close(FORMATIN(libtrace)->fd);
140                return -1;
141        }
142
143        FORMATIN(libtrace)->buffer = malloc(FORMATIN(libtrace)->buffersize);
144        FORMATIN(libtrace)->bufptr = FORMATIN(libtrace)->buffer;
145        FORMATIN(libtrace)->remaining = 0;
146
147        /* attach to the device */
148        strncpy(ifr.ifr_name, libtrace->uridata, sizeof(ifr.ifr_name));
149        if (ioctl(FORMATIN(libtrace)->fd, BIOCSETIF, &ifr) == -1) {
150                trace_set_err(libtrace,errno,"Failed to attach");
151                close(FORMATIN(libtrace)->fd);
152                return -1;
153        }
154
155        if (ioctl(FORMATIN(libtrace)->fd, BIOCGDLT,
156                         &FORMATIN(libtrace)->linktype) == -1) {
157                trace_set_err(libtrace,errno,"Failed to retrieve link type");
158                close(FORMATIN(libtrace)->fd);
159                return -1;
160        }
161       
162        /* TODO: If BIOCGDLTLIST exists then we should perhaps do something
163         *       with it.  We don't have the same concept of multiple DLT's
164         *       as pcap does.  We grab the rawest possible thing and then
165         *       decode packets by understanding the protocols.  So perhaps
166         *       we should setup a rating of DLT's that we'll prefer in order.
167         *       For example we should try and get 802.11 frames rather than
168         *       802.3 frames.  The general rule should be "whatever actually
169         *       went over the air", although of course if we don't support
170         *       what went over the air we should fall back to something we
171         *       /do/ support.
172         */
173       
174        /* Using timeouts seems sucky.  We'll always use immediate mode.  We
175         * pray the kernel is smart enough that if a another packet arrives
176         * while we're processing this one that it will buffer them into it's
177         * kernel buffer so we can recieve packets later. (It'll need to do this
178         * to deal with us spending time processing the last 'n' packets anyway)
179         */
180       
181        v=1;
182        if (ioctl(FORMATIN(libtrace)->fd, BIOCIMMEDIATE, &v) == -1) {
183                trace_set_err(libtrace,errno,"Failed to set immediate mode");
184                close(FORMATIN(libtrace)->fd);
185                return -1;
186        }
187
188        if (FORMATIN(libtrace)->promisc) {
189                if (ioctl(FORMATIN(libtrace)->fd, BIOCPROMISC, NULL) == -1) {
190                        trace_set_err(libtrace,errno,
191                                "Failed to set promisc mode");
192                        close(FORMATIN(libtrace)->fd);
193                        return -1;
194
195                }
196        }
197
198        FORMATIN(libtrace)->stats_valid = 0;
199
200        /* TODO: we should always set a bpf filter for snapping */
201
202        /* We're done! */
203        return 0;
204}
205
206static uint64_t bpf_get_received_packets(libtrace_t *trace)
207{
208        if (trace->format_data == NULL)
209                return (uint64_t)-1;
210
211        if (FORMATIN(trace)->fd == -1) {
212                /* Almost certainly a 'dead' trace so there is no socket
213                 * for us to query */
214                return (uint64_t) -1;
215        }
216        /* If we're called with stats_valid == 0, or we're called again
217         * then refresh the stats.  Don't refresh the stats if we're called
218         * immediately after get_dropped_packets
219         */
220        if ((FORMATIN(trace)->stats_valid & 1)
221                || (FORMATIN(trace)->stats_valid == 0)) {
222                ioctl(FORMATIN(trace)->fd, BIOCGSTATS, &FORMATIN(trace)->stats);
223                FORMATIN(trace)->stats_valid |= 1;
224        }
225
226        return FORMATIN(trace)->stats.bs_recv;
227}
228
229static uint64_t bpf_get_dropped_packets(libtrace_t *trace)
230{
231        if (trace->format_data == NULL)
232                return (uint64_t)-1;
233
234        if (FORMATIN(trace)->fd == -1) {
235                /* Almost certainly a 'dead' trace so there is no socket
236                 * for us to query */
237                return (uint64_t) -1;
238        }
239        /* If we're called with stats_valid == 0, or we're called again
240         * then refresh the stats.  Don't refresh the stats if we're called
241         * immediately after get_received_packets
242         */
243        if ((FORMATIN(trace)->stats_valid & 2) 
244                || (FORMATIN(trace)->stats_valid == 0)) {
245                ioctl(FORMATIN(trace)->fd, BIOCGSTATS, &FORMATIN(trace)->stats);
246                FORMATIN(trace)->stats_valid |= 2;
247        }
248
249        return FORMATIN(trace)->stats.bs_drop;
250}
251
252static int bpf_pause_input(libtrace_t *libtrace)
253{
254        close(FORMATIN(libtrace)->fd);
255        FORMATIN(libtrace)->fd=-1;
256
257        return 0;
258}
259
260static int bpf_fin_input(libtrace_t *libtrace) 
261{
262        free(libtrace->format_data);
263        return 0;
264}
265
266static int bpf_config_input(libtrace_t *libtrace,
267                trace_option_t option,
268                void *data)
269{
270        switch(option) {
271                case TRACE_OPTION_SNAPLEN:
272                        FORMATIN(libtrace)->snaplen=*(int*)data;
273                        return 0;
274                case TRACE_OPTION_PROMISC:
275                        FORMATIN(libtrace)->promisc=*(int*)data;
276                        return 0;
277                case TRACE_OPTION_FILTER:
278                        /* We don't support bpf filters in any special way
279                         * so return an error and let libtrace deal with
280                         * emulating it
281                         */
282                        break;
283                case TRACE_OPTION_META_FREQ:
284                        /* No meta-data for this format */
285                        break;
286                case TRACE_OPTION_EVENT_REALTIME:
287                        /* captures are always realtime */
288                        break;
289
290                /* Avoid default: so that future options will cause a warning
291                 * here to remind us to implement it, or flag it as
292                 * unimplementable
293                 */
294        }
295        trace_set_err(libtrace,TRACE_ERR_UNKNOWN_OPTION,
296                        "Unknown option %i", option);
297        return -1;
298}
299
300static int bpf_prepare_packet(libtrace_t *libtrace, libtrace_packet_t *packet,
301                void *buffer, libtrace_rt_types_t rt_type, uint32_t flags) {
302        if (packet->buffer != buffer &&
303                        packet->buf_control == TRACE_CTRL_PACKET) {
304                free(packet->buffer);
305        }
306
307        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
308                packet->buf_control = TRACE_CTRL_PACKET;
309        } else
310                packet->buf_control = TRACE_CTRL_EXTERNAL;
311
312
313        packet->buffer = buffer;
314        packet->header = buffer;
315        packet->type = rt_type;
316
317        /* Find the payload */
318        /* TODO: Pcap deals with a padded FDDI linktype here */
319        packet->payload=(char *)buffer + BPFHDR(packet)->bh_hdrlen;
320
321        if (libtrace->format_data == NULL) {
322                if (bpf_init_input(libtrace))
323                        return -1;
324        }
325
326        return 0;
327}
328       
329static int bpf_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) 
330{
331        uint32_t flags = 0;
332       
333        /* Fill the buffer */
334        if (FORMATIN(libtrace)->remaining<=0) {
335                int ret;
336
337                ret=read(FORMATIN(libtrace)->fd,
338                        FORMATIN(libtrace)->buffer,
339                        FORMATIN(libtrace)->buffersize);
340
341                if (ret == -1) {
342                        trace_set_err(libtrace,errno,"Failed to read");
343                        return -1;
344                }
345
346                if (ret == 0) {
347                        /* EOF */
348                        return 0;
349                }
350
351                FORMATIN(libtrace)->remaining=ret;
352                FORMATIN(libtrace)->bufptr=
353                                FORMATIN(libtrace)->buffer;
354        }
355
356        /* Read one packet out */
357       
358        if (packet->buf_control == TRACE_CTRL_PACKET)
359                free(packet->buffer);
360
361        if (bpf_prepare_packet(libtrace, packet, FORMATIN(libtrace)->bufptr,
362                TRACE_RT_DATA_BPF, flags)) {
363                return -1;
364        }
365       
366
367        /* Now deal with any padding */
368        FORMATIN(libtrace)->bufptr+=
369                BPF_WORDALIGN(BPFHDR(packet)->bh_hdrlen
370                +BPFHDR(packet)->bh_caplen);
371        FORMATIN(libtrace)->remaining-=
372                BPF_WORDALIGN(BPFHDR(packet)->bh_hdrlen
373                +BPFHDR(packet)->bh_caplen);
374
375        return BPFHDR(packet)->bh_datalen+BPFHDR(packet)->bh_hdrlen;
376}
377
378static libtrace_linktype_t bpf_get_link_type(const libtrace_packet_t *packet) {
379        return pcap_linktype_to_libtrace(FORMATIN(packet->trace)->linktype);
380}
381
382static libtrace_direction_t bpf_get_direction(const libtrace_packet_t *packet) {
383        /* BPF Sadly can't do direction tagging */
384        return ~0;
385}
386
387static struct timeval bpf_get_timeval(const libtrace_packet_t *packet) 
388{
389        struct timeval tv;
390        tv=BPFHDR(packet)->bh_tstamp;
391        return tv;
392}
393
394static int bpf_get_capture_length(const libtrace_packet_t *packet)
395{
396        /* BPF Doesn't include the FCS, we do. */
397        return BPFHDR(packet)->bh_caplen+4;
398}
399
400static int bpf_get_wire_length(const libtrace_packet_t *packet) 
401{
402        return BPFHDR(packet)->bh_datalen+4;
403}
404
405static int bpf_get_framing_length(UNUSED
406                const libtrace_packet_t *packet) 
407{
408        return BPFHDR(packet)->bh_hdrlen;
409}
410
411static int bpf_get_fd(const libtrace_t *trace) {
412        return FORMATIN(trace)->fd;
413}
414
415static void bpf_help() {
416        printf("bpf format module: $Revision$\n");
417        printf("Supported input URIs:\n");
418        printf("\tbpf:\n");
419        printf("\n");
420        return;
421}
422static struct libtrace_format_t bpf = {
423        "bpf",
424        "$Id$",
425        TRACE_FORMAT_BPF,
426        bpf_init_input,         /* init_input */
427        bpf_config_input,       /* config_input */
428        bpf_start_input,        /* start_input */
429        bpf_pause_input,        /* pause_input */
430        NULL,                   /* init_output */
431        NULL,                   /* config_output */
432        NULL,                   /* start_ouput */
433        bpf_fin_input,          /* fin_input */
434        NULL,                   /* fin_output */
435        bpf_read_packet,        /* read_packet */
436        bpf_prepare_packet,     /* prepare_packet */
437        NULL,                   /* fin_packet */
438        NULL,                   /* write_packet */
439        bpf_get_link_type,      /* get_link_type */
440        bpf_get_direction,      /* get_direction */
441        NULL,                   /* set_direction */
442        NULL,                   /* get_erf_timestamp */
443        bpf_get_timeval,        /* get_timeval */
444        NULL,                   /* get_seconds */
445        NULL,                   /* seek_erf */
446        NULL,                   /* seek_timeval */
447        NULL,                   /* seek_seconds */
448        bpf_get_capture_length, /* get_capture_length */
449        bpf_get_wire_length,    /* get_wire_length */
450        bpf_get_framing_length, /* get_framing_length */
451        NULL,                   /* set_capture_length */
452        bpf_get_received_packets,/* get_received_packets */
453        NULL,                   /* get_filtered_packets */
454        bpf_get_dropped_packets,/* get_dropped_packets */
455        NULL,                   /* get_captured_packets */
456        bpf_get_fd,             /* get_fd */
457        trace_event_device,     /* trace_event */
458        bpf_help,               /* help */
459        NULL
460};
461
462void bpf_constructor() {
463        register_format(&bpf);
464}
Note: See TracBrowser for help on using the repository browser.