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