A Protocol Independent Hierarchical FIB (VPP-352)
[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 /**
16  *  @file
17  *  @brief Common utility functions for IPv4 and IPv6 VXLAN GPE tunnels
18  *
19 */
20 #include <vnet/vxlan-gpe/vxlan_gpe.h>
21 #include <vnet/fib/fib.h>
22 #include <vnet/ip/format.h>
23
24 vxlan_gpe_main_t vxlan_gpe_main;
25
26 /**
27  * @brief Tracing function for VXLAN GPE tunnel packets
28  *
29  * @param *s formatting string
30  * @param *args
31  *
32  * @return *s formatted string
33  *
34  */
35 u8 * format_vxlan_gpe_tunnel (u8 * s, va_list * args)
36 {
37   vxlan_gpe_tunnel_t * t = va_arg (*args, vxlan_gpe_tunnel_t *);
38   vxlan_gpe_main_t * gm = &vxlan_gpe_main;
39
40   s = format (s, "[%d] local: %U remote: %U ",
41               t - gm->tunnels,
42               format_ip46_address, &t->local, IP46_TYPE_ANY,
43               format_ip46_address, &t->remote, IP46_TYPE_ANY);
44
45   s = format (s, "  vxlan VNI %d ", t->vni);
46
47   switch (t->protocol)
48     {
49     case VXLAN_GPE_PROTOCOL_IP4:
50       s = format (s, "next-protocol ip4");
51       break;
52     case VXLAN_GPE_PROTOCOL_IP6:
53       s = format (s, "next-protocol ip6");
54       break;
55     case VXLAN_GPE_PROTOCOL_ETHERNET:
56       s = format (s, "next-protocol ethernet");
57       break;
58     case VXLAN_GPE_PROTOCOL_NSH:
59       s = format (s, "next-protocol nsh");
60       break;
61     default:
62       s = format (s, "next-protocol unknown %d", t->protocol);
63     }
64
65   s = format (s, " fibs: (encap %d, decap %d)",
66               t->encap_fib_index,
67               t->decap_fib_index);
68
69   return s;
70 }
71
72 /**
73  * @brief Naming for VXLAN GPE tunnel
74  *
75  * @param *s formatting string
76  * @param *args
77  *
78  * @return *s formatted string
79  *
80  */
81 static u8 * format_vxlan_gpe_name (u8 * s, va_list * args)
82 {
83   u32 dev_instance = va_arg (*args, u32);
84   return format (s, "vxlan_gpe_tunnel%d", dev_instance);
85 }
86
87 static uword dummy_interface_tx (vlib_main_t * vm,
88                                  vlib_node_runtime_t * node,
89                                  vlib_frame_t * frame)
90 {
91   clib_warning ("you shouldn't be here, leaking buffers...");
92   return frame->n_vectors;
93 }
94
95 /**
96  * @brief CLI function for VXLAN GPE admin up/down
97  *
98  * @param *vnm
99  * @param hw_if_index
100  * @param flag
101  *
102  * @return *rc
103  *
104  */
105 static clib_error_t *
106 vxlan_gpe_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
107 {
108   if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
109     vnet_hw_interface_set_flags (vnm, hw_if_index, VNET_HW_INTERFACE_FLAG_LINK_UP);
110   else
111     vnet_hw_interface_set_flags (vnm, hw_if_index, 0);
112
113   return 0;
114 }
115
116 VNET_DEVICE_CLASS (vxlan_gpe_device_class,static) = {
117   .name = "VXLAN_GPE",
118   .format_device_name = format_vxlan_gpe_name,
119   .format_tx_trace = format_vxlan_gpe_encap_trace,
120   .tx_function = dummy_interface_tx,
121   .admin_up_down_function = vxlan_gpe_interface_admin_up_down,
122 };
123
124 static uword dummy_set_rewrite (vnet_main_t * vnm,
125                                 u32 sw_if_index,
126                                 u32 l3_type,
127                                 void * dst_address,
128                                 void * rewrite,
129                                 uword max_rewrite_bytes)
130 {
131   return 0;
132 }
133
134
135 /**
136  * @brief Formatting function for tracing VXLAN GPE with length
137  *
138  * @param *s
139  * @param *args
140  *
141  * @return *s
142  *
143  */
144 static u8 * format_vxlan_gpe_header_with_length (u8 * s, va_list * args)
145 {
146   u32 dev_instance = va_arg (*args, u32);
147   s = format (s, "unimplemented dev %u", dev_instance);
148   return s;
149 }
150
151 VNET_HW_INTERFACE_CLASS (vxlan_gpe_hw_class) = {
152   .name = "VXLAN_GPE",
153   .format_header = format_vxlan_gpe_header_with_length,
154   .set_rewrite = dummy_set_rewrite,
155 };
156
157
158 #define foreach_gpe_copy_field                  \
159 _(vni)                                          \
160 _(protocol)                                \
161 _(encap_fib_index)                              \
162 _(decap_fib_index)
163
164 #define foreach_copy_ipv4 {                     \
165   _(local.ip4.as_u32)                           \
166   _(remote.ip4.as_u32)                          \
167 }
168
169 #define foreach_copy_ipv6 {                     \
170   _(local.ip6.as_u64[0])                        \
171   _(local.ip6.as_u64[1])                        \
172   _(remote.ip6.as_u64[0])                       \
173   _(remote.ip6.as_u64[1])                       \
174 }
175
176
177 /**
178  * @brief Calculate IPv4 VXLAN GPE rewrite header
179  *
180  * @param *t
181  *
182  * @return rc
183  *
184  */
185 static int vxlan4_gpe_rewrite (vxlan_gpe_tunnel_t * t)
186 {
187   u8 *rw = 0;
188   ip4_header_t * ip0;
189   ip4_vxlan_gpe_header_t * h0;
190   int len;
191
192   len = sizeof (*h0);
193
194   vec_validate_aligned (rw, len-1, CLIB_CACHE_LINE_BYTES);
195
196   h0 = (ip4_vxlan_gpe_header_t *) rw;
197
198   /* Fixed portion of the (outer) ip4 header */
199   ip0 = &h0->ip4;
200   ip0->ip_version_and_header_length = 0x45;
201   ip0->ttl = 254;
202   ip0->protocol = IP_PROTOCOL_UDP;
203
204   /* we fix up the ip4 header length and checksum after-the-fact */
205   ip0->src_address.as_u32 = t->local.ip4.as_u32;
206   ip0->dst_address.as_u32 = t->remote.ip4.as_u32;
207   ip0->checksum = ip4_header_checksum (ip0);
208
209   /* UDP header, randomize src port on something, maybe? */
210   h0->udp.src_port = clib_host_to_net_u16 (4790);
211   h0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_vxlan_gpe);
212
213   /* VXLAN header. Are we having fun yet? */
214   h0->vxlan.flags = VXLAN_GPE_FLAGS_I | VXLAN_GPE_FLAGS_P;
215   h0->vxlan.ver_res = VXLAN_GPE_VERSION;
216   h0->vxlan.protocol = t->protocol;
217   h0->vxlan.vni_res = clib_host_to_net_u32 (t->vni<<8);
218
219   t->rewrite = rw;
220   return (0);
221 }
222
223 /**
224  * @brief Calculate IPv6 VXLAN GPE rewrite header
225  *
226  * @param *t
227  *
228  * @return rc
229  *
230  */
231 static int vxlan6_gpe_rewrite (vxlan_gpe_tunnel_t * t)
232 {
233   u8 *rw = 0;
234   ip6_header_t * ip0;
235   ip6_vxlan_gpe_header_t * h0;
236   int len;
237
238   len = sizeof (*h0);
239
240   vec_validate_aligned (rw, len-1, CLIB_CACHE_LINE_BYTES);
241
242   h0 = (ip6_vxlan_gpe_header_t *) rw;
243
244   /* Fixed portion of the (outer) ip4 header */
245   ip0 = &h0->ip6;
246   ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(6 << 28);
247   ip0->hop_limit = 255;
248   ip0->protocol = IP_PROTOCOL_UDP;
249
250   ip0->src_address.as_u64[0] = t->local.ip6.as_u64[0];
251   ip0->src_address.as_u64[1] = t->local.ip6.as_u64[1];
252   ip0->dst_address.as_u64[0] = t->remote.ip6.as_u64[0];
253   ip0->dst_address.as_u64[1] = t->remote.ip6.as_u64[1];
254
255   /* UDP header, randomize src port on something, maybe? */
256   h0->udp.src_port = clib_host_to_net_u16 (4790);
257   h0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_vxlan_gpe);
258
259   /* VXLAN header. Are we having fun yet? */
260   h0->vxlan.flags = VXLAN_GPE_FLAGS_I | VXLAN_GPE_FLAGS_P;
261   h0->vxlan.ver_res = VXLAN_GPE_VERSION;
262   h0->vxlan.protocol = t->protocol;
263   h0->vxlan.vni_res = clib_host_to_net_u32 (t->vni<<8);
264
265   t->rewrite = rw;
266   return (0);
267 }
268
269 /**
270  * @brief Add or Del a VXLAN GPE tunnel
271  *
272  * @param *a
273  * @param *sw_if_index
274  *
275  * @return rc
276  *
277  */
278 int vnet_vxlan_gpe_add_del_tunnel
279 (vnet_vxlan_gpe_add_del_tunnel_args_t *a, u32 * sw_if_indexp)
280 {
281   vxlan_gpe_main_t * gm = &vxlan_gpe_main;
282   vxlan_gpe_tunnel_t *t = 0;
283   vnet_main_t * vnm = gm->vnet_main;
284   vnet_hw_interface_t * hi;
285   uword * p;
286   u32 hw_if_index = ~0;
287   u32 sw_if_index = ~0;
288   int rv;
289   vxlan4_gpe_tunnel_key_t key4, *key4_copy;
290   vxlan6_gpe_tunnel_key_t key6, *key6_copy;
291   hash_pair_t *hp;
292
293   if (!a->is_ip6)
294   {
295     key4.local = a->local.ip4.as_u32;
296     key4.remote = a->remote.ip4.as_u32;
297     key4.vni = clib_host_to_net_u32 (a->vni << 8);
298     key4.pad = 0;
299
300     p = hash_get_mem(gm->vxlan4_gpe_tunnel_by_key, &key4);
301   }
302   else
303   {
304     key6.local.as_u64[0] = a->local.ip6.as_u64[0];
305     key6.local.as_u64[1] = a->local.ip6.as_u64[1];
306     key6.remote.as_u64[0] = a->remote.ip6.as_u64[0];
307     key6.remote.as_u64[1] = a->remote.ip6.as_u64[1];
308     key6.vni = clib_host_to_net_u32 (a->vni << 8);
309
310     p = hash_get_mem(gm->vxlan6_gpe_tunnel_by_key, &key6);
311   }
312
313   if (a->is_add)
314     {
315       /* adding a tunnel: tunnel must not already exist */
316       if (p)
317         return VNET_API_ERROR_INVALID_VALUE;
318
319       pool_get_aligned (gm->tunnels, t, CLIB_CACHE_LINE_BYTES);
320       memset (t, 0, sizeof (*t));
321
322       /* copy from arg structure */
323 #define _(x) t->x = a->x;
324       foreach_gpe_copy_field;
325       if (!a->is_ip6) foreach_copy_ipv4
326       else            foreach_copy_ipv6
327 #undef _
328
329       if (!a->is_ip6) t->flags |= VXLAN_GPE_TUNNEL_IS_IPV4;
330
331       if (!a->is_ip6) {
332         rv = vxlan4_gpe_rewrite (t);
333       } else {
334         rv = vxlan6_gpe_rewrite (t);
335       }
336
337       if (rv)
338       {
339           pool_put (gm->tunnels, t);
340           return rv;
341       }
342
343       if (!a->is_ip6)
344       {
345         key4_copy = clib_mem_alloc (sizeof (*key4_copy));
346         clib_memcpy (key4_copy, &key4, sizeof (*key4_copy));
347         hash_set_mem (gm->vxlan4_gpe_tunnel_by_key, key4_copy,
348                       t - gm->tunnels);
349       }
350       else
351       {
352           key6_copy = clib_mem_alloc (sizeof (*key6_copy));
353           clib_memcpy (key6_copy, &key6, sizeof (*key6_copy));
354           hash_set_mem (gm->vxlan6_gpe_tunnel_by_key, key6_copy,
355                         t - gm->tunnels);
356       }
357
358       if (vec_len (gm->free_vxlan_gpe_tunnel_hw_if_indices) > 0)
359         {
360           hw_if_index = gm->free_vxlan_gpe_tunnel_hw_if_indices
361             [vec_len (gm->free_vxlan_gpe_tunnel_hw_if_indices)-1];
362           _vec_len (gm->free_vxlan_gpe_tunnel_hw_if_indices) -= 1;
363
364           hi = vnet_get_hw_interface (vnm, hw_if_index);
365           hi->dev_instance = t - gm->tunnels;
366           hi->hw_instance = hi->dev_instance;
367         }
368       else
369         {
370           hw_if_index = vnet_register_interface
371             (vnm, vxlan_gpe_device_class.index, t - gm->tunnels,
372              vxlan_gpe_hw_class.index, t - gm->tunnels);
373           hi = vnet_get_hw_interface (vnm, hw_if_index);
374           hi->output_node_index = vxlan_gpe_encap_node.index;
375         }
376
377       t->hw_if_index = hw_if_index;
378       t->sw_if_index = sw_if_index = hi->sw_if_index;
379       vec_validate_init_empty (gm->tunnel_index_by_sw_if_index, sw_if_index, ~0);
380       gm->tunnel_index_by_sw_if_index[sw_if_index] = t - gm->tunnels;
381
382       vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
383                                    VNET_SW_INTERFACE_FLAG_ADMIN_UP);
384     }
385   else
386     {
387       /* deleting a tunnel: tunnel must exist */
388       if (!p)
389         return VNET_API_ERROR_NO_SUCH_ENTRY;
390
391       t = pool_elt_at_index (gm->tunnels, p[0]);
392
393       vnet_sw_interface_set_flags (vnm, t->sw_if_index, 0 /* down */);
394       vec_add1 (gm->free_vxlan_gpe_tunnel_hw_if_indices, t->hw_if_index);
395
396       gm->tunnel_index_by_sw_if_index[t->sw_if_index] = ~0;
397
398       if (!a->is_ip6)
399       {
400         hp = hash_get_pair (gm->vxlan4_gpe_tunnel_by_key, &key4);
401         key4_copy = (void *)(hp->key);
402         hash_unset_mem (gm->vxlan4_gpe_tunnel_by_key, &key4);
403         clib_mem_free (key4_copy);
404       }
405       else
406       {
407         hp = hash_get_pair (gm->vxlan6_gpe_tunnel_by_key, &key6);
408         key6_copy = (void *)(hp->key);
409         hash_unset_mem (gm->vxlan4_gpe_tunnel_by_key, &key6);
410         clib_mem_free (key6_copy);
411       }
412
413       vec_free (t->rewrite);
414       pool_put (gm->tunnels, t);
415     }
416
417   if (sw_if_indexp)
418       *sw_if_indexp = sw_if_index;
419
420   return 0;
421 }
422
423 static clib_error_t *
424 vxlan_gpe_add_del_tunnel_command_fn (vlib_main_t * vm,
425                                    unformat_input_t * input,
426                                    vlib_cli_command_t * cmd)
427 {
428   unformat_input_t _line_input, * line_input = &_line_input;
429   u8 is_add = 1;
430   ip46_address_t local, remote;
431   u8 local_set = 0;
432   u8 remote_set = 0;
433   u8 ipv4_set = 0;
434   u8 ipv6_set = 0;
435   u32 encap_fib_index = 0;
436   u32 decap_fib_index = 0;
437   u8 protocol = VXLAN_GPE_PROTOCOL_IP4;
438   u32 vni;
439   u8 vni_set = 0;
440   int rv;
441   u32 tmp;
442   vnet_vxlan_gpe_add_del_tunnel_args_t _a, * a = &_a;
443   u32 sw_if_index;
444
445   /* Get a line of input. */
446   if (! unformat_user (input, unformat_line_input, line_input))
447     return 0;
448
449   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
450     if (unformat (line_input, "del"))
451       is_add = 0;
452     else if (unformat (line_input, "local %U",
453                        unformat_ip4_address, &local.ip4))
454     {
455       local_set = 1;
456       ipv4_set = 1;
457     }
458     else if (unformat (line_input, "remote %U",
459                        unformat_ip4_address, &remote.ip4))
460     {
461       remote_set = 1;
462       ipv4_set = 1;
463     }
464     else if (unformat (line_input, "local %U",
465                        unformat_ip6_address, &local.ip6))
466     {
467       local_set = 1;
468       ipv6_set = 1;
469     }
470     else if (unformat (line_input, "remote %U",
471                        unformat_ip6_address, &remote.ip6))
472     {
473       remote_set = 1;
474       ipv6_set = 1;
475     }
476     else if (unformat (line_input, "encap-vrf-id %d", &tmp))
477       {
478         if (ipv6_set)
479           encap_fib_index = ip6_fib_index_from_table_id (tmp);
480         else
481           encap_fib_index =  ip4_fib_index_from_table_id (tmp);
482
483         if (encap_fib_index == ~0)
484           return clib_error_return (0, "nonexistent encap fib id %d", tmp);
485       }
486     else if (unformat (line_input, "decap-vrf-id %d", &tmp))
487       {
488         if (ipv6_set)
489           decap_fib_index = ip6_fib_index_from_table_id (tmp);
490         else
491           decap_fib_index = ip4_fib_index_from_table_id (tmp);
492
493         if (decap_fib_index == ~0)
494           return clib_error_return (0, "nonexistent decap fib id %d", tmp);
495       }
496     else if (unformat (line_input, "vni %d", &vni))
497       vni_set = 1;
498     else if (unformat(line_input, "next-ip4"))
499       protocol = VXLAN_GPE_PROTOCOL_IP4;
500     else if (unformat(line_input, "next-ip6"))
501       protocol = VXLAN_GPE_PROTOCOL_IP6;
502     else if (unformat(line_input, "next-ethernet"))
503       protocol = VXLAN_GPE_PROTOCOL_ETHERNET;
504     else if (unformat(line_input, "next-nsh"))
505       protocol = VXLAN_GPE_PROTOCOL_NSH;
506     else
507       return clib_error_return (0, "parse error: '%U'",
508                                 format_unformat_error, line_input);
509   }
510
511   unformat_free (line_input);
512
513   if (local_set == 0)
514     return clib_error_return (0, "tunnel local address not specified");
515
516   if (remote_set == 0)
517     return clib_error_return (0, "tunnel remote address not specified");
518
519   if (ipv4_set && ipv6_set)
520     return clib_error_return (0, "both IPv4 and IPv6 addresses specified");
521
522   if ((ipv4_set && memcmp(&local.ip4, &remote.ip4, sizeof(local.ip4)) == 0) ||
523       (ipv6_set && memcmp(&local.ip6, &remote.ip6, sizeof(local.ip6)) == 0))
524     return clib_error_return (0, "src and dst addresses are identical");
525
526   if (vni_set == 0)
527     return clib_error_return (0, "vni not specified");
528
529   memset (a, 0, sizeof (*a));
530
531   a->is_add = is_add;
532   a->is_ip6 = ipv6_set;
533
534 #define _(x) a->x = x;
535   foreach_gpe_copy_field;
536   if (ipv4_set) foreach_copy_ipv4
537   else          foreach_copy_ipv6
538 #undef _
539
540   rv = vnet_vxlan_gpe_add_del_tunnel (a, &sw_if_index);
541
542   switch(rv)
543     {
544     case 0:
545       vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), sw_if_index);
546       break;
547     case VNET_API_ERROR_INVALID_DECAP_NEXT:
548       return clib_error_return (0, "invalid decap-next...");
549
550     case VNET_API_ERROR_TUNNEL_EXIST:
551       return clib_error_return (0, "tunnel already exists...");
552
553     case VNET_API_ERROR_NO_SUCH_ENTRY:
554       return clib_error_return (0, "tunnel does not exist...");
555
556     default:
557       return clib_error_return
558         (0, "vnet_vxlan_gpe_add_del_tunnel returned %d", rv);
559     }
560
561   return 0;
562 }
563
564 VLIB_CLI_COMMAND (create_vxlan_gpe_tunnel_command, static) = {
565   .path = "create vxlan-gpe tunnel",
566   .short_help =
567   "create vxlan-gpe tunnel local <local-addr> remote <remote-addr>"
568   " vni <nn> [next-ip4][next-ip6][next-ethernet][next-nsh]"
569   " [encap-vrf-id <nn>] [decap-vrf-id <nn>]"
570   " [del]\n",
571   .function = vxlan_gpe_add_del_tunnel_command_fn,
572 };
573
574 /**
575  * @brief CLI function for showing VXLAN GPE tunnels
576  *
577  * @param *vm
578  * @param *input
579  * @param *cmd
580  *
581  * @return error
582  *
583  */
584 static clib_error_t *
585 show_vxlan_gpe_tunnel_command_fn (vlib_main_t * vm,
586                                 unformat_input_t * input,
587                                 vlib_cli_command_t * cmd)
588 {
589   vxlan_gpe_main_t * gm = &vxlan_gpe_main;
590   vxlan_gpe_tunnel_t * t;
591
592   if (pool_elts (gm->tunnels) == 0)
593     vlib_cli_output (vm, "No vxlan-gpe tunnels configured.");
594
595   pool_foreach (t, gm->tunnels,
596   ({
597     vlib_cli_output (vm, "%U", format_vxlan_gpe_tunnel, t);
598   }));
599
600   return 0;
601 }
602
603 VLIB_CLI_COMMAND (show_vxlan_gpe_tunnel_command, static) = {
604     .path = "show vxlan-gpe",
605     .function = show_vxlan_gpe_tunnel_command_fn,
606 };
607
608 /**
609  * @brief Feature init function for VXLAN GPE
610  *
611  * @param *vm
612  *
613  * @return error
614  *
615  */
616 clib_error_t *vxlan_gpe_init (vlib_main_t *vm)
617 {
618   vxlan_gpe_main_t *gm = &vxlan_gpe_main;
619
620   gm->vnet_main = vnet_get_main();
621   gm->vlib_main = vm;
622
623   gm->vxlan4_gpe_tunnel_by_key
624     = hash_create_mem (0, sizeof(vxlan4_gpe_tunnel_key_t), sizeof (uword));
625
626   gm->vxlan6_gpe_tunnel_by_key
627     = hash_create_mem (0, sizeof(vxlan6_gpe_tunnel_key_t), sizeof (uword));
628
629
630   udp_register_dst_port (vm, UDP_DST_PORT_vxlan_gpe,
631                          vxlan4_gpe_input_node.index, 1 /* is_ip4 */);
632   udp_register_dst_port (vm, UDP_DST_PORT_vxlan6_gpe,
633                          vxlan6_gpe_input_node.index, 0 /* is_ip4 */);
634   return 0;
635 }
636
637 VLIB_INIT_FUNCTION(vxlan_gpe_init);
638