blob: 4e93725b97c8ace8f8cb5e1ab78c694423e64ded [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * ipsec_if_in.c : IPSec interface input node
3 *
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:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 */
17
18#include <vnet/vnet.h>
19#include <vnet/api_errno.h>
20#include <vnet/ip/ip.h>
21
22#include <vnet/ipsec/ipsec.h>
23#include <vnet/ipsec/esp.h>
Neale Ranns918c1612019-02-21 23:34:59 -080024#include <vnet/ipsec/ipsec_io.h>
Neale Rannsb71fa752019-04-04 12:43:36 +000025#include <vnet/ipsec/ipsec_punt.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070026
27/* Statistics (not really errors) */
Matthew Smith831fd642018-05-15 22:03:05 -050028#define foreach_ipsec_if_input_error \
29_(RX, "good packets received") \
Neale Ranns8d7c5022019-02-06 01:41:05 -080030_(DISABLED, "ipsec packets received on disabled interface") \
Neale Rannsb71fa752019-04-04 12:43:36 +000031_(NO_TUNNEL, "no matching tunnel") \
32_(SPI_0, "SPI 0")
Ed Warnickecb9cada2015-12-08 15:45:58 -070033
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070034static char *ipsec_if_input_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -070035#define _(sym,string) string,
36 foreach_ipsec_if_input_error
37#undef _
38};
39
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070040typedef enum
41{
Ed Warnickecb9cada2015-12-08 15:45:58 -070042#define _(sym,str) IPSEC_IF_INPUT_ERROR_##sym,
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070043 foreach_ipsec_if_input_error
Ed Warnickecb9cada2015-12-08 15:45:58 -070044#undef _
45 IPSEC_IF_INPUT_N_ERROR,
46} ipsec_if_input_error_t;
47
Ed Warnickecb9cada2015-12-08 15:45:58 -070048
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070049typedef struct
50{
Ed Warnickecb9cada2015-12-08 15:45:58 -070051 u32 spi;
52 u32 seq;
53} ipsec_if_input_trace_t;
54
Kingwel Xiec69ac312019-02-04 01:49:29 -080055static u8 *
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070056format_ipsec_if_input_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -070057{
58 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
59 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070060 ipsec_if_input_trace_t *t = va_arg (*args, ipsec_if_input_trace_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -070061
Guillaume Solignac8f818cc2019-05-15 12:02:33 +020062 s = format (s, "IPSec: spi %u (0x%08x) seq %u", t->spi, t->spi, t->seq);
Ed Warnickecb9cada2015-12-08 15:45:58 -070063 return s;
64}
65
Neale Rannsb71fa752019-04-04 12:43:36 +000066always_inline u16
67ipsec_ip4_if_no_tunnel (vlib_node_runtime_t * node,
68 vlib_buffer_t * b,
69 const esp_header_t * esp,
70 const ip4_header_t * ip4, u16 offset)
71{
72 if (PREDICT_FALSE (0 == esp->spi))
73 {
74 b->error = node->errors[IPSEC_IF_INPUT_ERROR_SPI_0];
75 b->punt_reason =
76 ipsec_punt_reason[(ip4->protocol == IP_PROTOCOL_UDP ?
Neale Ranns719beb72019-07-10 07:10:25 +000077 IPSEC_PUNT_IP4_SPI_UDP_0 :
78 IPSEC_PUNT_IP4_NO_SUCH_TUNNEL)];
Neale Rannsb71fa752019-04-04 12:43:36 +000079 }
80 else
81 {
82 b->error = node->errors[IPSEC_IF_INPUT_ERROR_NO_TUNNEL];
83 b->punt_reason = ipsec_punt_reason[IPSEC_PUNT_IP4_NO_SUCH_TUNNEL];
84 }
85 vlib_buffer_advance (b, -offset);
86 return IPSEC_INPUT_NEXT_PUNT;
87}
88
89always_inline u16
90ipsec_ip6_if_no_tunnel (vlib_node_runtime_t * node,
91 vlib_buffer_t * b,
92 const esp_header_t * esp, u16 offset)
93{
Neale Ranns719beb72019-07-10 07:10:25 +000094 b->error = node->errors[IPSEC_IF_INPUT_ERROR_NO_TUNNEL];
95 b->punt_reason = ipsec_punt_reason[IPSEC_PUNT_IP6_NO_SUCH_TUNNEL];
96
Neale Rannsb71fa752019-04-04 12:43:36 +000097 vlib_buffer_advance (b, -offset);
98 return (IPSEC_INPUT_NEXT_PUNT);
99}
Kingwel Xie00bff192019-03-07 01:25:32 -0500100
101always_inline uword
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400102ipsec_if_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
103 vlib_frame_t * from_frame, int is_ip6)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700104{
105 ipsec_main_t *im = &ipsec_main;
Matthew Smith01034be2017-05-16 11:51:18 -0500106 vnet_main_t *vnm = im->vnet_main;
107 vnet_interface_main_t *vim = &vnm->interface_main;
Kingwel Xie00bff192019-03-07 01:25:32 -0500108
109 int is_trace = node->flags & VLIB_NODE_FLAG_TRACE;
Damjan Marion067cd622018-07-11 12:47:43 +0200110 u32 thread_index = vm->thread_index;
Kingwel Xie00bff192019-03-07 01:25:32 -0500111
112 u32 n_left_from, *from;
113 u16 nexts[VLIB_FRAME_SIZE], *next;
114 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
115
116 from = vlib_frame_vector_args (from_frame);
117 n_left_from = from_frame->n_vectors;
118
119 vlib_get_buffers (vm, from, bufs, n_left_from);
120 b = bufs;
121 next = nexts;
122
123 clib_memset_u16 (nexts, im->esp4_decrypt_next_index, n_left_from);
124
Matthew Smith01034be2017-05-16 11:51:18 -0500125 u64 n_bytes = 0, n_packets = 0;
Kingwel Xie00bff192019-03-07 01:25:32 -0500126 u32 n_disabled = 0, n_no_tunnel = 0;
127
128 u32 last_sw_if_index = ~0;
129 u32 last_tunnel_id = ~0;
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400130 ipsec4_tunnel_key_t last_key4;
131 ipsec6_tunnel_key_t last_key6;
Kingwel Xie00bff192019-03-07 01:25:32 -0500132
Matthew Smith831fd642018-05-15 22:03:05 -0500133 vlib_combined_counter_main_t *rx_counter;
134 vlib_combined_counter_main_t *drop_counter;
Matthew Smith831fd642018-05-15 22:03:05 -0500135
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400136 if (is_ip6)
137 clib_memset (&last_key6, 0xff, sizeof (last_key6));
138 else
139 last_key4.as_u64 = ~0;
140
Matthew Smith831fd642018-05-15 22:03:05 -0500141 rx_counter = vim->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX;
142 drop_counter = vim->combined_sw_if_counters + VNET_INTERFACE_COUNTER_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700143
Kingwel Xie00bff192019-03-07 01:25:32 -0500144 while (n_left_from >= 2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700145 {
Kingwel Xie00bff192019-03-07 01:25:32 -0500146 u32 sw_if_index0, sw_if_index1;
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400147 ip4_header_t *ip40, *ip41;
148 ip6_header_t *ip60, *ip61;
Kingwel Xie00bff192019-03-07 01:25:32 -0500149 esp_header_t *esp0, *esp1;
150 u32 len0, len1;
151 u16 buf_adv0, buf_adv1;
152 u32 tid0, tid1;
153 ipsec_tunnel_if_t *t0, *t1;
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400154 ipsec4_tunnel_key_t key40, key41;
155 ipsec6_tunnel_key_t key60, key61;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700156
Kingwel Xie00bff192019-03-07 01:25:32 -0500157 if (n_left_from >= 4)
Neale Ranns77eb28f2019-03-04 14:13:14 +0000158 {
Kingwel Xie00bff192019-03-07 01:25:32 -0500159 CLIB_PREFETCH (b[2], CLIB_CACHE_LINE_BYTES, STORE);
160 CLIB_PREFETCH (b[2]->data, CLIB_CACHE_LINE_BYTES, LOAD);
161 CLIB_PREFETCH (b[3], CLIB_CACHE_LINE_BYTES, STORE);
162 CLIB_PREFETCH (b[3]->data, CLIB_CACHE_LINE_BYTES, LOAD);
163 }
Neale Ranns77eb28f2019-03-04 14:13:14 +0000164
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400165 ip40 =
166 (ip4_header_t *) (b[0]->data + vnet_buffer (b[0])->l3_hdr_offset);
167 ip41 =
168 (ip4_header_t *) (b[1]->data + vnet_buffer (b[1])->l3_hdr_offset);
Neale Ranns77eb28f2019-03-04 14:13:14 +0000169
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400170 if (is_ip6)
Kingwel Xie00bff192019-03-07 01:25:32 -0500171 {
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400172 ip60 = (ip6_header_t *) ip40;
173 ip61 = (ip6_header_t *) ip41;
174 esp0 = (esp_header_t *) ((u8 *) ip60 + sizeof (ip6_header_t));
175 esp1 = (esp_header_t *) ((u8 *) ip61 + sizeof (ip6_header_t));
176 buf_adv0 = sizeof (ip6_header_t);
177 buf_adv1 = sizeof (ip6_header_t);
Kingwel Xie00bff192019-03-07 01:25:32 -0500178 }
179 else
180 {
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400181 /* NAT UDP port 4500 case, don't advance any more */
182 if (ip40->protocol == IP_PROTOCOL_UDP)
183 {
184 esp0 =
185 (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40) +
186 sizeof (udp_header_t));
187 buf_adv0 = 0;
188 }
189 else
190 {
191 esp0 = (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40));
192 buf_adv0 = ip4_header_bytes (ip40);
193 }
194 /* NAT UDP port 4500 case, don't advance any more */
195 if (ip41->protocol == IP_PROTOCOL_UDP)
196 {
197 esp1 =
198 (esp_header_t *) ((u8 *) ip41 + ip4_header_bytes (ip41) +
199 sizeof (udp_header_t));
200 buf_adv1 = 0;
201 }
202 else
203 {
204 esp1 = (esp_header_t *) ((u8 *) ip41 + ip4_header_bytes (ip41));
205 buf_adv1 = ip4_header_bytes (ip41);
206 }
Kingwel Xie00bff192019-03-07 01:25:32 -0500207 }
Neale Ranns77eb28f2019-03-04 14:13:14 +0000208
Kingwel Xie00bff192019-03-07 01:25:32 -0500209 vlib_buffer_advance (b[0], buf_adv0);
210 vlib_buffer_advance (b[1], buf_adv1);
Neale Ranns77eb28f2019-03-04 14:13:14 +0000211
Kingwel Xie00bff192019-03-07 01:25:32 -0500212 len0 = vlib_buffer_length_in_chain (vm, b[0]);
213 len1 = vlib_buffer_length_in_chain (vm, b[1]);
Neale Ranns77eb28f2019-03-04 14:13:14 +0000214
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400215 if (is_ip6)
216 {
217 key60.remote_ip = ip60->src_address;
218 key60.spi = esp0->spi;
Neale Ranns77eb28f2019-03-04 14:13:14 +0000219
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400220 if (memcmp (&key60, &last_key6, sizeof (last_key6)) == 0)
Neale Ranns77eb28f2019-03-04 14:13:14 +0000221 {
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400222 tid0 = last_tunnel_id;
Neale Ranns77eb28f2019-03-04 14:13:14 +0000223 }
224 else
225 {
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400226 uword *p =
227 hash_get_mem (im->ipsec6_if_pool_index_by_key, &key60);
228 if (p)
229 {
230 tid0 = p[0];
231 last_tunnel_id = tid0;
232 clib_memcpy_fast (&last_key6, &key60, sizeof (key60));
233 }
234 else
235 {
Neale Rannsb71fa752019-04-04 12:43:36 +0000236 next[0] =
237 ipsec_ip6_if_no_tunnel (node, b[0], esp0, buf_adv0);
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400238 n_no_tunnel++;
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400239 goto pkt1;
240 }
241 }
242 }
243 else /* !is_ip6 */
244 {
245 key40.remote_ip = ip40->src_address.as_u32;
246 key40.spi = esp0->spi;
247
248 if (key40.as_u64 == last_key4.as_u64)
249 {
250 tid0 = last_tunnel_id;
251 }
252 else
253 {
254 uword *p =
255 hash_get (im->ipsec4_if_pool_index_by_key, key40.as_u64);
256 if (p)
257 {
258 tid0 = p[0];
259 last_tunnel_id = tid0;
260 last_key4.as_u64 = key40.as_u64;
261 }
262 else
263 {
Neale Rannsb71fa752019-04-04 12:43:36 +0000264 next[0] =
265 ipsec_ip4_if_no_tunnel (node, b[0], esp0, ip40, buf_adv0);
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400266 n_no_tunnel++;
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400267 goto pkt1;
268 }
Kingwel Xie00bff192019-03-07 01:25:32 -0500269 }
270 }
271
272 t0 = pool_elt_at_index (im->tunnel_interfaces, tid0);
273 vnet_buffer (b[0])->ipsec.sad_index = t0->input_sa_index;
274
275 if (PREDICT_TRUE (t0->hw_if_index != ~0))
276 {
Kingwel Xie00bff192019-03-07 01:25:32 -0500277 sw_if_index0 = t0->sw_if_index;
278 vnet_buffer (b[0])->sw_if_index[VLIB_RX] = sw_if_index0;
279
280 if (PREDICT_FALSE (!(t0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP)))
281 {
282 vlib_increment_combined_counter
283 (drop_counter, thread_index, sw_if_index0, 1, len0);
284 n_disabled++;
Neale Rannse524d452019-02-19 15:22:46 +0000285 b[0]->error = node->errors[IPSEC_IF_INPUT_ERROR_DISABLED];
Kingwel Xie00bff192019-03-07 01:25:32 -0500286 next[0] = IPSEC_INPUT_NEXT_DROP;
287 goto pkt1;
Neale Ranns77eb28f2019-03-04 14:13:14 +0000288 }
289
Kingwel Xie00bff192019-03-07 01:25:32 -0500290 if (PREDICT_TRUE (sw_if_index0 == last_sw_if_index))
Neale Ranns77eb28f2019-03-04 14:13:14 +0000291 {
Kingwel Xie00bff192019-03-07 01:25:32 -0500292 n_packets++;
293 n_bytes += len0;
Neale Ranns77eb28f2019-03-04 14:13:14 +0000294 }
295 else
296 {
Kingwel Xie00bff192019-03-07 01:25:32 -0500297 if (n_packets)
298 {
299 vlib_increment_combined_counter
300 (rx_counter, thread_index, last_sw_if_index,
301 n_packets, n_bytes);
302 }
303
304 last_sw_if_index = sw_if_index0;
305 n_packets = 1;
306 n_bytes = len0;
307 }
308 }
Kingwel Xie00bff192019-03-07 01:25:32 -0500309
310 pkt1:
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400311 if (is_ip6)
Kingwel Xie00bff192019-03-07 01:25:32 -0500312 {
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400313 key61.remote_ip = ip61->src_address;
314 key61.spi = esp1->spi;
315
316 if (memcmp (&key61, &last_key6, sizeof (last_key6)) == 0)
Kingwel Xie00bff192019-03-07 01:25:32 -0500317 {
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400318 tid1 = last_tunnel_id;
Kingwel Xie00bff192019-03-07 01:25:32 -0500319 }
320 else
321 {
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400322 uword *p =
323 hash_get_mem (im->ipsec6_if_pool_index_by_key, &key61);
324 if (p)
325 {
326 tid1 = p[0];
327 last_tunnel_id = tid1;
328 clib_memcpy_fast (&last_key6, &key61, sizeof (key61));
329 }
330 else
331 {
Neale Rannsb71fa752019-04-04 12:43:36 +0000332 next[1] =
333 ipsec_ip6_if_no_tunnel (node, b[1], esp1, buf_adv1);
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400334 n_no_tunnel++;
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400335 goto trace1;
336 }
337 }
338 }
339 else /* !is_ip6 */
340 {
341 key41.remote_ip = ip41->src_address.as_u32;
342 key41.spi = esp1->spi;
343
344 if (key41.as_u64 == last_key4.as_u64)
345 {
346 tid1 = last_tunnel_id;
347 }
348 else
349 {
350 uword *p =
351 hash_get (im->ipsec4_if_pool_index_by_key, key41.as_u64);
352 if (p)
353 {
354 tid1 = p[0];
355 last_tunnel_id = tid1;
356 last_key4.as_u64 = key41.as_u64;
357 }
358 else
359 {
Neale Rannsb71fa752019-04-04 12:43:36 +0000360 next[1] =
361 ipsec_ip4_if_no_tunnel (node, b[1], esp1, ip41, buf_adv1);
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400362 n_no_tunnel++;
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400363 goto trace1;
364 }
Kingwel Xie00bff192019-03-07 01:25:32 -0500365 }
366 }
367
368 t1 = pool_elt_at_index (im->tunnel_interfaces, tid1);
369 vnet_buffer (b[1])->ipsec.sad_index = t1->input_sa_index;
370
371 if (PREDICT_TRUE (t1->hw_if_index != ~0))
372 {
Kingwel Xie00bff192019-03-07 01:25:32 -0500373 sw_if_index1 = t1->sw_if_index;
374 vnet_buffer (b[1])->sw_if_index[VLIB_RX] = sw_if_index1;
375
376 if (PREDICT_FALSE (!(t1->flags & VNET_HW_INTERFACE_FLAG_LINK_UP)))
377 {
378 vlib_increment_combined_counter
379 (drop_counter, thread_index, sw_if_index1, 1, len1);
380 n_disabled++;
Neale Rannse524d452019-02-19 15:22:46 +0000381 b[1]->error = node->errors[IPSEC_IF_INPUT_ERROR_DISABLED];
Kingwel Xie00bff192019-03-07 01:25:32 -0500382 next[1] = IPSEC_INPUT_NEXT_DROP;
383 goto trace1;
Neale Ranns77eb28f2019-03-04 14:13:14 +0000384 }
385
Kingwel Xie00bff192019-03-07 01:25:32 -0500386 if (PREDICT_TRUE (sw_if_index1 == last_sw_if_index))
387 {
388 n_packets++;
389 n_bytes += len1;
390 }
391 else
392 {
393 if (n_packets)
394 {
395 vlib_increment_combined_counter
396 (rx_counter, thread_index, last_sw_if_index,
397 n_packets, n_bytes);
398 }
399
400 last_sw_if_index = sw_if_index1;
401 n_packets = 1;
402 n_bytes = len1;
403 }
404 }
Kingwel Xie00bff192019-03-07 01:25:32 -0500405
406 trace1:
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400407 if (PREDICT_FALSE (is_trace))
Kingwel Xie00bff192019-03-07 01:25:32 -0500408 {
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400409 if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
Neale Ranns77eb28f2019-03-04 14:13:14 +0000410 {
411 ipsec_if_input_trace_t *tr =
Kingwel Xie00bff192019-03-07 01:25:32 -0500412 vlib_add_trace (vm, node, b[0], sizeof (*tr));
Neale Ranns77eb28f2019-03-04 14:13:14 +0000413 tr->spi = clib_host_to_net_u32 (esp0->spi);
414 tr->seq = clib_host_to_net_u32 (esp0->seq);
415 }
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400416 if (b[1]->flags & VLIB_BUFFER_IS_TRACED)
Neale Ranns77eb28f2019-03-04 14:13:14 +0000417 {
418 ipsec_if_input_trace_t *tr =
Kingwel Xie00bff192019-03-07 01:25:32 -0500419 vlib_add_trace (vm, node, b[1], sizeof (*tr));
Neale Ranns77eb28f2019-03-04 14:13:14 +0000420 tr->spi = clib_host_to_net_u32 (esp1->spi);
421 tr->seq = clib_host_to_net_u32 (esp1->seq);
422 }
Neale Ranns77eb28f2019-03-04 14:13:14 +0000423 }
Kingwel Xie00bff192019-03-07 01:25:32 -0500424
425 /* next */
426 b += 2;
427 next += 2;
428 n_left_from -= 2;
429 }
430 while (n_left_from > 0)
431 {
432 u32 sw_if_index0;
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400433 ip4_header_t *ip40;
434 ip6_header_t *ip60;
Kingwel Xie00bff192019-03-07 01:25:32 -0500435 esp_header_t *esp0;
436 u32 len0;
Neale Rannsa6bee0a2019-06-14 01:13:25 -0700437 u16 buf_adv0, buf_rewind0;
Kingwel Xie00bff192019-03-07 01:25:32 -0500438 u32 tid0;
439 ipsec_tunnel_if_t *t0;
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400440 ipsec4_tunnel_key_t key40;
441 ipsec6_tunnel_key_t key60;
Kingwel Xie00bff192019-03-07 01:25:32 -0500442
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400443 ip40 =
444 (ip4_header_t *) (b[0]->data + vnet_buffer (b[0])->l3_hdr_offset);
Kingwel Xie00bff192019-03-07 01:25:32 -0500445
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400446 if (is_ip6)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700447 {
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400448 ip60 = (ip6_header_t *) ip40;
449 esp0 = (esp_header_t *) ((u8 *) ip60 + sizeof (ip6_header_t));
450 buf_adv0 = sizeof (ip6_header_t);
Kingwel Xie00bff192019-03-07 01:25:32 -0500451 }
452 else
453 {
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400454 /* NAT UDP port 4500 case, don't advance any more */
455 if (ip40->protocol == IP_PROTOCOL_UDP)
456 {
457 esp0 =
458 (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40) +
459 sizeof (udp_header_t));
460 buf_adv0 = 0;
Neale Rannsa6bee0a2019-06-14 01:13:25 -0700461 buf_rewind0 = ip4_header_bytes (ip40) + sizeof (udp_header_t);
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400462 }
463 else
464 {
465 esp0 = (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40));
Neale Rannsa6bee0a2019-06-14 01:13:25 -0700466 buf_rewind0 = buf_adv0 = ip4_header_bytes (ip40);
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400467 }
Kingwel Xie00bff192019-03-07 01:25:32 -0500468 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700469
Kingwel Xie00bff192019-03-07 01:25:32 -0500470 /* stats for the tunnel include all the data after the IP header
471 just like a norml IP-IP tunnel */
472 vlib_buffer_advance (b[0], buf_adv0);
473 len0 = vlib_buffer_length_in_chain (vm, b[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700474
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400475 if (is_ip6)
Kingwel Xie00bff192019-03-07 01:25:32 -0500476 {
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400477 key60.remote_ip = ip60->src_address;
478 key60.spi = esp0->spi;
479
480 if (memcmp (&key60, &last_key6, sizeof (last_key6)) == 0)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700481 {
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400482 tid0 = last_tunnel_id;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700483 }
Neale Ranns8d7c5022019-02-06 01:41:05 -0800484 else
485 {
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400486 uword *p =
487 hash_get_mem (im->ipsec6_if_pool_index_by_key, &key60);
488 if (p)
489 {
490 tid0 = p[0];
491 last_tunnel_id = tid0;
492 clib_memcpy_fast (&last_key6, &key60, sizeof (key60));
493 }
494 else
495 {
Neale Rannsb71fa752019-04-04 12:43:36 +0000496 next[0] =
497 ipsec_ip6_if_no_tunnel (node, b[0], esp0, buf_adv0);
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400498 n_no_tunnel++;
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400499 goto trace00;
500 }
501 }
502 }
503 else /* !is_ip6 */
504 {
505 key40.remote_ip = ip40->src_address.as_u32;
506 key40.spi = esp0->spi;
507
508 if (key40.as_u64 == last_key4.as_u64)
509 {
510 tid0 = last_tunnel_id;
511 }
512 else
513 {
514 uword *p =
515 hash_get (im->ipsec4_if_pool_index_by_key, key40.as_u64);
516 if (p)
517 {
518 tid0 = p[0];
519 last_tunnel_id = tid0;
520 last_key4.as_u64 = key40.as_u64;
521 }
522 else
523 {
Neale Rannsb71fa752019-04-04 12:43:36 +0000524 next[0] =
Neale Rannsa6bee0a2019-06-14 01:13:25 -0700525 ipsec_ip4_if_no_tunnel (node, b[0], esp0, ip40,
526 buf_rewind0);
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400527 n_no_tunnel++;
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400528 goto trace00;
529 }
Kingwel Xie00bff192019-03-07 01:25:32 -0500530 }
531 }
532
533 t0 = pool_elt_at_index (im->tunnel_interfaces, tid0);
534 vnet_buffer (b[0])->ipsec.sad_index = t0->input_sa_index;
535
536 if (PREDICT_TRUE (t0->hw_if_index != ~0))
537 {
Kingwel Xie00bff192019-03-07 01:25:32 -0500538 sw_if_index0 = t0->sw_if_index;
539 vnet_buffer (b[0])->sw_if_index[VLIB_RX] = sw_if_index0;
540
541 if (PREDICT_FALSE (!(t0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP)))
542 {
543 vlib_increment_combined_counter
544 (drop_counter, thread_index, sw_if_index0, 1, len0);
545 n_disabled++;
Neale Rannse524d452019-02-19 15:22:46 +0000546 b[0]->error = node->errors[IPSEC_IF_INPUT_ERROR_DISABLED];
Kingwel Xie00bff192019-03-07 01:25:32 -0500547 next[0] = IPSEC_INPUT_NEXT_DROP;
548 goto trace00;
Neale Ranns8d7c5022019-02-06 01:41:05 -0800549 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700550
Kingwel Xie00bff192019-03-07 01:25:32 -0500551 if (PREDICT_TRUE (sw_if_index0 == last_sw_if_index))
552 {
553 n_packets++;
554 n_bytes += len0;
555 }
556 else
557 {
558 if (n_packets)
559 {
560 vlib_increment_combined_counter
561 (rx_counter, thread_index, last_sw_if_index,
562 n_packets, n_bytes);
563 }
564
565 last_sw_if_index = sw_if_index0;
566 n_packets = 1;
567 n_bytes = len0;
568 }
569 }
Kingwel Xie00bff192019-03-07 01:25:32 -0500570
571 trace00:
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400572 if (PREDICT_FALSE (is_trace))
Kingwel Xie00bff192019-03-07 01:25:32 -0500573 {
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400574 if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700575 {
576 ipsec_if_input_trace_t *tr =
Kingwel Xie00bff192019-03-07 01:25:32 -0500577 vlib_add_trace (vm, node, b[0], sizeof (*tr));
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700578 tr->spi = clib_host_to_net_u32 (esp0->spi);
579 tr->seq = clib_host_to_net_u32 (esp0->seq);
580 }
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700581 }
Kingwel Xie00bff192019-03-07 01:25:32 -0500582
583 /* next */
584 b += 1;
585 next += 1;
586 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700587 }
588
Kingwel Xie00bff192019-03-07 01:25:32 -0500589 if (n_packets)
Matthew Smith01034be2017-05-16 11:51:18 -0500590 {
Matthew Smith831fd642018-05-15 22:03:05 -0500591 vlib_increment_combined_counter (rx_counter,
Matthew Smith01034be2017-05-16 11:51:18 -0500592 thread_index,
593 last_sw_if_index, n_packets, n_bytes);
594 }
595
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400596 vlib_node_increment_counter (vm, node->node_index,
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700597 IPSEC_IF_INPUT_ERROR_RX,
Neale Rannse524d452019-02-19 15:22:46 +0000598 from_frame->n_vectors - (n_disabled +
599 n_no_tunnel));
Kingwel Xie00bff192019-03-07 01:25:32 -0500600
601 vlib_buffer_enqueue_to_next (vm, node, from, nexts, from_frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700602
603 return from_frame->n_vectors;
604}
605
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400606VLIB_NODE_FN (ipsec4_if_input_node) (vlib_main_t * vm,
607 vlib_node_runtime_t * node,
608 vlib_frame_t * from_frame)
Kingwel Xie00bff192019-03-07 01:25:32 -0500609{
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400610 return ipsec_if_input_inline (vm, node, from_frame, 0 /* is_ip6 */ );
Kingwel Xie00bff192019-03-07 01:25:32 -0500611}
612
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700613/* *INDENT-OFF* */
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400614VLIB_REGISTER_NODE (ipsec4_if_input_node) = {
615 .name = "ipsec4-if-input",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700616 .vector_size = sizeof (u32),
617 .format_trace = format_ipsec_if_input_trace,
618 .type = VLIB_NODE_TYPE_INTERNAL,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700619 .n_errors = ARRAY_LEN(ipsec_if_input_error_strings),
620 .error_strings = ipsec_if_input_error_strings,
Pierre Pfister057b3562018-12-10 17:01:01 +0100621 .sibling_of = "ipsec4-input-feature",
Damjan Marion1c80e832016-05-11 23:07:18 +0200622};
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700623/* *INDENT-ON* */
Damjan Marion1c80e832016-05-11 23:07:18 +0200624
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400625VLIB_NODE_FN (ipsec6_if_input_node) (vlib_main_t * vm,
626 vlib_node_runtime_t * node,
627 vlib_frame_t * from_frame)
628{
629 return ipsec_if_input_inline (vm, node, from_frame, 1 /* is_ip6 */ );
630}
631
632/* *INDENT-OFF* */
633VLIB_REGISTER_NODE (ipsec6_if_input_node) = {
634 .name = "ipsec6-if-input",
635 .vector_size = sizeof (u32),
636 .format_trace = format_ipsec_if_input_trace,
637 .type = VLIB_NODE_TYPE_INTERNAL,
638 .n_errors = ARRAY_LEN(ipsec_if_input_error_strings),
639 .error_strings = ipsec_if_input_error_strings,
640 .sibling_of = "ipsec6-input-feature",
641};
642/* *INDENT-ON* */
643
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700644/*
645 * fd.io coding-style-patch-verification: ON
646 *
647 * Local Variables:
648 * eval: (c-set-style "gnu")
649 * End:
650 */