FD.io VPP  v16.09
Vector Packet Processing
l2t_ip6.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 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 #include <vnet/vnet.h>
16 #include <vnet/ip/ip.h>
17 #include <vnet/ethernet/ethernet.h>
18 
19 #if DPDK == 0
20 #include <vnet/devices/pci/ixgev.h>
21 #include <vnet/devices/pci/ixge.h>
22 #include <vnet/devices/pci/ige.h>
23 #include <vnet/devices/pci/vice.h>
24 #else
25 #include <vnet/devices/dpdk/dpdk.h>
26 #endif
27 
28 #include <vppinfra/error.h>
29 #include <vppinfra/hash.h>
30 #include <app/l2t.h>
31 
33 
34 /* Statistics (not really errors) */
35 #define foreach_l2t_ip6_error \
36 _(USER_TO_NETWORK, "User (v6) to L2 network pkts") \
37 _(SESSION_ID_MISMATCH, "l2tpv3 local session id mismatches") \
38 _(COOKIE_MISMATCH, "l2tpv3 local cookie mismatches")
39 
40 static char *l2t_ip6_error_strings[] = {
41 #define _(sym,string) string,
43 #undef _
44 };
45 
46 typedef enum
47 {
48 #define _(sym,str) L2T_IP6_ERROR_##sym,
50 #undef _
53 
54 /*
55  * Packets go to ip6-input when they don't match a mapping,
56  * example: v6 neighbor discovery. They go to ip4-input
57  * when they do match, and are decapsulated.
58  */
59 typedef enum
60 {
64  /* Pseudo next, fixed in last_stage */
67 
69 
70 #define NSTAGES 3
71 
72 static inline void
73 stage0 (vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
74 {
75  vlib_buffer_t *b = vlib_get_buffer (vm, buffer_index);
76  vlib_prefetch_buffer_header (b, STORE);
77  /* l2tpv3 header is a long way away, need 2 cache lines */
78  CLIB_PREFETCH (b->data, 2 * CLIB_CACHE_LINE_BYTES, STORE);
79 }
80 
81 static inline void
83 {
84  vlib_buffer_t *b = vlib_get_buffer (vm, bi);
85  l2t_main_t *lm = &l2t_main;
87  u32 session_index;
88  uword *p;
89  l2tpv3_header_t *l2t;
90 
91  /* Not L2tpv3 (0x73, 0t115)? Use the normal path. */
92  if (PREDICT_FALSE (ip6->protocol != 0x73))
93  {
94  vnet_buffer (b)->l2t.next_index = L2T_IP6_NEXT_IP6_INPUT;
95  return;
96  }
97 
98  /* Make up your minds, people... */
99  switch (lm->lookup_type)
100  {
103  break;
106  break;
108  l2t = (l2tpv3_header_t *) (ip6 + 1);
109  p = hash_get (lm->session_by_session_id, l2t->session_id);
110  break;
111  default:
112  ASSERT (0);
113  }
114 
115  if (PREDICT_FALSE (p == 0))
116  {
117  vnet_buffer (b)->l2t.next_index = L2T_IP6_NEXT_IP6_INPUT;
118  return;
119  }
120  else
121  {
122  session_index = p[0];
123  }
124 
125  /* Remember mapping index, prefetch the mini counter */
126  vnet_buffer (b)->l2t.next_index = L2T_IP6_NEXT_OUTPUT;
127  vnet_buffer (b)->l2t.session_index = session_index;
128 
129  /* Each mapping has 2 x (pkt, byte) counters, hence the shift */
130  CLIB_PREFETCH (lm->counter_main.mini + (p[0] << 1), CLIB_CACHE_LINE_BYTES,
131  STORE);
132 }
133 
134 static inline u32
136 {
137  vlib_buffer_t *b = vlib_get_buffer (vm, bi);
138  l2t_main_t *lm = &l2t_main;
140  vlib_node_t *n = vlib_get_node (vm, l2t_ip6_node.index);
141  u32 node_counter_base_index = n->error_heap_index;
142  vlib_error_main_t *em = &vm->error_main;
143  ethernet_header_t *l2_payload;
144  l2tpv3_header_t *l2t; /* original l2 header */
145  ethernet_vlan_header_t *vh; /* synthesized 802.1q vlan header */
147  l2t_session_t *session;
148  u16 payload_ethertype;
149  u8 dst_mac_address[6];
150  u8 src_mac_address[6];
151  u8 *vlan_header_pos;
152 
153  /* Other-than-output pkt? We're done... */
154  if (vnet_buffer (b)->l2t.next_index != L2T_IP6_NEXT_OUTPUT)
155  return vnet_buffer (b)->l2t.next_index;
156 
157  em->counters[node_counter_base_index + L2T_IP6_ERROR_USER_TO_NETWORK] += 1;
158 
159  counter_index =
160  session_index_to_counter_index (vnet_buffer (b)->l2t.session_index,
162 
163  /* per-mapping byte stats include the ethernet header */
164  vlib_increment_combined_counter (&lm->counter_main, counter_index,
165  1 /* packet_increment */ ,
167  sizeof (ethernet_header_t));
168 
169  session = pool_elt_at_index (lm->sessions,
170  vnet_buffer (b)->l2t.session_index);
171 
172  /* build the 802.1q encaps. Advance past ip6 and l2tpv3 hds */
173  vlib_buffer_advance (b, sizeof (*ip6));
174  l2t = vlib_buffer_get_current (b);
175 
176  /* $$$ wonder if we really need these checks... */
177  if (PREDICT_FALSE (l2t->session_id != session->local_session_id))
178  {
179  b->error =
180  lm->ip6_error_node->errors[L2T_IP6_ERROR_SESSION_ID_MISMATCH];
181  return L2T_IP6_NEXT_DROP;
182  }
183 
184  if (PREDICT_FALSE (!((l2t->cookie == session->local_cookie) ||
185  ((session->cookie_flags & L2TP_COOKIE_ROLLOVER_LOCAL)
186  && (l2t->cookie == session->lcl_ro_cookie)))))
187  {
188  b->error = lm->ip6_error_node->errors[L2T_IP6_ERROR_COOKIE_MISMATCH];
189  return L2T_IP6_NEXT_DROP;
190  }
191 
192  vnet_buffer (b)->sw_if_index[VLIB_TX] = session->l2_output_sw_if_index;
193 
194  vlib_buffer_advance (b, sizeof (*l2t));
195 
196  /* point at currrent l2 hdr */
197  l2_payload = vlib_buffer_get_current (b);
198 
199  /* $$$$ rework for speed */
200 
201  /* Save type */
202  payload_ethertype = l2_payload->type;
203 
204  /* Save src/dst MAC addresses */
205 #define _(i) dst_mac_address[i] = l2_payload->dst_address[i];
206  _(0) _(1) _(2) _(3) _(4) _(5);
207 #undef _
208 #define _(i) src_mac_address[i] = l2_payload->src_address[i];
209  _(0) _(1) _(2) _(3) _(4) _(5);
210 #undef _
211 
212  /* Punch in space for 802.1q tag */
213  vlib_buffer_advance (b, -4);
214  l2_payload = vlib_buffer_get_current (b);
215 
216  /* Restore MAC addresses */
217 #define _(i) l2_payload->dst_address[i] = dst_mac_address[i];
218  _(0) _(1) _(2) _(3) _(4) _(5);
219 #undef _
220 #define _(i) l2_payload->src_address[i] = src_mac_address[i];
221  _(0) _(1) _(2) _(3) _(4) _(5);
222 #undef _
223  /* Set (outer) ethertype to 802.1q vlan */
224  l2_payload->type = clib_host_to_net_u16 (0x8100);
225  vlan_header_pos = (u8 *) (l2_payload + 1);
226 #if 0
227  vlan_header_pos = session->l2_sublayer_present ?
228  vlan_header_pos : vlan_header_pos - 4;
229 #endif
230  vh = (ethernet_vlan_header_t *) vlan_header_pos;
231  vh->priority_cfi_and_id = session->vlan_id;
232  vh->type = payload_ethertype;
233 
235  {
236  l2t_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t));
237  t->is_user_to_network = 1;
238  t->our_address.as_u64[0] = ip6->dst_address.as_u64[0];
239  t->our_address.as_u64[1] = ip6->dst_address.as_u64[1];
240  t->client_address.as_u64[0] = ip6->src_address.as_u64[0];
241  t->client_address.as_u64[1] = ip6->src_address.as_u64[1];
242  t->session_index = vnet_buffer (b)->l2t.session_index;
243  t->vlan_id_host_byte_order = clib_net_to_host_u16 (session->vlan_id);
244  }
245 
246  return session->l2_output_next_index;
247 }
248 
249 #include <vnet/pipeline.h>
250 
251 static uword
253  vlib_node_runtime_t * node, vlib_frame_t * frame)
254 {
255  l2t_main_t *lm = &l2t_main;
256  lm->ip6_error_node = vlib_node_get_runtime (vm, l2t_ip6_node.index);
257 
258  return dispatch_pipeline (vm, node, frame);
259 }
260 
261 /* *INDENT-OFF* */
263  .function = ip6_l2t_node_fn,
264  .name = "ip6-l2t-input",
265  .vector_size = sizeof (u32),
266  .format_trace = format_l2t_trace,
268 
269  .n_errors = ARRAY_LEN(l2t_ip6_error_strings),
270  .error_strings = l2t_ip6_error_strings,
271 
272  .n_next_nodes = L2T_IP6_N_NEXT,
273 
274  /* edit / add dispositions here */
275  .next_nodes = {
276  [L2T_IP6_NEXT_IP6_INPUT] = "ip6-input",
277  [L2T_IP6_NEXT_DROP] = "error-drop",
278  },
279 };
280 /* *INDENT-ON* */
281 
283 static clib_error_t *
285 {
286  l2t_main_t *lm = &l2t_main;
287 
289  {
290  if (unformat (input, "lookup-v6-src"))
292  else if (unformat (input, "lookup-v6-dst"))
294  else if (unformat (input, "lookup-session-id"))
296  else
297  return clib_error_return (0, "unknown input `%U'",
298  format_unformat_error, input);
299  }
300  return 0;
301 }
302 
304 
305 clib_error_t *
307 {
308  l2t_main_t *lm = &l2t_main;
309 
310  lm->vnet_main = vnet_get_main ();
311  lm->vlib_main = vm;
313 
315  (0, sizeof (ip6_address_t) /* key bytes */ ,
316  sizeof (u32) /* value bytes */ );
318  (0, sizeof (ip6_address_t) /* key bytes */ ,
319  sizeof (u32) /* value bytes */ );
320  lm->session_by_session_id = hash_create (0, sizeof (uword));
321 
322  lm->session_by_vlan_and_rx_sw_if_index = hash_create (0, sizeof (uword));
323 
324 #if DPDK == 0
325  vice_set_next_node (VICE_RX_NEXT_IP6_INPUT, "ip6-l2t-input");
326  ixgev_set_next_node (IXGEV_RX_NEXT_IP6_INPUT, "ip6-l2t-input");
327  ixge_set_next_node (IXGE_RX_NEXT_IP6_INPUT, "ip6-l2t-input");
328  ige_set_next_node (IGE_RX_NEXT_IP6_INPUT, "ip6-l2t-input");
329 #else
330  dpdk_set_next_node (DPDK_RX_NEXT_IP6_INPUT, "ip6-l2t-input");
331 #endif
332  return 0;
333 }
334 
336 
337 /*
338  * fd.io coding-style-patch-verification: ON
339  *
340  * Local Variables:
341  * eval: (c-set-style "gnu")
342  * End:
343  */
int is_user_to_network
Definition: l2tp.h:88
u8 cookie_flags
Definition: l2tp.h:46
u64 local_cookie[2]
Definition: l2tp.h:32
VLIB_NODE_FUNCTION_MULTIARCH(sw6_ip6_node, ip6_l2t_node_fn)
u32 error_heap_index
Definition: node.h:278
ip6_address_t client_address
Definition: l2tp.h:91
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
bad routing header type(not 4)") sr_error (NO_MORE_SEGMENTS
vlib_node_registration_t l2t_ip6_node
Definition: l2t_ip6.c:68
u64 as_u64[2]
Definition: ip6_packet.h:50
uword * session_by_session_id
Definition: l2tp.h:66
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
struct _vlib_node_registration vlib_node_registration_t
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
#define foreach_l2t_ip6_error
Definition: l2t_ip6.c:35
clib_error_t * l2t_ip6_init(vlib_main_t *vm)
Definition: l2t_ip6.c:306
vnet_main_t * vnet_get_main(void)
Definition: misc.c:45
static char * l2t_ip6_error_strings[]
Definition: l2t_ip6.c:40
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:187
void dpdk_set_next_node(dpdk_rx_next_t, char *)
Definition: node.c:828
static u32 counter_index(vlib_main_t *vm, vlib_error_t e)
#define hash_create_mem(elts, key_bytes, value_bytes)
Definition: hash.h:626
#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
l2t_main_t l2t_main
Definition: l2t_ip6.c:32
#define PREDICT_FALSE(x)
Definition: clib.h:97
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:118
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
static void stage1(vlib_main_t *vm, vlib_node_runtime_t *node, u32 bi)
Definition: l2t_ip6.c:82
static void stage0(vlib_main_t *vm, vlib_node_runtime_t *node, u32 buffer_index)
Definition: l2t_ip6.c:73
ip6_address_t our_address
Definition: l2tp.h:90
u64 * counters
Definition: error.h:78
static clib_error_t * l2tp_config(vlib_main_t *vm, unformat_input_t *input)
Definition: l2t_ip6.c:284
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
static u32 last_stage(vlib_main_t *vm, vlib_node_runtime_t *node, u32 bi)
Definition: l2t_ip6.c:135
static vlib_node_runtime_t * vlib_node_get_runtime(vlib_main_t *vm, u32 node_index)
Get node runtime by node index.
Definition: node_funcs.h:88
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
static vlib_node_registration_t sw6_ip6_node
(constructor) VLIB_REGISTER_NODE (sw6_ip6_node)
Definition: l2t_ip6.c:262
#define hash_create(elts, value_bytes)
Definition: hash.h:647
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)
l2t_ip6_next_t
Definition: l2t_ip6.c:59
vlib_main_t * vlib_main
Definition: l2tp.h:80
unsigned int u32
Definition: types.h:88
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
#define vnet_buffer(b)
Definition: buffer.h:335
static uword ip6_l2t_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: l2t_ip6.c:252
vnet_main_t * vnet_main
Definition: l2tp.h:81
uword * session_by_dst_address
Definition: l2tp.h:65
#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
Definition: defs.h:47
void ixge_set_next_node(ixge_rx_next_t next, char *name)
Definition: ixge.c:2912
unsigned short u16
Definition: types.h:57
unsigned char u8
Definition: types.h:56
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
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
#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
#define clib_error_return(e, args...)
Definition: error.h:111
struct _unformat_input_t unformat_input_t
uword * session_by_src_address
Definition: l2tp.h:64
l2t_ip6_error_t
Definition: l2t_ip6.c:46
u8 l2_sublayer_present
Definition: l2tp.h:45
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:85
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
u32 session_index
Definition: l2tp.h:89
ip6_address_t dst_address
Definition: ip6_packet.h:298