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