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