app/test: add EFD functional and perf tests
[dpdk.git] / app / test / test_efd.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2016-2017 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 <rte_memcpy.h>
35 #include <rte_malloc.h>
36 #include <rte_efd.h>
37 #include <rte_byteorder.h>
38 #include <rte_random.h>
39 #include <rte_debug.h>
40 #include <rte_ip.h>
41
42 #include "test.h"
43
44 #define EFD_TEST_KEY_LEN 8
45 #define TABLE_SIZE (1 << 21)
46 #define ITERATIONS 3
47 static unsigned int test_socket_id;
48
49 /* 5-tuple key type */
50 struct flow_key {
51         uint32_t ip_src;
52         uint32_t ip_dst;
53         uint16_t port_src;
54         uint16_t port_dst;
55         uint8_t proto;
56 } __attribute__((packed));
57 /*
58  * Print out result of unit test efd operation.
59  */
60 #if defined(UNIT_TEST_EFD_VERBOSE)
61
62 static void print_key_info(const char *msg, const struct flow_key *key,
63                 efd_value_t val)
64 {
65         const uint8_t *p = (const uint8_t *) key;
66         unsigned int i;
67
68         printf("%s key:0x", msg);
69         for (i = 0; i < sizeof(struct flow_key); i++)
70                 printf("%02X", p[i]);
71
72         printf(" @ val %d\n", val);
73 }
74 #else
75
76 static void print_key_info(__attribute__((unused)) const char *msg,
77                 __attribute__((unused)) const struct flow_key *key,
78                 __attribute__((unused)) efd_value_t val)
79 {
80 }
81 #endif
82
83 /* Keys used by unit test functions */
84 static struct flow_key keys[5] = {
85         {
86                 .ip_src = IPv4(0x03, 0x02, 0x01, 0x00),
87                 .ip_dst = IPv4(0x07, 0x06, 0x05, 0x04),
88                 .port_src = 0x0908,
89                 .port_dst = 0x0b0a,
90                 .proto = 0x0c,
91         },
92         {
93                 .ip_src = IPv4(0x13, 0x12, 0x11, 0x10),
94                 .ip_dst = IPv4(0x17, 0x16, 0x15, 0x14),
95                 .port_src = 0x1918,
96                 .port_dst = 0x1b1a,
97                 .proto = 0x1c,
98         },
99         {
100                 .ip_src = IPv4(0x23, 0x22, 0x21, 0x20),
101                 .ip_dst = IPv4(0x27, 0x26, 0x25, 0x24),
102                 .port_src = 0x2928,
103                 .port_dst = 0x2b2a,
104                 .proto = 0x2c,
105         },
106         {
107                 .ip_src = IPv4(0x33, 0x32, 0x31, 0x30),
108                 .ip_dst = IPv4(0x37, 0x36, 0x35, 0x34),
109                 .port_src = 0x3938,
110                 .port_dst = 0x3b3a,
111                 .proto = 0x3c,
112         },
113         {
114                 .ip_src = IPv4(0x43, 0x42, 0x41, 0x40),
115                 .ip_dst = IPv4(0x47, 0x46, 0x45, 0x44),
116                 .port_src = 0x4948,
117                 .port_dst = 0x4b4a,
118                 .proto = 0x4c,
119         }
120 };
121 /* Array to store the data */
122 efd_value_t data[5];
123
124 static inline uint8_t efd_get_all_sockets_bitmask(void)
125 {
126         uint8_t all_cpu_sockets_bitmask = 0;
127         unsigned int i;
128         unsigned int next_lcore = rte_get_master_lcore();
129         const int val_true = 1, val_false = 0;
130         for (i = 0; i < rte_lcore_count(); i++) {
131                 all_cpu_sockets_bitmask |= 1 << rte_lcore_to_socket_id(next_lcore);
132                 next_lcore = rte_get_next_lcore(next_lcore, val_false, val_true);
133         }
134
135         return all_cpu_sockets_bitmask;
136 }
137
138 /*
139  * Basic sequence of operations for a single key:
140  *      - add
141  *      - lookup (hit)
142  *      - delete
143  * Note: lookup (miss) is not applicable since this is a filter
144  */
145 static int test_add_delete(void)
146 {
147         struct rte_efd_table *handle;
148         /* test with standard add/lookup/delete functions */
149         efd_value_t prev_value;
150         printf("Entering %s\n", __func__);
151
152         handle = rte_efd_create("test_add_delete",
153                         TABLE_SIZE, sizeof(struct flow_key),
154                         efd_get_all_sockets_bitmask(), test_socket_id);
155         TEST_ASSERT_NOT_NULL(handle, "Error creating the EFD table\n");
156
157         data[0] = mrand48() & ((1 << RTE_EFD_VALUE_NUM_BITS) - 1);
158         TEST_ASSERT_SUCCESS(rte_efd_update(handle, test_socket_id, &keys[0],
159                         data[0]),
160                         "Error inserting the key");
161         print_key_info("Add", &keys[0], data[0]);
162
163         TEST_ASSERT_EQUAL(rte_efd_lookup(handle, test_socket_id, &keys[0]),
164                         data[0],
165                         "failed to find key");
166
167         TEST_ASSERT_SUCCESS(rte_efd_delete(handle, test_socket_id, &keys[0],
168                         &prev_value),
169                         "failed to delete key");
170         TEST_ASSERT_EQUAL(prev_value, data[0],
171                         "failed to delete the expected value, got %d, "
172                         "expected %d", prev_value, data[0]);
173         print_key_info("Del", &keys[0], data[0]);
174
175         rte_efd_free(handle);
176
177         return 0;
178 }
179
180 /*
181  * Sequence of operations for a single key:
182  *      - add
183  *      - lookup: hit
184  *      - add: update
185  *      - lookup: hit (updated data)
186  *      - delete: hit
187  */
188 static int test_add_update_delete(void)
189 {
190         struct rte_efd_table *handle;
191         printf("Entering %s\n", __func__);
192         /* test with standard add/lookup/delete functions */
193         efd_value_t prev_value;
194         data[1] = mrand48() & ((1 << RTE_EFD_VALUE_NUM_BITS) - 1);
195
196         handle = rte_efd_create("test_add_update_delete", TABLE_SIZE,
197                         sizeof(struct flow_key),
198                         efd_get_all_sockets_bitmask(), test_socket_id);
199         TEST_ASSERT_NOT_NULL(handle, "Error creating the efd table\n");
200
201         TEST_ASSERT_SUCCESS(rte_efd_update(handle, test_socket_id, &keys[1],
202                         data[1]), "Error inserting the key");
203         print_key_info("Add", &keys[1], data[1]);
204
205         TEST_ASSERT_EQUAL(rte_efd_lookup(handle, test_socket_id, &keys[1]),
206                         data[1], "failed to find key");
207         print_key_info("Lkp", &keys[1], data[1]);
208
209         data[1] = data[1] + 1;
210         TEST_ASSERT_SUCCESS(rte_efd_update(handle, test_socket_id, &keys[1],
211                         data[1]), "Error re-inserting the key");
212         print_key_info("Add", &keys[1], data[1]);
213
214         TEST_ASSERT_EQUAL(rte_efd_lookup(handle, test_socket_id, &keys[1]),
215                         data[1], "failed to find key");
216         print_key_info("Lkp", &keys[1], data[1]);
217
218         TEST_ASSERT_SUCCESS(rte_efd_delete(handle, test_socket_id, &keys[1],
219                         &prev_value), "failed to delete key");
220         TEST_ASSERT_EQUAL(prev_value, data[1],
221                         "failed to delete the expected value, got %d, "
222                         "expected %d", prev_value, data[1]);
223         print_key_info("Del", &keys[1], data[1]);
224
225
226         rte_efd_free(handle);
227         return 0;
228 }
229
230 /*
231  * Sequence of operations for find existing EFD table
232  *
233  *  - create table
234  *  - find existing table: hit
235  *  - find non-existing table: miss
236  *
237  */
238 static int test_efd_find_existing(void)
239 {
240         struct rte_efd_table *handle = NULL, *result = NULL;
241
242         printf("Entering %s\n", __func__);
243
244         /* Create EFD table. */
245         handle = rte_efd_create("efd_find_existing", TABLE_SIZE,
246                         sizeof(struct flow_key),
247                         efd_get_all_sockets_bitmask(), test_socket_id);
248         TEST_ASSERT_NOT_NULL(handle, "Error creating the efd table\n");
249
250         /* Try to find existing EFD table */
251         result = rte_efd_find_existing("efd_find_existing");
252         TEST_ASSERT_EQUAL(result, handle, "could not find existing efd table");
253
254         /* Try to find non-existing EFD table */
255         result = rte_efd_find_existing("efd_find_non_existing");
256         TEST_ASSERT_NULL(result, "found table that shouldn't exist");
257
258         /* Cleanup. */
259         rte_efd_free(handle);
260
261         return 0;
262 }
263
264 /*
265  * Sequence of operations for 5 keys
266  *      - add keys
267  *      - lookup keys: hit  (bulk)
268  *      - add keys (update)
269  *      - lookup keys: hit (updated data)
270  *      - delete keys : hit
271  */
272 static int test_five_keys(void)
273 {
274         struct rte_efd_table *handle;
275         const void *key_array[5] = {0};
276         efd_value_t result[5] = {0};
277         efd_value_t prev_value;
278         unsigned int i;
279         printf("Entering %s\n", __func__);
280
281         handle = rte_efd_create("test_five_keys", TABLE_SIZE,
282                         sizeof(struct flow_key),
283                         efd_get_all_sockets_bitmask(), test_socket_id);
284         TEST_ASSERT_NOT_NULL(handle, "Error creating the efd table\n");
285
286         /* Setup data */
287         for (i = 0; i < 5; i++)
288                 data[i] = mrand48() & ((1 << RTE_EFD_VALUE_NUM_BITS) - 1);
289
290         /* Add */
291         for (i = 0; i < 5; i++) {
292                 TEST_ASSERT_SUCCESS(rte_efd_update(handle, test_socket_id,
293                                 &keys[i], data[i]),
294                                 "Error inserting the key");
295                 print_key_info("Add", &keys[i], data[i]);
296         }
297
298         /* Lookup */
299         for (i = 0; i < 5; i++)
300                 key_array[i] = &keys[i];
301
302         rte_efd_lookup_bulk(handle, test_socket_id, 5,
303                         (const void **) (void *) &key_array, result);
304
305         for (i = 0; i < 5; i++) {
306                 TEST_ASSERT_EQUAL(result[i], data[i],
307                                 "bulk: failed to find key. Expected %d, got %d",
308                                 data[i], result[i]);
309                 print_key_info("Lkp", &keys[i], data[i]);
310         }
311
312         /* Modify data (bulk) */
313         for (i = 0; i < 5; i++)
314                 data[i] = data[i] + 1;
315
316         /* Add - update */
317         for (i = 0; i < 5; i++) {
318                 TEST_ASSERT_SUCCESS(rte_efd_update(handle, test_socket_id,
319                                 &keys[i], data[i]),
320                                 "Error inserting the key");
321                 print_key_info("Add", &keys[i], data[i]);
322         }
323
324         /* Lookup */
325         for (i = 0; i < 5; i++) {
326                 TEST_ASSERT_EQUAL(rte_efd_lookup(handle, test_socket_id,
327                                 &keys[i]), data[i],
328                                 "failed to find key");
329                 print_key_info("Lkp", &keys[i], data[i]);
330         }
331
332         /* Delete */
333         for (i = 0; i < 5; i++) {
334                 TEST_ASSERT_SUCCESS(rte_efd_delete(handle, test_socket_id,
335                                 &keys[i], &prev_value),
336                                 "failed to delete key");
337                 TEST_ASSERT_EQUAL(prev_value, data[i],
338                                 "failed to delete the expected value, got %d, "
339                                 "expected %d", prev_value, data[i]);
340                 print_key_info("Del", &keys[i], data[i]);
341         }
342
343
344         rte_efd_free(handle);
345
346         return 0;
347 }
348
349 /*
350  * Test to see the average table utilization (entries added/max entries)
351  * before hitting a random entry that cannot be added
352  */
353 static int test_average_table_utilization(void)
354 {
355         struct rte_efd_table *handle = NULL;
356         uint32_t num_rules_in = TABLE_SIZE;
357         uint8_t simple_key[EFD_TEST_KEY_LEN];
358         unsigned int i, j;
359         unsigned int added_keys, average_keys_added = 0;
360
361         printf("Evaluating table utilization and correctness, please wait\n");
362         fflush(stdout);
363
364         for (j = 0; j < ITERATIONS; j++) {
365                 handle = rte_efd_create("test_efd", num_rules_in,
366                                 EFD_TEST_KEY_LEN, efd_get_all_sockets_bitmask(),
367                                 test_socket_id);
368                 if (handle == NULL) {
369                         printf("efd table creation failed\n");
370                         return -1;
371                 }
372
373                 unsigned int succeeded = 0;
374                 unsigned int lost_keys = 0;
375
376                 /* Add random entries until key cannot be added */
377                 for (added_keys = 0; added_keys < num_rules_in; added_keys++) {
378
379                         for (i = 0; i < EFD_TEST_KEY_LEN; i++)
380                                 simple_key[i] = rte_rand() & 0xFF;
381
382                         efd_value_t val = simple_key[0];
383
384                         if (rte_efd_update(handle, test_socket_id, simple_key,
385                                                 val))
386                                 break; /* continue;*/
387                         if (rte_efd_lookup(handle, test_socket_id, simple_key)
388                                         != val)
389                                 lost_keys++;
390                         else
391                                 succeeded++;
392                 }
393
394                 average_keys_added += succeeded;
395
396                 /* Reset the table */
397                 rte_efd_free(handle);
398
399                 /* Print progress on operations */
400                 printf("Added %10u      Succeeded %10u  Lost %10u\n",
401                                 added_keys, succeeded, lost_keys);
402                 fflush(stdout);
403         }
404
405         average_keys_added /= ITERATIONS;
406
407         printf("\nAverage table utilization = %.2f%% (%u/%u)\n",
408                         ((double) average_keys_added / num_rules_in * 100),
409                         average_keys_added, num_rules_in);
410
411         return 0;
412 }
413
414 /*
415  * Do tests for EFD creation with bad parameters.
416  */
417 static int test_efd_creation_with_bad_parameters(void)
418 {
419         struct rte_efd_table *handle, *tmp;
420         printf("Entering %s, **Errors are expected **\n", __func__);
421
422         handle = rte_efd_create("creation_with_bad_parameters_0", TABLE_SIZE, 0,
423                         efd_get_all_sockets_bitmask(), test_socket_id);
424         if (handle != NULL) {
425                 rte_efd_free(handle);
426                 printf("Impossible creating EFD table successfully "
427                         "if key_len in parameter is zero\n");
428                 return -1;
429         }
430
431         handle = rte_efd_create("creation_with_bad_parameters_1", TABLE_SIZE,
432                         sizeof(struct flow_key), 0, test_socket_id);
433         if (handle != NULL) {
434                 rte_efd_free(handle);
435                 printf("Impossible creating EFD table successfully "
436                         "with invalid socket bitmask\n");
437                 return -1;
438         }
439
440         handle = rte_efd_create("creation_with_bad_parameters_2", TABLE_SIZE,
441                         sizeof(struct flow_key), efd_get_all_sockets_bitmask(),
442                         255);
443         if (handle != NULL) {
444                 rte_efd_free(handle);
445                 printf("Impossible creating EFD table successfully "
446                         "with invalid socket\n");
447                 return -1;
448         }
449
450         /* test with same name should fail */
451         handle = rte_efd_create("same_name", TABLE_SIZE,
452                         sizeof(struct flow_key),
453                         efd_get_all_sockets_bitmask(), 0);
454         if (handle == NULL) {
455                 printf("Cannot create first EFD table with 'same_name'\n");
456                 return -1;
457         }
458         tmp = rte_efd_create("same_name", TABLE_SIZE, sizeof(struct flow_key),
459                         efd_get_all_sockets_bitmask(), 0);
460         if (tmp != NULL) {
461                 printf("Creation of EFD table with same name should fail\n");
462                 rte_efd_free(handle);
463                 rte_efd_free(tmp);
464                 return -1;
465         }
466         rte_efd_free(handle);
467
468         printf("# Test successful. No more errors expected\n");
469
470         return 0;
471 }
472
473 static int
474 test_efd(void)
475 {
476
477         /* Unit tests */
478         if (test_add_delete() < 0)
479                 return -1;
480         if (test_efd_find_existing() < 0)
481                 return -1;
482         if (test_add_update_delete() < 0)
483                 return -1;
484         if (test_five_keys() < 0)
485                 return -1;
486         if (test_efd_creation_with_bad_parameters() < 0)
487                 return -1;
488         if (test_average_table_utilization() < 0)
489                 return -1;
490
491         return 0;
492 }
493
494 REGISTER_TEST_COMMAND(efd_autotest, test_efd);