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