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 ``linuxapp`` environment:
26 .. code-block:: console
28 ./build/basicfwd -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 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 rte_eth_promiscuous_enable(port);
157 The Ethernet ports are configured with default settings using the
158 ``rte_eth_dev_configure()`` function and the ``port_conf_default`` struct:
162 static const struct rte_eth_conf port_conf_default = {
163 .rxmode = { .max_rx_pkt_len = ETHER_MAX_LEN }
166 For 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.
169 The Ethernet port is then started:
173 retval = rte_eth_dev_start(port);
176 Finally the RX port is set in promiscuous mode:
180 rte_eth_promiscuous_enable(port);
186 As we saw above the ``main()`` function calls an application function on the
187 available lcores. For the Basic Forwarding application the lcore function
188 looks like the following:
192 static __attribute__((noreturn)) void
198 * Check that the port is on the same NUMA node as the polling thread
199 * for best performance.
201 RTE_ETH_FOREACH_DEV(port)
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);
209 printf("\nCore %u forwarding packets. [Ctrl+C to quit]\n",
212 /* Run until the application is quit or killed. */
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.
218 RTE_ETH_FOREACH_DEV(port) {
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,
225 if (unlikely(nb_rx == 0))
228 /* Send burst of TX packets, to second port of pair. */
229 const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0,
232 /* Free any unsent packets. */
233 if (unlikely(nb_tx < nb_rx)) {
235 for (buf = nb_tx; buf < nb_rx; buf++)
236 rte_pktmbuf_free(bufs[buf]);
243 The main work of the application is done within the loop:
248 RTE_ETH_FOREACH_DEV(port) {
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,
255 if (unlikely(nb_rx == 0))
258 /* Send burst of TX packets, to second port of pair. */
259 const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0,
262 /* Free any unsent packets. */
263 if (unlikely(nb_tx < nb_rx)) {
265 for (buf = nb_tx; buf < nb_rx; buf++)
266 rte_pktmbuf_free(bufs[buf]);
271 Packets are received in bursts on the RX ports and transmitted in bursts on
272 the TX ports. The ports are grouped in pairs with a simple mapping scheme
273 using the an XOR on the port number::
283 The ``rte_eth_tx_burst()`` function frees the memory buffers of packets that
284 are transmitted. If packets fail to transmit, ``(nb_tx < nb_rx)``, then they
285 must be freed explicitly using ``rte_pktmbuf_free()``.
287 The forwarding loop can be interrupted and the application closed using