6de444fd3bc7af426cdaedac31657e9e6cfa7456
[vpp.git] / src / plugins / dpdk / ipsec / esp_encrypt.c
1 /*
2  * esp_encrypt.c : IPSec ESP encrypt node using DPDK Cryptodev
3  *
4  * Copyright (c) 2016 Intel 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 <dpdk/ipsec/ipsec.h>
24 #include <dpdk/ipsec/esp.h>
25 #include <dpdk/device/dpdk.h>
26 #include <dpdk/device/dpdk_priv.h>
27
28 #define foreach_esp_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) ESP_ENCRYPT_NEXT_##v,
35 typedef enum
36 {
37   foreach_esp_encrypt_next
38 #undef _
39     ESP_ENCRYPT_N_NEXT,
40 } esp_encrypt_next_t;
41
42 #define foreach_esp_encrypt_error                   \
43  _(RX_PKTS, "ESP pkts received")                    \
44  _(SEQ_CYCLED, "sequence number cycled")            \
45  _(ENQ_FAIL, "Enqueue failed (buffer full)")        \
46  _(NO_CRYPTODEV, "Cryptodev not configured")
47
48
49 typedef enum
50 {
51 #define _(sym,str) ESP_ENCRYPT_ERROR_##sym,
52   foreach_esp_encrypt_error
53 #undef _
54     ESP_ENCRYPT_N_ERROR,
55 } esp_encrypt_error_t;
56
57 static char *esp_encrypt_error_strings[] = {
58 #define _(sym,string) string,
59   foreach_esp_encrypt_error
60 #undef _
61 };
62
63 vlib_node_registration_t dpdk_esp_encrypt_node;
64
65 typedef struct
66 {
67   u32 spi;
68   u32 seq;
69   ipsec_crypto_alg_t crypto_alg;
70   ipsec_integ_alg_t integ_alg;
71 } esp_encrypt_trace_t;
72
73 /* packet trace format function */
74 static u8 *
75 format_esp_encrypt_trace (u8 * s, va_list * args)
76 {
77   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
78   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
79   esp_encrypt_trace_t *t = va_arg (*args, esp_encrypt_trace_t *);
80
81   s = format (s, "esp: spi %u seq %u crypto %U integrity %U",
82               t->spi, t->seq,
83               format_ipsec_crypto_alg, t->crypto_alg,
84               format_ipsec_integ_alg, t->integ_alg);
85   return s;
86 }
87
88 static uword
89 dpdk_esp_encrypt_node_fn (vlib_main_t * vm,
90                           vlib_node_runtime_t * node,
91                           vlib_frame_t * from_frame)
92 {
93   u32 n_left_from, *from, *to_next, next_index;
94   ipsec_main_t *im = &ipsec_main;
95   u32 thread_index = vlib_get_thread_index ();
96   dpdk_crypto_main_t *dcm = &dpdk_crypto_main;
97   dpdk_esp_main_t *em = &dpdk_esp_main;
98   u32 i;
99
100   from = vlib_frame_vector_args (from_frame);
101   n_left_from = from_frame->n_vectors;
102
103   crypto_worker_main_t *cwm =
104     vec_elt_at_index (dcm->workers_main, thread_index);
105   u32 n_qps = vec_len (cwm->qp_data);
106   struct rte_crypto_op **cops_to_enq[n_qps];
107   u32 n_cop_qp[n_qps], *bi_to_enq[n_qps];
108
109   for (i = 0; i < n_qps; i++)
110     {
111       bi_to_enq[i] = cwm->qp_data[i].bi;
112       cops_to_enq[i] = cwm->qp_data[i].cops;
113     }
114
115   memset (n_cop_qp, 0, n_qps * sizeof (u32));
116
117   crypto_alloc_cops ();
118
119   next_index = ESP_ENCRYPT_NEXT_DROP;
120
121   while (n_left_from > 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           ip4_and_esp_header_t *ih0, *oh0 = 0;
134           ip6_and_esp_header_t *ih6_0, *oh6_0 = 0;
135           struct rte_mbuf *mb0 = 0;
136           esp_footer_t *f0;
137           u8 is_ipv6;
138           u8 ip_hdr_size;
139           u8 next_hdr_type;
140           u8 transport_mode = 0;
141           const int BLOCK_SIZE = 16;
142           u32 iv_size;
143           u16 orig_sz;
144           u8 trunc_size;
145           crypto_sa_session_t *sa_sess;
146           void *sess;
147           struct rte_crypto_op *cop = 0;
148           u16 qp_index;
149
150           bi0 = from[0];
151           from += 1;
152           n_left_from -= 1;
153
154           b0 = vlib_get_buffer (vm, bi0);
155           sa_index0 = vnet_buffer (b0)->ipsec.sad_index;
156           sa0 = pool_elt_at_index (im->sad, sa_index0);
157
158           if (PREDICT_FALSE (esp_seq_advance (sa0)))
159             {
160               clib_warning ("sequence number counter has cycled SPI %u",
161                             sa0->spi);
162               vlib_node_increment_counter (vm, dpdk_esp_encrypt_node.index,
163                                            ESP_ENCRYPT_ERROR_SEQ_CYCLED, 1);
164               //TODO: rekey SA
165               to_next[0] = bi0;
166               to_next += 1;
167               n_left_to_next -= 1;
168               goto trace;
169             }
170
171           sa0->total_data_size += b0->current_length;
172
173           sa_sess = pool_elt_at_index (cwm->sa_sess_d[1], sa_index0);
174           if (PREDICT_FALSE (!sa_sess->sess))
175             {
176               int ret = create_sym_sess (sa0, sa_sess, 1);
177
178               if (PREDICT_FALSE (ret))
179                 {
180                   to_next[0] = bi0;
181                   to_next += 1;
182                   n_left_to_next -= 1;
183                   goto trace;
184                 }
185             }
186
187           qp_index = sa_sess->qp_index;
188           sess = sa_sess->sess;
189
190           ASSERT (vec_len (vec_elt (cwm->qp_data, qp_index).free_cops) > 0);
191           cop = vec_pop (vec_elt (cwm->qp_data, qp_index).free_cops);
192           ASSERT (cop->status == RTE_CRYPTO_OP_STATUS_NOT_PROCESSED);
193
194           cops_to_enq[qp_index][0] = cop;
195           cops_to_enq[qp_index] += 1;
196           n_cop_qp[qp_index] += 1;
197           bi_to_enq[qp_index][0] = bi0;
198           bi_to_enq[qp_index] += 1;
199
200           ssize_t adv;
201           iv_size = em->esp_crypto_algs[sa0->crypto_alg].iv_len;
202           if (sa0->crypto_alg == IPSEC_CRYPTO_ALG_AES_GCM_128)
203             trunc_size = 16;
204           else
205             trunc_size = em->esp_integ_algs[sa0->integ_alg].trunc_size;
206
207           ih0 = vlib_buffer_get_current (b0);
208           orig_sz = b0->current_length;
209           is_ipv6 = (ih0->ip4.ip_version_and_header_length & 0xF0) == 0x60;
210           /* is ipv6 */
211           if (PREDICT_TRUE (sa0->is_tunnel))
212             {
213               if (PREDICT_TRUE (!is_ipv6))
214                 adv = -sizeof (ip4_and_esp_header_t);
215               else
216                 adv = -sizeof (ip6_and_esp_header_t);
217             }
218           else
219             {
220               adv = -sizeof (esp_header_t);
221               if (PREDICT_TRUE (!is_ipv6))
222                 orig_sz -= sizeof (ip4_header_t);
223               else
224                 orig_sz -= sizeof (ip6_header_t);
225             }
226
227           /*transport mode save the eth header before it is overwritten */
228           if (PREDICT_FALSE (!sa0->is_tunnel))
229             {
230               ethernet_header_t *ieh0 = (ethernet_header_t *)
231                 ((u8 *) vlib_buffer_get_current (b0) -
232                  sizeof (ethernet_header_t));
233               ethernet_header_t *oeh0 =
234                 (ethernet_header_t *) ((u8 *) ieh0 + (adv - iv_size));
235               clib_memcpy (oeh0, ieh0, sizeof (ethernet_header_t));
236             }
237
238           vlib_buffer_advance (b0, adv - iv_size);
239
240           /* XXX IP6/ip4 and IP4/IP6 not supported, only IP4/IP4 and IP6/IP6 */
241
242           /* is ipv6 */
243           if (PREDICT_FALSE (is_ipv6))
244             {
245               ih6_0 = (ip6_and_esp_header_t *) ih0;
246               ip_hdr_size = sizeof (ip6_header_t);
247               oh6_0 = vlib_buffer_get_current (b0);
248
249               if (PREDICT_TRUE (sa0->is_tunnel))
250                 {
251                   next_hdr_type = IP_PROTOCOL_IPV6;
252                   oh6_0->ip6.ip_version_traffic_class_and_flow_label =
253                     ih6_0->ip6.ip_version_traffic_class_and_flow_label;
254                 }
255               else
256                 {
257                   next_hdr_type = ih6_0->ip6.protocol;
258                   memmove (oh6_0, ih6_0, sizeof (ip6_header_t));
259                 }
260
261               oh6_0->ip6.protocol = IP_PROTOCOL_IPSEC_ESP;
262               oh6_0->ip6.hop_limit = 254;
263               oh6_0->esp.spi = clib_net_to_host_u32 (sa0->spi);
264               oh6_0->esp.seq = clib_net_to_host_u32 (sa0->seq);
265             }
266           else
267             {
268               ip_hdr_size = sizeof (ip4_header_t);
269               oh0 = vlib_buffer_get_current (b0);
270
271               if (PREDICT_TRUE (sa0->is_tunnel))
272                 {
273                   next_hdr_type = IP_PROTOCOL_IP_IN_IP;
274                   oh0->ip4.tos = ih0->ip4.tos;
275                 }
276               else
277                 {
278                   next_hdr_type = ih0->ip4.protocol;
279                   memmove (oh0, ih0, sizeof (ip4_header_t));
280                 }
281
282               oh0->ip4.ip_version_and_header_length = 0x45;
283               oh0->ip4.fragment_id = 0;
284               oh0->ip4.flags_and_fragment_offset = 0;
285               oh0->ip4.ttl = 254;
286               oh0->ip4.protocol = IP_PROTOCOL_IPSEC_ESP;
287               oh0->esp.spi = clib_net_to_host_u32 (sa0->spi);
288               oh0->esp.seq = clib_net_to_host_u32 (sa0->seq);
289             }
290
291           if (PREDICT_TRUE
292               (!is_ipv6 && sa0->is_tunnel && !sa0->is_tunnel_ip6))
293             {
294               oh0->ip4.src_address.as_u32 = sa0->tunnel_src_addr.ip4.as_u32;
295               oh0->ip4.dst_address.as_u32 = sa0->tunnel_dst_addr.ip4.as_u32;
296
297               /* in tunnel mode send it back to FIB */
298               next0 = ESP_ENCRYPT_NEXT_IP4_LOOKUP;
299               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
300             }
301           else if (is_ipv6 && sa0->is_tunnel && sa0->is_tunnel_ip6)
302             {
303               oh6_0->ip6.src_address.as_u64[0] =
304                 sa0->tunnel_src_addr.ip6.as_u64[0];
305               oh6_0->ip6.src_address.as_u64[1] =
306                 sa0->tunnel_src_addr.ip6.as_u64[1];
307               oh6_0->ip6.dst_address.as_u64[0] =
308                 sa0->tunnel_dst_addr.ip6.as_u64[0];
309               oh6_0->ip6.dst_address.as_u64[1] =
310                 sa0->tunnel_dst_addr.ip6.as_u64[1];
311
312               /* in tunnel mode send it back to FIB */
313               next0 = ESP_ENCRYPT_NEXT_IP6_LOOKUP;
314               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
315             }
316           else
317             {
318               next0 = ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT;
319               transport_mode = 1;
320             }
321
322           int blocks = 1 + (orig_sz + 1) / BLOCK_SIZE;
323
324           /* pad packet in input buffer */
325           u8 pad_bytes = BLOCK_SIZE * blocks - 2 - orig_sz;
326           u8 i;
327           u8 *padding = vlib_buffer_get_current (b0) + b0->current_length;
328
329           for (i = 0; i < pad_bytes; ++i)
330             padding[i] = i + 1;
331
332           f0 = vlib_buffer_get_current (b0) + b0->current_length + pad_bytes;
333           f0->pad_length = pad_bytes;
334           f0->next_header = next_hdr_type;
335           b0->current_length += pad_bytes + 2 + trunc_size;
336
337           vnet_buffer (b0)->sw_if_index[VLIB_RX] =
338             vnet_buffer (b0)->sw_if_index[VLIB_RX];
339           b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
340
341           struct rte_crypto_sym_op *sym_cop;
342           sym_cop = (struct rte_crypto_sym_op *) (cop + 1);
343
344           dpdk_cop_priv_t *priv = (dpdk_cop_priv_t *) (sym_cop + 1);
345
346           vnet_buffer (b0)->unused[0] = next0;
347
348           mb0 = rte_mbuf_from_vlib_buffer (b0);
349           mb0->data_len = b0->current_length;
350           mb0->pkt_len = b0->current_length;
351           mb0->data_off = RTE_PKTMBUF_HEADROOM + b0->current_data;
352
353           dpdk_gcm_cnt_blk *icb = &priv->cb;
354
355           crypto_set_icb (icb, sa0->salt, sa0->seq, sa0->seq_hi);
356
357           u8 is_aead = sa0->crypto_alg == IPSEC_CRYPTO_ALG_AES_GCM_128;
358           u32 cipher_off, cipher_len;
359           u32 auth_off = 0, auth_len = 0, aad_size = 0;
360           u8 *aad = NULL, *digest = NULL;
361
362           if (is_aead)
363             {
364               u32 *esp_iv =
365                 (u32 *) (b0->data + b0->current_data + ip_hdr_size +
366                          sizeof (esp_header_t));
367               esp_iv[0] = sa0->seq;
368               esp_iv[1] = sa0->seq_hi;
369
370               cipher_off = ip_hdr_size + sizeof (esp_header_t) + iv_size;
371               cipher_len = BLOCK_SIZE * blocks;
372               iv_size = 16;     /* GCM IV size, not ESP IV size */
373
374               aad = priv->aad;
375               clib_memcpy (aad, vlib_buffer_get_current (b0) + ip_hdr_size,
376                            8);
377               aad_size = 8;
378               if (PREDICT_FALSE (sa0->use_esn))
379                 {
380                   *((u32 *) & aad[8]) = sa0->seq_hi;
381                   aad_size = 12;
382                 }
383
384               digest =
385                 vlib_buffer_get_current (b0) + b0->current_length -
386                 trunc_size;
387             }
388           else
389             {
390               cipher_off = ip_hdr_size + sizeof (esp_header_t);
391               cipher_len = BLOCK_SIZE * blocks + iv_size;
392
393               auth_off = ip_hdr_size;
394               auth_len = b0->current_length - ip_hdr_size - trunc_size;
395
396               digest =
397                 vlib_buffer_get_current (b0) + b0->current_length -
398                 trunc_size;
399
400               if (PREDICT_FALSE (sa0->use_esn))
401                 {
402                   *((u32 *) digest) = sa0->seq_hi;
403                   auth_len += sizeof (sa0->seq_hi);
404                 }
405             }
406
407           crypto_op_setup (is_aead, mb0, cop, sess,
408                            cipher_off, cipher_len, (u8 *) icb, iv_size,
409                            auth_off, auth_len, aad, aad_size,
410                            digest, 0, trunc_size);
411
412           if (PREDICT_FALSE (is_ipv6))
413             {
414               oh6_0->ip6.payload_length =
415                 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) -
416                                       sizeof (ip6_header_t));
417             }
418           else
419             {
420               oh0->ip4.length =
421                 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
422               oh0->ip4.checksum = ip4_header_checksum (&oh0->ip4);
423             }
424
425           if (transport_mode)
426             vlib_buffer_advance (b0, -sizeof (ethernet_header_t));
427
428         trace:
429           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
430             {
431               esp_encrypt_trace_t *tr =
432                 vlib_add_trace (vm, node, b0, sizeof (*tr));
433               tr->spi = sa0->spi;
434               tr->seq = sa0->seq - 1;
435               tr->crypto_alg = sa0->crypto_alg;
436               tr->integ_alg = sa0->integ_alg;
437             }
438         }
439       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
440     }
441   vlib_node_increment_counter (vm, dpdk_esp_encrypt_node.index,
442                                ESP_ENCRYPT_ERROR_RX_PKTS,
443                                from_frame->n_vectors);
444   crypto_qp_data_t *qpd;
445   /* *INDENT-OFF* */
446   vec_foreach_index (i, cwm->qp_data)
447     {
448       u32 enq;
449
450       if (!n_cop_qp[i])
451         continue;
452
453       qpd = vec_elt_at_index(cwm->qp_data, i);
454       enq = rte_cryptodev_enqueue_burst(qpd->dev_id, qpd->qp_id,
455                                         qpd->cops, n_cop_qp[i]);
456       qpd->inflights += enq;
457
458       if (PREDICT_FALSE(enq < n_cop_qp[i]))
459         {
460           crypto_free_cop (qpd, &qpd->cops[enq], n_cop_qp[i] - enq);
461           vlib_buffer_free (vm, &qpd->bi[enq], n_cop_qp[i] - enq);
462
463           vlib_node_increment_counter (vm, dpdk_esp_encrypt_node.index,
464                                        ESP_ENCRYPT_ERROR_ENQ_FAIL,
465                                        n_cop_qp[i] - enq);
466         }
467     }
468   /* *INDENT-ON* */
469
470   return from_frame->n_vectors;
471 }
472
473 /* *INDENT-OFF* */
474 VLIB_REGISTER_NODE (dpdk_esp_encrypt_node) = {
475   .function = dpdk_esp_encrypt_node_fn,
476   .name = "dpdk-esp-encrypt",
477   .flags = VLIB_NODE_FLAG_IS_OUTPUT,
478   .vector_size = sizeof (u32),
479   .format_trace = format_esp_encrypt_trace,
480   .n_errors = ARRAY_LEN (esp_encrypt_error_strings),
481   .error_strings = esp_encrypt_error_strings,
482   .n_next_nodes = 1,
483   .next_nodes =
484     {
485       [ESP_ENCRYPT_NEXT_DROP] = "error-drop",
486     }
487 };
488 /* *INDENT-ON* */
489
490 VLIB_NODE_FUNCTION_MULTIARCH (dpdk_esp_encrypt_node, dpdk_esp_encrypt_node_fn)
491 /*
492  * ESP Encrypt Post Node
493  */
494 #define foreach_esp_encrypt_post_error              \
495  _(PKTS, "ESP post pkts")
496      typedef enum
497      {
498 #define _(sym,str) ESP_ENCRYPT_POST_ERROR_##sym,
499        foreach_esp_encrypt_post_error
500 #undef _
501          ESP_ENCRYPT_POST_N_ERROR,
502      } esp_encrypt_post_error_t;
503
504      static char *esp_encrypt_post_error_strings[] = {
505 #define _(sym,string) string,
506        foreach_esp_encrypt_post_error
507 #undef _
508      };
509
510 vlib_node_registration_t dpdk_esp_encrypt_post_node;
511
512 static u8 *
513 format_esp_encrypt_post_trace (u8 * s, va_list * args)
514 {
515   return s;
516 }
517
518 static uword
519 dpdk_esp_encrypt_post_node_fn (vlib_main_t * vm,
520                                vlib_node_runtime_t * node,
521                                vlib_frame_t * from_frame)
522 {
523   u32 n_left_from, *from, *to_next = 0, next_index;
524
525   from = vlib_frame_vector_args (from_frame);
526   n_left_from = from_frame->n_vectors;
527
528   next_index = node->cached_next_index;
529
530   while (n_left_from > 0)
531     {
532       u32 n_left_to_next;
533
534       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
535
536       while (n_left_from > 0 && n_left_to_next > 0)
537         {
538           u32 bi0, next0;
539           vlib_buffer_t *b0 = 0;
540
541           bi0 = from[0];
542           from += 1;
543           n_left_from -= 1;
544           n_left_to_next -= 1;
545
546           b0 = vlib_get_buffer (vm, bi0);
547
548           to_next[0] = bi0;
549           to_next += 1;
550
551           next0 = vnet_buffer (b0)->unused[0];
552
553           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
554                                            to_next, n_left_to_next, bi0,
555                                            next0);
556         }
557       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
558     }
559
560   vlib_node_increment_counter (vm, dpdk_esp_encrypt_post_node.index,
561                                ESP_ENCRYPT_POST_ERROR_PKTS,
562                                from_frame->n_vectors);
563
564   return from_frame->n_vectors;
565 }
566
567 /* *INDENT-OFF* */
568 VLIB_REGISTER_NODE (dpdk_esp_encrypt_post_node) = {
569   .function = dpdk_esp_encrypt_post_node_fn,
570   .name = "dpdk-esp-encrypt-post",
571   .vector_size = sizeof (u32),
572   .format_trace = format_esp_encrypt_post_trace,
573   .type = VLIB_NODE_TYPE_INTERNAL,
574   .n_errors = ARRAY_LEN (esp_encrypt_post_error_strings),
575   .error_strings = esp_encrypt_post_error_strings,
576   .n_next_nodes = ESP_ENCRYPT_N_NEXT,
577   .next_nodes =
578     {
579 #define _(s,n) [ESP_ENCRYPT_NEXT_##s] = n,
580       foreach_esp_encrypt_next
581 #undef _
582     }
583 };
584 /* *INDENT-ON* */
585
586 VLIB_NODE_FUNCTION_MULTIARCH (dpdk_esp_encrypt_post_node,
587                               dpdk_esp_encrypt_post_node_fn)
588 /*
589  * fd.io coding-style-patch-verification: ON
590  *
591  * Local Variables:
592  * eval: (c-set-style "gnu")
593  * End:
594  */