net: Allow setting network interface to use for multicast
[fio.git] / engines / net.c
CommitLineData
ed92ac0c 1/*
da751ca9
JA
2 * net engine
3 *
4 * IO engine that reads/writes to/from sockets.
5 *
ed92ac0c
JA
6 */
7#include <stdio.h>
8#include <stdlib.h>
9#include <unistd.h>
842805f5 10#include <signal.h>
ed92ac0c
JA
11#include <errno.h>
12#include <assert.h>
13#include <netinet/in.h>
70a7878c 14#include <netinet/tcp.h>
ed92ac0c
JA
15#include <arpa/inet.h>
16#include <netdb.h>
5fdd124a 17#include <sys/poll.h>
7292056a 18#include <sys/types.h>
0fd666bf 19#include <sys/stat.h>
7292056a 20#include <sys/socket.h>
0fd666bf 21#include <sys/un.h>
ed92ac0c
JA
22
23#include "../fio.h"
ed92ac0c 24
b5af8293
JA
25struct netio_data {
26 int listenfd;
9cce02e8
JA
27 int use_splice;
28 int pipes[2];
b5af8293 29 struct sockaddr_in addr;
0fd666bf 30 struct sockaddr_un addr_un;
b5af8293 31};
ed92ac0c 32
de890a1e
SL
33struct netio_options {
34 struct thread_data *td;
35 unsigned int port;
36 unsigned int proto;
37 unsigned int listen;
6f73a7f8 38 unsigned int pingpong;
70a7878c 39 unsigned int nodelay;
b93b6a2e 40 char * interface;
de890a1e
SL
41};
42
664fb3bd
JA
43struct udp_close_msg {
44 uint32_t magic;
45 uint32_t cmd;
46};
47
48enum {
49 FIO_LINK_CLOSE = 0x89,
b96d2430
JA
50 FIO_LINK_OPEN_CLOSE_MAGIC = 0x6c696e6b,
51 FIO_LINK_OPEN = 0x98,
0fd666bf
JA
52
53 FIO_TYPE_TCP = 1,
54 FIO_TYPE_UDP = 2,
55 FIO_TYPE_UNIX = 3,
664fb3bd
JA
56};
57
de890a1e
SL
58static int str_hostname_cb(void *data, const char *input);
59static struct fio_option options[] = {
60 {
61 .name = "hostname",
e8b0e958 62 .lname = "net engine hostname",
de890a1e
SL
63 .type = FIO_OPT_STR_STORE,
64 .cb = str_hostname_cb,
65 .help = "Hostname for net IO engine",
e90a0adf
JA
66 .category = FIO_OPT_C_ENGINE,
67 .group = FIO_OPT_G_NETIO,
de890a1e
SL
68 },
69 {
70 .name = "port",
e8b0e958 71 .lname = "net engine port",
de890a1e
SL
72 .type = FIO_OPT_INT,
73 .off1 = offsetof(struct netio_options, port),
74 .minval = 1,
75 .maxval = 65535,
76 .help = "Port to use for TCP or UDP net connections",
e90a0adf
JA
77 .category = FIO_OPT_C_ENGINE,
78 .group = FIO_OPT_G_NETIO,
de890a1e
SL
79 },
80 {
81 .name = "protocol",
e8b0e958 82 .lname = "net engine protocol",
de890a1e
SL
83 .alias = "proto",
84 .type = FIO_OPT_STR,
85 .off1 = offsetof(struct netio_options, proto),
86 .help = "Network protocol to use",
87 .def = "tcp",
88 .posval = {
89 { .ival = "tcp",
90 .oval = FIO_TYPE_TCP,
91 .help = "Transmission Control Protocol",
92 },
93 { .ival = "udp",
94 .oval = FIO_TYPE_UDP,
f5cc3d0e 95 .help = "User Datagram Protocol",
de890a1e
SL
96 },
97 { .ival = "unix",
98 .oval = FIO_TYPE_UNIX,
99 .help = "UNIX domain socket",
100 },
101 },
e90a0adf
JA
102 .category = FIO_OPT_C_ENGINE,
103 .group = FIO_OPT_G_NETIO,
de890a1e 104 },
1eafa37a 105#ifdef CONFIG_TCP_NODELAY
70a7878c
SN
106 {
107 .name = "nodelay",
108 .type = FIO_OPT_BOOL,
109 .off1 = offsetof(struct netio_options, nodelay),
110 .help = "Use TCP_NODELAY on TCP connections",
e90a0adf
JA
111 .category = FIO_OPT_C_ENGINE,
112 .group = FIO_OPT_G_NETIO,
70a7878c 113 },
1eafa37a 114#endif
de890a1e
SL
115 {
116 .name = "listen",
e8b0e958 117 .lname = "net engine listen",
de890a1e
SL
118 .type = FIO_OPT_STR_SET,
119 .off1 = offsetof(struct netio_options, listen),
120 .help = "Listen for incoming TCP connections",
e90a0adf
JA
121 .category = FIO_OPT_C_ENGINE,
122 .group = FIO_OPT_G_NETIO,
de890a1e 123 },
6f73a7f8
JA
124 {
125 .name = "pingpong",
126 .type = FIO_OPT_STR_SET,
127 .off1 = offsetof(struct netio_options, pingpong),
128 .help = "Ping-pong IO requests",
e90a0adf
JA
129 .category = FIO_OPT_C_ENGINE,
130 .group = FIO_OPT_G_NETIO,
6f73a7f8 131 },
b93b6a2e
SB
132 {
133 .name = "interface",
134 .lname = "net engine interface",
135 .type = FIO_OPT_STR_STORE,
136 .off1 = offsetof(struct netio_options, interface),
137 .help = "Network interface to use",
138 .category = FIO_OPT_C_ENGINE,
139 .group = FIO_OPT_G_NETIO,
140 },
de890a1e
SL
141 {
142 .name = NULL,
143 },
144};
145
371d456c
JA
146/*
147 * Return -1 for error and 'nr events' for a positive number
148 * of events
149 */
150static int poll_wait(struct thread_data *td, int fd, short events)
151{
152 struct pollfd pfd;
153 int ret;
154
155 while (!td->terminate) {
156 pfd.fd = fd;
157 pfd.events = events;
158 ret = poll(&pfd, 1, -1);
159 if (ret < 0) {
160 if (errno == EINTR)
d5b388a5 161 break;
371d456c
JA
162
163 td_verror(td, errno, "poll");
164 return -1;
165 } else if (!ret)
166 continue;
167
168 break;
169 }
170
171 if (pfd.revents & events)
172 return 1;
371d456c
JA
173
174 return -1;
175}
176
b511c9aa
SB
177static int fio_netio_is_multicast(const char *mcaddr)
178{
179 in_addr_t addr = inet_network(mcaddr);
180 if (addr == -1)
181 return 0;
182
183 if (inet_network("224.0.0.0") <= addr &&
184 inet_network("239.255.255.255") >= addr)
185 return 1;
186
187 return 0;
188}
189
190
ed92ac0c
JA
191static int fio_netio_prep(struct thread_data *td, struct io_u *io_u)
192{
de890a1e 193 struct netio_options *o = td->eo;
ed92ac0c 194
7a6499da
JA
195 /*
196 * Make sure we don't see spurious reads to a receiver, and vice versa
197 */
de890a1e
SL
198 if (o->proto == FIO_TYPE_TCP)
199 return 0;
200
201 if ((o->listen && io_u->ddir == DDIR_WRITE) ||
202 (!o->listen && io_u->ddir == DDIR_READ)) {
e1161c32 203 td_verror(td, EINVAL, "bad direction");
7a6499da 204 return 1;
ed92ac0c 205 }
3f457bea 206
f85ac25a 207 return 0;
ed92ac0c
JA
208}
209
67bf9823 210#ifdef CONFIG_LINUX_SPLICE
cd963e18 211static int splice_io_u(int fdin, int fdout, unsigned int len)
ed92ac0c 212{
9cce02e8 213 int bytes = 0;
7a6499da 214
9cce02e8 215 while (len) {
cd963e18 216 int ret = splice(fdin, NULL, fdout, NULL, len, 0);
9cce02e8
JA
217
218 if (ret < 0) {
219 if (!bytes)
220 bytes = ret;
221
222 break;
223 } else if (!ret)
224 break;
225
226 bytes += ret;
f657a2fb 227 len -= ret;
9cce02e8
JA
228 }
229
230 return bytes;
231}
232
233/*
cd963e18 234 * Receive bytes from a socket and fill them into the internal pipe
9cce02e8 235 */
cd963e18 236static int splice_in(struct thread_data *td, struct io_u *io_u)
9cce02e8
JA
237{
238 struct netio_data *nd = td->io_ops->data;
9cce02e8 239
cd963e18 240 return splice_io_u(io_u->file->fd, nd->pipes[1], io_u->xfer_buflen);
9cce02e8
JA
241}
242
243/*
cd963e18 244 * Transmit 'len' bytes from the internal pipe
9cce02e8 245 */
cd963e18
JA
246static int splice_out(struct thread_data *td, struct io_u *io_u,
247 unsigned int len)
9cce02e8
JA
248{
249 struct netio_data *nd = td->io_ops->data;
cd963e18
JA
250
251 return splice_io_u(nd->pipes[0], io_u->file->fd, len);
252}
253
254static int vmsplice_io_u(struct io_u *io_u, int fd, unsigned int len)
255{
9cce02e8
JA
256 struct iovec iov = {
257 .iov_base = io_u->xfer_buf,
258 .iov_len = len,
259 };
260 int bytes = 0;
261
262 while (iov.iov_len) {
cd963e18 263 int ret = vmsplice(fd, &iov, 1, SPLICE_F_MOVE);
9cce02e8
JA
264
265 if (ret < 0) {
266 if (!bytes)
267 bytes = ret;
268 break;
269 } else if (!ret)
270 break;
271
272 iov.iov_len -= ret;
cd963e18 273 iov.iov_base += ret;
f657a2fb 274 bytes += ret;
9cce02e8
JA
275 }
276
277 return bytes;
cd963e18 278
9cce02e8
JA
279}
280
281/*
cd963e18 282 * vmsplice() pipe to io_u buffer
9cce02e8 283 */
cd963e18
JA
284static int vmsplice_io_u_out(struct thread_data *td, struct io_u *io_u,
285 unsigned int len)
9cce02e8
JA
286{
287 struct netio_data *nd = td->io_ops->data;
9cce02e8 288
cd963e18
JA
289 return vmsplice_io_u(io_u, nd->pipes[0], len);
290}
9cce02e8 291
cd963e18
JA
292/*
293 * vmsplice() io_u to pipe
294 */
295static int vmsplice_io_u_in(struct thread_data *td, struct io_u *io_u)
296{
297 struct netio_data *nd = td->io_ops->data;
ed92ac0c 298
cd963e18 299 return vmsplice_io_u(io_u, nd->pipes[1], io_u->xfer_buflen);
9cce02e8
JA
300}
301
cd963e18
JA
302/*
303 * splice receive - transfer socket data into a pipe using splice, then map
304 * that pipe data into the io_u using vmsplice.
305 */
9cce02e8
JA
306static int fio_netio_splice_in(struct thread_data *td, struct io_u *io_u)
307{
308 int ret;
309
310 ret = splice_in(td, io_u);
cd963e18
JA
311 if (ret > 0)
312 return vmsplice_io_u_out(td, io_u, ret);
9cce02e8 313
cd963e18 314 return ret;
9cce02e8
JA
315}
316
cd963e18
JA
317/*
318 * splice transmit - map data from the io_u into a pipe by using vmsplice,
319 * then transfer that pipe to a socket using splice.
320 */
9cce02e8
JA
321static int fio_netio_splice_out(struct thread_data *td, struct io_u *io_u)
322{
323 int ret;
324
325 ret = vmsplice_io_u_in(td, io_u);
cd963e18
JA
326 if (ret > 0)
327 return splice_out(td, io_u, ret);
9cce02e8 328
cd963e18 329 return ret;
9cce02e8 330}
5921e80c
JA
331#else
332static int fio_netio_splice_in(struct thread_data *td, struct io_u *io_u)
333{
af8771b9 334 errno = EOPNOTSUPP;
5921e80c
JA
335 return -1;
336}
337
338static int fio_netio_splice_out(struct thread_data *td, struct io_u *io_u)
339{
af8771b9 340 errno = EOPNOTSUPP;
5921e80c
JA
341 return -1;
342}
343#endif
9cce02e8
JA
344
345static int fio_netio_send(struct thread_data *td, struct io_u *io_u)
346{
414c2a3e 347 struct netio_data *nd = td->io_ops->data;
de890a1e 348 struct netio_options *o = td->eo;
6f73a7f8 349 int ret, flags = 0;
371d456c 350
664fb3bd 351 do {
de890a1e 352 if (o->proto == FIO_TYPE_UDP) {
62b38926
JA
353 struct sockaddr *to = (struct sockaddr *) &nd->addr;
354
664fb3bd 355 ret = sendto(io_u->file->fd, io_u->xfer_buf,
62b38926
JA
356 io_u->xfer_buflen, flags, to,
357 sizeof(*to));
664fb3bd
JA
358 } else {
359 /*
360 * if we are going to write more, set MSG_MORE
361 */
5921e80c 362#ifdef MSG_MORE
6f73a7f8
JA
363 if ((td->this_io_bytes[DDIR_WRITE] + io_u->xfer_buflen <
364 td->o.size) && !o->pingpong)
664fb3bd 365 flags |= MSG_MORE;
5921e80c 366#endif
664fb3bd
JA
367 ret = send(io_u->file->fd, io_u->xfer_buf,
368 io_u->xfer_buflen, flags);
369 }
370 if (ret > 0)
371 break;
9cce02e8 372
664fb3bd
JA
373 ret = poll_wait(td, io_u->file->fd, POLLOUT);
374 if (ret <= 0)
375 break;
664fb3bd
JA
376 } while (1);
377
378 return ret;
379}
380
381static int is_udp_close(struct io_u *io_u, int len)
382{
383 struct udp_close_msg *msg;
384
385 if (len != sizeof(struct udp_close_msg))
386 return 0;
387
388 msg = io_u->xfer_buf;
b96d2430 389 if (ntohl(msg->magic) != FIO_LINK_OPEN_CLOSE_MAGIC)
664fb3bd
JA
390 return 0;
391 if (ntohl(msg->cmd) != FIO_LINK_CLOSE)
392 return 0;
393
394 return 1;
9cce02e8
JA
395}
396
414c2a3e 397static int fio_netio_recv(struct thread_data *td, struct io_u *io_u)
9cce02e8 398{
414c2a3e 399 struct netio_data *nd = td->io_ops->data;
de890a1e 400 struct netio_options *o = td->eo;
6f73a7f8 401 int ret, flags = 0;
664fb3bd
JA
402
403 do {
de890a1e 404 if (o->proto == FIO_TYPE_UDP) {
b511c9aa
SB
405 socklen_t l;
406 socklen_t *len = &l;
407 struct sockaddr *from;
408
409 if (o->listen) {
410 from = (struct sockaddr *) &nd->addr;
411 *len = sizeof(nd->addr);
412 } else {
413 from = NULL;
414 len = NULL;
415 }
664fb3bd
JA
416
417 ret = recvfrom(io_u->file->fd, io_u->xfer_buf,
b511c9aa 418 io_u->xfer_buflen, flags, from, len);
664fb3bd
JA
419 if (is_udp_close(io_u, ret)) {
420 td->done = 1;
421 return 0;
422 }
423 } else {
424 ret = recv(io_u->file->fd, io_u->xfer_buf,
425 io_u->xfer_buflen, flags);
426 }
427 if (ret > 0)
428 break;
7d988f68
JA
429 else if (!ret && (flags & MSG_WAITALL))
430 break;
9cce02e8 431
664fb3bd
JA
432 ret = poll_wait(td, io_u->file->fd, POLLIN);
433 if (ret <= 0)
434 break;
664fb3bd
JA
435 flags |= MSG_WAITALL;
436 } while (1);
414c2a3e 437
664fb3bd 438 return ret;
9cce02e8
JA
439}
440
6f73a7f8
JA
441static int __fio_netio_queue(struct thread_data *td, struct io_u *io_u,
442 enum fio_ddir ddir)
9cce02e8
JA
443{
444 struct netio_data *nd = td->io_ops->data;
de890a1e 445 struct netio_options *o = td->eo;
9cce02e8
JA
446 int ret;
447
6f73a7f8 448 if (ddir == DDIR_WRITE) {
de890a1e
SL
449 if (!nd->use_splice || o->proto == FIO_TYPE_UDP ||
450 o->proto == FIO_TYPE_UNIX)
9cce02e8 451 ret = fio_netio_send(td, io_u);
414c2a3e
JA
452 else
453 ret = fio_netio_splice_out(td, io_u);
6f73a7f8 454 } else if (ddir == DDIR_READ) {
de890a1e
SL
455 if (!nd->use_splice || o->proto == FIO_TYPE_UDP ||
456 o->proto == FIO_TYPE_UNIX)
414c2a3e 457 ret = fio_netio_recv(td, io_u);
9cce02e8 458 else
414c2a3e 459 ret = fio_netio_splice_in(td, io_u);
d4f12dd0 460 } else
7a6499da 461 ret = 0; /* must be a SYNC */
ed92ac0c 462
cec6b55d 463 if (ret != (int) io_u->xfer_buflen) {
22819ec2 464 if (ret >= 0) {
cec6b55d
JA
465 io_u->resid = io_u->xfer_buflen - ret;
466 io_u->error = 0;
36167d82 467 return FIO_Q_COMPLETED;
414c2a3e
JA
468 } else {
469 int err = errno;
470
6f73a7f8 471 if (ddir == DDIR_WRITE && err == EMSGSIZE)
414c2a3e
JA
472 return FIO_Q_BUSY;
473
474 io_u->error = err;
475 }
ed92ac0c
JA
476 }
477
36167d82 478 if (io_u->error)
e1161c32 479 td_verror(td, io_u->error, "xfer");
ed92ac0c 480
36167d82 481 return FIO_Q_COMPLETED;
ed92ac0c
JA
482}
483
6f73a7f8
JA
484static int fio_netio_queue(struct thread_data *td, struct io_u *io_u)
485{
486 struct netio_options *o = td->eo;
487 int ret;
488
489 fio_ro_check(td, io_u);
490
491 ret = __fio_netio_queue(td, io_u, io_u->ddir);
492 if (!o->pingpong || ret != FIO_Q_COMPLETED)
493 return ret;
494
495 /*
496 * For ping-pong mode, receive or send reply as needed
497 */
498 if (td_read(td) && io_u->ddir == DDIR_READ)
499 ret = __fio_netio_queue(td, io_u, DDIR_WRITE);
500 else if (td_write(td) && io_u->ddir == DDIR_WRITE)
501 ret = __fio_netio_queue(td, io_u, DDIR_READ);
502
503 return ret;
504}
505
b5af8293 506static int fio_netio_connect(struct thread_data *td, struct fio_file *f)
ed92ac0c 507{
b5af8293 508 struct netio_data *nd = td->io_ops->data;
de890a1e 509 struct netio_options *o = td->eo;
6264c7a8 510 int type, domain;
414c2a3e 511
de890a1e 512 if (o->proto == FIO_TYPE_TCP) {
0fd666bf 513 domain = AF_INET;
414c2a3e 514 type = SOCK_STREAM;
de890a1e 515 } else if (o->proto == FIO_TYPE_UDP) {
0fd666bf 516 domain = AF_INET;
414c2a3e 517 type = SOCK_DGRAM;
de890a1e 518 } else if (o->proto == FIO_TYPE_UNIX) {
0fd666bf
JA
519 domain = AF_UNIX;
520 type = SOCK_STREAM;
521 } else {
de890a1e 522 log_err("fio: bad network type %d\n", o->proto);
0fd666bf
JA
523 f->fd = -1;
524 return 1;
525 }
ed92ac0c 526
0fd666bf 527 f->fd = socket(domain, type, 0);
b5af8293
JA
528 if (f->fd < 0) {
529 td_verror(td, errno, "socket");
530 return 1;
ed92ac0c
JA
531 }
532
1eafa37a 533#ifdef CONFIG_TCP_NODELAY
70a7878c 534 if (o->nodelay && o->proto == FIO_TYPE_TCP) {
6264c7a8
JA
535 int optval = 1;
536
26e594a5 537 if (setsockopt(f->fd, IPPROTO_TCP, TCP_NODELAY, (void *) &optval, sizeof(int)) < 0) {
70a7878c
SN
538 log_err("fio: cannot set TCP_NODELAY option on socket (%s), disable with 'nodelay=0'\n", strerror(errno));
539 return 1;
540 }
541 }
1eafa37a 542#endif
70a7878c 543
b93b6a2e
SB
544 if (o->proto == FIO_TYPE_UDP) {
545 if (o->interface && fio_netio_is_multicast(td->o.filename)) {
546 struct in_addr interface_addr;
547 if (inet_aton(o->interface, &interface_addr) == 0) {
548 log_err("fio: interface not valid interface IP\n");
549 close(f->fd);
550 return 1;
551 }
552 if (setsockopt(f->fd, IPPROTO_IP, IP_MULTICAST_IF, &interface_addr, sizeof(interface_addr)) < 0) {
553 td_verror(td, errno, "setsockopt IP_MULTICAST_IF");
554 close(f->fd);
555 return 1;
556 }
557 }
414c2a3e 558 return 0;
b93b6a2e 559 } else if (o->proto == FIO_TYPE_TCP) {
67bf9823 560 socklen_t len = sizeof(nd->addr);
414c2a3e 561
0fd666bf
JA
562 if (connect(f->fd, (struct sockaddr *) &nd->addr, len) < 0) {
563 td_verror(td, errno, "connect");
b94cba47 564 close(f->fd);
0fd666bf
JA
565 return 1;
566 }
567 } else {
568 struct sockaddr_un *addr = &nd->addr_un;
67bf9823 569 socklen_t len;
0fd666bf
JA
570
571 len = sizeof(addr->sun_family) + strlen(addr->sun_path) + 1;
572
573 if (connect(f->fd, (struct sockaddr *) addr, len) < 0) {
574 td_verror(td, errno, "connect");
b94cba47 575 close(f->fd);
0fd666bf
JA
576 return 1;
577 }
ed92ac0c
JA
578 }
579
580 return 0;
ed92ac0c
JA
581}
582
b5af8293 583static int fio_netio_accept(struct thread_data *td, struct fio_file *f)
5fdd124a 584{
b5af8293 585 struct netio_data *nd = td->io_ops->data;
de890a1e 586 struct netio_options *o = td->eo;
67bf9823 587 socklen_t socklen = sizeof(nd->addr);
6264c7a8 588 int state;
5fdd124a 589
de890a1e 590 if (o->proto == FIO_TYPE_UDP) {
414c2a3e
JA
591 f->fd = nd->listenfd;
592 return 0;
593 }
594
859088d3
JA
595 state = td->runstate;
596 td_set_runstate(td, TD_SETTING_UP);
597
6d86144d 598 log_info("fio: waiting for connection\n");
5fdd124a 599
371d456c 600 if (poll_wait(td, nd->listenfd, POLLIN) < 0)
859088d3 601 goto err;
0c09442b 602
371d456c
JA
603 f->fd = accept(nd->listenfd, (struct sockaddr *) &nd->addr, &socklen);
604 if (f->fd < 0) {
605 td_verror(td, errno, "accept");
859088d3 606 goto err;
b5af8293 607 }
5fdd124a 608
1eafa37a 609#ifdef CONFIG_TCP_NODELAY
70a7878c 610 if (o->nodelay && o->proto == FIO_TYPE_TCP) {
6264c7a8
JA
611 int optval = 1;
612
26e594a5 613 if (setsockopt(f->fd, IPPROTO_TCP, TCP_NODELAY, (void *) &optval, sizeof(int)) < 0) {
70a7878c
SN
614 log_err("fio: cannot set TCP_NODELAY option on socket (%s), disable with 'nodelay=0'\n", strerror(errno));
615 return 1;
616 }
617 }
1eafa37a 618#endif
70a7878c 619
0cae16ff 620 reset_all_stats(td);
859088d3 621 td_set_runstate(td, state);
b5af8293 622 return 0;
859088d3
JA
623err:
624 td_set_runstate(td, state);
625 return 1;
b5af8293
JA
626}
627
664fb3bd
JA
628static void fio_netio_udp_close(struct thread_data *td, struct fio_file *f)
629{
630 struct netio_data *nd = td->io_ops->data;
631 struct udp_close_msg msg;
62b38926 632 struct sockaddr *to = (struct sockaddr *) &nd->addr;
664fb3bd
JA
633 int ret;
634
b96d2430 635 msg.magic = htonl(FIO_LINK_OPEN_CLOSE_MAGIC);
664fb3bd
JA
636 msg.cmd = htonl(FIO_LINK_CLOSE);
637
1f81991e 638 ret = sendto(f->fd, (void *) &msg, sizeof(msg), MSG_WAITALL, to,
664fb3bd
JA
639 sizeof(nd->addr));
640 if (ret < 0)
641 td_verror(td, errno, "sendto udp link close");
642}
643
644static int fio_netio_close_file(struct thread_data *td, struct fio_file *f)
645{
de890a1e 646 struct netio_options *o = td->eo;
664fb3bd
JA
647
648 /*
649 * If this is an UDP connection, notify the receiver that we are
650 * closing down the link
651 */
de890a1e 652 if (o->proto == FIO_TYPE_UDP)
664fb3bd
JA
653 fio_netio_udp_close(td, f);
654
655 return generic_close_file(td, f);
656}
657
b96d2430
JA
658static int fio_netio_udp_recv_open(struct thread_data *td, struct fio_file *f)
659{
660 struct netio_data *nd = td->io_ops->data;
661 struct udp_close_msg msg;
662 struct sockaddr *to = (struct sockaddr *) &nd->addr;
67bf9823 663 socklen_t len = sizeof(nd->addr);
b96d2430
JA
664 int ret;
665
1f81991e 666 ret = recvfrom(f->fd, (void *) &msg, sizeof(msg), MSG_WAITALL, to, &len);
b96d2430 667 if (ret < 0) {
ee7062fd 668 td_verror(td, errno, "recvfrom udp link open");
b96d2430
JA
669 return ret;
670 }
671
672 if (ntohl(msg.magic) != FIO_LINK_OPEN_CLOSE_MAGIC ||
673 ntohl(msg.cmd) != FIO_LINK_OPEN) {
674 log_err("fio: bad udp open magic %x/%x\n", ntohl(msg.magic),
675 ntohl(msg.cmd));
676 return -1;
677 }
678
679 return 0;
680}
681
682static int fio_netio_udp_send_open(struct thread_data *td, struct fio_file *f)
683{
684 struct netio_data *nd = td->io_ops->data;
685 struct udp_close_msg msg;
686 struct sockaddr *to = (struct sockaddr *) &nd->addr;
687 int ret;
688
689 msg.magic = htonl(FIO_LINK_OPEN_CLOSE_MAGIC);
690 msg.cmd = htonl(FIO_LINK_OPEN);
691
1f81991e 692 ret = sendto(f->fd, (void *) &msg, sizeof(msg), MSG_WAITALL, to,
b96d2430
JA
693 sizeof(nd->addr));
694 if (ret < 0) {
695 td_verror(td, errno, "sendto udp link open");
696 return ret;
697 }
698
699 return 0;
700}
701
702static int fio_netio_open_file(struct thread_data *td, struct fio_file *f)
703{
704 int ret;
705 struct netio_options *o = td->eo;
706
707 if (o->listen)
708 ret = fio_netio_accept(td, f);
709 else
710 ret = fio_netio_connect(td, f);
711
712 if (ret) {
713 f->fd = -1;
714 return ret;
715 }
716
717 if (o->proto == FIO_TYPE_UDP) {
718 if (td_write(td))
719 ret = fio_netio_udp_send_open(td, f);
720 else {
721 int state;
722
723 state = td->runstate;
724 td_set_runstate(td, TD_SETTING_UP);
725 ret = fio_netio_udp_recv_open(td, f);
726 td_set_runstate(td, state);
727 }
728 }
729
730 if (ret)
731 fio_netio_close_file(td, f);
732
733 return ret;
734}
735
0fd666bf
JA
736static int fio_netio_setup_connect_inet(struct thread_data *td,
737 const char *host, unsigned short port)
b5af8293
JA
738{
739 struct netio_data *nd = td->io_ops->data;
740
166dce4b
JA
741 if (!host) {
742 log_err("fio: connect with no host to connect to.\n");
743 if (td_read(td))
744 log_err("fio: did you forget to set 'listen'?\n");
745
746 td_verror(td, EINVAL, "no hostname= set");
747 return 1;
748 }
749
b5af8293
JA
750 nd->addr.sin_family = AF_INET;
751 nd->addr.sin_port = htons(port);
752
753 if (inet_aton(host, &nd->addr.sin_addr) != 1) {
754 struct hostent *hent;
755
756 hent = gethostbyname(host);
757 if (!hent) {
758 td_verror(td, errno, "gethostbyname");
759 return 1;
5fdd124a 760 }
b5af8293
JA
761
762 memcpy(&nd->addr.sin_addr, hent->h_addr, 4);
5fdd124a
JA
763 }
764
765 return 0;
766}
767
0fd666bf
JA
768static int fio_netio_setup_connect_unix(struct thread_data *td,
769 const char *path)
770{
771 struct netio_data *nd = td->io_ops->data;
772 struct sockaddr_un *soun = &nd->addr_un;
773
774 soun->sun_family = AF_UNIX;
775 strcpy(soun->sun_path, path);
776 return 0;
777}
778
de890a1e 779static int fio_netio_setup_connect(struct thread_data *td)
0fd666bf 780{
de890a1e 781 struct netio_options *o = td->eo;
0fd666bf 782
de890a1e
SL
783 if (o->proto == FIO_TYPE_UDP || o->proto == FIO_TYPE_TCP)
784 return fio_netio_setup_connect_inet(td, td->o.filename,o->port);
0fd666bf 785 else
de890a1e 786 return fio_netio_setup_connect_unix(td, td->o.filename);
0fd666bf
JA
787}
788
789static int fio_netio_setup_listen_unix(struct thread_data *td, const char *path)
790{
791 struct netio_data *nd = td->io_ops->data;
792 struct sockaddr_un *addr = &nd->addr_un;
793 mode_t mode;
794 int len, fd;
795
796 fd = socket(AF_UNIX, SOCK_STREAM, 0);
797 if (fd < 0) {
798 log_err("fio: socket: %s\n", strerror(errno));
799 return -1;
800 }
801
802 mode = umask(000);
803
804 memset(addr, 0, sizeof(*addr));
805 addr->sun_family = AF_UNIX;
806 strcpy(addr->sun_path, path);
807 unlink(path);
808
809 len = sizeof(addr->sun_family) + strlen(path) + 1;
810
811 if (bind(fd, (struct sockaddr *) addr, len) < 0) {
812 log_err("fio: bind: %s\n", strerror(errno));
b94cba47 813 close(fd);
0fd666bf
JA
814 return -1;
815 }
816
817 umask(mode);
818 nd->listenfd = fd;
819 return 0;
820}
821
822static int fio_netio_setup_listen_inet(struct thread_data *td, short port)
ed92ac0c 823{
b5af8293 824 struct netio_data *nd = td->io_ops->data;
de890a1e 825 struct netio_options *o = td->eo;
b511c9aa
SB
826 struct ip_mreq mr;
827 struct sockaddr_in sin;
414c2a3e 828 int fd, opt, type;
ed92ac0c 829
b511c9aa 830 memset(&sin, 0, sizeof(sin));
de890a1e 831 if (o->proto == FIO_TYPE_TCP)
414c2a3e
JA
832 type = SOCK_STREAM;
833 else
834 type = SOCK_DGRAM;
835
0fd666bf 836 fd = socket(AF_INET, type, 0);
ed92ac0c 837 if (fd < 0) {
e1161c32 838 td_verror(td, errno, "socket");
ed92ac0c
JA
839 return 1;
840 }
841
842 opt = 1;
26e594a5 843 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &opt, sizeof(opt)) < 0) {
e1161c32 844 td_verror(td, errno, "setsockopt");
4a93dec2 845 close(fd);
ed92ac0c
JA
846 return 1;
847 }
6bedbfaf 848#ifdef SO_REUSEPORT
26e594a5 849 if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (void *) &opt, sizeof(opt)) < 0) {
e1161c32 850 td_verror(td, errno, "setsockopt");
4a93dec2 851 close(fd);
6bedbfaf
JA
852 return 1;
853 }
854#endif
ed92ac0c 855
b511c9aa
SB
856 if (td->o.filename){
857 if(o->proto != FIO_TYPE_UDP ||
858 !fio_netio_is_multicast(td->o.filename)) {
859 log_err("fio: hostname not valid for non-multicast inbound network IO\n");
860 close(fd);
861 return 1;
862 }
863
864 inet_aton(td->o.filename, &sin.sin_addr);
865
866 mr.imr_multiaddr = sin.sin_addr;
b93b6a2e
SB
867 if (o->interface) {
868 if (inet_aton(o->interface, &mr.imr_interface) == 0) {
869 log_err("fio: interface not valid interface IP\n");
870 close(fd);
871 return 1;
872 }
873 } else {
874 mr.imr_interface.s_addr = htonl(INADDR_ANY);
875 }
b511c9aa
SB
876 if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0) {
877 td_verror(td, errno, "setsockopt IP_ADD_MEMBERSHIP");
878 close(fd);
879 return 1;
880 }
881 }
882
b5af8293 883 nd->addr.sin_family = AF_INET;
b511c9aa 884 nd->addr.sin_addr.s_addr = sin.sin_addr.s_addr ? sin.sin_addr.s_addr : htonl(INADDR_ANY);
b5af8293 885 nd->addr.sin_port = htons(port);
ed92ac0c 886
b5af8293 887 if (bind(fd, (struct sockaddr *) &nd->addr, sizeof(nd->addr)) < 0) {
e1161c32 888 td_verror(td, errno, "bind");
ed92ac0c
JA
889 return 1;
890 }
0fd666bf
JA
891
892 nd->listenfd = fd;
893 return 0;
894}
895
de890a1e 896static int fio_netio_setup_listen(struct thread_data *td)
0fd666bf
JA
897{
898 struct netio_data *nd = td->io_ops->data;
de890a1e 899 struct netio_options *o = td->eo;
0fd666bf
JA
900 int ret;
901
de890a1e
SL
902 if (o->proto == FIO_TYPE_UDP || o->proto == FIO_TYPE_TCP)
903 ret = fio_netio_setup_listen_inet(td, o->port);
0fd666bf 904 else
de890a1e 905 ret = fio_netio_setup_listen_unix(td, td->o.filename);
0fd666bf
JA
906
907 if (ret)
908 return ret;
de890a1e 909 if (o->proto == FIO_TYPE_UDP)
0fd666bf
JA
910 return 0;
911
912 if (listen(nd->listenfd, 10) < 0) {
e1161c32 913 td_verror(td, errno, "listen");
0fd666bf 914 nd->listenfd = -1;
ed92ac0c
JA
915 return 1;
916 }
917
b5af8293 918 return 0;
ed92ac0c
JA
919}
920
9bec88e1 921static int fio_netio_init(struct thread_data *td)
ed92ac0c 922{
de890a1e 923 struct netio_options *o = td->eo;
af52b345 924 int ret;
ed92ac0c 925
3f457bea
BC
926#ifdef WIN32
927 WSADATA wsd;
928 WSAStartup(MAKEWORD(2,2), &wsd);
929#endif
930
16d55aae
JA
931 if (td_random(td)) {
932 log_err("fio: network IO can't be random\n");
933 return 1;
934 }
ed92ac0c 935
de890a1e
SL
936 if (o->proto == FIO_TYPE_UNIX && o->port) {
937 log_err("fio: network IO port not valid with unix socket\n");
938 return 1;
939 } else if (o->proto != FIO_TYPE_UNIX && !o->port) {
940 log_err("fio: network IO requires port for tcp or udp\n");
941 return 1;
942 }
ed92ac0c 943
de890a1e
SL
944 if (o->proto != FIO_TYPE_TCP) {
945 if (o->listen) {
9b986065
JA
946 log_err("fio: listen only valid for TCP proto IO\n");
947 return 1;
de890a1e
SL
948 }
949 if (td_rw(td)) {
9b986065 950 log_err("fio: datagram network connections must be"
de890a1e 951 " read OR write\n");
9b986065
JA
952 return 1;
953 }
954 if (o->proto == FIO_TYPE_UNIX && !td->o.filename) {
955 log_err("fio: UNIX sockets need host/filename\n");
956 return 1;
de890a1e
SL
957 }
958 o->listen = td_read(td);
959 }
443662ef 960
de890a1e
SL
961 if (o->listen)
962 ret = fio_netio_setup_listen(td);
0fd666bf 963 else
de890a1e 964 ret = fio_netio_setup_connect(td);
ed92ac0c 965
7bb48f84 966 return ret;
ed92ac0c
JA
967}
968
b5af8293 969static void fio_netio_cleanup(struct thread_data *td)
9bec88e1 970{
b5af8293
JA
971 struct netio_data *nd = td->io_ops->data;
972
973 if (nd) {
64b24cd8
JA
974 if (nd->listenfd != -1)
975 close(nd->listenfd);
976 if (nd->pipes[0] != -1)
977 close(nd->pipes[0]);
978 if (nd->pipes[1] != -1)
979 close(nd->pipes[1]);
980
b5af8293 981 free(nd);
b5af8293
JA
982 }
983}
984
985static int fio_netio_setup(struct thread_data *td)
986{
7bb48f84 987 struct netio_data *nd;
7bb48f84 988
de890a1e
SL
989 if (!td->files_index) {
990 add_file(td, td->o.filename ?: "net");
991 td->o.nr_files = td->o.nr_files ?: 1;
992 }
993
7bb48f84
JA
994 if (!td->io_ops->data) {
995 nd = malloc(sizeof(*nd));;
996
997 memset(nd, 0, sizeof(*nd));
998 nd->listenfd = -1;
64b24cd8 999 nd->pipes[0] = nd->pipes[1] = -1;
7bb48f84 1000 td->io_ops->data = nd;
7bb48f84 1001 }
b5af8293 1002
9bec88e1
JA
1003 return 0;
1004}
1005
36d80bc7
JA
1006static void fio_netio_terminate(struct thread_data *td)
1007{
1008 kill(td->pid, SIGUSR2);
1009}
1010
67bf9823 1011#ifdef CONFIG_LINUX_SPLICE
9cce02e8
JA
1012static int fio_netio_setup_splice(struct thread_data *td)
1013{
1014 struct netio_data *nd;
1015
1016 fio_netio_setup(td);
1017
1018 nd = td->io_ops->data;
1019 if (nd) {
1020 if (pipe(nd->pipes) < 0)
1021 return 1;
1022
1023 nd->use_splice = 1;
1024 return 0;
1025 }
1026
1027 return 1;
1028}
1029
5921e80c 1030static struct ioengine_ops ioengine_splice = {
de890a1e
SL
1031 .name = "netsplice",
1032 .version = FIO_IOOPS_VERSION,
1033 .prep = fio_netio_prep,
1034 .queue = fio_netio_queue,
1035 .setup = fio_netio_setup_splice,
1036 .init = fio_netio_init,
1037 .cleanup = fio_netio_cleanup,
1038 .open_file = fio_netio_open_file,
36d80bc7
JA
1039 .close_file = fio_netio_close_file,
1040 .terminate = fio_netio_terminate,
de890a1e
SL
1041 .options = options,
1042 .option_struct_size = sizeof(struct netio_options),
1043 .flags = FIO_SYNCIO | FIO_DISKLESSIO | FIO_UNIDIR |
36d80bc7 1044 FIO_PIPEIO,
ed92ac0c 1045};
5921e80c 1046#endif
ed92ac0c 1047
5921e80c 1048static struct ioengine_ops ioengine_rw = {
de890a1e
SL
1049 .name = "net",
1050 .version = FIO_IOOPS_VERSION,
1051 .prep = fio_netio_prep,
1052 .queue = fio_netio_queue,
1053 .setup = fio_netio_setup,
1054 .init = fio_netio_init,
1055 .cleanup = fio_netio_cleanup,
1056 .open_file = fio_netio_open_file,
1057 .close_file = fio_netio_close_file,
36d80bc7 1058 .terminate = fio_netio_terminate,
de890a1e
SL
1059 .options = options,
1060 .option_struct_size = sizeof(struct netio_options),
1061 .flags = FIO_SYNCIO | FIO_DISKLESSIO | FIO_UNIDIR |
ad705bcb 1062 FIO_PIPEIO | FIO_BIT_BASED,
9cce02e8
JA
1063};
1064
de890a1e
SL
1065static int str_hostname_cb(void *data, const char *input)
1066{
1067 struct netio_options *o = data;
1068
1069 if (o->td->o.filename)
1070 free(o->td->o.filename);
1071 o->td->o.filename = strdup(input);
1072 return 0;
1073}
1074
ed92ac0c
JA
1075static void fio_init fio_netio_register(void)
1076{
9cce02e8 1077 register_ioengine(&ioengine_rw);
67bf9823 1078#ifdef CONFIG_LINUX_SPLICE
9cce02e8 1079 register_ioengine(&ioengine_splice);
5921e80c 1080#endif
ed92ac0c
JA
1081}
1082
1083static void fio_exit fio_netio_unregister(void)
1084{
9cce02e8 1085 unregister_ioengine(&ioengine_rw);
67bf9823 1086#ifdef CONFIG_LINUX_SPLICE
9cce02e8 1087 unregister_ioengine(&ioengine_splice);
5921e80c 1088#endif
ed92ac0c 1089}