ipsec: one thread index per-SA
[vpp.git] / src / vnet / ipsec / ipsec_handoff.c
1 /*
2  * esp_encrypt.c : IPSec ESP encrypt node
3  *
4  * Copyright (c) 2015 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <vnet/ipsec/ipsec.h>
19 #include <vnet/ipsec/ipsec_sa.h>
20
21 #define foreach_ipsec_handoff_error  \
22 _(CONGESTION_DROP, "congestion drop")
23
24 typedef enum
25 {
26 #define _(sym,str) IPSEC_HANDOFF_ERROR_##sym,
27   foreach_ipsec_handoff_error
28 #undef _
29     NAT44_HANDOFF_N_ERROR,
30 } ipsec_handoff_error_t;
31
32 static char *ipsec_handoff_error_strings[] = {
33 #define _(sym,string) string,
34   foreach_ipsec_handoff_error
35 #undef _
36 };
37
38 typedef struct ipsec_handoff_trace_t_
39 {
40   u32 next_worker_index;
41 } ipsec_handoff_trace_t;
42
43 static u8 *
44 format_ipsec_handoff_trace (u8 * s, va_list * args)
45 {
46   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
47   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
48   ipsec_handoff_trace_t *t = va_arg (*args, ipsec_handoff_trace_t *);
49
50   s = format (s, "next-worker %d", t->next_worker_index);
51
52   return s;
53 }
54
55 /* do worker handoff based on thread_index in NAT HA protcol header */
56 static_always_inline uword
57 ipsec_handoff (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame,
58                u32 fq_index)
59 {
60   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
61   u16 thread_indices[VLIB_FRAME_SIZE], *ti;
62   u32 n_enq, n_left_from, *from;
63   ipsec_main_t *im;
64
65   im = &ipsec_main;
66   from = vlib_frame_vector_args (frame);
67   n_left_from = frame->n_vectors;
68   vlib_get_buffers (vm, from, bufs, n_left_from);
69
70   b = bufs;
71   ti = thread_indices;
72
73   while (n_left_from >= 4)
74     {
75       ipsec_sa_t *sa0, *sa1, *sa2, *sa3;
76       u32 sai0, sai1, sai2, sai3;
77
78       /* Prefetch next iteration. */
79       if (n_left_from >= 12)
80         {
81           vlib_prefetch_buffer_header (b[8], LOAD);
82           vlib_prefetch_buffer_header (b[9], LOAD);
83           vlib_prefetch_buffer_header (b[10], LOAD);
84           vlib_prefetch_buffer_header (b[11], LOAD);
85
86           vlib_prefetch_buffer_data (b[4], LOAD);
87           vlib_prefetch_buffer_data (b[5], LOAD);
88           vlib_prefetch_buffer_data (b[6], LOAD);
89           vlib_prefetch_buffer_data (b[7], LOAD);
90         }
91
92       sai0 = vnet_buffer (b[0])->ipsec.sad_index;
93       sai1 = vnet_buffer (b[1])->ipsec.sad_index;
94       sai2 = vnet_buffer (b[2])->ipsec.sad_index;
95       sai3 = vnet_buffer (b[3])->ipsec.sad_index;
96       sa0 = pool_elt_at_index (im->sad, sai0);
97       sa1 = pool_elt_at_index (im->sad, sai1);
98       sa2 = pool_elt_at_index (im->sad, sai2);
99       sa3 = pool_elt_at_index (im->sad, sai3);
100
101       ti[0] = sa0->thread_index;
102       ti[1] = sa1->thread_index;
103       ti[2] = sa2->thread_index;
104       ti[3] = sa3->thread_index;
105
106       if (node->flags & VLIB_NODE_FLAG_TRACE)
107         {
108           if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
109             {
110               ipsec_handoff_trace_t *t =
111                 vlib_add_trace (vm, node, b[0], sizeof (*t));
112               t->next_worker_index = ti[0];
113             }
114           if (PREDICT_FALSE (b[1]->flags & VLIB_BUFFER_IS_TRACED))
115             {
116               ipsec_handoff_trace_t *t =
117                 vlib_add_trace (vm, node, b[1], sizeof (*t));
118               t->next_worker_index = ti[1];
119             }
120           if (PREDICT_FALSE (b[2]->flags & VLIB_BUFFER_IS_TRACED))
121             {
122               ipsec_handoff_trace_t *t =
123                 vlib_add_trace (vm, node, b[2], sizeof (*t));
124               t->next_worker_index = ti[2];
125             }
126           if (PREDICT_FALSE (b[3]->flags & VLIB_BUFFER_IS_TRACED))
127             {
128               ipsec_handoff_trace_t *t =
129                 vlib_add_trace (vm, node, b[3], sizeof (*t));
130               t->next_worker_index = ti[3];
131             }
132         }
133
134       n_left_from -= 4;
135       ti += 4;
136       b += 4;
137     }
138   while (n_left_from > 0)
139     {
140       ipsec_sa_t *sa0;
141       u32 sai0;
142
143       sai0 = vnet_buffer (b[0])->ipsec.sad_index;
144       sa0 = pool_elt_at_index (im->sad, sai0);
145
146       ti[0] = sa0->thread_index;
147
148       if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
149         {
150           ipsec_handoff_trace_t *t =
151             vlib_add_trace (vm, node, b[0], sizeof (*t));
152           t->next_worker_index = ti[0];
153         }
154
155       n_left_from -= 1;
156       ti += 1;
157       b += 1;
158     }
159
160   n_enq = vlib_buffer_enqueue_to_thread (vm, fq_index, from,
161                                          thread_indices, frame->n_vectors, 1);
162
163   if (n_enq < frame->n_vectors)
164     vlib_node_increment_counter (vm, node->node_index,
165                                  IPSEC_HANDOFF_ERROR_CONGESTION_DROP,
166                                  frame->n_vectors - n_enq);
167
168   return n_enq;
169 }
170
171 VLIB_NODE_FN (esp4_encrypt_handoff) (vlib_main_t * vm,
172                                      vlib_node_runtime_t * node,
173                                      vlib_frame_t * from_frame)
174 {
175   ipsec_main_t *im = &ipsec_main;
176
177   return ipsec_handoff (vm, node, from_frame, im->esp4_enc_fq_index);
178 }
179
180 VLIB_NODE_FN (esp6_encrypt_handoff) (vlib_main_t * vm,
181                                      vlib_node_runtime_t * node,
182                                      vlib_frame_t * from_frame)
183 {
184   ipsec_main_t *im = &ipsec_main;
185
186   return ipsec_handoff (vm, node, from_frame, im->esp6_enc_fq_index);
187 }
188
189 VLIB_NODE_FN (esp4_encrypt_tun_handoff) (vlib_main_t * vm,
190                                          vlib_node_runtime_t * node,
191                                          vlib_frame_t * from_frame)
192 {
193   ipsec_main_t *im = &ipsec_main;
194
195   return ipsec_handoff (vm, node, from_frame, im->esp4_enc_tun_fq_index);
196 }
197
198 VLIB_NODE_FN (esp6_encrypt_tun_handoff) (vlib_main_t * vm,
199                                          vlib_node_runtime_t * node,
200                                          vlib_frame_t * from_frame)
201 {
202   ipsec_main_t *im = &ipsec_main;
203
204   return ipsec_handoff (vm, node, from_frame, im->esp6_enc_tun_fq_index);
205 }
206
207 VLIB_NODE_FN (esp_mpls_encrypt_tun_handoff)
208 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
209 {
210   ipsec_main_t *im = &ipsec_main;
211
212   return ipsec_handoff (vm, node, from_frame, im->esp_mpls_enc_tun_fq_index);
213 }
214
215 VLIB_NODE_FN (esp4_decrypt_handoff) (vlib_main_t * vm,
216                                      vlib_node_runtime_t * node,
217                                      vlib_frame_t * from_frame)
218 {
219   ipsec_main_t *im = &ipsec_main;
220
221   return ipsec_handoff (vm, node, from_frame, im->esp4_dec_fq_index);
222 }
223
224 VLIB_NODE_FN (esp6_decrypt_handoff) (vlib_main_t * vm,
225                                      vlib_node_runtime_t * node,
226                                      vlib_frame_t * from_frame)
227 {
228   ipsec_main_t *im = &ipsec_main;
229
230   return ipsec_handoff (vm, node, from_frame, im->esp6_dec_fq_index);
231 }
232
233 VLIB_NODE_FN (esp4_decrypt_tun_handoff) (vlib_main_t * vm,
234                                          vlib_node_runtime_t * node,
235                                          vlib_frame_t * from_frame)
236 {
237   ipsec_main_t *im = &ipsec_main;
238
239   return ipsec_handoff (vm, node, from_frame, im->esp4_dec_tun_fq_index);
240 }
241
242 VLIB_NODE_FN (esp6_decrypt_tun_handoff) (vlib_main_t * vm,
243                                          vlib_node_runtime_t * node,
244                                          vlib_frame_t * from_frame)
245 {
246   ipsec_main_t *im = &ipsec_main;
247
248   return ipsec_handoff (vm, node, from_frame, im->esp6_dec_tun_fq_index);
249 }
250
251 VLIB_NODE_FN (ah4_encrypt_handoff) (vlib_main_t * vm,
252                                     vlib_node_runtime_t * node,
253                                     vlib_frame_t * from_frame)
254 {
255   ipsec_main_t *im = &ipsec_main;
256
257   return ipsec_handoff (vm, node, from_frame, im->ah4_enc_fq_index);
258 }
259
260 VLIB_NODE_FN (ah6_encrypt_handoff) (vlib_main_t * vm,
261                                     vlib_node_runtime_t * node,
262                                     vlib_frame_t * from_frame)
263 {
264   ipsec_main_t *im = &ipsec_main;
265
266   return ipsec_handoff (vm, node, from_frame, im->ah6_enc_fq_index);
267 }
268
269 VLIB_NODE_FN (ah4_decrypt_handoff) (vlib_main_t * vm,
270                                     vlib_node_runtime_t * node,
271                                     vlib_frame_t * from_frame)
272 {
273   ipsec_main_t *im = &ipsec_main;
274
275   return ipsec_handoff (vm, node, from_frame, im->ah4_dec_fq_index);
276 }
277
278 VLIB_NODE_FN (ah6_decrypt_handoff) (vlib_main_t * vm,
279                                     vlib_node_runtime_t * node,
280                                     vlib_frame_t * from_frame)
281 {
282   ipsec_main_t *im = &ipsec_main;
283
284   return ipsec_handoff (vm, node, from_frame, im->ah6_dec_fq_index);
285 }
286
287 /* *INDENT-OFF* */
288 VLIB_REGISTER_NODE (esp4_encrypt_handoff) = {
289   .name = "esp4-encrypt-handoff",
290   .vector_size = sizeof (u32),
291   .format_trace = format_ipsec_handoff_trace,
292   .type = VLIB_NODE_TYPE_INTERNAL,
293   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
294   .error_strings = ipsec_handoff_error_strings,
295   .n_next_nodes = 1,
296   .next_nodes = {
297     [0] = "error-drop",
298   },
299 };
300 VLIB_REGISTER_NODE (esp6_encrypt_handoff) = {
301   .name = "esp6-encrypt-handoff",
302   .vector_size = sizeof (u32),
303   .format_trace = format_ipsec_handoff_trace,
304   .type = VLIB_NODE_TYPE_INTERNAL,
305   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
306   .error_strings = ipsec_handoff_error_strings,
307   .n_next_nodes = 1,
308   .next_nodes = {
309     [0] = "error-drop",
310   },
311 };
312 VLIB_REGISTER_NODE (esp4_encrypt_tun_handoff) = {
313   .name = "esp4-encrypt-tun-handoff",
314   .vector_size = sizeof (u32),
315   .format_trace = format_ipsec_handoff_trace,
316   .type = VLIB_NODE_TYPE_INTERNAL,
317   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
318   .error_strings = ipsec_handoff_error_strings,
319   .n_next_nodes = 1,
320   .next_nodes = {
321     [0] = "error-drop",
322   },
323 };
324 VLIB_REGISTER_NODE (esp6_encrypt_tun_handoff) = {
325   .name = "esp6-encrypt-tun-handoff",
326   .vector_size = sizeof (u32),
327   .format_trace = format_ipsec_handoff_trace,
328   .type = VLIB_NODE_TYPE_INTERNAL,
329   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
330   .error_strings = ipsec_handoff_error_strings,
331   .n_next_nodes = 1,
332   .next_nodes = {
333     [0] = "error-drop",
334   },
335 };
336 VLIB_REGISTER_NODE (esp_mpls_encrypt_tun_handoff) = {
337   .name = "esp-mpls-encrypt-tun-handoff",
338   .vector_size = sizeof (u32),
339   .format_trace = format_ipsec_handoff_trace,
340   .type = VLIB_NODE_TYPE_INTERNAL,
341   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
342   .error_strings = ipsec_handoff_error_strings,
343   .n_next_nodes = 1,
344   .next_nodes = {
345     [0] = "error-drop",
346   },
347 };
348 VLIB_REGISTER_NODE (esp4_decrypt_handoff) = {
349   .name = "esp4-decrypt-handoff",
350   .vector_size = sizeof (u32),
351   .format_trace = format_ipsec_handoff_trace,
352   .type = VLIB_NODE_TYPE_INTERNAL,
353   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
354   .error_strings = ipsec_handoff_error_strings,
355   .n_next_nodes = 1,
356   .next_nodes = {
357     [0] = "error-drop",
358   },
359 };
360 VLIB_REGISTER_NODE (esp6_decrypt_handoff) = {
361   .name = "esp6-decrypt-handoff",
362   .vector_size = sizeof (u32),
363   .format_trace = format_ipsec_handoff_trace,
364   .type = VLIB_NODE_TYPE_INTERNAL,
365   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
366   .error_strings = ipsec_handoff_error_strings,
367   .n_next_nodes = 1,
368   .next_nodes = {
369     [0] = "error-drop",
370   },
371 };
372 VLIB_REGISTER_NODE (esp4_decrypt_tun_handoff) = {
373   .name = "esp4-decrypt-tun-handoff",
374   .vector_size = sizeof (u32),
375   .format_trace = format_ipsec_handoff_trace,
376   .type = VLIB_NODE_TYPE_INTERNAL,
377   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
378   .error_strings = ipsec_handoff_error_strings,
379   .n_next_nodes = 1,
380   .next_nodes = {
381     [0] = "error-drop",
382   },
383 };
384 VLIB_REGISTER_NODE (esp6_decrypt_tun_handoff) = {
385   .name = "esp6-decrypt-tun-handoff",
386   .vector_size = sizeof (u32),
387   .format_trace = format_ipsec_handoff_trace,
388   .type = VLIB_NODE_TYPE_INTERNAL,
389   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
390   .error_strings = ipsec_handoff_error_strings,
391   .n_next_nodes = 1,
392   .next_nodes = {
393     [0] = "error-drop",
394   },
395 };
396 VLIB_REGISTER_NODE (ah4_encrypt_handoff) = {
397   .name = "ah4-encrypt-handoff",
398   .vector_size = sizeof (u32),
399   .format_trace = format_ipsec_handoff_trace,
400   .type = VLIB_NODE_TYPE_INTERNAL,
401   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
402   .error_strings = ipsec_handoff_error_strings,
403   .n_next_nodes = 1,
404   .next_nodes = {
405     [0] = "error-drop",
406   },
407 };
408 VLIB_REGISTER_NODE (ah6_encrypt_handoff) = {
409   .name = "ah6-encrypt-handoff",
410   .vector_size = sizeof (u32),
411   .format_trace = format_ipsec_handoff_trace,
412   .type = VLIB_NODE_TYPE_INTERNAL,
413   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
414   .error_strings = ipsec_handoff_error_strings,
415   .n_next_nodes = 1,
416   .next_nodes = {
417     [0] = "error-drop",
418   },
419 };
420 VLIB_REGISTER_NODE (ah4_decrypt_handoff) = {
421   .name = "ah4-decrypt-handoff",
422   .vector_size = sizeof (u32),
423   .format_trace = format_ipsec_handoff_trace,
424   .type = VLIB_NODE_TYPE_INTERNAL,
425   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
426   .error_strings = ipsec_handoff_error_strings,
427   .n_next_nodes = 1,
428   .next_nodes = {
429     [0] = "error-drop",
430   },
431 };
432 VLIB_REGISTER_NODE (ah6_decrypt_handoff) = {
433   .name = "ah6-decrypt-handoff",
434   .vector_size = sizeof (u32),
435   .format_trace = format_ipsec_handoff_trace,
436   .type = VLIB_NODE_TYPE_INTERNAL,
437   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
438   .error_strings = ipsec_handoff_error_strings,
439   .n_next_nodes = 1,
440   .next_nodes = {
441     [0] = "error-drop",
442   },
443 };
444 /* *INDENT-ON* */
445
446 /*
447  * fd.io coding-style-patch-verification: ON
448  *
449  * Local Variables:
450  * eval: (c-set-style "gnu")
451  * End:
452  */