doc: refactor figure numbers into references
[dpdk.git] / doc / guides / sample_app_ug / exception_path.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 Exception Path Sample Application
32 =================================
33
34 The Exception Path sample application is a simple example that demonstrates the use of the DPDK
35 to set up an exception path for packets to go through the Linux* kernel.
36 This is done by using virtual TAP network interfaces.
37 These can be read from and written to by the DPDK application and
38 appear to the kernel as a standard network interface.
39
40 Overview
41 --------
42
43 The application creates two threads for each NIC port being used.
44 One thread reads from the port and writes the data unmodified to a thread-specific TAP interface.
45 The second thread reads from a TAP interface and writes the data unmodified to the NIC port.
46
47 The packet flow through the exception path application is as shown in the following figure.
48
49 .. _figure_exception_path_example:
50
51 .. figure:: img/exception_path_example.*
52
53    Packet Flow
54
55
56 To make throughput measurements, kernel bridges must be setup to forward data between the bridges appropriately.
57
58 Compiling the Application
59 -------------------------
60
61 #.  Go to example directory:
62
63     .. code-block:: console
64
65         export RTE_SDK=/path/to/rte_sdk
66         cd ${RTE_SDK}/examples/exception_path
67
68 #.  Set the target (a default target will be used if not specified).
69     For example:
70
71     .. code-block:: console
72
73         export RTE_TARGET=x86_64-native-linuxapp-gcc
74
75 This application is intended as a linuxapp only.
76 See the *DPDK Getting Started Guide* for possible RTE_TARGET values.
77
78 #.  Build the application:
79
80     .. code-block:: console
81
82         make
83
84 Running the Application
85 -----------------------
86
87 The application requires a number of command line options:
88
89 .. code-block:: console
90
91     .build/exception_path [EAL options] -- -p PORTMASK -i IN_CORES -o OUT_CORES
92
93 where:
94
95 *   -p PORTMASK: A hex bitmask of ports to use
96
97 *   -i IN_CORES: A hex bitmask of cores which read from NIC
98
99 *   -o OUT_CORES: A hex bitmask of cores which write to NIC
100
101 Refer to the *DPDK Getting Started Guide* for general information on running applications
102 and the Environment Abstraction Layer (EAL) options.
103
104 The number of bits set in each bitmask must be the same.
105 The coremask -c parameter of the EAL options should include IN_CORES and OUT_CORES.
106 The same bit must not be set in IN_CORES and OUT_CORES.
107 The affinities between ports and cores are set beginning with the least significant bit of each mask, that is,
108 the port represented by the lowest bit in PORTMASK is read from by the core represented by the lowest bit in IN_CORES,
109 and written to by the core represented by the lowest bit in OUT_CORES.
110
111 For example to run the application with two ports and four cores:
112
113 .. code-block:: console
114
115     ./build/exception_path -c f -n 4 -- -p 3 -i 3 -o c
116
117 Getting Statistics
118 ~~~~~~~~~~~~~~~~~~
119
120 While the application is running, statistics on packets sent and
121 received can be displayed by sending the SIGUSR1 signal to the application from another terminal:
122
123 .. code-block:: console
124
125     killall -USR1 exception_path
126
127 The statistics can be reset by sending a SIGUSR2 signal in a similar way.
128
129 Explanation
130 -----------
131
132 The following sections provide some explanation of the code.
133
134 Initialization
135 ~~~~~~~~~~~~~~
136
137 Setup of the mbuf pool, driver and queues is similar to the setup done in the L2 Forwarding sample application
138 (see Chapter 9 "L2 forwarding Sample Application (in Real and Virtualized Environments" for details).
139 In addition, the TAP interfaces must also be created.
140 A TAP interface is created for each lcore that is being used.
141 The code for creating the TAP interface is as follows:
142
143 .. code-block:: c
144
145     /*
146      *   Create a tap network interface, or use existing one with same name.
147      *   If name[0]='\0' then a name is automatically assigned and returned in name.
148      */
149
150     static int tap_create(char *name)
151     {
152         struct ifreq ifr;
153         int fd, ret;
154
155         fd = open("/dev/net/tun", O_RDWR);
156         if (fd < 0)
157             return fd;
158
159         memset(&ifr, 0, sizeof(ifr));
160
161         /* TAP device without packet information */
162
163         ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
164         if (name && *name)
165             rte_snprinf(ifr.ifr_name, IFNAMSIZ, name);
166
167         ret = ioctl(fd, TUNSETIFF, (void *) &ifr);
168
169         if (ret < 0) {
170             close(fd);
171             return ret;
172
173         }
174
175         if (name)
176             rte_snprintf(name, IFNAMSIZ, ifr.ifr_name);
177
178         return fd;
179     }
180
181 The other step in the initialization process that is unique to this sample application
182 is the association of each port with two cores:
183
184 *   One core to read from the port and write to a TAP interface
185
186 *   A second core to read from a TAP interface and write to the port
187
188 This is done using an array called port_ids[], which is indexed by the lcore IDs.
189 The population of this array is shown below:
190
191 .. code-block:: c
192
193     tx_port = 0;
194     rx_port = 0;
195
196     RTE_LCORE_FOREACH(i) {
197         if (input_cores_mask & (1ULL << i)) {
198             /* Skip ports that are not enabled */
199             while ((ports_mask & (1 << rx_port)) == 0) {
200                 rx_port++;
201                 if (rx_port > (sizeof(ports_mask) * 8))
202                     goto fail; /* not enough ports */
203             }
204             port_ids[i] = rx_port++;
205         } else if (output_cores_mask & (1ULL << i)) {
206             /* Skip ports that are not enabled */
207             while ((ports_mask & (1 << tx_port)) == 0) {
208                 tx_port++;
209                 if (tx_port > (sizeof(ports_mask) * 8))
210                    goto fail; /* not enough ports */
211             }
212             port_ids[i] = tx_port++;
213         }
214    }
215
216 Packet Forwarding
217 ~~~~~~~~~~~~~~~~~
218
219 After the initialization steps are complete, the main_loop() function is run on each lcore.
220 This function first checks the lcore_id against the user provided input_cores_mask and output_cores_mask to see
221 if this core is reading from or writing to a TAP interface.
222
223 For the case that reads from a NIC port, the packet reception is the same as in the L2 Forwarding sample application
224 (see Section 9.4.6, "Receive, Process and Transmit Packets").
225 The packet transmission is done by calling write() with the file descriptor of the appropriate TAP interface
226 and then explicitly freeing the mbuf back to the pool.
227
228 ..  code-block:: c
229
230     /* Loop forever reading from NIC and writing to tap */
231
232     for (;;) {
233         struct rte_mbuf *pkts_burst[PKT_BURST_SZ];
234         unsigned i;
235
236         const unsigned nb_rx = rte_eth_rx_burst(port_ids[lcore_id], 0, pkts_burst, PKT_BURST_SZ);
237
238         lcore_stats[lcore_id].rx += nb_rx;
239
240         for (i = 0; likely(i < nb_rx); i++) {
241             struct rte_mbuf *m = pkts_burst[i];
242             int ret = write(tap_fd, rte_pktmbuf_mtod(m, void*),
243
244             rte_pktmbuf_data_len(m));
245             rte_pktmbuf_free(m);
246             if (unlikely(ret<0))
247                 lcore_stats[lcore_id].dropped++;
248             else
249                 lcore_stats[lcore_id].tx++;
250         }
251     }
252
253 For the other case that reads from a TAP interface and writes to a NIC port,
254 packets are retrieved by doing a read() from the file descriptor of the appropriate TAP interface.
255 This fills in the data into the mbuf, then other fields are set manually.
256 The packet can then be transmitted as normal.
257
258 .. code-block:: c
259
260     /* Loop forever reading from tap and writing to NIC */
261
262     for (;;) {
263         int ret;
264         struct rte_mbuf *m = rte_pktmbuf_alloc(pktmbuf_pool);
265
266         if (m == NULL)
267             continue;
268
269         ret = read(tap_fd, m->pkt.data, MAX_PACKET_SZ); lcore_stats[lcore_id].rx++;
270         if (unlikely(ret < 0)) {
271             FATAL_ERROR("Reading from %s interface failed", tap_name);
272         }
273
274         m->pkt.nb_segs = 1;
275         m->pkt.next = NULL;
276         m->pkt.data_len = (uint16_t)ret;
277
278         ret = rte_eth_tx_burst(port_ids[lcore_id], 0, &m, 1);
279         if (unlikely(ret < 1)) {
280             rte_pktmuf_free(m);
281             lcore_stats[lcore_id].dropped++;
282         }
283         else {
284             lcore_stats[lcore_id].tx++;
285         }
286     }
287
288 To set up loops for measuring throughput, TAP interfaces can be connected using bridging.
289 The steps to do this are described in the section that follows.
290
291 Managing TAP Interfaces and Bridges
292 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
293
294 The Exception Path sample application creates TAP interfaces with names of the format tap_dpdk_nn,
295 where nn is the lcore ID. These TAP interfaces need to be configured for use:
296
297 .. code-block:: console
298
299     ifconfig tap_dpdk_00 up
300
301 To set up a bridge between two interfaces so that packets sent to one interface can be read from another,
302 use the brctl tool:
303
304 .. code-block:: console
305
306     brctl addbr "br0"
307     brctl addif br0 tap_dpdk_00
308     brctl addif br0 tap_dpdk_03
309     ifconfig br0 up
310
311 The TAP interfaces created by this application exist only when the application is running,
312 so the steps above need to be repeated each time the application is run.
313 To avoid this, persistent TAP interfaces can be created using openvpn:
314
315 .. code-block:: console
316
317     openvpn --mktun --dev tap_dpdk_00
318
319 If this method is used, then the steps above have to be done only once and
320 the same TAP interfaces can be reused each time the application is run.
321 To remove bridges and persistent TAP interfaces, the following commands are used:
322
323 .. code-block:: console
324
325     ifconfig br0 down
326     brctl delbr br0
327     openvpn --rmtun --dev tap_dpdk_00
328