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