source: lib/format_linux.c @ 50bbce8

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 50bbce8 was 50bbce8, checked in by Perry Lorier <perry@…>, 14 years ago

First pass implementation of loss recording framework.

  • Property mode set to 100644
File size: 15.7 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007 The University of Waikato, Hamilton, New Zealand.
5 * Authors: Daniel Lawson
6 *          Perry Lorier
7 *         
8 * All rights reserved.
9 *
10 * This code has been developed by the University of Waikato WAND
11 * research group. For further information please see http://www.wand.net.nz/
12 *
13 * libtrace is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * libtrace is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with libtrace; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 *
27 * $Id$
28 *
29 */
30
31#include "libtrace.h"
32#include "libtrace_int.h"
33#include "format_helper.h"
34#include "config.h"
35#include "stdlib.h"
36
37#ifdef HAVE_INTTYPES_H
38#  include <inttypes.h>
39#else
40# error "Can't find inttypes.h"
41#endif
42
43#include <sys/socket.h>
44#include <netpacket/packet.h>
45#include <net/ethernet.h>
46#include <net/if_arp.h>
47
48#include <string.h>
49#include <net/if.h>
50#include <sys/ioctl.h>
51#include <errno.h>
52
53#include <assert.h>
54
55struct tpacket_stats {
56        unsigned int tp_packets;
57        unsigned int tp_drops;
58};
59
60struct libtrace_format_data_t {
61        int fd;
62        int snaplen;
63        int promisc;
64        libtrace_filter_t *filter;
65        struct tpacket_stats stats;
66        int stats_valid;
67};
68
69struct libtrace_linuxnative_header {
70        struct timeval ts;
71        int wirelen;
72        int caplen;
73        struct sockaddr_ll hdr;
74};
75
76struct libtrace_linuxnative_format_data_t {
77        int fd;
78};
79
80#define FORMAT(x) ((struct libtrace_format_data_t*)(x))
81#define DATAOUT(x) ((struct libtrace_linuxnative_format_data_t*)((x)->format_data))
82
83static int linuxnative_init_input(libtrace_t *libtrace) 
84{
85        libtrace->format_data = (struct libtrace_format_data_t *)
86                malloc(sizeof(struct libtrace_format_data_t));
87        FORMAT(libtrace->format_data)->fd = -1;
88        FORMAT(libtrace->format_data)->promisc = -1;
89        FORMAT(libtrace->format_data)->snaplen = 65536;
90        FORMAT(libtrace->format_data)->filter = NULL;
91        FORMAT(libtrace->format_data)->stats_valid = 0;
92
93        return 0;
94}
95
96static int linuxnative_init_output(libtrace_out_t *libtrace)
97{
98        libtrace->format_data = (struct libtrace_linuxnative_format_data_t*)
99                malloc(sizeof(struct libtrace_linuxnative_format_data_t));
100        DATAOUT(libtrace)->fd = -1;
101
102        return 0;
103}
104
105static int linuxnative_start_input(libtrace_t *libtrace)
106{
107        struct sockaddr_ll addr;
108        int one = 1;
109        memset(&addr,0,sizeof(addr));
110        libtrace_filter_t *filter = FORMAT(libtrace->format_data)->filter;
111        FORMAT(libtrace->format_data)->fd = 
112                                socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
113        if (FORMAT(libtrace->format_data)->fd==-1) {
114                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Could not create raw socket");
115                free(libtrace->format_data);
116                return -1;
117        }
118        addr.sll_family = AF_PACKET;
119        addr.sll_protocol = htons(ETH_P_ALL);
120        if (strlen(libtrace->uridata)) {
121                addr.sll_ifindex = if_nametoindex(libtrace->uridata);
122                if (addr.sll_ifindex == 0) {
123                        close(FORMAT(libtrace->format_data)->fd);
124                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Failed to find interface %s", libtrace->uridata);
125                        free(libtrace->format_data);
126                        return -1;
127                }
128        }
129        else {
130                addr.sll_ifindex = 0;
131        }
132        if (bind(FORMAT(libtrace->format_data)->fd,
133                                (struct sockaddr*)&addr,
134                                (socklen_t)sizeof(addr))==-1) {
135                free(libtrace->format_data);
136                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Failed to bind to interface %s", libtrace->uridata);
137                return -1;
138        }
139
140        /* If promisc hasn't been specified, set it to "true" if we're
141         * capturing on one interface, or "false" if we're capturing on
142         * all interfaces.
143         */ 
144        if (FORMAT(libtrace->format_data)->promisc==-1) {
145                if (addr.sll_ifindex!=0)
146                        FORMAT(libtrace->format_data)->promisc=1;
147                else
148                        FORMAT(libtrace->format_data)->promisc=0;
149        }
150                               
151        if (FORMAT(libtrace->format_data)->promisc) {
152                struct packet_mreq mreq;
153                socklen_t socklen = sizeof(mreq);
154                memset(&mreq,0,sizeof(mreq));
155                mreq.mr_ifindex = addr.sll_ifindex;
156                mreq.mr_type = PACKET_MR_PROMISC;
157                setsockopt(FORMAT(libtrace->format_data)->fd,
158                                SOL_PACKET,
159                                PACKET_ADD_MEMBERSHIP,
160                                &mreq,
161                                socklen);
162        }
163
164        if (setsockopt(FORMAT(libtrace->format_data)->fd,
165                        SOL_SOCKET,
166                        SO_TIMESTAMP,
167                        &one,
168                        (socklen_t)sizeof(one))==-1) {
169                perror("setsockopt(SO_TIMESTAMP)");
170        }
171
172        /* Push BPF filter into the kernel. At this stage we can safely assume
173         * that the filterstring has been compiled, or the filter was supplied
174         * pre-compiled.
175         */
176        if (filter != NULL) {
177                assert(filter->flag == 1);
178                if (setsockopt(FORMAT(libtrace->format_data)->fd,
179                                        SOL_SOCKET,
180                                        SO_ATTACH_FILTER,
181                                        &filter->filter,
182                                        sizeof(filter->filter)) == -1) {
183                        perror("setsockopt(SO_ATTACH_FILTER)");
184                } else { 
185                        /* The socket accepted the filter, so we need to
186                         * consume any buffered packets that were received
187                         * between opening the socket and applying the filter.
188                         */
189                        void *buf = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
190                        while(recv(FORMAT(libtrace->format_data)->fd,
191                                        buf,
192                                        (size_t) LIBTRACE_PACKET_BUFSIZE,
193                                        MSG_DONTWAIT) != -1) { }
194                        free(buf);
195                }
196        }
197
198        FORMAT(libtrace->format_data)->stats_valid=0;
199                                       
200        return 0;
201}
202
203static int linuxnative_start_output(libtrace_out_t *libtrace)
204{
205        FORMAT(libtrace->format_data)->fd = 
206                                socket(PF_PACKET, SOCK_RAW, 0);
207        if (FORMAT(libtrace->format_data)->fd==-1) {
208                free(libtrace->format_data);
209                return -1;
210        }
211        FORMAT(libtrace->format_data)->stats_valid=0;
212
213        return 0;
214}
215
216static int linuxnative_pause_input(libtrace_t *libtrace)
217{
218        close(FORMAT(libtrace->format_data)->fd);
219        FORMAT(libtrace->format_data)->fd=-1;
220
221        return 0;
222}
223
224static int linuxnative_fin_input(libtrace_t *libtrace) 
225{
226        if (FORMAT(libtrace->format_data)->filter != NULL)
227                free(FORMAT(libtrace->format_data)->filter);
228        free(libtrace->format_data);
229       
230        return 0;
231}
232
233static int linuxnative_fin_output(libtrace_out_t *libtrace)
234{
235        close(DATAOUT(libtrace)->fd);
236        DATAOUT(libtrace)->fd=-1;
237        free(libtrace->format_data);
238        return 0;
239}
240
241static int linuxnative_configure_bpf(libtrace_t *libtrace, 
242                libtrace_filter_t *filter) {
243#ifdef HAVE_LIBPCAP
244        struct ifreq ifr;
245        unsigned int arphrd;
246        libtrace_dlt_t dlt;
247        libtrace_filter_t *f;
248        int sock;
249        pcap_t *pcap;
250
251        /* Take a copy of the filter object as it was passed in */
252        f = (libtrace_filter_t *) malloc(sizeof(libtrace_filter_t));
253        memcpy(f, filter, sizeof(libtrace_filter_t));
254       
255        /* If we are passed a filter with "flag" set to zero, then we must
256         * compile the filterstring before continuing. This involves
257         * determining the linktype, passing the filterstring to libpcap to
258         * compile, and saving the result for trace_start() to push into the
259         * kernel.
260         * If flag is set to one, then the filter was probably generated using
261         * trace_create_filter_from_bytecode() and so we don't need to do
262         * anything (we've just copied it above).
263         */
264        if (f->flag == 0) {
265                sock = socket(PF_INET, SOCK_STREAM, 0);
266                memset(&ifr, 0, sizeof(struct ifreq));
267                strncpy(ifr.ifr_name, libtrace->uridata, IF_NAMESIZE);
268                if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0) {
269                        perror("Can't get HWADDR for interface");
270                        return -1;
271                }
272                close(sock);
273
274                arphrd = ifr.ifr_hwaddr.sa_family;
275                dlt = libtrace_to_pcap_dlt(arphrd_type_to_libtrace(arphrd));
276
277                pcap = pcap_open_dead(dlt, 
278                                FORMAT(libtrace->format_data)->snaplen);
279
280                if (pcap_compile(pcap, &f->filter, f->filterstring, 0, 0) == -1) {
281                        perror("PCAP failed to compile the filterstring");
282                        return -1;
283                }
284
285                pcap_close(pcap);
286               
287                /* Set the "flag" to indicate that the filterstring has been
288                 * compiled
289                 */
290                f->flag = 1;
291        }
292       
293        if (FORMAT(libtrace->format_data)->filter != NULL)
294                free(FORMAT(libtrace->format_data)->filter);
295       
296        FORMAT(libtrace->format_data)->filter = f;
297       
298        return 0;
299#else
300        return -1
301#endif
302}
303static int linuxnative_config_input(libtrace_t *libtrace,
304                trace_option_t option,
305                void *data)
306{
307        switch(option) {
308                case TRACE_OPTION_SNAPLEN:
309                        FORMAT(libtrace->format_data)->snaplen=*(int*)data;
310                        return 0;
311                case TRACE_OPTION_PROMISC:
312                        FORMAT(libtrace->format_data)->promisc=*(int*)data;
313                        return 0;
314                case TRACE_OPTION_FILTER:
315                        return linuxnative_configure_bpf(libtrace, 
316                                        (libtrace_filter_t *) data);
317                case TRACE_OPTION_META_FREQ:
318                        /* No meta-data for this format */
319                        break;
320                case TRACE_OPTION_EVENT_REALTIME:
321                        break;
322                /* Avoid default: so that future options will cause a warning
323                 * here to remind us to implement it, or flag it as
324                 * unimplementable
325                 */
326        }
327       
328        /* Don't set an error - trace_config will try to deal with the
329         * option and will set an error if it fails */
330        return -1;
331}
332
333#define LIBTRACE_MIN(a,b) ((a)<(b) ? (a) : (b))
334
335/* 20 isn't enough on x86_64 */
336#define CMSG_BUF_SIZE 128
337static int linuxnative_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) 
338{
339        struct libtrace_linuxnative_header *hdr;
340        struct msghdr msghdr;
341        struct iovec iovec;
342        unsigned char controlbuf[CMSG_BUF_SIZE];
343        struct cmsghdr *cmsg;
344        socklen_t socklen;
345        int snaplen;
346
347        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
348                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
349                packet->buf_control = TRACE_CTRL_PACKET;
350        }
351
352        packet->header = packet->buffer;
353        packet->type = TRACE_RT_DATA_LINUX_NATIVE;
354        packet->payload = (char*)packet->buffer+sizeof(*hdr);
355
356        hdr=(struct libtrace_linuxnative_header*)packet->buffer;
357        socklen=sizeof(hdr->hdr);
358        snaplen=LIBTRACE_MIN(
359                        (int)LIBTRACE_PACKET_BUFSIZE-(int)sizeof(*hdr),
360                        (int)FORMAT(libtrace->format_data)->snaplen);
361
362        msghdr.msg_name = &hdr->hdr;
363        msghdr.msg_namelen = sizeof(struct sockaddr_ll);
364
365        msghdr.msg_iov = &iovec;
366        msghdr.msg_iovlen = 1;
367
368        msghdr.msg_control = &controlbuf;
369        msghdr.msg_controllen = CMSG_BUF_SIZE;
370        msghdr.msg_flags = 0;
371
372        iovec.iov_base = (void*)packet->payload;
373        iovec.iov_len = snaplen;
374
375        hdr->wirelen = recvmsg(FORMAT(libtrace->format_data)->fd, &msghdr, 0);
376
377        if (hdr->wirelen==-1) {
378                trace_set_err(libtrace,errno,"recvmsg");
379                return -1;
380        }
381
382        hdr->caplen=LIBTRACE_MIN(snaplen,hdr->wirelen);
383
384        for (cmsg = CMSG_FIRSTHDR(&msghdr);
385                        cmsg != NULL;
386                        cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
387                if (cmsg->cmsg_level == SOL_SOCKET
388                        && cmsg->cmsg_type == SO_TIMESTAMP
389                        && cmsg->cmsg_len <= CMSG_LEN(sizeof(struct timeval))) {
390                        memcpy(&hdr->ts, CMSG_DATA(cmsg),
391                                        sizeof(struct timeval));
392                        break;
393                }
394        }
395
396        if (cmsg == NULL && ioctl(FORMAT(libtrace->format_data)->fd,
397                                SIOCGSTAMP,&hdr->ts)==-1)
398                perror("ioctl(SIOCGSTAMP)");
399
400        return hdr->wirelen+sizeof(*hdr);
401}
402
403static int linuxnative_write_packet(libtrace_out_t *trace, 
404                libtrace_packet_t *packet) 
405{
406        struct sockaddr_ll hdr;
407
408        hdr.sll_family = AF_PACKET;
409        hdr.sll_protocol = 0;
410        hdr.sll_ifindex = if_nametoindex(trace->uridata);
411        hdr.sll_hatype = 0;
412        hdr.sll_pkttype = 0;
413        hdr.sll_halen = htons(6); /* FIXME */
414        memcpy(hdr.sll_addr,packet->payload,(size_t)hdr.sll_halen);
415
416        return sendto(DATAOUT(trace)->fd,
417                        packet->payload,
418                        trace_get_capture_length(packet),
419                        0,
420                        (struct sockaddr*)&hdr, (socklen_t)sizeof(hdr));
421
422}
423
424static libtrace_linktype_t linuxnative_get_link_type(const struct libtrace_packet_t *packet) {
425        int linktype=(((struct libtrace_linuxnative_header*)(packet->buffer))
426                                ->hdr.sll_hatype);
427        switch (linktype) {
428                case ARPHRD_ETHER:
429                        return TRACE_TYPE_ETH;
430                case ARPHRD_PPP:
431                        return TRACE_TYPE_NONE;
432                case ARPHRD_80211_RADIOTAP:
433                        return TRACE_TYPE_80211_RADIO;
434                case ARPHRD_IEEE80211:
435                        return TRACE_TYPE_80211;
436                case ARPHRD_SIT:
437                        return TRACE_TYPE_NONE;
438                default: /* shrug, beyond me! */
439                        printf("unknown Linux ARPHRD type 0x%04x\n",linktype);
440                        return (libtrace_linktype_t)~0U;
441        }
442}
443
444static libtrace_direction_t linuxnative_get_direction(const struct libtrace_packet_t *packet) {
445        switch (((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype) {
446                case PACKET_OUTGOING:
447                case PACKET_LOOPBACK:
448                        return TRACE_DIR_OUTGOING;
449                default:
450                        return TRACE_DIR_INCOMING;
451        }
452}
453
454static libtrace_direction_t linuxnative_set_direction(
455                libtrace_packet_t *packet,
456                libtrace_direction_t direction) {
457
458        switch (direction) {
459                case TRACE_DIR_OUTGOING:
460                        ((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype = PACKET_OUTGOING;
461                        return TRACE_DIR_OUTGOING;
462                case TRACE_DIR_INCOMING:
463                        ((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype = PACKET_HOST;
464                        return TRACE_DIR_INCOMING;
465                default:
466                        return -1;
467        }
468}
469
470static struct timeval linuxnative_get_timeval(const libtrace_packet_t *packet) 
471{
472        return ((struct libtrace_linuxnative_header*)(packet->buffer))->ts;
473}
474
475static int linuxnative_get_capture_length(const libtrace_packet_t *packet)
476{
477        return ((struct libtrace_linuxnative_header*)(packet->buffer))->caplen;
478}
479
480static int linuxnative_get_wire_length(const libtrace_packet_t *packet) 
481{
482        return ((struct libtrace_linuxnative_header*)(packet->buffer))->wirelen;
483}
484
485static int linuxnative_get_framing_length(UNUSED
486                const libtrace_packet_t *packet) 
487{
488        return sizeof(struct libtrace_linuxnative_header);
489}
490
491static int linuxnative_get_fd(const libtrace_t *trace) {
492        return FORMAT(trace->format_data)->fd;
493}
494
495static uint64_t linuxnative_get_captured_packets(libtrace_t *trace) {
496        if (FORMAT(trace->format_data)->stats_valid != 2) {
497                socklen_t len = sizeof(FORMAT(trace->format_data)->stats);
498                getsockopt(FORMAT(trace->format_data)->fd, 
499                                SOL_PACKET,
500                                PACKET_STATISTICS,
501                                &FORMAT(trace->format_data)->stats,
502                                &len);
503                FORMAT(trace->format_data)->stats_valid = 1;
504        }
505
506        return FORMAT(trace->format_data)->stats.tp_packets;
507}
508
509static uint64_t linuxnative_get_dropped_packets(libtrace_t *trace) {
510        if (FORMAT(trace->format_data)->stats_valid != 1) {
511                socklen_t len = sizeof(FORMAT(trace->format_data)->stats);
512                getsockopt(FORMAT(trace->format_data)->fd, 
513                                SOL_PACKET,
514                                PACKET_STATISTICS,
515                                &FORMAT(trace->format_data)->stats,
516                                &len);
517                FORMAT(trace->format_data)->stats_valid = 2;
518        }
519
520        return FORMAT(trace->format_data)->stats.tp_drops;
521}
522
523static void linuxnative_help(void) {
524        printf("linuxnative format module: $Revision$\n");
525        printf("Supported input URIs:\n");
526        printf("\tint:\n");
527        printf("\n");
528        printf("Supported output URIs:\n");
529        printf("\tnone\n");
530        printf("\n");
531        return;
532}
533static struct libtrace_format_t linuxnative = {
534        "int",
535        "$Id$",
536        TRACE_FORMAT_LINUX_NATIVE,
537        linuxnative_init_input,         /* init_input */
538        linuxnative_config_input,       /* config_input */
539        linuxnative_start_input,        /* start_input */
540        linuxnative_pause_input,        /* pause_input */
541        linuxnative_init_output,        /* init_output */
542        NULL,                           /* config_output */
543        linuxnative_start_output,       /* start_ouput */
544        linuxnative_fin_input,          /* fin_input */
545        linuxnative_fin_output,         /* fin_output */
546        linuxnative_read_packet,        /* read_packet */
547        NULL,                           /* fin_packet */
548        linuxnative_write_packet,       /* write_packet */
549        linuxnative_get_link_type,      /* get_link_type */
550        linuxnative_get_direction,      /* get_direction */
551        linuxnative_set_direction,      /* set_direction */
552        NULL,                           /* get_erf_timestamp */
553        linuxnative_get_timeval,        /* get_timeval */
554        NULL,                           /* get_seconds */
555        NULL,                           /* seek_erf */
556        NULL,                           /* seek_timeval */
557        NULL,                           /* seek_seconds */
558        linuxnative_get_capture_length, /* get_capture_length */
559        linuxnative_get_wire_length,    /* get_wire_length */
560        linuxnative_get_framing_length, /* get_framing_length */
561        NULL,                           /* set_capture_length */
562        NULL,                           /* get_received_packets */
563        NULL,                           /* get_filtered_packets */
564        linuxnative_get_dropped_packets,/* get_dropped_packets */
565        linuxnative_get_captured_packets,/* get_captured_packets */
566        linuxnative_get_fd,             /* get_fd */
567        trace_event_device,             /* trace_event */
568        linuxnative_help,               /* help */
569        NULL
570};
571
572void linuxnative_constructor(void) {
573        register_format(&linuxnative);
574}
Note: See TracBrowser for help on using the repository browser.