+ ah_header_t *ah0;
+ ip4_header_t *ih4;
+ ip6_header_t *ih6;
+
+ if (vnet_buffer (b[0])->ipsec.sad_index != current_sa_index)
+ {
+ if (current_sa_index != ~0)
+ vlib_increment_combined_counter (&ipsec_sa_counters, thread_index,
+ current_sa_index,
+ current_sa_pkts,
+ current_sa_bytes);
+ current_sa_index = vnet_buffer (b[0])->ipsec.sad_index;
+ sa0 = pool_elt_at_index (im->sad, current_sa_index);
+
+ current_sa_bytes = current_sa_pkts = 0;
+ vlib_prefetch_combined_counter (&ipsec_sa_counters,
+ thread_index, current_sa_index);
+ }
+
+ if (PREDICT_FALSE (~0 == sa0->decrypt_thread_index))
+ {
+ /* this is the first packet to use this SA, claim the SA
+ * for this thread. this could happen simultaneously on
+ * another thread */
+ clib_atomic_cmp_and_swap (&sa0->decrypt_thread_index, ~0,
+ ipsec_sa_assign_thread (thread_index));
+ }
+
+ if (PREDICT_TRUE (thread_index != sa0->decrypt_thread_index))
+ {
+ next[0] = AH_DECRYPT_NEXT_HANDOFF;
+ goto next;
+ }
+
+ pd->sa_index = current_sa_index;
+
+ ih4 = vlib_buffer_get_current (b[0]);
+ ih6 = vlib_buffer_get_current (b[0]);
+ pd->current_data = b[0]->current_data;
+
+ if (is_ip6)
+ {
+ ip6_ext_header_t *prev = NULL;
+ ah0 =
+ ip6_ext_header_find (vm, b[0], ih6, IP_PROTOCOL_IPSEC_AH, &prev);
+ pd->ip_hdr_size = sizeof (ip6_header_t);
+ ASSERT ((u8 *) ah0 - (u8 *) ih6 == pd->ip_hdr_size);
+ }
+ else
+ {
+ if (ip4_is_fragment (ih4))
+ {
+ b[0]->error = node->errors[AH_DECRYPT_ERROR_DROP_FRAGMENTS];
+ next[0] = AH_DECRYPT_NEXT_DROP;
+ goto next;
+ }
+ pd->ip_hdr_size = ip4_header_bytes (ih4);
+ ah0 = (ah_header_t *) ((u8 *) ih4 + pd->ip_hdr_size);
+ }
+
+ pd->seq = clib_host_to_net_u32 (ah0->seq_no);
+
+ /* anti-replay check */
+ if (ipsec_sa_anti_replay_check (sa0, pd->seq))
+ {
+ b[0]->error = node->errors[AH_DECRYPT_ERROR_REPLAY];
+ next[0] = AH_DECRYPT_NEXT_DROP;
+ goto next;
+ }