Merge "Secretkeeper: add Trusty fuzzers" into main
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 26726cf..0d4b91f 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -91,6 +91,15 @@
     }
   }
 
+  // unfreeze if pid is frozen.
+  const std::string freeze_file = android::base::StringPrintf(
+      "/sys/fs/cgroup/uid_%d/pid_%d/cgroup.freeze", proc_info.uid, proc_info.pid);
+  if (std::string freeze_status;
+      android::base::ReadFileToString(freeze_file, &freeze_status) && freeze_status[0] == '1') {
+    android::base::WriteStringToFile("0", freeze_file);
+    // we don't restore the frozen state as this is considered a benign change.
+  }
+
   unique_fd output_fd(fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0));
   if (output_fd.get() == -1) {
     err(1, "failed to fcntl dup stdout");
diff --git a/fs_mgr/fs_mgr_overlayfs_mount.cpp b/fs_mgr/fs_mgr_overlayfs_mount.cpp
index e168436..a1ec63b 100644
--- a/fs_mgr/fs_mgr_overlayfs_mount.cpp
+++ b/fs_mgr/fs_mgr_overlayfs_mount.cpp
@@ -98,7 +98,12 @@
     if (mount_point.empty() || !android::base::Realpath(mount_point, &normalized_path)) {
         return "";
     }
-    return android::base::StringReplace(normalized_path, "/", "@", true);
+    std::string_view sv(normalized_path);
+    if (sv != "/") {
+        android::base::ConsumePrefix(&sv, "/");
+        android::base::ConsumeSuffix(&sv, "/");
+    }
+    return android::base::StringReplace(sv, "/", "@", true);
 }
 
 static bool fs_mgr_is_dir(const std::string& path) {
diff --git a/trusty/libtrusty/tipc-test/tipc_test.c b/trusty/libtrusty/tipc-test/tipc_test.c
index 0f50787..dabe118 100644
--- a/trusty/libtrusty/tipc-test/tipc_test.c
+++ b/trusty/libtrusty/tipc-test/tipc_test.c
@@ -22,8 +22,10 @@
 #include <unistd.h>
 #include <getopt.h>
 #define __USE_GNU
+#include <inttypes.h>
 #include <sys/mman.h>
 #include <sys/uio.h>
+#include <time.h>
 
 #include <BufferAllocator/BufferAllocatorWrapper.h>
 
@@ -31,8 +33,27 @@
 
 #define TIPC_DEFAULT_DEVNAME "/dev/trusty-ipc-dev0"
 
-static const char *dev_name = NULL;
-static const char *test_name = NULL;
+/* clang-format off */
+#define BENCH_RESULT_TPL                                    \
+"{"                                                         \
+"    \"schema_version\": 3,"                                \
+"    \"suite_name\": \"crypto\","                           \
+"    \"bench_name\": \"%s\","                               \
+"    \"results\": ["                                        \
+"        {"                                                 \
+"            \"metric_name\": \"time_micro_sec\","          \
+"            \"min\": \"%" PRId64 "\","                     \
+"            \"max\": \"%" PRId64 "\","                     \
+"            \"avg\": \"%" PRId64 "\","                     \
+"            \"cold\": \"%" PRId64 "\","                    \
+"            \"raw_min\": %" PRId64 ","                     \
+"            \"raw_max\": %" PRId64 ","                     \
+"            \"raw_avg\": %" PRId64 ","                     \
+"            \"raw_cold\": %" PRId64 ""                     \
+"        },"                                                \
+"    ]"                                                     \
+"}"
+/* clang-format on */
 
 static const char *uuid_name = "com.android.ipc-unittest.srv.uuid";
 static const char *echo_name = "com.android.ipc-unittest.srv.echo";
@@ -46,7 +67,7 @@
 static const char* receiver_name = "com.android.trusty.memref.receiver";
 static const size_t memref_chunk_size = 4096;
 
-static const char* _sopts = "hsvDS:t:r:m:b:";
+static const char* _sopts = "hsvDS:t:r:m:b:B:";
 /* clang-format off */
 static const struct option _lopts[] =  {
     {"help",    no_argument,       0, 'h'},
@@ -57,6 +78,8 @@
     {"repeat",  required_argument, 0, 'r'},
     {"burst",   required_argument, 0, 'b'},
     {"msgsize", required_argument, 0, 'm'},
+    {"test",    required_argument, 0, 't'},
+    {"bench",   required_argument, 0, 'B'},
     {0, 0, 0, 0}
 };
 /* clang-format on */
@@ -74,6 +97,7 @@
         "  -m, --msgsize size    max message size\n"
         "  -v, --variable        variable message size\n"
         "  -s, --silent          silent\n"
+        "  -B, --bench           Run as Benchmark N times\n"
         "\n";
 
 static const char* usage_long =
@@ -96,12 +120,34 @@
         "   send-fd      - transmit dma_buf to trusty, use as shm\n"
         "\n";
 
-static uint opt_repeat  = 1;
-static uint opt_msgsize = 32;
-static uint opt_msgburst = 32;
-static bool opt_variable = false;
-static bool opt_silent = false;
-static char* srv_name = NULL;
+struct tipc_test_params {
+    uint repeat;
+    uint msgsize;
+    uint msgburst;
+    bool variable;
+    bool silent;
+    uint bench;
+    char* srv_name;
+    char* dev_name;
+    char* test_name;
+};
+typedef int (*tipc_test_func_t)(const struct tipc_test_params*);
+
+struct tipc_test_def {
+    char* test_name;
+    tipc_test_func_t func;
+};
+
+static void init_params(struct tipc_test_params* params) {
+    params->repeat = 1;
+    params->msgsize = 32;
+    params->msgburst = 32;
+    params->variable = false;
+    params->silent = false;
+    params->bench = 0;
+    params->srv_name = NULL;
+    params->test_name = NULL;
+}
 
 static void print_usage_and_exit(const char *prog, int code, bool verbose)
 {
@@ -110,8 +156,7 @@
     exit(code);
 }
 
-static void parse_options(int argc, char **argv)
-{
+static void parse_options(int argc, char** argv, struct tipc_test_params* params) {
     int c;
     int oidx = 0;
 
@@ -121,35 +166,39 @@
 
         switch (c) {
             case 'D':
-                dev_name = strdup(optarg);
+                params->dev_name = strdup(optarg);
                 break;
 
             case 'S':
-                srv_name = strdup(optarg);
+                params->srv_name = strdup(optarg);
                 break;
 
             case 't':
-                test_name = strdup(optarg);
+                params->test_name = strdup(optarg);
                 break;
 
             case 'v':
-                opt_variable = true;
+                params->variable = true;
                 break;
 
             case 'r':
-                opt_repeat = atoi(optarg);
+                params->repeat = atoi(optarg);
                 break;
 
             case 'm':
-                opt_msgsize = atoi(optarg);
+                params->msgsize = atoi(optarg);
                 break;
 
             case 'b':
-                opt_msgburst = atoi(optarg);
+                params->msgburst = atoi(optarg);
                 break;
 
             case 's':
-                opt_silent = true;
+                params->silent = true;
+                break;
+
+            case 'B':
+                params->bench = atoi(optarg);
                 break;
 
             case 'h':
@@ -162,32 +211,31 @@
     }
 }
 
-static int connect_test(uint repeat)
-{
+static int connect_test(const struct tipc_test_params* params) {
     uint i;
     int echo_fd;
     int dsink_fd;
     int custom_fd;
 
-    if (!opt_silent) {
-        printf("%s: repeat = %u\n", __func__, repeat);
+    if (!params->silent) {
+        printf("%s: repeat = %u\n", __func__, params->repeat);
     }
 
-    for (i = 0; i < repeat; i++) {
-        if (srv_name) {
-            custom_fd = tipc_connect(dev_name, srv_name);
+    for (i = 0; i < params->repeat; i++) {
+        if (params->srv_name) {
+            custom_fd = tipc_connect(params->dev_name, params->srv_name);
             if (custom_fd < 0) {
-                fprintf(stderr, "Failed to connect to '%s' service\n", srv_name);
+                fprintf(stderr, "Failed to connect to '%s' service\n", params->srv_name);
             }
             if (custom_fd >= 0) {
                 tipc_close(custom_fd);
             }
         } else {
-            echo_fd = tipc_connect(dev_name, echo_name);
+            echo_fd = tipc_connect(params->dev_name, echo_name);
             if (echo_fd < 0) {
                 fprintf(stderr, "Failed to connect to '%s' service\n", "echo");
             }
-            dsink_fd = tipc_connect(dev_name, datasink_name);
+            dsink_fd = tipc_connect(params->dev_name, datasink_name);
             if (dsink_fd < 0) {
                 fprintf(stderr, "Failed to connect to '%s' service\n", "datasink");
             }
@@ -201,79 +249,75 @@
         }
     }
 
-    if (!opt_silent) {
+    if (!params->silent) {
         printf("%s: done\n", __func__);
     }
 
     return 0;
 }
 
-static int connect_foo(uint repeat)
-{
+static int connect_foo(const struct tipc_test_params* params) {
     uint i;
     int fd;
 
-    if (!opt_silent) {
-        printf("%s: repeat = %u\n", __func__, repeat);
+    if (!params->silent) {
+        printf("%s: repeat = %u\n", __func__, params->repeat);
     }
 
-    for (i = 0; i < repeat; i++) {
-        fd = tipc_connect(dev_name, "foo");
+    for (i = 0; i < params->repeat; i++) {
+        fd = tipc_connect(params->dev_name, "foo");
         if (fd >= 0) {
             fprintf(stderr, "succeeded to connect to '%s' service\n", "foo");
             tipc_close(fd);
         }
     }
 
-    if (!opt_silent) {
+    if (!params->silent) {
         printf("%s: done\n", __func__);
     }
 
     return 0;
 }
 
-
-static int closer1_test(uint repeat)
-{
+static int closer1_test(const struct tipc_test_params* params) {
     uint i;
     int fd;
 
-    if (!opt_silent) {
-        printf("%s: repeat = %u\n", __func__, repeat);
+    if (!params->silent) {
+        printf("%s: repeat = %u\n", __func__, params->repeat);
     }
 
-    for (i = 0; i < repeat; i++) {
-        fd = tipc_connect(dev_name, closer1_name);
+    for (i = 0; i < params->repeat; i++) {
+        fd = tipc_connect(params->dev_name, closer1_name);
         if (fd < 0) {
             fprintf(stderr, "Failed to connect to '%s' service\n", "closer1");
             continue;
         }
-        if (!opt_silent) {
+        if (!params->silent) {
             printf("%s: connected\n", __func__);
         }
         tipc_close(fd);
     }
 
-    if (!opt_silent) {
+    if (!params->silent) {
         printf("%s: done\n", __func__);
     }
 
     return 0;
 }
 
-static int closer2_test(uint repeat)
-{
+static int closer2_test(const struct tipc_test_params* params) {
     uint i;
     int fd;
 
-    if (!opt_silent) {
-        printf("%s: repeat = %u\n", __func__, repeat);
+    if (!params->silent) {
+        printf("%s: repeat = %u\n", __func__, params->repeat);
     }
 
-    for (i = 0; i < repeat; i++) {
-        fd = tipc_connect(dev_name, closer2_name);
+    for (i = 0; i < params->repeat; i++) {
+        fd = tipc_connect(params->dev_name, closer2_name);
         if (fd < 0) {
-            if (!opt_silent) {
+            if (!params->silent) {
                 printf("failed to connect to '%s' service\n", "closer2");
             }
         } else {
@@ -283,38 +327,37 @@
         }
     }
 
-    if (!opt_silent) {
+    if (!params->silent) {
         printf("%s: done\n", __func__);
     }
 
     return 0;
 }
 
-static int closer3_test(uint repeat)
-{
+static int closer3_test(const struct tipc_test_params* params) {
     uint i, j;
     ssize_t rc;
     int fd[4];
     char buf[64];
 
-    if (!opt_silent) {
-        printf("%s: repeat = %u\n", __func__, repeat);
+    if (!params->silent) {
+        printf("%s: repeat = %u\n", __func__, params->repeat);
     }
 
-    for (i = 0; i < repeat; i++) {
+    for (i = 0; i < params->repeat; i++) {
         /* open 4 connections to closer3 service */
         for (j = 0; j < 4; j++) {
-            fd[j] = tipc_connect(dev_name, closer3_name);
+            fd[j] = tipc_connect(params->dev_name, closer3_name);
             if (fd[j] < 0) {
                 fprintf(stderr, "fd[%d]: failed to connect to '%s' service\n", j, "closer3");
             } else {
-                if (!opt_silent) {
+                if (!params->silent) {
                     printf("%s: fd[%d]=%d: connected\n", __func__, j, fd[j]);
                 }
                 memset(buf, i + j, sizeof(buf));
                 rc = write(fd[j], buf, sizeof(buf));
                 if (rc != sizeof(buf)) {
-                    if (!opt_silent) {
+                    if (!params->silent) {
                         printf("%s: fd[%d]=%d: write returned  = %zd\n", __func__, j, fd[j], rc);
                     }
                     perror("closer3_test: write");
@@ -330,7 +373,7 @@
             if (fd[j] < 0) continue;
             rc = write(fd[j], buf, sizeof(buf));
             if (rc != sizeof(buf)) {
-                if (!opt_silent) {
+                if (!params->silent) {
                     printf("%s: fd[%d]=%d: write returned = %zd\n", __func__, j, fd[j], rc);
                 }
                 perror("closer3_test: write");
@@ -345,38 +388,36 @@
         }
     }
 
-    if (!opt_silent) {
+    if (!params->silent) {
         printf("%s: done\n", __func__);
     }
 
     return 0;
 }
 
-
-static int echo_test(uint repeat, uint msgsz, bool var)
-{
+static int echo_test(const struct tipc_test_params* params) {
     uint i;
     ssize_t rc;
     size_t msg_len;
     int echo_fd = -1;
-    char tx_buf[msgsz];
-    char rx_buf[msgsz];
+    char tx_buf[params->msgsize];
+    char rx_buf[params->msgsize];
 
-    if (!opt_silent) {
-        printf("%s: repeat %u: msgsz %u: variable %s\n", __func__, repeat, msgsz,
-               var ? "true" : "false");
+    if (!params->silent) {
+        printf("%s: repeat %u: params->msgsize %u: variable %s\n", __func__, params->repeat,
+               params->msgsize, params->variable ? "true" : "false");
     }
 
-    echo_fd = tipc_connect(dev_name, echo_name);
+    echo_fd = tipc_connect(params->dev_name, echo_name);
     if (echo_fd < 0) {
         fprintf(stderr, "Failed to connect to service\n");
         return echo_fd;
     }
 
-    for (i = 0; i < repeat; i++) {
-        msg_len = msgsz;
-        if (opt_variable && msgsz) {
-            msg_len = rand() % msgsz;
+    for (i = 0; i < params->repeat; i++) {
+        msg_len = params->msgsize;
+        if (params->variable && params->msgsize) {
+            msg_len = rand() % params->msgsize;
         }
 
         memset(tx_buf, i + 1, msg_len);
@@ -406,37 +447,37 @@
 
     tipc_close(echo_fd);
 
-    if (!opt_silent) {
+    if (!params->silent) {
         printf("%s: done\n", __func__);
     }
 
     return 0;
 }
 
-static int burst_write_test(uint repeat, uint msgburst, uint msgsz, bool var)
-{
+static int burst_write_test(const struct tipc_test_params* params) {
     int fd;
     uint i, j;
     ssize_t rc;
     size_t msg_len;
-    char tx_buf[msgsz];
+    char tx_buf[params->msgsize];
 
-    if (!opt_silent) {
-        printf("%s: repeat %u: burst %u: msgsz %u: variable %s\n", __func__, repeat, msgburst,
-               msgsz, var ? "true" : "false");
+    if (!params->silent) {
+        printf("%s: repeat %u: burst %u: params->msgsize %u: variable %s\n", __func__,
+               params->repeat, params->msgburst, params->msgsize,
+               params->variable ? "true" : "false");
     }
 
-    for (i = 0; i < repeat; i++) {
-        fd = tipc_connect(dev_name, datasink_name);
+    for (i = 0; i < params->repeat; i++) {
+        fd = tipc_connect(params->dev_name, datasink_name);
         if (fd < 0) {
             fprintf(stderr, "Failed to connect to '%s' service\n", "datasink");
             break;
         }
 
-        for (j = 0; j < msgburst; j++) {
-            msg_len = msgsz;
-            if (var && msgsz) {
-                msg_len = rand() % msgsz;
+        for (j = 0; j < params->msgburst; j++) {
+            msg_len = params->msgsize;
+            if (params->variable && params->msgsize) {
+                msg_len = rand() % params->msgsize;
             }
 
             memset(tx_buf, i + 1, msg_len);
@@ -450,23 +491,21 @@
         tipc_close(fd);
     }
 
-    if (!opt_silent) {
+    if (!params->silent) {
         printf("%s: done\n", __func__);
     }
 
     return 0;
 }
 
-
-static int _wait_for_msg(int fd, uint msgsz, int timeout)
-{
+static int _wait_for_msg(int fd, int timeout, const struct tipc_test_params* params) {
     int rc;
     fd_set rfds;
     uint msgcnt = 0;
-    char rx_buf[msgsz];
+    char rx_buf[params->msgsize];
     struct timeval tv;
 
-    if (!opt_silent) {
+    if (!params->silent) {
         printf("waiting (%d) for msg\n", timeout);
     }
 
@@ -480,7 +519,7 @@
         rc = select(fd + 1, &rfds, NULL, NULL, &tv);
 
         if (rc == 0) {
-            if (!opt_silent) {
+            if (!params->silent) {
                 printf("select timedout\n");
             }
             break;
@@ -502,42 +541,40 @@
         }
     }
 
-    if (!opt_silent) {
+    if (!params->silent) {
         printf("got %u messages\n", msgcnt);
     }
 
     return 0;
 }
 
-
-static int select_test(uint repeat, uint msgburst, uint msgsz)
-{
+static int select_test(const struct tipc_test_params* params) {
     int fd;
     uint i, j;
     ssize_t rc;
-    char tx_buf[msgsz];
+    char tx_buf[params->msgsize];
 
-    if (!opt_silent) {
-        printf("%s: repeat %u\n", __func__, repeat);
+    if (!params->silent) {
+        printf("%s: repeat %u\n", __func__, params->repeat);
     }
 
-    fd = tipc_connect(dev_name, echo_name);
+    fd = tipc_connect(params->dev_name, echo_name);
     if (fd < 0) {
         fprintf(stderr, "Failed to connect to '%s' service\n", "echo");
         return fd;
     }
 
-    for (i = 0; i < repeat; i++) {
-        _wait_for_msg(fd, msgsz, 1);
+    for (i = 0; i < params->repeat; i++) {
+        _wait_for_msg(fd, 1, params);
 
-        if (!opt_silent) {
-            printf("sending burst: %u msg\n", msgburst);
+        if (!params->silent) {
+            printf("sending burst: %u msg\n", params->msgburst);
         }
 
-        for (j = 0; j < msgburst; j++) {
-            memset(tx_buf, i + j, msgsz);
-            rc = write(fd, tx_buf, msgsz);
-            if ((size_t)rc != msgsz) {
+        for (j = 0; j < params->msgburst; j++) {
+            memset(tx_buf, i + j, params->msgsize);
+            rc = write(fd, tx_buf, params->msgsize);
+            if ((size_t)rc != params->msgsize) {
                 perror("burst_test: write");
                 break;
             }
@@ -546,37 +583,36 @@
 
     tipc_close(fd);
 
-    if (!opt_silent) {
+    if (!params->silent) {
         printf("%s: done\n", __func__);
     }
 
     return 0;
 }
 
-static int blocked_read_test(uint repeat)
-{
+static int blocked_read_test(const struct tipc_test_params* params) {
     int fd;
     uint i;
     ssize_t rc;
     char rx_buf[512];
 
-    if (!opt_silent) {
-        printf("%s: repeat %u\n", __func__, repeat);
+    if (!params->silent) {
+        printf("%s: repeat %u\n", __func__, params->repeat);
     }
 
-    fd = tipc_connect(dev_name, echo_name);
+    fd = tipc_connect(params->dev_name, echo_name);
     if (fd < 0) {
         fprintf(stderr, "Failed to connect to '%s' service\n", "echo");
         return fd;
     }
 
-    for (i = 0; i < repeat; i++) {
+    for (i = 0; i < params->repeat; i++) {
         rc = read(fd, rx_buf, sizeof(rx_buf));
         if (rc < 0) {
             perror("select_test: read");
             break;
         } else {
-            if (!opt_silent) {
+            if (!params->silent) {
                 printf("got %zd bytes\n", rc);
             }
         }
@@ -584,15 +620,14 @@
 
     tipc_close(fd);
 
-    if (!opt_silent) {
+    if (!params->silent) {
         printf("%s: done\n", __func__);
     }
 
     return 0;
 }
 
-static int ta2ta_ipc_test(void)
-{
+static int ta2ta_ipc_test(const struct tipc_test_params* params) {
     enum test_message_header {
         TEST_PASSED = 0,
         TEST_FAILED = 1,
@@ -604,11 +639,11 @@
     int ret;
     unsigned char rx_buf[256];
 
-    if (!opt_silent) {
+    if (!params->silent) {
         printf("%s:\n", __func__);
     }
 
-    fd = tipc_connect(dev_name, main_ctrl_name);
+    fd = tipc_connect(params->dev_name, main_ctrl_name);
     if (fd < 0) {
         fprintf(stderr, "Failed to connect to '%s' service\n", "main_ctrl");
         return fd;
@@ -658,13 +693,12 @@
            uuid->clock_seq_and_node[7]);
 }
 
-static int dev_uuid_test(void)
-{
+static int dev_uuid_test(const struct tipc_test_params* params) {
     int fd;
     ssize_t rc;
     uuid_t uuid;
 
-    fd = tipc_connect(dev_name, uuid_name);
+    fd = tipc_connect(params->dev_name, uuid_name);
     if (fd < 0) {
         fprintf(stderr, "Failed to connect to '%s' service\n", "uuid");
         return fd;
@@ -677,7 +711,7 @@
     } else if (rc != sizeof(uuid)) {
         fprintf(stderr, "unexpected uuid size (%d vs. %d)\n", (int)rc, (int)sizeof(uuid));
     } else {
-        print_uuid(dev_name, &uuid);
+        print_uuid(params->dev_name, &uuid);
     }
 
     tipc_close(fd);
@@ -685,61 +719,58 @@
     return 0;
 }
 
-static int ta_access_test(void)
-{
+static int ta_access_test(const struct tipc_test_params* params) {
     int fd;
 
-    if (!opt_silent) {
+    if (!params->silent) {
         printf("%s:\n", __func__);
     }
 
-    fd = tipc_connect(dev_name, ta_only_name);
+    fd = tipc_connect(params->dev_name, ta_only_name);
     if (fd >= 0) {
         fprintf(stderr, "Succeed to connect to '%s' service\n", "ta_only");
         tipc_close(fd);
     }
 
-    fd = tipc_connect(dev_name, ns_only_name);
+    fd = tipc_connect(params->dev_name, ns_only_name);
     if (fd < 0) {
         fprintf(stderr, "Failed to connect to '%s' service\n", "ns_only");
         return fd;
     }
     tipc_close(fd);
 
-    if (!opt_silent) {
+    if (!params->silent) {
         printf("%s: done\n", __func__);
     }
 
     return 0;
 }
 
-
-static int writev_test(uint repeat, uint msgsz, bool var)
-{
+static int writev_test(const struct tipc_test_params* params) {
     uint i;
     ssize_t rc;
     size_t msg_len;
     int echo_fd = -1;
-    char tx0_buf[msgsz];
-    char tx1_buf[msgsz];
-    char rx_buf[msgsz];
+    char tx0_buf[params->msgsize];
+    char tx1_buf[params->msgsize];
+    char rx_buf[params->msgsize];
     struct iovec iovs[2] = {{tx0_buf, 0}, {tx1_buf, 0}};
 
-    if (!opt_silent) {
-        printf("%s: repeat %u: msgsz %u: variable %s\n", __func__, repeat, msgsz,
-               var ? "true" : "false");
+    if (!params->silent) {
+        printf("%s: repeat %u: params->msgsize %u: variable %s\n", __func__, params->repeat,
+               params->msgsize, params->variable ? "true" : "false");
     }
 
-    echo_fd = tipc_connect(dev_name, echo_name);
+    echo_fd = tipc_connect(params->dev_name, echo_name);
     if (echo_fd < 0) {
         fprintf(stderr, "Failed to connect to service\n");
         return echo_fd;
     }
 
-    for (i = 0; i < repeat; i++) {
-        msg_len = msgsz;
-        if (opt_variable && msgsz) {
-            msg_len = rand() % msgsz;
+    for (i = 0; i < params->repeat; i++) {
+        msg_len = params->msgsize;
+        if (params->variable && params->msgsize) {
+            msg_len = rand() % params->msgsize;
         }
 
         iovs[0].iov_len = msg_len / 3;
@@ -786,39 +817,38 @@
 
     tipc_close(echo_fd);
 
-    if (!opt_silent) {
+    if (!params->silent) {
         printf("%s: done\n", __func__);
     }
 
     return 0;
 }
 
-static int readv_test(uint repeat, uint msgsz, bool var)
-{
+static int readv_test(const struct tipc_test_params* params) {
     uint i;
     ssize_t rc;
     size_t msg_len;
     int echo_fd = -1;
-    char tx_buf[msgsz];
-    char rx0_buf[msgsz];
-    char rx1_buf[msgsz];
+    char tx_buf[params->msgsize];
+    char rx0_buf[params->msgsize];
+    char rx1_buf[params->msgsize];
     struct iovec iovs[2] = {{rx0_buf, 0}, {rx1_buf, 0}};
 
-    if (!opt_silent) {
-        printf("%s: repeat %u: msgsz %u: variable %s\n", __func__, repeat, msgsz,
-               var ? "true" : "false");
+    if (!params->silent) {
+        printf("%s: repeat %u: params->msgsize %u: variable %s\n", __func__, params->repeat,
+               params->msgsize, params->variable ? "true" : "false");
     }
 
-    echo_fd = tipc_connect(dev_name, echo_name);
+    echo_fd = tipc_connect(params->dev_name, echo_name);
     if (echo_fd < 0) {
         fprintf(stderr, "Failed to connect to service\n");
         return echo_fd;
     }
 
-    for (i = 0; i < repeat; i++) {
-        msg_len = msgsz;
-        if (opt_variable && msgsz) {
-            msg_len = rand() % msgsz;
+    for (i = 0; i < params->repeat; i++) {
+        msg_len = params->msgsize;
+        if (params->variable && params->msgsize) {
+            msg_len = rand() % params->msgsize;
         }
 
         iovs[0].iov_len = msg_len / 3;
@@ -865,14 +895,14 @@
 
     tipc_close(echo_fd);
 
-    if (!opt_silent) {
+    if (!params->silent) {
         printf("%s: done\n", __func__);
     }
 
     return 0;
 }
 
-static int send_fd_test(void) {
+static int send_fd_test(const struct tipc_test_params* params) {
     int ret;
     int dma_buf = -1;
     int fd = -1;
@@ -881,7 +911,7 @@
 
     const size_t num_chunks = 10;
 
-    fd = tipc_connect(dev_name, receiver_name);
+    fd = tipc_connect(params->dev_name, receiver_name);
     if (fd < 0) {
         fprintf(stderr, "Failed to connect to test support TA - is it missing?\n");
         ret = -1;
@@ -948,6 +978,73 @@
     return ret;
 }
 
+uint64_t get_time_us(void) {
+    struct timespec spec;
+
+    clock_gettime(CLOCK_MONOTONIC, &spec);
+    return spec.tv_sec * 1000000 + spec.tv_nsec / 1000;
+}
+
+static const struct tipc_test_def tipc_tests[] = {
+        {"connect", connect_test},
+        {"connect_foo", connect_foo},
+        {"burst_write", burst_write_test},
+        {"select", select_test},
+        {"blocked_read", blocked_read_test},
+        {"closer1", closer1_test},
+        {"closer2", closer2_test},
+        {"closer3", closer3_test},
+        {"echo", echo_test},
+        {"ta2ta-ipc", ta2ta_ipc_test},
+        {"dev-uuid", dev_uuid_test},
+        {"ta-access", ta_access_test},
+        {"writev", writev_test},
+        {"readv", readv_test},
+        {"send-fd", send_fd_test},
+};
+
+tipc_test_func_t get_test_function(const struct tipc_test_params* params) {
+    for (size_t i = 0; i < sizeof(tipc_tests) / sizeof(tipc_tests[0]); i++) {
+        if (strcmp(params->test_name, tipc_tests[i].test_name) == 0) {
+            return tipc_tests[i].func;
+        }
+    }
+    fprintf(stderr, "Unrecognized test name '%s'\n", params->test_name);
+    exit(1);
+}
+
+static int run_as_bench(const struct tipc_test_params* params) {
+    int rc = 0;
+    int64_t min = INT64_MAX;
+    int64_t max = 0;
+    int64_t avg = 0;
+    int64_t cold = 0;
+
+    uint64_t start;
+    uint64_t end;
+
+    tipc_test_func_t test = get_test_function(params);
+
+    for (size_t i = 0; (i < params->bench + 1) && rc == 0; ++i) {
+        start = get_time_us();
+        rc |= test(params);
+        end = get_time_us();
+        int64_t t = end - start;
+
+        if (i == 0) {
+            cold = t;
+        } else {
+            min = (t < min) ? t : min;
+            max = (t > max) ? t : max;
+            avg += t;
+        }
+    }
+    avg /= params->bench;
+
+    fprintf(stderr, BENCH_RESULT_TPL, params->test_name, min, max, avg, cold, min, max, avg, cold);
+    return rc;
+}
+
 int main(int argc, char **argv)
 {
     int rc = 0;
@@ -955,52 +1052,25 @@
     if (argc <= 1) {
         print_usage_and_exit(argv[0], EXIT_FAILURE, false);
     }
+    struct tipc_test_params params;
+    init_params(&params);
+    parse_options(argc, argv, &params);
 
-    parse_options(argc, argv);
-
-    if (!dev_name) {
-        dev_name = TIPC_DEFAULT_DEVNAME;
+    if (!params.dev_name) {
+        params.dev_name = TIPC_DEFAULT_DEVNAME;
     }
 
-    if (!test_name) {
+    if (!params.test_name) {
         fprintf(stderr, "need a Test to run\n");
         print_usage_and_exit(argv[0], EXIT_FAILURE, true);
     }
 
-    if (strcmp(test_name, "connect") == 0) {
-        rc = connect_test(opt_repeat);
-    } else if (strcmp(test_name, "connect_foo") == 0) {
-        rc = connect_foo(opt_repeat);
-    } else if (strcmp(test_name, "burst_write") == 0) {
-        rc = burst_write_test(opt_repeat, opt_msgburst, opt_msgsize, opt_variable);
-    } else if (strcmp(test_name, "select") == 0) {
-        rc = select_test(opt_repeat, opt_msgburst, opt_msgsize);
-    } else if (strcmp(test_name, "blocked_read") == 0) {
-        rc = blocked_read_test(opt_repeat);
-    } else if (strcmp(test_name, "closer1") == 0) {
-        rc = closer1_test(opt_repeat);
-    } else if (strcmp(test_name, "closer2") == 0) {
-        rc = closer2_test(opt_repeat);
-    } else if (strcmp(test_name, "closer3") == 0) {
-        rc = closer3_test(opt_repeat);
-    } else if (strcmp(test_name, "echo") == 0) {
-        rc = echo_test(opt_repeat, opt_msgsize, opt_variable);
-    } else if (strcmp(test_name, "ta2ta-ipc") == 0) {
-        rc = ta2ta_ipc_test();
-    } else if (strcmp(test_name, "dev-uuid") == 0) {
-        rc = dev_uuid_test();
-    } else if (strcmp(test_name, "ta-access") == 0) {
-        rc = ta_access_test();
-    } else if (strcmp(test_name, "writev") == 0) {
-        rc = writev_test(opt_repeat, opt_msgsize, opt_variable);
-    } else if (strcmp(test_name, "readv") == 0) {
-        rc = readv_test(opt_repeat, opt_msgsize, opt_variable);
-    } else if (strcmp(test_name, "send-fd") == 0) {
-        rc = send_fd_test();
+    if (params.bench > 0) {
+        rc = run_as_bench(&params);
+        params.bench = 0;
     } else {
-        fprintf(stderr, "Unrecognized test name '%s'\n", test_name);
-        print_usage_and_exit(argv[0], EXIT_FAILURE, true);
+        tipc_test_func_t test = get_test_function(&params);
+        rc = test(&params);
     }
-
     return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }