+ n_left = from_frame->n_vectors;
+ next = nexts;
+ pd = pkt_data;
+ b = bufs;
+
+ while (n_left)
+ {
+ const u8 tun_flags = IPSEC_SA_FLAG_IS_TUNNEL |
+ IPSEC_SA_FLAG_IS_TUNNEL_V6;
+
+ if (n_left >= 2)
+ {
+ void *data = b[1]->data + pd[1].current_data;
+
+ /* buffer metadata */
+ vlib_prefetch_buffer_header (b[1], LOAD);
+
+ /* esp_footer_t */
+ CLIB_PREFETCH (data + pd[1].current_length - pd[1].icv_sz - 2,
+ CLIB_CACHE_LINE_BYTES, LOAD);
+
+ /* packet headers */
+ CLIB_PREFETCH (data - CLIB_CACHE_LINE_BYTES,
+ CLIB_CACHE_LINE_BYTES * 2, LOAD);
+ }
+
+ if (next[0] < ESP_DECRYPT_N_NEXT)
+ goto trace;
+
+ sa0 = vec_elt_at_index (im->sad, pd->sa_index);
+ u8 *payload = b[0]->data + pd->current_data;
+
+ ipsec_sa_anti_replay_advance (sa0, &((esp_header_t *) payload)->seq);
+
+ esp_footer_t *f = (esp_footer_t *) (b[0]->data + pd->current_data +
+ pd->current_length - sizeof (*f) -
+ pd->icv_sz);
+ u16 adv = pd->iv_sz + esp_sz;
+ u16 tail = sizeof (esp_footer_t) + f->pad_length + pd->icv_sz;
+
+ if ((pd->flags & tun_flags) == 0) /* transport mode */
+ {
+ u8 udp_sz = (is_ip6 == 0 && pd->flags & IPSEC_SA_FLAG_UDP_ENCAP) ?
+ sizeof (udp_header_t) : 0;
+ u16 ip_hdr_sz = pd->hdr_sz - udp_sz;
+ u8 *old_ip = b[0]->data + pd->current_data - ip_hdr_sz - udp_sz;
+ u8 *ip = old_ip + adv + udp_sz;
+
+ if (is_ip6 && ip_hdr_sz > 64)
+ memmove (ip, old_ip, ip_hdr_sz);
+ else
+ clib_memcpy_le64 (ip, old_ip, ip_hdr_sz);
+
+ b[0]->current_data = pd->current_data + adv - ip_hdr_sz;
+ b[0]->current_length = pd->current_length + ip_hdr_sz - tail - adv;
+
+ if (is_ip6)