Fix an issue in format_vxlan_gpe_tunnel
[vpp.git] / vnet / vnet / vxlan-gpe / vxlan_gpe.c
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/vxlan-gpe/vxlan_gpe.h>
16
17 vxlan_gpe_main_t vxlan_gpe_main;
18
19 u8 * format_vxlan_gpe_tunnel (u8 * s, va_list * args)
20 {
21   vxlan_gpe_tunnel_t * t = va_arg (*args, vxlan_gpe_tunnel_t *);
22   vxlan_gpe_main_t * gm = &vxlan_gpe_main;
23
24   s = format (s, "[%d] local: %U remote: %U ",
25               t - gm->tunnels,
26               format_ip4_address, &t->local,
27               format_ip4_address, &t->remote);    
28
29   switch (t->protocol)
30     {
31     case VXLAN_GPE_PROTOCOL_IP4:
32       s = format (s, "next-protocol ip4");
33       break;
34     case VXLAN_GPE_PROTOCOL_IP6:
35       s = format (s, "next-protocol ip6");
36       break;
37     case VXLAN_GPE_PROTOCOL_ETHERNET:
38       s = format (s, "next-protocol ethernet");
39       break;
40     case VXLAN_GPE_PROTOCOL_NSH:
41       s = format (s, "next-protocol nsh");
42       break;
43     default:
44       s = format (s, "next-protocol unknown %d", t->protocol);
45     }
46
47   s = format (s, " fibs: (encap %d, decap %d)",
48               t->encap_fib_index,
49               t->decap_fib_index);
50
51   s = format (s, "  vxlan VNI %d ", t->vni);
52
53   return s;
54 }
55
56 static u8 * format_vxlan_gpe_name (u8 * s, va_list * args)
57 {
58   vxlan_gpe_main_t * gm = &vxlan_gpe_main;
59   u32 i = va_arg (*args, u32);
60   u32 show_dev_instance = ~0;
61
62   if (i < vec_len (gm->dev_inst_by_real))
63     show_dev_instance = gm->dev_inst_by_real[i];
64
65   if (show_dev_instance != ~0)
66     i = show_dev_instance;
67
68   return format (s, "vxlan_gpe_tunnel%d", i);
69 }
70
71 static int vxlan_gpe_name_renumber (vnet_hw_interface_t * hi,
72                                         u32 new_dev_instance)
73 {
74   vxlan_gpe_main_t * gm = &vxlan_gpe_main;
75
76   vec_validate_init_empty (gm->dev_inst_by_real, hi->dev_instance, ~0);
77
78   gm->dev_inst_by_real [hi->dev_instance] = new_dev_instance;
79
80   return 0;
81 }
82
83 static uword dummy_interface_tx (vlib_main_t * vm,
84                                  vlib_node_runtime_t * node,
85                                  vlib_frame_t * frame)
86 {
87   clib_warning ("you shouldn't be here, leaking buffers...");
88   return frame->n_vectors;
89 }
90
91 static uword dummy_set_rewrite (vnet_main_t * vnm,
92                                 u32 sw_if_index,
93                                 u32 l3_type,
94                                 void * dst_address,
95                                 void * rewrite,
96                                 uword max_rewrite_bytes)
97 {
98   return 0;
99 }
100
101 VNET_DEVICE_CLASS (vxlan_gpe_device_class,static) = {
102   .name = "VXLAN_GPE",
103   .format_device_name = format_vxlan_gpe_name,
104   .format_tx_trace = format_vxlan_gpe_encap_trace,
105   .tx_function = dummy_interface_tx,
106   .name_renumber = vxlan_gpe_name_renumber,
107 };
108
109 static u8 * format_vxlan_gpe_header_with_length (u8 * s, va_list * args)
110 {
111   u32 dev_instance = va_arg (*args, u32);
112   s = format (s, "unimplemented dev %u", dev_instance);
113   return s;
114 }
115
116 VNET_HW_INTERFACE_CLASS (vxlan_gpe_hw_class) = {
117   .name = "VXLAN_GPE",
118   .format_header = format_vxlan_gpe_header_with_length,
119   .set_rewrite = dummy_set_rewrite,
120 };
121
122
123 #define foreach_gpe_copy_field                  \
124 _(local.as_u32)                                 \
125 _(remote.as_u32)                                \
126 _(vni)                                          \
127 _(protocol)                                \
128 _(encap_fib_index)                              \
129 _(decap_fib_index)                              
130
131 #define foreach_copy_field                      \
132 _(src.as_u32)                                   \
133 _(dst.as_u32)                                   \
134 _(vni)                                          \
135 _(encap_fib_index)                              \
136 _(decap_fib_index)                              \
137 _(decap_next_index)
138
139
140
141 static int vxlan_gpe_rewrite (vxlan_gpe_tunnel_t * t)
142 {
143   u8 *rw = 0;
144   ip4_header_t * ip0;
145   ip4_vxlan_gpe_header_t * h0;
146   int len;
147
148   len = sizeof (*h0);
149
150   vec_validate_aligned (rw, len-1, CLIB_CACHE_LINE_BYTES);
151
152   h0 = (ip4_vxlan_gpe_header_t *) rw;
153
154   /* Fixed portion of the (outer) ip4 header */
155   ip0 = &h0->ip4;
156   ip0->ip_version_and_header_length = 0x45;
157   ip0->ttl = 254;
158   ip0->protocol = IP_PROTOCOL_UDP;
159
160   /* we fix up the ip4 header length and checksum after-the-fact */
161   ip0->src_address.as_u32 = t->local.as_u32; 
162   ip0->dst_address.as_u32 = t->remote.as_u32; 
163   ip0->checksum = ip4_header_checksum (ip0);
164
165   /* UDP header, randomize src port on something, maybe? */
166   h0->udp.src_port = clib_host_to_net_u16 (4790);
167   h0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_vxlan_gpe);
168
169   /* VXLAN header. Are we having fun yet? */
170   h0->vxlan.flags = VXLAN_GPE_FLAGS_I | VXLAN_GPE_FLAGS_P;
171   h0->vxlan.ver_res = VXLAN_GPE_VERSION;
172   h0->vxlan.protocol = VXLAN_GPE_PROTOCOL_IP4;
173   h0->vxlan.vni_res = clib_host_to_net_u32 (t->vni<<8);
174
175   t->rewrite = rw;
176   return (0);
177 }
178
179 int vnet_vxlan_gpe_add_del_tunnel 
180 (vnet_vxlan_gpe_add_del_tunnel_args_t *a, u32 * sw_if_indexp)
181 {
182   vxlan_gpe_main_t * gm = &vxlan_gpe_main;
183   vxlan_gpe_tunnel_t *t = 0;
184   vnet_main_t * vnm = gm->vnet_main;
185   vnet_hw_interface_t * hi;
186   uword * p;
187   u32 hw_if_index = ~0;
188   u32 sw_if_index = ~0;
189   int rv;
190   vxlan_gpe_tunnel_key_t key, *key_copy;
191   hash_pair_t *hp;
192   
193   key.local = a->local.as_u32; 
194   key.remote = a->remote.as_u32; 
195   key.vni = clib_host_to_net_u32 (a->vni << 8);
196   key.pad = 0;
197
198   p = hash_get_mem (gm->vxlan_gpe_tunnel_by_key, &key);
199   
200   if (a->is_add)
201     {
202       /* adding a tunnel: tunnel must not already exist */
203       if (p) 
204         return VNET_API_ERROR_INVALID_VALUE;
205       
206       if (a->decap_next_index >= VXLAN_GPE_INPUT_N_NEXT)
207         return VNET_API_ERROR_INVALID_DECAP_NEXT;
208       
209       pool_get_aligned (gm->tunnels, t, CLIB_CACHE_LINE_BYTES);
210       memset (t, 0, sizeof (*t));
211       
212       /* copy from arg structure */
213 #define _(x) t->x = a->x;
214       foreach_gpe_copy_field;
215 #undef _
216
217       rv = vxlan_gpe_rewrite (t);
218
219       if (rv)
220         {
221           pool_put (gm->tunnels, t);
222           return rv;
223         }
224
225       key_copy = clib_mem_alloc (sizeof (*key_copy));
226       clib_memcpy (key_copy, &key, sizeof (*key_copy));
227
228       hash_set_mem (gm->vxlan_gpe_tunnel_by_key, key_copy, 
229                     t - gm->tunnels);
230       
231       if (vec_len (gm->free_vxlan_gpe_tunnel_hw_if_indices) > 0)
232         {
233           hw_if_index = gm->free_vxlan_gpe_tunnel_hw_if_indices
234             [vec_len (gm->free_vxlan_gpe_tunnel_hw_if_indices)-1];
235           _vec_len (gm->free_vxlan_gpe_tunnel_hw_if_indices) -= 1;
236           
237           hi = vnet_get_hw_interface (vnm, hw_if_index);
238           hi->dev_instance = t - gm->tunnels;
239           hi->hw_instance = hi->dev_instance;
240         }
241       else 
242         {
243           hw_if_index = vnet_register_interface
244             (vnm, vxlan_gpe_device_class.index, t - gm->tunnels,
245              vxlan_gpe_hw_class.index, t - gm->tunnels);
246           hi = vnet_get_hw_interface (vnm, hw_if_index);
247           hi->output_node_index = vxlan_gpe_encap_node.index;
248         }
249       
250       t->hw_if_index = hw_if_index;
251       t->sw_if_index = sw_if_index = hi->sw_if_index;
252       
253       vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 
254                                    VNET_SW_INTERFACE_FLAG_ADMIN_UP);
255     }
256   else
257     {
258       /* deleting a tunnel: tunnel must exist */
259       if (!p) 
260         return VNET_API_ERROR_NO_SUCH_ENTRY;
261
262       t = pool_elt_at_index (gm->tunnels, p[0]);
263
264       vnet_sw_interface_set_flags (vnm, t->sw_if_index, 0 /* down */);
265       vec_add1 (gm->free_vxlan_gpe_tunnel_hw_if_indices, t->hw_if_index);
266
267       hp = hash_get_pair (gm->vxlan_gpe_tunnel_by_key, &key);
268       key_copy = (void *)(hp->key);
269       hash_unset_mem (gm->vxlan_gpe_tunnel_by_key, &key);
270       clib_mem_free (key_copy);
271
272       vec_free (t->rewrite);
273       pool_put (gm->tunnels, t);
274     }
275
276   if (sw_if_indexp)
277       *sw_if_indexp = sw_if_index;
278
279   return 0;
280 }
281
282 static u32 fib_index_from_fib_id (u32 fib_id)
283 {
284   ip4_main_t * im = &ip4_main;
285   uword * p;
286
287   p = hash_get (im->fib_index_by_table_id, fib_id);
288   if (!p)
289     return ~0;
290
291   return p[0];
292 }
293
294 static uword unformat_gpe_decap_next (unformat_input_t * input, va_list * args)
295 {
296   u32 * result = va_arg (*args, u32 *);
297   u32 tmp;
298   
299   if (unformat (input, "drop"))
300     *result = VXLAN_GPE_INPUT_NEXT_DROP;
301   else if (unformat (input, "ip4"))
302     *result = VXLAN_GPE_INPUT_NEXT_IP4_INPUT;
303   else if (unformat (input, "ip6"))
304     *result = VXLAN_GPE_INPUT_NEXT_IP6_INPUT;
305   else if (unformat (input, "ethernet"))
306     *result = VXLAN_GPE_INPUT_NEXT_ETHERNET_INPUT;
307   else if (unformat (input, "%d", &tmp))
308     *result = tmp;
309   else
310     return 0;
311   return 1;
312 }
313
314 static clib_error_t *
315 vxlan_gpe_add_del_tunnel_command_fn (vlib_main_t * vm,
316                                    unformat_input_t * input,
317                                    vlib_cli_command_t * cmd)
318 {
319   unformat_input_t _line_input, * line_input = &_line_input;
320   u8 is_add = 1;
321   ip4_address_t local, remote;
322   u8 local_set = 0;
323   u8 remote_set = 0;
324   u32 encap_fib_index = 0;
325   u32 decap_fib_index = 0;
326   u8 protocol = VXLAN_GPE_PROTOCOL_IP4;
327   u32 decap_next_index = VXLAN_GPE_INPUT_NEXT_IP4_INPUT; 
328   u32 vni;
329   u8 vni_set = 0;
330   int rv;
331   u32 tmp;
332   vnet_vxlan_gpe_add_del_tunnel_args_t _a, * a = &_a;
333   u32 sw_if_index;
334   
335   /* Get a line of input. */
336   if (! unformat_user (input, unformat_line_input, line_input))
337     return 0;
338
339   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
340     if (unformat (line_input, "del"))
341       is_add = 0;
342     else if (unformat (line_input, "local %U", 
343                        unformat_ip4_address, &local))
344       local_set = 1;
345     else if (unformat (line_input, "remote %U",
346                        unformat_ip4_address, &remote))
347       remote_set = 1;
348     else if (unformat (line_input, "encap-vrf-id %d", &tmp))
349       {
350         encap_fib_index = fib_index_from_fib_id (tmp);
351         if (encap_fib_index == ~0)
352           return clib_error_return (0, "nonexistent encap fib id %d", tmp);
353       }
354     else if (unformat (line_input, "decap-vrf-id %d", &tmp))
355       {
356         decap_fib_index = fib_index_from_fib_id (tmp);
357         if (decap_fib_index == ~0)
358           return clib_error_return (0, "nonexistent decap fib id %d", tmp);
359       }
360     else if (unformat (line_input, "decap-next %U", unformat_gpe_decap_next, 
361                        &decap_next_index))
362       ;
363     else if (unformat (line_input, "vni %d", &vni))
364       vni_set = 1;
365     else if (unformat(line_input, "next-ip4"))
366       protocol = VXLAN_GPE_PROTOCOL_IP4;
367     else if (unformat(line_input, "next-ip6"))
368       protocol = VXLAN_GPE_PROTOCOL_IP6;
369     else if (unformat(line_input, "next-ethernet"))
370       protocol = VXLAN_GPE_PROTOCOL_ETHERNET;
371     else if (unformat(line_input, "next-nsh"))
372       protocol = VXLAN_GPE_PROTOCOL_NSH;
373     else 
374       return clib_error_return (0, "parse error: '%U'", 
375                                 format_unformat_error, line_input);
376   }
377
378   unformat_free (line_input);
379
380   if (local_set == 0)
381     return clib_error_return (0, "tunnel local address not specified");
382
383   if (remote_set == 0)
384     return clib_error_return (0, "tunnel remote address not specified");
385
386   if (vni_set == 0)
387     return clib_error_return (0, "vni not specified");
388
389   memset (a, 0, sizeof (*a));
390
391   a->is_add = is_add;
392
393 #define _(x) a->x = x;
394   foreach_gpe_copy_field;
395 #undef _
396
397   rv = vnet_vxlan_gpe_add_del_tunnel (a, &sw_if_index);
398
399   switch(rv)
400     {
401     case 0:
402       vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), sw_if_index);
403       break;
404     case VNET_API_ERROR_INVALID_DECAP_NEXT:
405       return clib_error_return (0, "invalid decap-next...");
406
407     case VNET_API_ERROR_TUNNEL_EXIST:
408       return clib_error_return (0, "tunnel already exists...");
409
410     case VNET_API_ERROR_NO_SUCH_ENTRY:
411       return clib_error_return (0, "tunnel does not exist...");
412
413     default:
414       return clib_error_return 
415         (0, "vnet_vxlan_gpe_add_del_tunnel returned %d", rv);
416     }
417
418   return 0;
419 }
420
421 VLIB_CLI_COMMAND (create_vxlan_gpe_tunnel_command, static) = {
422   .path = "create vxlan-gpe tunnel",
423   .short_help = 
424   "create vxlan-gpe tunnel local <ip4-addr> remote <ip4-addr>"
425   " vni <nn> [next-ip4][next-ip6][next-ethernet][next-nsh]"
426   " [encap-vrf-id <nn>] [decap-vrf-id <nn>]"
427   " [del]\n",
428   .function = vxlan_gpe_add_del_tunnel_command_fn,
429 };
430
431 static clib_error_t *
432 show_vxlan_gpe_tunnel_command_fn (vlib_main_t * vm,
433                                 unformat_input_t * input,
434                                 vlib_cli_command_t * cmd)
435 {
436   vxlan_gpe_main_t * gm = &vxlan_gpe_main;
437   vxlan_gpe_tunnel_t * t;
438   
439   if (pool_elts (gm->tunnels) == 0)
440     vlib_cli_output (vm, "No vxlan-gpe tunnels configured.");
441
442   pool_foreach (t, gm->tunnels,
443   ({
444     vlib_cli_output (vm, "%U", format_vxlan_gpe_tunnel, t);
445   }));
446   
447   return 0;
448 }
449
450 VLIB_CLI_COMMAND (show_vxlan_gpe_tunnel_command, static) = {
451     .path = "show vxlan-gpe",
452     .function = show_vxlan_gpe_tunnel_command_fn,
453 };
454
455 clib_error_t *vxlan_gpe_init (vlib_main_t *vm)
456 {
457   vxlan_gpe_main_t *gm = &vxlan_gpe_main;
458   
459   gm->vnet_main = vnet_get_main();
460   gm->vlib_main = vm;
461   
462   gm->vxlan_gpe_tunnel_by_key 
463     = hash_create_mem (0, sizeof(vxlan_gpe_tunnel_key_t), sizeof (uword));
464
465   udp_register_dst_port (vm, UDP_DST_PORT_vxlan_gpe, 
466                          vxlan_gpe_input_node.index, 1 /* is_ip4 */);
467   return 0;
468 }
469
470 VLIB_INIT_FUNCTION(vxlan_gpe_init);
471