FD.io VPP  v17.10-9-gd594711
Vector Packet Processing
decap.c
Go to the documentation of this file.
1 /*
2  * decap.c : L2TPv3 tunnel decapsulation
3  *
4  * Copyright (c) 2013 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 <vppinfra/error.h>
19 #include <vppinfra/hash.h>
20 #include <vnet/vnet.h>
21 #include <vnet/ip/ip.h>
22 #include <vnet/ethernet/ethernet.h>
23 #include <vnet/l2tp/l2tp.h>
24 
25 /* Statistics (not really errors) */
26 #define foreach_l2t_decap_error \
27 _(USER_TO_NETWORK, "L2TP user (ip6) to L2 network pkts") \
28 _(SESSION_ID_MISMATCH, "l2tpv3 local session id mismatches") \
29 _(COOKIE_MISMATCH, "l2tpv3 local cookie mismatches") \
30 _(NO_SESSION, "l2tpv3 session not found") \
31 _(ADMIN_DOWN, "l2tpv3 tunnel is down")
32 
33 static char *l2t_decap_error_strings[] = {
34 #define _(sym,string) string,
36 #undef _
37 };
38 
39 typedef enum
40 {
41 #define _(sym,str) L2T_DECAP_ERROR_##sym,
43 #undef _
46 
47 typedef enum
48 {
52  /* Pseudo next index */
55 
56 #define NSTAGES 3
57 
58 static inline void
59 stage0 (vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
60 {
61  vlib_buffer_t *b = vlib_get_buffer (vm, buffer_index);
62  vlib_prefetch_buffer_header (b, STORE);
63  /* l2tpv3 header is a long way away, need 2 cache lines */
64  CLIB_PREFETCH (b->data, 2 * CLIB_CACHE_LINE_BYTES, STORE);
65 }
66 
67 static inline void
69 {
70  vlib_buffer_t *b = vlib_get_buffer (vm, bi);
71  l2t_main_t *lm = &l2t_main;
73  u32 session_index;
74  uword *p = 0;
75  l2tpv3_header_t *l2t;
76 
77  /* Not L2tpv3 (0x73, 0t115)? Use the normal path. */
78  if (PREDICT_FALSE (ip6->protocol != IP_PROTOCOL_L2TP))
79  {
80  vnet_buffer (b)->l2t.next_index = L2T_DECAP_NEXT_NO_INTERCEPT;
81  return;
82  }
83 
84  /* Make up your minds, people... */
85  switch (lm->lookup_type)
86  {
89  break;
92  break;
94  l2t = (l2tpv3_header_t *) (ip6 + 1);
95  p = hash_get (lm->session_by_session_id, l2t->session_id);
96  break;
97  default:
98  ASSERT (0);
99  }
100 
101  if (PREDICT_FALSE (p == 0))
102  {
103  vnet_buffer (b)->l2t.next_index = L2T_DECAP_NEXT_NO_INTERCEPT;
104  return;
105  }
106  else
107  {
108  session_index = p[0];
109  }
110 
111  /* Remember mapping index, prefetch the mini counter */
112  vnet_buffer (b)->l2t.next_index = L2T_DECAP_NEXT_L2_INPUT;
113  vnet_buffer (b)->l2t.session_index = session_index;
114 
115  /* $$$$$ prefetch counter */
116 }
117 
118 static inline u32
120 {
121  vlib_buffer_t *b = vlib_get_buffer (vm, bi);
122  l2t_main_t *lm = &l2t_main;
124  vlib_node_t *n = vlib_get_node (vm, node->node_index);
125  u32 node_counter_base_index = n->error_heap_index;
126  vlib_error_main_t *em = &vm->error_main;
127  l2tpv3_header_t *l2tp;
129  l2t_session_t *session = 0;
130  u32 session_index;
131  u32 next_index;
132  u8 l2tp_decap_local = (l2t_decap_local_node.index == n->index);
133 
134  /* Other-than-output pkt? We're done... */
135  if (vnet_buffer (b)->l2t.next_index != L2T_DECAP_NEXT_L2_INPUT)
136  {
137  next_index = vnet_buffer (b)->l2t.next_index;
138  goto done;
139  }
140 
141  em->counters[node_counter_base_index + L2T_DECAP_ERROR_USER_TO_NETWORK] +=
142  1;
143 
144  session_index = vnet_buffer (b)->l2t.session_index;
145 
146  counter_index =
147  session_index_to_counter_index (session_index,
149 
150  /* per-mapping byte stats include the ethernet header */
153  counter_index, 1 /* packet_increment */ ,
155  sizeof (ethernet_header_t));
156 
157  session = pool_elt_at_index (lm->sessions, session_index);
158 
159  l2tp = vlib_buffer_get_current (b) + sizeof (*ip6);
160 
161  if (PREDICT_FALSE (l2tp->session_id != session->local_session_id))
162  {
163  /* Key matched but session id does not. Assume packet is not for us. */
164  em->counters[node_counter_base_index +
165  L2T_DECAP_ERROR_SESSION_ID_MISMATCH] += 1;
166  next_index = L2T_DECAP_NEXT_NO_INTERCEPT;
167  goto done;
168  }
169 
170  if (PREDICT_FALSE (l2tp->cookie != session->local_cookie[0]))
171  {
172  if (l2tp->cookie != session->local_cookie[1])
173  {
174  /* Key and session ID matched, but cookie doesn't. Drop this packet. */
175  b->error = node->errors[L2T_DECAP_ERROR_COOKIE_MISMATCH];
176  next_index = L2T_DECAP_NEXT_DROP;
177  goto done;
178  }
179  }
180 
181  vnet_buffer (b)->sw_if_index[VLIB_RX] = session->sw_if_index;
182 
183  if (PREDICT_FALSE (!(session->admin_up)))
184  {
185  b->error = node->errors[L2T_DECAP_ERROR_ADMIN_DOWN];
186  next_index = L2T_DECAP_NEXT_DROP;
187  goto done;
188  }
189 
190  /* strip the ip6 and L2TP header */
191  vlib_buffer_advance (b, sizeof (*ip6) + session->l2tp_hdr_size);
192 
193  /* Required to make the l2 tag push / pop code work on l2 subifs */
194  vnet_update_l2_len (b);
195 
197  {
198  l2t_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t));
199  t->is_user_to_network = 1;
200  t->our_address.as_u64[0] = ip6->dst_address.as_u64[0];
201  t->our_address.as_u64[1] = ip6->dst_address.as_u64[1];
202  t->client_address.as_u64[0] = ip6->src_address.as_u64[0];
203  t->client_address.as_u64[1] = ip6->src_address.as_u64[1];
204  t->session_index = session_index;
205  }
206 
208 
209 done:
210  if (next_index == L2T_DECAP_NEXT_NO_INTERCEPT)
211  {
212  /* Small behavioral change between l2tp-decap and l2tp-decap-local */
213  if (l2tp_decap_local)
214  {
215  b->error = node->errors[L2T_DECAP_ERROR_NO_SESSION];
216  next_index = L2T_DECAP_NEXT_DROP;
217  }
218  else
219  {
220  /* Go to next node on the ip6 configuration chain */
221  if (PREDICT_TRUE (session != 0))
222  vnet_feature_next (session->sw_if_index, &next_index, b);
223  }
224  }
225 
227  {
228  l2t_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t));
229  t->is_user_to_network = 1;
230  t->our_address.as_u64[0] = ip6->dst_address.as_u64[0];
231  t->our_address.as_u64[1] = ip6->dst_address.as_u64[1];
232  t->client_address.as_u64[0] = ip6->src_address.as_u64[0];
233  t->client_address.as_u64[1] = ip6->src_address.as_u64[1];
234  t->session_index = ~0;
235  }
236  return next_index;
237 }
238 
239 #include <vnet/pipeline.h>
240 
241 static uword
243  vlib_node_runtime_t * node, vlib_frame_t * frame)
244 {
245  return dispatch_pipeline (vm, node, frame);
246 }
247 
248 /*
249  * l2tp-decap and l2tp-decap-local have very slightly different behavior.
250  * When a packet has no associated session l2tp-decap let it go to ip6 forward,
251  * while l2tp-decap-local drops it.
252  */
253 
254 /* *INDENT-OFF* */
256  .function = l2t_decap_node_fn,
257  .name = "l2tp-decap",
258  .vector_size = sizeof (u32),
259  .format_trace = format_l2t_trace,
260  .type = VLIB_NODE_TYPE_INTERNAL,
261 
262  .n_errors = ARRAY_LEN(l2t_decap_error_strings),
263  .error_strings = l2t_decap_error_strings,
264 
265  .n_next_nodes = L2T_DECAP_N_NEXT,
266 
267  /* edit / add dispositions here */
268  .next_nodes = {
269  [L2T_DECAP_NEXT_L2_INPUT] = "l2-input",
270  [L2T_DECAP_NEXT_DROP] = "error-drop",
271  },
272 };
273 /* *INDENT-ON* */
274 
276 /* *INDENT-OFF* */
278  .function = l2t_decap_node_fn,
279  .name = "l2tp-decap-local",
280  .vector_size = sizeof (u32),
281  .format_trace = format_l2t_trace,
282  .type = VLIB_NODE_TYPE_INTERNAL,
283 
284  .n_errors = ARRAY_LEN(l2t_decap_error_strings),
285  .error_strings = l2t_decap_error_strings,
286 
287  .n_next_nodes = L2T_DECAP_N_NEXT,
288 
289  /* edit / add dispositions here */
290  .next_nodes = {
291  [L2T_DECAP_NEXT_L2_INPUT] = "l2-input",
292  [L2T_DECAP_NEXT_DROP] = "error-drop",
293  },
294 };
295 /* *INDENT-ON* */
296 
297 void
299 {
300  ip6_register_protocol (IP_PROTOCOL_L2TP, l2t_decap_local_node.index);
301 }
302 
303 /*
304  * fd.io coding-style-patch-verification: ON
305  *
306  * Local Variables:
307  * eval: (c-set-style "gnu")
308  * End:
309  */
int is_user_to_network
Definition: l2tp.h:88
u64 local_cookie[2]
Definition: l2tp.h:32
u32 error_heap_index
Definition: node.h:278
ip6_address_t client_address
Definition: l2tp.h:91
static void vlib_increment_combined_counter(vlib_combined_counter_main_t *cm, u32 thread_index, u32 index, u64 n_packets, u64 n_bytes)
Increment a combined counter.
Definition: counter.h:211
void ip6_register_protocol(u32 protocol, u32 node_index)
Definition: ip6_forward.c:1690
static u32 last_stage(vlib_main_t *vm, vlib_node_runtime_t *node, u32 bi)
Definition: decap.c:119
l2t_DECAP_error_t
Definition: decap.c:39
#define PREDICT_TRUE(x)
Definition: clib.h:98
u64 as_u64[2]
Definition: ip6_packet.h:51
uword * session_by_session_id
Definition: l2tp.h:66
u32 index
Definition: node.h:237
vlib_node_registration_t l2t_decap_node
(constructor) VLIB_REGISTER_NODE (l2t_decap_node)
Definition: decap.c:255
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:415
static uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:107
ip6_address_t src_address
Definition: ip6_packet.h:341
static u32 session_index_to_counter_index(u32 session_index, u32 counter_id)
Definition: l2tp.h:106
l2t_main_t l2t_main
Definition: l2tp.c:26
static char * l2t_decap_error_strings[]
Definition: decap.c:33
static u32 counter_index(vlib_main_t *vm, vlib_error_t e)
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:169
static void stage1(vlib_main_t *vm, vlib_node_runtime_t *node, u32 bi)
Definition: decap.c:68
#define hash_get(h, key)
Definition: hash.h:248
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:458
vlib_error_main_t error_main
Definition: main.h:138
u32 local_session_id
Definition: l2tp.h:34
u8 * format_l2t_trace(u8 *s, va_list *args)
Definition: l2tp.c:30
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:193
#define PREDICT_FALSE(x)
Definition: clib.h:97
u32 node_index
Node index.
Definition: node.h:437
static_always_inline void vnet_feature_next(u32 sw_if_index, u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:221
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:113
ip6_to_l2_lookup_t lookup_type
Definition: l2tp.h:68
ip6_address_t our_address
Definition: l2tp.h:90
u64 * counters
Definition: error.h:78
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:221
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
vlib_main_t * vm
Definition: buffer.c:283
static void stage0(vlib_main_t *vm, vlib_node_runtime_t *node, u32 buffer_index)
Definition: decap.c:59
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:93
#define ARRAY_LEN(x)
Definition: clib.h:59
vlib_node_registration_t l2t_decap_local_node
(constructor) VLIB_REGISTER_NODE (l2t_decap_local_node)
Definition: decap.c:277
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
#define foreach_l2t_decap_error
Definition: decap.c:26
static uword l2t_decap_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: decap.c:242
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:206
uword * session_by_dst_address
Definition: l2tp.h:65
l2t_decap_next_t
Definition: decap.c:47
vlib_combined_counter_main_t counter_main
Definition: l2tp.h:71
u64 uword
Definition: types.h:112
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
void l2tp_decap_init(void)
Definition: decap.c:298
u8 l2tp_hdr_size
Definition: l2tp.h:44
unsigned char u8
Definition: types.h:56
static void vnet_update_l2_len(vlib_buffer_t *b)
Definition: l2_input.h:216
l2t_session_t * sessions
Definition: l2tp.h:61
#define hash_get_mem(h, key)
Definition: hash.h:268
#define vnet_buffer(b)
Definition: buffer.h:306
VLIB_NODE_FUNCTION_MULTIARCH(l2t_decap_node, l2t_decap_node_fn)
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u8 data[0]
Packet data.
Definition: buffer.h:157
static vlib_node_t * vlib_get_node(vlib_main_t *vm, u32 i)
Get vlib node by index.
Definition: node_funcs.h:59
u8 admin_up
Definition: l2tp.h:48
uword * session_by_src_address
Definition: l2tp.h:64
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:75
u32 sw_if_index
Definition: l2tp.h:39
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
Definition: defs.h:46
u32 session_index
Definition: l2tp.h:89
ip6_address_t dst_address
Definition: ip6_packet.h:341