FD.io VPP  v17.04-9-g99c0734
Vector Packet Processing
application_interface.c
Go to the documentation of this file.
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  */
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;
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 {
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 api_client_index, ip46_address_t * ip46, u16 port_host_order,
83  session_type_t sst, u64 * options, session_cb_vft_t * cb_fns,
84  application_t ** app, u32 * len_seg_name, char *seg_name)
85 {
86  u8 *segment_name = 0;
87  application_t *server = 0;
88  stream_session_t *listener;
89  u8 is_ip4;
90 
91  listener =
93  clib_host_to_net_u16 (port_host_order),
94  sst);
95 
96  if (listener)
97  return VNET_API_ERROR_ADDRESS_IN_USE;
98 
99  if (application_lookup (api_client_index))
100  {
101  clib_warning ("Only one connection supported for now");
102  return VNET_API_ERROR_ADDRESS_IN_USE;
103  }
104 
105  is_ip4 = SESSION_TYPE_IP4_UDP == sst || SESSION_TYPE_IP4_TCP == sst;
106  if (!ip_is_zero (ip46, is_ip4) && !ip_is_local (ip46, is_ip4))
107  return VNET_API_ERROR_INVALID_VALUE;
108 
109  /* Allocate and initialize stream server */
110  server = application_new (APP_SERVER, sst, api_client_index,
111  options[SESSION_OPTIONS_FLAGS], cb_fns);
112 
117  &segment_name);
118 
119  /* Setup listen path down to transport */
120  stream_session_start_listen (server->index, ip46, port_host_order);
121 
122  /*
123  * Return values
124  */
125 
126  ASSERT (vec_len (segment_name) <= 128);
127  *len_seg_name = vec_len (segment_name);
128  memcpy (seg_name, segment_name, *len_seg_name);
129  *app = server;
130 
131  return 0;
132 }
133 
134 int
135 vnet_unbind_i (u32 api_client_index)
136 {
137  application_t *server;
138 
139  /*
140  * Find the stream_server_t corresponding to the api client
141  */
142  server = application_lookup (api_client_index);
143  if (!server)
144  return VNET_API_ERROR_INVALID_VALUE_2;
145 
146  /* Clear the listener */
147  stream_session_stop_listen (server->index);
148  application_del (server);
149 
150  return 0;
151 }
152 
153 int
154 vnet_connect_i (u32 api_client_index, u32 api_context, session_type_t sst,
155  ip46_address_t * ip46, u16 port, u64 * options, void *mp,
156  session_cb_vft_t * cb_fns)
157 {
158  stream_session_t *listener;
159  application_t *server, *app;
160 
161  /*
162  * Figure out if connecting to a local server
163  */
164  listener = stream_session_lookup_listener (ip46,
165  clib_host_to_net_u16 (port),
166  sst);
167  if (listener)
168  {
169  server = application_get (listener->app_index);
170 
171  /*
172  * Server is willing to have a direct fifo connection created
173  * instead of going through the state machine, etc.
174  */
175  if (server->flags & SESSION_OPTIONS_FLAGS_USE_FIFO)
176  return server->cb_fns.
177  redirect_connect_callback (server->api_client_index, mp);
178  }
179 
180  /* Create client app */
181  app = application_new (APP_CLIENT, sst, api_client_index,
182  options[SESSION_OPTIONS_FLAGS], cb_fns);
183 
184  app->api_context = api_context;
185 
186  /*
187  * Not connecting to a local server. Create regular session
188  */
189  return stream_session_open (sst, ip46, port, app->index);
190 }
191 
192 /**
193  * unformat a vnet URI
194  *
195  * fifo://name
196  * tcp://ip46-addr:port
197  * udp://ip46-addr:port
198  *
199  * u8 ip46_address[16];
200  * u16 port_in_host_byte_order;
201  * stream_session_type_t sst;
202  * u8 *fifo_name;
203  *
204  * if (unformat (input, "%U", unformat_vnet_uri, &ip46_address,
205  * &sst, &port, &fifo_name))
206  * etc...
207  *
208  */
209 uword
210 unformat_vnet_uri (unformat_input_t * input, va_list * args)
211 {
212  ip46_address_t *address = va_arg (*args, ip46_address_t *);
213  session_type_t *sst = va_arg (*args, session_type_t *);
214  u16 *port = va_arg (*args, u16 *);
215 
216  if (unformat (input, "tcp://%U/%d", unformat_ip4_address, &address->ip4,
217  port))
218  {
219  *sst = SESSION_TYPE_IP4_TCP;
220  return 1;
221  }
222  if (unformat (input, "udp://%U/%d", unformat_ip4_address, &address->ip4,
223  port))
224  {
225  *sst = SESSION_TYPE_IP4_UDP;
226  return 1;
227  }
228  if (unformat (input, "udp://%U/%d", unformat_ip6_address, &address->ip6,
229  port))
230  {
231  *sst = SESSION_TYPE_IP6_UDP;
232  return 1;
233  }
234  if (unformat (input, "tcp://%U/%d", unformat_ip6_address, &address->ip6,
235  port))
236  {
237  *sst = SESSION_TYPE_IP6_TCP;
238  return 1;
239  }
240 
241  return 0;
242 }
243 
244 int
245 parse_uri (char *uri, session_type_t * sst, ip46_address_t * addr,
246  u16 * port_number_host_byte_order)
247 {
248  unformat_input_t _input, *input = &_input;
249 
250  /* Make sure */
251  uri = (char *) format (0, "%s%c", uri, 0);
252 
253  /* Parse uri */
254  unformat_init_string (input, uri, strlen (uri));
255  if (!unformat (input, "%U", unformat_vnet_uri, addr, sst,
256  port_number_host_byte_order))
257  {
258  unformat_free (input);
259  return VNET_API_ERROR_INVALID_VALUE;
260  }
261  unformat_free (input);
262 
263  return 0;
264 }
265 
266 int
268 {
269  application_t *server = 0;
270  u16 port_host_order;
272  ip46_address_t ip46;
273  int rv;
274 
275  memset (&ip46, 0, sizeof (ip46));
276  rv = parse_uri (a->uri, &sst, &ip46, &port_host_order);
277  if (rv)
278  return rv;
279 
280  if ((rv = vnet_bind_i (a->api_client_index, &ip46, port_host_order, sst,
281  a->options, a->session_cb_vft, &server,
282  &a->segment_name_length, a->segment_name)))
283  return rv;
284 
285  a->server_event_queue_address = (u64) server->event_queue;
286  return 0;
287 }
288 
291 {
292  if (proto == SESSION_PROTO_TCP)
293  {
294  if (is_ip4)
295  return SESSION_TYPE_IP4_TCP;
296  else
297  return SESSION_TYPE_IP6_TCP;
298  }
299  else
300  {
301  if (is_ip4)
302  return SESSION_TYPE_IP4_UDP;
303  else
304  return SESSION_TYPE_IP6_UDP;
305  }
306 
307  return SESSION_N_TYPES;
308 }
309 
310 int
311 vnet_unbind_uri (char *uri, u32 api_client_index)
312 {
313  u16 port_number_host_byte_order;
315  ip46_address_t ip46_address;
316  stream_session_t *listener;
317  int rv;
318 
319  rv = parse_uri (uri, &sst, &ip46_address, &port_number_host_byte_order);
320  if (rv)
321  return rv;
322 
323  listener =
324  stream_session_lookup_listener (&ip46_address,
325  clib_host_to_net_u16
326  (port_number_host_byte_order), sst);
327 
328  if (!listener)
329  return VNET_API_ERROR_ADDRESS_NOT_IN_USE;
330 
331  /* External client? */
332  if (api_client_index != ~0)
333  {
334  ASSERT (vl_api_client_index_to_registration (api_client_index));
335  }
336 
337  return vnet_unbind_i (api_client_index);
338 }
339 
340 int
342 {
343  ip46_address_t ip46_address;
344  u16 port;
345  session_type_t sst;
346  application_t *app;
347  int rv;
348 
349  app = application_lookup (a->api_client_index);
350  if (app)
351  {
352  clib_warning ("Already have a connect from this app");
353  return VNET_API_ERROR_INVALID_VALUE_2;
354  }
355 
356  /* Parse uri */
357  rv = parse_uri (a->uri, &sst, &ip46_address, &port);
358  if (rv)
359  return rv;
360 
361  return vnet_connect_i (a->api_client_index, a->api_context, sst,
362  &ip46_address, port, a->options, a->mp,
363  a->session_cb_vft);
364 }
365 
366 int
367 vnet_disconnect_session (u32 session_index, u32 thread_index)
368 {
369  stream_session_t *session;
370 
371  session = stream_session_get (session_index, thread_index);
372  stream_session_disconnect (session);
373 
374  return 0;
375 }
376 
377 
378 int
380 {
381  application_t *server = 0;
383  int rv;
384 
385  sst = session_type_from_proto_and_ip (a->proto, a->tep.is_ip4);
386  if ((rv = vnet_bind_i (a->api_client_index, &a->tep.ip, a->tep.port, sst,
387  a->options, a->session_cb_vft, &server,
388  &a->segment_name_length, a->segment_name)))
389  return rv;
390 
391  a->server_event_queue_address = (u64) server->event_queue;
392  a->handle = (u64) a->tep.vrf << 32 | (u64) server->session_index;
393  return 0;
394 }
395 
396 int
398 {
399  application_t *server;
400 
401  if (a->api_client_index != ~0)
402  {
403  ASSERT (vl_api_client_index_to_registration (a->api_client_index));
404  }
405 
406  /* Make sure this is the right one */
407  server = application_lookup (a->api_client_index);
408  ASSERT (server->session_index == (0xFFFFFFFF & a->handle));
409 
410  /* TODO use handle to disambiguate namespaces/vrfs */
411  return vnet_unbind_i (a->api_client_index);
412 }
413 
414 int
416 {
417  session_type_t sst;
418  application_t *app;
419 
420  app = application_lookup (a->api_client_index);
421  if (app)
422  {
423  clib_warning ("Already have a connect from this app");
424  return VNET_API_ERROR_INVALID_VALUE_2;
425  }
426 
427  sst = session_type_from_proto_and_ip (a->proto, a->tep.is_ip4);
428  return vnet_connect_i (a->api_client_index, a->api_context, sst, &a->tep.ip,
429  a->tep.port, a->options, a->mp, a->session_cb_vft);
430 }
431 
432 int
434 {
435  stream_session_t *session;
436  u32 session_index, thread_index;
437 
438  if (api_parse_session_handle (a->handle, &session_index, &thread_index))
439  {
440  clib_warning ("Invalid handle");
441  return -1;
442  }
443 
444  session = stream_session_get (session_index, thread_index);
445  stream_session_disconnect (session);
446 
447  return 0;
448 }
449 
450 /*
451  * fd.io coding-style-patch-verification: ON
452  *
453  * Local Variables:
454  * eval: (c-set-style "gnu")
455  * End:
456  */
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:169
a
Definition: bitmap.h:516
struct _vnet_connect_args vnet_connect_args_t
int vnet_bind_uri(vnet_bind_args_t *a)
int vnet_unbind_uri(char *uri, u32 api_client_index)
int vnet_disconnect_session(u32 session_index, u32 thread_index)
application_t * application_lookup(u32 api_client_index)
Definition: application.c:60
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
int stream_session_open(u8 sst, ip46_address_t *addr, u16 port_host_byte_order, u32 app_index)
Definition: session.c:1157
struct _stream_session_t stream_session_t
static stream_session_t * stream_session_get(u64 si, u32 thread_index)
Definition: session.h:303
static u8 ip_is_local(ip46_address_t *ip46_address, u8 is_ip4)
unformat_function_t unformat_ip4_address
Definition: format.h:76
struct _vnet_disconnect_args_t vnet_disconnect_args_t
int vnet_bind(vnet_bind_args_t *a)
struct _stream_session_cb_vft session_cb_vft_t
struct _vnet_unbind_args_t vnet_unbind_args_t
Aggregrate type for a prefix.
Definition: fib_types.h:160
unsigned long u64
Definition: types.h:89
u16 fp_len
The mask length.
Definition: fib_types.h:164
fib_node_index_t fib_table_lookup(u32 fib_index, const fib_prefix_t *prefix)
Perfom a longest prefix match in the non-forwarding table.
Definition: fib_table.c:66
void unformat_init_string(unformat_input_t *input, char *string, int string_len)
Definition: unformat.c:1022
vl_api_registration_t * vl_api_client_index_to_registration(u32 index)
Definition: fib_entry.h:232
static session_manager_main_t * vnet_get_session_manager_main()
Definition: session.h:230
enum _session_api_proto session_api_proto_t
ip46_address_t fp_addr
The address type is not deriveable from the fp_addr member.
Definition: fib_types.h:183
struct _unformat_input_t unformat_input_t
session_type_t
Definition: session.h:74
application_t * application_new(application_type_t type, session_type_t sst, u32 api_client_index, u32 flags, session_cb_vft_t *cb_fns)
Definition: application.c:109
struct _session_manager_main session_manager_main_t
Definition: session.h:157
static u8 ip_is_zero(ip46_address_t *ip46_address, u8 is_ip4)
int parse_uri(char *uri, session_type_t *sst, ip46_address_t *addr, u16 *port_number_host_byte_order)
unformat_function_t unformat_ip6_address
Definition: format.h:94
int vnet_disconnect(vnet_disconnect_args_t *a)
int stream_session_start_listen(u32 server_index, ip46_address_t *ip, u16 port)
Definition: session.c:886
#define clib_warning(format, args...)
Definition: error.h:59
static int redirect_connect_callback(u32 server_api_client_index, void *mp_arg)
Redirect a connect_uri message to the indicated server.
Definition: session_api.c:397
#define clib_memcpy(a, b, c)
Definition: string.h:69
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:28
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:238
struct _application application_t
int api_parse_session_handle(u64 handle, u32 *session_index, u32 *thread_index)
enum fib_entry_flag_t_ fib_entry_flag_t
int vnet_unbind_i(u32 api_client_index)
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
void application_del(application_t *app)
Definition: application.c:71
void stream_session_disconnect(stream_session_t *s)
Disconnect session and propagate to transport.
Definition: session.c:1193
#define SESSION_OPTIONS_FLAGS_USE_FIFO
Server can handle delegated connect requests from local clients.
u64 uword
Definition: types.h:112
uword unformat_vnet_uri(unformat_input_t *input, va_list *args)
unformat a vnet URI
unsigned short u16
Definition: types.h:57
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
application_t * application_get(u32 index)
Definition: application.c:168
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
int vnet_connect(vnet_connect_args_t *a)
int vnet_unbind(vnet_unbind_args_t *a)
void stream_session_stop_listen(u32 server_index)
Definition: session.c:920
int vnet_bind_i(u32 api_client_index, ip46_address_t *ip46, u16 port_host_order, session_type_t sst, u64 *options, session_cb_vft_t *cb_fns, application_t **app, u32 *len_seg_name, char *seg_name)
int vnet_connect_i(u32 api_client_index, u32 api_context, session_type_t sst, ip46_address_t *ip46, u16 port, u64 *options, void *mp, session_cb_vft_t *cb_fns)
int application_server_init(application_t *server, u32 segment_size, u32 add_segment_size, u32 rx_fifo_size, u32 tx_fifo_size, u8 **segment_name)
Definition: application.c:189
session_type_t session_type_from_proto_and_ip(session_api_proto_t proto, u8 is_ip4)
stream_session_t * stream_session_lookup_listener(ip46_address_t *lcl, u16 lcl_port, u8 proto)
Definition: session.c:264
vhost_vring_addr_t addr
Definition: vhost-user.h:84
u32 flags
Definition: vhost-user.h:78
int vnet_connect_uri(vnet_connect_args_t *a)
struct _vnet_bind_args_t vnet_bind_args_t
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:971
fib_entry_flag_t fib_entry_get_flags(fib_node_index_t fib_entry_index)
Definition: fib_entry.c:278