FD.io VPP  v16.06
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 #define _(sym,str) L2T_IP6_ERROR_##sym,
49 #undef _
52 
53 /*
54  * Packets go to ip6-input when they don't match a mapping,
55  * example: v6 neighbor discovery. They go to ip4-input
56  * when they do match, and are decapsulated.
57  */
58 typedef enum {
62  /* Pseudo next, fixed in last_stage */
65 
67 
68 #define NSTAGES 3
69 
70 static inline void stage0 (vlib_main_t * vm,
71  vlib_node_runtime_t * node,
72  u32 buffer_index)
73 {
74  vlib_buffer_t *b = vlib_get_buffer (vm, buffer_index);
75  vlib_prefetch_buffer_header (b, STORE);
76  /* l2tpv3 header is a long way away, need 2 cache lines */
78 }
79 
80 static inline void stage1 (vlib_main_t * vm,
81  vlib_node_runtime_t * node,
82  u32 bi)
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  vnet_buffer(b)->l2t.next_index = L2T_IP6_NEXT_IP6_INPUT;
94  return;
95  }
96 
97  /* Make up your minds, people... */
98  switch (lm->lookup_type) {
101  break;
104  break;
106  l2t = (l2tpv3_header_t*)(ip6+1);
107  p = hash_get (lm->session_by_session_id, l2t->session_id);
108  break;
109  default:
110  ASSERT(0);
111  }
112 
113  if (PREDICT_FALSE(p == 0)) {
114  vnet_buffer(b)->l2t.next_index = L2T_IP6_NEXT_IP6_INPUT;
115  return;
116  } else {
117  session_index = p[0];
118  }
119 
120  /* Remember mapping index, prefetch the mini counter */
121  vnet_buffer(b)->l2t.next_index = L2T_IP6_NEXT_OUTPUT;
122  vnet_buffer(b)->l2t.session_index = session_index;
123 
124  /* Each mapping has 2 x (pkt, byte) counters, hence the shift */
125  CLIB_PREFETCH(lm->counter_main.mini + (p[0]<<1), CLIB_CACHE_LINE_BYTES,
126  STORE);
127 }
128 
129 static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
130  u32 bi)
131 {
132  vlib_buffer_t *b = vlib_get_buffer (vm, bi);
133  l2t_main_t *lm = &l2t_main;
135  vlib_node_t *n = vlib_get_node (vm, l2t_ip6_node.index);
136  u32 node_counter_base_index = n->error_heap_index;
137  vlib_error_main_t * em = &vm->error_main;
138  ethernet_header_t * l2_payload;
139  l2tpv3_header_t * l2t; /* original l2 header */
140  ethernet_vlan_header_t * vh; /* synthesized 802.1q vlan header */
142  l2t_session_t * session;
143  u16 payload_ethertype;
144  u8 dst_mac_address[6];
145  u8 src_mac_address[6];
146  u8 *vlan_header_pos;
147 
148  /* Other-than-output pkt? We're done... */
149  if (vnet_buffer(b)->l2t.next_index != L2T_IP6_NEXT_OUTPUT)
150  return vnet_buffer(b)->l2t.next_index;
151 
152  em->counters[node_counter_base_index + L2T_IP6_ERROR_USER_TO_NETWORK] += 1;
153 
154  counter_index =
155  session_index_to_counter_index (vnet_buffer(b)->l2t.session_index,
157 
158  /* per-mapping byte stats include the ethernet header */
159  vlib_increment_combined_counter (&lm->counter_main, counter_index,
160  1 /* packet_increment */,
162  sizeof (ethernet_header_t));
163 
164  session = pool_elt_at_index (lm->sessions,
165  vnet_buffer(b)->l2t.session_index);
166 
167  /* build the 802.1q encaps. Advance past ip6 and l2tpv3 hds */
168  vlib_buffer_advance (b, sizeof (*ip6));
169  l2t = vlib_buffer_get_current (b);
170 
171  /* $$$ wonder if we really need these checks... */
172  if (PREDICT_FALSE(l2t->session_id != session->local_session_id)) {
173  b->error = lm->ip6_error_node->
174  errors[L2T_IP6_ERROR_SESSION_ID_MISMATCH];
175  return L2T_IP6_NEXT_DROP;
176  }
177 
178  if (PREDICT_FALSE(!((l2t->cookie == session->local_cookie) ||
179  ((session->cookie_flags & L2TP_COOKIE_ROLLOVER_LOCAL) &&
180  (l2t->cookie == session->lcl_ro_cookie))))) {
181  b->error = lm->ip6_error_node->
182  errors[L2T_IP6_ERROR_COOKIE_MISMATCH];
183  return L2T_IP6_NEXT_DROP;
184  }
185 
186  vnet_buffer(b)->sw_if_index[VLIB_TX] = session->l2_output_sw_if_index;
187 
188  vlib_buffer_advance (b, sizeof (*l2t));
189 
190  /* point at currrent l2 hdr */
191  l2_payload = vlib_buffer_get_current (b);
192 
193  /* $$$$ rework for speed */
194 
195  /* Save type */
196  payload_ethertype = l2_payload->type;
197 
198  /* Save src/dst MAC addresses */
199 #define _(i) dst_mac_address[i] = l2_payload->dst_address[i];
200  _(0) _(1) _(2) _(3) _(4) _(5);
201 #undef _
202 #define _(i) src_mac_address[i] = l2_payload->src_address[i];
203  _(0) _(1) _(2) _(3) _(4) _(5);
204 #undef _
205 
206  /* Punch in space for 802.1q tag */
207  vlib_buffer_advance (b, -4);
208  l2_payload = vlib_buffer_get_current (b);
209 
210  /* Restore MAC addresses */
211 #define _(i) l2_payload->dst_address[i] = dst_mac_address[i];
212  _(0) _(1) _(2) _(3) _(4) _(5);
213 #undef _
214 #define _(i) l2_payload->src_address[i] = src_mac_address[i];
215  _(0) _(1) _(2) _(3) _(4) _(5);
216 #undef _
217  /* Set (outer) ethertype to 802.1q vlan */
218  l2_payload->type = clib_host_to_net_u16 (0x8100);
219  vlan_header_pos = (u8 *)(l2_payload+1);
220 #if 0
221  vlan_header_pos = session->l2_sublayer_present ?
222  vlan_header_pos : vlan_header_pos - 4;
223 #endif
224  vh = (ethernet_vlan_header_t *)vlan_header_pos;
225  vh->priority_cfi_and_id = session->vlan_id;
226  vh->type = payload_ethertype;
227 
229  l2t_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t));
230  t->is_user_to_network = 1;
231  t->our_address.as_u64[0] =
232  ip6->dst_address.as_u64[0];
233  t->our_address.as_u64[1] =
234  ip6->dst_address.as_u64[1];
235  t->client_address.as_u64[0] =
236  ip6->src_address.as_u64[0];
237  t->client_address.as_u64[1] =
238  ip6->src_address.as_u64[1];
239  t->session_index = vnet_buffer(b)->l2t.session_index;
240  t->vlan_id_host_byte_order = clib_net_to_host_u16 (session->vlan_id);
241  }
242 
243  return session->l2_output_next_index;
244 }
245 
246 #include <vnet/pipeline.h>
247 
249  vlib_node_runtime_t * node,
250  vlib_frame_t * frame)
251 {
252  l2t_main_t *lm = &l2t_main;
253  lm->ip6_error_node = vlib_node_get_runtime (vm, l2t_ip6_node.index);
254 
255  return dispatch_pipeline (vm, node, frame);
256 }
257 
259  .function = ip6_l2t_node_fn,
260  .name = "ip6-l2t-input",
261  .vector_size = sizeof (u32),
262  .format_trace = format_l2t_trace,
264 
265  .n_errors = ARRAY_LEN(l2t_ip6_error_strings),
266  .error_strings = l2t_ip6_error_strings,
267 
268  .n_next_nodes = L2T_IP6_N_NEXT,
269 
270  /* edit / add dispositions here */
271  .next_nodes = {
272  [L2T_IP6_NEXT_IP6_INPUT] = "ip6-input",
273  [L2T_IP6_NEXT_DROP] = "error-drop",
274  },
275 };
276 
277 static clib_error_t *
279 {
280  l2t_main_t *lm = &l2t_main;
281 
282  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
283  if (unformat (input, "lookup-v6-src"))
285  else if (unformat (input, "lookup-v6-dst"))
287  else if (unformat (input, "lookup-session-id"))
289  else return clib_error_return (0, "unknown input `%U'",
290  format_unformat_error, input);
291  }
292  return 0;
293 }
294 
296 
297 clib_error_t *
299 {
300  l2t_main_t *lm = &l2t_main;
301 
302  lm->vnet_main = vnet_get_main();
303  lm->vlib_main = vm;
305 
307  (0, sizeof (ip6_address_t) /* key bytes */,
308  sizeof (u32) /* value bytes */);
310  (0, sizeof (ip6_address_t) /* key bytes */,
311  sizeof (u32) /* value bytes */);
312  lm->session_by_session_id = hash_create (0, sizeof (uword));
313 
314  lm->session_by_vlan_and_rx_sw_if_index = hash_create (0, sizeof (uword));
315 
316 #if DPDK == 0
317  vice_set_next_node (VICE_RX_NEXT_IP6_INPUT, "ip6-l2t-input");
318  ixgev_set_next_node (IXGEV_RX_NEXT_IP6_INPUT, "ip6-l2t-input");
319  ixge_set_next_node (IXGE_RX_NEXT_IP6_INPUT, "ip6-l2t-input");
320  ige_set_next_node (IGE_RX_NEXT_IP6_INPUT, "ip6-l2t-input");
321 #else
322  dpdk_set_next_node (DPDK_RX_NEXT_IP6_INPUT, "ip6-l2t-input");
323 #endif
324  return 0;
325 }
326 
int is_user_to_network
Definition: l2tp.h:81
u8 cookie_flags
Definition: l2tp.h:44
u64 local_cookie[2]
Definition: l2tp.h:33
u32 error_heap_index
Definition: node.h:244
ip6_address_t client_address
Definition: l2tp.h:84
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:942
always_inline vlib_node_t * vlib_get_node(vlib_main_t *vm, u32 i)
Definition: node_funcs.h:46
bad routing header type(not 4)") sr_error (NO_MORE_SEGMENTS
vlib_node_registration_t l2t_ip6_node
Definition: l2t_ip6.c:66
u64 as_u64[2]
Definition: ip6_packet.h:50
uword * session_by_session_id
Definition: l2tp.h:60
#define UNFORMAT_END_OF_INPUT
Definition: format.h:142
struct _vlib_node_registration vlib_node_registration_t
ip6_address_t src_address
Definition: ip6_packet.h:293
static u32 session_index_to_counter_index(u32 session_index, u32 counter_id)
Definition: l2tp.h:96
always_inline void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:184
#define foreach_l2t_ip6_error
Definition: l2t_ip6.c:35
always_inline uword unformat_check_input(unformat_input_t *i)
Definition: format.h:168
clib_error_t * l2t_ip6_init(vlib_main_t *vm)
Definition: l2t_ip6.c:298
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:109
void dpdk_set_next_node(dpdk_rx_next_t, char *)
Definition: node.c:857
always_inline void vlib_increment_combined_counter(vlib_combined_counter_main_t *cm, u32 cpu_index, u32 index, u32 packet_increment, u32 byte_increment)
Definition: counter.h:210
always_inline 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
#define hash_create_mem(elts, key_bytes, value_bytes)
Definition: hash.h:594
#define hash_get(h, key)
Definition: hash.h:231
#define pool_elt_at_index(p, i)
Definition: pool.h:346
vlib_error_main_t error_main
Definition: main.h:124
u32 local_session_id
Definition: l2tp.h:35
u8 * format_l2t_trace(u8 *s, va_list *args)
Definition: l2tp.c:29
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:116
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:129
ip6_to_l2_lookup_t lookup_type
Definition: l2tp.h:62
static void stage1(vlib_main_t *vm, vlib_node_runtime_t *node, u32 bi)
Definition: l2t_ip6.c:80
static void stage0(vlib_main_t *vm, vlib_node_runtime_t *node, u32 buffer_index)
Definition: l2t_ip6.c:70
ip6_address_t our_address
Definition: l2tp.h:83
u64 * counters
Definition: error.h:73
static clib_error_t * l2tp_config(vlib_main_t *vm, unformat_input_t *input)
Definition: l2t_ip6.c:278
#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:129
#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:258
#define hash_create(elts, value_bytes)
Definition: hash.h:615
#define ASSERT(truth)
l2t_ip6_next_t
Definition: l2t_ip6.c:58
vlib_main_t * vlib_main
Definition: l2tp.h:74
unsigned int u32
Definition: types.h:88
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:87
#define vnet_buffer(b)
Definition: buffer.h:300
static uword ip6_l2t_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: l2t_ip6.c:248
vnet_main_t * vnet_main
Definition: l2tp.h:75
uword * session_by_dst_address
Definition: l2tp.h:59
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:91
vlib_combined_counter_main_t counter_main
Definition: l2tp.h:65
u64 uword
Definition: types.h:112
Definition: defs.h:46
unsigned short u16
Definition: types.h:57
always_inline void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:197
unsigned char u8
Definition: types.h:56
l2t_session_t * sessions
Definition: l2tp.h:55
always_inline 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
#define hash_get_mem(h, key)
Definition: hash.h:251
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:162
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:140
always_inline vlib_node_runtime_t * vlib_node_get_runtime(vlib_main_t *vm, u32 node_index)
Definition: node_funcs.h:61
u8 data[0]
Packet data.
Definition: buffer.h:150
#define clib_error_return(e, args...)
Definition: error.h:112
struct _unformat_input_t unformat_input_t
uword * session_by_src_address
Definition: l2tp.h:58
l2t_ip6_error_t
Definition: l2t_ip6.c:46
u8 l2_sublayer_present
Definition: l2tp.h:43
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:84
always_inline vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:69
always_inline u32 counter_index(vlib_main_t *vm, vlib_error_t e)
u32 session_index
Definition: l2tp.h:82
ip6_address_t dst_address
Definition: ip6_packet.h:293