Horizontal (nSessions) scaling draft
[vpp.git] / src / vnet / session / session_cli.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 #include <vnet/session/application.h>
16 #include <vnet/session/session.h>
17
18 u8 *
19 format_stream_session_fifos (u8 * s, va_list * args)
20 {
21   stream_session_t *ss = va_arg (*args, stream_session_t *);
22   s = format (s, " Rx fifo: %U", format_svm_fifo, ss->server_rx_fifo, 1);
23   s = format (s, " Tx fifo: %U", format_svm_fifo, ss->server_tx_fifo, 1);
24   return s;
25 }
26
27 /**
28  * Format stream session as per the following format
29  *
30  * verbose:
31  *   "Connection", "Rx fifo", "Tx fifo", "Session Index"
32  * non-verbose:
33  *   "Connection"
34  */
35 u8 *
36 format_stream_session (u8 * s, va_list * args)
37 {
38   stream_session_t *ss = va_arg (*args, stream_session_t *);
39   int verbose = va_arg (*args, int);
40   transport_proto_vft_t *tp_vft;
41   u8 *str = 0;
42   tp_vft = session_get_transport_vft (ss->session_type);
43
44   if (verbose == 1)
45     str = format (0, "%-10u%-10u%-10lld",
46                   svm_fifo_max_dequeue (ss->server_rx_fifo),
47                   svm_fifo_max_enqueue (ss->server_tx_fifo),
48                   stream_session_get_index (ss));
49
50   if (ss->session_state == SESSION_STATE_READY
51       || ss->session_state == SESSION_STATE_ACCEPTING)
52     {
53       s = format (s, "%U", tp_vft->format_connection, ss->connection_index,
54                   ss->thread_index, verbose);
55       if (verbose == 1)
56         s = format (s, "%v", str);
57       if (verbose > 1)
58         s = format (s, "%U", format_stream_session_fifos, ss);
59     }
60   else if (ss->session_state == SESSION_STATE_LISTENING)
61     {
62       s = format (s, "%-40U%v", tp_vft->format_listener, ss->connection_index,
63                   str);
64     }
65   else if (ss->session_state == SESSION_STATE_CONNECTING)
66     {
67       s = format (s, "%-40U%v", tp_vft->format_half_open,
68                   ss->connection_index, str);
69     }
70   else if (ss->session_state == SESSION_STATE_CLOSED)
71     {
72       s =
73         format (s, "[CL] %U", tp_vft->format_connection, ss->connection_index,
74                 ss->thread_index, verbose);
75       if (verbose == 1)
76         s = format (s, "%v", str);
77       if (verbose > 1)
78         s = format (s, "%U", format_stream_session_fifos, ss);
79     }
80   else
81     {
82       clib_warning ("Session in state: %d!", ss->session_state);
83     }
84
85   vec_free (str);
86
87   return s;
88 }
89
90 static clib_error_t *
91 show_session_command_fn (vlib_main_t * vm, unformat_input_t * input,
92                          vlib_cli_command_t * cmd)
93 {
94   session_manager_main_t *smm = &session_manager_main;
95   int verbose = 0, i;
96   stream_session_t *pool;
97   stream_session_t *s;
98   u8 *str = 0, one_session = 0, proto_set = 0, proto = 0;
99   u8 is_ip4 = 0, s_type = 0;
100   ip4_address_t lcl_ip4, rmt_ip4;
101   u32 lcl_port = 0, rmt_port = 0;
102
103   memset (&lcl_ip4, 0, sizeof (lcl_ip4));
104   memset (&rmt_ip4, 0, sizeof (rmt_ip4));
105
106   if (!smm->is_enabled)
107     {
108       return clib_error_return (0, "session layer is not enabled");
109     }
110
111   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
112     {
113       if (unformat (input, "verbose %d", &verbose))
114         ;
115       else if (unformat (input, "verbose"))
116         verbose = 1;
117       else if (unformat (input, "tcp"))
118         {
119           proto_set = 1;
120           proto = TRANSPORT_PROTO_TCP;
121         }
122       else if (unformat (input, "%U:%d->%U:%d",
123                          unformat_ip4_address, &lcl_ip4, &lcl_port,
124                          unformat_ip4_address, &rmt_ip4, &rmt_port))
125         {
126           one_session = 1;
127           is_ip4 = 1;
128         }
129
130       else
131         break;
132     }
133
134   if (one_session)
135     {
136       if (!proto_set)
137         {
138           vlib_cli_output (vm, "proto not set");
139           return clib_error_return (0, "proto not set");
140         }
141
142       s_type = session_type_from_proto_and_ip (proto, is_ip4);
143       s = stream_session_lookup4 (&lcl_ip4, &rmt_ip4,
144                                   clib_host_to_net_u16 (lcl_port),
145                                   clib_host_to_net_u16 (rmt_port), s_type);
146       if (s)
147         vlib_cli_output (vm, "%U", format_stream_session, s, 2);
148       else
149         vlib_cli_output (vm, "session does not exist");
150
151       return 0;
152     }
153
154   for (i = 0; i < vec_len (smm->sessions); i++)
155     {
156       u32 once_per_pool;
157       pool = smm->sessions[i];
158
159       once_per_pool = 1;
160
161       if (pool_elts (pool))
162         {
163
164           vlib_cli_output (vm, "Thread %d: %d active sessions",
165                            i, pool_elts (pool));
166           if (verbose)
167             {
168               if (once_per_pool && verbose == 1)
169                 {
170                   str =
171                     format (str, "%-50s%-15s%-10s%-10s%-10s", "Connection",
172                             "State", "Rx-f", "Tx-f", "S-idx");
173                   vlib_cli_output (vm, "%v", str);
174                   vec_reset_length (str);
175                   once_per_pool = 0;
176                 }
177
178               /* *INDENT-OFF* */
179               pool_foreach (s, pool,
180               ({
181                 vec_reset_length (str);
182                 str = format (str, "%U", format_stream_session, s, verbose);
183                 vlib_cli_output (vm, "%v", str);
184               }));
185               /* *INDENT-ON* */
186             }
187         }
188       else
189         vlib_cli_output (vm, "Thread %d: no active sessions", i);
190       vec_reset_length (str);
191     }
192   vec_free (str);
193
194   return 0;
195 }
196
197 /* *INDENT-OFF* */
198 VLIB_CLI_COMMAND (show_session_command, static) =
199 {
200   .path = "show session",
201   .short_help = "show session [verbose]",
202   .function = show_session_command_fn,
203 };
204 /* *INDENT-ON* */
205
206 static int
207 clear_session (stream_session_t * s)
208 {
209   application_t *server = application_get (s->app_index);
210   server->cb_fns.session_disconnect_callback (s);
211   return 0;
212 }
213
214 static clib_error_t *
215 clear_session_command_fn (vlib_main_t * vm, unformat_input_t * input,
216                           vlib_cli_command_t * cmd)
217 {
218   session_manager_main_t *smm = &session_manager_main;
219   u32 thread_index = 0, clear_all = 0;
220   u32 session_index = ~0;
221   stream_session_t **pool, *session;
222
223   if (!smm->is_enabled)
224     {
225       return clib_error_return (0, "session layer is not enabled");
226     }
227
228   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
229     {
230       if (unformat (input, "thread %d", &thread_index))
231         ;
232       else if (unformat (input, "session %d", &session_index))
233         ;
234       else if (unformat (input, "all"))
235         clear_all = 1;
236       else
237         return clib_error_return (0, "unknown input `%U'",
238                                   format_unformat_error, input);
239     }
240
241   if (!clear_all && session_index == ~0)
242     return clib_error_return (0, "session <nn> required, but not set.");
243
244   if (session_index != ~0)
245     {
246       session = stream_session_get_if_valid (session_index, thread_index);
247       if (!session)
248         return clib_error_return (0, "no session %d on thread %d",
249                                   session_index, thread_index);
250       clear_session (session);
251     }
252
253   if (clear_all)
254     {
255       /* *INDENT-OFF* */
256       vec_foreach (pool, smm->sessions)
257         {
258           pool_foreach(session, *pool, ({
259             clear_session (session);
260           }));
261         };
262       /* *INDENT-ON* */
263     }
264
265   return 0;
266 }
267
268 /* *INDENT-OFF* */
269 VLIB_CLI_COMMAND (clear_session_command, static) =
270 {
271   .path = "clear session",
272   .short_help = "clear session thread <thread> session <index>",
273   .function = clear_session_command_fn,
274 };
275 /* *INDENT-ON* */
276
277 static clib_error_t *
278 session_enable_disable_fn (vlib_main_t * vm, unformat_input_t * input,
279                            vlib_cli_command_t * cmd)
280 {
281   u8 is_en = 1;
282
283   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
284     {
285       if (unformat (input, "enable"))
286         is_en = 1;
287       else if (unformat (input, "disable"))
288         is_en = 0;
289       else
290         return clib_error_return (0, "unknown input `%U'",
291                                   format_unformat_error, input);
292     }
293
294   return vnet_session_enable_disable (vm, is_en);
295 }
296
297 /* *INDENT-OFF* */
298 VLIB_CLI_COMMAND (session_enable_disable_command, static) =
299 {
300   .path = "session",
301   .short_help = "session [enable|disable]",
302   .function = session_enable_disable_fn,
303 };
304 /* *INDENT-ON* */
305
306 /*
307  * fd.io coding-style-patch-verification: ON
308  *
309  * Local Variables:
310  * eval: (c-set-style "gnu")
311  * End:
312  */