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 32RX/TX Callbacks Sample Application 33================================== 34 35The RX/TX Callbacks sample application is a packet forwarding application that 36demonstrates the use of user defined callbacks on received and transmitted 37packets. The application performs a simple latency check, using callbacks, to 38determine the time packets spend within the application. 39 40In the sample application a user defined callback is applied to all received 41packets to add a timestamp. A separate callback is applied to all packets 42prior to transmission to calculate the elapsed time, in CPU cycles. 43 44 45Compiling the Application 46------------------------- 47 48To compile the sample application see :doc:`compiling`. 49 50The application is located in the ``rxtx_callbacks`` sub-directory. 51 52The callbacks feature requires that the ``CONFIG_RTE_ETHDEV_RXTX_CALLBACKS`` 53setting is on in the ``config/common_`` config file that applies to the 54target. This is generally on by default: 55 56.. code-block:: console 57 58 CONFIG_RTE_ETHDEV_RXTX_CALLBACKS=y 59 60Running the Application 61----------------------- 62 63To run the example in a ``linuxapp`` environment: 64 65.. code-block:: console 66 67 ./build/rxtx_callbacks -l 1 -n 4 68 69Refer to *DPDK Getting Started Guide* for general information on running 70applications and the Environment Abstraction Layer (EAL) options. 71 72 73 74Explanation 75----------- 76 77The ``rxtx_callbacks`` application is mainly a simple forwarding application 78based on the :doc:`skeleton`. See that section of the documentation for more 79details of the forwarding part of the application. 80 81The sections below explain the additional RX/TX callback code. 82 83 84The Main Function 85~~~~~~~~~~~~~~~~~ 86 87The ``main()`` function performs the application initialization and calls the 88execution threads for each lcore. This function is effectively identical to 89the ``main()`` function explained in :doc:`skeleton`. 90 91The ``lcore_main()`` function is also identical. 92 93The main difference is in the user defined ``port_init()`` function where the 94callbacks are added. This is explained in the next section: 95 96 97The Port Initialization Function 98~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 99 100The main functional part of the port initialization is shown below with 101comments: 102 103.. code-block:: c 104 105 static inline int 106 port_init(uint16_t port, struct rte_mempool *mbuf_pool) 107 { 108 struct rte_eth_conf port_conf = port_conf_default; 109 const uint16_t rx_rings = 1, tx_rings = 1; 110 struct ether_addr addr; 111 int retval; 112 uint16_t q; 113 114 if (port >= rte_eth_dev_count()) 115 return -1; 116 117 /* Configure the Ethernet device. */ 118 retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf); 119 if (retval != 0) 120 return retval; 121 122 /* Allocate and set up 1 RX queue per Ethernet port. */ 123 for (q = 0; q < rx_rings; q++) { 124 retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE, 125 rte_eth_dev_socket_id(port), NULL, mbuf_pool); 126 if (retval < 0) 127 return retval; 128 } 129 130 /* Allocate and set up 1 TX queue per Ethernet port. */ 131 for (q = 0; q < tx_rings; q++) { 132 retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE, 133 rte_eth_dev_socket_id(port), NULL); 134 if (retval < 0) 135 return retval; 136 } 137 138 /* Start the Ethernet port. */ 139 retval = rte_eth_dev_start(port); 140 if (retval < 0) 141 return retval; 142 143 /* Enable RX in promiscuous mode for the Ethernet device. */ 144 rte_eth_promiscuous_enable(port); 145 146 147 /* Add the callbacks for RX and TX.*/ 148 rte_eth_add_rx_callback(port, 0, add_timestamps, NULL); 149 rte_eth_add_tx_callback(port, 0, calc_latency, NULL); 150 151 return 0; 152 } 153 154 155The RX and TX callbacks are added to the ports/queues as function pointers: 156 157.. code-block:: c 158 159 rte_eth_add_rx_callback(port, 0, add_timestamps, NULL); 160 rte_eth_add_tx_callback(port, 0, calc_latency, NULL); 161 162More than one callback can be added and additional information can be passed 163to callback function pointers as a ``void*``. In the examples above ``NULL`` 164is used. 165 166The ``add_timestamps()`` and ``calc_latency()`` functions are explained below. 167 168 169The add_timestamps() Callback 170~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 171 172The ``add_timestamps()`` callback is added to the RX port and is applied to 173all packets received: 174 175.. code-block:: c 176 177 static uint16_t 178 add_timestamps(uint16_t port __rte_unused, uint16_t qidx __rte_unused, 179 struct rte_mbuf **pkts, uint16_t nb_pkts, void *_ __rte_unused) 180 { 181 unsigned i; 182 uint64_t now = rte_rdtsc(); 183 184 for (i = 0; i < nb_pkts; i++) 185 pkts[i]->udata64 = now; 186 187 return nb_pkts; 188 } 189 190The DPDK function ``rte_rdtsc()`` is used to add a cycle count timestamp to 191each packet (see the *cycles* section of the *DPDK API Documentation* for 192details). 193 194 195The calc_latency() Callback 196~~~~~~~~~~~~~~~~~~~~~~~~~~~ 197 198The ``calc_latency()`` callback is added to the TX port and is applied to all 199packets prior to transmission: 200 201.. code-block:: c 202 203 static uint16_t 204 calc_latency(uint16_t port __rte_unused, uint16_t qidx __rte_unused, 205 struct rte_mbuf **pkts, uint16_t nb_pkts, void *_ __rte_unused) 206 { 207 uint64_t cycles = 0; 208 uint64_t now = rte_rdtsc(); 209 unsigned i; 210 211 for (i = 0; i < nb_pkts; i++) 212 cycles += now - pkts[i]->udata64; 213 214 latency_numbers.total_cycles += cycles; 215 latency_numbers.total_pkts += nb_pkts; 216 217 if (latency_numbers.total_pkts > (100 * 1000 * 1000ULL)) { 218 printf("Latency = %"PRIu64" cycles\n", 219 latency_numbers.total_cycles / latency_numbers.total_pkts); 220 221 latency_numbers.total_cycles = latency_numbers.total_pkts = 0; 222 } 223 224 return nb_pkts; 225 } 226 227The ``calc_latency()`` function accumulates the total number of packets and 228the total number of cycles used. Once more than 100 million packets have been 229transmitted the average cycle count per packet is printed out and the counters 230are reset. 231