FD.io VPP  v17.07.01-10-g3be13f0
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,
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
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
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
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 
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
301 {
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
319 {
321  stream_session_t *listener;
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
340 {
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
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 
370  thread_index);
371  return 0;
372 }
373 
374 int
376 {
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
389 {
390  return vnet_unbind_i (a->app_index, a->handle);
391 }
392 
393 int
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  */
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:271
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
struct _stream_session_t stream_session_t
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
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)
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:973
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:238
static session_manager_main_t * vnet_get_session_manager_main()
Definition: session.h:237
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:75
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)
unformat_function_t unformat_ip6_address
Definition: format.h:94
#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:203
#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 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:287
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:317
#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:144
void application_del(application_t *app)
Definition: application.c:88
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:235
struct _vnet_app_detach_args_t vnet_app_detach_args_t
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:189
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
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:262
int parse_uri(char *uri, session_type_t *sst, transport_endpoint_t *tep)
u32 flags
Definition: vhost-user.h:76
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:414
int application_open_session(application_t *app, session_type_t sst, transport_endpoint_t *tep, u32 api_context)
Definition: application.c:298
application_t * application_get_if_valid(u32 index)
Definition: application.c:195
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:252