Fix remaining 32-bit compile issues
[vpp.git] / src / vnet / session / application_interface.c
1 /*
2  * Copyright (c) 2016 Cisco 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 #include <vnet/session/application_interface.h>
16
17 #include <vnet/session/session.h>
18 #include <vlibmemory/api.h>
19 #include <vnet/dpo/load_balance.h>
20 #include <vnet/fib/ip4_fib.h>
21
22 /** @file
23     VPP's application/session API bind/unbind/connect/disconnect calls
24 */
25
26 static u8
27 ip_is_zero (ip46_address_t * ip46_address, u8 is_ip4)
28 {
29   if (is_ip4)
30     return (ip46_address->ip4.as_u32 == 0);
31   else
32     return (ip46_address->as_u64[0] == 0 && ip46_address->as_u64[1] == 0);
33 }
34
35 static u8
36 ip_is_local (ip46_address_t * ip46_address, u8 is_ip4)
37 {
38   fib_node_index_t fei;
39   fib_entry_flag_t flags;
40   fib_prefix_t prefix;
41
42   /* Check if requester is local */
43   if (is_ip4)
44     {
45       prefix.fp_len = 32;
46       prefix.fp_proto = FIB_PROTOCOL_IP4;
47     }
48   else
49     {
50       prefix.fp_len = 128;
51       prefix.fp_proto = FIB_PROTOCOL_IP6;
52     }
53
54   clib_memcpy (&prefix.fp_addr, ip46_address, sizeof (ip46_address_t));
55   fei = fib_table_lookup (0, &prefix);
56   flags = fib_entry_get_flags (fei);
57
58   return (flags & FIB_ENTRY_FLAG_LOCAL);
59 }
60
61 int
62 api_parse_session_handle (u64 handle, u32 * session_index, u32 * thread_index)
63 {
64   session_manager_main_t *smm = vnet_get_session_manager_main ();
65   stream_session_t *pool;
66
67   *thread_index = handle & 0xFFFFFFFF;
68   *session_index = handle >> 32;
69
70   if (*thread_index >= vec_len (smm->sessions))
71     return VNET_API_ERROR_INVALID_VALUE;
72
73   pool = smm->sessions[*thread_index];
74
75   if (pool_is_free_index (pool, *session_index))
76     return VNET_API_ERROR_INVALID_VALUE_2;
77
78   return 0;
79 }
80
81 int
82 vnet_bind_i (u32 app_index, session_type_t sst,
83              transport_endpoint_t * tep, u64 * handle)
84 {
85   application_t *app;
86   stream_session_t *listener;
87
88   app = application_get_if_valid (app_index);
89   if (!app)
90     {
91       clib_warning ("app not attached");
92       return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
93     }
94
95   listener = stream_session_lookup_listener (&tep->ip,
96                                              clib_host_to_net_u16 (tep->port),
97                                              sst);
98   if (listener)
99     return VNET_API_ERROR_ADDRESS_IN_USE;
100
101   if (!ip_is_zero (&tep->ip, tep->is_ip4)
102       && !ip_is_local (&tep->ip, tep->is_ip4))
103     return VNET_API_ERROR_INVALID_VALUE_2;
104
105   /* Setup listen path down to transport */
106   return application_start_listen (app, sst, tep, handle);
107 }
108
109 int
110 vnet_unbind_i (u32 app_index, u64 handle)
111 {
112   application_t *app = application_get_if_valid (app_index);
113
114   if (!app)
115     {
116       clib_warning ("app not attached");
117       return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
118     }
119
120   /* Clear the listener */
121   return application_stop_listen (app, handle);
122 }
123
124 int
125 vnet_connect_i (u32 app_index, u32 api_context, session_type_t sst,
126                 transport_endpoint_t * tep, void *mp)
127 {
128   stream_session_t *listener;
129   application_t *server, *app;
130
131   /*
132    * Figure out if connecting to a local server
133    */
134   listener = stream_session_lookup_listener (&tep->ip,
135                                              clib_host_to_net_u16 (tep->port),
136                                              sst);
137   if (listener)
138     {
139       server = application_get (listener->app_index);
140
141       /*
142        * Server is willing to have a direct fifo connection created
143        * instead of going through the state machine, etc.
144        */
145       if (server->flags & APP_OPTIONS_FLAGS_USE_FIFO)
146         return server->cb_fns.
147           redirect_connect_callback (server->api_client_index, mp);
148     }
149
150   /*
151    * Not connecting to a local server. Create regular session
152    */
153   app = application_get (app_index);
154   return application_open_session (app, sst, tep, api_context);
155 }
156
157 /**
158  * unformat a vnet URI
159  *
160  * fifo://name
161  * tcp://ip46-addr:port
162  * udp://ip46-addr:port
163  *
164  * u8 ip46_address[16];
165  * u16  port_in_host_byte_order;
166  * stream_session_type_t sst;
167  * u8 *fifo_name;
168  *
169  * if (unformat (input, "%U", unformat_vnet_uri, &ip46_address,
170  *              &sst, &port, &fifo_name))
171  *  etc...
172  *
173  */
174 uword
175 unformat_vnet_uri (unformat_input_t * input, va_list * args)
176 {
177   session_type_t *sst = va_arg (*args, session_type_t *);
178   transport_endpoint_t *tep = va_arg (*args, transport_endpoint_t *);
179
180   if (unformat (input, "tcp://%U/%d", unformat_ip4_address, &tep->ip.ip4,
181                 &tep->port))
182     {
183       *sst = SESSION_TYPE_IP4_TCP;
184       tep->is_ip4 = 1;
185       return 1;
186     }
187   if (unformat (input, "udp://%U/%d", unformat_ip4_address, &tep->ip.ip4,
188                 &tep->port))
189     {
190       *sst = SESSION_TYPE_IP4_UDP;
191       tep->is_ip4 = 1;
192       return 1;
193     }
194   if (unformat (input, "udp://%U/%d", unformat_ip6_address, &tep->ip.ip6,
195                 &tep->port))
196     {
197       *sst = SESSION_TYPE_IP6_UDP;
198       return 1;
199     }
200   if (unformat (input, "tcp://%U/%d", unformat_ip6_address, &tep->ip.ip6,
201                 &tep->port))
202     {
203       *sst = SESSION_TYPE_IP6_TCP;
204       return 1;
205     }
206
207   return 0;
208 }
209
210 int
211 parse_uri (char *uri, session_type_t * sst, transport_endpoint_t * tep)
212 {
213   unformat_input_t _input, *input = &_input;
214
215   /* Make sure */
216   uri = (char *) format (0, "%s%c", uri, 0);
217
218   /* Parse uri */
219   unformat_init_string (input, uri, strlen (uri));
220   if (!unformat (input, "%U", unformat_vnet_uri, sst, tep))
221     {
222       unformat_free (input);
223       return VNET_API_ERROR_INVALID_VALUE;
224     }
225   unformat_free (input);
226
227   return 0;
228 }
229
230 /**
231  * Attaches application.
232  *
233  * Allocates a vpp app, i.e., a structure that keeps back pointers
234  * to external app and a segment manager for shared memory fifo based
235  * communication with the external app.
236  */
237 int
238 vnet_application_attach (vnet_app_attach_args_t * a)
239 {
240   application_t *app = 0;
241   segment_manager_t *sm;
242   u8 *seg_name;
243   int rv;
244
245   app = application_new ();
246   if ((rv = application_init (app, a->api_client_index, a->options,
247                               a->session_cb_vft)))
248     return rv;
249
250   a->app_event_queue_address = pointer_to_uword (app->event_queue);
251   sm = segment_manager_get (app->first_segment_manager);
252   segment_manager_get_segment_info (sm->segment_indices[0],
253                                     &seg_name, &a->segment_size);
254
255   a->segment_name_length = vec_len (seg_name);
256   a->segment_name = seg_name;
257   ASSERT (vec_len (a->segment_name) <= 128);
258   a->app_index = app->index;
259   return 0;
260 }
261
262 int
263 vnet_application_detach (vnet_app_detach_args_t * a)
264 {
265   application_t *app;
266   app = application_get_if_valid (a->app_index);
267
268   if (!app)
269     {
270       clib_warning ("app not attached");
271       return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
272     }
273
274   application_del (app);
275   return 0;
276 }
277
278 session_type_t
279 session_type_from_proto_and_ip (session_api_proto_t proto, u8 is_ip4)
280 {
281   if (proto == SESSION_PROTO_TCP)
282     {
283       if (is_ip4)
284         return SESSION_TYPE_IP4_TCP;
285       else
286         return SESSION_TYPE_IP6_TCP;
287     }
288   else
289     {
290       if (is_ip4)
291         return SESSION_TYPE_IP4_UDP;
292       else
293         return SESSION_TYPE_IP6_UDP;
294     }
295
296   return SESSION_N_TYPES;
297 }
298
299 int
300 vnet_bind_uri (vnet_bind_args_t * a)
301 {
302   session_type_t sst = SESSION_N_TYPES;
303   transport_endpoint_t tep;
304   int rv;
305
306   memset (&tep, 0, sizeof (tep));
307   rv = parse_uri (a->uri, &sst, &tep);
308   if (rv)
309     return rv;
310
311   if ((rv = vnet_bind_i (a->app_index, sst, &tep, &a->handle)))
312     return rv;
313
314   return 0;
315 }
316
317 int
318 vnet_unbind_uri (vnet_unbind_args_t * a)
319 {
320   session_type_t sst = SESSION_N_TYPES;
321   stream_session_t *listener;
322   transport_endpoint_t tep;
323   int rv;
324
325   rv = parse_uri (a->uri, &sst, &tep);
326   if (rv)
327     return rv;
328
329   listener = stream_session_lookup_listener (&tep.ip,
330                                              clib_host_to_net_u16 (tep.port),
331                                              sst);
332   if (!listener)
333     return VNET_API_ERROR_ADDRESS_NOT_IN_USE;
334
335   return vnet_unbind_i (a->app_index, listen_session_get_handle (listener));
336 }
337
338 int
339 vnet_connect_uri (vnet_connect_args_t * a)
340 {
341   transport_endpoint_t tep;
342   session_type_t sst;
343   int rv;
344
345   /* Parse uri */
346   memset (&tep, 0, sizeof (tep));
347   rv = parse_uri (a->uri, &sst, &tep);
348   if (rv)
349     return rv;
350
351   return vnet_connect_i (a->app_index, a->api_context, sst, &tep, a->mp);
352 }
353
354 int
355 vnet_disconnect_session (vnet_disconnect_args_t * a)
356 {
357   u32 index, thread_index;
358   stream_session_t *s;
359
360   stream_session_parse_handle (a->handle, &index, &thread_index);
361   s = stream_session_get_if_valid (index, thread_index);
362
363   if (!s || s->app_index != a->app_index)
364     return VNET_API_ERROR_INVALID_VALUE;
365
366   /* We're peeking into another's thread pool. Make sure */
367   ASSERT (s->session_index == index);
368
369   session_send_session_evt_to_thread (a->handle, FIFO_EVENT_DISCONNECT,
370                                       thread_index);
371   return 0;
372 }
373
374 int
375 vnet_bind (vnet_bind_args_t * a)
376 {
377   session_type_t sst = SESSION_N_TYPES;
378   int rv;
379
380   sst = session_type_from_proto_and_ip (a->proto, a->tep.is_ip4);
381   if ((rv = vnet_bind_i (a->app_index, sst, &a->tep, &a->handle)))
382     return rv;
383
384   return 0;
385 }
386
387 int
388 vnet_unbind (vnet_unbind_args_t * a)
389 {
390   return vnet_unbind_i (a->app_index, a->handle);
391 }
392
393 int
394 vnet_connect (vnet_connect_args_t * a)
395 {
396   session_type_t sst;
397
398   sst = session_type_from_proto_and_ip (a->proto, a->tep.is_ip4);
399   return vnet_connect_i (a->app_index, a->api_context, sst, &a->tep, a->mp);
400 }
401
402 /*
403  * fd.io coding-style-patch-verification: ON
404  *
405  * Local Variables:
406  * eval: (c-set-style "gnu")
407  * End:
408  */