blob: 3f2de2604b2cbe1c96a572a54c2d1fa4c51680cb [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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
Damjan Marion3d9c86e2016-07-04 21:04:40 +020040#include <sys/stat.h>
41
Ed Warnickecb9cada2015-12-08 15:45:58 -070042#include <vnet/vnet.h>
43#include <vnet/pg/pg.h>
44
Kingwel Xie42223472019-01-19 22:49:26 -050045#include <strings.h>
Dave Barach3ae28732018-11-16 17:19:00 -050046#include <vppinfra/pcap.h>
Kingwel Xie42223472019-01-19 22:49:26 -050047
Ed Warnickecb9cada2015-12-08 15:45:58 -070048
49/* Root of all packet generator cli commands. */
50VLIB_CLI_COMMAND (vlib_cli_pg_command, static) = {
51 .path = "packet-generator",
52 .short_help = "Packet generator commands",
53};
54
Calvin71e97c62016-08-19 16:23:14 -040055void
56pg_enable_disable (u32 stream_index, int is_enable)
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +020057{
Calvin71e97c62016-08-19 16:23:14 -040058 pg_main_t *pg = &pg_main;
59 pg_stream_t *s;
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +020060
Calvin71e97c62016-08-19 16:23:14 -040061 if (stream_index == ~0)
62 {
63 /* No stream specified: enable/disable all streams. */
Damjan Marionb2c31b62020-12-13 21:47:40 +010064 pool_foreach (s, pg->streams) {
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +020065 pg_stream_enable_disable (pg, s, is_enable);
Damjan Marionb2c31b62020-12-13 21:47:40 +010066 }
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +020067 }
Calvin71e97c62016-08-19 16:23:14 -040068 else
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +020069 {
Calvin71e97c62016-08-19 16:23:14 -040070 /* enable/disable specified stream. */
71 s = pool_elt_at_index (pg->streams, stream_index);
72 pg_stream_enable_disable (pg, s, is_enable);
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +020073 }
74}
75
Calvin71e97c62016-08-19 16:23:14 -040076clib_error_t *
77pg_capture (pg_capture_args_t * a)
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +020078{
Calvin71e97c62016-08-19 16:23:14 -040079 pg_main_t *pg = &pg_main;
80 pg_interface_t *pi;
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +020081
Calvin71e97c62016-08-19 16:23:14 -040082 if (a->is_enabled == 1)
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +020083 {
Calvin71e97c62016-08-19 16:23:14 -040084 struct stat sb;
Jakub Grajciardb863292020-01-30 14:14:15 +010085 if (stat (a->pcap_file_name, &sb) != -1)
Andrew Yourtchenkoe3cb1f92019-07-29 09:27:10 +000086 return clib_error_return (0, "pcap file '%s' already exists.",
Paul Vinciguerra9673e3e2019-05-10 20:41:08 -040087 a->pcap_file_name);
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +020088 }
89
Calvin71e97c62016-08-19 16:23:14 -040090 pi = pool_elt_at_index (pg->interfaces, a->dev_instance);
91 vec_free (pi->pcap_file_name);
Christian E. Hopps19871f22019-09-27 14:35:32 -040092 if ((pi->pcap_main.flags & PCAP_MAIN_INIT_DONE))
93 pcap_close (&pi->pcap_main);
Dave Barachb7b92992018-10-17 10:38:51 -040094 clib_memset (&pi->pcap_main, 0, sizeof (pi->pcap_main));
Christian E. Hopps19871f22019-09-27 14:35:32 -040095 pi->pcap_main.file_descriptor = -1;
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +020096
Calvin71e97c62016-08-19 16:23:14 -040097 if (a->is_enabled == 0)
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +020098 return 0;
Calvin71e97c62016-08-19 16:23:14 -040099
100 pi->pcap_file_name = a->pcap_file_name;
101 pi->pcap_main.file_name = (char *) pi->pcap_file_name;
102 pi->pcap_main.n_packets_to_capture = a->count;
103 pi->pcap_main.packet_type = PCAP_PACKET_TYPE_ethernet;
104
105 return 0;
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +0200106}
107
Ed Warnickecb9cada2015-12-08 15:45:58 -0700108static clib_error_t *
109enable_disable_stream (vlib_main_t * vm,
Calvin71e97c62016-08-19 16:23:14 -0400110 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700111{
Dave Barach7d31ab22019-05-08 19:18:18 -0400112 unformat_input_t _line_input, *line_input = &_line_input;
Calvin71e97c62016-08-19 16:23:14 -0400113 pg_main_t *pg = &pg_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700114 int is_enable = cmd->function_arg != 0;
115 u32 stream_index = ~0;
116
Dave Barach7d31ab22019-05-08 19:18:18 -0400117 if (!unformat_user (input, unformat_line_input, line_input))
118 goto doit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700119
Dave Barach7d31ab22019-05-08 19:18:18 -0400120 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
121 {
122 if (unformat (line_input, "%U", unformat_hash_vec_string,
123 pg->stream_index_by_name, &stream_index))
124 ;
125 else
126 return clib_error_create ("unknown input `%U'",
127 format_unformat_error, line_input);
128 }
129 unformat_free (line_input);
130
131doit:
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +0200132 pg_enable_disable (stream_index, is_enable);
133
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134 return 0;
135}
136
137VLIB_CLI_COMMAND (enable_streams_cli, static) = {
138 .path = "packet-generator enable-stream",
139 .short_help = "Enable packet generator streams",
140 .function = enable_disable_stream,
141 .function_arg = 1, /* is_enable */
142};
143
144VLIB_CLI_COMMAND (disable_streams_cli, static) = {
145 .path = "packet-generator disable-stream",
146 .short_help = "Disable packet generator streams",
147 .function = enable_disable_stream,
148 .function_arg = 0, /* is_enable */
149};
150
Calvin71e97c62016-08-19 16:23:14 -0400151static u8 *
Kingwel Xie42223472019-01-19 22:49:26 -0500152format_pg_edit_group (u8 * s, va_list * va)
153{
154 pg_edit_group_t *g = va_arg (*va, pg_edit_group_t *);
155
156 s =
157 format (s, "hdr-size %d, offset %d, ", g->n_packet_bytes,
158 g->start_byte_offset);
159 if (g->edit_function)
160 {
161 u8 *function_name;
162 u8 *junk_after_name;
163 function_name = format (0, "%U%c", format_clib_elf_symbol_with_address,
164 g->edit_function, 0);
165 junk_after_name = function_name;
166 while (*junk_after_name && *junk_after_name != ' ')
167 junk_after_name++;
168 *junk_after_name = 0;
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700169 s = format (s, "edit-function %s, ", function_name);
Kingwel Xie42223472019-01-19 22:49:26 -0500170 vec_free (function_name);
171 }
172
173 return s;
174}
175
176static u8 *
Calvin71e97c62016-08-19 16:23:14 -0400177format_pg_stream (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700178{
Calvin71e97c62016-08-19 16:23:14 -0400179 pg_stream_t *t = va_arg (*va, pg_stream_t *);
Kingwel Xie42223472019-01-19 22:49:26 -0500180 int verbose = va_arg (*va, int);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700181
Calvin71e97c62016-08-19 16:23:14 -0400182 if (!t)
Kingwel Xie42223472019-01-19 22:49:26 -0500183 return format (s, "%-16s%=12s%=16s%s",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700184 "Name", "Enabled", "Count", "Parameters");
185
Kingwel Xie42223472019-01-19 22:49:26 -0500186 s = format (s, "%-16v%=12s%=16Ld",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700187 t->name,
188 pg_stream_is_enabled (t) ? "Yes" : "No",
189 t->n_packets_generated);
190
Kingwel Xie42223472019-01-19 22:49:26 -0500191 int indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700192
Kingwel Xie42223472019-01-19 22:49:26 -0500193 s = format (s, "limit %Ld, ", t->n_packets_limit);
194 s = format (s, "rate %.2e pps, ", t->rate_packets_per_second);
195 s = format (s, "size %d%c%d, ",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700196 t->min_packet_bytes,
197 t->packet_size_edit_type == PG_EDIT_RANDOM ? '+' : '-',
198 t->max_packet_bytes);
Kingwel Xie42223472019-01-19 22:49:26 -0500199 s = format (s, "buffer-size %d, ", t->buffer_bytes);
200 s = format (s, "worker %d, ", t->worker_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700201
Kingwel Xie42223472019-01-19 22:49:26 -0500202 if (verbose)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700203 {
Kingwel Xie42223472019-01-19 22:49:26 -0500204 pg_edit_group_t *g;
Kingwel Xie42223472019-01-19 22:49:26 -0500205 vec_foreach (g, t->edit_groups)
206 {
207 s = format (s, "\n%U%U", format_white_space, indent, format_pg_edit_group, g);
208 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700209 }
210
211 return s;
212}
213
214static clib_error_t *
215show_streams (vlib_main_t * vm,
Calvin71e97c62016-08-19 16:23:14 -0400216 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700217{
Calvin71e97c62016-08-19 16:23:14 -0400218 pg_main_t *pg = &pg_main;
219 pg_stream_t *s;
Kingwel Xie42223472019-01-19 22:49:26 -0500220 int verbose = 0;
221
222 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
223 {
224 if (unformat (input, "verbose"))
225 verbose = 1;
226 else
227 break;
228 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700229
230 if (pool_elts (pg->streams) == 0)
231 {
232 vlib_cli_output (vm, "no streams currently defined");
233 goto done;
234 }
235
Kingwel Xie42223472019-01-19 22:49:26 -0500236 vlib_cli_output (vm, "%U", format_pg_stream, 0, 0);
Damjan Marionb2c31b62020-12-13 21:47:40 +0100237 pool_foreach (s, pg->streams) {
Kingwel Xie42223472019-01-19 22:49:26 -0500238 vlib_cli_output (vm, "%U", format_pg_stream, s, verbose);
Damjan Marionb2c31b62020-12-13 21:47:40 +0100239 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700240
Calvin71e97c62016-08-19 16:23:14 -0400241done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700242 return 0;
243}
244
245VLIB_CLI_COMMAND (show_streams_cli, static) = {
Kingwel Xie42223472019-01-19 22:49:26 -0500246 .path = "show packet-generator ",
247 .short_help = "show packet-generator [verbose]",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700248 .function = show_streams,
249};
250
251static clib_error_t *
Calvin71e97c62016-08-19 16:23:14 -0400252pg_pcap_read (pg_stream_t * s, char *file_name)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700253{
254#ifndef CLIB_UNIX
255 return clib_error_return (0, "no pcap support");
256#else
257 pcap_main_t pm;
Calvin71e97c62016-08-19 16:23:14 -0400258 clib_error_t *error;
Dave Barachb7b92992018-10-17 10:38:51 -0400259 clib_memset (&pm, 0, sizeof (pm));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700260 pm.file_name = file_name;
261 error = pcap_read (&pm);
262 s->replay_packet_templates = pm.packets_read;
Dave Barach78c56892018-05-16 11:34:35 -0400263 s->replay_packet_timestamps = pm.timestamps;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700264 s->min_packet_bytes = pm.min_packet_bytes;
265 s->max_packet_bytes = pm.max_packet_bytes;
266 s->buffer_bytes = pm.max_packet_bytes;
Damjan Marionddbdd4f2016-07-08 22:08:16 +0200267
268 if (s->n_packets_limit == 0)
269 s->n_packets_limit = vec_len (pm.packets_read);
270
Ed Warnickecb9cada2015-12-08 15:45:58 -0700271 return error;
272#endif /* CLIB_UNIX */
273}
274
275static uword
276unformat_pg_stream_parameter (unformat_input_t * input, va_list * args)
277{
Calvin71e97c62016-08-19 16:23:14 -0400278 pg_stream_t *s = va_arg (*args, pg_stream_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700279 f64 x;
280
281 if (unformat (input, "limit %f", &x))
282 s->n_packets_limit = x;
283
284 else if (unformat (input, "rate %f", &x))
285 s->rate_packets_per_second = x;
286
287 else if (unformat (input, "size %d-%d", &s->min_packet_bytes,
288 &s->max_packet_bytes))
289 s->packet_size_edit_type = PG_EDIT_INCREMENT;
290
291 else if (unformat (input, "size %d+%d", &s->min_packet_bytes,
292 &s->max_packet_bytes))
293 s->packet_size_edit_type = PG_EDIT_RANDOM;
294
295 else if (unformat (input, "buffer-size %d", &s->buffer_bytes))
296 ;
297
298 else
299 return 0;
300
301 return 1;
302}
303
304static clib_error_t *
305validate_stream (pg_stream_t * s)
306{
307 if (s->max_packet_bytes < s->min_packet_bytes)
308 return clib_error_create ("max-size < min-size");
309
Kingwel Xie42223472019-01-19 22:49:26 -0500310 u32 hdr_size = pg_edit_group_n_bytes (s, 0);
311 if (s->min_packet_bytes < hdr_size)
312 return clib_error_create ("min-size < total header size %d", hdr_size);
313 if (s->buffer_bytes == 0)
314 return clib_error_create ("buffer-size must be positive");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700315
316 if (s->rate_packets_per_second < 0)
317 return clib_error_create ("negative rate");
318
319 return 0;
320}
321
Neale Ranns6197cb72021-06-03 14:43:21 +0000322const char *
323pg_interface_get_input_node (pg_interface_t *pi)
324{
325 switch (pi->mode)
326 {
327 case PG_MODE_ETHERNET:
328 return ("ethernet-input");
329 case PG_MODE_IP4:
330 return ("ip4-input");
331 case PG_MODE_IP6:
332 return ("ip6-input");
333 }
334
335 ASSERT (0);
336 return ("ethernet-input");
337}
338
Ed Warnickecb9cada2015-12-08 15:45:58 -0700339static clib_error_t *
340new_stream (vlib_main_t * vm,
Calvin71e97c62016-08-19 16:23:14 -0400341 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700342{
Calvin71e97c62016-08-19 16:23:14 -0400343 clib_error_t *error = 0;
344 u8 *tmp = 0;
Christian E. Hopps87d7bac2019-09-27 12:59:30 -0400345 u32 maxframe, hw_if_index;
Calvin71e97c62016-08-19 16:23:14 -0400346 unformat_input_t sub_input = { 0 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700347 int sub_input_given = 0;
Calvin71e97c62016-08-19 16:23:14 -0400348 vnet_main_t *vnm = vnet_get_main ();
349 pg_main_t *pg = &pg_main;
350 pg_stream_t s = { 0 };
351 char *pcap_file_name;
352
Ed Warnickecb9cada2015-12-08 15:45:58 -0700353 s.sw_if_index[VLIB_RX] = s.sw_if_index[VLIB_TX] = ~0;
354 s.node_index = ~0;
355 s.max_packet_bytes = s.min_packet_bytes = 64;
Damjan Marion8934a042019-02-09 23:29:26 +0100356 s.buffer_bytes = vlib_buffer_get_default_data_size (vm);
Neale Ranns6197cb72021-06-03 14:43:21 +0000357 s.if_id = ~0;
Christian E. Hopps87d7bac2019-09-27 12:59:30 -0400358 s.n_max_frame = VLIB_FRAME_SIZE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700359 pcap_file_name = 0;
Christian E. Hopps87d7bac2019-09-27 12:59:30 -0400360
Ed Warnickecb9cada2015-12-08 15:45:58 -0700361 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
362 {
363 if (unformat (input, "name %v", &tmp))
364 {
365 if (s.name)
366 vec_free (s.name);
367 s.name = tmp;
368 }
369
370 else if (unformat (input, "node %U",
371 unformat_vnet_hw_interface, vnm, &hw_if_index))
372 {
Calvin71e97c62016-08-19 16:23:14 -0400373 vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700374
375 s.node_index = hi->output_node_index;
376 s.sw_if_index[VLIB_TX] = hi->sw_if_index;
377 }
378
Calvin71e97c62016-08-19 16:23:14 -0400379 else if (unformat (input, "source pg%u", &s.if_id))
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200380 ;
381
Dave Barach08eb2bb2020-04-15 09:34:43 -0400382 else if (unformat (input, "buffer-flags %U",
383 unformat_vnet_buffer_flags, &s.buffer_flags))
384 ;
Mohsin Kazmi68095382021-02-10 11:26:24 +0100385 else if (unformat (input, "buffer-offload-flags %U",
386 unformat_vnet_buffer_offload_flags, &s.buffer_oflags))
387 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700388 else if (unformat (input, "node %U",
389 unformat_vlib_node, vm, &s.node_index))
390 ;
Christian E. Hopps87d7bac2019-09-27 12:59:30 -0400391 else if (unformat (input, "maxframe %u", &maxframe))
392 s.n_max_frame = s.n_max_frame < maxframe ? s.n_max_frame : maxframe;
Damjan Marion64034362016-11-07 22:19:55 +0100393 else if (unformat (input, "worker %u", &s.worker_index))
394 ;
395
Ed Warnickecb9cada2015-12-08 15:45:58 -0700396 else if (unformat (input, "interface %U",
Calvin71e97c62016-08-19 16:23:14 -0400397 unformat_vnet_sw_interface, vnm,
398 &s.sw_if_index[VLIB_RX]))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700399 ;
Dave Barach7d31ab22019-05-08 19:18:18 -0400400 else if (unformat (input, "tx-interface %U",
401 unformat_vnet_sw_interface, vnm,
402 &s.sw_if_index[VLIB_TX]))
403 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700404
405 else if (unformat (input, "pcap %s", &pcap_file_name))
406 ;
407
Calvin71e97c62016-08-19 16:23:14 -0400408 else if (!sub_input_given
Ed Warnickecb9cada2015-12-08 15:45:58 -0700409 && unformat (input, "data %U", unformat_input, &sub_input))
410 sub_input_given++;
Calvin71e97c62016-08-19 16:23:14 -0400411
Ed Warnickecb9cada2015-12-08 15:45:58 -0700412 else if (unformat_user (input, unformat_pg_stream_parameter, &s))
413 ;
414
Ed Warnickecb9cada2015-12-08 15:45:58 -0700415 else
416 {
417 error = clib_error_create ("unknown input `%U'",
418 format_unformat_error, input);
419 goto done;
420 }
421 }
422
Calvin71e97c62016-08-19 16:23:14 -0400423 if (!sub_input_given && !pcap_file_name)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700424 {
425 error = clib_error_create ("no packet data given");
426 goto done;
427 }
428
429 if (s.node_index == ~0)
430 {
Damjan Marionddbdd4f2016-07-08 22:08:16 +0200431 if (pcap_file_name != 0)
432 {
Neale Ranns6197cb72021-06-03 14:43:21 +0000433 vlib_node_t *n;
434
Neale Ranns6197cb72021-06-03 14:43:21 +0000435 if (s.if_id != ~0)
436 n = vlib_get_node_by_name (vm, (u8 *) pg_interface_get_input_node (
437 &pg->interfaces[s.if_id]));
438 else
439 n = vlib_get_node_by_name (vm, (u8 *) "ethernet-input");
Damjan Marionddbdd4f2016-07-08 22:08:16 +0200440 s.node_index = n->index;
441 }
442 else
443 {
444 error = clib_error_create ("output interface or node not given");
445 goto done;
446 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700447 }
448
449 {
Calvin71e97c62016-08-19 16:23:14 -0400450 pg_node_t *n;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700451
452 if (s.node_index < vec_len (pg->nodes))
453 n = pg->nodes + s.node_index;
454 else
455 n = 0;
456
Damjan Marion64034362016-11-07 22:19:55 +0100457 if (s.worker_index >= vlib_num_workers ())
458 s.worker_index = 0;
459
Ed Warnickecb9cada2015-12-08 15:45:58 -0700460 if (pcap_file_name != 0)
461 {
462 error = pg_pcap_read (&s, pcap_file_name);
463 if (error)
464 goto done;
465 vec_free (pcap_file_name);
466 }
467
468 else if (n && n->unformat_edit
Calvin71e97c62016-08-19 16:23:14 -0400469 && unformat_user (&sub_input, n->unformat_edit, &s))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700470 ;
471
Calvin71e97c62016-08-19 16:23:14 -0400472 else if (!unformat_user (&sub_input, unformat_pg_payload, &s))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700473 {
474 error = clib_error_create
475 ("failed to parse packet data from `%U'",
476 format_unformat_error, &sub_input);
477 goto done;
478 }
479 }
480
Kingwel Xie42223472019-01-19 22:49:26 -0500481 error = validate_stream (&s);
482 if (error)
483 return error;
484
Ed Warnickecb9cada2015-12-08 15:45:58 -0700485 pg_stream_add (pg, &s);
486 return 0;
487
Calvin71e97c62016-08-19 16:23:14 -0400488done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700489 pg_stream_free (&s);
490 unformat_free (&sub_input);
491 return error;
492}
493
494VLIB_CLI_COMMAND (new_stream_cli, static) = {
495 .path = "packet-generator new",
496 .function = new_stream,
497 .short_help = "Create packet generator stream",
498 .long_help =
499 "Create packet generator stream\n"
500 "\n"
501 "Arguments:\n"
502 "\n"
503 "name STRING sets stream name\n"
504 "interface STRING interface for stream output \n"
505 "node NODE-NAME node for stream output\n"
Damjan Marionddbdd4f2016-07-08 22:08:16 +0200506 "data STRING specifies packet data\n"
Christian E. Hopps87d7bac2019-09-27 12:59:30 -0400507 "pcap FILENAME read packet data from pcap file\n"
508 "rate PPS rate to transfer packet data\n"
509 "maxframe NPKTS maximum number of packets per frame\n",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700510};
511
512static clib_error_t *
513del_stream (vlib_main_t * vm,
Calvin71e97c62016-08-19 16:23:14 -0400514 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700515{
Calvin71e97c62016-08-19 16:23:14 -0400516 pg_main_t *pg = &pg_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700517 u32 i;
Calvin71e97c62016-08-19 16:23:14 -0400518
519 if (!unformat (input, "%U",
520 &unformat_hash_vec_string, pg->stream_index_by_name, &i))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700521 return clib_error_create ("expected stream name `%U'",
522 format_unformat_error, input);
523
524 pg_stream_del (pg, i);
525 return 0;
526}
527
528VLIB_CLI_COMMAND (del_stream_cli, static) = {
529 .path = "packet-generator delete",
530 .function = del_stream,
531 .short_help = "Delete stream with given name",
532};
533
534static clib_error_t *
535change_stream_parameters (vlib_main_t * vm,
Calvin71e97c62016-08-19 16:23:14 -0400536 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700537{
Calvin71e97c62016-08-19 16:23:14 -0400538 pg_main_t *pg = &pg_main;
539 pg_stream_t *s, s_new;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700540 u32 stream_index = ~0;
Calvin71e97c62016-08-19 16:23:14 -0400541 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700542
543 if (unformat (input, "%U", unformat_hash_vec_string,
544 pg->stream_index_by_name, &stream_index))
545 ;
546 else
547 return clib_error_create ("expecting stream name; got `%U'",
548 format_unformat_error, input);
549
550 s = pool_elt_at_index (pg->streams, stream_index);
551 s_new = s[0];
552
553 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
554 {
555 if (unformat_user (input, unformat_pg_stream_parameter, &s_new))
556 ;
557
558 else
559 return clib_error_create ("unknown input `%U'",
560 format_unformat_error, input);
561 }
562
563 error = validate_stream (&s_new);
Calvin71e97c62016-08-19 16:23:14 -0400564 if (!error)
Kingwel Xie42223472019-01-19 22:49:26 -0500565 {
566 s[0] = s_new;
567 pg_stream_change (pg, s);
568 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700569
570 return error;
571}
572
573VLIB_CLI_COMMAND (change_stream_parameters_cli, static) = {
574 .path = "packet-generator configure",
575 .short_help = "Change packet generator stream parameters",
576 .function = change_stream_parameters,
577};
578
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200579static clib_error_t *
580pg_capture_cmd_fn (vlib_main_t * vm,
Calvin71e97c62016-08-19 16:23:14 -0400581 unformat_input_t * input, vlib_cli_command_t * cmd)
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200582{
Calvin71e97c62016-08-19 16:23:14 -0400583 clib_error_t *error = 0;
584 vnet_main_t *vnm = vnet_get_main ();
585 unformat_input_t _line_input, *line_input = &_line_input;
586 vnet_hw_interface_t *hi = 0;
587 u8 *pcap_file_name = 0;
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200588 u32 hw_if_index;
Damjan Marion92217f32016-07-12 21:58:19 +0200589 u32 is_disable = 0;
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200590 u32 count = ~0;
591
Calvin71e97c62016-08-19 16:23:14 -0400592 if (!unformat_user (input, unformat_line_input, line_input))
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200593 return 0;
594
595 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
596 {
597 if (unformat (line_input, "%U",
Calvin71e97c62016-08-19 16:23:14 -0400598 unformat_vnet_hw_interface, vnm, &hw_if_index))
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200599 {
600 hi = vnet_get_hw_interface (vnm, hw_if_index);
601 }
602
603 else if (unformat (line_input, "pcap %s", &pcap_file_name))
604 ;
605 else if (unformat (line_input, "count %u", &count))
606 ;
Damjan Marion92217f32016-07-12 21:58:19 +0200607 else if (unformat (line_input, "disable"))
608 is_disable = 1;
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200609
610 else
611 {
612 error = clib_error_create ("unknown input `%U'",
Billy McFalla9a20e72017-02-15 11:39:12 -0500613 format_unformat_error, line_input);
614 goto done;
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200615 }
616 }
617
618 if (!hi)
Billy McFalla9a20e72017-02-15 11:39:12 -0500619 {
620 error = clib_error_return (0, "Please specify interface name");
621 goto done;
622 }
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200623
624 if (hi->dev_class_index != pg_dev_class.index)
Billy McFalla9a20e72017-02-15 11:39:12 -0500625 {
626 error =
627 clib_error_return (0, "Please specify packet-generator interface");
628 goto done;
629 }
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200630
Damjan Marion92217f32016-07-12 21:58:19 +0200631 if (!pcap_file_name && is_disable == 0)
Billy McFalla9a20e72017-02-15 11:39:12 -0500632 {
633 error = clib_error_return (0, "Please specify pcap file name");
634 goto done;
635 }
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200636
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200637
Calvin71e97c62016-08-19 16:23:14 -0400638 pg_capture_args_t _a, *a = &_a;
Damjan Marion92217f32016-07-12 21:58:19 +0200639
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +0200640 a->hw_if_index = hw_if_index;
641 a->dev_instance = hi->dev_instance;
642 a->is_enabled = !is_disable;
Jakub Grajciardb863292020-01-30 14:14:15 +0100643 a->pcap_file_name = (char *) pcap_file_name;
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +0200644 a->count = count;
Damjan Marion92217f32016-07-12 21:58:19 +0200645
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +0200646 error = pg_capture (a);
Billy McFalla9a20e72017-02-15 11:39:12 -0500647
648done:
649 unformat_free (line_input);
650
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +0200651 return error;
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200652}
653
654VLIB_CLI_COMMAND (pg_capture_cmd, static) = {
655 .path = "packet-generator capture",
656 .short_help = "packet-generator capture <interface name> pcap <filename> [count <n>]",
657 .function = pg_capture_cmd_fn,
658};
659
660static clib_error_t *
661create_pg_if_cmd_fn (vlib_main_t * vm,
Calvin71e97c62016-08-19 16:23:14 -0400662 unformat_input_t * input, vlib_cli_command_t * cmd)
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200663{
Calvin71e97c62016-08-19 16:23:14 -0400664 pg_main_t *pg = &pg_main;
665 unformat_input_t _line_input, *line_input = &_line_input;
Maxime Peim7217dcd2024-02-19 11:26:23 +0100666 u32 if_id = ~0, gso_enabled = 0, gso_size = 0, coalesce_enabled = 0;
Billy McFalla9a20e72017-02-15 11:39:12 -0500667 clib_error_t *error = NULL;
Mohsin Kazmi59183e92022-03-04 16:05:01 +0100668 pg_interface_mode_t mode = PG_MODE_ETHERNET;
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200669
Calvin71e97c62016-08-19 16:23:14 -0400670 if (!unformat_user (input, unformat_line_input, line_input))
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200671 return 0;
672
673 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
674 {
675 if (unformat (line_input, "interface pg%u", &if_id))
676 ;
Ray Kinsellac99ab122021-03-12 14:29:48 +0000677 else if (unformat (line_input, "coalesce-enabled"))
678 coalesce_enabled = 1;
Mohsin Kazmi22e9cfd2019-07-23 11:54:48 +0200679 else if (unformat (line_input, "gso-enabled"))
680 {
681 gso_enabled = 1;
682 if (unformat (line_input, "gso-size %u", &gso_size))
683 ;
684 else
685 {
686 error = clib_error_create ("gso enabled but gso size missing");
687 goto done;
688 }
689 }
Mohsin Kazmi59183e92022-03-04 16:05:01 +0100690 else if (unformat (line_input, "mode ip4"))
691 mode = PG_MODE_IP4;
692 else if (unformat (line_input, "mode ip6"))
693 mode = PG_MODE_IP6;
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200694 else
Billy McFalla9a20e72017-02-15 11:39:12 -0500695 {
696 error = clib_error_create ("unknown input `%U'",
697 format_unformat_error, line_input);
698 goto done;
699 }
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200700 }
701
Neale Ranns6197cb72021-06-03 14:43:21 +0000702 pg_interface_add_or_get (pg, if_id, gso_enabled, gso_size, coalesce_enabled,
Mohsin Kazmi59183e92022-03-04 16:05:01 +0100703 mode);
Billy McFalla9a20e72017-02-15 11:39:12 -0500704
705done:
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200706 unformat_free (line_input);
707
Billy McFalla9a20e72017-02-15 11:39:12 -0500708 return error;
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200709}
710
711VLIB_CLI_COMMAND (create_pg_if_cmd, static) = {
712 .path = "create packet-generator",
Mohsin Kazmif382b062020-08-11 15:00:44 +0200713 .short_help = "create packet-generator interface <interface name>"
Mohsin Kazmi59183e92022-03-04 16:05:01 +0100714 " [gso-enabled gso-size <size> [coalesce-enabled]]"
715 " [mode <ethernet | ip4 | ip6>]",
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200716 .function = create_pg_if_cmd_fn,
717};
718
Ed Warnickecb9cada2015-12-08 15:45:58 -0700719/* Dummy init function so that we can be linked in. */
Calvin71e97c62016-08-19 16:23:14 -0400720static clib_error_t *
721pg_cli_init (vlib_main_t * vm)
722{
723 return 0;
724}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700725
726VLIB_INIT_FUNCTION (pg_cli_init);
Calvin71e97c62016-08-19 16:23:14 -0400727
728/*
729 * fd.io coding-style-patch-verification: ON
730 *
731 * Local Variables:
732 * eval: (c-set-style "gnu")
733 * End:
734 */