FD.io VPP  v16.09
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;
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  ip6_main_t *im = &ip6_main;
222  ip_lookup_main_t *lm = &im->lookup_main;
225 
228  &next_index, sizeof (c0[0]));
229  }
230  }
231 
233  {
234  l2t_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t));
235  t->is_user_to_network = 1;
236  t->our_address.as_u64[0] = ip6->dst_address.as_u64[0];
237  t->our_address.as_u64[1] = ip6->dst_address.as_u64[1];
238  t->client_address.as_u64[0] = ip6->src_address.as_u64[0];
239  t->client_address.as_u64[1] = ip6->src_address.as_u64[1];
240  t->session_index = ~0;
241  }
242  return next_index;
243 }
244 
245 #include <vnet/pipeline.h>
246 
247 static uword
249  vlib_node_runtime_t * node, vlib_frame_t * frame)
250 {
251  return dispatch_pipeline (vm, node, frame);
252 }
253 
254 /*
255  * l2tp-decap and l2tp-decap-local have very slightly different behavior.
256  * When a packet has no associated session l2tp-decap let it go to ip6 forward,
257  * while l2tp-decap-local drops it.
258  */
259 
260 /* *INDENT-OFF* */
262  .function = l2t_decap_node_fn,
263  .name = "l2tp-decap",
264  .vector_size = sizeof (u32),
265  .format_trace = format_l2t_trace,
267 
268  .n_errors = ARRAY_LEN(l2t_decap_error_strings),
269  .error_strings = l2t_decap_error_strings,
270 
271  .n_next_nodes = L2T_DECAP_N_NEXT,
272 
273  /* edit / add dispositions here */
274  .next_nodes = {
275  [L2T_DECAP_NEXT_L2_INPUT] = "l2-input",
276  [L2T_DECAP_NEXT_DROP] = "error-drop",
277  },
278 };
279 /* *INDENT-ON* */
280 
282 /* *INDENT-OFF* */
284  .function = l2t_decap_node_fn,
285  .name = "l2tp-decap-local",
286  .vector_size = sizeof (u32),
287  .format_trace = format_l2t_trace,
289 
290  .n_errors = ARRAY_LEN(l2t_decap_error_strings),
291  .error_strings = l2t_decap_error_strings,
292 
293  .n_next_nodes = L2T_DECAP_N_NEXT,
294 
295  /* edit / add dispositions here */
296  .next_nodes = {
297  [L2T_DECAP_NEXT_L2_INPUT] = "l2-input",
298  [L2T_DECAP_NEXT_DROP] = "error-drop",
299  },
300 };
301 /* *INDENT-ON* */
302 
303 void
305 {
306  ip6_register_protocol (IP_PROTOCOL_L2TP, l2t_decap_local_node.index);
307 }
308 
309 /*
310  * fd.io coding-style-patch-verification: ON
311  *
312  * Local Variables:
313  * eval: (c-set-style "gnu")
314  * End:
315  */
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
void ip6_register_protocol(u32 protocol, u32 node_index)
Definition: ip6_forward.c:2032
u32 current_config_index
Used by feature subgraph arcs to visit enabled feature nodes.
Definition: buffer.h:121
bad routing header type(not 4)") sr_error (NO_MORE_SEGMENTS
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
u64 as_u64[2]
Definition: ip6_packet.h:50
uword * session_by_session_id
Definition: l2tp.h:66
u32 index
Definition: node.h:237
ip_config_main_t rx_config_mains[VNET_N_CAST]
rx/tx interface/feature configuration.
Definition: lookup.h:452
vlib_node_registration_t l2t_decap_node
(constructor) VLIB_REGISTER_NODE (l2t_decap_node)
Definition: decap.c:261
vlib_error_t * errors
Definition: node.h:418
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:112
ip6_address_t src_address
Definition: ip6_packet.h:298
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 void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:187
static u32 counter_index(vlib_main_t *vm, vlib_error_t e)
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:369
vlib_error_main_t error_main
Definition: main.h:124
u32 local_session_id
Definition: l2tp.h:34
u8 * format_l2t_trace(u8 *s, va_list *args)
Definition: l2tp.c:30
uword os_get_cpu_number(void)
Definition: unix-misc.c:224
static void * vnet_get_config_data(vnet_config_main_t *cm, u32 *config_index, u32 *next_index, u32 n_data_bytes)
Definition: config.h:122
#define PREDICT_FALSE(x)
Definition: clib.h:97
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:118
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
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
static void stage0(vlib_main_t *vm, vlib_node_runtime_t *node, u32 buffer_index)
Definition: decap.c:59
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:200
#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:283
static void vlib_increment_combined_counter(vlib_combined_counter_main_t *cm, u32 cpu_index, u32 index, u32 packet_increment, u32 byte_increment)
Increment a combined counter.
Definition: counter.h:241
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
#define vnet_buffer(b)
Definition: buffer.h:335
ip6_main_t ip6_main
Definition: ip6_forward.c:2955
ip_lookup_main_t lookup_main
Definition: ip6.h:110
#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:248
uword * session_by_dst_address
Definition: l2tp.h:65
l2t_decap_next_t
Definition: decap.c:47
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:93
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:304
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:230
l2t_session_t * sessions
Definition: l2tp.h:61
#define hash_get_mem(h, key)
Definition: hash.h:268
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:163
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:151
static vlib_node_t * vlib_get_node(vlib_main_t *vm, u32 i)
Get vlib node by index.
Definition: node_funcs.h:58
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_IS_TRACED: trace this buffer.
Definition: buffer.h:85
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:69
vnet_config_main_t config_main
Definition: lookup.h:367
Definition: defs.h:46
u32 session_index
Definition: l2tp.h:89
ip6_address_t dst_address
Definition: ip6_packet.h:298