ipsec: esp-encrypt and esp-decrypt cleanup
[vpp.git] / src / vnet / ipsec / esp_encrypt.c
index 1e0bd7f..080a345 100644 (file)
@@ -122,325 +122,282 @@ esp_encrypt_inline (vlib_main_t * vm,
                    vlib_node_runtime_t * node, vlib_frame_t * from_frame,
                    int is_ip6)
 {
-  u32 n_left_from, *from, *to_next = 0, next_index;
-  from = vlib_frame_vector_args (from_frame);
-  n_left_from = from_frame->n_vectors;
+  u32 *from = vlib_frame_vector_args (from_frame);
+  u32 n_left_from = from_frame->n_vectors;
   ipsec_main_t *im = &ipsec_main;
   ipsec_proto_main_t *em = &ipsec_proto_main;
-  u32 *recycle = 0;
-  u32 thread_index = vm->thread_index;
-
-  ipsec_alloc_empty_buffers (vm, im);
-
-  u32 *empty_buffers = im->empty_buffers[thread_index];
-
-  if (PREDICT_FALSE (vec_len (empty_buffers) < n_left_from))
+  u32 new_bufs[VLIB_FRAME_SIZE];
+  vlib_buffer_t *i_bufs[VLIB_FRAME_SIZE], **ib = i_bufs;
+  vlib_buffer_t *o_bufs[VLIB_FRAME_SIZE], **ob = o_bufs;
+  u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
+  u32 n_alloc, thread_index = vm->thread_index;
+
+  n_alloc = vlib_buffer_alloc (vm, new_bufs, n_left_from);
+  if (n_alloc != n_left_from)
     {
       vlib_node_increment_counter (vm, node->node_index,
-                                  ESP_ENCRYPT_ERROR_NO_BUFFER, n_left_from);
-      clib_warning ("not enough empty buffers. discarding frame");
-      goto free_buffers_and_exit;
+                                  ESP_ENCRYPT_ERROR_NO_BUFFER,
+                                  n_left_from - n_alloc);
+      if (n_alloc == 0)
+       goto done;
+      n_left_from = n_alloc;
     }
 
