f00977c8cd609ec3c0d5b6a2586456979d092c04
[vpp.git] / vnet / vnet / gre / gre.c
1 /*
2  * gre.c: gre
3  *
4  * Copyright (c) 2012 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 <vnet/vnet.h>
19 #include <vnet/gre/gre.h>
20
21 gre_main_t gre_main;
22
23 typedef CLIB_PACKED (struct {
24   ip4_header_t ip4;
25   gre_header_t gre;
26 }) ip4_and_gre_header_t;
27
28 typedef struct {
29   union {
30     ip4_and_gre_header_t ip4_and_gre;
31     u64 as_u64[3];
32   };
33 } ip4_and_gre_union_t;
34
35
36 /* Packet trace structure */
37 typedef struct {
38   /* Tunnel-id / index in tunnel vector */
39   u32 tunnel_id;
40
41   /* pkt length */
42   u32 length;
43
44   /* tunnel ip4 addresses */
45   ip4_address_t src;
46   ip4_address_t dst;
47 } gre_tx_trace_t;
48
49 u8 * format_gre_tx_trace (u8 * s, va_list * args)
50 {
51   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
52   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
53   gre_tx_trace_t * t = va_arg (*args, gre_tx_trace_t *);
54     
55   s = format (s, "GRE: tunnel %d len %d src %U dst %U",
56               t->tunnel_id, clib_net_to_host_u16 (t->length),
57               format_ip4_address, &t->src.as_u8,
58               format_ip4_address, &t->dst.as_u8);
59   return s;
60 }
61
62 u8 * format_gre_protocol (u8 * s, va_list * args)
63 {
64   gre_protocol_t p = va_arg (*args, u32);
65   gre_main_t * gm = &gre_main;
66   gre_protocol_info_t * pi = gre_get_protocol_info (gm, p);
67
68   if (pi)
69     s = format (s, "%s", pi->name);
70   else
71     s = format (s, "0x%04x", p);
72
73   return s;
74 }
75
76 u8 * format_gre_header_with_length (u8 * s, va_list * args)
77 {
78   gre_main_t * gm = &gre_main;
79   gre_header_t * h = va_arg (*args, gre_header_t *);
80   u32 max_header_bytes = va_arg (*args, u32);
81   gre_protocol_t p = clib_net_to_host_u16 (h->protocol);
82   uword indent, header_bytes;
83
84   header_bytes = sizeof (h[0]);
85   if (max_header_bytes != 0 && header_bytes > max_header_bytes)
86     return format (s, "gre header truncated");
87
88   indent = format_get_indent (s);
89
90   s = format (s, "GRE %U", format_gre_protocol, p);
91
92   if (max_header_bytes != 0 && header_bytes > max_header_bytes)
93     {
94       gre_protocol_info_t * pi = gre_get_protocol_info (gm, p);
95       vlib_node_t * node = vlib_get_node (gm->vlib_main, pi->node_index);
96       if (node->format_buffer)
97         s = format (s, "\n%U%U",
98                     format_white_space, indent,
99                     node->format_buffer, (void *) (h + 1),
100                     max_header_bytes - header_bytes);
101     }
102
103   return s;
104 }
105
106 u8 * format_gre_header (u8 * s, va_list * args)
107 {
108   gre_header_t * h = va_arg (*args, gre_header_t *);
109   return format (s, "%U", format_gre_header_with_length, h, 0);
110 }
111
112 /* Returns gre protocol as an int in host byte order. */
113 uword
114 unformat_gre_protocol_host_byte_order (unformat_input_t * input,
115                                        va_list * args)
116 {
117   u16 * result = va_arg (*args, u16 *);
118   gre_main_t * gm = &gre_main;
119   int i;
120
121   /* Named type. */
122   if (unformat_user (input, unformat_vlib_number_by_name,
123                      gm->protocol_info_by_name, &i))
124     {
125       gre_protocol_info_t * pi = vec_elt_at_index (gm->protocol_infos, i);
126       *result = pi->protocol;
127       return 1;
128     }
129
130   return 0;
131 }
132
133 uword
134 unformat_gre_protocol_net_byte_order (unformat_input_t * input,
135                                       va_list * args)
136 {
137   u16 * result = va_arg (*args, u16 *);
138   if (! unformat_user (input, unformat_gre_protocol_host_byte_order, result))
139     return 0;
140   *result = clib_host_to_net_u16 ((u16) *result);
141   return 1;
142 }
143
144 uword
145 unformat_gre_header (unformat_input_t * input, va_list * args)
146 {
147   u8 ** result = va_arg (*args, u8 **);
148   gre_header_t _h, * h = &_h;
149   u16 p;
150
151   if (! unformat (input, "%U",
152                   unformat_gre_protocol_host_byte_order, &p))
153     return 0;
154
155   h->protocol = clib_host_to_net_u16 (p);
156
157   /* Add header to result. */
158   {
159     void * p;
160     u32 n_bytes = sizeof (h[0]);
161
162     vec_add2 (*result, p, n_bytes);
163     clib_memcpy (p, h, n_bytes);
164   }
165   
166   return 1;
167 }
168
169 static uword gre_set_rewrite (vnet_main_t * vnm,
170                                u32 sw_if_index,
171                                u32 l3_type,
172                                void * dst_address,
173                                void * rewrite,
174                                uword max_rewrite_bytes)
175 {
176   /*
177    * Conundrum: packets from tun/tap destined for the tunnel
178    * actually have this rewrite applied. Transit packets do not.
179    * To make the two cases equivalent, don't generate a
180    * rewrite here, build the entire header in the fast path.
181    */
182   return 0;
183
184 #ifdef THINGS_WORKED_AS_ONE_MIGHT_LIKE
185   ip4_and_gre_header_t * h = rewrite;
186   gre_protocol_t protocol;
187
188   if (max_rewrite_bytes < sizeof (h[0]))
189     return 0;
190
191   switch (l3_type) {
192 #define _(a,b) case VNET_L3_PACKET_TYPE_##a: protocol = GRE_PROTOCOL_##b; break
193     _ (IP4, ip4);
194     _ (IP6, ip6);
195 #undef _
196   default:
197     return 0;
198   }
199
200   memset (h, 0, sizeof (*h));
201   h->ip4.ip_version_and_header_length = 0x45;
202   h->ip4.ttl = 64;
203   h->ip4.protocol = IP_PROTOCOL_GRE;
204   h->gre.protocol = clib_host_to_net_u16 (protocol);
205                      
206   return sizeof (h[0]);
207 #endif  
208 }
209
210 static uword
211 gre_interface_tx (vlib_main_t * vm,
212                   vlib_node_runtime_t * node,
213                   vlib_frame_t * frame)
214 {
215   gre_main_t * gm = &gre_main;
216   u32 next_index;
217   u32 * from, * to_next, n_left_from, n_left_to_next;
218   vnet_interface_output_runtime_t * rd = (void *) node->runtime_data;
219   gre_tunnel_t *t = pool_elt_at_index (gm->tunnels, rd->dev_instance);
220
221   /* Vector of buffer / pkt indices we're supposed to process */
222   from = vlib_frame_vector_args (frame);
223
224   /* Number of buffers / pkts */
225   n_left_from = frame->n_vectors;   
226
227   /* Speculatively send the first buffer to the last disposition we used */
228   next_index = node->cached_next_index;
229   
230   while (n_left_from > 0)
231     {
232       /* set up to enqueue to our disposition with index = next_index */
233       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
234
235       /* 
236        * As long as we have enough pkts left to process two pkts
237        * and prefetch two pkts...
238        */
239       while (n_left_from >= 4 && n_left_to_next >= 2)
240         {
241           vlib_buffer_t * b0, * b1;
242           ip4_header_t * ip0, * ip1;
243           ip4_and_gre_union_t * h0, * h1;
244           u32 bi0, next0, bi1, next1;
245           __attribute__((unused)) u8 error0, error1;
246           u16 gre_protocol0, gre_protocol1;
247       
248           /* Prefetch the next iteration */
249           {
250             vlib_buffer_t * p2, * p3;
251
252             p2 = vlib_get_buffer (vm, from[2]);
253             p3 = vlib_get_buffer (vm, from[3]);
254
255             vlib_prefetch_buffer_header (p2, LOAD);
256             vlib_prefetch_buffer_header (p3, LOAD);
257
258             /* 
259              * Prefetch packet data. We expect to overwrite
260              * the inbound L2 header with an ip header and a
261              * gre header. Might want to prefetch the last line
262              * of rewrite space as well; need profile data
263              */
264             CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
265             CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
266           }
267
268           /* Pick up the next two buffer indices */
269           bi0 = from[0];
270           bi1 = from[1];
271
272           /* Speculatively enqueue them where we sent the last buffer */
273           to_next[0] = bi0;
274           to_next[1] = bi1;
275           from += 2;
276           to_next += 2;
277           n_left_to_next -= 2;
278           n_left_from -= 2;
279       
280           b0 = vlib_get_buffer (vm, bi0);
281           b1 = vlib_get_buffer (vm, bi1);
282
283           vnet_buffer (b0)->sw_if_index[VLIB_TX] = t->outer_fib_index;
284           vnet_buffer (b1)->sw_if_index[VLIB_TX] = t->outer_fib_index;
285
286           if (PREDICT_FALSE(t->teb))
287           {
288             gre_protocol0 = clib_net_to_host_u16(GRE_PROTOCOL_teb);
289             gre_protocol1 = clib_net_to_host_u16(GRE_PROTOCOL_teb);
290           }
291           else
292           {
293             ip0 = vlib_buffer_get_current (b0);
294             gre_protocol0 = clib_net_to_host_u16 (0x800);
295             gre_protocol0 =
296                 ((ip0->ip_version_and_header_length & 0xF0) == 0x60) ?
297                 0x86DD : gre_protocol0;
298
299             ip1 = vlib_buffer_get_current (b1);
300             gre_protocol1 = clib_net_to_host_u16 (0x800);
301             gre_protocol1 =
302                 ((ip1->ip_version_and_header_length & 0xF0) == 0x60) ?
303                 0x86DD : gre_protocol1;
304           }
305
306           vlib_buffer_advance (b0, -sizeof(*h0));
307           vlib_buffer_advance (b1, -sizeof(*h1));
308
309           h0 = vlib_buffer_get_current (b0);
310           h1 = vlib_buffer_get_current (b1);
311           h0->as_u64[0] = 0;
312           h0->as_u64[1] = 0;
313           h0->as_u64[2] = 0;
314
315           h1->as_u64[0] = 0;
316           h1->as_u64[1] = 0;
317           h1->as_u64[2] = 0;
318
319           ip0 = &h0->ip4_and_gre.ip4;
320           h0->ip4_and_gre.gre.protocol = gre_protocol0;
321           ip0->ip_version_and_header_length = 0x45;
322           ip0->ttl = 254;
323           ip0->protocol = IP_PROTOCOL_GRE;
324
325           ip1 = &h1->ip4_and_gre.ip4;
326           h1->ip4_and_gre.gre.protocol = gre_protocol1;
327           ip1->ip_version_and_header_length = 0x45;
328           ip1->ttl = 254;
329           ip1->protocol = IP_PROTOCOL_GRE;
330
331           ip0->length = 
332             clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
333           ip1->length = 
334             clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1));
335           ip0->src_address.as_u32 = t->tunnel_src.as_u32;
336           ip1->src_address.as_u32 = t->tunnel_src.as_u32;
337           ip0->dst_address.as_u32 = t->tunnel_dst.as_u32;
338           ip1->dst_address.as_u32 = t->tunnel_dst.as_u32;
339           ip0->checksum = ip4_header_checksum (ip0);
340           ip1->checksum = ip4_header_checksum (ip1);
341
342           /* ip4_lookup will route to the tunnel partner */
343           next0 = GRE_OUTPUT_NEXT_LOOKUP;
344           next1 = GRE_OUTPUT_NEXT_LOOKUP;
345           error0 = GRE_ERROR_NONE;
346           error1 = GRE_ERROR_NONE;
347
348           /* 
349            * Enqueue 2 pkts. This macro deals with next0 != next1,
350            * acquiring enqueue rights to the indicated next
351            * node input frame, etc.
352            */
353           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
354                                            to_next, n_left_to_next,
355                                            bi0, bi1, next0, next1);
356         }
357
358       while (n_left_from > 0 && n_left_to_next > 0)
359         {
360           vlib_buffer_t * b0;
361           ip4_header_t * ip0;
362           ip4_and_gre_union_t * h0;
363           u32 bi0, next0;
364           __attribute__((unused)) u8 error0;
365           u16 gre_protocol0;
366       
367           bi0 = to_next[0] = from[0];
368           from += 1;
369           n_left_from -= 1;
370           to_next += 1;
371           n_left_to_next -= 1;
372       
373           b0 = vlib_get_buffer (vm, bi0);
374
375           vnet_buffer (b0)->sw_if_index[VLIB_TX] = t->outer_fib_index;
376           ip0 = vlib_buffer_get_current (b0);
377           if (PREDICT_FALSE(t->teb))
378           {
379             gre_protocol0 = clib_net_to_host_u16(GRE_PROTOCOL_teb);
380           }
381           else
382           {
383             gre_protocol0 = clib_net_to_host_u16 (0x800);
384             gre_protocol0 =
385                 ((ip0->ip_version_and_header_length & 0xF0) == 0x60) ?
386                 0x86DD : gre_protocol0;
387           }
388
389           vlib_buffer_advance (b0, -sizeof(*h0));
390
391           h0 = vlib_buffer_get_current (b0);
392           h0->as_u64[0] = 0;
393           h0->as_u64[1] = 0;
394           h0->as_u64[2] = 0;
395
396           ip0 = &h0->ip4_and_gre.ip4;
397           h0->ip4_and_gre.gre.protocol = gre_protocol0;
398           ip0->ip_version_and_header_length = 0x45;
399           ip0->ttl = 254;
400           ip0->protocol = IP_PROTOCOL_GRE;
401           ip0->length = 
402             clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
403           ip0->src_address.as_u32 = t->tunnel_src.as_u32;
404           ip0->dst_address.as_u32 = t->tunnel_dst.as_u32;
405           ip0->checksum = ip4_header_checksum (ip0);
406
407           next0 = GRE_OUTPUT_NEXT_LOOKUP;
408           error0 = GRE_ERROR_NONE;
409
410           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
411             {
412               gre_tx_trace_t *tr = vlib_add_trace (vm, node, 
413                                                    b0, sizeof (*tr));
414               tr->tunnel_id = t - gm->tunnels;
415               tr->length = ip0->length;
416               tr->src.as_u32 = ip0->src_address.as_u32;
417               tr->dst.as_u32 = ip0->dst_address.as_u32;
418             }
419
420           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
421                                            to_next, n_left_to_next,
422                                            bi0, next0);
423         }
424   
425       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
426     }
427
428   vlib_node_increment_counter (vm, gre_input_node.index,
429                                GRE_ERROR_PKTS_ENCAP, frame->n_vectors);
430
431   return frame->n_vectors;
432 }
433
434 static clib_error_t *
435 gre_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
436 {
437   if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
438     vnet_hw_interface_set_flags (vnm, hw_if_index, VNET_HW_INTERFACE_FLAG_LINK_UP);
439   else
440     vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */);
441
442   return /* no error */ 0;
443 }
444
445 static u8 * format_gre_tunnel_name (u8 * s, va_list * args)
446 {
447   u32 dev_instance = va_arg (*args, u32);
448   return format (s, "gre%d", dev_instance);
449 }
450
451 static u8 * format_gre_device (u8 * s, va_list * args)
452 {
453   u32 dev_instance = va_arg (*args, u32);
454   CLIB_UNUSED (int verbose) = va_arg (*args, int);
455
456   s = format (s, "GRE tunnel: id %d\n", dev_instance);
457   return s;
458 }
459
460 VNET_DEVICE_CLASS (gre_device_class) = {
461   .name = "GRE tunnel device",
462   .format_device_name = format_gre_tunnel_name,
463   .format_device = format_gre_device,
464   .format_tx_trace = format_gre_tx_trace,
465   .tx_function = gre_interface_tx,
466   .admin_up_down_function = gre_interface_admin_up_down,
467 #ifdef SOON
468   .clear counter = 0;
469 #endif
470 };
471
472 VLIB_DEVICE_TX_FUNCTION_MULTIARCH (gre_device_class,
473                                    gre_interface_tx)
474
475
476 VNET_HW_INTERFACE_CLASS (gre_hw_interface_class) = {
477   .name = "GRE",
478   .format_header = format_gre_header_with_length,
479   .unformat_header = unformat_gre_header,
480   .set_rewrite = gre_set_rewrite,
481 };
482
483 static void add_protocol (gre_main_t * gm,
484                           gre_protocol_t protocol,
485                           char * protocol_name)
486 {
487   gre_protocol_info_t * pi;
488   u32 i;
489
490   vec_add2 (gm->protocol_infos, pi, 1);
491   i = pi - gm->protocol_infos;
492
493   pi->name = protocol_name;
494   pi->protocol = protocol;
495   pi->next_index = pi->node_index = ~0;
496
497   hash_set (gm->protocol_info_by_protocol, protocol, i);
498   hash_set_mem (gm->protocol_info_by_name, pi->name, i);
499 }
500
501 static clib_error_t * gre_init (vlib_main_t * vm)
502 {
503   gre_main_t * gm = &gre_main;
504   clib_error_t * error;
505   ip_main_t * im = &ip_main;
506   ip_protocol_info_t * pi;
507
508   memset (gm, 0, sizeof (gm[0]));
509   gm->vlib_main = vm;
510   gm->vnet_main = vnet_get_main();
511
512   if ((error = vlib_call_init_function (vm, ip_main_init)))
513     return error;
514
515   if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
516     return error;
517
518   /* Set up the ip packet generator */
519   pi = ip_get_protocol_info (im, IP_PROTOCOL_GRE);
520   pi->format_header = format_gre_header;
521   pi->unformat_pg_edit = unformat_pg_gre_header;
522
523   gm->protocol_info_by_name = hash_create_string (0, sizeof (uword));
524   gm->protocol_info_by_protocol = hash_create (0, sizeof (uword));
525   gm->tunnel_by_key = hash_create (0, sizeof (uword));
526
527 #define _(n,s) add_protocol (gm, GRE_PROTOCOL_##s, #s);
528   foreach_gre_protocol
529 #undef _
530
531   return vlib_call_init_function (vm, gre_input_init);
532 }
533
534 VLIB_INIT_FUNCTION (gre_init);
535
536 gre_main_t * gre_get_main (vlib_main_t * vm)
537 {
538   vlib_call_init_function (vm, gre_init);
539   return &gre_main;
540 }
541