source: lib/format_linux.c @ 035f8a7

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivelibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 035f8a7 was 035f8a7, checked in by Dan Collins <dan@…>, 6 years ago

Massive refactor that involves moving ring out into its own file.

format_linux is pretty unmaintainable the way it is, so this branch covers
trying to fix that. Ring is basically a subclass of native, so we use OOP
techniques to reduce code duplication. Putting ring in its own file makes
maintaining the code a lot easier as there is less code to read.

The ring format has been spun off, we just need to finish tidying the
native format (stripping out ring, FORMAT(x) turns to FORMAT_DATA etc).
There's bound to be errors in getting it going, but it should be fairly
smooth sailing.

Finally, work was started in moving from the old format design to the
new format design where threaded or not there is a list holding the
per_stream format data.

  • Property mode set to 100644
File size: 33.3 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/* This format module deals with using the Linux Native capture format.
36 *
37 * Linux Native is a LIVE capture format.
38 *
39 * This format also supports writing which will write packets out to the
40 * network as a form of packet replay. This should not be confused with the
41 * RT protocol which is intended to transfer captured packet records between
42 * RT-speaking programs.
43 */
44
45#include "config.h"
46#include "libtrace.h"
47#include "libtrace_int.h"
48#include "format_helper.h"
49#include "libtrace_arphrd.h"
50#include <stdlib.h>
51#include <errno.h>
52#include <unistd.h>
53#include <string.h>
54#include <assert.h>
55
56#ifdef HAVE_INTTYPES_H
57#  include <inttypes.h>
58#else
59# error "Can't find inttypes.h"
60#endif
61
62#include "format_linux.h"
63
64
65#ifdef HAVE_NETPACKET_PACKET_H
66static int linuxnative_probe_filename(const char *filename)
67{
68        /* Is this an interface? */
69        return (if_nametoindex(filename) != 0);
70}
71
72static int linuxnative_init_input(libtrace_t *libtrace)
73{
74        struct linux_per_stream_t stream_data;
75
76        libtrace->format_data = (struct linux_format_data_t *)
77                malloc(sizeof(struct linux_format_data_t));
78        assert(libtrace->format_data != NULL);
79
80        FORMAT_DATA->per_stream =
81                libtrace_list_init(sizeof(stream_data));
82        assert(FORMAT_DATA->per_stream != NULL);
83
84        /* We'll start with just one instance of stream_data, and we'll
85         * add more later if we need them */
86        memset(&stream_data, 0, sizeof(stream_data));
87        libtrace_list_push_back(FORMAT_DATA->per_stream, &stream_data);
88
89        FORMAT_DATA_FIRST->fd = -1;
90        FORMAT_DATA->promisc = -1;
91        FORMAT_DATA->snaplen = LIBTRACE_PACKET_BUFSIZE;
92        FORMAT_DATA->filter = NULL;
93        FORMAT_DATA->stats_valid = 0;
94        FORMAT_DATA->fanout_flags = PACKET_FANOUT_LB;
95        /* Some examples use pid for the group however that would limit a single
96         * application to use only int/ring format, instead using rand */
97        FORMAT_DATA->fanout_group = (uint16_t) rand();
98        FORMAT_DATA->format = TRACE_RT_DATA_LINUX_NATIVE;
99
100        return 0;
101}
102
103static int linuxnative_init_output(libtrace_out_t *libtrace)
104{
105        libtrace->format_data = (struct linux_output_format_data_t*)
106                malloc(sizeof(struct linux_output_format_data_t));
107        assert(libtrace->format_data != NULL);
108
109        FORMAT_DATA_OUT->fd = -1;
110        FORMAT_DATA_OUT->tx_ring = NULL;
111        FORMAT_DATA_OUT->txring_offset = 0;
112        FORMAT_DATA_OUT->queue = 0;
113        FORMAT_DATA_OUT->max_order = MAX_ORDER;
114        FORMAT_DATA_OUT->format = TRACE_FORMAT_LINUX_NATIVE;
115
116        return 0;
117}
118
119static int linuxnative_start_input(libtrace_t *libtrace)
120{
121        struct sockaddr_ll addr;
122        int one = 1;
123        memset(&addr,0,sizeof(addr));
124        libtrace_filter_t *filter = FORMAT_DATA->filter;
125
126        /* Create a raw socket for reading packets on */
127        FORMAT_DATA_FIRST->fd =
128                socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
129        if (FORMAT_DATA_FIRST->fd==-1) {
130                trace_set_err(libtrace, errno, "Could not create raw socket");
131                free(libtrace->format_data);
132                libtrace->format_data = NULL;
133                return -1;
134        }
135
136        /* Bind to the capture interface */
137        addr.sll_family = AF_PACKET;
138        addr.sll_protocol = htons(ETH_P_ALL);
139        if (strlen(libtrace->uridata)) {
140                addr.sll_ifindex = if_nametoindex(libtrace->uridata);
141                if (addr.sll_ifindex == 0) {
142                        close(FORMAT_DATA_FIRST->fd);
143                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
144                                      "Failed to find interface %s",
145                                      libtrace->uridata);
146                        free(libtrace->format_data);
147                        libtrace->format_data = NULL;
148                        return -1;
149                }
150        } else {
151                addr.sll_ifindex = 0;
152        }
153        if (bind(FORMAT_DATA_FIRST->fd,
154                 (struct sockaddr*)&addr,
155                 (socklen_t)sizeof(addr))==-1) {
156                free(libtrace->format_data);
157                libtrace->format_data = NULL;
158                trace_set_err(libtrace, errno,
159                              "Failed to bind to interface %s",
160                              libtrace->uridata);
161                return -1;
162        }
163
164        /* If promisc hasn't been specified, set it to "true" if we're
165         * capturing on one interface, or "false" if we're capturing on
166         * all interfaces.
167         */
168        if (FORMAT_DATA->promisc==-1) {
169                if (addr.sll_ifindex!=0)
170                        FORMAT_DATA->promisc=1;
171                else
172                        FORMAT_DATA->promisc=0;
173        }
174
175        /* Enable promiscuous mode, if requested */
176        if (FORMAT_DATA->promisc) {
177                struct packet_mreq mreq;
178                socklen_t socklen = sizeof(mreq);
179                memset(&mreq,0,sizeof(mreq));
180                mreq.mr_ifindex = addr.sll_ifindex;
181                mreq.mr_type = PACKET_MR_PROMISC;
182                if (setsockopt(FORMAT_DATA_FIRST->fd,
183                               SOL_PACKET,
184                               PACKET_ADD_MEMBERSHIP,
185                               &mreq,
186                               socklen)==-1) {
187                        perror("setsockopt(PROMISC)");
188                }
189        }
190
191        /* Set the timestamp option on the socket - aim for the most detailed
192         * clock resolution possible */
193#ifdef SO_TIMESTAMPNS
194        if (setsockopt(FORMAT_DATA_FIRST->fd,
195                       SOL_SOCKET,
196                       SO_TIMESTAMPNS,
197                       &one,
198                       (socklen_t)sizeof(one))!=-1) {
199                FORMAT_DATA->timestamptype = TS_TIMESPEC;
200        }
201        else
202        /* DANGER: This is a dangling else to only do the next setsockopt()
203         * if we fail the first! */
204#endif
205                if (setsockopt(FORMAT_DATA_FIRST->fd,
206                               SOL_SOCKET,
207                               SO_TIMESTAMP,
208                               &one,
209                               (socklen_t)sizeof(one))!=-1) {
210                        FORMAT_DATA->timestamptype = TS_TIMEVAL;
211                }
212                else
213                        FORMAT_DATA->timestamptype = TS_NONE;
214
215        /* Push BPF filter into the kernel. At this stage we can safely assume
216         * that the filterstring has been compiled, or the filter was supplied
217         * pre-compiled.
218         */
219        if (filter != NULL) {
220                /* Check if the filter was successfully compiled. If not,
221                 * it is probably a bad filter and we should return an error
222                 * before the caller tries to read any packets */
223                if (filter->flag == 0) {
224                        return -1;
225                }
226
227                if (setsockopt(FORMAT_DATA_FIRST->fd,
228                               SOL_SOCKET,
229                               SO_ATTACH_FILTER,
230                               &filter->filter,
231                               sizeof(filter->filter)) == -1) {
232                        perror("setsockopt(SO_ATTACH_FILTER)");
233                } else {
234                        /* The socket accepted the filter, so we need to
235                         * consume any buffered packets that were received
236                         * between opening the socket and applying the filter.
237                         */
238                        void *buf = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
239                        while(recv(FORMAT_DATA_FIRST->fd,
240                                   buf,
241                                   (size_t)LIBTRACE_PACKET_BUFSIZE,
242                                   MSG_DONTWAIT) != -1) { }
243                        free(buf);
244                }
245        }
246
247        FORMAT_DATA->stats_valid = 0;
248
249        return 0;
250}
251
252/**
253 * Converts a socket, either packet_mmap or standard raw socket into a
254 * fanout socket.
255 * NOTE: This means we can read from the socket with multiple queues,
256 * each must be setup (identically) and then this called upon them
257 *
258 * @return 0 success, -1 error
259 */
260static inline int socket_to_packet_fanout(int fd,
261                                          uint16_t fanout_flags,
262                                          uint16_t fanout_group)
263{
264        int fanout_opt = ((int)fanout_flags << 16) | (int)fanout_group;
265        if (setsockopt(fd, SOL_PACKET, PACKET_FANOUT,
266                        &fanout_opt, sizeof(fanout_opt)) == -1) {
267                return -1;
268        }
269        return 0;
270}
271
272static int linuxnative_pstart_input(libtrace_t *libtrace) {
273        int i = 0;
274        int tot = libtrace->perpkt_thread_count;
275        int iserror = 0;
276        // We store this here otherwise it will be leaked if the memory doesn't know
277        struct linux_per_thread_t *per_thread = NULL;
278       
279        if (!FORMAT(libtrace->format_data)->per_thread) {
280                //per_thread = calloc(tot, sizeof(struct linux_per_thread_t));
281                posix_memalign((void **)&per_thread, CACHE_LINE_SIZE, tot*sizeof(struct linux_per_thread_t));
282                FORMAT(libtrace->format_data)->per_thread = per_thread;
283        } else {
284                // Whats going on this might not work 100%
285                // We assume all sockets have been closed ;)
286                printf("Pause and then start called again lets hope that perpkt_thread_count hasn't changed\n");
287        }
288       
289        printf("Calling native pstart packet\n");
290        for (i = 0; i < tot; ++i)
291        {
292                if (FORMAT(libtrace->format_data)->format == TRACE_RT_DATA_LINUX_NATIVE) {
293                        if (linuxnative_start_input(libtrace) != 0) {
294                                iserror = 1;
295                                break;
296                        }
297                } else {
298                        // This must be ring
299                        if (linuxring_start_input(libtrace) != 0) {
300                                iserror = 1;
301                                break;
302                        }
303                }
304                if (socket_to_packet_fanout(FORMAT(libtrace->format_data)->fd, FORMAT(libtrace->format_data)->fanout_flags, FORMAT(libtrace->format_data)->fanout_group) != 0)
305                {
306                        iserror = 1;
307                        // Clean up here to keep consistent with every one else
308                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Converting the fd to a socket fanout failed");
309                        close(FORMAT(libtrace->format_data)->fd);
310                        free(libtrace->format_data);
311                        libtrace->format_data = NULL;
312                        break;
313                }
314                per_thread[i].fd = FORMAT(libtrace->format_data)->fd;
315                if (FORMAT(libtrace->format_data)->format == TRACE_RT_DATA_LINUX_RING) {
316                        per_thread[i].rxring_offset = FORMAT(libtrace->format_data)->rxring_offset;
317                        per_thread[i].rx_ring = FORMAT(libtrace->format_data)->rx_ring;
318                }
319        }
320       
321        // Roll back those that failed - by this point in time the format_data
322        // has been freed
323        if (iserror) {
324                for (i = i - 1; i >= 0; i--) {
325                        close(per_thread[i].fd);
326                }
327                free(per_thread);
328                per_thread = NULL;
329                return -1;
330        }
331       
332        return 0;
333}
334
335static int linux_pregister_thread(libtrace_t *libtrace, libtrace_thread_t *t, bool reading) {
336        fprintf(stderr, "registering thread %d!!\n", t->perpkt_num);
337    if (reading) {
338        if(t->type == THREAD_PERPKT) {
339            t->format_data = &FORMAT(libtrace->format_data)->per_thread[t->perpkt_num];
340        } else {
341            t->format_data = &FORMAT(libtrace->format_data)->per_thread[0];
342        }
343    }
344    return 0;
345}
346
347static int linuxnative_start_output(libtrace_out_t *libtrace)
348{
349        DATAOUT(libtrace)->fd = socket(PF_PACKET, SOCK_RAW, 0);
350        if (DATAOUT(libtrace)->fd==-1) {
351                free(DATAOUT(libtrace));
352                return -1;
353        }
354
355        return 0;
356}
357
358
359static int linuxnative_pause_input(libtrace_t *libtrace)
360{
361        libtrace_list_node_t *tmp = FORMAT_DATA_HEAD;
362
363        /* Stop and detach each stream */
364        while (tmp != NULL) {
365                close(STREAM_DATA(tmp)->fd);
366                tmp = tmp->next;
367        }
368
369        return 0;
370}
371
372static int linuxnative_fin_input(libtrace_t *libtrace)
373{
374        if (libtrace->format_data) {
375                if (FORMAT_DATA->filter != NULL)
376                        free(FORMAT_DATA->filter);
377
378                if (FORMAT_DATA->per_stream)
379                        libtrace_list_deinit(FORMAT_DATA->per_stream);
380
381                free(libtrace->format_data);
382        }
383
384        return 0;
385}
386
387static int linuxnative_fin_output(libtrace_out_t *libtrace)
388{
389        close(DATAOUT(libtrace)->fd);
390        DATAOUT(libtrace)->fd=-1;
391        free(libtrace->format_data);
392        return 0;
393}
394
395/* Compiles a libtrace BPF filter for use with a linux native socket */
396static int linuxnative_configure_bpf(libtrace_t *libtrace, 
397                libtrace_filter_t *filter) {
398#ifdef HAVE_LIBPCAP
399        struct ifreq ifr;
400        unsigned int arphrd;
401        libtrace_dlt_t dlt;
402        libtrace_filter_t *f;
403        int sock;
404        pcap_t *pcap;
405
406        /* Take a copy of the filter object as it was passed in */
407        f = (libtrace_filter_t *) malloc(sizeof(libtrace_filter_t));
408        memcpy(f, filter, sizeof(libtrace_filter_t));
409       
410        /* If we are passed a filter with "flag" set to zero, then we must
411         * compile the filterstring before continuing. This involves
412         * determining the linktype, passing the filterstring to libpcap to
413         * compile, and saving the result for trace_start() to push into the
414         * kernel.
415         * If flag is set to one, then the filter was probably generated using
416         * trace_create_filter_from_bytecode() and so we don't need to do
417         * anything (we've just copied it above).
418         */
419        if (f->flag == 0) {
420                sock = socket(PF_INET, SOCK_STREAM, 0);
421                memset(&ifr, 0, sizeof(struct ifreq));
422                strncpy(ifr.ifr_name, libtrace->uridata, IF_NAMESIZE);
423                if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0) {
424                        perror("Can't get HWADDR for interface");
425                        return -1;
426                }
427                close(sock);
428
429                arphrd = ifr.ifr_hwaddr.sa_family;
430                dlt = libtrace_to_pcap_dlt(arphrd_type_to_libtrace(arphrd));
431
432                pcap = pcap_open_dead(dlt, 
433                                FORMAT(libtrace->format_data)->snaplen);
434
435                if (pcap_compile(pcap, &f->filter, f->filterstring, 0, 0) == -1) {
436                        /* Filter didn't compile, set flag to 0 so we can
437                         * detect this when trace_start() is called and
438                         * produce a useful error
439                         */
440                        f->flag = 0;
441                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, 
442                                        "Failed to compile BPF filter (%s): %s",
443                                        f->filterstring, pcap_geterr(pcap));
444                } else {
445                        /* Set the "flag" to indicate that the filterstring
446                         * has been compiled
447                         */
448                        f->flag = 1;
449                }
450
451                pcap_close(pcap);
452               
453        }
454       
455        if (FORMAT(libtrace->format_data)->filter != NULL)
456                free(FORMAT(libtrace->format_data)->filter);
457       
458        FORMAT(libtrace->format_data)->filter = f;
459       
460        return 0;
461#else
462        return -1
463#endif
464}
465static int linuxnative_config_input(libtrace_t *libtrace,
466                trace_option_t option,
467                void *data)
468{
469        switch(option) {
470                case TRACE_OPTION_SNAPLEN:
471                        FORMAT(libtrace->format_data)->snaplen=*(int*)data;
472                        return 0;
473                case TRACE_OPTION_PROMISC:
474                        FORMAT(libtrace->format_data)->promisc=*(int*)data;
475                        return 0;
476                case TRACE_OPTION_FILTER:
477                        return linuxnative_configure_bpf(libtrace, 
478                                        (libtrace_filter_t *) data);
479                case TRACE_OPTION_META_FREQ:
480                        /* No meta-data for this format */
481                        break;
482                case TRACE_OPTION_EVENT_REALTIME:
483                        /* Live captures are always going to be in trace time */
484                        break;
485                /* Avoid default: so that future options will cause a warning
486                 * here to remind us to implement it, or flag it as
487                 * unimplementable
488                 */
489        }
490       
491        /* Don't set an error - trace_config will try to deal with the
492         * option and will set an error if it fails */
493        return -1;
494}
495#endif /* HAVE_NETPACKET_PACKET_H */
496
497
498static int linuxnative_pconfig_input(libtrace_t *libtrace,
499                trace_parallel_option_t option,
500                void *data)
501{
502        switch(option) {
503                case TRACE_OPTION_SET_HASHER:
504                        switch (*((enum hasher_types *)data)) {
505                                case HASHER_BALANCE:
506                                        // Do fanout
507                                        FORMAT(libtrace->format_data)->fanout_flags = PACKET_FANOUT_LB;
508                                        // Or we could balance to the CPU
509                                        return 0;
510                                case HASHER_BIDIRECTIONAL:
511                                case HASHER_UNIDIRECTIONAL:
512                                        FORMAT(libtrace->format_data)->fanout_flags = PACKET_FANOUT_HASH;
513                                        return 0;
514                                case HASHER_CUSTOM:
515                                case HASHER_HARDWARE:
516                                        return -1;
517                        }
518                        break;
519                /* Avoid default: so that future options will cause a warning
520                 * here to remind us to implement it, or flag it as
521                 * unimplementable
522                 */
523        }
524       
525        /* Don't set an error - trace_config will try to deal with the
526         * option and will set an error if it fails */
527        return -1;
528}
529
530
531static int linuxnative_prepare_packet(libtrace_t *libtrace UNUSED, 
532                libtrace_packet_t *packet, void *buffer, 
533                libtrace_rt_types_t rt_type, uint32_t flags) {
534
535        if (packet->buffer != buffer &&
536                        packet->buf_control == TRACE_CTRL_PACKET) {
537                free(packet->buffer);
538        }
539
540        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
541                packet->buf_control = TRACE_CTRL_PACKET;
542        } else
543                packet->buf_control = TRACE_CTRL_EXTERNAL;
544
545
546        packet->buffer = buffer;
547        packet->header = buffer;
548        packet->payload = (char *)buffer + 
549                sizeof(struct libtrace_linuxnative_header);
550        packet->type = rt_type;
551
552        /*
553        if (libtrace->format_data == NULL) {
554                if (linuxnative_init_input(libtrace))
555                        return -1;
556        }
557        */
558        return 0;
559       
560}
561
562
563#define LIBTRACE_MIN(a,b) ((a)<(b) ? (a) : (b))
564
565/* 20 isn't enough on x86_64 */
566#define CMSG_BUF_SIZE 128
567
568#ifdef HAVE_NETPACKET_PACKET_H
569libtrace_thread_t * get_thread_table(libtrace_t *libtrace) ;
570inline static int linuxnative_read_packet_fd(libtrace_t *libtrace, libtrace_packet_t *packet, int fd, const int check_queue) 
571{
572        struct libtrace_linuxnative_header *hdr;
573        struct msghdr msghdr;
574        struct iovec iovec;
575        unsigned char controlbuf[CMSG_BUF_SIZE];
576        struct cmsghdr *cmsg;
577        int snaplen;
578
579        uint32_t flags = 0;
580        fd_set readfds;
581        struct timeval tout;
582        int ret;
583       
584        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
585                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
586                if (!packet->buffer) {
587                        perror("Cannot allocate buffer");
588                }
589        }
590
591        flags |= TRACE_PREP_OWN_BUFFER;
592       
593        packet->type = TRACE_RT_DATA_LINUX_NATIVE;
594
595        hdr=(struct libtrace_linuxnative_header*)packet->buffer;
596        snaplen=LIBTRACE_MIN(
597                        (int)LIBTRACE_PACKET_BUFSIZE-(int)sizeof(*hdr),
598                        (int)FORMAT(libtrace->format_data)->snaplen);
599        /* Prepare the msghdr and iovec for the kernel to write the
600         * captured packet into. The msghdr will point to the part of our
601         * buffer reserved for sll header, while the iovec will point at
602         * the buffer following the sll header. */
603
604        msghdr.msg_name = &hdr->hdr;
605        msghdr.msg_namelen = sizeof(struct sockaddr_ll);
606
607        msghdr.msg_iov = &iovec;
608        msghdr.msg_iovlen = 1;
609
610        msghdr.msg_control = &controlbuf;
611        msghdr.msg_controllen = CMSG_BUF_SIZE;
612        msghdr.msg_flags = 0;
613
614        iovec.iov_base = (void*)(packet->buffer+sizeof(*hdr));
615        iovec.iov_len = snaplen;
616       
617        if (check_queue) {
618                // Check for a packet - TODO only Linux has MSG_DONTWAIT should use fctl O_NONBLOCK
619                hdr->wirelen = recvmsg(fd, &msghdr, MSG_DONTWAIT | MSG_TRUNC);
620                if ((int) hdr->wirelen == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
621                        // Do message queue check or select
622                        int ret;
623                        fd_set rfds;
624                        FD_ZERO(&rfds);
625                        FD_SET(fd, &rfds);
626                        FD_SET(get_thread_table(libtrace)->messages.pipefd[0], &rfds);
627                        int largestfd = fd > get_thread_table(libtrace)->messages.pipefd[0] ? fd : get_thread_table(libtrace)->messages.pipefd[0];
628                        do {
629                                ret = select(largestfd+1, &rfds, NULL, NULL, NULL);
630                                if (ret == -1 && errno != EINTR)
631                                        perror("Select() failed");
632                        }
633                        while (ret == -1);
634                       
635                        assert (ret == 1 || ret == 2); // No timeout 0 is not an option
636                       
637                        if (FD_ISSET(get_thread_table(libtrace)->messages.pipefd[0], &rfds)) {
638                                // Not an error but check the message queue we have something
639                                return -2;
640                        }
641                        // Otherwise we must have a packet
642                        hdr->wirelen = recvmsg(fd, &msghdr, MSG_TRUNC);
643                }
644        } else {
645        /* Use select to allow us to time out occasionally to check if someone
646         * has hit Ctrl-C or otherwise wants us to stop reading and return
647         * so they can exit their program.
648         */
649
650        while (1) {
651                tout.tv_sec = 0;
652                tout.tv_usec = 500000;
653                FD_ZERO(&readfds);
654                FD_SET(FORMAT(libtrace->format_data)->fd, &readfds);
655
656                ret = select(FORMAT(libtrace->format_data)->fd + 1, &readfds,
657                                NULL, NULL, &tout);
658                if (ret < 0 && errno != EINTR) {
659                        trace_set_err(libtrace, errno, "select");
660                        return -1;
661                } else if (ret < 0) {
662                        continue;
663                } 
664               
665                if (FD_ISSET(FORMAT(libtrace->format_data)->fd, &readfds)) {
666                        /* There's something available for us to read */
667                        break;
668                }
669
670               
671                /* If we get here, we timed out -- check if we should halt */
672                if (libtrace_halt)
673                        return 0;
674        }
675        hdr->wirelen = recvmsg(FORMAT(libtrace->format_data)->fd, &msghdr, MSG_TRUNC);
676        }
677
678       
679        if (hdr->wirelen==~0U) {
680                trace_set_err(libtrace,errno,"recvmsg");
681                return -1;
682        }
683
684        hdr->caplen=LIBTRACE_MIN((unsigned int)snaplen,(unsigned int)hdr->wirelen);
685
686        /* Extract the timestamps from the msghdr and store them in our
687         * linux native encapsulation, so that we can preserve the formatting
688         * across multiple architectures */
689
690        for (cmsg = CMSG_FIRSTHDR(&msghdr);
691                        cmsg != NULL;
692                        cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
693                if (cmsg->cmsg_level == SOL_SOCKET
694                        && cmsg->cmsg_type == SO_TIMESTAMP
695                        && cmsg->cmsg_len <= CMSG_LEN(sizeof(struct timeval))) {
696                       
697                        struct timeval *tv;
698                        tv = (struct timeval *)CMSG_DATA(cmsg);
699                       
700                       
701                        hdr->tv.tv_sec = tv->tv_sec;
702                        hdr->tv.tv_usec = tv->tv_usec;
703                        hdr->timestamptype = TS_TIMEVAL;
704                        break;
705                } 
706#ifdef SO_TIMESTAMPNS
707                else if (cmsg->cmsg_level == SOL_SOCKET
708                        && cmsg->cmsg_type == SO_TIMESTAMPNS
709                        && cmsg->cmsg_len <= CMSG_LEN(sizeof(struct timespec))) {
710
711                        struct timespec *tv;
712                        tv = (struct timespec *)CMSG_DATA(cmsg);
713
714                        hdr->ts.tv_sec = tv->tv_sec;
715                        hdr->ts.tv_nsec = tv->tv_nsec;
716                        hdr->timestamptype = TS_TIMESPEC;
717                        break;
718                }
719#endif
720        }
721
722        /* Did we not get given a timestamp? Try to get one from the
723         * file descriptor directly */
724        if (cmsg == NULL) {
725                struct timeval tv;
726                if (ioctl(fd, SIOCGSTAMP,&tv)==0) {
727                        hdr->tv.tv_sec = tv.tv_sec;
728                        hdr->tv.tv_usec = tv.tv_usec;
729                        hdr->timestamptype = TS_TIMEVAL;
730                }
731                else {
732                        hdr->timestamptype = TS_NONE;
733                }
734        }
735
736        /* Buffer contains all of our packet (including our custom header) so
737         * we just need to get prepare_packet to set all our packet pointers
738         * appropriately */
739       
740        if (linuxnative_prepare_packet(libtrace, packet, packet->buffer,
741                                packet->type, flags))
742                return -1;
743       
744        return hdr->wirelen+sizeof(*hdr);
745}
746
747static int linuxnative_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) 
748{
749        int fd = FORMAT(libtrace->format_data)->fd;
750        return linuxnative_read_packet_fd(libtrace, packet, fd, 0);
751}
752
753static int linuxnative_pread_packets(libtrace_t *libtrace,
754                                     libtrace_thread_t *t,
755                                     libtrace_packet_t **packets,
756                                     UNUSED size_t nb_packets) {
757        /* For now just read one packet */
758        int fd = PERPKT_FORMAT(t)->fd;
759        packets[0]->error = linuxnative_read_packet_fd(libtrace, packets[0],
760                                                       fd, 1);
761        if (packets[0]->error >= 1)
762                return 1;
763        else
764                return packets[0]->error;
765}
766
767static int linuxnative_write_packet(libtrace_out_t *trace, 
768                libtrace_packet_t *packet) 
769{
770        struct sockaddr_ll hdr;
771        int ret = 0;
772
773        if (trace_get_link_type(packet) == TRACE_TYPE_NONDATA)
774                return 0;
775
776        hdr.sll_family = AF_PACKET;
777        hdr.sll_protocol = 0;
778        hdr.sll_ifindex = if_nametoindex(trace->uridata);
779        hdr.sll_hatype = 0;
780        hdr.sll_pkttype = 0;
781        hdr.sll_halen = htons(6); /* FIXME */
782        memcpy(hdr.sll_addr,packet->payload,(size_t)ntohs(hdr.sll_halen));
783
784        /* This is pretty easy, just send the payload using sendto() (after
785         * setting up the sll header properly, of course) */
786        ret = sendto(DATAOUT(trace)->fd,
787                        packet->payload,
788                        trace_get_capture_length(packet),
789                        0,
790                        (struct sockaddr*)&hdr, (socklen_t)sizeof(hdr));
791
792        if (ret < 0) {
793                trace_set_err_out(trace, errno, "sendto failed");
794        }
795
796        return ret;
797}
798#endif /* HAVE_NETPACKET_PACKET_H */
799
800
801static libtrace_linktype_t linuxnative_get_link_type(const struct libtrace_packet_t *packet) {
802        uint16_t linktype=(((struct libtrace_linuxnative_header*)(packet->buffer))
803                                ->hdr.sll_hatype);
804        return get_libtrace_link_type(linktype);
805}
806
807static libtrace_direction_t linuxnative_get_direction(const struct libtrace_packet_t *packet) {
808        return get_libtrace_direction(((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype);
809}
810
811static libtrace_direction_t linuxnative_set_direction(
812                libtrace_packet_t *packet,
813                libtrace_direction_t direction) {
814        return set_direction(&((struct libtrace_linuxnative_header*)(packet->buffer))->hdr, direction);
815}
816
817static struct timespec linuxnative_get_timespec(const libtrace_packet_t *packet) 
818{
819        struct libtrace_linuxnative_header *hdr = 
820                (struct libtrace_linuxnative_header*) packet->buffer;
821        /* We have to upconvert from timeval to timespec */
822        if (hdr->timestamptype == TS_TIMEVAL) {
823                struct timespec ts;
824                ts.tv_sec = hdr->tv.tv_sec;
825                ts.tv_nsec = hdr->tv.tv_usec*1000;
826                return ts;
827        }
828        else {
829                struct timespec ts;
830                ts.tv_sec = hdr->ts.tv_sec;
831                ts.tv_nsec = hdr->ts.tv_nsec;
832                return ts;
833        }
834}
835
836static struct timeval linuxnative_get_timeval(const libtrace_packet_t *packet) 
837{
838        struct libtrace_linuxnative_header *hdr = 
839                (struct libtrace_linuxnative_header*) packet->buffer;
840        /* We have to downconvert from timespec to timeval */
841        if (hdr->timestamptype == TS_TIMESPEC) {
842                struct timeval tv;
843                tv.tv_sec = hdr->ts.tv_sec;
844                tv.tv_usec = hdr->ts.tv_nsec/1000;
845                return tv;
846        }
847        else {
848                struct timeval tv;
849                tv.tv_sec = hdr->tv.tv_sec;
850                tv.tv_usec = hdr->tv.tv_usec;
851                return tv;
852        }
853}
854
855static int linuxnative_get_capture_length(const libtrace_packet_t *packet)
856{
857        return ((struct libtrace_linuxnative_header*)(packet->buffer))->caplen;
858}
859
860
861static int linuxnative_get_wire_length(const libtrace_packet_t *packet) 
862{
863
864        int wirelen = ((struct libtrace_linuxnative_header*)(packet->buffer))->wirelen;
865
866        /* Include the missing FCS */
867        if (trace_get_link_type(packet) == TRACE_TYPE_ETH)
868                wirelen += 4;
869
870        return wirelen;
871}
872
873
874static int linuxnative_get_framing_length(UNUSED
875                const libtrace_packet_t *packet) 
876{
877        return sizeof(struct libtrace_linuxnative_header);
878}
879
880static size_t linuxnative_set_capture_length(libtrace_packet_t *packet, 
881                size_t size) {
882
883        struct libtrace_linuxnative_header *linux_hdr = NULL;
884        assert(packet);
885        if (size > trace_get_capture_length(packet)) {
886                /* We should avoid making a packet larger */
887                return trace_get_capture_length(packet);
888        }
889       
890        /* Reset the cached capture length */
891        packet->capture_length = -1;
892
893        linux_hdr = (struct libtrace_linuxnative_header *)packet->header;
894        linux_hdr->caplen = size;
895        return trace_get_capture_length(packet);
896}
897
898static int linuxnative_get_fd(const libtrace_t *trace) {
899        if (trace->format_data == NULL)
900                return -1;
901        return FORMAT(trace->format_data)->fd;
902}
903
904/* Linux doesn't keep track how many packets were seen before filtering
905 * so we can't tell how many packets were filtered.  Bugger.  So annoying.
906 *
907 * Since we tell libtrace that we do support filtering, if we don't declare
908 * this here as failing, libtrace will happily report for us that it didn't
909 * filter any packets, so don't lie -- return that we don't know.
910 */
911static uint64_t linuxnative_get_filtered_packets(libtrace_t *trace UNUSED) {
912        return UINT64_MAX;
913}
914
915/* Number of packets that passed filtering */
916static uint64_t linuxnative_get_captured_packets(libtrace_t *trace) {
917        struct tpacket_stats stats;
918
919        if (trace->format_data == NULL)
920                return UINT64_MAX;
921        if (FORMAT(trace->format_data)->fd == -1) {
922                /* This is probably a 'dead' trace so obviously we can't query
923                 * the socket for capture counts, can we? */
924                return UINT64_MAX;
925        }
926
927#ifdef HAVE_NETPACKET_PACKET_H
928
929        if ((FORMAT(trace->format_data)->stats_valid & 1)
930                || FORMAT(trace->format_data)->stats_valid == 0) {
931                if (FORMAT(trace->format_data)->per_thread) {
932                        int i;
933                        FORMAT(trace->format_data)->stats.tp_drops = 0;
934                        FORMAT(trace->format_data)->stats.tp_packets = 0;
935                        for (i = 0; i < trace->perpkt_thread_count; ++i) {
936                                socklen_t len = sizeof(stats);
937                                getsockopt(FORMAT(trace->format_data)->per_thread[i].fd,
938                                           SOL_PACKET,
939                                           PACKET_STATISTICS,
940                                           &stats,
941                                           &len);
942                                FORMAT(trace->format_data)->stats.tp_drops += stats.tp_drops;
943                                FORMAT(trace->format_data)->stats.tp_packets += stats.tp_packets;
944                        }
945                        FORMAT(trace->format_data)->stats_valid |= 1;
946                } else {
947                        socklen_t len = sizeof(FORMAT(trace->format_data)->stats);
948                        getsockopt(FORMAT(trace->format_data)->fd,
949                                   SOL_PACKET,
950                                   PACKET_STATISTICS,
951                                   &FORMAT(trace->format_data)->stats,
952                                   &len);
953                        FORMAT(trace->format_data)->stats_valid |= 1;
954                }
955        }
956
957        return FORMAT(trace->format_data)->stats.tp_packets;
958#else
959        return UINT64_MAX;
960#endif
961}
962
963/* Number of packets that got past filtering and were then dropped because
964 * of lack of space
965 */
966static uint64_t linuxnative_get_dropped_packets(libtrace_t *trace) {
967        struct tpacket_stats stats;
968        if (trace->format_data == NULL)
969                return UINT64_MAX;
970        if (FORMAT(trace->format_data)->fd == -1) {
971                /* This is probably a 'dead' trace so obviously we can't query
972                 * the socket for drop counts, can we? */
973                return UINT64_MAX;
974        }
975
976#ifdef HAVE_NETPACKET_PACKET_H 
977        if ((FORMAT(trace->format_data)->stats_valid & 2)
978                || (FORMAT(trace->format_data)->stats_valid==0)) {
979                if (FORMAT(trace->format_data)->per_thread) {
980                        int i;
981                        FORMAT(trace->format_data)->stats.tp_drops = 0;
982                        FORMAT(trace->format_data)->stats.tp_packets = 0;
983                        for (i = 0; i < trace->perpkt_thread_count; ++i) {
984                                socklen_t len = sizeof(stats);
985                                getsockopt(FORMAT(trace->format_data)->per_thread[i].fd,
986                                           SOL_PACKET,
987                                           PACKET_STATISTICS,
988                                           &stats,
989                                           &len);
990                                FORMAT(trace->format_data)->stats.tp_drops += stats.tp_drops;
991                                FORMAT(trace->format_data)->stats.tp_packets += stats.tp_packets;
992                        }
993                        FORMAT(trace->format_data)->stats_valid |= 2;
994                } else {
995                        socklen_t len = sizeof(FORMAT(trace->format_data)->stats);
996                        getsockopt(FORMAT(trace->format_data)->fd,
997                                   SOL_PACKET,
998                                   PACKET_STATISTICS,
999                                   &FORMAT(trace->format_data)->stats,
1000                                   &len);
1001                        FORMAT(trace->format_data)->stats_valid |= 2;
1002                }
1003        }
1004
1005        return FORMAT(trace->format_data)->stats.tp_drops;
1006#else
1007        return UINT64_MAX;
1008#endif
1009}
1010
1011#ifdef HAVE_NETPACKET_PACKET_H
1012static void linuxnative_help(void) {
1013        printf("linuxnative format module: $Revision: 1793 $\n");
1014        printf("Supported input URIs:\n");
1015        printf("\tint:eth0\n");
1016        printf("\n");
1017        printf("Supported output URIs:\n");
1018        printf("\tint:eth0\n");
1019        printf("\n");
1020        return;
1021}
1022
1023static struct libtrace_format_t linuxnative = {
1024        "int",
1025        "$Id$",
1026        TRACE_FORMAT_LINUX_NATIVE,
1027        linuxnative_probe_filename,     /* probe filename */
1028        NULL,                           /* probe magic */
1029        linuxnative_init_input,         /* init_input */
1030        linuxnative_config_input,       /* config_input */
1031        linuxnative_start_input,        /* start_input */
1032        linuxnative_pause_input,        /* pause_input */
1033        linuxnative_init_output,        /* init_output */
1034        NULL,                           /* config_output */
1035        linuxnative_start_output,       /* start_ouput */
1036        linuxnative_fin_input,          /* fin_input */
1037        linuxnative_fin_output,         /* fin_output */
1038        linuxnative_read_packet,        /* read_packet */
1039        linuxnative_prepare_packet,     /* prepare_packet */
1040        NULL,                           /* fin_packet */
1041        linuxnative_write_packet,       /* write_packet */
1042        linuxnative_get_link_type,      /* get_link_type */
1043        linuxnative_get_direction,      /* get_direction */
1044        linuxnative_set_direction,      /* set_direction */
1045        NULL,                           /* get_erf_timestamp */
1046        linuxnative_get_timeval,        /* get_timeval */
1047        linuxnative_get_timespec,       /* get_timespec */
1048        NULL,                           /* get_seconds */
1049        NULL,                           /* seek_erf */
1050        NULL,                           /* seek_timeval */
1051        NULL,                           /* seek_seconds */
1052        linuxnative_get_capture_length, /* get_capture_length */
1053        linuxnative_get_wire_length,    /* get_wire_length */
1054        linuxnative_get_framing_length, /* get_framing_length */
1055        linuxnative_set_capture_length, /* set_capture_length */
1056        NULL,                           /* get_received_packets */
1057        linuxnative_get_filtered_packets,/* get_filtered_packets */
1058        linuxnative_get_dropped_packets,/* get_dropped_packets */
1059        linuxnative_get_captured_packets,/* get_captured_packets */
1060        linuxnative_get_fd,             /* get_fd */
1061        trace_event_device,             /* trace_event */
1062        linuxnative_help,               /* help */
1063        NULL,                                   /* next pointer */
1064        {true, -1},              /* Live, no thread limit */
1065        linuxnative_pstart_input,                       /* pstart_input */
1066        linuxnative_pread_packets,                      /* pread_packets */
1067        linuxnative_ppause_input,                       /* ppause */
1068        linuxnative_fin_input,                          /* p_fin */
1069        linuxnative_pconfig_input,                      /* pconfig input */
1070        linux_pregister_thread,
1071        NULL
1072};
1073#else
1074static void linuxnative_help(void) {
1075        printf("linuxnative format module: $Revision: 1793 $\n");
1076        printf("Not supported on this host\n");
1077}
1078
1079static struct libtrace_format_t linuxnative = {
1080        "int",
1081        "$Id$",
1082        TRACE_FORMAT_LINUX_NATIVE,
1083        NULL,                           /* probe filename */
1084        NULL,                           /* probe magic */
1085        NULL,                           /* init_input */
1086        NULL,                           /* config_input */
1087        NULL,                           /* start_input */
1088        NULL,                           /* pause_input */
1089        NULL,                           /* init_output */
1090        NULL,                           /* config_output */
1091        NULL,                           /* start_ouput */
1092        NULL,                           /* fin_input */
1093        NULL,                           /* fin_output */
1094        NULL,                           /* read_packet */
1095        linuxnative_prepare_packet,     /* prepare_packet */
1096        NULL,                           /* fin_packet */
1097        NULL,                           /* write_packet */
1098        linuxnative_get_link_type,      /* get_link_type */
1099        linuxnative_get_direction,      /* get_direction */
1100        linuxnative_set_direction,      /* set_direction */
1101        NULL,                           /* get_erf_timestamp */
1102        linuxnative_get_timeval,        /* get_timeval */
1103        linuxnative_get_timespec,       /* get_timespec */
1104        NULL,                           /* get_seconds */
1105        NULL,                           /* seek_erf */
1106        NULL,                           /* seek_timeval */
1107        NULL,                           /* seek_seconds */
1108        linuxnative_get_capture_length, /* get_capture_length */
1109        linuxnative_get_wire_length,    /* get_wire_length */
1110        linuxnative_get_framing_length, /* get_framing_length */
1111        linuxnative_set_capture_length, /* set_capture_length */
1112        NULL,                           /* get_received_packets */
1113        linuxnative_get_filtered_packets,/* get_filtered_packets */
1114        linuxnative_get_dropped_packets,/* get_dropped_packets */
1115        linuxnative_get_captured_packets,/* get_captured_packets */
1116        linuxnative_get_fd,             /* get_fd */
1117        trace_event_device,             /* trace_event */
1118        linuxnative_help,               /* help */
1119        NULL,                   /* next pointer */
1120        NON_PARALLEL(true)
1121};
1122#endif /* HAVE_NETPACKET_PACKET_H */
1123
1124struct libtrace_format_t *get_native_format(void)
1125{
1126        return &linuxnative;
1127}
1128
1129
1130void linuxnative_constructor(void) {
1131        register_format(&linuxnative);
1132}
Note: See TracBrowser for help on using the repository browser.