-  next_index = node->cached_next_index;
+  vlib_get_buffers (vm, from, ib, n_left_from);
+  vlib_get_buffers (vm, new_bufs, ob, n_left_from);
 
   while (n_left_from > 0)
     {
-      u32 n_left_to_next;
-
-      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
-
-      while (n_left_from > 0 && n_left_to_next > 0)
+      u32 sa_index0;
+      ipsec_sa_t *sa0;
+      ip4_and_esp_header_t *oh0 = 0;
+      ip6_and_esp_header_t *ih6_0, *oh6_0 = 0;
+      ip4_and_udp_and_esp_header_t *iuh0, *ouh0 = 0;
+      esp_header_t *o_esp0;
+      esp_footer_t *f0;
+      u8 ip_udp_hdr_size;
+      u8 next_hdr_type;
+      u32 ip_proto = 0;
+      u8 transport_mode = 0;
+      u32 esp_seq_err;
+
+      next[0] = ESP_ENCRYPT_NEXT_DROP;
+
+      sa_index0 = vnet_buffer (ib[0])->ipsec.sad_index;
+      sa0 = pool_elt_at_index (im->sad, sa_index0);
+
+      vlib_prefetch_combined_counter (&ipsec_sa_counters, thread_index,
+                                     sa_index0);
+
+      esp_seq_err = esp_seq_advance (sa0);
+
+      /* grab free buffer */
+      ob[0]->flags = VLIB_BUFFER_TOTAL_LENGTH_VALID;
+      ob[0]->current_data = sizeof (ethernet_header_t);
+      iuh0 = vlib_buffer_get_current (ib[0]);
+
+      if (is_ip6)
        {
-         u32 i_bi0, o_bi0, next0;
-         vlib_buffer_t *i_b0, *o_b0 = 0;
-         u32 sa_index0;
-         ipsec_sa_t *sa0;
-         ip4_and_esp_header_t *oh0 = 0;
-         ip6_and_esp_header_t *ih6_0, *oh6_0 = 0;
-         ip4_and_udp_and_esp_header_t *iuh0, *ouh0 = 0;
-         uword last_empty_buffer;
-         esp_header_t *o_esp0;
-         esp_footer_t *f0;
-         u8 ip_udp_hdr_size;
-         u8 next_hdr_type;
-         u32 ip_proto = 0;
-         u8 transport_mode = 0;
-
-         i_bi0 = from[0];
-         from += 1;
-         n_left_from -= 1;
-         n_left_to_next -= 1;
-
-         next0 = ESP_ENCRYPT_NEXT_DROP;
-
-         i_b0 = vlib_get_buffer (vm, i_bi0);
-         sa_index0 = vnet_buffer (i_b0)->ipsec.sad_index;
-         sa0 = pool_elt_at_index (im->sad, sa_index0);
-
-         vlib_prefetch_combined_counter
-           (&ipsec_sa_counters, thread_index, sa_index0);
-
-         if (PREDICT_FALSE (esp_seq_advance (sa0)))
-           {
-             clib_warning ("sequence number counter has cycled SPI %u",
-                           sa0->spi);
-             vlib_node_increment_counter (vm, node->node_index,
-                                          ESP_ENCRYPT_ERROR_SEQ_CYCLED, 1);
-             //TODO: rekey SA
-             o_bi0 = i_bi0;
-             to_next[0] = o_bi0;
-             to_next += 1;
-             goto trace;
-           }
-
-         /* grab free buffer */
-         last_empty_buffer = vec_len (empty_buffers) - 1;
-         o_bi0 = empty_buffers[last_empty_buffer];
-         o_b0 = vlib_get_buffer (vm, o_bi0);
-         o_b0->flags = VLIB_BUFFER_TOTAL_LENGTH_VALID;
-         o_b0->current_data = sizeof (ethernet_header_t);
-         iuh0 = vlib_buffer_get_current (i_b0);
-         vlib_prefetch_buffer_with_index (vm,
-                                          empty_buffers[last_empty_buffer -
-                                                        1], STORE);
-         _vec_len (empty_buffers) = last_empty_buffer;
-         to_next[0] = o_bi0;
-         to_next += 1;
-
-         /* add old buffer to the recycle list */
-         vec_add1 (recycle, i_bi0);
-
-         if (is_ip6)
+         ih6_0 = vlib_buffer_get_current (ib[0]);
+         next_hdr_type = IP_PROTOCOL_IPV6;
+         oh6_0 = vlib_buffer_get_current (ob[0]);
+
+         oh6_0->ip6.ip_version_traffic_class_and_flow_label =
+           ih6_0->ip6.ip_version_traffic_class_and_flow_label;
+         oh6_0->ip6.protocol = IP_PROTOCOL_IPSEC_ESP;
+         ip_udp_hdr_size = sizeof (ip6_header_t);
+         o_esp0 = vlib_buffer_get_current (ob[0]) + ip_udp_hdr_size;
+         oh6_0->ip6.hop_limit = 254;
+         oh6_0->ip6.src_address.as_u64[0] = ih6_0->ip6.src_address.as_u64[0];
+         oh6_0->ip6.src_address.as_u64[1] = ih6_0->ip6.src_address.as_u64[1];
+         oh6_0->ip6.dst_address.as_u64[0] = ih6_0->ip6.dst_address.as_u64[0];
+         oh6_0->ip6.dst_address.as_u64[1] = ih6_0->ip6.dst_address.as_u64[1];
+         o_esp0->spi = clib_net_to_host_u32 (sa0->spi);
+         o_esp0->seq = clib_net_to_host_u32 (sa0->seq);
+         ip_proto = ih6_0->ip6.protocol;
+
+         next[0] = ESP_ENCRYPT_NEXT_IP6_LOOKUP;
+       }
+      else
+       {
+         next_hdr_type = IP_PROTOCOL_IP_IN_IP;
+         oh0 = vlib_buffer_get_current (ob[0]);
+         ouh0 = vlib_buffer_get_current (ob[0]);
+
+         oh0->ip4.ip_version_and_header_length = 0x45;
+         oh0->ip4.tos = iuh0->ip4.tos;
+         oh0->ip4.fragment_id = 0;
+         oh0->ip4.flags_and_fragment_offset = 0;
+         oh0->ip4.ttl = 254;
+         if (sa0->udp_encap)
            {
-             ih6_0 = vlib_buffer_get_current (i_b0);
-             next_hdr_type = IP_PROTOCOL_IPV6;
-             oh6_0 = vlib_buffer_get_current (o_b0);
-
-             oh6_0->ip6.ip_version_traffic_class_and_flow_label =
-               ih6_0->ip6.ip_version_traffic_class_and_flow_label;
-             oh6_0->ip6.protocol = IP_PROTOCOL_IPSEC_ESP;
-             ip_udp_hdr_size = sizeof (ip6_header_t);
-             o_esp0 = vlib_buffer_get_current (o_b0) + ip_udp_hdr_size;
-             oh6_0->ip6.hop_limit = 254;
-             oh6_0->ip6.src_address.as_u64[0] =
-               ih6_0->ip6.src_address.as_u64[0];
-             oh6_0->ip6.src_address.as_u64[1] =
-               ih6_0->ip6.src_address.as_u64[1];
-             oh6_0->ip6.dst_address.as_u64[0] =
-               ih6_0->ip6.dst_address.as_u64[0];
-             oh6_0->ip6.dst_address.as_u64[1] =
-               ih6_0->ip6.dst_address.as_u64[1];
-             o_esp0->spi = clib_net_to_host_u32 (sa0->spi);
-             o_esp0->seq = clib_net_to_host_u32 (sa0->seq);
-             ip_proto = ih6_0->ip6.protocol;
-
-             next0 = ESP_ENCRYPT_NEXT_IP6_LOOKUP;
+             ouh0->udp.src_port = clib_host_to_net_u16 (UDP_DST_PORT_ipsec);
+             ouh0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipsec);
+             ouh0->udp.checksum = 0;
+             ouh0->ip4.protocol = IP_PROTOCOL_UDP;
+             ip_udp_hdr_size = sizeof (udp_header_t) + sizeof (ip4_header_t);
            }
          else
            {
-             next_hdr_type = IP_PROTOCOL_IP_IN_IP;
-             oh0 = vlib_buffer_get_current (o_b0);
-             ouh0 = vlib_buffer_get_current (o_b0);
-
-             oh0->ip4.ip_version_and_header_length = 0x45;
-             oh0->ip4.tos = iuh0->ip4.tos;
-             oh0->ip4.fragment_id = 0;
-             oh0->ip4.flags_and_fragment_offset = 0;
-             oh0->ip4.ttl = 254;
-             if (sa0->udp_encap)
-               {
-                 ouh0->udp.src_port =
-                   clib_host_to_net_u16 (UDP_DST_PORT_ipsec);
-                 ouh0->udp.dst_port =
-                   clib_host_to_net_u16 (UDP_DST_PORT_ipsec);
-                 ouh0->udp.checksum = 0;
-                 ouh0->ip4.protocol = IP_PROTOCOL_UDP;
-                 ip_udp_hdr_size =
-                   sizeof (udp_header_t) + sizeof (ip4_header_t);
-               }
-             else
-               {
-                 oh0->ip4.protocol = IP_PROTOCOL_IPSEC_ESP;
-                 ip_udp_hdr_size = sizeof (ip4_header_t);
-               }
-             o_esp0 = vlib_buffer_get_current (o_b0) + ip_udp_hdr_size;
-             oh0->ip4.src_address.as_u32 = iuh0->ip4.src_address.as_u32;
-             oh0->ip4.dst_address.as_u32 = iuh0->ip4.dst_address.as_u32;
-             o_esp0->spi = clib_net_to_host_u32 (sa0->spi);
-             o_esp0->seq = clib_net_to_host_u32 (sa0->seq);
-             ip_proto = iuh0->ip4.protocol;
-
-             next0 = ESP_ENCRYPT_NEXT_IP4_LOOKUP;
+             oh0->ip4.protocol = IP_PROTOCOL_IPSEC_ESP;
+             ip_udp_hdr_size = sizeof (ip4_header_t);
            }
+         o_esp0 = vlib_buffer_get_current (ob[0]) + ip_udp_hdr_size;
+         oh0->ip4.src_address.as_u32 = iuh0->ip4.src_address.as_u32;
+         oh0->ip4.dst_address.as_u32 = iuh0->ip4.dst_address.as_u32;
+         o_esp0->spi = clib_net_to_host_u32 (sa0->spi);
+         o_esp0->seq = clib_net_to_host_u32 (sa0->seq);
+         ip_proto = iuh0->ip4.protocol;
+
+         next[0] = ESP_ENCRYPT_NEXT_IP4_LOOKUP;
+       }
 
