2 * Copyright (c) 2016 Intel and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
15 #include <vnet/vnet.h>
16 #include <vnet/ip/ip.h>
17 #include <vnet/api_errno.h>
18 #include <vnet/ipsec/ipsec.h>
19 #include <vlib/node_funcs.h>
21 #include <dpdk/device/dpdk.h>
22 #include <dpdk/ipsec/ipsec.h>
23 #include <dpdk/ipsec/esp.h>
25 #define DPDK_CRYPTO_NB_SESS_OBJS 20000
26 #define DPDK_CRYPTO_CACHE_SIZE 512
27 #define DPDK_CRYPTO_PRIV_SIZE 128
28 #define DPDK_CRYPTO_N_QUEUE_DESC 1024
29 #define DPDK_CRYPTO_NB_COPS (1024 * 4)
32 add_del_sa_sess (u32 sa_index, u8 is_add)
34 dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
35 crypto_worker_main_t *cwm;
36 u8 skip_master = vlib_num_workers () > 0;
39 vec_foreach (cwm, dcm->workers_main)
41 crypto_sa_session_t *sa_sess;
50 for (is_outbound = 0; is_outbound < 2; is_outbound++)
54 pool_get (cwm->sa_sess_d[is_outbound], sa_sess);
61 sa_sess = pool_elt_at_index (cwm->sa_sess_d[is_outbound], sa_index);
62 dev_id = cwm->qp_data[sa_sess->qp_index].dev_id;
67 ret = (rte_cryptodev_sym_session_free(dev_id, sa_sess->sess) == NULL);
70 ret = rte_cryptodev_sym_session_clear(dev_id, sa_sess->sess);
73 ret = rte_cryptodev_sym_session_free(sa_sess->sess);
76 memset(sa_sess, 0, sizeof(sa_sess[0]));
86 update_qp_data (crypto_worker_main_t * cwm,
87 u8 cdev_id, u16 qp_id, u8 is_outbound, u16 * idx)
89 crypto_qp_data_t *qpd;
92 vec_foreach_index (*idx, cwm->qp_data)
94 qpd = vec_elt_at_index(cwm->qp_data, *idx);
96 if (qpd->dev_id == cdev_id && qpd->qp_id == qp_id &&
97 qpd->is_outbound == is_outbound)
102 vec_add2_aligned (cwm->qp_data, qpd, 1, CLIB_CACHE_LINE_BYTES);
104 qpd->dev_id = cdev_id;
106 qpd->is_outbound = is_outbound;
115 add_mapping (crypto_worker_main_t * cwm,
116 u8 cdev_id, u16 qp, u8 is_outbound,
117 const struct rte_cryptodev_capabilities *cipher_cap,
118 const struct rte_cryptodev_capabilities *auth_cap)
121 uword key = 0, data, *ret;
122 crypto_worker_qp_key_t *p_key = (crypto_worker_qp_key_t *) & key;
124 p_key->cipher_algo = (u8) cipher_cap->sym.cipher.algo;
125 p_key->auth_algo = (u8) auth_cap->sym.auth.algo;
126 p_key->is_outbound = is_outbound;
128 p_key->is_aead = cipher_cap->sym.xform_type == RTE_CRYPTO_SYM_XFORM_AEAD;
131 ret = hash_get (cwm->algo_qp_map, key);
135 update_qp_data (cwm, cdev_id, qp, is_outbound, &qp_index);
137 data = (uword) qp_index;
138 hash_set (cwm->algo_qp_map, key, data);
149 add_cdev_mapping (crypto_worker_main_t * cwm,
150 struct rte_cryptodev_info *dev_info, u8 cdev_id,
151 u16 qp, u8 is_outbound)
153 const struct rte_cryptodev_capabilities *i, *j;
156 for (i = dev_info->capabilities; i->op != RTE_CRYPTO_OP_TYPE_UNDEFINED; i++)
159 if (i->sym.xform_type == RTE_CRYPTO_SYM_XFORM_AEAD)
161 struct rte_cryptodev_capabilities none = { 0 };
163 if (check_algo_is_supported (i, NULL) != 0)
166 none.sym.auth.algo = RTE_CRYPTO_AUTH_NULL;
168 mapped |= add_mapping (cwm, cdev_id, qp, is_outbound, i, &none);
172 if (i->sym.xform_type != RTE_CRYPTO_SYM_XFORM_CIPHER)
175 if (check_algo_is_supported (i, NULL) != 0)
178 for (j = dev_info->capabilities; j->op != RTE_CRYPTO_OP_TYPE_UNDEFINED;
181 if (j->sym.xform_type != RTE_CRYPTO_SYM_XFORM_AUTH)
184 if (check_algo_is_supported (j, NULL) != 0)
187 mapped |= add_mapping (cwm, cdev_id, qp, is_outbound, i, j);
195 check_cryptodev_queues ()
201 if (vlib_num_workers () > 0)
202 n_req_qs = vlib_num_workers () * 2;
204 for (cdev_id = 0; cdev_id < rte_cryptodev_count (); cdev_id++)
206 struct rte_cryptodev_info cdev_info;
208 rte_cryptodev_info_get (cdev_id, &cdev_info);
211 (cdev_info.feature_flags & RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING))
214 n_qs += cdev_info.max_nb_queue_pairs;
217 if (n_qs >= n_req_qs)
223 static clib_error_t *
224 dpdk_ipsec_check_support (ipsec_sa_t * sa)
226 if (sa->crypto_alg == IPSEC_CRYPTO_ALG_AES_GCM_128)
228 if (sa->integ_alg != IPSEC_INTEG_ALG_NONE)
229 return clib_error_return (0, "unsupported integ-alg %U with "
230 "crypto-alg aes-gcm-128",
231 format_ipsec_integ_alg, sa->integ_alg);
233 sa->integ_alg = IPSEC_INTEG_ALG_AES_GCM_128;
237 else if (sa->crypto_alg == IPSEC_CRYPTO_ALG_NONE ||
238 sa->integ_alg == IPSEC_INTEG_ALG_NONE ||
239 sa->integ_alg == IPSEC_INTEG_ALG_AES_GCM_128)
241 else if (sa->integ_alg == IPSEC_INTEG_ALG_NONE)
243 return clib_error_return (0,
244 "unsupported integ-alg %U with crypto-alg %U",
245 format_ipsec_integ_alg, sa->integ_alg,
246 format_ipsec_crypto_alg, sa->crypto_alg);
252 dpdk_ipsec_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
255 ipsec_main_t *im = &ipsec_main;
256 dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
257 vlib_thread_main_t *tm = vlib_get_thread_main ();
258 struct rte_cryptodev_config dev_conf;
259 struct rte_cryptodev_qp_conf qp_conf;
260 struct rte_cryptodev_info cdev_info;
261 struct rte_mempool *rmp;
265 u32 max_sess_size = 0, sess_size;
269 if (check_cryptodev_queues () < 0)
271 clib_warning ("not enough Cryptodevs, default to OpenSSL IPsec");
276 vec_alloc (dcm->workers_main, tm->n_vlib_mains);
277 _vec_len (dcm->workers_main) = tm->n_vlib_mains;
279 fprintf (stdout, "DPDK Cryptodevs info:\n");
280 fprintf (stdout, "dev_id\tn_qp\tnb_obj\tcache_size\n");
281 /* HW cryptodevs have higher dev_id, use HW first */
282 for (dev_id = rte_cryptodev_count () - 1; dev_id >= 0; dev_id--)
284 u16 max_nb_qp, qp = 0;
285 skip_master = vlib_num_workers () > 0;
287 rte_cryptodev_info_get (dev_id, &cdev_info);
290 (cdev_info.feature_flags & RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING))
293 max_nb_qp = cdev_info.max_nb_queue_pairs;
295 for (i = 0; i < tm->n_vlib_mains; i++)
298 crypto_worker_main_t *cwm;
307 cwm = vec_elt_at_index (dcm->workers_main, i);
308 map = cwm->algo_qp_map;
312 map = hash_create (0, sizeof (crypto_worker_qp_key_t));
315 clib_warning ("unable to create hash table for worker %u",
316 vlib_mains[i]->thread_index);
319 cwm->algo_qp_map = map;
322 for (is_outbound = 0; is_outbound < 2 && qp < max_nb_qp;
324 qp += add_cdev_mapping (cwm, &cdev_info, dev_id, qp, is_outbound);
330 dev_conf.socket_id = rte_cryptodev_socket_id (dev_id);
331 dev_conf.nb_queue_pairs = cdev_info.max_nb_queue_pairs;
333 dev_conf.session_mp.nb_objs = DPDK_CRYPTO_NB_SESS_OBJS;
334 dev_conf.session_mp.cache_size = DPDK_CRYPTO_CACHE_SIZE;
336 ret = rte_cryptodev_configure (dev_id, &dev_conf);
339 clib_warning ("cryptodev %u config error", dev_id);
343 qp_conf.nb_descriptors = DPDK_CRYPTO_N_QUEUE_DESC;
344 for (qp = 0; qp < dev_conf.nb_queue_pairs; qp++)
347 ret = rte_cryptodev_queue_pair_setup (dev_id, qp, &qp_conf,
350 ret = rte_cryptodev_queue_pair_setup (dev_id, qp, &qp_conf,
351 dev_conf.socket_id, NULL);
355 clib_warning ("cryptodev %u qp %u setup error", dev_id, qp);
359 vec_validate (dcm->cop_pools, dev_conf.socket_id);
362 sess_size = rte_cryptodev_get_private_session_size (dev_id);
363 if (sess_size > max_sess_size)
364 max_sess_size = sess_size;
367 if (!vec_elt (dcm->cop_pools, dev_conf.socket_id))
369 u8 *pool_name = format (0, "crypto_op_pool_socket%u%c",
370 dev_conf.socket_id, 0);
372 rmp = rte_crypto_op_pool_create ((char *) pool_name,
373 RTE_CRYPTO_OP_TYPE_SYMMETRIC,
374 DPDK_CRYPTO_NB_COPS *
375 (1 + vlib_num_workers ()),
376 DPDK_CRYPTO_CACHE_SIZE,
377 DPDK_CRYPTO_PRIV_SIZE,
382 clib_warning ("failed to allocate %s", pool_name);
383 vec_free (pool_name);
386 vec_free (pool_name);
387 vec_elt (dcm->cop_pools, dev_conf.socket_id) = rmp;
390 fprintf (stdout, "%u\t%u\t%u\t%u\n", dev_id, dev_conf.nb_queue_pairs,
391 DPDK_CRYPTO_NB_SESS_OBJS, DPDK_CRYPTO_CACHE_SIZE);
396 vec_foreach_index (socket_id, dcm->cop_pools)
400 if (!vec_elt (dcm->cop_pools, socket_id))
403 vec_validate (dcm->sess_h_pools, socket_id);
404 pool_name = format (0, "crypto_sess_h_socket%u%c",
407 rte_mempool_create((i8 *)pool_name, DPDK_CRYPTO_NB_SESS_OBJS,
408 rte_cryptodev_get_header_session_size (),
409 512, 0, NULL, NULL, NULL, NULL,
413 clib_warning ("failed to allocate %s", pool_name);
414 vec_free (pool_name);
417 vec_free (pool_name);
418 vec_elt (dcm->sess_h_pools, socket_id) = rmp;
420 vec_validate (dcm->sess_pools, socket_id);
421 pool_name = format (0, "crypto_sess_socket%u%c",
424 rte_mempool_create((i8 *)pool_name, DPDK_CRYPTO_NB_SESS_OBJS,
425 max_sess_size, 512, 0, NULL, NULL, NULL, NULL,
429 clib_warning ("failed to allocate %s", pool_name);
430 vec_free (pool_name);
433 vec_free (pool_name);
434 vec_elt (dcm->sess_pools, socket_id) = rmp;
441 /* Add new next node and set as default */
442 vlib_node_t *node, *next_node;
444 next_node = vlib_get_node_by_name (vm, (u8 *) "dpdk-esp-encrypt");
446 node = vlib_get_node_by_name (vm, (u8 *) "ipsec-output-ip4");
448 im->esp_encrypt_node_index = next_node->index;
449 im->esp_encrypt_next_index =
450 vlib_node_add_next (vm, node->index, next_node->index);
452 next_node = vlib_get_node_by_name (vm, (u8 *) "dpdk-esp-decrypt");
454 node = vlib_get_node_by_name (vm, (u8 *) "ipsec-input-ip4");
456 im->esp_decrypt_node_index = next_node->index;
457 im->esp_decrypt_next_index =
458 vlib_node_add_next (vm, node->index, next_node->index);
460 im->cb.check_support_cb = dpdk_ipsec_check_support;
461 im->cb.add_del_sa_sess_cb = add_del_sa_sess;
463 for (i = 1; i < tm->n_vlib_mains; i++)
464 vlib_node_set_state (vlib_mains[i], dpdk_crypto_input_node.index,
465 VLIB_NODE_STATE_POLLING);
467 /* TODO cryptodev counters */
473 crypto_worker_main_t *cwm;
474 struct rte_mempool **mp;
476 vec_foreach (cwm, dcm->workers_main)
477 hash_free (cwm->algo_qp_map);
479 vec_foreach (mp, dcm->cop_pools)
482 rte_mempool_free (mp[0]);
485 vec_free (dcm->workers_main);
486 vec_free (dcm->cop_pools);
492 VLIB_REGISTER_NODE (dpdk_ipsec_process_node,static) = {
493 .function = dpdk_ipsec_process,
494 .type = VLIB_NODE_TYPE_PROCESS,
495 .name = "dpdk-ipsec-process",
496 .process_log2_n_stack_bytes = 17,
501 * fd.io coding-style-patch-verification: ON
504 * eval: (c-set-style "gnu")