cmsg_sender.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. #include <errno.h>
  3. #include <error.h>
  4. #include <netdb.h>
  5. #include <stdbool.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <time.h>
  10. #include <unistd.h>
  11. #include <linux/errqueue.h>
  12. #include <linux/icmp.h>
  13. #include <linux/icmpv6.h>
  14. #include <linux/net_tstamp.h>
  15. #include <linux/types.h>
  16. #include <linux/udp.h>
  17. #include <sys/socket.h>
  18. #include "../kselftest.h"
  19. enum {
  20. ERN_SUCCESS = 0,
  21. /* Well defined errors, callers may depend on these */
  22. ERN_SEND = 1,
  23. /* Informational, can reorder */
  24. ERN_HELP,
  25. ERN_SEND_SHORT,
  26. ERN_SOCK_CREATE,
  27. ERN_RESOLVE,
  28. ERN_CMSG_WR,
  29. ERN_SOCKOPT,
  30. ERN_GETTIME,
  31. ERN_RECVERR,
  32. ERN_CMSG_RD,
  33. ERN_CMSG_RCV,
  34. };
  35. struct option_cmsg_u32 {
  36. bool ena;
  37. unsigned int val;
  38. };
  39. struct options {
  40. bool silent_send;
  41. const char *host;
  42. const char *service;
  43. unsigned int size;
  44. unsigned int num_pkt;
  45. struct {
  46. unsigned int mark;
  47. unsigned int dontfrag;
  48. unsigned int tclass;
  49. unsigned int hlimit;
  50. unsigned int priority;
  51. } sockopt;
  52. struct {
  53. unsigned int family;
  54. unsigned int type;
  55. unsigned int proto;
  56. } sock;
  57. struct option_cmsg_u32 mark;
  58. struct {
  59. bool ena;
  60. unsigned int delay;
  61. } txtime;
  62. struct {
  63. bool ena;
  64. } ts;
  65. struct {
  66. struct option_cmsg_u32 dontfrag;
  67. struct option_cmsg_u32 tclass;
  68. struct option_cmsg_u32 hlimit;
  69. struct option_cmsg_u32 exthdr;
  70. } v6;
  71. } opt = {
  72. .size = 13,
  73. .num_pkt = 1,
  74. .sock = {
  75. .family = AF_UNSPEC,
  76. .type = SOCK_DGRAM,
  77. .proto = IPPROTO_UDP,
  78. },
  79. };
  80. static struct timespec time_start_real;
  81. static struct timespec time_start_mono;
  82. static void __attribute__((noreturn)) cs_usage(const char *bin)
  83. {
  84. printf("Usage: %s [opts] <dst host> <dst port / service>\n", bin);
  85. printf("Options:\n"
  86. "\t\t-s Silent send() failures\n"
  87. "\t\t-S send() size\n"
  88. "\t\t-4/-6 Force IPv4 / IPv6 only\n"
  89. "\t\t-p prot Socket protocol\n"
  90. "\t\t (u = UDP (default); i = ICMP; r = RAW)\n"
  91. "\n"
  92. "\t\t-m val Set SO_MARK with given value\n"
  93. "\t\t-M val Set SO_MARK via setsockopt\n"
  94. "\t\t-d val Set SO_TXTIME with given delay (usec)\n"
  95. "\t\t-t Enable time stamp reporting\n"
  96. "\t\t-f val Set don't fragment via cmsg\n"
  97. "\t\t-F val Set don't fragment via setsockopt\n"
  98. "\t\t-c val Set TCLASS via cmsg\n"
  99. "\t\t-C val Set TCLASS via setsockopt\n"
  100. "\t\t-l val Set HOPLIMIT via cmsg\n"
  101. "\t\t-L val Set HOPLIMIT via setsockopt\n"
  102. "\t\t-H type Add an IPv6 header option\n"
  103. "\t\t (h = HOP; d = DST; r = RTDST)"
  104. "");
  105. exit(ERN_HELP);
  106. }
  107. static void cs_parse_args(int argc, char *argv[])
  108. {
  109. int o;
  110. while ((o = getopt(argc, argv, "46sS:p:P:m:M:n:d:tf:F:c:C:l:L:H:")) != -1) {
  111. switch (o) {
  112. case 's':
  113. opt.silent_send = true;
  114. break;
  115. case 'S':
  116. opt.size = atoi(optarg);
  117. break;
  118. case '4':
  119. opt.sock.family = AF_INET;
  120. break;
  121. case '6':
  122. opt.sock.family = AF_INET6;
  123. break;
  124. case 'p':
  125. if (*optarg == 'u' || *optarg == 'U') {
  126. opt.sock.proto = IPPROTO_UDP;
  127. } else if (*optarg == 'i' || *optarg == 'I') {
  128. opt.sock.proto = IPPROTO_ICMP;
  129. } else if (*optarg == 'r') {
  130. opt.sock.type = SOCK_RAW;
  131. } else {
  132. printf("Error: unknown protocol: %s\n", optarg);
  133. cs_usage(argv[0]);
  134. }
  135. break;
  136. case 'P':
  137. opt.sockopt.priority = atoi(optarg);
  138. break;
  139. case 'm':
  140. opt.mark.ena = true;
  141. opt.mark.val = atoi(optarg);
  142. break;
  143. case 'M':
  144. opt.sockopt.mark = atoi(optarg);
  145. break;
  146. case 'n':
  147. opt.num_pkt = atoi(optarg);
  148. break;
  149. case 'd':
  150. opt.txtime.ena = true;
  151. opt.txtime.delay = atoi(optarg);
  152. break;
  153. case 't':
  154. opt.ts.ena = true;
  155. break;
  156. case 'f':
  157. opt.v6.dontfrag.ena = true;
  158. opt.v6.dontfrag.val = atoi(optarg);
  159. break;
  160. case 'F':
  161. opt.sockopt.dontfrag = atoi(optarg);
  162. break;
  163. case 'c':
  164. opt.v6.tclass.ena = true;
  165. opt.v6.tclass.val = atoi(optarg);
  166. break;
  167. case 'C':
  168. opt.sockopt.tclass = atoi(optarg);
  169. break;
  170. case 'l':
  171. opt.v6.hlimit.ena = true;
  172. opt.v6.hlimit.val = atoi(optarg);
  173. break;
  174. case 'L':
  175. opt.sockopt.hlimit = atoi(optarg);
  176. break;
  177. case 'H':
  178. opt.v6.exthdr.ena = true;
  179. switch (optarg[0]) {
  180. case 'h':
  181. opt.v6.exthdr.val = IPV6_HOPOPTS;
  182. break;
  183. case 'd':
  184. opt.v6.exthdr.val = IPV6_DSTOPTS;
  185. break;
  186. case 'r':
  187. opt.v6.exthdr.val = IPV6_RTHDRDSTOPTS;
  188. break;
  189. default:
  190. printf("Error: hdr type: %s\n", optarg);
  191. break;
  192. }
  193. break;
  194. }
  195. }
  196. if (optind != argc - 2)
  197. cs_usage(argv[0]);
  198. opt.host = argv[optind];
  199. opt.service = argv[optind + 1];
  200. }
  201. static void memrnd(void *s, size_t n)
  202. {
  203. int *dword = s;
  204. char *byte;
  205. for (; n >= 4; n -= 4)
  206. *dword++ = rand();
  207. byte = (void *)dword;
  208. while (n--)
  209. *byte++ = rand();
  210. }
  211. static void
  212. ca_write_cmsg_u32(char *cbuf, size_t cbuf_sz, size_t *cmsg_len,
  213. int level, int optname, struct option_cmsg_u32 *uopt)
  214. {
  215. struct cmsghdr *cmsg;
  216. if (!uopt->ena)
  217. return;
  218. cmsg = (struct cmsghdr *)(cbuf + *cmsg_len);
  219. *cmsg_len += CMSG_SPACE(sizeof(__u32));
  220. if (cbuf_sz < *cmsg_len)
  221. error(ERN_CMSG_WR, EFAULT, "cmsg buffer too small");
  222. cmsg->cmsg_level = level;
  223. cmsg->cmsg_type = optname;
  224. cmsg->cmsg_len = CMSG_LEN(sizeof(__u32));
  225. *(__u32 *)CMSG_DATA(cmsg) = uopt->val;
  226. }
  227. static void
  228. cs_write_cmsg(int fd, struct msghdr *msg, char *cbuf, size_t cbuf_sz)
  229. {
  230. struct cmsghdr *cmsg;
  231. size_t cmsg_len;
  232. msg->msg_control = cbuf;
  233. cmsg_len = 0;
  234. ca_write_cmsg_u32(cbuf, cbuf_sz, &cmsg_len,
  235. SOL_SOCKET, SO_MARK, &opt.mark);
  236. ca_write_cmsg_u32(cbuf, cbuf_sz, &cmsg_len,
  237. SOL_IPV6, IPV6_DONTFRAG, &opt.v6.dontfrag);
  238. ca_write_cmsg_u32(cbuf, cbuf_sz, &cmsg_len,
  239. SOL_IPV6, IPV6_TCLASS, &opt.v6.tclass);
  240. ca_write_cmsg_u32(cbuf, cbuf_sz, &cmsg_len,
  241. SOL_IPV6, IPV6_HOPLIMIT, &opt.v6.hlimit);
  242. if (opt.txtime.ena) {
  243. __u64 txtime;
  244. txtime = time_start_mono.tv_sec * (1000ULL * 1000 * 1000) +
  245. time_start_mono.tv_nsec +
  246. opt.txtime.delay * 1000;
  247. cmsg = (struct cmsghdr *)(cbuf + cmsg_len);
  248. cmsg_len += CMSG_SPACE(sizeof(txtime));
  249. if (cbuf_sz < cmsg_len)
  250. error(ERN_CMSG_WR, EFAULT, "cmsg buffer too small");
  251. cmsg->cmsg_level = SOL_SOCKET;
  252. cmsg->cmsg_type = SCM_TXTIME;
  253. cmsg->cmsg_len = CMSG_LEN(sizeof(txtime));
  254. memcpy(CMSG_DATA(cmsg), &txtime, sizeof(txtime));
  255. }
  256. if (opt.ts.ena) {
  257. cmsg = (struct cmsghdr *)(cbuf + cmsg_len);
  258. cmsg_len += CMSG_SPACE(sizeof(__u32));
  259. if (cbuf_sz < cmsg_len)
  260. error(ERN_CMSG_WR, EFAULT, "cmsg buffer too small");
  261. cmsg->cmsg_level = SOL_SOCKET;
  262. cmsg->cmsg_type = SO_TIMESTAMPING;
  263. cmsg->cmsg_len = CMSG_LEN(sizeof(__u32));
  264. *(__u32 *)CMSG_DATA(cmsg) = SOF_TIMESTAMPING_TX_SCHED |
  265. SOF_TIMESTAMPING_TX_SOFTWARE;
  266. }
  267. if (opt.v6.exthdr.ena) {
  268. cmsg = (struct cmsghdr *)(cbuf + cmsg_len);
  269. cmsg_len += CMSG_SPACE(8);
  270. if (cbuf_sz < cmsg_len)
  271. error(ERN_CMSG_WR, EFAULT, "cmsg buffer too small");
  272. cmsg->cmsg_level = SOL_IPV6;
  273. cmsg->cmsg_type = opt.v6.exthdr.val;
  274. cmsg->cmsg_len = CMSG_LEN(8);
  275. *(__u64 *)CMSG_DATA(cmsg) = 0;
  276. }
  277. if (cmsg_len)
  278. msg->msg_controllen = cmsg_len;
  279. else
  280. msg->msg_control = NULL;
  281. }
  282. static const char *cs_ts_info2str(unsigned int info)
  283. {
  284. static const char *names[] = {
  285. [SCM_TSTAMP_SND] = "SND",
  286. [SCM_TSTAMP_SCHED] = "SCHED",
  287. [SCM_TSTAMP_ACK] = "ACK",
  288. };
  289. if (info < ARRAY_SIZE(names))
  290. return names[info];
  291. return "unknown";
  292. }
  293. static unsigned long
  294. cs_read_cmsg(int fd, struct msghdr *msg, char *cbuf, size_t cbuf_sz)
  295. {
  296. struct sock_extended_err *see;
  297. struct scm_timestamping *ts;
  298. unsigned long ts_seen = 0;
  299. struct cmsghdr *cmsg;
  300. int i, err;
  301. if (!opt.ts.ena)
  302. return 0;
  303. msg->msg_control = cbuf;
  304. msg->msg_controllen = cbuf_sz;
  305. while (true) {
  306. ts = NULL;
  307. see = NULL;
  308. memset(cbuf, 0, cbuf_sz);
  309. err = recvmsg(fd, msg, MSG_ERRQUEUE);
  310. if (err < 0) {
  311. if (errno == EAGAIN)
  312. break;
  313. error(ERN_RECVERR, errno, "recvmsg ERRQ");
  314. }
  315. for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
  316. cmsg = CMSG_NXTHDR(msg, cmsg)) {
  317. if (cmsg->cmsg_level == SOL_SOCKET &&
  318. cmsg->cmsg_type == SO_TIMESTAMPING_OLD) {
  319. if (cmsg->cmsg_len < sizeof(*ts))
  320. error(ERN_CMSG_RD, EINVAL, "TS cmsg");
  321. ts = (void *)CMSG_DATA(cmsg);
  322. }
  323. if ((cmsg->cmsg_level == SOL_IP &&
  324. cmsg->cmsg_type == IP_RECVERR) ||
  325. (cmsg->cmsg_level == SOL_IPV6 &&
  326. cmsg->cmsg_type == IPV6_RECVERR)) {
  327. if (cmsg->cmsg_len < sizeof(*see))
  328. error(ERN_CMSG_RD, EINVAL, "sock_err cmsg");
  329. see = (void *)CMSG_DATA(cmsg);
  330. }
  331. }
  332. if (!ts)
  333. error(ERN_CMSG_RCV, ENOENT, "TS cmsg not found");
  334. if (!see)
  335. error(ERN_CMSG_RCV, ENOENT, "sock_err cmsg not found");
  336. for (i = 0; i < 3; i++) {
  337. unsigned long long rel_time;
  338. if (!ts->ts[i].tv_sec && !ts->ts[i].tv_nsec)
  339. continue;
  340. rel_time = (ts->ts[i].tv_sec - time_start_real.tv_sec) *
  341. (1000ULL * 1000) +
  342. (ts->ts[i].tv_nsec - time_start_real.tv_nsec) /
  343. 1000;
  344. printf(" %5s ts%d %lluus\n",
  345. cs_ts_info2str(see->ee_info),
  346. i, rel_time);
  347. ts_seen |= 1 << see->ee_info;
  348. }
  349. }
  350. return ts_seen;
  351. }
  352. static void ca_set_sockopts(int fd)
  353. {
  354. if (opt.sockopt.mark &&
  355. setsockopt(fd, SOL_SOCKET, SO_MARK,
  356. &opt.sockopt.mark, sizeof(opt.sockopt.mark)))
  357. error(ERN_SOCKOPT, errno, "setsockopt SO_MARK");
  358. if (opt.sockopt.dontfrag &&
  359. setsockopt(fd, SOL_IPV6, IPV6_DONTFRAG,
  360. &opt.sockopt.dontfrag, sizeof(opt.sockopt.dontfrag)))
  361. error(ERN_SOCKOPT, errno, "setsockopt IPV6_DONTFRAG");
  362. if (opt.sockopt.tclass &&
  363. setsockopt(fd, SOL_IPV6, IPV6_TCLASS,
  364. &opt.sockopt.tclass, sizeof(opt.sockopt.tclass)))
  365. error(ERN_SOCKOPT, errno, "setsockopt IPV6_TCLASS");
  366. if (opt.sockopt.hlimit &&
  367. setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS,
  368. &opt.sockopt.hlimit, sizeof(opt.sockopt.hlimit)))
  369. error(ERN_SOCKOPT, errno, "setsockopt IPV6_HOPLIMIT");
  370. if (opt.sockopt.priority &&
  371. setsockopt(fd, SOL_SOCKET, SO_PRIORITY,
  372. &opt.sockopt.priority, sizeof(opt.sockopt.priority)))
  373. error(ERN_SOCKOPT, errno, "setsockopt SO_PRIORITY");
  374. if (opt.txtime.ena) {
  375. struct sock_txtime so_txtime = {
  376. .clockid = CLOCK_MONOTONIC,
  377. };
  378. if (setsockopt(fd, SOL_SOCKET, SO_TXTIME,
  379. &so_txtime, sizeof(so_txtime)))
  380. error(ERN_SOCKOPT, errno, "setsockopt TXTIME");
  381. }
  382. if (opt.ts.ena) {
  383. __u32 val = SOF_TIMESTAMPING_SOFTWARE |
  384. SOF_TIMESTAMPING_OPT_TSONLY;
  385. if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING,
  386. &val, sizeof(val)))
  387. error(ERN_SOCKOPT, errno, "setsockopt TIMESTAMPING");
  388. }
  389. }
  390. int main(int argc, char *argv[])
  391. {
  392. struct addrinfo hints, *ai;
  393. struct iovec iov[1];
  394. unsigned char *buf;
  395. struct msghdr msg;
  396. char cbuf[1024];
  397. int err;
  398. int fd;
  399. int i;
  400. cs_parse_args(argc, argv);
  401. buf = malloc(opt.size);
  402. memrnd(buf, opt.size);
  403. memset(&hints, 0, sizeof(hints));
  404. hints.ai_family = opt.sock.family;
  405. ai = NULL;
  406. err = getaddrinfo(opt.host, opt.service, &hints, &ai);
  407. if (err) {
  408. fprintf(stderr, "Can't resolve address [%s]:%s\n",
  409. opt.host, opt.service);
  410. return ERN_SOCK_CREATE;
  411. }
  412. if (ai->ai_family == AF_INET6 && opt.sock.proto == IPPROTO_ICMP)
  413. opt.sock.proto = IPPROTO_ICMPV6;
  414. fd = socket(ai->ai_family, opt.sock.type, opt.sock.proto);
  415. if (fd < 0) {
  416. fprintf(stderr, "Can't open socket: %s\n", strerror(errno));
  417. freeaddrinfo(ai);
  418. return ERN_RESOLVE;
  419. }
  420. if (opt.sock.proto == IPPROTO_ICMP) {
  421. buf[0] = ICMP_ECHO;
  422. buf[1] = 0;
  423. } else if (opt.sock.proto == IPPROTO_ICMPV6) {
  424. buf[0] = ICMPV6_ECHO_REQUEST;
  425. buf[1] = 0;
  426. } else if (opt.sock.type == SOCK_RAW) {
  427. struct udphdr hdr = { 1, 2, htons(opt.size), 0 };
  428. struct sockaddr_in6 *sin6 = (void *)ai->ai_addr;
  429. memcpy(buf, &hdr, sizeof(hdr));
  430. sin6->sin6_port = htons(opt.sock.proto);
  431. }
  432. ca_set_sockopts(fd);
  433. if (clock_gettime(CLOCK_REALTIME, &time_start_real))
  434. error(ERN_GETTIME, errno, "gettime REALTIME");
  435. if (clock_gettime(CLOCK_MONOTONIC, &time_start_mono))
  436. error(ERN_GETTIME, errno, "gettime MONOTONIC");
  437. iov[0].iov_base = buf;
  438. iov[0].iov_len = opt.size;
  439. memset(&msg, 0, sizeof(msg));
  440. msg.msg_name = ai->ai_addr;
  441. msg.msg_namelen = ai->ai_addrlen;
  442. msg.msg_iov = iov;
  443. msg.msg_iovlen = 1;
  444. cs_write_cmsg(fd, &msg, cbuf, sizeof(cbuf));
  445. for (i = 0; i < opt.num_pkt; i++) {
  446. err = sendmsg(fd, &msg, 0);
  447. if (err < 0) {
  448. if (!opt.silent_send)
  449. fprintf(stderr, "send failed: %s\n", strerror(errno));
  450. err = ERN_SEND;
  451. goto err_out;
  452. } else if (err != (int)opt.size) {
  453. fprintf(stderr, "short send\n");
  454. err = ERN_SEND_SHORT;
  455. goto err_out;
  456. }
  457. }
  458. err = ERN_SUCCESS;
  459. if (opt.ts.ena) {
  460. unsigned long seen;
  461. int i;
  462. /* Make sure all timestamps have time to loop back */
  463. for (i = 0; i < 40; i++) {
  464. seen = cs_read_cmsg(fd, &msg, cbuf, sizeof(cbuf));
  465. if (seen & (1 << SCM_TSTAMP_SND))
  466. break;
  467. usleep(opt.txtime.delay / 20);
  468. }
  469. }
  470. err_out:
  471. close(fd);
  472. freeaddrinfo(ai);
  473. return err;
  474. }