-         if (PREDICT_TRUE (!is_ip6 && sa0->is_tunnel && !sa0->is_tunnel_ip6))
-           {
-             oh0->ip4.src_address.as_u32 = sa0->tunnel_src_addr.ip4.as_u32;
-             oh0->ip4.dst_address.as_u32 = sa0->tunnel_dst_addr.ip4.as_u32;
+      if (PREDICT_TRUE (!is_ip6 && sa0->is_tunnel && !sa0->is_tunnel_ip6))
+       {
+         oh0->ip4.src_address.as_u32 = sa0->tunnel_src_addr.ip4.as_u32;
+         oh0->ip4.dst_address.as_u32 = sa0->tunnel_dst_addr.ip4.as_u32;
 
-             next0 = sa0->dpo[IPSEC_PROTOCOL_ESP].dpoi_next_node;
-             vnet_buffer (o_b0)->ip.adj_index[VLIB_TX] =
-               sa0->dpo[IPSEC_PROTOCOL_ESP].dpoi_index;
-           }
-         else if (is_ip6 && sa0->is_tunnel && sa0->is_tunnel_ip6)
+         next[0] = sa0->dpo[IPSEC_PROTOCOL_ESP].dpoi_next_node;
+         vnet_buffer (ob[0])->ip.adj_index[VLIB_TX] =
+           sa0->dpo[IPSEC_PROTOCOL_ESP].dpoi_index;
+       }
+      else if (is_ip6 && sa0->is_tunnel && sa0->is_tunnel_ip6)
+       {
+         oh6_0->ip6.src_address.as_u64[0] =
+           sa0->tunnel_src_addr.ip6.as_u64[0];
+         oh6_0->ip6.src_address.as_u64[1] =
+           sa0->tunnel_src_addr.ip6.as_u64[1];
+         oh6_0->ip6.dst_address.as_u64[0] =
+           sa0->tunnel_dst_addr.ip6.as_u64[0];
+         oh6_0->ip6.dst_address.as_u64[1] =
+           sa0->tunnel_dst_addr.ip6.as_u64[1];
+
+         next[0] = sa0->dpo[IPSEC_PROTOCOL_ESP].dpoi_next_node;
+         vnet_buffer (ob[0])->ip.adj_index[VLIB_TX] =
+           sa0->dpo[IPSEC_PROTOCOL_ESP].dpoi_index;
+       }
+      else
+       {
+         next_hdr_type = ip_proto;
+         if (vnet_buffer (ib[0])->sw_if_index[VLIB_TX] != ~0)
            {
-             oh6_0->ip6.src_address.as_u64[0] =
-               sa0->tunnel_src_addr.ip6.as_u64[0];
-             oh6_0->ip6.src_address.as_u64[1] =
-               sa0->tunnel_src_addr.ip6.as_u64[1];
-             oh6_0->ip6.dst_address.as_u64[0] =
-               sa0->tunnel_dst_addr.ip6.as_u64[0];
-             oh6_0->ip6.dst_address.as_u64[1] =
-               sa0->tunnel_dst_addr.ip6.as_u64[1];
-
-             next0 = sa0->dpo[IPSEC_PROTOCOL_ESP].dpoi_next_node;
-             vnet_buffer (o_b0)->ip.adj_index[VLIB_TX] =
-               sa0->dpo[IPSEC_PROTOCOL_ESP].dpoi_index;
+             transport_mode = 1;
+             ethernet_header_t *ieh0, *oeh0;
+             ieh0 =
+               (ethernet_header_t *) ((u8 *)
+                                      vlib_buffer_get_current (ib[0]) -
+                                      sizeof (ethernet_header_t));
+             oeh0 = (ethernet_header_t *) ob[0]->data;
+             clib_memcpy_fast (oeh0, ieh0, sizeof (ethernet_header_t));
+             next[0] = ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT;
+             vnet_buffer (ob[0])->sw_if_index[VLIB_TX] =
+               vnet_buffer (ib[0])->sw_if_index[VLIB_TX];
            }
+
+         if (is_ip6)
+           vlib_buffer_advance (ib[0], sizeof (ip6_header_t));
          else
-           {
-             next_hdr_type = ip_proto;
-             if (vnet_buffer (i_b0)->sw_if_index[VLIB_TX] != ~0)
-               {
-                 transport_mode = 1;
-                 ethernet_header_t *ieh0, *oeh0;
-                 ieh0 =
-                   (ethernet_header_t *) ((u8 *)
-                                          vlib_buffer_get_current (i_b0) -
-                                          sizeof (ethernet_header_t));
-                 oeh0 = (ethernet_header_t *) o_b0->data;
-                 clib_memcpy_fast (oeh0, ieh0, sizeof (ethernet_header_t));
-                 next0 = ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT;
-                 vnet_buffer (o_b0)->sw_if_index[VLIB_TX] =
-                   vnet_buffer (i_b0)->sw_if_index[VLIB_TX];
-               }
-
-             if (is_ip6)
-               {
-                 vlib_buffer_advance (i_b0, sizeof (ip6_header_t));
-               }
-             else
-               {
-                 vlib_buffer_advance (i_b0, sizeof (ip4_header_t));
-               }
-           }
+           vlib_buffer_advance (ib[0], sizeof (ip4_header_t));
+       }
 
