ethernet-input optimizations
[vpp.git] / src / vnet / pg / input.c
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_input.c: buffer generator input
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 <vlib/vlib.h>
41 #include <vnet/pg/pg.h>
42 #include <vnet/vnet.h>
43 #include <vnet/ethernet/ethernet.h>
44 #include <vnet/feature/feature.h>
45 #include <vnet/devices/devices.h>
46
47 static int
48 validate_buffer_data2 (vlib_buffer_t * b, pg_stream_t * s,
49                        u32 data_offset, u32 n_bytes)
50 {
51   u8 *bd, *pd, *pm;
52   u32 i;
53
54   bd = b->data;
55   pd = s->fixed_packet_data + data_offset;
56   pm = s->fixed_packet_data_mask + data_offset;
57
58   if (pd + n_bytes >= vec_end (s->fixed_packet_data))
59     n_bytes = (pd < vec_end (s->fixed_packet_data)
60                ? vec_end (s->fixed_packet_data) - pd : 0);
61
62   for (i = 0; i < n_bytes; i++)
63     if ((bd[i] & pm[i]) != pd[i])
64       break;
65
66   if (i >= n_bytes)
67     return 1;
68
69   clib_warning ("buffer %U", format_vnet_buffer, b);
70   clib_warning ("differ at index %d", i);
71   clib_warning ("is     %U", format_hex_bytes, bd, n_bytes);
72   clib_warning ("mask   %U", format_hex_bytes, pm, n_bytes);
73   clib_warning ("expect %U", format_hex_bytes, pd, n_bytes);
74   return 0;
75 }
76
77 static int
78 validate_buffer_data (vlib_buffer_t * b, pg_stream_t * s)
79 {
80   return validate_buffer_data2 (b, s, 0, s->buffer_bytes);
81 }
82
83 always_inline void
84 set_1 (void *a0,
85        u64 v0, u64 v_min, u64 v_max, u32 n_bits, u32 is_net_byte_order)
86 {
87   ASSERT (v0 >= v_min && v0 <= v_max);
88   if (n_bits == BITS (u8))
89     {
90       ((u8 *) a0)[0] = v0;
91     }
92   else if (n_bits == BITS (u16))
93     {
94       if (is_net_byte_order)
95         v0 = clib_host_to_net_u16 (v0);
96       clib_mem_unaligned (a0, u16) = v0;
97     }
98   else if (n_bits == BITS (u32))
99     {
100       if (is_net_byte_order)
101         v0 = clib_host_to_net_u32 (v0);
102       clib_mem_unaligned (a0, u32) = v0;
103     }
104   else if (n_bits == BITS (u64))
105     {
106       if (is_net_byte_order)
107         v0 = clib_host_to_net_u64 (v0);
108       clib_mem_unaligned (a0, u64) = v0;
109     }
110 }
111
112 always_inline void
113 set_2 (void *a0, void *a1,
114        u64 v0, u64 v1,
115        u64 v_min, u64 v_max,
116        u32 n_bits, u32 is_net_byte_order, u32 is_increment)
117 {
118   ASSERT (v0 >= v_min && v0 <= v_max);
119   ASSERT (v1 >= v_min && v1 <= (v_max + is_increment));
120   if (n_bits == BITS (u8))
121     {
122       ((u8 *) a0)[0] = v0;
123       ((u8 *) a1)[0] = v1;
124     }
125   else if (n_bits == BITS (u16))
126     {
127       if (is_net_byte_order)
128         {
129           v0 = clib_host_to_net_u16 (v0);
130           v1 = clib_host_to_net_u16 (v1);
131         }
132       clib_mem_unaligned (a0, u16) = v0;
133       clib_mem_unaligned (a1, u16) = v1;
134     }
135   else if (n_bits == BITS (u32))
136     {
137       if (is_net_byte_order)
138         {
139           v0 = clib_host_to_net_u32 (v0);
140           v1 = clib_host_to_net_u32 (v1);
141         }
142       clib_mem_unaligned (a0, u32) = v0;
143       clib_mem_unaligned (a1, u32) = v1;
144     }
145   else if (n_bits == BITS (u64))
146     {
147       if (is_net_byte_order)
148         {
149           v0 = clib_host_to_net_u64 (v0);
150           v1 = clib_host_to_net_u64 (v1);
151         }
152       clib_mem_unaligned (a0, u64) = v0;
153       clib_mem_unaligned (a1, u64) = v1;
154     }
155 }
156
157 static_always_inline void
158 do_set_fixed (pg_main_t * pg,
159               pg_stream_t * s,
160               u32 * buffers,
161               u32 n_buffers,
162               u32 n_bits,
163               u32 byte_offset, u32 is_net_byte_order, u64 v_min, u64 v_max)
164 {
165   vlib_main_t *vm = vlib_get_main ();
166
167   while (n_buffers >= 4)
168     {
169       vlib_buffer_t *b0, *b1, *b2, *b3;
170       void *a0, *a1;
171
172       b0 = vlib_get_buffer (vm, buffers[0]);
173       b1 = vlib_get_buffer (vm, buffers[1]);
174       b2 = vlib_get_buffer (vm, buffers[2]);
175       b3 = vlib_get_buffer (vm, buffers[3]);
176       buffers += 2;
177       n_buffers -= 2;
178
179       a0 = (void *) b0 + byte_offset;
180       a1 = (void *) b1 + byte_offset;
181       CLIB_PREFETCH ((void *) b2 + byte_offset, sizeof (v_min), WRITE);
182       CLIB_PREFETCH ((void *) b3 + byte_offset, sizeof (v_min), WRITE);
183
184       set_2 (a0, a1, v_min, v_min, v_min, v_max, n_bits, is_net_byte_order,
185              /* is_increment */ 0);
186
187       ASSERT (validate_buffer_data (b0, s));
188       ASSERT (validate_buffer_data (b1, s));
189     }
190
191   while (n_buffers > 0)
192     {
193       vlib_buffer_t *b0;
194       void *a0;
195
196       b0 = vlib_get_buffer (vm, buffers[0]);
197       buffers += 1;
198       n_buffers -= 1;
199
200       a0 = (void *) b0 + byte_offset;
201
202       set_1 (a0, v_min, v_min, v_max, n_bits, is_net_byte_order);
203
204       ASSERT (validate_buffer_data (b0, s));
205     }
206 }
207
208 static_always_inline u64
209 do_set_increment (pg_main_t * pg,
210                   pg_stream_t * s,
211                   u32 * buffers,
212                   u32 n_buffers,
213                   u32 n_bits,
214                   u32 byte_offset,
215                   u32 is_net_byte_order,
216                   u32 want_sum, u64 * sum_result, u64 v_min, u64 v_max, u64 v)
217 {
218   vlib_main_t *vm = vlib_get_main ();
219   u64 sum = 0;
220
221   ASSERT (v >= v_min && v <= v_max);
222
223   while (n_buffers >= 4)
224     {
225       vlib_buffer_t *b0, *b1, *b2, *b3;
226       void *a0, *a1;
227       u64 v_old;
228
229       b0 = vlib_get_buffer (vm, buffers[0]);
230       b1 = vlib_get_buffer (vm, buffers[1]);
231       b2 = vlib_get_buffer (vm, buffers[2]);
232       b3 = vlib_get_buffer (vm, buffers[3]);
233       buffers += 2;
234       n_buffers -= 2;
235
236       a0 = (void *) b0 + byte_offset;
237       a1 = (void *) b1 + byte_offset;
238       CLIB_PREFETCH ((void *) b2 + byte_offset, sizeof (v_min), WRITE);
239       CLIB_PREFETCH ((void *) b3 + byte_offset, sizeof (v_min), WRITE);
240
241       v_old = v;
242       v = v_old + 2;
243       v = v > v_max ? v_min : v;
244       set_2 (a0, a1,
245              v_old + 0, v_old + 1, v_min, v_max, n_bits, is_net_byte_order,
246              /* is_increment */ 1);
247
248       if (want_sum)
249         sum += 2 * v_old + 1;
250
251       if (PREDICT_FALSE (v_old + 1 > v_max))
252         {
253           if (want_sum)
254             sum -= 2 * v_old + 1;
255
256           v = v_old;
257           set_1 (a0, v + 0, v_min, v_max, n_bits, is_net_byte_order);
258           if (want_sum)
259             sum += v;
260           v += 1;
261
262           v = v > v_max ? v_min : v;
263           set_1 (a1, v + 0, v_min, v_max, n_bits, is_net_byte_order);
264           if (want_sum)
265             sum += v;
266           v += 1;
267         }
268
269       ASSERT (validate_buffer_data (b0, s));
270       ASSERT (validate_buffer_data (b1, s));
271     }
272
273   while (n_buffers > 0)
274     {
275       vlib_buffer_t *b0;
276       void *a0;
277       u64 v_old;
278
279       b0 = vlib_get_buffer (vm, buffers[0]);
280       buffers += 1;
281       n_buffers -= 1;
282
283       a0 = (void *) b0 + byte_offset;
284
285       v_old = v;
286       if (want_sum)
287         sum += v_old;
288       v += 1;
289       v = v > v_max ? v_min : v;
290
291       ASSERT (v_old >= v_min && v_old <= v_max);
292       set_1 (a0, v_old, v_min, v_max, n_bits, is_net_byte_order);
293
294       ASSERT (validate_buffer_data (b0, s));
295     }
296
297   if (want_sum)
298     *sum_result = sum;
299
300   return v;
301 }
302
303 static_always_inline void
304 do_set_random (pg_main_t * pg,
305                pg_stream_t * s,
306                u32 * buffers,
307                u32 n_buffers,
308                u32 n_bits,
309                u32 byte_offset,
310                u32 is_net_byte_order,
311                u32 want_sum, u64 * sum_result, u64 v_min, u64 v_max)
312 {
313   vlib_main_t *vm = vlib_get_main ();
314   u64 v_diff = v_max - v_min + 1;
315   u64 r_mask = max_pow2 (v_diff) - 1;
316   u64 v0, v1;
317   u64 sum = 0;
318   void *random_data;
319
320   random_data = clib_random_buffer_get_data
321     (&vm->random_buffer, n_buffers * n_bits / BITS (u8));
322
323   v0 = v1 = v_min;
324
325   while (n_buffers >= 4)
326     {
327       vlib_buffer_t *b0, *b1, *b2, *b3;
328       void *a0, *a1;
329       u64 r0 = 0, r1 = 0;       /* warnings be gone */
330
331       b0 = vlib_get_buffer (vm, buffers[0]);
332       b1 = vlib_get_buffer (vm, buffers[1]);
333       b2 = vlib_get_buffer (vm, buffers[2]);
334       b3 = vlib_get_buffer (vm, buffers[3]);
335       buffers += 2;
336       n_buffers -= 2;
337
338       a0 = (void *) b0 + byte_offset;
339       a1 = (void *) b1 + byte_offset;
340       CLIB_PREFETCH ((void *) b2 + byte_offset, sizeof (v_min), WRITE);
341       CLIB_PREFETCH ((void *) b3 + byte_offset, sizeof (v_min), WRITE);
342
343       switch (n_bits)
344         {
345 #define _(n)                                    \
346           case BITS (u##n):                     \
347             {                                   \
348               u##n * r = random_data;           \
349               r0 = r[0];                        \
350               r1 = r[1];                        \
351               random_data = r + 2;              \
352             }                                   \
353           break;
354
355           _(8);
356           _(16);
357           _(32);
358           _(64);
359
360 #undef _
361         }
362
363       /* Add power of 2 sized random number which may be out of range. */
364       v0 += r0 & r_mask;
365       v1 += r1 & r_mask;
366
367       /* Twice should be enough to reduce to v_min .. v_max range. */
368       v0 = v0 > v_max ? v0 - v_diff : v0;
369       v1 = v1 > v_max ? v1 - v_diff : v1;
370       v0 = v0 > v_max ? v0 - v_diff : v0;
371       v1 = v1 > v_max ? v1 - v_diff : v1;
372
373       if (want_sum)
374         sum += v0 + v1;
375
376       set_2 (a0, a1, v0, v1, v_min, v_max, n_bits, is_net_byte_order,
377              /* is_increment */ 0);
378
379       ASSERT (validate_buffer_data (b0, s));
380       ASSERT (validate_buffer_data (b1, s));
381     }
382
383   while (n_buffers > 0)
384     {
385       vlib_buffer_t *b0;
386       void *a0;
387       u64 r0 = 0;               /* warnings be gone */
388
389       b0 = vlib_get_buffer (vm, buffers[0]);
390       buffers += 1;
391       n_buffers -= 1;
392
393       a0 = (void *) b0 + byte_offset;
394
395       switch (n_bits)
396         {
397 #define _(n)                                    \
398           case BITS (u##n):                     \
399             {                                   \
400               u##n * r = random_data;           \
401               r0 = r[0];                        \
402               random_data = r + 1;              \
403             }                                   \
404           break;
405
406           _(8);
407           _(16);
408           _(32);
409           _(64);
410
411 #undef _
412         }
413
414       /* Add power of 2 sized random number which may be out of range. */
415       v0 += r0 & r_mask;
416
417       /* Twice should be enough to reduce to v_min .. v_max range. */
418       v0 = v0 > v_max ? v0 - v_diff : v0;
419       v0 = v0 > v_max ? v0 - v_diff : v0;
420
421       if (want_sum)
422         sum += v0;
423
424       set_1 (a0, v0, v_min, v_max, n_bits, is_net_byte_order);
425
426       ASSERT (validate_buffer_data (b0, s));
427     }
428
429   if (want_sum)
430     *sum_result = sum;
431 }
432
433 #define _(i,t)                                                  \
434   clib_mem_unaligned (a##i, t) =                                \
435     clib_host_to_net_##t ((clib_net_to_host_mem_##t (a##i) &~ mask)     \
436                           | (v##i << shift))
437
438 always_inline void
439 setbits_1 (void *a0,
440            u64 v0,
441            u64 v_min, u64 v_max,
442            u32 max_bits, u32 n_bits, u64 mask, u32 shift)
443 {
444   ASSERT (v0 >= v_min && v0 <= v_max);
445   if (max_bits == BITS (u8))
446     ((u8 *) a0)[0] = (((u8 *) a0)[0] & ~mask) | (v0 << shift);
447
448   else if (max_bits == BITS (u16))
449     {
450       _(0, u16);
451     }
452   else if (max_bits == BITS (u32))
453     {
454       _(0, u32);
455     }
456   else if (max_bits == BITS (u64))
457     {
458       _(0, u64);
459     }
460 }
461
462 always_inline void
463 setbits_2 (void *a0, void *a1,
464            u64 v0, u64 v1,
465            u64 v_min, u64 v_max,
466            u32 max_bits, u32 n_bits, u64 mask, u32 shift, u32 is_increment)
467 {
468   ASSERT (v0 >= v_min && v0 <= v_max);
469   ASSERT (v1 >= v_min && v1 <= v_max + is_increment);
470   if (max_bits == BITS (u8))
471     {
472       ((u8 *) a0)[0] = (((u8 *) a0)[0] & ~mask) | (v0 << shift);
473       ((u8 *) a1)[0] = (((u8 *) a1)[0] & ~mask) | (v1 << shift);
474     }
475
476   else if (max_bits == BITS (u16))
477     {
478       _(0, u16);
479       _(1, u16);
480     }
481   else if (max_bits == BITS (u32))
482     {
483       _(0, u32);
484       _(1, u32);
485     }
486   else if (max_bits == BITS (u64))
487     {
488       _(0, u64);
489       _(1, u64);
490     }
491 }
492
493 #undef _
494
495 static_always_inline void
496 do_setbits_fixed (pg_main_t * pg,
497                   pg_stream_t * s,
498                   u32 * buffers,
499                   u32 n_buffers,
500                   u32 max_bits,
501                   u32 n_bits,
502                   u32 byte_offset, u64 v_min, u64 v_max, u64 mask, u32 shift)
503 {
504   vlib_main_t *vm = vlib_get_main ();
505
506   while (n_buffers >= 4)
507     {
508       vlib_buffer_t *b0, *b1, *b2, *b3;
509       void *a0, *a1;
510
511       b0 = vlib_get_buffer (vm, buffers[0]);
512       b1 = vlib_get_buffer (vm, buffers[1]);
513       b2 = vlib_get_buffer (vm, buffers[2]);
514       b3 = vlib_get_buffer (vm, buffers[3]);
515       buffers += 2;
516       n_buffers -= 2;
517
518       a0 = (void *) b0 + byte_offset;
519       a1 = (void *) b1 + byte_offset;
520       CLIB_PREFETCH ((void *) b2 + byte_offset, sizeof (v_min), WRITE);
521       CLIB_PREFETCH ((void *) b3 + byte_offset, sizeof (v_min), WRITE);
522
523       setbits_2 (a0, a1,
524                  v_min, v_min, v_min, v_max, max_bits, n_bits, mask, shift,
525                  /* is_increment */ 0);
526
527       ASSERT (validate_buffer_data (b0, s));
528       ASSERT (validate_buffer_data (b1, s));
529     }
530
531   while (n_buffers > 0)
532     {
533       vlib_buffer_t *b0;
534       void *a0;
535
536       b0 = vlib_get_buffer (vm, buffers[0]);
537       buffers += 1;
538       n_buffers -= 1;
539
540       a0 = (void *) b0 + byte_offset;
541
542       setbits_1 (a0, v_min, v_min, v_max, max_bits, n_bits, mask, shift);
543       ASSERT (validate_buffer_data (b0, s));
544     }
545 }
546
547 static_always_inline u64
548 do_setbits_increment (pg_main_t * pg,
549                       pg_stream_t * s,
550                       u32 * buffers,
551                       u32 n_buffers,
552                       u32 max_bits,
553                       u32 n_bits,
554                       u32 byte_offset,
555                       u64 v_min, u64 v_max, u64 v, u64 mask, u32 shift)
556 {
557   vlib_main_t *vm = vlib_get_main ();
558
559   ASSERT (v >= v_min && v <= v_max);
560
561   while (n_buffers >= 4)
562     {
563       vlib_buffer_t *b0, *b1, *b2, *b3;
564       void *a0, *a1;
565       u64 v_old;
566
567       b0 = vlib_get_buffer (vm, buffers[0]);
568       b1 = vlib_get_buffer (vm, buffers[1]);
569       b2 = vlib_get_buffer (vm, buffers[2]);
570       b3 = vlib_get_buffer (vm, buffers[3]);
571       buffers += 2;
572       n_buffers -= 2;
573
574       a0 = (void *) b0 + byte_offset;
575       a1 = (void *) b1 + byte_offset;
576       CLIB_PREFETCH ((void *) b2 + byte_offset, sizeof (v_min), WRITE);
577       CLIB_PREFETCH ((void *) b3 + byte_offset, sizeof (v_min), WRITE);
578
579       v_old = v;
580       v = v_old + 2;
581       v = v > v_max ? v_min : v;
582       setbits_2 (a0, a1,
583                  v_old + 0, v_old + 1,
584                  v_min, v_max, max_bits, n_bits, mask, shift,
585                  /* is_increment */ 1);
586
587       if (PREDICT_FALSE (v_old + 1 > v_max))
588         {
589           v = v_old;
590           setbits_1 (a0, v + 0, v_min, v_max, max_bits, n_bits, mask, shift);
591           v += 1;
592
593           v = v > v_max ? v_min : v;
594           setbits_1 (a1, v + 0, v_min, v_max, max_bits, n_bits, mask, shift);
595           v += 1;
596         }
597       ASSERT (validate_buffer_data (b0, s));
598       ASSERT (validate_buffer_data (b1, s));
599     }
600
601   while (n_buffers > 0)
602     {
603       vlib_buffer_t *b0;
604       void *a0;
605       u64 v_old;
606
607       b0 = vlib_get_buffer (vm, buffers[0]);
608       buffers += 1;
609       n_buffers -= 1;
610
611       a0 = (void *) b0 + byte_offset;
612
613       v_old = v;
614       v = v_old + 1;
615       v = v > v_max ? v_min : v;
616
617       ASSERT (v_old >= v_min && v_old <= v_max);
618       setbits_1 (a0, v_old, v_min, v_max, max_bits, n_bits, mask, shift);
619
620       ASSERT (validate_buffer_data (b0, s));
621     }
622
623   return v;
624 }
625
626 static_always_inline void
627 do_setbits_random (pg_main_t * pg,
628                    pg_stream_t * s,
629                    u32 * buffers,
630                    u32 n_buffers,
631                    u32 max_bits,
632                    u32 n_bits,
633                    u32 byte_offset, u64 v_min, u64 v_max, u64 mask, u32 shift)
634 {
635   vlib_main_t *vm = vlib_get_main ();
636   u64 v_diff = v_max - v_min + 1;
637   u64 r_mask = max_pow2 (v_diff) - 1;
638   u64 v0, v1;
639   void *random_data;
640
641   random_data = clib_random_buffer_get_data
642     (&vm->random_buffer, n_buffers * max_bits / BITS (u8));
643   v0 = v1 = v_min;
644
645   while (n_buffers >= 4)
646     {
647       vlib_buffer_t *b0, *b1, *b2, *b3;
648       void *a0, *a1;
649       u64 r0 = 0, r1 = 0;       /* warnings be gone */
650
651       b0 = vlib_get_buffer (vm, buffers[0]);
652       b1 = vlib_get_buffer (vm, buffers[1]);
653       b2 = vlib_get_buffer (vm, buffers[2]);
654       b3 = vlib_get_buffer (vm, buffers[3]);
655       buffers += 2;
656       n_buffers -= 2;
657
658       a0 = (void *) b0 + byte_offset;
659       a1 = (void *) b1 + byte_offset;
660       CLIB_PREFETCH ((void *) b2 + byte_offset, sizeof (v_min), WRITE);
661       CLIB_PREFETCH ((void *) b3 + byte_offset, sizeof (v_min), WRITE);
662
663       switch (max_bits)
664         {
665 #define _(n)                                    \
666           case BITS (u##n):                     \
667             {                                   \
668               u##n * r = random_data;           \
669               r0 = r[0];                        \
670               r1 = r[1];                        \
671               random_data = r + 2;              \
672             }                                   \
673           break;
674
675           _(8);
676           _(16);
677           _(32);
678           _(64);
679
680 #undef _
681         }
682
683       /* Add power of 2 sized random number which may be out of range. */
684       v0 += r0 & r_mask;
685       v1 += r1 & r_mask;
686
687       /* Twice should be enough to reduce to v_min .. v_max range. */
688       v0 = v0 > v_max ? v0 - v_diff : v0;
689       v1 = v1 > v_max ? v1 - v_diff : v1;
690       v0 = v0 > v_max ? v0 - v_diff : v0;
691       v1 = v1 > v_max ? v1 - v_diff : v1;
692
693       setbits_2 (a0, a1, v0, v1, v_min, v_max, max_bits, n_bits, mask, shift,
694                  /* is_increment */ 0);
695
696       ASSERT (validate_buffer_data (b0, s));
697       ASSERT (validate_buffer_data (b1, s));
698     }
699
700   while (n_buffers > 0)
701     {
702       vlib_buffer_t *b0;
703       void *a0;
704       u64 r0 = 0;               /* warnings be gone */
705
706       b0 = vlib_get_buffer (vm, buffers[0]);
707       buffers += 1;
708       n_buffers -= 1;
709
710       a0 = (void *) b0 + byte_offset;
711
712       switch (max_bits)
713         {
714 #define _(n)                                    \
715           case BITS (u##n):                     \
716             {                                   \
717               u##n * r = random_data;           \
718               r0 = r[0];                        \
719               random_data = r + 1;              \
720             }                                   \
721           break;
722
723           _(8);
724           _(16);
725           _(32);
726           _(64);
727
728 #undef _
729         }
730
731       /* Add power of 2 sized random number which may be out of range. */
732       v0 += r0 & r_mask;
733
734       /* Twice should be enough to reduce to v_min .. v_max range. */
735       v0 = v0 > v_max ? v0 - v_diff : v0;
736       v0 = v0 > v_max ? v0 - v_diff : v0;
737
738       setbits_1 (a0, v0, v_min, v_max, max_bits, n_bits, mask, shift);
739
740       ASSERT (validate_buffer_data (b0, s));
741     }
742 }
743
744 static u64
745 do_it (pg_main_t * pg,
746        pg_stream_t * s,
747        u32 * buffers,
748        u32 n_buffers,
749        u32 lo_bit, u32 hi_bit,
750        u64 v_min, u64 v_max, u64 v, pg_edit_type_t edit_type)
751 {
752   u32 max_bits, l0, l1, h1, start_bit;
753
754   if (v_min == v_max)
755     edit_type = PG_EDIT_FIXED;
756
757   l0 = lo_bit / BITS (u8);
758   l1 = lo_bit % BITS (u8);
759   h1 = hi_bit % BITS (u8);
760
761   start_bit = l0 * BITS (u8);
762
763   max_bits = hi_bit - start_bit;
764   ASSERT (max_bits <= 64);
765
766 #define _(n)                                            \
767   case (n):                                             \
768     if (edit_type == PG_EDIT_INCREMENT)                 \
769       v = do_set_increment (pg, s, buffers, n_buffers,  \
770                             BITS (u##n),                \
771                             l0,                         \
772                             /* is_net_byte_order */ 1,  \
773                             /* want sum */ 0, 0,        \
774                             v_min, v_max,               \
775                             v);                         \
776     else if (edit_type == PG_EDIT_RANDOM)               \
777       do_set_random (pg, s, buffers, n_buffers,         \
778                      BITS (u##n),                       \
779                      l0,                                \
780                      /* is_net_byte_order */ 1,         \
781                      /* want sum */ 0, 0,               \
782                      v_min, v_max);                     \
783     else /* edit_type == PG_EDIT_FIXED */               \
784       do_set_fixed (pg, s, buffers, n_buffers,          \
785                     BITS (u##n),                        \
786                     l0,                                 \
787                     /* is_net_byte_order */ 1,          \
788                     v_min, v_max);                      \
789   goto done;
790
791   if (l1 == 0 && h1 == 0)
792     {
793       switch (max_bits)
794         {
795           _(8);
796           _(16);
797           _(32);
798           _(64);
799         }
800     }
801
802 #undef _
803
804   {
805     u64 mask;
806     u32 shift = l1;
807     u32 n_bits = max_bits;
808
809     max_bits = clib_max (max_pow2 (n_bits), 8);
810
811     mask = ((u64) 1 << (u64) n_bits) - 1;
812     mask &= ~(((u64) 1 << (u64) shift) - 1);
813
814     mask <<= max_bits - n_bits;
815     shift += max_bits - n_bits;
816
817     switch (max_bits)
818       {
819 #define _(n)                                                            \
820         case (n):                                                       \
821           if (edit_type == PG_EDIT_INCREMENT)                           \
822             v = do_setbits_increment (pg, s, buffers, n_buffers,        \
823                                       BITS (u##n), n_bits,              \
824                                       l0, v_min, v_max, v,              \
825                                       mask, shift);                     \
826           else if (edit_type == PG_EDIT_RANDOM)                         \
827             do_setbits_random (pg, s, buffers, n_buffers,               \
828                                BITS (u##n), n_bits,                     \
829                                l0, v_min, v_max,                        \
830                                mask, shift);                            \
831           else /* edit_type == PG_EDIT_FIXED */                         \
832             do_setbits_fixed (pg, s, buffers, n_buffers,                \
833                               BITS (u##n), n_bits,                      \
834                               l0, v_min, v_max,                         \
835                               mask, shift);                             \
836         goto done;
837
838         _(8);
839         _(16);
840         _(32);
841         _(64);
842
843 #undef _
844       }
845   }
846
847 done:
848   return v;
849 }
850
851 static void
852 pg_generate_set_lengths (pg_main_t * pg,
853                          pg_stream_t * s, u32 * buffers, u32 n_buffers)
854 {
855   u64 v_min, v_max, length_sum;
856   pg_edit_type_t edit_type;
857
858   v_min = s->min_packet_bytes;
859   v_max = s->max_packet_bytes;
860   edit_type = s->packet_size_edit_type;
861
862   if (edit_type == PG_EDIT_INCREMENT)
863     s->last_increment_packet_size
864       = do_set_increment (pg, s, buffers, n_buffers,
865                           8 * STRUCT_SIZE_OF (vlib_buffer_t, current_length),
866                           STRUCT_OFFSET_OF (vlib_buffer_t, current_length),
867                           /* is_net_byte_order */ 0,
868                           /* want sum */ 1, &length_sum,
869                           v_min, v_max, s->last_increment_packet_size);
870
871   else if (edit_type == PG_EDIT_RANDOM)
872     do_set_random (pg, s, buffers, n_buffers,
873                    8 * STRUCT_SIZE_OF (vlib_buffer_t, current_length),
874                    STRUCT_OFFSET_OF (vlib_buffer_t, current_length),
875                    /* is_net_byte_order */ 0,
876                    /* want sum */ 1, &length_sum,
877                    v_min, v_max);
878
879   else                          /* edit_type == PG_EDIT_FIXED */
880     {
881       do_set_fixed (pg, s, buffers, n_buffers,
882                     8 * STRUCT_SIZE_OF (vlib_buffer_t, current_length),
883                     STRUCT_OFFSET_OF (vlib_buffer_t, current_length),
884                     /* is_net_byte_order */ 0,
885                     v_min, v_max);
886       length_sum = v_min * n_buffers;
887     }
888
889   {
890     vnet_main_t *vnm = vnet_get_main ();
891     vnet_interface_main_t *im = &vnm->interface_main;
892     vnet_sw_interface_t *si =
893       vnet_get_sw_interface (vnm, s->sw_if_index[VLIB_RX]);
894
895     vlib_increment_combined_counter (im->combined_sw_if_counters
896                                      + VNET_INTERFACE_COUNTER_RX,
897                                      vlib_get_thread_index (),
898                                      si->sw_if_index, n_buffers, length_sum);
899   }
900
901 }
902
903 static void
904 pg_generate_fix_multi_buffer_lengths (pg_main_t * pg,
905                                       pg_stream_t * s,
906                                       u32 * buffers, u32 n_buffers)
907 {
908   vlib_main_t *vm = vlib_get_main ();
909   pg_buffer_index_t *pbi;
910   uword n_bytes_left;
911   static u32 *unused_buffers = 0;
912
913   while (n_buffers > 0)
914     {
915       vlib_buffer_t *b;
916       u32 bi;
917
918       bi = buffers[0];
919       b = vlib_get_buffer (vm, bi);
920
921       /* Current length here is length of whole packet. */
922       n_bytes_left = b->current_length;
923
924       pbi = s->buffer_indices;
925       while (1)
926         {
927           uword n = clib_min (n_bytes_left, s->buffer_bytes);
928
929           b->current_length = n;
930           n_bytes_left -= n;
931           if (n_bytes_left > 0)
932             b->flags |= VLIB_BUFFER_NEXT_PRESENT;
933           else
934             b->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
935
936           /* Return unused buffers to fifos. */
937           if (n == 0)
938             vec_add1 (unused_buffers, bi);
939
940           pbi++;
941           if (pbi >= vec_end (s->buffer_indices))
942             break;
943
944           bi = b->next_buffer;
945           b = vlib_get_buffer (vm, bi);
946         }
947       ASSERT (n_bytes_left == 0);
948
949       buffers += 1;
950       n_buffers -= 1;
951     }
952
953   if (vec_len (unused_buffers) > 0)
954     {
955       vlib_buffer_free_no_next (vm, unused_buffers, vec_len (unused_buffers));
956       _vec_len (unused_buffers) = 0;
957     }
958 }
959
960 static void
961 pg_generate_edit (pg_main_t * pg,
962                   pg_stream_t * s, u32 * buffers, u32 n_buffers)
963 {
964   pg_edit_t *e;
965
966   vec_foreach (e, s->non_fixed_edits)
967   {
968     switch (e->type)
969       {
970       case PG_EDIT_RANDOM:
971       case PG_EDIT_INCREMENT:
972         {
973           u32 lo_bit, hi_bit;
974           u64 v_min, v_max;
975
976           v_min = pg_edit_get_value (e, PG_EDIT_LO);
977           v_max = pg_edit_get_value (e, PG_EDIT_HI);
978
979           hi_bit = (BITS (u8) * STRUCT_OFFSET_OF (vlib_buffer_t, data)
980                     + BITS (u8) + e->lsb_bit_offset);
981           lo_bit = hi_bit - e->n_bits;
982
983           e->last_increment_value
984             = do_it (pg, s, buffers, n_buffers, lo_bit, hi_bit, v_min, v_max,
985                      e->last_increment_value, e->type);
986         }
987         break;
988
989       case PG_EDIT_UNSPECIFIED:
990         break;
991
992       default:
993         /* Should not be any fixed edits left. */
994         ASSERT (0);
995         break;
996       }
997   }
998
999   /* Call any edit functions to e.g. completely IP lengths, checksums, ... */
1000   {
1001     int i;
1002     for (i = vec_len (s->edit_groups) - 1; i >= 0; i--)
1003       {
1004         pg_edit_group_t *g = s->edit_groups + i;
1005         if (g->edit_function)
1006           g->edit_function (pg, s, g, buffers, n_buffers);
1007       }
1008   }
1009 }
1010
1011 static void
1012 pg_set_next_buffer_pointers (pg_main_t * pg,
1013                              pg_stream_t * s,
1014                              u32 * buffers, u32 * next_buffers, u32 n_buffers)
1015 {
1016   vlib_main_t *vm = vlib_get_main ();
1017
1018   while (n_buffers >= 4)
1019     {
1020       u32 ni0, ni1;
1021       vlib_buffer_t *b0, *b1;
1022
1023       b0 = vlib_get_buffer (vm, buffers[0]);
1024       b1 = vlib_get_buffer (vm, buffers[1]);
1025       ni0 = next_buffers[0];
1026       ni1 = next_buffers[1];
1027
1028       vlib_prefetch_buffer_with_index (vm, buffers[2], WRITE);
1029       vlib_prefetch_buffer_with_index (vm, buffers[3], WRITE);
1030
1031       b0->flags |= VLIB_BUFFER_NEXT_PRESENT;
1032       b1->flags |= VLIB_BUFFER_NEXT_PRESENT;
1033       b0->next_buffer = ni0;
1034       b1->next_buffer = ni1;
1035
1036       buffers += 2;
1037       next_buffers += 2;
1038       n_buffers -= 2;
1039     }
1040
1041   while (n_buffers > 0)
1042     {
1043       u32 ni0;
1044       vlib_buffer_t *b0;
1045
1046       b0 = vlib_get_buffer (vm, buffers[0]);
1047       ni0 = next_buffers[0];
1048       buffers += 1;
1049       next_buffers += 1;
1050       n_buffers -= 1;
1051
1052       b0->flags |= VLIB_BUFFER_NEXT_PRESENT;
1053       b0->next_buffer = ni0;
1054     }
1055 }
1056
1057 static_always_inline void
1058 init_replay_buffers_inline (vlib_main_t * vm,
1059                             pg_stream_t * s,
1060                             u32 * buffers,
1061                             u32 n_buffers, u32 data_offset, u32 n_data)
1062 {
1063   u32 n_left, *b, i, l;
1064
1065   n_left = n_buffers;
1066   b = buffers;
1067   i = s->current_replay_packet_index;
1068   l = vec_len (s->replay_packet_templates);
1069
1070   while (n_left >= 1)
1071     {
1072       u32 bi0, n0;
1073       vlib_buffer_t *b0;
1074       u8 *d0;
1075
1076       bi0 = b[0];
1077       b += 1;
1078       n_left -= 1;
1079
1080       b0 = vlib_get_buffer (vm, bi0);
1081
1082       vnet_buffer (b0)->sw_if_index[VLIB_RX] = s->sw_if_index[VLIB_RX];
1083       /* was s->sw_if_index[VLIB_TX]; */
1084       vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1085
1086       d0 = vec_elt (s->replay_packet_templates, i);
1087       vnet_buffer2 (b0)->pg_replay_timestamp = s->replay_packet_timestamps[i];
1088
1089       n0 = n_data;
1090       if (data_offset + n_data >= vec_len (d0))
1091         n0 = vec_len (d0) > data_offset ? vec_len (d0) - data_offset : 0;
1092
1093       b0->current_length = n0;
1094
1095       clib_memcpy_fast (b0->data, d0 + data_offset, n0);
1096       i = i + 1 == l ? 0 : i + 1;
1097     }
1098 }
1099
1100 static_always_inline void
1101 init_buffers_inline (vlib_main_t * vm,
1102                      pg_stream_t * s,
1103                      u32 * buffers,
1104                      u32 n_buffers, u32 data_offset, u32 n_data, u32 set_data)
1105 {
1106   u32 n_left, *b;
1107   u8 *data, *mask;
1108
1109   if (vec_len (s->replay_packet_templates) > 0)
1110     return init_replay_buffers_inline (vm, s, buffers, n_buffers, data_offset,
1111                                        n_data);
1112
1113   data = s->fixed_packet_data + data_offset;
1114   mask = s->fixed_packet_data_mask + data_offset;
1115   if (data + n_data >= vec_end (s->fixed_packet_data))
1116     n_data = (data < vec_end (s->fixed_packet_data)
1117               ? vec_end (s->fixed_packet_data) - data : 0);
1118   if (n_data > 0)
1119     {
1120       ASSERT (data + n_data <= vec_end (s->fixed_packet_data));
1121       ASSERT (mask + n_data <= vec_end (s->fixed_packet_data_mask));
1122     }
1123
1124   n_left = n_buffers;
1125   b = buffers;
1126
1127   while (n_left >= 4)
1128     {
1129       u32 bi0, bi1;
1130       vlib_buffer_t *b0, *b1;
1131
1132       /* Prefetch next iteration. */
1133       vlib_prefetch_buffer_with_index (vm, b[2], STORE);
1134       vlib_prefetch_buffer_with_index (vm, b[3], STORE);
1135
1136       bi0 = b[0];
1137       bi1 = b[1];
1138       b += 2;
1139       n_left -= 2;
1140
1141       b0 = vlib_get_buffer (vm, bi0);
1142       b1 = vlib_get_buffer (vm, bi1);
1143
1144       vnet_buffer (b0)->sw_if_index[VLIB_RX] =
1145         vnet_buffer (b1)->sw_if_index[VLIB_RX] = s->sw_if_index[VLIB_RX];
1146
1147       vnet_buffer (b0)->sw_if_index[VLIB_TX] =
1148         vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1149
1150       if (set_data)
1151         {
1152           clib_memcpy_fast (b0->data, data, n_data);
1153           clib_memcpy_fast (b1->data, data, n_data);
1154         }
1155       else
1156         {
1157           ASSERT (validate_buffer_data2 (b0, s, data_offset, n_data));
1158           ASSERT (validate_buffer_data2 (b1, s, data_offset, n_data));
1159         }
1160     }
1161
1162   while (n_left >= 1)
1163     {
1164       u32 bi0;
1165       vlib_buffer_t *b0;
1166
1167       bi0 = b[0];
1168       b += 1;
1169       n_left -= 1;
1170
1171       b0 = vlib_get_buffer (vm, bi0);
1172       vnet_buffer (b0)->sw_if_index[VLIB_RX] = s->sw_if_index[VLIB_RX];
1173       /* s->sw_if_index[VLIB_TX]; */
1174       vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1175
1176       if (set_data)
1177         clib_memcpy_fast (b0->data, data, n_data);
1178       else
1179         ASSERT (validate_buffer_data2 (b0, s, data_offset, n_data));
1180     }
1181 }
1182
1183 static u32
1184 pg_stream_fill_helper (pg_main_t * pg,
1185                        pg_stream_t * s,
1186                        pg_buffer_index_t * bi,
1187                        u32 * buffers, u32 * next_buffers, u32 n_alloc)
1188 {
1189   vlib_main_t *vm = vlib_get_main ();
1190   uword is_start_of_packet = bi == s->buffer_indices;
1191   u32 n_allocated;
1192
1193   n_allocated = vlib_buffer_alloc_from_free_list (vm,
1194                                                   buffers,
1195                                                   n_alloc,
1196                                                   bi->free_list_index);
1197   if (n_allocated == 0)
1198     return 0;
1199
1200   /*
1201    * We can't assume we got all the buffers we asked for...
1202    * This never worked until recently.
1203    */
1204   n_alloc = n_allocated;
1205
1206   /* Reinitialize buffers */
1207   init_buffers_inline
1208     (vm, s,
1209      buffers,
1210      n_alloc, (bi - s->buffer_indices) * s->buffer_bytes /* data offset */ ,
1211      s->buffer_bytes,
1212      /* set_data */ 1);
1213
1214   if (next_buffers)
1215     pg_set_next_buffer_pointers (pg, s, buffers, next_buffers, n_alloc);
1216
1217   if (is_start_of_packet)
1218     {
1219       if (vec_len (s->replay_packet_templates) > 0)
1220         {
1221           vnet_main_t *vnm = vnet_get_main ();
1222           vnet_interface_main_t *im = &vnm->interface_main;
1223           vnet_sw_interface_t *si =
1224             vnet_get_sw_interface (vnm, s->sw_if_index[VLIB_RX]);
1225           u32 l = 0;
1226           u32 i;
1227           for (i = 0; i < n_alloc; i++)
1228             l += vlib_buffer_index_length_in_chain (vm, buffers[i]);
1229           vlib_increment_combined_counter (im->combined_sw_if_counters
1230                                            + VNET_INTERFACE_COUNTER_RX,
1231                                            vlib_get_thread_index (),
1232                                            si->sw_if_index, n_alloc, l);
1233           s->current_replay_packet_index += n_alloc;
1234           s->current_replay_packet_index %=
1235             vec_len (s->replay_packet_templates);
1236         }
1237       else
1238         {
1239           pg_generate_set_lengths (pg, s, buffers, n_alloc);
1240           if (vec_len (s->buffer_indices) > 1)
1241             pg_generate_fix_multi_buffer_lengths (pg, s, buffers, n_alloc);
1242
1243           pg_generate_edit (pg, s, buffers, n_alloc);
1244         }
1245     }
1246
1247   return n_alloc;
1248 }
1249
1250 static u32
1251 pg_stream_fill (pg_main_t * pg, pg_stream_t * s, u32 n_buffers)
1252 {
1253   pg_buffer_index_t *bi;
1254   word i, n_in_fifo, n_alloc, n_free, n_added;
1255   u32 *tail, *start, *end, *last_tail, *last_start;
1256
1257   bi = s->buffer_indices;
1258
1259   n_in_fifo = clib_fifo_elts (bi->buffer_fifo);
1260   if (n_in_fifo >= n_buffers)
1261     return n_in_fifo;
1262
1263   n_alloc = n_buffers - n_in_fifo;
1264
1265   /* Round up, but never generate more than limit. */
1266   n_alloc = clib_max (VLIB_FRAME_SIZE, n_alloc);
1267
1268   if (s->n_packets_limit > 0
1269       && s->n_packets_generated + n_in_fifo + n_alloc >= s->n_packets_limit)
1270     {
1271       n_alloc = s->n_packets_limit - s->n_packets_generated - n_in_fifo;
1272       if (n_alloc < 0)
1273         n_alloc = 0;
1274     }
1275
1276   /* All buffer fifos should have the same size. */
1277   if (CLIB_DEBUG > 0)
1278     {
1279       uword l = ~0, e;
1280       vec_foreach (bi, s->buffer_indices)
1281       {
1282         e = clib_fifo_elts (bi->buffer_fifo);
1283         if (bi == s->buffer_indices)
1284           l = e;
1285         ASSERT (l == e);
1286       }
1287     }
1288
1289   last_tail = last_start = 0;
1290   n_added = n_alloc;
1291
1292   for (i = vec_len (s->buffer_indices) - 1; i >= 0; i--)
1293     {
1294       bi = vec_elt_at_index (s->buffer_indices, i);
1295
1296       n_free = clib_fifo_free_elts (bi->buffer_fifo);
1297       if (n_free < n_alloc)
1298         clib_fifo_resize (bi->buffer_fifo, n_alloc - n_free);
1299
1300       tail = clib_fifo_advance_tail (bi->buffer_fifo, n_alloc);
1301       start = bi->buffer_fifo;
1302       end = clib_fifo_end (bi->buffer_fifo);
1303
1304       if (tail + n_alloc <= end)
1305         {
1306           n_added =
1307             pg_stream_fill_helper (pg, s, bi, tail, last_tail, n_alloc);
1308         }
1309       else
1310         {
1311           u32 n = clib_min (end - tail, n_alloc);
1312           n_added = pg_stream_fill_helper (pg, s, bi, tail, last_tail, n);
1313
1314           if (n_added == n && n_alloc > n_added)
1315             {
1316               n_added += pg_stream_fill_helper
1317                 (pg, s, bi, start, last_start, n_alloc - n_added);
1318             }
1319         }
1320
1321       if (PREDICT_FALSE (n_added < n_alloc))
1322         tail = clib_fifo_advance_tail (bi->buffer_fifo, n_added - n_alloc);
1323
1324       last_tail = tail;
1325       last_start = start;
1326
1327       /* Verify that pkts in the fifo are properly allocated */
1328     }
1329
1330   return n_in_fifo + n_added;
1331 }
1332
1333 typedef struct
1334 {
1335   u32 stream_index;
1336
1337   u32 packet_length;
1338   u32 sw_if_index;
1339
1340   /* Use pre data for packet data. */
1341   vlib_buffer_t buffer;
1342 } pg_input_trace_t;
1343
1344 static u8 *
1345 format_pg_input_trace (u8 * s, va_list * va)
1346 {
1347   vlib_main_t *vm = va_arg (*va, vlib_main_t *);
1348   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
1349   pg_input_trace_t *t = va_arg (*va, pg_input_trace_t *);
1350   pg_main_t *pg = &pg_main;
1351   pg_stream_t *stream;
1352   vlib_node_t *n;
1353   u32 indent = format_get_indent (s);
1354
1355   stream = 0;
1356   if (!pool_is_free_index (pg->streams, t->stream_index))
1357     stream = pool_elt_at_index (pg->streams, t->stream_index);
1358
1359   if (stream)
1360     s = format (s, "stream %v", pg->streams[t->stream_index].name);
1361   else
1362     s = format (s, "stream %d", t->stream_index);
1363
1364   s = format (s, ", %d bytes", t->packet_length);
1365   s = format (s, ", %d sw_if_index", t->sw_if_index);
1366
1367   s = format (s, "\n%U%U",
1368               format_white_space, indent, format_vnet_buffer, &t->buffer);
1369
1370   s = format (s, "\n%U", format_white_space, indent);
1371
1372   n = 0;
1373   if (stream)
1374     n = vlib_get_node (vm, stream->node_index);
1375
1376   if (n && n->format_buffer)
1377     s = format (s, "%U", n->format_buffer,
1378                 t->buffer.pre_data, sizeof (t->buffer.pre_data));
1379   else
1380     s = format (s, "%U",
1381                 format_hex_bytes, t->buffer.pre_data,
1382                 ARRAY_LEN (t->buffer.pre_data));
1383   return s;
1384 }
1385
1386 static void
1387 pg_input_trace (pg_main_t * pg,
1388                 vlib_node_runtime_t * node,
1389                 pg_stream_t * s, u32 * buffers, u32 n_buffers)
1390 {
1391   vlib_main_t *vm = vlib_get_main ();
1392   u32 *b, n_left, stream_index, next_index;
1393
1394   n_left = n_buffers;
1395   b = buffers;
1396   stream_index = s - pg->streams;
1397   next_index = s->next_index;
1398
1399   while (n_left >= 2)
1400     {
1401       u32 bi0, bi1;
1402       vlib_buffer_t *b0, *b1;
1403       pg_input_trace_t *t0, *t1;
1404
1405       bi0 = b[0];
1406       bi1 = b[1];
1407       b += 2;
1408       n_left -= 2;
1409
1410       b0 = vlib_get_buffer (vm, bi0);
1411       b1 = vlib_get_buffer (vm, bi1);
1412
1413       vlib_trace_buffer (vm, node, next_index, b0, /* follow_chain */ 1);
1414       vlib_trace_buffer (vm, node, next_index, b1, /* follow_chain */ 1);
1415
1416       t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1417       t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1418
1419       t0->stream_index = stream_index;
1420       t1->stream_index = stream_index;
1421
1422       t0->packet_length = vlib_buffer_length_in_chain (vm, b0);
1423       t1->packet_length = vlib_buffer_length_in_chain (vm, b1);
1424
1425       t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1426       t1->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];
1427
1428       clib_memcpy_fast (&t0->buffer, b0,
1429                         sizeof (b0[0]) - sizeof (b0->pre_data));
1430       clib_memcpy_fast (&t1->buffer, b1,
1431                         sizeof (b1[0]) - sizeof (b1->pre_data));
1432
1433       clib_memcpy_fast (t0->buffer.pre_data, b0->data,
1434                         sizeof (t0->buffer.pre_data));
1435       clib_memcpy_fast (t1->buffer.pre_data, b1->data,
1436                         sizeof (t1->buffer.pre_data));
1437     }
1438
1439   while (n_left >= 1)
1440     {
1441       u32 bi0;
1442       vlib_buffer_t *b0;
1443       pg_input_trace_t *t0;
1444
1445       bi0 = b[0];
1446       b += 1;
1447       n_left -= 1;
1448
1449       b0 = vlib_get_buffer (vm, bi0);
1450
1451       vlib_trace_buffer (vm, node, next_index, b0, /* follow_chain */ 1);
1452       t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1453
1454       t0->stream_index = stream_index;
1455       t0->packet_length = vlib_buffer_length_in_chain (vm, b0);
1456       t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1457       clib_memcpy_fast (&t0->buffer, b0,
1458                         sizeof (b0[0]) - sizeof (b0->pre_data));
1459       clib_memcpy_fast (t0->buffer.pre_data, b0->data,
1460                         sizeof (t0->buffer.pre_data));
1461     }
1462 }
1463
1464 static uword
1465 pg_generate_packets (vlib_node_runtime_t * node,
1466                      pg_main_t * pg,
1467                      pg_stream_t * s, uword n_packets_to_generate)
1468 {
1469   vlib_main_t *vm = vlib_get_main ();
1470   u32 *to_next, n_this_frame, n_left, n_trace, n_packets_in_fifo;
1471   uword n_packets_generated;
1472   pg_buffer_index_t *bi, *bi0;
1473   u32 next_index = s->next_index;
1474   vnet_feature_main_t *fm = &feature_main;
1475   vnet_feature_config_main_t *cm;
1476   u8 feature_arc_index = fm->device_input_feature_arc_index;
1477   cm = &fm->feature_config_mains[feature_arc_index];
1478   u32 current_config_index = ~(u32) 0;
1479   int i;
1480
1481   bi0 = s->buffer_indices;
1482
1483   n_packets_in_fifo = pg_stream_fill (pg, s, n_packets_to_generate);
1484   n_packets_to_generate = clib_min (n_packets_in_fifo, n_packets_to_generate);
1485   n_packets_generated = 0;
1486
1487   if (PREDICT_FALSE
1488       (vnet_have_features (feature_arc_index, s->sw_if_index[VLIB_RX])))
1489     {
1490       current_config_index =
1491         vec_elt (cm->config_index_by_sw_if_index, s->sw_if_index[VLIB_RX]);
1492       vnet_get_config_data (&cm->config_main, &current_config_index,
1493                             &next_index, 0);
1494     }
1495
1496   while (n_packets_to_generate > 0)
1497     {
1498       u32 *head, *start, *end;
1499
1500       if (PREDICT_TRUE (next_index == VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT))
1501         {
1502           vlib_next_frame_t *nf;
1503           vlib_frame_t *f;
1504           ethernet_input_frame_t *ef;
1505           pg_interface_t *pi;
1506           vlib_get_new_next_frame (vm, node, next_index, to_next, n_left);
1507           nf = vlib_node_runtime_get_next_frame (vm, node, next_index);
1508           f = vlib_get_frame (vm, nf->frame_index);
1509           f->flags = ETH_INPUT_FRAME_F_SINGLE_SW_IF_IDX;
1510
1511           ef = vlib_frame_scalar_args (f);
1512           pi = pool_elt_at_index (pg->interfaces, s->pg_if_index);
1513           ef->sw_if_index = pi->sw_if_index;
1514           ef->hw_if_index = pi->hw_if_index;
1515         }
1516       else
1517         vlib_get_next_frame (vm, node, next_index, to_next, n_left);
1518
1519       n_this_frame = n_packets_to_generate;
1520       if (n_this_frame > n_left)
1521         n_this_frame = n_left;
1522
1523       start = bi0->buffer_fifo;
1524       end = clib_fifo_end (bi0->buffer_fifo);
1525       head = clib_fifo_head (bi0->buffer_fifo);
1526
1527       if (head + n_this_frame <= end)
1528         vlib_copy_buffers (to_next, head, n_this_frame);
1529       else
1530         {
1531           u32 n = end - head;
1532           vlib_copy_buffers (to_next + 0, head, n);
1533           vlib_copy_buffers (to_next + n, start, n_this_frame - n);
1534         }
1535
1536       vec_foreach (bi, s->buffer_indices)
1537         clib_fifo_advance_head (bi->buffer_fifo, n_this_frame);
1538
1539       if (current_config_index != ~(u32) 0)
1540         for (i = 0; i < n_this_frame; i++)
1541           {
1542             vlib_buffer_t *b;
1543             b = vlib_get_buffer (vm, to_next[i]);
1544             b->current_config_index = current_config_index;
1545             vnet_buffer (b)->feature_arc_index = feature_arc_index;
1546           }
1547
1548       n_trace = vlib_get_trace_count (vm, node);
1549       if (n_trace > 0)
1550         {
1551           u32 n = clib_min (n_trace, n_this_frame);
1552           pg_input_trace (pg, node, s, to_next, n);
1553           vlib_set_trace_count (vm, node, n_trace - n);
1554         }
1555       n_packets_to_generate -= n_this_frame;
1556       n_packets_generated += n_this_frame;
1557       n_left -= n_this_frame;
1558       vlib_put_next_frame (vm, node, next_index, n_left);
1559     }
1560
1561   return n_packets_generated;
1562 }
1563
1564 static uword
1565 pg_input_stream (vlib_node_runtime_t * node, pg_main_t * pg, pg_stream_t * s)
1566 {
1567   vlib_main_t *vm = vlib_get_main ();
1568   uword n_packets;
1569   f64 time_now, dt;
1570
1571   if (s->n_packets_limit > 0 && s->n_packets_generated >= s->n_packets_limit)
1572     {
1573       pg_stream_enable_disable (pg, s, /* want_enabled */ 0);
1574       return 0;
1575     }
1576
1577   /* Apply rate limit. */
1578   time_now = vlib_time_now (vm);
1579   if (s->time_last_generate == 0)
1580     s->time_last_generate = time_now;
1581
1582   dt = time_now - s->time_last_generate;
1583   s->time_last_generate = time_now;
1584
1585   n_packets = VLIB_FRAME_SIZE;
1586   if (s->rate_packets_per_second > 0)
1587     {
1588       s->packet_accumulator += dt * s->rate_packets_per_second;
1589       n_packets = s->packet_accumulator;
1590
1591       /* Never allow accumulator to grow if we get behind. */
1592       s->packet_accumulator -= n_packets;
1593     }
1594
1595   /* Apply fixed limit. */
1596   if (s->n_packets_limit > 0
1597       && s->n_packets_generated + n_packets > s->n_packets_limit)
1598     n_packets = s->n_packets_limit - s->n_packets_generated;
1599
1600   /* Generate up to one frame's worth of packets. */
1601   if (n_packets > VLIB_FRAME_SIZE)
1602     n_packets = VLIB_FRAME_SIZE;
1603
1604   if (n_packets > 0)
1605     n_packets = pg_generate_packets (node, pg, s, n_packets);
1606
1607   s->n_packets_generated += n_packets;
1608
1609   return n_packets;
1610 }
1611
1612 uword
1613 pg_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1614 {
1615   uword i;
1616   pg_main_t *pg = &pg_main;
1617   uword n_packets = 0;
1618   u32 worker_index = 0;
1619
1620   if (vlib_num_workers ())
1621     worker_index = vlib_get_current_worker_index ();
1622
1623   /* *INDENT-OFF* */
1624   clib_bitmap_foreach (i, pg->enabled_streams[worker_index], ({
1625     pg_stream_t *s = vec_elt_at_index (pg->streams, i);
1626     n_packets += pg_input_stream (node, pg, s);
1627   }));
1628   /* *INDENT-ON* */
1629
1630   return n_packets;
1631 }
1632
1633 /* *INDENT-OFF* */
1634 VLIB_REGISTER_NODE (pg_input_node) = {
1635   .function = pg_input,
1636   .name = "pg-input",
1637   .sibling_of = "device-input",
1638   .type = VLIB_NODE_TYPE_INPUT,
1639
1640   .format_trace = format_pg_input_trace,
1641
1642   /* Input node will be left disabled until a stream is active. */
1643   .state = VLIB_NODE_STATE_DISABLED,
1644 };
1645 /* *INDENT-ON* */
1646
1647 /*
1648  * fd.io coding-style-patch-verification: ON
1649  *
1650  * Local Variables:
1651  * eval: (c-set-style "gnu")
1652  * End:
1653  */