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