1 .. SPDX-License-Identifier: BSD-3-Clause
2 Copyright(c) 2015 Intel Corporation.
4 Basic Forwarding Sample Application
5 ===================================
7 The Basic Forwarding sample application is a simple *skeleton* example of a
8 forwarding application.
10 It is intended as a demonstration of the basic components of a DPDK forwarding
11 application. For more detailed implementations see the L2 and L3 forwarding
14 Compiling the Application
15 -------------------------
17 To compile the sample application see :doc:`compiling`.
19 The application is located in the ``skeleton`` sub-directory.
21 Running the Application
22 -----------------------
24 To run the example in a ``linux`` environment:
26 .. code-block:: console
28 ./<build_dir>/examples/dpdk-skeleton -l 1 -n 4
30 Refer to *DPDK Getting Started Guide* for general information on running
31 applications and the Environment Abstraction Layer (EAL) options.
37 The following sections provide an explanation of the main components of the
40 All DPDK library functions used in the sample code are prefixed with ``rte_``
41 and are explained in detail in the *DPDK API Documentation*.
47 The ``main()`` function performs the initialization and calls the execution
48 threads for each lcore.
50 The first task is to initialize the Environment Abstraction Layer (EAL). The
51 ``argc`` and ``argv`` arguments are provided to the ``rte_eal_init()``
52 function. The value returned is the number of parsed arguments:
56 int ret = rte_eal_init(argc, argv);
58 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
61 The ``main()`` also allocates a mempool to hold the mbufs (Message Buffers)
62 used by the application:
66 mbuf_pool = rte_mempool_create("MBUF_POOL",
70 sizeof(struct rte_pktmbuf_pool_private),
71 rte_pktmbuf_pool_init, NULL,
72 rte_pktmbuf_init, NULL,
76 Mbufs are the packet buffer structure used by DPDK. They are explained in
77 detail in the "Mbuf Library" section of the *DPDK Programmer's Guide*.
79 The ``main()`` function also initializes all the ports using the user defined
80 ``port_init()`` function which is explained in the next section:
84 RTE_ETH_FOREACH_DEV(portid) {
85 if (port_init(portid, mbuf_pool) != 0) {
86 rte_exit(EXIT_FAILURE,
87 "Cannot init port %" PRIu8 "\n", portid);
92 Once the initialization is complete, the application is ready to launch a
93 function on an lcore. In this example ``lcore_main()`` is called on a single
101 The ``lcore_main()`` function is explained below.
105 The Port Initialization Function
106 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
108 The main functional part of the port initialization used in the Basic
109 Forwarding application is shown below:
114 port_init(uint16_t port, struct rte_mempool *mbuf_pool)
116 struct rte_eth_conf port_conf = port_conf_default;
117 const uint16_t rx_rings = 1, tx_rings = 1;
118 struct rte_ether_addr addr;
122 if (!rte_eth_dev_is_valid_port(port))
125 /* Configure the Ethernet device. */
126 retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
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);
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);
146 /* Start the Ethernet port. */
147 retval = rte_eth_dev_start(port);
151 /* Enable RX in promiscuous mode for the Ethernet device. */
152 retval = rte_eth_promiscuous_enable(port);
159 The Ethernet ports are configured with default settings using the
160 ``rte_eth_dev_configure()`` function and the ``port_conf_default`` struct:
164 static const struct rte_eth_conf port_conf_default = {
165 .rxmode = { .max_rx_pkt_len = RTE_ETHER_MAX_LEN }
168 For this example the ports are set up with 1 RX and 1 TX queue using the
169 ``rte_eth_rx_queue_setup()`` and ``rte_eth_tx_queue_setup()`` functions.
171 The Ethernet port is then started:
175 retval = rte_eth_dev_start(port);
178 Finally the RX port is set in promiscuous mode:
182 retval = rte_eth_promiscuous_enable(port);
188 As we saw above the ``main()`` function calls an application function on the
189 available lcores. For the Basic Forwarding application the lcore function
190 looks like the following:
194 static __rte_noreturn void
200 * Check that the port is on the same NUMA node as the polling thread
201 * for best performance.
203 RTE_ETH_FOREACH_DEV(port)
204 if (rte_eth_dev_socket_id(port) > 0 &&
205 rte_eth_dev_socket_id(port) !=
206 (int)rte_socket_id())
207 printf("WARNING, port %u is on remote NUMA node to "
208 "polling thread.\n\tPerformance will "
209 "not be optimal.\n", port);
211 printf("\nCore %u forwarding packets. [Ctrl+C to quit]\n",
214 /* Run until the application is quit or killed. */
217 * Receive packets on a port and forward them on the paired
218 * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
220 RTE_ETH_FOREACH_DEV(port) {
222 /* Get burst of RX packets, from first port of pair. */
223 struct rte_mbuf *bufs[BURST_SIZE];
224 const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
227 if (unlikely(nb_rx == 0))
230 /* Send burst of TX packets, to second port of pair. */
231 const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0,
234 /* Free any unsent packets. */
235 if (unlikely(nb_tx < nb_rx)) {
237 for (buf = nb_tx; buf < nb_rx; buf++)
238 rte_pktmbuf_free(bufs[buf]);
245 The main work of the application is done within the loop:
250 RTE_ETH_FOREACH_DEV(port) {
252 /* Get burst of RX packets, from first port of pair. */
253 struct rte_mbuf *bufs[BURST_SIZE];
254 const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
257 if (unlikely(nb_rx == 0))
260 /* Send burst of TX packets, to second port of pair. */
261 const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0,
264 /* Free any unsent packets. */
265 if (unlikely(nb_tx < nb_rx)) {
267 for (buf = nb_tx; buf < nb_rx; buf++)
268 rte_pktmbuf_free(bufs[buf]);
273 Packets are received in bursts on the RX ports and transmitted in bursts on
274 the TX ports. The ports are grouped in pairs with a simple mapping scheme
275 using the an XOR on the port number::
285 The ``rte_eth_tx_burst()`` function frees the memory buffers of packets that
286 are transmitted. If packets fail to transmit, ``(nb_tx < nb_rx)``, then they
287 must be freed explicitly using ``rte_pktmbuf_free()``.
289 The forwarding loop can be interrupted and the application closed using