mbuf: use pktmbuf helper to create the pool
[dpdk.git] / doc / guides / sample_app_ug / quota_watermark.rst
1 ..  BSD LICENSE
2     Copyright(c) 2010-2014 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 Quota and Watermark Sample Application
32 ======================================
33
34 The Quota and Watermark sample application is a simple example of packet processing using Data Plane Development Kit (DPDK) that
35 showcases the use of a quota as the maximum number of packets enqueue/dequeue at a time and low and high watermarks
36 to signal low and high ring usage respectively.
37
38 Additionally, it shows how ring watermarks can be used to feedback congestion notifications to data producers by
39 temporarily stopping processing overloaded rings and sending Ethernet flow control frames.
40
41 This sample application is split in two parts:
42
43 *   qw - The core quota and watermark sample application
44
45 *   qwctl - A command line tool to alter quota and watermarks while qw is running
46
47 Overview
48 --------
49
50 The Quota and Watermark sample application performs forwarding for each packet that is received on a given port.
51 The destination port is the adjacent port from the enabled port mask, that is,
52 if the first four ports are enabled (port mask 0xf), ports 0 and 1 forward into each other,
53 and ports 2 and 3 forward into each other.
54 The MAC addresses of the forwarded Ethernet frames are not affected.
55
56 Internally, packets are pulled from the ports by the master logical core and put on a variable length processing pipeline,
57 each stage of which being connected by rings, as shown in :numref:`figure_pipeline_overview`.
58
59 .. _figure_pipeline_overview:
60
61 .. figure:: img/pipeline_overview.*
62
63    Pipeline Overview
64
65
66 An adjustable quota value controls how many packets are being moved through the pipeline per enqueue and dequeue.
67 Adjustable watermark values associated with the rings control a back-off mechanism that
68 tries to prevent the pipeline from being overloaded by:
69
70 *   Stopping enqueuing on rings for which the usage has crossed the high watermark threshold
71
72 *   Sending Ethernet pause frames
73
74 *   Only resuming enqueuing on a ring once its usage goes below a global low watermark threshold
75
76 This mechanism allows congestion notifications to go up the ring pipeline and
77 eventually lead to an Ethernet flow control frame being send to the source.
78
79 On top of serving as an example of quota and watermark usage,
80 this application can be used to benchmark ring based processing pipelines performance using a traffic- generator,
81 as shown in :numref:`figure_ring_pipeline_perf_setup`.
82
83 .. _figure_ring_pipeline_perf_setup:
84
85 .. figure:: img/ring_pipeline_perf_setup.*
86
87    Ring-based Processing Pipeline Performance Setup
88
89
90 Compiling the Application
91 -------------------------
92
93 #.  Go to the example directory:
94
95     .. code-block:: console
96
97         export RTE_SDK=/path/to/rte_sdk
98         cd ${RTE_SDK}/examples/quota_watermark
99
100 #.  Set the target (a default target is used if not specified). For example:
101
102     .. code-block:: console
103
104         export RTE_TARGET=x86_64-native-linuxapp-gcc
105
106     See the *DPDK Getting Started Guide* for possible RTE_TARGET values.
107
108 #.  Build the application:
109
110     .. code-block:: console
111
112         make
113
114 Running the Application
115 -----------------------
116
117 The core application, qw, has to be started first.
118
119 Once it is up and running, one can alter quota and watermarks while it runs using the control application, qwctl.
120
121 Running the Core Application
122 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
123
124 The application requires a single command line option:
125
126 .. code-block:: console
127
128     ./qw/build/qw [EAL options] -- -p PORTMASK
129
130 where,
131
132 -p PORTMASK: A hexadecimal bitmask of the ports to configure
133
134 To run the application in a linuxapp environment with four logical cores and ports 0 and 2,
135 issue the following command:
136
137 .. code-block:: console
138
139     ./qw/build/qw -l 0-3 -n 4 -- -p 5
140
141 Refer to the *DPDK Getting Started Guide* for general information on running applications and
142 the Environment Abstraction Layer (EAL) options.
143
144 Running the Control Application
145 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
146
147 The control application requires a number of command line options:
148
149 .. code-block:: console
150
151     ./qwctl/build/qwctl [EAL options] --proc-type=secondary
152
153 The --proc-type=secondary option is necessary for the EAL to properly initialize the control application to
154 use the same huge pages as the core application and  thus be able to access its rings.
155
156 To run the application in a linuxapp environment on logical core 0, issue the following command:
157
158 .. code-block:: console
159
160     ./qwctl/build/qwctl -l 0 -n 4 --proc-type=secondary
161
162 Refer to the *DPDK Getting Started* Guide for general information on running applications and
163 the Environment Abstraction Layer (EAL) options.
164
165 qwctl is an interactive command line that let the user change variables in a running instance of qw.
166 The help command gives a list of available commands:
167
168 .. code-block:: console
169
170     $ qwctl > help
171
172 Code Overview
173 -------------
174
175 The following sections provide a quick guide to the application's source code.
176
177 Core Application - qw
178 ~~~~~~~~~~~~~~~~~~~~~
179
180 EAL and Drivers Setup
181 ^^^^^^^^^^^^^^^^^^^^^
182
183 The EAL arguments are parsed at the beginning of the main() function:
184
185 .. code-block:: c
186
187     ret = rte_eal_init(argc, argv);
188     if (ret < 0)
189         rte_exit(EXIT_FAILURE, "Cannot initialize EAL\n");
190
191     argc -= ret;
192     argv += ret;
193
194 Then, a call to init_dpdk(), defined in init.c, is made to initialize the poll mode drivers:
195
196 .. code-block:: c
197
198     void
199     init_dpdk(void)
200     {
201         int ret;
202
203         /* Bind the drivers to usable devices */
204
205         ret = rte_eal_pci_probe();
206         if (ret < 0)
207             rte_exit(EXIT_FAILURE, "rte_eal_pci_probe(): error %d\n", ret);
208
209         if (rte_eth_dev_count() < 2)
210             rte_exit(EXIT_FAILURE, "Not enough Ethernet port available\n");
211     }
212
213 To fully understand this code, it is recommended to study the chapters that relate to the *Poll Mode Driver*
214 in the *DPDK Getting Started Guide* and the *DPDK API Reference*.
215
216 Shared Variables Setup
217 ^^^^^^^^^^^^^^^^^^^^^^
218
219 The quota and low_watermark shared variables are put into an rte_memzone using a call to setup_shared_variables():
220
221 .. code-block:: c
222
223     void
224     setup_shared_variables(void)
225     {
226         const struct rte_memzone *qw_memzone;
227
228         qw_memzone = rte_memzone_reserve(QUOTA_WATERMARK_MEMZONE_NAME, 2 * sizeof(int), rte_socket_id(), RTE_MEMZONE_2MB);
229
230         if (qw_memzone == NULL)
231             rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno));
232
233         quota = qw_memzone->addr;
234         low_watermark = (unsigned int *) qw_memzone->addr + sizeof(int);
235    }
236
237 These two variables are initialized to a default value in main() and
238 can be changed while qw is running using the qwctl control program.
239
240 Application Arguments
241 ^^^^^^^^^^^^^^^^^^^^^
242
243 The qw application only takes one argument: a port mask that specifies which ports should be used by the application.
244 At least two ports are needed to run the application and there should be an even number of ports given in the port mask.
245
246 The port mask parsing is done in parse_qw_args(), defined in args.c.
247
248 Mbuf Pool Initialization
249 ^^^^^^^^^^^^^^^^^^^^^^^^
250
251 Once the application's arguments are parsed, an mbuf pool is created.
252 It contains a set of mbuf objects that are used by the driver and the application to store network packets:
253
254 .. code-block:: c
255
256     /* Create a pool of mbuf to store packets */
257     mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", MBUF_PER_POOL, 32, 0,
258                                          MBUF_DATA_SIZE, rte_socket_id());
259
260     if (mbuf_pool == NULL)
261         rte_panic("%s\n", rte_strerror(rte_errno));
262
263 The rte_mempool is a generic structure used to handle pools of objects.
264 In this case, it is necessary to create a pool that will be used by the driver.
265
266 The number of allocated pkt mbufs is MBUF_PER_POOL, with a data room size
267 of MBUF_DATA_SIZE each.
268 A per-lcore cache of 32 mbufs is kept.
269 The memory is allocated in on the master lcore's socket, but it is possible to extend this code to allocate one mbuf pool per socket.
270
271 The rte_pktmbuf_pool_create() function uses the default mbuf pool and mbuf
272 initializers, respectively rte_pktmbuf_pool_init() and rte_pktmbuf_init().
273 An advanced application may want to use the mempool API to create the
274 mbuf pool with more control.
275
276 Ports Configuration and Pairing
277 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
278
279 Each port in the port mask is configured and a corresponding ring is created in the master lcore's array of rings.
280 This ring is the first in the pipeline and will hold the packets directly coming from the port.
281
282 .. code-block:: c
283
284     for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++)
285         if (is_bit_set(port_id, portmask)) {
286             configure_eth_port(port_id);
287             init_ring(master_lcore_id, port_id);
288         }
289
290     pair_ports();
291
292 The configure_eth_port() and init_ring() functions are used to configure a port and a ring respectively and are defined in init.c.
293 They make use of the DPDK APIs defined in rte_eth.h and rte_ring.h.
294
295 pair_ports() builds the port_pairs[] array so that its key-value pairs are a mapping between reception and transmission ports.
296 It is defined in init.c.
297
298 Logical Cores Assignment
299 ^^^^^^^^^^^^^^^^^^^^^^^^
300
301 The application uses the master logical core to poll all the ports for new packets and enqueue them on a ring associated with the port.
302
303 Each logical core except the last runs pipeline_stage() after a ring for each used port is initialized on that core.
304 pipeline_stage() on core X dequeues packets from core X-1's rings and enqueue them on its own rings. See :numref:`figure_threads_pipelines`.
305
306 .. code-block:: c
307
308     /* Start pipeline_stage() on all the available slave lcore but the last */
309
310     for (lcore_id = 0 ; lcore_id < last_lcore_id; lcore_id++) {
311         if (rte_lcore_is_enabled(lcore_id) && lcore_id != master_lcore_id) {
312             for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++)
313                 if (is_bit_set(port_id, portmask))
314                     init_ring(lcore_id, port_id);
315
316                 rte_eal_remote_launch(pipeline_stage, NULL, lcore_id);
317         }
318     }
319
320 The last available logical core runs send_stage(),
321 which is the last stage of the pipeline dequeuing packets from the last ring in the pipeline and
322 sending them out on the destination port setup by pair_ports().
323
324 .. code-block:: c
325
326     /* Start send_stage() on the last slave core */
327
328     rte_eal_remote_launch(send_stage, NULL, last_lcore_id);
329
330 Receive, Process and Transmit Packets
331 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
332
333 .. _figure_threads_pipelines:
334
335 .. figure:: img/threads_pipelines.*
336
337    Threads and Pipelines
338
339
340 In the receive_stage() function running on the master logical core,
341 the main task is to read ingress packets from the RX ports and enqueue them
342 on the port's corresponding first ring in the pipeline.
343 This is done using the following code:
344
345 .. code-block:: c
346
347     lcore_id = rte_lcore_id();
348
349     /* Process each port round robin style */
350
351     for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) {
352         if (!is_bit_set(port_id, portmask))
353             continue;
354
355         ring = rings[lcore_id][port_id];
356
357         if (ring_state[port_id] != RING_READY) {
358             if (rte_ring_count(ring) > *low_watermark)
359                 continue;
360         else
361             ring_state[port_id] = RING_READY;
362         }
363
364         /* Enqueue received packets on the RX ring */
365
366         nb_rx_pkts = rte_eth_rx_burst(port_id, 0, pkts, *quota);
367
368         ret = rte_ring_enqueue_bulk(ring, (void *) pkts, nb_rx_pkts);
369         if (ret == -EDQUOT) {
370             ring_state[port_id] = RING_OVERLOADED;
371             send_pause_frame(port_id, 1337);
372         }
373     }
374
375 For each port in the port mask, the corresponding ring's pointer is fetched into ring and that ring's state is checked:
376
377 *   If it is in the RING_READY state, \*quota packets are grabbed from the port and put on the ring.
378     Should this operation make the ring's usage cross its high watermark,
379     the ring is marked as overloaded and an Ethernet flow control frame is sent to the source.
380
381 *   If it is not in the RING_READY state, this port is ignored until the ring's usage crosses the \*low_watermark  value.
382
383 The pipeline_stage() function's task is to process and move packets from the preceding pipeline stage.
384 This thread is running on most of the logical cores to create and arbitrarily long pipeline.
385
386 .. code-block:: c
387
388     lcore_id = rte_lcore_id();
389
390     previous_lcore_id = get_previous_lcore_id(lcore_id);
391
392     for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) {
393         if (!is_bit_set(port_id, portmask))
394             continue;
395
396         tx = rings[lcore_id][port_id];
397         rx = rings[previous_lcore_id][port_id];
398         if (ring_state[port_id] != RING_READY) {
399             if (rte_ring_count(tx) > *low_watermark)
400                 continue;
401         else
402             ring_state[port_id] = RING_READY;
403         }
404
405         /* Dequeue up to quota mbuf from rx */
406
407         nb_dq_pkts = rte_ring_dequeue_burst(rx, pkts, *quota);
408
409         if (unlikely(nb_dq_pkts < 0))
410             continue;
411
412         /* Enqueue them on tx */
413
414         ret = rte_ring_enqueue_bulk(tx, pkts, nb_dq_pkts);
415         if (ret == -EDQUOT)
416             ring_state[port_id] = RING_OVERLOADED;
417     }
418
419 The thread's logic works mostly like receive_stage(),
420 except that packets are moved from ring to ring instead of port to ring.
421
422 In this example, no actual processing is done on the packets,
423 but pipeline_stage() is an ideal place to perform any processing required by the application.
424
425 Finally, the send_stage() function's task is to read packets from the last ring in a pipeline and
426 send them on the destination port defined in the port_pairs[] array.
427 It is running on the last available logical core only.
428
429 .. code-block:: c
430
431     lcore_id = rte_lcore_id();
432
433     previous_lcore_id = get_previous_lcore_id(lcore_id);
434
435     for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) {
436         if (!is_bit_set(port_id, portmask)) continue;
437
438         dest_port_id = port_pairs[port_id];
439         tx = rings[previous_lcore_id][port_id];
440
441         if (rte_ring_empty(tx)) continue;
442
443         /* Dequeue packets from tx and send them */
444
445         nb_dq_pkts = rte_ring_dequeue_burst(tx, (void *) tx_pkts, *quota);
446         nb_tx_pkts = rte_eth_tx_burst(dest_port_id, 0, tx_pkts, nb_dq_pkts);
447     }
448
449 For each port in the port mask, up to \*quota packets are pulled from the last ring in its pipeline and
450 sent on the destination port paired with the current port.
451
452 Control Application - qwctl
453 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
454
455 The qwctl application uses the rte_cmdline library to provide the user with an interactive command line that
456 can be used to modify and inspect parameters in a running qw application.
457 Those parameters are the global quota and low_watermark value as well as each ring's built-in high watermark.
458
459 Command Definitions
460 ^^^^^^^^^^^^^^^^^^^
461
462 The available commands are defined in commands.c.
463
464 It is advised to use the cmdline sample application user guide as a reference for everything related to the rte_cmdline library.
465
466 Accessing Shared Variables
467 ^^^^^^^^^^^^^^^^^^^^^^^^^^
468
469 The setup_shared_variables() function retrieves the shared variables quota and
470 low_watermark from the rte_memzone previously created by qw.
471
472 .. code-block:: c
473
474     static void
475     setup_shared_variables(void)
476     {
477         const struct rte_memzone *qw_memzone;
478
479         qw_memzone = rte_memzone_lookup(QUOTA_WATERMARK_MEMZONE_NAME);
480         if (qw_memzone == NULL)
481             rte_exit(EXIT_FAILURE, "Couldn't find memzone\n");
482
483         quota = qw_memzone->addr;
484
485         low_watermark = (unsigned int *) qw_memzone->addr + sizeof(int);
486     }