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