source: lib/format_pfring.c @ 4c365fa

pfring
Last change on this file since 4c365fa was 4c365fa, checked in by Shane Alcock <salcock@…>, 6 years ago

Wrote a useful pfring_event function

PF_RING should now work with the event API.

  • Property mode set to 100644
File size: 15.6 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 * Author: Shane Alcock
8 *
9 * All rights reserved.
10 *
11 * This code has been developed by the University of Waikato WAND
12 * research group. For further information please see http://www.wand.net.nz/
13 *
14 * libtrace is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * libtrace is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with libtrace; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27 *
28 */
29
30#include "config.h"
31#include "libtrace.h"
32#include "libtrace_int.h"
33#include "format_helper.h"
34#include "data-struct/linked_list.h"
35
36#include <stdlib.h>
37#include <assert.h>
38#include <unistd.h>
39#include <string.h>
40
41#if HAVE_LIBNUMA
42#include <numa.h>
43#endif
44
45#include <pthread.h>
46#ifdef __FreeBSD__
47#include <pthread_np.h>
48#endif
49
50#include <pfring.h>
51
52struct pfring_format_data_t {
53        libtrace_list_t *per_stream;   
54        int8_t promisc;
55        int snaplen;
56        int8_t ringenabled;
57        char *bpffilter;
58};
59
60struct pfring_per_stream_t {
61
62        pfring *pd;
63        int affinity;
64
65} ALIGN_STRUCT(CACHE_LINE_SIZE);
66
67#define ZERO_PFRING_STREAM {NULL, -1}
68
69#define DATA(x) ((struct pfring_format_data_t *)x->format_data)
70#define STREAM_DATA(x) ((struct pfring_per_stream_t *)x->data)
71
72#define FORMAT_DATA DATA(libtrace)
73#define FORMAT_DATA_HEAD FORMAT_DATA->per_stream->head
74#define FORMAT_DATA_FIRST ((struct pfring_per_stream_t *)FORMAT_DATA_HEAD->data)
75
76
77typedef union {
78        uint32_t ipv4;
79        uint8_t ipv6[16];
80} ip_addr_union;
81
82struct tunnelinfo {
83        uint32_t id;
84        uint8_t tunneledproto;
85        ip_addr_union tunnel_src;
86        ip_addr_union tunnel_dst;
87        uint16_t tunnel_srcport;
88        uint16_t tunnel_dstport;
89};
90
91struct pktoffset {
92        int16_t ethoffset;
93        int16_t vlanoffset;
94        int16_t l3offset;
95        int16_t l4offset;
96        int16_t payloadoffset;
97};
98
99struct parsing_info {
100        uint8_t dmac[ETH_ALEN];
101        uint8_t smac[ETH_ALEN];
102        uint16_t eth_type;
103        uint16_t vlan_id;
104        uint8_t ip_version;
105        uint8_t l3_proto;
106        uint8_t ip_tos;
107        ip_addr_union ip_src;
108        ip_addr_union ip_dst;
109        uint16_t l4_src_port;
110        uint16_t l4_dst_port;
111        struct {
112                uint8_t flags;
113                uint32_t seqno;
114                uint32_t ackno;
115        } tcp;
116        struct tunnelinfo tunnel;
117        uint16_t last_matched_plugin;
118        uint16_t last_matched_rule;
119        struct pktoffset offset;
120
121};
122
123struct libtrace_pfring_extend {
124
125        uint64_t ts_ns;
126        uint32_t flags;
127        uint8_t direction;
128        int32_t if_index;
129        uint32_t hash;
130        struct {
131                int bounce_iface;
132                void *reserved;
133        } tx;
134        uint16_t parsed_hdr_len;
135        struct parsing_info parsed;
136};
137
138struct local_pfring_header {
139        struct timeval ts;
140        uint32_t caplen;
141        uint32_t wlen;
142        struct libtrace_pfring_extend ext;     
143       
144};
145
146
147struct libtrace_pfring_header {
148        struct {
149                uint64_t tv_sec;
150                uint64_t tv_usec;
151        } ts;
152        uint32_t caplen;
153        uint32_t wlen;
154        struct libtrace_pfring_extend ext;     
155       
156};
157
158static inline int pfring_start_input_stream(libtrace_t *libtrace,
159                struct pfring_per_stream_t *stream) {
160
161        int rc;
162
163        if (FORMAT_DATA->bpffilter) {
164                rc = pfring_set_bpf_filter(stream->pd, FORMAT_DATA->bpffilter);
165                if (rc != 0) {
166                        trace_set_err(libtrace, TRACE_ERR_BAD_FILTER,
167                                "Failed to set BPF filter on pfring:");
168                        return -1;
169                }
170        }
171
172        if ((rc = pfring_set_socket_mode(stream->pd, recv_only_mode)) != 0) {
173                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
174                                "Failed to set recv only mode on pfring:");
175                return -1;
176        }
177
178        if (pfring_enable_ring(stream->pd) != 0) {
179                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, 
180                        "Failed to enable the pfring");
181                return -1;
182        }
183       
184        return 0;
185
186}
187
188static int pfring_start_input(libtrace_t *libtrace) {
189        struct pfring_per_stream_t *stream = FORMAT_DATA_FIRST;
190        if (libtrace->uridata == NULL) {
191                trace_set_err(libtrace, TRACE_ERR_BAD_FORMAT, 
192                                "Missing interface name from pfring: URI");
193                return -1;
194        }
195        uint32_t flags = PF_RING_TIMESTAMP | PF_RING_LONG_HEADER;
196        flags |= PF_RING_HW_TIMESTAMP;
197
198        if (FORMAT_DATA->promisc > 0) 
199                flags |= PF_RING_PROMISC;
200       
201        if (FORMAT_DATA->ringenabled) {
202                trace_set_err(libtrace, TRACE_ERR_BAD_STATE,
203                        "Attempted to start a pfring: input that was already started!");
204                return -1;
205        }
206
207        stream->pd = pfring_open(libtrace->uridata, FORMAT_DATA->snaplen, flags);
208
209        return pfring_start_input_stream(libtrace, FORMAT_DATA_FIRST);
210}
211
212static int pfring_init_input(libtrace_t *libtrace) {
213
214        struct pfring_per_stream_t stream_data = ZERO_PFRING_STREAM;
215
216        libtrace->format_data = (struct pfring_format_data_t *)
217                malloc(sizeof(struct pfring_format_data_t));
218        assert(libtrace->format_data != NULL);
219
220        FORMAT_DATA->promisc = -1;
221        FORMAT_DATA->snaplen = LIBTRACE_PACKET_BUFSIZE;
222        FORMAT_DATA->per_stream = libtrace_list_init(sizeof(stream_data));
223        FORMAT_DATA->ringenabled = 0;
224        FORMAT_DATA->bpffilter = NULL;
225
226        libtrace_list_push_back(FORMAT_DATA->per_stream, &stream_data);
227
228        return 0;
229}
230
231static int pfring_config_input(libtrace_t *libtrace, trace_option_t option,
232                void *data) {
233
234        switch (option) {
235                case TRACE_OPTION_SNAPLEN:
236                        FORMAT_DATA->snaplen = *(int *)data;
237                        return 0;
238                case TRACE_OPTION_PROMISC:
239                        FORMAT_DATA->promisc = *(int *)data;
240                        return 0;
241                case TRACE_OPTION_FILTER:
242                        FORMAT_DATA->bpffilter = strdup((char *)data);
243                        return 0;
244                case TRACE_OPTION_HASHER:
245                        /* We can do unidirectional hashing on hardware
246                         * by default, but symmetric hash requires the
247                         * extra ZC or DNA drivers. */
248                        switch (*((enum hasher_types *)data)) {
249                                case HASHER_UNIDIRECTIONAL:
250                                        return 0;
251                                case HASHER_BALANCE:
252                                case HASHER_CUSTOM:
253                                case HASHER_BIDIRECTIONAL:
254                                        return -1;
255                        }
256                        break;
257                case TRACE_OPTION_META_FREQ:
258                        break;
259                case TRACE_OPTION_EVENT_REALTIME:
260                        break;
261        }
262        return -1;
263}
264
265static int pfring_pause_input(libtrace_t *libtrace) {
266        size_t i;
267
268        for (i = 0; i < libtrace_list_get_size(FORMAT_DATA->per_stream); ++i) {
269                struct pfring_per_stream_t *stream;
270                stream = libtrace_list_get_index(FORMAT_DATA->per_stream, i)->data;
271                pfring_disable_ring(stream->pd);       
272                pfring_remove_bpf_filter(stream->pd);
273                pfring_close(stream->pd);
274        }
275
276        FORMAT_DATA->ringenabled = 0;
277        return 0;
278
279}
280
281static int pfring_fin_input(libtrace_t *libtrace) {
282
283        if (libtrace->format_data) {
284                if (FORMAT_DATA->bpffilter)
285                        free(FORMAT_DATA->bpffilter);
286                if (FORMAT_DATA->per_stream) 
287                        libtrace_list_deinit(FORMAT_DATA->per_stream);
288                free(libtrace->format_data);
289        }
290        return 0;
291}
292
293
294static int pfring_get_capture_length(const libtrace_packet_t *packet) {
295        struct libtrace_pfring_header *phdr;
296        phdr = (struct libtrace_pfring_header *)packet->header;
297
298        if (packet->payload == NULL)
299                return 0;
300        if (ntohl(phdr->wlen) < ntohl(phdr->caplen))
301                return ntohl(phdr->wlen);
302        return ntohl(phdr->caplen);
303       
304}
305
306static int pfring_get_wire_length(const libtrace_packet_t *packet) {
307        struct libtrace_pfring_header *phdr;
308        phdr = (struct libtrace_pfring_header *)packet->header;
309        return ntohl(phdr->wlen);
310}
311
312static int pfring_get_framing_length(UNUSED const libtrace_packet_t *packet) {
313        return sizeof(struct libtrace_pfring_header);
314}
315
316static int pfring_prepare_packet(libtrace_t *libtrace UNUSED, 
317                libtrace_packet_t *packet, void *buffer, 
318                libtrace_rt_types_t rt_type, uint32_t flags) {
319
320
321        if (packet->buffer != buffer && packet->buf_control == 
322                        TRACE_CTRL_PACKET) {
323                free(packet->buffer);
324        }
325
326        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
327                packet->buf_control = TRACE_CTRL_PACKET;
328        } else {
329                packet->buf_control = TRACE_CTRL_EXTERNAL;
330        }
331
332        packet->type = rt_type;
333        packet->buffer = buffer;
334        packet->header = buffer;
335        packet->payload = (buffer + sizeof(struct libtrace_pfring_header));
336
337        return 0;
338}
339
340static int pfring_read_generic(libtrace_t *libtrace, libtrace_packet_t *packet,
341                uint8_t block)
342{
343
344        struct pfring_per_stream_t *stream = FORMAT_DATA_FIRST;
345        struct libtrace_pfring_header *hdr;
346        struct local_pfring_header local;
347        int rc;
348
349        if (packet->buf_control == TRACE_CTRL_EXTERNAL || !packet->buffer) {
350                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
351                if (!packet->buffer) {
352                        trace_set_err(libtrace, errno, 
353                                "Cannot allocate memory for packet buffer");
354                        return -1;
355                }
356        }
357
358        hdr = (struct libtrace_pfring_header *)packet->buffer;
359        if ((rc = pfring_recv(stream->pd, (u_char **)&packet->payload, 
360                        0, (struct pfring_pkthdr *)&local, block)) == -1)
361        {
362                trace_set_err(libtrace, errno, "Failed to read packet from pfring:");
363                return -1;
364        }
365
366        /* We were asked not to block and there are no packets available */
367        if (rc == 0)
368                return 0;
369
370        /* Convert the header fields to network byte order so we can
371         * export them over RT safely. Also deal with 32 vs 64 bit
372         * timevals! */
373        hdr->ts.tv_sec = bswap_host_to_le64((uint64_t)local.ts.tv_sec);
374        hdr->ts.tv_usec = bswap_host_to_le64((uint64_t)local.ts.tv_usec);
375        hdr->caplen = htonl(local.caplen);
376        hdr->wlen = htonl(local.wlen);
377        hdr->ts.tv_sec = htonl(local.ts.tv_sec);
378        hdr->ts.tv_usec = htonl(local.ts.tv_usec);
379        hdr->ext.ts_ns = bswap_host_to_le64(local.ext.ts_ns);
380        hdr->ext.flags = htonl(local.ext.flags);
381        hdr->ext.if_index = htonl(local.ext.if_index);
382        hdr->ext.hash = htonl(local.ext.hash);
383        hdr->ext.tx.bounce_iface = htonl(local.ext.tx.bounce_iface);
384        hdr->ext.parsed_hdr_len = htons(local.ext.parsed_hdr_len);
385        hdr->ext.direction = local.ext.direction;
386
387        /* I think we can ignore parsed as it will only be populated if
388         * we call pfring_parse_pkt (?)
389         */
390
391        packet->trace = libtrace;
392        packet->type = TRACE_RT_DATA_PFRING;
393        packet->header = packet->buffer;
394
395        return pfring_get_capture_length(packet) + 
396                        pfring_get_framing_length(packet);
397
398}
399
400static int pfring_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet)
401{
402        return pfring_read_generic(libtrace, packet, 1);
403}
404
405static libtrace_linktype_t pfring_get_link_type(const libtrace_packet_t *packet UNUSED)
406{
407        return TRACE_TYPE_ETH;
408}
409
410static libtrace_direction_t lt_pfring_set_direction(libtrace_packet_t *packet,
411                libtrace_direction_t dir) {
412
413        struct libtrace_pfring_header *phdr;
414
415        phdr = (struct libtrace_pfring_header *)packet->header;
416        phdr->ext.direction = dir;
417        return dir;     
418}
419
420static libtrace_direction_t pfring_get_direction(
421                const libtrace_packet_t *packet) {
422
423        struct libtrace_pfring_header *phdr;
424        phdr = (struct libtrace_pfring_header *)packet->header;
425        return phdr->ext.direction;
426}
427
428static uint64_t pfring_get_erf_timestamp(const libtrace_packet_t *packet) {
429        uint64_t ts;
430        struct libtrace_pfring_header *phdr;
431        phdr = (struct libtrace_pfring_header *)packet->header;
432
433        if (phdr->ext.ts_ns) {
434                uint64_t tns = bswap_le_to_host64(phdr->ext.ts_ns);
435
436                ts = ((tns / 1000000000) << 32);
437                ts += ((tns % 1000000000) << 32) / 1000000000;
438        } else {
439                ts = (((uint64_t)ntohl(phdr->ts.tv_sec)) << 32);
440                ts += (((uint64_t)(ntohl(phdr->ts.tv_usec)) << 32)/1000000);
441        }
442        return ts;
443               
444
445}
446static size_t pfring_set_capture_length(libtrace_packet_t *packet, size_t size)
447{
448        struct libtrace_pfring_header *phdr;
449        phdr = (struct libtrace_pfring_header *)packet->header;
450
451        if (size > trace_get_capture_length(packet)) {
452                /* Can't make a packet larger */
453                return trace_get_capture_length(packet);
454        }
455
456        packet->capture_length = -1;
457        phdr->caplen = htonl(size);
458        return trace_get_capture_length(packet);
459}
460
461static void pfring_get_statistics(libtrace_t *libtrace, libtrace_stat_t *stat) {
462
463        pfring_stat st;
464
465        size_t i;
466
467        for (i = 0; i < libtrace_list_get_size(FORMAT_DATA->per_stream); ++i) {
468                struct pfring_per_stream_t *stream;
469                stream = libtrace_list_get_index(FORMAT_DATA->per_stream, i)->data;
470
471                if (pfring_stats(stream->pd, &st) != 0) {
472                        trace_set_err(libtrace, errno, "Failed to get statistics for pfring stream %u", (uint32_t)i);
473                        continue;
474                }
475
476                if (stat->dropped_valid) {
477                        stat->dropped += st.drop;
478                } else {
479                        stat->dropped = st.drop;
480                        stat->dropped_valid = 1;
481                }
482
483                if (stat->received_valid) {
484                        stat->received += st.recv;
485                } else {
486                        stat->received = st.recv;
487                        stat->received_valid = 1;
488                }
489        }
490
491}
492
493static libtrace_eventobj_t pfring_event(libtrace_t *libtrace, 
494                libtrace_packet_t *packet) {
495
496        libtrace_eventobj_t event = {0,0,0.0,0};
497        int rc;
498
499        rc = pfring_read_generic(libtrace, packet, 0);
500       
501        if (rc > 0) {
502                event.size = rc;
503                event.type = TRACE_EVENT_PACKET;
504        } else if (rc == 0) {
505                if (libtrace_halt) {
506                        event.type = TRACE_EVENT_TERMINATE;
507                } else {
508                        event.type = TRACE_EVENT_SLEEP;
509                        event.seconds = 0.0001;
510                }
511        } else {
512                event.type = TRACE_EVENT_TERMINATE;
513        }
514        return event;
515}
516
517static int pfring_pstart_input(libtrace_t *libtrace) {
518        trace_set_err(libtrace, TRACE_ERR_UNSUPPORTED, "Haven't implemented parallel support for pfring yet!");
519        return -1;
520}
521
522static int pfring_pread_packets(libtrace_t *libtrace,
523                libtrace_thread_t *t UNUSED, libtrace_packet_t *packets[] UNUSED,
524                UNUSED size_t nb_packets) {
525
526        trace_set_err(libtrace, TRACE_ERR_UNSUPPORTED, "Haven't implemented parallel support for pfring yet!");
527        return -1;
528}
529
530
531
532static struct libtrace_format_t pfringformat = {
533        "pfring",
534        "$Id$",
535        TRACE_FORMAT_PFRING,
536        NULL,                           /* probe filename */
537        NULL,                           /* probe magic */
538        pfring_init_input,                /* init_input */
539        pfring_config_input,              /* config_input */
540        pfring_start_input,               /* start_input */
541        pfring_pause_input,               /* pause_input */
542        NULL,                           /* init_output */
543        NULL,                           /* config_output */
544        NULL,                           /* start_output */
545        pfring_fin_input,                 /* fin_input */
546        NULL,                           /* fin_output */
547        pfring_read_packet,               /* read_packet */
548        pfring_prepare_packet,            /* prepare_packet */
549        NULL,                           /* fin_packet */
550        NULL,                             /* write_packet */
551        pfring_get_link_type,             /* get_link_type */
552        pfring_get_direction,             /* get_direction */
553        lt_pfring_set_direction,             /* set_direction */
554        pfring_get_erf_timestamp,         /* get_erf_timestamp */
555        NULL,               /* get_timeval */
556        NULL,                           /* get_seconds */
557        NULL,                           /* get_timespec */
558        NULL,                           /* seek_erf */
559        NULL,                           /* seek_timeval */
560        NULL,                           /* seek_seconds */
561        pfring_get_capture_length,        /* get_capture_length */
562        pfring_get_wire_length,           /* get_wire_length */
563        pfring_get_framing_length,        /* get_framing_length */
564        pfring_set_capture_length,        /* set_capture_length */
565        NULL,                           /* get_received_packets */
566        NULL,                           /* get_filtered_packets */
567        NULL,                           /* get_dropped_packets */
568        pfring_get_statistics,          /* get_statistics */
569        NULL,                           /* get_fd */
570        pfring_event,              /* trace_event */
571        NULL,                      /* help */
572        NULL,                   /* next pointer */
573        {true, -1},                     /* Live, no thread limit */
574        pfring_pstart_input,         /* pstart_input */
575        pfring_pread_packets,        /* pread_packets */
576        pfring_pause_input,        /* ppause */
577        pfring_fin_input,          /* p_fin */
578        NULL,                   /* register thread XXX */ 
579        NULL,                           /* unregister thread */
580        NULL                            /* get thread stats */
581
582};
583
584void pfring_constructor(void) {
585        register_format(&pfringformat);
586}
Note: See TracBrowser for help on using the repository browser.