+static_always_inline void
+esp_process_ops (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vnet_crypto_op_t * ops, vlib_buffer_t * b[], u16 * nexts,
+ int e)
+{
+ vnet_crypto_op_t *op = ops;
+ u32 n_fail, n_ops = vec_len (ops);
+
+ if (n_ops == 0)
+ return;
+
+ n_fail = n_ops - vnet_crypto_process_ops (vm, op, n_ops);
+
+ while (n_fail)
+ {
+ ASSERT (op - ops < n_ops);
+ if (op->status != VNET_CRYPTO_OP_STATUS_COMPLETED)
+ {
+ u32 err, bi = op->user_data;
+ if (op->status == VNET_CRYPTO_OP_STATUS_FAIL_BAD_HMAC)
+ err = e;
+ else
+ err = ESP_DECRYPT_ERROR_CRYPTO_ENGINE_ERROR;
+ b[bi]->error = node->errors[err];
+ nexts[bi] = ESP_DECRYPT_NEXT_DROP;
+ n_fail--;
+ }
+ op++;
+ }
+}
+
+static_always_inline void
+esp_process_chained_ops (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vnet_crypto_op_t * ops, vlib_buffer_t * b[],
+ u16 * nexts, vnet_crypto_op_chunk_t * chunks, int e)
+{
+
+ vnet_crypto_op_t *op = ops;
+ u32 n_fail, n_ops = vec_len (ops);
+
+ if (n_ops == 0)
+ return;
+
+ n_fail = n_ops - vnet_crypto_process_chained_ops (vm, op, chunks, n_ops);
+
+ while (n_fail)
+ {
+ ASSERT (op - ops < n_ops);
+ if (op->status != VNET_CRYPTO_OP_STATUS_COMPLETED)
+ {
+ u32 err, bi = op->user_data;
+ if (op->status == VNET_CRYPTO_OP_STATUS_FAIL_BAD_HMAC)
+ err = e;
+ else
+ err = ESP_DECRYPT_ERROR_CRYPTO_ENGINE_ERROR;
+ b[bi]->error = node->errors[err];
+ nexts[bi] = ESP_DECRYPT_NEXT_DROP;
+ n_fail--;
+ }
+ op++;
+ }
+}
+
+always_inline void
+esp_remove_tail (vlib_main_t * vm, vlib_buffer_t * b, vlib_buffer_t * last,
+ u16 tail)
+{
+ vlib_buffer_t *before_last = b;
+
+ if (last->current_length > tail)
+ {
+ last->current_length -= tail;
+ return;
+ }
+ ASSERT (b->flags & VLIB_BUFFER_NEXT_PRESENT);
+
+ while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
+ {
+ before_last = b;
+ b = vlib_get_buffer (vm, b->next_buffer);
+ }
+ before_last->current_length -= tail - last->current_length;
+ vlib_buffer_free_one (vm, before_last->next_buffer);
+ before_last->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
+}
+
+/* ICV is splitted in last two buffers so move it to the last buffer and
+ return pointer to it */
+static_always_inline u8 *
+esp_move_icv (vlib_main_t * vm, vlib_buffer_t * first,
+ esp_decrypt_packet_data_t * pd, u16 icv_sz)
+{
+ vlib_buffer_t *before_last, *bp;
+ u16 last_sz = pd->lb->current_length;
+ u16 first_sz = icv_sz - last_sz;
+
+ bp = before_last = first;
+ while (bp->flags & VLIB_BUFFER_NEXT_PRESENT)
+ {
+ before_last = bp;
+ bp = vlib_get_buffer (vm, bp->next_buffer);
+ }
+
+ u8 *lb_curr = vlib_buffer_get_current (pd->lb);
+ memmove (lb_curr + first_sz, lb_curr, last_sz);
+ clib_memcpy_fast (lb_curr, vlib_buffer_get_tail (before_last) - first_sz,
+ first_sz);
+ before_last->current_length -= first_sz;
+ pd->lb = before_last;
+ pd->icv_removed = 1;
+ pd->free_buffer_index = before_last->next_buffer;
+ before_last->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
+ return lb_curr;
+}
+