FD.io VPP  v17.01.1-3-gc6833f8
Vector Packet Processing
ipsec.c
Go to the documentation of this file.
1 /*
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:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15 #include <vnet/vnet.h>
16 #include <vnet/ip/ip.h>
17 #include <vnet/api_errno.h>
18 #include <vnet/devices/dpdk/dpdk.h>
21 #include <vnet/ipsec/ipsec.h>
22 
23 #define DPDK_CRYPTO_NB_OBJS 2048
24 #define DPDK_CRYPTO_CACHE_SIZE 512
25 #define DPDK_CRYPTO_PRIV_SIZE 128
26 #define DPDK_CRYPTO_N_QUEUE_DESC 512
27 #define DPDK_CRYPTO_NB_COPS (1024 * 4)
28 
29 /*
30  * return:
31  * -1: update failed
32  * 0: already exist
33  * 1: mapped
34  */
35 static int
37  u8 cdev_id, u16 qp_id, u8 is_outbound, u16 * idx)
38 {
39  crypto_qp_data_t *qpd;
40 
41  /* *INDENT-OFF* */
42  vec_foreach_index (*idx, cwm->qp_data)
43  {
44  qpd = vec_elt_at_index(cwm->qp_data, *idx);
45 
46  if (qpd->dev_id == cdev_id && qpd->qp_id == qp_id &&
47  qpd->is_outbound == is_outbound)
48  return 0;
49  }
50  /* *INDENT-ON* */
51 
52  vec_add2 (cwm->qp_data, qpd, 1);
53 
54  qpd->dev_id = cdev_id;
55  qpd->qp_id = qp_id;
56  qpd->is_outbound = is_outbound;
57 
58  return 1;
59 }
60 
61 /*
62  * return:
63  * -1: error
64  * 0: already exist
65  * 1: mapped
66  */
67 static int
69  u8 cdev_id, u16 qp, u8 is_outbound,
70  const struct rte_cryptodev_capabilities *cipher_cap,
71  const struct rte_cryptodev_capabilities *auth_cap)
72 {
73  int mapped;
74  u16 qp_index;
75  uword key = 0, data, *ret;
77 
78  p_key->cipher_algo = (u8) cipher_cap->sym.cipher.algo;
79  p_key->auth_algo = (u8) auth_cap->sym.auth.algo;
80  p_key->is_outbound = is_outbound;
81 
82  ret = hash_get (cwm->algo_qp_map, key);
83  if (ret)
84  return 0;
85 
86  mapped = update_qp_data (cwm, cdev_id, qp, is_outbound, &qp_index);
87  if (mapped < 0)
88  return -1;
89 
90  data = (uword) qp_index;
91 
92  ret = hash_set (cwm->algo_qp_map, key, data);
93  if (!ret)
94  rte_panic ("Failed to insert hash table\n");
95 
96  return mapped;
97 }
98 
99 /*
100  * return:
101  * 0: already exist
102  * 1: mapped
103  */
104 static int
106  struct rte_cryptodev_info *dev_info, u8 cdev_id,
107  u16 qp, u8 is_outbound)
108 {
109  const struct rte_cryptodev_capabilities *i, *j;
110  u32 mapped = 0;
111 
112  for (i = dev_info->capabilities; i->op != RTE_CRYPTO_OP_TYPE_UNDEFINED; i++)
113  {
114  if (i->sym.xform_type != RTE_CRYPTO_SYM_XFORM_CIPHER)
115  continue;
116 
117  if (check_algo_is_supported (i, NULL) != 0)
118  continue;
119 
120  for (j = dev_info->capabilities; j->op != RTE_CRYPTO_OP_TYPE_UNDEFINED;
121  j++)
122  {
123  int status = 0;
124 
125  if (j->sym.xform_type != RTE_CRYPTO_SYM_XFORM_AUTH)
126  continue;
127 
128  if (check_algo_is_supported (j, NULL) != 0)
129  continue;
130 
131  status = add_mapping (cwm, cdev_id, qp, is_outbound, i, j);
132  if (status == 1)
133  mapped += 1;
134  if (status < 0)
135  return status;
136  }
137  }
138 
139  return mapped;
140 }
141 
142 static int
144 {
145  u32 n_qs = 0;
146  u8 cdev_id;
147  u32 n_req_qs = 2;
148 
149  if (vlib_num_workers () > 0)
150  n_req_qs = vlib_num_workers () * 2;
151 
152  for (cdev_id = 0; cdev_id < rte_cryptodev_count (); cdev_id++)
153  {
154  struct rte_cryptodev_info cdev_info;
155 
156  rte_cryptodev_info_get (cdev_id, &cdev_info);
157 
158  if (!
159  (cdev_info.feature_flags & RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING))
160  continue;
161 
162  n_qs += cdev_info.max_nb_queue_pairs;
163  }
164 
165  if (n_qs >= n_req_qs)
166  return 0;
167  else
168  return -1;
169 }
170 
171 static clib_error_t *
173 {
176  struct rte_cryptodev_config dev_conf;
177  struct rte_cryptodev_qp_conf qp_conf;
178  struct rte_cryptodev_info cdev_info;
179  struct rte_mempool *rmp;
180  i32 dev_id, ret;
181  u32 i, skip_master;
182 
183  if (check_cryptodev_queues () < 0)
184  return clib_error_return (0, "not enough cryptodevs for ipsec");
185 
186  vec_alloc (dcm->workers_main, tm->n_vlib_mains);
187  _vec_len (dcm->workers_main) = tm->n_vlib_mains;
188 
189  fprintf (stdout, "DPDK Cryptodevs info:\n");
190  fprintf (stdout, "dev_id\tn_qp\tnb_obj\tcache_size\n");
191  /* HW cryptodevs have higher dev_id, use HW first */
192  for (dev_id = rte_cryptodev_count () - 1; dev_id >= 0; dev_id--)
193  {
194  u16 max_nb_qp, qp = 0;
195  skip_master = vlib_num_workers () > 0;
196 
197  rte_cryptodev_info_get (dev_id, &cdev_info);
198 
199  if (!
200  (cdev_info.feature_flags & RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING))
201  continue;
202 
203  max_nb_qp = cdev_info.max_nb_queue_pairs;
204 
205  for (i = 0; i < tm->n_vlib_mains; i++)
206  {
207  u8 is_outbound;
209  uword *map;
210 
211  if (skip_master)
212  {
213  skip_master = 0;
214  continue;
215  }
216 
217  cwm = vec_elt_at_index (dcm->workers_main, i);
218  map = cwm->algo_qp_map;
219 
220  if (!map)
221  {
222  map = hash_create (0, sizeof (crypto_worker_qp_key_t));
223  if (!map)
224  return clib_error_return (0, "unable to create hash table "
225  "for worker %u",
226  vlib_mains[i]->cpu_index);
227  cwm->algo_qp_map = map;
228  }
229 
230  for (is_outbound = 0; is_outbound < 2 && qp < max_nb_qp;
231  is_outbound++)
232  {
233  int mapped = add_cdev_mapping (cwm, &cdev_info,
234  dev_id, qp, is_outbound);
235  if (mapped > 0)
236  qp++;
237 
238  if (mapped < 0)
239  return clib_error_return (0,
240  "too many queues for one worker");
241  }
242  }
243 
244  if (qp == 0)
245  continue;
246 
247  dev_conf.socket_id = rte_cryptodev_socket_id (dev_id);
248  dev_conf.nb_queue_pairs = cdev_info.max_nb_queue_pairs;
249  dev_conf.session_mp.nb_objs = DPDK_CRYPTO_NB_OBJS;
250  dev_conf.session_mp.cache_size = DPDK_CRYPTO_CACHE_SIZE;
251 
252  ret = rte_cryptodev_configure (dev_id, &dev_conf);
253  if (ret < 0)
254  return clib_error_return (0, "cryptodev %u config error", dev_id);
255 
256  qp_conf.nb_descriptors = DPDK_CRYPTO_N_QUEUE_DESC;
257  for (qp = 0; qp < dev_conf.nb_queue_pairs; qp++)
258  {
259  ret = rte_cryptodev_queue_pair_setup (dev_id, qp, &qp_conf,
260  dev_conf.socket_id);
261  if (ret < 0)
262  return clib_error_return (0, "cryptodev %u qp %u setup error",
263  dev_id, qp);
264  }
265  fprintf (stdout, "%u\t%u\t%u\t%u\n", dev_id, dev_conf.nb_queue_pairs,
267  }
268 
269  u32 socket_id = rte_socket_id ();
270 
272 
273  /* pool already exists, nothing to do */
274  if (dcm->cop_pools[socket_id])
275  return 0;
276 
277  u8 *pool_name = format (0, "crypto_op_pool_socket%u%c", socket_id, 0);
278 
279  rmp = rte_crypto_op_pool_create ((char *) pool_name,
280  RTE_CRYPTO_OP_TYPE_SYMMETRIC,
282  (1 + vlib_num_workers ()),
284  DPDK_CRYPTO_PRIV_SIZE, socket_id);
285  vec_free (pool_name);
286 
287  if (!rmp)
288  return clib_error_return (0, "failed to allocate mempool on socket %u",
289  socket_id);
290  dcm->cop_pools[socket_id] = rmp;
291 
292  dpdk_esp_init ();
293 
294  if (vec_len (vlib_mains) == 0)
296  VLIB_NODE_STATE_POLLING);
297  else
298  for (i = 1; i < tm->n_vlib_mains; i++)
300  VLIB_NODE_STATE_POLLING);
301 
302  return 0;
303 }
304 
306 
307 /*
308  * fd.io coding-style-patch-verification: ON
309  *
310  * Local Variables:
311  * eval: (c-set-style "gnu")
312  * End:
313  */
static int add_mapping(crypto_worker_main_t *cwm, u8 cdev_id, u16 qp, u8 is_outbound, const struct rte_cryptodev_capabilities *cipher_cap, const struct rte_cryptodev_capabilities *auth_cap)
Definition: ipsec.c:68
#define vec_foreach_index(var, v)
Iterate over vector indices.
#define hash_set(h, key, value)
Definition: hash.h:254
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
static clib_error_t * dpdk_ipsec_init(vlib_main_t *vm)
Definition: ipsec.c:172
#define VLIB_MAIN_LOOP_ENTER_FUNCTION(x)
Definition: init.h:113
#define NULL
Definition: clib.h:55
u16 is_outbound
Definition: ipsec.h:61
unsigned rte_socket_id()
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:521
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:407
vlib_node_registration_t dpdk_crypto_input_node
(constructor) VLIB_REGISTER_NODE (dpdk_crypto_input_node)
Definition: crypto_node.c:58
static int update_qp_data(crypto_worker_main_t *cwm, u8 cdev_id, u16 qp_id, u8 is_outbound, u16 *idx)
Definition: ipsec.c:36
#define vec_alloc(V, N)
Allocate space for N more elements (no header, unspecified alignment)
Definition: vec.h:239
static int add_cdev_mapping(crypto_worker_main_t *cwm, struct rte_cryptodev_info *dev_info, u8 cdev_id, u16 qp, u8 is_outbound)
Definition: ipsec.c:105
uword * algo_qp_map
Definition: ipsec.h:78
#define DPDK_CRYPTO_NB_COPS
Definition: ipsec.c:27
int i32
Definition: types.h:81
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
dpdk_crypto_main_t dpdk_crypto_main
Definition: ipsec.h:87
#define hash_get(h, key)
Definition: hash.h:248
#define DPDK_CRYPTO_PRIV_SIZE
Definition: ipsec.c:25
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
#define DPDK_CRYPTO_NB_OBJS
Definition: ipsec.c:23
static_always_inline void dpdk_esp_init()
Definition: esp.h:44
vlib_main_t vlib_global_main
Definition: main.c:1562
#define DPDK_CRYPTO_N_QUEUE_DESC
Definition: ipsec.c:26
#define hash_create(elts, value_bytes)
Definition: hash.h:658
unsigned int u32
Definition: types.h:88
struct rte_mempool ** cop_pools
Definition: ipsec.h:83
crypto_worker_main_t * workers_main
Definition: ipsec.h:84
static void vlib_node_set_state(vlib_main_t *vm, u32 node_index, vlib_node_state_t new_state)
Set node dispatch state.
Definition: node_funcs.h:146
crypto_qp_data_t * qp_data
Definition: ipsec.h:77
u64 uword
Definition: types.h:112
unsigned short u16
Definition: types.h:57
static_always_inline int check_algo_is_supported(const struct rte_cryptodev_capabilities *cap, char *name)
Definition: ipsec.h:142
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
#define DPDK_CRYPTO_CACHE_SIZE
Definition: ipsec.c:24
static int check_cryptodev_queues()
Definition: ipsec.c:143
vlib_main_t ** vlib_mains
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
static u32 vlib_num_workers()
Definition: threads.h:340
#define clib_error_return(e, args...)
Definition: error.h:111
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67