-         ASSERT (sa0->crypto_alg < IPSEC_CRYPTO_N_ALG);
-         vlib_increment_combined_counter
-           (&ipsec_sa_counters, thread_index, sa_index0,
-            1, i_b0->current_length);
+      ASSERT (sa0->crypto_alg < IPSEC_CRYPTO_N_ALG);
+      vlib_increment_combined_counter
+       (&ipsec_sa_counters, thread_index, sa_index0,
+        1, ib[0]->current_length);
 
-         if (PREDICT_TRUE (sa0->crypto_alg != IPSEC_CRYPTO_ALG_NONE))
-           {
+      if (PREDICT_TRUE (sa0->crypto_alg != IPSEC_CRYPTO_ALG_NONE))
+       {
 
-             const int BLOCK_SIZE =
-               em->ipsec_proto_main_crypto_algs[sa0->crypto_alg].block_size;
-             const int IV_SIZE =
-               em->ipsec_proto_main_crypto_algs[sa0->crypto_alg].iv_size;
-             int blocks = 1 + (i_b0->current_length + 1) / BLOCK_SIZE;
-
-             /* pad packet in input buffer */
-             u8 pad_bytes = BLOCK_SIZE * blocks - 2 - i_b0->current_length;
-             u8 i;
-             u8 *padding =
-               vlib_buffer_get_current (i_b0) + i_b0->current_length;
-             i_b0->current_length = BLOCK_SIZE * blocks;
-             for (i = 0; i < pad_bytes; ++i)
-               {
-                 padding[i] = i + 1;
-               }
-             f0 = vlib_buffer_get_current (i_b0) + i_b0->current_length - 2;
-             f0->pad_length = pad_bytes;
-             f0->next_header = next_hdr_type;
-
-             o_b0->current_length = ip_udp_hdr_size + sizeof (esp_header_t) +
-               BLOCK_SIZE * blocks + IV_SIZE;
-
-             vnet_buffer (o_b0)->sw_if_index[VLIB_RX] =
-               vnet_buffer (i_b0)->sw_if_index[VLIB_RX];
-
-             u8 iv[em->
-                   ipsec_proto_main_crypto_algs[sa0->crypto_alg].iv_size];
-             RAND_bytes (iv, sizeof (iv));
-
-             clib_memcpy_fast ((u8 *) vlib_buffer_get_current (o_b0) +
-                               ip_udp_hdr_size + sizeof (esp_header_t), iv,
-                               em->ipsec_proto_main_crypto_algs[sa0->
-                                                                crypto_alg].iv_size);
-
-             esp_encrypt_cbc (vm, sa0->crypto_alg,
-                              (u8 *) vlib_buffer_get_current (i_b0),
-                              (u8 *) vlib_buffer_get_current (o_b0) +
-                              ip_udp_hdr_size + sizeof (esp_header_t) +
-                              IV_SIZE, BLOCK_SIZE * blocks,
-                              sa0->crypto_key.data, iv);
+         const int BLOCK_SIZE =
+           em->ipsec_proto_main_crypto_algs[sa0->crypto_alg].block_size;
+         const int IV_SIZE =
+           em->ipsec_proto_main_crypto_algs[sa0->crypto_alg].iv_size;
+         int blocks = 1 + (ib[0]->current_length + 1) / BLOCK_SIZE;
+
+         /* pad packet in input buffer */
+         u8 pad_bytes = BLOCK_SIZE * blocks - 2 - ib[0]->current_length;
+         u8 i;
+         u8 *padding =
+           vlib_buffer_get_current (ib[0]) + ib[0]->current_length;
+         ib[0]->current_length = BLOCK_SIZE * blocks;
+         for (i = 0; i < pad_bytes; ++i)
+           {
+             padding[i] = i + 1;
            }
+         f0 = vlib_buffer_get_current (ib[0]) + ib[0]->current_length - 2;
+         f0->pad_length = pad_bytes;
+         f0->next_header = next_hdr_type;
+
+         ob[0]->current_length = ip_udp_hdr_size + sizeof (esp_header_t) +
+           BLOCK_SIZE * blocks + IV_SIZE;
+
+         vnet_buffer (ob[0])->sw_if_index[VLIB_RX] =
+           vnet_buffer (ib[0])->sw_if_index[VLIB_RX];
+
+         u8 iv[em->ipsec_proto_main_crypto_algs[sa0->crypto_alg].iv_size];
+         RAND_bytes (iv, sizeof (iv));
+
+         clib_memcpy_fast ((u8 *) vlib_buffer_get_current (ob[0]) +
+                           ip_udp_hdr_size + sizeof (esp_header_t), iv,
+                           em->ipsec_proto_main_crypto_algs[sa0->
+                                                            crypto_alg].iv_size);
+
+         esp_encrypt_cbc (vm, sa0->crypto_alg,
+                          (u8 *) vlib_buffer_get_current (ib[0]),
+                          (u8 *) vlib_buffer_get_current (ob[0]) +
+                          ip_udp_hdr_size + sizeof (esp_header_t) +
+                          IV_SIZE, BLOCK_SIZE * blocks,
+                          sa0->crypto_key.data, iv);
+       }
 
-         o_b0->current_length +=
-           hmac_calc (sa0->integ_alg, sa0->integ_key.data,
-                      sa0->integ_key.len, (u8 *) o_esp0,
-                      o_b0->current_length - ip_udp_hdr_size,
-                      vlib_buffer_get_current (o_b0) + o_b0->current_length,
-                      sa0->use_esn, sa0->seq_hi);
+      ob[0]->current_length +=
+       hmac_calc (sa0->integ_alg, sa0->integ_key.data,
+                  sa0->integ_key.len, (u8 *) o_esp0,
+                  ob[0]->current_length - ip_udp_hdr_size,
+                  vlib_buffer_get_current (ob[0]) + ob[0]->current_length,
+                  sa0->use_esn, sa0->seq_hi);
 
 
-         if (is_ip6)
-           {
-             oh6_0->ip6.payload_length =
-               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, o_b0) -
-                                     sizeof (ip6_header_t));
-           }
-         else
+      if (is_ip6)
+       {
+         oh6_0->ip6.payload_length =
+           clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, ob[0]) -
+                                 sizeof (ip6_header_t));
+       }
+      else
+       {
+         oh0->ip4.length =
+           clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, ob[0]));
+         oh0->ip4.checksum = ip4_header_checksum (&oh0->ip4);
+         if (sa0->udp_encap)
            {
-             oh0->ip4.length =
-               clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, o_b0));
-             oh0->ip4.checksum = ip4_header_checksum (&oh0->ip4);
-             if (sa0->udp_encap)
-               {
-                 ouh0->udp.length =
-                   clib_host_to_net_u16 (clib_net_to_host_u16
-                                         (oh0->ip4.length) -
-                                         ip4_header_bytes (&oh0->ip4));
-               }
+             ouh0->udp.length =
+               clib_host_to_net_u16 (clib_net_to_host_u16
+                                     (oh0->ip4.length) -
+                                     ip4_header_bytes (&oh0->ip4));
            }
