- u32 i_bi0, next0;
- vlib_buffer_t *i_b0 = 0;
- u32 sa_index0;
- ipsec_sa_t *sa0;
- ip4_and_ah_header_t *ih0, *oh0 = 0;
- ip6_and_ah_header_t *ih6_0, *oh6_0 = 0;
- u8 ip_hdr_size;
- u8 next_hdr_type;
- u8 tos = 0;
- u8 ttl = 0;
- u8 hop_limit = 0;
- u32 ip_version_traffic_class_and_flow_label = 0;
-
- i_bi0 = from[0];
- from += 1;
- n_left_from -= 1;
- n_left_to_next -= 1;
- next0 = AH_ENCRYPT_NEXT_DROP;
-
- i_b0 = vlib_get_buffer (vm, i_bi0);
- to_next[0] = i_bi0;
- to_next += 1;
- sa_index0 = vnet_buffer (i_b0)->ipsec.sad_index;
- sa0 = pool_elt_at_index (im->sad, sa_index0);
-
- if (PREDICT_FALSE (esp_seq_advance (sa0)))
- {
- i_b0->error = node->errors[AH_ENCRYPT_ERROR_SEQ_CYCLED];
- goto trace;
- }
- vlib_increment_combined_counter
- (&ipsec_sa_counters, thread_index, sa_index0,
- 1, i_b0->current_length);
+ /* 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->thread_index, ~0,
+ ipsec_sa_assign_thread (thread_index));
+ }
+
+ if (PREDICT_TRUE (thread_index != sa0->thread_index))
+ {
+ next[0] = AH_ENCRYPT_NEXT_HANDOFF;
+ goto next;
+ }
+
+ if (PREDICT_FALSE (esp_seq_advance (sa0)))
+ {
+ b[0]->error = node->errors[AH_ENCRYPT_ERROR_SEQ_CYCLED];
+ pd->skip = 1;
+ goto next;
+ }
+
+ current_sa_pkts += 1;
+ current_sa_bytes += b[0]->current_length;
+
+ ssize_t adv;
+ ih0 = vlib_buffer_get_current (b[0]);
+
+ if (PREDICT_TRUE (ipsec_sa_is_set_IS_TUNNEL (sa0)))
+ {
+ if (is_ip6)
+ adv = -sizeof (ip6_and_ah_header_t);
+ else
+ adv = -sizeof (ip4_and_ah_header_t);
+ }
+ else
+ {
+ adv = -sizeof (ah_header_t);
+ }
+
+ icv_size = sa0->integ_icv_size;
+ const u8 padding_len = ah_calc_icv_padding_len (icv_size, is_ip6);
+ adv -= padding_len;
+ /* transport mode save the eth header before it is overwritten */
+ if (PREDICT_FALSE (!ipsec_sa_is_set_IS_TUNNEL (sa0)))
+ {
+ const u32 l2_len = vnet_buffer (b[0])->ip.save_rewrite_length;
+ u8 *l2_hdr_in = (u8 *) vlib_buffer_get_current (b[0]) - l2_len;
+
+ u8 *l2_hdr_out = l2_hdr_in + adv - icv_size;
+
+ clib_memcpy_le32 (l2_hdr_out, l2_hdr_in, l2_len);
+ }
+
+ vlib_buffer_advance (b[0], adv - icv_size);
+
+ if (is_ip6)
+ {
+ ih6_0 = (ip6_and_ah_header_t *) ih0;
+ ip_hdr_size = sizeof (ip6_header_t);
+ oh6_0 = vlib_buffer_get_current (b[0]);
+ pd->current_data = b[0]->current_data;
+ pd->hop_limit = ih6_0->ip6.hop_limit;
+
+ oh6_0->ip6.ip_version_traffic_class_and_flow_label =
+ ih6_0->ip6.ip_version_traffic_class_and_flow_label;