xref: /dpdk/examples/l2fwd-crypto/main.c (revision acdfecba455401d91ca1e2d16e33e42588bdde16)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <time.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <stdint.h>
39 #include <inttypes.h>
40 #include <sys/types.h>
41 #include <sys/queue.h>
42 #include <netinet/in.h>
43 #include <setjmp.h>
44 #include <stdarg.h>
45 #include <ctype.h>
46 #include <errno.h>
47 #include <getopt.h>
48 #include <fcntl.h>
49 #include <unistd.h>
50 
51 #include <rte_atomic.h>
52 #include <rte_branch_prediction.h>
53 #include <rte_common.h>
54 #include <rte_cryptodev.h>
55 #include <rte_cycles.h>
56 #include <rte_debug.h>
57 #include <rte_eal.h>
58 #include <rte_ether.h>
59 #include <rte_ethdev.h>
60 #include <rte_interrupts.h>
61 #include <rte_ip.h>
62 #include <rte_launch.h>
63 #include <rte_lcore.h>
64 #include <rte_log.h>
65 #include <rte_malloc.h>
66 #include <rte_mbuf.h>
67 #include <rte_memcpy.h>
68 #include <rte_memory.h>
69 #include <rte_mempool.h>
70 #include <rte_memzone.h>
71 #include <rte_pci.h>
72 #include <rte_per_lcore.h>
73 #include <rte_prefetch.h>
74 #include <rte_random.h>
75 #include <rte_hexdump.h>
76 
77 enum cdev_type {
78 	CDEV_TYPE_ANY,
79 	CDEV_TYPE_HW,
80 	CDEV_TYPE_SW
81 };
82 
83 #define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
84 
85 #define NB_MBUF   8192
86 
87 #define MAX_STR_LEN 32
88 #define MAX_KEY_SIZE 128
89 #define MAX_PKT_BURST 32
90 #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
91 #define MAX_SESSIONS 32
92 #define SESSION_POOL_CACHE_SIZE 0
93 
94 #define MAXIMUM_IV_LENGTH	16
95 #define IV_OFFSET		(sizeof(struct rte_crypto_op) + \
96 				sizeof(struct rte_crypto_sym_op))
97 
98 /*
99  * Configurable number of RX/TX ring descriptors
100  */
101 #define RTE_TEST_RX_DESC_DEFAULT 128
102 #define RTE_TEST_TX_DESC_DEFAULT 512
103 
104 static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
105 static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
106 
107 /* ethernet addresses of ports */
108 static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
109 
110 /* mask of enabled ports */
111 static uint64_t l2fwd_enabled_port_mask;
112 static uint64_t l2fwd_enabled_crypto_mask;
113 
114 /* list of enabled ports */
115 static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
116 
117 
118 struct pkt_buffer {
119 	unsigned len;
120 	struct rte_mbuf *buffer[MAX_PKT_BURST];
121 };
122 
123 struct op_buffer {
124 	unsigned len;
125 	struct rte_crypto_op *buffer[MAX_PKT_BURST];
126 };
127 
128 #define MAX_RX_QUEUE_PER_LCORE 16
129 #define MAX_TX_QUEUE_PER_PORT 16
130 
131 enum l2fwd_crypto_xform_chain {
132 	L2FWD_CRYPTO_CIPHER_HASH,
133 	L2FWD_CRYPTO_HASH_CIPHER,
134 	L2FWD_CRYPTO_CIPHER_ONLY,
135 	L2FWD_CRYPTO_HASH_ONLY,
136 	L2FWD_CRYPTO_AEAD
137 };
138 
139 struct l2fwd_key {
140 	uint8_t *data;
141 	uint32_t length;
142 	phys_addr_t phys_addr;
143 };
144 
145 struct l2fwd_iv {
146 	uint8_t *data;
147 	uint16_t length;
148 };
149 
150 /** l2fwd crypto application command line options */
151 struct l2fwd_crypto_options {
152 	unsigned portmask;
153 	unsigned nb_ports_per_lcore;
154 	unsigned refresh_period;
155 	unsigned single_lcore:1;
156 
157 	enum cdev_type type;
158 	unsigned sessionless:1;
159 
160 	enum l2fwd_crypto_xform_chain xform_chain;
161 
162 	struct rte_crypto_sym_xform cipher_xform;
163 	unsigned ckey_param;
164 	int ckey_random_size;
165 
166 	struct l2fwd_iv cipher_iv;
167 	unsigned int cipher_iv_param;
168 	int cipher_iv_random_size;
169 
170 	struct rte_crypto_sym_xform auth_xform;
171 	uint8_t akey_param;
172 	int akey_random_size;
173 
174 	struct l2fwd_iv auth_iv;
175 	unsigned int auth_iv_param;
176 	int auth_iv_random_size;
177 
178 	struct rte_crypto_sym_xform aead_xform;
179 	unsigned int aead_key_param;
180 	int aead_key_random_size;
181 
182 	struct l2fwd_iv aead_iv;
183 	unsigned int aead_iv_param;
184 	int aead_iv_random_size;
185 
186 	struct l2fwd_key aad;
187 	unsigned aad_param;
188 	int aad_random_size;
189 
190 	int digest_size;
191 
192 	uint16_t block_size;
193 	char string_type[MAX_STR_LEN];
194 
195 	uint64_t cryptodev_mask;
196 
197 	unsigned int mac_updating;
198 };
199 
200 /** l2fwd crypto lcore params */
201 struct l2fwd_crypto_params {
202 	uint8_t dev_id;
203 	uint8_t qp_id;
204 
205 	unsigned digest_length;
206 	unsigned block_size;
207 
208 	struct l2fwd_iv cipher_iv;
209 	struct l2fwd_iv auth_iv;
210 	struct l2fwd_iv aead_iv;
211 	struct l2fwd_key aad;
212 	struct rte_cryptodev_sym_session *session;
213 
214 	uint8_t do_cipher;
215 	uint8_t do_hash;
216 	uint8_t do_aead;
217 	uint8_t hash_verify;
218 
219 	enum rte_crypto_cipher_algorithm cipher_algo;
220 	enum rte_crypto_auth_algorithm auth_algo;
221 	enum rte_crypto_aead_algorithm aead_algo;
222 };
223 
224 /** lcore configuration */
225 struct lcore_queue_conf {
226 	unsigned nb_rx_ports;
227 	unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
228 
229 	unsigned nb_crypto_devs;
230 	unsigned cryptodev_list[MAX_RX_QUEUE_PER_LCORE];
231 
232 	struct op_buffer op_buf[RTE_CRYPTO_MAX_DEVS];
233 	struct pkt_buffer pkt_buf[RTE_MAX_ETHPORTS];
234 } __rte_cache_aligned;
235 
236 struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
237 
238 static const struct rte_eth_conf port_conf = {
239 	.rxmode = {
240 		.mq_mode = ETH_MQ_RX_NONE,
241 		.max_rx_pkt_len = ETHER_MAX_LEN,
242 		.split_hdr_size = 0,
243 		.header_split   = 0, /**< Header Split disabled */
244 		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
245 		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
246 		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
247 		.hw_strip_crc   = 1, /**< CRC stripped by hardware */
248 	},
249 	.txmode = {
250 		.mq_mode = ETH_MQ_TX_NONE,
251 	},
252 };
253 
254 struct rte_mempool *l2fwd_pktmbuf_pool;
255 struct rte_mempool *l2fwd_crypto_op_pool;
256 struct rte_mempool *session_pool_socket[RTE_MAX_NUMA_NODES] = { 0 };
257 
258 /* Per-port statistics struct */
259 struct l2fwd_port_statistics {
260 	uint64_t tx;
261 	uint64_t rx;
262 
263 	uint64_t crypto_enqueued;
264 	uint64_t crypto_dequeued;
265 
266 	uint64_t dropped;
267 } __rte_cache_aligned;
268 
269 struct l2fwd_crypto_statistics {
270 	uint64_t enqueued;
271 	uint64_t dequeued;
272 
273 	uint64_t errors;
274 } __rte_cache_aligned;
275 
276 struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
277 struct l2fwd_crypto_statistics crypto_statistics[RTE_CRYPTO_MAX_DEVS];
278 
279 /* A tsc-based timer responsible for triggering statistics printout */
280 #define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
281 #define MAX_TIMER_PERIOD 86400UL /* 1 day max */
282 
283 /* default period is 10 seconds */
284 static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000;
285 
286 /* Print out statistics on packets dropped */
287 static void
288 print_stats(void)
289 {
290 	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
291 	uint64_t total_packets_enqueued, total_packets_dequeued,
292 		total_packets_errors;
293 	unsigned portid;
294 	uint64_t cdevid;
295 
296 	total_packets_dropped = 0;
297 	total_packets_tx = 0;
298 	total_packets_rx = 0;
299 	total_packets_enqueued = 0;
300 	total_packets_dequeued = 0;
301 	total_packets_errors = 0;
302 
303 	const char clr[] = { 27, '[', '2', 'J', '\0' };
304 	const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
305 
306 		/* Clear screen and move to top left */
307 	printf("%s%s", clr, topLeft);
308 
309 	printf("\nPort statistics ====================================");
310 
311 	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
312 		/* skip disabled ports */
313 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
314 			continue;
315 		printf("\nStatistics for port %u ------------------------------"
316 			   "\nPackets sent: %32"PRIu64
317 			   "\nPackets received: %28"PRIu64
318 			   "\nPackets dropped: %29"PRIu64,
319 			   portid,
320 			   port_statistics[portid].tx,
321 			   port_statistics[portid].rx,
322 			   port_statistics[portid].dropped);
323 
324 		total_packets_dropped += port_statistics[portid].dropped;
325 		total_packets_tx += port_statistics[portid].tx;
326 		total_packets_rx += port_statistics[portid].rx;
327 	}
328 	printf("\nCrypto statistics ==================================");
329 
330 	for (cdevid = 0; cdevid < RTE_CRYPTO_MAX_DEVS; cdevid++) {
331 		/* skip disabled ports */
332 		if ((l2fwd_enabled_crypto_mask & (((uint64_t)1) << cdevid)) == 0)
333 			continue;
334 		printf("\nStatistics for cryptodev %"PRIu64
335 				" -------------------------"
336 			   "\nPackets enqueued: %28"PRIu64
337 			   "\nPackets dequeued: %28"PRIu64
338 			   "\nPackets errors: %30"PRIu64,
339 			   cdevid,
340 			   crypto_statistics[cdevid].enqueued,
341 			   crypto_statistics[cdevid].dequeued,
342 			   crypto_statistics[cdevid].errors);
343 
344 		total_packets_enqueued += crypto_statistics[cdevid].enqueued;
345 		total_packets_dequeued += crypto_statistics[cdevid].dequeued;
346 		total_packets_errors += crypto_statistics[cdevid].errors;
347 	}
348 	printf("\nAggregate statistics ==============================="
349 		   "\nTotal packets received: %22"PRIu64
350 		   "\nTotal packets enqueued: %22"PRIu64
351 		   "\nTotal packets dequeued: %22"PRIu64
352 		   "\nTotal packets sent: %26"PRIu64
353 		   "\nTotal packets dropped: %23"PRIu64
354 		   "\nTotal packets crypto errors: %17"PRIu64,
355 		   total_packets_rx,
356 		   total_packets_enqueued,
357 		   total_packets_dequeued,
358 		   total_packets_tx,
359 		   total_packets_dropped,
360 		   total_packets_errors);
361 	printf("\n====================================================\n");
362 }
363 
364 static int
365 l2fwd_crypto_send_burst(struct lcore_queue_conf *qconf, unsigned n,
366 		struct l2fwd_crypto_params *cparams)
367 {
368 	struct rte_crypto_op **op_buffer;
369 	unsigned ret;
370 
371 	op_buffer = (struct rte_crypto_op **)
372 			qconf->op_buf[cparams->dev_id].buffer;
373 
374 	ret = rte_cryptodev_enqueue_burst(cparams->dev_id,
375 			cparams->qp_id,	op_buffer, (uint16_t) n);
376 
377 	crypto_statistics[cparams->dev_id].enqueued += ret;
378 	if (unlikely(ret < n)) {
379 		crypto_statistics[cparams->dev_id].errors += (n - ret);
380 		do {
381 			rte_pktmbuf_free(op_buffer[ret]->sym->m_src);
382 			rte_crypto_op_free(op_buffer[ret]);
383 		} while (++ret < n);
384 	}
385 
386 	return 0;
387 }
388 
389 static int
390 l2fwd_crypto_enqueue(struct rte_crypto_op *op,
391 		struct l2fwd_crypto_params *cparams)
392 {
393 	unsigned lcore_id, len;
394 	struct lcore_queue_conf *qconf;
395 
396 	lcore_id = rte_lcore_id();
397 
398 	qconf = &lcore_queue_conf[lcore_id];
399 	len = qconf->op_buf[cparams->dev_id].len;
400 	qconf->op_buf[cparams->dev_id].buffer[len] = op;
401 	len++;
402 
403 	/* enough ops to be sent */
404 	if (len == MAX_PKT_BURST) {
405 		l2fwd_crypto_send_burst(qconf, MAX_PKT_BURST, cparams);
406 		len = 0;
407 	}
408 
409 	qconf->op_buf[cparams->dev_id].len = len;
410 	return 0;
411 }
412 
413 static int
414 l2fwd_simple_crypto_enqueue(struct rte_mbuf *m,
415 		struct rte_crypto_op *op,
416 		struct l2fwd_crypto_params *cparams)
417 {
418 	struct ether_hdr *eth_hdr;
419 	struct ipv4_hdr *ip_hdr;
420 
421 	uint32_t ipdata_offset, data_len;
422 	uint32_t pad_len = 0;
423 	char *padding;
424 
425 	eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
426 
427 	if (eth_hdr->ether_type != rte_cpu_to_be_16(ETHER_TYPE_IPv4))
428 		return -1;
429 
430 	ipdata_offset = sizeof(struct ether_hdr);
431 
432 	ip_hdr = (struct ipv4_hdr *)(rte_pktmbuf_mtod(m, char *) +
433 			ipdata_offset);
434 
435 	ipdata_offset += (ip_hdr->version_ihl & IPV4_HDR_IHL_MASK)
436 			* IPV4_IHL_MULTIPLIER;
437 
438 
439 	/* Zero pad data to be crypto'd so it is block aligned */
440 	data_len  = rte_pktmbuf_data_len(m) - ipdata_offset;
441 
442 	if (cparams->do_hash && cparams->hash_verify)
443 		data_len -= cparams->digest_length;
444 
445 	if (cparams->do_cipher) {
446 		/*
447 		 * Following algorithms are block cipher algorithms,
448 		 * and might need padding
449 		 */
450 		switch (cparams->cipher_algo) {
451 		case RTE_CRYPTO_CIPHER_AES_CBC:
452 		case RTE_CRYPTO_CIPHER_AES_ECB:
453 		case RTE_CRYPTO_CIPHER_DES_CBC:
454 		case RTE_CRYPTO_CIPHER_3DES_CBC:
455 		case RTE_CRYPTO_CIPHER_3DES_ECB:
456 			if (data_len % cparams->block_size)
457 				pad_len = cparams->block_size -
458 					(data_len % cparams->block_size);
459 			break;
460 		default:
461 			pad_len = 0;
462 		}
463 
464 		if (pad_len) {
465 			padding = rte_pktmbuf_append(m, pad_len);
466 			if (unlikely(!padding))
467 				return -1;
468 
469 			data_len += pad_len;
470 			memset(padding, 0, pad_len);
471 		}
472 	}
473 
474 	/* Set crypto operation data parameters */
475 	rte_crypto_op_attach_sym_session(op, cparams->session);
476 
477 	if (cparams->do_hash) {
478 		if (cparams->auth_iv.length) {
479 			uint8_t *iv_ptr = rte_crypto_op_ctod_offset(op,
480 						uint8_t *,
481 						IV_OFFSET +
482 						cparams->cipher_iv.length);
483 			/*
484 			 * Copy IV at the end of the crypto operation,
485 			 * after the cipher IV, if added
486 			 */
487 			rte_memcpy(iv_ptr, cparams->auth_iv.data,
488 					cparams->auth_iv.length);
489 		}
490 		if (!cparams->hash_verify) {
491 			/* Append space for digest to end of packet */
492 			op->sym->auth.digest.data = (uint8_t *)rte_pktmbuf_append(m,
493 				cparams->digest_length);
494 		} else {
495 			op->sym->auth.digest.data = rte_pktmbuf_mtod(m,
496 				uint8_t *) + ipdata_offset + data_len;
497 		}
498 
499 		op->sym->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(m,
500 				rte_pktmbuf_pkt_len(m) - cparams->digest_length);
501 
502 		/* For wireless algorithms, offset/length must be in bits */
503 		if (cparams->auth_algo == RTE_CRYPTO_AUTH_SNOW3G_UIA2 ||
504 				cparams->auth_algo == RTE_CRYPTO_AUTH_KASUMI_F9 ||
505 				cparams->auth_algo == RTE_CRYPTO_AUTH_ZUC_EIA3) {
506 			op->sym->auth.data.offset = ipdata_offset << 3;
507 			op->sym->auth.data.length = data_len << 3;
508 		} else {
509 			op->sym->auth.data.offset = ipdata_offset;
510 			op->sym->auth.data.length = data_len;
511 		}
512 	}
513 
514 	if (cparams->do_cipher) {
515 		uint8_t *iv_ptr = rte_crypto_op_ctod_offset(op, uint8_t *,
516 							IV_OFFSET);
517 		/* Copy IV at the end of the crypto operation */
518 		rte_memcpy(iv_ptr, cparams->cipher_iv.data,
519 				cparams->cipher_iv.length);
520 
521 		/* For wireless algorithms, offset/length must be in bits */
522 		if (cparams->cipher_algo == RTE_CRYPTO_CIPHER_SNOW3G_UEA2 ||
523 				cparams->cipher_algo == RTE_CRYPTO_CIPHER_KASUMI_F8 ||
524 				cparams->cipher_algo == RTE_CRYPTO_CIPHER_ZUC_EEA3) {
525 			op->sym->cipher.data.offset = ipdata_offset << 3;
526 			op->sym->cipher.data.length = data_len << 3;
527 		} else {
528 			op->sym->cipher.data.offset = ipdata_offset;
529 			op->sym->cipher.data.length = data_len;
530 		}
531 	}
532 
533 	if (cparams->do_aead) {
534 		uint8_t *iv_ptr = rte_crypto_op_ctod_offset(op, uint8_t *,
535 							IV_OFFSET);
536 		/* Copy IV at the end of the crypto operation */
537 		rte_memcpy(iv_ptr, cparams->aead_iv.data, cparams->aead_iv.length);
538 
539 		op->sym->aead.data.offset = ipdata_offset;
540 		op->sym->aead.data.length = data_len;
541 
542 		if (!cparams->hash_verify) {
543 			/* Append space for digest to end of packet */
544 			op->sym->aead.digest.data = (uint8_t *)rte_pktmbuf_append(m,
545 				cparams->digest_length);
546 		} else {
547 			op->sym->aead.digest.data = rte_pktmbuf_mtod(m,
548 				uint8_t *) + ipdata_offset + data_len;
549 		}
550 
551 		op->sym->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(m,
552 				rte_pktmbuf_pkt_len(m) - cparams->digest_length);
553 
554 		if (cparams->aad.length) {
555 			op->sym->aead.aad.data = cparams->aad.data;
556 			op->sym->aead.aad.phys_addr = cparams->aad.phys_addr;
557 		}
558 	}
559 
560 	op->sym->m_src = m;
561 
562 	return l2fwd_crypto_enqueue(op, cparams);
563 }
564 
565 
566 /* Send the burst of packets on an output interface */
567 static int
568 l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n,
569 		uint8_t port)
570 {
571 	struct rte_mbuf **pkt_buffer;
572 	unsigned ret;
573 
574 	pkt_buffer = (struct rte_mbuf **)qconf->pkt_buf[port].buffer;
575 
576 	ret = rte_eth_tx_burst(port, 0, pkt_buffer, (uint16_t)n);
577 	port_statistics[port].tx += ret;
578 	if (unlikely(ret < n)) {
579 		port_statistics[port].dropped += (n - ret);
580 		do {
581 			rte_pktmbuf_free(pkt_buffer[ret]);
582 		} while (++ret < n);
583 	}
584 
585 	return 0;
586 }
587 
588 /* Enqueue packets for TX and prepare them to be sent */
589 static int
590 l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
591 {
592 	unsigned lcore_id, len;
593 	struct lcore_queue_conf *qconf;
594 
595 	lcore_id = rte_lcore_id();
596 
597 	qconf = &lcore_queue_conf[lcore_id];
598 	len = qconf->pkt_buf[port].len;
599 	qconf->pkt_buf[port].buffer[len] = m;
600 	len++;
601 
602 	/* enough pkts to be sent */
603 	if (unlikely(len == MAX_PKT_BURST)) {
604 		l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
605 		len = 0;
606 	}
607 
608 	qconf->pkt_buf[port].len = len;
609 	return 0;
610 }
611 
612 static void
613 l2fwd_mac_updating(struct rte_mbuf *m, unsigned int dest_portid)
614 {
615 	struct ether_hdr *eth;
616 	void *tmp;
617 
618 	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
619 
620 	/* 02:00:00:00:00:xx */
621 	tmp = &eth->d_addr.addr_bytes[0];
622 	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dest_portid << 40);
623 
624 	/* src addr */
625 	ether_addr_copy(&l2fwd_ports_eth_addr[dest_portid], &eth->s_addr);
626 }
627 
628 static void
629 l2fwd_simple_forward(struct rte_mbuf *m, unsigned int portid,
630 		struct l2fwd_crypto_options *options)
631 {
632 	unsigned int dst_port;
633 
634 	dst_port = l2fwd_dst_ports[portid];
635 
636 	if (options->mac_updating)
637 		l2fwd_mac_updating(m, dst_port);
638 
639 	l2fwd_send_packet(m, (uint8_t) dst_port);
640 }
641 
642 /** Generate random key */
643 static void
644 generate_random_key(uint8_t *key, unsigned length)
645 {
646 	int fd;
647 	int ret;
648 
649 	fd = open("/dev/urandom", O_RDONLY);
650 	if (fd < 0)
651 		rte_exit(EXIT_FAILURE, "Failed to generate random key\n");
652 
653 	ret = read(fd, key, length);
654 	close(fd);
655 
656 	if (ret != (signed)length)
657 		rte_exit(EXIT_FAILURE, "Failed to generate random key\n");
658 }
659 
660 static struct rte_cryptodev_sym_session *
661 initialize_crypto_session(struct l2fwd_crypto_options *options, uint8_t cdev_id)
662 {
663 	struct rte_crypto_sym_xform *first_xform;
664 	struct rte_cryptodev_sym_session *session;
665 	uint8_t socket_id = rte_cryptodev_socket_id(cdev_id);
666 	struct rte_mempool *sess_mp = session_pool_socket[socket_id];
667 
668 	if (options->xform_chain == L2FWD_CRYPTO_AEAD) {
669 		first_xform = &options->aead_xform;
670 	} else if (options->xform_chain == L2FWD_CRYPTO_CIPHER_HASH) {
671 		first_xform = &options->cipher_xform;
672 		first_xform->next = &options->auth_xform;
673 	} else if (options->xform_chain == L2FWD_CRYPTO_HASH_CIPHER) {
674 		first_xform = &options->auth_xform;
675 		first_xform->next = &options->cipher_xform;
676 	} else if (options->xform_chain == L2FWD_CRYPTO_CIPHER_ONLY) {
677 		first_xform = &options->cipher_xform;
678 	} else {
679 		first_xform = &options->auth_xform;
680 	}
681 
682 	session = rte_cryptodev_sym_session_create(sess_mp);
683 
684 	if (session == NULL)
685 		return NULL;
686 
687 	if (rte_cryptodev_sym_session_init(cdev_id, session,
688 				first_xform, sess_mp) < 0)
689 		return NULL;
690 
691 	return session;
692 }
693 
694 static void
695 l2fwd_crypto_options_print(struct l2fwd_crypto_options *options);
696 
697 /* main processing loop */
698 static void
699 l2fwd_main_loop(struct l2fwd_crypto_options *options)
700 {
701 	struct rte_mbuf *m, *pkts_burst[MAX_PKT_BURST];
702 	struct rte_crypto_op *ops_burst[MAX_PKT_BURST];
703 
704 	unsigned lcore_id = rte_lcore_id();
705 	uint64_t prev_tsc = 0, diff_tsc, cur_tsc, timer_tsc = 0;
706 	unsigned i, j, portid, nb_rx, len;
707 	struct lcore_queue_conf *qconf = &lcore_queue_conf[lcore_id];
708 	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
709 			US_PER_S * BURST_TX_DRAIN_US;
710 	struct l2fwd_crypto_params *cparams;
711 	struct l2fwd_crypto_params port_cparams[qconf->nb_crypto_devs];
712 	struct rte_cryptodev_sym_session *session;
713 
714 	if (qconf->nb_rx_ports == 0) {
715 		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
716 		return;
717 	}
718 
719 	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
720 
721 	for (i = 0; i < qconf->nb_rx_ports; i++) {
722 
723 		portid = qconf->rx_port_list[i];
724 		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
725 			portid);
726 	}
727 
728 	for (i = 0; i < qconf->nb_crypto_devs; i++) {
729 		port_cparams[i].do_cipher = 0;
730 		port_cparams[i].do_hash = 0;
731 		port_cparams[i].do_aead = 0;
732 
733 		switch (options->xform_chain) {
734 		case L2FWD_CRYPTO_AEAD:
735 			port_cparams[i].do_aead = 1;
736 			break;
737 		case L2FWD_CRYPTO_CIPHER_HASH:
738 		case L2FWD_CRYPTO_HASH_CIPHER:
739 			port_cparams[i].do_cipher = 1;
740 			port_cparams[i].do_hash = 1;
741 			break;
742 		case L2FWD_CRYPTO_HASH_ONLY:
743 			port_cparams[i].do_hash = 1;
744 			break;
745 		case L2FWD_CRYPTO_CIPHER_ONLY:
746 			port_cparams[i].do_cipher = 1;
747 			break;
748 		}
749 
750 		port_cparams[i].dev_id = qconf->cryptodev_list[i];
751 		port_cparams[i].qp_id = 0;
752 
753 		port_cparams[i].block_size = options->block_size;
754 
755 		if (port_cparams[i].do_hash) {
756 			port_cparams[i].auth_iv.data = options->auth_iv.data;
757 			port_cparams[i].auth_iv.length = options->auth_iv.length;
758 			if (!options->auth_iv_param)
759 				generate_random_key(port_cparams[i].auth_iv.data,
760 						port_cparams[i].auth_iv.length);
761 			if (options->auth_xform.auth.op == RTE_CRYPTO_AUTH_OP_VERIFY)
762 				port_cparams[i].hash_verify = 1;
763 			else
764 				port_cparams[i].hash_verify = 0;
765 
766 			port_cparams[i].auth_algo = options->auth_xform.auth.algo;
767 			port_cparams[i].digest_length =
768 					options->auth_xform.auth.digest_length;
769 			/* Set IV parameters */
770 			if (options->auth_iv.length) {
771 				options->auth_xform.auth.iv.offset =
772 					IV_OFFSET + options->cipher_iv.length;
773 				options->auth_xform.auth.iv.length =
774 					options->auth_iv.length;
775 			}
776 		}
777 
778 		if (port_cparams[i].do_aead) {
779 			port_cparams[i].aead_iv.data = options->aead_iv.data;
780 			port_cparams[i].aead_iv.length = options->aead_iv.length;
781 			if (!options->aead_iv_param)
782 				generate_random_key(port_cparams[i].aead_iv.data,
783 						port_cparams[i].aead_iv.length);
784 			port_cparams[i].aead_algo = options->aead_xform.aead.algo;
785 			port_cparams[i].digest_length =
786 					options->aead_xform.aead.digest_length;
787 			if (options->aead_xform.aead.aad_length) {
788 				port_cparams[i].aad.data = options->aad.data;
789 				port_cparams[i].aad.phys_addr = options->aad.phys_addr;
790 				port_cparams[i].aad.length = options->aad.length;
791 				if (!options->aad_param)
792 					generate_random_key(port_cparams[i].aad.data,
793 						port_cparams[i].aad.length);
794 
795 			} else
796 				port_cparams[i].aad.length = 0;
797 
798 			if (options->aead_xform.aead.op == RTE_CRYPTO_AEAD_OP_DECRYPT)
799 				port_cparams[i].hash_verify = 1;
800 			else
801 				port_cparams[i].hash_verify = 0;
802 
803 			/* Set IV parameters */
804 			options->aead_xform.aead.iv.offset = IV_OFFSET;
805 			options->aead_xform.aead.iv.length = options->aead_iv.length;
806 		}
807 
808 		if (port_cparams[i].do_cipher) {
809 			port_cparams[i].cipher_iv.data = options->cipher_iv.data;
810 			port_cparams[i].cipher_iv.length = options->cipher_iv.length;
811 			if (!options->cipher_iv_param)
812 				generate_random_key(port_cparams[i].cipher_iv.data,
813 						port_cparams[i].cipher_iv.length);
814 
815 			port_cparams[i].cipher_algo = options->cipher_xform.cipher.algo;
816 			/* Set IV parameters */
817 			options->cipher_xform.cipher.iv.offset = IV_OFFSET;
818 			options->cipher_xform.cipher.iv.length =
819 						options->cipher_iv.length;
820 		}
821 
822 		session = initialize_crypto_session(options,
823 				port_cparams[i].dev_id);
824 		if (session == NULL)
825 			rte_exit(EXIT_FAILURE, "Failed to initialize crypto session\n");
826 
827 		port_cparams[i].session = session;
828 
829 		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u cryptoid=%u\n", lcore_id,
830 				port_cparams[i].dev_id);
831 	}
832 
833 	l2fwd_crypto_options_print(options);
834 
835 	/*
836 	 * Initialize previous tsc timestamp before the loop,
837 	 * to avoid showing the port statistics immediately,
838 	 * so user can see the crypto information.
839 	 */
840 	prev_tsc = rte_rdtsc();
841 	while (1) {
842 
843 		cur_tsc = rte_rdtsc();
844 
845 		/*
846 		 * Crypto device/TX burst queue drain
847 		 */
848 		diff_tsc = cur_tsc - prev_tsc;
849 		if (unlikely(diff_tsc > drain_tsc)) {
850 			/* Enqueue all crypto ops remaining in buffers */
851 			for (i = 0; i < qconf->nb_crypto_devs; i++) {
852 				cparams = &port_cparams[i];
853 				len = qconf->op_buf[cparams->dev_id].len;
854 				l2fwd_crypto_send_burst(qconf, len, cparams);
855 				qconf->op_buf[cparams->dev_id].len = 0;
856 			}
857 			/* Transmit all packets remaining in buffers */
858 			for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
859 				if (qconf->pkt_buf[portid].len == 0)
860 					continue;
861 				l2fwd_send_burst(&lcore_queue_conf[lcore_id],
862 						 qconf->pkt_buf[portid].len,
863 						 (uint8_t) portid);
864 				qconf->pkt_buf[portid].len = 0;
865 			}
866 
867 			/* if timer is enabled */
868 			if (timer_period > 0) {
869 
870 				/* advance the timer */
871 				timer_tsc += diff_tsc;
872 
873 				/* if timer has reached its timeout */
874 				if (unlikely(timer_tsc >=
875 						(uint64_t)timer_period)) {
876 
877 					/* do this only on master core */
878 					if (lcore_id == rte_get_master_lcore()
879 						&& options->refresh_period) {
880 						print_stats();
881 						timer_tsc = 0;
882 					}
883 				}
884 			}
885 
886 			prev_tsc = cur_tsc;
887 		}
888 
889 		/*
890 		 * Read packet from RX queues
891 		 */
892 		for (i = 0; i < qconf->nb_rx_ports; i++) {
893 			portid = qconf->rx_port_list[i];
894 
895 			cparams = &port_cparams[i];
896 
897 			nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
898 						 pkts_burst, MAX_PKT_BURST);
899 
900 			port_statistics[portid].rx += nb_rx;
901 
902 			if (nb_rx) {
903 				/*
904 				 * If we can't allocate a crypto_ops, then drop
905 				 * the rest of the burst and dequeue and
906 				 * process the packets to free offload structs
907 				 */
908 				if (rte_crypto_op_bulk_alloc(
909 						l2fwd_crypto_op_pool,
910 						RTE_CRYPTO_OP_TYPE_SYMMETRIC,
911 						ops_burst, nb_rx) !=
912 								nb_rx) {
913 					for (j = 0; j < nb_rx; j++)
914 						rte_pktmbuf_free(pkts_burst[j]);
915 
916 					nb_rx = 0;
917 				}
918 
919 				/* Enqueue packets from Crypto device*/
920 				for (j = 0; j < nb_rx; j++) {
921 					m = pkts_burst[j];
922 
923 					l2fwd_simple_crypto_enqueue(m,
924 							ops_burst[j], cparams);
925 				}
926 			}
927 
928 			/* Dequeue packets from Crypto device */
929 			do {
930 				nb_rx = rte_cryptodev_dequeue_burst(
931 						cparams->dev_id, cparams->qp_id,
932 						ops_burst, MAX_PKT_BURST);
933 
934 				crypto_statistics[cparams->dev_id].dequeued +=
935 						nb_rx;
936 
937 				/* Forward crypto'd packets */
938 				for (j = 0; j < nb_rx; j++) {
939 					m = ops_burst[j]->sym->m_src;
940 
941 					rte_crypto_op_free(ops_burst[j]);
942 					l2fwd_simple_forward(m, portid,
943 							options);
944 				}
945 			} while (nb_rx == MAX_PKT_BURST);
946 		}
947 	}
948 }
949 
950 static int
951 l2fwd_launch_one_lcore(void *arg)
952 {
953 	l2fwd_main_loop((struct l2fwd_crypto_options *)arg);
954 	return 0;
955 }
956 
957 /* Display command line arguments usage */
958 static void
959 l2fwd_crypto_usage(const char *prgname)
960 {
961 	printf("%s [EAL options] --\n"
962 		"  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
963 		"  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
964 		"  -s manage all ports from single lcore\n"
965 		"  -T PERIOD: statistics will be refreshed each PERIOD seconds"
966 		" (0 to disable, 10 default, 86400 maximum)\n"
967 
968 		"  --cdev_type HW / SW / ANY\n"
969 		"  --chain HASH_CIPHER / CIPHER_HASH / CIPHER_ONLY /"
970 		" HASH_ONLY / AEAD\n"
971 
972 		"  --cipher_algo ALGO\n"
973 		"  --cipher_op ENCRYPT / DECRYPT\n"
974 		"  --cipher_key KEY (bytes separated with \":\")\n"
975 		"  --cipher_key_random_size SIZE: size of cipher key when generated randomly\n"
976 		"  --cipher_iv IV (bytes separated with \":\")\n"
977 		"  --cipher_iv_random_size SIZE: size of cipher IV when generated randomly\n"
978 
979 		"  --auth_algo ALGO\n"
980 		"  --auth_op GENERATE / VERIFY\n"
981 		"  --auth_key KEY (bytes separated with \":\")\n"
982 		"  --auth_key_random_size SIZE: size of auth key when generated randomly\n"
983 		"  --auth_iv IV (bytes separated with \":\")\n"
984 		"  --auth_iv_random_size SIZE: size of auth IV when generated randomly\n"
985 
986 		"  --aead_algo ALGO\n"
987 		"  --aead_op ENCRYPT / DECRYPT\n"
988 		"  --aead_key KEY (bytes separated with \":\")\n"
989 		"  --aead_key_random_size SIZE: size of AEAD key when generated randomly\n"
990 		"  --aead_iv IV (bytes separated with \":\")\n"
991 		"  --aead_iv_random_size SIZE: size of AEAD IV when generated randomly\n"
992 		"  --aad AAD (bytes separated with \":\")\n"
993 		"  --aad_random_size SIZE: size of AAD when generated randomly\n"
994 
995 		"  --digest_size SIZE: size of digest to be generated/verified\n"
996 
997 		"  --sessionless\n"
998 		"  --cryptodev_mask MASK: hexadecimal bitmask of crypto devices to configure\n"
999 
1000 		"  --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n"
1001 		"      When enabled:\n"
1002 		"       - The source MAC address is replaced by the TX port MAC address\n"
1003 		"       - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n",
1004 	       prgname);
1005 }
1006 
1007 /** Parse crypto device type command line argument */
1008 static int
1009 parse_cryptodev_type(enum cdev_type *type, char *optarg)
1010 {
1011 	if (strcmp("HW", optarg) == 0) {
1012 		*type = CDEV_TYPE_HW;
1013 		return 0;
1014 	} else if (strcmp("SW", optarg) == 0) {
1015 		*type = CDEV_TYPE_SW;
1016 		return 0;
1017 	} else if (strcmp("ANY", optarg) == 0) {
1018 		*type = CDEV_TYPE_ANY;
1019 		return 0;
1020 	}
1021 
1022 	return -1;
1023 }
1024 
1025 /** Parse crypto chain xform command line argument */
1026 static int
1027 parse_crypto_opt_chain(struct l2fwd_crypto_options *options, char *optarg)
1028 {
1029 	if (strcmp("CIPHER_HASH", optarg) == 0) {
1030 		options->xform_chain = L2FWD_CRYPTO_CIPHER_HASH;
1031 		return 0;
1032 	} else if (strcmp("HASH_CIPHER", optarg) == 0) {
1033 		options->xform_chain = L2FWD_CRYPTO_HASH_CIPHER;
1034 		return 0;
1035 	} else if (strcmp("CIPHER_ONLY", optarg) == 0) {
1036 		options->xform_chain = L2FWD_CRYPTO_CIPHER_ONLY;
1037 		return 0;
1038 	} else if (strcmp("HASH_ONLY", optarg) == 0) {
1039 		options->xform_chain = L2FWD_CRYPTO_HASH_ONLY;
1040 		return 0;
1041 	} else if (strcmp("AEAD", optarg) == 0) {
1042 		options->xform_chain = L2FWD_CRYPTO_AEAD;
1043 		return 0;
1044 	}
1045 
1046 	return -1;
1047 }
1048 
1049 /** Parse crypto cipher algo option command line argument */
1050 static int
1051 parse_cipher_algo(enum rte_crypto_cipher_algorithm *algo, char *optarg)
1052 {
1053 
1054 	if (rte_cryptodev_get_cipher_algo_enum(algo, optarg) < 0) {
1055 		RTE_LOG(ERR, USER1, "Cipher algorithm specified "
1056 				"not supported!\n");
1057 		return -1;
1058 	}
1059 
1060 	return 0;
1061 }
1062 
1063 /** Parse crypto cipher operation command line argument */
1064 static int
1065 parse_cipher_op(enum rte_crypto_cipher_operation *op, char *optarg)
1066 {
1067 	if (strcmp("ENCRYPT", optarg) == 0) {
1068 		*op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
1069 		return 0;
1070 	} else if (strcmp("DECRYPT", optarg) == 0) {
1071 		*op = RTE_CRYPTO_CIPHER_OP_DECRYPT;
1072 		return 0;
1073 	}
1074 
1075 	printf("Cipher operation not supported!\n");
1076 	return -1;
1077 }
1078 
1079 /** Parse crypto key command line argument */
1080 static int
1081 parse_key(uint8_t *data, char *input_arg)
1082 {
1083 	unsigned byte_count;
1084 	char *token;
1085 
1086 	for (byte_count = 0, token = strtok(input_arg, ":");
1087 			(byte_count < MAX_KEY_SIZE) && (token != NULL);
1088 			token = strtok(NULL, ":")) {
1089 
1090 		int number = (int)strtol(token, NULL, 16);
1091 
1092 		if (errno == EINVAL || errno == ERANGE || number > 0xFF)
1093 			return -1;
1094 
1095 		data[byte_count++] = (uint8_t)number;
1096 	}
1097 
1098 	return byte_count;
1099 }
1100 
1101 /** Parse size param*/
1102 static int
1103 parse_size(int *size, const char *q_arg)
1104 {
1105 	char *end = NULL;
1106 	unsigned long n;
1107 
1108 	/* parse hexadecimal string */
1109 	n = strtoul(q_arg, &end, 10);
1110 	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
1111 		n = 0;
1112 
1113 	if (n == 0) {
1114 		printf("invalid size\n");
1115 		return -1;
1116 	}
1117 
1118 	*size = n;
1119 	return 0;
1120 }
1121 
1122 /** Parse crypto cipher operation command line argument */
1123 static int
1124 parse_auth_algo(enum rte_crypto_auth_algorithm *algo, char *optarg)
1125 {
1126 	if (rte_cryptodev_get_auth_algo_enum(algo, optarg) < 0) {
1127 		RTE_LOG(ERR, USER1, "Authentication algorithm specified "
1128 				"not supported!\n");
1129 		return -1;
1130 	}
1131 
1132 	return 0;
1133 }
1134 
1135 static int
1136 parse_auth_op(enum rte_crypto_auth_operation *op, char *optarg)
1137 {
1138 	if (strcmp("VERIFY", optarg) == 0) {
1139 		*op = RTE_CRYPTO_AUTH_OP_VERIFY;
1140 		return 0;
1141 	} else if (strcmp("GENERATE", optarg) == 0) {
1142 		*op = RTE_CRYPTO_AUTH_OP_GENERATE;
1143 		return 0;
1144 	}
1145 
1146 	printf("Authentication operation specified not supported!\n");
1147 	return -1;
1148 }
1149 
1150 static int
1151 parse_aead_algo(enum rte_crypto_aead_algorithm *algo, char *optarg)
1152 {
1153 	if (rte_cryptodev_get_aead_algo_enum(algo, optarg) < 0) {
1154 		RTE_LOG(ERR, USER1, "AEAD algorithm specified "
1155 				"not supported!\n");
1156 		return -1;
1157 	}
1158 
1159 	return 0;
1160 }
1161 
1162 static int
1163 parse_aead_op(enum rte_crypto_aead_operation *op, char *optarg)
1164 {
1165 	if (strcmp("ENCRYPT", optarg) == 0) {
1166 		*op = RTE_CRYPTO_AEAD_OP_ENCRYPT;
1167 		return 0;
1168 	} else if (strcmp("DECRYPT", optarg) == 0) {
1169 		*op = RTE_CRYPTO_AEAD_OP_DECRYPT;
1170 		return 0;
1171 	}
1172 
1173 	printf("AEAD operation specified not supported!\n");
1174 	return -1;
1175 }
1176 static int
1177 parse_cryptodev_mask(struct l2fwd_crypto_options *options,
1178 		const char *q_arg)
1179 {
1180 	char *end = NULL;
1181 	uint64_t pm;
1182 
1183 	/* parse hexadecimal string */
1184 	pm = strtoul(q_arg, &end, 16);
1185 	if ((pm == '\0') || (end == NULL) || (*end != '\0'))
1186 		pm = 0;
1187 
1188 	options->cryptodev_mask = pm;
1189 	if (options->cryptodev_mask == 0) {
1190 		printf("invalid cryptodev_mask specified\n");
1191 		return -1;
1192 	}
1193 
1194 	return 0;
1195 }
1196 
1197 /** Parse long options */
1198 static int
1199 l2fwd_crypto_parse_args_long_options(struct l2fwd_crypto_options *options,
1200 		struct option *lgopts, int option_index)
1201 {
1202 	int retval;
1203 
1204 	if (strcmp(lgopts[option_index].name, "cdev_type") == 0) {
1205 		retval = parse_cryptodev_type(&options->type, optarg);
1206 		if (retval == 0)
1207 			snprintf(options->string_type, MAX_STR_LEN,
1208 				"%s", optarg);
1209 		return retval;
1210 	}
1211 
1212 	else if (strcmp(lgopts[option_index].name, "chain") == 0)
1213 		return parse_crypto_opt_chain(options, optarg);
1214 
1215 	/* Cipher options */
1216 	else if (strcmp(lgopts[option_index].name, "cipher_algo") == 0)
1217 		return parse_cipher_algo(&options->cipher_xform.cipher.algo,
1218 				optarg);
1219 
1220 	else if (strcmp(lgopts[option_index].name, "cipher_op") == 0)
1221 		return parse_cipher_op(&options->cipher_xform.cipher.op,
1222 				optarg);
1223 
1224 	else if (strcmp(lgopts[option_index].name, "cipher_key") == 0) {
1225 		options->ckey_param = 1;
1226 		options->cipher_xform.cipher.key.length =
1227 			parse_key(options->cipher_xform.cipher.key.data, optarg);
1228 		if (options->cipher_xform.cipher.key.length > 0)
1229 			return 0;
1230 		else
1231 			return -1;
1232 	}
1233 
1234 	else if (strcmp(lgopts[option_index].name, "cipher_key_random_size") == 0)
1235 		return parse_size(&options->ckey_random_size, optarg);
1236 
1237 	else if (strcmp(lgopts[option_index].name, "cipher_iv") == 0) {
1238 		options->cipher_iv_param = 1;
1239 		options->cipher_iv.length =
1240 			parse_key(options->cipher_iv.data, optarg);
1241 		if (options->cipher_iv.length > 0)
1242 			return 0;
1243 		else
1244 			return -1;
1245 	}
1246 
1247 	else if (strcmp(lgopts[option_index].name, "cipher_iv_random_size") == 0)
1248 		return parse_size(&options->cipher_iv_random_size, optarg);
1249 
1250 	/* Authentication options */
1251 	else if (strcmp(lgopts[option_index].name, "auth_algo") == 0) {
1252 		return parse_auth_algo(&options->auth_xform.auth.algo,
1253 				optarg);
1254 	}
1255 
1256 	else if (strcmp(lgopts[option_index].name, "auth_op") == 0)
1257 		return parse_auth_op(&options->auth_xform.auth.op,
1258 				optarg);
1259 
1260 	else if (strcmp(lgopts[option_index].name, "auth_key") == 0) {
1261 		options->akey_param = 1;
1262 		options->auth_xform.auth.key.length =
1263 			parse_key(options->auth_xform.auth.key.data, optarg);
1264 		if (options->auth_xform.auth.key.length > 0)
1265 			return 0;
1266 		else
1267 			return -1;
1268 	}
1269 
1270 	else if (strcmp(lgopts[option_index].name, "auth_key_random_size") == 0) {
1271 		return parse_size(&options->akey_random_size, optarg);
1272 	}
1273 
1274 	else if (strcmp(lgopts[option_index].name, "auth_iv") == 0) {
1275 		options->auth_iv_param = 1;
1276 		options->auth_iv.length =
1277 			parse_key(options->auth_iv.data, optarg);
1278 		if (options->auth_iv.length > 0)
1279 			return 0;
1280 		else
1281 			return -1;
1282 	}
1283 
1284 	else if (strcmp(lgopts[option_index].name, "auth_iv_random_size") == 0)
1285 		return parse_size(&options->auth_iv_random_size, optarg);
1286 
1287 	/* AEAD options */
1288 	else if (strcmp(lgopts[option_index].name, "aead_algo") == 0) {
1289 		return parse_aead_algo(&options->aead_xform.aead.algo,
1290 				optarg);
1291 	}
1292 
1293 	else if (strcmp(lgopts[option_index].name, "aead_op") == 0)
1294 		return parse_aead_op(&options->aead_xform.aead.op,
1295 				optarg);
1296 
1297 	else if (strcmp(lgopts[option_index].name, "aead_key") == 0) {
1298 		options->aead_key_param = 1;
1299 		options->aead_xform.aead.key.length =
1300 			parse_key(options->aead_xform.aead.key.data, optarg);
1301 		if (options->aead_xform.aead.key.length > 0)
1302 			return 0;
1303 		else
1304 			return -1;
1305 	}
1306 
1307 	else if (strcmp(lgopts[option_index].name, "aead_key_random_size") == 0)
1308 		return parse_size(&options->aead_key_random_size, optarg);
1309 
1310 
1311 	else if (strcmp(lgopts[option_index].name, "aead_iv") == 0) {
1312 		options->aead_iv_param = 1;
1313 		options->aead_iv.length =
1314 			parse_key(options->aead_iv.data, optarg);
1315 		if (options->aead_iv.length > 0)
1316 			return 0;
1317 		else
1318 			return -1;
1319 	}
1320 
1321 	else if (strcmp(lgopts[option_index].name, "aead_iv_random_size") == 0)
1322 		return parse_size(&options->aead_iv_random_size, optarg);
1323 
1324 	else if (strcmp(lgopts[option_index].name, "aad") == 0) {
1325 		options->aad_param = 1;
1326 		options->aad.length =
1327 			parse_key(options->aad.data, optarg);
1328 		if (options->aad.length > 0)
1329 			return 0;
1330 		else
1331 			return -1;
1332 	}
1333 
1334 	else if (strcmp(lgopts[option_index].name, "aad_random_size") == 0) {
1335 		return parse_size(&options->aad_random_size, optarg);
1336 	}
1337 
1338 	else if (strcmp(lgopts[option_index].name, "digest_size") == 0) {
1339 		return parse_size(&options->digest_size, optarg);
1340 	}
1341 
1342 	else if (strcmp(lgopts[option_index].name, "sessionless") == 0) {
1343 		options->sessionless = 1;
1344 		return 0;
1345 	}
1346 
1347 	else if (strcmp(lgopts[option_index].name, "cryptodev_mask") == 0)
1348 		return parse_cryptodev_mask(options, optarg);
1349 
1350 	else if (strcmp(lgopts[option_index].name, "mac-updating") == 0) {
1351 		options->mac_updating = 1;
1352 		return 0;
1353 	}
1354 
1355 	else if (strcmp(lgopts[option_index].name, "no-mac-updating") == 0) {
1356 		options->mac_updating = 0;
1357 		return 0;
1358 	}
1359 
1360 	return -1;
1361 }
1362 
1363 /** Parse port mask */
1364 static int
1365 l2fwd_crypto_parse_portmask(struct l2fwd_crypto_options *options,
1366 		const char *q_arg)
1367 {
1368 	char *end = NULL;
1369 	unsigned long pm;
1370 
1371 	/* parse hexadecimal string */
1372 	pm = strtoul(q_arg, &end, 16);
1373 	if ((pm == '\0') || (end == NULL) || (*end != '\0'))
1374 		pm = 0;
1375 
1376 	options->portmask = pm;
1377 	if (options->portmask == 0) {
1378 		printf("invalid portmask specified\n");
1379 		return -1;
1380 	}
1381 
1382 	return pm;
1383 }
1384 
1385 /** Parse number of queues */
1386 static int
1387 l2fwd_crypto_parse_nqueue(struct l2fwd_crypto_options *options,
1388 		const char *q_arg)
1389 {
1390 	char *end = NULL;
1391 	unsigned long n;
1392 
1393 	/* parse hexadecimal string */
1394 	n = strtoul(q_arg, &end, 10);
1395 	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
1396 		n = 0;
1397 	else if (n >= MAX_RX_QUEUE_PER_LCORE)
1398 		n = 0;
1399 
1400 	options->nb_ports_per_lcore = n;
1401 	if (options->nb_ports_per_lcore == 0) {
1402 		printf("invalid number of ports selected\n");
1403 		return -1;
1404 	}
1405 
1406 	return 0;
1407 }
1408 
1409 /** Parse timer period */
1410 static int
1411 l2fwd_crypto_parse_timer_period(struct l2fwd_crypto_options *options,
1412 		const char *q_arg)
1413 {
1414 	char *end = NULL;
1415 	unsigned long n;
1416 
1417 	/* parse number string */
1418 	n = (unsigned)strtol(q_arg, &end, 10);
1419 	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
1420 		n = 0;
1421 
1422 	if (n >= MAX_TIMER_PERIOD) {
1423 		printf("Warning refresh period specified %lu is greater than "
1424 				"max value %lu! using max value",
1425 				n, MAX_TIMER_PERIOD);
1426 		n = MAX_TIMER_PERIOD;
1427 	}
1428 
1429 	options->refresh_period = n * 1000 * TIMER_MILLISECOND;
1430 
1431 	return 0;
1432 }
1433 
1434 /** Generate default options for application */
1435 static void
1436 l2fwd_crypto_default_options(struct l2fwd_crypto_options *options)
1437 {
1438 	options->portmask = 0xffffffff;
1439 	options->nb_ports_per_lcore = 1;
1440 	options->refresh_period = 10000;
1441 	options->single_lcore = 0;
1442 	options->sessionless = 0;
1443 
1444 	options->xform_chain = L2FWD_CRYPTO_CIPHER_HASH;
1445 
1446 	/* Cipher Data */
1447 	options->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
1448 	options->cipher_xform.next = NULL;
1449 	options->ckey_param = 0;
1450 	options->ckey_random_size = -1;
1451 	options->cipher_xform.cipher.key.length = 0;
1452 	options->cipher_iv_param = 0;
1453 	options->cipher_iv_random_size = -1;
1454 	options->cipher_iv.length = 0;
1455 
1456 	options->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_AES_CBC;
1457 	options->cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
1458 
1459 	/* Authentication Data */
1460 	options->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH;
1461 	options->auth_xform.next = NULL;
1462 	options->akey_param = 0;
1463 	options->akey_random_size = -1;
1464 	options->auth_xform.auth.key.length = 0;
1465 	options->auth_iv_param = 0;
1466 	options->auth_iv_random_size = -1;
1467 	options->auth_iv.length = 0;
1468 
1469 	options->auth_xform.auth.algo = RTE_CRYPTO_AUTH_SHA1_HMAC;
1470 	options->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
1471 
1472 	/* AEAD Data */
1473 	options->aead_xform.type = RTE_CRYPTO_SYM_XFORM_AEAD;
1474 	options->aead_xform.next = NULL;
1475 	options->aead_key_param = 0;
1476 	options->aead_key_random_size = -1;
1477 	options->aead_xform.aead.key.length = 0;
1478 	options->aead_iv_param = 0;
1479 	options->aead_iv_random_size = -1;
1480 	options->aead_iv.length = 0;
1481 
1482 	options->auth_xform.aead.algo = RTE_CRYPTO_AEAD_AES_GCM;
1483 	options->auth_xform.aead.op = RTE_CRYPTO_AEAD_OP_ENCRYPT;
1484 
1485 	options->aad_param = 0;
1486 	options->aad_random_size = -1;
1487 	options->aad.length = 0;
1488 
1489 	options->digest_size = -1;
1490 
1491 	options->type = CDEV_TYPE_ANY;
1492 	options->cryptodev_mask = UINT64_MAX;
1493 
1494 	options->mac_updating = 1;
1495 }
1496 
1497 static void
1498 display_cipher_info(struct l2fwd_crypto_options *options)
1499 {
1500 	printf("\n---- Cipher information ---\n");
1501 	printf("Algorithm: %s\n",
1502 		rte_crypto_cipher_algorithm_strings[options->cipher_xform.cipher.algo]);
1503 	rte_hexdump(stdout, "Cipher key:",
1504 			options->cipher_xform.cipher.key.data,
1505 			options->cipher_xform.cipher.key.length);
1506 	rte_hexdump(stdout, "IV:", options->cipher_iv.data, options->cipher_iv.length);
1507 }
1508 
1509 static void
1510 display_auth_info(struct l2fwd_crypto_options *options)
1511 {
1512 	printf("\n---- Authentication information ---\n");
1513 	printf("Algorithm: %s\n",
1514 		rte_crypto_auth_algorithm_strings[options->auth_xform.auth.algo]);
1515 	rte_hexdump(stdout, "Auth key:",
1516 			options->auth_xform.auth.key.data,
1517 			options->auth_xform.auth.key.length);
1518 	rte_hexdump(stdout, "IV:", options->auth_iv.data, options->auth_iv.length);
1519 }
1520 
1521 static void
1522 display_aead_info(struct l2fwd_crypto_options *options)
1523 {
1524 	printf("\n---- AEAD information ---\n");
1525 	printf("Algorithm: %s\n",
1526 		rte_crypto_aead_algorithm_strings[options->aead_xform.aead.algo]);
1527 	rte_hexdump(stdout, "AEAD key:",
1528 			options->aead_xform.aead.key.data,
1529 			options->aead_xform.aead.key.length);
1530 	rte_hexdump(stdout, "IV:", options->aead_iv.data, options->aead_iv.length);
1531 	rte_hexdump(stdout, "AAD:", options->aad.data, options->aad.length);
1532 }
1533 
1534 static void
1535 l2fwd_crypto_options_print(struct l2fwd_crypto_options *options)
1536 {
1537 	char string_cipher_op[MAX_STR_LEN];
1538 	char string_auth_op[MAX_STR_LEN];
1539 	char string_aead_op[MAX_STR_LEN];
1540 
1541 	if (options->cipher_xform.cipher.op == RTE_CRYPTO_CIPHER_OP_ENCRYPT)
1542 		strcpy(string_cipher_op, "Encrypt");
1543 	else
1544 		strcpy(string_cipher_op, "Decrypt");
1545 
1546 	if (options->auth_xform.auth.op == RTE_CRYPTO_AUTH_OP_GENERATE)
1547 		strcpy(string_auth_op, "Auth generate");
1548 	else
1549 		strcpy(string_auth_op, "Auth verify");
1550 
1551 	if (options->aead_xform.aead.op == RTE_CRYPTO_AEAD_OP_ENCRYPT)
1552 		strcpy(string_aead_op, "Authenticated encryption");
1553 	else
1554 		strcpy(string_aead_op, "Authenticated decryption");
1555 
1556 
1557 	printf("Options:-\nn");
1558 	printf("portmask: %x\n", options->portmask);
1559 	printf("ports per lcore: %u\n", options->nb_ports_per_lcore);
1560 	printf("refresh period : %u\n", options->refresh_period);
1561 	printf("single lcore mode: %s\n",
1562 			options->single_lcore ? "enabled" : "disabled");
1563 	printf("stats_printing: %s\n",
1564 			options->refresh_period == 0 ? "disabled" : "enabled");
1565 
1566 	printf("sessionless crypto: %s\n",
1567 			options->sessionless ? "enabled" : "disabled");
1568 
1569 	if (options->ckey_param && (options->ckey_random_size != -1))
1570 		printf("Cipher key already parsed, ignoring size of random key\n");
1571 
1572 	if (options->akey_param && (options->akey_random_size != -1))
1573 		printf("Auth key already parsed, ignoring size of random key\n");
1574 
1575 	if (options->cipher_iv_param && (options->cipher_iv_random_size != -1))
1576 		printf("Cipher IV already parsed, ignoring size of random IV\n");
1577 
1578 	if (options->auth_iv_param && (options->auth_iv_random_size != -1))
1579 		printf("Auth IV already parsed, ignoring size of random IV\n");
1580 
1581 	if (options->aad_param && (options->aad_random_size != -1))
1582 		printf("AAD already parsed, ignoring size of random AAD\n");
1583 
1584 	printf("\nCrypto chain: ");
1585 	switch (options->xform_chain) {
1586 	case L2FWD_CRYPTO_AEAD:
1587 		printf("Input --> %s --> Output\n", string_aead_op);
1588 		display_aead_info(options);
1589 		break;
1590 	case L2FWD_CRYPTO_CIPHER_HASH:
1591 		printf("Input --> %s --> %s --> Output\n",
1592 			string_cipher_op, string_auth_op);
1593 		display_cipher_info(options);
1594 		display_auth_info(options);
1595 		break;
1596 	case L2FWD_CRYPTO_HASH_CIPHER:
1597 		printf("Input --> %s --> %s --> Output\n",
1598 			string_auth_op, string_cipher_op);
1599 		display_cipher_info(options);
1600 		display_auth_info(options);
1601 		break;
1602 	case L2FWD_CRYPTO_HASH_ONLY:
1603 		printf("Input --> %s --> Output\n", string_auth_op);
1604 		display_auth_info(options);
1605 		break;
1606 	case L2FWD_CRYPTO_CIPHER_ONLY:
1607 		printf("Input --> %s --> Output\n", string_cipher_op);
1608 		display_cipher_info(options);
1609 		break;
1610 	}
1611 }
1612 
1613 /* Parse the argument given in the command line of the application */
1614 static int
1615 l2fwd_crypto_parse_args(struct l2fwd_crypto_options *options,
1616 		int argc, char **argv)
1617 {
1618 	int opt, retval, option_index;
1619 	char **argvopt = argv, *prgname = argv[0];
1620 
1621 	static struct option lgopts[] = {
1622 			{ "sessionless", no_argument, 0, 0 },
1623 
1624 			{ "cdev_type", required_argument, 0, 0 },
1625 			{ "chain", required_argument, 0, 0 },
1626 
1627 			{ "cipher_algo", required_argument, 0, 0 },
1628 			{ "cipher_op", required_argument, 0, 0 },
1629 			{ "cipher_key", required_argument, 0, 0 },
1630 			{ "cipher_key_random_size", required_argument, 0, 0 },
1631 			{ "cipher_iv", required_argument, 0, 0 },
1632 			{ "cipher_iv_random_size", required_argument, 0, 0 },
1633 
1634 			{ "auth_algo", required_argument, 0, 0 },
1635 			{ "auth_op", required_argument, 0, 0 },
1636 			{ "auth_key", required_argument, 0, 0 },
1637 			{ "auth_key_random_size", required_argument, 0, 0 },
1638 			{ "auth_iv", required_argument, 0, 0 },
1639 			{ "auth_iv_random_size", required_argument, 0, 0 },
1640 
1641 			{ "aead_algo", required_argument, 0, 0 },
1642 			{ "aead_op", required_argument, 0, 0 },
1643 			{ "aead_key", required_argument, 0, 0 },
1644 			{ "aead_key_random_size", required_argument, 0, 0 },
1645 			{ "aead_iv", required_argument, 0, 0 },
1646 			{ "aead_iv_random_size", required_argument, 0, 0 },
1647 
1648 			{ "aad", required_argument, 0, 0 },
1649 			{ "aad_random_size", required_argument, 0, 0 },
1650 
1651 			{ "digest_size", required_argument, 0, 0 },
1652 
1653 			{ "sessionless", no_argument, 0, 0 },
1654 			{ "cryptodev_mask", required_argument, 0, 0},
1655 
1656 			{ "mac-updating", no_argument, 0, 0},
1657 			{ "no-mac-updating", no_argument, 0, 0},
1658 
1659 			{ NULL, 0, 0, 0 }
1660 	};
1661 
1662 	l2fwd_crypto_default_options(options);
1663 
1664 	while ((opt = getopt_long(argc, argvopt, "p:q:sT:", lgopts,
1665 			&option_index)) != EOF) {
1666 		switch (opt) {
1667 		/* long options */
1668 		case 0:
1669 			retval = l2fwd_crypto_parse_args_long_options(options,
1670 					lgopts, option_index);
1671 			if (retval < 0) {
1672 				l2fwd_crypto_usage(prgname);
1673 				return -1;
1674 			}
1675 			break;
1676 
1677 		/* portmask */
1678 		case 'p':
1679 			retval = l2fwd_crypto_parse_portmask(options, optarg);
1680 			if (retval < 0) {
1681 				l2fwd_crypto_usage(prgname);
1682 				return -1;
1683 			}
1684 			break;
1685 
1686 		/* nqueue */
1687 		case 'q':
1688 			retval = l2fwd_crypto_parse_nqueue(options, optarg);
1689 			if (retval < 0) {
1690 				l2fwd_crypto_usage(prgname);
1691 				return -1;
1692 			}
1693 			break;
1694 
1695 		/* single  */
1696 		case 's':
1697 			options->single_lcore = 1;
1698 
1699 			break;
1700 
1701 		/* timer period */
1702 		case 'T':
1703 			retval = l2fwd_crypto_parse_timer_period(options,
1704 					optarg);
1705 			if (retval < 0) {
1706 				l2fwd_crypto_usage(prgname);
1707 				return -1;
1708 			}
1709 			break;
1710 
1711 		default:
1712 			l2fwd_crypto_usage(prgname);
1713 			return -1;
1714 		}
1715 	}
1716 
1717 
1718 	if (optind >= 0)
1719 		argv[optind-1] = prgname;
1720 
1721 	retval = optind-1;
1722 	optind = 1; /* reset getopt lib */
1723 
1724 	return retval;
1725 }
1726 
1727 /* Check the link status of all ports in up to 9s, and print them finally */
1728 static void
1729 check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
1730 {
1731 #define CHECK_INTERVAL 100 /* 100ms */
1732 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
1733 	uint8_t portid, count, all_ports_up, print_flag = 0;
1734 	struct rte_eth_link link;
1735 
1736 	printf("\nChecking link status");
1737 	fflush(stdout);
1738 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
1739 		all_ports_up = 1;
1740 		for (portid = 0; portid < port_num; portid++) {
1741 			if ((port_mask & (1 << portid)) == 0)
1742 				continue;
1743 			memset(&link, 0, sizeof(link));
1744 			rte_eth_link_get_nowait(portid, &link);
1745 			/* print link status if flag set */
1746 			if (print_flag == 1) {
1747 				if (link.link_status)
1748 					printf("Port %d Link Up - speed %u "
1749 						"Mbps - %s\n", (uint8_t)portid,
1750 						(unsigned)link.link_speed,
1751 				(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
1752 					("full-duplex") : ("half-duplex\n"));
1753 				else
1754 					printf("Port %d Link Down\n",
1755 						(uint8_t)portid);
1756 				continue;
1757 			}
1758 			/* clear all_ports_up flag if any link down */
1759 			if (link.link_status == ETH_LINK_DOWN) {
1760 				all_ports_up = 0;
1761 				break;
1762 			}
1763 		}
1764 		/* after finally printing all link status, get out */
1765 		if (print_flag == 1)
1766 			break;
1767 
1768 		if (all_ports_up == 0) {
1769 			printf(".");
1770 			fflush(stdout);
1771 			rte_delay_ms(CHECK_INTERVAL);
1772 		}
1773 
1774 		/* set the print_flag if all ports up or timeout */
1775 		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
1776 			print_flag = 1;
1777 			printf("done\n");
1778 		}
1779 	}
1780 }
1781 
1782 /* Check if device has to be HW/SW or any */
1783 static int
1784 check_type(const struct l2fwd_crypto_options *options,
1785 		const struct rte_cryptodev_info *dev_info)
1786 {
1787 	if (options->type == CDEV_TYPE_HW &&
1788 			(dev_info->feature_flags & RTE_CRYPTODEV_FF_HW_ACCELERATED))
1789 		return 0;
1790 	if (options->type == CDEV_TYPE_SW &&
1791 			!(dev_info->feature_flags & RTE_CRYPTODEV_FF_HW_ACCELERATED))
1792 		return 0;
1793 	if (options->type == CDEV_TYPE_ANY)
1794 		return 0;
1795 
1796 	return -1;
1797 }
1798 
1799 static const struct rte_cryptodev_capabilities *
1800 check_device_support_cipher_algo(const struct l2fwd_crypto_options *options,
1801 		const struct rte_cryptodev_info *dev_info,
1802 		uint8_t cdev_id)
1803 {
1804 	unsigned int i = 0;
1805 	const struct rte_cryptodev_capabilities *cap = &dev_info->capabilities[0];
1806 	enum rte_crypto_cipher_algorithm cap_cipher_algo;
1807 	enum rte_crypto_cipher_algorithm opt_cipher_algo =
1808 					options->cipher_xform.cipher.algo;
1809 
1810 	while (cap->op != RTE_CRYPTO_OP_TYPE_UNDEFINED) {
1811 		cap_cipher_algo = cap->sym.cipher.algo;
1812 		if (cap->sym.xform_type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
1813 			if (cap_cipher_algo == opt_cipher_algo) {
1814 				if (check_type(options, dev_info) == 0)
1815 					break;
1816 			}
1817 		}
1818 		cap = &dev_info->capabilities[++i];
1819 	}
1820 
1821 	if (cap->op == RTE_CRYPTO_OP_TYPE_UNDEFINED) {
1822 		printf("Algorithm %s not supported by cryptodev %u"
1823 			" or device not of preferred type (%s)\n",
1824 			rte_crypto_cipher_algorithm_strings[opt_cipher_algo],
1825 			cdev_id,
1826 			options->string_type);
1827 		return NULL;
1828 	}
1829 
1830 	return cap;
1831 }
1832 
1833 static const struct rte_cryptodev_capabilities *
1834 check_device_support_auth_algo(const struct l2fwd_crypto_options *options,
1835 		const struct rte_cryptodev_info *dev_info,
1836 		uint8_t cdev_id)
1837 {
1838 	unsigned int i = 0;
1839 	const struct rte_cryptodev_capabilities *cap = &dev_info->capabilities[0];
1840 	enum rte_crypto_auth_algorithm cap_auth_algo;
1841 	enum rte_crypto_auth_algorithm opt_auth_algo =
1842 					options->auth_xform.auth.algo;
1843 
1844 	while (cap->op != RTE_CRYPTO_OP_TYPE_UNDEFINED) {
1845 		cap_auth_algo = cap->sym.auth.algo;
1846 		if (cap->sym.xform_type == RTE_CRYPTO_SYM_XFORM_AUTH) {
1847 			if (cap_auth_algo == opt_auth_algo) {
1848 				if (check_type(options, dev_info) == 0)
1849 					break;
1850 			}
1851 		}
1852 		cap = &dev_info->capabilities[++i];
1853 	}
1854 
1855 	if (cap->op == RTE_CRYPTO_OP_TYPE_UNDEFINED) {
1856 		printf("Algorithm %s not supported by cryptodev %u"
1857 			" or device not of preferred type (%s)\n",
1858 			rte_crypto_auth_algorithm_strings[opt_auth_algo],
1859 			cdev_id,
1860 			options->string_type);
1861 		return NULL;
1862 	}
1863 
1864 	return cap;
1865 }
1866 
1867 static const struct rte_cryptodev_capabilities *
1868 check_device_support_aead_algo(const struct l2fwd_crypto_options *options,
1869 		const struct rte_cryptodev_info *dev_info,
1870 		uint8_t cdev_id)
1871 {
1872 	unsigned int i = 0;
1873 	const struct rte_cryptodev_capabilities *cap = &dev_info->capabilities[0];
1874 	enum rte_crypto_aead_algorithm cap_aead_algo;
1875 	enum rte_crypto_aead_algorithm opt_aead_algo =
1876 					options->aead_xform.aead.algo;
1877 
1878 	while (cap->op != RTE_CRYPTO_OP_TYPE_UNDEFINED) {
1879 		cap_aead_algo = cap->sym.aead.algo;
1880 		if (cap->sym.xform_type == RTE_CRYPTO_SYM_XFORM_AEAD) {
1881 			if (cap_aead_algo == opt_aead_algo) {
1882 				if (check_type(options, dev_info) == 0)
1883 					break;
1884 			}
1885 		}
1886 		cap = &dev_info->capabilities[++i];
1887 	}
1888 
1889 	if (cap->op == RTE_CRYPTO_OP_TYPE_UNDEFINED) {
1890 		printf("Algorithm %s not supported by cryptodev %u"
1891 			" or device not of preferred type (%s)\n",
1892 			rte_crypto_aead_algorithm_strings[opt_aead_algo],
1893 			cdev_id,
1894 			options->string_type);
1895 		return NULL;
1896 	}
1897 
1898 	return cap;
1899 }
1900 
1901 /* Check if the device is enabled by cryptodev_mask */
1902 static int
1903 check_cryptodev_mask(struct l2fwd_crypto_options *options,
1904 		uint8_t cdev_id)
1905 {
1906 	if (options->cryptodev_mask & (1 << cdev_id))
1907 		return 0;
1908 
1909 	return -1;
1910 }
1911 
1912 static inline int
1913 check_supported_size(uint16_t length, uint16_t min, uint16_t max,
1914 		uint16_t increment)
1915 {
1916 	uint16_t supp_size;
1917 
1918 	/* Single value */
1919 	if (increment == 0) {
1920 		if (length == min)
1921 			return 0;
1922 		else
1923 			return -1;
1924 	}
1925 
1926 	/* Range of values */
1927 	for (supp_size = min; supp_size <= max; supp_size += increment) {
1928 		if (length == supp_size)
1929 			return 0;
1930 	}
1931 
1932 	return -1;
1933 }
1934 
1935 static int
1936 check_iv_param(const struct rte_crypto_param_range *iv_range_size,
1937 		unsigned int iv_param, int iv_random_size,
1938 		uint16_t *iv_length)
1939 {
1940 	/*
1941 	 * Check if length of provided IV is supported
1942 	 * by the algorithm chosen.
1943 	 */
1944 	if (iv_param) {
1945 		if (check_supported_size(*iv_length,
1946 				iv_range_size->min,
1947 				iv_range_size->max,
1948 				iv_range_size->increment)
1949 					!= 0) {
1950 			printf("Unsupported IV length\n");
1951 			return -1;
1952 		}
1953 	/*
1954 	 * Check if length of IV to be randomly generated
1955 	 * is supported by the algorithm chosen.
1956 	 */
1957 	} else if (iv_random_size != -1) {
1958 		if (check_supported_size(iv_random_size,
1959 				iv_range_size->min,
1960 				iv_range_size->max,
1961 				iv_range_size->increment)
1962 					!= 0) {
1963 			printf("Unsupported IV length\n");
1964 			return -1;
1965 		}
1966 		*iv_length = iv_random_size;
1967 	/* No size provided, use minimum size. */
1968 	} else
1969 		*iv_length = iv_range_size->min;
1970 
1971 	return 0;
1972 }
1973 
1974 static int
1975 initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
1976 		uint8_t *enabled_cdevs)
1977 {
1978 	unsigned int cdev_id, cdev_count, enabled_cdev_count = 0;
1979 	const struct rte_cryptodev_capabilities *cap;
1980 	unsigned int sess_sz, max_sess_sz = 0;
1981 	int retval;
1982 
1983 	cdev_count = rte_cryptodev_count();
1984 	if (cdev_count == 0) {
1985 		printf("No crypto devices available\n");
1986 		return -1;
1987 	}
1988 
1989 	for (cdev_id = 0; cdev_id < cdev_count; cdev_id++) {
1990 		sess_sz = rte_cryptodev_get_private_session_size(cdev_id);
1991 		if (sess_sz > max_sess_sz)
1992 			max_sess_sz = sess_sz;
1993 	}
1994 
1995 	for (cdev_id = 0; cdev_id < cdev_count && enabled_cdev_count < nb_ports;
1996 			cdev_id++) {
1997 		struct rte_cryptodev_qp_conf qp_conf;
1998 		struct rte_cryptodev_info dev_info;
1999 		uint8_t socket_id = rte_cryptodev_socket_id(cdev_id);
2000 
2001 		struct rte_cryptodev_config conf = {
2002 			.nb_queue_pairs = 1,
2003 			.socket_id = socket_id,
2004 		};
2005 
2006 		if (check_cryptodev_mask(options, (uint8_t)cdev_id))
2007 			continue;
2008 
2009 		rte_cryptodev_info_get(cdev_id, &dev_info);
2010 
2011 		if (session_pool_socket[socket_id] == NULL) {
2012 			char mp_name[RTE_MEMPOOL_NAMESIZE];
2013 			struct rte_mempool *sess_mp;
2014 
2015 			snprintf(mp_name, RTE_MEMPOOL_NAMESIZE,
2016 				"sess_mp_%u", socket_id);
2017 
2018 			/*
2019 			 * Create enough objects for session headers and
2020 			 * device private data
2021 			 */
2022 			sess_mp = rte_mempool_create(mp_name,
2023 						MAX_SESSIONS * 2,
2024 						max_sess_sz,
2025 						SESSION_POOL_CACHE_SIZE,
2026 						0, NULL, NULL, NULL,
2027 						NULL, socket_id,
2028 						0);
2029 
2030 			if (sess_mp == NULL) {
2031 				printf("Cannot create session pool on socket %d\n",
2032 					socket_id);
2033 				return -ENOMEM;
2034 			}
2035 
2036 			printf("Allocated session pool on socket %d\n", socket_id);
2037 			session_pool_socket[socket_id] = sess_mp;
2038 		}
2039 
2040 		/* Set AEAD parameters */
2041 		if (options->xform_chain == L2FWD_CRYPTO_AEAD) {
2042 			/* Check if device supports AEAD algo */
2043 			cap = check_device_support_aead_algo(options, &dev_info,
2044 							cdev_id);
2045 			if (cap == NULL)
2046 				continue;
2047 
2048 			options->block_size = cap->sym.aead.block_size;
2049 
2050 			check_iv_param(&cap->sym.aead.iv_size,
2051 					options->aead_iv_param,
2052 					options->aead_iv_random_size,
2053 					&options->aead_iv.length);
2054 
2055 			/*
2056 			 * Check if length of provided AEAD key is supported
2057 			 * by the algorithm chosen.
2058 			 */
2059 			if (options->aead_key_param) {
2060 				if (check_supported_size(
2061 						options->aead_xform.aead.key.length,
2062 						cap->sym.aead.key_size.min,
2063 						cap->sym.aead.key_size.max,
2064 						cap->sym.aead.key_size.increment)
2065 							!= 0) {
2066 					printf("Unsupported aead key length\n");
2067 					return -1;
2068 				}
2069 			/*
2070 			 * Check if length of the aead key to be randomly generated
2071 			 * is supported by the algorithm chosen.
2072 			 */
2073 			} else if (options->aead_key_random_size != -1) {
2074 				if (check_supported_size(options->aead_key_random_size,
2075 						cap->sym.aead.key_size.min,
2076 						cap->sym.aead.key_size.max,
2077 						cap->sym.aead.key_size.increment)
2078 							!= 0) {
2079 					printf("Unsupported aead key length\n");
2080 					return -1;
2081 				}
2082 				options->aead_xform.aead.key.length =
2083 							options->aead_key_random_size;
2084 			/* No size provided, use minimum size. */
2085 			} else
2086 				options->aead_xform.aead.key.length =
2087 						cap->sym.aead.key_size.min;
2088 
2089 			if (!options->aead_key_param)
2090 				generate_random_key(
2091 					options->aead_xform.aead.key.data,
2092 					options->aead_xform.aead.key.length);
2093 
2094 			/*
2095 			 * Check if length of provided AAD is supported
2096 			 * by the algorithm chosen.
2097 			 */
2098 			if (options->aad_param) {
2099 				if (check_supported_size(options->aad.length,
2100 						cap->sym.aead.aad_size.min,
2101 						cap->sym.aead.aad_size.max,
2102 						cap->sym.aead.aad_size.increment)
2103 							!= 0) {
2104 					printf("Unsupported AAD length\n");
2105 					return -1;
2106 				}
2107 			/*
2108 			 * Check if length of AAD to be randomly generated
2109 			 * is supported by the algorithm chosen.
2110 			 */
2111 			} else if (options->aad_random_size != -1) {
2112 				if (check_supported_size(options->aad_random_size,
2113 						cap->sym.aead.aad_size.min,
2114 						cap->sym.aead.aad_size.max,
2115 						cap->sym.aead.aad_size.increment)
2116 							!= 0) {
2117 					printf("Unsupported AAD length\n");
2118 					return -1;
2119 				}
2120 				options->aad.length = options->aad_random_size;
2121 			/* No size provided, use minimum size. */
2122 			} else
2123 				options->aad.length = cap->sym.auth.aad_size.min;
2124 
2125 			options->aead_xform.aead.aad_length =
2126 						options->aad.length;
2127 
2128 			/* Check if digest size is supported by the algorithm. */
2129 			if (options->digest_size != -1) {
2130 				if (check_supported_size(options->digest_size,
2131 						cap->sym.aead.digest_size.min,
2132 						cap->sym.aead.digest_size.max,
2133 						cap->sym.aead.digest_size.increment)
2134 							!= 0) {
2135 					printf("Unsupported digest length\n");
2136 					return -1;
2137 				}
2138 				options->aead_xform.aead.digest_length =
2139 							options->digest_size;
2140 			/* No size provided, use minimum size. */
2141 			} else
2142 				options->aead_xform.aead.digest_length =
2143 						cap->sym.aead.digest_size.min;
2144 		}
2145 
2146 		/* Set cipher parameters */
2147 		if (options->xform_chain == L2FWD_CRYPTO_CIPHER_HASH ||
2148 				options->xform_chain == L2FWD_CRYPTO_HASH_CIPHER ||
2149 				options->xform_chain == L2FWD_CRYPTO_CIPHER_ONLY) {
2150 			/* Check if device supports cipher algo */
2151 			cap = check_device_support_cipher_algo(options, &dev_info,
2152 							cdev_id);
2153 			if (cap == NULL)
2154 				continue;
2155 
2156 			options->block_size = cap->sym.cipher.block_size;
2157 
2158 			check_iv_param(&cap->sym.cipher.iv_size,
2159 					options->cipher_iv_param,
2160 					options->cipher_iv_random_size,
2161 					&options->cipher_iv.length);
2162 
2163 			/*
2164 			 * Check if length of provided cipher key is supported
2165 			 * by the algorithm chosen.
2166 			 */
2167 			if (options->ckey_param) {
2168 				if (check_supported_size(
2169 						options->cipher_xform.cipher.key.length,
2170 						cap->sym.cipher.key_size.min,
2171 						cap->sym.cipher.key_size.max,
2172 						cap->sym.cipher.key_size.increment)
2173 							!= 0) {
2174 					printf("Unsupported cipher key length\n");
2175 					return -1;
2176 				}
2177 			/*
2178 			 * Check if length of the cipher key to be randomly generated
2179 			 * is supported by the algorithm chosen.
2180 			 */
2181 			} else if (options->ckey_random_size != -1) {
2182 				if (check_supported_size(options->ckey_random_size,
2183 						cap->sym.cipher.key_size.min,
2184 						cap->sym.cipher.key_size.max,
2185 						cap->sym.cipher.key_size.increment)
2186 							!= 0) {
2187 					printf("Unsupported cipher key length\n");
2188 					return -1;
2189 				}
2190 				options->cipher_xform.cipher.key.length =
2191 							options->ckey_random_size;
2192 			/* No size provided, use minimum size. */
2193 			} else
2194 				options->cipher_xform.cipher.key.length =
2195 						cap->sym.cipher.key_size.min;
2196 
2197 			if (!options->ckey_param)
2198 				generate_random_key(
2199 					options->cipher_xform.cipher.key.data,
2200 					options->cipher_xform.cipher.key.length);
2201 
2202 		}
2203 
2204 		/* Set auth parameters */
2205 		if (options->xform_chain == L2FWD_CRYPTO_CIPHER_HASH ||
2206 				options->xform_chain == L2FWD_CRYPTO_HASH_CIPHER ||
2207 				options->xform_chain == L2FWD_CRYPTO_HASH_ONLY) {
2208 			/* Check if device supports auth algo */
2209 			cap = check_device_support_auth_algo(options, &dev_info,
2210 							cdev_id);
2211 			if (cap == NULL)
2212 				continue;
2213 
2214 			check_iv_param(&cap->sym.auth.iv_size,
2215 					options->auth_iv_param,
2216 					options->auth_iv_random_size,
2217 					&options->auth_iv.length);
2218 			/*
2219 			 * Check if length of provided auth key is supported
2220 			 * by the algorithm chosen.
2221 			 */
2222 			if (options->akey_param) {
2223 				if (check_supported_size(
2224 						options->auth_xform.auth.key.length,
2225 						cap->sym.auth.key_size.min,
2226 						cap->sym.auth.key_size.max,
2227 						cap->sym.auth.key_size.increment)
2228 							!= 0) {
2229 					printf("Unsupported auth key length\n");
2230 					return -1;
2231 				}
2232 			/*
2233 			 * Check if length of the auth key to be randomly generated
2234 			 * is supported by the algorithm chosen.
2235 			 */
2236 			} else if (options->akey_random_size != -1) {
2237 				if (check_supported_size(options->akey_random_size,
2238 						cap->sym.auth.key_size.min,
2239 						cap->sym.auth.key_size.max,
2240 						cap->sym.auth.key_size.increment)
2241 							!= 0) {
2242 					printf("Unsupported auth key length\n");
2243 					return -1;
2244 				}
2245 				options->auth_xform.auth.key.length =
2246 							options->akey_random_size;
2247 			/* No size provided, use minimum size. */
2248 			} else
2249 				options->auth_xform.auth.key.length =
2250 						cap->sym.auth.key_size.min;
2251 
2252 			if (!options->akey_param)
2253 				generate_random_key(
2254 					options->auth_xform.auth.key.data,
2255 					options->auth_xform.auth.key.length);
2256 
2257 			/* Check if digest size is supported by the algorithm. */
2258 			if (options->digest_size != -1) {
2259 				if (check_supported_size(options->digest_size,
2260 						cap->sym.auth.digest_size.min,
2261 						cap->sym.auth.digest_size.max,
2262 						cap->sym.auth.digest_size.increment)
2263 							!= 0) {
2264 					printf("Unsupported digest length\n");
2265 					return -1;
2266 				}
2267 				options->auth_xform.auth.digest_length =
2268 							options->digest_size;
2269 			/* No size provided, use minimum size. */
2270 			} else
2271 				options->auth_xform.auth.digest_length =
2272 						cap->sym.auth.digest_size.min;
2273 		}
2274 
2275 		retval = rte_cryptodev_configure(cdev_id, &conf);
2276 		if (retval < 0) {
2277 			printf("Failed to configure cryptodev %u", cdev_id);
2278 			return -1;
2279 		}
2280 
2281 		qp_conf.nb_descriptors = 2048;
2282 
2283 		retval = rte_cryptodev_queue_pair_setup(cdev_id, 0, &qp_conf,
2284 				socket_id, session_pool_socket[socket_id]);
2285 		if (retval < 0) {
2286 			printf("Failed to setup queue pair %u on cryptodev %u",
2287 					0, cdev_id);
2288 			return -1;
2289 		}
2290 
2291 		retval = rte_cryptodev_start(cdev_id);
2292 		if (retval < 0) {
2293 			printf("Failed to start device %u: error %d\n",
2294 					cdev_id, retval);
2295 			return -1;
2296 		}
2297 
2298 		l2fwd_enabled_crypto_mask |= (((uint64_t)1) << cdev_id);
2299 
2300 		enabled_cdevs[cdev_id] = 1;
2301 		enabled_cdev_count++;
2302 	}
2303 
2304 	return enabled_cdev_count;
2305 }
2306 
2307 static int
2308 initialize_ports(struct l2fwd_crypto_options *options)
2309 {
2310 	uint8_t last_portid, portid;
2311 	unsigned enabled_portcount = 0;
2312 	unsigned nb_ports = rte_eth_dev_count();
2313 
2314 	if (nb_ports == 0) {
2315 		printf("No Ethernet ports - bye\n");
2316 		return -1;
2317 	}
2318 
2319 	/* Reset l2fwd_dst_ports */
2320 	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
2321 		l2fwd_dst_ports[portid] = 0;
2322 
2323 	for (last_portid = 0, portid = 0; portid < nb_ports; portid++) {
2324 		int retval;
2325 
2326 		/* Skip ports that are not enabled */
2327 		if ((options->portmask & (1 << portid)) == 0)
2328 			continue;
2329 
2330 		/* init port */
2331 		printf("Initializing port %u... ", (unsigned) portid);
2332 		fflush(stdout);
2333 		retval = rte_eth_dev_configure(portid, 1, 1, &port_conf);
2334 		if (retval < 0) {
2335 			printf("Cannot configure device: err=%d, port=%u\n",
2336 				  retval, (unsigned) portid);
2337 			return -1;
2338 		}
2339 
2340 		retval = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
2341 							  &nb_txd);
2342 		if (retval < 0) {
2343 			printf("Cannot adjust number of descriptors: err=%d, port=%u\n",
2344 				retval, (unsigned) portid);
2345 			return -1;
2346 		}
2347 
2348 		/* init one RX queue */
2349 		fflush(stdout);
2350 		retval = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
2351 					     rte_eth_dev_socket_id(portid),
2352 					     NULL, l2fwd_pktmbuf_pool);
2353 		if (retval < 0) {
2354 			printf("rte_eth_rx_queue_setup:err=%d, port=%u\n",
2355 					retval, (unsigned) portid);
2356 			return -1;
2357 		}
2358 
2359 		/* init one TX queue on each port */
2360 		fflush(stdout);
2361 		retval = rte_eth_tx_queue_setup(portid, 0, nb_txd,
2362 				rte_eth_dev_socket_id(portid),
2363 				NULL);
2364 		if (retval < 0) {
2365 			printf("rte_eth_tx_queue_setup:err=%d, port=%u\n",
2366 				retval, (unsigned) portid);
2367 
2368 			return -1;
2369 		}
2370 
2371 		/* Start device */
2372 		retval = rte_eth_dev_start(portid);
2373 		if (retval < 0) {
2374 			printf("rte_eth_dev_start:err=%d, port=%u\n",
2375 					retval, (unsigned) portid);
2376 			return -1;
2377 		}
2378 
2379 		rte_eth_promiscuous_enable(portid);
2380 
2381 		rte_eth_macaddr_get(portid, &l2fwd_ports_eth_addr[portid]);
2382 
2383 		printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
2384 				(unsigned) portid,
2385 				l2fwd_ports_eth_addr[portid].addr_bytes[0],
2386 				l2fwd_ports_eth_addr[portid].addr_bytes[1],
2387 				l2fwd_ports_eth_addr[portid].addr_bytes[2],
2388 				l2fwd_ports_eth_addr[portid].addr_bytes[3],
2389 				l2fwd_ports_eth_addr[portid].addr_bytes[4],
2390 				l2fwd_ports_eth_addr[portid].addr_bytes[5]);
2391 
2392 		/* initialize port stats */
2393 		memset(&port_statistics, 0, sizeof(port_statistics));
2394 
2395 		/* Setup port forwarding table */
2396 		if (enabled_portcount % 2) {
2397 			l2fwd_dst_ports[portid] = last_portid;
2398 			l2fwd_dst_ports[last_portid] = portid;
2399 		} else {
2400 			last_portid = portid;
2401 		}
2402 
2403 		l2fwd_enabled_port_mask |= (1 << portid);
2404 		enabled_portcount++;
2405 	}
2406 
2407 	if (enabled_portcount == 1) {
2408 		l2fwd_dst_ports[last_portid] = last_portid;
2409 	} else if (enabled_portcount % 2) {
2410 		printf("odd number of ports in portmask- bye\n");
2411 		return -1;
2412 	}
2413 
2414 	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
2415 
2416 	return enabled_portcount;
2417 }
2418 
2419 static void
2420 reserve_key_memory(struct l2fwd_crypto_options *options)
2421 {
2422 	options->cipher_xform.cipher.key.data = rte_malloc("crypto key",
2423 						MAX_KEY_SIZE, 0);
2424 	if (options->cipher_xform.cipher.key.data == NULL)
2425 		rte_exit(EXIT_FAILURE, "Failed to allocate memory for cipher key");
2426 
2427 	options->auth_xform.auth.key.data = rte_malloc("auth key",
2428 						MAX_KEY_SIZE, 0);
2429 	if (options->auth_xform.auth.key.data == NULL)
2430 		rte_exit(EXIT_FAILURE, "Failed to allocate memory for auth key");
2431 
2432 	options->aead_xform.aead.key.data = rte_malloc("aead key",
2433 						MAX_KEY_SIZE, 0);
2434 	if (options->aead_xform.aead.key.data == NULL)
2435 		rte_exit(EXIT_FAILURE, "Failed to allocate memory for AEAD key");
2436 
2437 	options->cipher_iv.data = rte_malloc("cipher iv", MAX_KEY_SIZE, 0);
2438 	if (options->cipher_iv.data == NULL)
2439 		rte_exit(EXIT_FAILURE, "Failed to allocate memory for cipher IV");
2440 
2441 	options->auth_iv.data = rte_malloc("auth iv", MAX_KEY_SIZE, 0);
2442 	if (options->auth_iv.data == NULL)
2443 		rte_exit(EXIT_FAILURE, "Failed to allocate memory for auth IV");
2444 
2445 	options->aead_iv.data = rte_malloc("aead_iv", MAX_KEY_SIZE, 0);
2446 	if (options->aead_iv.data == NULL)
2447 		rte_exit(EXIT_FAILURE, "Failed to allocate memory for AEAD iv");
2448 
2449 	options->aad.data = rte_malloc("aad", MAX_KEY_SIZE, 0);
2450 	if (options->aad.data == NULL)
2451 		rte_exit(EXIT_FAILURE, "Failed to allocate memory for AAD");
2452 	options->aad.phys_addr = rte_malloc_virt2phy(options->aad.data);
2453 }
2454 
2455 int
2456 main(int argc, char **argv)
2457 {
2458 	struct lcore_queue_conf *qconf;
2459 	struct l2fwd_crypto_options options;
2460 
2461 	uint8_t nb_ports, nb_cryptodevs, portid, cdev_id;
2462 	unsigned lcore_id, rx_lcore_id;
2463 	int ret, enabled_cdevcount, enabled_portcount;
2464 	uint8_t enabled_cdevs[RTE_CRYPTO_MAX_DEVS] = {0};
2465 
2466 	/* init EAL */
2467 	ret = rte_eal_init(argc, argv);
2468 	if (ret < 0)
2469 		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
2470 	argc -= ret;
2471 	argv += ret;
2472 
2473 	/* reserve memory for Cipher/Auth key and IV */
2474 	reserve_key_memory(&options);
2475 
2476 	/* parse application arguments (after the EAL ones) */
2477 	ret = l2fwd_crypto_parse_args(&options, argc, argv);
2478 	if (ret < 0)
2479 		rte_exit(EXIT_FAILURE, "Invalid L2FWD-CRYPTO arguments\n");
2480 
2481 	printf("MAC updating %s\n",
2482 			options.mac_updating ? "enabled" : "disabled");
2483 
2484 	/* create the mbuf pool */
2485 	l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF, 512,
2486 			sizeof(struct rte_crypto_op),
2487 			RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
2488 	if (l2fwd_pktmbuf_pool == NULL)
2489 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
2490 
2491 	/* create crypto op pool */
2492 	l2fwd_crypto_op_pool = rte_crypto_op_pool_create("crypto_op_pool",
2493 			RTE_CRYPTO_OP_TYPE_SYMMETRIC, NB_MBUF, 128, MAXIMUM_IV_LENGTH,
2494 			rte_socket_id());
2495 	if (l2fwd_crypto_op_pool == NULL)
2496 		rte_exit(EXIT_FAILURE, "Cannot create crypto op pool\n");
2497 
2498 	/* Enable Ethernet ports */
2499 	enabled_portcount = initialize_ports(&options);
2500 	if (enabled_portcount < 1)
2501 		rte_exit(EXIT_FAILURE, "Failed to initial Ethernet ports\n");
2502 
2503 	nb_ports = rte_eth_dev_count();
2504 	/* Initialize the port/queue configuration of each logical core */
2505 	for (rx_lcore_id = 0, qconf = NULL, portid = 0;
2506 			portid < nb_ports; portid++) {
2507 
2508 		/* skip ports that are not enabled */
2509 		if ((options.portmask & (1 << portid)) == 0)
2510 			continue;
2511 
2512 		if (options.single_lcore && qconf == NULL) {
2513 			while (rte_lcore_is_enabled(rx_lcore_id) == 0) {
2514 				rx_lcore_id++;
2515 				if (rx_lcore_id >= RTE_MAX_LCORE)
2516 					rte_exit(EXIT_FAILURE,
2517 							"Not enough cores\n");
2518 			}
2519 		} else if (!options.single_lcore) {
2520 			/* get the lcore_id for this port */
2521 			while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
2522 			       lcore_queue_conf[rx_lcore_id].nb_rx_ports ==
2523 			       options.nb_ports_per_lcore) {
2524 				rx_lcore_id++;
2525 				if (rx_lcore_id >= RTE_MAX_LCORE)
2526 					rte_exit(EXIT_FAILURE,
2527 							"Not enough cores\n");
2528 			}
2529 		}
2530 
2531 		/* Assigned a new logical core in the loop above. */
2532 		if (qconf != &lcore_queue_conf[rx_lcore_id])
2533 			qconf = &lcore_queue_conf[rx_lcore_id];
2534 
2535 		qconf->rx_port_list[qconf->nb_rx_ports] = portid;
2536 		qconf->nb_rx_ports++;
2537 
2538 		printf("Lcore %u: RX port %u\n", rx_lcore_id, (unsigned)portid);
2539 	}
2540 
2541 	/* Enable Crypto devices */
2542 	enabled_cdevcount = initialize_cryptodevs(&options, enabled_portcount,
2543 			enabled_cdevs);
2544 	if (enabled_cdevcount < 0)
2545 		rte_exit(EXIT_FAILURE, "Failed to initialize crypto devices\n");
2546 
2547 	if (enabled_cdevcount < enabled_portcount)
2548 		rte_exit(EXIT_FAILURE, "Number of capable crypto devices (%d) "
2549 				"has to be more or equal to number of ports (%d)\n",
2550 				enabled_cdevcount, enabled_portcount);
2551 
2552 	nb_cryptodevs = rte_cryptodev_count();
2553 
2554 	/* Initialize the port/cryptodev configuration of each logical core */
2555 	for (rx_lcore_id = 0, qconf = NULL, cdev_id = 0;
2556 			cdev_id < nb_cryptodevs && enabled_cdevcount;
2557 			cdev_id++) {
2558 		/* Crypto op not supported by crypto device */
2559 		if (!enabled_cdevs[cdev_id])
2560 			continue;
2561 
2562 		if (options.single_lcore && qconf == NULL) {
2563 			while (rte_lcore_is_enabled(rx_lcore_id) == 0) {
2564 				rx_lcore_id++;
2565 				if (rx_lcore_id >= RTE_MAX_LCORE)
2566 					rte_exit(EXIT_FAILURE,
2567 							"Not enough cores\n");
2568 			}
2569 		} else if (!options.single_lcore) {
2570 			/* get the lcore_id for this port */
2571 			while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
2572 			       lcore_queue_conf[rx_lcore_id].nb_crypto_devs ==
2573 			       options.nb_ports_per_lcore) {
2574 				rx_lcore_id++;
2575 				if (rx_lcore_id >= RTE_MAX_LCORE)
2576 					rte_exit(EXIT_FAILURE,
2577 							"Not enough cores\n");
2578 			}
2579 		}
2580 
2581 		/* Assigned a new logical core in the loop above. */
2582 		if (qconf != &lcore_queue_conf[rx_lcore_id])
2583 			qconf = &lcore_queue_conf[rx_lcore_id];
2584 
2585 		qconf->cryptodev_list[qconf->nb_crypto_devs] = cdev_id;
2586 		qconf->nb_crypto_devs++;
2587 
2588 		enabled_cdevcount--;
2589 
2590 		printf("Lcore %u: cryptodev %u\n", rx_lcore_id,
2591 				(unsigned)cdev_id);
2592 	}
2593 
2594 	/* launch per-lcore init on every lcore */
2595 	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, (void *)&options,
2596 			CALL_MASTER);
2597 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
2598 		if (rte_eal_wait_lcore(lcore_id) < 0)
2599 			return -1;
2600 	}
2601 
2602 	return 0;
2603 }
2604