misc: minimize dependencies on udp.h
[vpp.git] / src / vnet / vxlan / vxlan.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/vxlan.h>
16 #include <vnet/ip/format.h>
17 #include <vnet/fib/fib_entry.h>
18 #include <vnet/fib/fib_table.h>
19 #include <vnet/fib/fib_entry_track.h>
20 #include <vnet/mfib/mfib_table.h>
21 #include <vnet/adj/adj_mcast.h>
22 #include <vnet/adj/rewrite.h>
23 #include <vnet/interface.h>
24 #include <vnet/flow/flow.h>
25 #include <vnet/udp/udp_local.h>
26 #include <vlib/vlib.h>
27
28 /**
29  * @file
30  * @brief VXLAN.
31  *
32  * VXLAN provides the features needed to allow L2 bridge domains (BDs)
33  * to span multiple servers. This is done by building an L2 overlay on
34  * top of an L3 network underlay using VXLAN tunnels.
35  *
36  * This makes it possible for servers to be co-located in the same data
37  * center or be separated geographically as long as they are reachable
38  * through the underlay L3 network.
39  *
40  * You can refer to this kind of L2 overlay bridge domain as a VXLAN
41  * (Virtual eXtensible VLAN) segment.
42  */
43
44
45 vxlan_main_t vxlan_main;
46
47 static u8 *
48 format_decap_next (u8 * s, va_list * args)
49 {
50   u32 next_index = va_arg (*args, u32);
51
52   if (next_index == VXLAN_INPUT_NEXT_DROP)
53     return format (s, "drop");
54   else
55     return format (s, "index %d", next_index);
56   return s;
57 }
58
59 u8 *
60 format_vxlan_tunnel (u8 * s, va_list * args)
61 {
62   vxlan_tunnel_t *t = va_arg (*args, vxlan_tunnel_t *);
63
64   s = format (s,
65               "[%d] instance %d src %U dst %U vni %d fib-idx %d sw-if-idx %d ",
66               t->dev_instance, t->user_instance,
67               format_ip46_address, &t->src, IP46_TYPE_ANY,
68               format_ip46_address, &t->dst, IP46_TYPE_ANY,
69               t->vni, t->encap_fib_index, t->sw_if_index);
70
71   s = format (s, "encap-dpo-idx %d ", t->next_dpo.dpoi_index);
72
73   if (PREDICT_FALSE (t->decap_next_index != VXLAN_INPUT_NEXT_L2_INPUT))
74     s = format (s, "decap-next-%U ", format_decap_next, t->decap_next_index);
75
76   if (PREDICT_FALSE (ip46_address_is_multicast (&t->dst)))
77     s = format (s, "mcast-sw-if-idx %d ", t->mcast_sw_if_index);
78
79   if (t->flow_index != ~0)
80     s = format (s, "flow-index %d [%U]", t->flow_index,
81                 format_flow_enabled_hw, t->flow_index);
82
83   return s;
84 }
85
86 static u8 *
87 format_vxlan_name (u8 * s, va_list * args)
88 {
89   u32 dev_instance = va_arg (*args, u32);
90   vxlan_main_t *vxm = &vxlan_main;
91   vxlan_tunnel_t *t;
92
93   if (dev_instance == ~0)
94     return format (s, "<cached-unused>");
95
96   if (dev_instance >= vec_len (vxm->tunnels))
97     return format (s, "<improperly-referenced>");
98
99   t = pool_elt_at_index (vxm->tunnels, dev_instance);
100
101   return format (s, "vxlan_tunnel%d", t->user_instance);
102 }
103
104 static clib_error_t *
105 vxlan_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
106 {
107   u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
108     VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
109   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
110
111   return /* no error */ 0;
112 }
113
114 /* *INDENT-OFF* */
115 VNET_DEVICE_CLASS (vxlan_device_class, static) = {
116   .name = "VXLAN",
117   .format_device_name = format_vxlan_name,
118   .format_tx_trace = format_vxlan_encap_trace,
119   .admin_up_down_function = vxlan_interface_admin_up_down,
120 };
121 /* *INDENT-ON* */
122
123 static u8 *
124 format_vxlan_header_with_length (u8 * s, va_list * args)
125 {
126   u32 dev_instance = va_arg (*args, u32);
127   s = format (s, "unimplemented dev %u", dev_instance);
128   return s;
129 }
130
131 /* *INDENT-OFF* */
132 VNET_HW_INTERFACE_CLASS (vxlan_hw_class) = {
133   .name = "VXLAN",
134   .format_header = format_vxlan_header_with_length,
135   .build_rewrite = default_build_rewrite,
136 };
137 /* *INDENT-ON* */
138
139 static void
140 vxlan_tunnel_restack_dpo (vxlan_tunnel_t * t)
141 {
142   u8 is_ip4 = ip46_address_is_ip4 (&t->dst);
143   dpo_id_t dpo = DPO_INVALID;
144   fib_forward_chain_type_t forw_type = is_ip4 ?
145     FIB_FORW_CHAIN_TYPE_UNICAST_IP4 : FIB_FORW_CHAIN_TYPE_UNICAST_IP6;
146
147   fib_entry_contribute_forwarding (t->fib_entry_index, forw_type, &dpo);
148
149   /* vxlan uses the payload hash as the udp source port
150    * hence the packet's hash is unknown
151    * skip single bucket load balance dpo's */
152   while (DPO_LOAD_BALANCE == dpo.dpoi_type)
153     {
154       load_balance_t *lb = load_balance_get (dpo.dpoi_index);
155       if (lb->lb_n_buckets > 1)
156         break;
157
158       dpo_copy (&dpo, load_balance_get_bucket_i (lb, 0));
159     }
160
161   u32 encap_index = is_ip4 ?
162     vxlan4_encap_node.index : vxlan6_encap_node.index;
163   dpo_stack_from_node (encap_index, &t->next_dpo, &dpo);
164   dpo_reset (&dpo);
165 }
166
167 static vxlan_tunnel_t *
168 vxlan_tunnel_from_fib_node (fib_node_t * node)
169 {
170   ASSERT (FIB_NODE_TYPE_VXLAN_TUNNEL == node->fn_type);
171   return ((vxlan_tunnel_t *) (((char *) node) -
172                               STRUCT_OFFSET_OF (vxlan_tunnel_t, node)));
173 }
174
175 /**
176  * Function definition to backwalk a FIB node -
177  * Here we will restack the new dpo of VXLAN DIP to encap node.
178  */
179 static fib_node_back_walk_rc_t
180 vxlan_tunnel_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
181 {
182   vxlan_tunnel_restack_dpo (vxlan_tunnel_from_fib_node (node));
183   return (FIB_NODE_BACK_WALK_CONTINUE);
184 }
185
186 /**
187  * Function definition to get a FIB node from its index
188  */
189 static fib_node_t *
190 vxlan_tunnel_fib_node_get (fib_node_index_t index)
191 {
192   vxlan_tunnel_t *t;
193   vxlan_main_t *vxm = &vxlan_main;
194
195   t = pool_elt_at_index (vxm->tunnels, index);
196
197   return (&t->node);
198 }
199
200 /**
201  * Function definition to inform the FIB node that its last lock has gone.
202  */
203 static void
204 vxlan_tunnel_last_lock_gone (fib_node_t * node)
205 {
206   /*
207    * The VXLAN tunnel is a root of the graph. As such
208    * it never has children and thus is never locked.
209    */
210   ASSERT (0);
211 }
212
213 /*
214  * Virtual function table registered by VXLAN tunnels
215  * for participation in the FIB object graph.
216  */
217 const static fib_node_vft_t vxlan_vft = {
218   .fnv_get = vxlan_tunnel_fib_node_get,
219   .fnv_last_lock = vxlan_tunnel_last_lock_gone,
220   .fnv_back_walk = vxlan_tunnel_back_walk,
221 };
222
223
224 #define foreach_copy_field                      \
225 _(vni)                                          \
226 _(mcast_sw_if_index)                            \
227 _(encap_fib_index)                              \
228 _(decap_next_index)                             \
229 _(src)                                          \
230 _(dst)
231
232 static void
233 vxlan_rewrite (vxlan_tunnel_t * t, bool is_ip6)
234 {
235   union
236   {
237     ip4_vxlan_header_t h4;
238     ip6_vxlan_header_t h6;
239   } h;
240   int len = is_ip6 ? sizeof h.h6 : sizeof h.h4;
241
242   udp_header_t *udp;
243   vxlan_header_t *vxlan;
244   /* Fixed portion of the (outer) ip header */
245
246   clib_memset (&h, 0, sizeof (h));
247   if (!is_ip6)
248     {
249       ip4_header_t *ip = &h.h4.ip4;
250       udp = &h.h4.udp, vxlan = &h.h4.vxlan;
251       ip->ip_version_and_header_length = 0x45;
252       ip->ttl = 254;
253       ip->protocol = IP_PROTOCOL_UDP;
254
255       ip->src_address = t->src.ip4;
256       ip->dst_address = t->dst.ip4;
257
258       /* we fix up the ip4 header length and checksum after-the-fact */
259       ip->checksum = ip4_header_checksum (ip);
260     }
261   else
262     {
263       ip6_header_t *ip = &h.h6.ip6;
264       udp = &h.h6.udp, vxlan = &h.h6.vxlan;
265       ip->ip_version_traffic_class_and_flow_label =
266         clib_host_to_net_u32 (6 << 28);
267       ip->hop_limit = 255;
268       ip->protocol = IP_PROTOCOL_UDP;
269
270       ip->src_address = t->src.ip6;
271       ip->dst_address = t->dst.ip6;
272     }
273
274   /* UDP header, randomize src port on something, maybe? */
275   udp->src_port = clib_host_to_net_u16 (4789);
276   udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_vxlan);
277
278   /* VXLAN header */
279   vnet_set_vni_and_flags (vxlan, t->vni);
280   vnet_rewrite_set_data (*t, &h, len);
281 }
282
283 static bool
284 vxlan_decap_next_is_valid (vxlan_main_t * vxm, u32 is_ip6,
285                            u32 decap_next_index)
286 {
287   vlib_main_t *vm = vxm->vlib_main;
288   u32 input_idx = (!is_ip6) ?
289     vxlan4_input_node.index : vxlan6_input_node.index;
290   vlib_node_runtime_t *r = vlib_node_get_runtime (vm, input_idx);
291
292   return decap_next_index < r->n_next_nodes;
293 }
294
295 /* *INDENT-OFF* */
296 typedef CLIB_PACKED(union
297 {
298   struct
299   {
300     fib_node_index_t mfib_entry_index;
301     adj_index_t mcast_adj_index;
302   };
303   u64 as_u64;
304 }) mcast_shared_t;
305 /* *INDENT-ON* */
306
307 static inline mcast_shared_t
308 mcast_shared_get (ip46_address_t * ip)
309 {
310   ASSERT (ip46_address_is_multicast (ip));
311   uword *p = hash_get_mem (vxlan_main.mcast_shared, ip);
312   ALWAYS_ASSERT (p);
313   mcast_shared_t ret = {.as_u64 = *p };
314   return ret;
315 }
316
317 static inline void
318 mcast_shared_add (ip46_address_t * dst, fib_node_index_t mfei, adj_index_t ai)
319 {
320   mcast_shared_t new_ep = {
321     .mcast_adj_index = ai,
322     .mfib_entry_index = mfei,
323   };
324
325   hash_set_mem_alloc (&vxlan_main.mcast_shared, dst, new_ep.as_u64);
326 }
327
328 static inline void
329 mcast_shared_remove (ip46_address_t * dst)
330 {
331   mcast_shared_t ep = mcast_shared_get (dst);
332
333   adj_unlock (ep.mcast_adj_index);
334   mfib_table_entry_delete_index (ep.mfib_entry_index, MFIB_SOURCE_VXLAN);
335
336   hash_unset_mem_free (&vxlan_main.mcast_shared, dst);
337 }
338
339 int vnet_vxlan_add_del_tunnel
340   (vnet_vxlan_add_del_tunnel_args_t * a, u32 * sw_if_indexp)
341 {
342   vxlan_main_t *vxm = &vxlan_main;
343   vnet_main_t *vnm = vxm->vnet_main;
344   vxlan_decap_info_t *p;
345   u32 sw_if_index = ~0;
346   vxlan4_tunnel_key_t key4;
347   vxlan6_tunnel_key_t key6;
348   u32 is_ip6 = a->is_ip6;
349
350   int not_found;
351   if (!is_ip6)
352     {
353       /* ip4 mcast is indexed by mcast addr only */
354       key4.key[0] = ip46_address_is_multicast (&a->dst) ?
355         a->dst.ip4.as_u32 :
356         a->dst.ip4.as_u32 | (((u64) a->src.ip4.as_u32) << 32);
357       key4.key[1] = (((u64) a->encap_fib_index) << 32)
358         | clib_host_to_net_u32 (a->vni << 8);
359       not_found =
360         clib_bihash_search_inline_16_8 (&vxm->vxlan4_tunnel_by_key, &key4);
361       p = (void *) &key4.value;
362     }
363   else
364     {
365       key6.key[0] = a->dst.ip6.as_u64[0];
366       key6.key[1] = a->dst.ip6.as_u64[1];
367       key6.key[2] = (((u64) a->encap_fib_index) << 32)
368         | clib_host_to_net_u32 (a->vni << 8);
369       not_found =
370         clib_bihash_search_inline_24_8 (&vxm->vxlan6_tunnel_by_key, &key6);
371       p = (void *) &key6.value;
372     }
373
374   if (not_found)
375     p = 0;
376
377   if (a->is_add)
378     {
379       l2input_main_t *l2im = &l2input_main;
380       u32 dev_instance;         /* real dev instance tunnel index */
381       u32 user_instance;        /* request and actual instance number */
382
383       /* adding a tunnel: tunnel must not already exist */
384       if (p)
385         return VNET_API_ERROR_TUNNEL_EXIST;
386
387       /*if not set explicitly, default to l2 */
388       if (a->decap_next_index == ~0)
389         a->decap_next_index = VXLAN_INPUT_NEXT_L2_INPUT;
390       if (!vxlan_decap_next_is_valid (vxm, is_ip6, a->decap_next_index))
391         return VNET_API_ERROR_INVALID_DECAP_NEXT;
392
393       vxlan_tunnel_t *t;
394       pool_get_aligned (vxm->tunnels, t, CLIB_CACHE_LINE_BYTES);
395       clib_memset (t, 0, sizeof (*t));
396       dev_instance = t - vxm->tunnels;
397
398       /* copy from arg structure */
399 #define _(x) t->x = a->x;
400       foreach_copy_field;
401 #undef _
402
403       vxlan_rewrite (t, is_ip6);
404       /*
405        * Reconcile the real dev_instance and a possible requested instance.
406        */
407       user_instance = a->instance;
408       if (user_instance == ~0)
409         user_instance = dev_instance;
410       if (hash_get (vxm->instance_used, user_instance))
411         {
412           pool_put (vxm->tunnels, t);
413           return VNET_API_ERROR_INSTANCE_IN_USE;
414         }
415       hash_set (vxm->instance_used, user_instance, 1);
416
417       t->dev_instance = dev_instance;   /* actual */
418       t->user_instance = user_instance; /* name */
419       t->flow_index = ~0;
420
421       t->hw_if_index = vnet_register_interface
422         (vnm, vxlan_device_class.index, dev_instance,
423          vxlan_hw_class.index, dev_instance);
424       vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, t->hw_if_index);
425
426       /* Set vxlan tunnel output node */
427       u32 encap_index = !is_ip6 ?
428         vxlan4_encap_node.index : vxlan6_encap_node.index;
429       vnet_set_interface_output_node (vnm, t->hw_if_index, encap_index);
430
431       t->sw_if_index = sw_if_index = hi->sw_if_index;
432
433       /* copy the key */
434       int add_failed;
435       if (is_ip6)
436         {
437           key6.value = (u64) dev_instance;
438           add_failed = clib_bihash_add_del_24_8 (&vxm->vxlan6_tunnel_by_key,
439                                                  &key6, 1 /*add */ );
440         }
441       else
442         {
443           vxlan_decap_info_t di = {.sw_if_index = t->sw_if_index, };
444           if (ip46_address_is_multicast (&t->dst))
445             di.local_ip = t->src.ip4;
446           else
447             di.next_index = t->decap_next_index;
448           key4.value = di.as_u64;
449           add_failed = clib_bihash_add_del_16_8 (&vxm->vxlan4_tunnel_by_key,
450                                                  &key4, 1 /*add */ );
451         }
452
453       if (add_failed)
454         {
455           vnet_delete_hw_interface (vnm, t->hw_if_index);
456           hash_unset (vxm->instance_used, t->user_instance);
457           pool_put (vxm->tunnels, t);
458           return VNET_API_ERROR_INVALID_REGISTRATION;
459         }
460
461       vec_validate_init_empty (vxm->tunnel_index_by_sw_if_index, sw_if_index,
462                                ~0);
463       vxm->tunnel_index_by_sw_if_index[sw_if_index] = dev_instance;
464
465       /* setup l2 input config with l2 feature and bd 0 to drop packet */
466       vec_validate (l2im->configs, sw_if_index);
467       l2im->configs[sw_if_index].feature_bitmap = L2INPUT_FEAT_DROP;
468       l2im->configs[sw_if_index].bd_index = 0;
469
470       vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
471       si->flags &= ~VNET_SW_INTERFACE_FLAG_HIDDEN;
472       vnet_sw_interface_set_flags (vnm, sw_if_index,
473                                    VNET_SW_INTERFACE_FLAG_ADMIN_UP);
474
475       fib_node_init (&t->node, FIB_NODE_TYPE_VXLAN_TUNNEL);
476       fib_prefix_t tun_dst_pfx;
477       vnet_flood_class_t flood_class = VNET_FLOOD_CLASS_TUNNEL_NORMAL;
478
479       fib_prefix_from_ip46_addr (&t->dst, &tun_dst_pfx);
480       if (!ip46_address_is_multicast (&t->dst))
481         {
482           /* Unicast tunnel -
483            * source the FIB entry for the tunnel's destination
484            * and become a child thereof. The tunnel will then get poked
485            * when the forwarding for the entry updates, and the tunnel can
486            * re-stack accordingly
487            */
488           vtep_addr_ref (&vxm->vtep_table, t->encap_fib_index, &t->src);
489           t->fib_entry_index = fib_entry_track (t->encap_fib_index,
490                                                 &tun_dst_pfx,
491                                                 FIB_NODE_TYPE_VXLAN_TUNNEL,
492                                                 dev_instance,
493                                                 &t->sibling_index);
494           vxlan_tunnel_restack_dpo (t);
495         }
496       else
497         {
498           /* Multicast tunnel -
499            * as the same mcast group can be used for multiple mcast tunnels
500            * with different VNIs, create the output fib adjacency only if
501            * it does not already exist
502            */
503           fib_protocol_t fp = fib_ip_proto (is_ip6);
504
505           if (vtep_addr_ref (&vxm->vtep_table,
506                              t->encap_fib_index, &t->dst) == 1)
507             {
508               fib_node_index_t mfei;
509               adj_index_t ai;
510               fib_route_path_t path = {
511                 .frp_proto = fib_proto_to_dpo (fp),
512                 .frp_addr = zero_addr,
513                 .frp_sw_if_index = 0xffffffff,
514                 .frp_fib_index = ~0,
515                 .frp_weight = 1,
516                 .frp_flags = FIB_ROUTE_PATH_LOCAL,
517                 .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
518               };
519               const mfib_prefix_t mpfx = {
520                 .fp_proto = fp,
521                 .fp_len = (is_ip6 ? 128 : 32),
522                 .fp_grp_addr = tun_dst_pfx.fp_addr,
523               };
524
525               /*
526                * Setup the (*,G) to receive traffic on the mcast group
527                *  - the forwarding interface is for-us
528                *  - the accepting interface is that from the API
529                */
530               mfib_table_entry_path_update (t->encap_fib_index,
531                                             &mpfx, MFIB_SOURCE_VXLAN, &path);
532
533               path.frp_sw_if_index = a->mcast_sw_if_index;
534               path.frp_flags = FIB_ROUTE_PATH_FLAG_NONE;
535               path.frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT;
536               mfei = mfib_table_entry_path_update (t->encap_fib_index,
537                                                    &mpfx,
538                                                    MFIB_SOURCE_VXLAN, &path);
539
540               /*
541                * Create the mcast adjacency to send traffic to the group
542                */
543               ai = adj_mcast_add_or_lock (fp,
544                                           fib_proto_to_link (fp),
545                                           a->mcast_sw_if_index);
546
547               /*
548                * create a new end-point
549                */
550               mcast_shared_add (&t->dst, mfei, ai);
551             }
552
553           dpo_id_t dpo = DPO_INVALID;
554           mcast_shared_t ep = mcast_shared_get (&t->dst);
555
556           /* Stack shared mcast dst mac addr rewrite on encap */
557           dpo_set (&dpo, DPO_ADJACENCY_MCAST,
558                    fib_proto_to_dpo (fp), ep.mcast_adj_index);
559
560           dpo_stack_from_node (encap_index, &t->next_dpo, &dpo);
561           dpo_reset (&dpo);
562           flood_class = VNET_FLOOD_CLASS_TUNNEL_MASTER;
563         }
564
565       vnet_get_sw_interface (vnet_get_main (), sw_if_index)->flood_class =
566         flood_class;
567     }
568   else
569     {
570       /* deleting a tunnel: tunnel must exist */
571       if (!p)
572         return VNET_API_ERROR_NO_SUCH_ENTRY;
573
574       u32 instance = is_ip6 ? key6.value :
575         vxm->tunnel_index_by_sw_if_index[p->sw_if_index];
576       vxlan_tunnel_t *t = pool_elt_at_index (vxm->tunnels, instance);
577
578       sw_if_index = t->sw_if_index;
579       vnet_sw_interface_set_flags (vnm, sw_if_index, 0 /* down */ );
580
581       vxm->tunnel_index_by_sw_if_index[sw_if_index] = ~0;
582
583       if (!is_ip6)
584         clib_bihash_add_del_16_8 (&vxm->vxlan4_tunnel_by_key, &key4,
585                                   0 /*del */ );
586       else
587         clib_bihash_add_del_24_8 (&vxm->vxlan6_tunnel_by_key, &key6,
588                                   0 /*del */ );
589
590       if (!ip46_address_is_multicast (&t->dst))
591         {
592           if (t->flow_index != ~0)
593             vnet_flow_del (vnm, t->flow_index);
594
595           vtep_addr_unref (&vxm->vtep_table, t->encap_fib_index, &t->src);
596           fib_entry_untrack (t->fib_entry_index, t->sibling_index);
597         }
598       else if (vtep_addr_unref (&vxm->vtep_table,
599                                 t->encap_fib_index, &t->dst) == 0)
600         {
601           mcast_shared_remove (&t->dst);
602         }
603
604       vnet_delete_hw_interface (vnm, t->hw_if_index);
605       hash_unset (vxm->instance_used, t->user_instance);
606
607       fib_node_deinit (&t->node);
608       pool_put (vxm->tunnels, t);
609     }
610
611   if (sw_if_indexp)
612     *sw_if_indexp = sw_if_index;
613
614   if (a->is_add)
615     {
616       /* register udp ports */
617       if (!is_ip6 && !udp_is_valid_dst_port (UDP_DST_PORT_vxlan, 1))
618         udp_register_dst_port (vxm->vlib_main, UDP_DST_PORT_vxlan,
619                                vxlan4_input_node.index, 1);
620       if (is_ip6 && !udp_is_valid_dst_port (UDP_DST_PORT_vxlan6, 0))
621         udp_register_dst_port (vxm->vlib_main, UDP_DST_PORT_vxlan6,
622                                vxlan6_input_node.index, 0);
623     }
624
625   return 0;
626 }
627
628 static uword
629 get_decap_next_for_node (u32 node_index, u32 ipv4_set)
630 {
631   vxlan_main_t *vxm = &vxlan_main;
632   vlib_main_t *vm = vxm->vlib_main;
633   uword input_node = (ipv4_set) ? vxlan4_input_node.index :
634     vxlan6_input_node.index;
635
636   return vlib_node_add_next (vm, input_node, node_index);
637 }
638
639 static uword
640 unformat_decap_next (unformat_input_t * input, va_list * args)
641 {
642   u32 *result = va_arg (*args, u32 *);
643   u32 ipv4_set = va_arg (*args, int);
644   vxlan_main_t *vxm = &vxlan_main;
645   vlib_main_t *vm = vxm->vlib_main;
646   u32 node_index;
647   u32 tmp;
648
649   if (unformat (input, "l2"))
650     *result = VXLAN_INPUT_NEXT_L2_INPUT;
651   else if (unformat (input, "node %U", unformat_vlib_node, vm, &node_index))
652     *result = get_decap_next_for_node (node_index, ipv4_set);
653   else if (unformat (input, "%d", &tmp))
654     *result = tmp;
655   else
656     return 0;
657   return 1;
658 }
659
660 static clib_error_t *
661 vxlan_add_del_tunnel_command_fn (vlib_main_t * vm,
662                                  unformat_input_t * input,
663                                  vlib_cli_command_t * cmd)
664 {
665   unformat_input_t _line_input, *line_input = &_line_input;
666   ip46_address_t src = ip46_address_initializer, dst =
667     ip46_address_initializer;
668   u8 is_add = 1;
669   u8 src_set = 0;
670   u8 dst_set = 0;
671   u8 grp_set = 0;
672   u8 ipv4_set = 0;
673   u8 ipv6_set = 0;
674   u32 instance = ~0;
675   u32 encap_fib_index = 0;
676   u32 mcast_sw_if_index = ~0;
677   u32 decap_next_index = VXLAN_INPUT_NEXT_L2_INPUT;
678   u32 vni = 0;
679   u32 table_id;
680   clib_error_t *parse_error = NULL;
681
682   /* Get a line of input. */
683   if (!unformat_user (input, unformat_line_input, line_input))
684     return 0;
685
686   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
687     {
688       if (unformat (line_input, "del"))
689         {
690           is_add = 0;
691         }
692       else if (unformat (line_input, "instance %d", &instance))
693         ;
694       else if (unformat (line_input, "src %U",
695                          unformat_ip46_address, &src, IP46_TYPE_ANY))
696         {
697           src_set = 1;
698           ip46_address_is_ip4 (&src) ? (ipv4_set = 1) : (ipv6_set = 1);
699         }
700       else if (unformat (line_input, "dst %U",
701                          unformat_ip46_address, &dst, IP46_TYPE_ANY))
702         {
703           dst_set = 1;
704           ip46_address_is_ip4 (&dst) ? (ipv4_set = 1) : (ipv6_set = 1);
705         }
706       else if (unformat (line_input, "group %U %U",
707                          unformat_ip46_address, &dst, IP46_TYPE_ANY,
708                          unformat_vnet_sw_interface,
709                          vnet_get_main (), &mcast_sw_if_index))
710         {
711           grp_set = dst_set = 1;
712           ip46_address_is_ip4 (&dst) ? (ipv4_set = 1) : (ipv6_set = 1);
713         }
714       else if (unformat (line_input, "encap-vrf-id %d", &table_id))
715         {
716           encap_fib_index =
717             fib_table_find (fib_ip_proto (ipv6_set), table_id);
718         }
719       else if (unformat (line_input, "decap-next %U", unformat_decap_next,
720                          &decap_next_index, ipv4_set))
721         ;
722       else if (unformat (line_input, "vni %d", &vni))
723         ;
724       else
725         {
726           parse_error = clib_error_return (0, "parse error: '%U'",
727                                            format_unformat_error, line_input);
728           break;
729         }
730     }
731
732   unformat_free (line_input);
733
734   if (parse_error)
735     return parse_error;
736
737   if (encap_fib_index == ~0)
738     return clib_error_return (0, "nonexistent encap-vrf-id %d", table_id);
739
740   if (src_set == 0)
741     return clib_error_return (0, "tunnel src address not specified");
742
743   if (dst_set == 0)
744     return clib_error_return (0, "tunnel dst address not specified");
745
746   if (grp_set && !ip46_address_is_multicast (&dst))
747     return clib_error_return (0, "tunnel group address not multicast");
748
749   if (grp_set == 0 && ip46_address_is_multicast (&dst))
750     return clib_error_return (0, "dst address must be unicast");
751
752   if (grp_set && mcast_sw_if_index == ~0)
753     return clib_error_return (0, "tunnel nonexistent multicast device");
754
755   if (ipv4_set && ipv6_set)
756     return clib_error_return (0, "both IPv4 and IPv6 addresses specified");
757
758   if (ip46_address_cmp (&src, &dst) == 0)
759     return clib_error_return (0, "src and dst addresses are identical");
760
761   if (decap_next_index == ~0)
762     return clib_error_return (0, "next node not found");
763
764   if (vni == 0)
765     return clib_error_return (0, "vni not specified");
766
767   if (vni >> 24)
768     return clib_error_return (0, "vni %d out of range", vni);
769
770   vnet_vxlan_add_del_tunnel_args_t a = {
771     .is_add = is_add,
772     .is_ip6 = ipv6_set,
773     .instance = instance,
774 #define _(x) .x = x,
775     foreach_copy_field
776 #undef _
777   };
778
779   u32 tunnel_sw_if_index;
780   int rv = vnet_vxlan_add_del_tunnel (&a, &tunnel_sw_if_index);
781
782   switch (rv)
783     {
784     case 0:
785       if (is_add)
786         vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
787                          vnet_get_main (), tunnel_sw_if_index);
788       break;
789
790     case VNET_API_ERROR_TUNNEL_EXIST:
791       return clib_error_return (0, "tunnel already exists...");
792
793     case VNET_API_ERROR_NO_SUCH_ENTRY:
794       return clib_error_return (0, "tunnel does not exist...");
795
796     case VNET_API_ERROR_INSTANCE_IN_USE:
797       return clib_error_return (0, "Instance is in use");
798
799     default:
800       return clib_error_return
801         (0, "vnet_vxlan_add_del_tunnel returned %d", rv);
802     }
803
804   return 0;
805 }
806
807 /*?
808  * Add or delete a VXLAN Tunnel.
809  *
810  * VXLAN provides the features needed to allow L2 bridge domains (BDs)
811  * to span multiple servers. This is done by building an L2 overlay on
812  * top of an L3 network underlay using VXLAN tunnels.
813  *
814  * This makes it possible for servers to be co-located in the same data
815  * center or be separated geographically as long as they are reachable
816  * through the underlay L3 network.
817  *
818  * You can refer to this kind of L2 overlay bridge domain as a VXLAN
819  * (Virtual eXtensible VLAN) segment.
820  *
821  * @cliexpar
822  * Example of how to create a VXLAN Tunnel:
823  * @cliexcmd{create vxlan tunnel src 10.0.3.1 dst 10.0.3.3 vni 13 encap-vrf-id 7}
824  * Example of how to create a VXLAN Tunnel with a known name, vxlan_tunnel42:
825  * @cliexcmd{create vxlan tunnel src 10.0.3.1 dst 10.0.3.3 instance 42}
826  * Example of how to create a multicast VXLAN Tunnel with a known name, vxlan_tunnel23:
827  * @cliexcmd{create vxlan tunnel src 10.0.3.1 group 239.1.1.1 GigabitEthernet0/8/0 instance 23}
828  * Example of how to delete a VXLAN Tunnel:
829  * @cliexcmd{create vxlan tunnel src 10.0.3.1 dst 10.0.3.3 vni 13 del}
830  ?*/
831 /* *INDENT-OFF* */
832 VLIB_CLI_COMMAND (create_vxlan_tunnel_command, static) = {
833   .path = "create vxlan tunnel",
834   .short_help =
835   "create vxlan tunnel src <local-vtep-addr>"
836   " {dst <remote-vtep-addr>|group <mcast-vtep-addr> <intf-name>} vni <nn>"
837   " [instance <id>]"
838   " [encap-vrf-id <nn>] [decap-next [l2|node <name>]] [del]",
839   .function = vxlan_add_del_tunnel_command_fn,
840 };
841 /* *INDENT-ON* */
842
843 static clib_error_t *
844 show_vxlan_tunnel_command_fn (vlib_main_t * vm,
845                               unformat_input_t * input,
846                               vlib_cli_command_t * cmd)
847 {
848   vxlan_main_t *vxm = &vxlan_main;
849   vxlan_tunnel_t *t;
850   int raw = 0;
851
852   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
853     {
854       if (unformat (input, "raw"))
855         raw = 1;
856       else
857         return clib_error_return (0, "parse error: '%U'",
858                                   format_unformat_error, input);
859     }
860
861   if (pool_elts (vxm->tunnels) == 0)
862     vlib_cli_output (vm, "No vxlan tunnels configured...");
863
864 /* *INDENT-OFF* */
865   pool_foreach (t, vxm->tunnels,
866   ({
867     vlib_cli_output (vm, "%U", format_vxlan_tunnel, t);
868   }));
869 /* *INDENT-ON* */
870
871   if (raw)
872     {
873       vlib_cli_output (vm, "Raw IPv4 Hash Table:\n%U\n",
874                        format_bihash_16_8, &vxm->vxlan4_tunnel_by_key,
875                        1 /* verbose */ );
876       vlib_cli_output (vm, "Raw IPv6 Hash Table:\n%U\n",
877                        format_bihash_24_8, &vxm->vxlan6_tunnel_by_key,
878                        1 /* verbose */ );
879     }
880
881   return 0;
882 }
883
884 /*?
885  * Display all the VXLAN Tunnel entries.
886  *
887  * @cliexpar
888  * Example of how to display the VXLAN Tunnel entries:
889  * @cliexstart{show vxlan tunnel}
890  * [0] src 10.0.3.1 dst 10.0.3.3 vni 13 encap_fib_index 0 sw_if_index 5 decap_next l2
891  * @cliexend
892  ?*/
893 /* *INDENT-OFF* */
894 VLIB_CLI_COMMAND (show_vxlan_tunnel_command, static) = {
895     .path = "show vxlan tunnel",
896     .short_help = "show vxlan tunnel [raw]",
897     .function = show_vxlan_tunnel_command_fn,
898 };
899 /* *INDENT-ON* */
900
901
902 void
903 vnet_int_vxlan_bypass_mode (u32 sw_if_index, u8 is_ip6, u8 is_enable)
904 {
905   vxlan_main_t *vxm = &vxlan_main;
906
907   if (pool_is_free_index (vxm->vnet_main->interface_main.sw_interfaces,
908                           sw_if_index))
909     return;
910
911   is_enable = ! !is_enable;
912
913   if (is_ip6)
914     {
915       if (clib_bitmap_get (vxm->bm_ip6_bypass_enabled_by_sw_if, sw_if_index)
916           != is_enable)
917         {
918           vnet_feature_enable_disable ("ip6-unicast", "ip6-vxlan-bypass",
919                                        sw_if_index, is_enable, 0, 0);
920           vxm->bm_ip6_bypass_enabled_by_sw_if =
921             clib_bitmap_set (vxm->bm_ip6_bypass_enabled_by_sw_if,
922                              sw_if_index, is_enable);
923         }
924     }
925   else
926     {
927       if (clib_bitmap_get (vxm->bm_ip4_bypass_enabled_by_sw_if, sw_if_index)
928           != is_enable)
929         {
930           vnet_feature_enable_disable ("ip4-unicast", "ip4-vxlan-bypass",
931                                        sw_if_index, is_enable, 0, 0);
932           vxm->bm_ip4_bypass_enabled_by_sw_if =
933             clib_bitmap_set (vxm->bm_ip4_bypass_enabled_by_sw_if,
934                              sw_if_index, is_enable);
935         }
936     }
937 }
938
939
940 static clib_error_t *
941 set_ip_vxlan_bypass (u32 is_ip6,
942                      unformat_input_t * input, vlib_cli_command_t * cmd)
943 {
944   unformat_input_t _line_input, *line_input = &_line_input;
945   vnet_main_t *vnm = vnet_get_main ();
946   clib_error_t *error = 0;
947   u32 sw_if_index, is_enable;
948
949   sw_if_index = ~0;
950   is_enable = 1;
951
952   if (!unformat_user (input, unformat_line_input, line_input))
953     return 0;
954
955   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
956     {
957       if (unformat_user
958           (line_input, unformat_vnet_sw_interface, vnm, &sw_if_index))
959         ;
960       else if (unformat (line_input, "del"))
961         is_enable = 0;
962       else
963         {
964           error = unformat_parse_error (line_input);
965           goto done;
966         }
967     }
968
969   if (~0 == sw_if_index)
970     {
971       error = clib_error_return (0, "unknown interface `%U'",
972                                  format_unformat_error, line_input);
973       goto done;
974     }
975
976   vnet_int_vxlan_bypass_mode (sw_if_index, is_ip6, is_enable);
977
978 done:
979   unformat_free (line_input);
980
981   return error;
982 }
983
984 static clib_error_t *
985 set_ip4_vxlan_bypass (vlib_main_t * vm,
986                       unformat_input_t * input, vlib_cli_command_t * cmd)
987 {
988   return set_ip_vxlan_bypass (0, input, cmd);
989 }
990
991 /*?
992  * This command adds the 'ip4-vxlan-bypass' graph node for a given interface.
993  * By adding the IPv4 vxlan-bypass graph node to an interface, the node checks
994  *  for and validate input vxlan packet and bypass ip4-lookup, ip4-local,
995  * ip4-udp-lookup nodes to speedup vxlan packet forwarding. This node will
996  * cause extra overhead to for non-vxlan packets which is kept at a minimum.
997  *
998  * @cliexpar
999  * @parblock
1000  * Example of graph node before ip4-vxlan-bypass is enabled:
1001  * @cliexstart{show vlib graph ip4-vxlan-bypass}
1002  *            Name                      Next                    Previous
1003  * ip4-vxlan-bypass                error-drop [0]
1004  *                                vxlan4-input [1]
1005  *                                 ip4-lookup [2]
1006  * @cliexend
1007  *
1008  * Example of how to enable ip4-vxlan-bypass on an interface:
1009  * @cliexcmd{set interface ip vxlan-bypass GigabitEthernet2/0/0}
1010  *
1011  * Example of graph node after ip4-vxlan-bypass is enabled:
1012  * @cliexstart{show vlib graph ip4-vxlan-bypass}
1013  *            Name                      Next                    Previous
1014  * ip4-vxlan-bypass                error-drop [0]               ip4-input
1015  *                                vxlan4-input [1]        ip4-input-no-checksum
1016  *                                 ip4-lookup [2]
1017  * @cliexend
1018  *
1019  * Example of how to display the feature enabled on an interface:
1020  * @cliexstart{show ip interface features GigabitEthernet2/0/0}
1021  * IP feature paths configured on GigabitEthernet2/0/0...
1022  * ...
1023  * ipv4 unicast:
1024  *   ip4-vxlan-bypass
1025  *   ip4-lookup
1026  * ...
1027  * @cliexend
1028  *
1029  * Example of how to disable ip4-vxlan-bypass on an interface:
1030  * @cliexcmd{set interface ip vxlan-bypass GigabitEthernet2/0/0 del}
1031  * @endparblock
1032 ?*/
1033 /* *INDENT-OFF* */
1034 VLIB_CLI_COMMAND (set_interface_ip_vxlan_bypass_command, static) = {
1035   .path = "set interface ip vxlan-bypass",
1036   .function = set_ip4_vxlan_bypass,
1037   .short_help = "set interface ip vxlan-bypass <interface> [del]",
1038 };
1039 /* *INDENT-ON* */
1040
1041 static clib_error_t *
1042 set_ip6_vxlan_bypass (vlib_main_t * vm,
1043                       unformat_input_t * input, vlib_cli_command_t * cmd)
1044 {
1045   return set_ip_vxlan_bypass (1, input, cmd);
1046 }
1047
1048 /*?
1049  * This command adds the 'ip6-vxlan-bypass' graph node for a given interface.
1050  * By adding the IPv6 vxlan-bypass graph node to an interface, the node checks
1051  *  for and validate input vxlan packet and bypass ip6-lookup, ip6-local,
1052  * ip6-udp-lookup nodes to speedup vxlan packet forwarding. This node will
1053  * cause extra overhead to for non-vxlan packets which is kept at a minimum.
1054  *
1055  * @cliexpar
1056  * @parblock
1057  * Example of graph node before ip6-vxlan-bypass is enabled:
1058  * @cliexstart{show vlib graph ip6-vxlan-bypass}
1059  *            Name                      Next                    Previous
1060  * ip6-vxlan-bypass                error-drop [0]
1061  *                                vxlan6-input [1]
1062  *                                 ip6-lookup [2]
1063  * @cliexend
1064  *
1065  * Example of how to enable ip6-vxlan-bypass on an interface:
1066  * @cliexcmd{set interface ip6 vxlan-bypass GigabitEthernet2/0/0}
1067  *
1068  * Example of graph node after ip6-vxlan-bypass is enabled:
1069  * @cliexstart{show vlib graph ip6-vxlan-bypass}
1070  *            Name                      Next                    Previous
1071  * ip6-vxlan-bypass                error-drop [0]               ip6-input
1072  *                                vxlan6-input [1]        ip4-input-no-checksum
1073  *                                 ip6-lookup [2]
1074  * @cliexend
1075  *
1076  * Example of how to display the feature enabled on an interface:
1077  * @cliexstart{show ip interface features GigabitEthernet2/0/0}
1078  * IP feature paths configured on GigabitEthernet2/0/0...
1079  * ...
1080  * ipv6 unicast:
1081  *   ip6-vxlan-bypass
1082  *   ip6-lookup
1083  * ...
1084  * @cliexend
1085  *
1086  * Example of how to disable ip6-vxlan-bypass on an interface:
1087  * @cliexcmd{set interface ip6 vxlan-bypass GigabitEthernet2/0/0 del}
1088  * @endparblock
1089 ?*/
1090 /* *INDENT-OFF* */
1091 VLIB_CLI_COMMAND (set_interface_ip6_vxlan_bypass_command, static) = {
1092   .path = "set interface ip6 vxlan-bypass",
1093   .function = set_ip6_vxlan_bypass,
1094   .short_help = "set interface ip6 vxlan-bypass <interface> [del]",
1095 };
1096 /* *INDENT-ON* */
1097
1098 int
1099 vnet_vxlan_add_del_rx_flow (u32 hw_if_index, u32 t_index, int is_add)
1100 {
1101   vxlan_main_t *vxm = &vxlan_main;
1102   vxlan_tunnel_t *t = pool_elt_at_index (vxm->tunnels, t_index);
1103   vnet_main_t *vnm = vnet_get_main ();
1104   if (is_add)
1105     {
1106       if (t->flow_index == ~0)
1107         {
1108           vxlan_main_t *vxm = &vxlan_main;
1109           vnet_flow_t flow = {
1110             .actions =
1111               VNET_FLOW_ACTION_REDIRECT_TO_NODE | VNET_FLOW_ACTION_MARK |
1112               VNET_FLOW_ACTION_BUFFER_ADVANCE,
1113             .mark_flow_id = t->dev_instance + vxm->flow_id_start,
1114             .redirect_node_index = vxlan4_flow_input_node.index,
1115             .buffer_advance = sizeof (ethernet_header_t),
1116             .type = VNET_FLOW_TYPE_IP4_VXLAN,
1117             .ip4_vxlan = {
1118                           .protocol.prot = IP_PROTOCOL_UDP,
1119                           .src_addr.addr = t->dst.ip4,
1120                           .dst_addr.addr = t->src.ip4,
1121                           .src_addr.mask.as_u32 = ~0,
1122                           .dst_addr.mask.as_u32 = ~0,
1123                           .dst_port.port = UDP_DST_PORT_vxlan,
1124                           .dst_port.mask = 0xFF,
1125                           .vni = t->vni,
1126                           }
1127             ,
1128           };
1129           vnet_flow_add (vnm, &flow, &t->flow_index);
1130         }
1131       return vnet_flow_enable (vnm, t->flow_index, hw_if_index);
1132     }
1133   /* flow index is removed when the tunnel is deleted */
1134   return vnet_flow_disable (vnm, t->flow_index, hw_if_index);
1135 }
1136
1137 u32
1138 vnet_vxlan_get_tunnel_index (u32 sw_if_index)
1139 {
1140   vxlan_main_t *vxm = &vxlan_main;
1141
1142   if (sw_if_index >= vec_len (vxm->tunnel_index_by_sw_if_index))
1143     return ~0;
1144   return vxm->tunnel_index_by_sw_if_index[sw_if_index];
1145 }
1146
1147 static clib_error_t *
1148 vxlan_offload_command_fn (vlib_main_t * vm,
1149                           unformat_input_t * input, vlib_cli_command_t * cmd)
1150 {
1151   unformat_input_t _line_input, *line_input = &_line_input;
1152
1153   /* Get a line of input. */
1154   if (!unformat_user (input, unformat_line_input, line_input))
1155     return 0;
1156
1157   vnet_main_t *vnm = vnet_get_main ();
1158   u32 rx_sw_if_index = ~0;
1159   u32 hw_if_index = ~0;
1160   int is_add = 1;
1161
1162   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1163     {
1164       if (unformat (line_input, "hw %U", unformat_vnet_hw_interface, vnm,
1165                     &hw_if_index))
1166         continue;
1167       if (unformat (line_input, "rx %U", unformat_vnet_sw_interface, vnm,
1168                     &rx_sw_if_index))
1169         continue;
1170       if (unformat (line_input, "del"))
1171         {
1172           is_add = 0;
1173           continue;
1174         }
1175       return clib_error_return (0, "unknown input `%U'",
1176                                 format_unformat_error, line_input);
1177     }
1178
1179   if (rx_sw_if_index == ~0)
1180     return clib_error_return (0, "missing rx interface");
1181   if (hw_if_index == ~0)
1182     return clib_error_return (0, "missing hw interface");
1183
1184   u32 t_index = vnet_vxlan_get_tunnel_index (rx_sw_if_index);;
1185   if (t_index == ~0)
1186     return clib_error_return (0, "%U is not a vxlan tunnel",
1187                               format_vnet_sw_if_index_name, vnm,
1188                               rx_sw_if_index);
1189
1190   vxlan_main_t *vxm = &vxlan_main;
1191   vxlan_tunnel_t *t = pool_elt_at_index (vxm->tunnels, t_index);
1192
1193   if (!ip46_address_is_ip4 (&t->dst))
1194     return clib_error_return (0, "currently only IPV4 tunnels are supported");
1195
1196   vnet_hw_interface_t *hw_if = vnet_get_hw_interface (vnm, hw_if_index);
1197   ip4_main_t *im = &ip4_main;
1198   u32 rx_fib_index =
1199     vec_elt (im->fib_index_by_sw_if_index, hw_if->sw_if_index);
1200
1201   if (t->encap_fib_index != rx_fib_index)
1202     return clib_error_return (0, "interface/tunnel fib mismatch");
1203
1204   if (vnet_vxlan_add_del_rx_flow (hw_if_index, t_index, is_add))
1205     return clib_error_return (0, "error %s flow",
1206                               is_add ? "enabling" : "disabling");
1207
1208   return 0;
1209 }
1210
1211 /* *INDENT-OFF* */
1212 VLIB_CLI_COMMAND (vxlan_offload_command, static) = {
1213     .path = "set flow-offload vxlan",
1214     .short_help =
1215     "set flow-offload vxlan hw <interface-name> rx <tunnel-name> [del]",
1216     .function = vxlan_offload_command_fn,
1217 };
1218 /* *INDENT-ON* */
1219
1220 #define VXLAN_HASH_NUM_BUCKETS (2 * 1024)
1221 #define VXLAN_HASH_MEMORY_SIZE (1 << 20)
1222
1223 clib_error_t *
1224 vxlan_init (vlib_main_t * vm)
1225 {
1226   vxlan_main_t *vxm = &vxlan_main;
1227
1228   vxm->vnet_main = vnet_get_main ();
1229   vxm->vlib_main = vm;
1230
1231   vnet_flow_get_range (vxm->vnet_main, "vxlan", 1024 * 1024,
1232                        &vxm->flow_id_start);
1233
1234   vxm->bm_ip4_bypass_enabled_by_sw_if = 0;
1235   vxm->bm_ip6_bypass_enabled_by_sw_if = 0;
1236
1237   /* initialize the ip6 hash */
1238   clib_bihash_init_16_8 (&vxm->vxlan4_tunnel_by_key, "vxlan4",
1239                          VXLAN_HASH_NUM_BUCKETS, VXLAN_HASH_MEMORY_SIZE);
1240   clib_bihash_init_24_8 (&vxm->vxlan6_tunnel_by_key, "vxlan6",
1241                          VXLAN_HASH_NUM_BUCKETS, VXLAN_HASH_MEMORY_SIZE);
1242   vxm->vtep_table = vtep_table_create ();
1243   vxm->mcast_shared = hash_create_mem (0,
1244                                        sizeof (ip46_address_t),
1245                                        sizeof (mcast_shared_t));
1246
1247   fib_node_register_type (FIB_NODE_TYPE_VXLAN_TUNNEL, &vxlan_vft);
1248
1249   return 0;
1250 }
1251
1252 VLIB_INIT_FUNCTION (vxlan_init);
1253
1254 /*
1255  * fd.io coding-style-patch-verification: ON
1256  *
1257  * Local Variables:
1258  * eval: (c-set-style "gnu")
1259  * End:
1260  */