blob: f576fe251452d60ca902f6263f91f84155c341d4 [file] [log] [blame]
Nathan Skrzypczak8acc5ee2021-10-12 14:00:25 +02001.. _libmemif_gettingstarted_doc:
2
3Getting started
4===============
5
6For detailed information on api calls and structures please refer to
7``libmemif.h``.
8
9Start by creating a memif socket. Memif socket represents UNIX domain
10socket and interfaces assigned to use this socket. Memif uses UNIX domain
11socket to communicate with other memif drivers.
12
13First fill out the ``memif_socket_args`` struct. The minimum required
14configuration is the UNIX socket path. > Use ``@`` or ``\0`` at the
15beginning of the path to use abstract socket.
16
17.. code:: c
18
19 memif_socket_args_t sargs;
20
21 strncpy(sargs.path, socket_path, sizeof(sargs.path));
22
23.. code:: c
24
25 memif_socket_handle_t memif_socket;
26
27 memif_create_socket(&memif_socket, &sargs, &private_data);
28
29Once you have created your socket, you can create memif interfaces on
30this socket. Fill out the ``memif_conn_args`` struct. Then call
31``memif_create()``.
32
33.. code:: c
34
35 memif_conn_args_t cargs;
36
37 /* Assign your socket handle */
38 cargs.socket = memif_socket;
39
40.. code:: c
41
42 memif_conn_handle_t conn;
43
44 /* Assign callbacks */
45 memif_create (&conn, &cargs, on_connect_cb, on_disconnect_cb, on_interrupt_cb, &private_data);
46
47Now start the polling events using libmemifs builtin polling.
48
49.. code:: c
50
51 do {
52 err = memif_poll_event(memif_socket, /* timeout -1 = blocking */ -1);
53 } while (err == MEMIF_ERR_SUCCESS);
54
55Polling can be canceled by calling ``memif_cancel_poll_event()``.
56
57.. code:: c
58
59 memif_cancel_poll_event (memif_socket);
60
61On link status change ``on_connect`` and ``on_disconnect`` callbacks are
62called respectively. Before you can start transmitting data you, first
63need to call ``memif_refill_queue()`` for each RX queue to initialize
64this queue.
65
66.. code:: c
67
68 int on_connect (memif_conn_handle_t conn, void *private_ctx)
69 {
70 my_private_data_t *data = (my_private_data_t *) private_ctx;
71
72 err = memif_refill_queue(conn, 0, -1, 0);
73 if (err != MEMIF_ERR_SUCCESS) {
74 INFO("memif_refill_queue: %s", memif_strerror(err));
75 return err;
76 }
77
78 /*
79 * Do stuff.
80 */
81
82 return 0;
83 }
84
85Now you are ready to transmit packets. > Example implementation
86``examples/common/sender.c`` and ``examples/common/responder.c``
87
88To transmit or receive data you will need to use ``memif_buffer``
89struct. The important fields here are ``void *data``, ``uint32_t len``
90and ``uint8_t flags``. The ``data`` pointer points directly to the
91shared memory packet buffer. This is where you will find/insert your
92packets. The ``len`` field is the length of the buffer. If the flag
93``MEMIF_BUFFER_FLAG_NEXT`` is present in ``flags`` field, this buffer is
94chained so the rest of the data is located in the next buffer, and so
95on.
96
97First lets receive data. To receive data call ``memif_rx_burst()``. The
98function will fill out memif buffers passed to it. Then you would
99process your data (e.gcopy to your stack). Last you must refill the
100queue using ``memif_refill_queue()`` to notify peer that the buffers are
101now free and can be overwritten.
102
103.. code:: c
104
105 /* Fill out memif buffers and mark them as received */
106 err = memif_rx_burst(conn, qid, buffers, num_buffers, &num_received);
107 if (err != MEMIF_ERR_SUCCESS) {
108 INFO ("memif_rx_burst: %s", memif_strerror(err));
109 return err;
110 }
111 /*
112 Process the buffers.
113 */
114
115 /* Refill the queue, so that the peer interface can transmit more packets */
116 err = memif_refill_queue(conn, qid, num_received, 0);
117 if (err != MEMIF_ERR_SUCCESS) {
118 INFO("memif_refill_queue: %s", memif_strerror(err));
119 goto error;
120 }
121
122In order to transmit data you first need to allocate memif buffers
123using ``memif_buffer_alloc()``. This function similar to
124``memif_rx_burst`` will fill out provided memif buffers. You will then
125insert your packets directly into the shared memory (dont forget to
126update ``len`` filed if your packet is smaller that buffer length).
127Finally call ``memif_tx_burst`` to transmit the buffers.
128
129.. code:: c
130
131 /* Alocate memif buffers */
132 err = memif_buffer_alloc(conn, qid, buffers, num_pkts, &num_allocated, packet_size);
133 if (err != MEMIF_ERR_SUCCESS) {
134 INFO("memif_buffer_alloc: %s", memif_strerror(err));
135 goto error;
136 }
137
138 /*
139 Fill out the buffers.
140
141 tx_buffers[i].data field points to the shared memory.
142 update tx_buffers[i].len to your packet length, if the packet is smaller.
143 */
144
145 /* Transmit the buffers */
146 err = memif_tx_burst(conn, qid, buffers, num_allocated, &num_transmitted);
147 if (err != MEMIF_ERR_SUCCESS) {
148 INFO("memif_tx_burst: %s", memif_strerror(err));
149 goto error;
150 }
151
152Zero-copy Slave
153---------------
154
155Interface with slave role is the buffer producer, as such it can use
156zero-copy mode.
157
158After receiving buffers, process your packets in place. Then use
159``memif_buffer_enq_tx()`` to enqueue rx buffers to tx queue (by swapping
160rx buffer with a free tx buffer).
161
162.. code:: c
163
164 /* Fill out memif buffers and mark them as received */
165 err = memif_rx_burst(conn, qid, buffers, num_buffers, &num_received);
166 if (err != MEMIF_ERR_SUCCESS) {
167 INFO ("memif_rx_burst: %s", memif_strerror(err));
168 return err;
169 }
170
171 /*
172 Process the buffers in place.
173 */
174
175 /* Enqueue processed buffers to tx queue */
176 err = memif_buffer_enq_tx(conn, qid, buffers, num_buffers, &num_enqueued);
177 if (err != MEMIF_ERR_SUCCESS) {
178 INFO("memif_buffer_alloc: %s", memif_strerror(err));
179 goto error;
180 }
181
182 /* Refill the queue, so that the peer interface can transmit more packets */
183 err = memif_refill_queue(conn, qid, num_enqueued, 0);
184 if (err != MEMIF_ERR_SUCCESS) {
185 INFO("memif_refill_queue: %s", memif_strerror(err));
186 goto error;
187 }
188
189 /* Transmit the buffers. */
190 err = memif_tx_burst(conn, qid, buffers, num_enqueued, &num_transmitted);
191 if (err != MEMIF_ERR_SUCCESS) {
192 INFO("memif_tx_burst: %s", memif_strerror(err));
193 goto error;
194 }
195
196Custom Event Polling
197--------------------
198
199Libmemif can be integrated into your applications fd event polling. You
200will need to implement ``memif_control_fd_update_t`` callback and pass
201it to ``memif_socket_args.on_control_fd_update``. Now each time any file
202descriptor belonging to that socket updates, ``on_control_fd_update``
203callback is called. The file descriptor and event type is passed in
204``memif_fd_event_t``. It also contains private context that is
205associated with this fd. When event is polled on the fd you need to call
206``memif_control_fd_handler`` and pass the event type and private context
207associated with the fd.
208
209Multi Threading
210---------------
211
212Connection establishment
213~~~~~~~~~~~~~~~~~~~~~~~~
214
215Memif sockets should not be handled in parallel. Instead each thread
216should have its own socket. However the UNIX socket can be the same. In
217case of non-listener socket, its straight forward, just create the
218socket using the same path. In case of listener socket, the polling
219should be done by single thread. > The socket becomes listener once a
220Master interface is assigned to it.
221
222Packet handling
223~~~~~~~~~~~~~~~
224
225Single queue must not be handled in parallel. Instead you can assign
226queues to threads in such way that each queue is only assigned single
227thread.
228
229Shared Memory Layout
230--------------------
231
232Please refer to `DPDK MEMIF
233documentation <http://doc.dpdk.org/guides/nics/memif.html>`__
234``'Shared memory'`` section.