gtpu: offload RX flow
[vpp.git] / src / plugins / gtpu / gtpu_test.c
1 /*
2  * Copyright (c) 2017 Intel and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <vat/vat.h>
17 #include <vlibapi/api.h>
18 #include <vlibmemory/api.h>
19 #include <vppinfra/error.h>
20 #include <gtpu/gtpu.h>
21 #include <vnet/ip/ip_types_api.h>
22
23 #define __plugin_msg_base gtpu_test_main.msg_id_base
24 #include <vlibapi/vat_helper_macros.h>
25
26 #include <vnet/format_fns.h>
27 #include <gtpu/gtpu.api_enum.h>
28 #include <gtpu/gtpu.api_types.h>
29
30 uword unformat_ip46_address (unformat_input_t * input, va_list * args)
31 {
32   ip46_address_t *ip46 = va_arg (*args, ip46_address_t *);
33   ip46_type_t type = va_arg (*args, ip46_type_t);
34   if ((type != IP46_TYPE_IP6) &&
35       unformat(input, "%U", unformat_ip4_address, &ip46->ip4)) {
36     ip46_address_mask_ip4(ip46);
37     return 1;
38   } else if ((type != IP46_TYPE_IP4) &&
39       unformat(input, "%U", unformat_ip6_address, &ip46->ip6)) {
40     return 1;
41   }
42   return 0;
43 }
44 uword unformat_ip46_prefix (unformat_input_t * input, va_list * args)
45 {
46   ip46_address_t *ip46 = va_arg (*args, ip46_address_t *);
47   u8 *len = va_arg (*args, u8 *);
48   ip46_type_t type = va_arg (*args, ip46_type_t);
49
50   u32 l;
51   if ((type != IP46_TYPE_IP6) && unformat(input, "%U/%u", unformat_ip4_address, &ip46->ip4, &l)) {
52     if (l > 32)
53       return 0;
54     *len = l + 96;
55     ip46->pad[0] = ip46->pad[1] = ip46->pad[2] = 0;
56   } else if ((type != IP46_TYPE_IP4) && unformat(input, "%U/%u", unformat_ip6_address, &ip46->ip6, &l)) {
57     if (l > 128)
58       return 0;
59     *len = l;
60   } else {
61     return 0;
62   }
63   return 1;
64 }
65 /////////////////////////
66
67 typedef struct {
68     /* API message ID base */
69     u16 msg_id_base;
70     vat_main_t *vat_main;
71 } gtpu_test_main_t;
72
73 gtpu_test_main_t gtpu_test_main;
74
75 static void vl_api_gtpu_add_del_tunnel_reply_t_handler
76   (vl_api_gtpu_add_del_tunnel_reply_t * mp)
77 {
78   vat_main_t *vam = &vat_main;
79   i32 retval = ntohl (mp->retval);
80   if (vam->async_mode)
81     {
82       vam->async_errors += (retval < 0);
83     }
84   else
85     {
86       vam->retval = retval;
87       vam->sw_if_index = ntohl (mp->sw_if_index);
88       vam->result_ready = 1;
89     }
90 }
91
92 static uword
93 api_unformat_sw_if_index (unformat_input_t * input, va_list * args)
94 {
95   vat_main_t *vam = va_arg (*args, vat_main_t *);
96   u32 *result = va_arg (*args, u32 *);
97   u8 *if_name;
98   uword *p;
99
100   if (!unformat (input, "%s", &if_name))
101     return 0;
102
103   p = hash_get_mem (vam->sw_if_index_by_interface_name, if_name);
104   if (p == 0)
105     return 0;
106   *result = p[0];
107   return 1;
108 }
109
110 static uword
111 api_unformat_hw_if_index (unformat_input_t * input, va_list * args)
112 {
113   return 0;
114 }
115
116 static int
117 api_sw_interface_set_gtpu_bypass (vat_main_t * vam)
118 {
119   unformat_input_t *i = vam->input;
120   vl_api_sw_interface_set_gtpu_bypass_t *mp;
121   u32 sw_if_index = 0;
122   u8 sw_if_index_set = 0;
123   u8 is_enable = 1;
124   u8 is_ipv6 = 0;
125   int ret;
126
127   /* Parse args required to build the message */
128   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
129     {
130       if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
131       sw_if_index_set = 1;
132       else if (unformat (i, "sw_if_index %d", &sw_if_index))
133       sw_if_index_set = 1;
134       else if (unformat (i, "enable"))
135       is_enable = 1;
136       else if (unformat (i, "disable"))
137       is_enable = 0;
138       else if (unformat (i, "ip4"))
139       is_ipv6 = 0;
140       else if (unformat (i, "ip6"))
141       is_ipv6 = 1;
142       else
143       break;
144     }
145
146   if (sw_if_index_set == 0)
147     {
148       errmsg ("missing interface name or sw_if_index");
149       return -99;
150     }
151
152   /* Construct the API message */
153   M (SW_INTERFACE_SET_GTPU_BYPASS, mp);
154
155   mp->sw_if_index = ntohl (sw_if_index);
156   mp->enable = is_enable;
157   mp->is_ipv6 = is_ipv6;
158
159   /* send it... */
160   S (mp);
161
162   /* Wait for a reply... */
163   W (ret);
164   return ret;
165 }
166
167 static uword unformat_gtpu_decap_next
168   (unformat_input_t * input, va_list * args)
169 {
170   u32 *result = va_arg (*args, u32 *);
171   u32 tmp;
172
173   if (unformat (input, "l2"))
174     *result = GTPU_INPUT_NEXT_L2_INPUT;
175   else if (unformat (input, "%d", &tmp))
176     *result = tmp;
177   else
178     return 0;
179   return 1;
180 }
181
182 static int
183 api_gtpu_offload_rx (vat_main_t * vam)
184 {
185   unformat_input_t *line_input = vam->input;
186   vl_api_gtpu_offload_rx_t *mp;
187   u32 rx_sw_if_index = ~0;
188   u32 hw_if_index = ~0;
189   int is_add = 1;
190   int ret;
191
192   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
193     {
194                   if (unformat (line_input, "hw %U", api_unformat_hw_if_index, vam, &hw_if_index))
195                     ;
196                   else
197                   if (unformat (line_input, "rx %U", api_unformat_sw_if_index, vam, &rx_sw_if_index))
198                     ;
199                   else
200       if (unformat (line_input, "del"))
201       {
202         is_add = 0;
203         continue;
204             }
205       else
206       {
207         errmsg ("parse error '%U'", format_unformat_error, line_input);
208         return -99;
209       }
210     }
211
212   if (rx_sw_if_index == ~0)
213     {
214       errmsg ("missing rx interface");
215       return -99;
216     }
217
218   if (hw_if_index == ~0)
219     {
220       errmsg ("missing hw interface");
221       return -99;
222     }
223
224   M (GTPU_OFFLOAD_RX, mp);
225   mp->hw_if_index = ntohl (hw_if_index);
226   mp->sw_if_index = ntohl (rx_sw_if_index);
227   mp->enable = is_add;
228
229   S (mp);
230   W (ret);
231   return ret;
232 }
233
234 static int
235 api_gtpu_add_del_tunnel (vat_main_t * vam)
236 {
237   unformat_input_t *line_input = vam->input;
238   vl_api_gtpu_add_del_tunnel_t *mp;
239   ip46_address_t src, dst;
240   u8 is_add = 1;
241   u8 ipv4_set = 0, ipv6_set = 0;
242   u8 src_set = 0;
243   u8 dst_set = 0;
244   u8 grp_set = 0;
245   u32 mcast_sw_if_index = ~0;
246   u32 encap_vrf_id = 0;
247   u32 decap_next_index = ~0;
248   u32 teid = 0;
249   int ret;
250
251   /* Can't "universally zero init" (={0}) due to GCC bug 53119 */
252   clib_memset (&src, 0, sizeof src);
253   clib_memset (&dst, 0, sizeof dst);
254
255   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
256     {
257       if (unformat (line_input, "del"))
258       is_add = 0;
259       else
260       if (unformat (line_input, "src %U", unformat_ip4_address, &src.ip4))
261       {
262         ipv4_set = 1;
263         src_set = 1;
264       }
265       else
266       if (unformat (line_input, "dst %U", unformat_ip4_address, &dst.ip4))
267       {
268         ipv4_set = 1;
269         dst_set = 1;
270       }
271       else
272       if (unformat (line_input, "src %U", unformat_ip6_address, &src.ip6))
273       {
274         ipv6_set = 1;
275         src_set = 1;
276       }
277       else
278       if (unformat (line_input, "dst %U", unformat_ip6_address, &dst.ip6))
279       {
280         ipv6_set = 1;
281         dst_set = 1;
282       }
283       else if (unformat (line_input, "group %U %U",
284                        unformat_ip4_address, &dst.ip4,
285                        api_unformat_sw_if_index, vam, &mcast_sw_if_index))
286       {
287         grp_set = dst_set = 1;
288         ipv4_set = 1;
289       }
290       else if (unformat (line_input, "group %U",
291                        unformat_ip4_address, &dst.ip4))
292       {
293         grp_set = dst_set = 1;
294         ipv4_set = 1;
295       }
296       else if (unformat (line_input, "group %U %U",
297                        unformat_ip6_address, &dst.ip6,
298                        api_unformat_sw_if_index, vam, &mcast_sw_if_index))
299       {
300         grp_set = dst_set = 1;
301         ipv6_set = 1;
302       }
303       else if (unformat (line_input, "group %U",
304                        unformat_ip6_address, &dst.ip6))
305       {
306         grp_set = dst_set = 1;
307         ipv6_set = 1;
308       }
309       else
310       if (unformat (line_input, "mcast_sw_if_index %u", &mcast_sw_if_index))
311       ;
312       else if (unformat (line_input, "encap-vrf-id %d", &encap_vrf_id))
313       ;
314       else if (unformat (line_input, "decap-next %U",
315                        unformat_gtpu_decap_next, &decap_next_index))
316       ;
317       else if (unformat (line_input, "teid %d", &teid))
318       ;
319       else
320       {
321         errmsg ("parse error '%U'", format_unformat_error, line_input);
322         return -99;
323       }
324     }
325
326   if (src_set == 0)
327     {
328       errmsg ("tunnel src address not specified");
329       return -99;
330     }
331   if (dst_set == 0)
332     {
333       errmsg ("tunnel dst address not specified");
334       return -99;
335     }
336
337   if (grp_set && !ip46_address_is_multicast (&dst))
338     {
339       errmsg ("tunnel group address not multicast");
340       return -99;
341     }
342   if (grp_set && mcast_sw_if_index == ~0)
343     {
344       errmsg ("tunnel nonexistent multicast device");
345       return -99;
346     }
347   if (grp_set == 0 && ip46_address_is_multicast (&dst))
348     {
349       errmsg ("tunnel dst address must be unicast");
350       return -99;
351     }
352
353
354   if (ipv4_set && ipv6_set)
355     {
356       errmsg ("both IPv4 and IPv6 addresses specified");
357       return -99;
358     }
359
360   M (GTPU_ADD_DEL_TUNNEL, mp);
361
362   ip_address_encode(&src, ipv6_set ? IP46_TYPE_IP6 : IP46_TYPE_IP4,
363                     &mp->src_address);
364   ip_address_encode(&dst, ipv6_set ? IP46_TYPE_IP6 : IP46_TYPE_IP4,
365                     &mp->dst_address);
366   mp->encap_vrf_id = ntohl (encap_vrf_id);
367   mp->decap_next_index = ntohl (decap_next_index);
368   mp->mcast_sw_if_index = ntohl (mcast_sw_if_index);
369   mp->teid = ntohl (teid);
370   mp->is_add = is_add;
371
372   S (mp);
373   W (ret);
374   return ret;
375 }
376
377 static void vl_api_gtpu_tunnel_details_t_handler
378   (vl_api_gtpu_tunnel_details_t * mp)
379 {
380   vat_main_t *vam = &vat_main;
381   ip46_address_t src;
382   ip46_address_t dst;
383   ip_address_decode(&mp->dst_address, &dst);
384   ip_address_decode(&mp->src_address, &src);
385   print (vam->ofp, "%11d%24U%24U%14d%18d%13d%19d",
386        ntohl (mp->sw_if_index),
387        format_ip46_address, &src, IP46_TYPE_ANY,
388        format_ip46_address, &dst, IP46_TYPE_ANY,
389        ntohl (mp->encap_vrf_id),
390        ntohl (mp->decap_next_index), ntohl (mp->teid),
391        ntohl (mp->mcast_sw_if_index));
392 }
393
394 static int
395 api_gtpu_tunnel_dump (vat_main_t * vam)
396 {
397   unformat_input_t *i = vam->input;
398   vl_api_gtpu_tunnel_dump_t *mp;
399   u32 sw_if_index;
400   u8 sw_if_index_set = 0;
401   int ret;
402
403   /* Parse args required to build the message */
404   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
405     {
406       if (unformat (i, "sw_if_index %d", &sw_if_index))
407       sw_if_index_set = 1;
408       else
409       break;
410     }
411
412   if (sw_if_index_set == 0)
413     {
414       sw_if_index = ~0;
415     }
416
417   if (!vam->json_output)
418     {
419       print (vam->ofp, "%11s%24s%24s%14s%18s%13s%19s",
420            "sw_if_index", "src_address", "dst_address",
421            "encap_vrf_id", "decap_next_index", "teid", "mcast_sw_if_index");
422     }
423
424   /* Get list of gtpu-tunnel interfaces */
425   M (GTPU_TUNNEL_DUMP, mp);
426
427   mp->sw_if_index = htonl (sw_if_index);
428
429   S (mp);
430
431   W (ret);
432   return ret;
433 }
434
435 #include <gtpu/gtpu.api_test.c>