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