d663fd2043a6288958c0e8f4d848a58387fbfa90
[govpp.git] / extras / libmemif / README.md
1 ## Go-libmemif
2
3 Package **libmemif** is a Golang adapter for the **libmemif library**
4 (`extras/libmemif` in the [VPP](https://wiki.fd.io/view/VPP) repository).
5 To differentiate between the adapter and the underlying C-written library,
6 labels `Go-libmemif` and `C-libmemif` are used in the documentation.
7
8 ### Requirements
9
10 libmemif for Golang is build on the top of the original, C-written
11 libmemif library using `cgo`. It is therefore necessary to have C-libmemif
12 header files and the library itself installed in locations known
13 to the compiler.
14
15 For example, to install C-libmemif system-wide into the standard
16 locations, execute:
17 ```
18 $ git clone https://gerrit.fd.io/r/vpp
19 $ cd vpp/extras/libmemif
20 $ ./bootstrap
21 $ ./configure
22 $ make install
23 ```
24
25 ### Build
26
27 Package **libmemif** is not part of the **GoVPP** core and as such it is
28 not included in the [make build](../../Makefile) target.
29 Instead, it has its own target in the [top-level Makefile](../../Makefile)
30 used to build the attached examples with the adapter:
31 ```
32 $ make extras
33 ```
34
35 ### APIs
36
37 All **Go-libmemif** public APIs can be found in [adapter.go](adapter.go).
38 Please see the comments for a more detailed description.
39 Additionally, a list of all errors thrown by libmemif can be found
40 in [error.go](error.go).
41
42 ### Usage
43
44 **libmemif** needs to be first initialized with `Init(appName)`.
45 This has to be done only once in the context of the entire process.
46 Make sure to call `Cleanup()` to release all the resources allocated
47 by **libmemif** before exiting your application. Consider calling
48 `Init()` followed by `Cleanup()` scheduled with `defer` in the `main()`
49 function.
50
51 Log messages are by default printed to stdout. Use `SetLogger()` to use
52 your own customized logger (can be changed before `Init()`).
53
54 Once **libmemif** is initialized, new memif interfaces can be created
55 with `CreateInterface(config, callbacks)`. See `MemifConfig` structure
56 definition to learn about possible memif configuration options.
57 If successful, `CreateInterface()` returns an instance of `Memif`
58 structure representing the underlying memif interface.
59
60 Callbacks are optional and can be shared across multiple memif instances.
61 Available callbacks are:
62 1. **OnConnect**: called when the connection is established.
63    By the time the callback is called, the Rx/Tx queues are initialized
64    and ready for data transmission. Interrupt channels are also
65    created and ready to be read from.
66    The user is expected to start polling for input packets via repeated
67    calls to `Memif.RxBurst(queueID, count)` or to initiate select
68    on the interrupt channels obtained with `Get*InterruptChan()`,
69    depending on the Rx mode. By default, all memif Rx queues are created
70    in the interrupt mode, but this can be changed per-queue with
71    `Memif.SetRxMode(queueID, mode)`.
72 2. **OnDisconnect**: called after the connection was closed. Immediately
73    after the user callback returns, Rx/Tx queues and interrupt channels
74    are also deallocated. The user defined callback should therefore ensure
75    that all the Rx/Tx operations are stopped before it returns.
76
77 **libmemif** was designed for a maximum possible performance. Packets
78 are sent and received in bulks, rather than one-by-one, using
79 `Memif.TxBurst(queueID, packets)` and `Memif.RxBurst(queueID, count)`,
80 respectively. Memif connection can consists of multiple queues in both
81 directions. A queue is one-directional wait-free ring buffer.
82 It is the unit of parallelism for data transmission. The maximum possible
83 lock-free granularity is therefore one go routine for one queue.
84
85 Interrupt channel for one specific Rx queue can be obtained with
86 `GetQueueInterruptChan(queueID)` as opposed to `GetInterruptChan()`
87 for all the Rx queues. There is only one interrupt signal sent for
88 an entire burst of packets, therefore an interrupt handling routine
89 should repeatedly call RxBurst() until an empty slice of packets
90 is returned. This way it is ensured that there are no packets left
91 on the queue unread when the interrupt signal is cleared.
92 Study the `ReadAndPrintPackets()` function in [raw-data example](examples/raw-data/raw-data.go).
93
94 For **libmemif** the packet is just an array of bytes. It does not care
95 what the actual content is. It is not required for a packet to follow
96 any network protocol in order to get transported from one end to another.
97 See the type declaration for `RawPacketData` and its use in `Memif.TxBurst()`
98 and `Memif.RxBurst()`.
99
100 In order to remove a memif interface, call `Memif.Close()`. If the memif
101 is in the connected state, the connection is first properly closed.
102 Do not touch memif after it was closed, let garbage collector to remove
103 the `Memif` instance. In the end, `Cleanup()` will also ensure that all
104 active memif interfaces are closed before the cleanup finalizes.
105
106 To use libmemif with `google/gopacket`, simply call `Memif.NewPacketHandle()`
107 to create `google/gopacket/PacketDataSource` from memif queue. After this you
108 can use gopacket API to read from `MemifPacketHandle` as normal. You can pass
109 optional `rxCount` when creating the packet handle and then when reading data,
110 handle will try to read more packets at once and cache them for next iteration.
111 Handle also includes convenience method `MemifPacketHandle.WritePacketData()`
112 that is simply calling 1 `Memif.TxBurst()` for provided data.
113
114 ### Examples
115
116 **Go-libmemif** ships with two simple examples demonstrating the usage
117 of the package with a detailed commentary.
118 The examples can be found in the subdirectory [examples](./examples).
119
120 #### Raw data (libmemif <-> libmemif)
121
122 *raw-data* is a basic example showing how to create a memif interface,
123 handle events through callbacks and perform Rx/Tx of raw data. Before
124 handling an actual packets it is important to understand the skeleton
125 of libmemif-based applications.
126
127 Since VPP expects proper packet data, it is not very useful to connect
128 *raw-data* example with VPP, even though it will work, since all
129 the received data will get dropped on the VPP side.
130
131 To create a connection of two raw-data instances, start two processes
132 concurrently in an arbitrary order:
133  - *master* memif:
134    ```
135    $ cd extras/libmemif/examples/raw-data
136    $ ./raw-data
137    ```
138  - *slave* memif:
139    ```
140    $ cd extras/libmemif/examples/raw-data
141    $ ./raw-data --slave
142    ```
143
144 Every 3 seconds both sides send 3 raw-data packets to the opposite end
145 through each of the 3 queues. The received packets are printed to stdout.
146
147 Stop an instance of *raw-data* with an interrupt signal (^C).
148
149 #### Jumbo Frames Raw data (libmemif <-> libmemif)
150
151 *jumbo-frames* is simple example how to send larger and larger jumbo
152 packets with libmemif adapter. This is simple copy of *raw-data* but with
153 sending larger packets, so for more information read its code and documentation.
154
155 #### ICMP Responder
156
157 *icmp-responder* is a simple example showing how to answer APR and ICMP
158 echo requests through a memif interface. Package `google/gopacket` is
159 used to decode and construct packets.
160
161 The appropriate VPP configuration for the opposite memif is:
162 ```
163 vpp$ create memif socket id 1 filename /tmp/icmp-responder-example
164 vpp$ create interface memif id 1 socket-id 1 slave secret secret no-zero-copy
165 vpp$ set int state memif1/1 up
166 vpp$ set int ip address memif1/1 192.168.1.2/24
167 ```
168
169 To start the example, simply type:
170 ```
171 root$ ./icmp-responder
172 ```
173
174 *icmp-responder* needs to be run as root so that it can access the socket
175 created by VPP.
176
177 Normally, the memif interface is in the master mode. Pass CLI flag `--slave`
178 to create memif in the slave mode:
179 ```
180 root$ ./icmp-responder --slave
181 ```
182
183 Don't forget to put the opposite memif into the master mode in that case.
184
185 To verify the connection, run:
186 ```
187 vpp$ ping 192.168.1.1
188 64 bytes from 192.168.1.1: icmp_seq=2 ttl=255 time=.6974 ms
189 64 bytes from 192.168.1.1: icmp_seq=3 ttl=255 time=.6310 ms
190 64 bytes from 192.168.1.1: icmp_seq=4 ttl=255 time=1.0350 ms
191 64 bytes from 192.168.1.1: icmp_seq=5 ttl=255 time=.5359 ms
192
193 Statistics: 5 sent, 4 received, 20% packet loss
194 vpp$ sh ip arp
195     Time           IP4       Flags      Ethernet              Interface
196     68.5648   192.168.1.1     D    aa:aa:aa:aa:aa:aa memif0/1
197 ```
198 *Note*: it is expected that the first ping is shown as lost.
199         It was actually converted to an ARP request. This is a VPP
200         specific feature common to all interface types.
201
202 Stop the example with an interrupt signal (^C).
203
204 #### GoPacket ICMP Responder
205
206 *gopacket* is a simple example showing how to answer APR and ICMP echo
207 requests through a memif interface. This example is mostly identical
208 to icmp-responder example, but it is using MemifPacketHandle API to
209 read and write packets using gopacket API.
210
211 The appropriate VPP configuration for the opposite memif is:
212 ```
213 vpp$ create memif socket id 1 filename /tmp/gopacket-example
214 vpp$ create interface memif id 1 socket-id 1 slave secret secret no-zero-copy
215 vpp$ set int state memif1/1 up
216 vpp$ set int ip address memif1/1 192.168.1.2/24
217 ```
218
219 To start the example, simply type:
220 ```
221 root$ ./gopacket
222 ```
223
224 gopacket needs to be run as root so that it can access the socket
225 created by VPP.
226
227 Normally, the memif interface is in the master mode. Pass CLI flag "--slave"
228 to create memif in the slave mode:
229 ```
230 root$ ./gopacket --slave
231 ```
232
233 Don't forget to put the opposite memif into the master mode in that case.
234
235 To verify the connection, run:
236 ```
237 vpp$ ping 192.168.1.1
238 64 bytes from 192.168.1.1: icmp_seq=2 ttl=255 time=.6974 ms
239 64 bytes from 192.168.1.1: icmp_seq=3 ttl=255 time=.6310 ms
240 64 bytes from 192.168.1.1: icmp_seq=4 ttl=255 time=1.0350 ms
241 64 bytes from 192.168.1.1: icmp_seq=5 ttl=255 time=.5359 ms
242
243 Statistics: 5 sent, 4 received, 20% packet loss
244 vpp$ sh ip arp
245 Time           IP4       Flags      Ethernet              Interface
246 68.5648   192.168.1.1     D    aa:aa:aa:aa:aa:aa memif0/1
247 ```
248
249 *Note*: it is expected that the first ping is shown as lost.
250         It was actually converted to an ARP request. This is a VPP
251         specific feature common to all interface types.
252
253 Stop the example with an interrupt signal (^C).