+       }
 
-         if (transport_mode)
-           vlib_buffer_reset (o_b0);
+      if (transport_mode)
+       vlib_buffer_reset (ob[0]);
+
+      if (PREDICT_FALSE (esp_seq_err))
+       {
+         ob[0]->error = node->errors[ESP_ENCRYPT_ERROR_SEQ_CYCLED];
+         next[0] = ESP_ENCRYPT_NEXT_DROP;
+       }
 
-       trace:
-         if (PREDICT_FALSE (i_b0->flags & VLIB_BUFFER_IS_TRACED))
+      if (PREDICT_FALSE (ib[0]->flags & VLIB_BUFFER_IS_TRACED))
+       {
+         if (ob[0])
            {
-             if (o_b0)
-               {
-                 o_b0->flags |= VLIB_BUFFER_IS_TRACED;
-                 o_b0->trace_index = i_b0->trace_index;
-                 esp_encrypt_trace_t *tr =
-                   vlib_add_trace (vm, node, o_b0, sizeof (*tr));
-                 tr->sa_index = sa_index0;
-                 tr->spi = sa0->spi;
-                 tr->seq = sa0->seq - 1;
-                 tr->udp_encap = sa0->udp_encap;
-                 tr->crypto_alg = sa0->crypto_alg;
-                 tr->integ_alg = sa0->integ_alg;
-               }
+             ob[0]->flags |= VLIB_BUFFER_IS_TRACED;
+             ob[0]->trace_index = ib[0]->trace_index;
+             esp_encrypt_trace_t *tr =
+               vlib_add_trace (vm, node, ob[0], sizeof (*tr));
+             tr->sa_index = sa_index0;
+             tr->spi = sa0->spi;
+             tr->seq = sa0->seq - 1;
+             tr->udp_encap = sa0->udp_encap;
+             tr->crypto_alg = sa0->crypto_alg;
+             tr->integ_alg = sa0->integ_alg;
            }
-
-         vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
-                                          to_next, n_left_to_next, o_bi0,
-                                          next0);
        }
-      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+
+      /* next */
+      n_left_from -= 1;
+      ib += 1;
+      ob += 1;
+      next += 1;
     }
+
   vlib_node_increment_counter (vm, node->node_index,
-                              ESP_ENCRYPT_ERROR_RX_PKTS,
-                              from_frame->n_vectors);
-
-free_buffers_and_exit:
-  if (recycle)
-    vlib_buffer_free (vm, recycle, vec_len (recycle));
-  vec_free (recycle);
-  return from_frame->n_vectors;
+                              ESP_ENCRYPT_ERROR_RX_PKTS, n_alloc);
+
+  vlib_buffer_enqueue_to_next (vm, node, new_bufs, nexts, n_alloc);
+done:
+  vlib_buffer_free (vm, from, from_frame->n_vectors);
+  return n_alloc;
 }
 
 VLIB_NODE_FN (esp4_encrypt_node) (vlib_main_t * vm,