source: lib/format_linux_common.c @ 2193905

develop
Last change on this file since 2193905 was 2193905, checked in by Jacob Van Walraven <jcv9@…>, 2 years ago

Apply changes required for pull request #81

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