blob: 6a3aaa12e8cb142a535bb63e4a56f677aa489305 [file] [log] [blame]
Matus Fabian694265d2016-08-10 01:55:36 -07001/*
2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/**
Chris Luke16bcf7d2016-09-01 14:31:46 -040016 * @file
Matus Fabian694265d2016-08-10 01:55:36 -070017 * @brief L2-GRE over IPSec packet processing.
18 *
Chris Luke16bcf7d2016-09-01 14:31:46 -040019 * Removes GRE header from the packet and sends it to the l2-input node.
Matus Fabian694265d2016-08-10 01:55:36 -070020*/
21
22#include <vlib/vlib.h>
23#include <vnet/pg/pg.h>
24#include <vnet/ipsec-gre/ipsec_gre.h>
25#include <vppinfra/sparse_vec.h>
26
27#define foreach_ipsec_gre_input_next \
28_(PUNT, "error-punt") \
29_(DROP, "error-drop") \
30_(L2_INPUT, "l2-input")
31
32typedef enum {
33#define _(s,n) IPSEC_GRE_INPUT_NEXT_##s,
34 foreach_ipsec_gre_input_next
35#undef _
36 IPSEC_GRE_INPUT_N_NEXT,
37} ipsec_gre_input_next_t;
38
39typedef struct {
40 u32 tunnel_id;
41 u32 length;
42 ip4_address_t src;
43 ip4_address_t dst;
44} ipsec_gre_rx_trace_t;
45
Filip Tehlarc3a0e8d2019-03-11 05:53:35 -070046static u8 * format_ipsec_gre_rx_trace (u8 * s, va_list * args)
Matus Fabian694265d2016-08-10 01:55:36 -070047{
48 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
49 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
50 ipsec_gre_rx_trace_t * t = va_arg (*args, ipsec_gre_rx_trace_t *);
51
52 s = format (s, "GRE: tunnel %d len %d src %U dst %U",
53 t->tunnel_id, clib_net_to_host_u16(t->length),
54 format_ip4_address, &t->src.as_u8,
55 format_ip4_address, &t->dst.as_u8);
56 return s;
57}
58
59/**
60 * @brief L2-GRE over IPSec input node.
61 * @node ipsec-gre-input
62 *
63 * This node remove GRE header.
64 *
Chris Luked4024f52016-09-06 09:32:36 -040065 * @param vm vlib_main_t corresponding to the current thread.
66 * @param node vlib_node_runtime_t data for this node.
67 * @param from_frame vlib_frame_t whose contents should be dispatched.
Matus Fabian694265d2016-08-10 01:55:36 -070068 *
69 * @par Graph mechanics: buffer metadata, next index usage
70 *
Chris Luke16bcf7d2016-09-01 14:31:46 -040071 * <em>Uses:</em>
Matus Fabian694265d2016-08-10 01:55:36 -070072 * - <code>ip->src_address</code> and <code>ip->dst_address</code>
73 * - Match tunnel by source and destination addresses in GRE IP header.
74 *
75 * <em>Sets:</em>
76 * - <code>vnet_buffer(b)->gre.src</code>
77 * - Save tunnel source IPv4 address.
78 * - <code>vnet_buffer(b)->gre.dst</code>
79 * - Save tunnel destination IPv4 address.
80 * - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
81 * - Set input sw_if_index to IPSec-GRE tunnel for learning.
82 *
83 * <em>Next Index:</em>
84 * - Dispatches the packet to the l2-input node.
85*/
Filip Tehlarc3a0e8d2019-03-11 05:53:35 -070086VLIB_NODE_FN (ipsec_gre_input_node) (vlib_main_t * vm,
Matus Fabian694265d2016-08-10 01:55:36 -070087 vlib_node_runtime_t * node,
88 vlib_frame_t * from_frame)
89{
90 ipsec_gre_main_t * igm = &ipsec_gre_main;
91 u32 n_left_from, next_index, * from, * to_next;
92 u64 cached_tunnel_key = (u64) ~0;
93 u32 cached_tunnel_sw_if_index = 0, tunnel_sw_if_index;
Ciara Loftus7eac9162016-09-30 15:47:03 +010094 u32 tun_src0, tun_dst0;
95 u32 tun_src1, tun_dst1;
Matus Fabian694265d2016-08-10 01:55:36 -070096
97 from = vlib_frame_vector_args (from_frame);
98 n_left_from = from_frame->n_vectors;
99
100 next_index = node->cached_next_index;
101
102 while (n_left_from > 0)
103 {
104 u32 n_left_to_next;
105
106 vlib_get_next_frame (vm, node, next_index,
107 to_next, n_left_to_next);
108
109 while (n_left_from >= 4 && n_left_to_next >= 2)
110 {
111 u32 bi0, bi1;
112 vlib_buffer_t * b0, * b1;
113 gre_header_t * h0, * h1;
114 u16 version0, version1, protocol0, protocol1;
115 int verr0, verr1;
116 u32 next0, next1;
117 ip4_header_t *ip0, *ip1;
118
119 /* Prefetch next iteration. */
120 {
121 vlib_buffer_t * p2, * p3;
122
123 p2 = vlib_get_buffer (vm, from[2]);
124 p3 = vlib_get_buffer (vm, from[3]);
125
126 vlib_prefetch_buffer_header (p2, LOAD);
127 vlib_prefetch_buffer_header (p3, LOAD);
128
129 CLIB_PREFETCH (p2->data, sizeof (h0[0]), LOAD);
130 CLIB_PREFETCH (p3->data, sizeof (h1[0]), LOAD);
131 }
132
133 bi0 = from[0];
134 bi1 = from[1];
135 to_next[0] = bi0;
136 to_next[1] = bi1;
137 from += 2;
138 to_next += 2;
139 n_left_to_next -= 2;
140 n_left_from -= 2;
141
142 b0 = vlib_get_buffer (vm, bi0);
143 b1 = vlib_get_buffer (vm, bi1);
144
145 /* ip4_local hands us the ip header, not the gre header */
146 ip0 = vlib_buffer_get_current (b0);
147 ip1 = vlib_buffer_get_current (b1);
148
149 /* Save src + dst ip4 address */
Ciara Loftus7eac9162016-09-30 15:47:03 +0100150 tun_src0 = ip0->src_address.as_u32;
151 tun_dst0 = ip0->dst_address.as_u32;
152 tun_src1 = ip1->src_address.as_u32;
153 tun_dst1 = ip1->dst_address.as_u32;
Matus Fabian694265d2016-08-10 01:55:36 -0700154
155 vlib_buffer_advance (b0, sizeof (*ip0));
156 vlib_buffer_advance (b1, sizeof (*ip1));
157
158 h0 = vlib_buffer_get_current (b0);
159 h1 = vlib_buffer_get_current (b1);
160
161 protocol0 = clib_net_to_host_u16 (h0->protocol);
162 protocol1 = clib_net_to_host_u16 (h1->protocol);
Neale Rannse524d452019-02-19 15:22:46 +0000163 if (PREDICT_TRUE(protocol0 == GRE_PROTOCOL_teb))
Matus Fabian694265d2016-08-10 01:55:36 -0700164 {
165 next0 = IPSEC_GRE_INPUT_NEXT_L2_INPUT;
166 b0->error = node->errors[IPSEC_GRE_ERROR_NONE];
167 }
168 else
169 {
Matus Fabian694265d2016-08-10 01:55:36 -0700170 b0->error = node->errors[IPSEC_GRE_ERROR_UNKNOWN_PROTOCOL];
171 next0 = IPSEC_GRE_INPUT_NEXT_DROP;
172 }
Neale Rannse524d452019-02-19 15:22:46 +0000173 if (PREDICT_TRUE(protocol1 == GRE_PROTOCOL_teb))
Matus Fabian694265d2016-08-10 01:55:36 -0700174 {
175 next1 = IPSEC_GRE_INPUT_NEXT_L2_INPUT;
176 b1->error = node->errors[IPSEC_GRE_ERROR_NONE];
177 }
178 else
179 {
Matus Fabian694265d2016-08-10 01:55:36 -0700180 b1->error = node->errors[IPSEC_GRE_ERROR_UNKNOWN_PROTOCOL];
181 next1 = IPSEC_GRE_INPUT_NEXT_DROP;
182 }
183
184 version0 = clib_net_to_host_u16 (h0->flags_and_version);
185 verr0 = version0 & GRE_VERSION_MASK;
186 version1 = clib_net_to_host_u16 (h1->flags_and_version);
187 verr1 = version1 & GRE_VERSION_MASK;
188
189 b0->error = verr0 ? node->errors[IPSEC_GRE_ERROR_UNSUPPORTED_VERSION]
190 : b0->error;
191 next0 = verr0 ? IPSEC_GRE_INPUT_NEXT_DROP : next0;
192 b1->error = verr1 ? node->errors[IPSEC_GRE_ERROR_UNSUPPORTED_VERSION]
193 : b1->error;
194 next1 = verr1 ? IPSEC_GRE_INPUT_NEXT_DROP : next1;
195
196 /* For L2 payload set input sw_if_index to GRE tunnel for learning */
197 if (PREDICT_TRUE(next0 == IPSEC_GRE_INPUT_NEXT_L2_INPUT))
198 {
Ciara Loftus7eac9162016-09-30 15:47:03 +0100199 u64 key = ((u64)(tun_dst0) << 32) | (u64)(tun_src0);
Matus Fabian694265d2016-08-10 01:55:36 -0700200
201 if (cached_tunnel_key != key)
202 {
203 vnet_hw_interface_t * hi;
204 ipsec_gre_tunnel_t * t;
205 uword * p;
206
207 p = hash_get (igm->tunnel_by_key, key);
208 if (!p)
209 {
210 next0 = IPSEC_GRE_INPUT_NEXT_DROP;
211 b0->error = node->errors[IPSEC_GRE_ERROR_NO_SUCH_TUNNEL];
212 goto drop0;
213 }
214 t = pool_elt_at_index (igm->tunnels, p[0]);
215 hi = vnet_get_hw_interface (igm->vnet_main,
216 t->hw_if_index);
217 tunnel_sw_if_index = hi->sw_if_index;
218 cached_tunnel_sw_if_index = tunnel_sw_if_index;
219 }
220 else
221 {
222 tunnel_sw_if_index = cached_tunnel_sw_if_index;
223 }
224 vnet_buffer(b0)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
225 }
226
227drop0:
228 /* For L2 payload set input sw_if_index to GRE tunnel for learning */
229 if (PREDICT_TRUE(next1 == IPSEC_GRE_INPUT_NEXT_L2_INPUT))
230 {
Ciara Loftus7eac9162016-09-30 15:47:03 +0100231 u64 key = ((u64)(tun_dst1) << 32) | (u64)(tun_src1);
Matus Fabian694265d2016-08-10 01:55:36 -0700232
233 if (cached_tunnel_key != key)
234 {
235 vnet_hw_interface_t * hi;
236 ipsec_gre_tunnel_t * t;
237 uword * p;
238
239 p = hash_get (igm->tunnel_by_key, key);
240 if (!p)
241 {
242 next1 = IPSEC_GRE_INPUT_NEXT_DROP;
243 b1->error = node->errors[IPSEC_GRE_ERROR_NO_SUCH_TUNNEL];
244 goto drop1;
245 }
246 t = pool_elt_at_index (igm->tunnels, p[0]);
247 hi = vnet_get_hw_interface (igm->vnet_main,
248 t->hw_if_index);
249 tunnel_sw_if_index = hi->sw_if_index;
250 cached_tunnel_sw_if_index = tunnel_sw_if_index;
251 }
252 else
253 {
254 tunnel_sw_if_index = cached_tunnel_sw_if_index;
255 }
256 vnet_buffer(b1)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
257 }
258
259drop1:
260 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
261 {
262 ipsec_gre_rx_trace_t *tr = vlib_add_trace (vm, node,
263 b0, sizeof (*tr));
264 tr->tunnel_id = ~0;
265 tr->length = ip0->length;
266 tr->src.as_u32 = ip0->src_address.as_u32;
267 tr->dst.as_u32 = ip0->dst_address.as_u32;
268 }
269
270 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
271 {
272 ipsec_gre_rx_trace_t *tr = vlib_add_trace (vm, node,
273 b1, sizeof (*tr));
274 tr->tunnel_id = ~0;
275 tr->length = ip1->length;
276 tr->src.as_u32 = ip1->src_address.as_u32;
277 tr->dst.as_u32 = ip1->dst_address.as_u32;
278 }
279
280 vlib_buffer_advance (b0, sizeof (*h0));
281 vlib_buffer_advance (b1, sizeof (*h1));
282
283 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
284 to_next, n_left_to_next,
285 bi0, bi1, next0, next1);
286 }
287
288 while (n_left_from > 0 && n_left_to_next > 0)
289 {
290 u32 bi0;
291 vlib_buffer_t * b0;
292 gre_header_t * h0;
293 ip4_header_t * ip0;
294 u16 version0, protocol0;
295 int verr0;
296 u32 next0;
Ciara Loftus7eac9162016-09-30 15:47:03 +0100297 u32 tun_src0, tun_dst0;
Matus Fabian694265d2016-08-10 01:55:36 -0700298
299 bi0 = from[0];
300 to_next[0] = bi0;
301 from += 1;
302 to_next += 1;
303 n_left_from -= 1;
304 n_left_to_next -= 1;
305
306 b0 = vlib_get_buffer (vm, bi0);
307 ip0 = vlib_buffer_get_current (b0);
308
Ciara Loftus7eac9162016-09-30 15:47:03 +0100309 tun_src0 = ip0->src_address.as_u32;
310 tun_dst0 = ip0->dst_address.as_u32;
Matus Fabian694265d2016-08-10 01:55:36 -0700311
312 vlib_buffer_advance (b0, sizeof (*ip0));
313
314 h0 = vlib_buffer_get_current (b0);
315
316 protocol0 = clib_net_to_host_u16 (h0->protocol);
Neale Rannse524d452019-02-19 15:22:46 +0000317 if (PREDICT_TRUE(protocol0 == GRE_PROTOCOL_teb))
Matus Fabian694265d2016-08-10 01:55:36 -0700318 {
319 next0 = IPSEC_GRE_INPUT_NEXT_L2_INPUT;
320 b0->error = node->errors[IPSEC_GRE_ERROR_NONE];
321 }
322 else
323 {
Matus Fabian694265d2016-08-10 01:55:36 -0700324 b0->error = node->errors[IPSEC_GRE_ERROR_UNKNOWN_PROTOCOL];
325 next0 = IPSEC_GRE_INPUT_NEXT_DROP;
326 }
327
328 version0 = clib_net_to_host_u16 (h0->flags_and_version);
329 verr0 = version0 & GRE_VERSION_MASK;
330 b0->error = verr0 ? node->errors[IPSEC_GRE_ERROR_UNSUPPORTED_VERSION]
331 : b0->error;
332 next0 = verr0 ? IPSEC_GRE_INPUT_NEXT_DROP : next0;
333
334 /* For L2 payload set input sw_if_index to GRE tunnel for learning */
Neale Rannse524d452019-02-19 15:22:46 +0000335 if (PREDICT_TRUE(next0 == IPSEC_GRE_INPUT_NEXT_L2_INPUT))
Matus Fabian694265d2016-08-10 01:55:36 -0700336 {
Ciara Loftus7eac9162016-09-30 15:47:03 +0100337 u64 key = ((u64)(tun_dst0) << 32) | (u64)(tun_src0);
Matus Fabian694265d2016-08-10 01:55:36 -0700338
339 if (cached_tunnel_key != key)
340 {
341 vnet_hw_interface_t * hi;
342 ipsec_gre_tunnel_t * t;
343 uword * p;
344
345 p = hash_get (igm->tunnel_by_key, key);
346 if (!p)
347 {
348 next0 = IPSEC_GRE_INPUT_NEXT_DROP;
349 b0->error = node->errors[IPSEC_GRE_ERROR_NO_SUCH_TUNNEL];
350 goto drop;
351 }
352 t = pool_elt_at_index (igm->tunnels, p[0]);
353 hi = vnet_get_hw_interface (igm->vnet_main,
354 t->hw_if_index);
355 tunnel_sw_if_index = hi->sw_if_index;
356 cached_tunnel_sw_if_index = tunnel_sw_if_index;
357 }
358 else
359 {
360 tunnel_sw_if_index = cached_tunnel_sw_if_index;
361 }
362 vnet_buffer(b0)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
363 }
364
365drop:
366 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
367 {
368 ipsec_gre_rx_trace_t *tr = vlib_add_trace (vm, node,
369 b0, sizeof (*tr));
370 tr->tunnel_id = ~0;
371 tr->length = ip0->length;
372 tr->src.as_u32 = ip0->src_address.as_u32;
373 tr->dst.as_u32 = ip0->dst_address.as_u32;
374 }
375
376 vlib_buffer_advance (b0, sizeof (*h0));
377
378 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
379 to_next, n_left_to_next,
380 bi0, next0);
381 }
382
383 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
384 }
385 vlib_node_increment_counter (vm, ipsec_gre_input_node.index,
386 IPSEC_GRE_ERROR_PKTS_DECAP, from_frame->n_vectors);
387 return from_frame->n_vectors;
388}
389
390static char * ipsec_gre_error_strings[] = {
391#define ipsec_gre_error(n,s) s,
392#include "error.def"
393#undef ipsec_gre_error
394};
395
396VLIB_REGISTER_NODE (ipsec_gre_input_node) = {
Matus Fabian694265d2016-08-10 01:55:36 -0700397 .name = "ipsec-gre-input",
398 /* Takes a vector of packets. */
399 .vector_size = sizeof (u32),
400
401 .n_errors = IPSEC_GRE_N_ERROR,
402 .error_strings = ipsec_gre_error_strings,
403
404 .n_next_nodes = IPSEC_GRE_INPUT_N_NEXT,
405 .next_nodes = {
406#define _(s,n) [IPSEC_GRE_INPUT_NEXT_##s] = n,
407 foreach_ipsec_gre_input_next
408#undef _
409 },
410
411 .format_trace = format_ipsec_gre_rx_trace,
412};
413
Matus Fabian694265d2016-08-10 01:55:36 -0700414static clib_error_t * ipsec_gre_input_init (vlib_main_t * vm)
415{
416 {
417 clib_error_t * error;
418 error = vlib_call_init_function (vm, ipsec_gre_init);
419 if (error)
420 clib_error_report (error);
421 }
422
423 return 0;
424}
425
426VLIB_INIT_FUNCTION (ipsec_gre_input_init);