]> git.proxmox.com Git - ceph.git/blame - ceph/src/spdk/dpdk/doc/guides/sample_app_ug/skeleton.rst
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / dpdk / doc / guides / sample_app_ug / skeleton.rst
CommitLineData
11fdf7f2
TL
1.. SPDX-License-Identifier: BSD-3-Clause
2 Copyright(c) 2015 Intel Corporation.
7c673cae
FG
3
4Basic Forwarding Sample Application
5===================================
6
7The Basic Forwarding sample application is a simple *skeleton* example of a
8forwarding application.
9
10It is intended as a demonstration of the basic components of a DPDK forwarding
11application. For more detailed implementations see the L2 and L3 forwarding
12sample applications.
13
7c673cae
FG
14Compiling the Application
15-------------------------
16
11fdf7f2 17To compile the sample application see :doc:`compiling`.
7c673cae 18
11fdf7f2 19The application is located in the ``skeleton`` sub-directory.
7c673cae
FG
20
21Running the Application
22-----------------------
23
9f95a23c 24To run the example in a ``linux`` environment:
7c673cae
FG
25
26.. code-block:: console
27
11fdf7f2 28 ./build/basicfwd -l 1 -n 4
7c673cae
FG
29
30Refer to *DPDK Getting Started Guide* for general information on running
31applications and the Environment Abstraction Layer (EAL) options.
32
33
34Explanation
35-----------
36
37The following sections provide an explanation of the main components of the
38code.
39
40All DPDK library functions used in the sample code are prefixed with ``rte_``
41and are explained in detail in the *DPDK API Documentation*.
42
43
44The Main Function
45~~~~~~~~~~~~~~~~~
46
47The ``main()`` function performs the initialization and calls the execution
48threads for each lcore.
49
50The first task is to initialize the Environment Abstraction Layer (EAL). The
51``argc`` and ``argv`` arguments are provided to the ``rte_eal_init()``
52function. The value returned is the number of parsed arguments:
53
54.. code-block:: c
55
56 int ret = rte_eal_init(argc, argv);
57 if (ret < 0)
58 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
59
60
61The ``main()`` also allocates a mempool to hold the mbufs (Message Buffers)
62used by the application:
63
64.. code-block:: c
65
66 mbuf_pool = rte_mempool_create("MBUF_POOL",
67 NUM_MBUFS * nb_ports,
68 MBUF_SIZE,
69 MBUF_CACHE_SIZE,
70 sizeof(struct rte_pktmbuf_pool_private),
71 rte_pktmbuf_pool_init, NULL,
72 rte_pktmbuf_init, NULL,
73 rte_socket_id(),
74 0);
75
76Mbufs are the packet buffer structure used by DPDK. They are explained in
77detail in the "Mbuf Library" section of the *DPDK Programmer's Guide*.
78
79The ``main()`` function also initializes all the ports using the user defined
80``port_init()`` function which is explained in the next section:
81
82.. code-block:: c
83
11fdf7f2 84 RTE_ETH_FOREACH_DEV(portid) {
7c673cae
FG
85 if (port_init(portid, mbuf_pool) != 0) {
86 rte_exit(EXIT_FAILURE,
87 "Cannot init port %" PRIu8 "\n", portid);
88 }
89 }
90
91
92Once the initialization is complete, the application is ready to launch a
93function on an lcore. In this example ``lcore_main()`` is called on a single
94lcore.
95
96
97.. code-block:: c
98
99 lcore_main();
100
101The ``lcore_main()`` function is explained below.
102
103
104
105The Port Initialization Function
106~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
107
108The main functional part of the port initialization used in the Basic
109Forwarding application is shown below:
110
111.. code-block:: c
112
113 static inline int
11fdf7f2 114 port_init(uint16_t port, struct rte_mempool *mbuf_pool)
7c673cae
FG
115 {
116 struct rte_eth_conf port_conf = port_conf_default;
117 const uint16_t rx_rings = 1, tx_rings = 1;
118 struct ether_addr addr;
119 int retval;
120 uint16_t q;
121
11fdf7f2 122 if (!rte_eth_dev_is_valid_port(port))
7c673cae
FG
123 return -1;
124
125 /* Configure the Ethernet device. */
126 retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
127 if (retval != 0)
128 return retval;
129
130 /* Allocate and set up 1 RX queue per Ethernet port. */
131 for (q = 0; q < rx_rings; q++) {
132 retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE,
133 rte_eth_dev_socket_id(port), NULL, mbuf_pool);
134 if (retval < 0)
135 return retval;
136 }
137
138 /* Allocate and set up 1 TX queue per Ethernet port. */
139 for (q = 0; q < tx_rings; q++) {
140 retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE,
141 rte_eth_dev_socket_id(port), NULL);
142 if (retval < 0)
143 return retval;
144 }
145
146 /* Start the Ethernet port. */
147 retval = rte_eth_dev_start(port);
148 if (retval < 0)
149 return retval;
150
151 /* Enable RX in promiscuous mode for the Ethernet device. */
152 rte_eth_promiscuous_enable(port);
153
154 return 0;
155 }
156
157The Ethernet ports are configured with default settings using the
158``rte_eth_dev_configure()`` function and the ``port_conf_default`` struct:
159
160.. code-block:: c
161
162 static const struct rte_eth_conf port_conf_default = {
163 .rxmode = { .max_rx_pkt_len = ETHER_MAX_LEN }
164 };
165
166For this example the ports are set up with 1 RX and 1 TX queue using the
167``rte_eth_rx_queue_setup()`` and ``rte_eth_tx_queue_setup()`` functions.
168
169The Ethernet port is then started:
170
171.. code-block:: c
172
173 retval = rte_eth_dev_start(port);
174
175
176Finally the RX port is set in promiscuous mode:
177
178.. code-block:: c
179
180 rte_eth_promiscuous_enable(port);
181
182
183The Lcores Main
184~~~~~~~~~~~~~~~
185
186As we saw above the ``main()`` function calls an application function on the
187available lcores. For the Basic Forwarding application the lcore function
188looks like the following:
189
190.. code-block:: c
191
192 static __attribute__((noreturn)) void
193 lcore_main(void)
194 {
11fdf7f2 195 uint16_t port;
7c673cae
FG
196
197 /*
198 * Check that the port is on the same NUMA node as the polling thread
199 * for best performance.
200 */
11fdf7f2 201 RTE_ETH_FOREACH_DEV(port)
7c673cae
FG
202 if (rte_eth_dev_socket_id(port) > 0 &&
203 rte_eth_dev_socket_id(port) !=
204 (int)rte_socket_id())
205 printf("WARNING, port %u is on remote NUMA node to "
206 "polling thread.\n\tPerformance will "
207 "not be optimal.\n", port);
208
209 printf("\nCore %u forwarding packets. [Ctrl+C to quit]\n",
210 rte_lcore_id());
211
212 /* Run until the application is quit or killed. */
213 for (;;) {
214 /*
215 * Receive packets on a port and forward them on the paired
216 * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
217 */
11fdf7f2 218 RTE_ETH_FOREACH_DEV(port) {
7c673cae
FG
219
220 /* Get burst of RX packets, from first port of pair. */
221 struct rte_mbuf *bufs[BURST_SIZE];
222 const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
223 bufs, BURST_SIZE);
224
225 if (unlikely(nb_rx == 0))
226 continue;
227
228 /* Send burst of TX packets, to second port of pair. */
229 const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0,
230 bufs, nb_rx);
231
232 /* Free any unsent packets. */
233 if (unlikely(nb_tx < nb_rx)) {
234 uint16_t buf;
235 for (buf = nb_tx; buf < nb_rx; buf++)
236 rte_pktmbuf_free(bufs[buf]);
237 }
238 }
239 }
240 }
241
242
243The main work of the application is done within the loop:
244
245.. code-block:: c
246
247 for (;;) {
11fdf7f2 248 RTE_ETH_FOREACH_DEV(port) {
7c673cae
FG
249
250 /* Get burst of RX packets, from first port of pair. */
251 struct rte_mbuf *bufs[BURST_SIZE];
252 const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
253 bufs, BURST_SIZE);
254
255 if (unlikely(nb_rx == 0))
256 continue;
257
258 /* Send burst of TX packets, to second port of pair. */
259 const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0,
260 bufs, nb_rx);
261
262 /* Free any unsent packets. */
263 if (unlikely(nb_tx < nb_rx)) {
264 uint16_t buf;
265 for (buf = nb_tx; buf < nb_rx; buf++)
266 rte_pktmbuf_free(bufs[buf]);
267 }
268 }
269 }
270
271Packets are received in bursts on the RX ports and transmitted in bursts on
272the TX ports. The ports are grouped in pairs with a simple mapping scheme
273using the an XOR on the port number::
274
275 0 -> 1
276 1 -> 0
277
278 2 -> 3
279 3 -> 2
280
281 etc.
282
283The ``rte_eth_tx_burst()`` function frees the memory buffers of packets that
284are transmitted. If packets fail to transmit, ``(nb_tx < nb_rx)``, then they
285must be freed explicitly using ``rte_pktmbuf_free()``.
286
287The forwarding loop can be interrupted and the application closed using
288``Ctrl-C``.