1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2017-2018 Intel Corporation
13 #include <rte_malloc.h>
14 #include <rte_cycles.h>
15 #include <rte_vhost.h>
16 #include <rte_cryptodev.h>
17 #include <rte_vhost_crypto.h>
18 #include <rte_string_fns.h>
20 #include <cmdline_rdline.h>
21 #include <cmdline_parse.h>
22 #include <cmdline_parse_string.h>
25 #define NB_VIRTIO_QUEUES (1)
26 #define MAX_PKT_BURST (64)
27 #define MAX_IV_LEN (32)
28 #define NB_MEMPOOL_OBJS (8192)
29 #define NB_CRYPTO_DESCRIPTORS (4096)
30 #define NB_CACHE_OBJS (128)
31 #define SESSION_MAP_ENTRIES (1024)
32 #define REFRESH_TIME_SEC (3)
34 #define MAX_NB_SOCKETS (4)
35 #define MAX_NB_WORKER_CORES (16)
39 char *socket_files
[MAX_NB_SOCKETS
];
45 struct vhost_crypto_info
{
46 int vids
[MAX_NB_SOCKETS
];
48 struct rte_mempool
*sess_pool
;
49 struct rte_mempool
*sess_priv_pool
;
50 struct rte_mempool
*cop_pool
;
53 uint32_t nb_inflight_ops
;
54 volatile uint32_t initialized
[MAX_NB_SOCKETS
];
55 } __rte_cache_aligned
;
57 struct vhost_crypto_options
{
58 struct lcore_option los
[MAX_NB_WORKER_CORES
];
59 struct vhost_crypto_info
*infos
[MAX_NB_WORKER_CORES
];
62 uint32_t guest_polling
;
65 #define CONFIG_KEYWORD "config"
66 #define SOCKET_FILE_KEYWORD "socket-file"
67 #define ZERO_COPY_KEYWORD "zero-copy"
68 #define POLLING_KEYWORD "guest-polling"
70 #define NB_SOCKET_FIELDS (2)
73 find_lo(uint32_t lcore_id
)
77 for (i
= 0; i
< options
.nb_los
; i
++)
78 if (options
.los
[i
].lcore_id
== lcore_id
)
84 /** support *SOCKET_FILE_PATH:CRYPTODEV_ID* format */
86 parse_socket_arg(char *arg
)
90 char *str_fld
[NB_SOCKET_FIELDS
];
91 struct lcore_option
*lo
;
95 if (rte_strsplit(arg
, strlen(arg
), str_fld
, NB_SOCKET_FIELDS
, ',') !=
97 RTE_LOG(ERR
, USER1
, "Invalid socket parameter '%s'\n", arg
);
102 lcore_id
= strtoul(str_fld
[0], &end
, 0);
103 if (errno
!= 0 || end
== str_fld
[0] || lcore_id
> 255)
106 idx
= find_lo(lcore_id
);
107 if (idx
== UINT32_MAX
) {
108 if (options
.nb_los
== MAX_NB_WORKER_CORES
)
110 lo
= &options
.los
[options
.nb_los
];
111 lo
->lcore_id
= lcore_id
;
114 lo
= &options
.los
[idx
];
116 nb_sockets
= lo
->nb_sockets
;
118 if (nb_sockets
>= MAX_NB_SOCKETS
) {
119 RTE_LOG(ERR
, USER1
, "Too many socket files!\n");
123 lo
->socket_files
[nb_sockets
] = strdup(str_fld
[1]);
124 if (!lo
->socket_files
[nb_sockets
]) {
125 RTE_LOG(ERR
, USER1
, "Insufficient memory\n");
135 parse_config(char *q_arg
)
137 struct lcore_option
*lo
;
139 const char *p
, *p0
= q_arg
;
147 uint32_t flds
[_NUM_FLD
];
148 char *str_fld
[_NUM_FLD
];
152 while ((p
= strchr(p0
, '(')) != NULL
) {
159 if (size
>= sizeof(s
))
162 snprintf(s
, sizeof(s
), "%.*s", size
, p
);
163 if (rte_strsplit(s
, sizeof(s
), str_fld
, _NUM_FLD
, ',') !=
166 for (i
= 0; i
< _NUM_FLD
; i
++) {
168 flds
[i
] = strtoul(str_fld
[i
], &end
, 0);
169 if (errno
!= 0 || end
== str_fld
[i
] || flds
[i
] > 255)
173 if (flds
[FLD_LCORE
] > RTE_MAX_LCORE
)
176 i
= find_lo(flds
[FLD_LCORE
]);
177 if (i
== UINT32_MAX
) {
178 if (options
.nb_los
== MAX_NB_WORKER_CORES
)
180 lo
= &options
.los
[options
.nb_los
];
183 lo
= &options
.los
[i
];
185 lo
->lcore_id
= flds
[FLD_LCORE
];
186 lo
->cid
= flds
[FLD_CID
];
187 lo
->qid
= flds
[FLD_QID
];
194 vhost_crypto_usage(const char *prgname
)
196 printf("%s [EAL options] --\n"
197 " --%s <lcore>,SOCKET-FILE-PATH\n"
198 " --%s (lcore,cdev_id,queue_id)[,(lcore,cdev_id,queue_id)]"
200 " --%s: guest polling\n",
201 prgname
, SOCKET_FILE_KEYWORD
, CONFIG_KEYWORD
,
202 ZERO_COPY_KEYWORD
, POLLING_KEYWORD
);
206 vhost_crypto_parse_args(int argc
, char **argv
)
209 char *prgname
= argv
[0];
212 struct option lgopts
[] = {
213 {SOCKET_FILE_KEYWORD
, required_argument
, 0, 0},
214 {CONFIG_KEYWORD
, required_argument
, 0, 0},
215 {ZERO_COPY_KEYWORD
, no_argument
, 0, 0},
216 {POLLING_KEYWORD
, no_argument
, 0, 0},
222 while ((opt
= getopt_long(argc
, argvopt
, "s:",
223 lgopts
, &option_index
)) != EOF
) {
227 if (strcmp(lgopts
[option_index
].name
,
228 SOCKET_FILE_KEYWORD
) == 0) {
229 ret
= parse_socket_arg(optarg
);
231 vhost_crypto_usage(prgname
);
234 } else if (strcmp(lgopts
[option_index
].name
,
235 CONFIG_KEYWORD
) == 0) {
236 ret
= parse_config(optarg
);
238 vhost_crypto_usage(prgname
);
241 } else if (strcmp(lgopts
[option_index
].name
,
242 ZERO_COPY_KEYWORD
) == 0) {
244 RTE_VHOST_CRYPTO_ZERO_COPY_ENABLE
;
245 } else if (strcmp(lgopts
[option_index
].name
,
246 POLLING_KEYWORD
) == 0) {
247 options
.guest_polling
= 1;
249 vhost_crypto_usage(prgname
);
264 struct vhost_crypto_info
*info
= NULL
;
269 ret
= rte_vhost_get_ifname(vid
, path
, PATH_MAX
);
271 RTE_LOG(ERR
, USER1
, "Cannot find matched socket\n");
275 for (i
= 0; i
< options
.nb_los
; i
++) {
276 for (j
= 0; j
< options
.los
[i
].nb_sockets
; j
++) {
277 if (strcmp(path
, options
.los
[i
].socket_files
[j
]) == 0) {
278 info
= options
.infos
[i
];
288 RTE_LOG(ERR
, USER1
, "Cannot find recorded socket\n");
292 ret
= rte_vhost_crypto_create(vid
, info
->cid
, info
->sess_pool
,
293 info
->sess_priv_pool
,
294 rte_lcore_to_socket_id(options
.los
[i
].lcore_id
));
296 RTE_LOG(ERR
, USER1
, "Cannot create vhost crypto\n");
300 ret
= rte_vhost_crypto_set_zero_copy(vid
, options
.zero_copy
);
302 RTE_LOG(ERR
, USER1
, "Cannot %s zero copy feature\n",
303 options
.zero_copy
== 1 ? "enable" : "disable");
308 info
->initialized
[j
] = 1;
312 RTE_LOG(INFO
, USER1
, "New Vhost-crypto Device %s, Device ID %d\n", path
,
318 destroy_device(int vid
)
320 struct vhost_crypto_info
*info
= NULL
;
323 for (i
= 0; i
< options
.nb_los
; i
++) {
324 for (j
= 0; j
< options
.los
[i
].nb_sockets
; j
++) {
325 if (options
.infos
[i
]->vids
[j
] == vid
) {
326 info
= options
.infos
[i
];
335 RTE_LOG(ERR
, USER1
, "Cannot find socket file from list\n");
341 } while (info
->nb_inflight_ops
);
343 info
->initialized
[j
] = 0;
347 rte_vhost_crypto_free(vid
);
349 RTE_LOG(INFO
, USER1
, "Vhost Crypto Device %i Removed\n", vid
);
352 static const struct vhost_device_ops virtio_crypto_device_ops
= {
353 .new_device
= new_device
,
354 .destroy_device
= destroy_device
,
357 __attribute__((unused
))
358 static void clrscr(void)
360 system("@cls||clear");
364 vhost_crypto_worker(void *arg
)
366 struct rte_crypto_op
*ops
[NB_VIRTIO_QUEUES
][MAX_PKT_BURST
+ 1];
367 struct rte_crypto_op
*ops_deq
[NB_VIRTIO_QUEUES
][MAX_PKT_BURST
+ 1];
368 struct vhost_crypto_info
*info
= arg
;
370 int callfds
[VIRTIO_CRYPTO_MAX_NUM_BURST_VQS
];
371 uint32_t lcore_id
= rte_lcore_id();
372 uint32_t burst_size
= MAX_PKT_BURST
;
374 uint32_t to_fetch
, fetched
;
378 RTE_LOG(INFO
, USER1
, "Processing on Core %u started\n", lcore_id
);
380 for (i
= 0; i
< NB_VIRTIO_QUEUES
; i
++) {
381 if (rte_crypto_op_bulk_alloc(info
->cop_pool
,
382 RTE_CRYPTO_OP_TYPE_SYMMETRIC
, ops
[i
],
383 burst_size
) < burst_size
) {
384 RTE_LOG(ERR
, USER1
, "Failed to alloc cops\n");
391 for (i
= 0; i
< info
->nb_vids
; i
++) {
392 if (unlikely(info
->initialized
[i
] == 0))
395 for (j
= 0; j
< NB_VIRTIO_QUEUES
; j
++) {
396 to_fetch
= RTE_MIN(burst_size
,
397 (NB_CRYPTO_DESCRIPTORS
-
398 info
->nb_inflight_ops
));
399 fetched
= rte_vhost_crypto_fetch_requests(
400 info
->vids
[i
], j
, ops
[j
],
402 info
->nb_inflight_ops
+=
403 rte_cryptodev_enqueue_burst(
404 info
->cid
, info
->qid
, ops
[j
],
406 if (unlikely(rte_crypto_op_bulk_alloc(
408 RTE_CRYPTO_OP_TYPE_SYMMETRIC
,
409 ops
[j
], fetched
) < fetched
)) {
410 RTE_LOG(ERR
, USER1
, "Failed realloc\n");
414 fetched
= rte_cryptodev_dequeue_burst(
415 info
->cid
, info
->qid
,
416 ops_deq
[j
], RTE_MIN(burst_size
,
417 info
->nb_inflight_ops
));
418 fetched
= rte_vhost_crypto_finalize_requests(
419 ops_deq
[j
], fetched
, callfds
,
422 info
->nb_inflight_ops
-= fetched
;
424 if (!options
.guest_polling
) {
425 for (k
= 0; k
< nb_callfds
; k
++)
426 eventfd_write(callfds
[k
],
430 rte_mempool_put_bulk(info
->cop_pool
,
431 (void **)ops_deq
[j
], fetched
);
444 for (i
= 0; i
< options
.nb_los
; i
++) {
445 struct lcore_option
*lo
= &options
.los
[i
];
446 struct vhost_crypto_info
*info
= options
.infos
[i
];
451 rte_mempool_free(info
->cop_pool
);
452 rte_mempool_free(info
->sess_pool
);
453 rte_mempool_free(info
->sess_priv_pool
);
455 for (j
= 0; j
< lo
->nb_sockets
; j
++) {
456 rte_vhost_driver_unregister(lo
->socket_files
[i
]);
457 free(lo
->socket_files
[i
]);
463 memset(&options
, 0, sizeof(options
));
467 main(int argc
, char *argv
[])
469 struct rte_cryptodev_qp_conf qp_conf
;
470 struct rte_cryptodev_config config
;
471 struct rte_cryptodev_info dev_info
;
473 uint32_t i
, j
, lcore
;
476 ret
= rte_eal_init(argc
, argv
);
482 ret
= vhost_crypto_parse_args(argc
, argv
);
484 rte_exit(EXIT_FAILURE
, "Failed to parse arguments!\n");
486 for (i
= 0; i
< options
.nb_los
; i
++) {
487 struct lcore_option
*lo
= &options
.los
[i
];
488 struct vhost_crypto_info
*info
;
490 info
= rte_zmalloc_socket(NULL
, sizeof(*info
),
491 RTE_CACHE_LINE_SIZE
, rte_lcore_to_socket_id(
500 info
->nb_vids
= lo
->nb_sockets
;
502 rte_cryptodev_info_get(info
->cid
, &dev_info
);
503 if (options
.zero_copy
== RTE_VHOST_CRYPTO_ZERO_COPY_ENABLE
) {
504 #define VHOST_CRYPTO_CDEV_NAME_AESNI_MB_PMD crypto_aesni_mb
505 #define VHOST_CRYPTO_CDEV_NAME_AESNI_GCM_PMD crypto_aesni_gcm
506 if (strstr(dev_info
.driver_name
,
507 RTE_STR(VHOST_CRYPTO_CDEV_NAME_AESNI_MB_PMD
)) ||
508 strstr(dev_info
.driver_name
,
509 RTE_STR(VHOST_CRYPTO_CDEV_NAME_AESNI_GCM_PMD
))) {
510 RTE_LOG(ERR
, USER1
, "Cannot enable zero-copy in %s\n",
511 dev_info
.driver_name
);
517 if (dev_info
.max_nb_queue_pairs
< info
->qid
+ 1) {
518 RTE_LOG(ERR
, USER1
, "Number of queues cannot over %u",
519 dev_info
.max_nb_queue_pairs
);
523 config
.nb_queue_pairs
= dev_info
.max_nb_queue_pairs
;
524 config
.socket_id
= rte_lcore_to_socket_id(lo
->lcore_id
);
526 ret
= rte_cryptodev_configure(info
->cid
, &config
);
528 RTE_LOG(ERR
, USER1
, "Failed to configure cryptodev %u",
533 snprintf(name
, 127, "SESS_POOL_%u", lo
->lcore_id
);
534 info
->sess_pool
= rte_cryptodev_sym_session_pool_create(name
,
535 SESSION_MAP_ENTRIES
, 0, 0, 0,
536 rte_lcore_to_socket_id(lo
->lcore_id
));
538 snprintf(name
, 127, "SESS_POOL_PRIV_%u", lo
->lcore_id
);
539 info
->sess_priv_pool
= rte_mempool_create(name
,
541 rte_cryptodev_sym_get_private_session_size(
542 info
->cid
), 64, 0, NULL
, NULL
, NULL
, NULL
,
543 rte_lcore_to_socket_id(lo
->lcore_id
), 0);
544 if (!info
->sess_priv_pool
|| !info
->sess_pool
) {
545 RTE_LOG(ERR
, USER1
, "Failed to create mempool");
549 snprintf(name
, 127, "COPPOOL_%u", lo
->lcore_id
);
550 info
->cop_pool
= rte_crypto_op_pool_create(name
,
551 RTE_CRYPTO_OP_TYPE_SYMMETRIC
, NB_MEMPOOL_OBJS
,
553 rte_lcore_to_socket_id(lo
->lcore_id
));
555 if (!info
->cop_pool
) {
556 RTE_LOG(ERR
, USER1
, "Failed to create crypto pool");
561 options
.infos
[i
] = info
;
563 qp_conf
.nb_descriptors
= NB_CRYPTO_DESCRIPTORS
;
564 qp_conf
.mp_session
= info
->sess_pool
;
565 qp_conf
.mp_session_private
= info
->sess_priv_pool
;
567 for (j
= 0; j
< dev_info
.max_nb_queue_pairs
; j
++) {
568 ret
= rte_cryptodev_queue_pair_setup(info
->cid
, j
,
569 &qp_conf
, rte_lcore_to_socket_id(
572 RTE_LOG(ERR
, USER1
, "Failed to configure qp\n");
578 for (i
= 0; i
< options
.nb_los
; i
++) {
579 struct lcore_option
*lo
= &options
.los
[i
];
580 struct vhost_crypto_info
*info
= options
.infos
[i
];
582 ret
= rte_cryptodev_start(lo
->cid
);
584 RTE_LOG(ERR
, USER1
, "Failed to start cryptodev\n");
588 if (rte_eal_remote_launch(vhost_crypto_worker
, info
,
590 RTE_LOG(ERR
, USER1
, "Failed to start worker lcore");
594 for (j
= 0; j
< lo
->nb_sockets
; j
++) {
595 ret
= rte_vhost_driver_register(lo
->socket_files
[j
],
596 RTE_VHOST_USER_DEQUEUE_ZERO_COPY
);
598 RTE_LOG(ERR
, USER1
, "socket %s already exists\n",
599 lo
->socket_files
[j
]);
603 rte_vhost_driver_callback_register(lo
->socket_files
[j
],
604 &virtio_crypto_device_ops
);
606 ret
= rte_vhost_driver_start(lo
->socket_files
[j
]);
608 RTE_LOG(ERR
, USER1
, "failed to start vhost.\n");
614 RTE_LCORE_FOREACH(lcore
)
615 rte_eal_wait_lcore(lcore
);