Unify and cleanup usage of hash_set/unset_mem by various tunnels
[vpp.git] / src / vnet / geneve / geneve.c
1 /*
2  * Copyright (c) 2017 SUSE LLC.
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/geneve/geneve.h>
16 #include <vnet/ip/format.h>
17 #include <vnet/fib/fib_entry.h>
18 #include <vnet/fib/fib_table.h>
19 #include <vnet/mfib/mfib_table.h>
20 #include <vnet/adj/adj_mcast.h>
21 #include <vnet/interface.h>
22 #include <vlib/vlib.h>
23
24 /**
25  * @file
26  * @brief GENEVE.
27  *
28  * GENEVE provides the features needed to allow L2 bridge domains (BDs)
29  * to span multiple servers. This is done by building an L2 overlay on
30  * top of an L3 network underlay using GENEVE tunnels.
31  *
32  * This makes it possible for servers to be co-located in the same data
33  * center or be separated geographically as long as they are reachable
34  * through the underlay L3 network.
35  */
36
37
38 geneve_main_t geneve_main;
39
40 static u8 *
41 format_decap_next (u8 * s, va_list * args)
42 {
43   u32 next_index = va_arg (*args, u32);
44
45   switch (next_index)
46     {
47     case GENEVE_INPUT_NEXT_DROP:
48       return format (s, "drop");
49     case GENEVE_INPUT_NEXT_L2_INPUT:
50       return format (s, "l2");
51     default:
52       return format (s, "index %d", next_index);
53     }
54   return s;
55 }
56
57 u8 *
58 format_geneve_tunnel (u8 * s, va_list * args)
59 {
60   geneve_tunnel_t *t = va_arg (*args, geneve_tunnel_t *);
61   geneve_main_t *ngm = &geneve_main;
62
63   s = format (s, "[%d] local %U remote %U vni %d sw_if_index %d ",
64               t - ngm->tunnels,
65               format_ip46_address, &t->local, IP46_TYPE_ANY,
66               format_ip46_address, &t->remote, IP46_TYPE_ANY,
67               t->vni, t->sw_if_index);
68
69   if (ip46_address_is_multicast (&t->remote))
70     s = format (s, "mcast_sw_if_index %d ", t->mcast_sw_if_index);
71
72   s = format (s, "encap_fib_index %d fib_entry_index %d decap_next %U\n",
73               t->encap_fib_index, t->fib_entry_index,
74               format_decap_next, t->decap_next_index);
75   return s;
76 }
77
78 static u8 *
79 format_geneve_name (u8 * s, va_list * args)
80 {
81   u32 dev_instance = va_arg (*args, u32);
82   return format (s, "geneve_tunnel%d", dev_instance);
83 }
84
85 static uword
86 dummy_interface_tx (vlib_main_t * vm,
87                     vlib_node_runtime_t * node, vlib_frame_t * frame)
88 {
89   clib_warning ("you shouldn't be here, leaking buffers...");
90   return frame->n_vectors;
91 }
92
93 static clib_error_t *
94 geneve_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
95 {
96   u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
97     VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
98   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
99
100   return /* no error */ 0;
101 }
102
103 /* *INDENT-OFF* */
104 VNET_DEVICE_CLASS (geneve_device_class, static) = {
105   .name = "GENEVE",
106   .format_device_name = format_geneve_name,
107   .format_tx_trace = format_geneve_encap_trace,
108   .tx_function = dummy_interface_tx,
109   .admin_up_down_function = geneve_interface_admin_up_down,
110 };
111 /* *INDENT-ON* */
112
113 static u8 *
114 format_geneve_header_with_length (u8 * s, va_list * args)
115 {
116   u32 dev_instance = va_arg (*args, u32);
117   s = format (s, "unimplemented dev %u", dev_instance);
118   return s;
119 }
120
121 /* *INDENT-OFF* */
122 VNET_HW_INTERFACE_CLASS (geneve_hw_class) = {
123   .name = "GENEVE",
124   .format_header = format_geneve_header_with_length,
125   .build_rewrite = default_build_rewrite,
126 };
127 /* *INDENT-ON* */
128
129 static void
130 geneve_tunnel_restack_dpo (geneve_tunnel_t * t)
131 {
132   dpo_id_t dpo = DPO_INVALID;
133   u32 encap_index = ip46_address_is_ip4 (&t->remote) ?
134     geneve4_encap_node.index : geneve6_encap_node.index;
135   fib_forward_chain_type_t forw_type = ip46_address_is_ip4 (&t->remote) ?
136     FIB_FORW_CHAIN_TYPE_UNICAST_IP4 : FIB_FORW_CHAIN_TYPE_UNICAST_IP6;
137
138   fib_entry_contribute_forwarding (t->fib_entry_index, forw_type, &dpo);
139   dpo_stack_from_node (encap_index, &t->next_dpo, &dpo);
140   dpo_reset (&dpo);
141 }
142
143 static geneve_tunnel_t *
144 geneve_tunnel_from_fib_node (fib_node_t * node)
145 {
146   ASSERT (FIB_NODE_TYPE_GENEVE_TUNNEL == node->fn_type);
147   return ((geneve_tunnel_t *) (((char *) node) -
148                                STRUCT_OFFSET_OF (geneve_tunnel_t, node)));
149 }
150
151 /**
152  * Function definition to backwalk a FIB node -
153  * Here we will restack the new dpo of GENEVE DIP to encap node.
154  */
155 static fib_node_back_walk_rc_t
156 geneve_tunnel_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
157 {
158   geneve_tunnel_restack_dpo (geneve_tunnel_from_fib_node (node));
159   return (FIB_NODE_BACK_WALK_CONTINUE);
160 }
161
162 /**
163  * Function definition to get a FIB node from its index
164  */
165 static fib_node_t *
166 geneve_tunnel_fib_node_get (fib_node_index_t index)
167 {
168   geneve_tunnel_t *t;
169   geneve_main_t *vxm = &geneve_main;
170
171   t = pool_elt_at_index (vxm->tunnels, index);
172
173   return (&t->node);
174 }
175
176 /**
177  * Function definition to inform the FIB node that its last lock has gone.
178  */
179 static void
180 geneve_tunnel_last_lock_gone (fib_node_t * node)
181 {
182   /*
183    * The GENEVE tunnel is a root of the graph. As such
184    * it never has children and thus is never locked.
185    */
186   ASSERT (0);
187 }
188
189 /*
190  * Virtual function table registered by GENEVE tunnels
191  * for participation in the FIB object graph.
192  */
193 const static fib_node_vft_t geneve_vft = {
194   .fnv_get = geneve_tunnel_fib_node_get,
195   .fnv_last_lock = geneve_tunnel_last_lock_gone,
196   .fnv_back_walk = geneve_tunnel_back_walk,
197 };
198
199
200 #define foreach_copy_field                      \
201 _(vni)                                          \
202 _(mcast_sw_if_index)                            \
203 _(encap_fib_index)                              \
204 _(decap_next_index)                             \
205 _(local)                                          \
206 _(remote)
207
208 static int
209 geneve_rewrite (geneve_tunnel_t * t, bool is_ip6)
210 {
211   union
212   {
213     ip4_geneve_header_t *h4;
214     ip6_geneve_header_t *h6;
215     u8 *rw;
216   } r =
217   {
218   .rw = 0};
219   int len = is_ip6 ? sizeof *r.h6 : sizeof *r.h4;
220 #if SUPPORT_OPTIONS_HEADER==1
221   len += t->options_len;
222 #endif
223
224   vec_validate_aligned (r.rw, len - 1, CLIB_CACHE_LINE_BYTES);
225
226   udp_header_t *udp;
227   geneve_header_t *geneve;
228   /* Fixed portion of the (outer) ip header */
229   if (!is_ip6)
230     {
231       ip4_header_t *ip = &r.h4->ip4;
232       udp = &r.h4->udp, geneve = &r.h4->geneve;
233       ip->ip_version_and_header_length = 0x45;
234       ip->ttl = 254;
235       ip->protocol = IP_PROTOCOL_UDP;
236
237       ip->src_address = t->local.ip4;
238       ip->dst_address = t->remote.ip4;
239
240       /* we fix up the ip4 header length and checksum after-the-fact */
241       ip->checksum = ip4_header_checksum (ip);
242     }
243   else
244     {
245       ip6_header_t *ip = &r.h6->ip6;
246       udp = &r.h6->udp, geneve = &r.h6->geneve;
247       ip->ip_version_traffic_class_and_flow_label =
248         clib_host_to_net_u32 (6 << 28);
249       ip->hop_limit = 255;
250       ip->protocol = IP_PROTOCOL_UDP;
251
252       ip->src_address = t->local.ip6;
253       ip->dst_address = t->remote.ip6;
254     }
255
256   /* UDP header, randomize local port on something, maybe? */
257   udp->src_port = clib_host_to_net_u16 (5251);
258   udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_geneve);
259
260   /* GENEVE header */
261   vnet_set_geneve_version (geneve, GENEVE_VERSION);
262 #if SUPPORT_OPTIONS_HEADER==1
263   vnet_set_geneve_options_len (geneve, t->options_len);
264 #else
265   vnet_set_geneve_options_len (geneve, 0);
266 #endif
267   vnet_set_geneve_oamframe_bit (geneve, 0);
268   vnet_set_geneve_critical_bit (geneve, 0);
269   vnet_set_geneve_protocol (geneve, GENEVE_ETH_PROTOCOL);
270
271   vnet_geneve_hdr_1word_hton (geneve);
272
273   vnet_set_geneve_vni (geneve, t->vni);
274
275   t->rewrite = r.rw;
276   return (0);
277 }
278
279 static bool
280 geneve_decap_next_is_valid (geneve_main_t * vxm, u32 is_ip6,
281                             u32 decap_next_index)
282 {
283   vlib_main_t *vm = vxm->vlib_main;
284   u32 input_idx =
285     (!is_ip6) ? geneve4_input_node.index : geneve6_input_node.index;
286   vlib_node_runtime_t *r = vlib_node_get_runtime (vm, input_idx);
287
288   return decap_next_index < r->n_next_nodes;
289 }
290
291 static uword
292 vtep_addr_ref (ip46_address_t * ip)
293 {
294   uword *vtep = ip46_address_is_ip4 (ip) ?
295     hash_get (geneve_main.vtep4, ip->ip4.as_u32) :
296     hash_get_mem (geneve_main.vtep6, &ip->ip6);
297   if (vtep)
298     return ++(*vtep);
299   ip46_address_is_ip4 (ip) ?
300     hash_set (geneve_main.vtep4, ip->ip4.as_u32, 1) :
301     hash_set_mem_alloc (&geneve_main.vtep6, &ip->ip6, 1);
302   return 1;
303 }
304
305 static uword
306 vtep_addr_unref (ip46_address_t * ip)
307 {
308   uword *vtep = ip46_address_is_ip4 (ip) ?
309     hash_get (geneve_main.vtep4, ip->ip4.as_u32) :
310     hash_get_mem (geneve_main.vtep6, &ip->ip6);
311   ASSERT (vtep);
312   if (--(*vtep) != 0)
313     return *vtep;
314   ip46_address_is_ip4 (ip) ?
315     hash_unset (geneve_main.vtep4, ip->ip4.as_u32) :
316     hash_unset_mem_free (&geneve_main.vtep6, &ip->ip6);
317   return 0;
318 }
319
320 typedef CLIB_PACKED (union
321                      {
322                      struct
323                      {
324                      fib_node_index_t mfib_entry_index;
325                      adj_index_t mcast_adj_index;
326                      }; u64 as_u64;
327                      }) mcast_shared_t;
328
329 static inline mcast_shared_t
330 mcast_shared_get (ip46_address_t * ip)
331 {
332   ASSERT (ip46_address_is_multicast (ip));
333   uword *p = hash_get_mem (geneve_main.mcast_shared, ip);
334   ASSERT (p);
335   return (mcast_shared_t)
336   {
337   .as_u64 = *p};
338 }
339
340 static inline void
341 mcast_shared_add (ip46_address_t * remote,
342                   fib_node_index_t mfei, adj_index_t ai)
343 {
344   mcast_shared_t new_ep = {
345     .mcast_adj_index = ai,
346     .mfib_entry_index = mfei,
347   };
348
349   hash_set_mem_alloc (&geneve_main.mcast_shared, remote, new_ep.as_u64);
350 }
351
352 static inline void
353 mcast_shared_remove (ip46_address_t * remote)
354 {
355   mcast_shared_t ep = mcast_shared_get (remote);
356
357   adj_unlock (ep.mcast_adj_index);
358   mfib_table_entry_delete_index (ep.mfib_entry_index, MFIB_SOURCE_GENEVE);
359
360   hash_unset_mem_free (&geneve_main.mcast_shared, remote);
361 }
362
363 static inline fib_protocol_t
364 fib_ip_proto (bool is_ip6)
365 {
366   return (is_ip6) ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4;
367 }
368
369 int vnet_geneve_add_del_tunnel
370   (vnet_geneve_add_del_tunnel_args_t * a, u32 * sw_if_indexp)
371 {
372   geneve_main_t *vxm = &geneve_main;
373   geneve_tunnel_t *t = 0;
374   vnet_main_t *vnm = vxm->vnet_main;
375   uword *p;
376   u32 hw_if_index = ~0;
377   u32 sw_if_index = ~0;
378   int rv;
379   geneve4_tunnel_key_t key4;
380   geneve6_tunnel_key_t key6;
381   u32 is_ip6 = a->is_ip6;
382
383   if (!is_ip6)
384     {
385       key4.remote = a->remote.ip4.as_u32;
386       key4.vni =
387         clib_host_to_net_u32 ((a->vni << GENEVE_VNI_SHIFT) & GENEVE_VNI_MASK);
388       p = hash_get (vxm->geneve4_tunnel_by_key, key4.as_u64);
389     }
390   else
391     {
392       key6.remote = a->remote.ip6;
393       key6.vni =
394         clib_host_to_net_u32 ((a->vni << GENEVE_VNI_SHIFT) & GENEVE_VNI_MASK);
395       p = hash_get_mem (vxm->geneve6_tunnel_by_key, &key6);
396     }
397
398   if (a->is_add)
399     {
400       l2input_main_t *l2im = &l2input_main;
401
402       /* adding a tunnel: tunnel must not already exist */
403       if (p)
404         return VNET_API_ERROR_TUNNEL_EXIST;
405
406       /*if not set explicitly, default to l2 */
407       if (a->decap_next_index == ~0)
408         a->decap_next_index = GENEVE_INPUT_NEXT_L2_INPUT;
409       if (!geneve_decap_next_is_valid (vxm, is_ip6, a->decap_next_index))
410         return VNET_API_ERROR_INVALID_DECAP_NEXT;
411
412       pool_get_aligned (vxm->tunnels, t, CLIB_CACHE_LINE_BYTES);
413       memset (t, 0, sizeof (*t));
414
415       /* copy from arg structure */
416 #define _(x) t->x = a->x;
417       foreach_copy_field;
418 #undef _
419
420       rv = geneve_rewrite (t, is_ip6);
421       if (rv)
422         {
423           pool_put (vxm->tunnels, t);
424           return rv;
425         }
426
427       /* copy the key */
428       if (is_ip6)
429         hash_set_mem_alloc (&vxm->geneve6_tunnel_by_key, &key6,
430                             t - vxm->tunnels);
431       else
432         hash_set (vxm->geneve4_tunnel_by_key, key4.as_u64, t - vxm->tunnels);
433
434       vnet_hw_interface_t *hi;
435       if (vec_len (vxm->free_geneve_tunnel_hw_if_indices) > 0)
436         {
437           vnet_interface_main_t *im = &vnm->interface_main;
438           hw_if_index = vxm->free_geneve_tunnel_hw_if_indices
439             [vec_len (vxm->free_geneve_tunnel_hw_if_indices) - 1];
440           _vec_len (vxm->free_geneve_tunnel_hw_if_indices) -= 1;
441
442           hi = vnet_get_hw_interface (vnm, hw_if_index);
443           hi->dev_instance = t - vxm->tunnels;
444           hi->hw_instance = hi->dev_instance;
445
446           /* clear old stats of freed tunnel before reuse */
447           sw_if_index = hi->sw_if_index;
448           vnet_interface_counter_lock (im);
449           vlib_zero_combined_counter
450             (&im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX],
451              sw_if_index);
452           vlib_zero_combined_counter (&im->combined_sw_if_counters
453                                       [VNET_INTERFACE_COUNTER_RX],
454                                       sw_if_index);
455           vlib_zero_simple_counter (&im->sw_if_counters
456                                     [VNET_INTERFACE_COUNTER_DROP],
457                                     sw_if_index);
458           vnet_interface_counter_unlock (im);
459         }
460       else
461         {
462           hw_if_index = vnet_register_interface
463             (vnm, geneve_device_class.index, t - vxm->tunnels,
464              geneve_hw_class.index, t - vxm->tunnels);
465           hi = vnet_get_hw_interface (vnm, hw_if_index);
466         }
467
468       t->hw_if_index = hw_if_index;
469       t->sw_if_index = sw_if_index = hi->sw_if_index;
470
471       vec_validate_init_empty (vxm->tunnel_index_by_sw_if_index, sw_if_index,
472                                ~0);
473       vxm->tunnel_index_by_sw_if_index[sw_if_index] = t - vxm->tunnels;
474
475       /* setup l2 input config with l2 feature and bd 0 to drop packet */
476       vec_validate (l2im->configs, sw_if_index);
477       l2im->configs[sw_if_index].feature_bitmap = L2INPUT_FEAT_DROP;
478       l2im->configs[sw_if_index].bd_index = 0;
479
480       vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
481       si->flags &= ~VNET_SW_INTERFACE_FLAG_HIDDEN;
482       vnet_sw_interface_set_flags (vnm, sw_if_index,
483                                    VNET_SW_INTERFACE_FLAG_ADMIN_UP);
484
485       fib_node_init (&t->node, FIB_NODE_TYPE_GENEVE_TUNNEL);
486       fib_prefix_t tun_remote_pfx;
487       u32 encap_index = !is_ip6 ?
488         geneve4_encap_node.index : geneve6_encap_node.index;
489       vnet_flood_class_t flood_class = VNET_FLOOD_CLASS_TUNNEL_NORMAL;
490
491       fib_prefix_from_ip46_addr (&t->remote, &tun_remote_pfx);
492       if (!ip46_address_is_multicast (&t->remote))
493         {
494           /* Unicast tunnel -
495            * source the FIB entry for the tunnel's destination
496            * and become a child thereof. The tunnel will then get poked
497            * when the forwarding for the entry updates, and the tunnel can
498            * re-stack accordingly
499            */
500           vtep_addr_ref (&t->local);
501           t->fib_entry_index = fib_table_entry_special_add
502             (t->encap_fib_index, &tun_remote_pfx, FIB_SOURCE_RR,
503              FIB_ENTRY_FLAG_NONE);
504           t->sibling_index = fib_entry_child_add
505             (t->fib_entry_index, FIB_NODE_TYPE_GENEVE_TUNNEL,
506              t - vxm->tunnels);
507           geneve_tunnel_restack_dpo (t);
508         }
509       else
510         {
511           /* Multicast tunnel -
512            * as the same mcast group can be used for mutiple mcast tunnels
513            * with different VNIs, create the output fib adjecency only if
514            * it does not already exist
515            */
516           fib_protocol_t fp = fib_ip_proto (is_ip6);
517
518           if (vtep_addr_ref (&t->remote) == 1)
519             {
520               fib_node_index_t mfei;
521               adj_index_t ai;
522               fib_route_path_t path = {
523                 .frp_proto = fib_proto_to_dpo (fp),
524                 .frp_addr = zero_addr,
525                 .frp_sw_if_index = 0xffffffff,
526                 .frp_fib_index = ~0,
527                 .frp_weight = 0,
528                 .frp_flags = FIB_ROUTE_PATH_LOCAL,
529               };
530               const mfib_prefix_t mpfx = {
531                 .fp_proto = fp,
532                 .fp_len = (is_ip6 ? 128 : 32),
533                 .fp_grp_addr = tun_remote_pfx.fp_addr,
534               };
535
536               /*
537                * Setup the (*,G) to receive traffic on the mcast group
538                *  - the forwarding interface is for-us
539                *  - the accepting interface is that from the API
540                */
541               mfib_table_entry_path_update (t->encap_fib_index,
542                                             &mpfx,
543                                             MFIB_SOURCE_GENEVE,
544                                             &path, MFIB_ITF_FLAG_FORWARD);
545
546               path.frp_sw_if_index = a->mcast_sw_if_index;
547               path.frp_flags = FIB_ROUTE_PATH_FLAG_NONE;
548               mfei = mfib_table_entry_path_update (t->encap_fib_index,
549                                                    &mpfx,
550                                                    MFIB_SOURCE_GENEVE,
551                                                    &path,
552                                                    MFIB_ITF_FLAG_ACCEPT);
553
554               /*
555                * Create the mcast adjacency to send traffic to the group
556                */
557               ai = adj_mcast_add_or_lock (fp,
558                                           fib_proto_to_link (fp),
559                                           a->mcast_sw_if_index);
560
561               /*
562                * create a new end-point
563                */
564               mcast_shared_add (&t->remote, mfei, ai);
565             }
566
567           dpo_id_t dpo = DPO_INVALID;
568           mcast_shared_t ep = mcast_shared_get (&t->remote);
569
570           /* Stack shared mcast remote mac addr rewrite on encap */
571           dpo_set (&dpo, DPO_ADJACENCY_MCAST,
572                    fib_proto_to_dpo (fp), ep.mcast_adj_index);
573
574           dpo_stack_from_node (encap_index, &t->next_dpo, &dpo);
575           dpo_reset (&dpo);
576           flood_class = VNET_FLOOD_CLASS_TUNNEL_MASTER;
577         }
578
579       /* Set geneve tunnel output node */
580       hi->output_node_index = encap_index;
581
582       vnet_get_sw_interface (vnet_get_main (), sw_if_index)->flood_class =
583         flood_class;
584     }
585   else
586     {
587       /* deleting a tunnel: tunnel must exist */
588       if (!p)
589         return VNET_API_ERROR_NO_SUCH_ENTRY;
590
591       t = pool_elt_at_index (vxm->tunnels, p[0]);
592
593       sw_if_index = t->sw_if_index;
594       vnet_sw_interface_set_flags (vnm, t->sw_if_index, 0 /* down */ );
595       vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, t->sw_if_index);
596       si->flags |= VNET_SW_INTERFACE_FLAG_HIDDEN;
597
598       /* make sure tunnel is removed from l2 bd or xconnect */
599       set_int_l2_mode (vxm->vlib_main, vnm, MODE_L3, t->sw_if_index, 0, 0, 0,
600                        0);
601       vec_add1 (vxm->free_geneve_tunnel_hw_if_indices, t->hw_if_index);
602
603       vxm->tunnel_index_by_sw_if_index[t->sw_if_index] = ~0;
604
605       if (!is_ip6)
606         hash_unset (vxm->geneve4_tunnel_by_key, key4.as_u64);
607       else
608         hash_unset_mem_free (&vxm->geneve6_tunnel_by_key, &key6);
609
610       if (!ip46_address_is_multicast (&t->remote))
611         {
612           vtep_addr_unref (&t->local);
613           fib_entry_child_remove (t->fib_entry_index, t->sibling_index);
614           fib_table_entry_delete_index (t->fib_entry_index, FIB_SOURCE_RR);
615         }
616       else if (vtep_addr_unref (&t->remote) == 0)
617         {
618           mcast_shared_remove (&t->remote);
619         }
620
621       fib_node_deinit (&t->node);
622       vec_free (t->rewrite);
623       pool_put (vxm->tunnels, t);
624     }
625
626   if (sw_if_indexp)
627     *sw_if_indexp = sw_if_index;
628
629   return 0;
630 }
631
632 static uword
633 get_decap_next_for_node (u32 node_index, u32 ipv4_set)
634 {
635   geneve_main_t *vxm = &geneve_main;
636   vlib_main_t *vm = vxm->vlib_main;
637   uword input_node = (ipv4_set) ? geneve4_input_node.index :
638     geneve6_input_node.index;
639
640   return vlib_node_add_next (vm, input_node, node_index);
641 }
642
643 static uword
644 unformat_decap_next (unformat_input_t * input, va_list * args)
645 {
646   u32 *result = va_arg (*args, u32 *);
647   u32 ipv4_set = va_arg (*args, int);
648   geneve_main_t *vxm = &geneve_main;
649   vlib_main_t *vm = vxm->vlib_main;
650   u32 node_index;
651   u32 tmp;
652
653   if (unformat (input, "l2"))
654     *result = GENEVE_INPUT_NEXT_L2_INPUT;
655   else if (unformat (input, "node %U", unformat_vlib_node, vm, &node_index))
656     *result = get_decap_next_for_node (node_index, ipv4_set);
657   else if (unformat (input, "%d", &tmp))
658     *result = tmp;
659   else
660     return 0;
661   return 1;
662 }
663
664 static clib_error_t *
665 geneve_add_del_tunnel_command_fn (vlib_main_t * vm,
666                                   unformat_input_t * input,
667                                   vlib_cli_command_t * cmd)
668 {
669   unformat_input_t _line_input, *line_input = &_line_input;
670   ip46_address_t local, remote;
671   u8 is_add = 1;
672   u8 local_set = 0;
673   u8 remote_set = 0;
674   u8 grp_set = 0;
675   u8 ipv4_set = 0;
676   u8 ipv6_set = 0;
677   u32 encap_fib_index = 0;
678   u32 mcast_sw_if_index = ~0;
679   u32 decap_next_index = GENEVE_INPUT_NEXT_L2_INPUT;
680   u32 vni = 0;
681   u32 tmp;
682   int rv;
683   vnet_geneve_add_del_tunnel_args_t _a, *a = &_a;
684   u32 tunnel_sw_if_index;
685   clib_error_t *error = NULL;
686
687   /* Cant "universally zero init" (={0}) due to GCC bug 53119 */
688   memset (&local, 0, sizeof local);
689   memset (&remote, 0, sizeof remote);
690
691   /* Get a line of input. */
692   if (!unformat_user (input, unformat_line_input, line_input))
693     return 0;
694
695   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
696     {
697       if (unformat (line_input, "del"))
698         {
699           is_add = 0;
700         }
701       else if (unformat (line_input, "local %U",
702                          unformat_ip4_address, &local.ip4))
703         {
704           local_set = 1;
705           ipv4_set = 1;
706         }
707       else if (unformat (line_input, "remote %U",
708                          unformat_ip4_address, &remote.ip4))
709         {
710           remote_set = 1;
711           ipv4_set = 1;
712         }
713       else if (unformat (line_input, "local %U",
714                          unformat_ip6_address, &local.ip6))
715         {
716           local_set = 1;
717           ipv6_set = 1;
718         }
719       else if (unformat (line_input, "remote %U",
720                          unformat_ip6_address, &remote.ip6))
721         {
722           remote_set = 1;
723           ipv6_set = 1;
724         }
725       else if (unformat (line_input, "group %U %U",
726                          unformat_ip4_address, &remote.ip4,
727                          unformat_vnet_sw_interface,
728                          vnet_get_main (), &mcast_sw_if_index))
729         {
730           grp_set = remote_set = 1;
731           ipv4_set = 1;
732         }
733       else if (unformat (line_input, "group %U %U",
734                          unformat_ip6_address, &remote.ip6,
735                          unformat_vnet_sw_interface,
736                          vnet_get_main (), &mcast_sw_if_index))
737         {
738           grp_set = remote_set = 1;
739           ipv6_set = 1;
740         }
741       else if (unformat (line_input, "encap-vrf-id %d", &tmp))
742         {
743           encap_fib_index = fib_table_find (fib_ip_proto (ipv6_set), tmp);
744           if (encap_fib_index == ~0)
745             {
746               error =
747                 clib_error_return (0, "nonexistent encap-vrf-id %d", tmp);
748               goto done;
749             }
750         }
751       else if (unformat (line_input, "decap-next %U", unformat_decap_next,
752                          &decap_next_index, ipv4_set))
753         ;
754       else if (unformat (line_input, "vni %d", &vni))
755         {
756           if (vni >> 24)
757             {
758               error = clib_error_return (0, "vni %d out of range", vni);
759               goto done;
760             }
761         }
762       else
763         {
764           error = clib_error_return (0, "parse error: '%U'",
765                                      format_unformat_error, line_input);
766           goto done;
767         }
768     }
769
770   if (local_set == 0)
771     {
772       error = clib_error_return (0, "tunnel local address not specified");
773       goto done;
774     }
775
776   if (remote_set == 0)
777     {
778       error = clib_error_return (0, "tunnel remote address not specified");
779       goto done;
780     }
781
782   if (grp_set && !ip46_address_is_multicast (&remote))
783     {
784       error = clib_error_return (0, "tunnel group address not multicast");
785       goto done;
786     }
787
788   if (grp_set == 0 && ip46_address_is_multicast (&remote))
789     {
790       error = clib_error_return (0, "remote address must be unicast");
791       goto done;
792     }
793
794   if (grp_set && mcast_sw_if_index == ~0)
795     {
796       error = clib_error_return (0, "tunnel nonexistent multicast device");
797       goto done;
798     }
799
800   if (ipv4_set && ipv6_set)
801     {
802       error = clib_error_return (0, "both IPv4 and IPv6 addresses specified");
803       goto done;
804     }
805
806   if (ip46_address_cmp (&local, &remote) == 0)
807     {
808       error =
809         clib_error_return (0, "local and remote addresses are identical");
810       goto done;
811     }
812
813   if (decap_next_index == ~0)
814     {
815       error = clib_error_return (0, "next node not found");
816       goto done;
817     }
818
819   if (vni == 0)
820     {
821       error = clib_error_return (0, "vni not specified");
822       goto done;
823     }
824
825   memset (a, 0, sizeof (*a));
826
827   a->is_add = is_add;
828   a->is_ip6 = ipv6_set;
829
830 #define _(x) a->x = x;
831   foreach_copy_field;
832 #undef _
833
834   rv = vnet_geneve_add_del_tunnel (a, &tunnel_sw_if_index);
835
836   switch (rv)
837     {
838     case 0:
839       if (is_add)
840         vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
841                          vnet_get_main (), tunnel_sw_if_index);
842       break;
843
844     case VNET_API_ERROR_TUNNEL_EXIST:
845       error = clib_error_return (0, "tunnel already exists...");
846       goto done;
847
848     case VNET_API_ERROR_NO_SUCH_ENTRY:
849       error = clib_error_return (0, "tunnel does not exist...");
850       goto done;
851
852     default:
853       error = clib_error_return
854         (0, "vnet_geneve_add_del_tunnel returned %d", rv);
855       goto done;
856     }
857
858 done:
859   unformat_free (line_input);
860
861   return error;
862 }
863
864 /*?
865  * Add or delete a GENEVE Tunnel.
866  *
867  * GENEVE provides the features needed to allow L2 bridge domains (BDs)
868  * to span multiple servers. This is done by building an L2 overlay on
869  * top of an L3 network underlay using GENEVE tunnels.
870  *
871  * This makes it possible for servers to be co-located in the same data
872  * center or be separated geographically as long as they are reachable
873  * through the underlay L3 network.
874  *
875  * You can refer to this kind of L2 overlay bridge domain as a GENEVE
876  * segment.
877  *
878  * @cliexpar
879  * Example of how to create a GENEVE Tunnel:
880  * @cliexcmd{create geneve tunnel local 10.0.3.1 remote 10.0.3.3 vni 13 encap-vrf-id 7}
881  * Example of how to delete a GENEVE Tunnel:
882  * @cliexcmd{create geneve tunnel local 10.0.3.1 remote 10.0.3.3 vni 13 del}
883  ?*/
884 /* *INDENT-OFF* */
885 VLIB_CLI_COMMAND (create_geneve_tunnel_command, static) = {
886   .path = "create geneve tunnel",
887   .short_help =
888   "create geneve tunnel local <local-vtep-addr>"
889   " {remote <remote-vtep-addr>|group <mcast-vtep-addr> <intf-name>} vni <nn>"
890   " [encap-vrf-id <nn>] [decap-next [l2|node <name>]] [del]",
891   .function = geneve_add_del_tunnel_command_fn,
892 };
893 /* *INDENT-ON* */
894
895 static clib_error_t *
896 show_geneve_tunnel_command_fn (vlib_main_t * vm,
897                                unformat_input_t * input,
898                                vlib_cli_command_t * cmd)
899 {
900   geneve_main_t *vxm = &geneve_main;
901   geneve_tunnel_t *t;
902
903   if (pool_elts (vxm->tunnels) == 0)
904     vlib_cli_output (vm, "No geneve tunnels configured...");
905
906   pool_foreach (t, vxm->tunnels, (
907                                    {
908                                    vlib_cli_output (vm, "%U",
909                                                     format_geneve_tunnel, t);
910                                    }
911                 ));
912
913   return 0;
914 }
915
916 /*?
917  * Display all the GENEVE Tunnel entries.
918  *
919  * @cliexpar
920  * Example of how to display the GENEVE Tunnel entries:
921  * @cliexstart{show geneve tunnel}
922  * [0] local 10.0.3.1 remote 10.0.3.3 vni 13 encap_fib_index 0 sw_if_index 5 decap_next l2
923  * @cliexend
924  ?*/
925 /* *INDENT-OFF* */
926 VLIB_CLI_COMMAND (show_geneve_tunnel_command, static) = {
927     .path = "show geneve tunnel",
928     .short_help = "show geneve tunnel",
929     .function = show_geneve_tunnel_command_fn,
930 };
931 /* *INDENT-ON* */
932
933
934 void
935 vnet_int_geneve_bypass_mode (u32 sw_if_index, u8 is_ip6, u8 is_enable)
936 {
937   if (is_ip6)
938     vnet_feature_enable_disable ("ip6-unicast", "ip6-geneve-bypass",
939                                  sw_if_index, is_enable, 0, 0);
940   else
941     vnet_feature_enable_disable ("ip4-unicast", "ip4-geneve-bypass",
942                                  sw_if_index, is_enable, 0, 0);
943 }
944
945
946 static clib_error_t *
947 set_ip_geneve_bypass (u32 is_ip6,
948                       unformat_input_t * input, vlib_cli_command_t * cmd)
949 {
950   unformat_input_t _line_input, *line_input = &_line_input;
951   vnet_main_t *vnm = vnet_get_main ();
952   clib_error_t *error = 0;
953   u32 sw_if_index, is_enable;
954
955   sw_if_index = ~0;
956   is_enable = 1;
957
958   if (!unformat_user (input, unformat_line_input, line_input))
959     return 0;
960
961   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
962     {
963       if (unformat_user
964           (line_input, unformat_vnet_sw_interface, vnm, &sw_if_index))
965         ;
966       else if (unformat (line_input, "del"))
967         is_enable = 0;
968       else
969         {
970           error = unformat_parse_error (line_input);
971           goto done;
972         }
973     }
974
975   if (~0 == sw_if_index)
976     {
977       error = clib_error_return (0, "unknown interface `%U'",
978                                  format_unformat_error, line_input);
979       goto done;
980     }
981
982   vnet_int_geneve_bypass_mode (sw_if_index, is_ip6, is_enable);
983
984 done:
985   unformat_free (line_input);
986
987   return error;
988 }
989
990 static clib_error_t *
991 set_ip4_geneve_bypass (vlib_main_t * vm,
992                        unformat_input_t * input, vlib_cli_command_t * cmd)
993 {
994   return set_ip_geneve_bypass (0, input, cmd);
995 }
996
997 /*?
998  * This command adds the 'ip4-geneve-bypass' graph node for a given interface.
999  * By adding the IPv4 geneve-bypass graph node to an interface, the node checks
1000  *  for and validate input geneve packet and bypass ip4-lookup, ip4-local,
1001  * ip4-udp-lookup nodes to speedup geneve packet forwarding. This node will
1002  * cause extra overhead to for non-geneve packets which is kept at a minimum.
1003  *
1004  * @cliexpar
1005  * @parblock
1006  * Example of graph node before ip4-geneve-bypass is enabled:
1007  * @cliexstart{show vlib graph ip4-geneve-bypass}
1008  *            Name                      Next                    Previous
1009  * ip4-geneve-bypass                error-drop [0]
1010  *                                geneve4-input [1]
1011  *                                 ip4-lookup [2]
1012  * @cliexend
1013  *
1014  * Example of how to enable ip4-geneve-bypass on an interface:
1015  * @cliexcmd{set interface ip geneve-bypass GigabitEthernet2/0/0}
1016  *
1017  * Example of graph node after ip4-geneve-bypass is enabled:
1018  * @cliexstart{show vlib graph ip4-geneve-bypass}
1019  *            Name                      Next                    Previous
1020  * ip4-geneve-bypass                error-drop [0]               ip4-input
1021  *                                geneve4-input [1]        ip4-input-no-checksum
1022  *                                 ip4-lookup [2]
1023  * @cliexend
1024  *
1025  * Example of how to display the feature enabed on an interface:
1026  * @cliexstart{show ip interface features GigabitEthernet2/0/0}
1027  * IP feature paths configured on GigabitEthernet2/0/0...
1028  * ...
1029  * ipv4 unicast:
1030  *   ip4-geneve-bypass
1031  *   ip4-lookup
1032  * ...
1033  * @cliexend
1034  *
1035  * Example of how to disable ip4-geneve-bypass on an interface:
1036  * @cliexcmd{set interface ip geneve-bypass GigabitEthernet2/0/0 del}
1037  * @endparblock
1038 ?*/
1039 /* *INDENT-OFF* */
1040 VLIB_CLI_COMMAND (set_interface_ip_geneve_bypass_command, static) = {
1041   .path = "set interface ip geneve-bypass",
1042   .function = set_ip4_geneve_bypass,
1043   .short_help = "set interface ip geneve-bypass <interface> [del]",
1044 };
1045 /* *INDENT-ON* */
1046
1047 static clib_error_t *
1048 set_ip6_geneve_bypass (vlib_main_t * vm,
1049                        unformat_input_t * input, vlib_cli_command_t * cmd)
1050 {
1051   return set_ip_geneve_bypass (1, input, cmd);
1052 }
1053
1054 /*?
1055  * This command adds the 'ip6-geneve-bypass' graph node for a given interface.
1056  * By adding the IPv6 geneve-bypass graph node to an interface, the node checks
1057  *  for and validate input geneve packet and bypass ip6-lookup, ip6-local,
1058  * ip6-udp-lookup nodes to speedup geneve packet forwarding. This node will
1059  * cause extra overhead to for non-geneve packets which is kept at a minimum.
1060  *
1061  * @cliexpar
1062  * @parblock
1063  * Example of graph node before ip6-geneve-bypass is enabled:
1064  * @cliexstart{show vlib graph ip6-geneve-bypass}
1065  *            Name                      Next                    Previous
1066  * ip6-geneve-bypass                error-drop [0]
1067  *                                geneve6-input [1]
1068  *                                 ip6-lookup [2]
1069  * @cliexend
1070  *
1071  * Example of how to enable ip6-geneve-bypass on an interface:
1072  * @cliexcmd{set interface ip6 geneve-bypass GigabitEthernet2/0/0}
1073  *
1074  * Example of graph node after ip6-geneve-bypass is enabled:
1075  * @cliexstart{show vlib graph ip6-geneve-bypass}
1076  *            Name                      Next                    Previous
1077  * ip6-geneve-bypass                error-drop [0]               ip6-input
1078  *                                geneve6-input [1]        ip4-input-no-checksum
1079  *                                 ip6-lookup [2]
1080  * @cliexend
1081  *
1082  * Example of how to display the feature enabed on an interface:
1083  * @cliexstart{show ip interface features GigabitEthernet2/0/0}
1084  * IP feature paths configured on GigabitEthernet2/0/0...
1085  * ...
1086  * ipv6 unicast:
1087  *   ip6-geneve-bypass
1088  *   ip6-lookup
1089  * ...
1090  * @cliexend
1091  *
1092  * Example of how to disable ip6-geneve-bypass on an interface:
1093  * @cliexcmd{set interface ip6 geneve-bypass GigabitEthernet2/0/0 del}
1094  * @endparblock
1095 ?*/
1096 /* *INDENT-OFF* */
1097 VLIB_CLI_COMMAND (set_interface_ip6_geneve_bypass_command, static) = {
1098   .path = "set interface ip6 geneve-bypass",
1099   .function = set_ip6_geneve_bypass,
1100   .short_help = "set interface ip geneve-bypass <interface> [del]",
1101 };
1102 /* *INDENT-ON* */
1103
1104 clib_error_t *
1105 geneve_init (vlib_main_t * vm)
1106 {
1107   geneve_main_t *vxm = &geneve_main;
1108
1109   vxm->vnet_main = vnet_get_main ();
1110   vxm->vlib_main = vm;
1111
1112   /* initialize the ip6 hash */
1113   vxm->geneve6_tunnel_by_key = hash_create_mem (0,
1114                                                 sizeof (geneve6_tunnel_key_t),
1115                                                 sizeof (uword));
1116   vxm->vtep6 = hash_create_mem (0, sizeof (ip6_address_t), sizeof (uword));
1117   vxm->mcast_shared = hash_create_mem (0,
1118                                        sizeof (ip46_address_t),
1119                                        sizeof (mcast_shared_t));
1120
1121   udp_register_dst_port (vm, UDP_DST_PORT_geneve,
1122                          geneve4_input_node.index, /* is_ip4 */ 1);
1123   udp_register_dst_port (vm, UDP_DST_PORT_geneve6,
1124                          geneve6_input_node.index, /* is_ip4 */ 0);
1125
1126   fib_node_register_type (FIB_NODE_TYPE_GENEVE_TUNNEL, &geneve_vft);
1127
1128   return 0;
1129 }
1130
1131 VLIB_INIT_FUNCTION (geneve_init);
1132
1133 /*
1134  * fd.io coding-style-patch-verification: ON
1135  *
1136  * Local Variables:
1137  * eval: (c-set-style "gnu")
1138  * End:
1139  */