VPP-598: tcp stack initial commit
[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 application_t *
96 application_new (application_type_t type, session_type_t sst,
97                  u32 api_client_index, u32 flags, session_cb_vft_t * cb_fns)
98 {
99   session_manager_main_t *smm = vnet_get_session_manager_main ();
100   api_main_t *am = &api_main;
101   application_t *app;
102   void *oldheap;
103   session_manager_t *sm;
104
105   pool_get (app_pool, app);
106   memset (app, 0, sizeof (*app));
107
108   /* Allocate event fifo in the /vpe-api shared-memory segment */
109   oldheap = svm_push_data_heap (am->vlib_rp);
110
111   /* Allocate server event queue */
112   app->event_queue =
113     unix_shared_memory_queue_init (128 /* nels $$$$ config */ ,
114                                    sizeof (session_fifo_event_t),
115                                    0 /* consumer pid */ ,
116                                    0
117                                    /* (do not) signal when queue non-empty */
118     );
119
120   svm_pop_heap (oldheap);
121
122   /* If a server, allocate session manager */
123   if (type == APP_SERVER)
124     {
125       pool_get (smm->session_managers, sm);
126       memset (sm, 0, sizeof (*sm));
127
128       app->session_manager_index = sm - smm->session_managers;
129     }
130   else if (type == APP_CLIENT)
131     {
132       /* Allocate connect session manager if needed */
133       if (smm->connect_manager_index[sst] == INVALID_INDEX)
134         connects_session_manager_init (smm, sst);
135       app->session_manager_index = smm->connect_manager_index[sst];
136     }
137
138   app->mode = type;
139   app->index = application_get_index (app);
140   app->session_type = sst;
141   app->api_client_index = api_client_index;
142   app->flags = flags;
143   app->cb_fns = *cb_fns;
144
145   /* Add app to lookup by api_client_index table */
146   application_table_add (app);
147
148   return app;
149 }
150
151 application_t *
152 application_get (u32 index)
153 {
154   return pool_elt_at_index (app_pool, index);
155 }
156
157 u32
158 application_get_index (application_t * app)
159 {
160   return app - app_pool;
161 }
162
163 int
164 application_server_init (application_t * server, u32 segment_size,
165                          u32 add_segment_size, u32 rx_fifo_size,
166                          u32 tx_fifo_size, u8 ** segment_name)
167 {
168   session_manager_main_t *smm = vnet_get_session_manager_main ();
169   session_manager_t *sm;
170   int rv;
171
172   sm = session_manager_get (server->session_manager_index);
173
174   /* Add first segment */
175   if ((rv = session_manager_add_first_segment (smm, sm, segment_size,
176                                                segment_name)))
177     {
178       return rv;
179     }
180
181   /* Setup session manager */
182   sm->add_segment_size = add_segment_size;
183   sm->rx_fifo_size = rx_fifo_size;
184   sm->tx_fifo_size = tx_fifo_size;
185   sm->add_segment = sm->add_segment_size != 0;
186   return 0;
187 }
188
189 u8 *
190 format_application_server (u8 * s, va_list * args)
191 {
192   application_t *srv = va_arg (*args, application_t *);
193   int verbose = va_arg (*args, int);
194   vl_api_registration_t *regp;
195   stream_session_t *listener;
196   u8 *server_name, *str, *seg_name;
197   u32 segment_size;
198
199   if (srv == 0)
200     {
201       if (verbose)
202         s = format (s, "%-40s%-20s%-15s%-15s%-10s", "Connection", "Server",
203                     "Segment", "API Client", "Cookie");
204       else
205         s = format (s, "%-40s%-20s", "Connection", "Server");
206
207       return s;
208     }
209
210   regp = vl_api_client_index_to_registration (srv->api_client_index);
211   if (!regp)
212     server_name = format (0, "%s%c", regp->name, 0);
213   else
214     server_name = regp->name;
215
216   listener = stream_session_listener_get (srv->session_type,
217                                           srv->session_index);
218   str = format (0, "%U", format_stream_session, listener, verbose);
219
220   session_manager_get_segment_info (listener->server_segment_index, &seg_name,
221                                     &segment_size);
222   if (verbose)
223     {
224       s = format (s, "%-40s%-20s%-20s%-10d%-10d", str, server_name,
225                   seg_name, srv->api_client_index, srv->accept_cookie);
226     }
227   else
228     s = format (s, "%-40s%-20s", str, server_name);
229   return s;
230 }
231
232 u8 *
233 format_application_client (u8 * s, va_list * args)
234 {
235   application_t *client = va_arg (*args, application_t *);
236   int verbose = va_arg (*args, int);
237   stream_session_t *session;
238   u8 *str, *seg_name;
239   u32 segment_size;
240
241   if (client == 0)
242     {
243       if (verbose)
244         s =
245           format (s, "%-40s%-20s%-10s", "Connection", "Segment",
246                   "API Client");
247       else
248         s = format (s, "%-40s", "Connection");
249
250       return s;
251     }
252
253   session = stream_session_get (client->session_index, client->thread_index);
254   str = format (0, "%U", format_stream_session, session, verbose);
255
256   session_manager_get_segment_info (session->server_segment_index, &seg_name,
257                                     &segment_size);
258   if (verbose)
259     {
260       s = format (s, "%-40s%-20s%-10d%", str, seg_name,
261                   client->api_client_index);
262     }
263   else
264     s = format (s, "%-40s", str);
265   return s;
266 }
267
268 static clib_error_t *
269 show_app_command_fn (vlib_main_t * vm, unformat_input_t * input,
270                      vlib_cli_command_t * cmd)
271 {
272   application_t *app;
273   int do_server = 0;
274   int do_client = 0;
275   int verbose = 0;
276
277   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
278     {
279       if (unformat (input, "server"))
280         do_server = 1;
281       else if (unformat (input, "client"))
282         do_client = 1;
283       else if (unformat (input, "verbose"))
284         verbose = 1;
285       else
286         break;
287     }
288
289   if (do_server)
290     {
291       if (pool_elts (app_pool))
292         {
293           vlib_cli_output (vm, "%U", format_application_server,
294                            0 /* header */ ,
295                            verbose);
296           /* *INDENT-OFF* */
297           pool_foreach (app, app_pool,
298           ({
299             if (app->mode == APP_SERVER)
300               vlib_cli_output (vm, "%U", format_application_server, app,
301                                verbose);
302           }));
303           /* *INDENT-ON* */
304         }
305       else
306         vlib_cli_output (vm, "No active server bindings");
307     }
308
309   if (do_client)
310     {
311       if (pool_elts (app_pool))
312         {
313           vlib_cli_output (vm, "%U", format_application_client,
314                            0 /* header */ ,
315                            verbose);
316           /* *INDENT-OFF* */
317           pool_foreach (app, app_pool,
318           ({
319             if (app->mode == APP_CLIENT)
320               vlib_cli_output (vm, "%U", format_application_client, app,
321                                verbose);
322           }));
323           /* *INDENT-ON* */
324         }
325       else
326         vlib_cli_output (vm, "No active server bindings");
327     }
328
329   return 0;
330 }
331
332 VLIB_CLI_COMMAND (show_app_command, static) =
333 {
334 .path = "show app",.short_help =
335     "show app [server|client] [verbose]",.function = show_app_command_fn,};
336
337 /*
338  * fd.io coding-style-patch-verification: ON
339  *
340  * Local Variables:
341  * eval: (c-set-style "gnu")
342  * End:
343  */