xref: /dpdk/app/test/test_efd.c (revision 68a03efeed657e6e05f281479b33b51102797e15)
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_main_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);
465