Imported Upstream version 16.07-rc1
[deb_dpdk.git] / app / test / test_red.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <stdint.h>
38 #include <unistd.h>
39 #include <inttypes.h>
40 #include <sys/time.h>
41 #include <time.h>
42 #include <math.h>
43
44 #include "test.h"
45
46 #include <rte_red.h>
47
48 #ifdef __INTEL_COMPILER
49 #pragma warning(disable:2259)       /* conversion may lose significant bits */
50 #pragma warning(disable:181)        /* Arg incompatible with format string */
51 #endif
52
53 #define TEST_HZ_PER_KHZ 1000
54 #define TEST_NSEC_MARGIN 500        /**< nanosecond margin when calculating clk freq */
55
56 #define MAX_QEMPTY_TIME_MSEC   50000
57 #define MSEC_PER_SEC           1000      /**< Milli-seconds per second */
58 #define USEC_PER_MSEC          1000      /**< Micro-seconds per milli-second */
59 #define USEC_PER_SEC           1000000   /**< Micro-seconds per second */
60 #define NSEC_PER_SEC           (USEC_PER_SEC * 1000) /**< Nano-seconds per second */
61
62 /**< structures for testing rte_red performance and function */
63 struct test_rte_red_config {        /**< Test structure for RTE_RED config */
64         struct rte_red_config *rconfig; /**< RTE_RED configuration parameters */
65         uint8_t num_cfg;                /**< Number of RTE_RED configs to test */
66         uint8_t *wq_log2;               /**< Test wq_log2 value to use */
67         uint32_t min_th;                /**< Queue minimum threshold */
68         uint32_t max_th;                /**< Queue maximum threshold */
69         uint8_t *maxp_inv;              /**< Inverse mark probability */
70 };
71
72 struct test_queue {                 /**< Test structure for RTE_RED Queues */
73         struct rte_red *rdata;          /**< RTE_RED runtime data */
74         uint32_t num_queues;            /**< Number of RTE_RED queues to test */
75         uint32_t *qconfig;              /**< Configuration of RTE_RED queues for test */
76         uint32_t *q;                    /**< Queue size */
77         uint32_t q_ramp_up;             /**< Num of enqueues to ramp up the queue */
78         uint32_t avg_ramp_up;           /**< Average num of enqueues to ramp up the queue */
79         uint32_t avg_tolerance;         /**< Tolerance in queue average */
80         double drop_tolerance;          /**< Drop tolerance of packets not enqueued */
81 };
82
83 struct test_var {                   /**< Test variables used for testing RTE_RED */
84         uint32_t wait_usec;             /**< Micro second wait interval */
85         uint32_t num_iterations;        /**< Number of test iterations */
86         uint32_t num_ops;               /**< Number of test operations */
87         uint64_t clk_freq;              /**< CPU clock frequency */
88         uint32_t sleep_sec;             /**< Seconds to sleep */
89         uint32_t *dropped;              /**< Test operations dropped */
90         uint32_t *enqueued;             /**< Test operations enqueued */
91 };
92
93 struct test_config {                /**< Master test structure for RTE_RED */
94         const char *ifname;             /**< Interface name */
95         const char *msg;                /**< Test message for display */
96         const char *htxt;               /**< Header txt display for result output */
97         struct test_rte_red_config *tconfig; /**< Test structure for RTE_RED config */
98         struct test_queue *tqueue;      /**< Test structure for RTE_RED Queues */
99         struct test_var *tvar;          /**< Test variables used for testing RTE_RED */
100         uint32_t *tlevel;               /**< Queue levels */
101 };
102
103 enum test_result {
104         FAIL = 0,
105         PASS
106 };
107
108 /**< Test structure to define tests to run */
109 struct tests {
110         struct test_config *testcfg;
111         enum test_result (*testfn)(struct test_config *);
112 };
113
114 struct rdtsc_prof {
115         uint64_t clk_start;
116         uint64_t clk_min;               /**< min clocks */
117         uint64_t clk_max;               /**< max clocks */
118         uint64_t clk_avgc;              /**< count to calc average */
119         double clk_avg;                 /**< cumulative sum to calc average */
120         const char *name;
121 };
122
123 static const uint64_t port_speed_bytes = (10ULL*1000ULL*1000ULL*1000ULL)/8ULL;
124 static double inv_cycles_per_byte = 0;
125 static double pkt_time_usec = 0;
126
127 static void init_port_ts(uint64_t cpu_clock)
128 {
129         double cycles_per_byte = (double)(cpu_clock) / (double)(port_speed_bytes);
130         inv_cycles_per_byte = 1.0 / cycles_per_byte;
131         pkt_time_usec = 1000000.0 / ((double)port_speed_bytes / (double)RTE_RED_S);
132 }
133
134 static uint64_t get_port_ts(void)
135 {
136         return (uint64_t)((double)rte_rdtsc() * inv_cycles_per_byte);
137 }
138
139 static void rdtsc_prof_init(struct rdtsc_prof *p, const char *name)
140 {
141         p->clk_min = (uint64_t)(-1LL);
142         p->clk_max = 0;
143         p->clk_avg = 0;
144         p->clk_avgc = 0;
145         p->name = name;
146 }
147
148 static inline void rdtsc_prof_start(struct rdtsc_prof *p)
149 {
150         p->clk_start = rte_rdtsc_precise();
151 }
152
153 static inline void rdtsc_prof_end(struct rdtsc_prof *p)
154 {
155         uint64_t clk_start = rte_rdtsc() - p->clk_start;
156
157         p->clk_avgc++;
158         p->clk_avg += (double) clk_start;
159
160         if (clk_start > p->clk_max)
161                 p->clk_max = clk_start;
162         if (clk_start < p->clk_min)
163                 p->clk_min = clk_start;
164 }
165
166 static void rdtsc_prof_print(struct rdtsc_prof *p)
167 {
168         if (p->clk_avgc>0) {
169                 printf("RDTSC stats for %s: n=%" PRIu64 ", min=%" PRIu64 ", max=%" PRIu64 ", avg=%.1f\n",
170                         p->name,
171                         p->clk_avgc,
172                         p->clk_min,
173                         p->clk_max,
174                         (p->clk_avg / ((double) p->clk_avgc)));
175         }
176 }
177
178 static uint32_t rte_red_get_avg_int(const struct rte_red_config *red_cfg,
179                                     struct rte_red *red)
180 {
181         /**
182          * scale by 1/n and convert from fixed-point to integer
183          */
184         return red->avg >> (RTE_RED_SCALING + red_cfg->wq_log2);
185 }
186
187 static double rte_red_get_avg_float(const struct rte_red_config *red_cfg,
188                                     struct rte_red *red)
189 {
190         /**
191          * scale by 1/n and convert from fixed-point to floating-point
192          */
193         return ldexp((double)red->avg,  -(RTE_RED_SCALING + red_cfg->wq_log2));
194 }
195
196 static void rte_red_set_avg_int(const struct rte_red_config *red_cfg,
197                                 struct rte_red *red,
198                                 uint32_t avg)
199 {
200         /**
201          * scale by n and convert from integer to fixed-point
202          */
203         red->avg = avg << (RTE_RED_SCALING + red_cfg->wq_log2);
204 }
205
206 static double calc_exp_avg_on_empty(double avg, uint32_t n, uint32_t time_diff)
207 {
208         return avg * pow((1.0 - 1.0 / (double)n), (double)time_diff / pkt_time_usec);
209 }
210
211 static double calc_drop_rate(uint32_t enqueued, uint32_t dropped)
212 {
213         return (double)dropped / ((double)enqueued + (double)dropped);
214 }
215
216 /**
217  * calculate the drop probability
218  */
219 static double calc_drop_prob(uint32_t min_th, uint32_t max_th,
220                              uint32_t maxp_inv, uint32_t avg)
221 {
222         double drop_prob = 0.0;
223
224         if (avg < min_th) {
225                 drop_prob = 0.0;
226         } else if (avg < max_th) {
227                 drop_prob = (1.0 / (double)maxp_inv)
228                         * ((double)(avg - min_th)
229                            / (double)(max_th - min_th));
230         } else {
231                 drop_prob = 1.0;
232         }
233         return drop_prob;
234 }
235
236 /**
237  *  check if drop rate matches drop probability within tolerance
238  */
239 static int check_drop_rate(double *diff, double drop_rate, double drop_prob, double tolerance)
240 {
241         double abs_diff = 0.0;
242         int ret = 1;
243
244         abs_diff = fabs(drop_rate - drop_prob);
245         if ((int)abs_diff == 0) {
246                 *diff = 0.0;
247         } else {
248                 *diff = (abs_diff / drop_prob) * 100.0;
249                 if (*diff > tolerance) {
250                         ret = 0;
251                 }
252         }
253         return ret;
254 }
255
256 /**
257  *  check if average queue size is within tolerance
258  */
259 static int check_avg(double *diff, double avg, double exp_avg, double tolerance)
260 {
261         double abs_diff = 0.0;
262         int ret = 1;
263
264         abs_diff = fabs(avg - exp_avg);
265         if ((int)abs_diff == 0) {
266                 *diff = 0.0;
267         } else {
268                 *diff = (abs_diff / exp_avg) * 100.0;
269                 if (*diff > tolerance) {
270                         ret = 0;
271                 }
272         }
273         return ret;
274 }
275
276 /**
277  * get the clk frequency in Hz
278  */
279 static uint64_t get_machclk_freq(void)
280 {
281         uint64_t start = 0;
282         uint64_t end = 0;
283         uint64_t diff = 0;
284         static uint64_t clk_freq_hz;
285         struct timespec tv_start = {0, 0}, tv_end = {0, 0};
286         struct timespec req = {0, 0};
287
288         if (clk_freq_hz != 0)
289                 return clk_freq_hz;
290
291         req.tv_sec = 0;
292         req.tv_nsec = NSEC_PER_SEC / 4;
293
294         clock_gettime(CLOCK_REALTIME, &tv_start);
295         start = rte_rdtsc();
296
297         if (nanosleep(&req, NULL) != 0) {
298                 perror("get_machclk_freq()");
299                 exit(EXIT_FAILURE);
300         }
301
302         clock_gettime(CLOCK_REALTIME, &tv_end);
303         end = rte_rdtsc();
304
305         diff = (uint64_t)(tv_end.tv_sec - tv_start.tv_sec) * USEC_PER_SEC
306                 + ((tv_end.tv_nsec - tv_start.tv_nsec + TEST_NSEC_MARGIN) /
307                    USEC_PER_MSEC); /**< diff is in micro secs */
308
309         if (diff == 0)
310                 return 0;
311
312         clk_freq_hz = ((end - start) * USEC_PER_SEC / diff);
313         return clk_freq_hz;
314 }
315
316 /**
317  * initialize the test rte_red config
318  */
319 static enum test_result
320 test_rte_red_init(struct test_config *tcfg)
321 {
322         unsigned i = 0;
323
324         tcfg->tvar->clk_freq = get_machclk_freq();
325         init_port_ts( tcfg->tvar->clk_freq );
326
327         for (i = 0; i < tcfg->tconfig->num_cfg; i++) {
328                 if (rte_red_config_init(&tcfg->tconfig->rconfig[i],
329                                         (uint16_t)tcfg->tconfig->wq_log2[i],
330                                         (uint16_t)tcfg->tconfig->min_th,
331                                         (uint16_t)tcfg->tconfig->max_th,
332                                         (uint16_t)tcfg->tconfig->maxp_inv[i]) != 0) {
333                         return FAIL;
334                 }
335         }
336
337         *tcfg->tqueue->q = 0;
338         *tcfg->tvar->dropped = 0;
339         *tcfg->tvar->enqueued = 0;
340         return PASS;
341 }
342
343 /**
344  * enqueue until actual queue size reaches target level
345  */
346 static int
347 increase_actual_qsize(struct rte_red_config *red_cfg,
348                       struct rte_red *red,
349                       uint32_t *q,
350                       uint32_t level,
351                       uint32_t attempts)
352 {
353         uint32_t i = 0;
354
355         for (i = 0; i < attempts; i++) {
356                 int ret = 0;
357
358                 /**
359                  * enqueue
360                  */
361                 ret = rte_red_enqueue(red_cfg, red, *q, get_port_ts() );
362                 if (ret == 0) {
363                         if (++(*q) >= level)
364                                 break;
365                 }
366         }
367         /**
368         * check if target actual queue size has been reached
369         */
370         if (*q != level)
371                 return -1;
372         /**
373          * success
374          */
375         return 0;
376 }
377
378 /**
379  * enqueue until average queue size reaches target level
380  */
381 static int
382 increase_average_qsize(struct rte_red_config *red_cfg,
383                        struct rte_red *red,
384                        uint32_t *q,
385                        uint32_t level,
386                        uint32_t num_ops)
387 {
388         uint32_t avg = 0;
389         uint32_t i = 0;
390
391         for (i = 0; i < num_ops; i++) {
392                 /**
393                  * enqueue
394                  */
395                 rte_red_enqueue(red_cfg, red, *q, get_port_ts());
396         }
397         /**
398          * check if target average queue size has been reached
399          */
400         avg = rte_red_get_avg_int(red_cfg, red);
401         if (avg != level)
402                 return -1;
403         /**
404          * success
405          */
406         return 0;
407 }
408
409 /**
410  * setup default values for the functional test structures
411  */
412 static struct rte_red_config ft_wrconfig[1];
413 static struct rte_red ft_rtdata[1];
414 static uint8_t ft_wq_log2[] = {9};
415 static uint8_t ft_maxp_inv[] = {10};
416 static uint32_t  ft_qconfig[] = {0, 0, 1, 1};
417 static uint32_t  ft_q[] ={0};
418 static uint32_t  ft_dropped[] ={0};
419 static uint32_t  ft_enqueued[] ={0};
420
421 static struct test_rte_red_config ft_tconfig =  {
422         .rconfig = ft_wrconfig,
423         .num_cfg = RTE_DIM(ft_wrconfig),
424         .wq_log2 = ft_wq_log2,
425         .min_th = 32,
426         .max_th = 128,
427         .maxp_inv = ft_maxp_inv,
428 };
429
430 static struct test_queue ft_tqueue = {
431         .rdata = ft_rtdata,
432         .num_queues = RTE_DIM(ft_rtdata),
433         .qconfig = ft_qconfig,
434         .q = ft_q,
435         .q_ramp_up = 1000000,
436         .avg_ramp_up = 1000000,
437         .avg_tolerance = 5,  /* 5 percent */
438         .drop_tolerance = 50,  /* 50 percent */
439 };
440
441 static struct test_var ft_tvar = {
442         .wait_usec = 10000,
443         .num_iterations = 5,
444         .num_ops = 10000,
445         .clk_freq = 0,
446         .dropped = ft_dropped,
447         .enqueued = ft_enqueued,
448         .sleep_sec = (MAX_QEMPTY_TIME_MSEC / MSEC_PER_SEC) + 2,
449 };
450
451 /**
452  * functional test enqueue/dequeue packets
453  */
454 static void enqueue_dequeue_func(struct rte_red_config *red_cfg,
455                                  struct rte_red *red,
456                                  uint32_t *q,
457                                  uint32_t num_ops,
458                                  uint32_t *enqueued,
459                                  uint32_t *dropped)
460 {
461         uint32_t i = 0;
462
463         for (i = 0; i < num_ops; i++) {
464                 int ret = 0;
465
466                 /**
467                  * enqueue
468                  */
469                 ret = rte_red_enqueue(red_cfg, red, *q, get_port_ts());
470                 if (ret == 0)
471                         (*enqueued)++;
472                 else
473                         (*dropped)++;
474         }
475 }
476
477 /**
478  * Test F1: functional test 1
479  */
480 static uint32_t ft1_tlevels[] =  {6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 78, 84, 90, 96, 102, 108, 114, 120, 126, 132, 138, 144};
481
482 static struct test_config func_test1_config = {
483         .ifname = "functional test 1 interface",
484         .msg = "functional test 1 : use one rte_red configuration,\n"
485         "                   increase average queue size to various levels,\n"
486         "                   compare drop rate to drop probability\n\n",
487         .htxt = "                "
488         "avg queue size "
489         "enqueued       "
490         "dropped        "
491         "drop prob %    "
492         "drop rate %    "
493         "diff %         "
494         "tolerance %    "
495         "\n",
496         .tconfig = &ft_tconfig,
497         .tqueue = &ft_tqueue,
498         .tvar = &ft_tvar,
499         .tlevel = ft1_tlevels,
500 };
501
502 static enum test_result func_test1(struct test_config *tcfg)
503 {
504         enum test_result result = PASS;
505         uint32_t i = 0;
506
507         printf("%s", tcfg->msg);
508
509         if (test_rte_red_init(tcfg) != PASS) {
510                 result = FAIL;
511                 goto out;
512         }
513
514         printf("%s", tcfg->htxt);
515
516         for (i = 0; i < RTE_DIM(ft1_tlevels); i++) {
517                 const char *label = NULL;
518                 uint32_t avg = 0;
519                 double drop_rate = 0.0;
520                 double drop_prob = 0.0;
521                 double diff = 0.0;
522
523                 /**
524                  * reset rte_red run-time data
525                  */
526                 rte_red_rt_data_init(tcfg->tqueue->rdata);
527                 *tcfg->tvar->enqueued = 0;
528                 *tcfg->tvar->dropped = 0;
529
530                 if (increase_actual_qsize(tcfg->tconfig->rconfig,
531                                           tcfg->tqueue->rdata,
532                                           tcfg->tqueue->q,
533                                           tcfg->tlevel[i],
534                                           tcfg->tqueue->q_ramp_up) != 0) {
535                         result = FAIL;
536                         goto out;
537                 }
538
539                 if (increase_average_qsize(tcfg->tconfig->rconfig,
540                                            tcfg->tqueue->rdata,
541                                            tcfg->tqueue->q,
542                                            tcfg->tlevel[i],
543                                            tcfg->tqueue->avg_ramp_up) != 0)  {
544                         result = FAIL;
545                         goto out;
546                 }
547
548                 enqueue_dequeue_func(tcfg->tconfig->rconfig,
549                                      tcfg->tqueue->rdata,
550                                      tcfg->tqueue->q,
551                                      tcfg->tvar->num_ops,
552                                      tcfg->tvar->enqueued,
553                                      tcfg->tvar->dropped);
554
555                 avg = rte_red_get_avg_int(tcfg->tconfig->rconfig, tcfg->tqueue->rdata);
556                 if (avg != tcfg->tlevel[i]) {
557                         fprintf(stderr, "Fail: avg != level\n");
558                         result = FAIL;
559                 }
560
561                 drop_rate = calc_drop_rate(*tcfg->tvar->enqueued, *tcfg->tvar->dropped);
562                 drop_prob = calc_drop_prob(tcfg->tconfig->min_th, tcfg->tconfig->max_th,
563                                            *tcfg->tconfig->maxp_inv, tcfg->tlevel[i]);
564                 if (!check_drop_rate(&diff, drop_rate, drop_prob, (double)tcfg->tqueue->drop_tolerance))
565                         result = FAIL;
566
567                 if (tcfg->tlevel[i] == tcfg->tconfig->min_th)
568                         label = "min thresh:     ";
569                 else if (tcfg->tlevel[i] == tcfg->tconfig->max_th)
570                         label = "max thresh:     ";
571                 else
572                         label = "                ";
573                 printf("%s%-15u%-15u%-15u%-15.4lf%-15.4lf%-15.4lf%-15.4lf\n",
574                        label, avg, *tcfg->tvar->enqueued, *tcfg->tvar->dropped,
575                        drop_prob * 100.0, drop_rate * 100.0, diff,
576                        (double)tcfg->tqueue->drop_tolerance);
577         }
578 out:
579         return result;
580 }
581
582 /**
583  * Test F2: functional test 2
584  */
585 static uint32_t ft2_tlevel[] = {127};
586 static uint8_t ft2_wq_log2[] = {9, 9, 9, 9, 9, 9, 9, 9, 9, 9};
587 static uint8_t ft2_maxp_inv[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
588 static struct rte_red_config ft2_rconfig[10];
589
590 static struct test_rte_red_config ft2_tconfig =  {
591         .rconfig = ft2_rconfig,
592         .num_cfg = RTE_DIM(ft2_rconfig),
593         .wq_log2 = ft2_wq_log2,
594         .min_th = 32,
595         .max_th = 128,
596         .maxp_inv = ft2_maxp_inv,
597 };
598
599 static struct test_config func_test2_config = {
600         .ifname = "functional test 2 interface",
601         .msg = "functional test 2 : use several RED configurations,\n"
602         "                   increase average queue size to just below maximum threshold,\n"
603         "                   compare drop rate to drop probability\n\n",
604         .htxt = "RED config     "
605         "avg queue size "
606         "min threshold  "
607         "max threshold  "
608         "drop prob %    "
609         "drop rate %    "
610         "diff %         "
611         "tolerance %    "
612         "\n",
613         .tconfig = &ft2_tconfig,
614         .tqueue = &ft_tqueue,
615         .tvar = &ft_tvar,
616         .tlevel = ft2_tlevel,
617 };
618
619 static enum test_result func_test2(struct test_config *tcfg)
620 {
621         enum test_result result = PASS;
622         double prev_drop_rate = 1.0;
623         uint32_t i = 0;
624
625         printf("%s", tcfg->msg);
626
627         if (test_rte_red_init(tcfg) != PASS) {
628                 result = FAIL;
629                 goto out;
630         }
631         rte_red_rt_data_init(tcfg->tqueue->rdata);
632
633         if (increase_actual_qsize(tcfg->tconfig->rconfig,
634                                   tcfg->tqueue->rdata,
635                                   tcfg->tqueue->q,
636                                   *tcfg->tlevel,
637                                   tcfg->tqueue->q_ramp_up) != 0) {
638                 result = FAIL;
639                 goto out;
640         }
641
642         if (increase_average_qsize(tcfg->tconfig->rconfig,
643                                    tcfg->tqueue->rdata,
644                                    tcfg->tqueue->q,
645                                    *tcfg->tlevel,
646                                    tcfg->tqueue->avg_ramp_up) != 0) {
647                 result = FAIL;
648                 goto out;
649         }
650         printf("%s", tcfg->htxt);
651
652         for (i = 0; i < tcfg->tconfig->num_cfg; i++) {
653                 uint32_t avg = 0;
654                 double drop_rate = 0.0;
655                 double drop_prob = 0.0;
656                 double diff = 0.0;
657
658                 *tcfg->tvar->dropped = 0;
659                 *tcfg->tvar->enqueued = 0;
660
661                 enqueue_dequeue_func(&tcfg->tconfig->rconfig[i],
662                                      tcfg->tqueue->rdata,
663                                      tcfg->tqueue->q,
664                                      tcfg->tvar->num_ops,
665                                      tcfg->tvar->enqueued,
666                                      tcfg->tvar->dropped);
667
668                 avg = rte_red_get_avg_int(&tcfg->tconfig->rconfig[i], tcfg->tqueue->rdata);
669                 if (avg != *tcfg->tlevel)
670                         result = FAIL;
671
672                 drop_rate = calc_drop_rate(*tcfg->tvar->enqueued, *tcfg->tvar->dropped);
673                 drop_prob = calc_drop_prob(tcfg->tconfig->min_th, tcfg->tconfig->max_th,
674                                            tcfg->tconfig->maxp_inv[i], *tcfg->tlevel);
675                 if (!check_drop_rate(&diff, drop_rate, drop_prob, (double)tcfg->tqueue->drop_tolerance))
676                         result = FAIL;
677                 /**
678                  * drop rate should decrease as maxp_inv increases
679                  */
680                 if (drop_rate > prev_drop_rate)
681                         result = FAIL;
682                 prev_drop_rate = drop_rate;
683
684                 printf("%-15u%-15u%-15u%-15u%-15.4lf%-15.4lf%-15.4lf%-15.4lf\n",
685                        i, avg, tcfg->tconfig->min_th, tcfg->tconfig->max_th,
686                        drop_prob * 100.0, drop_rate * 100.0, diff,
687                        (double)tcfg->tqueue->drop_tolerance);
688         }
689 out:
690         return result;
691 }
692
693 /**
694  * Test F3: functional test 3
695  */
696 static uint32_t ft3_tlevel[] = {1022};
697
698 static struct test_rte_red_config ft3_tconfig =  {
699         .rconfig = ft_wrconfig,
700         .num_cfg = RTE_DIM(ft_wrconfig),
701         .wq_log2 = ft_wq_log2,
702         .min_th = 32,
703         .max_th = 1023,
704         .maxp_inv = ft_maxp_inv,
705 };
706
707 static struct test_config func_test3_config = {
708         .ifname = "functional test 3 interface",
709         .msg = "functional test 3 : use one RED configuration,\n"
710         "                   increase average queue size to target level,\n"
711         "                   dequeue all packets until queue is empty,\n"
712         "                   confirm that average queue size is computed correctly while queue is empty\n\n",
713         .htxt = "q avg before   "
714         "q avg after    "
715         "expected       "
716         "difference %   "
717         "tolerance %    "
718         "result  "
719         "\n",
720         .tconfig = &ft3_tconfig,
721         .tqueue = &ft_tqueue,
722         .tvar = &ft_tvar,
723         .tlevel = ft3_tlevel,
724 };
725
726 static enum test_result func_test3(struct test_config *tcfg)
727 {
728         enum test_result result = PASS;
729         uint32_t i = 0;
730
731         printf("%s", tcfg->msg);
732
733         if (test_rte_red_init(tcfg) != PASS) {
734                 result = FAIL;
735                 goto out;
736         }
737
738         rte_red_rt_data_init(tcfg->tqueue->rdata);
739
740         if (increase_actual_qsize(tcfg->tconfig->rconfig,
741                                   tcfg->tqueue->rdata,
742                                   tcfg->tqueue->q,
743                                   *tcfg->tlevel,
744                                   tcfg->tqueue->q_ramp_up) != 0) {
745                 result = FAIL;
746                 goto out;
747         }
748
749         if (increase_average_qsize(tcfg->tconfig->rconfig,
750                                    tcfg->tqueue->rdata,
751                                    tcfg->tqueue->q,
752                                    *tcfg->tlevel,
753                                    tcfg->tqueue->avg_ramp_up) != 0) {
754                 result = FAIL;
755                 goto out;
756         }
757
758         printf("%s", tcfg->htxt);
759
760         for (i = 0; i < tcfg->tvar->num_iterations; i++) {
761                 double avg_before = 0;
762                 double avg_after = 0;
763                 double exp_avg = 0;
764                 double diff = 0.0;
765
766                 avg_before = rte_red_get_avg_float(tcfg->tconfig->rconfig, tcfg->tqueue->rdata);
767
768                 /**
769                 * empty the queue
770                 */
771                 *tcfg->tqueue->q = 0;
772                 rte_red_mark_queue_empty(tcfg->tqueue->rdata, get_port_ts());
773
774                 rte_delay_us(tcfg->tvar->wait_usec);
775
776                 /**
777                  * enqueue one packet to recalculate average queue size
778                  */
779                 if (rte_red_enqueue(tcfg->tconfig->rconfig,
780                                     tcfg->tqueue->rdata,
781                                     *tcfg->tqueue->q,
782                                     get_port_ts()) == 0) {
783                         (*tcfg->tqueue->q)++;
784                 } else {
785                         printf("%s:%d: packet enqueued on empty queue was dropped\n", __func__, __LINE__);
786                         result = FAIL;
787                 }
788
789                 exp_avg = calc_exp_avg_on_empty(avg_before,
790                                               (1 << *tcfg->tconfig->wq_log2),
791                                               tcfg->tvar->wait_usec);
792                 avg_after = rte_red_get_avg_float(tcfg->tconfig->rconfig,
793                                                   tcfg->tqueue->rdata);
794                 if (!check_avg(&diff, avg_after, exp_avg, (double)tcfg->tqueue->avg_tolerance))
795                         result = FAIL;
796
797                 printf("%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15s\n",
798                        avg_before, avg_after, exp_avg, diff,
799                        (double)tcfg->tqueue->avg_tolerance,
800                        diff <= (double)tcfg->tqueue->avg_tolerance ? "pass" : "fail");
801         }
802 out:
803         return result;
804 }
805
806 /**
807  * Test F4: functional test 4
808  */
809 static uint32_t ft4_tlevel[] = {1022};
810 static uint8_t ft4_wq_log2[] = {11};
811
812 static struct test_rte_red_config ft4_tconfig =  {
813         .rconfig = ft_wrconfig,
814         .num_cfg = RTE_DIM(ft_wrconfig),
815         .min_th = 32,
816         .max_th = 1023,
817         .wq_log2 = ft4_wq_log2,
818         .maxp_inv = ft_maxp_inv,
819 };
820
821 static struct test_queue ft4_tqueue = {
822         .rdata = ft_rtdata,
823         .num_queues = RTE_DIM(ft_rtdata),
824         .qconfig = ft_qconfig,
825         .q = ft_q,
826         .q_ramp_up = 1000000,
827         .avg_ramp_up = 1000000,
828         .avg_tolerance = 0,  /* 0 percent */
829         .drop_tolerance = 50,  /* 50 percent */
830 };
831
832 static struct test_config func_test4_config = {
833         .ifname = "functional test 4 interface",
834         .msg = "functional test 4 : use one RED configuration,\n"
835         "                   increase average queue size to target level,\n"
836         "                   dequeue all packets until queue is empty,\n"
837         "                   confirm that average queue size is computed correctly while\n"
838         "                   queue is empty for more than 50 sec,\n"
839         "                   (this test takes 52 sec to run)\n\n",
840         .htxt = "q avg before   "
841         "q avg after    "
842         "expected       "
843         "difference %   "
844         "tolerance %    "
845         "result  "
846         "\n",
847         .tconfig = &ft4_tconfig,
848         .tqueue = &ft4_tqueue,
849         .tvar = &ft_tvar,
850         .tlevel = ft4_tlevel,
851 };
852
853 static enum test_result func_test4(struct test_config *tcfg)
854 {
855         enum test_result result = PASS;
856         uint64_t time_diff = 0;
857         uint64_t start = 0;
858         double avg_before = 0.0;
859         double avg_after = 0.0;
860         double exp_avg = 0.0;
861         double diff = 0.0;
862
863         printf("%s", tcfg->msg);
864
865         if (test_rte_red_init(tcfg) != PASS) {
866                 result = FAIL;
867                 goto out;
868         }
869
870         rte_red_rt_data_init(tcfg->tqueue->rdata);
871
872         if (increase_actual_qsize(tcfg->tconfig->rconfig,
873                                   tcfg->tqueue->rdata,
874                                   tcfg->tqueue->q,
875                                   *tcfg->tlevel,
876                                   tcfg->tqueue->q_ramp_up) != 0) {
877                 result = FAIL;
878                 goto out;
879         }
880
881         if (increase_average_qsize(tcfg->tconfig->rconfig,
882                                    tcfg->tqueue->rdata,
883                                    tcfg->tqueue->q,
884                                    *tcfg->tlevel,
885                                    tcfg->tqueue->avg_ramp_up) != 0) {
886                 result = FAIL;
887                 goto out;
888         }
889
890         printf("%s", tcfg->htxt);
891
892         avg_before = rte_red_get_avg_float(tcfg->tconfig->rconfig, tcfg->tqueue->rdata);
893
894         /**
895          * empty the queue
896          */
897         *tcfg->tqueue->q = 0;
898         rte_red_mark_queue_empty(tcfg->tqueue->rdata, get_port_ts());
899
900         /**
901          * record empty time locally
902          */
903         start = rte_rdtsc();
904
905         sleep(tcfg->tvar->sleep_sec);
906
907         /**
908          * enqueue one packet to recalculate average queue size
909          */
910         if (rte_red_enqueue(tcfg->tconfig->rconfig,
911                             tcfg->tqueue->rdata,
912                             *tcfg->tqueue->q,
913                             get_port_ts()) != 0) {
914                 result = FAIL;
915                 goto out;
916         }
917         (*tcfg->tqueue->q)++;
918
919         /**
920          * calculate how long queue has been empty
921          */
922         time_diff = ((rte_rdtsc() - start) / tcfg->tvar->clk_freq)
923                   * MSEC_PER_SEC;
924         if (time_diff < MAX_QEMPTY_TIME_MSEC) {
925                 /**
926                  * this could happen if sleep was interrupted for some reason
927                  */
928                 result = FAIL;
929                 goto out;
930         }
931
932         /**
933          * confirm that average queue size is now at expected level
934          */
935         exp_avg = 0.0;
936         avg_after = rte_red_get_avg_float(tcfg->tconfig->rconfig, tcfg->tqueue->rdata);
937         if (!check_avg(&diff, avg_after, exp_avg, (double)tcfg->tqueue->avg_tolerance))
938                 result = FAIL;
939
940         printf("%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15s\n",
941                avg_before, avg_after, exp_avg,
942                diff, (double)tcfg->tqueue->avg_tolerance,
943                diff <= (double)tcfg->tqueue->avg_tolerance ? "pass" : "fail");
944 out:
945         return result;
946 }
947
948 /**
949  * Test F5: functional test 5
950  */
951 static uint32_t ft5_tlevel[] = {127};
952 static uint8_t ft5_wq_log2[] = {9, 8};
953 static uint8_t ft5_maxp_inv[] = {10, 20};
954 static struct rte_red_config ft5_config[2];
955 static struct rte_red ft5_data[4];
956 static uint32_t ft5_q[4];
957 static uint32_t ft5_dropped[] = {0, 0, 0, 0};
958 static uint32_t ft5_enqueued[] = {0, 0, 0, 0};
959
960 static struct test_rte_red_config ft5_tconfig =  {
961         .rconfig = ft5_config,
962         .num_cfg = RTE_DIM(ft5_config),
963         .min_th = 32,
964         .max_th = 128,
965         .wq_log2 = ft5_wq_log2,
966         .maxp_inv = ft5_maxp_inv,
967 };
968
969 static struct test_queue ft5_tqueue = {
970         .rdata = ft5_data,
971         .num_queues = RTE_DIM(ft5_data),
972         .qconfig = ft_qconfig,
973         .q = ft5_q,
974         .q_ramp_up = 1000000,
975         .avg_ramp_up = 1000000,
976         .avg_tolerance = 5,  /* 10 percent */
977         .drop_tolerance = 50,  /* 50 percent */
978 };
979
980 struct test_var ft5_tvar = {
981         .wait_usec = 0,
982         .num_iterations = 15,
983         .num_ops = 10000,
984         .clk_freq = 0,
985         .dropped = ft5_dropped,
986         .enqueued = ft5_enqueued,
987         .sleep_sec = 0,
988 };
989
990 static struct test_config func_test5_config = {
991         .ifname = "functional test 5 interface",
992         .msg = "functional test 5 : use several queues (each with its own run-time data),\n"
993         "                   use several RED configurations (such that each configuration is shared by multiple queues),\n"
994         "                   increase average queue size to just below maximum threshold,\n"
995         "                   compare drop rate to drop probability,\n"
996         "                   (this is a larger scale version of functional test 2)\n\n",
997         .htxt = "queue          "
998         "config         "
999         "avg queue size "
1000         "min threshold  "
1001         "max threshold  "
1002         "drop prob %    "
1003         "drop rate %    "
1004         "diff %         "
1005         "tolerance %    "
1006         "\n",
1007         .tconfig = &ft5_tconfig,
1008         .tqueue = &ft5_tqueue,
1009         .tvar = &ft5_tvar,
1010         .tlevel = ft5_tlevel,
1011 };
1012
1013 static enum test_result func_test5(struct test_config *tcfg)
1014 {
1015         enum test_result result = PASS;
1016         uint32_t j = 0;
1017
1018         printf("%s", tcfg->msg);
1019
1020         if (test_rte_red_init(tcfg) != PASS) {
1021                 result = FAIL;
1022                 goto out;
1023         }
1024
1025         printf("%s", tcfg->htxt);
1026
1027         for (j = 0; j < tcfg->tqueue->num_queues; j++) {
1028                 rte_red_rt_data_init(&tcfg->tqueue->rdata[j]);
1029                 tcfg->tqueue->q[j] = 0;
1030
1031                 if (increase_actual_qsize(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]],
1032                                           &tcfg->tqueue->rdata[j],
1033                                           &tcfg->tqueue->q[j],
1034                                           *tcfg->tlevel,
1035                                           tcfg->tqueue->q_ramp_up) != 0) {
1036                         result = FAIL;
1037                         goto out;
1038                 }
1039
1040                 if (increase_average_qsize(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]],
1041                                            &tcfg->tqueue->rdata[j],
1042                                            &tcfg->tqueue->q[j],
1043                                            *tcfg->tlevel,
1044                                            tcfg->tqueue->avg_ramp_up) != 0) {
1045                         result = FAIL;
1046                         goto out;
1047                 }
1048         }
1049
1050         for (j = 0; j < tcfg->tqueue->num_queues; j++) {
1051                 uint32_t avg = 0;
1052                 double drop_rate = 0.0;
1053                 double drop_prob = 0.0;
1054                 double diff = 0.0;
1055
1056                 tcfg->tvar->dropped[j] = 0;
1057                 tcfg->tvar->enqueued[j] = 0;
1058
1059                 enqueue_dequeue_func(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]],
1060                                      &tcfg->tqueue->rdata[j],
1061                                      &tcfg->tqueue->q[j],
1062                                      tcfg->tvar->num_ops,
1063                                      &tcfg->tvar->enqueued[j],
1064                                      &tcfg->tvar->dropped[j]);
1065
1066                 avg = rte_red_get_avg_int(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]],
1067                                           &tcfg->tqueue->rdata[j]);
1068                 if (avg != *tcfg->tlevel)
1069                         result = FAIL;
1070
1071                 drop_rate = calc_drop_rate(tcfg->tvar->enqueued[j],tcfg->tvar->dropped[j]);
1072                 drop_prob = calc_drop_prob(tcfg->tconfig->min_th, tcfg->tconfig->max_th,
1073                                            tcfg->tconfig->maxp_inv[tcfg->tqueue->qconfig[j]],
1074                                            *tcfg->tlevel);
1075                 if (!check_drop_rate(&diff, drop_rate, drop_prob, (double)tcfg->tqueue->drop_tolerance))
1076                         result = FAIL;
1077
1078                 printf("%-15u%-15u%-15u%-15u%-15u%-15.4lf%-15.4lf%-15.4lf%-15.4lf\n",
1079                        j, tcfg->tqueue->qconfig[j], avg,
1080                        tcfg->tconfig->min_th, tcfg->tconfig->max_th,
1081                        drop_prob * 100.0, drop_rate * 100.0,
1082                        diff, (double)tcfg->tqueue->drop_tolerance);
1083         }
1084 out:
1085         return result;
1086 }
1087
1088 /**
1089  * Test F6: functional test 6
1090  */
1091 static uint32_t ft6_tlevel[] = {1022};
1092 static uint8_t ft6_wq_log2[] = {9, 8};
1093 static uint8_t ft6_maxp_inv[] = {10, 20};
1094 static struct rte_red_config ft6_config[2];
1095 static struct rte_red ft6_data[4];
1096 static uint32_t ft6_q[4];
1097
1098 static struct test_rte_red_config ft6_tconfig =  {
1099         .rconfig = ft6_config,
1100         .num_cfg = RTE_DIM(ft6_config),
1101         .min_th = 32,
1102         .max_th = 1023,
1103         .wq_log2 = ft6_wq_log2,
1104         .maxp_inv = ft6_maxp_inv,
1105 };
1106
1107 static struct test_queue ft6_tqueue = {
1108         .rdata = ft6_data,
1109         .num_queues = RTE_DIM(ft6_data),
1110         .qconfig = ft_qconfig,
1111         .q = ft6_q,
1112         .q_ramp_up = 1000000,
1113         .avg_ramp_up = 1000000,
1114         .avg_tolerance = 5,  /* 10 percent */
1115         .drop_tolerance = 50,  /* 50 percent */
1116 };
1117
1118 static struct test_config func_test6_config = {
1119         .ifname = "functional test 6 interface",
1120         .msg = "functional test 6 : use several queues (each with its own run-time data),\n"
1121         "                   use several RED configurations (such that each configuration is sharte_red by multiple queues),\n"
1122         "                   increase average queue size to target level,\n"
1123         "                   dequeue all packets until queue is empty,\n"
1124         "                   confirm that average queue size is computed correctly while queue is empty\n"
1125         "                   (this is a larger scale version of functional test 3)\n\n",
1126         .htxt = "queue          "
1127         "config         "
1128         "q avg before   "
1129         "q avg after    "
1130         "expected       "
1131         "difference %   "
1132         "tolerance %    "
1133         "result  ""\n",
1134         .tconfig = &ft6_tconfig,
1135         .tqueue = &ft6_tqueue,
1136         .tvar = &ft_tvar,
1137         .tlevel = ft6_tlevel,
1138 };
1139
1140 static enum test_result func_test6(struct test_config *tcfg)
1141 {
1142         enum test_result result = PASS;
1143         uint32_t j = 0;
1144
1145         printf("%s", tcfg->msg);
1146         if (test_rte_red_init(tcfg) != PASS) {
1147                 result = FAIL;
1148                 goto out;
1149         }
1150         printf("%s", tcfg->htxt);
1151
1152         for (j = 0; j < tcfg->tqueue->num_queues; j++) {
1153                 rte_red_rt_data_init(&tcfg->tqueue->rdata[j]);
1154                 tcfg->tqueue->q[j] = 0;
1155
1156                 if (increase_actual_qsize(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]],
1157                                           &tcfg->tqueue->rdata[j],
1158                                           &tcfg->tqueue->q[j],
1159                                           *tcfg->tlevel,
1160                                           tcfg->tqueue->q_ramp_up) != 0) {
1161                         result = FAIL;
1162                         goto out;
1163                 }
1164                 if (increase_average_qsize(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]],
1165                                            &tcfg->tqueue->rdata[j],
1166                                            &tcfg->tqueue->q[j],
1167                                            *tcfg->tlevel,
1168                                            tcfg->tqueue->avg_ramp_up) != 0) {
1169                         result = FAIL;
1170                         goto out;
1171                 }
1172         }
1173         for (j = 0; j < tcfg->tqueue->num_queues; j++) {
1174                 double avg_before = 0;
1175                 double avg_after = 0;
1176                 double exp_avg = 0;
1177                 double diff = 0.0;
1178
1179                 avg_before = rte_red_get_avg_float(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]],
1180                                                    &tcfg->tqueue->rdata[j]);
1181
1182                 /**
1183                  * empty the queue
1184                  */
1185                 tcfg->tqueue->q[j] = 0;
1186                 rte_red_mark_queue_empty(&tcfg->tqueue->rdata[j], get_port_ts());
1187                 rte_delay_us(tcfg->tvar->wait_usec);
1188
1189                 /**
1190                  * enqueue one packet to recalculate average queue size
1191                  */
1192                 if (rte_red_enqueue(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]],
1193                                     &tcfg->tqueue->rdata[j],
1194                                     tcfg->tqueue->q[j],
1195                                     get_port_ts()) == 0) {
1196                         tcfg->tqueue->q[j]++;
1197                 } else {
1198                         printf("%s:%d: packet enqueued on empty queue was dropped\n", __func__, __LINE__);
1199                         result = FAIL;
1200                 }
1201
1202                 exp_avg = calc_exp_avg_on_empty(avg_before,
1203                                 (1 << tcfg->tconfig->wq_log2[tcfg->tqueue->qconfig[j]]),
1204                                 tcfg->tvar->wait_usec);
1205                 avg_after = rte_red_get_avg_float(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]],
1206                                                 &tcfg->tqueue->rdata[j]);
1207                 if (!check_avg(&diff, avg_after, exp_avg, (double)tcfg->tqueue->avg_tolerance))
1208                         result = FAIL;
1209
1210                 printf("%-15u%-15u%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15s\n",
1211                        j, tcfg->tqueue->qconfig[j], avg_before, avg_after,
1212                        exp_avg, diff, (double)tcfg->tqueue->avg_tolerance,
1213                        diff <= tcfg->tqueue->avg_tolerance ? "pass" : "fail");
1214         }
1215 out:
1216         return result;
1217 }
1218
1219 /**
1220  * setup default values for the performance test structures
1221  */
1222 static struct rte_red_config pt_wrconfig[1];
1223 static struct rte_red pt_rtdata[1];
1224 static uint8_t pt_wq_log2[] = {9};
1225 static uint8_t pt_maxp_inv[] = {10};
1226 static uint32_t pt_qconfig[] = {0};
1227 static uint32_t pt_q[] = {0};
1228 static uint32_t pt_dropped[] = {0};
1229 static uint32_t pt_enqueued[] = {0};
1230
1231 static struct test_rte_red_config pt_tconfig =  {
1232         .rconfig = pt_wrconfig,
1233         .num_cfg = RTE_DIM(pt_wrconfig),
1234         .wq_log2 = pt_wq_log2,
1235         .min_th = 32,
1236         .max_th = 128,
1237         .maxp_inv = pt_maxp_inv,
1238 };
1239
1240 static struct test_queue pt_tqueue = {
1241         .rdata = pt_rtdata,
1242         .num_queues = RTE_DIM(pt_rtdata),
1243         .qconfig = pt_qconfig,
1244         .q = pt_q,
1245         .q_ramp_up = 1000000,
1246         .avg_ramp_up = 1000000,
1247         .avg_tolerance = 5,  /* 10 percent */
1248         .drop_tolerance = 50,  /* 50 percent */
1249 };
1250
1251 /**
1252  * enqueue/dequeue packets
1253  */
1254 static void enqueue_dequeue_perf(struct rte_red_config *red_cfg,
1255                                  struct rte_red *red,
1256                                  uint32_t *q,
1257                                  uint32_t num_ops,
1258                                  uint32_t *enqueued,
1259                                  uint32_t *dropped,
1260                                  struct rdtsc_prof *prof)
1261 {
1262         uint32_t i = 0;
1263
1264         for (i = 0; i < num_ops; i++) {
1265                 uint64_t ts = 0;
1266                 int ret = 0;
1267                 /**
1268                  * enqueue
1269                  */
1270                 ts = get_port_ts();
1271                 rdtsc_prof_start(prof);
1272                 ret = rte_red_enqueue(red_cfg, red, *q, ts );
1273                 rdtsc_prof_end(prof);
1274                 if (ret == 0)
1275                         (*enqueued)++;
1276                 else
1277                         (*dropped)++;
1278         }
1279 }
1280
1281 /**
1282  * Setup test structures for tests P1, P2, P3
1283  * performance tests 1, 2 and 3
1284  */
1285 static uint32_t pt1_tlevel[] = {16};
1286 static uint32_t pt2_tlevel[] = {80};
1287 static uint32_t pt3_tlevel[] = {144};
1288
1289 static struct test_var perf1_tvar = {
1290         .wait_usec = 0,
1291         .num_iterations = 15,
1292         .num_ops = 50000000,
1293         .clk_freq = 0,
1294         .dropped = pt_dropped,
1295         .enqueued = pt_enqueued,
1296         .sleep_sec = 0
1297 };
1298
1299 static struct test_config perf1_test1_config = {
1300         .ifname = "performance test 1 interface",
1301         .msg = "performance test 1 : use one RED configuration,\n"
1302         "                    set actual and average queue sizes to level below min threshold,\n"
1303         "                    measure enqueue performance\n\n",
1304         .tconfig = &pt_tconfig,
1305         .tqueue = &pt_tqueue,
1306         .tvar = &perf1_tvar,
1307         .tlevel = pt1_tlevel,
1308 };
1309
1310 static struct test_config perf1_test2_config = {
1311         .ifname = "performance test 2 interface",
1312         .msg = "performance test 2 : use one RED configuration,\n"
1313         "                    set actual and average queue sizes to level in between min and max thresholds,\n"
1314         "                    measure enqueue performance\n\n",
1315         .tconfig = &pt_tconfig,
1316         .tqueue = &pt_tqueue,
1317         .tvar = &perf1_tvar,
1318         .tlevel = pt2_tlevel,
1319 };
1320
1321 static struct test_config perf1_test3_config = {
1322         .ifname = "performance test 3 interface",
1323         .msg = "performance test 3 : use one RED configuration,\n"
1324         "                    set actual and average queue sizes to level above max threshold,\n"
1325         "                    measure enqueue performance\n\n",
1326         .tconfig = &pt_tconfig,
1327         .tqueue = &pt_tqueue,
1328         .tvar = &perf1_tvar,
1329         .tlevel = pt3_tlevel,
1330 };
1331
1332 /**
1333  * Performance test function to measure enqueue performance.
1334  * This runs performance tests 1, 2 and 3
1335  */
1336 static enum test_result perf1_test(struct test_config *tcfg)
1337 {
1338         enum test_result result = PASS;
1339         struct rdtsc_prof prof = {0, 0, 0, 0, 0.0, NULL};
1340         uint32_t total = 0;
1341
1342         printf("%s", tcfg->msg);
1343
1344         rdtsc_prof_init(&prof, "enqueue");
1345
1346         if (test_rte_red_init(tcfg) != PASS) {
1347                 result = FAIL;
1348                 goto out;
1349         }
1350
1351         /**
1352          * set average queue size to target level
1353          */
1354         *tcfg->tqueue->q = *tcfg->tlevel;
1355
1356         /**
1357          * initialize the rte_red run time data structure
1358          */
1359         rte_red_rt_data_init(tcfg->tqueue->rdata);
1360
1361         /**
1362          *  set the queue average
1363          */
1364         rte_red_set_avg_int(tcfg->tconfig->rconfig, tcfg->tqueue->rdata, *tcfg->tlevel);
1365         if (rte_red_get_avg_int(tcfg->tconfig->rconfig, tcfg->tqueue->rdata)
1366             != *tcfg->tlevel) {
1367                 result = FAIL;
1368                 goto out;
1369         }
1370
1371         enqueue_dequeue_perf(tcfg->tconfig->rconfig,
1372                              tcfg->tqueue->rdata,
1373                              tcfg->tqueue->q,
1374                              tcfg->tvar->num_ops,
1375                              tcfg->tvar->enqueued,
1376                              tcfg->tvar->dropped,
1377                              &prof);
1378
1379         total = *tcfg->tvar->enqueued + *tcfg->tvar->dropped;
1380
1381         printf("\ntotal: %u, enqueued: %u (%.2lf%%), dropped: %u (%.2lf%%)\n", total,
1382                *tcfg->tvar->enqueued, ((double)(*tcfg->tvar->enqueued) / (double)total) * 100.0,
1383                *tcfg->tvar->dropped, ((double)(*tcfg->tvar->dropped) / (double)total) * 100.0);
1384
1385         rdtsc_prof_print(&prof);
1386 out:
1387         return result;
1388 }
1389
1390 /**
1391  * Setup test structures for tests P4, P5, P6
1392  * performance tests 4, 5 and 6
1393  */
1394 static uint32_t pt4_tlevel[] = {16};
1395 static uint32_t pt5_tlevel[] = {80};
1396 static uint32_t pt6_tlevel[] = {144};
1397
1398 static struct test_var perf2_tvar = {
1399         .wait_usec = 500,
1400         .num_iterations = 10000,
1401         .num_ops = 10000,
1402         .dropped = pt_dropped,
1403         .enqueued = pt_enqueued,
1404         .sleep_sec = 0
1405 };
1406
1407 static struct test_config perf2_test4_config = {
1408         .ifname = "performance test 4 interface",
1409         .msg = "performance test 4 : use one RED configuration,\n"
1410         "                    set actual and average queue sizes to level below min threshold,\n"
1411         "                    dequeue all packets until queue is empty,\n"
1412         "                    measure enqueue performance when queue is empty\n\n",
1413         .htxt = "iteration      "
1414         "q avg before   "
1415         "q avg after    "
1416         "expected       "
1417         "difference %   "
1418         "tolerance %    "
1419         "result  ""\n",
1420         .tconfig = &pt_tconfig,
1421         .tqueue = &pt_tqueue,
1422         .tvar = &perf2_tvar,
1423         .tlevel = pt4_tlevel,
1424 };
1425
1426 static struct test_config perf2_test5_config = {
1427         .ifname = "performance test 5 interface",
1428         .msg = "performance test 5 : use one RED configuration,\n"
1429         "                    set actual and average queue sizes to level in between min and max thresholds,\n"
1430         "                    dequeue all packets until queue is empty,\n"
1431         "                    measure enqueue performance when queue is empty\n\n",
1432         .htxt = "iteration      "
1433         "q avg before   "
1434         "q avg after    "
1435         "expected       "
1436         "difference     "
1437         "tolerance      "
1438         "result  ""\n",
1439         .tconfig = &pt_tconfig,
1440         .tqueue = &pt_tqueue,
1441         .tvar = &perf2_tvar,
1442         .tlevel = pt5_tlevel,
1443 };
1444
1445 static struct test_config perf2_test6_config = {
1446         .ifname = "performance test 6 interface",
1447         .msg = "performance test 6 : use one RED configuration,\n"
1448         "                    set actual and average queue sizes to level above max threshold,\n"
1449         "                    dequeue all packets until queue is empty,\n"
1450         "                    measure enqueue performance when queue is empty\n\n",
1451         .htxt = "iteration      "
1452         "q avg before   "
1453         "q avg after    "
1454         "expected       "
1455         "difference %   "
1456         "tolerance %    "
1457         "result  ""\n",
1458         .tconfig = &pt_tconfig,
1459         .tqueue = &pt_tqueue,
1460         .tvar = &perf2_tvar,
1461         .tlevel = pt6_tlevel,
1462 };
1463
1464 /**
1465  * Performance test function to measure enqueue performance when the
1466  * queue is empty. This runs performance tests 4, 5 and 6
1467  */
1468 static enum test_result perf2_test(struct test_config *tcfg)
1469 {
1470         enum test_result result = PASS;
1471         struct rdtsc_prof prof = {0, 0, 0, 0, 0.0, NULL};
1472         uint32_t total = 0;
1473         uint32_t i = 0;
1474
1475         printf("%s", tcfg->msg);
1476
1477         rdtsc_prof_init(&prof, "enqueue");
1478
1479         if (test_rte_red_init(tcfg) != PASS) {
1480                 result = FAIL;
1481                 goto out;
1482         }
1483
1484         printf("%s", tcfg->htxt);
1485
1486         for (i = 0; i < tcfg->tvar->num_iterations; i++) {
1487                 uint32_t count = 0;
1488                 uint64_t ts = 0;
1489                 double avg_before = 0;
1490                 int ret = 0;
1491
1492                 /**
1493                  * set average queue size to target level
1494                  */
1495                 *tcfg->tqueue->q = *tcfg->tlevel;
1496                 count = (*tcfg->tqueue->rdata).count;
1497
1498                 /**
1499                  * initialize the rte_red run time data structure
1500                  */
1501                 rte_red_rt_data_init(tcfg->tqueue->rdata);
1502                 (*tcfg->tqueue->rdata).count = count;
1503
1504                 /**
1505                  * set the queue average
1506                  */
1507                 rte_red_set_avg_int(tcfg->tconfig->rconfig, tcfg->tqueue->rdata, *tcfg->tlevel);
1508                 avg_before = rte_red_get_avg_float(tcfg->tconfig->rconfig, tcfg->tqueue->rdata);
1509                 if ((avg_before < *tcfg->tlevel) || (avg_before > *tcfg->tlevel)) {
1510                         result = FAIL;
1511                         goto out;
1512                 }
1513
1514                 /**
1515                  * empty the queue
1516                  */
1517                 *tcfg->tqueue->q = 0;
1518                 rte_red_mark_queue_empty(tcfg->tqueue->rdata, get_port_ts());
1519
1520                 /**
1521                  * wait for specified period of time
1522                  */
1523                 rte_delay_us(tcfg->tvar->wait_usec);
1524
1525                 /**
1526                  * measure performance of enqueue operation while queue is empty
1527                  */
1528                 ts = get_port_ts();
1529                 rdtsc_prof_start(&prof);
1530                 ret = rte_red_enqueue(tcfg->tconfig->rconfig, tcfg->tqueue->rdata,
1531                                       *tcfg->tqueue->q, ts );
1532                 rdtsc_prof_end(&prof);
1533
1534                 /**
1535                  * gather enqueued/dropped statistics
1536                  */
1537                 if (ret == 0)
1538                         (*tcfg->tvar->enqueued)++;
1539                 else
1540                         (*tcfg->tvar->dropped)++;
1541
1542                 /**
1543                  * on first and last iteration, confirm that
1544                  * average queue size was computed correctly
1545                  */
1546                 if ((i == 0) || (i == tcfg->tvar->num_iterations - 1)) {
1547                         double avg_after = 0;
1548                         double exp_avg = 0;
1549                         double diff = 0.0;
1550                         int ok = 0;
1551
1552                         avg_after = rte_red_get_avg_float(tcfg->tconfig->rconfig, tcfg->tqueue->rdata);
1553                         exp_avg = calc_exp_avg_on_empty(avg_before,
1554                                                   (1 << *tcfg->tconfig->wq_log2),
1555                                                   tcfg->tvar->wait_usec);
1556                         if (check_avg(&diff, avg_after, exp_avg, (double)tcfg->tqueue->avg_tolerance))
1557                                 ok = 1;
1558                         printf("%-15u%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15s\n",
1559                                 i, avg_before, avg_after, exp_avg, diff,
1560                                 (double)tcfg->tqueue->avg_tolerance, ok ? "pass" : "fail");
1561                         if (!ok) {
1562                                 result = FAIL;
1563                                 goto out;
1564                         }
1565                 }
1566         }
1567         total =  *tcfg->tvar->enqueued +  *tcfg->tvar->dropped;
1568         printf("\ntotal: %u, enqueued: %u (%.2lf%%), dropped: %u (%.2lf%%)\n", total,
1569                *tcfg->tvar->enqueued, ((double)(*tcfg->tvar->enqueued) / (double)total) * 100.0,
1570                *tcfg->tvar->dropped, ((double)(*tcfg->tvar->dropped) / (double)total) * 100.0);
1571
1572         rdtsc_prof_print(&prof);
1573 out:
1574         return result;
1575 }
1576
1577 /**
1578  * setup default values for overflow test structures
1579  */
1580 static uint32_t avg_max = 0;
1581 static uint32_t avg_max_bits = 0;
1582
1583 static struct rte_red_config ovfl_wrconfig[1];
1584 static struct rte_red ovfl_rtdata[1];
1585 static uint8_t ovfl_maxp_inv[] = {10};
1586 static uint32_t ovfl_qconfig[] = {0, 0, 1, 1};
1587 static uint32_t ovfl_q[] ={0};
1588 static uint32_t ovfl_dropped[] ={0};
1589 static uint32_t ovfl_enqueued[] ={0};
1590 static uint32_t ovfl_tlevel[] = {1023};
1591 static uint8_t ovfl_wq_log2[] = {12};
1592
1593 static struct test_rte_red_config ovfl_tconfig =  {
1594         .rconfig = ovfl_wrconfig,
1595         .num_cfg = RTE_DIM(ovfl_wrconfig),
1596         .wq_log2 = ovfl_wq_log2,
1597         .min_th = 32,
1598         .max_th = 1023,
1599         .maxp_inv = ovfl_maxp_inv,
1600 };
1601
1602 static struct test_queue ovfl_tqueue = {
1603         .rdata = ovfl_rtdata,
1604         .num_queues = RTE_DIM(ovfl_rtdata),
1605         .qconfig = ovfl_qconfig,
1606         .q = ovfl_q,
1607         .q_ramp_up = 1000000,
1608         .avg_ramp_up = 1000000,
1609         .avg_tolerance = 5,  /* 10 percent */
1610         .drop_tolerance = 50,  /* 50 percent */
1611 };
1612
1613 static struct test_var ovfl_tvar = {
1614         .wait_usec = 10000,
1615         .num_iterations = 1,
1616         .num_ops = 10000,
1617         .clk_freq = 0,
1618         .dropped = ovfl_dropped,
1619         .enqueued = ovfl_enqueued,
1620         .sleep_sec = 0
1621 };
1622
1623 static void ovfl_check_avg(uint32_t avg)
1624 {
1625         if (avg > avg_max) {
1626                 double avg_log = 0;
1627                 uint32_t bits = 0;
1628                 avg_max = avg;
1629                 avg_log = log(((double)avg_max));
1630                 avg_log = avg_log / log(2.0);
1631                 bits = (uint32_t)ceil(avg_log);
1632                 if (bits > avg_max_bits)
1633                         avg_max_bits = bits;
1634         }
1635 }
1636
1637 static struct test_config ovfl_test1_config = {
1638         .ifname = "queue avergage overflow test interface",
1639         .msg = "overflow test 1 : use one RED configuration,\n"
1640         "                 increase average queue size to target level,\n"
1641         "                 check maximum number of bits requirte_red to represent avg_s\n\n",
1642         .htxt = "avg queue size  "
1643         "wq_log2  "
1644         "fraction bits  "
1645         "max queue avg  "
1646         "num bits  "
1647         "enqueued  "
1648         "dropped   "
1649         "drop prob %  "
1650         "drop rate %  "
1651         "\n",
1652         .tconfig = &ovfl_tconfig,
1653         .tqueue = &ovfl_tqueue,
1654         .tvar = &ovfl_tvar,
1655         .tlevel = ovfl_tlevel,
1656 };
1657
1658 static enum test_result ovfl_test1(struct test_config *tcfg)
1659 {
1660         enum test_result result = PASS;
1661         uint32_t avg = 0;
1662         uint32_t i = 0;
1663         double drop_rate = 0.0;
1664         double drop_prob = 0.0;
1665         double diff = 0.0;
1666         int ret = 0;
1667
1668         printf("%s", tcfg->msg);
1669
1670         if (test_rte_red_init(tcfg) != PASS) {
1671
1672                 result = FAIL;
1673                 goto out;
1674         }
1675
1676         /**
1677          * reset rte_red run-time data
1678          */
1679         rte_red_rt_data_init(tcfg->tqueue->rdata);
1680
1681         /**
1682          * increase actual queue size
1683          */
1684         for (i = 0; i < tcfg->tqueue->q_ramp_up; i++) {
1685                 ret = rte_red_enqueue(tcfg->tconfig->rconfig, tcfg->tqueue->rdata,
1686                                       *tcfg->tqueue->q, get_port_ts());
1687
1688                 if (ret == 0) {
1689                         if (++(*tcfg->tqueue->q) >= *tcfg->tlevel)
1690                                 break;
1691                 }
1692         }
1693
1694         /**
1695          * enqueue
1696          */
1697         for (i = 0; i < tcfg->tqueue->avg_ramp_up; i++) {
1698                 ret = rte_red_enqueue(tcfg->tconfig->rconfig, tcfg->tqueue->rdata,
1699                                       *tcfg->tqueue->q, get_port_ts());
1700                 ovfl_check_avg((*tcfg->tqueue->rdata).avg);
1701                 avg = rte_red_get_avg_int(tcfg->tconfig->rconfig, tcfg->tqueue->rdata);
1702                 if (avg == *tcfg->tlevel) {
1703                         if (ret == 0)
1704                                 (*tcfg->tvar->enqueued)++;
1705                         else
1706                                 (*tcfg->tvar->dropped)++;
1707                 }
1708         }
1709
1710         /**
1711          * check if target average queue size has been reached
1712          */
1713         avg = rte_red_get_avg_int(tcfg->tconfig->rconfig, tcfg->tqueue->rdata);
1714         if (avg != *tcfg->tlevel) {
1715                 result = FAIL;
1716                 goto out;
1717         }
1718
1719         /**
1720          * check drop rate against drop probability
1721          */
1722         drop_rate = calc_drop_rate(*tcfg->tvar->enqueued, *tcfg->tvar->dropped);
1723         drop_prob = calc_drop_prob(tcfg->tconfig->min_th,
1724                                    tcfg->tconfig->max_th,
1725                                    *tcfg->tconfig->maxp_inv,
1726                                    *tcfg->tlevel);
1727         if (!check_drop_rate(&diff, drop_rate, drop_prob, (double)tcfg->tqueue->drop_tolerance))
1728                 result = FAIL;
1729
1730         printf("%s", tcfg->htxt);
1731
1732         printf("%-16u%-9u%-15u0x%08x     %-10u%-10u%-10u%-13.2lf%-13.2lf\n",
1733                avg, *tcfg->tconfig->wq_log2, RTE_RED_SCALING,
1734                avg_max, avg_max_bits,
1735                *tcfg->tvar->enqueued, *tcfg->tvar->dropped,
1736                drop_prob * 100.0, drop_rate * 100.0);
1737 out:
1738         return result;
1739 }
1740
1741 /**
1742  * define the functional and performance tests to be executed
1743  */
1744 struct tests func_tests[] = {
1745         { &func_test1_config, func_test1 },
1746         { &func_test2_config, func_test2 },
1747         { &func_test3_config, func_test3 },
1748         { &func_test4_config, func_test4 },
1749         { &func_test5_config, func_test5 },
1750         { &func_test6_config, func_test6 },
1751         { &ovfl_test1_config, ovfl_test1 },
1752 };
1753
1754 struct tests func_tests_quick[] = {
1755         { &func_test1_config, func_test1 },
1756         { &func_test2_config, func_test2 },
1757         { &func_test3_config, func_test3 },
1758         /* no test 4 as it takes a lot of time */
1759         { &func_test5_config, func_test5 },
1760         { &func_test6_config, func_test6 },
1761         { &ovfl_test1_config, ovfl_test1 },
1762 };
1763
1764 struct tests perf_tests[] = {
1765         { &perf1_test1_config, perf1_test },
1766         { &perf1_test2_config, perf1_test },
1767         { &perf1_test3_config, perf1_test },
1768         { &perf2_test4_config, perf2_test },
1769         { &perf2_test5_config, perf2_test },
1770         { &perf2_test6_config, perf2_test },
1771 };
1772
1773 /**
1774  * function to execute the required_red tests
1775  */
1776 static void run_tests(struct tests *test_type, uint32_t test_count, uint32_t *num_tests, uint32_t *num_pass)
1777 {
1778         enum test_result result = PASS;
1779         uint32_t i = 0;
1780
1781         for (i = 0; i < test_count; i++) {
1782                 printf("\n--------------------------------------------------------------------------------\n");
1783                 result = test_type[i].testfn(test_type[i].testcfg);
1784                 (*num_tests)++;
1785                 if (result == PASS) {
1786                         (*num_pass)++;
1787                                 printf("-------------------------------------<pass>-------------------------------------\n");
1788                 } else {
1789                         printf("-------------------------------------<fail>-------------------------------------\n");
1790                 }
1791         }
1792         return;
1793 }
1794
1795 /**
1796  * check if functions accept invalid parameters
1797  *
1798  * First, all functions will be called without initialized RED
1799  * Then, all of them will be called with NULL/invalid parameters
1800  *
1801  * Some functions are not tested as they are performance-critical and thus
1802  * don't do any parameter checking.
1803  */
1804 static int
1805 test_invalid_parameters(void)
1806 {
1807         struct rte_red_config config;
1808
1809         if (rte_red_rt_data_init(NULL) == 0) {
1810                 printf("rte_red_rt_data_init should have failed!\n");
1811                 return -1;
1812         }
1813
1814         if (rte_red_config_init(NULL, 0, 0, 0, 0) == 0) {
1815                 printf("rte_red_config_init should have failed!\n");
1816                 return -1;
1817         }
1818
1819         if (rte_red_rt_data_init(NULL) == 0) {
1820                 printf("rte_red_rt_data_init should have failed!\n");
1821                 return -1;
1822         }
1823
1824         /* NULL config */
1825         if (rte_red_config_init(NULL, 0, 0, 0, 0) == 0) {
1826                 printf("%i: rte_red_config_init should have failed!\n", __LINE__);
1827                 return -1;
1828         }
1829         /* min_treshold == max_treshold */
1830         if (rte_red_config_init(&config, 0, 1, 1, 0) == 0) {
1831                 printf("%i: rte_red_config_init should have failed!\n", __LINE__);
1832                 return -1;
1833         }
1834         /* min_treshold > max_treshold */
1835         if (rte_red_config_init(&config, 0, 2, 1, 0) == 0) {
1836                 printf("%i: rte_red_config_init should have failed!\n", __LINE__);
1837                 return -1;
1838         }
1839         /* wq_log2 > RTE_RED_WQ_LOG2_MAX */
1840         if (rte_red_config_init(&config,
1841                         RTE_RED_WQ_LOG2_MAX + 1, 1, 2, 0) == 0) {
1842                 printf("%i: rte_red_config_init should have failed!\n", __LINE__);
1843                 return -1;
1844         }
1845         /* wq_log2 < RTE_RED_WQ_LOG2_MIN */
1846         if (rte_red_config_init(&config,
1847                         RTE_RED_WQ_LOG2_MIN - 1, 1, 2, 0) == 0) {
1848                 printf("%i: rte_red_config_init should have failed!\n", __LINE__);
1849                 return -1;
1850         }
1851         /* maxp_inv > RTE_RED_MAXP_INV_MAX */
1852         if (rte_red_config_init(&config,
1853                         RTE_RED_WQ_LOG2_MIN, 1, 2, RTE_RED_MAXP_INV_MAX + 1) == 0) {
1854                 printf("%i: rte_red_config_init should have failed!\n", __LINE__);
1855                 return -1;
1856         }
1857         /* maxp_inv < RTE_RED_MAXP_INV_MIN */
1858         if (rte_red_config_init(&config,
1859                         RTE_RED_WQ_LOG2_MIN, 1, 2, RTE_RED_MAXP_INV_MIN - 1) == 0) {
1860                 printf("%i: rte_red_config_init should have failed!\n", __LINE__);
1861                 return -1;
1862         }
1863
1864         return 0;
1865 }
1866
1867 static void
1868 show_stats(const uint32_t num_tests, const uint32_t num_pass)
1869 {
1870         if (num_pass == num_tests)
1871                 printf("[total: %u, pass: %u]\n", num_tests, num_pass);
1872         else
1873                 printf("[total: %u, pass: %u, fail: %u]\n", num_tests, num_pass,
1874                        num_tests - num_pass);
1875 }
1876
1877 static int
1878 tell_the_result(const uint32_t num_tests, const uint32_t num_pass)
1879 {
1880         return (num_pass == num_tests) ? 0 : 1;
1881 }
1882
1883 static int
1884 test_red(void)
1885 {
1886         uint32_t num_tests = 0;
1887         uint32_t num_pass = 0;
1888
1889         if (test_invalid_parameters() < 0)
1890                 return -1;
1891         run_tests(func_tests_quick, RTE_DIM(func_tests_quick),
1892                   &num_tests, &num_pass);
1893         show_stats(num_tests, num_pass);
1894         return tell_the_result(num_tests, num_pass);
1895 }
1896
1897 static int
1898 test_red_perf(void)
1899 {
1900         uint32_t num_tests = 0;
1901         uint32_t num_pass = 0;
1902
1903         run_tests(perf_tests, RTE_DIM(perf_tests), &num_tests, &num_pass);
1904         show_stats(num_tests, num_pass);
1905         return tell_the_result(num_tests, num_pass);
1906 }
1907
1908 static int
1909 test_red_all(void)
1910 {
1911         uint32_t num_tests = 0;
1912         uint32_t num_pass = 0;
1913
1914         if (test_invalid_parameters() < 0)
1915                 return -1;
1916
1917         run_tests(func_tests, RTE_DIM(func_tests), &num_tests, &num_pass);
1918         run_tests(perf_tests, RTE_DIM(perf_tests), &num_tests, &num_pass);
1919         show_stats(num_tests, num_pass);
1920         return tell_the_result(num_tests, num_pass);
1921 }
1922
1923 static struct test_command red_cmd = {
1924         .command = "red_autotest",
1925         .callback = test_red,
1926 };
1927 REGISTER_TEST_COMMAND(red_cmd);
1928
1929 static struct test_command red_cmd_perf = {
1930         .command = "red_perf",
1931         .callback = test_red_perf,
1932 };
1933 REGISTER_TEST_COMMAND(red_cmd_perf);
1934
1935 static struct test_command red_cmd_all = {
1936         .command = "red_all",
1937         .callback = test_red_all,
1938 };
1939 REGISTER_TEST_COMMAND(red_cmd_all);