cmsg_sender.c 14 KB

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