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