source: lib/format_linux.c @ 771ab22

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivelibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 771ab22 was 771ab22, checked in by Richard Sanger <rsangerarj@…>, 6 years ago

Bring linux int: back to a compiling and working condition

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