VPP-659 TCP improvements
[vpp.git] / src / vnet / session / application.c
1 /*
2  * Copyright (c) 2017 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
16 #include <vnet/session/application.h>
17 #include <vnet/session/session.h>
18
19 /*
20  * Pool from which we allocate all applications
21  */
22 static application_t *app_pool;
23
24 /*
25  * Hash table of apps by api client index
26  */
27 static uword *app_by_api_client_index;
28
29 int
30 application_api_queue_is_full (application_t * app)
31 {
32   unix_shared_memory_queue_t *q;
33
34   /* builtin servers are always OK */
35   if (app->api_client_index == ~0)
36     return 0;
37
38   q = vl_api_client_index_to_input_queue (app->api_client_index);
39   if (!q)
40     return 1;
41
42   if (q->cursize == q->maxsize)
43     return 1;
44   return 0;
45 }
46
47 static void
48 application_table_add (application_t * app)
49 {
50   hash_set (app_by_api_client_index, app->api_client_index, app->index);
51 }
52
53 static void
54 application_table_del (application_t * app)
55 {
56   hash_unset (app_by_api_client_index, app->api_client_index);
57 }
58
59 application_t *
60 application_lookup (u32 api_client_index)
61 {
62   uword *p;
63   p = hash_get (app_by_api_client_index, api_client_index);
64   if (p)
65     return application_get (p[0]);
66
67   return 0;
68 }
69
70 void
71 application_del (application_t * app)
72 {
73   session_manager_main_t *smm = vnet_get_session_manager_main ();
74   api_main_t *am = &api_main;
75   void *oldheap;
76   session_manager_t *sm;
77
78   if (app->mode == APP_SERVER)
79     {
80       sm = session_manager_get (app->session_manager_index);
81       session_manager_del (smm, sm);
82     }
83
84   /* Free the event fifo in the /vpe-api shared-memory segment */
85   oldheap = svm_push_data_heap (am->vlib_rp);
86   if (app->event_queue)
87     unix_shared_memory_queue_free (app->event_queue);
88   svm_pop_heap (oldheap);
89
90   application_table_del (app);
91
92   pool_put (app_pool, app);
93 }
94
95 static void
96 application_verify_cb_fns (application_type_t type, session_cb_vft_t * cb_fns)
97 {
98   if (type == APP_SERVER && cb_fns->session_accept_callback == 0)
99     clib_warning ("No accept callback function provided");
100   if (type == APP_CLIENT && cb_fns->session_connected_callback == 0)
101     clib_warning ("No session connected callback function provided");
102   if (cb_fns->session_disconnect_callback == 0)
103     clib_warning ("No session disconnect callback function provided");
104   if (cb_fns->session_reset_callback == 0)
105     clib_warning ("No session reset callback function provided");
106 }
107
108 application_t *
109 application_new (application_type_t type, session_type_t sst,
110                  u32 api_client_index, u32 flags, session_cb_vft_t * cb_fns)
111 {
112   session_manager_main_t *smm = vnet_get_session_manager_main ();
113   api_main_t *am = &api_main;
114   application_t *app;
115   void *oldheap;
116   session_manager_t *sm;
117
118   pool_get (app_pool, app);
119   memset (app, 0, sizeof (*app));
120
121   /* Allocate event fifo in the /vpe-api shared-memory segment */
122   oldheap = svm_push_data_heap (am->vlib_rp);
123
124   /* Allocate server event queue */
125   app->event_queue =
126     unix_shared_memory_queue_init (128 /* nels $$$$ config */ ,
127                                    sizeof (session_fifo_event_t),
128                                    0 /* consumer pid */ ,
129                                    0
130                                    /* (do not) signal when queue non-empty */
131     );
132
133   svm_pop_heap (oldheap);
134
135   /* If a server, allocate session manager */
136   if (type == APP_SERVER)
137     {
138       pool_get (smm->session_managers, sm);
139       memset (sm, 0, sizeof (*sm));
140
141       app->session_manager_index = sm - smm->session_managers;
142     }
143   else if (type == APP_CLIENT)
144     {
145       /* Allocate connect session manager if needed */
146       if (smm->connect_manager_index[sst] == INVALID_INDEX)
147         connects_session_manager_init (smm, sst);
148       app->session_manager_index = smm->connect_manager_index[sst];
149     }
150
151   app->mode = type;
152   app->index = application_get_index (app);
153   app->session_type = sst;
154   app->api_client_index = api_client_index;
155   app->flags = flags;
156   app->cb_fns = *cb_fns;
157
158   /* Check that the obvious things are properly set up */
159   application_verify_cb_fns (type, cb_fns);
160
161   /* Add app to lookup by api_client_index table */
162   application_table_add (app);
163
164   return app;
165 }
166
167 application_t *
168 application_get (u32 index)
169 {
170   return pool_elt_at_index (app_pool, index);
171 }
172
173 application_t *
174 application_get_if_valid (u32 index)
175 {
176   if (pool_is_free_index (app_pool, index))
177     return 0;
178
179   return pool_elt_at_index (app_pool, index);
180 }
181
182 u32
183 application_get_index (application_t * app)
184 {
185   return app - app_pool;
186 }
187
188 int
189 application_server_init (application_t * server, u32 segment_size,
190                          u32 add_segment_size, u32 rx_fifo_size,
191                          u32 tx_fifo_size, u8 ** segment_name)
192 {
193   session_manager_main_t *smm = vnet_get_session_manager_main ();
194   session_manager_t *sm;
195   int rv;
196
197   sm = session_manager_get (server->session_manager_index);
198
199   /* Add first segment */
200   if ((rv = session_manager_add_first_segment (smm, sm, segment_size,
201                                                segment_name)))
202     {
203       return rv;
204     }
205
206   /* Setup session manager */
207   sm->add_segment_size = add_segment_size;
208   sm->rx_fifo_size = rx_fifo_size;
209   sm->tx_fifo_size = tx_fifo_size;
210   sm->add_segment = sm->add_segment_size != 0;
211   return 0;
212 }
213
214 u8 *
215 format_application_server (u8 * s, va_list * args)
216 {
217   application_t *srv = va_arg (*args, application_t *);
218   int verbose = va_arg (*args, int);
219   vl_api_registration_t *regp;
220   stream_session_t *listener;
221   u8 *server_name, *str, *seg_name;
222   u32 segment_size;
223
224   if (srv == 0)
225     {
226       if (verbose)
227         s = format (s, "%-40s%-20s%-15s%-15s%-10s", "Connection", "Server",
228                     "Segment", "API Client", "Cookie");
229       else
230         s = format (s, "%-40s%-20s", "Connection", "Server");
231
232       return s;
233     }
234
235   regp = vl_api_client_index_to_registration (srv->api_client_index);
236   if (!regp)
237     server_name = format (0, "builtin-%d%c", srv->index, 0);
238   else
239     server_name = regp->name;
240
241   listener = stream_session_listener_get (srv->session_type,
242                                           srv->session_index);
243   str = format (0, "%U", format_stream_session, listener, verbose);
244
245   session_manager_get_segment_info (listener->server_segment_index, &seg_name,
246                                     &segment_size);
247   if (verbose)
248     {
249       s = format (s, "%-40s%-20s%-20s%-10d%-10d", str, server_name,
250                   seg_name, srv->api_client_index, srv->accept_cookie);
251     }
252   else
253     s = format (s, "%-40s%-20s", str, server_name);
254   return s;
255 }
256
257 u8 *
258 format_application_client (u8 * s, va_list * args)
259 {
260   application_t *client = va_arg (*args, application_t *);
261   int verbose = va_arg (*args, int);
262   stream_session_t *session;
263   u8 *str, *seg_name;
264   u32 segment_size;
265
266   if (client == 0)
267     {
268       if (verbose)
269         s =
270           format (s, "%-40s%-20s%-10s", "Connection", "Segment",
271                   "API Client");
272       else
273         s = format (s, "%-40s", "Connection");
274
275       return s;
276     }
277
278   session = stream_session_get (client->session_index, client->thread_index);
279   str = format (0, "%U", format_stream_session, session, verbose);
280
281   session_manager_get_segment_info (session->server_segment_index, &seg_name,
282                                     &segment_size);
283   if (verbose)
284     {
285       s = format (s, "%-40s%-20s%-10d%", str, seg_name,
286                   client->api_client_index);
287     }
288   else
289     s = format (s, "%-40s", str);
290   return s;
291 }
292
293 static clib_error_t *
294 show_app_command_fn (vlib_main_t * vm, unformat_input_t * input,
295                      vlib_cli_command_t * cmd)
296 {
297   session_manager_main_t *smm = &session_manager_main;
298   application_t *app;
299   int do_server = 0;
300   int do_client = 0;
301   int verbose = 0;
302
303   if (!smm->is_enabled)
304     {
305       clib_error_return (0, "session layer is not enabled");
306     }
307
308   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
309     {
310       if (unformat (input, "server"))
311         do_server = 1;
312       else if (unformat (input, "client"))
313         do_client = 1;
314       else if (unformat (input, "verbose"))
315         verbose = 1;
316       else
317         break;
318     }
319
320   if (do_server)
321     {
322       if (pool_elts (app_pool))
323         {
324           vlib_cli_output (vm, "%U", format_application_server,
325                            0 /* header */ ,
326                            verbose);
327           /* *INDENT-OFF* */
328           pool_foreach (app, app_pool,
329           ({
330             if (app->mode == APP_SERVER)
331               vlib_cli_output (vm, "%U", format_application_server, app,
332                                verbose);
333           }));
334           /* *INDENT-ON* */
335         }
336       else
337         vlib_cli_output (vm, "No active server bindings");
338     }
339
340   if (do_client)
341     {
342       if (pool_elts (app_pool))
343         {
344           vlib_cli_output (vm, "%U", format_application_client,
345                            0 /* header */ ,
346                            verbose);
347           /* *INDENT-OFF* */
348           pool_foreach (app, app_pool,
349           ({
350             if (app->mode == APP_CLIENT)
351               vlib_cli_output (vm, "%U", format_application_client, app,
352                                verbose);
353           }));
354           /* *INDENT-ON* */
355         }
356       else
357         vlib_cli_output (vm, "No active client bindings");
358     }
359
360   return 0;
361 }
362
363 /* *INDENT-OFF* */
364 VLIB_CLI_COMMAND (show_app_command, static) =
365 {
366   .path = "show app",
367   .short_help = "show app [server|client] [verbose]",
368   .function = show_app_command_fn,
369 };
370 /* *INDENT-ON* */
371
372 /*
373  * fd.io coding-style-patch-verification: ON
374  *
375  * Local Variables:
376  * eval: (c-set-style "gnu")
377  * End:
378  */