source: lib/format_linux.c @ f240823

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since f240823 was f240823, checked in by Richard Sanger <rjs51@…>, 9 years ago

Added in a working trace_event handler, Shanes tests showed the default handler was not working for PACKET_MMAP. Also fixed minor calculate_buffers bugs resulting in larger buffer allocation then needed.

  • Property mode set to 100644
File size: 43.6 KB
Line 
1/*
2 * This file is part of libtrace
3 *
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
10 *          Richard Sanger
11 *         
12 * All rights reserved.
13 *
14 * This code has been developed by the University of Waikato WAND
15 * research group. For further information please see http://www.wand.net.nz/
16 *
17 * libtrace is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * libtrace is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with libtrace; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
30 *
31 * $Id$
32 *
33 */
34
35
36#include "libtrace.h"
37#include "libtrace_int.h"
38#include "format_helper.h"
39#include "config.h"
40#include <stdlib.h>
41
42#ifdef HAVE_INTTYPES_H
43#  include <inttypes.h>
44#else
45# error "Can't find inttypes.h"
46#endif
47
48#include <sys/socket.h>
49#include <netpacket/packet.h>
50#include <net/ethernet.h>
51#include <net/if_arp.h>
52
53#include <string.h>
54#include <net/if.h>
55#include <sys/ioctl.h>
56#include <errno.h>
57#include <unistd.h>
58
59#include <assert.h>
60
61#include <poll.h>
62#include <sys/mman.h>
63
64/* This format module deals with using the Linux Native capture format.
65 *
66 * Linux Native is a LIVE capture format.
67 *
68 * This format also supports writing which will write packets out to the
69 * network as a form of packet replay. This should not be confused with the
70 * RT protocol which is intended to transfer captured packet records between
71 * RT-speaking programs.
72 */
73
74/* Declared in linux/if_arp.h but not in net/if_arp.h sigh */
75#ifndef ARPHRD_NONE
76#define ARPHRD_NONE 0xfffe
77#endif
78
79struct tpacket_stats {
80        unsigned int tp_packets;
81        unsigned int tp_drops;
82};
83
84typedef enum { TS_NONE, TS_TIMEVAL, TS_TIMESPEC } timestamptype_t;
85
86/* linux/if_packet.h defines. They are here rather than including the header
87 * this means that we can interpret a ring frame on a kernel that doesn't
88 * support the format directly.
89 */
90#define PACKET_RX_RING  5
91#define PACKET_VERSION  10
92#define PACKET_HDRLEN   11
93#define PACKET_TX_RING  13
94#define TP_STATUS_USER  0x1
95#define TP_STATUS_SEND_REQUEST  0x1
96#define TP_STATUS_AVAILABLE     0x0
97#define TO_TP_HDR(x)    ((struct tpacket2_hdr *) (x))
98#define TPACKET_ALIGNMENT       16
99#define TPACKET_ALIGN(x)        (((x)+TPACKET_ALIGNMENT-1)&~(TPACKET_ALIGNMENT-1))
100#define TPACKET2_HDRLEN         (TPACKET_ALIGN(sizeof(struct tpacket2_hdr)) + sizeof(struct sockaddr_ll))
101
102enum tpacket_versions {
103        TPACKET_V1,
104        TPACKET_V2
105};
106
107struct tpacket2_hdr {
108        /* Frame status - in use by kernel or libtrace etc. */
109        __u32   tp_status;
110        /* Wire length */
111        __u32   tp_len;
112        /* Captured length */
113        __u32   tp_snaplen;
114        /* Offset in bytes from frame start to the mac (link layer) header */
115        __u16   tp_mac;
116        /* Offset in bytes from frame start to the net (network layer) header */
117        __u16   tp_net;
118        /* Timestamp */
119        __u32   tp_sec;
120        __u32   tp_nsec;
121        /* Not used VLAN tag control information */
122        __u16   tp_vlan_tci;
123        __u16   tp_padding;
124};
125
126struct tpacket_req {
127        unsigned int tp_block_size;  /* Minimal size of contiguous block */
128        unsigned int tp_block_nr;    /* Number of blocks */
129        unsigned int tp_frame_size;  /* Size of frame */
130        unsigned int tp_frame_nr;    /* Total number of frames */
131};
132
133struct linux_format_data_t {
134        /* The file descriptor being used for the capture */
135        int fd;
136        /* The snap length for the capture */
137        int snaplen;
138        /* Flag indicating whether the interface should be placed in
139         * promiscuous mode */
140        int promisc;
141        /* The timestamp format used by the capture */ 
142        timestamptype_t timestamptype;
143        /* A BPF filter that is applied to every captured packet */
144        libtrace_filter_t *filter;
145        /* Statistics for the capture process, e.g. dropped packet counts */
146        struct tpacket_stats stats;
147        /* Flag indicating whether the statistics are current or not */
148        int stats_valid;
149        /* The rx ring mmap location*/
150        char * rx_ring;
151        /* The current frame number within the rx ring */       
152        int rxring_offset;
153        /* The format this trace is using linuxring or linuxnative */
154        libtrace_rt_types_t format;
155        /* The current ring buffer layout */
156        struct tpacket_req req;
157};
158
159
160/* Note that this structure is passed over the wire in rt encapsulation, and
161 * thus we need to be careful with data sizes.  timeval's and timespec's
162 * can also change their size on 32/64 machines.
163 */
164
165/* Format header for encapsulating packets captured using linux native */
166struct libtrace_linuxnative_header {
167        /* Timestamp of the packet, as a timeval */
168        struct {
169                uint32_t tv_sec;
170                uint32_t tv_usec;
171        } tv;
172        /* Timestamp of the packet, as a timespec */
173        struct {
174                uint32_t tv_sec;
175                uint32_t tv_nsec;
176        } ts;
177        /* The timestamp format used by the process that captured this packet */
178        uint8_t timestamptype;
179        /* Wire length */
180        uint32_t wirelen;
181        /* Capture length */
182        uint32_t caplen;
183        /* The linux native header itself */
184        struct sockaddr_ll hdr;
185};
186
187struct linux_output_format_data_t {
188        /* The file descriptor used to write the packets */
189        int fd;
190        /* The tx ring mmap location */
191        char * tx_ring;
192        /* The current frame number within the tx ring */       
193        int txring_offset;
194        /* The current ring buffer layout */
195        struct tpacket_req req;
196        /* Our sockaddr structure, here so we can cache the interface number */
197        struct sockaddr_ll sock_hdr;
198        /* The (maximum) number of packets that haven't been written */
199        int queue;
200        /* The format this trace is using linuxring or linuxnative */
201        libtrace_rt_types_t format;
202};
203
204/* MAX_ORDER is defined in linux/mmzone.h. 10 is default for 2.4 kernel.
205 * max_order will be decreased by one if the ring buffer fails to allocate.
206 * Used to get correct sized buffers from the kernel.
207 */
208#define MAX_ORDER 10
209static unsigned int max_order = MAX_ORDER;
210
211/* Cached page size, the page size shoudn't be changing */
212static int pagesize = 0;
213
214/* Number of frames in the ring used by both TX and TR rings. More frames
215 * hopefully means less packet loss, especially if traffic comes in bursts.
216 */
217#define CONF_RING_FRAMES        0x100
218
219/* The maximum frames allowed to be waiting in the TX_RING before the kernel is
220 * notified to write them out. Make sure this is less than CONF_RING_FRAMES.
221 * Performance doesn't seem to increase any more when setting this above 10.
222 */
223#define TX_MAX_QUEUE            10
224
225/* Get the start of the captured data. I'm not sure if tp_mac (link layer) is
226 * always guaranteed. If it's not there then just use tp_net.
227 */
228#define TP_TRACE_START(mac, net, hdrend) \
229        ((mac) > (hdrend) && (mac) < (net) ? (mac) : (net))
230
231/* Get current frame in the ring buffer*/
232#define GET_CURRENT_BUFFER(libtrace) ((void *) FORMAT(libtrace->format_data)->rx_ring + \
233        (FORMAT(libtrace->format_data)->rxring_offset * FORMAT(libtrace->format_data)->req.tp_frame_size))
234
235/* Get the sockaddr_ll structure from a frame */
236#define GET_SOCKADDR_HDR(x)  ((struct sockaddr_ll *) (((char *) (x))\
237        + TPACKET_ALIGN(sizeof(struct tpacket2_hdr))))
238
239#define TPACKET_HDRLEN TPACKET2_HDRLEN
240
241#define FORMAT(x) ((struct linux_format_data_t*)(x))
242#define DATAOUT(x) ((struct linux_output_format_data_t*)((x)->format_data))
243
244
245/*
246 * Try figure out the best sizes for the ring buffer. Ensure that:
247 * - max(Block_size) == page_size << max_order
248 * - Frame_size == page_size << x (so that block_size%frame_size == 0)
249 *   This means that there will be no wasted space between blocks
250 * - Frame_size < block_size
251 * - Frame_size is as close as possible to LIBTRACE_PACKET_BUFSIZE, but not
252 *   bigger
253 * - Frame_nr = Block_nr * (frames per block)
254 * - CONF_RING_FRAMES is used a minimum number of frames to hold
255 * - Calculates based on max_order and buf_min
256 */
257static void calculate_buffers(struct tpacket_req * req, int fd, char * uri){
258       
259        struct ifreq ifr;
260        unsigned mtu = LIBTRACE_PACKET_BUFSIZE;
261        pagesize = getpagesize();
262
263        /* Don't bother trying to set frame size above mtu linux will drop
264         * these anyway
265         */
266        strcpy(ifr.ifr_name, uri);
267        if (ioctl(fd, SIOCGIFMTU, (caddr_t) &ifr) >= 0) 
268                mtu = ifr.ifr_mtu;
269        if(mtu > LIBTRACE_PACKET_BUFSIZE)
270                mtu = LIBTRACE_PACKET_BUFSIZE;
271
272        /* Calculate frame size */
273        req->tp_frame_size = pagesize;
274        while(req->tp_frame_size < mtu && req->tp_frame_size < LIBTRACE_PACKET_BUFSIZE){
275                req->tp_frame_size <<= 1;
276        }
277        if(req->tp_frame_size > LIBTRACE_PACKET_BUFSIZE)
278                req->tp_frame_size >>= 1;
279
280        /* Calculate block size */
281        req->tp_block_size = pagesize << max_order;
282        do{
283                req->tp_block_size >>= 1;
284        } while((CONF_RING_FRAMES * req->tp_frame_size) <= req->tp_block_size);
285        req->tp_block_size <<= 1;
286       
287        /* Calculate number of blocks */
288        req->tp_block_nr = (CONF_RING_FRAMES * req->tp_frame_size) 
289                        / req->tp_block_size;
290        if((CONF_RING_FRAMES * req->tp_frame_size) % req->tp_block_size != 0)
291                req->tp_block_nr++;
292
293        /* Calculate packets such that we use all the space we have to allocated */
294        req->tp_frame_nr = req->tp_block_nr * 
295                        (req->tp_block_size / req->tp_frame_size);
296
297        /*printf("MaxO 0x%x BS 0x%x BN 0x%x FS 0x%x FN 0x%x\n",
298                max_order,
299                req->tp_block_size,
300                req->tp_block_nr,
301                req->tp_frame_size,
302                req->tp_frame_nr);*/
303       
304        /* In case we have some silly values*/
305        assert(req->tp_block_size);
306        assert(req->tp_block_nr);
307        assert(req->tp_frame_size);
308        assert(req->tp_frame_nr);
309        assert(req->tp_block_size % req->tp_frame_size == 0);
310}
311
312static int linuxnative_probe_filename(const char *filename)
313{
314        /* Is this an interface? */
315        return (if_nametoindex(filename) != 0);
316}
317
318static inline void init_input(libtrace_t *libtrace){
319        libtrace->format_data = (struct linux_format_data_t *)
320                malloc(sizeof(struct linux_format_data_t));
321        FORMAT(libtrace->format_data)->fd = -1;
322        FORMAT(libtrace->format_data)->promisc = -1;
323        FORMAT(libtrace->format_data)->snaplen = LIBTRACE_PACKET_BUFSIZE;
324        FORMAT(libtrace->format_data)->filter = NULL;
325        FORMAT(libtrace->format_data)->stats_valid = 0;
326        FORMAT(libtrace->format_data)->rx_ring = NULL;
327        FORMAT(libtrace->format_data)->rxring_offset = 0;
328}
329static int linuxring_init_input(libtrace_t *libtrace) 
330{       
331        init_input(libtrace);
332        FORMAT(libtrace->format_data)->format = TRACE_FORMAT_LINUX_RING;
333        return 0;
334}
335static int linuxnative_init_input(libtrace_t *libtrace) 
336{
337        init_input(libtrace);
338        FORMAT(libtrace->format_data)->format = TRACE_FORMAT_LINUX_NATIVE;
339        return 0;
340}
341
342static inline void init_output(libtrace_out_t *libtrace)
343{
344        libtrace->format_data = (struct linux_output_format_data_t*)
345                malloc(sizeof(struct linux_output_format_data_t));
346        DATAOUT(libtrace)->fd = -1;
347        DATAOUT(libtrace)->tx_ring = NULL;
348        DATAOUT(libtrace)->txring_offset = 0;
349        DATAOUT(libtrace)->queue = 0;
350}
351static int linuxnative_init_output(libtrace_out_t *libtrace)
352{
353        init_output(libtrace);
354        DATAOUT(libtrace)->format = TRACE_FORMAT_LINUX_NATIVE;
355        return 0;
356}
357static int linuxring_init_output(libtrace_out_t *libtrace)
358{
359        init_output(libtrace);
360        DATAOUT(libtrace)->format = TRACE_FORMAT_LINUX_RING;
361        return 0;
362}
363
364static int linuxnative_start_input(libtrace_t *libtrace)
365{
366        struct sockaddr_ll addr;
367        int one = 1;
368        memset(&addr,0,sizeof(addr));
369        libtrace_filter_t *filter = FORMAT(libtrace->format_data)->filter;
370       
371        /* Create a raw socket for reading packets on */
372        FORMAT(libtrace->format_data)->fd = 
373                                socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
374        if (FORMAT(libtrace->format_data)->fd==-1) {
375                trace_set_err(libtrace, errno, "Could not create raw socket");
376                free(libtrace->format_data);
377                libtrace->format_data = NULL;
378                return -1;
379        }
380
381        /* Bind to the capture interface */
382        addr.sll_family = AF_PACKET;
383        addr.sll_protocol = htons(ETH_P_ALL);
384        if (strlen(libtrace->uridata)) {
385                addr.sll_ifindex = if_nametoindex(libtrace->uridata);
386                if (addr.sll_ifindex == 0) {
387                        close(FORMAT(libtrace->format_data)->fd);
388                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Failed to find interface %s", libtrace->uridata);
389                        free(libtrace->format_data);
390                        libtrace->format_data = NULL;
391                        return -1;
392                }
393        }
394        else {
395                addr.sll_ifindex = 0;
396        }
397        if (bind(FORMAT(libtrace->format_data)->fd,
398                                (struct sockaddr*)&addr,
399                                (socklen_t)sizeof(addr))==-1) {
400                free(libtrace->format_data);
401                libtrace->format_data = NULL;
402                trace_set_err(libtrace, errno, "Failed to bind to interface %s", libtrace->uridata);
403                return -1;
404        }
405
406        /* If promisc hasn't been specified, set it to "true" if we're
407         * capturing on one interface, or "false" if we're capturing on
408         * all interfaces.
409         */ 
410        if (FORMAT(libtrace->format_data)->promisc==-1) {
411                if (addr.sll_ifindex!=0)
412                        FORMAT(libtrace->format_data)->promisc=1;
413                else
414                        FORMAT(libtrace->format_data)->promisc=0;
415        }
416       
417        /* Enable promiscuous mode, if requested */                     
418        if (FORMAT(libtrace->format_data)->promisc) {
419                struct packet_mreq mreq;
420                socklen_t socklen = sizeof(mreq);
421                memset(&mreq,0,sizeof(mreq));
422                mreq.mr_ifindex = addr.sll_ifindex;
423                mreq.mr_type = PACKET_MR_PROMISC;
424                if (setsockopt(FORMAT(libtrace->format_data)->fd,
425                                SOL_PACKET,
426                                PACKET_ADD_MEMBERSHIP,
427                                &mreq,
428                                socklen)==-1) {
429                        perror("setsockopt(PROMISC)");
430                }
431        }
432
433        /* Set the timestamp option on the socket - aim for the most detailed
434         * clock resolution possible */
435#ifdef SO_TIMESTAMPNS
436        if (setsockopt(FORMAT(libtrace->format_data)->fd,
437                        SOL_SOCKET,
438                        SO_TIMESTAMPNS,
439                        &one,
440                        (socklen_t)sizeof(one))!=-1) {
441                FORMAT(libtrace->format_data)->timestamptype = TS_TIMESPEC;
442        }
443        else
444        /* DANGER: This is a dangling else to only do the next setsockopt() if we fail the first! */
445#endif
446        if (setsockopt(FORMAT(libtrace->format_data)->fd,
447                        SOL_SOCKET,
448                        SO_TIMESTAMP,
449                        &one,
450                        (socklen_t)sizeof(one))!=-1) {
451                FORMAT(libtrace->format_data)->timestamptype = TS_TIMEVAL;
452        }
453        else 
454                FORMAT(libtrace->format_data)->timestamptype = TS_NONE;
455
456        /* Push BPF filter into the kernel. At this stage we can safely assume
457         * that the filterstring has been compiled, or the filter was supplied
458         * pre-compiled.
459         */
460        if (filter != NULL) {
461                assert(filter->flag == 1);
462                if (setsockopt(FORMAT(libtrace->format_data)->fd,
463                                        SOL_SOCKET,
464                                        SO_ATTACH_FILTER,
465                                        &filter->filter,
466                                        sizeof(filter->filter)) == -1) {
467                        perror("setsockopt(SO_ATTACH_FILTER)");
468                } else { 
469                        /* The socket accepted the filter, so we need to
470                         * consume any buffered packets that were received
471                         * between opening the socket and applying the filter.
472                         */
473                        void *buf = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
474                        while(recv(FORMAT(libtrace->format_data)->fd,
475                                        buf,
476                                        (size_t) LIBTRACE_PACKET_BUFSIZE,
477                                        MSG_DONTWAIT) != -1) { }
478                        free(buf);
479                }
480        }
481
482        FORMAT(libtrace->format_data)->stats_valid=0;
483                                       
484        return 0;
485}
486static inline int socket_to_packetmmap(char * uridata, int ring_type, 
487                                        int fd, 
488                                        struct tpacket_req * req,
489                                        char ** ring_location){
490        socklen_t len;
491        int val;
492
493        /* Switch to TPACKET header version 2, we only try support v2 because v1 had problems */
494        val = TPACKET_V2;
495        len = sizeof(val);
496        if(getsockopt(fd, 
497                        SOL_PACKET, 
498                        PACKET_HDRLEN, 
499                        &val, 
500                        &len) == -1){
501                return -1;
502        }
503
504        val = TPACKET_V2;
505        if (setsockopt(fd, 
506                        SOL_PACKET, 
507                        PACKET_VERSION, 
508                        &val, 
509                        sizeof(val)) == -1){
510                return -1;
511        }
512
513        /* Try switch to a ring buffer. If it fails we assume the the kernel 
514         * cannot allocate a block of that size, so decrease max_block and retry.
515         */
516        while(1) {     
517                if (max_order <= 0) {
518                        return -1;
519                }
520                calculate_buffers(req, fd, uridata);
521                if (setsockopt(fd, 
522                                SOL_PACKET, 
523                                ring_type, 
524                                req, 
525                                sizeof(struct tpacket_req)) == -1) {
526                        if(errno == ENOMEM){
527                                max_order--;
528                        } else {
529                                return -1;
530                        }
531
532                } else break;
533        }
534       
535        /* Map the ring buffer into userspace */
536        *ring_location = mmap(NULL, 
537                                        req->tp_block_size * req->tp_block_nr, 
538                                        PROT_READ | PROT_WRITE, 
539                                        MAP_SHARED, 
540                                        fd, 0);
541        if(*ring_location == MAP_FAILED){
542                return -1;
543        }
544        return 0;
545}
546static int linuxring_start_input(libtrace_t *libtrace){
547       
548
549        /* We set the socket up the same and then convert it to PACKET_MMAP */
550        if(linuxnative_start_input(libtrace) != 0)
551                return -1;
552
553        /* Make it a packetmmap */
554        if(socket_to_packetmmap(libtrace->uridata, PACKET_RX_RING, FORMAT(libtrace->format_data)->fd,
555                 &FORMAT(libtrace->format_data)->req, &FORMAT(libtrace->format_data)->rx_ring) != 0){
556                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, 
557                        "TPACKET2 not supported or ring buffer is too large");
558                close(DATAOUT(libtrace)->fd);
559                free(libtrace->format_data);
560                return -1;
561        }
562               
563        return 0;
564}
565
566static int linuxnative_start_output(libtrace_out_t *libtrace)
567{
568        DATAOUT(libtrace)->fd = socket(PF_PACKET, SOCK_RAW, 0);
569        if (DATAOUT(libtrace)->fd==-1) {
570                free(DATAOUT(libtrace));
571                return -1;
572        }       
573
574        return 0;
575}
576
577static int linuxring_start_output(libtrace_out_t *libtrace)
578{
579        /* We set the socket up the same and then convert it to PACKET_MMAP */
580        if(linuxnative_start_output(libtrace) != 0)
581                return -1;
582
583        /* Make it a packetmmap */
584        if(socket_to_packetmmap(libtrace->uridata, PACKET_TX_RING, DATAOUT(libtrace)->fd,
585                 &DATAOUT(libtrace)->req, &DATAOUT(libtrace)->tx_ring) != 0){
586                trace_set_err_out(libtrace, TRACE_ERR_INIT_FAILED, 
587                        "TPACKET2 not supported or ring buffer is too large");
588                close(DATAOUT(libtrace)->fd);
589                free(libtrace->format_data);
590                return -1;
591        }
592       
593        DATAOUT(libtrace)->sock_hdr.sll_family = AF_PACKET;
594        DATAOUT(libtrace)->sock_hdr.sll_protocol = 0;
595        DATAOUT(libtrace)->sock_hdr.sll_ifindex = 
596                                        if_nametoindex(libtrace->uridata);
597        DATAOUT(libtrace)->sock_hdr.sll_hatype = 0;
598        DATAOUT(libtrace)->sock_hdr.sll_pkttype = 0;
599        DATAOUT(libtrace)->sock_hdr.sll_halen = 0;
600        DATAOUT(libtrace)->queue = 0;   
601
602        return 0;
603}
604
605static int linuxnative_pause_input(libtrace_t *libtrace)
606{
607        close(FORMAT(libtrace->format_data)->fd);
608        FORMAT(libtrace->format_data)->fd=-1;
609
610        return 0;
611}
612static int linuxring_pause_input(libtrace_t *libtrace)
613{
614        munmap(FORMAT(libtrace->format_data)->rx_ring, 
615                FORMAT(libtrace->format_data)->req.tp_block_size *
616                        FORMAT(libtrace->format_data)->req.tp_block_nr);
617        FORMAT(libtrace->format_data)->rx_ring = NULL;
618        return linuxnative_pause_input(libtrace);
619}
620
621static int linuxnative_fin_input(libtrace_t *libtrace) 
622{
623        if (libtrace->format_data) {
624                if (FORMAT(libtrace->format_data)->filter != NULL)
625                        free(FORMAT(libtrace->format_data)->filter);
626                free(libtrace->format_data);
627        }
628       
629        return 0;
630}
631
632static int linuxnative_fin_output(libtrace_out_t *libtrace)
633{
634        close(DATAOUT(libtrace)->fd);
635        DATAOUT(libtrace)->fd=-1;
636        free(libtrace->format_data);
637        return 0;
638}
639static int linuxring_fin_output(libtrace_out_t *libtrace)
640{
641        /* Make sure any remaining frames get sent */
642        sendto(DATAOUT(libtrace)->fd, 
643                NULL, 
644                0, 
645                0, 
646                (void *) &DATAOUT(libtrace)->sock_hdr, 
647                sizeof(DATAOUT(libtrace)->sock_hdr));
648
649        /* Unmap our data area */
650        munmap(DATAOUT(libtrace)->tx_ring,
651                DATAOUT(libtrace)->req.tp_block_size * 
652                        DATAOUT(libtrace)->req.tp_block_nr);
653
654        return linuxnative_fin_output(libtrace);
655}
656
657/* Compiles a libtrace BPF filter for use with a linux native socket */
658static int linuxnative_configure_bpf(libtrace_t *libtrace, 
659                libtrace_filter_t *filter) {
660#ifdef HAVE_LIBPCAP
661        struct ifreq ifr;
662        unsigned int arphrd;
663        libtrace_dlt_t dlt;
664        libtrace_filter_t *f;
665        int sock;
666        pcap_t *pcap;
667
668        /* Take a copy of the filter object as it was passed in */
669        f = (libtrace_filter_t *) malloc(sizeof(libtrace_filter_t));
670        memcpy(f, filter, sizeof(libtrace_filter_t));
671       
672        /* If we are passed a filter with "flag" set to zero, then we must
673         * compile the filterstring before continuing. This involves
674         * determining the linktype, passing the filterstring to libpcap to
675         * compile, and saving the result for trace_start() to push into the
676         * kernel.
677         * If flag is set to one, then the filter was probably generated using
678         * trace_create_filter_from_bytecode() and so we don't need to do
679         * anything (we've just copied it above).
680         */
681        if (f->flag == 0) {
682                sock = socket(PF_INET, SOCK_STREAM, 0);
683                memset(&ifr, 0, sizeof(struct ifreq));
684                strncpy(ifr.ifr_name, libtrace->uridata, IF_NAMESIZE);
685                if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0) {
686                        perror("Can't get HWADDR for interface");
687                        return -1;
688                }
689                close(sock);
690
691                arphrd = ifr.ifr_hwaddr.sa_family;
692                dlt = libtrace_to_pcap_dlt(arphrd_type_to_libtrace(arphrd));
693
694                pcap = pcap_open_dead(dlt, 
695                                FORMAT(libtrace->format_data)->snaplen);
696
697                if (pcap_compile(pcap, &f->filter, f->filterstring, 0, 0) == -1) {
698                        perror("PCAP failed to compile the filterstring");
699                        return -1;
700                }
701
702                pcap_close(pcap);
703               
704                /* Set the "flag" to indicate that the filterstring has been
705                 * compiled
706                 */
707                f->flag = 1;
708        }
709       
710        if (FORMAT(libtrace->format_data)->filter != NULL)
711                free(FORMAT(libtrace->format_data)->filter);
712       
713        FORMAT(libtrace->format_data)->filter = f;
714       
715        return 0;
716#else
717        return -1
718#endif
719}
720static int linuxnative_config_input(libtrace_t *libtrace,
721                trace_option_t option,
722                void *data)
723{
724        switch(option) {
725                case TRACE_OPTION_SNAPLEN:
726                        FORMAT(libtrace->format_data)->snaplen=*(int*)data;
727                        return 0;
728                case TRACE_OPTION_PROMISC:
729                        FORMAT(libtrace->format_data)->promisc=*(int*)data;
730                        return 0;
731                case TRACE_OPTION_FILTER:
732                        return linuxnative_configure_bpf(libtrace, 
733                                        (libtrace_filter_t *) data);
734                case TRACE_OPTION_META_FREQ:
735                        /* No meta-data for this format */
736                        break;
737                case TRACE_OPTION_EVENT_REALTIME:
738                        /* Live captures are always going to be in trace time */
739                        break;
740                /* Avoid default: so that future options will cause a warning
741                 * here to remind us to implement it, or flag it as
742                 * unimplementable
743                 */
744        }
745       
746        /* Don't set an error - trace_config will try to deal with the
747         * option and will set an error if it fails */
748        return -1;
749}
750
751static int linuxnative_prepare_packet(libtrace_t *libtrace, 
752                libtrace_packet_t *packet, void *buffer, 
753                libtrace_rt_types_t rt_type, uint32_t flags) {
754
755        if (packet->buffer != buffer &&
756                        packet->buf_control == TRACE_CTRL_PACKET) {
757                free(packet->buffer);
758        }
759
760        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
761                packet->buf_control = TRACE_CTRL_PACKET;
762        } else
763                packet->buf_control = TRACE_CTRL_EXTERNAL;
764
765
766        packet->buffer = buffer;
767        packet->header = buffer;
768        packet->payload = (char *)buffer + 
769                sizeof(struct libtrace_linuxnative_header);
770        packet->type = rt_type;
771
772        if (libtrace->format_data == NULL) {
773                if (linuxnative_init_input(libtrace))
774                        return -1;
775        }
776        return 0;
777       
778}
779
780static int linuxring_prepare_packet(libtrace_t *libtrace, 
781                libtrace_packet_t *packet, void *buffer, 
782                libtrace_rt_types_t rt_type, uint32_t flags) {
783
784        if (packet->buffer != buffer &&
785                        packet->buf_control == TRACE_CTRL_PACKET) {
786                free(packet->buffer);
787        }
788
789        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
790                packet->buf_control = TRACE_CTRL_PACKET;
791        } else
792                packet->buf_control = TRACE_CTRL_EXTERNAL;
793
794
795        packet->buffer = buffer;
796        packet->header = buffer;
797        packet->payload = (char *)buffer + 
798                                        TP_TRACE_START(
799                                        TO_TP_HDR(packet->header)->tp_mac, 
800                                        TO_TP_HDR(packet->header)->tp_net, 
801                                        TPACKET2_HDRLEN);
802        packet->type = rt_type;
803
804        if (libtrace->format_data == NULL) {
805                if (linuxnative_init_input(libtrace))
806                        return -1;
807        }
808        return 0;
809       
810}
811
812#define LIBTRACE_MIN(a,b) ((a)<(b) ? (a) : (b))
813
814/* 20 isn't enough on x86_64 */
815#define CMSG_BUF_SIZE 128
816static int linuxnative_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) 
817{
818        struct libtrace_linuxnative_header *hdr;
819        struct msghdr msghdr;
820        struct iovec iovec;
821        unsigned char controlbuf[CMSG_BUF_SIZE];
822        struct cmsghdr *cmsg;
823        int snaplen;
824        uint32_t flags = 0;
825       
826        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
827                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
828                if (!packet->buffer) {
829                        perror("Cannot allocate buffer");
830                }
831        }
832
833        flags |= TRACE_PREP_OWN_BUFFER;
834       
835        packet->type = TRACE_RT_DATA_LINUX_NATIVE;
836
837        hdr=(struct libtrace_linuxnative_header*)packet->buffer;
838        snaplen=LIBTRACE_MIN(
839                        (int)LIBTRACE_PACKET_BUFSIZE-(int)sizeof(*hdr),
840                        (int)FORMAT(libtrace->format_data)->snaplen);
841
842        /* Prepare the msghdr and iovec for the kernel to write the
843         * captured packet into. The msghdr will point to the part of our
844         * buffer reserved for sll header, while the iovec will point at
845         * the buffer following the sll header. */
846
847        msghdr.msg_name = &hdr->hdr;
848        msghdr.msg_namelen = sizeof(struct sockaddr_ll);
849
850        msghdr.msg_iov = &iovec;
851        msghdr.msg_iovlen = 1;
852
853        msghdr.msg_control = &controlbuf;
854        msghdr.msg_controllen = CMSG_BUF_SIZE;
855        msghdr.msg_flags = 0;
856
857        iovec.iov_base = (void*)(packet->buffer+sizeof(*hdr));
858        iovec.iov_len = snaplen;
859
860        hdr->wirelen = recvmsg(FORMAT(libtrace->format_data)->fd, &msghdr, 0);
861
862        if (hdr->wirelen==~0U) {
863                trace_set_err(libtrace,errno,"recvmsg");
864                return -1;
865        }
866
867        hdr->caplen=LIBTRACE_MIN((unsigned int)snaplen,(unsigned int)hdr->wirelen);
868
869        /* Extract the timestamps from the msghdr and store them in our
870         * linux native encapsulation, so that we can preserve the formatting
871         * across multiple architectures */
872
873        for (cmsg = CMSG_FIRSTHDR(&msghdr);
874                        cmsg != NULL;
875                        cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
876                if (cmsg->cmsg_level == SOL_SOCKET
877                        && cmsg->cmsg_type == SO_TIMESTAMP
878                        && cmsg->cmsg_len <= CMSG_LEN(sizeof(struct timeval))) {
879                       
880                        struct timeval *tv;
881                        tv = (struct timeval *)CMSG_DATA(cmsg);
882                       
883                       
884                        hdr->tv.tv_sec = tv->tv_sec;
885                        hdr->tv.tv_usec = tv->tv_usec;
886                        hdr->timestamptype = TS_TIMEVAL;
887                        break;
888                } 
889#ifdef SO_TIMESTAMPNS
890                else if (cmsg->cmsg_level == SOL_SOCKET
891                        && cmsg->cmsg_type == SO_TIMESTAMPNS
892                        && cmsg->cmsg_len <= CMSG_LEN(sizeof(struct timespec))) {
893
894                        struct timespec *tv;
895                        tv = (struct timespec *)CMSG_DATA(cmsg);
896
897                        hdr->ts.tv_sec = tv->tv_sec;
898                        hdr->ts.tv_nsec = tv->tv_nsec;
899                        hdr->timestamptype = TS_TIMESPEC;
900                        break;
901                }
902#endif
903        }
904
905        /* Did we not get given a timestamp? Try to get one from the
906         * file descriptor directly */
907        if (cmsg == NULL) {
908                struct timeval tv;
909                if (ioctl(FORMAT(libtrace->format_data)->fd, 
910                                  SIOCGSTAMP,&tv)==0) {
911                        hdr->tv.tv_sec = tv.tv_sec;
912                        hdr->tv.tv_usec = tv.tv_usec;
913                        hdr->timestamptype = TS_TIMEVAL;
914                }
915                else {
916                        hdr->timestamptype = TS_NONE;
917                }
918        }
919
920        /* Buffer contains all of our packet (including our custom header) so
921         * we just need to get prepare_packet to set all our packet pointers
922         * appropriately */
923       
924        if (linuxnative_prepare_packet(libtrace, packet, packet->buffer,
925                                packet->type, flags))
926                return -1;
927       
928        return hdr->wirelen+sizeof(*hdr);
929}
930
931#define LIBTRACE_BETWEEN(test,a,b) ((test) >= (a) && (test) < (b))
932static int linuxring_get_capture_length(const libtrace_packet_t *packet);
933static int linuxring_get_framing_length(const libtrace_packet_t *packet);
934
935/* Release a frame back to the kernel or free() if it's a malloc'd buffer
936 */
937inline static void ring_release_frame(libtrace_t *libtrace, libtrace_packet_t *packet ){
938        /* Free the old packet */
939        if(packet->buffer == NULL)
940                return;
941
942        if(packet->buf_control == TRACE_CTRL_PACKET){
943                free(packet->buffer);
944                packet->buffer = NULL;
945        }
946        if(packet->buf_control == TRACE_CTRL_EXTERNAL) {
947                struct linux_format_data_t *ftd = FORMAT(libtrace->format_data);
948               
949                /* Check it's within our buffer first */
950                if(LIBTRACE_BETWEEN((char *) packet->buffer, 
951                                (char *) ftd->rx_ring,
952                                ftd->rx_ring
953                                + ftd->req.tp_block_size * ftd->req.tp_block_nr)){
954                        TO_TP_HDR(packet->buffer)->tp_status = 0;
955                        packet->buffer = NULL;
956                }
957        }
958}
959
960static int linuxring_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
961
962        struct tpacket2_hdr *header;
963        struct pollfd pollset; 
964        int ret;
965       
966        ring_release_frame(libtrace, packet);
967       
968        packet->buf_control = TRACE_CTRL_EXTERNAL;
969        packet->type = TRACE_RT_DATA_LINUX_RING;
970       
971        /* Fetch the current frame */
972        header = GET_CURRENT_BUFFER(libtrace);
973        assert((((unsigned long) header) & (pagesize - 1)) == 0);
974
975        /* TP_STATUS_USER means that we can use the frame.
976         * When a slot does not have this flag set, the frame is not
977         * ready for consumption.
978         */
979        while (!(header->tp_status & TP_STATUS_USER)) {
980                printf("I shouldn't run if event handler\n");
981                pollset.fd = FORMAT(libtrace->format_data)->fd;
982                pollset.events = POLLIN;
983                pollset.revents = 0;
984                /* Wait for more data */
985                ret = poll(&pollset, 1, -1);
986                if (ret < 0) {
987                        if (errno != EINTR)
988                        trace_set_err(libtrace,errno,"poll()");
989                        return -1;
990                }
991        }
992
993        packet->buffer = header;
994
995        /* Move to next buffer */
996        FORMAT(libtrace->format_data)->rxring_offset++;
997        FORMAT(libtrace->format_data)->rxring_offset %= FORMAT(libtrace->format_data)->req.tp_frame_nr;
998
999        /* We just need to get prepare_packet to set all our packet pointers
1000         * appropriately */
1001        if (linuxring_prepare_packet(libtrace, packet, packet->buffer,
1002                                packet->type, 0))
1003                return -1;
1004        return  linuxring_get_framing_length(packet) + 
1005                                linuxring_get_capture_length(packet);
1006
1007}
1008
1009/* Non-blocking read */
1010static libtrace_eventobj_t linuxring_event(libtrace_t *libtrace, libtrace_packet_t *packet) {
1011        struct tpacket2_hdr *header;
1012        libtrace_eventobj_t event = {0,0,0.0,0};
1013
1014        /* We must free the old packet, otherwise select() will instantly return
1015         */
1016        ring_release_frame(libtrace, packet);
1017
1018        /* Fetch the current frame */
1019        header = GET_CURRENT_BUFFER(libtrace);
1020        if(header->tp_status & TP_STATUS_USER){
1021                /* We have a frame waiting */
1022                event.size = linuxring_read_packet(libtrace, packet);
1023                event.type = TRACE_EVENT_PACKET;
1024        } else {
1025                /* Ok we don't have a packet waiting */
1026                event.type = TRACE_EVENT_IOWAIT;
1027                event.fd = FORMAT(libtrace->format_data)->fd;
1028        }
1029
1030        return event;
1031}
1032
1033
1034static int linuxnative_write_packet(libtrace_out_t *trace, 
1035                libtrace_packet_t *packet) 
1036{
1037        struct sockaddr_ll hdr;
1038
1039        if (trace_get_link_type(packet) == TRACE_TYPE_NONDATA)
1040                return 0;
1041
1042        hdr.sll_family = AF_PACKET;
1043        hdr.sll_protocol = 0;
1044        hdr.sll_ifindex = if_nametoindex(trace->uridata);
1045        hdr.sll_hatype = 0;
1046        hdr.sll_pkttype = 0;
1047        hdr.sll_halen = htons(6); /* FIXME */
1048        memcpy(hdr.sll_addr,packet->payload,(size_t)ntohs(hdr.sll_halen));
1049
1050        /* This is pretty easy, just send the payload using sendto() (after
1051         * setting up the sll header properly, of course) */
1052        return sendto(DATAOUT(trace)->fd,
1053                        packet->payload,
1054                        trace_get_capture_length(packet),
1055                        0,
1056                        (struct sockaddr*)&hdr, (socklen_t)sizeof(hdr));
1057
1058}
1059static int linuxring_write_packet(libtrace_out_t *trace, 
1060                libtrace_packet_t *packet)
1061{
1062        struct tpacket2_hdr *header;
1063        struct pollfd pollset;
1064        struct socket_addr;
1065        int ret; 
1066        unsigned max_size;
1067        void * off;
1068
1069        if (trace_get_link_type(packet) == TRACE_TYPE_NONDATA)
1070                return 0;
1071
1072        max_size = DATAOUT(trace)->req.tp_frame_size - 
1073                 - TPACKET_HDRLEN + sizeof(struct sockaddr_ll);
1074
1075        header = (void *) DATAOUT(trace)->tx_ring + 
1076        (DATAOUT(trace)->txring_offset * DATAOUT(trace)->req.tp_frame_size);
1077
1078        while(header->tp_status != TP_STATUS_AVAILABLE){
1079                /* if none available: wait on more data */
1080                pollset.fd = DATAOUT(trace)->fd;
1081                pollset.events = POLLOUT;
1082                pollset.revents = 0;
1083                ret = poll(&pollset, 1, 1000);
1084                if (ret < 0 && errno != EINTR) {
1085                        perror("poll");
1086                        return -1;
1087                }
1088                if(ret == 0) 
1089                        /* Timeout something has gone wrong - maybe the queue is
1090                         * to large so try issue another send command
1091                         */
1092                        sendto(DATAOUT(trace)->fd, 
1093                                NULL, 
1094                                0, 
1095                                0, 
1096                                (void *) &DATAOUT(trace)->sock_hdr, 
1097                                sizeof(DATAOUT(trace)->sock_hdr));
1098        }
1099       
1100        header->tp_len = trace_get_capture_length(packet);
1101
1102        /* We cannot write the whole packet so just write part of it */
1103        if (header->tp_len > max_size)
1104                header->tp_len = max_size;
1105
1106        /* Fill packet - no sockaddr_ll in header when writing to the TX_RING */
1107        off = ((void *) header) + (TPACKET_HDRLEN - sizeof(struct sockaddr_ll));
1108        memcpy(off, 
1109                (char *) packet->payload, 
1110                header->tp_len);
1111       
1112        /* 'Send it' and increase ring pointer to the next frame */
1113        header->tp_status = TP_STATUS_SEND_REQUEST;
1114        DATAOUT(trace)->txring_offset = (DATAOUT(trace)->txring_offset + 1) % 
1115                                                DATAOUT(trace)->req.tp_frame_nr;
1116
1117        /* Notify kernel there are frames to send */
1118        DATAOUT(trace)->queue = (++DATAOUT(trace)->queue) % TX_MAX_QUEUE;
1119        if(DATAOUT(trace)->queue == 0){
1120                sendto(DATAOUT(trace)->fd, 
1121                        NULL, 
1122                        0, 
1123                        MSG_DONTWAIT, 
1124                        (void *) &DATAOUT(trace)->sock_hdr, 
1125                        sizeof(DATAOUT(trace)->sock_hdr));
1126        }
1127        return header->tp_len;
1128
1129}
1130
1131static inline libtrace_linktype_t get_libtrace_link_type(uint16_t linktype){
1132        /* Convert the ARPHRD type into an appropriate libtrace link type */
1133        switch (linktype) {
1134                case ARPHRD_ETHER:
1135                case ARPHRD_LOOPBACK:
1136                        return TRACE_TYPE_ETH;
1137                case ARPHRD_PPP:
1138                        return TRACE_TYPE_NONE;
1139                case ARPHRD_80211_RADIOTAP:
1140                        return TRACE_TYPE_80211_RADIO;
1141                case ARPHRD_IEEE80211:
1142                        return TRACE_TYPE_80211;
1143                case ARPHRD_SIT:
1144                case ARPHRD_NONE:
1145                        return TRACE_TYPE_NONE;
1146                default: /* shrug, beyond me! */
1147                        printf("unknown Linux ARPHRD type 0x%04x\n",linktype);
1148                        return (libtrace_linktype_t)~0U;
1149        }
1150}
1151static libtrace_linktype_t linuxnative_get_link_type(const struct libtrace_packet_t *packet) {
1152        uint16_t linktype=(((struct libtrace_linuxnative_header*)(packet->buffer))
1153                                ->hdr.sll_hatype);
1154        return get_libtrace_link_type(linktype);
1155}
1156static libtrace_linktype_t linuxring_get_link_type(const struct libtrace_packet_t *packet) {
1157        uint16_t linktype= GET_SOCKADDR_HDR(packet->buffer)->sll_hatype;
1158        return get_libtrace_link_type(linktype);
1159}
1160
1161static inline libtrace_direction_t get_libtrace_direction(uint8_t pkttype){
1162        switch (pkttype) {
1163                case PACKET_OUTGOING:
1164                case PACKET_LOOPBACK:
1165                        return TRACE_DIR_OUTGOING;
1166                default:
1167                        return TRACE_DIR_INCOMING;
1168        }
1169}
1170static libtrace_direction_t linuxnative_get_direction(const struct libtrace_packet_t *packet) {
1171        return get_libtrace_direction(((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype);
1172}
1173static libtrace_direction_t linuxring_get_direction(const struct libtrace_packet_t *packet) {
1174        return get_libtrace_direction(GET_SOCKADDR_HDR(packet->buffer)->sll_pkttype);
1175}
1176
1177static libtrace_direction_t set_direction(struct sockaddr_ll * skadr, libtrace_direction_t direction){
1178        switch (direction) {
1179                case TRACE_DIR_OUTGOING:
1180                        skadr->sll_pkttype = PACKET_OUTGOING;
1181                        return TRACE_DIR_OUTGOING;
1182                case TRACE_DIR_INCOMING:
1183                        skadr->sll_pkttype = PACKET_HOST;
1184                        return TRACE_DIR_INCOMING;
1185                default:
1186                        return -1;
1187        }
1188}
1189static libtrace_direction_t linuxnative_set_direction(
1190                libtrace_packet_t *packet,
1191                libtrace_direction_t direction) {
1192        return set_direction(&((struct libtrace_linuxnative_header*)(packet->buffer))->hdr, direction);
1193}
1194static libtrace_direction_t linuxring_set_direction(
1195                libtrace_packet_t *packet,
1196                libtrace_direction_t direction) {
1197        return set_direction(GET_SOCKADDR_HDR(packet->buffer), direction);
1198}
1199
1200static struct timespec linuxnative_get_timespec(const libtrace_packet_t *packet) 
1201{
1202        struct libtrace_linuxnative_header *hdr = 
1203                (struct libtrace_linuxnative_header*) packet->buffer;
1204        /* We have to upconvert from timeval to timespec */
1205        if (hdr->timestamptype == TS_TIMEVAL) {
1206                struct timespec ts;
1207                ts.tv_sec = hdr->tv.tv_sec;
1208                ts.tv_nsec = hdr->tv.tv_usec*1000;
1209                return ts;
1210        }
1211        else {
1212                struct timespec ts;
1213                ts.tv_sec = hdr->ts.tv_sec;
1214                ts.tv_nsec = hdr->ts.tv_nsec;
1215                return ts;
1216        }
1217}
1218static struct timespec linuxring_get_timespec(const libtrace_packet_t *packet) 
1219{
1220        struct timespec ts;
1221        ts.tv_sec = TO_TP_HDR(packet->buffer)->tp_sec;
1222        ts.tv_nsec = TO_TP_HDR(packet->buffer)->tp_nsec;
1223        return ts;
1224}
1225
1226
1227static struct timeval linuxnative_get_timeval(const libtrace_packet_t *packet) 
1228{
1229        struct libtrace_linuxnative_header *hdr = 
1230                (struct libtrace_linuxnative_header*) packet->buffer;
1231        /* We have to downconvert from timespec to timeval */
1232        if (hdr->timestamptype == TS_TIMESPEC) {
1233                struct timeval tv;
1234                tv.tv_sec = hdr->ts.tv_sec;
1235                tv.tv_usec = hdr->ts.tv_nsec/1000;
1236                return tv;
1237        }
1238        else {
1239                struct timeval tv;
1240                tv.tv_sec = hdr->tv.tv_sec;
1241                tv.tv_usec = hdr->tv.tv_usec;
1242                return tv;
1243        }
1244}
1245static struct timeval linuxring_get_timeval(const libtrace_packet_t *packet) 
1246{
1247        struct timeval tv;
1248        tv.tv_sec = TO_TP_HDR(packet->buffer)->tp_sec;
1249        tv.tv_usec = TO_TP_HDR(packet->buffer)->tp_nsec / 1000;
1250        return tv;
1251}
1252
1253static int linuxnative_get_capture_length(const libtrace_packet_t *packet)
1254{
1255        return ((struct libtrace_linuxnative_header*)(packet->buffer))->caplen;
1256}
1257
1258static int linuxring_get_capture_length(const libtrace_packet_t *packet)
1259{
1260        return TO_TP_HDR(packet->buffer)->tp_snaplen;
1261}
1262
1263static int linuxnative_get_wire_length(const libtrace_packet_t *packet) 
1264{
1265
1266        int wirelen = ((struct libtrace_linuxnative_header*)(packet->buffer))->wirelen;
1267
1268        /* Include the missing FCS */
1269        if (trace_get_link_type(packet) == TRACE_TYPE_ETH)
1270                wirelen += 4;
1271
1272        return wirelen;
1273}
1274
1275static int linuxring_get_wire_length(const libtrace_packet_t *packet) 
1276{
1277        int wirelen = TO_TP_HDR(packet->buffer)->tp_len;
1278
1279        /* Include the missing FCS */
1280        if (trace_get_link_type(packet) == TRACE_TYPE_ETH)
1281                wirelen += 4;
1282
1283        return wirelen;
1284}
1285
1286static int linuxnative_get_framing_length(UNUSED
1287                const libtrace_packet_t *packet) 
1288{
1289        return sizeof(struct libtrace_linuxnative_header);
1290}
1291
1292static int linuxring_get_framing_length(const libtrace_packet_t *packet)
1293{       
1294        /*
1295         * Need to make frame_length + capture_length = compelete capture length
1296         * so include alligment whitespace. So reverse calculate from packet.
1297         */
1298        return (char *) packet->payload - (char *) packet->buffer;
1299}
1300
1301static size_t linuxnative_set_capture_length(libtrace_packet_t *packet, 
1302                size_t size) {
1303
1304        struct libtrace_linuxnative_header *linux_hdr = NULL;
1305        assert(packet);
1306        if (size > trace_get_capture_length(packet)) {
1307                /* We should avoid making a packet larger */
1308                return trace_get_capture_length(packet);
1309        }
1310       
1311        /* Reset the cached capture length */
1312        packet->capture_length = -1;
1313
1314        linux_hdr = (struct libtrace_linuxnative_header *)packet->header;
1315        linux_hdr->caplen = size;
1316        return trace_get_capture_length(packet);
1317}
1318
1319static size_t linuxring_set_capture_length(libtrace_packet_t *packet, 
1320                size_t size) {
1321        assert(packet);
1322        if (size > trace_get_capture_length(packet)) {
1323                /* We should avoid making a packet larger */
1324                return trace_get_capture_length(packet);
1325        }
1326       
1327        /* Reset the cached capture length */
1328        packet->capture_length = -1;
1329
1330        TO_TP_HDR(packet->buffer)->tp_len = size;
1331
1332        return trace_get_capture_length(packet);
1333}
1334
1335static int linuxnative_get_fd(const libtrace_t *trace) {
1336        if (trace->format_data == NULL)
1337                return -1;
1338        return FORMAT(trace->format_data)->fd;
1339}
1340
1341/* Linux doesn't keep track how many packets were seen before filtering
1342 * so we can't tell how many packets were filtered.  Bugger.  So annoying.
1343 *
1344 * Since we tell libtrace that we do support filtering, if we don't declare
1345 * this here as failing, libtrace will happily report for us that it didn't
1346 * filter any packets, so don't lie -- return that we don't know.
1347 */
1348static uint64_t linuxnative_get_filtered_packets(libtrace_t *trace UNUSED) {
1349        return UINT64_MAX;
1350}
1351
1352/* Number of packets that passed filtering */
1353static uint64_t linuxnative_get_captured_packets(libtrace_t *trace) {
1354        if (trace->format_data == NULL)
1355                return UINT64_MAX;
1356        if (FORMAT(trace->format_data)->fd == -1) {
1357                /* This is probably a 'dead' trace so obviously we can't query
1358                 * the socket for capture counts, can we? */
1359                return UINT64_MAX;
1360        }
1361       
1362        if ((FORMAT(trace->format_data)->stats_valid & 1) 
1363                        || FORMAT(trace->format_data)->stats_valid == 0) {
1364                socklen_t len = sizeof(FORMAT(trace->format_data)->stats);
1365                getsockopt(FORMAT(trace->format_data)->fd, 
1366                                SOL_PACKET,
1367                                PACKET_STATISTICS,
1368                                &FORMAT(trace->format_data)->stats,
1369                                &len);
1370                FORMAT(trace->format_data)->stats_valid |= 1;
1371        }
1372
1373        return FORMAT(trace->format_data)->stats.tp_packets;
1374}
1375
1376/* Number of packets that got past filtering and were then dropped because
1377 * of lack of space
1378 */
1379static uint64_t linuxnative_get_dropped_packets(libtrace_t *trace) {
1380        if (trace->format_data == NULL)
1381                return UINT64_MAX;
1382        if (FORMAT(trace->format_data)->fd == -1) {
1383                /* This is probably a 'dead' trace so obviously we can't query
1384                 * the socket for drop counts, can we? */
1385                return UINT64_MAX;
1386        }
1387       
1388        if ((FORMAT(trace->format_data)->stats_valid & 2)
1389                        || (FORMAT(trace->format_data)->stats_valid==0)) {
1390                socklen_t len = sizeof(FORMAT(trace->format_data)->stats);
1391                getsockopt(FORMAT(trace->format_data)->fd, 
1392                                SOL_PACKET,
1393                                PACKET_STATISTICS,
1394                                &FORMAT(trace->format_data)->stats,
1395                                &len);
1396                FORMAT(trace->format_data)->stats_valid |= 2;
1397        }
1398
1399        return FORMAT(trace->format_data)->stats.tp_drops;
1400}
1401
1402static void linuxnative_help(void) {
1403        printf("linuxnative format module: $Revision$\n");
1404        printf("Supported input URIs:\n");
1405        printf("\tint:eth0\n");
1406        printf("\n");
1407        printf("Supported output URIs:\n");
1408        printf("\tint:eth0\n");
1409        printf("\n");
1410        return;
1411}
1412
1413static void linuxring_help(void) {
1414        printf("linuxring format module: $Revision$\n");
1415        printf("Supported input URIs:\n");
1416        printf("\tring:eth0\n");
1417        printf("\n");
1418        printf("Supported output URIs:\n");
1419        printf("\tring:eth0\n");
1420        printf("\n");
1421        return;
1422}
1423
1424static struct libtrace_format_t linuxnative = {
1425        "int",
1426        "$Id$",
1427        TRACE_FORMAT_LINUX_NATIVE,
1428        linuxnative_probe_filename,     /* probe filename */
1429        NULL,                           /* probe magic */
1430        linuxnative_init_input,         /* init_input */
1431        linuxnative_config_input,       /* config_input */
1432        linuxnative_start_input,        /* start_input */
1433        linuxnative_pause_input,        /* pause_input */
1434        linuxnative_init_output,        /* init_output */
1435        NULL,                           /* config_output */
1436        linuxnative_start_output,       /* start_ouput */
1437        linuxnative_fin_input,          /* fin_input */
1438        linuxnative_fin_output,         /* fin_output */
1439        linuxnative_read_packet,        /* read_packet */
1440        linuxnative_prepare_packet,     /* prepare_packet */
1441        NULL,                           /* fin_packet */
1442        linuxnative_write_packet,       /* write_packet */
1443        linuxnative_get_link_type,      /* get_link_type */
1444        linuxnative_get_direction,      /* get_direction */
1445        linuxnative_set_direction,      /* set_direction */
1446        NULL,                           /* get_erf_timestamp */
1447        linuxnative_get_timeval,        /* get_timeval */
1448        linuxnative_get_timespec,       /* get_timespec */
1449        NULL,                           /* get_seconds */
1450        NULL,                           /* seek_erf */
1451        NULL,                           /* seek_timeval */
1452        NULL,                           /* seek_seconds */
1453        linuxnative_get_capture_length, /* get_capture_length */
1454        linuxnative_get_wire_length,    /* get_wire_length */
1455        linuxnative_get_framing_length, /* get_framing_length */
1456        linuxnative_set_capture_length, /* set_capture_length */
1457        NULL,                           /* get_received_packets */
1458        linuxnative_get_filtered_packets,/* get_filtered_packets */
1459        linuxnative_get_dropped_packets,/* get_dropped_packets */
1460        linuxnative_get_captured_packets,/* get_captured_packets */
1461        linuxnative_get_fd,             /* get_fd */
1462        trace_event_device,             /* trace_event */
1463        linuxnative_help,               /* help */
1464        NULL
1465};
1466
1467static struct libtrace_format_t linuxring = {
1468        "ring",
1469        "$Id$",
1470        TRACE_FORMAT_LINUX_RING,
1471        linuxnative_probe_filename,     /* probe filename */
1472        NULL,                           /* probe magic */
1473        linuxring_init_input,           /* init_input */
1474        linuxnative_config_input,       /* config_input */
1475        linuxring_start_input,  /* start_input */
1476        linuxring_pause_input,  /* pause_input */
1477        linuxring_init_output,  /* init_output */
1478        NULL,                           /* config_output */
1479        linuxring_start_output, /* start_ouput */
1480        linuxnative_fin_input,          /* fin_input */
1481        linuxring_fin_output,           /* fin_output */
1482        linuxring_read_packet,  /* read_packet */
1483        linuxring_prepare_packet,       /* prepare_packet */
1484        NULL,                           /* fin_packet */
1485        linuxring_write_packet, /* write_packet */
1486        linuxring_get_link_type,        /* get_link_type */
1487        linuxring_get_direction,        /* get_direction */
1488        linuxring_set_direction,        /* set_direction */
1489        NULL,                           /* get_erf_timestamp */
1490        linuxring_get_timeval,  /* get_timeval */
1491        linuxring_get_timespec, /* get_timespec */
1492        NULL,                           /* get_seconds */
1493        NULL,                           /* seek_erf */
1494        NULL,                           /* seek_timeval */
1495        NULL,                           /* seek_seconds */
1496        linuxring_get_capture_length,   /* get_capture_length */
1497        linuxring_get_wire_length,      /* get_wire_length */
1498        linuxring_get_framing_length,   /* get_framing_length */
1499        linuxring_set_capture_length,   /* set_capture_length */
1500        NULL,                           /* get_received_packets */
1501        linuxnative_get_filtered_packets,/* get_filtered_packets */
1502        linuxnative_get_dropped_packets,/* get_dropped_packets */
1503        linuxnative_get_captured_packets,/* get_captured_packets */
1504        linuxnative_get_fd,             /* get_fd */
1505        linuxring_event,                /* trace_event */
1506        linuxring_help,         /* help */
1507        NULL
1508};
1509
1510void linuxnative_constructor(void) {
1511        register_format(&linuxnative);
1512        register_format(&linuxring);
1513}
Note: See TracBrowser for help on using the repository browser.