xref: /dpdk/app/test/test_service_cores.c (revision fd1bcb6c58b0752f408beaedfdb83a2e82173129)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2017 Intel Corporation
3  */
4 
5 #include <rte_common.h>
6 #include <rte_cycles.h>
7 #include <rte_hexdump.h>
8 #include <rte_malloc.h>
9 #include <rte_mbuf.h>
10 #include <rte_memcpy.h>
11 #include <rte_random.h>
12 
13 #include <rte_service.h>
14 #include <rte_service_component.h>
15 
16 #include "test.h"
17 
18 /* used as the service core ID */
19 static uint32_t slcore_id;
20 /* track service call count */
21 static uint64_t service_calls;
22 static uint64_t service_idle_calls;
23 static uint64_t service_error_calls;
24 /* used as a flag to check if a function was run */
25 static uint32_t service_remote_launch_flag;
26 
27 #define SERVICE_DELAY 1
28 #define TIMEOUT_MS 1000
29 
30 #define DUMMY_SERVICE_NAME "dummy_service"
31 #define MT_SAFE_SERVICE_NAME "mt_safe_service"
32 
33 static int
34 testsuite_setup(void)
35 {
36 	slcore_id = rte_get_next_lcore(/* start core */ -1,
37 				       /* skip main */ 1,
38 				       /* wrap */ 0);
39 
40 	return TEST_SUCCESS;
41 }
42 
43 static void
44 testsuite_teardown(void)
45 {
46 	/* release service cores? */
47 }
48 
49 static int32_t dummy_cb(void *args)
50 {
51 	RTE_SET_USED(args);
52 	int32_t rc;
53 
54 	service_calls++;
55 
56 	switch (rte_rand_max(3)) {
57 	case 0:
58 		rc = 0;
59 		break;
60 	case 1:
61 		service_idle_calls++;
62 		rc = -EAGAIN;
63 		break;
64 	default:
65 		service_error_calls++;
66 		rc = -ENOENT;
67 		break;
68 	}
69 
70 	rte_delay_ms(SERVICE_DELAY);
71 
72 	return rc;
73 }
74 
75 static int32_t dummy_mt_unsafe_cb(void *args)
76 {
77 	/* before running test, the initialization has set pass_test to 1.
78 	 * If the CAS in service-cores is working correctly, the code here
79 	 * should never fail to take the lock. If the lock *is* taken, fail the
80 	 * test, because two threads are concurrently in a non-MT safe callback.
81 	 */
82 	uint32_t *test_params = args;
83 	RTE_ATOMIC(uint32_t) *lock = (uint32_t __rte_atomic *)&test_params[0];
84 	uint32_t *pass_test = &test_params[1];
85 	uint32_t exp = 0;
86 	int lock_taken = rte_atomic_compare_exchange_strong_explicit(lock, &exp, 1,
87 					rte_memory_order_relaxed, rte_memory_order_relaxed);
88 	if (lock_taken) {
89 		/* delay with the lock held */
90 		rte_delay_ms(250);
91 		rte_atomic_store_explicit(lock, 0, rte_memory_order_relaxed);
92 	} else {
93 		/* 2nd thread will fail to take lock, so clear pass flag */
94 		*pass_test = 0;
95 	}
96 
97 	return 0;
98 }
99 
100 
101 static int32_t dummy_mt_safe_cb(void *args)
102 {
103 	/* Atomic checks to ensure MT safe services allow > 1 thread to
104 	 * concurrently run the callback. The concept is as follows;
105 	 * 1) if lock is available, take the lock then delay
106 	 * 2) if first lock is taken, and a thread arrives in the CB, we know
107 	 *    that 2 threads are running the callback at the same time: MT safe
108 	 */
109 	uint32_t *test_params = args;
110 	RTE_ATOMIC(uint32_t) *lock = (uint32_t __rte_atomic *)&test_params[0];
111 	uint32_t *pass_test = &test_params[1];
112 	uint32_t exp = 0;
113 	int lock_taken = rte_atomic_compare_exchange_strong_explicit(lock, &exp, 1,
114 					rte_memory_order_relaxed, rte_memory_order_relaxed);
115 	if (lock_taken) {
116 		/* delay with the lock held */
117 		rte_delay_ms(250);
118 		rte_atomic_store_explicit(lock, 0, rte_memory_order_relaxed);
119 	} else {
120 		/* 2nd thread will fail to take lock, so set pass flag */
121 		*pass_test = 1;
122 	}
123 
124 	return 0;
125 }
126 
127 /* unregister all services */
128 static int
129 unregister_all(void)
130 {
131 	uint32_t i;
132 
133 	TEST_ASSERT_EQUAL(-EINVAL, rte_service_component_unregister(1000),
134 			"Unregistered invalid service id");
135 
136 	uint32_t c = rte_service_get_count();
137 	for (i = 0; i < c; i++) {
138 		TEST_ASSERT_EQUAL(0, rte_service_component_unregister(i),
139 				"Error unregistering a valid service");
140 	}
141 
142 	rte_service_lcore_reset_all();
143 	rte_eal_mp_wait_lcore();
144 
145 	service_calls = 0;
146 	service_idle_calls = 0;
147 	service_error_calls = 0;
148 
149 	return TEST_SUCCESS;
150 }
151 
152 /* Wait until service lcore not active, or for TIMEOUT_MS */
153 static void
154 wait_slcore_inactive(uint32_t slcore_id)
155 {
156 	int i;
157 
158 	for (i = 0; rte_service_lcore_may_be_active(slcore_id) == 1 &&
159 			i < TIMEOUT_MS; i++)
160 		rte_delay_ms(1);
161 }
162 
163 /* register a single dummy service */
164 static int
165 dummy_register(void)
166 {
167 	/* make sure there are no remains from previous tests */
168 	unregister_all();
169 
170 	struct rte_service_spec service;
171 	memset(&service, 0, sizeof(struct rte_service_spec));
172 
173 	TEST_ASSERT_EQUAL(-EINVAL,
174 			rte_service_component_register(&service, NULL),
175 			"Invalid callback");
176 	service.callback = dummy_cb;
177 
178 	TEST_ASSERT_EQUAL(-EINVAL,
179 			rte_service_component_register(&service, NULL),
180 			"Invalid name");
181 	snprintf(service.name, sizeof(service.name), DUMMY_SERVICE_NAME);
182 
183 	uint32_t id;
184 	TEST_ASSERT_EQUAL(0, rte_service_component_register(&service, &id),
185 			"Failed to register valid service");
186 
187 	rte_service_component_runstate_set(id, 1);
188 
189 	return TEST_SUCCESS;
190 }
191 
192 /* verify get_by_name() service lookup */
193 static int
194 service_get_by_name(void)
195 {
196 	unregister_all();
197 
198 	uint32_t sid;
199 	TEST_ASSERT_EQUAL(-ENODEV,
200 			rte_service_get_by_name(DUMMY_SERVICE_NAME, &sid),
201 			"get by name with invalid name should return -ENODEV");
202 	TEST_ASSERT_EQUAL(-EINVAL,
203 			rte_service_get_by_name(DUMMY_SERVICE_NAME, 0x0),
204 			"get by name with NULL ptr should return -ENODEV");
205 
206 	/* register service */
207 	struct rte_service_spec service;
208 	memset(&service, 0, sizeof(struct rte_service_spec));
209 	TEST_ASSERT_EQUAL(-EINVAL,
210 			rte_service_component_register(&service, NULL),
211 			"Invalid callback");
212 	service.callback = dummy_cb;
213 	TEST_ASSERT_EQUAL(-EINVAL,
214 			rte_service_component_register(&service, NULL),
215 			"Invalid name");
216 	snprintf(service.name, sizeof(service.name), DUMMY_SERVICE_NAME);
217 	TEST_ASSERT_EQUAL(0, rte_service_component_register(&service, NULL),
218 			"Failed to register valid service");
219 
220 	/* we unregistered all service, now registering 1, should be id 0 */
221 	uint32_t service_id_as_expected = 0;
222 	TEST_ASSERT_EQUAL(0, rte_service_get_by_name(DUMMY_SERVICE_NAME, &sid),
223 			"Service get_by_name should return 0 on valid inputs");
224 	TEST_ASSERT_EQUAL(service_id_as_expected, sid,
225 			"Service get_by_name should equal expected id");
226 
227 	unregister_all();
228 
229 	/* ensure after unregister, get_by_name returns NULL */
230 	TEST_ASSERT_EQUAL(-ENODEV,
231 			rte_service_get_by_name(DUMMY_SERVICE_NAME, &sid),
232 			"get by name should return -ENODEV after unregister");
233 
234 	return TEST_SUCCESS;
235 }
236 
237 /* verify probe of capabilities */
238 static int
239 service_probe_capability(void)
240 {
241 	unregister_all();
242 
243 	struct rte_service_spec service;
244 	memset(&service, 0, sizeof(struct rte_service_spec));
245 	service.callback = dummy_cb;
246 	snprintf(service.name, sizeof(service.name), DUMMY_SERVICE_NAME);
247 	service.capabilities |= RTE_SERVICE_CAP_MT_SAFE;
248 	TEST_ASSERT_EQUAL(0, rte_service_component_register(&service, NULL),
249 			"Register of MT SAFE service failed");
250 
251 	/* verify flag is enabled */
252 	const uint32_t sid = 0;
253 	int32_t mt = rte_service_probe_capability(sid, RTE_SERVICE_CAP_MT_SAFE);
254 	TEST_ASSERT_EQUAL(1, mt, "MT SAFE capability flag not set.");
255 
256 
257 	unregister_all();
258 
259 	memset(&service, 0, sizeof(struct rte_service_spec));
260 	service.callback = dummy_cb;
261 	snprintf(service.name, sizeof(service.name), DUMMY_SERVICE_NAME);
262 	TEST_ASSERT_EQUAL(0, rte_service_component_register(&service, NULL),
263 			"Register of non-MT safe service failed");
264 
265 	/* verify flag is enabled */
266 	mt = rte_service_probe_capability(sid, RTE_SERVICE_CAP_MT_SAFE);
267 	TEST_ASSERT_EQUAL(0, mt, "MT SAFE cap flag set on non MT SAFE service");
268 
269 	return unregister_all();
270 }
271 
272 /* verify the service name */
273 static int
274 service_name(void)
275 {
276 	const char *name = rte_service_get_name(0);
277 	int equal = strcmp(name, DUMMY_SERVICE_NAME);
278 	TEST_ASSERT_EQUAL(0, equal, "Error: Service name not correct");
279 
280 	return unregister_all();
281 }
282 
283 /* verify service attr get */
284 static int
285 service_attr_get(void)
286 {
287 	/* ensure all services unregistered so cycle counts are zero */
288 	unregister_all();
289 
290 	struct rte_service_spec service;
291 	memset(&service, 0, sizeof(struct rte_service_spec));
292 	service.callback = dummy_cb;
293 	snprintf(service.name, sizeof(service.name), DUMMY_SERVICE_NAME);
294 	service.capabilities |= RTE_SERVICE_CAP_MT_SAFE;
295 	uint32_t id;
296 	TEST_ASSERT_EQUAL(0, rte_service_component_register(&service, &id),
297 			"Register of  service failed");
298 	rte_service_component_runstate_set(id, 1);
299 	TEST_ASSERT_EQUAL(0, rte_service_runstate_set(id, 1),
300 			"Error: Service start returned non-zero");
301 	rte_service_set_stats_enable(id, 1);
302 
303 	uint32_t attr_id = UINT32_MAX;
304 	uint64_t attr_value = 0xdead;
305 	/* check error return values */
306 	TEST_ASSERT_EQUAL(-EINVAL, rte_service_attr_get(id, attr_id,
307 							&attr_value),
308 			"Invalid attr_id didn't return -EINVAL");
309 
310 	attr_id = RTE_SERVICE_ATTR_CYCLES;
311 	TEST_ASSERT_EQUAL(-EINVAL, rte_service_attr_get(UINT32_MAX, attr_id,
312 							&attr_value),
313 			"Invalid service id didn't return -EINVAL");
314 
315 	TEST_ASSERT_EQUAL(-EINVAL, rte_service_attr_get(id, attr_id, NULL),
316 			"Invalid attr_value pointer id didn't return -EINVAL");
317 
318 	/* check correct (zero) return value and correct value (zero) */
319 	TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_id, &attr_value),
320 			"Valid attr_get() call didn't return success");
321 	TEST_ASSERT_EQUAL(0, attr_value,
322 			"attr_get() call didn't set correct cycles (zero)");
323 	/* check correct call counts */
324 	const int attr_calls = RTE_SERVICE_ATTR_CALL_COUNT;
325 	TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_calls, &attr_value),
326 			"Valid attr_get() call didn't return success");
327 	TEST_ASSERT_EQUAL(0, attr_value, "Call count was not zero");
328 	const int attr_idle_calls = RTE_SERVICE_ATTR_IDLE_CALL_COUNT;
329 	TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_idle_calls, &attr_value),
330 			"Valid attr_get() call didn't return success");
331 	TEST_ASSERT_EQUAL(0, attr_value, "Idle call count was not zero");
332 	const int attr_error_calls = RTE_SERVICE_ATTR_ERROR_CALL_COUNT;
333 	TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_error_calls, &attr_value),
334 			"Valid attr_get() call didn't return success");
335 	TEST_ASSERT_EQUAL(0, attr_value, "Error call count was not zero");
336 
337 	/* Call service to increment cycle count */
338 	TEST_ASSERT_EQUAL(0, rte_service_lcore_add(slcore_id),
339 			"Service core add did not return zero");
340 	TEST_ASSERT_EQUAL(0, rte_service_map_lcore_set(id, slcore_id, 1),
341 			"Enabling valid service and core failed");
342 	TEST_ASSERT_EQUAL(0, rte_service_lcore_start(slcore_id),
343 			"Starting service core failed");
344 
345 	/* wait for the service lcore to run */
346 	rte_delay_ms(200);
347 
348 	TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_id, &attr_value),
349 			"Valid attr_get() call didn't return success");
350 	int cycles_gt_zero = attr_value > 0;
351 	TEST_ASSERT_EQUAL(1, cycles_gt_zero,
352 			"attr_get() failed to get cycles (expected > zero)");
353 
354 	TEST_ASSERT_EQUAL(0, rte_service_map_lcore_set(id, slcore_id, 0),
355 			"Disabling valid service and core failed");
356 	TEST_ASSERT_EQUAL(0, rte_service_lcore_stop(slcore_id),
357 			"Failed to stop service lcore");
358 
359 	wait_slcore_inactive(slcore_id);
360 
361 	TEST_ASSERT_EQUAL(0, rte_service_lcore_may_be_active(slcore_id),
362 			  "Service lcore not stopped after waiting.");
363 
364 	TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_calls, &attr_value),
365 			"Valid attr_get() call didn't return success");
366 	TEST_ASSERT_EQUAL(service_calls, attr_value, "Unexpected call count");
367 	TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_idle_calls, &attr_value),
368 			"Valid attr_get() call didn't return success");
369 	TEST_ASSERT_EQUAL(service_idle_calls, attr_value, "Unexpected idle call count");
370 	TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_error_calls, &attr_value),
371 			"Valid attr_get() call didn't return success");
372 	TEST_ASSERT_EQUAL(service_error_calls, attr_value, "Unexpected error call count");
373 
374 	TEST_ASSERT_EQUAL(0, rte_service_attr_reset_all(id),
375 			"Valid attr_reset_all() return success");
376 
377 	TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_id, &attr_value),
378 			"Valid attr_get() call didn't return success");
379 	TEST_ASSERT_EQUAL(0, attr_value,
380 			"attr_get() call didn't set correct cycles (zero)");
381 	/* ensure call counts are zero */
382 	TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_calls, &attr_value),
383 			"Valid attr_get() call didn't return success");
384 	TEST_ASSERT_EQUAL(0, attr_value, "Call count was not reset");
385 	TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_idle_calls, &attr_value),
386 			"Valid attr_get() call didn't return success");
387 	TEST_ASSERT_EQUAL(0, attr_value, "Idle call count was not reset");
388 	TEST_ASSERT_EQUAL(0, rte_service_attr_get(id, attr_error_calls, &attr_value),
389 			"Valid attr_get() call didn't return success");
390 	TEST_ASSERT_EQUAL(0, attr_value, "Error call count was not reset");
391 
392 	return unregister_all();
393 }
394 
395 /* verify service lcore attr get */
396 static int
397 service_lcore_attr_get(void)
398 {
399 	/* ensure all services unregistered so cycle counts are zero */
400 	unregister_all();
401 
402 	struct rte_service_spec service;
403 	memset(&service, 0, sizeof(struct rte_service_spec));
404 	service.callback = dummy_cb;
405 	snprintf(service.name, sizeof(service.name), DUMMY_SERVICE_NAME);
406 	service.capabilities |= RTE_SERVICE_CAP_MT_SAFE;
407 	uint32_t id;
408 	TEST_ASSERT_EQUAL(0, rte_service_component_register(&service, &id),
409 			"Register of  service failed");
410 	rte_service_component_runstate_set(id, 1);
411 	TEST_ASSERT_EQUAL(0, rte_service_runstate_set(id, 1),
412 			"Error: Service start returned non-zero");
413 	rte_service_set_stats_enable(id, 1);
414 
415 	uint64_t lcore_attr_value = 0xdead;
416 	uint32_t lcore_attr_id = UINT32_MAX;
417 
418 	/* check error return values */
419 	TEST_ASSERT_EQUAL(-EINVAL, rte_service_lcore_attr_get(UINT32_MAX,
420 			lcore_attr_id, &lcore_attr_value),
421 			"Invalid lcore_id didn't return -EINVAL");
422 	TEST_ASSERT_EQUAL(-ENOTSUP, rte_service_lcore_attr_get(rte_lcore_id(),
423 			lcore_attr_id, &lcore_attr_value),
424 			"Non-service core didn't return -ENOTSUP");
425 
426 	/* Start service core to increment loop count */
427 	TEST_ASSERT_EQUAL(0, rte_service_lcore_add(slcore_id),
428 			"Service core add did not return zero");
429 	TEST_ASSERT_EQUAL(0, rte_service_map_lcore_set(id, slcore_id, 1),
430 			"Enabling valid service and core failed");
431 	/* Ensure service is not active before starting */
432 	TEST_ASSERT_EQUAL(0, rte_service_lcore_may_be_active(slcore_id),
433 			"Not-active service core reported as active");
434 	TEST_ASSERT_EQUAL(0, rte_service_lcore_start(slcore_id),
435 			"Starting service core failed");
436 
437 	/* wait for the service lcore to run */
438 	rte_delay_ms(200);
439 
440 	lcore_attr_id = RTE_SERVICE_LCORE_ATTR_LOOPS;
441 	TEST_ASSERT_EQUAL(0, rte_service_lcore_attr_get(slcore_id,
442 			lcore_attr_id, &lcore_attr_value),
443 			"Valid lcore_attr_get() call didn't return success");
444 	int loops_gt_zero = lcore_attr_value > 0;
445 	TEST_ASSERT_EQUAL(1, loops_gt_zero,
446 			"lcore_attr_get() failed to get loops "
447 			"(expected > zero)");
448 
449 	lcore_attr_id = 42; /* invalid lcore attr id */
450 	TEST_ASSERT_EQUAL(-EINVAL, rte_service_lcore_attr_get(slcore_id,
451 			lcore_attr_id, &lcore_attr_value),
452 			"Invalid lcore attr didn't return -EINVAL");
453 
454 	/* Ensure service is active */
455 	TEST_ASSERT_EQUAL(1, rte_service_lcore_may_be_active(slcore_id),
456 			"Active service core reported as not-active");
457 
458 	TEST_ASSERT_EQUAL(0, rte_service_map_lcore_set(id, slcore_id, 0),
459 			"Disabling valid service and core failed");
460 	TEST_ASSERT_EQUAL(0, rte_service_lcore_stop(slcore_id),
461 			"Failed to stop service lcore");
462 
463 	wait_slcore_inactive(slcore_id);
464 
465 	TEST_ASSERT_EQUAL(0, rte_service_lcore_may_be_active(slcore_id),
466 			  "Service lcore not stopped after waiting.");
467 
468 	TEST_ASSERT_EQUAL(0, rte_service_lcore_attr_reset_all(slcore_id),
469 			  "Valid lcore_attr_reset_all() didn't return success");
470 
471 	lcore_attr_id = RTE_SERVICE_LCORE_ATTR_LOOPS;
472 	TEST_ASSERT_EQUAL(0, rte_service_lcore_attr_get(slcore_id,
473 			lcore_attr_id, &lcore_attr_value),
474 			"Valid lcore_attr_get() call didn't return success");
475 	TEST_ASSERT_EQUAL(0, lcore_attr_value,
476 			"lcore_attr_get() didn't get correct loop count "
477 			"(zero)");
478 
479 	return unregister_all();
480 }
481 
482 /* verify service dump */
483 static int
484 service_dump(void)
485 {
486 	const uint32_t sid = 0;
487 	rte_service_set_stats_enable(sid, 1);
488 	rte_service_dump(stdout, 0);
489 	rte_service_set_stats_enable(sid, 0);
490 	rte_service_dump(stdout, 0);
491 	return unregister_all();
492 }
493 
494 /* start and stop a service */
495 static int
496 service_start_stop(void)
497 {
498 	const uint32_t sid = 0;
499 
500 	/* runstate_get() returns if service is running and slcore is mapped */
501 	TEST_ASSERT_EQUAL(0, rte_service_lcore_add(slcore_id),
502 			"Service core add did not return zero");
503 	int ret = rte_service_map_lcore_set(sid, slcore_id, 1);
504 	TEST_ASSERT_EQUAL(0, ret,
505 			"Enabling service core, expected 0 got %d", ret);
506 
507 	TEST_ASSERT_EQUAL(0, rte_service_runstate_get(sid),
508 			"Error: Service should be stopped");
509 
510 	TEST_ASSERT_EQUAL(0, rte_service_runstate_set(sid, 0),
511 			"Error: Service stopped returned non-zero");
512 
513 	TEST_ASSERT_EQUAL(0, rte_service_runstate_get(sid),
514 			"Error: Service is running - should be stopped");
515 
516 	TEST_ASSERT_EQUAL(0, rte_service_runstate_set(sid, 1),
517 			"Error: Service start returned non-zero");
518 
519 	TEST_ASSERT_EQUAL(1, rte_service_runstate_get(sid),
520 			"Error: Service is not running");
521 
522 	return unregister_all();
523 }
524 
525 
526 static int
527 service_remote_launch_func(void *arg)
528 {
529 	RTE_SET_USED(arg);
530 	service_remote_launch_flag = 1;
531 	return 0;
532 }
533 
534 /* enable and disable a lcore for a service */
535 static int
536 service_lcore_en_dis_able(void)
537 {
538 	const uint32_t sid = 0;
539 
540 	/* expected failure cases */
541 	TEST_ASSERT_EQUAL(-EINVAL, rte_service_map_lcore_set(sid, 100000, 1),
542 			"Enable on invalid core did not fail");
543 	TEST_ASSERT_EQUAL(-EINVAL, rte_service_map_lcore_set(sid, 100000, 0),
544 			"Disable on invalid core did not fail");
545 
546 	/* add service core to allow enabling */
547 	TEST_ASSERT_EQUAL(0, rte_service_lcore_add(slcore_id),
548 			"Add service core failed when not in use before");
549 
550 	/* valid enable */
551 	TEST_ASSERT_EQUAL(0, rte_service_map_lcore_set(sid, slcore_id, 1),
552 			"Enabling valid service and core failed");
553 	TEST_ASSERT_EQUAL(1, rte_service_map_lcore_get(sid, slcore_id),
554 			"Enabled core returned not-enabled");
555 
556 	/* valid disable */
557 	TEST_ASSERT_EQUAL(0, rte_service_map_lcore_set(sid, slcore_id, 0),
558 			"Disabling valid service and lcore failed");
559 	TEST_ASSERT_EQUAL(0, rte_service_map_lcore_get(sid, slcore_id),
560 			"Disabled core returned enabled");
561 
562 	/* call remote_launch to verify that app can launch ex-service lcore */
563 	service_remote_launch_flag = 0;
564 	rte_eal_wait_lcore(slcore_id);
565 	int ret = rte_eal_remote_launch(service_remote_launch_func, NULL,
566 					slcore_id);
567 	TEST_ASSERT_EQUAL(0, ret, "Ex-service core remote launch failed.");
568 	rte_eal_wait_lcore(slcore_id);
569 	TEST_ASSERT_EQUAL(1, service_remote_launch_flag,
570 			"Ex-service core function call had no effect.");
571 
572 	return unregister_all();
573 }
574 
575 static int
576 service_lcore_running_check(void)
577 {
578 	uint64_t calls = service_calls;
579 	rte_delay_ms(SERVICE_DELAY * 100);
580 	bool service_polled = calls != service_calls;
581 	return service_polled;
582 }
583 
584 static int
585 service_lcore_add_del(void)
586 {
587 	if (!rte_lcore_is_enabled(0) || !rte_lcore_is_enabled(1) ||
588 	    !rte_lcore_is_enabled(2) || !rte_lcore_is_enabled(3))
589 		return TEST_SKIPPED;
590 
591 	/* check initial count */
592 	TEST_ASSERT_EQUAL(0, rte_service_lcore_count(),
593 			"Service lcore count has value before adding a lcore");
594 
595 	/* check service lcore add */
596 	TEST_ASSERT_EQUAL(0, rte_service_lcore_add(slcore_id),
597 			"Add service core failed when not in use before");
598 	TEST_ASSERT_EQUAL(-EALREADY, rte_service_lcore_add(slcore_id),
599 			"Add service core failed to refuse in-use lcore");
600 
601 	/* check count */
602 	TEST_ASSERT_EQUAL(1, rte_service_lcore_count(),
603 			"Service core count not equal to one");
604 
605 	/* retrieve core list, checking lcore ids */
606 	const uint32_t size = 4;
607 	uint32_t service_core_ids[size];
608 	int32_t n = rte_service_lcore_list(service_core_ids, size);
609 	TEST_ASSERT_EQUAL(1, n, "Service core list return should equal 1");
610 	TEST_ASSERT_EQUAL(slcore_id, service_core_ids[0],
611 				"Service core list lcore must equal slcore_id");
612 
613 	/* recheck count, add more cores, and check count */
614 	TEST_ASSERT_EQUAL(1, rte_service_lcore_count(),
615 			"Service core count not equal to one");
616 	uint32_t slcore_1 = rte_get_next_lcore(/* start core */ -1,
617 					       /* skip main */ 1,
618 					       /* wrap */ 0);
619 	TEST_ASSERT_EQUAL(0, rte_service_lcore_add(slcore_1),
620 			"Service core add did not return zero");
621 	uint32_t slcore_2 = rte_get_next_lcore(/* start core */ slcore_1,
622 					       /* skip main */ 1,
623 					       /* wrap */ 0);
624 	TEST_ASSERT_EQUAL(0, rte_service_lcore_add(slcore_2),
625 			"Service core add did not return zero");
626 
627 	uint32_t count = rte_service_lcore_count();
628 	const uint32_t cores_at_this_point = 3;
629 	TEST_ASSERT_EQUAL(cores_at_this_point, count,
630 			"Service core count %d, expected %d", count,
631 			cores_at_this_point);
632 
633 	/* check longer service core list */
634 	n = rte_service_lcore_list(service_core_ids, size);
635 	TEST_ASSERT_EQUAL(3, n, "Service core list return should equal 3");
636 	TEST_ASSERT_EQUAL(slcore_id, service_core_ids[0],
637 				"Service core list[0] lcore must equal 1");
638 	TEST_ASSERT_EQUAL(slcore_1, service_core_ids[1],
639 				"Service core list[1] lcore must equal 2");
640 	TEST_ASSERT_EQUAL(slcore_2, service_core_ids[2],
641 				"Service core list[2] lcore must equal 3");
642 
643 	/* recheck count, remove lcores, check remaining lcore_id is correct */
644 	TEST_ASSERT_EQUAL(3, rte_service_lcore_count(),
645 			"Service core count not equal to three");
646 	TEST_ASSERT_EQUAL(0, rte_service_lcore_del(slcore_1),
647 			"Service core add did not return zero");
648 	TEST_ASSERT_EQUAL(0, rte_service_lcore_del(slcore_2),
649 			"Service core add did not return zero");
650 	TEST_ASSERT_EQUAL(1, rte_service_lcore_count(),
651 			"Service core count not equal to one");
652 	n = rte_service_lcore_list(service_core_ids, size);
653 	TEST_ASSERT_EQUAL(1, n, "Service core list return should equal one");
654 	TEST_ASSERT_EQUAL(slcore_id, service_core_ids[0],
655 				"Service core list[0] lcore must equal %d",
656 				slcore_id);
657 
658 	return unregister_all();
659 }
660 
661 static int
662 service_threaded_test(int mt_safe)
663 {
664 	unregister_all();
665 
666 	/* add next 2 cores */
667 	uint32_t slcore_1 = rte_get_next_lcore(/* start core */ -1,
668 					       /* skip main */ 1,
669 					       /* wrap */ 0);
670 	TEST_ASSERT_EQUAL(0, rte_service_lcore_add(slcore_1),
671 			"mt safe lcore add fail");
672 	uint32_t slcore_2 = rte_get_next_lcore(/* start core */ slcore_1,
673 					       /* skip main */ 1,
674 					       /* wrap */ 0);
675 	TEST_ASSERT_EQUAL(0, rte_service_lcore_add(slcore_2),
676 			"mt safe lcore add fail");
677 
678 	/* Use locks to verify that two threads are in the same function
679 	 * at the same time. These are passed to the unit tests through
680 	 * the callback userdata parameter.
681 	 */
682 	uint32_t test_params[2];
683 	memset(test_params, 0, sizeof(uint32_t) * 2);
684 
685 	/* register MT safe service. */
686 	struct rte_service_spec service;
687 	memset(&service, 0, sizeof(struct rte_service_spec));
688 	service.callback_userdata = test_params;
689 	snprintf(service.name, sizeof(service.name), MT_SAFE_SERVICE_NAME);
690 
691 	if (mt_safe) {
692 		service.callback = dummy_mt_safe_cb;
693 		service.capabilities |= RTE_SERVICE_CAP_MT_SAFE;
694 	} else
695 		service.callback = dummy_mt_unsafe_cb;
696 
697 	uint32_t id;
698 	TEST_ASSERT_EQUAL(0, rte_service_component_register(&service, &id),
699 			"Register of MT SAFE service failed");
700 
701 	const uint32_t sid = 0;
702 	TEST_ASSERT_EQUAL(0, rte_service_runstate_set(sid, 1),
703 			"Starting valid service failed");
704 	TEST_ASSERT_EQUAL(0, rte_service_map_lcore_set(sid, slcore_1, 1),
705 			"Failed to enable lcore 1 on mt safe service");
706 	TEST_ASSERT_EQUAL(0, rte_service_map_lcore_set(sid, slcore_2, 1),
707 			"Failed to enable lcore 2 on mt safe service");
708 	rte_service_lcore_start(slcore_1);
709 	rte_service_lcore_start(slcore_2);
710 
711 	/* wait for the worker threads to run */
712 	rte_delay_ms(500);
713 	rte_service_lcore_stop(slcore_1);
714 	rte_service_lcore_stop(slcore_2);
715 
716 	TEST_ASSERT_EQUAL(0, test_params[1],
717 			"Service run with component runstate = 0");
718 
719 	/* enable backend runstate: the service should run after this */
720 	rte_service_component_runstate_set(id, 1);
721 
722 	/* initialize to pass, see callback comment for details */
723 	if (!mt_safe)
724 		test_params[1] = 1;
725 
726 	/* wait for lcores before start() */
727 	rte_eal_wait_lcore(slcore_1);
728 	rte_eal_wait_lcore(slcore_2);
729 
730 	rte_service_lcore_start(slcore_1);
731 	rte_service_lcore_start(slcore_2);
732 
733 	/* wait for the worker threads to run */
734 	rte_delay_ms(500);
735 	rte_service_lcore_stop(slcore_1);
736 	rte_service_lcore_stop(slcore_2);
737 
738 	TEST_ASSERT_EQUAL(1, test_params[1],
739 			"MT Safe service not run by two cores concurrently");
740 	TEST_ASSERT_EQUAL(0, rte_service_runstate_set(sid, 0),
741 			"Failed to stop MT Safe service");
742 
743 	rte_eal_wait_lcore(slcore_1);
744 	rte_eal_wait_lcore(slcore_2);
745 	unregister_all();
746 
747 	/* return the value of the callback pass_test variable to caller */
748 	return test_params[1];
749 }
750 
751 /* tests an MT SAFE service with two cores. The callback function ensures that
752  * two threads access the callback concurrently.
753  */
754 static int
755 service_mt_safe_poll(void)
756 {
757 	int mt_safe = 1;
758 
759 	if (!rte_lcore_is_enabled(0) || !rte_lcore_is_enabled(1) ||
760 	    !rte_lcore_is_enabled(2))
761 		return TEST_SKIPPED;
762 
763 	TEST_ASSERT_EQUAL(1, service_threaded_test(mt_safe),
764 			"Error: MT Safe service not run by two cores concurrently");
765 	return TEST_SUCCESS;
766 }
767 
768 /* tests a NON mt safe service with two cores, the callback is serialized
769  * using the CAS.
770  */
771 static int
772 service_mt_unsafe_poll(void)
773 {
774 	int mt_safe = 0;
775 
776 	if (!rte_lcore_is_enabled(0) || !rte_lcore_is_enabled(1) ||
777 	    !rte_lcore_is_enabled(2))
778 		return TEST_SKIPPED;
779 
780 	TEST_ASSERT_EQUAL(1, service_threaded_test(mt_safe),
781 			"Error: NON MT Safe service run by two cores concurrently");
782 	return TEST_SUCCESS;
783 }
784 
785 static int32_t
786 delay_as_a_mt_safe_service(void *args)
787 {
788 	RTE_SET_USED(args);
789 	uint32_t *params = args;
790 
791 	/* retrieve done flag and lock to add/sub */
792 	uint32_t *done = &params[0];
793 	RTE_ATOMIC(uint32_t) *lock = (uint32_t __rte_atomic *)&params[1];
794 
795 	while (!*done) {
796 		rte_atomic_fetch_add_explicit(lock, 1, rte_memory_order_relaxed);
797 		rte_delay_us(500);
798 		if (rte_atomic_load_explicit(lock, rte_memory_order_relaxed) > 1)
799 			/* pass: second core has simultaneously incremented */
800 			*done = 1;
801 		rte_atomic_fetch_sub_explicit(lock, 1, rte_memory_order_relaxed);
802 	}
803 
804 	return 0;
805 }
806 
807 static int32_t
808 delay_as_a_service(void *args)
809 {
810 	uint32_t *done = (uint32_t *)args;
811 	while (!*done)
812 		rte_delay_ms(5);
813 	return 0;
814 }
815 
816 static int
817 service_run_on_app_core_func(void *arg)
818 {
819 	uint32_t *delay_service_id = (uint32_t *)arg;
820 	return rte_service_run_iter_on_app_lcore(*delay_service_id, 1);
821 }
822 
823 static float
824 service_app_lcore_perf_measure(uint32_t id)
825 {
826 	/* Performance test: call in a loop, and measure tsc() */
827 	const uint32_t perf_iters = (1 << 12);
828 	uint64_t start = rte_rdtsc();
829 	uint32_t i;
830 	for (i = 0; i < perf_iters; i++) {
831 		int err = service_run_on_app_core_func(&id);
832 		TEST_ASSERT_EQUAL(0, err, "perf test: returned run failure");
833 	}
834 	uint64_t end = rte_rdtsc();
835 
836 	return (end - start)/(float)perf_iters;
837 }
838 
839 static int
840 service_app_lcore_poll_impl(const int mt_safe)
841 {
842 	uint32_t params[2] = {0};
843 
844 	struct rte_service_spec service;
845 	memset(&service, 0, sizeof(struct rte_service_spec));
846 	snprintf(service.name, sizeof(service.name), MT_SAFE_SERVICE_NAME);
847 	if (mt_safe) {
848 		service.callback = delay_as_a_mt_safe_service;
849 		service.callback_userdata = params;
850 		service.capabilities |= RTE_SERVICE_CAP_MT_SAFE;
851 	} else {
852 		service.callback = delay_as_a_service;
853 		service.callback_userdata = &params;
854 	}
855 
856 	uint32_t id;
857 	TEST_ASSERT_EQUAL(0, rte_service_component_register(&service, &id),
858 			"Register of app lcore delay service failed");
859 
860 	rte_service_component_runstate_set(id, 1);
861 	rte_service_runstate_set(id, 1);
862 
863 	uint32_t app_core2 = rte_get_next_lcore(slcore_id, 1, 1);
864 	rte_eal_wait_lcore(app_core2);
865 	int app_core2_ret = rte_eal_remote_launch(service_run_on_app_core_func,
866 						  &id, app_core2);
867 
868 	rte_delay_ms(100);
869 
870 	int app_core1_ret = service_run_on_app_core_func(&id);
871 
872 	/* flag done, then wait for the spawned 2nd core to return */
873 	params[0] = 1;
874 	rte_eal_mp_wait_lcore();
875 
876 	/* core two gets launched first - and should hold the service lock */
877 	TEST_ASSERT_EQUAL(0, app_core2_ret,
878 			"App core2 : run service didn't return zero");
879 
880 	if (mt_safe) {
881 		/* mt safe should have both cores return 0 for success */
882 		TEST_ASSERT_EQUAL(0, app_core1_ret,
883 				"MT Safe: App core1 didn't return 0");
884 	} else {
885 		/* core one attempts to run later - should be blocked */
886 		TEST_ASSERT_EQUAL(-EBUSY, app_core1_ret,
887 				"MT Unsafe: App core1 didn't return -EBUSY");
888 	}
889 
890 	/* Measure performance of no-stats and with-stats. */
891 	float cyc_no_stats = service_app_lcore_perf_measure(id);
892 
893 	TEST_ASSERT_EQUAL(0, rte_service_set_stats_enable(id, 1),
894 			"failed to enable stats for service.");
895 	float cyc_with_stats = service_app_lcore_perf_measure(id);
896 
897 	printf("perf test for %s, no stats: %0.1f, with stats %0.1f cycles/call\n",
898 		mt_safe ? "MT Safe" : "MT Unsafe", cyc_no_stats, cyc_with_stats);
899 
900 	unregister_all();
901 	return TEST_SUCCESS;
902 }
903 
904 static int
905 service_app_lcore_mt_safe(void)
906 {
907 	const int mt_safe = 1;
908 	return service_app_lcore_poll_impl(mt_safe);
909 }
910 
911 static int
912 service_app_lcore_mt_unsafe(void)
913 {
914 	const int mt_safe = 0;
915 	return service_app_lcore_poll_impl(mt_safe);
916 }
917 
918 /* start and stop a service core - ensuring it goes back to sleep */
919 static int
920 service_lcore_start_stop(void)
921 {
922 	/* start service core and service, create mapping so tick() runs */
923 	const uint32_t sid = 0;
924 	TEST_ASSERT_EQUAL(0, rte_service_runstate_set(sid, 1),
925 			"Starting valid service failed");
926 	TEST_ASSERT_EQUAL(-EINVAL, rte_service_map_lcore_set(sid, slcore_id, 1),
927 			"Enabling valid service on non-service core must fail");
928 
929 	/* core start */
930 	TEST_ASSERT_EQUAL(-EINVAL, rte_service_lcore_start(slcore_id),
931 			"Service core start without add should return EINVAL");
932 	TEST_ASSERT_EQUAL(0, rte_service_lcore_add(slcore_id),
933 			"Service core add did not return zero");
934 	TEST_ASSERT_EQUAL(0, rte_service_map_lcore_set(sid, slcore_id, 1),
935 			"Enabling valid service on valid core failed");
936 	TEST_ASSERT_EQUAL(0, rte_service_lcore_start(slcore_id),
937 			"Service core start after add failed");
938 	TEST_ASSERT_EQUAL(-EALREADY, rte_service_lcore_start(slcore_id),
939 			"Service core expected as running but was stopped");
940 
941 	/* ensures core really is running the service function */
942 	TEST_ASSERT_EQUAL(1, service_lcore_running_check(),
943 			"Service core expected to poll service but it didn't");
944 
945 	/* core stop */
946 	TEST_ASSERT_EQUAL(-EBUSY, rte_service_lcore_stop(slcore_id),
947 			"Service core running a service should return -EBUSY");
948 	TEST_ASSERT_EQUAL(0, rte_service_runstate_set(sid, 0),
949 			"Stopping valid service failed");
950 	TEST_ASSERT_EQUAL(-EINVAL, rte_service_lcore_stop(100000),
951 			"Invalid Service core stop should return -EINVAL");
952 	TEST_ASSERT_EQUAL(0, rte_service_lcore_stop(slcore_id),
953 			"Service core stop expected to return 0");
954 	TEST_ASSERT_EQUAL(-EALREADY, rte_service_lcore_stop(slcore_id),
955 			"Already stopped service core should return -EALREADY");
956 
957 	/* ensure service is not longer running */
958 	TEST_ASSERT_EQUAL(0, service_lcore_running_check(),
959 			"Service core expected to poll service but it didn't");
960 
961 	TEST_ASSERT_EQUAL(0, rte_service_lcore_del(slcore_id),
962 			"Service core del did not return zero");
963 
964 	return unregister_all();
965 }
966 
967 static int
968 service_ensure_stopped_with_timeout(uint32_t sid)
969 {
970 	/* give the service time to stop running */
971 	int i;
972 	for (i = 0; i < TIMEOUT_MS; i++) {
973 		if (!rte_service_may_be_active(sid))
974 			break;
975 		rte_delay_ms(1);
976 	}
977 
978 	return rte_service_may_be_active(sid);
979 }
980 
981 /* stop a service and wait for it to become inactive */
982 static int
983 service_may_be_active(void)
984 {
985 	const uint32_t sid = 0;
986 
987 	/* expected failure cases */
988 	TEST_ASSERT_EQUAL(-EINVAL, rte_service_may_be_active(10000),
989 			"Invalid service may be active check did not fail");
990 
991 	/* start the service */
992 	TEST_ASSERT_EQUAL(0, rte_service_runstate_set(sid, 1),
993 			"Starting valid service failed");
994 	TEST_ASSERT_EQUAL(0, rte_service_lcore_add(slcore_id),
995 			"Add service core failed when not in use before");
996 	TEST_ASSERT_EQUAL(0, rte_service_map_lcore_set(sid, slcore_id, 1),
997 			"Enabling valid service on valid core failed");
998 	TEST_ASSERT_EQUAL(0, rte_service_lcore_start(slcore_id),
999 			"Service core start after add failed");
1000 
1001 	/* ensures core really is running the service function */
1002 	TEST_ASSERT_EQUAL(1, service_lcore_running_check(),
1003 			"Service core expected to poll service but it didn't");
1004 
1005 	/* stop the service, and wait for not-active with timeout */
1006 	TEST_ASSERT_EQUAL(0, rte_service_runstate_set(sid, 0),
1007 			"Error: Service stop returned non-zero");
1008 	TEST_ASSERT_EQUAL(0, service_ensure_stopped_with_timeout(sid),
1009 			  "Error: Service not stopped after timeout period.");
1010 
1011 	return unregister_all();
1012 }
1013 
1014 /* check service may be active when service is running on a second lcore */
1015 static int
1016 service_active_two_cores(void)
1017 {
1018 	if (!rte_lcore_is_enabled(0) || !rte_lcore_is_enabled(1) ||
1019 	    !rte_lcore_is_enabled(2))
1020 		return TEST_SKIPPED;
1021 
1022 	const uint32_t sid = 0;
1023 
1024 	uint32_t lcore = rte_get_next_lcore(/* start core */ -1,
1025 					    /* skip main */ 1,
1026 					    /* wrap */ 0);
1027 	uint32_t slcore = rte_get_next_lcore(/* start core */ lcore,
1028 					     /* skip main */ 1,
1029 					     /* wrap */ 0);
1030 
1031 	/* start the service on the second available lcore */
1032 	TEST_ASSERT_EQUAL(0, rte_service_runstate_set(sid, 1),
1033 			"Starting valid service failed");
1034 	TEST_ASSERT_EQUAL(0, rte_service_lcore_add(slcore),
1035 			"Add service core failed when not in use before");
1036 	TEST_ASSERT_EQUAL(0, rte_service_map_lcore_set(sid, slcore, 1),
1037 			"Enabling valid service on valid core failed");
1038 	TEST_ASSERT_EQUAL(0, rte_service_lcore_start(slcore),
1039 			"Service core start after add failed");
1040 
1041 	/* ensures core really is running the service function */
1042 	TEST_ASSERT_EQUAL(1, service_lcore_running_check(),
1043 			"Service core expected to poll service but it didn't");
1044 
1045 	/* ensures that service may be active reports running state */
1046 	TEST_ASSERT_EQUAL(1, rte_service_may_be_active(sid),
1047 			"Service may be active did not report running state");
1048 
1049 	/* stop the service */
1050 	TEST_ASSERT_EQUAL(0, rte_service_runstate_set(sid, 0),
1051 			"Error: Service stop returned non-zero");
1052 	TEST_ASSERT_EQUAL(0, service_ensure_stopped_with_timeout(sid),
1053 			  "Error: Service not stopped after timeout period.");
1054 
1055 	return unregister_all();
1056 }
1057 
1058 static struct unit_test_suite service_tests  = {
1059 	.suite_name = "service core test suite",
1060 	.setup = testsuite_setup,
1061 	.teardown = testsuite_teardown,
1062 	.unit_test_cases = {
1063 		TEST_CASE_ST(dummy_register, NULL, unregister_all),
1064 		TEST_CASE_ST(dummy_register, NULL, service_name),
1065 		TEST_CASE_ST(dummy_register, NULL, service_get_by_name),
1066 		TEST_CASE_ST(dummy_register, NULL, service_dump),
1067 		TEST_CASE_ST(dummy_register, NULL, service_probe_capability),
1068 		TEST_CASE_ST(dummy_register, NULL, service_start_stop),
1069 		TEST_CASE_ST(dummy_register, NULL, service_lcore_add_del),
1070 		TEST_CASE_ST(dummy_register, NULL, service_lcore_en_dis_able),
1071 		TEST_CASE_ST(dummy_register, NULL, service_mt_unsafe_poll),
1072 		TEST_CASE_ST(dummy_register, NULL, service_mt_safe_poll),
1073 		TEST_CASE_ST(dummy_register, NULL, service_may_be_active),
1074 		TEST_CASE_ST(dummy_register, NULL, service_active_two_cores),
1075 		TEST_CASES_END() /**< NULL terminate unit test array */
1076 	}
1077 };
1078 
1079 static int
1080 test_service_common(void)
1081 {
1082 	return unit_test_suite_runner(&service_tests);
1083 }
1084 
1085 REGISTER_FAST_TEST(service_autotest, true, true, test_service_common);
1086 
1087 static struct unit_test_suite service_perf_tests  = {
1088 	.suite_name = "service core performance test suite",
1089 	.setup = testsuite_setup,
1090 	.teardown = testsuite_teardown,
1091 	.unit_test_cases = {
1092 		TEST_CASE_ST(dummy_register, NULL, service_attr_get),
1093 		TEST_CASE_ST(dummy_register, NULL, service_lcore_attr_get),
1094 		TEST_CASE_ST(dummy_register, NULL, service_lcore_start_stop),
1095 		TEST_CASE_ST(dummy_register, NULL, service_app_lcore_mt_safe),
1096 		TEST_CASE_ST(dummy_register, NULL, service_app_lcore_mt_unsafe),
1097 		TEST_CASES_END() /**< NULL terminate unit test array */
1098 	}
1099 };
1100 
1101 static int
1102 test_service_perf(void)
1103 {
1104 	return unit_test_suite_runner(&service_perf_tests);
1105 }
1106 
1107 REGISTER_PERF_TEST(service_perf_autotest, test_service_perf);
1108