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