blob: 0b06803d384b204e108bc1329bf405645276155b [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.h: VLIB packet generator
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#ifndef included_vlib_pg_h
41#define included_vlib_pg_h
42
43#include <vlib/vlib.h> /* for VLIB_N_RX_TX */
44#include <vnet/pg/edit.h>
Calvin71e97c62016-08-19 16:23:14 -040045#include <vppinfra/fifo.h> /* for buffer_fifo */
Dave Barach3ae28732018-11-16 17:19:00 -050046#include <vppinfra/pcap.h>
Damjan Marion3d9c86e2016-07-04 21:04:40 +020047#include <vnet/interface.h>
48
49extern vnet_device_class_t pg_dev_class;
Ed Warnickecb9cada2015-12-08 15:45:58 -070050
51struct pg_main_t;
52struct pg_stream_t;
53
Calvin71e97c62016-08-19 16:23:14 -040054typedef struct pg_edit_group_t
55{
Ed Warnickecb9cada2015-12-08 15:45:58 -070056 /* Edits in this group. */
Calvin71e97c62016-08-19 16:23:14 -040057 pg_edit_t *edits;
Ed Warnickecb9cada2015-12-08 15:45:58 -070058
59 /* Vector of non-fixed edits for this group. */
Calvin71e97c62016-08-19 16:23:14 -040060 pg_edit_t *non_fixed_edits;
Ed Warnickecb9cada2015-12-08 15:45:58 -070061
62 /* Fixed edits for this group. */
Calvin71e97c62016-08-19 16:23:14 -040063 u8 *fixed_packet_data;
64 u8 *fixed_packet_data_mask;
Ed Warnickecb9cada2015-12-08 15:45:58 -070065
66 /* Byte offset where packet data begins. */
67 u32 start_byte_offset;
68
69 /* Number of packet bytes for this edit group. */
70 u32 n_packet_bytes;
71
72 /* Function to perform miscellaneous edits (e.g. set IP checksum, ...). */
Calvin71e97c62016-08-19 16:23:14 -040073 void (*edit_function) (struct pg_main_t * pg,
74 struct pg_stream_t * s,
75 struct pg_edit_group_t * g,
76 u32 * buffers, u32 n_buffers);
Ed Warnickecb9cada2015-12-08 15:45:58 -070077
78 /* Opaque data for edit function's use. */
79 uword edit_function_opaque;
80} pg_edit_group_t;
81
82/* Packets are made of multiple buffers chained together.
83 This struct keeps track of data per-chain index. */
Calvin71e97c62016-08-19 16:23:14 -040084typedef struct
85{
Ed Warnickecb9cada2015-12-08 15:45:58 -070086 /* Vector of buffer edits for this stream and buffer index. */
Calvin71e97c62016-08-19 16:23:14 -040087 pg_edit_t *edits;
Ed Warnickecb9cada2015-12-08 15:45:58 -070088
89 /* Buffers pre-initialized with fixed buffer data for this stream. */
Calvin71e97c62016-08-19 16:23:14 -040090 u32 *buffer_fifo;
Ed Warnickecb9cada2015-12-08 15:45:58 -070091
Ed Warnickecb9cada2015-12-08 15:45:58 -070092} pg_buffer_index_t;
93
Calvin71e97c62016-08-19 16:23:14 -040094typedef struct pg_stream_t
95{
Ed Warnickecb9cada2015-12-08 15:45:58 -070096 /* Stream name. */
Calvin71e97c62016-08-19 16:23:14 -040097 u8 *name;
Ed Warnickecb9cada2015-12-08 15:45:58 -070098
99 u32 flags;
100
101 /* Stream is currently enabled. */
102#define PG_STREAM_FLAGS_IS_ENABLED (1 << 0)
103#define PG_STREAM_FLAGS_DISABLE_BUFFER_RECYCLE (1 << 1)
104
105 /* Edit groups are created by each protocol level (e.g. ethernet,
106 ip4, tcp, ...). */
Calvin71e97c62016-08-19 16:23:14 -0400107 pg_edit_group_t *edit_groups;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700108
109 pg_edit_type_t packet_size_edit_type;
110
111 /* Min/max packet size. */
112 u32 min_packet_bytes, max_packet_bytes;
113
114 /* Vector of non-fixed edits for this stream.
115 All fixed edits are performed and placed into fixed_packet_data. */
Calvin71e97c62016-08-19 16:23:14 -0400116 pg_edit_t *non_fixed_edits;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700117
118 /* Packet data with all fixed edits performed.
119 All packets in stream are initialized according with this data.
120 Mask specifies which bits of packet data are covered by fixed edits. */
Calvin71e97c62016-08-19 16:23:14 -0400121 u8 *fixed_packet_data, *fixed_packet_data_mask;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700122
123 /* Size to use for buffers. 0 means use buffers big enough
124 for max_packet_bytes. */
125 u32 buffer_bytes;
126
127 /* Last packet length if packet size edit type is increment. */
128 u32 last_increment_packet_size;
129
130 /* Index into main interface pool for this stream. */
131 u32 pg_if_index;
132
133 /* Interface used to mark packets for this stream. May be different
134 than hw/sw index from pg main interface pool. They will be
135 different if this stream is being used generate buffers as if
136 they were received on a non-pg interface. For example, suppose you
137 are trying to test vlan code and you want to generate buffers that
138 appear to come from an ethernet interface. */
139 u32 sw_if_index[VLIB_N_RX_TX];
140
141 /* Node where stream's buffers get put. */
142 u32 node_index;
143
Damjan Marion64034362016-11-07 22:19:55 +0100144 /* Worker thread index */
145 u32 worker_index;
146
Ed Warnickecb9cada2015-12-08 15:45:58 -0700147 /* Output next index to reach output node from stream input node. */
148 u32 next_index;
149
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200150 u32 if_id;
151
Ed Warnickecb9cada2015-12-08 15:45:58 -0700152 /* Number of packets currently generated. */
153 u64 n_packets_generated;
154
155 /* Stream is disabled when packet limit is reached.
156 Zero means no packet limit. */
157 u64 n_packets_limit;
158
159 /* Rate for this stream in packets/second.
160 Zero means unlimited rate. */
161 f64 rate_packets_per_second;
162
163 f64 time_last_generate;
164
165 f64 packet_accumulator;
166
Calvin71e97c62016-08-19 16:23:14 -0400167 pg_buffer_index_t *buffer_indices;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700168
Calvin71e97c62016-08-19 16:23:14 -0400169 u8 **replay_packet_templates;
Dave Barach78c56892018-05-16 11:34:35 -0400170 u64 *replay_packet_timestamps;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700171 u32 current_replay_packet_index;
172} pg_stream_t;
173
174always_inline void
175pg_buffer_index_free (pg_buffer_index_t * bi)
176{
177 vec_free (bi->edits);
178 clib_fifo_free (bi->buffer_fifo);
179}
180
181always_inline void
182pg_edit_group_free (pg_edit_group_t * g)
183{
Calvin71e97c62016-08-19 16:23:14 -0400184 pg_edit_t *e;
185 vec_foreach (e, g->edits) pg_edit_free (e);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700186 vec_free (g->edits);
187 vec_free (g->fixed_packet_data);
188 vec_free (g->fixed_packet_data_mask);
189}
190
191always_inline void
192pg_stream_free (pg_stream_t * s)
193{
Dave Barach78c56892018-05-16 11:34:35 -0400194 int i;
Calvin71e97c62016-08-19 16:23:14 -0400195 pg_edit_group_t *g;
196 pg_edit_t *e;
197 vec_foreach (e, s->non_fixed_edits) pg_edit_free (e);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700198 vec_free (s->non_fixed_edits);
Calvin71e97c62016-08-19 16:23:14 -0400199 vec_foreach (g, s->edit_groups) pg_edit_group_free (g);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700200 vec_free (s->edit_groups);
201 vec_free (s->fixed_packet_data);
202 vec_free (s->fixed_packet_data_mask);
203 vec_free (s->name);
Dave Barach78c56892018-05-16 11:34:35 -0400204 for (i = 0; i < vec_len (s->replay_packet_templates); i++)
205 vec_free (s->replay_packet_templates[i]);
206 vec_free (s->replay_packet_templates);
207 vec_free (s->replay_packet_timestamps);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208
209 {
Calvin71e97c62016-08-19 16:23:14 -0400210 pg_buffer_index_t *bi;
211 vec_foreach (bi, s->buffer_indices) pg_buffer_index_free (bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700212 vec_free (s->buffer_indices);
213 }
214}
215
216always_inline int
217pg_stream_is_enabled (pg_stream_t * s)
Calvin71e97c62016-08-19 16:23:14 -0400218{
219 return (s->flags & PG_STREAM_FLAGS_IS_ENABLED) != 0;
220}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700221
222always_inline pg_edit_group_t *
223pg_stream_get_group (pg_stream_t * s, u32 group_index)
Calvin71e97c62016-08-19 16:23:14 -0400224{
225 return vec_elt_at_index (s->edit_groups, group_index);
226}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700227
228always_inline void *
229pg_create_edit_group (pg_stream_t * s,
Calvin71e97c62016-08-19 16:23:14 -0400230 int n_edit_bytes, int n_packet_bytes, u32 * group_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700231{
Calvin71e97c62016-08-19 16:23:14 -0400232 pg_edit_group_t *g;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700233 int n_edits;
234
235 vec_add2 (s->edit_groups, g, 1);
236 if (group_index)
237 *group_index = g - s->edit_groups;
238
239 ASSERT (n_edit_bytes % sizeof (pg_edit_t) == 0);
240 n_edits = n_edit_bytes / sizeof (pg_edit_t);
241 vec_resize (g->edits, n_edits);
242
243 g->n_packet_bytes = n_packet_bytes;
244
245 return g->edits;
246}
247
248always_inline void *
249pg_add_edits (pg_stream_t * s, int n_edit_bytes, int n_packet_bytes,
250 u32 group_index)
251{
Calvin71e97c62016-08-19 16:23:14 -0400252 pg_edit_group_t *g = pg_stream_get_group (s, group_index);
253 pg_edit_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700254 int n_edits;
255 ASSERT (n_edit_bytes % sizeof (pg_edit_t) == 0);
256 n_edits = n_edit_bytes / sizeof (pg_edit_t);
257 vec_add2 (g->edits, e, n_edits);
258 g->n_packet_bytes += n_packet_bytes;
259 return e;
260}
261
262always_inline void *
263pg_get_edit_group (pg_stream_t * s, u32 group_index)
264{
Calvin71e97c62016-08-19 16:23:14 -0400265 pg_edit_group_t *g = pg_stream_get_group (s, group_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700266 return g->edits;
267}
268
269/* Number of bytes for all groups >= given group. */
270always_inline uword
271pg_edit_group_n_bytes (pg_stream_t * s, u32 group_index)
272{
Calvin71e97c62016-08-19 16:23:14 -0400273 pg_edit_group_t *g;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700274 uword n_bytes = 0;
275
276 for (g = s->edit_groups + group_index; g < vec_end (s->edit_groups); g++)
277 n_bytes += g->n_packet_bytes;
278 return n_bytes;
279}
280
281always_inline void
282pg_free_edit_group (pg_stream_t * s)
283{
284 uword i = vec_len (s->edit_groups) - 1;
Calvin71e97c62016-08-19 16:23:14 -0400285 pg_edit_group_t *g = pg_stream_get_group (s, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700286
287 pg_edit_group_free (g);
Dave Barachb7b92992018-10-17 10:38:51 -0400288 clib_memset (g, 0, sizeof (g[0]));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700289 _vec_len (s->edit_groups) = i;
290}
291
Calvin71e97c62016-08-19 16:23:14 -0400292typedef struct
293{
Damjan Marion64034362016-11-07 22:19:55 +0100294 /* TX lock */
295 volatile u32 *lockp;
296
Ed Warnickecb9cada2015-12-08 15:45:58 -0700297 /* VLIB interface indices. */
298 u32 hw_if_index, sw_if_index;
299
300 /* Identifies stream for this interface. */
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200301 u32 id;
302
303 pcap_main_t pcap_main;
Calvin71e97c62016-08-19 16:23:14 -0400304 u8 *pcap_file_name;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700305} pg_interface_t;
306
307/* Per VLIB node data. */
Calvin71e97c62016-08-19 16:23:14 -0400308typedef struct
309{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700310 /* Parser function indexed by node index. */
Calvin71e97c62016-08-19 16:23:14 -0400311 unformat_function_t *unformat_edit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700312} pg_node_t;
313
Calvin71e97c62016-08-19 16:23:14 -0400314typedef struct pg_main_t
315{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700316 /* Pool of streams. */
Calvin71e97c62016-08-19 16:23:14 -0400317 pg_stream_t *streams;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700318
319 /* Bitmap indicating which streams are currently enabled. */
Damjan Marion3a4ed392016-11-08 13:20:42 +0100320 uword **enabled_streams;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700321
322 /* Hash mapping name -> stream index. */
Calvin71e97c62016-08-19 16:23:14 -0400323 uword *stream_index_by_name;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700324
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200325 /* Pool of interfaces. */
Calvin71e97c62016-08-19 16:23:14 -0400326 pg_interface_t *interfaces;
327 uword *if_index_by_if_id;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700328
329 /* Per VLIB node information. */
Calvin71e97c62016-08-19 16:23:14 -0400330 pg_node_t *nodes;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700331} pg_main_t;
332
333/* Global main structure. */
334extern pg_main_t pg_main;
335
336/* Global node. */
337extern vlib_node_registration_t pg_input_node;
338
339/* Buffer generator input, output node functions. */
340vlib_node_function_t pg_input, pg_output;
341
342/* Stream add/delete. */
343void pg_stream_del (pg_main_t * pg, uword index);
344void pg_stream_add (pg_main_t * pg, pg_stream_t * s_init);
345
346/* Enable/disable stream. */
Calvin71e97c62016-08-19 16:23:14 -0400347void pg_stream_enable_disable (pg_main_t * pg, pg_stream_t * s,
348 int is_enable);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700349
350/* Find/create free packet-generator interface index. */
Damjan Marion3d9c86e2016-07-04 21:04:40 +0200351u32 pg_interface_add_or_get (pg_main_t * pg, uword stream_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700352
353always_inline pg_node_t *
354pg_get_node (uword node_index)
355{
Calvin71e97c62016-08-19 16:23:14 -0400356 pg_main_t *pg = &pg_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700357 vec_validate (pg->nodes, node_index);
358 return pg->nodes + node_index;
359}
360
361void pg_edit_group_get_fixed_packet_data (pg_stream_t * s,
362 u32 group_index,
Calvin71e97c62016-08-19 16:23:14 -0400363 void *fixed_packet_data,
364 void *fixed_packet_data_mask);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700365
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +0200366void pg_enable_disable (u32 stream_index, int is_enable);
367
Calvin71e97c62016-08-19 16:23:14 -0400368typedef struct
369{
370 u32 hw_if_index;
371 u32 dev_instance;
372 u8 is_enabled;
373 u8 *pcap_file_name;
374 u32 count;
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +0200375} pg_capture_args_t;
376
Calvin71e97c62016-08-19 16:23:14 -0400377clib_error_t *pg_capture (pg_capture_args_t * a);
Pavel Kotucek9e6ed6e2016-07-12 10:18:26 +0200378
Damjan Marionbfe4dfa2017-02-03 21:16:16 +0100379typedef struct
380{
381 vlib_buffer_t buffer;
382 u32 buffer_index;
383}
384pg_output_trace_t;
385
Ed Warnickecb9cada2015-12-08 15:45:58 -0700386#endif /* included_vlib_pg_h */
Calvin71e97c62016-08-19 16:23:14 -0400387
388/*
389 * fd.io coding-style-patch-verification: ON
390 *
391 * Local Variables:
392 * eval: (c-set-style "gnu")
393 * End:
394 */