xref: /dpdk/app/test/test_efd.c (revision b5662e6d288762fe2c538551eb03d68854896e0b)
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