1/*
2 * Copyright (c) 2019 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 <stdbool.h>
17#include <vlib/vlib.h>
18#include <vnet/crypto/crypto.h>
19
20static clib_error_t *
21show_crypto_engines_command_fn (vlib_main_t * vm,
22				unformat_input_t * input,
23				vlib_cli_command_t * cmd)
24{
25  unformat_input_t _line_input, *line_input = &_line_input;
26  vnet_crypto_main_t *cm = &crypto_main;
27  vnet_crypto_engine_t *p;
28
29  if (unformat_user (input, unformat_line_input, line_input))
30    unformat_free (line_input);
31
32  if (vec_len (cm->engines) == 0)
33    {
34      vlib_cli_output (vm, "No crypto engines registered");
35      return 0;
36    }
37
38  vlib_cli_output (vm, "%-20s%-8s%s", "Name", "Prio", "Description");
39  /* *INDENT-OFF* */
40  vec_foreach (p, cm->engines)
41    {
42      vlib_cli_output (vm, "%-20s%-8u%s", p->name, p->priority, p->desc);
43    }
44  /* *INDENT-ON* */
45  return 0;
46}
47
48/* *INDENT-OFF* */
49VLIB_CLI_COMMAND (show_crypto_engines_command, static) =
50{
51  .path = "show crypto engines",
52  .short_help = "show crypto engines",
53  .function = show_crypto_engines_command_fn,
54};
55
56static u8 *
57format_vnet_crypto_engine_candidates (u8 * s, va_list * args)
58{
59  vnet_crypto_engine_t *e;
60  vnet_crypto_main_t *cm = &crypto_main;
61  u32 id = va_arg (*args, u32);
62  u32 ei = va_arg (*args, u32);
63  int is_chained = va_arg (*args, int);
64  int is_async = va_arg (*args, int);
65
66  if (is_async)
67    {
68      vec_foreach (e, cm->engines)
69	{
70	  if (e->enqueue_handlers[id] && e->dequeue_handlers[id])
71	    {
72	      s = format (s, "%U", format_vnet_crypto_engine, e - cm->engines);
73	      if (ei == e - cm->engines)
74		s = format (s, "%c ", '*');
75	      else
76		s = format (s, " ");
77	    }
78	}
79
80      return s;
81    }
82  else
83    {
84      vec_foreach (e, cm->engines)
85	{
86	  void * h = is_chained ? (void *) e->chained_ops_handlers[id]
87	    : (void *) e->ops_handlers[id];
88
89	  if (h)
90	    {
91	      s = format (s, "%U", format_vnet_crypto_engine, e - cm->engines);
92	      if (ei == e - cm->engines)
93		s = format (s, "%c ", '*');
94	      else
95		s = format (s, " ");
96	    }
97	}
98      return s;
99    }
100}
101
102static u8 *
103format_vnet_crypto_handlers (u8 * s, va_list * args)
104{
105  vnet_crypto_alg_t alg = va_arg (*args, vnet_crypto_alg_t);
106  vnet_crypto_main_t *cm = &crypto_main;
107  vnet_crypto_alg_data_t *d = vec_elt_at_index (cm->algs, alg);
108  u32 indent = format_get_indent (s);
109  int i, first = 1;
110
111  for (i = 0; i < VNET_CRYPTO_OP_N_TYPES; i++)
112    {
113      vnet_crypto_op_data_t *od;
114      vnet_crypto_op_id_t id = d->op_by_type[i];
115
116      if (id == 0)
117	continue;
118
119      od = cm->opt_data + id;
120      if (first == 0)
121        s = format (s, "\n%U", format_white_space, indent);
122      s = format (s, "%-16U", format_vnet_crypto_op_type, od->type);
123
124      s = format (s, "%-28U", format_vnet_crypto_engine_candidates, id,
125          od->active_engine_index_simple, 0, 0);
126      s = format (s, "%U", format_vnet_crypto_engine_candidates, id,
127          od->active_engine_index_chained, 1, 0);
128      first = 0;
129    }
130  return s;
131}
132
133
134static clib_error_t *
135show_crypto_handlers_command_fn (vlib_main_t * vm,
136			unformat_input_t * input, vlib_cli_command_t * cmd)
137{
138  unformat_input_t _line_input, *line_input = &_line_input;
139  int i;
140
141  if (unformat_user (input, unformat_line_input, line_input))
142    unformat_free (line_input);
143
144  vlib_cli_output (vm, "%-16s%-16s%-28s%s", "Algo", "Type", "Simple",
145      "Chained");
146
147  for (i = 0; i < VNET_CRYPTO_N_ALGS; i++)
148    vlib_cli_output (vm, "%-16U%U", format_vnet_crypto_alg, i,
149		     format_vnet_crypto_handlers, i);
150
151  return 0;
152}
153
154/* *INDENT-OFF* */
155VLIB_CLI_COMMAND (show_crypto_handlers_command, static) =
156{
157  .path = "show crypto handlers",
158  .short_help = "show crypto handlers",
159  .function = show_crypto_handlers_command_fn,
160};
161/* *INDENT-ON* */
162
163static clib_error_t *
164set_crypto_handler_command_fn (vlib_main_t * vm,
165			       unformat_input_t * input,
166			       vlib_cli_command_t * cmd)
167{
168  unformat_input_t _line_input, *line_input = &_line_input;
169  vnet_crypto_main_t *cm = &crypto_main;
170  int rc = 0;
171  char **args = 0, *s, **arg, *engine = 0;
172  int all = 0;
173  clib_error_t *error = 0;
174  crypto_op_class_type_t oct = CRYPTO_OP_BOTH;
175
176  if (!unformat_user (input, unformat_line_input, line_input))
177    return 0;
178
179  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
180    {
181      if (unformat (line_input, "all"))
182	all = 1;
183      else if (unformat (line_input, "simple"))
184	oct = CRYPTO_OP_SIMPLE;
185      else if (unformat (line_input, "chained"))
186	oct = CRYPTO_OP_CHAINED;
187      else if (unformat (line_input, "both"))
188	oct = CRYPTO_OP_BOTH;
189      else if (unformat (line_input, "%s", &s))
190	vec_add1 (args, s);
191      else
192	{
193	  error = clib_error_return (0, "invalid params");
194	  goto done;
195	}
196    }
197
198  if ((vec_len (args) < 2 && !all) || (vec_len (args) == 0 && all))
199    {
200      error = clib_error_return (0, "missing cipher or engine!");
201      goto done;
202    }
203
204  engine = vec_elt_at_index (args, vec_len (args) - 1)[0];
205  vec_del1 (args, vec_len (args) - 1);
206
207  if (all)
208    {
209      char *key;
210      u8 *value;
211
212      /* *INDENT-OFF* */
213      hash_foreach_mem (key, value, cm->alg_index_by_name,
214      ({
215        (void) value;
216        rc += vnet_crypto_set_handler2 (key, engine, oct);
217      }));
218      /* *INDENT-ON* */
219
220      if (rc)
221	vlib_cli_output (vm, "failed to set crypto engine!");
222    }
223  else
224    {
225      vec_foreach (arg, args)
226      {
227	rc = vnet_crypto_set_handler2 (arg[0], engine, oct);
228	if (rc)
229	  {
230	    vlib_cli_output (vm, "failed to set engine %s for %s!",
231			     engine, arg[0]);
232	  }
233      }
234    }
235
236done:
237  vec_free (engine);
238  vec_foreach (arg, args) vec_free (arg[0]);
239  vec_free (args);
240  unformat_free (line_input);
241  return error;
242}
243
244/* *INDENT-OFF* */
245VLIB_CLI_COMMAND (set_crypto_handler_command, static) =
246{
247  .path = "set crypto handler",
248  .short_help = "set crypto handler cipher [cipher2 cipher3 ...] engine"
249    " [simple|chained]",
250  .function = set_crypto_handler_command_fn,
251};
252/* *INDENT-ON* */
253
254static u8 *
255format_vnet_crypto_async_handlers (u8 * s, va_list * args)
256{
257  vnet_crypto_async_alg_t alg = va_arg (*args, vnet_crypto_async_alg_t);
258  vnet_crypto_main_t *cm = &crypto_main;
259  vnet_crypto_async_alg_data_t *d = vec_elt_at_index (cm->async_algs, alg);
260  u32 indent = format_get_indent (s);
261  int i, first = 1;
262
263  for (i = 0; i < VNET_CRYPTO_ASYNC_OP_N_TYPES; i++)
264    {
265      vnet_crypto_async_op_data_t *od;
266      vnet_crypto_async_op_id_t id = d->op_by_type[i];
267
268      if (id == 0)
269	continue;
270
271      od = cm->async_opt_data + id;
272      if (first == 0)
273	s = format (s, "\n%U", format_white_space, indent);
274      s = format (s, "%-16U", format_vnet_crypto_async_op_type, od->type);
275
276      s = format (s, "%U", format_vnet_crypto_engine_candidates, id,
277		  od->active_engine_index_async, 0, 1);
278      first = 0;
279    }
280  return s;
281}
282
283static clib_error_t *
284show_crypto_async_handlers_command_fn (vlib_main_t * vm,
285				       unformat_input_t * input,
286				       vlib_cli_command_t * cmd)
287{
288  unformat_input_t _line_input, *line_input = &_line_input;
289  int i;
290
291  if (unformat_user (input, unformat_line_input, line_input))
292    unformat_free (line_input);
293
294  vlib_cli_output (vm, "%-28s%-16s%s", "Algo", "Type", "Handler");
295
296  for (i = 0; i < VNET_CRYPTO_N_ASYNC_ALGS; i++)
297    vlib_cli_output (vm, "%-28U%U", format_vnet_crypto_async_alg, i,
298		     format_vnet_crypto_async_handlers, i);
299
300  return 0;
301}
302
303/* *INDENT-OFF* */
304VLIB_CLI_COMMAND (show_crypto_async_handlers_command, static) =
305{
306  .path = "show crypto async handlers",
307  .short_help = "show crypto async handlers",
308  .function = show_crypto_async_handlers_command_fn,
309};
310/* *INDENT-ON* */
311
312
313static clib_error_t *
314set_crypto_async_handler_command_fn (vlib_main_t * vm,
315				     unformat_input_t * input,
316				     vlib_cli_command_t * cmd)
317{
318  unformat_input_t _line_input, *line_input = &_line_input;
319  vnet_crypto_main_t *cm = &crypto_main;
320  int rc = 0;
321  char **args = 0, *s, **arg, *engine = 0;
322  int all = 0;
323  clib_error_t *error = 0;
324
325  if (!unformat_user (input, unformat_line_input, line_input))
326    return 0;
327
328  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
329    {
330      if (unformat (line_input, "all"))
331	all = 1;
332      else if (unformat (line_input, "%s", &s))
333	vec_add1 (args, s);
334      else
335	{
336	  error = clib_error_return (0, "invalid params");
337	  goto done;
338	}
339    }
340
341  if ((vec_len (args) < 2 && !all) || (vec_len (args) == 0 && all))
342    {
343      error = clib_error_return (0, "missing cipher or engine!");
344      goto done;
345    }
346
347  engine = vec_elt_at_index (args, vec_len (args) - 1)[0];
348  vec_del1 (args, vec_len (args) - 1);
349
350  if (all)
351    {
352      char *key;
353      u8 *value;
354
355      /* *INDENT-OFF* */
356      hash_foreach_mem (key, value, cm->async_alg_index_by_name,
357      ({
358        (void) value;
359        rc += vnet_crypto_set_async_handler2 (key, engine);
360      }));
361      /* *INDENT-ON* */
362
363      if (rc)
364	vlib_cli_output (vm, "failed to set crypto engine!");
365    }
366  else
367    {
368      vec_foreach (arg, args)
369      {
370	rc = vnet_crypto_set_async_handler2 (arg[0], engine);
371	if (rc)
372	  {
373	    vlib_cli_output (vm, "failed to set engine %s for %s!",
374			     engine, arg[0]);
375	  }
376      }
377    }
378
379done:
380  vec_free (engine);
381  vec_foreach (arg, args) vec_free (arg[0]);
382  vec_free (args);
383  unformat_free (line_input);
384  return error;
385}
386
387/* *INDENT-OFF* */
388VLIB_CLI_COMMAND (set_crypto_async_handler_command, static) =
389{
390  .path = "set crypto async handler",
391  .short_help = "set crypto async handler type [type2 type3 ...] engine",
392  .function = set_crypto_async_handler_command_fn,
393};
394/* *INDENT-ON* */
395
396/*
397 * fd.io coding-style-patch-verification: ON
398 *
399 * Local Variables:
400 * eval: (c-set-style "gnu")
401 * End:
402 */
403