FD.io VPP  v16.06
Vector Packet Processing
cli.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 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  * pg_cli.c: packet generator cli
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39 
40 #include <vnet/vnet.h>
41 #include <vnet/pg/pg.h>
42 
43 #ifdef CLIB_UNIX
44 #include <vnet/unix/pcap.h>
45 #endif
46 
47 /* Root of all packet generator cli commands. */
48 VLIB_CLI_COMMAND (vlib_cli_pg_command, static) = {
49  .path = "packet-generator",
50  .short_help = "Packet generator commands",
51 };
52 
53 static clib_error_t *
55  unformat_input_t * input,
56  vlib_cli_command_t * cmd)
57 {
58  pg_main_t * pg = &pg_main;
59  pg_stream_t * s;
60  int is_enable = cmd->function_arg != 0;
61  u32 stream_index = ~0;
62 
63  if (unformat (input, "%U", unformat_eof))
64  ;
65  else if (unformat (input, "%U", unformat_hash_vec_string,
66  pg->stream_index_by_name, &stream_index))
67  ;
68  else
69  return clib_error_create ("unknown input `%U'",
70  format_unformat_error, input);
71 
72  /* No stream specified: enable/disable all streams. */
73  if (stream_index == ~0)
74  pool_foreach (s, pg->streams, ({
75  pg_stream_enable_disable (pg, s, is_enable);
76  }));
77  else
78  {
79  /* enable/disable specified stream. */
80  s = pool_elt_at_index (pg->streams, stream_index);
81  pg_stream_enable_disable (pg, s, is_enable);
82  }
83 
84  return 0;
85 }
86 
87 VLIB_CLI_COMMAND (enable_streams_cli, static) = {
88  .path = "packet-generator enable-stream",
89  .short_help = "Enable packet generator streams",
90  .function = enable_disable_stream,
91  .function_arg = 1, /* is_enable */
92 };
93 
94 VLIB_CLI_COMMAND (disable_streams_cli, static) = {
95  .path = "packet-generator disable-stream",
96  .short_help = "Disable packet generator streams",
97  .function = enable_disable_stream,
98  .function_arg = 0, /* is_enable */
99 };
100 
101 static u8 * format_pg_stream (u8 * s, va_list * va)
102 {
103  pg_stream_t * t = va_arg (*va, pg_stream_t *);
104  u8 * v;
105 
106  if (! t)
107  return format (s, "%=16s%=12s%=16s%s",
108  "Name", "Enabled", "Count", "Parameters");
109 
110  s = format (s, "%-16v%=12s%16Ld",
111  t->name,
112  pg_stream_is_enabled (t) ? "Yes" : "No",
114 
115  v = 0;
116 
117  v = format (v, "limit %Ld, ", t->n_packets_limit);
118 
119  v = format (v, "rate %.2e pps, ", t->rate_packets_per_second);
120 
121  v = format (v, "size %d%c%d, ",
122  t->min_packet_bytes,
123  t->packet_size_edit_type == PG_EDIT_RANDOM ? '+' : '-',
124  t->max_packet_bytes);
125 
126  v = format (v, "buffer-size %d, ", t->buffer_bytes);
127 
128  if (v)
129  {
130  s = format (s, " %v", v);
131  vec_free (v);
132  }
133 
134  return s;
135 }
136 
137 static clib_error_t *
139  unformat_input_t * input,
140  vlib_cli_command_t * cmd)
141 {
142  pg_main_t * pg = &pg_main;
143  pg_stream_t * s;
144 
145  if (pool_elts (pg->streams) == 0)
146  {
147  vlib_cli_output (vm, "no streams currently defined");
148  goto done;
149  }
150 
151  vlib_cli_output (vm, "%U", format_pg_stream, 0);
152  pool_foreach (s, pg->streams, ({
153  vlib_cli_output (vm, "%U", format_pg_stream, s);
154  }));
155 
156  done:
157  return 0;
158 }
159 
160 VLIB_CLI_COMMAND (show_streams_cli, static) = {
161  .path = "show packet-generator",
162  .short_help = "Show packet generator streams",
163  .function = show_streams,
164 };
165 
166 static clib_error_t *
167 pg_pcap_read (pg_stream_t * s, char * file_name)
168 {
169 #ifndef CLIB_UNIX
170  return clib_error_return (0, "no pcap support");
171 #else
172  pcap_main_t pm;
173  clib_error_t * error;
174  memset (&pm, 0, sizeof (pm));
175  pm.file_name = file_name;
176  error = pcap_read (&pm);
181  /* For PCAP buffers we never re-use buffers. */
183  return error;
184 #endif /* CLIB_UNIX */
185 }
186 
187 static uword
189 {
190  pg_stream_t * s = va_arg (*args, pg_stream_t *);
191  f64 x;
192 
193  if (unformat (input, "limit %f", &x))
194  s->n_packets_limit = x;
195 
196  else if (unformat (input, "rate %f", &x))
198 
199  else if (unformat (input, "size %d-%d", &s->min_packet_bytes,
200  &s->max_packet_bytes))
202 
203  else if (unformat (input, "size %d+%d", &s->min_packet_bytes,
204  &s->max_packet_bytes))
206 
207  else if (unformat (input, "buffer-size %d", &s->buffer_bytes))
208  ;
209 
210  else
211  return 0;
212 
213  return 1;
214 }
215 
216 static clib_error_t *
218 {
220  return clib_error_create ("max-size < min-size");
221 
222  if (s->buffer_bytes >= 4096 || s->buffer_bytes == 0)
223  return clib_error_create ("buffer-size must be positive and < 4096, given %d",
224  s->buffer_bytes);
225 
226  if (s->rate_packets_per_second < 0)
227  return clib_error_create ("negative rate");
228 
229  return 0;
230 }
231 
232 static clib_error_t *
234  unformat_input_t * input,
235  vlib_cli_command_t * cmd)
236 {
237  clib_error_t * error = 0;
238  u8 * tmp = 0;
239  u32 hw_if_index;
240  unformat_input_t sub_input = {0};
241  int sub_input_given = 0;
242  vnet_main_t * vnm = vnet_get_main();
243  pg_main_t * pg = &pg_main;
244  pg_stream_t s = {0};
245  char * pcap_file_name;
246 
247  s.sw_if_index[VLIB_RX] = s.sw_if_index[VLIB_TX] = ~0;
248  s.node_index = ~0;
251  pcap_file_name = 0;
253  {
254  if (unformat (input, "name %v", &tmp))
255  {
256  if (s.name)
257  vec_free (s.name);
258  s.name = tmp;
259  }
260 
261  else if (unformat (input, "node %U",
262  unformat_vnet_hw_interface, vnm, &hw_if_index))
263  {
264  vnet_hw_interface_t * hi = vnet_get_hw_interface (vnm, hw_if_index);
265 
268  }
269 
270  else if (unformat (input, "node %U",
272  ;
273 
274  else if (unformat (input, "interface %U",
276  ;
277 
278  else if (unformat (input, "pcap %s", &pcap_file_name))
279  ;
280 
281  else if (! sub_input_given
282  && unformat (input, "data %U", unformat_input, &sub_input))
283  sub_input_given++;
284 
285  else if (unformat_user (input, unformat_pg_stream_parameter, &s))
286  ;
287 
288  else if (unformat (input, "no-recycle"))
290 
291  else
292  {
293  error = clib_error_create ("unknown input `%U'",
294  format_unformat_error, input);
295  goto done;
296  }
297  }
298 
299  error = validate_stream (&s);
300  if (error)
301  return error;
302 
303  if (! sub_input_given && ! pcap_file_name)
304  {
305  error = clib_error_create ("no packet data given");
306  goto done;
307  }
308 
309  if (s.node_index == ~0)
310  {
311  error = clib_error_create ("output interface or node not given");
312  goto done;
313  }
314 
315  {
316  pg_node_t * n;
317 
318  if (s.node_index < vec_len (pg->nodes))
319  n = pg->nodes + s.node_index;
320  else
321  n = 0;
322 
323  if (pcap_file_name != 0)
324  {
325  error = pg_pcap_read (&s, pcap_file_name);
326  if (error)
327  goto done;
328  vec_free (pcap_file_name);
329  }
330 
331  else if (n && n->unformat_edit
332  && unformat_user (&sub_input, n->unformat_edit, &s))
333  ;
334 
335  else if (! unformat_user (&sub_input, unformat_pg_payload, &s))
336  {
337  error = clib_error_create
338  ("failed to parse packet data from `%U'",
339  format_unformat_error, &sub_input);
340  goto done;
341  }
342  }
343 
344  pg_stream_add (pg, &s);
345  return 0;
346 
347  done:
348  pg_stream_free (&s);
349  unformat_free (&sub_input);
350  return error;
351 }
352 
353 VLIB_CLI_COMMAND (new_stream_cli, static) = {
354  .path = "packet-generator new",
355  .function = new_stream,
356  .short_help = "Create packet generator stream",
357  .long_help =
358  "Create packet generator stream\n"
359  "\n"
360  "Arguments:\n"
361  "\n"
362  "name STRING sets stream name\n"
363  "interface STRING interface for stream output \n"
364  "node NODE-NAME node for stream output\n"
365  "data STRING specifies packet data\n",
366 };
367 
368 static clib_error_t *
370  unformat_input_t * input,
371  vlib_cli_command_t * cmd)
372 {
373  pg_main_t * pg = &pg_main;
374  u32 i;
375 
376  if (! unformat (input, "%U",
378  return clib_error_create ("expected stream name `%U'",
379  format_unformat_error, input);
380 
381  pg_stream_del (pg, i);
382  return 0;
383 }
384 
385 VLIB_CLI_COMMAND (del_stream_cli, static) = {
386  .path = "packet-generator delete",
387  .function = del_stream,
388  .short_help = "Delete stream with given name",
389 };
390 
391 static clib_error_t *
393  unformat_input_t * input,
394  vlib_cli_command_t * cmd)
395 {
396  pg_main_t * pg = &pg_main;
397  pg_stream_t * s, s_new;
398  u32 stream_index = ~0;
399  clib_error_t * error;
400 
401  if (unformat (input, "%U", unformat_hash_vec_string,
402  pg->stream_index_by_name, &stream_index))
403  ;
404  else
405  return clib_error_create ("expecting stream name; got `%U'",
406  format_unformat_error, input);
407 
408  s = pool_elt_at_index (pg->streams, stream_index);
409  s_new = s[0];
410 
412  {
413  if (unformat_user (input, unformat_pg_stream_parameter, &s_new))
414  ;
415 
416  else
417  return clib_error_create ("unknown input `%U'",
418  format_unformat_error, input);
419  }
420 
421  error = validate_stream (&s_new);
422  if (! error)
423  s[0] = s_new;
424 
425  return error;
426 }
427 
428 VLIB_CLI_COMMAND (change_stream_parameters_cli, static) = {
429  .path = "packet-generator configure",
430  .short_help = "Change packet generator stream parameters",
431  .function = change_stream_parameters,
432 };
433 
434 /* Dummy init function so that we can be linked in. */
436 { return 0; }
437 
unformat_function_t unformat_vnet_hw_interface
vmrglw vmrglh hi
u64 n_packets_limit
Definition: pg.h:148
void pg_stream_add(pg_main_t *pg, pg_stream_t *s_init)
Definition: stream.c:310
char * file_name
Definition: pcap.h:107
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:942
static clib_error_t * show_streams(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:138
static u8 * format_pg_stream(u8 *s, va_list *va)
Definition: cli.c:101
static uword unformat_pg_stream_parameter(unformat_input_t *input, va_list *args)
Definition: cli.c:188
Definition: pg.h:293
always_inline void unformat_free(unformat_input_t *i)
Definition: format.h:160
#define UNFORMAT_END_OF_INPUT
Definition: format.h:142
uword * stream_index_by_name
Definition: pg.h:304
u32 max_packet_bytes
Definition: pcap.h:131
unformat_function_t unformat_vnet_sw_interface
pg_edit_type_t packet_size_edit_type
Definition: pg.h:105
void pg_stream_del(pg_main_t *pg, uword index)
Definition: stream.c:399
always_inline uword unformat_check_input(unformat_input_t *i)
Definition: format.h:168
vnet_main_t * vnet_get_main(void)
Definition: misc.c:45
#define pool_foreach(VAR, POOL, BODY)
Definition: pool.h:328
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:109
uword unformat_pg_payload(unformat_input_t *input, va_list *args)
Definition: edit.c:127
always_inline uword pool_elts(void *v)
Definition: pool.h:97
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:953
static clib_error_t * del_stream(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:369
u32 buffer_bytes
Definition: pg.h:121
#define pool_elt_at_index(p, i)
Definition: pool.h:346
#define VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES
Definition: buffer.h:297
u8 * name
Definition: pg.h:93
#define clib_error_create(args...)
Definition: error.h:109
pg_node_t * nodes
Definition: pg.h:310
#define PG_STREAM_FLAGS_DISABLE_BUFFER_RECYCLE
Definition: pg.h:99
unformat_function_t unformat_hash_vec_string
Definition: hash.h:637
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:538
static clib_error_t * validate_stream(pg_stream_t *s)
Definition: cli.c:217
clib_error_t * pcap_read(pcap_main_t *pm)
Definition: pcap.c:142
static clib_error_t * new_stream(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:233
uword function_arg
Definition: cli.h:101
static clib_error_t * pg_pcap_read(pg_stream_t *s, char *file_name)
Definition: cli.c:167
unformat_function_t unformat_eof
Definition: format.h:289
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:298
u32 min_packet_bytes
Definition: pg.h:108
u32 max_packet_bytes
Definition: pg.h:108
unformat_function_t * unformat_edit
Definition: pg.h:290
always_inline vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
u8 ** replay_packet_templates
Definition: pg.h:160
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:150
pg_stream_t * streams
Definition: pg.h:298
unsigned int u32
Definition: types.h:88
always_inline void pg_stream_free(pg_stream_t *s)
Definition: pg.h:183
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:87
always_inline int pg_stream_is_enabled(pg_stream_t *s)
Definition: pg.h:206
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:405
void pg_stream_enable_disable(pg_main_t *pg, pg_stream_t *s, int is_enable)
Definition: stream.c:44
Definition: pg.h:91
pg_main_t pg_main
Definition: init.c:44
u32 min_packet_bytes
Definition: pcap.h:131
static clib_error_t * enable_disable_stream(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:54
static clib_error_t * change_stream_parameters(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: cli.c:392
unformat_function_t unformat_input
Definition: format.h:273
u64 uword
Definition: types.h:112
u32 node_index
Definition: pg.h:138
Definition: defs.h:46
u32 sw_if_index[VLIB_N_RX_TX]
Definition: pg.h:135
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:140
unsigned char u8
Definition: types.h:56
unformat_function_t unformat_vlib_node
Definition: node_funcs.h:967
f64 rate_packets_per_second
Definition: pg.h:152
static clib_error_t * pg_cli_init(vlib_main_t *vm)
Definition: cli.c:435
u64 n_packets_generated
Definition: pg.h:144
u8 ** packets_read
Definition: pcap.h:129
#define clib_error_return(e, args...)
Definition: error.h:112
struct _unformat_input_t unformat_input_t
Definition: pg.h:288
Definition: defs.h:45
u32 flags
Definition: pg.h:95