xref: /dpdk/app/test/test_distributor.c (revision 6435f9a0)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2017 Intel Corporation
3  */
4 
5 #include "test.h"
6 
7 #include <unistd.h>
8 #include <string.h>
9 #include <rte_cycles.h>
10 #include <rte_errno.h>
11 #include <rte_mempool.h>
12 #include <rte_mbuf.h>
13 #include <rte_distributor.h>
14 #include <rte_string_fns.h>
15 
16 #define ITER_POWER 20 /* log 2 of how many iterations we do when timing. */
17 #define BURST 32
18 #define BIG_BATCH 1024
19 
20 struct worker_params {
21 	char name[64];
22 	struct rte_distributor *dist;
23 };
24 
25 struct worker_params worker_params;
26 
27 /* statics - all zero-initialized by default */
28 static volatile int quit;      /**< general quit variable for all threads */
29 static volatile int zero_quit; /**< var for when we just want thr0 to quit*/
30 static volatile unsigned worker_idx;
31 
32 struct worker_stats {
33 	volatile unsigned handled_packets;
34 } __rte_cache_aligned;
35 struct worker_stats worker_stats[RTE_MAX_LCORE];
36 
37 /* returns the total count of the number of packets handled by the worker
38  * functions given below.
39  */
40 static inline unsigned
41 total_packet_count(void)
42 {
43 	unsigned i, count = 0;
44 	for (i = 0; i < worker_idx; i++)
45 		count += worker_stats[i].handled_packets;
46 	return count;
47 }
48 
49 /* resets the packet counts for a new test */
50 static inline void
51 clear_packet_count(void)
52 {
53 	memset(&worker_stats, 0, sizeof(worker_stats));
54 }
55 
56 /* this is the basic worker function for sanity test
57  * it does nothing but return packets and count them.
58  */
59 static int
60 handle_work(void *arg)
61 {
62 	struct rte_mbuf *buf[8] __rte_cache_aligned;
63 	struct worker_params *wp = arg;
64 	struct rte_distributor *db = wp->dist;
65 	unsigned int count = 0, num = 0;
66 	unsigned int id = __sync_fetch_and_add(&worker_idx, 1);
67 	int i;
68 
69 	for (i = 0; i < 8; i++)
70 		buf[i] = NULL;
71 	num = rte_distributor_get_pkt(db, id, buf, buf, num);
72 	while (!quit) {
73 		worker_stats[id].handled_packets += num;
74 		count += num;
75 		num = rte_distributor_get_pkt(db, id,
76 				buf, buf, num);
77 	}
78 	worker_stats[id].handled_packets += num;
79 	count += num;
80 	rte_distributor_return_pkt(db, id, buf, num);
81 	return 0;
82 }
83 
84 /* do basic sanity testing of the distributor. This test tests the following:
85  * - send 32 packets through distributor with the same tag and ensure they
86  *   all go to the one worker
87  * - send 32 packets through the distributor with two different tags and
88  *   verify that they go equally to two different workers.
89  * - send 32 packets with different tags through the distributors and
90  *   just verify we get all packets back.
91  * - send 1024 packets through the distributor, gathering the returned packets
92  *   as we go. Then verify that we correctly got all 1024 pointers back again,
93  *   not necessarily in the same order (as different flows).
94  */
95 static int
96 sanity_test(struct worker_params *wp, struct rte_mempool *p)
97 {
98 	struct rte_distributor *db = wp->dist;
99 	struct rte_mbuf *bufs[BURST];
100 	struct rte_mbuf *returns[BURST*2];
101 	unsigned int i, count;
102 	unsigned int retries;
103 
104 	printf("=== Basic distributor sanity tests ===\n");
105 	clear_packet_count();
106 	if (rte_mempool_get_bulk(p, (void *)bufs, BURST) != 0) {
107 		printf("line %d: Error getting mbufs from pool\n", __LINE__);
108 		return -1;
109 	}
110 
111 	/* now set all hash values in all buffers to zero, so all pkts go to the
112 	 * one worker thread */
113 	for (i = 0; i < BURST; i++)
114 		bufs[i]->hash.usr = 0;
115 
116 	rte_distributor_process(db, bufs, BURST);
117 	count = 0;
118 	do {
119 
120 		rte_distributor_flush(db);
121 		count += rte_distributor_returned_pkts(db,
122 				returns, BURST*2);
123 	} while (count < BURST);
124 
125 	if (total_packet_count() != BURST) {
126 		printf("Line %d: Error, not all packets flushed. "
127 				"Expected %u, got %u\n",
128 				__LINE__, BURST, total_packet_count());
129 		return -1;
130 	}
131 
132 	for (i = 0; i < rte_lcore_count() - 1; i++)
133 		printf("Worker %u handled %u packets\n", i,
134 				worker_stats[i].handled_packets);
135 	printf("Sanity test with all zero hashes done.\n");
136 
137 	/* pick two flows and check they go correctly */
138 	if (rte_lcore_count() >= 3) {
139 		clear_packet_count();
140 		for (i = 0; i < BURST; i++)
141 			bufs[i]->hash.usr = (i & 1) << 8;
142 
143 		rte_distributor_process(db, bufs, BURST);
144 		count = 0;
145 		do {
146 			rte_distributor_flush(db);
147 			count += rte_distributor_returned_pkts(db,
148 					returns, BURST*2);
149 		} while (count < BURST);
150 		if (total_packet_count() != BURST) {
151 			printf("Line %d: Error, not all packets flushed. "
152 					"Expected %u, got %u\n",
153 					__LINE__, BURST, total_packet_count());
154 			return -1;
155 		}
156 
157 		for (i = 0; i < rte_lcore_count() - 1; i++)
158 			printf("Worker %u handled %u packets\n", i,
159 					worker_stats[i].handled_packets);
160 		printf("Sanity test with two hash values done\n");
161 	}
162 
163 	/* give a different hash value to each packet,
164 	 * so load gets distributed */
165 	clear_packet_count();
166 	for (i = 0; i < BURST; i++)
167 		bufs[i]->hash.usr = i+1;
168 
169 	rte_distributor_process(db, bufs, BURST);
170 	count = 0;
171 	do {
172 		rte_distributor_flush(db);
173 		count += rte_distributor_returned_pkts(db,
174 				returns, BURST*2);
175 	} while (count < BURST);
176 	if (total_packet_count() != BURST) {
177 		printf("Line %d: Error, not all packets flushed. "
178 				"Expected %u, got %u\n",
179 				__LINE__, BURST, total_packet_count());
180 		return -1;
181 	}
182 
183 	for (i = 0; i < rte_lcore_count() - 1; i++)
184 		printf("Worker %u handled %u packets\n", i,
185 				worker_stats[i].handled_packets);
186 	printf("Sanity test with non-zero hashes done\n");
187 
188 	rte_mempool_put_bulk(p, (void *)bufs, BURST);
189 
190 	/* sanity test with BIG_BATCH packets to ensure they all arrived back
191 	 * from the returned packets function */
192 	clear_packet_count();
193 	struct rte_mbuf *many_bufs[BIG_BATCH], *return_bufs[BIG_BATCH];
194 	unsigned num_returned = 0;
195 
196 	/* flush out any remaining packets */
197 	rte_distributor_flush(db);
198 	rte_distributor_clear_returns(db);
199 
200 	if (rte_mempool_get_bulk(p, (void *)many_bufs, BIG_BATCH) != 0) {
201 		printf("line %d: Error getting mbufs from pool\n", __LINE__);
202 		return -1;
203 	}
204 	for (i = 0; i < BIG_BATCH; i++)
205 		many_bufs[i]->hash.usr = i << 2;
206 
207 	printf("=== testing big burst (%s) ===\n", wp->name);
208 	for (i = 0; i < BIG_BATCH/BURST; i++) {
209 		rte_distributor_process(db,
210 				&many_bufs[i*BURST], BURST);
211 		count = rte_distributor_returned_pkts(db,
212 				&return_bufs[num_returned],
213 				BIG_BATCH - num_returned);
214 		num_returned += count;
215 	}
216 	rte_distributor_flush(db);
217 	count = rte_distributor_returned_pkts(db,
218 		&return_bufs[num_returned],
219 			BIG_BATCH - num_returned);
220 	num_returned += count;
221 	retries = 0;
222 	do {
223 		rte_distributor_flush(db);
224 		count = rte_distributor_returned_pkts(db,
225 				&return_bufs[num_returned],
226 				BIG_BATCH - num_returned);
227 		num_returned += count;
228 		retries++;
229 	} while ((num_returned < BIG_BATCH) && (retries < 100));
230 
231 	if (num_returned != BIG_BATCH) {
232 		printf("line %d: Missing packets, expected %d\n",
233 				__LINE__, num_returned);
234 		return -1;
235 	}
236 
237 	/* big check -  make sure all packets made it back!! */
238 	for (i = 0; i < BIG_BATCH; i++) {
239 		unsigned j;
240 		struct rte_mbuf *src = many_bufs[i];
241 		for (j = 0; j < BIG_BATCH; j++) {
242 			if (return_bufs[j] == src)
243 				break;
244 		}
245 
246 		if (j == BIG_BATCH) {
247 			printf("Error: could not find source packet #%u\n", i);
248 			return -1;
249 		}
250 	}
251 	printf("Sanity test of returned packets done\n");
252 
253 	rte_mempool_put_bulk(p, (void *)many_bufs, BIG_BATCH);
254 
255 	printf("\n");
256 	return 0;
257 }
258 
259 
260 /* to test that the distributor does not lose packets, we use this worker
261  * function which frees mbufs when it gets them. The distributor thread does
262  * the mbuf allocation. If distributor drops packets we'll eventually run out
263  * of mbufs.
264  */
265 static int
266 handle_work_with_free_mbufs(void *arg)
267 {
268 	struct rte_mbuf *buf[8] __rte_cache_aligned;
269 	struct worker_params *wp = arg;
270 	struct rte_distributor *d = wp->dist;
271 	unsigned int count = 0;
272 	unsigned int i;
273 	unsigned int num = 0;
274 	unsigned int id = __sync_fetch_and_add(&worker_idx, 1);
275 
276 	for (i = 0; i < 8; i++)
277 		buf[i] = NULL;
278 	num = rte_distributor_get_pkt(d, id, buf, buf, num);
279 	while (!quit) {
280 		worker_stats[id].handled_packets += num;
281 		count += num;
282 		for (i = 0; i < num; i++)
283 			rte_pktmbuf_free(buf[i]);
284 		num = rte_distributor_get_pkt(d,
285 				id, buf, buf, num);
286 	}
287 	worker_stats[id].handled_packets += num;
288 	count += num;
289 	rte_distributor_return_pkt(d, id, buf, num);
290 	return 0;
291 }
292 
293 /* Perform a sanity test of the distributor with a large number of packets,
294  * where we allocate a new set of mbufs for each burst. The workers then
295  * free the mbufs. This ensures that we don't have any packet leaks in the
296  * library.
297  */
298 static int
299 sanity_test_with_mbuf_alloc(struct worker_params *wp, struct rte_mempool *p)
300 {
301 	struct rte_distributor *d = wp->dist;
302 	unsigned i;
303 	struct rte_mbuf *bufs[BURST];
304 
305 	printf("=== Sanity test with mbuf alloc/free (%s) ===\n", wp->name);
306 
307 	clear_packet_count();
308 	for (i = 0; i < ((1<<ITER_POWER)); i += BURST) {
309 		unsigned j;
310 		while (rte_mempool_get_bulk(p, (void *)bufs, BURST) < 0)
311 			rte_distributor_process(d, NULL, 0);
312 		for (j = 0; j < BURST; j++) {
313 			bufs[j]->hash.usr = (i+j) << 1;
314 			rte_mbuf_refcnt_set(bufs[j], 1);
315 		}
316 
317 		rte_distributor_process(d, bufs, BURST);
318 	}
319 
320 	rte_distributor_flush(d);
321 
322 	rte_delay_us(10000);
323 
324 	if (total_packet_count() < (1<<ITER_POWER)) {
325 		printf("Line %u: Packet count is incorrect, %u, expected %u\n",
326 				__LINE__, total_packet_count(),
327 				(1<<ITER_POWER));
328 		return -1;
329 	}
330 
331 	printf("Sanity test with mbuf alloc/free passed\n\n");
332 	return 0;
333 }
334 
335 static int
336 handle_work_for_shutdown_test(void *arg)
337 {
338 	struct rte_mbuf *pkt = NULL;
339 	struct rte_mbuf *buf[8] __rte_cache_aligned;
340 	struct worker_params *wp = arg;
341 	struct rte_distributor *d = wp->dist;
342 	unsigned int count = 0;
343 	unsigned int num = 0;
344 	unsigned int total = 0;
345 	unsigned int i;
346 	unsigned int returned = 0;
347 	const unsigned int id = __sync_fetch_and_add(&worker_idx, 1);
348 
349 	num = rte_distributor_get_pkt(d, id, buf, buf, num);
350 
351 	/* wait for quit single globally, or for worker zero, wait
352 	 * for zero_quit */
353 	while (!quit && !(id == 0 && zero_quit)) {
354 		worker_stats[id].handled_packets += num;
355 		count += num;
356 		for (i = 0; i < num; i++)
357 			rte_pktmbuf_free(buf[i]);
358 		num = rte_distributor_get_pkt(d,
359 				id, buf, buf, num);
360 		total += num;
361 	}
362 	worker_stats[id].handled_packets += num;
363 	count += num;
364 	returned = rte_distributor_return_pkt(d, id, buf, num);
365 
366 	if (id == 0) {
367 		/* for worker zero, allow it to restart to pick up last packet
368 		 * when all workers are shutting down.
369 		 */
370 		while (zero_quit)
371 			usleep(100);
372 
373 		num = rte_distributor_get_pkt(d,
374 				id, buf, buf, num);
375 
376 		while (!quit) {
377 			worker_stats[id].handled_packets++, count++;
378 			rte_pktmbuf_free(pkt);
379 			num = rte_distributor_get_pkt(d, id, buf, buf, num);
380 		}
381 		returned = rte_distributor_return_pkt(d,
382 				id, buf, num);
383 		printf("Num returned = %d\n", returned);
384 	}
385 	return 0;
386 }
387 
388 
389 /* Perform a sanity test of the distributor with a large number of packets,
390  * where we allocate a new set of mbufs for each burst. The workers then
391  * free the mbufs. This ensures that we don't have any packet leaks in the
392  * library.
393  */
394 static int
395 sanity_test_with_worker_shutdown(struct worker_params *wp,
396 		struct rte_mempool *p)
397 {
398 	struct rte_distributor *d = wp->dist;
399 	struct rte_mbuf *bufs[BURST];
400 	unsigned i;
401 
402 	printf("=== Sanity test of worker shutdown ===\n");
403 
404 	clear_packet_count();
405 
406 	if (rte_mempool_get_bulk(p, (void *)bufs, BURST) != 0) {
407 		printf("line %d: Error getting mbufs from pool\n", __LINE__);
408 		return -1;
409 	}
410 
411 	/*
412 	 * Now set all hash values in all buffers to same value so all
413 	 * pkts go to the one worker thread
414 	 */
415 	for (i = 0; i < BURST; i++)
416 		bufs[i]->hash.usr = 1;
417 
418 	rte_distributor_process(d, bufs, BURST);
419 	rte_distributor_flush(d);
420 
421 	/* at this point, we will have processed some packets and have a full
422 	 * backlog for the other ones at worker 0.
423 	 */
424 
425 	/* get more buffers to queue up, again setting them to the same flow */
426 	if (rte_mempool_get_bulk(p, (void *)bufs, BURST) != 0) {
427 		printf("line %d: Error getting mbufs from pool\n", __LINE__);
428 		return -1;
429 	}
430 	for (i = 0; i < BURST; i++)
431 		bufs[i]->hash.usr = 1;
432 
433 	/* get worker zero to quit */
434 	zero_quit = 1;
435 	rte_distributor_process(d, bufs, BURST);
436 
437 	/* flush the distributor */
438 	rte_distributor_flush(d);
439 	rte_delay_us(10000);
440 
441 	for (i = 0; i < rte_lcore_count() - 1; i++)
442 		printf("Worker %u handled %u packets\n", i,
443 				worker_stats[i].handled_packets);
444 
445 	if (total_packet_count() != BURST * 2) {
446 		printf("Line %d: Error, not all packets flushed. "
447 				"Expected %u, got %u\n",
448 				__LINE__, BURST * 2, total_packet_count());
449 		return -1;
450 	}
451 
452 	printf("Sanity test with worker shutdown passed\n\n");
453 	return 0;
454 }
455 
456 /* Test that the flush function is able to move packets between workers when
457  * one worker shuts down..
458  */
459 static int
460 test_flush_with_worker_shutdown(struct worker_params *wp,
461 		struct rte_mempool *p)
462 {
463 	struct rte_distributor *d = wp->dist;
464 	struct rte_mbuf *bufs[BURST];
465 	unsigned i;
466 
467 	printf("=== Test flush fn with worker shutdown (%s) ===\n", wp->name);
468 
469 	clear_packet_count();
470 	if (rte_mempool_get_bulk(p, (void *)bufs, BURST) != 0) {
471 		printf("line %d: Error getting mbufs from pool\n", __LINE__);
472 		return -1;
473 	}
474 
475 	/* now set all hash values in all buffers to zero, so all pkts go to the
476 	 * one worker thread */
477 	for (i = 0; i < BURST; i++)
478 		bufs[i]->hash.usr = 0;
479 
480 	rte_distributor_process(d, bufs, BURST);
481 	/* at this point, we will have processed some packets and have a full
482 	 * backlog for the other ones at worker 0.
483 	 */
484 
485 	/* get worker zero to quit */
486 	zero_quit = 1;
487 
488 	/* flush the distributor */
489 	rte_distributor_flush(d);
490 
491 	rte_delay_us(10000);
492 
493 	zero_quit = 0;
494 	for (i = 0; i < rte_lcore_count() - 1; i++)
495 		printf("Worker %u handled %u packets\n", i,
496 				worker_stats[i].handled_packets);
497 
498 	if (total_packet_count() != BURST) {
499 		printf("Line %d: Error, not all packets flushed. "
500 				"Expected %u, got %u\n",
501 				__LINE__, BURST, total_packet_count());
502 		return -1;
503 	}
504 
505 	printf("Flush test with worker shutdown passed\n\n");
506 	return 0;
507 }
508 
509 static
510 int test_error_distributor_create_name(void)
511 {
512 	struct rte_distributor *d = NULL;
513 	struct rte_distributor *db = NULL;
514 	char *name = NULL;
515 
516 	d = rte_distributor_create(name, rte_socket_id(),
517 			rte_lcore_count() - 1,
518 			RTE_DIST_ALG_SINGLE);
519 	if (d != NULL || rte_errno != EINVAL) {
520 		printf("ERROR: No error on create() with NULL name param\n");
521 		return -1;
522 	}
523 
524 	db = rte_distributor_create(name, rte_socket_id(),
525 			rte_lcore_count() - 1,
526 			RTE_DIST_ALG_BURST);
527 	if (db != NULL || rte_errno != EINVAL) {
528 		printf("ERROR: No error on create() with NULL param\n");
529 		return -1;
530 	}
531 
532 	return 0;
533 }
534 
535 
536 static
537 int test_error_distributor_create_numworkers(void)
538 {
539 	struct rte_distributor *ds = NULL;
540 	struct rte_distributor *db = NULL;
541 
542 	ds = rte_distributor_create("test_numworkers", rte_socket_id(),
543 			RTE_MAX_LCORE + 10,
544 			RTE_DIST_ALG_SINGLE);
545 	if (ds != NULL || rte_errno != EINVAL) {
546 		printf("ERROR: No error on create() with num_workers > MAX\n");
547 		return -1;
548 	}
549 
550 	db = rte_distributor_create("test_numworkers", rte_socket_id(),
551 			RTE_MAX_LCORE + 10,
552 			RTE_DIST_ALG_BURST);
553 	if (db != NULL || rte_errno != EINVAL) {
554 		printf("ERROR: No error on create() num_workers > MAX\n");
555 		return -1;
556 	}
557 
558 	return 0;
559 }
560 
561 
562 /* Useful function which ensures that all worker functions terminate */
563 static void
564 quit_workers(struct worker_params *wp, struct rte_mempool *p)
565 {
566 	struct rte_distributor *d = wp->dist;
567 	const unsigned num_workers = rte_lcore_count() - 1;
568 	unsigned i;
569 	struct rte_mbuf *bufs[RTE_MAX_LCORE];
570 	rte_mempool_get_bulk(p, (void *)bufs, num_workers);
571 
572 	zero_quit = 0;
573 	quit = 1;
574 	for (i = 0; i < num_workers; i++)
575 		bufs[i]->hash.usr = i << 1;
576 	rte_distributor_process(d, bufs, num_workers);
577 
578 	rte_mempool_put_bulk(p, (void *)bufs, num_workers);
579 
580 	rte_distributor_process(d, NULL, 0);
581 	rte_distributor_flush(d);
582 	rte_eal_mp_wait_lcore();
583 	quit = 0;
584 	worker_idx = 0;
585 }
586 
587 static int
588 test_distributor(void)
589 {
590 	static struct rte_distributor *ds;
591 	static struct rte_distributor *db;
592 	static struct rte_distributor *dist[2];
593 	static struct rte_mempool *p;
594 	int i;
595 
596 	if (rte_lcore_count() < 2) {
597 		printf("ERROR: not enough cores to test distributor\n");
598 		return -1;
599 	}
600 
601 	if (db == NULL) {
602 		db = rte_distributor_create("Test_dist_burst", rte_socket_id(),
603 				rte_lcore_count() - 1,
604 				RTE_DIST_ALG_BURST);
605 		if (db == NULL) {
606 			printf("Error creating burst distributor\n");
607 			return -1;
608 		}
609 	} else {
610 		rte_distributor_flush(db);
611 		rte_distributor_clear_returns(db);
612 	}
613 
614 	if (ds == NULL) {
615 		ds = rte_distributor_create("Test_dist_single",
616 				rte_socket_id(),
617 				rte_lcore_count() - 1,
618 			RTE_DIST_ALG_SINGLE);
619 		if (ds == NULL) {
620 			printf("Error creating single distributor\n");
621 			return -1;
622 		}
623 	} else {
624 		rte_distributor_flush(ds);
625 		rte_distributor_clear_returns(ds);
626 	}
627 
628 	const unsigned nb_bufs = (511 * rte_lcore_count()) < BIG_BATCH ?
629 			(BIG_BATCH * 2) - 1 : (511 * rte_lcore_count());
630 	if (p == NULL) {
631 		p = rte_pktmbuf_pool_create("DT_MBUF_POOL", nb_bufs, BURST,
632 			0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
633 		if (p == NULL) {
634 			printf("Error creating mempool\n");
635 			return -1;
636 		}
637 	}
638 
639 	dist[0] = ds;
640 	dist[1] = db;
641 
642 	for (i = 0; i < 2; i++) {
643 
644 		worker_params.dist = dist[i];
645 		if (i)
646 			strlcpy(worker_params.name, "burst",
647 					sizeof(worker_params.name));
648 		else
649 			strlcpy(worker_params.name, "single",
650 					sizeof(worker_params.name));
651 
652 		rte_eal_mp_remote_launch(handle_work,
653 				&worker_params, SKIP_MASTER);
654 		if (sanity_test(&worker_params, p) < 0)
655 			goto err;
656 		quit_workers(&worker_params, p);
657 
658 		rte_eal_mp_remote_launch(handle_work_with_free_mbufs,
659 				&worker_params, SKIP_MASTER);
660 		if (sanity_test_with_mbuf_alloc(&worker_params, p) < 0)
661 			goto err;
662 		quit_workers(&worker_params, p);
663 
664 		if (rte_lcore_count() > 2) {
665 			rte_eal_mp_remote_launch(handle_work_for_shutdown_test,
666 					&worker_params,
667 					SKIP_MASTER);
668 			if (sanity_test_with_worker_shutdown(&worker_params,
669 					p) < 0)
670 				goto err;
671 			quit_workers(&worker_params, p);
672 
673 			rte_eal_mp_remote_launch(handle_work_for_shutdown_test,
674 					&worker_params,
675 					SKIP_MASTER);
676 			if (test_flush_with_worker_shutdown(&worker_params,
677 					p) < 0)
678 				goto err;
679 			quit_workers(&worker_params, p);
680 
681 		} else {
682 			printf("Too few cores to run worker shutdown test\n");
683 		}
684 
685 	}
686 
687 	if (test_error_distributor_create_numworkers() == -1 ||
688 			test_error_distributor_create_name() == -1) {
689 		printf("rte_distributor_create parameter check tests failed");
690 		return -1;
691 	}
692 
693 	return 0;
694 
695 err:
696 	quit_workers(&worker_params, p);
697 	return -1;
698 }
699 
700 REGISTER_TEST_COMMAND(distributor_autotest, test_distributor);
701