builtinurl: mark api as deprecated
[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 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
50 u8 * format_gtpu_encap_trace (u8 * s, va_list * args)
51 {
52   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
53   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
54   gtpu_encap_trace_t * t
55       = va_arg (*args, gtpu_encap_trace_t *);
56
57   s = format (s, "GTPU encap to gtpu_tunnel%d tteid %u ", t->tunnel_index,
58               t->tteid);
59
60   if (t->pdu_extension)
61     s = format (s, "pdu-extension qfi %d ", t->qfi);
62   else
63     s = format (s, "no-pdu-extension ");
64   return s;
65 }
66
67 static u8 *
68 format_decap_next (u8 * s, va_list * args)
69 {
70   u32 next_index = va_arg (*args, u32);
71
72   switch (next_index)
73     {
74     case GTPU_INPUT_NEXT_DROP:
75       return format (s, "drop");
76     case GTPU_INPUT_NEXT_L2_INPUT:
77       return format (s, "l2");
78     case GTPU_INPUT_NEXT_IP4_INPUT:
79       return format (s, "ip4");
80     case GTPU_INPUT_NEXT_IP6_INPUT:
81       return format (s, "ip6");
82     default:
83       return format (s, "index %d", next_index);
84     }
85   return s;
86 }
87
88 u8 *
89 format_gtpu_tunnel (u8 * s, va_list * args)
90 {
91   gtpu_tunnel_t *t = va_arg (*args, gtpu_tunnel_t *);
92   gtpu_main_t *ngm = &gtpu_main;
93   ip4_main_t *im4 = &ip4_main;
94   ip6_main_t *im6 = &ip6_main;
95   u8 is_ipv6 = !ip46_address_is_ip4 (&t->dst);
96
97   u32 encap_vrf_id =
98     is_ipv6 ? im6->fibs[t->encap_fib_index].ft_table_id :
99     im4->fibs[t->encap_fib_index].ft_table_id;
100
101   s = format (s,
102               "[%d] src %U dst %U teid %u tteid %u "
103               "encap-vrf-id %d sw-if-idx %d ",
104               t - ngm->tunnels, format_ip46_address, &t->src, IP46_TYPE_ANY,
105               format_ip46_address, &t->dst, IP46_TYPE_ANY, t->teid, t->tteid,
106               encap_vrf_id, t->sw_if_index);
107
108   s = format (s, "encap-dpo-idx %d ", t->next_dpo.dpoi_index);
109   s = format (s, "decap-next-%U ", format_decap_next, t->decap_next_index);
110
111   if (t->is_forwarding)
112     {
113       switch (t->forwarding_type)
114         {
115         case GTPU_FORWARD_BAD_HEADER:
116           s = format (s, "forwarding bad-header ");
117           break;
118         case GTPU_FORWARD_UNKNOWN_TEID:
119           s = format (s, "forwarding unknown-teid ");
120           break;
121         case GTPU_FORWARD_UNKNOWN_TYPE:
122           s = format (s, "forwarding unknown-type ");
123           break;
124         }
125       return s;
126     }
127   if (t->pdu_extension != 0)
128     s = format (s, "pdu-enabled qfi %d ", t->qfi);
129   else
130     s = format (s, "pdu-disabled ");
131
132   if (PREDICT_FALSE (ip46_address_is_multicast (&t->dst)))
133     s = format (s, "mcast-sw-if-idx %d ", t->mcast_sw_if_index);
134
135   return s;
136 }
137
138 static u8 *
139 format_gtpu_name (u8 * s, va_list * args)
140 {
141   u32 dev_instance = va_arg (*args, u32);
142   return format (s, "gtpu_tunnel%d", dev_instance);
143 }
144
145 static clib_error_t *
146 gtpu_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
147 {
148   u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
149     VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
150   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
151
152   return /* no error */ 0;
153 }
154
155 VNET_DEVICE_CLASS (gtpu_device_class,static) = {
156   .name = "GTPU",
157   .format_device_name = format_gtpu_name,
158   .format_tx_trace = format_gtpu_encap_trace,
159   .admin_up_down_function = gtpu_interface_admin_up_down,
160 };
161
162 static u8 *
163 format_gtpu_header_with_length (u8 * s, va_list * args)
164 {
165   u32 dev_instance = va_arg (*args, u32);
166   s = format (s, "unimplemented dev %u", dev_instance);
167   return s;
168 }
169
170 VNET_HW_INTERFACE_CLASS (gtpu_hw_class) =
171 {
172   .name = "GTPU",
173   .format_header = format_gtpu_header_with_length,
174   .build_rewrite = default_build_rewrite,
175   .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
176 };
177
178 static void
179 gtpu_tunnel_restack_dpo (gtpu_tunnel_t * t)
180 {
181   dpo_id_t dpo = DPO_INVALID;
182   u32 encap_index = ip46_address_is_ip4 (&t->dst) ?
183     gtpu4_encap_node.index : gtpu6_encap_node.index;
184   fib_forward_chain_type_t forw_type = ip46_address_is_ip4 (&t->dst) ?
185     FIB_FORW_CHAIN_TYPE_UNICAST_IP4 : FIB_FORW_CHAIN_TYPE_UNICAST_IP6;
186
187   fib_entry_contribute_forwarding (t->fib_entry_index, forw_type, &dpo);
188   dpo_stack_from_node (encap_index, &t->next_dpo, &dpo);
189   dpo_reset (&dpo);
190 }
191
192 static gtpu_tunnel_t *
193 gtpu_tunnel_from_fib_node (fib_node_t * node)
194 {
195   return ((gtpu_tunnel_t *) (((char *) node) -
196                              STRUCT_OFFSET_OF (gtpu_tunnel_t, node)));
197 }
198
199 /**
200  * Function definition to backwalk a FIB node -
201  * Here we will restack the new dpo of GTPU DIP to encap node.
202  */
203 static fib_node_back_walk_rc_t
204 gtpu_tunnel_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
205 {
206   gtpu_tunnel_restack_dpo (gtpu_tunnel_from_fib_node (node));
207   return (FIB_NODE_BACK_WALK_CONTINUE);
208 }
209
210 /**
211  * Function definition to get a FIB node from its index
212  */
213 static fib_node_t *
214 gtpu_tunnel_fib_node_get (fib_node_index_t index)
215 {
216   gtpu_tunnel_t *t;
217   gtpu_main_t *gtm = &gtpu_main;
218
219   t = pool_elt_at_index (gtm->tunnels, index);
220
221   return (&t->node);
222 }
223
224 /**
225  * Function definition to inform the FIB node that its last lock has gone.
226  */
227 static void
228 gtpu_tunnel_last_lock_gone (fib_node_t * node)
229 {
230   /*
231    * The GTPU tunnel is a root of the graph. As such
232    * it never has children and thus is never locked.
233    */
234   ASSERT (0);
235 }
236
237 /*
238  * Virtual function table registered by GTPU tunnels
239  * for participation in the FIB object graph.
240  */
241 const static fib_node_vft_t gtpu_vft = {
242   .fnv_get = gtpu_tunnel_fib_node_get,
243   .fnv_last_lock = gtpu_tunnel_last_lock_gone,
244   .fnv_back_walk = gtpu_tunnel_back_walk,
245 };
246
247 #define foreach_copy_field                                                    \
248   _ (teid)                                                                    \
249   _ (tteid)                                                                   \
250   _ (mcast_sw_if_index)                                                       \
251   _ (encap_fib_index)                                                         \
252   _ (decap_next_index)                                                        \
253   _ (src)                                                                     \
254   _ (dst)                                                                     \
255   _ (pdu_extension)                                                           \
256   _ (qfi)                                                                     \
257   _ (is_forwarding)                                                           \
258   _ (forwarding_type)
259
260 static void
261 ip_udp_gtpu_rewrite (gtpu_tunnel_t * t, bool is_ip6)
262 {
263   union
264   {
265     ip4_gtpu_header_t *h4;
266     ip6_gtpu_header_t *h6;
267     u8 *rw;
268   } r =
269   {
270   .rw = 0};
271   int len = is_ip6 ? sizeof *r.h6 : sizeof *r.h4;
272
273   vec_validate_aligned (r.rw, len - 1, CLIB_CACHE_LINE_BYTES);
274
275   udp_header_t *udp;
276   gtpu_header_t *gtpu;
277   gtpu_ext_with_pdu_session_header_t *gtpu_ext_pdu;
278   i64 length_adjustment = 0;
279   /* Fixed portion of the (outer) ip header */
280   if (!is_ip6)
281     {
282       ip4_header_t *ip = &r.h4->ip4;
283       udp = &r.h4->udp;
284       gtpu = &r.h4->gtpu;
285       gtpu_ext_pdu = &r.h4->gtpu_ext;
286       ip->ip_version_and_header_length = 0x45;
287       ip->ttl = 254;
288       ip->protocol = IP_PROTOCOL_UDP;
289
290       ip->src_address = t->src.ip4;
291       ip->dst_address = t->dst.ip4;
292
293       /* we fix up the ip4 header length and checksum after-the-fact */
294       ip->checksum = ip4_header_checksum (ip);
295     }
296   else
297     {
298       ip6_header_t *ip = &r.h6->ip6;
299       udp = &r.h6->udp;
300       gtpu = &r.h6->gtpu;
301       gtpu_ext_pdu = &r.h6->gtpu_ext;
302       ip->ip_version_traffic_class_and_flow_label =
303         clib_host_to_net_u32 (6 << 28);
304       ip->hop_limit = 255;
305       ip->protocol = IP_PROTOCOL_UDP;
306
307       ip->src_address = t->src.ip6;
308       ip->dst_address = t->dst.ip6;
309     }
310
311   /* UDP header, randomize src port on something, maybe? */
312   udp->src_port = clib_host_to_net_u16 (2152);
313   udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_GTPU);
314
315   /* GTPU header */
316   gtpu->ver_flags = GTPU_V1_VER | GTPU_PT_GTP;
317   gtpu->type = GTPU_TYPE_GTPU;
318   gtpu->teid = clib_host_to_net_u32 (t->tteid);
319
320   if (t->pdu_extension)
321     {
322       gtpu->ver_flags = GTPU_V1_VER | GTPU_PT_GTP | GTPU_E_BIT;
323       gtpu->next_ext_type = GTPU_EXT_HDR_PDU_SESSION_CONTAINER;
324       gtpu_ext_pdu->len = 1;
325       gtpu_ext_pdu->pdu.oct0 = GTPU_PDU_DL_SESSION_TYPE;
326       gtpu_ext_pdu->pdu.oct1 = t->qfi;
327       gtpu_ext_pdu->next_header = 0;
328     }
329   else
330     {
331       // Remove the size of the PDU session header and the optional fields
332       length_adjustment = -sizeof (gtpu_ext_with_pdu_session_header_t) - 4;
333     }
334
335   t->rewrite = r.rw;
336   /* Now only support 8-byte gtpu header or 12+4-byte header. TBD */
337   if (!is_ip6)
338     vec_set_len (t->rewrite, sizeof (ip4_gtpu_header_t) + length_adjustment);
339   else
340     vec_set_len (t->rewrite, sizeof (ip6_gtpu_header_t) + length_adjustment);
341
342   return;
343 }
344
345 static bool
346 gtpu_decap_next_is_valid (gtpu_main_t * gtm, u32 is_ip6, u32 decap_next_index)
347 {
348   vlib_main_t *vm = gtm->vlib_main;
349   u32 input_idx = (!is_ip6) ? gtpu4_input_node.index : gtpu6_input_node.index;
350   vlib_node_runtime_t *r = vlib_node_get_runtime (vm, input_idx);
351
352   return decap_next_index < r->n_next_nodes;
353 }
354
355 typedef CLIB_PACKED (union
356                      {
357                      struct
358                      {
359                      fib_node_index_t mfib_entry_index;
360                      adj_index_t mcast_adj_index;
361                      }; u64 as_u64;
362                      }) mcast_shared_t;
363
364 static inline mcast_shared_t
365 mcast_shared_get (ip46_address_t * ip)
366 {
367   ASSERT (ip46_address_is_multicast (ip));
368   uword *p = hash_get_mem (gtpu_main.mcast_shared, ip);
369   ALWAYS_ASSERT (p);
370   return (mcast_shared_t)
371   {
372   .as_u64 = *p};
373 }
374
375 static inline void
376 mcast_shared_add (ip46_address_t * dst, fib_node_index_t mfei, adj_index_t ai)
377 {
378   mcast_shared_t new_ep = {
379     .mcast_adj_index = ai,
380     .mfib_entry_index = mfei,
381   };
382
383   hash_set_mem_alloc (&gtpu_main.mcast_shared, dst, new_ep.as_u64);
384 }
385
386 static inline void
387 mcast_shared_remove (ip46_address_t * dst)
388 {
389   mcast_shared_t ep = mcast_shared_get (dst);
390
391   adj_unlock (ep.mcast_adj_index);
392   mfib_table_entry_delete_index (ep.mfib_entry_index, MFIB_SOURCE_GTPU);
393
394   hash_unset_mem_free (&gtpu_main.mcast_shared, dst);
395 }
396
397 int
398 vnet_gtpu_add_del_forwarding (vnet_gtpu_add_mod_del_tunnel_args_t *a,
399                               u32 *sw_if_indexp)
400 {
401   gtpu_main_t *gtm = &gtpu_main;
402   bool is_add;
403   u32 current_index_value, current_index_value_ipv6;
404   u32 address_tabel_ipv4;
405   ip6_address_t address_tabel_ipv6;
406   u32 sw_if_index = ~0;
407   bool is_ip6 = !ip46_address_is_ip4 (&a->dst);
408   int rv;
409   /* Check for errors */
410   if (!a->is_forwarding)
411     {
412       return VNET_API_ERROR_INVALID_ARGUMENT;
413     }
414
415   switch (a->opn)
416     {
417     case GTPU_ADD_TUNNEL:
418       is_add = 1;
419       break;
420     case GTPU_DEL_TUNNEL:
421       is_add = 0;
422       break;
423     default:
424       return VNET_API_ERROR_INVALID_ARGUMENT;
425     }
426
427   /* Check if the operation is valid, and get the current state if it is.
428    * Handling multiple flags at once is not supported yet. */
429   switch (a->forwarding_type)
430     {
431     case GTPU_FORWARD_BAD_HEADER:
432       current_index_value = gtm->bad_header_forward_tunnel_index_ipv4;
433       current_index_value_ipv6 = gtm->bad_header_forward_tunnel_index_ipv6;
434       address_tabel_ipv4 = GTPU_FORWARD_BAD_HEADER_ADDRESS_IPV4;
435       /* ipv6 is TBD */
436       ip6_address_t address_tabel_ipv6_ = GTPU_FORWARD_BAD_HEADER_ADDRESS_IPV6;
437       address_tabel_ipv6 = address_tabel_ipv6_;
438       break;
439     case GTPU_FORWARD_UNKNOWN_TEID:
440       current_index_value = gtm->unknown_teid_forward_tunnel_index_ipv4;
441       current_index_value_ipv6 = gtm->unknown_teid_forward_tunnel_index_ipv6;
442       address_tabel_ipv4 = GTPU_FORWARD_UNKNOWN_TEID_ADDRESS_IPV4;
443       ip6_address_t address_tabel_ipv6__ =
444         GTPU_FORWARD_UNKNOWN_TEID_ADDRESS_IPV6;
445       address_tabel_ipv6 = address_tabel_ipv6__;
446       break;
447     case GTPU_FORWARD_UNKNOWN_TYPE:
448       current_index_value = gtm->unknown_type_forward_tunnel_index_ipv4;
449       current_index_value_ipv6 = gtm->unknown_type_forward_tunnel_index_ipv6;
450       address_tabel_ipv4 = GTPU_FORWARD_UNKNOWN_TYPE_ADDRESS_IPV4;
451       ip6_address_t address_tabel_ipv6___ =
452         GTPU_FORWARD_UNKNOWN_TYPE_ADDRESS_IPV6;
453       address_tabel_ipv6 = address_tabel_ipv6___;
454       break;
455     default:
456       return VNET_API_ERROR_INVALID_ARGUMENT;
457     }
458
459   if (is_ip6)
460     current_index_value = current_index_value_ipv6;
461
462   /* Check if the existing forwarding rule state conflicts with this operation
463    */
464   if ((is_add) && (current_index_value != ~0))
465     {
466       return VNET_API_ERROR_TUNNEL_EXIST;
467     }
468   if (!is_add)
469     {
470       if (current_index_value == ~0)
471         return VNET_API_ERROR_NO_SUCH_ENTRY;
472       /* Clear the tunnel index before deleting the tunnel itself */
473       switch (a->forwarding_type)
474         {
475         case GTPU_FORWARD_BAD_HEADER:
476           gtm->bad_header_forward_tunnel_index_ipv4 = ~0;
477           break;
478         case GTPU_FORWARD_UNKNOWN_TEID:
479           gtm->unknown_teid_forward_tunnel_index_ipv4 = ~0;
480           break;
481         case GTPU_FORWARD_UNKNOWN_TYPE:
482           gtm->unknown_type_forward_tunnel_index_ipv4 = ~0;
483           break;
484         }
485     }
486
487   /* src is the tunnel lookup key, so it is fixed.
488    * dst is used for the new target */
489   a->src = a->dst;
490   if (is_ip6)
491     a->dst.ip6 = address_tabel_ipv6;
492   else
493     a->dst.ip4.as_u32 = address_tabel_ipv4;
494   rv = vnet_gtpu_add_mod_del_tunnel (a, &sw_if_index);
495
496   // Forward only if not nil
497   if (sw_if_indexp)
498     *sw_if_indexp = sw_if_index;
499
500   if (rv != 0)
501     return rv;
502
503   /* Update the forwarding tunnel index */
504   u32 tunnel_index = is_add ? vnet_gtpu_get_tunnel_index (sw_if_index) : ~0;
505   switch (a->forwarding_type)
506     {
507     case GTPU_FORWARD_BAD_HEADER:
508       if (is_ip6)
509         gtm->bad_header_forward_tunnel_index_ipv6 = tunnel_index;
510       else
511         gtm->bad_header_forward_tunnel_index_ipv4 = tunnel_index;
512
513       break;
514     case GTPU_FORWARD_UNKNOWN_TEID:
515       if (is_ip6)
516         gtm->unknown_teid_forward_tunnel_index_ipv6 = tunnel_index;
517       else
518         gtm->unknown_teid_forward_tunnel_index_ipv4 = tunnel_index;
519       break;
520     case GTPU_FORWARD_UNKNOWN_TYPE:
521       if (is_ip6)
522         gtm->unknown_type_forward_tunnel_index_ipv6 = tunnel_index;
523       else
524         gtm->unknown_type_forward_tunnel_index_ipv4 = tunnel_index;
525       break;
526     }
527   return 0;
528 }
529
530 int vnet_gtpu_add_mod_del_tunnel
531   (vnet_gtpu_add_mod_del_tunnel_args_t * a, u32 * sw_if_indexp)
532 {
533   gtpu_main_t *gtm = &gtpu_main;
534   gtpu_tunnel_t *t = 0;
535   vnet_main_t *vnm = gtm->vnet_main;
536   uword *p;
537   u32 hw_if_index = ~0;
538   u32 sw_if_index = ~0;
539   gtpu4_tunnel_key_t key4;
540   gtpu6_tunnel_key_t key6;
541   bool is_ip6 = !ip46_address_is_ip4 (&a->dst);
542
543   if (!is_ip6)
544     {
545       key4.src = a->dst.ip4.as_u32;     /* decap src in key is encap dst in config */
546       key4.teid = clib_host_to_net_u32 (a->teid);
547       p = hash_get (gtm->gtpu4_tunnel_by_key, key4.as_u64);
548     }
549   else
550     {
551       key6.src = a->dst.ip6;
552       key6.teid = clib_host_to_net_u32 (a->teid);
553       p = hash_get_mem (gtm->gtpu6_tunnel_by_key, &key6);
554     }
555
556   if (a->opn == GTPU_ADD_TUNNEL)
557     {
558       l2input_main_t *l2im = &l2input_main;
559
560       /* adding a tunnel: tunnel must not already exist */
561       if (p)
562         return VNET_API_ERROR_TUNNEL_EXIST;
563
564       /*if not set explicitly, default to l2 */
565       if (a->decap_next_index == ~0)
566         a->decap_next_index = GTPU_INPUT_NEXT_L2_INPUT;
567       if (!gtpu_decap_next_is_valid (gtm, is_ip6, a->decap_next_index))
568         return VNET_API_ERROR_INVALID_DECAP_NEXT;
569
570       pool_get_aligned (gtm->tunnels, t, CLIB_CACHE_LINE_BYTES);
571       clib_memset (t, 0, sizeof (*t));
572
573       /* copy from arg structure */
574 #define _(x) t->x = a->x;
575       foreach_copy_field;
576 #undef _
577
578       /* default to same as local rx teid */
579       if (t->tteid == 0)
580         t->tteid = t->teid;
581
582       ip_udp_gtpu_rewrite (t, is_ip6);
583
584       /* clear the flow index */
585       t->flow_index = ~0;
586
587       /* copy the key */
588       if (is_ip6)
589         hash_set_mem_alloc (&gtm->gtpu6_tunnel_by_key, &key6,
590                             t - gtm->tunnels);
591       else
592         hash_set (gtm->gtpu4_tunnel_by_key, key4.as_u64, t - gtm->tunnels);
593
594       vnet_hw_interface_t *hi;
595       if (vec_len (gtm->free_gtpu_tunnel_hw_if_indices) > 0)
596         {
597           vnet_interface_main_t *im = &vnm->interface_main;
598           hw_if_index = gtm->free_gtpu_tunnel_hw_if_indices
599             [vec_len (gtm->free_gtpu_tunnel_hw_if_indices) - 1];
600           vec_dec_len (gtm->free_gtpu_tunnel_hw_if_indices, 1);
601
602           hi = vnet_get_hw_interface (vnm, hw_if_index);
603           hi->dev_instance = t - gtm->tunnels;
604           hi->hw_instance = hi->dev_instance;
605
606           /* clear old stats of freed tunnel before reuse */
607           sw_if_index = hi->sw_if_index;
608           vnet_interface_counter_lock (im);
609           vlib_zero_combined_counter
610             (&im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX],
611              sw_if_index);
612           vlib_zero_combined_counter (&im->combined_sw_if_counters
613                                       [VNET_INTERFACE_COUNTER_RX],
614                                       sw_if_index);
615           vlib_zero_simple_counter (&im->sw_if_counters
616                                     [VNET_INTERFACE_COUNTER_DROP],
617                                     sw_if_index);
618           vnet_interface_counter_unlock (im);
619         }
620       else
621         {
622           hw_if_index = vnet_register_interface
623             (vnm, gtpu_device_class.index, t - gtm->tunnels,
624              gtpu_hw_class.index, t - gtm->tunnels);
625           hi = vnet_get_hw_interface (vnm, hw_if_index);
626         }
627
628       /* Set gtpu tunnel output node */
629       u32 encap_index = !is_ip6 ?
630         gtpu4_encap_node.index : gtpu6_encap_node.index;
631       vnet_set_interface_output_node (vnm, hw_if_index, encap_index);
632
633       t->hw_if_index = hw_if_index;
634       t->sw_if_index = sw_if_index = hi->sw_if_index;
635
636       vec_validate_init_empty (gtm->tunnel_index_by_sw_if_index, sw_if_index,
637                                ~0);
638       gtm->tunnel_index_by_sw_if_index[sw_if_index] = t - gtm->tunnels;
639
640       /* setup l2 input config with l2 feature and bd 0 to drop packet */
641       vec_validate (l2im->configs, sw_if_index);
642       l2im->configs[sw_if_index].feature_bitmap = L2INPUT_FEAT_DROP;
643       l2im->configs[sw_if_index].bd_index = 0;
644
645       vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
646       si->flags &= ~VNET_SW_INTERFACE_FLAG_HIDDEN;
647       vnet_sw_interface_set_flags (vnm, sw_if_index,
648                                    VNET_SW_INTERFACE_FLAG_ADMIN_UP);
649
650       fib_node_init (&t->node, gtm->fib_node_type);
651       fib_prefix_t tun_dst_pfx;
652       vnet_flood_class_t flood_class = VNET_FLOOD_CLASS_TUNNEL_NORMAL;
653
654       fib_protocol_t fp = fib_ip_proto (is_ip6);
655       fib_prefix_from_ip46_addr (fp, &t->dst, &tun_dst_pfx);
656       if (!ip46_address_is_multicast (&t->dst))
657         {
658           /* Unicast tunnel -
659            * Track the FIB entry for the tunnel's destination.
660            * The tunnel will then get poked
661            * when the forwarding for the entry updates, and the tunnel can
662            * re-stack accordingly
663            */
664           vtep_addr_ref (&gtm->vtep_table, t->encap_fib_index, &t->src);
665           t->fib_entry_index = fib_entry_track (t->encap_fib_index,
666                                                 &tun_dst_pfx,
667                                                 gtm->fib_node_type,
668                                                 t - gtm->tunnels,
669                                                 &t->sibling_index);
670           gtpu_tunnel_restack_dpo (t);
671         }
672       else
673         {
674           /* Multicast tunnel -
675            * as the same mcast group can be used for multiple mcast tunnels
676            * with different VNIs, create the output adjacency only if
677            * it does not already exist
678            */
679           if (vtep_addr_ref (&gtm->vtep_table,
680                              t->encap_fib_index, &t->dst) == 1)
681             {
682               fib_node_index_t mfei;
683               adj_index_t ai;
684               fib_route_path_t path = {
685                 .frp_proto = fib_proto_to_dpo (fp),
686                 .frp_addr = zero_addr,
687                 .frp_sw_if_index = 0xffffffff,
688                 .frp_fib_index = ~0,
689                 .frp_weight = 1,
690                 .frp_flags = FIB_ROUTE_PATH_LOCAL,
691                 .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
692               };
693               const mfib_prefix_t mpfx = {
694                 .fp_proto = fp,
695                 .fp_len = (is_ip6 ? 128 : 32),
696                 .fp_grp_addr = tun_dst_pfx.fp_addr,
697               };
698
699               /*
700                * Setup the (*,G) to receive traffic on the mcast group
701                *  - the forwarding interface is for-us
702                *  - the accepting interface is that from the API
703                */
704               mfib_table_entry_path_update (t->encap_fib_index, &mpfx,
705                                             MFIB_SOURCE_GTPU,
706                                             MFIB_ENTRY_FLAG_NONE, &path);
707
708               path.frp_sw_if_index = a->mcast_sw_if_index;
709               path.frp_flags = FIB_ROUTE_PATH_FLAG_NONE;
710               path.frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT;
711               mfei = mfib_table_entry_path_update (
712                 t->encap_fib_index, &mpfx, MFIB_SOURCE_GTPU,
713                 MFIB_ENTRY_FLAG_NONE, &path);
714
715               /*
716                * Create the mcast adjacency to send traffic to the group
717                */
718               ai = adj_mcast_add_or_lock (fp,
719                                           fib_proto_to_link (fp),
720                                           a->mcast_sw_if_index);
721
722               /*
723                * create a new end-point
724                */
725               mcast_shared_add (&t->dst, mfei, ai);
726             }
727
728           dpo_id_t dpo = DPO_INVALID;
729           mcast_shared_t ep = mcast_shared_get (&t->dst);
730
731           /* Stack shared mcast dst mac addr rewrite on encap */
732           dpo_set (&dpo, DPO_ADJACENCY_MCAST,
733                    fib_proto_to_dpo (fp), ep.mcast_adj_index);
734
735           dpo_stack_from_node (encap_index, &t->next_dpo, &dpo);
736
737           dpo_reset (&dpo);
738           flood_class = VNET_FLOOD_CLASS_TUNNEL_MASTER;
739         }
740
741       vnet_get_sw_interface (vnet_get_main (), sw_if_index)->flood_class =
742         flood_class;
743     }
744   else
745     {
746       /* mod-tteid or deleting a tunnel: tunnel must exist */
747       if (!p)
748         return VNET_API_ERROR_NO_SUCH_ENTRY;
749
750       t = pool_elt_at_index (gtm->tunnels, p[0]);
751       sw_if_index = t->sw_if_index;
752
753       if (a->opn == GTPU_UPD_TTEID)
754         {
755           if (a->tteid == 0)
756             return VNET_API_ERROR_INVALID_VALUE;
757           t->tteid = a->tteid;
758           vec_free (t->rewrite);
759           ip_udp_gtpu_rewrite (t, is_ip6);
760           return 0;
761         }
762
763       /* delete tunnel */
764       vnet_sw_interface_set_flags (vnm, t->sw_if_index, 0 /* down */ );
765       vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, t->sw_if_index);
766       si->flags |= VNET_SW_INTERFACE_FLAG_HIDDEN;
767
768       /* make sure tunnel is removed from l2 bd or xconnect */
769       set_int_l2_mode (gtm->vlib_main, vnm, MODE_L3, t->sw_if_index, 0,
770                        L2_BD_PORT_TYPE_NORMAL, 0, 0);
771       vec_add1 (gtm->free_gtpu_tunnel_hw_if_indices, t->hw_if_index);
772
773       gtm->tunnel_index_by_sw_if_index[t->sw_if_index] = ~0;
774
775       if (!is_ip6)
776         hash_unset (gtm->gtpu4_tunnel_by_key, key4.as_u64);
777       else
778         hash_unset_mem_free (&gtm->gtpu6_tunnel_by_key, &key6);
779
780       if (!ip46_address_is_multicast (&t->dst))
781         {
782           if (t->flow_index != ~0)
783             vnet_flow_del (vnm, t->flow_index);
784
785           vtep_addr_unref (&gtm->vtep_table, t->encap_fib_index, &t->src);
786           fib_entry_untrack (t->fib_entry_index, t->sibling_index);
787         }
788       else if (vtep_addr_unref (&gtm->vtep_table,
789                                 t->encap_fib_index, &t->dst) == 0)
790         {
791           mcast_shared_remove (&t->dst);
792         }
793
794       fib_node_deinit (&t->node);
795       vec_free (t->rewrite);
796       pool_put (gtm->tunnels, t);
797     }
798
799   if (sw_if_indexp)
800     *sw_if_indexp = sw_if_index;
801
802   if (a->opn == GTPU_ADD_TUNNEL)
803     {
804       /* register udp ports */
805       if (!is_ip6 && !udp_is_valid_dst_port (UDP_DST_PORT_GTPU, 1))
806         udp_register_dst_port (gtm->vlib_main, UDP_DST_PORT_GTPU,
807                                gtpu4_input_node.index, /* is_ip4 */ 1);
808       if (is_ip6 && !udp_is_valid_dst_port (UDP_DST_PORT_GTPU6, 0))
809         udp_register_dst_port (gtm->vlib_main, UDP_DST_PORT_GTPU6,
810                                gtpu6_input_node.index, /* is_ip4 */ 0);
811     }
812
813   return 0;
814 }
815
816 int
817 get_combined_counters (u32 sw_if_index, vlib_counter_t *result_rx,
818                        vlib_counter_t *result_tx)
819 {
820   gtpu_main_t *gtm = &gtpu_main;
821   vnet_main_t *vnm = gtm->vnet_main;
822   vnet_interface_main_t *im = &vnm->interface_main;
823   vlib_get_combined_counter (im->combined_sw_if_counters +
824                                VNET_INTERFACE_COUNTER_RX,
825                              sw_if_index, result_rx);
826   vlib_get_combined_counter (im->combined_sw_if_counters +
827                                VNET_INTERFACE_COUNTER_TX,
828                              sw_if_index, result_tx);
829   return 0;
830 }
831
832 static uword
833 get_decap_next_for_node (u32 node_index, u32 ipv4_set)
834 {
835   gtpu_main_t *gtm = &gtpu_main;
836   vlib_main_t *vm = gtm->vlib_main;
837   uword input_node = (ipv4_set) ? gtpu4_input_node.index :
838     gtpu6_input_node.index;
839
840   return vlib_node_add_next (vm, input_node, node_index);
841 }
842
843 static uword
844 unformat_decap_next (unformat_input_t * input, va_list * args)
845 {
846   u32 *result = va_arg (*args, u32 *);
847   u32 ipv4_set = va_arg (*args, int);
848   gtpu_main_t *gtm = &gtpu_main;
849   vlib_main_t *vm = gtm->vlib_main;
850   u32 node_index;
851   u32 tmp;
852
853   if (unformat (input, "l2"))
854     *result = GTPU_INPUT_NEXT_L2_INPUT;
855   else if (unformat (input, "ip4"))
856     *result = GTPU_INPUT_NEXT_IP4_INPUT;
857   else if (unformat (input, "ip6"))
858     *result = GTPU_INPUT_NEXT_IP6_INPUT;
859   else if (unformat (input, "node %U", unformat_vlib_node, vm, &node_index))
860     *result = get_decap_next_for_node (node_index, ipv4_set);
861   else if (unformat (input, "%d", &tmp))
862     *result = tmp;
863   else
864     return 0;
865
866   return 1;
867 }
868
869 static clib_error_t *
870 gtpu_add_del_tunnel_command_fn (vlib_main_t * vm,
871                                 unformat_input_t * input,
872                                 vlib_cli_command_t * cmd)
873 {
874   unformat_input_t _line_input, *line_input = &_line_input;
875   ip46_address_t src, dst;
876   u8 opn = GTPU_ADD_TUNNEL;
877   u8 src_set = 0;
878   u8 dst_set = 0;
879   u8 grp_set = 0;
880   u8 ipv4_set = 0;
881   u8 ipv6_set = 0;
882   u32 encap_fib_index = 0;
883   u32 mcast_sw_if_index = ~0;
884   u32 decap_next_index = GTPU_INPUT_NEXT_L2_INPUT;
885   u32 teid = 0, tteid = 0;
886   u32 tmp;
887   /* PDU is disabled by default */
888   u8 pdu_extension = 0;
889   u32 qfi = ~0;
890   u8 is_forwarding = 0;
891   u8 forwarding_type = 0;
892   int rv;
893   vnet_gtpu_add_mod_del_tunnel_args_t _a, *a = &_a;
894   u32 tunnel_sw_if_index;
895   clib_error_t *error = NULL;
896
897   /* Cant "universally zero init" (={0}) due to GCC bug 53119 */
898   clib_memset (&src, 0, sizeof src);
899   clib_memset (&dst, 0, sizeof dst);
900
901   /* Get a line of input. */
902   if (!unformat_user (input, unformat_line_input, line_input))
903     return 0;
904
905   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
906     {
907       if (unformat (line_input, "del"))
908         {
909           opn = GTPU_DEL_TUNNEL;
910         }
911       else if (unformat (line_input, "src %U",
912                          unformat_ip4_address, &src.ip4))
913         {
914           src_set = 1;
915           ipv4_set = 1;
916         }
917       else if (unformat (line_input, "dst %U",
918                          unformat_ip4_address, &dst.ip4))
919         {
920           dst_set = 1;
921           ipv4_set = 1;
922         }
923       else if (unformat (line_input, "src %U",
924                          unformat_ip6_address, &src.ip6))
925         {
926           src_set = 1;
927           ipv6_set = 1;
928         }
929       else if (unformat (line_input, "dst %U",
930                          unformat_ip6_address, &dst.ip6))
931         {
932           dst_set = 1;
933           ipv6_set = 1;
934         }
935       else if (unformat (line_input, "group %U %U",
936                          unformat_ip4_address, &dst.ip4,
937                          unformat_vnet_sw_interface,
938                          vnet_get_main (), &mcast_sw_if_index))
939         {
940           grp_set = dst_set = 1;
941           ipv4_set = 1;
942         }
943       else if (unformat (line_input, "group %U %U",
944                          unformat_ip6_address, &dst.ip6,
945                          unformat_vnet_sw_interface,
946                          vnet_get_main (), &mcast_sw_if_index))
947         {
948           grp_set = dst_set = 1;
949           ipv6_set = 1;
950         }
951       else if (unformat (line_input, "encap-vrf-id %d", &tmp))
952         {
953           encap_fib_index = fib_table_find (fib_ip_proto (ipv6_set), tmp);
954           if (encap_fib_index == ~0)
955             {
956               error =
957                 clib_error_return (0, "nonexistent encap-vrf-id %d", tmp);
958               goto done;
959             }
960         }
961       else if (unformat (line_input, "decap-next %U", unformat_decap_next,
962                          &decap_next_index, ipv4_set))
963         ;
964       else if (unformat (line_input, "teid %d", &teid))
965         ;
966       else if (unformat (line_input, "tteid %d", &tteid))
967         ;
968       else if (unformat (line_input, "upd-tteid %d", &tteid))
969         opn = GTPU_UPD_TTEID;
970       else if (unformat (line_input, "qfi %d", &qfi))
971         pdu_extension = 1;
972       else
973         {
974           error = clib_error_return (0, "parse error: '%U'",
975                                      format_unformat_error, line_input);
976           goto done;
977         }
978     }
979
980   if (teid == 0)
981     {
982       error = clib_error_return (0, "tunnel teid specified");
983       goto done;
984     }
985
986   if (src_set == 0 && opn == GTPU_ADD_TUNNEL)
987     {
988       error = clib_error_return (0, "tunnel src address not specified");
989       goto done;
990     }
991
992   if (dst_set == 0)
993     {
994       error = clib_error_return (0, "tunnel dst address not specified");
995       goto done;
996     }
997
998   if (grp_set && !ip46_address_is_multicast (&dst))
999     {
1000       error = clib_error_return (0, "tunnel group address not multicast");
1001       goto done;
1002     }
1003
1004   if (grp_set == 0 && ip46_address_is_multicast (&dst))
1005     {
1006       error = clib_error_return (0, "dst address must be unicast");
1007       goto done;
1008     }
1009
1010   if (grp_set && mcast_sw_if_index == ~0)
1011     {
1012       error = clib_error_return (0, "tunnel nonexistent multicast device");
1013       goto done;
1014     }
1015
1016   if (ipv4_set && ipv6_set)
1017     {
1018       error = clib_error_return (0, "both IPv4 and IPv6 addresses specified");
1019       goto done;
1020     }
1021
1022   if (ip46_address_cmp (&src, &dst) == 0)
1023     {
1024       error = clib_error_return (0, "src and dst addresses are identical");
1025       goto done;
1026     }
1027
1028   if (decap_next_index == ~0)
1029     {
1030       error = clib_error_return (0, "next node not found");
1031       goto done;
1032     }
1033   if (pdu_extension == 1 && qfi > 31)
1034     {
1035       error = clib_error_return (0, "qfi max value is 31");
1036       goto done;
1037     }
1038   clib_memset (a, 0, sizeof (*a));
1039
1040   a->opn = opn;
1041
1042 #define _(x) a->x = x;
1043   foreach_copy_field;
1044 #undef _
1045
1046   rv = vnet_gtpu_add_mod_del_tunnel (a, &tunnel_sw_if_index);
1047
1048   switch (rv)
1049     {
1050     case 0:
1051       if (opn == GTPU_ADD_TUNNEL)
1052         vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
1053                          vnet_get_main (), tunnel_sw_if_index);
1054       break;
1055
1056     case VNET_API_ERROR_TUNNEL_EXIST:
1057       error = clib_error_return (0, "tunnel already exists...");
1058       goto done;
1059
1060     case VNET_API_ERROR_NO_SUCH_ENTRY:
1061       error = clib_error_return (0, "tunnel does not exist...");
1062       goto done;
1063
1064     case VNET_API_ERROR_INVALID_VALUE:
1065       error = clib_error_return (0, "tx teid not specified...");
1066       goto done;
1067
1068     default:
1069       error = clib_error_return
1070         (0, "vnet_gtpu_add_del_tunnel returned %d", rv);
1071       goto done;
1072     }
1073
1074 done:
1075   unformat_free (line_input);
1076
1077   return error;
1078 }
1079
1080 /*?
1081  * Add or delete a GTPU Tunnel.
1082  *
1083  * GTPU can be used to transport Ethernet packets as its PDU type to
1084  * provides allow L2 network or bridge domains (BDs)
1085  * to span multiple servers. This is done by building an L2 overlay on
1086  * top of an L3 network underlay using GTPU tunnels.
1087  *
1088  * GTPU can also be used to transport IP packets as its PDU type to
1089  * allow IP forwarding over underlay network, e.g. between RAN and UPF
1090  * for mobility deployments.
1091  *
1092  * @cliexpar
1093  * Example of how to create a GTPU Tunnel:
1094  * @cliexcmd{create gtpu tunnel src 10.0.3.1 dst 10.0.3.3 teid 13 tteid 55
1095  * encap-vrf-id 7}
1096  * Example of how to delete a GTPU Tunnel:
1097  * @cliexcmd{create gtpu tunnel src 10.0.3.1 dst 10.0.3.3 teid 13 encap-vrf-id
1098  * 7 del}
1099  * Example of how to update tx TEID of a GTPU Tunnel:
1100  * @cliexcmd{create gtpu tunnel src 10.0.3.1 dst 10.0.3.3 encap-vrf-id 7
1101  * upd-tteid 55}
1102  ?*/
1103 VLIB_CLI_COMMAND (create_gtpu_tunnel_command, static) = {
1104   .path = "create gtpu tunnel",
1105   .short_help =
1106     "create gtpu tunnel src <local-tep-addr>"
1107     " {dst <remote-tep-addr>|group <mcast-addr> <intf-name>}"
1108     " teid <nn> [tteid <nn>] [encap-vrf-id <nn>]"
1109     " [decap-next [l2|ip4|ip6|node <name>]] [qfi <nn>] [del | upd-tteid <nn>]",
1110   .function = gtpu_add_del_tunnel_command_fn,
1111 };
1112
1113 static clib_error_t *
1114 show_gtpu_tunnel_command_fn (vlib_main_t * vm,
1115                              unformat_input_t * input,
1116                              vlib_cli_command_t * cmd)
1117 {
1118   gtpu_main_t *gtm = &gtpu_main;
1119   gtpu_tunnel_t *t;
1120
1121   if (pool_elts (gtm->tunnels) == 0)
1122     vlib_cli_output (vm, "No gtpu tunnels configured...");
1123
1124   pool_foreach (t, gtm->tunnels)
1125   {
1126     vlib_cli_output (vm, "%U", format_gtpu_tunnel, t);
1127   }
1128
1129   return 0;
1130 }
1131
1132 /*?
1133  * Display all the GTPU Tunnel entries.
1134  *
1135  * @cliexpar
1136  * Example of how to display the GTPU Tunnel entries:
1137  * @cliexstart{show gtpu tunnel}
1138  * [0] src 10.0.3.1 dst 10.0.3.3 teid 13 tx-teid 55 encap_fib_index 0
1139  sw_if_index 5 decap_next l2 pdu-disabled
1140  * @cliexend
1141  ?*/
1142 VLIB_CLI_COMMAND (show_gtpu_tunnel_command, static) = {
1143     .path = "show gtpu tunnel",
1144     .short_help = "show gtpu tunnel",
1145     .function = show_gtpu_tunnel_command_fn,
1146 };
1147
1148 void
1149 vnet_int_gtpu_bypass_mode (u32 sw_if_index, u8 is_ip6, u8 is_enable)
1150 {
1151   if (is_ip6)
1152     vnet_feature_enable_disable ("ip6-unicast", "ip6-gtpu-bypass",
1153                                  sw_if_index, is_enable, 0, 0);
1154   else
1155     vnet_feature_enable_disable ("ip4-unicast", "ip4-gtpu-bypass",
1156                                  sw_if_index, is_enable, 0, 0);
1157 }
1158
1159 static clib_error_t *
1160 set_ip_gtpu_bypass (u32 is_ip6,
1161                     unformat_input_t * input, vlib_cli_command_t * cmd)
1162 {
1163   unformat_input_t _line_input, *line_input = &_line_input;
1164   vnet_main_t *vnm = vnet_get_main ();
1165   clib_error_t *error = 0;
1166   u32 sw_if_index, is_enable;
1167
1168   sw_if_index = ~0;
1169   is_enable = 1;
1170
1171   if (!unformat_user (input, unformat_line_input, line_input))
1172     return 0;
1173
1174   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1175     {
1176       if (unformat_user
1177           (line_input, unformat_vnet_sw_interface, vnm, &sw_if_index))
1178         ;
1179       else if (unformat (line_input, "del"))
1180         is_enable = 0;
1181       else
1182         {
1183           error = unformat_parse_error (line_input);
1184           goto done;
1185         }
1186     }
1187
1188   if (~0 == sw_if_index)
1189     {
1190       error = clib_error_return (0, "unknown interface `%U'",
1191                                  format_unformat_error, line_input);
1192       goto done;
1193     }
1194
1195   vnet_int_gtpu_bypass_mode (sw_if_index, is_ip6, is_enable);
1196
1197 done:
1198   unformat_free (line_input);
1199
1200   return error;
1201 }
1202
1203 static clib_error_t *
1204 set_ip4_gtpu_bypass (vlib_main_t * vm,
1205                      unformat_input_t * input, vlib_cli_command_t * cmd)
1206 {
1207   return set_ip_gtpu_bypass (0, input, cmd);
1208 }
1209
1210 /*?
1211  * This command adds the 'ip4-gtpu-bypass' graph node for a given interface.
1212  * By adding the IPv4 gtpu-bypass graph node to an interface, the node checks
1213  * for and validate input gtpu packet and bypass ip4-lookup, ip4-local,
1214  * ip4-udp-lookup nodes to speedup gtpu packet forwarding. This node will
1215  * cause extra overhead to for non-gtpu packets which is kept at a minimum.
1216  *
1217  * @cliexpar
1218  * @parblock
1219  * Example of graph node before ip4-gtpu-bypass is enabled:
1220  * @cliexstart{show vlib graph ip4-gtpu-bypass}
1221  *            Name                      Next                    Previous
1222  * ip4-gtpu-bypass                error-drop [0]
1223  *                                gtpu4-input [1]
1224  *                                 ip4-lookup [2]
1225  * @cliexend
1226  *
1227  * Example of how to enable ip4-gtpu-bypass on an interface:
1228  * @cliexcmd{set interface ip gtpu-bypass GigabitEthernet2/0/0}
1229  *
1230  * Example of graph node after ip4-gtpu-bypass is enabled:
1231  * @cliexstart{show vlib graph ip4-gtpu-bypass}
1232  *            Name                      Next                    Previous
1233  * ip4-gtpu-bypass                error-drop [0]               ip4-input
1234  *                                gtpu4-input [1]        ip4-input-no-checksum
1235  *                                 ip4-lookup [2]
1236  * @cliexend
1237  *
1238  * Example of how to display the feature enabled on an interface:
1239  * @cliexstart{show ip interface features GigabitEthernet2/0/0}
1240  * IP feature paths configured on GigabitEthernet2/0/0...
1241  * ...
1242  * ipv4 unicast:
1243  *   ip4-gtpu-bypass
1244  *   ip4-lookup
1245  * ...
1246  * @cliexend
1247  *
1248  * Example of how to disable ip4-gtpu-bypass on an interface:
1249  * @cliexcmd{set interface ip gtpu-bypass GigabitEthernet2/0/0 del}
1250  * @endparblock
1251 ?*/
1252 VLIB_CLI_COMMAND (set_interface_ip_gtpu_bypass_command, static) = {
1253   .path = "set interface ip gtpu-bypass",
1254   .function = set_ip4_gtpu_bypass,
1255   .short_help = "set interface ip gtpu-bypass <interface> [del]",
1256 };
1257
1258 static clib_error_t *
1259 set_ip6_gtpu_bypass (vlib_main_t * vm,
1260                      unformat_input_t * input, vlib_cli_command_t * cmd)
1261 {
1262   return set_ip_gtpu_bypass (1, input, cmd);
1263 }
1264
1265 /*?
1266  * This command adds the 'ip6-gtpu-bypass' graph node for a given interface.
1267  * By adding the IPv6 gtpu-bypass graph node to an interface, the node checks
1268  * for and validate input gtpu packet and bypass ip6-lookup, ip6-local,
1269  * ip6-udp-lookup nodes to speedup gtpu packet forwarding. This node will
1270  * cause extra overhead to for non-gtpu packets which is kept at a minimum.
1271  *
1272  * @cliexpar
1273  * @parblock
1274  * Example of graph node before ip6-gtpu-bypass is enabled:
1275  * @cliexstart{show vlib graph ip6-gtpu-bypass}
1276  *            Name                      Next                    Previous
1277  * ip6-gtpu-bypass                error-drop [0]
1278  *                                gtpu6-input [1]
1279  *                                 ip6-lookup [2]
1280  * @cliexend
1281  *
1282  * Example of how to enable ip6-gtpu-bypass on an interface:
1283  * @cliexcmd{set interface ip6 gtpu-bypass GigabitEthernet2/0/0}
1284  *
1285  * Example of graph node after ip6-gtpu-bypass is enabled:
1286  * @cliexstart{show vlib graph ip6-gtpu-bypass}
1287  *            Name                      Next                    Previous
1288  * ip6-gtpu-bypass                error-drop [0]               ip6-input
1289  *                                gtpu6-input [1]        ip4-input-no-checksum
1290  *                                 ip6-lookup [2]
1291  * @cliexend
1292  *
1293  * Example of how to display the feature enabled on an interface:
1294  * @cliexstart{show ip interface features GigabitEthernet2/0/0}
1295  * IP feature paths configured on GigabitEthernet2/0/0...
1296  * ...
1297  * ipv6 unicast:
1298  *   ip6-gtpu-bypass
1299  *   ip6-lookup
1300  * ...
1301  * @cliexend
1302  *
1303  * Example of how to disable ip6-gtpu-bypass on an interface:
1304  * @cliexcmd{set interface ip6 gtpu-bypass GigabitEthernet2/0/0 del}
1305  * @endparblock
1306 ?*/
1307 VLIB_CLI_COMMAND (set_interface_ip6_gtpu_bypass_command, static) = {
1308   .path = "set interface ip6 gtpu-bypass",
1309   .function = set_ip6_gtpu_bypass,
1310   .short_help = "set interface ip6 gtpu-bypass <interface> [del]",
1311 };
1312
1313 int
1314 vnet_gtpu_add_del_rx_flow (u32 hw_if_index, u32 t_index, int is_add)
1315 {
1316   gtpu_main_t *gtm = &gtpu_main;
1317   gtpu_tunnel_t *t = pool_elt_at_index (gtm->tunnels, t_index);
1318   vnet_main_t *vnm = vnet_get_main ();
1319   if (is_add)
1320     {
1321       if (t->flow_index == ~0)
1322         {
1323           vnet_flow_t flow = {
1324             .actions =
1325               VNET_FLOW_ACTION_REDIRECT_TO_NODE | VNET_FLOW_ACTION_MARK |
1326               VNET_FLOW_ACTION_BUFFER_ADVANCE,
1327             .mark_flow_id = t_index + gtm->flow_id_start,
1328             .redirect_node_index = gtpu4_flow_input_node.index,
1329             .buffer_advance = sizeof (ethernet_header_t)
1330               + sizeof (ip4_header_t) + sizeof (udp_header_t),
1331             .type = VNET_FLOW_TYPE_IP4_GTPU,
1332             .ip4_gtpu = {
1333                          .protocol.prot = IP_PROTOCOL_UDP,
1334                          .src_addr.addr = t->dst.ip4,
1335                          .src_addr.mask.as_u32 = ~0,
1336                          .dst_addr.addr = t->src.ip4,
1337                          .dst_addr.mask.as_u32 = ~0,
1338                          .teid = t->teid,
1339                          }
1340             ,
1341           };
1342           vnet_flow_add (vnm, &flow, &t->flow_index);
1343         }
1344
1345       return vnet_flow_enable (vnm, t->flow_index, hw_if_index);
1346     }
1347
1348   /* flow index is removed when the tunnel is deleted */
1349   return vnet_flow_disable (vnm, t->flow_index, hw_if_index);
1350 }
1351
1352 u32
1353 vnet_gtpu_get_tunnel_index (u32 sw_if_index)
1354 {
1355   gtpu_main_t *gtm = &gtpu_main;
1356
1357   if (sw_if_index >= vec_len (gtm->tunnel_index_by_sw_if_index))
1358     return ~0;
1359   return gtm->tunnel_index_by_sw_if_index[sw_if_index];
1360 }
1361
1362 static clib_error_t *
1363 gtpu_offload_command_fn (vlib_main_t * vm,
1364                          unformat_input_t * input, vlib_cli_command_t * cmd)
1365 {
1366   unformat_input_t _line_input, *line_input = &_line_input;
1367
1368   /* Get a line of input. */
1369   if (!unformat_user (input, unformat_line_input, line_input))
1370     return 0;
1371
1372   vnet_main_t *vnm = vnet_get_main ();
1373   u32 rx_sw_if_index = ~0;
1374   u32 hw_if_index = ~0;
1375   int is_add = 1;
1376
1377   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1378     {
1379       if (unformat (line_input, "hw %U", unformat_vnet_hw_interface, vnm,
1380                     &hw_if_index))
1381         continue;
1382       if (unformat (line_input, "rx %U", unformat_vnet_sw_interface, vnm,
1383                     &rx_sw_if_index))
1384         continue;
1385       if (unformat (line_input, "del"))
1386         {
1387           is_add = 0;
1388           continue;
1389         }
1390       return clib_error_return (0, "unknown input `%U'",
1391                                 format_unformat_error, line_input);
1392     }
1393
1394   if (rx_sw_if_index == ~0)
1395     return clib_error_return (0, "missing rx interface");
1396   if (hw_if_index == ~0)
1397     return clib_error_return (0, "missing hw interface");
1398
1399   u32 t_index = vnet_gtpu_get_tunnel_index (rx_sw_if_index);;
1400   if (t_index == ~0)
1401     return clib_error_return (0, "%U is not a gtpu tunnel",
1402                               format_vnet_sw_if_index_name, vnm,
1403                               rx_sw_if_index);
1404
1405   gtpu_main_t *gtm = &gtpu_main;
1406   gtpu_tunnel_t *t = pool_elt_at_index (gtm->tunnels, t_index);
1407
1408   /* first support ipv4 hw offload */
1409   if (!ip46_address_is_ip4 (&t->dst))
1410     return clib_error_return (0, "currently only IPV4 tunnels are supported");
1411
1412   /* inner protocol should be IPv4/IPv6 */
1413   if ((t->decap_next_index != GTPU_INPUT_NEXT_IP4_INPUT) &&
1414       (t->decap_next_index != GTPU_INPUT_NEXT_IP6_INPUT))
1415     return clib_error_return (0,
1416                               "currently only inner IPv4/IPv6 protocol is supported");
1417
1418   vnet_hw_interface_t *hw_if = vnet_get_hw_interface (vnm, hw_if_index);
1419   ip4_main_t *im = &ip4_main;
1420   u32 rx_fib_index =
1421     vec_elt (im->fib_index_by_sw_if_index, hw_if->sw_if_index);
1422
1423   if (t->encap_fib_index != rx_fib_index)
1424     return clib_error_return (0, "interface/tunnel fib mismatch");
1425
1426   if (vnet_gtpu_add_del_rx_flow (hw_if_index, t_index, is_add))
1427     return clib_error_return (0, "error %s flow",
1428                               is_add ? "enabling" : "disabling");
1429
1430   return 0;
1431 }
1432
1433
1434 VLIB_CLI_COMMAND (gtpu_offload_command, static) = {
1435     .path = "set flow-offload gtpu",
1436     .short_help =
1437     "set flow-offload gtpu hw <inerface-name> rx <tunnel-name> [del]",
1438     .function = gtpu_offload_command_fn,
1439 };
1440
1441 static clib_error_t *
1442 gtpu_forward_command_fn (vlib_main_t *vm, unformat_input_t *input,
1443                          vlib_cli_command_t *cmd)
1444 {
1445   unformat_input_t _line_input, *line_input = &_line_input;
1446
1447   /* Get a line of input. */
1448   if (!unformat_user (input, unformat_line_input, line_input))
1449     return 0;
1450
1451   u32 tunnel_sw_if_index;
1452   clib_error_t *error = NULL;
1453
1454   u32 decap_next_index = GTPU_INPUT_NEXT_L2_INPUT;
1455
1456   int is_add = 1;
1457   u8 dst_set = 0;
1458   u8 ipv4_set = 0;
1459   u8 ipv6_set = 0;
1460   ip46_address_t src, dst;
1461   u32 encap_fib_index = 0;
1462   u32 mcast_sw_if_index = ~0;
1463   u32 teid = 0, tteid = 0;
1464   u32 tmp;
1465   /* PDU is disabled by default */
1466   u8 pdu_extension = 0;
1467   u32 qfi = ~0;
1468   u8 is_forwarding = 1;
1469   u8 forwarding_type = 0;
1470   int rv;
1471   vnet_gtpu_add_mod_del_tunnel_args_t _a, *a = &_a;
1472
1473   /* Cant "universally zero init" (={0}) due to GCC bug 53119 */
1474   clib_memset (&src, 0, sizeof src);
1475   clib_memset (&dst, 0, sizeof dst);
1476
1477   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1478     {
1479       if (unformat (line_input, "dst %U", unformat_ip4_address, &dst.ip4))
1480         {
1481           dst_set = 1;
1482           ipv4_set = 1;
1483         }
1484       else if (unformat (line_input, "dst %U", unformat_ip6_address, &dst.ip6))
1485         {
1486           dst_set = 1;
1487           ipv6_set = 1;
1488         }
1489       else if (unformat (line_input, "decap-next %U", unformat_decap_next,
1490                          &decap_next_index, ipv4_set))
1491         ;
1492       else if (unformat (line_input, "encap-vrf-id %d", &tmp))
1493         {
1494           encap_fib_index = fib_table_find (fib_ip_proto (ipv6_set), tmp);
1495           if (encap_fib_index == ~0)
1496             {
1497               error =
1498                 clib_error_return (0, "nonexistent encap-vrf-id %d", tmp);
1499               goto done;
1500             }
1501         }
1502       else if (unformat (line_input, "del"))
1503         is_add = 0;
1504       else if (unformat (line_input, "bad-header"))
1505         forwarding_type |= GTPU_FORWARD_BAD_HEADER;
1506       else if (unformat (line_input, "unknown-teid"))
1507         forwarding_type |= GTPU_FORWARD_UNKNOWN_TEID;
1508       else if (unformat (line_input, "unknown-type"))
1509         forwarding_type |= GTPU_FORWARD_UNKNOWN_TYPE;
1510       else
1511         {
1512           error = clib_error_return (0, "unknown input `%U'",
1513                                      format_unformat_error, line_input);
1514           goto done;
1515         }
1516     }
1517
1518   if (!dst_set)
1519     {
1520       error = clib_error_return (0, "dst must be set to a valid IP address");
1521       goto done;
1522     }
1523
1524   a->opn = is_add ? GTPU_ADD_TUNNEL : GTPU_DEL_TUNNEL;
1525 #define _(x) a->x = x;
1526   foreach_copy_field;
1527 #undef _
1528
1529   rv = vnet_gtpu_add_del_forwarding (a, &tunnel_sw_if_index);
1530
1531   switch (rv)
1532     {
1533     case 0:
1534       if (is_add)
1535         vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
1536                          vnet_get_main (), tunnel_sw_if_index);
1537       break;
1538
1539     case VNET_API_ERROR_TUNNEL_EXIST:
1540       error = clib_error_return (0, "tunnel already exists...");
1541       goto done;
1542
1543     case VNET_API_ERROR_NO_SUCH_ENTRY:
1544       error = clib_error_return (0, "tunnel does not exist...");
1545       goto done;
1546
1547     case VNET_API_ERROR_INVALID_ARGUMENT:
1548       error =
1549         clib_error_return (0, "one and only one of unknown-teid, unknown-type "
1550                               "or bad-header must be specified");
1551       goto done;
1552
1553     default:
1554       error =
1555         clib_error_return (0, "vnet_gtpu_add_del_tunnel returned %d", rv);
1556       goto done;
1557     }
1558
1559 done:
1560   unformat_free (line_input);
1561
1562   return error;
1563 }
1564
1565 VLIB_CLI_COMMAND (gtpu_forward_command, static) = {
1566   .path = "create gtpu forward",
1567   .short_help =
1568     "create gtpu forward dst <local-tep-addr> "
1569     "{unknown-teid|unknown-type|bad-header} "
1570     "[decap-next [l2|ip4|ip6|node <name>]] [encap-vrf-id <nn>] [del]",
1571   .function = gtpu_forward_command_fn,
1572 };
1573
1574 clib_error_t *
1575 gtpu_init (vlib_main_t * vm)
1576 {
1577   gtpu_main_t *gtm = &gtpu_main;
1578
1579   gtm->vnet_main = vnet_get_main ();
1580   gtm->vlib_main = vm;
1581
1582   vnet_flow_get_range (gtm->vnet_main, "gtpu", 1024 * 1024,
1583                        &gtm->flow_id_start);
1584
1585   /* initialize the ip6 hash */
1586   gtm->gtpu6_tunnel_by_key = hash_create_mem (0,
1587                                               sizeof (gtpu6_tunnel_key_t),
1588                                               sizeof (uword));
1589   gtm->vtep_table = vtep_table_create ();
1590   gtm->mcast_shared = hash_create_mem (0,
1591                                        sizeof (ip46_address_t),
1592                                        sizeof (mcast_shared_t));
1593
1594   gtm->fib_node_type = fib_node_register_new_type ("gtpu", &gtpu_vft);
1595
1596   /* Clear forward tunnels */
1597   gtm->bad_header_forward_tunnel_index_ipv4 = ~0;
1598   gtm->unknown_teid_forward_tunnel_index_ipv4 = ~0;
1599   gtm->unknown_type_forward_tunnel_index_ipv4 = ~0;
1600   gtm->bad_header_forward_tunnel_index_ipv6 = ~0;
1601   gtm->unknown_teid_forward_tunnel_index_ipv6 = ~0;
1602   gtm->unknown_type_forward_tunnel_index_ipv6 = ~0;
1603
1604   return 0;
1605 }
1606
1607 VLIB_INIT_FUNCTION (gtpu_init);
1608
1609 VLIB_PLUGIN_REGISTER () = {
1610     .version = VPP_BUILD_VER,
1611     .description = "GPRS Tunnelling Protocol, User Data (GTPv1-U)",
1612 };
1613
1614 /*
1615  * fd.io coding-style-patch-verification: ON
1616  *
1617  * Local Variables:
1618  * eval: (c-set-style "gnu")
1619  * End:
1620  */