FD.io VPP  v17.10-9-gd594711
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 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, tep->port, sst);
96  if (listener)
97  return VNET_API_ERROR_ADDRESS_IN_USE;
98 
99  if (!ip_is_zero (&tep->ip, tep->is_ip4)
100  && !ip_is_local (&tep->ip, tep->is_ip4))
101  return VNET_API_ERROR_INVALID_VALUE_2;
102 
103  /* Setup listen path down to transport */
104  return application_start_listen (app, sst, tep, handle);
105 }
106 
107 int
108 vnet_unbind_i (u32 app_index, u64 handle)
109 {
110  application_t *app = application_get_if_valid (app_index);
111 
112  if (!app)
113  {
114  clib_warning ("app (%d) not attached", app_index);
115  return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
116  }
117 
118  /* Clear the listener */
119  return application_stop_listen (app, handle);
120 }
121 
122 int
123 vnet_connect_i (u32 app_index, u32 api_context, session_type_t sst,
124  transport_endpoint_t * tep, void *mp)
125 {
126  stream_session_t *listener;
127  application_t *server, *app;
128 
129  /*
130  * Figure out if connecting to a local server
131  */
132  listener = stream_session_lookup_listener (&tep->ip, tep->port, sst);
133  if (listener)
134  {
135  server = application_get (listener->app_index);
136 
137  /*
138  * Server is willing to have a direct fifo connection created
139  * instead of going through the state machine, etc.
140  */
141  if (server->flags & APP_OPTIONS_FLAGS_USE_FIFO)
142  return server->cb_fns.
143  redirect_connect_callback (server->api_client_index, mp);
144  }
145 
146  /*
147  * Not connecting to a local server. Create regular session
148  */
149  app = application_get (app_index);
150  return application_open_session (app, sst, tep, api_context);
151 }
152 
153 /**
154  * unformat a vnet URI
155  *
156  * fifo://name
157  * tcp://ip46-addr:port
158  * udp://ip46-addr:port
159  *
160  * u8 ip46_address[16];
161  * u16 port_in_host_byte_order;
162  * stream_session_type_t sst;
163  * u8 *fifo_name;
164  *
165  * if (unformat (input, "%U", unformat_vnet_uri, &ip46_address,
166  * &sst, &port, &fifo_name))
167  * etc...
168  *
169  */
170 uword
171 unformat_vnet_uri (unformat_input_t * input, va_list * args)
172 {
173  session_type_t *sst = va_arg (*args, session_type_t *);
174  transport_endpoint_t *tep = va_arg (*args, transport_endpoint_t *);
175 
176  if (unformat (input, "tcp://%U/%d", unformat_ip4_address, &tep->ip.ip4,
177  &tep->port))
178  {
179  *sst = SESSION_TYPE_IP4_TCP;
180  tep->port = clib_host_to_net_u16 (tep->port);
181  tep->is_ip4 = 1;
182  return 1;
183  }
184  if (unformat (input, "udp://%U/%d", unformat_ip4_address, &tep->ip.ip4,
185  &tep->port))
186  {
187  *sst = SESSION_TYPE_IP4_UDP;
188  tep->port = clib_host_to_net_u16 (tep->port);
189  tep->is_ip4 = 1;
190  return 1;
191  }
192  if (unformat (input, "udp://%U/%d", unformat_ip6_address, &tep->ip.ip6,
193  &tep->port))
194  {
195  *sst = SESSION_TYPE_IP6_UDP;
196  tep->port = clib_host_to_net_u16 (tep->port);
197  return 1;
198  }
199  if (unformat (input, "tcp://%U/%d", unformat_ip6_address, &tep->ip.ip6,
200  &tep->port))
201  {
202  *sst = SESSION_TYPE_IP6_TCP;
203  tep->port = clib_host_to_net_u16 (tep->port);
204  return 1;
205  }
206 
207  return 0;
208 }
209 
210 static u8 *cache_uri;
213 
214 int
216 {
217  unformat_input_t _input, *input = &_input;
218 
219  if (cache_uri && !strncmp (uri, (char *) cache_uri, vec_len (cache_uri)))
220  {
221  *sst = cache_sst;
222  *tep = *cache_tep;
223  return 0;
224  }
225 
226  /* Make sure */
227  uri = (char *) format (0, "%s%c", uri, 0);
228 
229  /* Parse uri */
230  unformat_init_string (input, uri, strlen (uri));
231  if (!unformat (input, "%U", unformat_vnet_uri, sst, tep))
232  {
233  unformat_free (input);
234  return VNET_API_ERROR_INVALID_VALUE;
235  }
236  unformat_free (input);
237 
239  cache_uri = (u8 *) uri;
240  cache_sst = *sst;
241  if (cache_tep)
243  cache_tep = clib_mem_alloc (sizeof (*tep));
244  *cache_tep = *tep;
245 
246  return 0;
247 }
248 
249 /**
250  * Attaches application.
251  *
252  * Allocates a vpp app, i.e., a structure that keeps back pointers
253  * to external app and a segment manager for shared memory fifo based
254  * communication with the external app.
255  */
256 int
258 {
259  application_t *app = 0;
260  segment_manager_t *sm;
261  u8 *seg_name;
262  int rv;
263 
264  app = application_new ();
265  if ((rv = application_init (app, a->api_client_index, a->options,
266  a->session_cb_vft)))
267  return rv;
268 
269  a->app_event_queue_address = pointer_to_uword (app->event_queue);
270  sm = segment_manager_get (app->first_segment_manager);
271  segment_manager_get_segment_info (sm->segment_indices[0],
272  &seg_name, &a->segment_size);
273 
274  a->segment_name_length = vec_len (seg_name);
275  a->segment_name = seg_name;
276  ASSERT (vec_len (a->segment_name) <= 128);
277  a->app_index = app->index;
278  return 0;
279 }
280 
281 int
283 {
284  application_t *app;
285  app = application_get_if_valid (a->app_index);
286 
287  if (!app)
288  {
289  clib_warning ("app not attached");
290  return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
291  }
292 
293  application_del (app);
294  return 0;
295 }
296 
297 int
299 {
302  int rv;
303 
304  memset (&tep, 0, sizeof (tep));
305  rv = parse_uri (a->uri, &sst, &tep);
306  if (rv)
307  return rv;
308 
309  if ((rv = vnet_bind_i (a->app_index, sst, &tep, &a->handle)))
310  return rv;
311 
312  return 0;
313 }
314 
315 int
317 {
319  stream_session_t *listener;
321  int rv;
322 
323  rv = parse_uri (a->uri, &sst, &tep);
324  if (rv)
325  return rv;
326 
327  listener = stream_session_lookup_listener (&tep.ip,
328  clib_host_to_net_u16 (tep.port),
329  sst);
330  if (!listener)
331  return VNET_API_ERROR_ADDRESS_NOT_IN_USE;
332 
333  return vnet_unbind_i (a->app_index, listen_session_get_handle (listener));
334 }
335 
336 int
338 {
340  session_type_t sst;
341  int rv;
342 
343  /* Parse uri */
344  memset (&tep, 0, sizeof (tep));
345  rv = parse_uri (a->uri, &sst, &tep);
346  if (rv)
347  return rv;
348 
349  return vnet_connect_i (a->app_index, a->api_context, sst, &tep, a->mp);
350 }
351 
352 int
354 {
355  u32 index, thread_index;
356  stream_session_t *s;
357 
358  stream_session_parse_handle (a->handle, &index, &thread_index);
359  s = stream_session_get_if_valid (index, thread_index);
360 
361  if (!s || s->app_index != a->app_index)
362  return VNET_API_ERROR_INVALID_VALUE;
363 
364  /* We're peeking into another's thread pool. Make sure */
365  ASSERT (s->session_index == index);
366 
368  thread_index);
369  return 0;
370 }
371 
372 int
374 {
376  int rv;
377 
378  sst = session_type_from_proto_and_ip (a->proto, a->tep.is_ip4);
379  if ((rv = vnet_bind_i (a->app_index, sst, &a->tep, &a->handle)))
380  return rv;
381 
382  return 0;
383 }
384 
385 int
387 {
388  return vnet_unbind_i (a->app_index, a->handle);
389 }
390 
391 int
393 {
394  session_type_t sst;
395 
396  sst = session_type_from_proto_and_ip (a->proto, a->tep.is_ip4);
397  return vnet_connect_i (a->app_index, a->api_context, sst, &a->tep, a->mp);
398 }
399 
400 /*
401  * fd.io coding-style-patch-verification: ON
402  *
403  * Local Variables:
404  * eval: (c-set-style "gnu")
405  * End:
406  */
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:169
int application_stop_listen(application_t *srv, u64 handle)
Stop listening on session associated to handle.
Definition: application.c:308
a
Definition: bitmap.h:516
struct _vnet_connect_args vnet_connect_args_t
int vnet_bind_uri(vnet_bind_args_t *a)
application_t * application_new()
Definition: application.c:77
int vnet_bind_i(u32 app_index, session_type_t sst, transport_endpoint_t *tep, u64 *handle)
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
static u8 * cache_uri
static transport_endpoint_t * cache_tep
void segment_manager_get_segment_info(u32 index, u8 **name, u32 *size)
int vnet_unbind_uri(vnet_unbind_args_t *a)
static u8 ip_is_local(ip46_address_t *ip46_address, u8 is_ip4)
unformat_function_t unformat_ip4_address
Definition: format.h:76
static session_type_t cache_sst
struct _vnet_disconnect_args_t vnet_disconnect_args_t
int vnet_bind(vnet_bind_args_t *a)
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
int vnet_connect_i(u32 app_index, u32 api_context, session_type_t sst, transport_endpoint_t *tep, void *mp)
struct _stream_session_t stream_session_t
u16 fp_len
The mask length.
Definition: fib_types.h:164
void session_send_session_evt_to_thread(u64 session_handle, fifo_event_type_t evt_type, u32 thread_index)
Definition: session.c:730
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
static uword pointer_to_uword(const void *p)
Definition: types.h:131
void unformat_init_string(unformat_input_t *input, char *string, int string_len)
Definition: unformat.c:1023
struct _vnet_app_attach_args_t vnet_app_attach_args_t
Definition: fib_entry.h:233
static session_manager_main_t * vnet_get_session_manager_main()
Definition: session.h:197
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
struct _session_manager_main session_manager_main_t
Definition: session.h:113
static u8 ip_is_zero(ip46_address_t *ip46_address, u8 is_ip4)
unformat_function_t unformat_ip6_address
Definition: format.h:94
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:336
#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:196
#define clib_memcpy(a, b, c)
Definition: string.h:69
stream_session_t * stream_session_lookup_listener(ip46_address_t *lcl, u16 lcl_port, u8 proto)
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:267
struct _application application_t
int vnet_disconnect_session(vnet_disconnect_args_t *a)
int api_parse_session_handle(u64 handle, u32 *session_index, u32 *thread_index)
static stream_session_t * stream_session_get_if_valid(u64 si, u32 thread_index)
Definition: session.h:224
enum fib_entry_flag_t_ fib_entry_flag_t
int vnet_application_attach(vnet_app_attach_args_t *a)
Attaches application.
static void stream_session_parse_handle(u64 handle, u32 *index, u32 *thread_index)
Definition: session.h:255
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
int application_init(application_t *app, u32 api_client_index, u64 *options, session_cb_vft_t *cb_fns)
Definition: application.c:171
static void clib_mem_free(void *p)
Definition: mem.h:179
void application_del(application_t *app)
Definition: application.c:91
int application_start_listen(application_t *srv, session_type_t session_type, transport_endpoint_t *tep, u64 *res)
Start listening local transport endpoint for requested transport.
Definition: application.c:272
struct _vnet_app_detach_args_t vnet_app_detach_args_t
static void * clib_mem_alloc(uword size)
Definition: mem.h:112
session_type_t session_type_from_proto_and_ip(transport_proto_t proto, u8 is_ip4)
Definition: session.c:820
u64 uword
Definition: types.h:112
uword unformat_vnet_uri(unformat_input_t *input, va_list *args)
unformat a vnet URI
int vnet_unbind_i(u32 app_index, u64 handle)
#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:224
struct _transport_endpoint transport_endpoint_t
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)
struct _segment_manager segment_manager_t
int parse_uri(char *uri, session_type_t *sst, transport_endpoint_t *tep)
u32 flags
Definition: vhost-user.h:77
int vnet_connect_uri(vnet_connect_args_t *a)
int vnet_application_detach(vnet_app_detach_args_t *a)
struct _vnet_bind_args_t vnet_bind_args_t
static segment_manager_t * segment_manager_get(u32 index)
static u64 listen_session_get_handle(stream_session_t *s)
Definition: session.h:353
int application_open_session(application_t *app, session_type_t sst, transport_endpoint_t *tep, u32 api_context)
Definition: application.c:344
application_t * application_get_if_valid(u32 index)
Definition: application.c:230
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
fib_entry_flag_t fib_entry_get_flags(fib_node_index_t fib_entry_index)
Definition: fib_entry.c:267