2 * ah_encrypt.c : ipsecmb AH encrypt node
4 * Copyright (c) 2015 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #include <vnet/vnet.h>
19 #include <vnet/api_errno.h>
20 #include <vnet/ip/ip.h>
22 #include <vnet/ipsec/ipsec.h>
23 #include <vnet/ipsec/esp.h>
24 #include <vnet/ipsec/ah.h>
26 #include <ipsecmb/ipsecmb.h>
28 #define foreach_ah_encrypt_next \
29 _(DROP, "error-drop") \
30 _(IP4_LOOKUP, "ip4-lookup") \
31 _(IP6_LOOKUP, "ip6-lookup") \
32 _(INTERFACE_OUTPUT, "interface-output")
34 #define _(v, s) AH_ENCRYPT_NEXT_##v,
37 foreach_ah_encrypt_next
42 #define foreach_ah_encrypt_error \
43 _(RX_PKTS, "AH pkts received") \
44 _(SEQ_CYCLED, "sequence number cycled")
49 #define _(sym,str) AH_ENCRYPT_ERROR_##sym,
50 foreach_ah_encrypt_error
55 static char *ah_encrypt_error_strings[] = {
56 #define _(sym,string) string,
57 foreach_ah_encrypt_error
65 ipsec_integ_alg_t integ_alg;
68 /* packet trace format function */
70 format_ah_encrypt_trace (u8 * s, va_list * args)
72 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
73 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
74 ah_encrypt_trace_t *t = va_arg (*args, ah_encrypt_trace_t *);
76 s = format (s, "ah: spi %u seq %u integrity %U",
77 t->spi, t->seq, format_ipsec_integ_alg, t->integ_alg);
81 #ifdef CLIB_MARCH_VARIANT
83 ah_finish_encrypt (vlib_main_t * vm, vlib_buffer_t * b0, ipsec_sa_t * sa0,
88 ip6_header_t *oh6 = 0;
89 oh6 = vlib_buffer_get_current (b0);
90 oh6->ip_version_traffic_class_and_flow_label =
91 vnet_buffer (b0)->ipsec.ip_version_traffic_class_and_flow_label;
92 oh6->hop_limit = vnet_buffer (b0)->ipsec.ttl_or_hop_limit;
96 ip4_header_t *oh4 = 0;
97 oh4 = vlib_buffer_get_current (b0);
98 oh4->ttl = vnet_buffer (b0)->ipsec.ttl_or_hop_limit;
99 oh4->tos = vnet_buffer (b0)->ipsec.tos;
100 oh4->checksum = ip4_header_checksum (oh4);
105 ah_encrypt_ipsecmb_inline (vlib_main_t * vm,
106 vlib_node_runtime_t * node,
107 vlib_frame_t * from_frame, int is_ip6)
109 u32 n_left_from, *from, *to_next = 0, next_index;
111 from = vlib_frame_vector_args (from_frame);
112 n_left_from = from_frame->n_vectors;
113 ipsec_main_t *im = &ipsec_main;
114 ipsecmb_main_t *imbm = &ipsecmb_main;
115 ipsec_proto_main_t *em = &ipsec_proto_main;
116 next_index = node->cached_next_index;
117 u32 thread_index = vlib_get_thread_index ();
118 MB_MGR *mgr = imbm->mb_mgr[thread_index];
119 u32 packets_in_flight = 0;
121 while (n_left_from > 0 || packets_in_flight > 0)
125 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
127 while (n_left_from > 0 && n_left_to_next > 0)
130 vlib_buffer_t *b0 = 0;
134 ip4_header_t *ih4, *oh4 = 0;
135 ip6_header_t *ih6, *oh6 = 0;
138 u8 transport_mode = 0;
144 next0 = AH_ENCRYPT_NEXT_DROP;
146 b0 = vlib_get_buffer (vm, bi0);
147 sa_index0 = vnet_buffer (b0)->ipsec.sad_index;
148 sa0 = pool_elt_at_index (im->sad, sa_index0);
149 samb0 = pool_elt_at_index (imbm->sad, sa_index0);
151 if (PREDICT_FALSE (esp_seq_advance (sa0)))
153 clib_warning ("sequence number counter has cycled SPI %u",
155 vlib_node_increment_counter (vm, node->node_index,
156 AH_ENCRYPT_ERROR_SEQ_CYCLED, 1);
163 sa0->total_data_size += b0->current_length;
166 ih4 = vlib_buffer_get_current (b0);
168 if (PREDICT_TRUE (sa0->is_tunnel))
171 adv = -sizeof (ip4_and_ah_header_t);
173 adv = -sizeof (ip6_and_ah_header_t);
177 adv = -sizeof (ah_header_t);
180 const u8 padding_len = ah_calc_icv_padding_len (icv_size, is_ip6);
184 em->ipsec_proto_main_integ_algs[sa0->integ_alg].trunc_size;
185 /* transport mode save the eth header before it is overwritten */
186 if (PREDICT_FALSE (!sa0->is_tunnel))
188 ethernet_header_t *ieh0 = (ethernet_header_t *)
189 ((u8 *) vlib_buffer_get_current (b0) -
190 sizeof (ethernet_header_t));
191 ethernet_header_t *oeh0 =
192 (ethernet_header_t *) ((u8 *) ieh0 + (adv - icv_size));
193 clib_memcpy (oeh0, ieh0, sizeof (ethernet_header_t));
196 vlib_buffer_advance (b0, adv - icv_size);
200 ih6 = (ip6_header_t *) ih4;
201 oh6 = vlib_buffer_get_current (b0);
202 ah = (ah_header_t *) (oh6 + 1);
203 vnet_buffer (b0)->ipsec.ttl_or_hop_limit = ih6->hop_limit;
205 ipsec.ip_version_traffic_class_and_flow_label =
206 ih6->ip_version_traffic_class_and_flow_label;
208 if (PREDICT_TRUE (sa0->is_tunnel))
210 next_hdr_type = IP_PROTOCOL_IPV6;
214 next_hdr_type = ih6->protocol;
215 memmove (oh6, ih6, sizeof (ip6_header_t));
218 oh6->protocol = IP_PROTOCOL_IPSEC_AH;
219 oh6->ip_version_traffic_class_and_flow_label = 0x60;
222 ah->nexthdr = next_hdr_type;
223 ah->spi = clib_net_to_host_u32 (sa0->spi);
224 ah->seq_no = clib_net_to_host_u32 (sa0->seq);
226 (sizeof (ah_header_t) + icv_size + padding_len) / 4 - 2;
227 oh6->payload_length =
228 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) -
229 sizeof (ip6_header_t));
233 oh4 = vlib_buffer_get_current (b0);
234 memset (oh4, 0, sizeof (*oh4));
235 ah = (ah_header_t *) (oh4 + 1);
236 memset (ah, 0, sizeof (*ah));
237 vnet_buffer (b0)->ipsec.ttl_or_hop_limit = ih4->ttl;
238 vnet_buffer (b0)->ipsec.tos = ih4->tos;
240 if (PREDICT_TRUE (sa0->is_tunnel))
242 next_hdr_type = IP_PROTOCOL_IP_IN_IP;
246 next_hdr_type = ih4->protocol;
247 memmove (oh4, ih4, sizeof (ip4_header_t));
251 clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
252 oh4->ip_version_and_header_length = 0x45;
253 oh4->fragment_id = 0;
254 oh4->flags_and_fragment_offset = 0;
257 oh4->protocol = IP_PROTOCOL_IPSEC_AH;
258 ah->spi = clib_net_to_host_u32 (sa0->spi);
259 ah->seq_no = clib_net_to_host_u32 (sa0->seq);
261 ah->nexthdr = next_hdr_type;
263 (sizeof (ah_header_t) + icv_size + padding_len) / 4 - 2;
266 if (PREDICT_TRUE (!is_ip6 && sa0->is_tunnel && !sa0->is_tunnel_ip6))
268 oh4->src_address.as_u32 = sa0->tunnel_src_addr.ip4.as_u32;
269 oh4->dst_address.as_u32 = sa0->tunnel_dst_addr.ip4.as_u32;
271 next0 = AH_ENCRYPT_NEXT_IP4_LOOKUP;
272 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
274 else if (is_ip6 && sa0->is_tunnel && sa0->is_tunnel_ip6)
276 oh6->src_address.as_u64[0] = sa0->tunnel_src_addr.ip6.as_u64[0];
277 oh6->src_address.as_u64[1] = sa0->tunnel_src_addr.ip6.as_u64[1];
278 oh6->dst_address.as_u64[0] = sa0->tunnel_dst_addr.ip6.as_u64[0];
279 oh6->dst_address.as_u64[1] = sa0->tunnel_dst_addr.ip6.as_u64[1];
280 next0 = AH_ENCRYPT_NEXT_IP6_LOOKUP;
281 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
288 memset (ah + 1, 0, icv_size);
290 JOB_AES_HMAC *job = IPSECMB_FUNC (get_next_job) (mgr);
291 job->src = vlib_buffer_get_current (b0);
292 job->hash_start_src_offset_in_bytes = 0;
293 job->cipher_mode = NULL_CIPHER;
294 job->hash_alg = imbm->integ_algs[sa0->integ_alg].hash_alg;
295 job->auth_tag_output_len_in_bytes =
296 imbm->integ_algs[sa0->integ_alg].hash_output_length;
297 job->auth_tag_output = (u8 *) (ah + 1);
298 if (PREDICT_TRUE (sa0->use_esn))
300 *(u32 *) (vlib_buffer_get_current (b0) + b0->current_length) =
302 b0->current_length += sizeof (u32);
304 job->msg_len_to_hash_in_bytes = b0->current_length;
305 job->cipher_direction = ENCRYPT;
306 job->chain_order = HASH_CIPHER;
307 job->u.HMAC._hashed_auth_key_xor_ipad = samb0->ipad_hash;
308 job->u.HMAC._hashed_auth_key_xor_opad = samb0->opad_hash;
311 job->user_data = (void *) (uintptr_t) bi0;
312 job->user_data2 = (void *) (uintptr_t) next0;
313 vnet_buffer (b0)->ipsec.sad_index = sa_index0;
315 job = IPSECMB_FUNC (submit_job) (mgr);
324 ASSERT (STS_COMPLETED == job->status);
325 bi0 = (uintptr_t) job->user_data;
326 next0 = (uintptr_t) job->user_data2;
327 b0 = vlib_get_buffer (vm, bi0);
329 pool_elt_at_index (im->sad, vnet_buffer (b0)->ipsec.sad_index);
330 ah_finish_encrypt (vm, b0, sa0, is_ip6);
331 if (!sa0->is_tunnel && !sa0->is_tunnel_ip6)
333 next0 = AH_ENCRYPT_NEXT_INTERFACE_OUTPUT;
334 vlib_buffer_advance (b0, -sizeof (ethernet_header_t));
342 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
344 ah_encrypt_trace_t *tr =
345 vlib_add_trace (vm, node, b0, sizeof (*tr));
347 tr->seq = sa0->seq - 1;
348 tr->integ_alg = sa0->integ_alg;
351 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
352 to_next, n_left_to_next, bi0,
356 if (PREDICT_FALSE (n_left_from == 0))
358 JOB_AES_HMAC *job = NULL;
359 while (n_left_to_next > 0 && (job = IPSECMB_FUNC (flush_job) (mgr)))
366 ASSERT (STS_COMPLETED == job->status);
367 bi0 = (uintptr_t) job->user_data;
368 next0 = (uintptr_t) job->user_data2;
369 b0 = vlib_get_buffer (vm, bi0);
371 pool_elt_at_index (im->sad,
372 vnet_buffer (b0)->ipsec.sad_index);
373 ah_finish_encrypt (vm, b0, sa0, is_ip6);
374 if (!sa0->is_tunnel && !sa0->is_tunnel_ip6)
376 next0 = AH_ENCRYPT_NEXT_INTERFACE_OUTPUT;
377 vlib_buffer_advance (b0, -sizeof (ethernet_header_t));
384 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
386 ah_encrypt_trace_t *tr =
387 vlib_add_trace (vm, node, b0, sizeof (*tr));
389 tr->seq = sa0->seq - 1;
390 tr->integ_alg = sa0->integ_alg;
393 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
394 to_next, n_left_to_next, bi0,
398 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
400 vlib_node_increment_counter (vm, node->node_index, AH_ENCRYPT_ERROR_RX_PKTS,
401 from_frame->n_vectors);
403 return from_frame->n_vectors;
406 VLIB_NODE_FN (ah4_encrypt_ipsecmb_node) (vlib_main_t * vm,
407 vlib_node_runtime_t * node,
408 vlib_frame_t * from_frame)
410 return ah_encrypt_ipsecmb_inline (vm, node, from_frame, 0 /*is_ip6 */ );
413 VLIB_NODE_FN (ah6_encrypt_ipsecmb_node) (vlib_main_t * vm,
414 vlib_node_runtime_t * node,
415 vlib_frame_t * from_frame)
417 return ah_encrypt_ipsecmb_inline (vm, node, from_frame, 1 /*is_ip6 */ );
423 VLIB_REGISTER_NODE (ah4_encrypt_ipsecmb_node) = {
424 .name = "ah4-encrypt-ipsecmb",
425 .vector_size = sizeof (u32),
426 .format_trace = format_ah_encrypt_trace,
427 .type = VLIB_NODE_TYPE_INTERNAL,
429 .n_errors = ARRAY_LEN(ah_encrypt_error_strings),
430 .error_strings = ah_encrypt_error_strings,
432 .n_next_nodes = AH_ENCRYPT_N_NEXT,
434 #define _(s,n) [AH_ENCRYPT_NEXT_##s] = n,
435 foreach_ah_encrypt_next
442 VLIB_REGISTER_NODE (ah6_encrypt_ipsecmb_node) = {
443 .name = "ah6-encrypt-ipsecmb",
444 .vector_size = sizeof (u32),
445 .format_trace = format_ah_encrypt_trace,
446 .type = VLIB_NODE_TYPE_INTERNAL,
448 .n_errors = ARRAY_LEN(ah_encrypt_error_strings),
449 .error_strings = ah_encrypt_error_strings,
451 .n_next_nodes = AH_ENCRYPT_N_NEXT,
453 #define _(s,n) [AH_ENCRYPT_NEXT_##s] = n,
454 foreach_ah_encrypt_next
461 * fd.io coding-style-patch-verification: ON
464 * eval: (c-set-style "gnu")