Fixes for buliding for 32bit targets:
[vpp.git] / src / plugins / ipsecmb / ah_encrypt.c
1 /*
2  * ah_encrypt.c : ipsecmb AH 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/vnet.h>
19 #include <vnet/api_errno.h>
20 #include <vnet/ip/ip.h>
21
22 #include <vnet/ipsec/ipsec.h>
23 #include <vnet/ipsec/esp.h>
24 #include <vnet/ipsec/ah.h>
25
26 #include <ipsecmb/ipsecmb.h>
27
28 #define foreach_ah_encrypt_next                   \
29 _(DROP, "error-drop")                              \
30 _(IP4_LOOKUP, "ip4-lookup")                        \
31 _(IP6_LOOKUP, "ip6-lookup")                        \
32 _(INTERFACE_OUTPUT, "interface-output")
33
34 #define _(v, s) AH_ENCRYPT_NEXT_##v,
35 typedef enum
36 {
37   foreach_ah_encrypt_next
38 #undef _
39     AH_ENCRYPT_N_NEXT,
40 } ah_encrypt_next_t;
41
42 #define foreach_ah_encrypt_error                   \
43  _(RX_PKTS, "AH pkts received")                    \
44  _(SEQ_CYCLED, "sequence number cycled")
45
46
47 typedef enum
48 {
49 #define _(sym,str) AH_ENCRYPT_ERROR_##sym,
50   foreach_ah_encrypt_error
51 #undef _
52     AH_ENCRYPT_N_ERROR,
53 } ah_encrypt_error_t;
54
55 static char *ah_encrypt_error_strings[] = {
56 #define _(sym,string) string,
57   foreach_ah_encrypt_error
58 #undef _
59 };
60
61 typedef struct
62 {
63   u32 spi;
64   u32 seq;
65   ipsec_integ_alg_t integ_alg;
66 } ah_encrypt_trace_t;
67
68 /* packet trace format function */
69 static u8 *
70 format_ah_encrypt_trace (u8 * s, va_list * args)
71 {
72   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
73   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
74   ah_encrypt_trace_t *t = va_arg (*args, ah_encrypt_trace_t *);
75
76   s = format (s, "ah: spi %u seq %u integrity %U",
77               t->spi, t->seq, format_ipsec_integ_alg, t->integ_alg);
78   return s;
79 }
80
81 #ifdef CLIB_MARCH_VARIANT
82 always_inline void
83 ah_finish_encrypt (vlib_main_t * vm, vlib_buffer_t * b0, ipsec_sa_t * sa0,
84                    int is_ip6)
85 {
86   if (is_ip6)
87     {
88       ip6_header_t *oh6 = 0;
89       oh6 = vlib_buffer_get_current (b0);
90       oh6->ip_version_traffic_class_and_flow_label =
91         vnet_buffer (b0)->ipsec.ip_version_traffic_class_and_flow_label;
92       oh6->hop_limit = vnet_buffer (b0)->ipsec.ttl_or_hop_limit;
93     }
94   else
95     {
96       ip4_header_t *oh4 = 0;
97       oh4 = vlib_buffer_get_current (b0);
98       oh4->ttl = vnet_buffer (b0)->ipsec.ttl_or_hop_limit;
99       oh4->tos = vnet_buffer (b0)->ipsec.tos;
100       oh4->checksum = ip4_header_checksum (oh4);
101     }
102 }
103
104 always_inline uword
105 ah_encrypt_ipsecmb_inline (vlib_main_t * vm,
106                            vlib_node_runtime_t * node,
107                            vlib_frame_t * from_frame, int is_ip6)
108 {
109   u32 n_left_from, *from, *to_next = 0, next_index;
110   int icv_size = 0;
111   from = vlib_frame_vector_args (from_frame);
112   n_left_from = from_frame->n_vectors;
113   ipsec_main_t *im = &ipsec_main;
114   ipsecmb_main_t *imbm = &ipsecmb_main;
115   ipsec_proto_main_t *em = &ipsec_proto_main;
116   next_index = node->cached_next_index;
117   u32 thread_index = vlib_get_thread_index ();
118   MB_MGR *mgr = imbm->mb_mgr[thread_index];
119   u32 packets_in_flight = 0;
120
121   while (n_left_from > 0 || packets_in_flight > 0)
122     {
123       u32 n_left_to_next;
124
125       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
126
127       while (n_left_from > 0 && n_left_to_next > 0)
128         {
129           u32 bi0, next0;
130           vlib_buffer_t *b0 = 0;
131           u32 sa_index0;
132           ipsec_sa_t *sa0;
133           ipsecmb_sa_t *samb0;
134           ip4_header_t *ih4, *oh4 = 0;
135           ip6_header_t *ih6, *oh6 = 0;
136           ah_header_t *ah = 0;
137           u8 next_hdr_type;
138           u8 transport_mode = 0;
139
140           bi0 = from[0];
141           from += 1;
142           n_left_from -= 1;
143
144           next0 = AH_ENCRYPT_NEXT_DROP;
145
146           b0 = vlib_get_buffer (vm, bi0);
147           sa_index0 = vnet_buffer (b0)->ipsec.sad_index;
148           sa0 = pool_elt_at_index (im->sad, sa_index0);
149           samb0 = pool_elt_at_index (imbm->sad, sa_index0);
150
151           if (PREDICT_FALSE (esp_seq_advance (sa0)))
152             {
153               clib_warning ("sequence number counter has cycled SPI %u",
154                             sa0->spi);
155               vlib_node_increment_counter (vm, node->node_index,
156                                            AH_ENCRYPT_ERROR_SEQ_CYCLED, 1);
157               to_next[0] = bi0;
158               to_next += 1;
159               goto trace;
160             }
161
162
163           sa0->total_data_size += b0->current_length;
164
165           ssize_t adv;
166           ih4 = vlib_buffer_get_current (b0);
167
168           if (PREDICT_TRUE (sa0->is_tunnel))
169             {
170               if (!is_ip6)
171                 adv = -sizeof (ip4_and_ah_header_t);
172               else
173                 adv = -sizeof (ip6_and_ah_header_t);
174             }
175           else
176             {
177               adv = -sizeof (ah_header_t);
178             }
179
180           const u8 padding_len = ah_calc_icv_padding_len (icv_size, is_ip6);
181           adv -= padding_len;
182
183           icv_size =
184             em->ipsec_proto_main_integ_algs[sa0->integ_alg].trunc_size;
185           /* transport mode save the eth header before it is overwritten */
186           if (PREDICT_FALSE (!sa0->is_tunnel))
187             {
188               ethernet_header_t *ieh0 = (ethernet_header_t *)
189                 ((u8 *) vlib_buffer_get_current (b0) -
190                  sizeof (ethernet_header_t));
191               ethernet_header_t *oeh0 =
192                 (ethernet_header_t *) ((u8 *) ieh0 + (adv - icv_size));
193               clib_memcpy (oeh0, ieh0, sizeof (ethernet_header_t));
194             }
195
196           vlib_buffer_advance (b0, adv - icv_size);
197
198           if (is_ip6)
199             {
200               ih6 = (ip6_header_t *) ih4;
201               oh6 = vlib_buffer_get_current (b0);
202               ah = (ah_header_t *) (oh6 + 1);
203               vnet_buffer (b0)->ipsec.ttl_or_hop_limit = ih6->hop_limit;
204               vnet_buffer (b0)->
205                 ipsec.ip_version_traffic_class_and_flow_label =
206                 ih6->ip_version_traffic_class_and_flow_label;
207
208               if (PREDICT_TRUE (sa0->is_tunnel))
209                 {
210                   next_hdr_type = IP_PROTOCOL_IPV6;
211                 }
212               else
213                 {
214                   next_hdr_type = ih6->protocol;
215                   memmove (oh6, ih6, sizeof (ip6_header_t));
216                 }
217
218               oh6->protocol = IP_PROTOCOL_IPSEC_AH;
219               oh6->ip_version_traffic_class_and_flow_label = 0x60;
220               oh6->hop_limit = 0;
221               ah->reserved = 0;
222               ah->nexthdr = next_hdr_type;
223               ah->spi = clib_net_to_host_u32 (sa0->spi);
224               ah->seq_no = clib_net_to_host_u32 (sa0->seq);
225               ah->hdrlen =
226                 (sizeof (ah_header_t) + icv_size + padding_len) / 4 - 2;
227               oh6->payload_length =
228                 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) -
229                                       sizeof (ip6_header_t));
230             }
231           else
232             {
233               oh4 = vlib_buffer_get_current (b0);
234               memset (oh4, 0, sizeof (*oh4));
235               ah = (ah_header_t *) (oh4 + 1);
236               memset (ah, 0, sizeof (*ah));
237               vnet_buffer (b0)->ipsec.ttl_or_hop_limit = ih4->ttl;
238               vnet_buffer (b0)->ipsec.tos = ih4->tos;
239
240               if (PREDICT_TRUE (sa0->is_tunnel))
241                 {
242                   next_hdr_type = IP_PROTOCOL_IP_IN_IP;
243                 }
244               else
245                 {
246                   next_hdr_type = ih4->protocol;
247                   memmove (oh4, ih4, sizeof (ip4_header_t));
248                 }
249
250               oh4->length =
251                 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
252               oh4->ip_version_and_header_length = 0x45;
253               oh4->fragment_id = 0;
254               oh4->flags_and_fragment_offset = 0;
255               oh4->ttl = 0;
256               oh4->tos = 0;
257               oh4->protocol = IP_PROTOCOL_IPSEC_AH;
258               ah->spi = clib_net_to_host_u32 (sa0->spi);
259               ah->seq_no = clib_net_to_host_u32 (sa0->seq);
260               oh4->checksum = 0;
261               ah->nexthdr = next_hdr_type;
262               ah->hdrlen =
263                 (sizeof (ah_header_t) + icv_size + padding_len) / 4 - 2;
264             }
265
266           if (PREDICT_TRUE (!is_ip6 && sa0->is_tunnel && !sa0->is_tunnel_ip6))
267             {
268               oh4->src_address.as_u32 = sa0->tunnel_src_addr.ip4.as_u32;
269               oh4->dst_address.as_u32 = sa0->tunnel_dst_addr.ip4.as_u32;
270
271               next0 = AH_ENCRYPT_NEXT_IP4_LOOKUP;
272               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
273             }
274           else if (is_ip6 && sa0->is_tunnel && sa0->is_tunnel_ip6)
275             {
276               oh6->src_address.as_u64[0] = sa0->tunnel_src_addr.ip6.as_u64[0];
277               oh6->src_address.as_u64[1] = sa0->tunnel_src_addr.ip6.as_u64[1];
278               oh6->dst_address.as_u64[0] = sa0->tunnel_dst_addr.ip6.as_u64[0];
279               oh6->dst_address.as_u64[1] = sa0->tunnel_dst_addr.ip6.as_u64[1];
280               next0 = AH_ENCRYPT_NEXT_IP6_LOOKUP;
281               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
282             }
283           else
284             {
285               transport_mode = 1;
286             }
287
288           memset (ah + 1, 0, icv_size);
289
290           JOB_AES_HMAC *job = IPSECMB_FUNC (get_next_job) (mgr);
291           job->src = vlib_buffer_get_current (b0);
292           job->hash_start_src_offset_in_bytes = 0;
293           job->cipher_mode = NULL_CIPHER;
294           job->hash_alg = imbm->integ_algs[sa0->integ_alg].hash_alg;
295           job->auth_tag_output_len_in_bytes =
296             imbm->integ_algs[sa0->integ_alg].hash_output_length;
297           job->auth_tag_output = (u8 *) (ah + 1);
298           if (PREDICT_TRUE (sa0->use_esn))
299             {
300               *(u32 *) (vlib_buffer_get_current (b0) + b0->current_length) =
301                 sa0->seq_hi;
302               b0->current_length += sizeof (u32);
303             }
304           job->msg_len_to_hash_in_bytes = b0->current_length;
305           job->cipher_direction = ENCRYPT;
306           job->chain_order = HASH_CIPHER;
307           job->u.HMAC._hashed_auth_key_xor_ipad = samb0->ipad_hash;
308           job->u.HMAC._hashed_auth_key_xor_opad = samb0->opad_hash;
309
310
311           job->user_data = (void *) (uintptr_t) bi0;
312           job->user_data2 = (void *) (uintptr_t) next0;
313           vnet_buffer (b0)->ipsec.sad_index = sa_index0;
314
315           job = IPSECMB_FUNC (submit_job) (mgr);
316           ++packets_in_flight;
317
318           if (!job)
319             {
320               continue;
321             }
322
323           --packets_in_flight;
324           ASSERT (STS_COMPLETED == job->status);
325           bi0 = (uintptr_t) job->user_data;
326           next0 = (uintptr_t) job->user_data2;
327           b0 = vlib_get_buffer (vm, bi0);
328           sa0 =
329             pool_elt_at_index (im->sad, vnet_buffer (b0)->ipsec.sad_index);
330           ah_finish_encrypt (vm, b0, sa0, is_ip6);
331           if (!sa0->is_tunnel && !sa0->is_tunnel_ip6)
332             {
333               next0 = AH_ENCRYPT_NEXT_INTERFACE_OUTPUT;
334               vlib_buffer_advance (b0, -sizeof (ethernet_header_t));
335             }
336
337           to_next[0] = bi0;
338           to_next += 1;
339           n_left_to_next -= 1;
340
341         trace:
342           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
343             {
344               ah_encrypt_trace_t *tr =
345                 vlib_add_trace (vm, node, b0, sizeof (*tr));
346               tr->spi = sa0->spi;
347               tr->seq = sa0->seq - 1;
348               tr->integ_alg = sa0->integ_alg;
349             }
350
351           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
352                                            to_next, n_left_to_next, bi0,
353                                            next0);
354         }
355
356       if (PREDICT_FALSE (n_left_from == 0))
357         {
358           JOB_AES_HMAC *job = NULL;
359           while (n_left_to_next > 0 && (job = IPSECMB_FUNC (flush_job) (mgr)))
360             {
361               --packets_in_flight;
362               u32 bi0, next0;
363               vlib_buffer_t *b0;
364               ipsec_sa_t *sa0;
365
366               ASSERT (STS_COMPLETED == job->status);
367               bi0 = (uintptr_t) job->user_data;
368               next0 = (uintptr_t) job->user_data2;
369               b0 = vlib_get_buffer (vm, bi0);
370               sa0 =
371                 pool_elt_at_index (im->sad,
372                                    vnet_buffer (b0)->ipsec.sad_index);
373               ah_finish_encrypt (vm, b0, sa0, is_ip6);
374               if (!sa0->is_tunnel && !sa0->is_tunnel_ip6)
375                 {
376                   next0 = AH_ENCRYPT_NEXT_INTERFACE_OUTPUT;
377                   vlib_buffer_advance (b0, -sizeof (ethernet_header_t));
378                 }
379
380               to_next[0] = bi0;
381               to_next += 1;
382               n_left_to_next -= 1;
383
384               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
385                 {
386                   ah_encrypt_trace_t *tr =
387                     vlib_add_trace (vm, node, b0, sizeof (*tr));
388                   tr->spi = sa0->spi;
389                   tr->seq = sa0->seq - 1;
390                   tr->integ_alg = sa0->integ_alg;
391                 }
392
393               vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
394                                                to_next, n_left_to_next, bi0,
395                                                next0);
396             }
397         }
398       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
399     }
400   vlib_node_increment_counter (vm, node->node_index, AH_ENCRYPT_ERROR_RX_PKTS,
401                                from_frame->n_vectors);
402
403   return from_frame->n_vectors;
404 }
405
406 VLIB_NODE_FN (ah4_encrypt_ipsecmb_node) (vlib_main_t * vm,
407                                          vlib_node_runtime_t * node,
408                                          vlib_frame_t * from_frame)
409 {
410   return ah_encrypt_ipsecmb_inline (vm, node, from_frame, 0 /*is_ip6 */ );
411 }
412
413 VLIB_NODE_FN (ah6_encrypt_ipsecmb_node) (vlib_main_t * vm,
414                                          vlib_node_runtime_t * node,
415                                          vlib_frame_t * from_frame)
416 {
417   return ah_encrypt_ipsecmb_inline (vm, node, from_frame, 1 /*is_ip6 */ );
418 }
419
420 #endif
421
422 /* *INDENT-OFF* */
423 VLIB_REGISTER_NODE (ah4_encrypt_ipsecmb_node) = {
424   .name = "ah4-encrypt-ipsecmb",
425   .vector_size = sizeof (u32),
426   .format_trace = format_ah_encrypt_trace,
427   .type = VLIB_NODE_TYPE_INTERNAL,
428
429   .n_errors = ARRAY_LEN(ah_encrypt_error_strings),
430   .error_strings = ah_encrypt_error_strings,
431
432   .n_next_nodes = AH_ENCRYPT_N_NEXT,
433   .next_nodes = {
434 #define _(s,n) [AH_ENCRYPT_NEXT_##s] = n,
435     foreach_ah_encrypt_next
436 #undef _
437   },
438 };
439 /* *INDENT-ON* */
440
441 /* *INDENT-OFF* */
442 VLIB_REGISTER_NODE (ah6_encrypt_ipsecmb_node) = {
443   .name = "ah6-encrypt-ipsecmb",
444   .vector_size = sizeof (u32),
445   .format_trace = format_ah_encrypt_trace,
446   .type = VLIB_NODE_TYPE_INTERNAL,
447
448   .n_errors = ARRAY_LEN(ah_encrypt_error_strings),
449   .error_strings = ah_encrypt_error_strings,
450
451   .n_next_nodes = AH_ENCRYPT_N_NEXT,
452   .next_nodes = {
453 #define _(s,n) [AH_ENCRYPT_NEXT_##s] = n,
454     foreach_ah_encrypt_next
455 #undef _
456   },
457 };
458 /* *INDENT-ON* */
459
460 /*
461  * fd.io coding-style-patch-verification: ON
462  *
463  * Local Variables:
464  * eval: (c-set-style "gnu")
465  * End:
466  */