Categorize engine and profile options
[fio.git] / engines / net.c
... / ...
CommitLineData
1/*
2 * net engine
3 *
4 * IO engine that reads/writes to/from sockets.
5 *
6 */
7#include <stdio.h>
8#include <stdlib.h>
9#include <unistd.h>
10#include <signal.h>
11#include <errno.h>
12#include <assert.h>
13#include <netinet/in.h>
14#include <netinet/tcp.h>
15#include <arpa/inet.h>
16#include <netdb.h>
17#include <sys/poll.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <sys/socket.h>
21#include <sys/un.h>
22
23#include "../fio.h"
24
25struct netio_data {
26 int listenfd;
27 int use_splice;
28 int pipes[2];
29 struct sockaddr_in addr;
30 struct sockaddr_un addr_un;
31};
32
33struct netio_options {
34 struct thread_data *td;
35 unsigned int port;
36 unsigned int proto;
37 unsigned int listen;
38 unsigned int pingpong;
39 unsigned int nodelay;
40};
41
42struct udp_close_msg {
43 uint32_t magic;
44 uint32_t cmd;
45};
46
47enum {
48 FIO_LINK_CLOSE = 0x89,
49 FIO_LINK_OPEN_CLOSE_MAGIC = 0x6c696e6b,
50 FIO_LINK_OPEN = 0x98,
51
52 FIO_TYPE_TCP = 1,
53 FIO_TYPE_UDP = 2,
54 FIO_TYPE_UNIX = 3,
55};
56
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",
64 .category = FIO_OPT_C_ENGINE,
65 .group = FIO_OPT_G_NETIO,
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",
74 .category = FIO_OPT_C_ENGINE,
75 .group = FIO_OPT_G_NETIO,
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,
91 .help = "User Datagram Protocol",
92 },
93 { .ival = "unix",
94 .oval = FIO_TYPE_UNIX,
95 .help = "UNIX domain socket",
96 },
97 },
98 .category = FIO_OPT_C_ENGINE,
99 .group = FIO_OPT_G_NETIO,
100 },
101#ifdef CONFIG_TCP_NODELAY
102 {
103 .name = "nodelay",
104 .type = FIO_OPT_BOOL,
105 .off1 = offsetof(struct netio_options, nodelay),
106 .help = "Use TCP_NODELAY on TCP connections",
107 .category = FIO_OPT_C_ENGINE,
108 .group = FIO_OPT_G_NETIO,
109 },
110#endif
111 {
112 .name = "listen",
113 .type = FIO_OPT_STR_SET,
114 .off1 = offsetof(struct netio_options, listen),
115 .help = "Listen for incoming TCP connections",
116 .category = FIO_OPT_C_ENGINE,
117 .group = FIO_OPT_G_NETIO,
118 },
119 {
120 .name = "pingpong",
121 .type = FIO_OPT_STR_SET,
122 .off1 = offsetof(struct netio_options, pingpong),
123 .help = "Ping-pong IO requests",
124 .category = FIO_OPT_C_ENGINE,
125 .group = FIO_OPT_G_NETIO,
126 },
127 {
128 .name = NULL,
129 },
130};
131
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)
147 break;
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;
159
160 return -1;
161}
162
163static int fio_netio_prep(struct thread_data *td, struct io_u *io_u)
164{
165 struct netio_options *o = td->eo;
166
167 /*
168 * Make sure we don't see spurious reads to a receiver, and vice versa
169 */
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)) {
175 td_verror(td, EINVAL, "bad direction");
176 return 1;
177 }
178
179 return 0;
180}
181
182#ifdef CONFIG_LINUX_SPLICE
183static int splice_io_u(int fdin, int fdout, unsigned int len)
184{
185 int bytes = 0;
186
187 while (len) {
188 int ret = splice(fdin, NULL, fdout, NULL, len, 0);
189
190 if (ret < 0) {
191 if (!bytes)
192 bytes = ret;
193
194 break;
195 } else if (!ret)
196 break;
197
198 bytes += ret;
199 len -= ret;
200 }
201
202 return bytes;
203}
204
205/*
206 * Receive bytes from a socket and fill them into the internal pipe
207 */
208static int splice_in(struct thread_data *td, struct io_u *io_u)
209{
210 struct netio_data *nd = td->io_ops->data;
211
212 return splice_io_u(io_u->file->fd, nd->pipes[1], io_u->xfer_buflen);
213}
214
215/*
216 * Transmit 'len' bytes from the internal pipe
217 */
218static int splice_out(struct thread_data *td, struct io_u *io_u,
219 unsigned int len)
220{
221 struct netio_data *nd = td->io_ops->data;
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{
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) {
235 int ret = vmsplice(fd, &iov, 1, SPLICE_F_MOVE);
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;
245 iov.iov_base += ret;
246 bytes += ret;
247 }
248
249 return bytes;
250
251}
252
253/*
254 * vmsplice() pipe to io_u buffer
255 */
256static int vmsplice_io_u_out(struct thread_data *td, struct io_u *io_u,
257 unsigned int len)
258{
259 struct netio_data *nd = td->io_ops->data;
260
261 return vmsplice_io_u(io_u, nd->pipes[0], len);
262}
263
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;
270
271 return vmsplice_io_u(io_u, nd->pipes[1], io_u->xfer_buflen);
272}
273
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 */
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);
283 if (ret > 0)
284 return vmsplice_io_u_out(td, io_u, ret);
285
286 return ret;
287}
288
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 */
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);
298 if (ret > 0)
299 return splice_out(td, io_u, ret);
300
301 return ret;
302}
303#else
304static int fio_netio_splice_in(struct thread_data *td, struct io_u *io_u)
305{
306 errno = EOPNOTSUPP;
307 return -1;
308}
309
310static int fio_netio_splice_out(struct thread_data *td, struct io_u *io_u)
311{
312 errno = EOPNOTSUPP;
313 return -1;
314}
315#endif
316
317static int fio_netio_send(struct thread_data *td, struct io_u *io_u)
318{
319 struct netio_data *nd = td->io_ops->data;
320 struct netio_options *o = td->eo;
321 int ret, flags = 0;
322
323 do {
324 if (o->proto == FIO_TYPE_UDP) {
325 struct sockaddr *to = (struct sockaddr *) &nd->addr;
326
327 ret = sendto(io_u->file->fd, io_u->xfer_buf,
328 io_u->xfer_buflen, flags, to,
329 sizeof(*to));
330 } else {
331 /*
332 * if we are going to write more, set MSG_MORE
333 */
334#ifdef MSG_MORE
335 if ((td->this_io_bytes[DDIR_WRITE] + io_u->xfer_buflen <
336 td->o.size) && !o->pingpong)
337 flags |= MSG_MORE;
338#endif
339 ret = send(io_u->file->fd, io_u->xfer_buf,
340 io_u->xfer_buflen, flags);
341 }
342 if (ret > 0)
343 break;
344
345 ret = poll_wait(td, io_u->file->fd, POLLOUT);
346 if (ret <= 0)
347 break;
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;
361 if (ntohl(msg->magic) != FIO_LINK_OPEN_CLOSE_MAGIC)
362 return 0;
363 if (ntohl(msg->cmd) != FIO_LINK_CLOSE)
364 return 0;
365
366 return 1;
367}
368
369static int fio_netio_recv(struct thread_data *td, struct io_u *io_u)
370{
371 struct netio_data *nd = td->io_ops->data;
372 struct netio_options *o = td->eo;
373 int ret, flags = 0;
374
375 do {
376 if (o->proto == FIO_TYPE_UDP) {
377 socklen_t len = sizeof(nd->addr);
378 struct sockaddr *from = (struct sockaddr *) &nd->addr;
379
380 ret = recvfrom(io_u->file->fd, io_u->xfer_buf,
381 io_u->xfer_buflen, flags, from, &len);
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;
392 else if (!ret && (flags & MSG_WAITALL))
393 break;
394
395 ret = poll_wait(td, io_u->file->fd, POLLIN);
396 if (ret <= 0)
397 break;
398 flags |= MSG_WAITALL;
399 } while (1);
400
401 return ret;
402}
403
404static int __fio_netio_queue(struct thread_data *td, struct io_u *io_u,
405 enum fio_ddir ddir)
406{
407 struct netio_data *nd = td->io_ops->data;
408 struct netio_options *o = td->eo;
409 int ret;
410
411 if (ddir == DDIR_WRITE) {
412 if (!nd->use_splice || o->proto == FIO_TYPE_UDP ||
413 o->proto == FIO_TYPE_UNIX)
414 ret = fio_netio_send(td, io_u);
415 else
416 ret = fio_netio_splice_out(td, io_u);
417 } else if (ddir == DDIR_READ) {
418 if (!nd->use_splice || o->proto == FIO_TYPE_UDP ||
419 o->proto == FIO_TYPE_UNIX)
420 ret = fio_netio_recv(td, io_u);
421 else
422 ret = fio_netio_splice_in(td, io_u);
423 } else
424 ret = 0; /* must be a SYNC */
425
426 if (ret != (int) io_u->xfer_buflen) {
427 if (ret >= 0) {
428 io_u->resid = io_u->xfer_buflen - ret;
429 io_u->error = 0;
430 return FIO_Q_COMPLETED;
431 } else {
432 int err = errno;
433
434 if (ddir == DDIR_WRITE && err == EMSGSIZE)
435 return FIO_Q_BUSY;
436
437 io_u->error = err;
438 }
439 }
440
441 if (io_u->error)
442 td_verror(td, io_u->error, "xfer");
443
444 return FIO_Q_COMPLETED;
445}
446
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
469static int fio_netio_connect(struct thread_data *td, struct fio_file *f)
470{
471 struct netio_data *nd = td->io_ops->data;
472 struct netio_options *o = td->eo;
473 int type, domain;
474
475 if (o->proto == FIO_TYPE_TCP) {
476 domain = AF_INET;
477 type = SOCK_STREAM;
478 } else if (o->proto == FIO_TYPE_UDP) {
479 domain = AF_INET;
480 type = SOCK_DGRAM;
481 } else if (o->proto == FIO_TYPE_UNIX) {
482 domain = AF_UNIX;
483 type = SOCK_STREAM;
484 } else {
485 log_err("fio: bad network type %d\n", o->proto);
486 f->fd = -1;
487 return 1;
488 }
489
490 f->fd = socket(domain, type, 0);
491 if (f->fd < 0) {
492 td_verror(td, errno, "socket");
493 return 1;
494 }
495
496#ifdef CONFIG_TCP_NODELAY
497 if (o->nodelay && o->proto == FIO_TYPE_TCP) {
498 int optval = 1;
499
500 if (setsockopt(f->fd, IPPROTO_TCP, TCP_NODELAY, (void *) &optval, sizeof(int)) < 0) {
501 log_err("fio: cannot set TCP_NODELAY option on socket (%s), disable with 'nodelay=0'\n", strerror(errno));
502 return 1;
503 }
504 }
505#endif
506
507 if (o->proto == FIO_TYPE_UDP)
508 return 0;
509 else if (o->proto == FIO_TYPE_TCP) {
510 socklen_t len = sizeof(nd->addr);
511
512 if (connect(f->fd, (struct sockaddr *) &nd->addr, len) < 0) {
513 td_verror(td, errno, "connect");
514 close(f->fd);
515 return 1;
516 }
517 } else {
518 struct sockaddr_un *addr = &nd->addr_un;
519 socklen_t len;
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");
525 close(f->fd);
526 return 1;
527 }
528 }
529
530 return 0;
531}
532
533static int fio_netio_accept(struct thread_data *td, struct fio_file *f)
534{
535 struct netio_data *nd = td->io_ops->data;
536 struct netio_options *o = td->eo;
537 socklen_t socklen = sizeof(nd->addr);
538 int state;
539
540 if (o->proto == FIO_TYPE_UDP) {
541 f->fd = nd->listenfd;
542 return 0;
543 }
544
545 state = td->runstate;
546 td_set_runstate(td, TD_SETTING_UP);
547
548 log_info("fio: waiting for connection\n");
549
550 if (poll_wait(td, nd->listenfd, POLLIN) < 0)
551 goto err;
552
553 f->fd = accept(nd->listenfd, (struct sockaddr *) &nd->addr, &socklen);
554 if (f->fd < 0) {
555 td_verror(td, errno, "accept");
556 goto err;
557 }
558
559#ifdef CONFIG_TCP_NODELAY
560 if (o->nodelay && o->proto == FIO_TYPE_TCP) {
561 int optval = 1;
562
563 if (setsockopt(f->fd, IPPROTO_TCP, TCP_NODELAY, (void *) &optval, sizeof(int)) < 0) {
564 log_err("fio: cannot set TCP_NODELAY option on socket (%s), disable with 'nodelay=0'\n", strerror(errno));
565 return 1;
566 }
567 }
568#endif
569
570 reset_all_stats(td);
571 td_set_runstate(td, state);
572 return 0;
573err:
574 td_set_runstate(td, state);
575 return 1;
576}
577
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;
582 struct sockaddr *to = (struct sockaddr *) &nd->addr;
583 int ret;
584
585 msg.magic = htonl(FIO_LINK_OPEN_CLOSE_MAGIC);
586 msg.cmd = htonl(FIO_LINK_CLOSE);
587
588 ret = sendto(f->fd, (void *) &msg, sizeof(msg), MSG_WAITALL, to,
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{
596 struct netio_options *o = td->eo;
597
598 /*
599 * If this is an UDP connection, notify the receiver that we are
600 * closing down the link
601 */
602 if (o->proto == FIO_TYPE_UDP)
603 fio_netio_udp_close(td, f);
604
605 return generic_close_file(td, f);
606}
607
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;
613 socklen_t len = sizeof(nd->addr);
614 int ret;
615
616 ret = recvfrom(f->fd, (void *) &msg, sizeof(msg), MSG_WAITALL, to, &len);
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
642 ret = sendto(f->fd, (void *) &msg, sizeof(msg), MSG_WAITALL, to,
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
686static int fio_netio_setup_connect_inet(struct thread_data *td,
687 const char *host, unsigned short port)
688{
689 struct netio_data *nd = td->io_ops->data;
690
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
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;
710 }
711
712 memcpy(&nd->addr.sin_addr, hent->h_addr, 4);
713 }
714
715 return 0;
716}
717
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
729static int fio_netio_setup_connect(struct thread_data *td)
730{
731 struct netio_options *o = td->eo;
732
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);
735 else
736 return fio_netio_setup_connect_unix(td, td->o.filename);
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));
763 close(fd);
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)
773{
774 struct netio_data *nd = td->io_ops->data;
775 struct netio_options *o = td->eo;
776 int fd, opt, type;
777
778 if (o->proto == FIO_TYPE_TCP)
779 type = SOCK_STREAM;
780 else
781 type = SOCK_DGRAM;
782
783 fd = socket(AF_INET, type, 0);
784 if (fd < 0) {
785 td_verror(td, errno, "socket");
786 return 1;
787 }
788
789 opt = 1;
790 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &opt, sizeof(opt)) < 0) {
791 td_verror(td, errno, "setsockopt");
792 return 1;
793 }
794#ifdef SO_REUSEPORT
795 if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (void *) &opt, sizeof(opt)) < 0) {
796 td_verror(td, errno, "setsockopt");
797 return 1;
798 }
799#endif
800
801 nd->addr.sin_family = AF_INET;
802 nd->addr.sin_addr.s_addr = htonl(INADDR_ANY);
803 nd->addr.sin_port = htons(port);
804
805 if (bind(fd, (struct sockaddr *) &nd->addr, sizeof(nd->addr)) < 0) {
806 td_verror(td, errno, "bind");
807 return 1;
808 }
809
810 nd->listenfd = fd;
811 return 0;
812}
813
814static int fio_netio_setup_listen(struct thread_data *td)
815{
816 struct netio_data *nd = td->io_ops->data;
817 struct netio_options *o = td->eo;
818 int ret;
819
820 if (o->proto == FIO_TYPE_UDP || o->proto == FIO_TYPE_TCP)
821 ret = fio_netio_setup_listen_inet(td, o->port);
822 else
823 ret = fio_netio_setup_listen_unix(td, td->o.filename);
824
825 if (ret)
826 return ret;
827 if (o->proto == FIO_TYPE_UDP)
828 return 0;
829
830 if (listen(nd->listenfd, 10) < 0) {
831 td_verror(td, errno, "listen");
832 nd->listenfd = -1;
833 return 1;
834 }
835
836 return 0;
837}
838
839static int fio_netio_init(struct thread_data *td)
840{
841 struct netio_options *o = td->eo;
842 int ret;
843
844#ifdef WIN32
845 WSADATA wsd;
846 WSAStartup(MAKEWORD(2,2), &wsd);
847#endif
848
849 if (td_random(td)) {
850 log_err("fio: network IO can't be random\n");
851 return 1;
852 }
853
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 }
861
862 if (o->proto != FIO_TYPE_TCP) {
863 if (o->listen) {
864 log_err("fio: listen only valid for TCP proto IO\n");
865 return 1;
866 }
867 if (td_rw(td)) {
868 log_err("fio: datagram network connections must be"
869 " read OR write\n");
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;
875 }
876 o->listen = td_read(td);
877 }
878
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;
882 }
883
884 if (o->listen)
885 ret = fio_netio_setup_listen(td);
886 else
887 ret = fio_netio_setup_connect(td);
888
889 return ret;
890}
891
892static void fio_netio_cleanup(struct thread_data *td)
893{
894 struct netio_data *nd = td->io_ops->data;
895
896 if (nd) {
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
904 free(nd);
905 }
906}
907
908static int fio_netio_setup(struct thread_data *td)
909{
910 struct netio_data *nd;
911
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
917 if (!td->io_ops->data) {
918 nd = malloc(sizeof(*nd));;
919
920 memset(nd, 0, sizeof(*nd));
921 nd->listenfd = -1;
922 nd->pipes[0] = nd->pipes[1] = -1;
923 td->io_ops->data = nd;
924 }
925
926 return 0;
927}
928
929static void fio_netio_terminate(struct thread_data *td)
930{
931 kill(td->pid, SIGUSR2);
932}
933
934#ifdef CONFIG_LINUX_SPLICE
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
953static struct ioengine_ops ioengine_splice = {
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,
962 .close_file = fio_netio_close_file,
963 .terminate = fio_netio_terminate,
964 .options = options,
965 .option_struct_size = sizeof(struct netio_options),
966 .flags = FIO_SYNCIO | FIO_DISKLESSIO | FIO_UNIDIR |
967 FIO_PIPEIO,
968};
969#endif
970
971static struct ioengine_ops ioengine_rw = {
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,
981 .terminate = fio_netio_terminate,
982 .options = options,
983 .option_struct_size = sizeof(struct netio_options),
984 .flags = FIO_SYNCIO | FIO_DISKLESSIO | FIO_UNIDIR |
985 FIO_PIPEIO | FIO_BIT_BASED,
986};
987
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
998static void fio_init fio_netio_register(void)
999{
1000 register_ioengine(&ioengine_rw);
1001#ifdef CONFIG_LINUX_SPLICE
1002 register_ioengine(&ioengine_splice);
1003#endif
1004}
1005
1006static void fio_exit fio_netio_unregister(void)
1007{
1008 unregister_ioengine(&ioengine_rw);
1009#ifdef CONFIG_LINUX_SPLICE
1010 unregister_ioengine(&ioengine_splice);
1011#endif
1012}