source: lib/format_linux_int.c @ 21c0d70

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivelibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 21c0d70 was 6d1c2c0, checked in by Shane Alcock <salcock@…>, 6 years ago

Fix a few more warnings

  • Property mode set to 100644
File size: 16.3 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007-2015 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_common.h"
63
64
65#ifdef HAVE_NETPACKET_PACKET_H
66
67
68static int linuxnative_start_input(libtrace_t *libtrace)
69{
70        int ret = linuxcommon_start_input_stream(libtrace, FORMAT_DATA_FIRST);
71        return ret;
72}
73
74#ifdef HAVE_PACKET_FANOUT
75static int linuxnative_pstart_input(libtrace_t *libtrace) {
76        return linuxcommon_pstart_input(libtrace, linuxcommon_start_input_stream);
77}
78#endif
79
80static int linuxnative_start_output(libtrace_out_t *libtrace)
81{
82        FORMAT_DATA_OUT->fd = socket(PF_PACKET, SOCK_RAW, 0);
83        if (FORMAT_DATA_OUT->fd==-1) {
84                free(FORMAT_DATA_OUT);
85                trace_set_err_out(libtrace, errno, "Failed to create raw socket");
86                return -1;
87        }
88
89        return 0;
90}
91
92static int linuxnative_fin_output(libtrace_out_t *libtrace)
93{
94        close(FORMAT_DATA_OUT->fd);
95        FORMAT_DATA_OUT->fd=-1;
96        free(libtrace->format_data);
97        return 0;
98}
99#endif /* HAVE_NETPACKET_PACKET_H */
100
101static int linuxnative_prepare_packet(libtrace_t *libtrace UNUSED, 
102                libtrace_packet_t *packet, void *buffer, 
103                libtrace_rt_types_t rt_type, uint32_t flags) {
104
105        if (packet->buffer != buffer &&
106            packet->buf_control == TRACE_CTRL_PACKET) {
107                free(packet->buffer);
108        }
109
110        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
111                packet->buf_control = TRACE_CTRL_PACKET;
112        } else
113                packet->buf_control = TRACE_CTRL_EXTERNAL;
114
115
116        packet->buffer = buffer;
117        packet->header = buffer;
118        packet->payload = (char *)buffer + 
119                sizeof(struct libtrace_linuxnative_header);
120        packet->type = rt_type;
121
122        /*
123        if (libtrace->format_data == NULL) {
124                if (linuxnative_init_input(libtrace))
125                        return -1;
126        }
127        */
128        return 0;
129       
130}
131
132#define LIBTRACE_MIN(a,b) ((a)<(b) ? (a) : (b))
133
134/* 20 isn't enough on x86_64 */
135#define CMSG_BUF_SIZE 128
136
137#ifdef HAVE_NETPACKET_PACKET_H
138inline static int linuxnative_read_stream(libtrace_t *libtrace,
139                                          libtrace_packet_t *packet,
140                                          struct linux_per_stream_t *stream,
141                                          libtrace_message_queue_t *queue)
142{
143        struct libtrace_linuxnative_header *hdr;
144        struct msghdr msghdr;
145        struct iovec iovec;
146        unsigned char controlbuf[CMSG_BUF_SIZE];
147        struct cmsghdr *cmsg;
148        int snaplen;
149
150        uint32_t flags = 0;
151        fd_set readfds;
152        struct timeval tout;
153        int ret;
154       
155        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
156                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
157                if (!packet->buffer) {
158                        perror("Cannot allocate buffer");
159                }
160        }
161
162        flags |= TRACE_PREP_OWN_BUFFER;
163       
164        packet->type = TRACE_RT_DATA_LINUX_NATIVE;
165
166        hdr=(struct libtrace_linuxnative_header*)packet->buffer;
167        snaplen=LIBTRACE_MIN(
168                        (int)LIBTRACE_PACKET_BUFSIZE-(int)sizeof(*hdr),
169                        (int)FORMAT_DATA->snaplen);
170        /* Prepare the msghdr and iovec for the kernel to write the
171         * captured packet into. The msghdr will point to the part of our
172         * buffer reserved for sll header, while the iovec will point at
173         * the buffer following the sll header. */
174
175        msghdr.msg_name = &hdr->hdr;
176        msghdr.msg_namelen = sizeof(struct sockaddr_ll);
177
178        msghdr.msg_iov = &iovec;
179        msghdr.msg_iovlen = 1;
180
181        msghdr.msg_control = &controlbuf;
182        msghdr.msg_controllen = CMSG_BUF_SIZE;
183        msghdr.msg_flags = 0;
184
185        iovec.iov_base = (void*)(packet->buffer+sizeof(*hdr));
186        iovec.iov_len = snaplen;
187
188        // Check for a packet - TODO only Linux has MSG_DONTWAIT should use fctl O_NONBLOCK
189        /* Try check ahead this should be fast if something is waiting  */
190        hdr->wirelen = recvmsg(stream->fd, &msghdr, MSG_DONTWAIT | MSG_TRUNC);
191
192        /* No data was waiting */
193        if ((int) hdr->wirelen == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
194                /* Do message queue check or select */
195                int message_fd = 0;
196                int largestfd = stream->fd;
197
198                /* Also check the message queue */
199                if (queue) {
200                        message_fd = libtrace_message_queue_get_fd(queue);
201                        if (message_fd > largestfd)
202                                largestfd = message_fd;
203                }
204                do {
205                        /* Use select to allow us to time out occasionally to check if someone
206                         * has hit Ctrl-C or otherwise wants us to stop reading and return
207                         * so they can exit their program.
208                         */
209                        tout.tv_sec = 0;
210                        tout.tv_usec = 500000;
211                        /* Make sure we reset these each loop */
212                        FD_ZERO(&readfds);
213                        FD_SET(stream->fd, &readfds);
214                        if (queue)
215                                FD_SET(message_fd, &readfds);
216
217                        ret = select(largestfd+1, &readfds, NULL, NULL, &tout);
218                        if (ret >= 1) {
219                                /* A file descriptor triggered */
220                                break;
221                        } else if (ret < 0 && errno != EINTR) {
222                                trace_set_err(libtrace, errno, "select");
223                                return -1;
224                        } else {
225                                if (libtrace_halt)
226                                        return READ_EOF;
227                        }
228                }
229                while (ret <= 0);
230
231                /* Message waiting? */
232                if (queue && FD_ISSET(message_fd, &readfds))
233                        return READ_MESSAGE;
234
235                /* We must have a packet */
236                hdr->wirelen = recvmsg(stream->fd, &msghdr, MSG_TRUNC);
237        }
238
239        if (hdr->wirelen==~0U) {
240                trace_set_err(libtrace,errno,"recvmsg");
241                return -1;
242        }
243
244        hdr->caplen=LIBTRACE_MIN((unsigned int)snaplen,(unsigned int)hdr->wirelen);
245
246        /* Extract the timestamps from the msghdr and store them in our
247         * linux native encapsulation, so that we can preserve the formatting
248         * across multiple architectures */
249
250        for (cmsg = CMSG_FIRSTHDR(&msghdr);
251                        cmsg != NULL;
252                        cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
253                if (cmsg->cmsg_level == SOL_SOCKET
254                        && cmsg->cmsg_type == SO_TIMESTAMP
255                        && cmsg->cmsg_len <= CMSG_LEN(sizeof(struct timeval))) {
256                       
257                        struct timeval *tv;
258                        tv = (struct timeval *)CMSG_DATA(cmsg);
259                       
260                       
261                        hdr->tv.tv_sec = tv->tv_sec;
262                        hdr->tv.tv_usec = tv->tv_usec;
263                        hdr->timestamptype = TS_TIMEVAL;
264                        break;
265                } 
266#ifdef SO_TIMESTAMPNS
267                else if (cmsg->cmsg_level == SOL_SOCKET
268                        && cmsg->cmsg_type == SO_TIMESTAMPNS
269                        && cmsg->cmsg_len <= CMSG_LEN(sizeof(struct timespec))) {
270
271                        struct timespec *tv;
272                        tv = (struct timespec *)CMSG_DATA(cmsg);
273
274                        hdr->ts.tv_sec = tv->tv_sec;
275                        hdr->ts.tv_nsec = tv->tv_nsec;
276                        hdr->timestamptype = TS_TIMESPEC;
277                        break;
278                }
279#endif
280        }
281
282        /* Did we not get given a timestamp? Try to get one from the
283         * file descriptor directly */
284        if (cmsg == NULL) {
285                struct timeval tv;
286                if (ioctl(stream->fd, SIOCGSTAMP,&tv)==0) {
287                        hdr->tv.tv_sec = tv.tv_sec;
288                        hdr->tv.tv_usec = tv.tv_usec;
289                        hdr->timestamptype = TS_TIMEVAL;
290                }
291                else {
292                        hdr->timestamptype = TS_NONE;
293                }
294        }
295
296        /* Buffer contains all of our packet (including our custom header) so
297         * we just need to get prepare_packet to set all our packet pointers
298         * appropriately */
299        packet->trace = libtrace;
300        if (linuxnative_prepare_packet(libtrace, packet, packet->buffer,
301                                packet->type, flags))
302                return -1;
303       
304        return hdr->wirelen+sizeof(*hdr);
305}
306
307static int linuxnative_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) 
308{
309        return linuxnative_read_stream(libtrace, packet, FORMAT_DATA_FIRST, NULL);
310}
311
312#ifdef HAVE_PACKET_FANOUT
313static int linuxnative_pread_packets(libtrace_t *libtrace,
314                                     libtrace_thread_t *t,
315                                     libtrace_packet_t *packets[],
316                                     UNUSED size_t nb_packets) {
317        /* For now just read one packet */
318        packets[0]->error = linuxnative_read_stream(libtrace, packets[0],
319                                                       t->format_data, &t->messages);
320        if (packets[0]->error >= 1)
321                return 1;
322        else
323                return packets[0]->error;
324}
325#endif
326
327static int linuxnative_write_packet(libtrace_out_t *libtrace,
328                libtrace_packet_t *packet) 
329{
330        struct sockaddr_ll hdr;
331        int ret = 0;
332
333        if (trace_get_link_type(packet) == TRACE_TYPE_NONDATA)
334                return 0;
335
336        hdr.sll_family = AF_PACKET;
337        hdr.sll_protocol = 0;
338        hdr.sll_ifindex = if_nametoindex(libtrace->uridata);
339        hdr.sll_hatype = 0;
340        hdr.sll_pkttype = 0;
341        hdr.sll_halen = htons(6); /* FIXME */
342        memcpy(hdr.sll_addr,packet->payload,(size_t)ntohs(hdr.sll_halen));
343
344        /* This is pretty easy, just send the payload using sendto() (after
345         * setting up the sll header properly, of course) */
346        ret = sendto(FORMAT_DATA_OUT->fd,
347                        packet->payload,
348                        trace_get_capture_length(packet),
349                        0,
350                        (struct sockaddr*)&hdr, (socklen_t)sizeof(hdr));
351
352        if (ret < 0) {
353                trace_set_err_out(libtrace, errno, "sendto failed");
354        }
355
356        return ret;
357}
358#endif /* HAVE_NETPACKET_PACKET_H */
359
360
361static libtrace_linktype_t linuxnative_get_link_type(const struct libtrace_packet_t *packet) {
362        uint16_t linktype=(((struct libtrace_linuxnative_header*)(packet->buffer))
363                                ->hdr.sll_hatype);
364        return linuxcommon_get_link_type(linktype);
365}
366
367static libtrace_direction_t linuxnative_get_direction(const struct libtrace_packet_t *packet) {
368        return linuxcommon_get_direction(((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype);
369}
370
371static libtrace_direction_t linuxnative_set_direction(
372                libtrace_packet_t *packet,
373                libtrace_direction_t direction) {
374        return linuxcommon_set_direction(&((struct libtrace_linuxnative_header*)(packet->buffer))->hdr, direction);
375}
376
377static struct timespec linuxnative_get_timespec(const libtrace_packet_t *packet) 
378{
379        struct libtrace_linuxnative_header *hdr = 
380                (struct libtrace_linuxnative_header*) packet->buffer;
381        /* We have to upconvert from timeval to timespec */
382        if (hdr->timestamptype == TS_TIMEVAL) {
383                struct timespec ts;
384                ts.tv_sec = hdr->tv.tv_sec;
385                ts.tv_nsec = hdr->tv.tv_usec*1000;
386                return ts;
387        }
388        else {
389                struct timespec ts;
390                ts.tv_sec = hdr->ts.tv_sec;
391                ts.tv_nsec = hdr->ts.tv_nsec;
392                return ts;
393        }
394}
395
396static struct timeval linuxnative_get_timeval(const libtrace_packet_t *packet) 
397{
398        struct libtrace_linuxnative_header *hdr = 
399                (struct libtrace_linuxnative_header*) packet->buffer;
400        /* We have to downconvert from timespec to timeval */
401        if (hdr->timestamptype == TS_TIMESPEC) {
402                struct timeval tv;
403                tv.tv_sec = hdr->ts.tv_sec;
404                tv.tv_usec = hdr->ts.tv_nsec/1000;
405                return tv;
406        }
407        else {
408                struct timeval tv;
409                tv.tv_sec = hdr->tv.tv_sec;
410                tv.tv_usec = hdr->tv.tv_usec;
411                return tv;
412        }
413}
414
415static int linuxnative_get_capture_length(const libtrace_packet_t *packet)
416{
417        return ((struct libtrace_linuxnative_header*)(packet->buffer))->caplen;
418}
419
420
421static int linuxnative_get_wire_length(const libtrace_packet_t *packet) 
422{
423
424        int wirelen = ((struct libtrace_linuxnative_header*)(packet->buffer))->wirelen;
425
426        /* Include the missing FCS */
427        if (trace_get_link_type(packet) == TRACE_TYPE_ETH)
428                wirelen += 4;
429
430        return wirelen;
431}
432
433
434static int linuxnative_get_framing_length(UNUSED
435                const libtrace_packet_t *packet) 
436{
437        return sizeof(struct libtrace_linuxnative_header);
438}
439
440static size_t linuxnative_set_capture_length(libtrace_packet_t *packet, 
441                size_t size) {
442
443        struct libtrace_linuxnative_header *linux_hdr = NULL;
444        assert(packet);
445        if (size > trace_get_capture_length(packet)) {
446                /* We should avoid making a packet larger */
447                return trace_get_capture_length(packet);
448        }
449       
450        /* Reset the cached capture length */
451        packet->capture_length = -1;
452
453        linux_hdr = (struct libtrace_linuxnative_header *)packet->header;
454        linux_hdr->caplen = size;
455        return trace_get_capture_length(packet);
456}
457
458#ifdef HAVE_NETPACKET_PACKET_H
459static void linuxnative_help(void) {
460        printf("linuxnative format module: $Revision: 1793 $\n");
461        printf("Supported input URIs:\n");
462        printf("\tint:eth0\n");
463        printf("\n");
464        printf("Supported output URIs:\n");
465        printf("\tint:eth0\n");
466        printf("\n");
467        return;
468}
469
470static struct libtrace_format_t linuxnative = {
471        "int",
472        "$Id$",
473        TRACE_FORMAT_LINUX_NATIVE,
474        linuxcommon_probe_filename,     /* probe filename */
475        NULL,                           /* probe magic */
476        linuxcommon_init_input,         /* init_input */
477        linuxcommon_config_input,       /* config_input */
478        linuxnative_start_input,        /* start_input */
479        linuxcommon_pause_input,        /* pause_input */
480        linuxcommon_init_output,        /* init_output */
481        NULL,                           /* config_output */
482        linuxnative_start_output,       /* start_ouput */
483        linuxcommon_fin_input,          /* fin_input */
484        linuxnative_fin_output,         /* fin_output */
485        linuxnative_read_packet,        /* read_packet */
486        linuxnative_prepare_packet,     /* prepare_packet */
487        NULL,                           /* fin_packet */
488        linuxnative_write_packet,       /* write_packet */
489        linuxnative_get_link_type,      /* get_link_type */
490        linuxnative_get_direction,      /* get_direction */
491        linuxnative_set_direction,      /* set_direction */
492        NULL,                           /* get_erf_timestamp */
493        linuxnative_get_timeval,        /* get_timeval */
494        linuxnative_get_timespec,       /* get_timespec */
495        NULL,                           /* get_seconds */
496        NULL,                           /* seek_erf */
497        NULL,                           /* seek_timeval */
498        NULL,                           /* seek_seconds */
499        linuxnative_get_capture_length, /* get_capture_length */
500        linuxnative_get_wire_length,    /* get_wire_length */
501        linuxnative_get_framing_length, /* get_framing_length */
502        linuxnative_set_capture_length, /* set_capture_length */
503        NULL,                           /* get_received_packets */
504        NULL,                           /* get_filtered_packets */
505        NULL,                           /* get_dropped_packets */
506        linuxcommon_get_statistics,     /* get_statistics */
507        linuxcommon_get_fd,             /* get_fd */
508        trace_event_device,             /* trace_event */
509        linuxnative_help,               /* help */
510        NULL,                           /* next pointer */
511#ifdef HAVE_PACKET_FANOUT
512        {true, -1},                     /* Live, no thread limit */
513        linuxnative_pstart_input,       /* pstart_input */
514        linuxnative_pread_packets,      /* pread_packets */
515        linuxcommon_pause_input,        /* ppause */
516        linuxcommon_fin_input,          /* p_fin */
517        linuxcommon_pregister_thread,   /* register thread */
518        NULL,                           /* unregister thread */
519        NULL                            /* get thread stats */
520#else
521        NON_PARALLEL(true)
522#endif
523};
524#else
525static void linuxnative_help(void) {
526        printf("linuxnative format module: $Revision: 1793 $\n");
527        printf("Not supported on this host\n");
528}
529
530static struct libtrace_format_t linuxnative = {
531        "int",
532        "$Id$",
533        TRACE_FORMAT_LINUX_NATIVE,
534        NULL,                           /* probe filename */
535        NULL,                           /* probe magic */
536        NULL,                           /* init_input */
537        NULL,                           /* config_input */
538        NULL,                           /* start_input */
539        NULL,                           /* pause_input */
540        NULL,                           /* init_output */
541        NULL,                           /* config_output */
542        NULL,                           /* start_ouput */
543        NULL,                           /* fin_input */
544        NULL,                           /* fin_output */
545        NULL,                           /* read_packet */
546        linuxnative_prepare_packet,     /* prepare_packet */
547        NULL,                           /* fin_packet */
548        NULL,                           /* write_packet */
549        linuxnative_get_link_type,      /* get_link_type */
550        linuxnative_get_direction,      /* get_direction */
551        linuxnative_set_direction,      /* set_direction */
552        NULL,                           /* get_erf_timestamp */
553        linuxnative_get_timeval,        /* get_timeval */
554        linuxnative_get_timespec,       /* get_timespec */
555        NULL,                           /* get_seconds */
556        NULL,                           /* seek_erf */
557        NULL,                           /* seek_timeval */
558        NULL,                           /* seek_seconds */
559        linuxnative_get_capture_length, /* get_capture_length */
560        linuxnative_get_wire_length,    /* get_wire_length */
561        linuxnative_get_framing_length, /* get_framing_length */
562        linuxnative_set_capture_length, /* set_capture_length */
563        NULL,                           /* get_received_packets */
564        NULL,                           /* get_filtered_packets */
565        NULL,                           /* get_dropped_packets */
566        linuxcommon_get_statistics,     /* get_statistics */
567        NULL,                           /* get_fd */
568        NULL,                           /* trace_event */
569        linuxnative_help,               /* help */
570        NULL,                   /* next pointer */
571        NON_PARALLEL(true)
572};
573#endif /* HAVE_NETPACKET_PACKET_H */
574
575void linuxnative_constructor(void) {
576        register_format(&linuxnative);
577}
Note: See TracBrowser for help on using the repository browser.