]> git.proxmox.com Git - ceph.git/blame - ceph/src/dpdk/doc/guides/sample_app_ug/skeleton.rst
bump version to 12.2.12-pve1
[ceph.git] / ceph / src / dpdk / doc / guides / sample_app_ug / skeleton.rst
CommitLineData
7c673cae
FG
1.. BSD LICENSE
2 Copyright(c) 2015 Intel Corporation. All rights reserved.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in
13 the documentation and/or other materials provided with the
14 distribution.
15 * Neither the name of Intel Corporation nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31
32Basic Forwarding Sample Application
33===================================
34
35The Basic Forwarding sample application is a simple *skeleton* example of a
36forwarding application.
37
38It is intended as a demonstration of the basic components of a DPDK forwarding
39application. For more detailed implementations see the L2 and L3 forwarding
40sample applications.
41
42
43Compiling the Application
44-------------------------
45
46To compile the application export the path to the DPDK source tree and go to
47the example directory:
48
49.. code-block:: console
50
51 export RTE_SDK=/path/to/rte_sdk
52
53 cd ${RTE_SDK}/examples/skeleton
54
55Set the target, for example:
56
57.. code-block:: console
58
59 export RTE_TARGET=x86_64-native-linuxapp-gcc
60
61See the *DPDK Getting Started* Guide for possible ``RTE_TARGET`` values.
62
63Build the application as follows:
64
65.. code-block:: console
66
67 make
68
69
70Running the Application
71-----------------------
72
73To run the example in a ``linuxapp`` environment:
74
75.. code-block:: console
76
77 ./build/basicfwd -c 2 -n 4
78
79Refer to *DPDK Getting Started Guide* for general information on running
80applications and the Environment Abstraction Layer (EAL) options.
81
82
83Explanation
84-----------
85
86The following sections provide an explanation of the main components of the
87code.
88
89All DPDK library functions used in the sample code are prefixed with ``rte_``
90and are explained in detail in the *DPDK API Documentation*.
91
92
93The Main Function
94~~~~~~~~~~~~~~~~~
95
96The ``main()`` function performs the initialization and calls the execution
97threads for each lcore.
98
99The first task is to initialize the Environment Abstraction Layer (EAL). The
100``argc`` and ``argv`` arguments are provided to the ``rte_eal_init()``
101function. The value returned is the number of parsed arguments:
102
103.. code-block:: c
104
105 int ret = rte_eal_init(argc, argv);
106 if (ret < 0)
107 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
108
109
110The ``main()`` also allocates a mempool to hold the mbufs (Message Buffers)
111used by the application:
112
113.. code-block:: c
114
115 mbuf_pool = rte_mempool_create("MBUF_POOL",
116 NUM_MBUFS * nb_ports,
117 MBUF_SIZE,
118 MBUF_CACHE_SIZE,
119 sizeof(struct rte_pktmbuf_pool_private),
120 rte_pktmbuf_pool_init, NULL,
121 rte_pktmbuf_init, NULL,
122 rte_socket_id(),
123 0);
124
125Mbufs are the packet buffer structure used by DPDK. They are explained in
126detail in the "Mbuf Library" section of the *DPDK Programmer's Guide*.
127
128The ``main()`` function also initializes all the ports using the user defined
129``port_init()`` function which is explained in the next section:
130
131.. code-block:: c
132
133 for (portid = 0; portid < nb_ports; portid++) {
134 if (port_init(portid, mbuf_pool) != 0) {
135 rte_exit(EXIT_FAILURE,
136 "Cannot init port %" PRIu8 "\n", portid);
137 }
138 }
139
140
141Once the initialization is complete, the application is ready to launch a
142function on an lcore. In this example ``lcore_main()`` is called on a single
143lcore.
144
145
146.. code-block:: c
147
148 lcore_main();
149
150The ``lcore_main()`` function is explained below.
151
152
153
154The Port Initialization Function
155~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
156
157The main functional part of the port initialization used in the Basic
158Forwarding application is shown below:
159
160.. code-block:: c
161
162 static inline int
163 port_init(uint8_t port, struct rte_mempool *mbuf_pool)
164 {
165 struct rte_eth_conf port_conf = port_conf_default;
166 const uint16_t rx_rings = 1, tx_rings = 1;
167 struct ether_addr addr;
168 int retval;
169 uint16_t q;
170
171 if (port >= rte_eth_dev_count())
172 return -1;
173
174 /* Configure the Ethernet device. */
175 retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
176 if (retval != 0)
177 return retval;
178
179 /* Allocate and set up 1 RX queue per Ethernet port. */
180 for (q = 0; q < rx_rings; q++) {
181 retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE,
182 rte_eth_dev_socket_id(port), NULL, mbuf_pool);
183 if (retval < 0)
184 return retval;
185 }
186
187 /* Allocate and set up 1 TX queue per Ethernet port. */
188 for (q = 0; q < tx_rings; q++) {
189 retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE,
190 rte_eth_dev_socket_id(port), NULL);
191 if (retval < 0)
192 return retval;
193 }
194
195 /* Start the Ethernet port. */
196 retval = rte_eth_dev_start(port);
197 if (retval < 0)
198 return retval;
199
200 /* Enable RX in promiscuous mode for the Ethernet device. */
201 rte_eth_promiscuous_enable(port);
202
203 return 0;
204 }
205
206The Ethernet ports are configured with default settings using the
207``rte_eth_dev_configure()`` function and the ``port_conf_default`` struct:
208
209.. code-block:: c
210
211 static const struct rte_eth_conf port_conf_default = {
212 .rxmode = { .max_rx_pkt_len = ETHER_MAX_LEN }
213 };
214
215For this example the ports are set up with 1 RX and 1 TX queue using the
216``rte_eth_rx_queue_setup()`` and ``rte_eth_tx_queue_setup()`` functions.
217
218The Ethernet port is then started:
219
220.. code-block:: c
221
222 retval = rte_eth_dev_start(port);
223
224
225Finally the RX port is set in promiscuous mode:
226
227.. code-block:: c
228
229 rte_eth_promiscuous_enable(port);
230
231
232The Lcores Main
233~~~~~~~~~~~~~~~
234
235As we saw above the ``main()`` function calls an application function on the
236available lcores. For the Basic Forwarding application the lcore function
237looks like the following:
238
239.. code-block:: c
240
241 static __attribute__((noreturn)) void
242 lcore_main(void)
243 {
244 const uint8_t nb_ports = rte_eth_dev_count();
245 uint8_t port;
246
247 /*
248 * Check that the port is on the same NUMA node as the polling thread
249 * for best performance.
250 */
251 for (port = 0; port < nb_ports; port++)
252 if (rte_eth_dev_socket_id(port) > 0 &&
253 rte_eth_dev_socket_id(port) !=
254 (int)rte_socket_id())
255 printf("WARNING, port %u is on remote NUMA node to "
256 "polling thread.\n\tPerformance will "
257 "not be optimal.\n", port);
258
259 printf("\nCore %u forwarding packets. [Ctrl+C to quit]\n",
260 rte_lcore_id());
261
262 /* Run until the application is quit or killed. */
263 for (;;) {
264 /*
265 * Receive packets on a port and forward them on the paired
266 * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
267 */
268 for (port = 0; port < nb_ports; port++) {
269
270 /* Get burst of RX packets, from first port of pair. */
271 struct rte_mbuf *bufs[BURST_SIZE];
272 const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
273 bufs, BURST_SIZE);
274
275 if (unlikely(nb_rx == 0))
276 continue;
277
278 /* Send burst of TX packets, to second port of pair. */
279 const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0,
280 bufs, nb_rx);
281
282 /* Free any unsent packets. */
283 if (unlikely(nb_tx < nb_rx)) {
284 uint16_t buf;
285 for (buf = nb_tx; buf < nb_rx; buf++)
286 rte_pktmbuf_free(bufs[buf]);
287 }
288 }
289 }
290 }
291
292
293The main work of the application is done within the loop:
294
295.. code-block:: c
296
297 for (;;) {
298 for (port = 0; port < nb_ports; port++) {
299
300 /* Get burst of RX packets, from first port of pair. */
301 struct rte_mbuf *bufs[BURST_SIZE];
302 const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
303 bufs, BURST_SIZE);
304
305 if (unlikely(nb_rx == 0))
306 continue;
307
308 /* Send burst of TX packets, to second port of pair. */
309 const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0,
310 bufs, nb_rx);
311
312 /* Free any unsent packets. */
313 if (unlikely(nb_tx < nb_rx)) {
314 uint16_t buf;
315 for (buf = nb_tx; buf < nb_rx; buf++)
316 rte_pktmbuf_free(bufs[buf]);
317 }
318 }
319 }
320
321Packets are received in bursts on the RX ports and transmitted in bursts on
322the TX ports. The ports are grouped in pairs with a simple mapping scheme
323using the an XOR on the port number::
324
325 0 -> 1
326 1 -> 0
327
328 2 -> 3
329 3 -> 2
330
331 etc.
332
333The ``rte_eth_tx_burst()`` function frees the memory buffers of packets that
334are transmitted. If packets fail to transmit, ``(nb_tx < nb_rx)``, then they
335must be freed explicitly using ``rte_pktmbuf_free()``.
336
337The forwarding loop can be interrupted and the application closed using
338``Ctrl-C``.