rxtimestamp.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. #include <errno.h>
  2. #include <error.h>
  3. #include <getopt.h>
  4. #include <stdbool.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <sys/time.h>
  9. #include <sys/socket.h>
  10. #include <sys/select.h>
  11. #include <sys/ioctl.h>
  12. #include <arpa/inet.h>
  13. #include <net/if.h>
  14. #include <asm/types.h>
  15. #include <linux/net_tstamp.h>
  16. #include <linux/errqueue.h>
  17. #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
  18. struct options {
  19. int so_timestamp;
  20. int so_timestampns;
  21. int so_timestamping;
  22. };
  23. struct tstamps {
  24. bool tstamp;
  25. bool tstampns;
  26. bool swtstamp;
  27. bool hwtstamp;
  28. };
  29. struct socket_type {
  30. char *friendly_name;
  31. int type;
  32. int protocol;
  33. bool enabled;
  34. };
  35. struct test_case {
  36. struct options sockopt;
  37. struct tstamps expected;
  38. bool enabled;
  39. };
  40. struct sof_flag {
  41. int mask;
  42. char *name;
  43. };
  44. static struct sof_flag sof_flags[] = {
  45. #define SOF_FLAG(f) { f, #f }
  46. SOF_FLAG(SOF_TIMESTAMPING_SOFTWARE),
  47. SOF_FLAG(SOF_TIMESTAMPING_RX_SOFTWARE),
  48. SOF_FLAG(SOF_TIMESTAMPING_RX_HARDWARE),
  49. };
  50. static struct socket_type socket_types[] = {
  51. { "ip", SOCK_RAW, IPPROTO_EGP },
  52. { "udp", SOCK_DGRAM, IPPROTO_UDP },
  53. { "tcp", SOCK_STREAM, IPPROTO_TCP },
  54. };
  55. static struct test_case test_cases[] = {
  56. { {}, {} },
  57. {
  58. { so_timestamp: 1 },
  59. { tstamp: true }
  60. },
  61. {
  62. { so_timestampns: 1 },
  63. { tstampns: true }
  64. },
  65. {
  66. { so_timestamp: 1, so_timestampns: 1 },
  67. { tstampns: true }
  68. },
  69. {
  70. { so_timestamping: SOF_TIMESTAMPING_RX_SOFTWARE },
  71. {}
  72. },
  73. {
  74. /* Loopback device does not support hw timestamps. */
  75. { so_timestamping: SOF_TIMESTAMPING_RX_HARDWARE },
  76. {}
  77. },
  78. {
  79. { so_timestamping: SOF_TIMESTAMPING_SOFTWARE },
  80. {}
  81. },
  82. {
  83. { so_timestamping: SOF_TIMESTAMPING_RX_SOFTWARE
  84. | SOF_TIMESTAMPING_RX_HARDWARE },
  85. {}
  86. },
  87. {
  88. { so_timestamping: SOF_TIMESTAMPING_SOFTWARE
  89. | SOF_TIMESTAMPING_RX_SOFTWARE },
  90. { swtstamp: true }
  91. },
  92. {
  93. { so_timestamp: 1, so_timestamping: SOF_TIMESTAMPING_SOFTWARE
  94. | SOF_TIMESTAMPING_RX_SOFTWARE },
  95. { tstamp: true, swtstamp: true }
  96. },
  97. };
  98. static struct option long_options[] = {
  99. { "list_tests", no_argument, 0, 'l' },
  100. { "test_num", required_argument, 0, 'n' },
  101. { "op_size", required_argument, 0, 's' },
  102. { "tcp", no_argument, 0, 't' },
  103. { "udp", no_argument, 0, 'u' },
  104. { "ip", no_argument, 0, 'i' },
  105. };
  106. static int next_port = 19999;
  107. static int op_size = 10 * 1024;
  108. void print_test_case(struct test_case *t)
  109. {
  110. int f = 0;
  111. printf("sockopts {");
  112. if (t->sockopt.so_timestamp)
  113. printf(" SO_TIMESTAMP ");
  114. if (t->sockopt.so_timestampns)
  115. printf(" SO_TIMESTAMPNS ");
  116. if (t->sockopt.so_timestamping) {
  117. printf(" SO_TIMESTAMPING: {");
  118. for (f = 0; f < ARRAY_SIZE(sof_flags); f++)
  119. if (t->sockopt.so_timestamping & sof_flags[f].mask)
  120. printf(" %s |", sof_flags[f].name);
  121. printf("}");
  122. }
  123. printf("} expected cmsgs: {");
  124. if (t->expected.tstamp)
  125. printf(" SCM_TIMESTAMP ");
  126. if (t->expected.tstampns)
  127. printf(" SCM_TIMESTAMPNS ");
  128. if (t->expected.swtstamp || t->expected.hwtstamp) {
  129. printf(" SCM_TIMESTAMPING {");
  130. if (t->expected.swtstamp)
  131. printf("0");
  132. if (t->expected.swtstamp && t->expected.hwtstamp)
  133. printf(",");
  134. if (t->expected.hwtstamp)
  135. printf("2");
  136. printf("}");
  137. }
  138. printf("}\n");
  139. }
  140. void do_send(int src)
  141. {
  142. int r;
  143. char *buf = malloc(op_size);
  144. memset(buf, 'z', op_size);
  145. r = write(src, buf, op_size);
  146. if (r < 0)
  147. error(1, errno, "Failed to sendmsg");
  148. free(buf);
  149. }
  150. bool do_recv(int rcv, int read_size, struct tstamps expected)
  151. {
  152. const int CMSG_SIZE = 1024;
  153. struct scm_timestamping *ts;
  154. struct tstamps actual = {};
  155. char cmsg_buf[CMSG_SIZE];
  156. struct iovec recv_iov;
  157. struct cmsghdr *cmsg;
  158. bool failed = false;
  159. struct msghdr hdr;
  160. int flags = 0;
  161. int r;
  162. memset(&hdr, 0, sizeof(hdr));
  163. hdr.msg_iov = &recv_iov;
  164. hdr.msg_iovlen = 1;
  165. recv_iov.iov_base = malloc(read_size);
  166. recv_iov.iov_len = read_size;
  167. hdr.msg_control = cmsg_buf;
  168. hdr.msg_controllen = sizeof(cmsg_buf);
  169. r = recvmsg(rcv, &hdr, flags);
  170. if (r < 0)
  171. error(1, errno, "Failed to recvmsg");
  172. if (r != read_size)
  173. error(1, 0, "Only received %d bytes of payload.", r);
  174. if (hdr.msg_flags & (MSG_TRUNC | MSG_CTRUNC))
  175. error(1, 0, "Message was truncated.");
  176. for (cmsg = CMSG_FIRSTHDR(&hdr); cmsg != NULL;
  177. cmsg = CMSG_NXTHDR(&hdr, cmsg)) {
  178. if (cmsg->cmsg_level != SOL_SOCKET)
  179. error(1, 0, "Unexpected cmsg_level %d",
  180. cmsg->cmsg_level);
  181. switch (cmsg->cmsg_type) {
  182. case SCM_TIMESTAMP:
  183. actual.tstamp = true;
  184. break;
  185. case SCM_TIMESTAMPNS:
  186. actual.tstampns = true;
  187. break;
  188. case SCM_TIMESTAMPING:
  189. ts = (struct scm_timestamping *)CMSG_DATA(cmsg);
  190. actual.swtstamp = !!ts->ts[0].tv_sec;
  191. if (ts->ts[1].tv_sec != 0)
  192. error(0, 0, "ts[1] should not be set.");
  193. actual.hwtstamp = !!ts->ts[2].tv_sec;
  194. break;
  195. default:
  196. error(1, 0, "Unexpected cmsg_type %d", cmsg->cmsg_type);
  197. }
  198. }
  199. #define VALIDATE(field) \
  200. do { \
  201. if (expected.field != actual.field) { \
  202. if (expected.field) \
  203. error(0, 0, "Expected " #field " to be set."); \
  204. else \
  205. error(0, 0, \
  206. "Expected " #field " to not be set."); \
  207. failed = true; \
  208. } \
  209. } while (0)
  210. VALIDATE(tstamp);
  211. VALIDATE(tstampns);
  212. VALIDATE(swtstamp);
  213. VALIDATE(hwtstamp);
  214. #undef VALIDATE
  215. free(recv_iov.iov_base);
  216. return failed;
  217. }
  218. void config_so_flags(int rcv, struct options o)
  219. {
  220. int on = 1;
  221. if (setsockopt(rcv, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
  222. error(1, errno, "Failed to enable SO_REUSEADDR");
  223. if (o.so_timestamp &&
  224. setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMP,
  225. &o.so_timestamp, sizeof(o.so_timestamp)) < 0)
  226. error(1, errno, "Failed to enable SO_TIMESTAMP");
  227. if (o.so_timestampns &&
  228. setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMPNS,
  229. &o.so_timestampns, sizeof(o.so_timestampns)) < 0)
  230. error(1, errno, "Failed to enable SO_TIMESTAMPNS");
  231. if (o.so_timestamping &&
  232. setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMPING,
  233. &o.so_timestamping, sizeof(o.so_timestamping)) < 0)
  234. error(1, errno, "Failed to set SO_TIMESTAMPING");
  235. }
  236. bool run_test_case(struct socket_type s, struct test_case t)
  237. {
  238. int port = (s.type == SOCK_RAW) ? 0 : next_port++;
  239. int read_size = op_size;
  240. struct sockaddr_in addr;
  241. bool failed = false;
  242. int src, dst, rcv;
  243. src = socket(AF_INET, s.type, s.protocol);
  244. if (src < 0)
  245. error(1, errno, "Failed to open src socket");
  246. dst = socket(AF_INET, s.type, s.protocol);
  247. if (dst < 0)
  248. error(1, errno, "Failed to open dst socket");
  249. memset(&addr, 0, sizeof(addr));
  250. addr.sin_family = AF_INET;
  251. addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  252. addr.sin_port = htons(port);
  253. if (bind(dst, (struct sockaddr *)&addr, sizeof(addr)) < 0)
  254. error(1, errno, "Failed to bind to port %d", port);
  255. if (s.type == SOCK_STREAM && (listen(dst, 1) < 0))
  256. error(1, errno, "Failed to listen");
  257. if (connect(src, (struct sockaddr *)&addr, sizeof(addr)) < 0)
  258. error(1, errno, "Failed to connect");
  259. if (s.type == SOCK_STREAM) {
  260. rcv = accept(dst, NULL, NULL);
  261. if (rcv < 0)
  262. error(1, errno, "Failed to accept");
  263. close(dst);
  264. } else {
  265. rcv = dst;
  266. }
  267. config_so_flags(rcv, t.sockopt);
  268. usleep(20000); /* setsockopt for SO_TIMESTAMPING is asynchronous */
  269. do_send(src);
  270. if (s.type == SOCK_RAW)
  271. read_size += 20; /* for IP header */
  272. failed = do_recv(rcv, read_size, t.expected);
  273. close(rcv);
  274. close(src);
  275. return failed;
  276. }
  277. int main(int argc, char **argv)
  278. {
  279. bool all_protocols = true;
  280. bool all_tests = true;
  281. int arg_index = 0;
  282. int failures = 0;
  283. int s, t;
  284. char opt;
  285. while ((opt = getopt_long(argc, argv, "", long_options,
  286. &arg_index)) != -1) {
  287. switch (opt) {
  288. case 'l':
  289. for (t = 0; t < ARRAY_SIZE(test_cases); t++) {
  290. printf("%d\t", t);
  291. print_test_case(&test_cases[t]);
  292. }
  293. return 0;
  294. case 'n':
  295. t = atoi(optarg);
  296. if (t >= ARRAY_SIZE(test_cases))
  297. error(1, 0, "Invalid test case: %d", t);
  298. all_tests = false;
  299. test_cases[t].enabled = true;
  300. break;
  301. case 's':
  302. op_size = atoi(optarg);
  303. break;
  304. case 't':
  305. all_protocols = false;
  306. socket_types[2].enabled = true;
  307. break;
  308. case 'u':
  309. all_protocols = false;
  310. socket_types[1].enabled = true;
  311. break;
  312. case 'i':
  313. all_protocols = false;
  314. socket_types[0].enabled = true;
  315. break;
  316. default:
  317. error(1, 0, "Failed to parse parameters.");
  318. }
  319. }
  320. for (s = 0; s < ARRAY_SIZE(socket_types); s++) {
  321. if (!all_protocols && !socket_types[s].enabled)
  322. continue;
  323. printf("Testing %s...\n", socket_types[s].friendly_name);
  324. for (t = 0; t < ARRAY_SIZE(test_cases); t++) {
  325. if (!all_tests && !test_cases[t].enabled)
  326. continue;
  327. printf("Starting testcase %d...\n", t);
  328. if (run_test_case(socket_types[s], test_cases[t])) {
  329. failures++;
  330. printf("FAILURE in test case ");
  331. print_test_case(&test_cases[t]);
  332. }
  333. }
  334. }
  335. if (!failures)
  336. printf("PASSED.\n");
  337. return failures;
  338. }