New upstream version 17.11-rc3
[deb_dpdk.git] / doc / guides / sample_app_ug / rxtx_callbacks.rst
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
32 RX/TX Callbacks Sample Application
33 ==================================
34
35 The RX/TX Callbacks sample application is a packet forwarding application that
36 demonstrates the use of user defined callbacks on received and transmitted
37 packets. The application performs a simple latency check, using callbacks, to
38 determine the time packets spend within the application.
39
40 In the sample application a user defined callback is applied to all received
41 packets to add a timestamp. A separate callback is applied to all packets
42 prior to transmission to calculate the elapsed time, in CPU cycles.
43
44
45 Compiling the Application
46 -------------------------
47
48 To compile the sample application see :doc:`compiling`.
49
50 The application is located in the ``rxtx_callbacks`` sub-directory.
51
52 The callbacks feature requires that the ``CONFIG_RTE_ETHDEV_RXTX_CALLBACKS``
53 setting is on in the ``config/common_`` config file that applies to the
54 target. This is generally on by default:
55
56 .. code-block:: console
57
58     CONFIG_RTE_ETHDEV_RXTX_CALLBACKS=y
59
60 Running the Application
61 -----------------------
62
63 To run the example in a ``linuxapp`` environment:
64
65 .. code-block:: console
66
67     ./build/rxtx_callbacks -l 1 -n 4
68
69 Refer to *DPDK Getting Started Guide* for general information on running
70 applications and the Environment Abstraction Layer (EAL) options.
71
72
73
74 Explanation
75 -----------
76
77 The ``rxtx_callbacks`` application is mainly a simple forwarding application
78 based on the :doc:`skeleton`. See that section of the documentation for more
79 details of the forwarding part of the application.
80
81 The sections below explain the additional RX/TX callback code.
82
83
84 The Main Function
85 ~~~~~~~~~~~~~~~~~
86
87 The ``main()`` function performs the application initialization and calls the
88 execution threads for each lcore. This function is effectively identical to
89 the ``main()`` function explained in :doc:`skeleton`.
90
91 The ``lcore_main()`` function is also identical.
92
93 The main difference is in the user defined ``port_init()`` function where the
94 callbacks are added. This is explained in the next section:
95
96
97 The Port Initialization  Function
98 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
99
100 The main functional part of the port initialization is shown below with
101 comments:
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
155 The 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
162 More than one callback can be added and additional information can be passed
163 to callback function pointers as a ``void*``. In the examples above ``NULL``
164 is used.
165
166 The ``add_timestamps()`` and ``calc_latency()`` functions are explained below.
167
168
169 The add_timestamps() Callback
170 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
171
172 The ``add_timestamps()`` callback is added to the RX port and is applied to
173 all 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
190 The DPDK function ``rte_rdtsc()`` is used to add a cycle count timestamp to
191 each packet (see the *cycles* section of the *DPDK API Documentation* for
192 details).
193
194
195 The calc_latency() Callback
196 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
197
198 The ``calc_latency()`` callback is added to the TX port and is applied to all
199 packets 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
227 The ``calc_latency()`` function accumulates the total number of packets and
228 the total number of cycles used. Once more than 100 million packets have been
229 transmitted the average cycle count per packet is printed out and the counters
230 are reset.