pktgen: support mixed multi/single chunk pcap replay
[vpp.git] / src / vnet / pg / pg.h
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.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>
45 #include <vppinfra/fifo.h>      /* for buffer_fifo */
46 #include <vppinfra/pcap.h>
47 #include <vnet/interface.h>
48
49 extern vnet_device_class_t pg_dev_class;
50
51 struct pg_main_t;
52 struct pg_stream_t;
53
54 typedef struct pg_edit_group_t
55 {
56   /* Edits in this group. */
57   pg_edit_t *edits;
58
59   /* Vector of non-fixed edits for this group. */
60   pg_edit_t *non_fixed_edits;
61
62   /* Fixed edits for this group. */
63   u8 *fixed_packet_data;
64   u8 *fixed_packet_data_mask;
65
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, ...). */
73   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);
77
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. */
84 typedef struct
85 {
86   /* Vector of buffer edits for this stream and buffer index. */
87   pg_edit_t *edits;
88
89   /* Buffers pre-initialized with fixed buffer data for this stream. */
90   u32 *buffer_fifo;
91
92 } pg_buffer_index_t;
93
94 typedef struct pg_stream_t
95 {
96   /* Stream name. */
97   u8 *name;
98
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, ...). */
107   pg_edit_group_t *edit_groups;
108
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. */
116   pg_edit_t *non_fixed_edits;
117
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. */
121   u8 *fixed_packet_data, *fixed_packet_data_mask;
122
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
144   /* Worker thread index */
145   u32 worker_index;
146
147   /* Output next index to reach output node from stream input node. */
148   u32 next_index;
149
150   u32 if_id;
151
152   /* 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
167   pg_buffer_index_t *buffer_indices;
168
169   u8 **replay_packet_templates;
170   u64 *replay_packet_timestamps;
171   u32 current_replay_packet_index;
172 } pg_stream_t;
173
174 always_inline void
175 pg_buffer_index_free (pg_buffer_index_t * bi)
176 {
177   vec_free (bi->edits);
178   clib_fifo_free (bi->buffer_fifo);
179 }
180
181 always_inline void
182 pg_edit_group_free (pg_edit_group_t * g)
183 {
184   pg_edit_t *e;
185   vec_foreach (e, g->edits) pg_edit_free (e);
186   vec_free (g->edits);
187   vec_free (g->fixed_packet_data);
188   vec_free (g->fixed_packet_data_mask);
189 }
190
191 always_inline void
192 pg_stream_free (pg_stream_t * s)
193 {
194   int i;
195   pg_edit_group_t *g;
196   pg_edit_t *e;
197   vec_foreach (e, s->non_fixed_edits) pg_edit_free (e);
198   vec_free (s->non_fixed_edits);
199   vec_foreach (g, s->edit_groups) pg_edit_group_free (g);
200   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);
204   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);
208
209   {
210     pg_buffer_index_t *bi;
211     vec_foreach (bi, s->buffer_indices) pg_buffer_index_free (bi);
212     vec_free (s->buffer_indices);
213   }
214 }
215
216 always_inline int
217 pg_stream_is_enabled (pg_stream_t * s)
218 {
219   return (s->flags & PG_STREAM_FLAGS_IS_ENABLED) != 0;
220 }
221
222 always_inline pg_edit_group_t *
223 pg_stream_get_group (pg_stream_t * s, u32 group_index)
224 {
225   return vec_elt_at_index (s->edit_groups, group_index);
226 }
227
228 always_inline void *
229 pg_create_edit_group (pg_stream_t * s,
230                       int n_edit_bytes, int n_packet_bytes, u32 * group_index)
231 {
232   pg_edit_group_t *g;
233   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
248 always_inline void *
249 pg_add_edits (pg_stream_t * s, int n_edit_bytes, int n_packet_bytes,
250               u32 group_index)
251 {
252   pg_edit_group_t *g = pg_stream_get_group (s, group_index);
253   pg_edit_t *e;
254   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
262 always_inline void *
263 pg_get_edit_group (pg_stream_t * s, u32 group_index)
264 {
265   pg_edit_group_t *g = pg_stream_get_group (s, group_index);
266   return g->edits;
267 }
268
269 /* Number of bytes for all groups >= given group. */
270 always_inline uword
271 pg_edit_group_n_bytes (pg_stream_t * s, u32 group_index)
272 {
273   pg_edit_group_t *g;
274   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
281 always_inline void
282 pg_free_edit_group (pg_stream_t * s)
283 {
284   uword i = vec_len (s->edit_groups) - 1;
285   pg_edit_group_t *g = pg_stream_get_group (s, i);
286
287   pg_edit_group_free (g);
288   clib_memset (g, 0, sizeof (g[0]));
289   _vec_len (s->edit_groups) = i;
290 }
291
292 typedef struct
293 {
294   /* TX lock */
295   volatile u32 *lockp;
296
297   /* VLIB interface indices. */
298   u32 hw_if_index, sw_if_index;
299
300   /* Identifies stream for this interface. */
301   u32 id;
302
303   pcap_main_t pcap_main;
304   u8 *pcap_file_name;
305 } pg_interface_t;
306
307 /* Per VLIB node data. */
308 typedef struct
309 {
310   /* Parser function indexed by node index. */
311   unformat_function_t *unformat_edit;
312 } pg_node_t;
313
314 typedef struct pg_main_t
315 {
316   /* Pool of streams. */
317   pg_stream_t *streams;
318
319   /* Bitmap indicating which streams are currently enabled. */
320   uword **enabled_streams;
321
322   /* Hash mapping name -> stream index. */
323   uword *stream_index_by_name;
324
325   /* Pool of interfaces. */
326   pg_interface_t *interfaces;
327   uword *if_index_by_if_id;
328
329   /* Vector of buffer indices for use in pg_stream_fill_replay, per thread */
330   u32 **replay_buffers_by_thread;
331
332   /* Per VLIB node information. */
333   pg_node_t *nodes;
334 } pg_main_t;
335
336 /* Global main structure. */
337 extern pg_main_t pg_main;
338
339 /* Global node. */
340 extern vlib_node_registration_t pg_input_node;
341
342 /* Buffer generator input, output node functions. */
343 vlib_node_function_t pg_input, pg_output;
344
345 /* Stream add/delete. */
346 void pg_stream_del (pg_main_t * pg, uword index);
347 void pg_stream_add (pg_main_t * pg, pg_stream_t * s_init);
348
349 /* Enable/disable stream. */
350 void pg_stream_enable_disable (pg_main_t * pg, pg_stream_t * s,
351                                int is_enable);
352
353 /* Find/create free packet-generator interface index. */
354 u32 pg_interface_add_or_get (pg_main_t * pg, uword stream_index);
355
356 always_inline pg_node_t *
357 pg_get_node (uword node_index)
358 {
359   pg_main_t *pg = &pg_main;
360   vec_validate (pg->nodes, node_index);
361   return pg->nodes + node_index;
362 }
363
364 void pg_edit_group_get_fixed_packet_data (pg_stream_t * s,
365                                           u32 group_index,
366                                           void *fixed_packet_data,
367                                           void *fixed_packet_data_mask);
368
369 void pg_enable_disable (u32 stream_index, int is_enable);
370
371 typedef struct
372 {
373   u32 hw_if_index;
374   u32 dev_instance;
375   u8 is_enabled;
376   u8 *pcap_file_name;
377   u32 count;
378 } pg_capture_args_t;
379
380 clib_error_t *pg_capture (pg_capture_args_t * a);
381
382 typedef struct
383 {
384   vlib_buffer_t buffer;
385   u32 buffer_index;
386 }
387 pg_output_trace_t;
388
389 #endif /* included_vlib_pg_h */
390
391 /*
392  * fd.io coding-style-patch-verification: ON
393  *
394  * Local Variables:
395  * eval: (c-set-style "gnu")
396  * End:
397  */