4446f1e523ad9d3f21986a886313c0cc171ccc68
[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,
58                vlib_node_runtime_t * node,
59                vlib_frame_t * frame, u32 fq_index, bool is_enc)
60 {
61   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
62   u16 thread_indices[VLIB_FRAME_SIZE], *ti;
63   u32 n_enq, n_left_from, *from;
64   ipsec_main_t *im;
65
66   im = &ipsec_main;
67   from = vlib_frame_vector_args (frame);
68   n_left_from = frame->n_vectors;
69   vlib_get_buffers (vm, from, bufs, n_left_from);
70
71   b = bufs;
72   ti = thread_indices;
73
74   while (n_left_from >= 4)
75     {
76       ipsec_sa_t *sa0, *sa1, *sa2, *sa3;
77       u32 sai0, sai1, sai2, sai3;
78
79       /* Prefetch next iteration. */
80       if (n_left_from >= 12)
81         {
82           vlib_prefetch_buffer_header (b[8], LOAD);
83           vlib_prefetch_buffer_header (b[9], LOAD);
84           vlib_prefetch_buffer_header (b[10], LOAD);
85           vlib_prefetch_buffer_header (b[11], LOAD);
86
87           vlib_prefetch_buffer_data (b[4], LOAD);
88           vlib_prefetch_buffer_data (b[5], LOAD);
89           vlib_prefetch_buffer_data (b[6], LOAD);
90           vlib_prefetch_buffer_data (b[7], LOAD);
91         }
92
93       sai0 = vnet_buffer (b[0])->ipsec.sad_index;
94       sai1 = vnet_buffer (b[1])->ipsec.sad_index;
95       sai2 = vnet_buffer (b[2])->ipsec.sad_index;
96       sai3 = vnet_buffer (b[3])->ipsec.sad_index;
97       sa0 = pool_elt_at_index (im->sad, sai0);
98       sa1 = pool_elt_at_index (im->sad, sai1);
99       sa2 = pool_elt_at_index (im->sad, sai2);
100       sa3 = pool_elt_at_index (im->sad, sai3);
101
102       if (is_enc)
103         {
104           ti[0] = sa0->encrypt_thread_index;
105           ti[1] = sa1->encrypt_thread_index;
106           ti[2] = sa2->encrypt_thread_index;
107           ti[3] = sa3->encrypt_thread_index;
108         }
109       else
110         {
111           ti[0] = sa0->decrypt_thread_index;
112           ti[1] = sa1->decrypt_thread_index;
113           ti[2] = sa2->decrypt_thread_index;
114           ti[3] = sa3->decrypt_thread_index;
115         }
116
117       if (node->flags & VLIB_NODE_FLAG_TRACE)
118         {
119           if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
120             {
121               ipsec_handoff_trace_t *t =
122                 vlib_add_trace (vm, node, b[0], sizeof (*t));
123               t->next_worker_index = ti[0];
124             }
125           if (PREDICT_FALSE (b[1]->flags & VLIB_BUFFER_IS_TRACED))
126             {
127               ipsec_handoff_trace_t *t =
128                 vlib_add_trace (vm, node, b[1], sizeof (*t));
129               t->next_worker_index = ti[1];
130             }
131           if (PREDICT_FALSE (b[2]->flags & VLIB_BUFFER_IS_TRACED))
132             {
133               ipsec_handoff_trace_t *t =
134                 vlib_add_trace (vm, node, b[2], sizeof (*t));
135               t->next_worker_index = ti[2];
136             }
137           if (PREDICT_FALSE (b[3]->flags & VLIB_BUFFER_IS_TRACED))
138             {
139               ipsec_handoff_trace_t *t =
140                 vlib_add_trace (vm, node, b[3], sizeof (*t));
141               t->next_worker_index = ti[3];
142             }
143         }
144
145       n_left_from -= 4;
146       ti += 4;
147       b += 4;
148     }
149   while (n_left_from > 0)
150     {
151       ipsec_sa_t *sa0;
152       u32 sai0;
153
154       sai0 = vnet_buffer (b[0])->ipsec.sad_index;
155       sa0 = pool_elt_at_index (im->sad, sai0);
156
157       if (is_enc)
158         ti[0] = sa0->encrypt_thread_index;
159       else
160         ti[0] = sa0->decrypt_thread_index;
161
162       if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
163         {
164           ipsec_handoff_trace_t *t =
165             vlib_add_trace (vm, node, b[0], sizeof (*t));
166           t->next_worker_index = ti[0];
167         }
168
169       n_left_from -= 1;
170       ti += 1;
171       b += 1;
172     }
173
174   n_enq = vlib_buffer_enqueue_to_thread (vm, fq_index, from,
175                                          thread_indices, frame->n_vectors, 1);
176
177   if (n_enq < frame->n_vectors)
178     vlib_node_increment_counter (vm, node->node_index,
179                                  IPSEC_HANDOFF_ERROR_CONGESTION_DROP,
180                                  frame->n_vectors - n_enq);
181
182   return n_enq;
183 }
184
185 VLIB_NODE_FN (esp4_encrypt_handoff) (vlib_main_t * vm,
186                                      vlib_node_runtime_t * node,
187                                      vlib_frame_t * from_frame)
188 {
189   ipsec_main_t *im = &ipsec_main;
190
191   return ipsec_handoff (vm, node, from_frame, im->esp4_enc_fq_index, true);
192 }
193
194 VLIB_NODE_FN (esp6_encrypt_handoff) (vlib_main_t * vm,
195                                      vlib_node_runtime_t * node,
196                                      vlib_frame_t * from_frame)
197 {
198   ipsec_main_t *im = &ipsec_main;
199
200   return ipsec_handoff (vm, node, from_frame, im->esp6_enc_fq_index, true);
201 }
202
203 VLIB_NODE_FN (esp4_encrypt_tun_handoff) (vlib_main_t * vm,
204                                          vlib_node_runtime_t * node,
205                                          vlib_frame_t * from_frame)
206 {
207   ipsec_main_t *im = &ipsec_main;
208
209   return ipsec_handoff (vm, node, from_frame, im->esp4_enc_tun_fq_index,
210                         true);
211 }
212
213 VLIB_NODE_FN (esp6_encrypt_tun_handoff) (vlib_main_t * vm,
214                                          vlib_node_runtime_t * node,
215                                          vlib_frame_t * from_frame)
216 {
217   ipsec_main_t *im = &ipsec_main;
218
219   return ipsec_handoff (vm, node, from_frame, im->esp6_enc_tun_fq_index,
220                         true);
221 }
222
223 VLIB_NODE_FN (esp4_decrypt_handoff) (vlib_main_t * vm,
224                                      vlib_node_runtime_t * node,
225                                      vlib_frame_t * from_frame)
226 {
227   ipsec_main_t *im = &ipsec_main;
228
229   return ipsec_handoff (vm, node, from_frame, im->esp4_dec_fq_index, false);
230 }
231
232 VLIB_NODE_FN (esp6_decrypt_handoff) (vlib_main_t * vm,
233                                      vlib_node_runtime_t * node,
234                                      vlib_frame_t * from_frame)
235 {
236   ipsec_main_t *im = &ipsec_main;
237
238   return ipsec_handoff (vm, node, from_frame, im->esp6_dec_fq_index, false);
239 }
240
241 VLIB_NODE_FN (esp4_decrypt_tun_handoff) (vlib_main_t * vm,
242                                          vlib_node_runtime_t * node,
243                                          vlib_frame_t * from_frame)
244 {
245   ipsec_main_t *im = &ipsec_main;
246
247   return ipsec_handoff (vm, node, from_frame, im->esp4_dec_tun_fq_index,
248                         false);
249 }
250
251 VLIB_NODE_FN (esp6_decrypt_tun_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->esp6_dec_tun_fq_index,
258                         false);
259 }
260
261 VLIB_NODE_FN (ah4_encrypt_handoff) (vlib_main_t * vm,
262                                     vlib_node_runtime_t * node,
263                                     vlib_frame_t * from_frame)
264 {
265   ipsec_main_t *im = &ipsec_main;
266
267   return ipsec_handoff (vm, node, from_frame, im->ah4_enc_fq_index, true);
268 }
269
270 VLIB_NODE_FN (ah6_encrypt_handoff) (vlib_main_t * vm,
271                                     vlib_node_runtime_t * node,
272                                     vlib_frame_t * from_frame)
273 {
274   ipsec_main_t *im = &ipsec_main;
275
276   return ipsec_handoff (vm, node, from_frame, im->ah6_enc_fq_index, true);
277 }
278
279 VLIB_NODE_FN (ah4_decrypt_handoff) (vlib_main_t * vm,
280                                     vlib_node_runtime_t * node,
281                                     vlib_frame_t * from_frame)
282 {
283   ipsec_main_t *im = &ipsec_main;
284
285   return ipsec_handoff (vm, node, from_frame, im->ah4_dec_fq_index, false);
286 }
287
288 VLIB_NODE_FN (ah6_decrypt_handoff) (vlib_main_t * vm,
289                                     vlib_node_runtime_t * node,
290                                     vlib_frame_t * from_frame)
291 {
292   ipsec_main_t *im = &ipsec_main;
293
294   return ipsec_handoff (vm, node, from_frame, im->ah6_dec_fq_index, false);
295 }
296
297 /* *INDENT-OFF* */
298 VLIB_REGISTER_NODE (esp4_encrypt_handoff) = {
299   .name = "esp4-encrypt-handoff",
300   .vector_size = sizeof (u32),
301   .format_trace = format_ipsec_handoff_trace,
302   .type = VLIB_NODE_TYPE_INTERNAL,
303   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
304   .error_strings = ipsec_handoff_error_strings,
305   .n_next_nodes = 1,
306   .next_nodes = {
307     [0] = "error-drop",
308   },
309 };
310 VLIB_REGISTER_NODE (esp6_encrypt_handoff) = {
311   .name = "esp6-encrypt-handoff",
312   .vector_size = sizeof (u32),
313   .format_trace = format_ipsec_handoff_trace,
314   .type = VLIB_NODE_TYPE_INTERNAL,
315   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
316   .error_strings = ipsec_handoff_error_strings,
317   .n_next_nodes = 1,
318   .next_nodes = {
319     [0] = "error-drop",
320   },
321 };
322 VLIB_REGISTER_NODE (esp4_encrypt_tun_handoff) = {
323   .name = "esp4-encrypt-tun-handoff",
324   .vector_size = sizeof (u32),
325   .format_trace = format_ipsec_handoff_trace,
326   .type = VLIB_NODE_TYPE_INTERNAL,
327   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
328   .error_strings = ipsec_handoff_error_strings,
329   .n_next_nodes = 1,
330   .next_nodes = {
331     [0] = "error-drop",
332   },
333 };
334 VLIB_REGISTER_NODE (esp6_encrypt_tun_handoff) = {
335   .name = "esp6-encrypt-tun-handoff",
336   .vector_size = sizeof (u32),
337   .format_trace = format_ipsec_handoff_trace,
338   .type = VLIB_NODE_TYPE_INTERNAL,
339   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
340   .error_strings = ipsec_handoff_error_strings,
341   .n_next_nodes = 1,
342   .next_nodes = {
343     [0] = "error-drop",
344   },
345 };
346 VLIB_REGISTER_NODE (esp4_decrypt_handoff) = {
347   .name = "esp4-decrypt-handoff",
348   .vector_size = sizeof (u32),
349   .format_trace = format_ipsec_handoff_trace,
350   .type = VLIB_NODE_TYPE_INTERNAL,
351   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
352   .error_strings = ipsec_handoff_error_strings,
353   .n_next_nodes = 1,
354   .next_nodes = {
355     [0] = "error-drop",
356   },
357 };
358 VLIB_REGISTER_NODE (esp6_decrypt_handoff) = {
359   .name = "esp6-decrypt-handoff",
360   .vector_size = sizeof (u32),
361   .format_trace = format_ipsec_handoff_trace,
362   .type = VLIB_NODE_TYPE_INTERNAL,
363   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
364   .error_strings = ipsec_handoff_error_strings,
365   .n_next_nodes = 1,
366   .next_nodes = {
367     [0] = "error-drop",
368   },
369 };
370 VLIB_REGISTER_NODE (esp4_decrypt_tun_handoff) = {
371   .name = "esp4-decrypt-tun-handoff",
372   .vector_size = sizeof (u32),
373   .format_trace = format_ipsec_handoff_trace,
374   .type = VLIB_NODE_TYPE_INTERNAL,
375   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
376   .error_strings = ipsec_handoff_error_strings,
377   .n_next_nodes = 1,
378   .next_nodes = {
379     [0] = "error-drop",
380   },
381 };
382 VLIB_REGISTER_NODE (esp6_decrypt_tun_handoff) = {
383   .name = "esp6-decrypt-tun-handoff",
384   .vector_size = sizeof (u32),
385   .format_trace = format_ipsec_handoff_trace,
386   .type = VLIB_NODE_TYPE_INTERNAL,
387   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
388   .error_strings = ipsec_handoff_error_strings,
389   .n_next_nodes = 1,
390   .next_nodes = {
391     [0] = "error-drop",
392   },
393 };
394 VLIB_REGISTER_NODE (ah4_encrypt_handoff) = {
395   .name = "ah4-encrypt-handoff",
396   .vector_size = sizeof (u32),
397   .format_trace = format_ipsec_handoff_trace,
398   .type = VLIB_NODE_TYPE_INTERNAL,
399   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
400   .error_strings = ipsec_handoff_error_strings,
401   .n_next_nodes = 1,
402   .next_nodes = {
403     [0] = "error-drop",
404   },
405 };
406 VLIB_REGISTER_NODE (ah6_encrypt_handoff) = {
407   .name = "ah6-encrypt-handoff",
408   .vector_size = sizeof (u32),
409   .format_trace = format_ipsec_handoff_trace,
410   .type = VLIB_NODE_TYPE_INTERNAL,
411   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
412   .error_strings = ipsec_handoff_error_strings,
413   .n_next_nodes = 1,
414   .next_nodes = {
415     [0] = "error-drop",
416   },
417 };
418 VLIB_REGISTER_NODE (ah4_decrypt_handoff) = {
419   .name = "ah4-decrypt-handoff",
420   .vector_size = sizeof (u32),
421   .format_trace = format_ipsec_handoff_trace,
422   .type = VLIB_NODE_TYPE_INTERNAL,
423   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
424   .error_strings = ipsec_handoff_error_strings,
425   .n_next_nodes = 1,
426   .next_nodes = {
427     [0] = "error-drop",
428   },
429 };
430 VLIB_REGISTER_NODE (ah6_decrypt_handoff) = {
431   .name = "ah6-decrypt-handoff",
432   .vector_size = sizeof (u32),
433   .format_trace = format_ipsec_handoff_trace,
434   .type = VLIB_NODE_TYPE_INTERNAL,
435   .n_errors = ARRAY_LEN(ipsec_handoff_error_strings),
436   .error_strings = ipsec_handoff_error_strings,
437   .n_next_nodes = 1,
438   .next_nodes = {
439     [0] = "error-drop",
440   },
441 };
442 /* *INDENT-ON* */
443
444 /*
445  * fd.io coding-style-patch-verification: ON
446  *
447  * Local Variables:
448  * eval: (c-set-style "gnu")
449  * End:
450  */