Initial commit of vpp code.
[vpp.git] / vnet / vnet / vxlan / decap.c
1 /*
2  * decap.c: vxlan tunnel decap packet processing
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 <vlib/vlib.h>
19 #include <vnet/pg/pg.h>
20 #include <vnet/vxlan/vxlan.h>
21
22 vlib_node_registration_t vxlan_input_node;
23
24 typedef struct {
25   u32 next_index;
26   u32 tunnel_index;
27   u32 error;
28   u32 vni;
29 } vxlan_rx_trace_t;
30
31 static u8 * format_vxlan_rx_trace (u8 * s, va_list * args)
32 {
33   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
34   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
35   vxlan_rx_trace_t * t = va_arg (*args, vxlan_rx_trace_t *);
36
37   if (t->tunnel_index != ~0)
38     {
39       s = format (s, "VXLAN: tunnel %d vni %d next %d error %d", 
40                   t->tunnel_index, t->vni, t->next_index, t->error);
41     }
42   else
43     {
44       s = format (s, "VXLAN: no tunnel for vni %d next %d error %d", 
45                   t->vni, t->next_index, t->error);
46     }
47   return s;
48 }
49
50 static uword
51 vxlan_input (vlib_main_t * vm,
52              vlib_node_runtime_t * node,
53              vlib_frame_t * from_frame)
54 {
55   u32 n_left_from, next_index, * from, * to_next;
56   vxlan_main_t * vxm = &vxlan_main;
57   vnet_main_t * vnm = vxm->vnet_main;
58   vnet_interface_main_t * im = &vnm->interface_main;
59   u32 last_tunnel_index = ~0;
60   vxlan_tunnel_key_t last_key;
61   u32 pkts_decapsulated = 0;
62   u32 cpu_index = os_get_cpu_number();
63   u32 stats_sw_if_index, stats_n_packets, stats_n_bytes;
64
65   last_key.as_u64 = ~0;
66
67   from = vlib_frame_vector_args (from_frame);
68   n_left_from = from_frame->n_vectors;
69
70   next_index = node->cached_next_index;
71   stats_sw_if_index = node->runtime_data[0];
72   stats_n_packets = stats_n_bytes = 0;
73
74   while (n_left_from > 0)
75     {
76       u32 n_left_to_next;
77
78       vlib_get_next_frame (vm, node, next_index,
79                            to_next, n_left_to_next);
80       while (n_left_from >= 4 && n_left_to_next >= 2)
81         {
82           u32 bi0, bi1;
83           vlib_buffer_t * b0, * b1;
84           u32 next0, next1;
85           ip4_header_t * ip0, * ip1;
86           vxlan_header_t * vxlan0, * vxlan1;
87           uword * p0, * p1;
88           u32 tunnel_index0, tunnel_index1;
89           vxlan_tunnel_t * t0, * t1;
90           vxlan_tunnel_key_t key0, key1;
91           u32 error0, error1;
92           u32 sw_if_index0, sw_if_index1, len0, len1;
93
94           /* Prefetch next iteration. */
95           {
96             vlib_buffer_t * p2, * p3;
97
98             p2 = vlib_get_buffer (vm, from[2]);
99             p3 = vlib_get_buffer (vm, from[3]);
100
101             vlib_prefetch_buffer_header (p2, LOAD);
102             vlib_prefetch_buffer_header (p3, LOAD);
103
104             CLIB_PREFETCH (p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
105             CLIB_PREFETCH (p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
106           }
107
108           bi0 = from[0];
109           bi1 = from[1];
110           to_next[0] = bi0;
111           to_next[1] = bi1;
112           from += 2;
113           to_next += 2;
114           n_left_to_next -= 2;
115           n_left_from -= 2;
116
117           b0 = vlib_get_buffer (vm, bi0);
118           b1 = vlib_get_buffer (vm, bi1);
119
120           /* udp leaves current_data pointing at the vxlan header */
121           vxlan0 = vlib_buffer_get_current (b0);
122           vxlan1 = vlib_buffer_get_current (b1);
123
124           vlib_buffer_advance 
125             (b0, -(word)(sizeof(udp_header_t)+sizeof(ip4_header_t)));
126           vlib_buffer_advance 
127             (b1, -(word)(sizeof(udp_header_t)+sizeof(ip4_header_t)));
128           ip0 = vlib_buffer_get_current (b0);
129           ip1 = vlib_buffer_get_current (b1);
130
131           /* pop (ip, udp, vxlan) */
132           vlib_buffer_advance 
133             (b0, sizeof(*ip0)+sizeof(udp_header_t)+sizeof(*vxlan0));
134           vlib_buffer_advance 
135             (b1, sizeof(*ip1)+sizeof(udp_header_t)+sizeof(*vxlan1));
136
137           tunnel_index0 = ~0;
138           error0 = 0;
139
140           tunnel_index1 = ~0;
141           error1 = 0;
142
143           key0.src = ip0->src_address.as_u32;
144           key0.vni = vxlan0->vni_reserved;
145
146           if (PREDICT_FALSE (key0.as_u64 != last_key.as_u64))
147             {
148               p0 = hash_get (vxm->vxlan_tunnel_by_key, key0.as_u64);
149
150               if (p0 == 0)
151                 {
152                   error0 = VXLAN_ERROR_NO_SUCH_TUNNEL;
153                   next0 = VXLAN_INPUT_NEXT_DROP;
154                   goto trace0;
155                 }
156
157               last_key.as_u64 = key0.as_u64;
158               tunnel_index0 = last_tunnel_index = p0[0];
159             }
160           else
161             tunnel_index0 = last_tunnel_index;
162
163           t0 = pool_elt_at_index (vxm->tunnels, tunnel_index0);
164
165           next0 = t0->decap_next_index;
166           sw_if_index0 = t0->sw_if_index;
167           len0 = vlib_buffer_length_in_chain (vm, b0);
168
169           /* Required to make the l2 tag push / pop code work on l2 subifs */
170           vnet_update_l2_len (b0);
171
172           /* Set input sw_if_index to VXLAN tunnel for learning */
173           vnet_buffer(b0)->sw_if_index[VLIB_RX] = sw_if_index0;
174
175           pkts_decapsulated ++;
176           stats_n_packets += 1;
177           stats_n_bytes += len0;
178
179           /* Batch stats increment on the same vxlan tunnel so counter
180              is not incremented per packet */
181           if (PREDICT_FALSE (sw_if_index0 != stats_sw_if_index)) 
182             {
183               stats_n_packets -= 1;
184               stats_n_bytes -= len0;
185               if (stats_n_packets)
186                 vlib_increment_combined_counter 
187                   (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX,
188                    cpu_index, stats_sw_if_index, 
189                    stats_n_packets, stats_n_bytes);
190               stats_n_packets = 1;
191               stats_n_bytes = len0;
192               stats_sw_if_index = sw_if_index0;
193             }
194
195         trace0:
196           b0->error = error0 ? node->errors[error0] : 0;
197
198           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
199             {
200               vxlan_rx_trace_t *tr 
201                 = vlib_add_trace (vm, node, b0, sizeof (*tr));
202               tr->next_index = next0;
203               tr->error = error0;
204               tr->tunnel_index = tunnel_index0;
205               tr->vni = vnet_get_vni (vxlan0);
206             }
207
208           key1.src = ip1->src_address.as_u32;
209           key1.vni = vxlan1->vni_reserved;
210
211           if (PREDICT_FALSE (key1.as_u64 != last_key.as_u64))
212             {
213               p1 = hash_get (vxm->vxlan_tunnel_by_key, key1.as_u64);
214
215               if (p1 == 0)
216                 {
217                   error1 = VXLAN_ERROR_NO_SUCH_TUNNEL;
218                   next1 = VXLAN_INPUT_NEXT_DROP;
219                   goto trace1;
220                 }
221
222               last_key.as_u64 = key1.as_u64;
223               tunnel_index1 = last_tunnel_index = p1[0];
224             }
225           else
226             tunnel_index1 = last_tunnel_index;
227
228           t1 = pool_elt_at_index (vxm->tunnels, tunnel_index1);
229
230           next1 = t1->decap_next_index;
231           sw_if_index1 = t1->sw_if_index;
232           len1 = vlib_buffer_length_in_chain (vm, b1);
233
234           /* Required to make the l2 tag push / pop code work on l2 subifs */
235           vnet_update_l2_len (b1);
236
237           /* Set input sw_if_index to VXLAN tunnel for learning */
238           vnet_buffer(b1)->sw_if_index[VLIB_RX] = sw_if_index1;
239
240           pkts_decapsulated ++;
241           stats_n_packets += 1;
242           stats_n_bytes += len1;
243
244           /* Batch stats increment on the same vxlan tunnel so counter
245              is not incremented per packet */
246           if (PREDICT_FALSE (sw_if_index1 != stats_sw_if_index)) 
247             {
248               stats_n_packets -= 1;
249               stats_n_bytes -= len1;
250               if (stats_n_packets)
251                 vlib_increment_combined_counter 
252                   (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX,
253                    cpu_index, stats_sw_if_index, 
254                    stats_n_packets, stats_n_bytes);
255               stats_n_packets = 1;
256               stats_n_bytes = len1;
257               stats_sw_if_index = sw_if_index1;
258             }
259
260         trace1:
261           b1->error = error1 ? node->errors[error1] : 0;
262
263           if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED)) 
264             {
265               vxlan_rx_trace_t *tr 
266                 = vlib_add_trace (vm, node, b1, sizeof (*tr));
267               tr->next_index = next1;
268               tr->error = error1;
269               tr->tunnel_index = tunnel_index1;
270               tr->vni = vnet_get_vni (vxlan1);
271             }
272
273           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
274                                            to_next, n_left_to_next,
275                                            bi0, bi1, next0, next1);
276         }
277
278       while (n_left_from > 0 && n_left_to_next > 0)
279         {
280           u32 bi0;
281           vlib_buffer_t * b0;
282           u32 next0;
283           ip4_header_t * ip0;
284           vxlan_header_t * vxlan0;
285           uword * p0;
286           u32 tunnel_index0;
287           vxlan_tunnel_t * t0;
288           vxlan_tunnel_key_t key0;
289           u32 error0;
290           u32 sw_if_index0, len0;
291
292           bi0 = from[0];
293           to_next[0] = bi0;
294           from += 1;
295           to_next += 1;
296           n_left_from -= 1;
297           n_left_to_next -= 1;
298
299           b0 = vlib_get_buffer (vm, bi0);
300
301           /* udp leaves current_data pointing at the vxlan header */
302           vxlan0 = vlib_buffer_get_current (b0);
303
304           vlib_buffer_advance 
305             (b0, -(word)(sizeof(udp_header_t)+sizeof(ip4_header_t)));
306           ip0 = vlib_buffer_get_current (b0);
307
308           /* pop (ip, udp, vxlan) */
309           vlib_buffer_advance 
310             (b0, sizeof(*ip0)+sizeof(udp_header_t)+sizeof(*vxlan0));
311
312           tunnel_index0 = ~0;
313           error0 = 0;
314
315           key0.src = ip0->src_address.as_u32;
316           key0.vni = vxlan0->vni_reserved;
317
318           if (PREDICT_FALSE (key0.as_u64 != last_key.as_u64))
319             {
320               p0 = hash_get (vxm->vxlan_tunnel_by_key, key0.as_u64);
321
322               if (p0 == 0)
323                 {
324                   error0 = VXLAN_ERROR_NO_SUCH_TUNNEL;
325                   next0 = VXLAN_INPUT_NEXT_DROP;
326                   goto trace00;
327                 }
328
329               last_key.as_u64 = key0.as_u64;
330               tunnel_index0 = last_tunnel_index = p0[0];
331             }
332           else
333             tunnel_index0 = last_tunnel_index;
334
335           t0 = pool_elt_at_index (vxm->tunnels, tunnel_index0);
336
337           next0 = t0->decap_next_index;
338           sw_if_index0 = t0->sw_if_index;
339           len0 = vlib_buffer_length_in_chain (vm, b0);
340
341           /* Required to make the l2 tag push / pop code work on l2 subifs */
342           vnet_update_l2_len (b0);
343
344           /* Set input sw_if_index to VXLAN tunnel for learning */
345           vnet_buffer(b0)->sw_if_index[VLIB_RX] = sw_if_index0;
346
347           pkts_decapsulated ++;
348           stats_n_packets += 1;
349           stats_n_bytes += len0;
350
351           /* Batch stats increment on the same vxlan tunnel so counter
352              is not incremented per packet */
353           if (PREDICT_FALSE (sw_if_index0 != stats_sw_if_index)) 
354             {
355               stats_n_packets -= 1;
356               stats_n_bytes -= len0;
357               if (stats_n_packets)
358                 vlib_increment_combined_counter 
359                   (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX,
360                    cpu_index, stats_sw_if_index, 
361                    stats_n_packets, stats_n_bytes);
362               stats_n_packets = 1;
363               stats_n_bytes = len0;
364               stats_sw_if_index = sw_if_index0;
365             }
366
367         trace00:
368           b0->error = error0 ? node->errors[error0] : 0;
369
370           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
371             {
372               vxlan_rx_trace_t *tr 
373                 = vlib_add_trace (vm, node, b0, sizeof (*tr));
374               tr->next_index = next0;
375               tr->error = error0;
376               tr->tunnel_index = tunnel_index0;
377               tr->vni = vnet_get_vni (vxlan0);
378             }
379           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
380                                            to_next, n_left_to_next,
381                                            bi0, next0);
382         }
383
384       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
385     }
386   /* Do we still need this now that tunnel tx stats is kept? */
387   vlib_node_increment_counter (vm, vxlan_input_node.index,
388                                VXLAN_ERROR_DECAPSULATED, 
389                                pkts_decapsulated);
390
391   /* Increment any remaining batch stats */
392   if (stats_n_packets)
393     {
394       vlib_increment_combined_counter 
395         (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX,
396          cpu_index, stats_sw_if_index, stats_n_packets, stats_n_bytes);
397       node->runtime_data[0] = stats_sw_if_index;
398     }
399
400   return from_frame->n_vectors;
401 }
402
403 static char * vxlan_error_strings[] = {
404 #define vxlan_error(n,s) s,
405 #include <vnet/vxlan/vxlan_error.def>
406 #undef vxlan_error
407 #undef _
408 };
409
410 VLIB_REGISTER_NODE (vxlan_input_node) = {
411   .function = vxlan_input,
412   .name = "vxlan-input",
413   /* Takes a vector of packets. */
414   .vector_size = sizeof (u32),
415
416   .n_errors = VXLAN_N_ERROR,
417   .error_strings = vxlan_error_strings,
418
419   .n_next_nodes = VXLAN_INPUT_N_NEXT,
420   .next_nodes = {
421 #define _(s,n) [VXLAN_INPUT_NEXT_##s] = n,
422     foreach_vxlan_input_next
423 #undef _
424   },
425
426 //temp  .format_buffer = format_vxlan_header,
427   .format_trace = format_vxlan_rx_trace,
428   // $$$$ .unformat_buffer = unformat_vxlan_header,
429 };