source: lib/format_bpf.c @ 5952ff0

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 5952ff0 was 5952ff0, checked in by Shane Alcock <salcock@…>, 11 years ago
  • Updated internal documentation and licensing for several format modules
  • Property mode set to 100644
File size: 16.0 KB
RevLine 
[755e794]1/*
2 * This file is part of libtrace
3 *
[5952ff0]4 * Copyright (c) 2007,2008,2009,2010 The University of Waikato, Hamilton,
5 * New Zealand.
6 *
7 * Authors: Daniel Lawson
8 *          Perry Lorier
9 *          Shane Alcock
[755e794]10 *         
11 * All rights reserved.
12 *
13 * This code has been developed by the University of Waikato WAND
14 * research group. For further information please see http://www.wand.net.nz/
15 *
16 * libtrace is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * libtrace is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with libtrace; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29 *
[293999b]30 * $Id$
[755e794]31 *
32 */
33
34#include "libtrace.h"
35#include "libtrace_int.h"
36#include "format_helper.h"
37#include "config.h"
38#include "stdlib.h"
39
40#ifdef HAVE_INTTYPES_H
41#  include <inttypes.h>
42#else
43# error "Can't find inttypes.h"
44#endif
45
46#include <sys/socket.h>
47
48#include <sys/types.h>
49#include <sys/time.h>
50#include <sys/ioctl.h>
51
52#include <string.h>
53#include <net/if.h>
54#include <sys/ioctl.h>
55#include <errno.h>
56#include <fcntl.h>
57
[5952ff0]58/* This format deals with the BSD Native capture format, perhaps better
59 * known as BPF, which is the equivalent of the Linux Native format for
60 * *BSD systems.
61 *
62 * This is a LIVE capture format - we're always dealing with reading from an
63 * interface.
64 *
65 * This format does not support writing, but BPF packet records can be easily
66 * converted to PCAP or ERF.
67 */ 
[755e794]68
[5952ff0]69/* "Global" data that is stored for each BPF input trace */
[755e794]70struct libtrace_format_data_t {
[5952ff0]71        /* The file descriptor that is being captured from */
72        int fd; 
73        /* The snap length for the capture */
[755e794]74        int snaplen;
[5952ff0]75        /* A boolean flag indicating whether the capture interface should be
76         * in promiscuous mode */ 
[755e794]77        int promisc;
[5952ff0]78        /* A buffer to write captured data into */
[755e794]79        void *buffer;
[5952ff0]80        /* The current read location in the capture buffer */
[755e794]81        void *bufptr;
[5952ff0]82        /* The total size of the capture buffer */
[755e794]83        unsigned int buffersize;
[5952ff0]84        /* The amount of space remaining before the capture buffer is full */
[755e794]85        int remaining;
[5952ff0]86        /* The linktype of the capture interface */ 
[73dd29f]87        unsigned int linktype;
[5952ff0]88        /* Statistics about how many packets have been dropped, received etc. */
[50bbce8]89        struct bpf_stat stats;
[5952ff0]90        /* A boolean flag indicating whether the statistics are up-to-date */
[50bbce8]91        int stats_valid;
[755e794]92};
93
94#define FORMATIN(x) ((struct libtrace_format_data_t*)((x->format_data)))
95
96#define BPFHDR(x) ((struct bpf_hdr *)((x)->header))
97
[5952ff0]98/* Attempts to determine if a given filename could refer to a BPF interface */
[ed3820e]99static int bpf_probe_filename(const char *filename)
100{
101        return (if_nametoindex(filename) != 0);
102}
103
[5952ff0]104/* XXX This function doesn't appear to be used anywhere - nor does it do
105 * anything particularly useful :) */
[91b72d3]106static int bpf_start_filename(const char *filename)
107{
108        return 0;
109}
110
[5952ff0]111/* Initialises a BPF input trace */
[755e794]112static int bpf_init_input(libtrace_t *libtrace) 
113{
114        libtrace->format_data = (struct libtrace_format_data_t *)
115                malloc(sizeof(struct libtrace_format_data_t));
[5952ff0]116       
117        /* Throw some default values into the format data */
[755e794]118        FORMATIN(libtrace)->fd = -1;
119        FORMATIN(libtrace)->promisc = 0;
120        FORMATIN(libtrace)->snaplen = 65536;
[50bbce8]121        FORMATIN(libtrace)->stats_valid = 0;
[755e794]122
123        return 0;
124}
125
[5952ff0]126/* Starts a BPF input trace */
[755e794]127static int bpf_start_input(libtrace_t *libtrace)
128{
129        int bpfid=0;
130        struct bpf_version bv;
131        struct ifreq ifr;
132        unsigned int v;
133
134        /* Find and open a bpf device */
135        do {
136                char buffer[64];
137                snprintf(buffer,sizeof(buffer),"/dev/bpf%d", bpfid);
138                bpfid++;
139               
140                FORMATIN(libtrace)->fd = open(buffer, O_RDONLY);
141        } while(FORMATIN(libtrace)->fd == -1 && errno == EBUSY);
142
143        if (FORMATIN(libtrace)->fd == -1) {
144                trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,
145                                "No free bpf devices");
146                return -1;
147        }
148
149        /* Check the BPF Version is ok */
150        if (ioctl(FORMATIN(libtrace)->fd, BIOCVERSION, &bv) == -1) {
151                trace_set_err(libtrace,errno,
152                                "Failed to read the bpf version");
153                close(FORMATIN(libtrace)->fd);
154                return -1;
155        }
156
157        if (bv.bv_major != BPF_MAJOR_VERSION) {
158                trace_set_err(libtrace,errno, 
159                        "Unknown kernel BPF version (%d.%d, libtrace requires at least %d.%d)",
160                        bv.bv_major,
161                        bv.bv_minor,
162                        BPF_MAJOR_VERSION,
163                        BPF_MINOR_VERSION);
164                close(FORMATIN(libtrace)->fd);
165                return -1;
166        }
167
168        if (bv.bv_minor < BPF_MINOR_VERSION) {
169                trace_set_err(libtrace,errno, "Kernel version too old (%d.%d, libtrace requires at least %d.%d)",
170                        bv.bv_major,
171                        bv.bv_minor,
172                        BPF_MAJOR_VERSION,
173                        BPF_MINOR_VERSION);
174                close(FORMATIN(libtrace)->fd);
175                return -1;
176        }
177
178        /* We assume the default kernel buffer size is sufficient. */
179        if (ioctl(FORMATIN(libtrace)->fd, BIOCGBLEN,
180                        &FORMATIN(libtrace)->buffersize)==-1) {
181                trace_set_err(libtrace,errno,"Failed to find buffer length");
182                close(FORMATIN(libtrace)->fd);
183                return -1;
184        }
185
186        FORMATIN(libtrace)->buffer = malloc(FORMATIN(libtrace)->buffersize);
187        FORMATIN(libtrace)->bufptr = FORMATIN(libtrace)->buffer;
188        FORMATIN(libtrace)->remaining = 0;
189
[5952ff0]190        /* Attach to the device */
[755e794]191        strncpy(ifr.ifr_name, libtrace->uridata, sizeof(ifr.ifr_name));
192        if (ioctl(FORMATIN(libtrace)->fd, BIOCSETIF, &ifr) == -1) {
193                trace_set_err(libtrace,errno,"Failed to attach");
194                close(FORMATIN(libtrace)->fd);
195                return -1;
196        }
197
[5952ff0]198        /* Set the link type */
[755e794]199        if (ioctl(FORMATIN(libtrace)->fd, BIOCGDLT,
[73dd29f]200                         &FORMATIN(libtrace)->linktype) == -1) {
[755e794]201                trace_set_err(libtrace,errno,"Failed to retrieve link type");
202                close(FORMATIN(libtrace)->fd);
203                return -1;
204        }
205       
206        /* TODO: If BIOCGDLTLIST exists then we should perhaps do something
207         *       with it.  We don't have the same concept of multiple DLT's
208         *       as pcap does.  We grab the rawest possible thing and then
209         *       decode packets by understanding the protocols.  So perhaps
210         *       we should setup a rating of DLT's that we'll prefer in order.
211         *       For example we should try and get 802.11 frames rather than
212         *       802.3 frames.  The general rule should be "whatever actually
213         *       went over the air", although of course if we don't support
214         *       what went over the air we should fall back to something we
215         *       /do/ support.
216         */
217       
218        /* Using timeouts seems sucky.  We'll always use immediate mode.  We
219         * pray the kernel is smart enough that if a another packet arrives
220         * while we're processing this one that it will buffer them into it's
[5952ff0]221         * kernel buffer so we can receive packets later. (It'll need to do this
[755e794]222         * to deal with us spending time processing the last 'n' packets anyway)
223         */
224       
225        v=1;
226        if (ioctl(FORMATIN(libtrace)->fd, BIOCIMMEDIATE, &v) == -1) {
227                trace_set_err(libtrace,errno,"Failed to set immediate mode");
228                close(FORMATIN(libtrace)->fd);
229                return -1;
230        }
231
[5952ff0]232        /* Set promiscous mode, if the user has asked us to do so */
[755e794]233        if (FORMATIN(libtrace)->promisc) {
234                if (ioctl(FORMATIN(libtrace)->fd, BIOCPROMISC, NULL) == -1) {
235                        trace_set_err(libtrace,errno,
236                                "Failed to set promisc mode");
237                        close(FORMATIN(libtrace)->fd);
238                        return -1;
239
240                }
241        }
242
[50bbce8]243        FORMATIN(libtrace)->stats_valid = 0;
244
[755e794]245        /* TODO: we should always set a bpf filter for snapping */
246
247        /* We're done! */
248        return 0;
249}
250
[5952ff0]251/* Gets a count of the number of packets received on the BPF interface */
[50bbce8]252static uint64_t bpf_get_received_packets(libtrace_t *trace)
253{
[f0fb38f]254        if (trace->format_data == NULL)
255                return (uint64_t)-1;
256
257        if (FORMATIN(trace)->fd == -1) {
258                /* Almost certainly a 'dead' trace so there is no socket
259                 * for us to query */
260                return (uint64_t) -1;
261        }
[50bbce8]262        /* If we're called with stats_valid == 0, or we're called again
263         * then refresh the stats.  Don't refresh the stats if we're called
264         * immediately after get_dropped_packets
265         */
[95fee28]266        if ((FORMATIN(trace)->stats_valid & 1)
267                || (FORMATIN(trace)->stats_valid == 0)) {
[50bbce8]268                ioctl(FORMATIN(trace)->fd, BIOCGSTATS, &FORMATIN(trace)->stats);
[95fee28]269                FORMATIN(trace)->stats_valid |= 1;
[50bbce8]270        }
271
272        return FORMATIN(trace)->stats.bs_recv;
273}
274
[5952ff0]275/* Gets a count of the number of packets dropped on the BPF interface */
[50bbce8]276static uint64_t bpf_get_dropped_packets(libtrace_t *trace)
277{
[f0fb38f]278        if (trace->format_data == NULL)
279                return (uint64_t)-1;
280
281        if (FORMATIN(trace)->fd == -1) {
282                /* Almost certainly a 'dead' trace so there is no socket
283                 * for us to query */
284                return (uint64_t) -1;
285        }
[50bbce8]286        /* If we're called with stats_valid == 0, or we're called again
287         * then refresh the stats.  Don't refresh the stats if we're called
288         * immediately after get_received_packets
289         */
[95fee28]290        if ((FORMATIN(trace)->stats_valid & 2) 
291                || (FORMATIN(trace)->stats_valid == 0)) {
[50bbce8]292                ioctl(FORMATIN(trace)->fd, BIOCGSTATS, &FORMATIN(trace)->stats);
[95fee28]293                FORMATIN(trace)->stats_valid |= 2;
[50bbce8]294        }
295
296        return FORMATIN(trace)->stats.bs_drop;
297}
298
[5952ff0]299/* Pauses a BPF input trace */
[755e794]300static int bpf_pause_input(libtrace_t *libtrace)
301{
302        close(FORMATIN(libtrace)->fd);
303        FORMATIN(libtrace)->fd=-1;
304
305        return 0;
306}
307
[5952ff0]308/* Closes a BPF input trace */
[755e794]309static int bpf_fin_input(libtrace_t *libtrace) 
310{
311        free(libtrace->format_data);
312        return 0;
313}
314
[5952ff0]315/* Configures a BPF input trace */
[755e794]316static int bpf_config_input(libtrace_t *libtrace,
317                trace_option_t option,
318                void *data)
319{
320        switch(option) {
321                case TRACE_OPTION_SNAPLEN:
322                        FORMATIN(libtrace)->snaplen=*(int*)data;
323                        return 0;
324                case TRACE_OPTION_PROMISC:
325                        FORMATIN(libtrace)->promisc=*(int*)data;
326                        return 0;
327                case TRACE_OPTION_FILTER:
328                        /* We don't support bpf filters in any special way
329                         * so return an error and let libtrace deal with
330                         * emulating it
331                         */
332                        break;
[57f7965]333                case TRACE_OPTION_META_FREQ:
[755e794]334                        /* No meta-data for this format */
335                        break;
[57f7965]336                case TRACE_OPTION_EVENT_REALTIME:
[5952ff0]337                        /* Captures are always realtime */
[57f7965]338                        break;
339
[755e794]340                /* Avoid default: so that future options will cause a warning
341                 * here to remind us to implement it, or flag it as
342                 * unimplementable
343                 */
344        }
345        trace_set_err(libtrace,TRACE_ERR_UNKNOWN_OPTION,
346                        "Unknown option %i", option);
347        return -1;
348}
349
[5952ff0]350/* Converts a buffer containing a recently read BPF packet record into a
351 * libtrace packet */
[f0fb38f]352static int bpf_prepare_packet(libtrace_t *libtrace, libtrace_packet_t *packet,
353                void *buffer, libtrace_rt_types_t rt_type, uint32_t flags) {
[5952ff0]354       
355        /* If the packet previously owned a buffer that is not the buffer
356         * that contains the new packet data, we're going to need to free the
357         * old one to avoid memory leaks */
358        if (packet->buffer != buffer &&
[f0fb38f]359                        packet->buf_control == TRACE_CTRL_PACKET) {
360                free(packet->buffer);
361        }
362
[5952ff0]363        /* Set the buffer owner appropriately */
[f0fb38f]364        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
365                packet->buf_control = TRACE_CTRL_PACKET;
366        } else
367                packet->buf_control = TRACE_CTRL_EXTERNAL;
368
[5952ff0]369        /* Update the packet pointers and type appropriately */
[f0fb38f]370        packet->buffer = buffer;
371        packet->header = buffer;
372        packet->type = rt_type;
373
374        /* Find the payload */
375        /* TODO: Pcap deals with a padded FDDI linktype here */
376        packet->payload=(char *)buffer + BPFHDR(packet)->bh_hdrlen;
377
378        if (libtrace->format_data == NULL) {
379                if (bpf_init_input(libtrace))
380                        return -1;
381        }
382
383        return 0;
384}
[5952ff0]385
386/* Reads the next packet record from a BPF interface and writes it into a
387 * libtrace packet */   
[755e794]388static int bpf_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) 
389{
[f0fb38f]390        uint32_t flags = 0;
391       
[5952ff0]392        /* Read from the BPF interface into our capture buffer */
[755e794]393        if (FORMATIN(libtrace)->remaining<=0) {
394                int ret;
395
396                ret=read(FORMATIN(libtrace)->fd,
397                        FORMATIN(libtrace)->buffer,
398                        FORMATIN(libtrace)->buffersize);
399
400                if (ret == -1) {
401                        trace_set_err(libtrace,errno,"Failed to read");
402                        return -1;
403                }
404
405                if (ret == 0) {
406                        /* EOF */
407                        return 0;
408                }
409
410                FORMATIN(libtrace)->remaining=ret;
411                FORMATIN(libtrace)->bufptr=
412                                FORMATIN(libtrace)->buffer;
413        }
[5952ff0]414
415        /* We do NOT want anything trying to free the memory the packet is
416         * stored in */
[c0dba7a]417        flags |= TRACE_PREP_DO_NOT_OWN_BUFFER;
[5952ff0]418
[755e794]419        if (packet->buf_control == TRACE_CTRL_PACKET)
420                free(packet->buffer);
421
[5952ff0]422        /* Update 'packet' to point to the first packet in our capture
423         * buffer */
[f0fb38f]424        if (bpf_prepare_packet(libtrace, packet, FORMATIN(libtrace)->bufptr,
425                TRACE_RT_DATA_BPF, flags)) {
426                return -1;
427        }
428       
[755e794]429
[5952ff0]430        /* Skip past the packet record we're going to return, making sure
431         * that we deal with padding correctly */
[755e794]432        FORMATIN(libtrace)->bufptr+=
433                BPF_WORDALIGN(BPFHDR(packet)->bh_hdrlen
434                +BPFHDR(packet)->bh_caplen);
435        FORMATIN(libtrace)->remaining-=
436                BPF_WORDALIGN(BPFHDR(packet)->bh_hdrlen
437                +BPFHDR(packet)->bh_caplen);
438
439        return BPFHDR(packet)->bh_datalen+BPFHDR(packet)->bh_hdrlen;
440}
441
[5952ff0]442/* Returns the linktype for the interface that we are capturing from */
[755e794]443static libtrace_linktype_t bpf_get_link_type(const libtrace_packet_t *packet) {
[5952ff0]444        /* Convert the linktype that we recorded when we started the trace
445         * into a suitable libtrace linktype */
[73dd29f]446        return pcap_linktype_to_libtrace(FORMATIN(packet->trace)->linktype);
[755e794]447}
448
[5952ff0]449/* Returns the direction for a given BPF packet record */
[755e794]450static libtrace_direction_t bpf_get_direction(const libtrace_packet_t *packet) {
[5952ff0]451        /* BPF sadly can't do direction tagging */
[755e794]452        return ~0;
453}
454
[5952ff0]455/* Returns the timestamp for a given BPF packet record, in the form of a
456 * struct timeval */
[755e794]457static struct timeval bpf_get_timeval(const libtrace_packet_t *packet) 
458{
459        struct timeval tv;
[c0dba7a]460        /* OpenBSD uses a bpf_timeval rather than a timeval so we must copy
461         * each timeval element individually rather than doing a structure
462         * assignment */
463        tv.tv_sec = BPFHDR(packet)->bh_tstamp.tv_sec;
464        tv.tv_usec = BPFHDR(packet)->bh_tstamp.tv_usec;
465
[755e794]466        return tv;
467}
468
[5952ff0]469/* Returns the capture length for a given BPF packet record */
[755e794]470static int bpf_get_capture_length(const libtrace_packet_t *packet)
471{
[5952ff0]472        /* BPF doesn't include the FCS in its caplen field, but libtrace
473         * does so we need to add this extra 4 bytes */
[755e794]474        return BPFHDR(packet)->bh_caplen+4;
475}
476
[5952ff0]477/* Returns the wire length for a given BPF packet record */
[755e794]478static int bpf_get_wire_length(const libtrace_packet_t *packet) 
479{
[5952ff0]480
481        /* BPF doesn't include the FCS in its datalen field, but libtrace
482         * does so we need to add this extra 4 bytes */
[755e794]483        return BPFHDR(packet)->bh_datalen+4;
484}
485
[5952ff0]486/* Returns the framing length for a given BPF packet record */
[755e794]487static int bpf_get_framing_length(UNUSED
488                const libtrace_packet_t *packet) 
489{
490        return BPFHDR(packet)->bh_hdrlen;
491}
492
[5952ff0]493/* Returns the file descriptor that the capture interface is operating on */
[755e794]494static int bpf_get_fd(const libtrace_t *trace) {
495        return FORMATIN(trace)->fd;
496}
497
[5952ff0]498/* Prints some slightly useful help text for the BPF capture format */
[755e794]499static void bpf_help() {
500        printf("bpf format module: $Revision$\n");
501        printf("Supported input URIs:\n");
502        printf("\tbpf:\n");
503        printf("\n");
504        return;
505}
506static struct libtrace_format_t bpf = {
507        "bpf",
[293999b]508        "$Id$",
[755e794]509        TRACE_FORMAT_BPF,
[099c35e]510        //bpf_probe_filename,   /* probe filename */
511        NULL,
[91b72d3]512        NULL,                   /* probe magic */
[755e794]513        bpf_init_input,         /* init_input */
514        bpf_config_input,       /* config_input */
515        bpf_start_input,        /* start_input */
516        bpf_pause_input,        /* pause_input */
517        NULL,                   /* init_output */
518        NULL,                   /* config_output */
519        NULL,                   /* start_ouput */
520        bpf_fin_input,          /* fin_input */
521        NULL,                   /* fin_output */
522        bpf_read_packet,        /* read_packet */
[f0fb38f]523        bpf_prepare_packet,     /* prepare_packet */
[755e794]524        NULL,                   /* fin_packet */
525        NULL,                   /* write_packet */
526        bpf_get_link_type,      /* get_link_type */
527        bpf_get_direction,      /* get_direction */
528        NULL,                   /* set_direction */
529        NULL,                   /* get_erf_timestamp */
530        bpf_get_timeval,        /* get_timeval */
[1aa4bf7]531        NULL,                   /* get_timespec */
[755e794]532        NULL,                   /* get_seconds */
533        NULL,                   /* seek_erf */
534        NULL,                   /* seek_timeval */
535        NULL,                   /* seek_seconds */
536        bpf_get_capture_length, /* get_capture_length */
537        bpf_get_wire_length,    /* get_wire_length */
538        bpf_get_framing_length, /* get_framing_length */
539        NULL,                   /* set_capture_length */
[50bbce8]540        bpf_get_received_packets,/* get_received_packets */
[f2fae49]541        NULL,                   /* get_filtered_packets */
[50bbce8]542        bpf_get_dropped_packets,/* get_dropped_packets */
[f2fae49]543        NULL,                   /* get_captured_packets */
[755e794]544        bpf_get_fd,             /* get_fd */
545        trace_event_device,     /* trace_event */
546        bpf_help,               /* help */
547        NULL
548};
549
550void bpf_constructor() {
551        register_format(&bpf);
552}
Note: See TracBrowser for help on using the repository browser.