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