ipsec: add per-SA error counters
[vpp.git] / src / vnet / ipsec / esp.h
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #ifndef __ESP_H__
16 #define __ESP_H__
17
18 #include <vnet/ip/ip.h>
19 #include <vnet/crypto/crypto.h>
20 #include <vnet/ipsec/ipsec.h>
21 #include <vnet/ipsec/ipsec.api_enum.h>
22
23 typedef struct
24 {
25   union
26   {
27     u32 spi;
28     u8 spi_bytes[4];
29   };
30   u32 seq;
31   u8 data[0];
32 } esp_header_t;
33
34 typedef struct
35 {
36   u8 pad_length;
37   u8 next_header;
38 } esp_footer_t;
39
40 /* *INDENT-OFF* */
41 typedef CLIB_PACKED (struct {
42   ip4_header_t ip4;
43   esp_header_t esp;
44 }) ip4_and_esp_header_t;
45 /* *INDENT-ON* */
46
47 /* *INDENT-OFF* */
48 typedef CLIB_PACKED (struct {
49   ip4_header_t ip4;
50   udp_header_t udp;
51   esp_header_t esp;
52 }) ip4_and_udp_and_esp_header_t;
53 /* *INDENT-ON* */
54
55 /* *INDENT-OFF* */
56 typedef CLIB_PACKED (struct {
57   ip6_header_t ip6;
58   esp_header_t esp;
59 }) ip6_and_esp_header_t;
60 /* *INDENT-ON* */
61
62 /**
63  * AES counter mode nonce
64  */
65 typedef struct
66 {
67   u32 salt;
68   u64 iv;
69   u32 ctr; /* counter: 1 in big-endian for ctr, unused for gcm */
70 } __clib_packed esp_ctr_nonce_t;
71
72 STATIC_ASSERT_SIZEOF (esp_ctr_nonce_t, 16);
73
74 /**
75  * AES GCM Additional Authentication data
76  */
77 typedef struct esp_aead_t_
78 {
79   /**
80    * for GCM: when using ESN it's:
81    *   SPI, seq-hi, seg-low
82    * else
83    *   SPI, seq-low
84    */
85   u32 data[3];
86 } __clib_packed esp_aead_t;
87
88 #define ESP_SEQ_MAX             (4294967295UL)
89 #define ESP_MAX_BLOCK_SIZE      (16)
90 #define ESP_MAX_IV_SIZE         (16)
91 #define ESP_MAX_ICV_SIZE        (32)
92
93 u8 *format_esp_header (u8 * s, va_list * args);
94
95 /* TODO seq increment should be atomic to be accessed by multiple workers */
96 always_inline int
97 esp_seq_advance (ipsec_sa_t * sa)
98 {
99   if (PREDICT_TRUE (ipsec_sa_is_set_USE_ESN (sa)))
100     {
101       if (PREDICT_FALSE (sa->seq == ESP_SEQ_MAX))
102         {
103           if (PREDICT_FALSE (ipsec_sa_is_set_USE_ANTI_REPLAY (sa) &&
104                              sa->seq_hi == ESP_SEQ_MAX))
105             return 1;
106           sa->seq_hi++;
107         }
108       sa->seq++;
109     }
110   else
111     {
112       if (PREDICT_FALSE (ipsec_sa_is_set_USE_ANTI_REPLAY (sa) &&
113                          sa->seq == ESP_SEQ_MAX))
114         return 1;
115       sa->seq++;
116     }
117
118   return 0;
119 }
120
121 always_inline u16
122 esp_aad_fill (u8 *data, const esp_header_t *esp, const ipsec_sa_t *sa,
123               u32 seq_hi)
124 {
125   esp_aead_t *aad;
126
127   aad = (esp_aead_t *) data;
128   aad->data[0] = esp->spi;
129
130   if (ipsec_sa_is_set_USE_ESN (sa))
131     {
132       /* SPI, seq-hi, seq-low */
133       aad->data[1] = (u32) clib_host_to_net_u32 (seq_hi);
134       aad->data[2] = esp->seq;
135       return 12;
136     }
137   else
138     {
139       /* SPI, seq-low */
140       aad->data[1] = esp->seq;
141       return 8;
142     }
143 }
144
145 always_inline u32
146 esp_encrypt_err_to_sa_err (u32 err)
147 {
148   switch (err)
149     {
150     case ESP_ENCRYPT_ERROR_HANDOFF:
151       return IPSEC_SA_ERROR_HANDOFF;
152     case ESP_ENCRYPT_ERROR_SEQ_CYCLED:
153       return IPSEC_SA_ERROR_SEQ_CYCLED;
154     case ESP_ENCRYPT_ERROR_CRYPTO_ENGINE_ERROR:
155       return IPSEC_SA_ERROR_CRYPTO_ENGINE_ERROR;
156     case ESP_ENCRYPT_ERROR_CRYPTO_QUEUE_FULL:
157       return IPSEC_SA_ERROR_CRYPTO_QUEUE_FULL;
158     case ESP_ENCRYPT_ERROR_NO_BUFFERS:
159       return IPSEC_SA_ERROR_NO_BUFFERS;
160     case ESP_ENCRYPT_ERROR_NO_ENCRYPTION:
161       return IPSEC_SA_ERROR_NO_ENCRYPTION;
162     }
163   return ~0;
164 }
165
166 always_inline u32
167 esp_decrypt_err_to_sa_err (u32 err)
168 {
169   switch (err)
170     {
171     case ESP_DECRYPT_ERROR_HANDOFF:
172       return IPSEC_SA_ERROR_HANDOFF;
173     case ESP_DECRYPT_ERROR_DECRYPTION_FAILED:
174       return IPSEC_SA_ERROR_DECRYPTION_FAILED;
175     case ESP_DECRYPT_ERROR_INTEG_ERROR:
176       return IPSEC_SA_ERROR_INTEG_ERROR;
177     case ESP_DECRYPT_ERROR_CRYPTO_ENGINE_ERROR:
178       return IPSEC_SA_ERROR_CRYPTO_ENGINE_ERROR;
179     case ESP_DECRYPT_ERROR_REPLAY:
180       return IPSEC_SA_ERROR_REPLAY;
181     case ESP_DECRYPT_ERROR_RUNT:
182       return IPSEC_SA_ERROR_RUNT;
183     case ESP_DECRYPT_ERROR_NO_BUFFERS:
184       return IPSEC_SA_ERROR_NO_BUFFERS;
185     case ESP_DECRYPT_ERROR_OVERSIZED_HEADER:
186       return IPSEC_SA_ERROR_OVERSIZED_HEADER;
187     case ESP_DECRYPT_ERROR_NO_TAIL_SPACE:
188       return IPSEC_SA_ERROR_NO_TAIL_SPACE;
189     case ESP_DECRYPT_ERROR_TUN_NO_PROTO:
190       return IPSEC_SA_ERROR_TUN_NO_PROTO;
191     case ESP_DECRYPT_ERROR_UNSUP_PAYLOAD:
192       return IPSEC_SA_ERROR_UNSUP_PAYLOAD;
193     }
194   return ~0;
195 }
196
197 always_inline void
198 esp_encrypt_set_next_index (vlib_buffer_t *b, vlib_node_runtime_t *node,
199                             u32 thread_index, u32 err, u16 index, u16 *nexts,
200                             u16 drop_next, u32 sa_index)
201 {
202   ipsec_set_next_index (b, node, thread_index, err,
203                         esp_encrypt_err_to_sa_err (err), index, nexts,
204                         drop_next, sa_index);
205 }
206
207 always_inline void
208 esp_decrypt_set_next_index (vlib_buffer_t *b, vlib_node_runtime_t *node,
209                             u32 thread_index, u32 err, u16 index, u16 *nexts,
210                             u16 drop_next, u32 sa_index)
211 {
212   ipsec_set_next_index (b, node, thread_index, err,
213                         esp_decrypt_err_to_sa_err (err), index, nexts,
214                         drop_next, sa_index);
215 }
216
217 /* when submitting a frame is failed, drop all buffers in the frame */
218 always_inline u32
219 esp_async_recycle_failed_submit (vlib_main_t *vm, vnet_crypto_async_frame_t *f,
220                                  vlib_node_runtime_t *node, u32 err,
221                                  u32 ipsec_sa_err, u16 index, u32 *from,
222                                  u16 *nexts, u16 drop_next_index)
223 {
224   vlib_buffer_t *b;
225   u32 n_drop = f->n_elts;
226   u32 *bi = f->buffer_indices;
227
228   while (n_drop--)
229     {
230       from[index] = bi[0];
231       b = vlib_get_buffer (vm, bi[0]);
232       ipsec_set_next_index (b, node, vm->thread_index, err, ipsec_sa_err,
233                             index, nexts, drop_next_index,
234                             vnet_buffer (b)->ipsec.sad_index);
235       bi++;
236       index++;
237     }
238
239   return (f->n_elts);
240 }
241
242 /**
243  * The post data structure to for esp_encrypt/decrypt_inline to write to
244  * vib_buffer_t opaque unused field, and for post nodes to pick up after
245  * dequeue.
246  **/
247 typedef struct
248 {
249   union
250   {
251     struct
252     {
253       u8 icv_sz;
254       u8 iv_sz;
255       ipsec_sa_flags_t flags;
256       u32 sa_index;
257     };
258     u64 sa_data;
259   };
260
261   u32 seq;
262   i16 current_data;
263   i16 current_length;
264   u16 hdr_sz;
265   u16 is_chain;
266   u32 seq_hi;
267 } esp_decrypt_packet_data_t;
268
269 STATIC_ASSERT_SIZEOF (esp_decrypt_packet_data_t, 3 * sizeof (u64));
270 STATIC_ASSERT_OFFSET_OF (esp_decrypt_packet_data_t, seq, sizeof (u64));
271
272 /* we are forced to store the decrypt post data into 2 separate places -
273    vlib_opaque and opaque2. */
274 typedef struct
275 {
276   vlib_buffer_t *lb;
277   u32 free_buffer_index;
278   u8 icv_removed;
279 } esp_decrypt_packet_data2_t;
280
281 typedef union
282 {
283   u16 next_index;
284   esp_decrypt_packet_data_t decrypt_data;
285 } esp_post_data_t;
286
287 STATIC_ASSERT (sizeof (esp_post_data_t) <=
288                STRUCT_SIZE_OF (vnet_buffer_opaque_t, unused),
289                "Custom meta-data too large for vnet_buffer_opaque_t");
290
291 #define esp_post_data(b) \
292     ((esp_post_data_t *)((u8 *)((b)->opaque) \
293         + STRUCT_OFFSET_OF (vnet_buffer_opaque_t, unused)))
294
295 STATIC_ASSERT (sizeof (esp_decrypt_packet_data2_t) <=
296                STRUCT_SIZE_OF (vnet_buffer_opaque2_t, unused),
297                "Custom meta-data too large for vnet_buffer_opaque2_t");
298
299 #define esp_post_data2(b) \
300     ((esp_decrypt_packet_data2_t *)((u8 *)((b)->opaque2) \
301         + STRUCT_OFFSET_OF (vnet_buffer_opaque2_t, unused)))
302
303 typedef struct
304 {
305   /* esp post node index for async crypto */
306   u32 esp4_post_next;
307   u32 esp6_post_next;
308   u32 esp4_tun_post_next;
309   u32 esp6_tun_post_next;
310   u32 esp_mpls_tun_post_next;
311 } esp_async_post_next_t;
312
313 extern esp_async_post_next_t esp_encrypt_async_next;
314 extern esp_async_post_next_t esp_decrypt_async_next;
315
316 #endif /* __ESP_H__ */
317
318 /*
319  * fd.io coding-style-patch-verification: ON
320  *
321  * Local Variables:
322  * eval: (c-set-style "gnu")
323  * End:
324  */