VPP-241: Add custom dump functions for LISP
[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 always_inline uword
51 vxlan_input (vlib_main_t * vm,
52              vlib_node_runtime_t * node,
53              vlib_frame_t * from_frame,
54              char is_ip4)
55 {
56   u32 n_left_from, next_index, * from, * to_next;
57   vxlan_main_t * vxm = &vxlan_main;
58   vnet_main_t * vnm = vxm->vnet_main;
59   vnet_interface_main_t * im = &vnm->interface_main;
60   u32 last_tunnel_index = ~0;
61   vxlan4_tunnel_key_t last_key4;
62   vxlan6_tunnel_key_t last_key6;
63   u32 pkts_decapsulated = 0;
64   u32 cpu_index = os_get_cpu_number();
65   u32 stats_sw_if_index, stats_n_packets, stats_n_bytes;
66
67   if (is_ip4)
68     last_key4.as_u64 = ~0;
69   else
70     memset (&last_key6, 0xff, sizeof (last_key6));
71
72   from = vlib_frame_vector_args (from_frame);
73   n_left_from = from_frame->n_vectors;
74
75   next_index = node->cached_next_index;
76   stats_sw_if_index = node->runtime_data[0];
77   stats_n_packets = stats_n_bytes = 0;
78
79   while (n_left_from > 0)
80     {
81       u32 n_left_to_next;
82
83       vlib_get_next_frame (vm, node, next_index,
84                            to_next, n_left_to_next);
85       while (n_left_from >= 4 && n_left_to_next >= 2)
86         {
87           u32 bi0, bi1;
88           vlib_buffer_t * b0, * b1;
89           u32 next0, next1;
90           ip4_header_t * ip4_0, * ip4_1;
91           ip6_header_t * ip6_0, * ip6_1;
92           vxlan_header_t * vxlan0, * vxlan1;
93           uword * p0, * p1;
94           u32 tunnel_index0, tunnel_index1;
95           vxlan_tunnel_t * t0, * t1;
96           vxlan4_tunnel_key_t key4_0, key4_1;
97           vxlan6_tunnel_key_t key6_0, key6_1;
98           u32 error0, error1;
99           u32 sw_if_index0, sw_if_index1, len0, len1;
100
101           /* Prefetch next iteration. */
102           {
103             vlib_buffer_t * p2, * p3;
104
105             p2 = vlib_get_buffer (vm, from[2]);
106             p3 = vlib_get_buffer (vm, from[3]);
107
108             vlib_prefetch_buffer_header (p2, LOAD);
109             vlib_prefetch_buffer_header (p3, LOAD);
110
111             CLIB_PREFETCH (p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
112             CLIB_PREFETCH (p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
113           }
114
115           bi0 = from[0];
116           bi1 = from[1];
117           to_next[0] = bi0;
118           to_next[1] = bi1;
119           from += 2;
120           to_next += 2;
121           n_left_to_next -= 2;
122           n_left_from -= 2;
123
124           b0 = vlib_get_buffer (vm, bi0);
125           b1 = vlib_get_buffer (vm, bi1);
126
127           /* udp leaves current_data pointing at the vxlan header */
128           vxlan0 = vlib_buffer_get_current (b0);
129           vxlan1 = vlib_buffer_get_current (b1);
130
131           if (is_ip4) {
132           vlib_buffer_advance 
133             (b0, -(word)(sizeof(udp_header_t)+sizeof(ip4_header_t)));
134           vlib_buffer_advance 
135             (b1, -(word)(sizeof(udp_header_t)+sizeof(ip4_header_t)));
136             ip4_0 = vlib_buffer_get_current (b0);
137             ip4_1 = vlib_buffer_get_current (b1);
138           } else {
139             vlib_buffer_advance
140               (b0, -(word)(sizeof(udp_header_t)+sizeof(ip6_header_t)));
141             vlib_buffer_advance
142               (b1, -(word)(sizeof(udp_header_t)+sizeof(ip6_header_t)));
143             ip6_0 = vlib_buffer_get_current (b0);
144             ip6_1 = vlib_buffer_get_current (b1);
145           }
146
147           /* pop (ip, udp, vxlan) */
148           if (is_ip4) {
149             vlib_buffer_advance
150               (b0, sizeof(*ip4_0)+sizeof(udp_header_t)+sizeof(*vxlan0));
151           vlib_buffer_advance 
152               (b1, sizeof(*ip4_1)+sizeof(udp_header_t)+sizeof(*vxlan1));
153           } else {
154           vlib_buffer_advance 
155               (b0, sizeof(*ip6_0)+sizeof(udp_header_t)+sizeof(*vxlan0));
156             vlib_buffer_advance
157               (b1, sizeof(*ip6_1)+sizeof(udp_header_t)+sizeof(*vxlan1));
158           }
159
160           tunnel_index0 = ~0;
161           error0 = 0;
162
163           tunnel_index1 = ~0;
164           error1 = 0;
165
166           if (is_ip4) {
167             key4_0.src = ip4_0->src_address.as_u32;
168             key4_0.vni = vxlan0->vni_reserved;
169
170             if (PREDICT_FALSE (key4_0.as_u64 != last_key4.as_u64))
171               {
172                 p0 = hash_get (vxm->vxlan4_tunnel_by_key, key4_0.as_u64);
173
174                 if (p0 == 0)
175                   {
176                     error0 = VXLAN_ERROR_NO_SUCH_TUNNEL;
177                     next0 = VXLAN_INPUT_NEXT_DROP;
178                     goto trace0;
179                   }
180
181                 last_key4.as_u64 = key4_0.as_u64;
182                 tunnel_index0 = last_tunnel_index = p0[0];
183               }
184             else
185               tunnel_index0 = last_tunnel_index;
186           } else /* !is_ip4 */ {
187             key6_0.src.as_u64[0] = ip6_0->src_address.as_u64[0];
188             key6_0.src.as_u64[1] = ip6_0->src_address.as_u64[1];
189             key6_0.vni = vxlan0->vni_reserved;
190
191             if (PREDICT_FALSE (memcmp(&key6_0, &last_key6, sizeof(last_key6)) != 0))
192               {
193                 p0 = hash_get_mem (vxm->vxlan6_tunnel_by_key, &key6_0);
194
195                 if (p0 == 0)
196                   {
197                     error0 = VXLAN_ERROR_NO_SUCH_TUNNEL;
198                     next0 = VXLAN_INPUT_NEXT_DROP;
199                     goto trace0;
200                   }
201
202                 clib_memcpy (&last_key6, &key6_0, sizeof(key6_0));
203                 tunnel_index0 = last_tunnel_index = p0[0];
204               }
205             else
206               tunnel_index0 = last_tunnel_index;
207           }
208
209           t0 = pool_elt_at_index (vxm->tunnels, tunnel_index0);
210
211           next0 = t0->decap_next_index;
212           sw_if_index0 = t0->sw_if_index;
213           len0 = vlib_buffer_length_in_chain (vm, b0);
214
215           /* Required to make the l2 tag push / pop code work on l2 subifs */
216           if (PREDICT_TRUE(next0 == VXLAN_INPUT_NEXT_L2_INPUT))
217             vnet_update_l2_len (b0);
218
219           /* Set input sw_if_index to VXLAN tunnel for learning */
220           vnet_buffer(b0)->sw_if_index[VLIB_RX] = sw_if_index0;
221
222           pkts_decapsulated ++;
223           stats_n_packets += 1;
224           stats_n_bytes += len0;
225
226           /* Batch stats increment on the same vxlan tunnel so counter
227              is not incremented per packet */
228           if (PREDICT_FALSE (sw_if_index0 != stats_sw_if_index)) 
229             {
230               stats_n_packets -= 1;
231               stats_n_bytes -= len0;
232               if (stats_n_packets)
233                 vlib_increment_combined_counter 
234                   (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX,
235                    cpu_index, stats_sw_if_index, 
236                    stats_n_packets, stats_n_bytes);
237               stats_n_packets = 1;
238               stats_n_bytes = len0;
239               stats_sw_if_index = sw_if_index0;
240             }
241
242         trace0:
243           b0->error = error0 ? node->errors[error0] : 0;
244
245           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
246             {
247               vxlan_rx_trace_t *tr 
248                 = vlib_add_trace (vm, node, b0, sizeof (*tr));
249               tr->next_index = next0;
250               tr->error = error0;
251               tr->tunnel_index = tunnel_index0;
252               tr->vni = vnet_get_vni (vxlan0);
253             }
254
255
256           if (is_ip4) {
257             key4_1.src = ip4_1->src_address.as_u32;
258             key4_1.vni = vxlan1->vni_reserved;
259
260             if (PREDICT_FALSE (key4_1.as_u64 != last_key4.as_u64))
261               {
262                 p1 = hash_get (vxm->vxlan4_tunnel_by_key, key4_1.as_u64);
263
264                 if (p1 == 0)
265                   {
266                     error1 = VXLAN_ERROR_NO_SUCH_TUNNEL;
267                     next1 = VXLAN_INPUT_NEXT_DROP;
268                     goto trace1;
269                   }
270
271                 last_key4.as_u64 = key4_1.as_u64;
272                 tunnel_index1 = last_tunnel_index = p1[0];
273               }
274             else
275               tunnel_index1 = last_tunnel_index;
276           } else /* !is_ip4 */ {
277             key6_1.src.as_u64[0] = ip6_1->src_address.as_u64[0];
278             key6_1.src.as_u64[1] = ip6_1->src_address.as_u64[1];
279             key6_1.vni = vxlan1->vni_reserved;
280
281             if (PREDICT_FALSE (memcmp(&key6_1, &last_key6, sizeof(last_key6)) != 0))
282               {
283                 p1 = hash_get_mem (vxm->vxlan6_tunnel_by_key, &key6_1);
284
285                 if (p1 == 0)
286                   {
287                     error1 = VXLAN_ERROR_NO_SUCH_TUNNEL;
288                     next1 = VXLAN_INPUT_NEXT_DROP;
289                     goto trace1;
290                   }
291
292                 clib_memcpy (&last_key6, &key6_1, sizeof(key6_1));
293                 tunnel_index1 = last_tunnel_index = p1[0];
294               }
295             else
296               tunnel_index1 = last_tunnel_index;
297           }
298
299           t1 = pool_elt_at_index (vxm->tunnels, tunnel_index1);
300
301           next1 = t1->decap_next_index;
302           sw_if_index1 = t1->sw_if_index;
303           len1 = vlib_buffer_length_in_chain (vm, b1);
304
305           /* Required to make the l2 tag push / pop code work on l2 subifs */
306           if (PREDICT_TRUE(next1 == VXLAN_INPUT_NEXT_L2_INPUT))
307             vnet_update_l2_len (b1);
308
309           /* Set input sw_if_index to VXLAN tunnel for learning */
310           vnet_buffer(b1)->sw_if_index[VLIB_RX] = sw_if_index1;
311
312           pkts_decapsulated ++;
313           stats_n_packets += 1;
314           stats_n_bytes += len1;
315
316           /* Batch stats increment on the same vxlan tunnel so counter
317              is not incremented per packet */
318           if (PREDICT_FALSE (sw_if_index1 != stats_sw_if_index)) 
319             {
320               stats_n_packets -= 1;
321               stats_n_bytes -= len1;
322               if (stats_n_packets)
323                 vlib_increment_combined_counter 
324                   (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX,
325                    cpu_index, stats_sw_if_index, 
326                    stats_n_packets, stats_n_bytes);
327               stats_n_packets = 1;
328               stats_n_bytes = len1;
329               stats_sw_if_index = sw_if_index1;
330             }
331
332         trace1:
333           b1->error = error1 ? node->errors[error1] : 0;
334
335           if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED)) 
336             {
337               vxlan_rx_trace_t *tr 
338                 = vlib_add_trace (vm, node, b1, sizeof (*tr));
339               tr->next_index = next1;
340               tr->error = error1;
341               tr->tunnel_index = tunnel_index1;
342               tr->vni = vnet_get_vni (vxlan1);
343             }
344
345           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
346                                            to_next, n_left_to_next,
347                                            bi0, bi1, next0, next1);
348         }
349
350       while (n_left_from > 0 && n_left_to_next > 0)
351         {
352           u32 bi0;
353           vlib_buffer_t * b0;
354           u32 next0;
355           ip4_header_t * ip4_0;
356           ip6_header_t * ip6_0;
357           vxlan_header_t * vxlan0;
358           uword * p0;
359           u32 tunnel_index0;
360           vxlan_tunnel_t * t0;
361           vxlan4_tunnel_key_t key4_0;
362           vxlan6_tunnel_key_t key6_0;
363           u32 error0;
364           u32 sw_if_index0, len0;
365
366           bi0 = from[0];
367           to_next[0] = bi0;
368           from += 1;
369           to_next += 1;
370           n_left_from -= 1;
371           n_left_to_next -= 1;
372
373           b0 = vlib_get_buffer (vm, bi0);
374
375           /* udp leaves current_data pointing at the vxlan header */
376           vxlan0 = vlib_buffer_get_current (b0);
377
378           if (is_ip4) {
379           vlib_buffer_advance 
380             (b0, -(word)(sizeof(udp_header_t)+sizeof(ip4_header_t)));
381             ip4_0 = vlib_buffer_get_current (b0);
382           } else {
383             vlib_buffer_advance
384               (b0, -(word)(sizeof(udp_header_t)+sizeof(ip6_header_t)));
385             ip6_0 = vlib_buffer_get_current (b0);
386           }
387
388           /* pop (ip, udp, vxlan) */
389           if (is_ip4) {
390             vlib_buffer_advance
391               (b0, sizeof(*ip4_0)+sizeof(udp_header_t)+sizeof(*vxlan0));
392           } else {
393           vlib_buffer_advance 
394               (b0, sizeof(*ip6_0)+sizeof(udp_header_t)+sizeof(*vxlan0));
395           }
396
397           tunnel_index0 = ~0;
398           error0 = 0;
399
400           if (is_ip4) {
401             key4_0.src = ip4_0->src_address.as_u32;
402             key4_0.vni = vxlan0->vni_reserved;
403
404             if (PREDICT_FALSE (key4_0.as_u64 != last_key4.as_u64))
405               {
406                 p0 = hash_get (vxm->vxlan4_tunnel_by_key, key4_0.as_u64);
407
408                 if (p0 == 0)
409                   {
410                     error0 = VXLAN_ERROR_NO_SUCH_TUNNEL;
411                     next0 = VXLAN_INPUT_NEXT_DROP;
412                     goto trace00;
413                   }
414
415                 last_key4.as_u64 = key4_0.as_u64;
416                 tunnel_index0 = last_tunnel_index = p0[0];
417               }
418             else
419               tunnel_index0 = last_tunnel_index;
420           } else /* !is_ip4 */ {
421             key6_0.src.as_u64[0] = ip6_0->src_address.as_u64[0];
422             key6_0.src.as_u64[1] = ip6_0->src_address.as_u64[1];
423             key6_0.vni = vxlan0->vni_reserved;
424
425             if (PREDICT_FALSE (memcmp(&key6_0, &last_key6, sizeof(last_key6)) != 0))
426               {
427                 p0 = hash_get_mem (vxm->vxlan6_tunnel_by_key, &key6_0);
428
429                 if (p0 == 0)
430                   {
431                     error0 = VXLAN_ERROR_NO_SUCH_TUNNEL;
432                     next0 = VXLAN_INPUT_NEXT_DROP;
433                     goto trace00;
434                   }
435
436                 clib_memcpy (&last_key6, &key6_0, sizeof(key6_0));
437                 tunnel_index0 = last_tunnel_index = p0[0];
438               }
439             else
440               tunnel_index0 = last_tunnel_index;
441           }
442
443           t0 = pool_elt_at_index (vxm->tunnels, tunnel_index0);
444
445           next0 = t0->decap_next_index;
446           sw_if_index0 = t0->sw_if_index;
447           len0 = vlib_buffer_length_in_chain (vm, b0);
448
449           /* Required to make the l2 tag push / pop code work on l2 subifs */
450           if (PREDICT_TRUE(next0 == VXLAN_INPUT_NEXT_L2_INPUT))
451             vnet_update_l2_len (b0);
452
453           /* Set input sw_if_index to VXLAN tunnel for learning */
454           vnet_buffer(b0)->sw_if_index[VLIB_RX] = sw_if_index0;
455
456           pkts_decapsulated ++;
457           stats_n_packets += 1;
458           stats_n_bytes += len0;
459
460           /* Batch stats increment on the same vxlan tunnel so counter
461              is not incremented per packet */
462           if (PREDICT_FALSE (sw_if_index0 != stats_sw_if_index)) 
463             {
464               stats_n_packets -= 1;
465               stats_n_bytes -= len0;
466               if (stats_n_packets)
467                 vlib_increment_combined_counter 
468                   (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX,
469                    cpu_index, stats_sw_if_index, 
470                    stats_n_packets, stats_n_bytes);
471               stats_n_packets = 1;
472               stats_n_bytes = len0;
473               stats_sw_if_index = sw_if_index0;
474             }
475
476         trace00:
477           b0->error = error0 ? node->errors[error0] : 0;
478
479           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
480             {
481               vxlan_rx_trace_t *tr 
482                 = vlib_add_trace (vm, node, b0, sizeof (*tr));
483               tr->next_index = next0;
484               tr->error = error0;
485               tr->tunnel_index = tunnel_index0;
486               tr->vni = vnet_get_vni (vxlan0);
487             }
488           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
489                                            to_next, n_left_to_next,
490                                            bi0, next0);
491         }
492
493       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
494     }
495   /* Do we still need this now that tunnel tx stats is kept? */
496   vlib_node_increment_counter (vm, vxlan_input_node.index,
497                                VXLAN_ERROR_DECAPSULATED, 
498                                pkts_decapsulated);
499
500   /* Increment any remaining batch stats */
501   if (stats_n_packets)
502     {
503       vlib_increment_combined_counter 
504         (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX,
505          cpu_index, stats_sw_if_index, stats_n_packets, stats_n_bytes);
506       node->runtime_data[0] = stats_sw_if_index;
507     }
508
509   return from_frame->n_vectors;
510 }
511
512 static uword
513 vxlan4_input (vlib_main_t * vm,
514              vlib_node_runtime_t * node,
515              vlib_frame_t * from_frame)
516 {
517         return vxlan_input(vm, node, from_frame, /* is_ip4 */ 1);
518 }
519
520 static uword
521 vxlan6_input (vlib_main_t * vm,
522              vlib_node_runtime_t * node,
523              vlib_frame_t * from_frame)
524 {
525         return vxlan_input(vm, node, from_frame, /* is_ip4 */ 0);
526 }
527
528 static char * vxlan_error_strings[] = {
529 #define vxlan_error(n,s) s,
530 #include <vnet/vxlan/vxlan_error.def>
531 #undef vxlan_error
532 #undef _
533 };
534
535 VLIB_REGISTER_NODE (vxlan4_input_node) = {
536   .function = vxlan4_input,
537   .name = "vxlan4-input",
538   /* Takes a vector of packets. */
539   .vector_size = sizeof (u32),
540
541   .n_errors = VXLAN_N_ERROR,
542   .error_strings = vxlan_error_strings,
543
544   .n_next_nodes = VXLAN_INPUT_N_NEXT,
545   .next_nodes = {
546 #define _(s,n) [VXLAN_INPUT_NEXT_##s] = n,
547     foreach_vxlan_input_next
548 #undef _
549   },
550
551 //temp  .format_buffer = format_vxlan_header,
552   .format_trace = format_vxlan_rx_trace,
553   // $$$$ .unformat_buffer = unformat_vxlan_header,
554 };
555
556 VLIB_NODE_FUNCTION_MULTIARCH (vxlan4_input_node, vxlan4_input)
557
558 VLIB_REGISTER_NODE (vxlan6_input_node) = {
559   .function = vxlan6_input,
560   .name = "vxlan6-input",
561   /* Takes a vector of packets. */
562   .vector_size = sizeof (u32),
563
564   .n_errors = VXLAN_N_ERROR,
565   .error_strings = vxlan_error_strings,
566
567   .n_next_nodes = VXLAN_INPUT_N_NEXT,
568   .next_nodes = {
569 #define _(s,n) [VXLAN_INPUT_NEXT_##s] = n,
570     foreach_vxlan_input_next
571 #undef _
572   },
573
574 //temp  .format_buffer = format_vxlan_header,
575   .format_trace = format_vxlan_rx_trace,
576   // $$$$ .unformat_buffer = unformat_vxlan_header,
577 };
578
579 VLIB_NODE_FUNCTION_MULTIARCH (vxlan6_input_node, vxlan6_input)
580