source: lib/format_linux_common.c @ d47ca18

cachetimestampsdevelopdpdk-ndagetsilivendag_formatrc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformance
Last change on this file since d47ca18 was d47ca18, checked in by Richard Sanger <rsanger@…>, 4 years ago

Fix issue #49 compile issues when missing BPF header file

If pcap was installed but somehow the BPF header was missing.
Libtrace was using two different macros HAVE_BPF and HAVE_BPF_FILTER
to determine if BPF was installed.

HAVE_BPF_FILTER was set if pcap was found, wereas HAVE_BPF was
set if the BPF header was found.

This removes and replaces HAVE_BPF_FILTER with HAVE_BPF.
It also adds ifdef blocks around formats that try to install
BPF filters directly as needed.

  • Property mode set to 100644
File size: 18.6 KB
Line 
1/*
2 *
3 * Copyright (c) 2007-2016 The University of Waikato, Hamilton, New Zealand.
4 * All rights reserved.
5 *
6 * This file is part of libtrace.
7 *
8 * This code has been developed by the University of Waikato WAND
9 * research group. For further information please see http://www.wand.net.nz/
10 *
11 * libtrace is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * libtrace is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 *
24 *
25 */
26
27/* This file contains the common functions used by both the ring and int
28 * formats.
29 *
30 * Typically these deal with the socket descriptor or common conversions.
31 */
32
33#include "config.h"
34#include "libtrace.h"
35#include "libtrace_int.h"
36#include "format_helper.h"
37#include "libtrace_arphrd.h"
38#include <stdlib.h>
39#include <errno.h>
40#include <unistd.h>
41#include <string.h>
42#include <assert.h>
43
44#ifdef HAVE_INTTYPES_H
45#  include <inttypes.h>
46#else
47# error "Can't find inttypes.h"
48#endif
49
50#include "format_linux_common.h"
51
52#ifdef HAVE_NETPACKET_PACKET_H
53
54int linuxcommon_probe_filename(const char *filename)
55{
56        /* Is this an interface? */
57        return (if_nametoindex(filename) != 0);
58}
59
60/* Compiles a libtrace BPF filter for use with a linux native socket */
61static int linuxnative_configure_bpf(libtrace_t *libtrace,
62                libtrace_filter_t *filter) {
63#if defined(HAVE_LIBPCAP) && defined(HAVE_BPF)
64        struct ifreq ifr;
65        unsigned int arphrd;
66        libtrace_dlt_t dlt;
67        libtrace_filter_t *f;
68        int sock;
69        pcap_t *pcap;
70
71        /* Take a copy of the filter object as it was passed in */
72        f = (libtrace_filter_t *) malloc(sizeof(libtrace_filter_t));
73        memcpy(f, filter, sizeof(libtrace_filter_t));
74
75        /* If we are passed a filter with "flag" set to zero, then we must
76         * compile the filterstring before continuing. This involves
77         * determining the linktype, passing the filterstring to libpcap to
78         * compile, and saving the result for trace_start() to push into the
79         * kernel.
80         * If flag is set to one, then the filter was probably generated using
81         * trace_create_filter_from_bytecode() and so we don't need to do
82         * anything (we've just copied it above).
83         */
84        if (f->flag == 0) {
85                sock = socket(PF_INET, SOCK_STREAM, 0);
86                memset(&ifr, 0, sizeof(struct ifreq));
87                strncpy(ifr.ifr_name, libtrace->uridata, IF_NAMESIZE);
88                if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0) {
89                        perror("Can't get HWADDR for interface");
90                        return -1;
91                }
92                close(sock);
93
94                arphrd = ifr.ifr_hwaddr.sa_family;
95                dlt = libtrace_to_pcap_dlt(arphrd_type_to_libtrace(arphrd));
96
97                pcap = pcap_open_dead(dlt,
98                                FORMAT_DATA->snaplen);
99
100                if (pcap_compile(pcap, &f->filter, f->filterstring, 0, 0) == -1) {
101                        /* Filter didn't compile, set flag to 0 so we can
102                         * detect this when trace_start() is called and
103                         * produce a useful error
104                         */
105                        f->flag = 0;
106                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
107                                      "Failed to compile BPF filter (%s): %s",
108                                      f->filterstring, pcap_geterr(pcap));
109                } else {
110                        /* Set the "flag" to indicate that the filterstring
111                         * has been compiled
112                         */
113                        f->flag = 1;
114                }
115
116                pcap_close(pcap);
117
118        }
119
120        if (FORMAT_DATA->filter != NULL)
121                free(FORMAT_DATA->filter);
122
123        FORMAT_DATA->filter = f;
124
125        return 0;
126#else
127        return -1;
128#endif
129}
130
131int linuxcommon_config_input(libtrace_t *libtrace,
132                trace_option_t option,
133                void *data)
134{
135        switch(option) {
136                case TRACE_OPTION_SNAPLEN:
137                        FORMAT_DATA->snaplen=*(int*)data;
138                        return 0;
139                case TRACE_OPTION_PROMISC:
140                        FORMAT_DATA->promisc=*(int*)data;
141                        return 0;
142                case TRACE_OPTION_FILTER:
143                        return linuxnative_configure_bpf(libtrace,
144                                        (libtrace_filter_t *) data);
145                case TRACE_OPTION_HASHER:
146                        switch (*((enum hasher_types *)data)) {
147                                case HASHER_BALANCE:
148                                        // Do fanout
149                                        FORMAT_DATA->fanout_flags = PACKET_FANOUT_LB;
150                                        // Or we could balance to the CPU
151                                        return 0;
152                                case HASHER_BIDIRECTIONAL:
153                                case HASHER_UNIDIRECTIONAL:
154                                        FORMAT_DATA->fanout_flags = PACKET_FANOUT_HASH;
155                                        return 0;
156                                case HASHER_CUSTOM:
157                                        return -1;
158                        }
159                        break;
160                case TRACE_OPTION_META_FREQ:
161                        /* No meta-data for this format */
162                        break;
163                case TRACE_OPTION_EVENT_REALTIME:
164                        /* Live captures are always going to be in trace time */
165                        break;
166                /* Avoid default: so that future options will cause a warning
167                 * here to remind us to implement it, or flag it as
168                 * unimplementable
169                 */
170        }
171
172        /* Don't set an error - trace_config will try to deal with the
173         * option and will set an error if it fails */
174        return -1;
175}
176
177int linuxcommon_init_input(libtrace_t *libtrace)
178{
179        struct linux_per_stream_t stream_data = ZERO_LINUX_STREAM;
180
181        libtrace->format_data = (struct linux_format_data_t *)
182                malloc(sizeof(struct linux_format_data_t));
183        assert(libtrace->format_data != NULL);
184
185        FORMAT_DATA->per_stream =
186                libtrace_list_init(sizeof(stream_data));
187        assert(FORMAT_DATA->per_stream != NULL);
188
189        libtrace_list_push_back(FORMAT_DATA->per_stream, &stream_data);
190
191        FORMAT_DATA->promisc = -1;
192        FORMAT_DATA->snaplen = LIBTRACE_PACKET_BUFSIZE;
193        FORMAT_DATA->filter = NULL;
194        FORMAT_DATA->stats_valid = 0;
195        FORMAT_DATA->stats.tp_drops = 0;
196        FORMAT_DATA->stats.tp_packets = 0;
197        FORMAT_DATA->max_order = MAX_ORDER;
198        FORMAT_DATA->fanout_flags = PACKET_FANOUT_LB;
199        /* Some examples use pid for the group however that would limit a single
200         * application to use only int/ring format, instead using rand */
201        FORMAT_DATA->fanout_group = (uint16_t) rand();
202        return 0;
203}
204
205int linuxcommon_init_output(libtrace_out_t *libtrace)
206{
207        libtrace->format_data = (struct linux_format_data_out_t*)
208                malloc(sizeof(struct linux_format_data_out_t));
209        assert(libtrace->format_data != NULL);
210
211        FORMAT_DATA_OUT->fd = -1;
212        FORMAT_DATA_OUT->tx_ring = NULL;
213        FORMAT_DATA_OUT->txring_offset = 0;
214        FORMAT_DATA_OUT->queue = 0;
215        FORMAT_DATA_OUT->max_order = MAX_ORDER;
216        return 0;
217}
218
219/* Close an input stream, this is safe to be called part way through
220 * initilisation as a cleanup function assuming streams were set to
221 * ZERO_LINUX_STREAM to begin with.
222 *
223 * This works correctly with both int and ring
224 */
225void linuxcommon_close_input_stream(libtrace_t *libtrace,
226                                    struct linux_per_stream_t *stream) {
227        if (stream->fd != -1)
228                close(stream->fd);
229        stream->fd = -1;
230        if (stream->rx_ring != MAP_FAILED)
231                munmap(stream->rx_ring,
232                       stream->req.tp_block_size *
233                       stream->req.tp_block_nr);
234        stream->rx_ring = MAP_FAILED;
235        stream->rxring_offset = 0;
236        FORMAT_DATA->dev_stats.if_name[0] = 0;
237}
238
239#define REPEAT_16(x) x x x x x x x x x x x x x x x x
240#define xstr(s) str(s)
241#define str(s) #s
242
243/* These don't typically reset however an interface does exist to reset them */
244static int linuxcommon_get_dev_statistics(libtrace_t *libtrace, struct linux_dev_stats *stats) {
245        FILE *file;
246        char line[1024];
247        struct linux_dev_stats tmp_stats;
248
249        file = fopen("/proc/net/dev","r");
250        if (file == NULL) {
251                return -1;
252        }
253
254        /* Skip 2 header lines */
255        if (fgets(line, sizeof(line), file) == NULL) {
256                fclose(file);
257                return -1;
258        }
259
260        if (fgets(line, sizeof(line), file) == NULL) {
261                fclose(file);
262                return -1;
263        }
264
265        while (!(feof(file)||ferror(file))) {
266                int tot;
267                if (fgets(line, sizeof(line), file) == NULL)
268                        break;
269
270                tot = sscanf(line, " %"xstr(IF_NAMESIZE)"[^:]:" REPEAT_16(" %"SCNd64),
271                             tmp_stats.if_name,
272                             &tmp_stats.rx_bytes,
273                             &tmp_stats.rx_packets,
274                             &tmp_stats.rx_errors,
275                             &tmp_stats.rx_drops,
276                             &tmp_stats.rx_fifo,
277                             &tmp_stats.rx_frame,
278                             &tmp_stats.rx_compressed,
279                             &tmp_stats.rx_multicast,
280                             &tmp_stats.tx_bytes,
281                             &tmp_stats.tx_packets,
282                             &tmp_stats.tx_errors,
283                             &tmp_stats.tx_drops,
284                             &tmp_stats.tx_fifo,
285                             &tmp_stats.tx_colls,
286                             &tmp_stats.tx_carrier,
287                             &tmp_stats.tx_compressed);
288                if (tot != 17)
289                        continue;
290                if (strncmp(tmp_stats.if_name, libtrace->uridata, IF_NAMESIZE) == 0) {
291                        *stats = tmp_stats;
292                        fclose(file);
293                        return 0;
294                }
295        }
296        fclose(file);
297        return -1;
298}
299
300/* Start an input stream
301 * - Opens the file descriptor
302 * - Sets promiscuous correctly
303 * - Sets socket option
304 * - Add BPF filter
305 *
306 * The output is ready for int directly, for ring the conversion to ring still
307 * needs to take place.
308 */
309int linuxcommon_start_input_stream(libtrace_t *libtrace,
310                                   struct linux_per_stream_t *stream)
311{
312        struct sockaddr_ll addr;
313        const int one = 1;
314        memset(&addr,0,sizeof(addr));
315        libtrace_filter_t *filter = FORMAT_DATA->filter;
316
317        stream->last_timestamp = 0;
318
319        /* Create a raw socket for reading packets on */
320        stream->fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
321        if (stream->fd==-1) {
322                trace_set_err(libtrace, errno, "Could not create raw socket");
323                return -1;
324        }
325
326        /* Bind to the capture interface */
327        addr.sll_family = AF_PACKET;
328        addr.sll_protocol = htons(ETH_P_ALL);
329        if (strlen(libtrace->uridata)) {
330                addr.sll_ifindex = if_nametoindex(libtrace->uridata);
331                if (addr.sll_ifindex == 0) {
332                        linuxcommon_close_input_stream(libtrace, stream);
333                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
334                                      "Failed to find interface %s",
335                                      libtrace->uridata);
336                        return -1;
337                }
338        } else {
339                addr.sll_ifindex = 0;
340        }
341        if (bind(stream->fd,
342                 (struct sockaddr*)&addr,
343                 (socklen_t)sizeof(addr))==-1) {
344                linuxcommon_close_input_stream(libtrace, stream);
345                trace_set_err(libtrace, errno,
346                              "Failed to bind to interface %s",
347                              libtrace->uridata);
348                return -1;
349        }
350
351        /* If promisc hasn't been specified, set it to "true" if we're
352         * capturing on one interface, or "false" if we're capturing on
353         * all interfaces.
354         */
355        if (FORMAT_DATA->promisc==-1) {
356                if (addr.sll_ifindex!=0)
357                        FORMAT_DATA->promisc=1;
358                else
359                        FORMAT_DATA->promisc=0;
360        }
361
362        /* Enable promiscuous mode, if requested */
363        if (FORMAT_DATA->promisc) {
364                struct packet_mreq mreq;
365                socklen_t socklen = sizeof(mreq);
366                memset(&mreq,0,sizeof(mreq));
367                mreq.mr_ifindex = addr.sll_ifindex;
368                mreq.mr_type = PACKET_MR_PROMISC;
369                if (setsockopt(stream->fd,
370                               SOL_PACKET,
371                               PACKET_ADD_MEMBERSHIP,
372                               &mreq,
373                               socklen)==-1) {
374                        perror("setsockopt(PROMISC)");
375                }
376        }
377
378        /* Set the timestamp option on the socket - aim for the most detailed
379         * clock resolution possible */
380#ifdef SO_TIMESTAMPNS
381        if (setsockopt(stream->fd,
382                       SOL_SOCKET,
383                       SO_TIMESTAMPNS,
384                       &one,
385                       (socklen_t)sizeof(one))!=-1) {
386                FORMAT_DATA->timestamptype = TS_TIMESPEC;
387        }
388        else
389        /* DANGER: This is a dangling else to only do the next setsockopt()
390         * if we fail the first! */
391#endif
392                if (setsockopt(stream->fd,
393                               SOL_SOCKET,
394                               SO_TIMESTAMP,
395                               &one,
396                               (socklen_t)sizeof(one))!=-1) {
397                        FORMAT_DATA->timestamptype = TS_TIMEVAL;
398                }
399                else
400                        FORMAT_DATA->timestamptype = TS_NONE;
401
402        /* Push BPF filter into the kernel. At this stage we can safely assume
403         * that the filterstring has been compiled, or the filter was supplied
404         * pre-compiled.
405         */
406#ifdef HAVE_BPF
407        if (filter != NULL) {
408                /* Check if the filter was successfully compiled. If not,
409                 * it is probably a bad filter and we should return an error
410                 * before the caller tries to read any packets */
411                if (filter->flag == 0) {
412                        linuxcommon_close_input_stream(libtrace, stream);
413                        trace_set_err(libtrace, TRACE_ERR_BAD_FILTER,
414                                      "Cannot attach a bad filter to %s",
415                                      libtrace->uridata);
416                        return -1;
417                }
418
419                if (setsockopt(stream->fd,
420                               SOL_SOCKET,
421                               SO_ATTACH_FILTER,
422                               &filter->filter,
423                               sizeof(filter->filter)) == -1) {
424                        perror("setsockopt(SO_ATTACH_FILTER)");
425                }
426        }
427#endif
428
429        /* Consume any buffered packets that were received before the socket
430         * was properly setup, including those which missed the filter and
431         * bind()ing to an interface.
432         *
433         * If packet rate is high this could therotically hang forever. 4K
434         * should be a large enough limit.
435         */
436        int count = 0;
437        void *buf = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
438        while(count < 4096 &&
439                recv(stream->fd,
440                   buf,
441                   (size_t)LIBTRACE_PACKET_BUFSIZE,
442                   MSG_DONTWAIT) != -1) { count++; }
443        free(buf);
444
445        /* Mark that the stats are valid and apply an offset */
446        FORMAT_DATA->stats_valid = 1;
447        /* Offset by number we ate for each stream and reset stats after pause */
448        FORMAT_DATA->stats.tp_packets = -count;
449        FORMAT_DATA->stats.tp_drops = 0;
450
451        if (linuxcommon_get_dev_statistics(libtrace, &FORMAT_DATA->dev_stats) != 0) {
452                /* Mark this as bad */
453                FORMAT_DATA->dev_stats.if_name[0] = 0;
454        }
455
456        return 0;
457}
458
459int linuxcommon_pause_input(libtrace_t *libtrace)
460{
461        size_t i;
462
463        /* Stop and detach each stream */
464        for (i = 0; i < libtrace_list_get_size(FORMAT_DATA->per_stream); ++i) {
465                struct linux_per_stream_t *stream;
466                stream = libtrace_list_get_index(FORMAT_DATA->per_stream, i)->data;
467                linuxcommon_close_input_stream(libtrace, stream);
468        }
469
470        return 0;
471}
472
473int linuxcommon_fin_input(libtrace_t *libtrace)
474{
475        if (libtrace->format_data) {
476                if (FORMAT_DATA->filter != NULL)
477                        free(FORMAT_DATA->filter);
478
479                if (FORMAT_DATA->per_stream)
480                        libtrace_list_deinit(FORMAT_DATA->per_stream);
481
482                free(libtrace->format_data);
483        }
484
485        return 0;
486}
487
488int linuxcommon_pregister_thread(libtrace_t *libtrace,
489                                 libtrace_thread_t *t,
490                                 bool reading) {
491        if (reading) {
492                /* XXX TODO remove this oneday make sure hasher thread still works */
493                struct linux_per_stream_t *stream;
494                stream = libtrace_list_get_index(FORMAT_DATA->per_stream,
495                                                 t->perpkt_num)->data;
496                t->format_data = stream;
497                if (!stream) {
498                        /* This should never happen and indicates an
499                         * internal libtrace bug */
500                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
501                                      "Failed to attached thread %d to a stream",
502                                      t->perpkt_num);
503                        return -1;
504                }
505        }
506        return 0;
507}
508
509/* These counters reset with each read */
510static void linuxcommon_update_socket_statistics(libtrace_t *libtrace) {
511        struct tpacket_stats stats;
512        size_t i;
513        socklen_t len = sizeof(stats);
514
515        for (i = 0; i < libtrace_list_get_size(FORMAT_DATA->per_stream); ++i) {
516                struct linux_per_stream_t *stream;
517                stream = libtrace_list_get_index(FORMAT_DATA->per_stream, i)->data;
518                if (stream->fd != -1) {
519                        if (getsockopt(stream->fd,
520                                   SOL_PACKET,
521                                   PACKET_STATISTICS,
522                                   &stats,
523                                   &len) == 0) {
524                                if (FORMAT_DATA->stats_valid==0) {
525                                        FORMAT_DATA->stats.tp_drops = stats.tp_drops;
526                                        FORMAT_DATA->stats.tp_packets = stats.tp_packets;
527                                        FORMAT_DATA->stats_valid = 1;
528                                } else {
529                                        FORMAT_DATA->stats.tp_drops += stats.tp_drops;
530                                        FORMAT_DATA->stats.tp_packets += stats.tp_packets;
531                                }
532                        } else {
533                                perror("getsockopt PACKET_STATISTICS failed");
534                        }
535                }
536        }
537}
538
539#define DEV_DIFF(x) (dev_stats.x - FORMAT_DATA->dev_stats.x)
540/* Note these statistics come from two different sources, the socket itself and
541 * the linux device. As such this means it is highly likely that their is some
542 * margin of error in the returned statistics, we perform basic sanitising so
543 * that these are not too noticable.
544 */
545void linuxcommon_get_statistics(libtrace_t *libtrace, libtrace_stat_t *stat) {
546        struct linux_dev_stats dev_stats;
547        if (libtrace->format_data == NULL)
548                return;
549        /* Do we need to consider the case after the trace is closed? */
550        if (FORMAT_DATA_FIRST->fd == -1) {
551                /* This is probably a 'dead' trace so obviously we can't query
552                 * the socket for capture counts, can we? */
553                return;
554        }
555
556        dev_stats.if_name[0] = 0; /* This will be set if we retrive valid stats */
557        /* Do we have starting stats to compare to? */
558        if (FORMAT_DATA->dev_stats.if_name[0] != 0) {
559                linuxcommon_get_dev_statistics(libtrace, &dev_stats);
560        }
561        linuxcommon_update_socket_statistics(libtrace);
562
563        /* filtered count == dev received - socket received */
564        if (FORMAT_DATA->filter != NULL &&
565            FORMAT_DATA->stats_valid &&
566            dev_stats.if_name[0]) {
567                uint64_t filtered = DEV_DIFF(rx_packets) -
568                                    FORMAT_DATA->stats.tp_packets;
569                /* Check the value is sane, due to timing it could be below 0 */
570                if (filtered < UINT64_MAX - 100000) {
571                        stat->filtered += filtered;
572                }
573        }
574
575        /* dropped count == socket dropped + dev dropped */
576        if (FORMAT_DATA->stats_valid) {
577                stat->dropped_valid = 1;
578                stat->dropped = FORMAT_DATA->stats.tp_drops;
579                if (dev_stats.if_name[0]) {
580                        stat->dropped += DEV_DIFF(rx_drops);
581                }
582        }
583
584        /* received count - All good packets even those dropped or filtered */
585        if (dev_stats.if_name[0]) {
586                stat->received_valid = 1;
587                stat->received = DEV_DIFF(rx_packets) + DEV_DIFF(rx_drops);
588        }
589
590        /* captured count - received and but not dropped */
591        if (dev_stats.if_name[0] && FORMAT_DATA->stats_valid) {
592                stat->captured_valid = 1;
593                stat->captured = DEV_DIFF(rx_packets) - FORMAT_DATA->stats.tp_drops;
594        }
595
596        /* errors */
597        if (dev_stats.if_name[0]) {
598                stat->errors_valid = 1;
599                stat->errors = DEV_DIFF(rx_errors);
600        }
601
602}
603
604int linuxcommon_get_fd(const libtrace_t *libtrace) {
605        if (libtrace->format_data == NULL)
606                return -1;
607        return FORMAT_DATA_FIRST->fd;
608}
609
610int linuxcommon_pstart_input(libtrace_t *libtrace,
611                             int (*start_stream)(libtrace_t *, struct linux_per_stream_t*)) {
612        int i = 0;
613        int tot = libtrace->perpkt_thread_count;
614        int iserror = 0;
615        struct linux_per_stream_t empty_stream = ZERO_LINUX_STREAM;
616
617        for (i = 0; i < tot; ++i)
618        {
619                struct linux_per_stream_t *stream;
620                /* Add storage for another stream */
621                if (libtrace_list_get_size(FORMAT_DATA->per_stream) <= (size_t) i)
622                        libtrace_list_push_back(FORMAT_DATA->per_stream, &empty_stream);
623
624                stream = libtrace_list_get_index(FORMAT_DATA->per_stream, i)->data;
625                if (start_stream(libtrace, stream) != 0) {
626                        iserror = 1;
627                        break;
628                }
629                if (linuxcommon_to_packet_fanout(libtrace, stream) != 0)
630                {
631                        iserror = 1;
632                        close(stream->fd);
633                        stream->fd = -1;
634                        break;
635                }
636        }
637
638        if (iserror) {
639                /* Free those that succeeded */
640                for (i = i - 1; i >= 0; i--) {
641                        struct linux_per_stream_t *stream;
642                        stream = libtrace_list_get_index(FORMAT_DATA->per_stream, i)->data;
643                        linuxcommon_close_input_stream(libtrace, stream);
644                }
645                return -1;
646        }
647
648        return 0;
649}
650
651#else /* HAVE_NETPACKET_PACKET_H */
652
653/* No NETPACKET - So this format is not live */
654void linuxcommon_get_statistics(libtrace_t *libtrace UNUSED,
655                                libtrace_stat_t *stat UNUSED) {
656        return;
657}
658
659#endif /* HAVE_NETPACKET_PACKET_H */
660
Note: See TracBrowser for help on using the repository browser.