1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdio.h>
18 #include <errno.h>
19 #include <stdbool.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <getopt.h>
24 #define __USE_GNU
25 #include <inttypes.h>
26 #include <sys/mman.h>
27 #include <sys/uio.h>
28 #include <time.h>
29
30 #include <BufferAllocator/BufferAllocatorWrapper.h>
31
32 #include <trusty/tipc.h>
33
34 #define TIPC_DEFAULT_DEVNAME "/dev/trusty-ipc-dev0"
35
36 /* clang-format off */
37 #define BENCH_RESULT_TPL \
38 "{" \
39 " \"schema_version\": 3," \
40 " \"suite_name\": \"tipc\"," \
41 " \"bench_name\": \"%s\"," \
42 " \"results\": [" \
43 " {" \
44 " \"metric_name\": \"time_micro_sec\"," \
45 " \"min\": \"%" PRId64 "\"," \
46 " \"max\": \"%" PRId64 "\"," \
47 " \"avg\": \"%" PRId64 "\"," \
48 " \"cold\": \"%" PRId64 "\"," \
49 " \"raw_min\": %" PRId64 "," \
50 " \"raw_max\": %" PRId64 "," \
51 " \"raw_avg\": %" PRId64 "," \
52 " \"raw_cold\": %" PRId64 "" \
53 " }," \
54 " ]" \
55 "}"
56 /* clang-format on */
57
58 static const char *uuid_name = "com.android.ipc-unittest.srv.uuid";
59 static const char *echo_name = "com.android.ipc-unittest.srv.echo";
60 static const char *ta_only_name = "com.android.ipc-unittest.srv.ta_only";
61 static const char *ns_only_name = "com.android.ipc-unittest.srv.ns_only";
62 static const char *datasink_name = "com.android.ipc-unittest.srv.datasink";
63 static const char *closer1_name = "com.android.ipc-unittest.srv.closer1";
64 static const char *closer2_name = "com.android.ipc-unittest.srv.closer2";
65 static const char *closer3_name = "com.android.ipc-unittest.srv.closer3";
66 static const char *main_ctrl_name = "com.android.ipc-unittest.ctrl";
67 static const char* receiver_name = "com.android.trusty.memref.receiver";
68 static const size_t memref_chunk_size = 4096;
69
70 static const char* _sopts = "hsvDS:t:r:m:b:B:";
71 /* clang-format off */
72 static const struct option _lopts[] = {
73 {"help", no_argument, 0, 'h'},
74 {"silent", no_argument, 0, 's'},
75 {"variable",no_argument, 0, 'v'},
76 {"dev", required_argument, 0, 'D'},
77 {"srv", required_argument, 0, 'S'},
78 {"repeat", required_argument, 0, 'r'},
79 {"burst", required_argument, 0, 'b'},
80 {"msgsize", required_argument, 0, 'm'},
81 {"test", required_argument, 0, 't'},
82 {"bench", required_argument, 0, 'B'},
83 {0, 0, 0, 0}
84 };
85 /* clang-format on */
86
87 static const char* usage =
88 "Usage: %s [options]\n"
89 "\n"
90 "options:\n"
91 " -h, --help prints this message and exit\n"
92 " -D, --dev name device name\n"
93 " -S, --srv name service name\n"
94 " -t, --test name test to run\n"
95 " -r, --repeat cnt repeat count\n"
96 " -b, --burst cnt burst count\n"
97 " -m, --msgsize size max message size\n"
98 " -v, --variable variable message size\n"
99 " -s, --silent silent\n"
100 " -B, --bench Run as Benchmark N times\n"
101 "\n";
102
103 static const char* usage_long =
104 "\n"
105 "The following tests are available:\n"
106 " connect - connect to specified service, defaults to echo+datasink\n"
107 " connect_foo - connect to non existing service\n"
108 " burst_write - send messages to datasink service\n"
109 " echo - send/receive messages to echo service\n"
110 " select - test select call\n"
111 " blocked_read - test blocked read\n"
112 " closer1 - connection closed by remote (test1)\n"
113 " closer2 - connection closed by remote (test2)\n"
114 " closer3 - connection closed by remote (test3)\n"
115 " ta2ta-ipc - execute TA to TA unittest\n"
116 " dev-uuid - print device uuid\n"
117 " ta-access - test ta-access flags\n"
118 " writev - writev test\n"
119 " readv - readv test\n"
120 " send-fd - transmit dma_buf to trusty, use as shm\n"
121 "\n";
122
123 struct tipc_test_params {
124 uint repeat;
125 uint msgsize;
126 uint msgburst;
127 bool variable;
128 bool silent;
129 uint bench;
130 char* srv_name;
131 char* dev_name;
132 char* test_name;
133 };
134 typedef int (*tipc_test_func_t)(const struct tipc_test_params*);
135
136 struct tipc_test_def {
137 char* test_name;
138 tipc_test_func_t func;
139 };
140
init_params(struct tipc_test_params * params)141 static void init_params(struct tipc_test_params* params) {
142 params->repeat = 1;
143 params->msgsize = 32;
144 params->msgburst = 32;
145 params->variable = false;
146 params->silent = false;
147 params->bench = 0;
148 params->srv_name = NULL;
149 params->test_name = NULL;
150 }
151
print_usage_and_exit(const char * prog,int code,bool verbose)152 static void print_usage_and_exit(const char *prog, int code, bool verbose)
153 {
154 fprintf(stderr, usage, prog);
155 if (verbose) fprintf(stderr, "%s", usage_long);
156 exit(code);
157 }
158
parse_options(int argc,char ** argv,struct tipc_test_params * params)159 static void parse_options(int argc, char** argv, struct tipc_test_params* params) {
160 int c;
161 int oidx = 0;
162
163 while (1) {
164 c = getopt_long(argc, argv, _sopts, _lopts, &oidx);
165 if (c == -1) break; /* done */
166
167 switch (c) {
168 case 'D':
169 params->dev_name = strdup(optarg);
170 break;
171
172 case 'S':
173 params->srv_name = strdup(optarg);
174 break;
175
176 case 't':
177 params->test_name = strdup(optarg);
178 break;
179
180 case 'v':
181 params->variable = true;
182 break;
183
184 case 'r':
185 params->repeat = atoi(optarg);
186 break;
187
188 case 'm':
189 params->msgsize = atoi(optarg);
190 break;
191
192 case 'b':
193 params->msgburst = atoi(optarg);
194 break;
195
196 case 's':
197 params->silent = true;
198 break;
199
200 case 'B':
201 params->bench = atoi(optarg);
202 break;
203
204 case 'h':
205 print_usage_and_exit(argv[0], EXIT_SUCCESS, true);
206 break;
207
208 default:
209 print_usage_and_exit(argv[0], EXIT_FAILURE, false);
210 }
211 }
212 }
213
connect_test(const struct tipc_test_params * params)214 static int connect_test(const struct tipc_test_params* params) {
215 uint i;
216 int echo_fd;
217 int dsink_fd;
218 int custom_fd;
219
220 if (!params->silent) {
221 printf("%s: repeat = %u\n", __func__, params->repeat);
222 }
223
224 for (i = 0; i < params->repeat; i++) {
225 if (params->srv_name) {
226 custom_fd = tipc_connect(params->dev_name, params->srv_name);
227 if (custom_fd < 0) {
228 fprintf(stderr, "Failed to connect to '%s' service\n", params->srv_name);
229 }
230 if (custom_fd >= 0) {
231 tipc_close(custom_fd);
232 }
233 } else {
234 echo_fd = tipc_connect(params->dev_name, echo_name);
235 if (echo_fd < 0) {
236 fprintf(stderr, "Failed to connect to '%s' service\n", "echo");
237 }
238 dsink_fd = tipc_connect(params->dev_name, datasink_name);
239 if (dsink_fd < 0) {
240 fprintf(stderr, "Failed to connect to '%s' service\n", "datasink");
241 }
242
243 if (echo_fd >= 0) {
244 tipc_close(echo_fd);
245 }
246 if (dsink_fd >= 0) {
247 tipc_close(dsink_fd);
248 }
249 }
250 }
251
252 if (!params->silent) {
253 printf("%s: done\n", __func__);
254 }
255
256 return 0;
257 }
258
connect_foo(const struct tipc_test_params * params)259 static int connect_foo(const struct tipc_test_params* params) {
260 uint i;
261 int fd;
262
263 if (!params->silent) {
264 printf("%s: repeat = %u\n", __func__, params->repeat);
265 }
266
267 for (i = 0; i < params->repeat; i++) {
268 fd = tipc_connect(params->dev_name, "foo");
269 if (fd >= 0) {
270 fprintf(stderr, "succeeded to connect to '%s' service\n", "foo");
271 tipc_close(fd);
272 }
273 }
274
275 if (!params->silent) {
276 printf("%s: done\n", __func__);
277 }
278
279 return 0;
280 }
281
closer1_test(const struct tipc_test_params * params)282 static int closer1_test(const struct tipc_test_params* params) {
283 uint i;
284 int fd;
285
286 if (!params->silent) {
287 printf("%s: repeat = %u\n", __func__, params->repeat);
288 }
289
290 for (i = 0; i < params->repeat; i++) {
291 fd = tipc_connect(params->dev_name, closer1_name);
292 if (fd < 0) {
293 fprintf(stderr, "Failed to connect to '%s' service\n", "closer1");
294 continue;
295 }
296 if (!params->silent) {
297 printf("%s: connected\n", __func__);
298 }
299 tipc_close(fd);
300 }
301
302 if (!params->silent) {
303 printf("%s: done\n", __func__);
304 }
305
306 return 0;
307 }
308
closer2_test(const struct tipc_test_params * params)309 static int closer2_test(const struct tipc_test_params* params) {
310 uint i;
311 int fd;
312
313 if (!params->silent) {
314 printf("%s: repeat = %u\n", __func__, params->repeat);
315 }
316
317 for (i = 0; i < params->repeat; i++) {
318 fd = tipc_connect(params->dev_name, closer2_name);
319 if (fd < 0) {
320 if (!params->silent) {
321 printf("failed to connect to '%s' service\n", "closer2");
322 }
323 } else {
324 /* this should always fail */
325 fprintf(stderr, "connected to '%s' service\n", "closer2");
326 tipc_close(fd);
327 }
328 }
329
330 if (!params->silent) {
331 printf("%s: done\n", __func__);
332 }
333
334 return 0;
335 }
336
closer3_test(const struct tipc_test_params * params)337 static int closer3_test(const struct tipc_test_params* params) {
338 uint i, j;
339 ssize_t rc;
340 int fd[4];
341 char buf[64];
342
343 if (!params->silent) {
344 printf("%s: repeat = %u\n", __func__, params->repeat);
345 }
346
347 for (i = 0; i < params->repeat; i++) {
348 /* open 4 connections to closer3 service */
349 for (j = 0; j < 4; j++) {
350 fd[j] = tipc_connect(params->dev_name, closer3_name);
351 if (fd[j] < 0) {
352 fprintf(stderr, "fd[%d]: failed to connect to '%s' service\n", j, "closer3");
353 } else {
354 if (!params->silent) {
355 printf("%s: fd[%d]=%d: connected\n", __func__, j, fd[j]);
356 }
357 memset(buf, i + j, sizeof(buf));
358 rc = write(fd[j], buf, sizeof(buf));
359 if (rc != sizeof(buf)) {
360 if (!params->silent) {
361 printf("%s: fd[%d]=%d: write returned = %zd\n", __func__, j, fd[j], rc);
362 }
363 perror("closer3_test: write");
364 }
365 }
366 }
367
368 /* sleep a bit */
369 sleep(1);
370
371 /* It is expected that they will be closed by remote */
372 for (j = 0; j < 4; j++) {
373 if (fd[j] < 0) continue;
374 rc = write(fd[j], buf, sizeof(buf));
375 if (rc != sizeof(buf)) {
376 if (!params->silent) {
377 printf("%s: fd[%d]=%d: write returned = %zd\n", __func__, j, fd[j], rc);
378 }
379 perror("closer3_test: write");
380 }
381 }
382
383 /* then they have to be closed by remote */
384 for (j = 0; j < 4; j++) {
385 if (fd[j] >= 0) {
386 tipc_close(fd[j]);
387 }
388 }
389 }
390
391 if (!params->silent) {
392 printf("%s: done\n", __func__);
393 }
394
395 return 0;
396 }
397
echo_test(const struct tipc_test_params * params)398 static int echo_test(const struct tipc_test_params* params) {
399 uint i;
400 ssize_t rc;
401 size_t msg_len;
402 int echo_fd = -1;
403 char tx_buf[params->msgsize];
404 char rx_buf[params->msgsize];
405
406 if (!params->silent) {
407 printf("%s: repeat %u: params->msgsize %u: variable %s\n", __func__, params->repeat,
408 params->msgsize, params->variable ? "true" : "false");
409 }
410
411 echo_fd = tipc_connect(params->dev_name, echo_name);
412 if (echo_fd < 0) {
413 fprintf(stderr, "Failed to connect to service\n");
414 return echo_fd;
415 }
416
417 for (i = 0; i < params->repeat; i++) {
418 msg_len = params->msgsize;
419 if (params->variable && params->msgsize) {
420 msg_len = rand() % params->msgsize;
421 }
422
423 memset(tx_buf, i + 1, msg_len);
424
425 rc = write(echo_fd, tx_buf, msg_len);
426 if ((size_t)rc != msg_len) {
427 perror("echo_test: write");
428 break;
429 }
430
431 rc = read(echo_fd, rx_buf, msg_len);
432 if (rc < 0) {
433 perror("echo_test: read");
434 break;
435 }
436
437 if ((size_t)rc != msg_len) {
438 fprintf(stderr, "data truncated (%zu vs. %zu)\n", rc, msg_len);
439 continue;
440 }
441
442 if (memcmp(tx_buf, rx_buf, (size_t)rc)) {
443 fprintf(stderr, "data mismatch\n");
444 continue;
445 }
446 }
447
448 tipc_close(echo_fd);
449
450 if (!params->silent) {
451 printf("%s: done\n", __func__);
452 }
453
454 return 0;
455 }
456
burst_write_test(const struct tipc_test_params * params)457 static int burst_write_test(const struct tipc_test_params* params) {
458 int fd;
459 uint i, j;
460 ssize_t rc;
461 size_t msg_len;
462 char tx_buf[params->msgsize];
463
464 if (!params->silent) {
465 printf("%s: repeat %u: burst %u: params->msgsize %u: variable %s\n", __func__,
466 params->repeat, params->msgburst, params->msgsize,
467 params->variable ? "true" : "false");
468 }
469
470 for (i = 0; i < params->repeat; i++) {
471 fd = tipc_connect(params->dev_name, datasink_name);
472 if (fd < 0) {
473 fprintf(stderr, "Failed to connect to '%s' service\n", "datasink");
474 break;
475 }
476
477 for (j = 0; j < params->msgburst; j++) {
478 msg_len = params->msgsize;
479 if (params->variable && params->msgsize) {
480 msg_len = rand() % params->msgsize;
481 }
482
483 memset(tx_buf, i + 1, msg_len);
484 rc = write(fd, tx_buf, msg_len);
485 if ((size_t)rc != msg_len) {
486 perror("burst_test: write");
487 break;
488 }
489 }
490
491 tipc_close(fd);
492 }
493
494 if (!params->silent) {
495 printf("%s: done\n", __func__);
496 }
497
498 return 0;
499 }
500
_wait_for_msg(int fd,int timeout,const struct tipc_test_params * params)501 static int _wait_for_msg(int fd, int timeout, const struct tipc_test_params* params) {
502 int rc;
503 fd_set rfds;
504 uint msgcnt = 0;
505 char rx_buf[params->msgsize];
506 struct timeval tv;
507
508 if (!params->silent) {
509 printf("waiting (%d) for msg\n", timeout);
510 }
511
512 FD_ZERO(&rfds);
513 FD_SET(fd, &rfds);
514
515 tv.tv_sec = timeout;
516 tv.tv_usec = 0;
517
518 for (;;) {
519 rc = select(fd + 1, &rfds, NULL, NULL, &tv);
520
521 if (rc == 0) {
522 if (!params->silent) {
523 printf("select timedout\n");
524 }
525 break;
526 }
527
528 if (rc == -1) {
529 perror("select_test: select");
530 return rc;
531 }
532
533 rc = read(fd, rx_buf, sizeof(rx_buf));
534 if (rc < 0) {
535 perror("select_test: read");
536 return rc;
537 } else {
538 if (rc > 0) {
539 msgcnt++;
540 }
541 }
542 }
543
544 if (!params->silent) {
545 printf("got %u messages\n", msgcnt);
546 }
547
548 return 0;
549 }
550
select_test(const struct tipc_test_params * params)551 static int select_test(const struct tipc_test_params* params) {
552 int fd;
553 uint i, j;
554 ssize_t rc;
555 char tx_buf[params->msgsize];
556
557 if (!params->silent) {
558 printf("%s: repeat %u\n", __func__, params->repeat);
559 }
560
561 fd = tipc_connect(params->dev_name, echo_name);
562 if (fd < 0) {
563 fprintf(stderr, "Failed to connect to '%s' service\n", "echo");
564 return fd;
565 }
566
567 for (i = 0; i < params->repeat; i++) {
568 _wait_for_msg(fd, 1, params);
569
570 if (!params->silent) {
571 printf("sending burst: %u msg\n", params->msgburst);
572 }
573
574 for (j = 0; j < params->msgburst; j++) {
575 memset(tx_buf, i + j, params->msgsize);
576 rc = write(fd, tx_buf, params->msgsize);
577 if ((size_t)rc != params->msgsize) {
578 perror("burst_test: write");
579 break;
580 }
581 }
582 }
583
584 tipc_close(fd);
585
586 if (!params->silent) {
587 printf("%s: done\n", __func__);
588 }
589
590 return 0;
591 }
592
blocked_read_test(const struct tipc_test_params * params)593 static int blocked_read_test(const struct tipc_test_params* params) {
594 int fd;
595 uint i;
596 ssize_t rc;
597 char rx_buf[512];
598
599 if (!params->silent) {
600 printf("%s: repeat %u\n", __func__, params->repeat);
601 }
602
603 fd = tipc_connect(params->dev_name, echo_name);
604 if (fd < 0) {
605 fprintf(stderr, "Failed to connect to '%s' service\n", "echo");
606 return fd;
607 }
608
609 for (i = 0; i < params->repeat; i++) {
610 rc = read(fd, rx_buf, sizeof(rx_buf));
611 if (rc < 0) {
612 perror("select_test: read");
613 break;
614 } else {
615 if (!params->silent) {
616 printf("got %zd bytes\n", rc);
617 }
618 }
619 }
620
621 tipc_close(fd);
622
623 if (!params->silent) {
624 printf("%s: done\n", __func__);
625 }
626
627 return 0;
628 }
629
ta2ta_ipc_test(const struct tipc_test_params * params)630 static int ta2ta_ipc_test(const struct tipc_test_params* params) {
631 enum test_message_header {
632 TEST_PASSED = 0,
633 TEST_FAILED = 1,
634 TEST_MESSAGE = 2,
635 TEST_TEXT = 3,
636 };
637
638 int fd;
639 int ret;
640 unsigned char rx_buf[256];
641
642 if (!params->silent) {
643 printf("%s:\n", __func__);
644 }
645
646 fd = tipc_connect(params->dev_name, main_ctrl_name);
647 if (fd < 0) {
648 fprintf(stderr, "Failed to connect to '%s' service\n", "main_ctrl");
649 return fd;
650 }
651
652 /* Wait for tests to complete and read status */
653 while (true) {
654 ret = read(fd, rx_buf, sizeof(rx_buf));
655 if (ret <= 0 || ret >= (int)sizeof(rx_buf)) {
656 fprintf(stderr, "%s: Read failed: %d\n", __func__, ret);
657 tipc_close(fd);
658 return -1;
659 }
660
661 if (rx_buf[0] == TEST_PASSED) {
662 break;
663 } else if (rx_buf[0] == TEST_FAILED) {
664 break;
665 } else if (rx_buf[0] == TEST_MESSAGE || rx_buf[0] == TEST_TEXT) {
666 write(STDOUT_FILENO, rx_buf + 1, ret - 1);
667 } else {
668 fprintf(stderr, "%s: Bad message header: %d\n", __func__, rx_buf[0]);
669 break;
670 }
671 }
672
673 tipc_close(fd);
674
675 return rx_buf[0] == TEST_PASSED ? 0 : -1;
676 }
677
678 typedef struct uuid
679 {
680 uint32_t time_low;
681 uint16_t time_mid;
682 uint16_t time_hi_and_version;
683 uint8_t clock_seq_and_node[8];
684 } uuid_t;
685
print_uuid(const char * dev,uuid_t * uuid)686 static void print_uuid(const char *dev, uuid_t *uuid)
687 {
688 printf("%s:", dev);
689 printf("uuid: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", uuid->time_low,
690 uuid->time_mid, uuid->time_hi_and_version, uuid->clock_seq_and_node[0],
691 uuid->clock_seq_and_node[1], uuid->clock_seq_and_node[2], uuid->clock_seq_and_node[3],
692 uuid->clock_seq_and_node[4], uuid->clock_seq_and_node[5], uuid->clock_seq_and_node[6],
693 uuid->clock_seq_and_node[7]);
694 }
695
dev_uuid_test(const struct tipc_test_params * params)696 static int dev_uuid_test(const struct tipc_test_params* params) {
697 int fd;
698 ssize_t rc;
699 uuid_t uuid;
700
701 fd = tipc_connect(params->dev_name, uuid_name);
702 if (fd < 0) {
703 fprintf(stderr, "Failed to connect to '%s' service\n", "uuid");
704 return fd;
705 }
706
707 /* wait for test to complete */
708 rc = read(fd, &uuid, sizeof(uuid));
709 if (rc < 0) {
710 perror("dev_uuid_test: read");
711 } else if (rc != sizeof(uuid)) {
712 fprintf(stderr, "unexpected uuid size (%d vs. %d)\n", (int)rc, (int)sizeof(uuid));
713 } else {
714 print_uuid(params->dev_name, &uuid);
715 }
716
717 tipc_close(fd);
718
719 return 0;
720 }
721
ta_access_test(const struct tipc_test_params * params)722 static int ta_access_test(const struct tipc_test_params* params) {
723 int fd;
724
725 if (!params->silent) {
726 printf("%s:\n", __func__);
727 }
728
729 fd = tipc_connect(params->dev_name, ta_only_name);
730 if (fd >= 0) {
731 fprintf(stderr, "Succeed to connect to '%s' service\n", "ta_only");
732 tipc_close(fd);
733 }
734
735 fd = tipc_connect(params->dev_name, ns_only_name);
736 if (fd < 0) {
737 fprintf(stderr, "Failed to connect to '%s' service\n", "ns_only");
738 return fd;
739 }
740 tipc_close(fd);
741
742 if (!params->silent) {
743 printf("%s: done\n", __func__);
744 }
745
746 return 0;
747 }
748
writev_test(const struct tipc_test_params * params)749 static int writev_test(const struct tipc_test_params* params) {
750 uint i;
751 ssize_t rc;
752 size_t msg_len;
753 int echo_fd = -1;
754 char tx0_buf[params->msgsize];
755 char tx1_buf[params->msgsize];
756 char rx_buf[params->msgsize];
757 struct iovec iovs[2] = {{tx0_buf, 0}, {tx1_buf, 0}};
758
759 if (!params->silent) {
760 printf("%s: repeat %u: params->msgsize %u: variable %s\n", __func__, params->repeat,
761 params->msgsize, params->variable ? "true" : "false");
762 }
763
764 echo_fd = tipc_connect(params->dev_name, echo_name);
765 if (echo_fd < 0) {
766 fprintf(stderr, "Failed to connect to service\n");
767 return echo_fd;
768 }
769
770 for (i = 0; i < params->repeat; i++) {
771 msg_len = params->msgsize;
772 if (params->variable && params->msgsize) {
773 msg_len = rand() % params->msgsize;
774 }
775
776 iovs[0].iov_len = msg_len / 3;
777 iovs[1].iov_len = msg_len - iovs[0].iov_len;
778
779 memset(tx0_buf, i + 1, iovs[0].iov_len);
780 memset(tx1_buf, i + 2, iovs[1].iov_len);
781 memset(rx_buf, i + 3, sizeof(rx_buf));
782
783 rc = writev(echo_fd, iovs, 2);
784 if (rc < 0) {
785 perror("writev_test: writev");
786 break;
787 }
788
789 if ((size_t)rc != msg_len) {
790 fprintf(stderr, "%s: %s: data size mismatch (%zd vs. %zd)\n", __func__, "writev",
791 (size_t)rc, msg_len);
792 break;
793 }
794
795 rc = read(echo_fd, rx_buf, sizeof(rx_buf));
796 if (rc < 0) {
797 perror("writev_test: read");
798 break;
799 }
800
801 if ((size_t)rc != msg_len) {
802 fprintf(stderr, "%s: %s: data size mismatch (%zd vs. %zd)\n", __func__, "read",
803 (size_t)rc, msg_len);
804 break;
805 }
806
807 if (memcmp(tx0_buf, rx_buf, iovs[0].iov_len)) {
808 fprintf(stderr, "%s: data mismatch: buf 0\n", __func__);
809 break;
810 }
811
812 if (memcmp(tx1_buf, rx_buf + iovs[0].iov_len, iovs[1].iov_len)) {
813 fprintf(stderr, "%s: data mismatch, buf 1\n", __func__);
814 break;
815 }
816 }
817
818 tipc_close(echo_fd);
819
820 if (!params->silent) {
821 printf("%s: done\n", __func__);
822 }
823
824 return 0;
825 }
826
readv_test(const struct tipc_test_params * params)827 static int readv_test(const struct tipc_test_params* params) {
828 uint i;
829 ssize_t rc;
830 size_t msg_len;
831 int echo_fd = -1;
832 char tx_buf[params->msgsize];
833 char rx0_buf[params->msgsize];
834 char rx1_buf[params->msgsize];
835 struct iovec iovs[2] = {{rx0_buf, 0}, {rx1_buf, 0}};
836
837 if (!params->silent) {
838 printf("%s: repeat %u: params->msgsize %u: variable %s\n", __func__, params->repeat,
839 params->msgsize, params->variable ? "true" : "false");
840 }
841
842 echo_fd = tipc_connect(params->dev_name, echo_name);
843 if (echo_fd < 0) {
844 fprintf(stderr, "Failed to connect to service\n");
845 return echo_fd;
846 }
847
848 for (i = 0; i < params->repeat; i++) {
849 msg_len = params->msgsize;
850 if (params->variable && params->msgsize) {
851 msg_len = rand() % params->msgsize;
852 }
853
854 iovs[0].iov_len = msg_len / 3;
855 iovs[1].iov_len = msg_len - iovs[0].iov_len;
856
857 memset(tx_buf, i + 1, sizeof(tx_buf));
858 memset(rx0_buf, i + 2, iovs[0].iov_len);
859 memset(rx1_buf, i + 3, iovs[1].iov_len);
860
861 rc = write(echo_fd, tx_buf, msg_len);
862 if (rc < 0) {
863 perror("readv_test: write");
864 break;
865 }
866
867 if ((size_t)rc != msg_len) {
868 fprintf(stderr, "%s: %s: data size mismatch (%zd vs. %zd)\n", __func__, "write",
869 (size_t)rc, msg_len);
870 break;
871 }
872
873 rc = readv(echo_fd, iovs, 2);
874 if (rc < 0) {
875 perror("readv_test: readv");
876 break;
877 }
878
879 if ((size_t)rc != msg_len) {
880 fprintf(stderr, "%s: %s: data size mismatch (%zd vs. %zd)\n", __func__, "write",
881 (size_t)rc, msg_len);
882 break;
883 }
884
885 if (memcmp(rx0_buf, tx_buf, iovs[0].iov_len)) {
886 fprintf(stderr, "%s: data mismatch: buf 0\n", __func__);
887 break;
888 }
889
890 if (memcmp(rx1_buf, tx_buf + iovs[0].iov_len, iovs[1].iov_len)) {
891 fprintf(stderr, "%s: data mismatch, buf 1\n", __func__);
892 break;
893 }
894 }
895
896 tipc_close(echo_fd);
897
898 if (!params->silent) {
899 printf("%s: done\n", __func__);
900 }
901
902 return 0;
903 }
904
send_fd_test(const struct tipc_test_params * params)905 static int send_fd_test(const struct tipc_test_params* params) {
906 int ret;
907 int dma_buf = -1;
908 int fd = -1;
909 volatile char* buf = MAP_FAILED;
910 BufferAllocator* allocator = NULL;
911
912 const size_t num_chunks = 10;
913
914 fd = tipc_connect(params->dev_name, receiver_name);
915 if (fd < 0) {
916 fprintf(stderr, "Failed to connect to test support TA - is it missing?\n");
917 ret = -1;
918 goto cleanup;
919 }
920
921 allocator = CreateDmabufHeapBufferAllocator();
922 if (!allocator) {
923 fprintf(stderr, "Failed to create dma-buf allocator.\n");
924 ret = -1;
925 goto cleanup;
926 }
927
928 size_t buf_size = memref_chunk_size * num_chunks;
929 dma_buf = DmabufHeapAlloc(allocator, "system", buf_size, 0, 0 /* legacy align */);
930 if (dma_buf < 0) {
931 ret = dma_buf;
932 fprintf(stderr, "Failed to create dma-buf fd of size %zu err (%d)\n", buf_size, ret);
933 goto cleanup;
934 }
935
936 buf = mmap(0, buf_size, PROT_READ | PROT_WRITE, MAP_SHARED, dma_buf, 0);
937 if (buf == MAP_FAILED) {
938 fprintf(stderr, "Failed to map dma-buf: %s\n", strerror(errno));
939 ret = -1;
940 goto cleanup;
941 }
942
943 strcpy((char*)buf, "From NS");
944
945 struct trusty_shm shm = {
946 .fd = dma_buf,
947 .transfer = TRUSTY_SHARE,
948 };
949
950 ssize_t rc = tipc_send(fd, NULL, 0, &shm, 1);
951 if (rc < 0) {
952 fprintf(stderr, "tipc_send failed: %zd\n", rc);
953 ret = rc;
954 goto cleanup;
955 }
956 char c;
957 read(fd, &c, 1);
958 tipc_close(fd);
959
960 ret = 0;
961 for (size_t skip = 0; skip < num_chunks; skip++) {
962 int cmp = strcmp("Hello from Trusty!",
963 (const char*)&buf[skip * memref_chunk_size]) ? (-1) : 0;
964 if (cmp)
965 fprintf(stderr, "Failed: Unexpected content at page %zu in dmabuf\n", skip);
966 ret |= cmp;
967 }
968
969 cleanup:
970 if (buf != MAP_FAILED) {
971 munmap((char*)buf, buf_size);
972 }
973 close(dma_buf);
974 if (allocator) {
975 FreeDmabufHeapBufferAllocator(allocator);
976 }
977 tipc_close(fd);
978 return ret;
979 }
980
get_time_us(void)981 uint64_t get_time_us(void) {
982 struct timespec spec;
983
984 clock_gettime(CLOCK_MONOTONIC, &spec);
985 return spec.tv_sec * 1000000 + spec.tv_nsec / 1000;
986 }
987
988 static const struct tipc_test_def tipc_tests[] = {
989 {"connect", connect_test},
990 {"connect_foo", connect_foo},
991 {"burst_write", burst_write_test},
992 {"select", select_test},
993 {"blocked_read", blocked_read_test},
994 {"closer1", closer1_test},
995 {"closer2", closer2_test},
996 {"closer3", closer3_test},
997 {"echo", echo_test},
998 {"ta2ta-ipc", ta2ta_ipc_test},
999 {"dev-uuid", dev_uuid_test},
1000 {"ta-access", ta_access_test},
1001 {"writev", writev_test},
1002 {"readv", readv_test},
1003 {"send-fd", send_fd_test},
1004 };
1005
get_test_function(const struct tipc_test_params * params)1006 tipc_test_func_t get_test_function(const struct tipc_test_params* params) {
1007 for (size_t i = 0; i < sizeof(tipc_tests) / sizeof(tipc_tests[0]); i++) {
1008 if (strcmp(params->test_name, tipc_tests[i].test_name) == 0) {
1009 return tipc_tests[i].func;
1010 }
1011 }
1012 fprintf(stderr, "Unrecognized test name '%s'\n", params->test_name);
1013 exit(1);
1014 }
1015
run_as_bench(const struct tipc_test_params * params)1016 static int run_as_bench(const struct tipc_test_params* params) {
1017 int rc = 0;
1018 int64_t min = INT64_MAX;
1019 int64_t max = 0;
1020 int64_t avg = 0;
1021 int64_t cold = 0;
1022
1023 uint64_t start;
1024 uint64_t end;
1025
1026 tipc_test_func_t test = get_test_function(params);
1027
1028 for (size_t i = 0; (i < params->bench + 1) && rc == 0; ++i) {
1029 start = get_time_us();
1030 rc |= test(params);
1031 end = get_time_us();
1032 int64_t t = end - start;
1033
1034 if (i == 0) {
1035 cold = t;
1036 } else {
1037 min = (t < min) ? t : min;
1038 max = (t > max) ? t : max;
1039 avg += t;
1040 }
1041 }
1042 avg /= params->bench;
1043
1044 printf(BENCH_RESULT_TPL, params->test_name, min, max, avg, cold, min, max, avg, cold);
1045 return rc;
1046 }
1047
main(int argc,char ** argv)1048 int main(int argc, char **argv)
1049 {
1050 int rc = 0;
1051
1052 if (argc <= 1) {
1053 print_usage_and_exit(argv[0], EXIT_FAILURE, false);
1054 }
1055 struct tipc_test_params params;
1056 init_params(¶ms);
1057 parse_options(argc, argv, ¶ms);
1058
1059 if (!params.dev_name) {
1060 params.dev_name = TIPC_DEFAULT_DEVNAME;
1061 }
1062
1063 if (!params.test_name) {
1064 fprintf(stderr, "need a Test to run\n");
1065 print_usage_and_exit(argv[0], EXIT_FAILURE, true);
1066 }
1067
1068 if (params.bench > 0) {
1069 rc = run_as_bench(¶ms);
1070 params.bench = 0;
1071 } else {
1072 tipc_test_func_t test = get_test_function(¶ms);
1073 rc = test(¶ms);
1074 }
1075 return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1076 }
1077