]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | .. BSD LICENSE |
2 | Copyright(c) 2016 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 | .. _l2_fwd_crypto_app: | |
32 | ||
33 | L2 Forwarding with Crypto Sample Application | |
34 | ============================================ | |
35 | ||
36 | The L2 Forwarding with Crypto (l2fwd-crypto) sample application is a simple example of packet processing using | |
37 | the Data Plane Development Kit (DPDK), in conjunction with the Cryptodev library. | |
38 | ||
39 | Overview | |
40 | -------- | |
41 | ||
42 | The L2 Forwarding with Crypto sample application performs a crypto operation (cipher/hash) | |
43 | specified by the user from command line (or using the default values), | |
44 | with a crypto device capable of doing that operation, | |
45 | for each packet that is received on a RX_PORT and performs L2 forwarding. | |
46 | The destination port is the adjacent port from the enabled portmask, that is, | |
47 | if the first four ports are enabled (portmask 0xf), | |
48 | ports 0 and 1 forward into each other, and ports 2 and 3 forward into each other. | |
49 | Also, the MAC addresses are affected as follows: | |
50 | ||
51 | * The source MAC address is replaced by the TX_PORT MAC address | |
52 | ||
53 | * The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID | |
54 | ||
55 | Compiling the Application | |
56 | ------------------------- | |
57 | ||
58 | #. Go to the example directory: | |
59 | ||
60 | .. code-block:: console | |
61 | ||
62 | export RTE_SDK=/path/to/rte_sdk | |
63 | cd ${RTE_SDK}/examples/l2fwd-crypto | |
64 | ||
65 | #. Set the target (a default target is used if not specified). For example: | |
66 | ||
67 | .. code-block:: console | |
68 | ||
69 | export RTE_TARGET=x86_64-native-linuxapp-gcc | |
70 | ||
71 | *See the DPDK Getting Started Guide* for possible RTE_TARGET values. | |
72 | ||
73 | #. Build the application: | |
74 | ||
75 | .. code-block:: console | |
76 | ||
77 | make | |
78 | ||
79 | Running the Application | |
80 | ----------------------- | |
81 | ||
82 | The application requires a number of command line options: | |
83 | ||
84 | .. code-block:: console | |
85 | ||
86 | ./build/l2fwd-crypto [EAL options] -- [-p PORTMASK] [-q NQ] [-s] [-T PERIOD] / | |
87 | [--cdev_type HW/SW/ANY] [--chain HASH_CIPHER/CIPHER_HASH/CIPHER_ONLY/HASH_ONLY] / | |
88 | [--cipher_algo ALGO] [--cipher_op ENCRYPT/DECRYPT] [--cipher_key KEY] / | |
89 | [--cipher_key_random_size SIZE] [--iv IV] [--iv_random_size SIZE] / | |
90 | [--auth_algo ALGO] [--auth_op GENERATE/VERIFY] [--auth_key KEY] / | |
91 | [--auth_key_random_size SIZE] [--aad AAD] [--aad_random_size SIZE] / | |
92 | [--digest size SIZE] [--sessionless] | |
93 | ||
94 | where, | |
95 | ||
96 | * p PORTMASK: A hexadecimal bitmask of the ports to configure (default is all the ports) | |
97 | ||
98 | * q NQ: A number of queues (=ports) per lcore (default is 1) | |
99 | ||
100 | * s: manage all ports from single core | |
101 | ||
102 | * T PERIOD: statistics will be refreshed each PERIOD seconds | |
103 | ||
104 | (0 to disable, 10 default, 86400 maximum) | |
105 | ||
106 | * cdev_type: select preferred crypto device type: HW, SW or anything (ANY) | |
107 | ||
108 | (default is ANY) | |
109 | ||
110 | * chain: select the operation chaining to perform: Cipher->Hash (CIPHER_HASH), | |
111 | ||
112 | Hash->Cipher (HASH_CIPHER), Cipher (CIPHER_ONLY), Hash(HASH_ONLY) | |
113 | ||
114 | (default is Cipher->Hash) | |
115 | ||
116 | * cipher_algo: select the ciphering algorithm (default is AES CBC) | |
117 | ||
118 | * cipher_op: select the ciphering operation to perform: ENCRYPT or DECRYPT | |
119 | ||
120 | (default is ENCRYPT) | |
121 | ||
122 | * cipher_key: set the ciphering key to be used. Bytes has to be separated with ":" | |
123 | ||
124 | * cipher_key_random_size: set the size of the ciphering key, | |
125 | ||
126 | which will be generated randomly. | |
127 | ||
128 | Note that if --cipher_key is used, this will be ignored. | |
129 | ||
130 | * iv: set the IV to be used. Bytes has to be separated with ":" | |
131 | ||
132 | * iv_random_size: set the size of the IV, which will be generated randomly. | |
133 | ||
134 | Note that if --iv is used, this will be ignored. | |
135 | ||
136 | * auth_algo: select the authentication algorithm (default is SHA1-HMAC) | |
137 | ||
138 | * cipher_op: select the authentication operation to perform: GENERATE or VERIFY | |
139 | ||
140 | (default is GENERATE) | |
141 | ||
142 | * auth_key: set the authentication key to be used. Bytes has to be separated with ":" | |
143 | ||
144 | * auth_key_random_size: set the size of the authentication key, | |
145 | ||
146 | which will be generated randomly. | |
147 | ||
148 | Note that if --auth_key is used, this will be ignored. | |
149 | ||
150 | * aad: set the AAD to be used. Bytes has to be separated with ":" | |
151 | ||
152 | * aad_random_size: set the size of the AAD, which will be generated randomly. | |
153 | ||
154 | Note that if --aad is used, this will be ignored. | |
155 | ||
156 | * digest_size: set the size of the digest to be generated/verified. | |
157 | ||
158 | * sessionless: no crypto session will be created. | |
159 | ||
160 | ||
161 | The application requires that crypto devices capable of performing | |
162 | the specified crypto operation are available on application initialization. | |
163 | This means that HW crypto device/s must be bound to a DPDK driver or | |
164 | a SW crypto device/s (virtual crypto PMD) must be created (using --vdev). | |
165 | ||
166 | To run the application in linuxapp environment with 2 lcores, 2 ports and 2 crypto devices, issue the command: | |
167 | ||
168 | .. code-block:: console | |
169 | ||
170 | $ ./build/l2fwd-crypto -c 0x3 -n 4 --vdev "cryptodev_aesni_mb_pmd" \ | |
171 | --vdev "cryptodev_aesni_mb_pmd" -- -p 0x3 --chain CIPHER_HASH \ | |
172 | --cipher_op ENCRYPT --cipher_algo AES_CBC \ | |
173 | --cipher_key 00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f \ | |
174 | --auth_op GENERATE --auth_algo AES_XCBC_MAC \ | |
175 | --auth_key 10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f | |
176 | ||
177 | Refer to the *DPDK Getting Started Guide* for general information on running applications | |
178 | and the Environment Abstraction Layer (EAL) options. | |
179 | ||
180 | Explanation | |
181 | ----------- | |
182 | ||
183 | The L2 forward with Crypto application demonstrates the performance of a crypto operation | |
184 | on a packet received on a RX PORT before forwarding it to a TX PORT. | |
185 | ||
186 | The following figure illustrates a sample flow of a packet in the application, | |
187 | from reception until transmission. | |
188 | ||
189 | .. _figure_l2_fwd_encrypt_flow: | |
190 | ||
191 | .. figure:: img/l2_fwd_encrypt_flow.* | |
192 | ||
193 | Encryption flow Through the L2 Forwarding with Crypto Application | |
194 | ||
195 | ||
196 | The following sections provide some explanation of the application. | |
197 | ||
198 | Crypto operation specification | |
199 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
200 | ||
201 | All the packets received in all the ports get transformed by the crypto device/s | |
202 | (ciphering and/or authentication). | |
203 | The crypto operation to be performed on the packet is parsed from the command line | |
204 | (go to "Running the Application section for all the options). | |
205 | ||
206 | If no parameter is passed, the default crypto operation is: | |
207 | ||
208 | * Encryption with AES-CBC with 128 bit key. | |
209 | ||
210 | * Authentication with SHA1-HMAC (generation). | |
211 | ||
212 | * Keys, IV and AAD are generated randomly. | |
213 | ||
214 | There are two methods to pass keys, IV and ADD from the command line: | |
215 | ||
216 | * Passing the full key, separated bytes by ":":: | |
217 | ||
218 | --cipher_key 00:11:22:33:44 | |
219 | ||
220 | * Passing the size, so key is generated randomly:: | |
221 | ||
222 | --cipher_key_random_size 16 | |
223 | ||
224 | **Note**: | |
225 | If full key is passed (first method) and the size is passed as well (second method), | |
226 | the latter will be ignored. | |
227 | ||
228 | Size of these keys are checked (regardless the method), before starting the app, | |
229 | to make sure that it is supported by the crypto devices. | |
230 | ||
231 | Crypto device initialization | |
232 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
233 | ||
234 | Once the encryption operation is defined, crypto devices are initialized. | |
235 | The crypto devices must be either bound to a DPDK driver (if they are physical devices) | |
236 | or created using the EAL option --vdev (if they are virtual devices), | |
237 | when running the application. | |
238 | ||
239 | The initialize_cryptodevs() function performs the device initialization. | |
240 | It iterates through the list of the available crypto devices and | |
241 | check which ones are capable of performing the operation. | |
242 | Each device has a set of capabilities associated with it, | |
243 | which are stored in the device info structure, so the function checks if the operation | |
244 | is within the structure of each device. | |
245 | ||
246 | The following code checks if the device supports the specified cipher algorithm | |
247 | (similar for the authentication algorithm): | |
248 | ||
249 | .. code-block:: c | |
250 | ||
251 | /* Check if device supports cipher algo */ | |
252 | i = 0; | |
253 | opt_cipher_algo = options->cipher_xform.cipher.algo; | |
254 | cap = &dev_info.capabilities[i]; | |
255 | while (cap->op != RTE_CRYPTO_OP_TYPE_UNDEFINED) { | |
256 | cap_cipher_algo = cap->sym.cipher.algo; | |
257 | if (cap->sym.xform_type == | |
258 | RTE_CRYPTO_SYM_XFORM_CIPHER) { | |
259 | if (cap_cipher_algo == opt_cipher_algo) { | |
260 | if (check_type(options, &dev_info) == 0) | |
261 | break; | |
262 | } | |
263 | } | |
264 | cap = &dev_info.capabilities[++i]; | |
265 | } | |
266 | ||
267 | If a capable crypto device is found, key sizes are checked to see if they are supported | |
268 | (cipher key and IV for the ciphering): | |
269 | ||
270 | .. code-block:: c | |
271 | ||
272 | /* | |
273 | * Check if length of provided cipher key is supported | |
274 | * by the algorithm chosen. | |
275 | */ | |
276 | if (options->ckey_param) { | |
277 | if (check_supported_size( | |
278 | options->cipher_xform.cipher.key.length, | |
279 | cap->sym.cipher.key_size.min, | |
280 | cap->sym.cipher.key_size.max, | |
281 | cap->sym.cipher.key_size.increment) | |
282 | != 0) { | |
283 | printf("Unsupported cipher key length\n"); | |
284 | return -1; | |
285 | } | |
286 | /* | |
287 | * Check if length of the cipher key to be randomly generated | |
288 | * is supported by the algorithm chosen. | |
289 | */ | |
290 | } else if (options->ckey_random_size != -1) { | |
291 | if (check_supported_size(options->ckey_random_size, | |
292 | cap->sym.cipher.key_size.min, | |
293 | cap->sym.cipher.key_size.max, | |
294 | cap->sym.cipher.key_size.increment) | |
295 | != 0) { | |
296 | printf("Unsupported cipher key length\n"); | |
297 | return -1; | |
298 | } | |
299 | options->cipher_xform.cipher.key.length = | |
300 | options->ckey_random_size; | |
301 | /* No size provided, use minimum size. */ | |
302 | } else | |
303 | options->cipher_xform.cipher.key.length = | |
304 | cap->sym.cipher.key_size.min; | |
305 | ||
306 | After all the checks, the device is configured and it is added to the | |
307 | crypto device list. | |
308 | ||
309 | **Note**: | |
310 | The number of crypto devices that supports the specified crypto operation | |
311 | must be at least the number of ports to be used. | |
312 | ||
313 | Session creation | |
314 | ~~~~~~~~~~~~~~~~ | |
315 | ||
316 | The crypto operation has a crypto session associated to it, which contains | |
317 | information such as the transform chain to perform (e.g. ciphering then hashing), | |
318 | pointers to the keys, lengths... etc. | |
319 | ||
320 | This session is created and is later attached to the crypto operation: | |
321 | ||
322 | .. code-block:: c | |
323 | ||
324 | static struct rte_cryptodev_sym_session * | |
325 | initialize_crypto_session(struct l2fwd_crypto_options *options, | |
326 | uint8_t cdev_id) | |
327 | { | |
328 | struct rte_crypto_sym_xform *first_xform; | |
329 | ||
330 | if (options->xform_chain == L2FWD_CRYPTO_CIPHER_HASH) { | |
331 | first_xform = &options->cipher_xform; | |
332 | first_xform->next = &options->auth_xform; | |
333 | } else if (options->xform_chain == L2FWD_CRYPTO_HASH_CIPHER) { | |
334 | first_xform = &options->auth_xform; | |
335 | first_xform->next = &options->cipher_xform; | |
336 | } else if (options->xform_chain == L2FWD_CRYPTO_CIPHER_ONLY) { | |
337 | first_xform = &options->cipher_xform; | |
338 | } else { | |
339 | first_xform = &options->auth_xform; | |
340 | } | |
341 | ||
342 | /* Setup Cipher Parameters */ | |
343 | return rte_cryptodev_sym_session_create(cdev_id, first_xform); | |
344 | } | |
345 | ||
346 | ... | |
347 | ||
348 | port_cparams[i].session = initialize_crypto_session(options, | |
349 | port_cparams[i].dev_id); | |
350 | ||
351 | Crypto operation creation | |
352 | ~~~~~~~~~~~~~~~~~~~~~~~~~ | |
353 | ||
354 | Given N packets received from a RX PORT, N crypto operations are allocated | |
355 | and filled: | |
356 | ||
357 | .. code-block:: c | |
358 | ||
359 | if (nb_rx) { | |
360 | /* | |
361 | * If we can't allocate a crypto_ops, then drop | |
362 | * the rest of the burst and dequeue and | |
363 | * process the packets to free offload structs | |
364 | */ | |
365 | if (rte_crypto_op_bulk_alloc( | |
366 | l2fwd_crypto_op_pool, | |
367 | RTE_CRYPTO_OP_TYPE_SYMMETRIC, | |
368 | ops_burst, nb_rx) != | |
369 | nb_rx) { | |
370 | for (j = 0; j < nb_rx; j++) | |
371 | rte_pktmbuf_free(pkts_burst[i]); | |
372 | ||
373 | nb_rx = 0; | |
374 | } | |
375 | ||
376 | After filling the crypto operation (including session attachment), | |
377 | the mbuf which will be transformed is attached to it:: | |
378 | ||
379 | op->sym->m_src = m; | |
380 | ||
381 | Since no destination mbuf is set, the source mbuf will be overwritten | |
382 | after the operation is done (in-place). | |
383 | ||
384 | Crypto operation enqueuing/dequeuing | |
385 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
386 | ||
387 | Once the operation has been created, it has to be enqueued in one of the crypto devices. | |
388 | Before doing so, for performance reasons, the operation stays in a buffer. | |
389 | When the buffer has enough operations (MAX_PKT_BURST), they are enqueued in the device, | |
390 | which will perform the operation at that moment: | |
391 | ||
392 | .. code-block:: c | |
393 | ||
394 | static int | |
395 | l2fwd_crypto_enqueue(struct rte_crypto_op *op, | |
396 | struct l2fwd_crypto_params *cparams) | |
397 | { | |
398 | unsigned lcore_id, len; | |
399 | struct lcore_queue_conf *qconf; | |
400 | ||
401 | lcore_id = rte_lcore_id(); | |
402 | ||
403 | qconf = &lcore_queue_conf[lcore_id]; | |
404 | len = qconf->op_buf[cparams->dev_id].len; | |
405 | qconf->op_buf[cparams->dev_id].buffer[len] = op; | |
406 | len++; | |
407 | ||
408 | /* enough ops to be sent */ | |
409 | if (len == MAX_PKT_BURST) { | |
410 | l2fwd_crypto_send_burst(qconf, MAX_PKT_BURST, cparams); | |
411 | len = 0; | |
412 | } | |
413 | ||
414 | qconf->op_buf[cparams->dev_id].len = len; | |
415 | return 0; | |
416 | } | |
417 | ||
418 | ... | |
419 | ||
420 | static int | |
421 | l2fwd_crypto_send_burst(struct lcore_queue_conf *qconf, unsigned n, | |
422 | struct l2fwd_crypto_params *cparams) | |
423 | { | |
424 | struct rte_crypto_op **op_buffer; | |
425 | unsigned ret; | |
426 | ||
427 | op_buffer = (struct rte_crypto_op **) | |
428 | qconf->op_buf[cparams->dev_id].buffer; | |
429 | ||
430 | ret = rte_cryptodev_enqueue_burst(cparams->dev_id, | |
431 | cparams->qp_id, op_buffer, (uint16_t) n); | |
432 | ||
433 | crypto_statistics[cparams->dev_id].enqueued += ret; | |
434 | if (unlikely(ret < n)) { | |
435 | crypto_statistics[cparams->dev_id].errors += (n - ret); | |
436 | do { | |
437 | rte_pktmbuf_free(op_buffer[ret]->sym->m_src); | |
438 | rte_crypto_op_free(op_buffer[ret]); | |
439 | } while (++ret < n); | |
440 | } | |
441 | ||
442 | return 0; | |
443 | } | |
444 | ||
445 | After this, the operations are dequeued from the device, and the transformed mbuf | |
446 | is extracted from the operation. Then, the operation is freed and the mbuf is | |
447 | forwarded as it is done in the L2 forwarding application. | |
448 | ||
449 | .. code-block:: c | |
450 | ||
451 | /* Dequeue packets from Crypto device */ | |
452 | do { | |
453 | nb_rx = rte_cryptodev_dequeue_burst( | |
454 | cparams->dev_id, cparams->qp_id, | |
455 | ops_burst, MAX_PKT_BURST); | |
456 | ||
457 | crypto_statistics[cparams->dev_id].dequeued += | |
458 | nb_rx; | |
459 | ||
460 | /* Forward crypto'd packets */ | |
461 | for (j = 0; j < nb_rx; j++) { | |
462 | m = ops_burst[j]->sym->m_src; | |
463 | ||
464 | rte_crypto_op_free(ops_burst[j]); | |
465 | l2fwd_simple_forward(m, portid); | |
466 | } | |
467 | } while (nb_rx == MAX_PKT_BURST); |