Line data Source code
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 : #include <vnet/ethernet/mac_address.h>
49 : #include <vnet/gso/gro.h>
50 :
51 : extern vnet_device_class_t pg_dev_class;
52 :
53 : struct pg_main_t;
54 : struct pg_stream_t;
55 :
56 : typedef struct pg_edit_group_t
57 : {
58 : /* Edits in this group. */
59 : pg_edit_t *edits;
60 :
61 : /* Vector of non-fixed edits for this group. */
62 : pg_edit_t *non_fixed_edits;
63 :
64 : /* Fixed edits for this group. */
65 : u8 *fixed_packet_data;
66 : u8 *fixed_packet_data_mask;
67 :
68 : /* Byte offset where packet data begins. */
69 : u32 start_byte_offset;
70 :
71 : /* Number of packet bytes for this edit group. */
72 : u32 n_packet_bytes;
73 :
74 : /* Function to perform miscellaneous edits (e.g. set IP checksum, ...). */
75 : void (*edit_function) (struct pg_main_t * pg,
76 : struct pg_stream_t * s,
77 : struct pg_edit_group_t * g,
78 : u32 * buffers, u32 n_buffers);
79 :
80 : /* Opaque data for edit function's use. */
81 : uword edit_function_opaque;
82 : } pg_edit_group_t;
83 :
84 : /* Packets are made of multiple buffers chained together.
85 : This struct keeps track of data per-chain index. */
86 : typedef struct
87 : {
88 : /* Vector of buffer edits for this stream and buffer index. */
89 : pg_edit_t *edits;
90 :
91 : /* Buffers pre-initialized with fixed buffer data for this stream. */
92 : u32 *buffer_fifo;
93 :
94 : } pg_buffer_index_t;
95 :
96 : typedef struct pg_stream_t
97 : {
98 : /* Stream name. */
99 : u8 *name;
100 :
101 : u32 flags;
102 :
103 : /* Stream is currently enabled. */
104 : #define PG_STREAM_FLAGS_IS_ENABLED (1 << 0)
105 :
106 : /* Edit groups are created by each protocol level (e.g. ethernet,
107 : ip4, tcp, ...). */
108 : pg_edit_group_t *edit_groups;
109 :
110 : pg_edit_type_t packet_size_edit_type;
111 :
112 : /* Min/max packet size. */
113 : u32 min_packet_bytes, max_packet_bytes;
114 :
115 : /* Vector of non-fixed edits for this stream.
116 : All fixed edits are performed and placed into fixed_packet_data. */
117 : pg_edit_t *non_fixed_edits;
118 :
119 : /* Packet data with all fixed edits performed.
120 : All packets in stream are initialized according with this data.
121 : Mask specifies which bits of packet data are covered by fixed edits. */
122 : u8 *fixed_packet_data, *fixed_packet_data_mask;
123 :
124 : /* Size to use for buffers. 0 means use buffers big enough
125 : for max_packet_bytes. */
126 : u32 buffer_bytes;
127 :
128 : /* Buffer flags to set in each packet e.g. l2 valid flags */
129 : u32 buffer_flags;
130 :
131 : /* Buffer offload flags to set in each packet e.g. checksum offload flags */
132 : u32 buffer_oflags;
133 :
134 : /* Last packet length if packet size edit type is increment. */
135 : u32 last_increment_packet_size;
136 :
137 : /* Index into main interface pool for this stream. */
138 : u32 pg_if_index;
139 :
140 : /* Interface used to mark packets for this stream. May be different
141 : than hw/sw index from pg main interface pool. They will be
142 : different if this stream is being used generate buffers as if
143 : they were received on a non-pg interface. For example, suppose you
144 : are trying to test vlan code and you want to generate buffers that
145 : appear to come from an ethernet interface. */
146 : u32 sw_if_index[VLIB_N_RX_TX];
147 :
148 : /* Node where stream's buffers get put. */
149 : u32 node_index;
150 :
151 : /* Worker thread index */
152 : u32 worker_index;
153 :
154 : /* Output next index to reach output node from stream input node. */
155 : u32 next_index;
156 :
157 : u32 if_id;
158 :
159 : /* Number of packets currently generated. */
160 : u64 n_packets_generated;
161 :
162 : /* Stream is disabled when packet limit is reached.
163 : Zero means no packet limit. */
164 : u64 n_packets_limit;
165 :
166 : /* Only generate up to n_max_frame per frame. */
167 : u32 n_max_frame;
168 :
169 : /* Rate for this stream in packets/second.
170 : Zero means unlimited rate. */
171 : f64 rate_packets_per_second;
172 :
173 : f64 time_last_generate;
174 :
175 : f64 packet_accumulator;
176 :
177 : pg_buffer_index_t *buffer_indices;
178 :
179 : u8 **replay_packet_templates;
180 : u64 *replay_packet_timestamps;
181 : u32 current_replay_packet_index;
182 : } pg_stream_t;
183 :
184 : always_inline void
185 18660 : pg_buffer_index_free (pg_buffer_index_t * bi)
186 : {
187 18660 : vec_free (bi->edits);
188 18660 : clib_fifo_free (bi->buffer_fifo);
189 18660 : }
190 :
191 : always_inline void
192 1 : pg_edit_group_free (pg_edit_group_t * g)
193 : {
194 : pg_edit_t *e;
195 4 : vec_foreach (e, g->edits) pg_edit_free (e);
196 1 : vec_free (g->edits);
197 1 : vec_free (g->fixed_packet_data);
198 1 : vec_free (g->fixed_packet_data_mask);
199 1 : }
200 :
201 : always_inline void
202 15047 : pg_stream_free (pg_stream_t * s)
203 : {
204 : int i;
205 : pg_edit_group_t *g;
206 : pg_edit_t *e;
207 15047 : vec_foreach (e, s->non_fixed_edits) pg_edit_free (e);
208 15047 : vec_free (s->non_fixed_edits);
209 15047 : vec_foreach (g, s->edit_groups) pg_edit_group_free (g);
210 15047 : vec_free (s->edit_groups);
211 15047 : vec_free (s->fixed_packet_data);
212 15047 : vec_free (s->fixed_packet_data_mask);
213 15047 : vec_free (s->name);
214 543597 : for (i = 0; i < vec_len (s->replay_packet_templates); i++)
215 528550 : vec_free (s->replay_packet_templates[i]);
216 15047 : vec_free (s->replay_packet_templates);
217 15047 : vec_free (s->replay_packet_timestamps);
218 :
219 : {
220 : pg_buffer_index_t *bi;
221 33707 : vec_foreach (bi, s->buffer_indices) pg_buffer_index_free (bi);
222 15047 : vec_free (s->buffer_indices);
223 : }
224 15047 : }
225 :
226 : always_inline int
227 60309 : pg_stream_is_enabled (pg_stream_t * s)
228 : {
229 60309 : return (s->flags & PG_STREAM_FLAGS_IS_ENABLED) != 0;
230 : }
231 :
232 : always_inline pg_edit_group_t *
233 25 : pg_stream_get_group (pg_stream_t * s, u32 group_index)
234 : {
235 25 : return vec_elt_at_index (s->edit_groups, group_index);
236 : }
237 :
238 : always_inline void *
239 24 : pg_create_edit_group (pg_stream_t * s,
240 : int n_edit_bytes, int n_packet_bytes, u32 * group_index)
241 : {
242 : pg_edit_group_t *g;
243 : int n_edits;
244 :
245 24 : vec_add2 (s->edit_groups, g, 1);
246 24 : if (group_index)
247 18 : *group_index = g - s->edit_groups;
248 :
249 24 : ASSERT (n_edit_bytes % sizeof (pg_edit_t) == 0);
250 24 : n_edits = n_edit_bytes / sizeof (pg_edit_t);
251 24 : vec_resize (g->edits, n_edits);
252 :
253 24 : g->n_packet_bytes = n_packet_bytes;
254 :
255 24 : return g->edits;
256 : }
257 :
258 : always_inline void *
259 0 : pg_add_edits (pg_stream_t * s, int n_edit_bytes, int n_packet_bytes,
260 : u32 group_index)
261 : {
262 0 : pg_edit_group_t *g = pg_stream_get_group (s, group_index);
263 : pg_edit_t *e;
264 : int n_edits;
265 0 : ASSERT (n_edit_bytes % sizeof (pg_edit_t) == 0);
266 0 : n_edits = n_edit_bytes / sizeof (pg_edit_t);
267 0 : vec_add2 (g->edits, e, n_edits);
268 0 : g->n_packet_bytes += n_packet_bytes;
269 0 : return e;
270 : }
271 :
272 : always_inline void *
273 17 : pg_get_edit_group (pg_stream_t * s, u32 group_index)
274 : {
275 17 : pg_edit_group_t *g = pg_stream_get_group (s, group_index);
276 17 : return g->edits;
277 : }
278 :
279 : /* Number of bytes for all groups >= given group. */
280 : always_inline uword
281 15065 : pg_edit_group_n_bytes (pg_stream_t * s, u32 group_index)
282 : {
283 : pg_edit_group_t *g;
284 15065 : uword n_bytes = 0;
285 :
286 15122 : for (g = s->edit_groups + group_index; g < vec_end (s->edit_groups); g++)
287 57 : n_bytes += g->n_packet_bytes;
288 15065 : return n_bytes;
289 : }
290 :
291 : always_inline void
292 1 : pg_free_edit_group (pg_stream_t * s)
293 : {
294 1 : uword i = vec_len (s->edit_groups) - 1;
295 1 : pg_edit_group_t *g = pg_stream_get_group (s, i);
296 :
297 1 : pg_edit_group_free (g);
298 1 : clib_memset (g, 0, sizeof (g[0]));
299 1 : vec_set_len (s->edit_groups, i);
300 1 : }
301 :
302 : typedef enum pg_interface_mode_t_
303 : {
304 : PG_MODE_ETHERNET,
305 : PG_MODE_IP4,
306 : PG_MODE_IP6,
307 : } pg_interface_mode_t;
308 :
309 : typedef struct
310 : {
311 : /* TX lock */
312 : volatile u32 *lockp;
313 :
314 : /* VLIB interface indices. */
315 : u32 hw_if_index, sw_if_index;
316 :
317 : /* Identifies stream for this interface. */
318 : u32 id;
319 :
320 : u8 coalesce_enabled;
321 : gro_flow_table_t *flow_table;
322 : u8 gso_enabled;
323 : u32 gso_size;
324 : pcap_main_t pcap_main;
325 : char *pcap_file_name;
326 : pg_interface_mode_t mode;
327 :
328 : mac_address_t *allowed_mcast_macs;
329 : } pg_interface_t;
330 :
331 : /* Per VLIB node data. */
332 : typedef struct
333 : {
334 : /* Parser function indexed by node index. */
335 : unformat_function_t *unformat_edit;
336 : } pg_node_t;
337 :
338 : typedef struct pg_main_t
339 : {
340 : /* Pool of streams. */
341 : pg_stream_t *streams;
342 :
343 : /* Bitmap indicating which streams are currently enabled. */
344 : uword **enabled_streams;
345 :
346 : /* Hash mapping name -> stream index. */
347 : uword *stream_index_by_name;
348 :
349 : /* Pool of interfaces. */
350 : pg_interface_t *interfaces;
351 : uword *if_index_by_if_id;
352 : uword *if_id_by_sw_if_index;
353 :
354 : /* Vector of buffer indices for use in pg_stream_fill_replay, per thread */
355 : u32 **replay_buffers_by_thread;
356 :
357 : /* Per VLIB node information. */
358 : pg_node_t *nodes;
359 :
360 : u16 msg_id_base;
361 : } pg_main_t;
362 :
363 : /* Global main structure. */
364 : extern pg_main_t pg_main;
365 :
366 : /* Global node. */
367 : extern vlib_node_registration_t pg_input_node;
368 :
369 : /* Buffer generator input, output node functions. */
370 : vlib_node_function_t pg_input, pg_output;
371 :
372 : /* Stream add/delete. */
373 : void pg_stream_del (pg_main_t * pg, uword index);
374 : void pg_stream_add (pg_main_t * pg, pg_stream_t * s_init);
375 : void pg_stream_change (pg_main_t * pg, pg_stream_t * s);
376 :
377 : /* Enable/disable stream. */
378 : void pg_stream_enable_disable (pg_main_t * pg, pg_stream_t * s,
379 : int is_enable);
380 :
381 : /* Enable/disable packet coalesce on given interface */
382 : void pg_interface_enable_disable_coalesce (pg_interface_t * pi, u8 enable,
383 : u32 tx_node_index);
384 :
385 : /* Find/create free packet-generator interface index. */
386 : u32 pg_interface_add_or_get (pg_main_t *pg, uword stream_index, u8 gso_enabled,
387 : u32 gso_size, u8 coalesce_enabled,
388 : pg_interface_mode_t mode);
389 :
390 : always_inline pg_node_t *
391 17422 : pg_get_node (uword node_index)
392 : {
393 17422 : pg_main_t *pg = &pg_main;
394 17422 : vec_validate (pg->nodes, node_index);
395 17422 : return pg->nodes + node_index;
396 : }
397 :
398 : void pg_edit_group_get_fixed_packet_data (pg_stream_t * s,
399 : u32 group_index,
400 : void *fixed_packet_data,
401 : void *fixed_packet_data_mask);
402 :
403 : void pg_enable_disable (u32 stream_index, int is_enable);
404 :
405 : typedef struct
406 : {
407 : u32 hw_if_index;
408 : u32 dev_instance;
409 : u8 is_enabled;
410 : char *pcap_file_name;
411 : u32 count;
412 : } pg_capture_args_t;
413 :
414 : clib_error_t *pg_capture (pg_capture_args_t * a);
415 :
416 : typedef struct
417 : {
418 : u32 buffer_index;
419 : vlib_buffer_t buffer;
420 : }
421 : pg_output_trace_t;
422 :
423 : #endif /* included_vlib_pg_h */
424 :
425 : /*
426 : * fd.io coding-style-patch-verification: ON
427 : *
428 : * Local Variables:
429 : * eval: (c-set-style "gnu")
430 : * End:
431 : */
|