source: lib/format_linux_int.c @ e4f27d1

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

Move the ring sizes to the stream structures, it's possible rings could end up different sizes.
Other than that their are many operation related to reading packets which rely upon it and
it seems more natural to include this against the stream.

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