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