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