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