1d2fa68605eadad3cb7024f3a0aab8ccf727e8ff
[govpp.git] / vendor / github.com / google / gopacket / pfring / pfring.go
1 // Copyright 2012 Google, Inc. All rights reserved.
2 // Copyright 2009-2011 Andreas Krennmair. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style license
5 // that can be found in the LICENSE file in the root of the source
6 // tree.
7
8 package pfring
9
10 /*
11 #cgo LDFLAGS: -lpfring -lpcap
12 #include <stdlib.h>
13 #include <pfring.h>
14 #include <linux/pf_ring.h>
15
16 int pfring_readpacketdatato_wrapper(
17     pfring* ring,
18     u_char* buffer,
19     u_int buffer_len,
20     struct pfring_pkthdr* hdr) {
21   // We can't pass a Go pointer to a Go pointer which means we can't pass
22   // buffer as a uchar**, like pfring_recv wants, for ReadPacketDataTo.  So,
23   // this wrapper does the pointer conversion in C code.  Since this isn't
24   // zero-copy, it turns out that the pointer-to-pointer part of things isn't
25   // actually used anyway.
26   return pfring_recv(ring, &buffer, buffer_len, hdr, 1);
27 }
28 */
29 import "C"
30
31 // NOTE:  If you install PF_RING with non-standard options, you may also need
32 // to use LDFLAGS -lnuma and/or -lrt.  Both have been reported necessary if
33 // PF_RING is configured with --disable-bpf.
34
35 import (
36         "fmt"
37         "net"
38         "os"
39         "strconv"
40         "sync"
41         "time"
42         "unsafe"
43
44         "github.com/google/gopacket"
45 )
46
47 const errorBufferSize = 256
48
49 // Ring provides a handle to a pf_ring.
50 type Ring struct {
51         // cptr is the handle for the actual pcap C object.
52         cptr                    *C.pfring
53         snaplen                 int
54         useExtendedPacketHeader bool
55         interfaceIndex          int
56         mu                      sync.Mutex
57         // Since pointers to these objects are passed into a C function, if
58         // they're declared locally then the Go compiler thinks they may have
59         // escaped into C-land, so it allocates them on the heap.  This causes a
60         // huge memory hit, so to handle that we store them here instead.
61         pkthdr C.struct_pfring_pkthdr
62         bufPtr *C.u_char
63 }
64
65 // Flag provides a set of boolean flags to use when creating a new ring.
66 type Flag uint32
67
68 // Set of flags that can be passed (OR'd together) to NewRing.
69 const (
70         FlagReentrant       Flag = C.PF_RING_REENTRANT
71         FlagLongHeader      Flag = C.PF_RING_LONG_HEADER
72         FlagPromisc         Flag = C.PF_RING_PROMISC
73         FlagDNASymmetricRSS Flag = C.PF_RING_DNA_SYMMETRIC_RSS
74         FlagTimestamp       Flag = C.PF_RING_TIMESTAMP
75         FlagHWTimestamp     Flag = C.PF_RING_HW_TIMESTAMP
76 )
77
78 // NewRing creates a new PFRing.  Note that when the ring is initially created,
79 // it is disabled.  The caller must call Enable to start receiving packets.
80 // The caller should call Close on the given ring when finished with it.
81 func NewRing(device string, snaplen uint32, flags Flag) (ring *Ring, _ error) {
82         dev := C.CString(device)
83         defer C.free(unsafe.Pointer(dev))
84
85         cptr, err := C.pfring_open(dev, C.u_int32_t(snaplen), C.u_int32_t(flags))
86         if cptr == nil || err != nil {
87                 return nil, fmt.Errorf("pfring NewRing error: %v", err)
88         }
89         ring = &Ring{cptr: cptr, snaplen: int(snaplen)}
90
91         if flags&FlagLongHeader == FlagLongHeader {
92                 ring.useExtendedPacketHeader = true
93         } else {
94                 ifc, err := net.InterfaceByName(device)
95                 if err == nil {
96                         ring.interfaceIndex = ifc.Index
97                 }
98         }
99         ring.SetApplicationName(os.Args[0])
100         return
101 }
102
103 // Close closes the given Ring.  After this call, the Ring should no longer be
104 // used.
105 func (r *Ring) Close() {
106         C.pfring_close(r.cptr)
107 }
108
109 // NextResult is the return code from a call to Next.
110 type NextResult int32
111
112 // Set of results that could be returned from a call to get another packet.
113 const (
114         NextNoPacketNonblocking NextResult = 0
115         NextError               NextResult = -1
116         NextOk                  NextResult = 1
117         NextNotEnabled          NextResult = -7
118 )
119
120 // NextResult implements the error interface.
121 func (n NextResult) Error() string {
122         switch n {
123         case NextNoPacketNonblocking:
124                 return "No packet available, nonblocking socket"
125         case NextError:
126                 return "Generic error"
127         case NextOk:
128                 return "Success (not an error)"
129         case NextNotEnabled:
130                 return "Ring not enabled"
131         }
132         return strconv.Itoa(int(n))
133 }
134
135 // ReadPacketDataTo reads packet data into a user-supplied buffer.
136 // This function ignores snaplen and instead reads up to the length of the
137 // passed-in slice.
138 // The number of bytes read into data will be returned in ci.CaptureLength.
139 func (r *Ring) ReadPacketDataTo(data []byte) (ci gopacket.CaptureInfo, err error) {
140         // This tricky bufPtr points to the start of our slice data, so pfring_recv
141         // will actually write directly into our Go slice.  Nice!
142         r.mu.Lock()
143         r.bufPtr = (*C.u_char)(unsafe.Pointer(&data[0]))
144         result := NextResult(C.pfring_readpacketdatato_wrapper(r.cptr, r.bufPtr, C.u_int(len(data)), &r.pkthdr))
145         if result != NextOk {
146                 err = result
147                 r.mu.Unlock()
148                 return
149         }
150         ci.Timestamp = time.Unix(int64(r.pkthdr.ts.tv_sec),
151                 int64(r.pkthdr.ts.tv_usec)*1000) // convert micros to nanos
152         ci.CaptureLength = int(r.pkthdr.caplen)
153         ci.Length = int(r.pkthdr.len)
154         if r.useExtendedPacketHeader {
155                 ci.InterfaceIndex = int(r.pkthdr.extended_hdr.if_index)
156         } else {
157                 ci.InterfaceIndex = r.interfaceIndex
158         }
159         r.mu.Unlock()
160         return
161 }
162
163 // ReadPacketData returns the next packet read from the pcap handle, along with an error
164 // code associated with that packet.  If the packet is read successfully, the
165 // returned error is nil.
166 func (r *Ring) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
167         data = make([]byte, r.snaplen)
168         ci, err = r.ReadPacketDataTo(data)
169         if err != nil {
170                 data = nil
171                 return
172         }
173         data = data[:ci.CaptureLength]
174         return
175 }
176
177 // ClusterType is a type of clustering used when balancing across multiple
178 // rings.
179 type ClusterType C.cluster_type
180
181 const (
182         // ClusterPerFlow clusters by <src ip, src port, dst ip, dst port, proto,
183         // vlan>
184         ClusterPerFlow ClusterType = C.cluster_per_flow
185         // ClusterRoundRobin round-robins packets between applications, ignoring
186         // packet information.
187         ClusterRoundRobin ClusterType = C.cluster_round_robin
188         // ClusterPerFlow2Tuple clusters by <src ip, dst ip>
189         ClusterPerFlow2Tuple ClusterType = C.cluster_per_flow_2_tuple
190         // ClusterPerFlow4Tuple clusters by <src ip, src port, dst ip, dst port>
191         ClusterPerFlow4Tuple ClusterType = C.cluster_per_flow_4_tuple
192         // ClusterPerFlow5Tuple clusters by <src ip, src port, dst ip, dst port,
193         // proto>
194         ClusterPerFlow5Tuple ClusterType = C.cluster_per_flow_5_tuple
195         // ClusterPerFlowTCP5Tuple acts like ClusterPerFlow5Tuple for TCP packets and
196         // like ClusterPerFlow2Tuple for all other packets.
197         ClusterPerFlowTCP5Tuple ClusterType = C.cluster_per_flow_tcp_5_tuple
198 )
199
200 // SetCluster sets which cluster the ring should be part of, and the cluster
201 // type to use.
202 func (r *Ring) SetCluster(cluster int, typ ClusterType) error {
203         if rv := C.pfring_set_cluster(r.cptr, C.u_int(cluster), C.cluster_type(typ)); rv != 0 {
204                 return fmt.Errorf("Unable to set cluster, got error code %d", rv)
205         }
206         return nil
207 }
208
209 // RemoveFromCluster removes the ring from the cluster it was put in with
210 // SetCluster.
211 func (r *Ring) RemoveFromCluster() error {
212         if rv := C.pfring_remove_from_cluster(r.cptr); rv != 0 {
213                 return fmt.Errorf("Unable to remove from cluster, got error code %d", rv)
214         }
215         return nil
216 }
217
218 // SetSamplingRate sets the sampling rate to 1/<rate>.
219 func (r *Ring) SetSamplingRate(rate int) error {
220         if rv := C.pfring_set_sampling_rate(r.cptr, C.u_int32_t(rate)); rv != 0 {
221                 return fmt.Errorf("Unable to set sampling rate, got error code %d", rv)
222         }
223         return nil
224 }
225
226 // SetBPFFilter sets the BPF filter for the ring.
227 func (r *Ring) SetBPFFilter(bpfFilter string) error {
228         filter := C.CString(bpfFilter)
229         defer C.free(unsafe.Pointer(filter))
230         if rv := C.pfring_set_bpf_filter(r.cptr, filter); rv != 0 {
231                 return fmt.Errorf("Unable to set BPF filter, got error code %d", rv)
232         }
233         return nil
234 }
235
236 // RemoveBPFFilter removes the BPF filter from the ring.
237 func (r *Ring) RemoveBPFFilter() error {
238         if rv := C.pfring_remove_bpf_filter(r.cptr); rv != 0 {
239                 return fmt.Errorf("Unable to remove BPF filter, got error code %d", rv)
240         }
241         return nil
242 }
243
244 // WritePacketData uses the ring to send raw packet data to the interface.
245 func (r *Ring) WritePacketData(data []byte) error {
246         buf := (*C.char)(unsafe.Pointer(&data[0]))
247         if rv := C.pfring_send(r.cptr, buf, C.u_int(len(data)), 1); rv < 0 {
248                 return fmt.Errorf("Unable to send packet data, got error code %d", rv)
249         }
250         return nil
251 }
252
253 // Enable enables the given ring.  This function MUST be called on each new
254 // ring after it has been set up, or that ring will NOT receive packets.
255 func (r *Ring) Enable() error {
256         if rv := C.pfring_enable_ring(r.cptr); rv != 0 {
257                 return fmt.Errorf("Unable to enable ring, got error code %d", rv)
258         }
259         return nil
260 }
261
262 // Disable disables the given ring.  After this call, it will no longer receive
263 // packets.
264 func (r *Ring) Disable() error {
265         if rv := C.pfring_disable_ring(r.cptr); rv != 0 {
266                 return fmt.Errorf("Unable to disable ring, got error code %d", rv)
267         }
268         return nil
269 }
270
271 // Stats provides simple statistics on a ring.
272 type Stats struct {
273         Received, Dropped uint64
274 }
275
276 // Stats returns statistsics for the ring.
277 func (r *Ring) Stats() (s Stats, err error) {
278         var stats C.pfring_stat
279         if rv := C.pfring_stats(r.cptr, &stats); rv != 0 {
280                 err = fmt.Errorf("Unable to get ring stats, got error code %d", rv)
281                 return
282         }
283         s.Received = uint64(stats.recv)
284         s.Dropped = uint64(stats.drop)
285         return
286 }
287
288 // Direction is a simple enum to set which packets (TX, RX, or both) a ring
289 // captures.
290 type Direction C.packet_direction
291
292 const (
293         // TransmitOnly will only capture packets transmitted by the ring's
294         // interface(s).
295         TransmitOnly Direction = C.tx_only_direction
296         // ReceiveOnly will only capture packets received by the ring's
297         // interface(s).
298         ReceiveOnly Direction = C.rx_only_direction
299         // ReceiveAndTransmit will capture both received and transmitted packets on
300         // the ring's interface(s).
301         ReceiveAndTransmit Direction = C.rx_and_tx_direction
302 )
303
304 // SetDirection sets which packets should be captured by the ring.
305 func (r *Ring) SetDirection(d Direction) error {
306         if rv := C.pfring_set_direction(r.cptr, C.packet_direction(d)); rv != 0 {
307                 return fmt.Errorf("Unable to set ring direction, got error code %d", rv)
308         }
309         return nil
310 }
311
312 // SocketMode is an enum for setting whether a ring should read, write, or both.
313 type SocketMode C.socket_mode
314
315 const (
316         // WriteOnly sets up the ring to only send packets (Inject), not read them.
317         WriteOnly SocketMode = C.send_only_mode
318         // ReadOnly sets up the ring to only receive packets (ReadPacketData), not
319         // send them.
320         ReadOnly SocketMode = C.recv_only_mode
321         // WriteAndRead sets up the ring to both send and receive packets.
322         WriteAndRead SocketMode = C.send_and_recv_mode
323 )
324
325 // SetSocketMode sets the mode of the ring socket to send, receive, or both.
326 func (r *Ring) SetSocketMode(s SocketMode) error {
327         if rv := C.pfring_set_socket_mode(r.cptr, C.socket_mode(s)); rv != 0 {
328                 return fmt.Errorf("Unable to set socket mode, got error code %d", rv)
329         }
330         return nil
331 }
332
333 // SetApplicationName sets a string name to the ring.  This name is available in
334 // /proc stats for pf_ring.  By default, NewRing automatically calls this with
335 // argv[0].
336 func (r *Ring) SetApplicationName(name string) error {
337         buf := C.CString(name)
338         defer C.free(unsafe.Pointer(buf))
339         if rv := C.pfring_set_application_name(r.cptr, buf); rv != 0 {
340                 return fmt.Errorf("Unable to set ring application name, got error code %d", rv)
341         }
342         return nil
343 }