crypto-input impprovement:
[vpp.git] / src / plugins / dpdk / ipsec / crypto_node.c
1 /*
2  *------------------------------------------------------------------
3  * crypto_node.c - DPDK Cryptodev input node
4  *
5  * Copyright (c) 2017 Intel and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a opy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19
20 #include <vlib/vlib.h>
21 #include <vnet/ip/ip.h>
22 #include <vnet/ethernet/ethernet.h>
23 #include <vnet/ipsec/ipsec.h>
24
25 #include <dpdk/device/dpdk.h>
26 #include <dpdk/device/dpdk_priv.h>
27 #include <dpdk/ipsec/ipsec.h>
28
29 #define foreach_dpdk_crypto_input_error         \
30   _(DQ_COPS, "Crypto ops dequeued")             \
31   _(AUTH_FAILED, "Crypto verification failed")        \
32   _(STATUS, "Crypto operation failed")
33
34 typedef enum
35 {
36 #define _(f,s) DPDK_CRYPTO_INPUT_ERROR_##f,
37   foreach_dpdk_crypto_input_error
38 #undef _
39     DPDK_CRYPTO_INPUT_N_ERROR,
40 } dpdk_crypto_input_error_t;
41
42 static char *dpdk_crypto_input_error_strings[] = {
43 #define _(n, s) s,
44   foreach_dpdk_crypto_input_error
45 #undef _
46 };
47
48 extern vlib_node_registration_t dpdk_crypto_input_node;
49
50 typedef struct
51 {
52   u32 status;
53 } dpdk_crypto_input_trace_t;
54
55 #define foreach_cryptodev_status \
56     _(SUCCESS, "success") \
57     _(NOT_PROCESSED, "not processed") \
58     _(AUTH_FAILED, "auth failed") \
59     _(INVALID_SESSION, "invalid session") \
60     _(INVALID_ARGS, "invalid arguments") \
61     _(ERROR, "error")
62
63 static u8 *
64 format_cryptodev_status (u8 * s, va_list * args)
65 {
66   u32 status = va_arg (*args, u32);
67   char *str = 0;
68
69   switch (status)
70     {
71 #define _(x, z) case RTE_CRYPTO_OP_STATUS_##x: str = z; break;
72       foreach_cryptodev_status
73 #undef _
74     }
75   s = format (s, "%s", str);
76
77   return s;
78 }
79
80 static u8 *
81 format_dpdk_crypto_input_trace (u8 * s, va_list * args)
82 {
83   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
84   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
85   dpdk_crypto_input_trace_t *t = va_arg (*args, dpdk_crypto_input_trace_t *);
86
87   s = format (s, "status: %U", format_cryptodev_status, t->status);
88
89   return s;
90 }
91
92 static_always_inline void
93 dpdk_crypto_check_check_op (vlib_main_t * vm, vlib_node_runtime_t * node,
94                             struct rte_crypto_op *op0, u16 * next)
95 {
96   if (PREDICT_FALSE (op0->status != RTE_CRYPTO_OP_STATUS_SUCCESS))
97     {
98       next[0] = DPDK_CRYPTO_INPUT_NEXT_DROP;
99       vlib_node_increment_counter (vm,
100                                    node->node_index,
101                                    DPDK_CRYPTO_INPUT_ERROR_STATUS, 1);
102       /* if auth failed */
103       if (op0->status == RTE_CRYPTO_OP_STATUS_AUTH_FAILED)
104         vlib_node_increment_counter (vm,
105                                      node->node_index,
106                                      DPDK_CRYPTO_INPUT_ERROR_AUTH_FAILED, 1);
107     }
108 }
109
110 always_inline void
111 dpdk_crypto_input_trace (vlib_main_t * vm, vlib_node_runtime_t * node,
112                          struct rte_crypto_op **ops, u32 n_deq)
113 {
114   u32 n_left, n_trace;
115   if (PREDICT_FALSE ((n_trace = vlib_get_trace_count (vm, node))))
116     {
117       n_left = n_deq;
118
119       while (n_trace && n_left)
120         {
121           vlib_buffer_t *b0;
122           struct rte_crypto_op *op0;
123           u16 next;
124
125           op0 = ops[0];
126
127           next = crypto_op_get_priv (op0)->next;
128
129           b0 = vlib_buffer_from_rte_mbuf (op0->sym[0].m_src);
130
131           vlib_trace_buffer (vm, node, next, b0, /* follow_chain */ 0);
132
133           dpdk_crypto_input_trace_t *tr =
134             vlib_add_trace (vm, node, b0, sizeof (*tr));
135           tr->status = op0->status;
136
137           n_trace--;
138           n_left--;
139           ops++;
140         }
141       vlib_set_trace_count (vm, node, n_trace);
142     }
143 }
144
145 static_always_inline u32
146 dpdk_crypto_dequeue (vlib_main_t * vm, vlib_node_runtime_t * node,
147                      crypto_resource_t * res, u8 outbound)
148 {
149   u32 thread_idx = vlib_get_thread_index ();
150   u8 numa = rte_socket_id ();
151
152   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
153   crypto_worker_main_t *cwm =
154     vec_elt_at_index (dcm->workers_main, thread_idx);
155
156   u32 n_ops, n_deq;
157   u32 bis[VLIB_FRAME_SIZE], *bi;
158   u16 nexts[VLIB_FRAME_SIZE], *next;
159   struct rte_crypto_op **ops;
160
161   bi = bis;
162   next = nexts;
163   ops = cwm->ops;
164
165   n_ops = n_deq = rte_cryptodev_dequeue_burst (res->dev_id,
166                                                res->qp_id + outbound,
167                                                ops, VLIB_FRAME_SIZE);
168
169   res->inflights[outbound] -= n_ops;
170
171   dpdk_crypto_input_trace (vm, node, ops, n_deq);
172
173   while (n_ops >= 4)
174     {
175       struct rte_crypto_op *op0, *op1, *op2, *op3;
176       vlib_buffer_t *b0, *b1, *b2, *b3;
177
178       /* Prefetch next iteration. */
179       if (n_ops >= 8)
180         {
181           CLIB_PREFETCH (ops[4], CLIB_CACHE_LINE_BYTES, LOAD);
182           CLIB_PREFETCH (ops[5], CLIB_CACHE_LINE_BYTES, LOAD);
183           CLIB_PREFETCH (ops[6], CLIB_CACHE_LINE_BYTES, LOAD);
184           CLIB_PREFETCH (ops[7], CLIB_CACHE_LINE_BYTES, LOAD);
185
186           CLIB_PREFETCH (crypto_op_get_priv (ops[4]), CLIB_CACHE_LINE_BYTES,
187                          LOAD);
188           CLIB_PREFETCH (crypto_op_get_priv (ops[5]), CLIB_CACHE_LINE_BYTES,
189                          LOAD);
190           CLIB_PREFETCH (crypto_op_get_priv (ops[6]), CLIB_CACHE_LINE_BYTES,
191                          LOAD);
192           CLIB_PREFETCH (crypto_op_get_priv (ops[7]), CLIB_CACHE_LINE_BYTES,
193                          LOAD);
194         }
195
196       op0 = ops[0];
197       op1 = ops[1];
198       op2 = ops[2];
199       op3 = ops[3];
200
201       next[0] = crypto_op_get_priv (op0)->next;
202       next[1] = crypto_op_get_priv (op1)->next;
203       next[2] = crypto_op_get_priv (op2)->next;
204       next[3] = crypto_op_get_priv (op3)->next;
205
206       dpdk_crypto_check_check_op (vm, node, op0, next + 0);
207       dpdk_crypto_check_check_op (vm, node, op0, next + 1);
208       dpdk_crypto_check_check_op (vm, node, op0, next + 2);
209       dpdk_crypto_check_check_op (vm, node, op0, next + 3);
210
211       b0 = vlib_buffer_from_rte_mbuf (op0->sym[0].m_src);
212       b1 = vlib_buffer_from_rte_mbuf (op1->sym[0].m_src);
213       b2 = vlib_buffer_from_rte_mbuf (op2->sym[0].m_src);
214       b3 = vlib_buffer_from_rte_mbuf (op3->sym[0].m_src);
215
216       bi[0] = vlib_get_buffer_index (vm, b0);
217       bi[1] = vlib_get_buffer_index (vm, b1);
218       bi[2] = vlib_get_buffer_index (vm, b2);
219       bi[3] = vlib_get_buffer_index (vm, b3);
220
221       op0->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
222       op1->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
223       op2->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
224       op3->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
225
226       /* next */
227       next += 4;
228       n_ops -= 4;
229       ops += 4;
230       bi += 4;
231     }
232   while (n_ops > 0)
233     {
234       struct rte_crypto_op *op0;
235       vlib_buffer_t *b0;
236
237       op0 = ops[0];
238
239       next[0] = crypto_op_get_priv (op0)->next;
240
241       dpdk_crypto_check_check_op (vm, node, op0, next + 0);
242
243       /* XXX store bi0 and next0 in op0 private? */
244       b0 = vlib_buffer_from_rte_mbuf (op0->sym[0].m_src);
245       bi[0] = vlib_get_buffer_index (vm, b0);
246
247       op0->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
248
249       /* next */
250       next += 1;
251       n_ops -= 1;
252       ops += 1;
253       bi += 1;
254     }
255
256   vlib_node_increment_counter (vm, node->node_index,
257                                DPDK_CRYPTO_INPUT_ERROR_DQ_COPS, n_deq);
258
259   vlib_buffer_enqueue_to_next (vm, node, bis, nexts, n_deq);
260
261   crypto_free_ops (numa, cwm->ops, n_deq);
262
263   return n_deq;
264 }
265
266 static_always_inline uword
267 dpdk_crypto_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
268                           vlib_frame_t * frame)
269 {
270   u32 thread_index = vlib_get_thread_index ();
271   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
272   crypto_worker_main_t *cwm = &dcm->workers_main[thread_index];
273   crypto_resource_t *res;
274   u32 n_deq = 0;
275   u16 *remove = NULL, *res_idx;
276   word i;
277
278   /* *INDENT-OFF* */
279   vec_foreach (res_idx, cwm->resource_idx)
280     {
281       res = vec_elt_at_index (dcm->resource, res_idx[0]);
282
283       if (res->inflights[0])
284         n_deq += dpdk_crypto_dequeue (vm, node, res, 0);
285
286       if (res->inflights[1])
287         n_deq += dpdk_crypto_dequeue (vm, node, res, 1);
288
289       if (PREDICT_FALSE (res->remove && !(res->inflights[0] || res->inflights[1])))
290         vec_add1 (remove, res_idx[0]);
291     }
292   /* *INDENT-ON* */
293
294   /* TODO removal on master thread? */
295   if (PREDICT_FALSE (remove != NULL))
296     {
297       /* *INDENT-OFF* */
298       vec_foreach (res_idx, remove)
299         {
300           i = vec_search (cwm->resource_idx, res_idx[0]);
301           vec_del1 (cwm->resource_idx, i);
302
303           res = vec_elt_at_index (dcm->resource, res_idx[0]);
304           res->thread_idx = (u16) ~0;
305           res->remove = 0;
306
307           i = vec_search (dcm->dev[res->dev_id].used_resources, res_idx[0]);
308           ASSERT (i != (u16) ~0);
309           vec_del1 (dcm->dev[res->dev_id].used_resources, i);
310           vec_add1 (dcm->dev[res->dev_id].free_resources, res_idx[0]);
311         }
312       /* *INDENT-ON* */
313
314       vec_free (remove);
315     }
316
317   return n_deq;
318 }
319
320 VLIB_NODE_FN (dpdk_crypto_input_node) (vlib_main_t * vm,
321                                        vlib_node_runtime_t * node,
322                                        vlib_frame_t * from_frame)
323 {
324   return dpdk_crypto_input_inline (vm, node, from_frame);
325 }
326
327 /* *INDENT-OFF* */
328 VLIB_REGISTER_NODE (dpdk_crypto_input_node) =
329 {
330   .name = "dpdk-crypto-input",
331   .format_trace = format_dpdk_crypto_input_trace,
332   .type = VLIB_NODE_TYPE_INPUT,
333   .state = VLIB_NODE_STATE_DISABLED,
334   .n_errors = DPDK_CRYPTO_INPUT_N_ERROR,
335   .error_strings = dpdk_crypto_input_error_strings,
336   .n_next_nodes = DPDK_CRYPTO_INPUT_N_NEXT,
337   .next_nodes =
338   {
339 #define _(s,n) [DPDK_CRYPTO_INPUT_NEXT_##s] = n,
340     foreach_dpdk_crypto_input_next
341 #undef _
342   },
343 };
344 /* *INDENT-ON* */
345
346 /*
347  * fd.io coding-style-patch-verification: ON
348  *
349  * Local Variables:
350  * eval: (c-set-style "gnu")
351  * End:
352  */