Add FIO_OPT_G_IO_ENG category
[fio.git] / engines / net.c
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 <errno.h>
11 #include <assert.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
14 #include <netdb.h>
15 #include <sys/poll.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <sys/socket.h>
19 #include <sys/un.h>
20
21 #include "../fio.h"
22
23 struct netio_data {
24         int listenfd;
25         int use_splice;
26         int pipes[2];
27         struct sockaddr_in addr;
28         struct sockaddr_un addr_un;
29 };
30
31 struct netio_options {
32         struct thread_data *td;
33         unsigned int port;
34         unsigned int proto;
35         unsigned int listen;
36 };
37
38 struct udp_close_msg {
39         uint32_t magic;
40         uint32_t cmd;
41 };
42
43 enum {
44         FIO_LINK_CLOSE = 0x89,
45         FIO_LINK_CLOSE_MAGIC = 0x6c696e6b,
46
47         FIO_TYPE_TCP    = 1,
48         FIO_TYPE_UDP    = 2,
49         FIO_TYPE_UNIX   = 3,
50 };
51
52 static int str_hostname_cb(void *data, const char *input);
53 static struct fio_option options[] = {
54         {
55                 .name   = "hostname",
56                 .type   = FIO_OPT_STR_STORE,
57                 .cb     = str_hostname_cb,
58                 .help   = "Hostname for net IO engine",
59                 .category = FIO_OPT_G_IO_ENG,
60         },
61         {
62                 .name   = "port",
63                 .type   = FIO_OPT_INT,
64                 .off1   = offsetof(struct netio_options, port),
65                 .minval = 1,
66                 .maxval = 65535,
67                 .help   = "Port to use for TCP or UDP net connections",
68                 .category = FIO_OPT_G_IO_ENG,
69         },
70         {
71                 .name   = "protocol",
72                 .alias  = "proto",
73                 .type   = FIO_OPT_STR,
74                 .off1   = offsetof(struct netio_options, proto),
75                 .help   = "Network protocol to use",
76                 .def    = "tcp",
77                 .category = FIO_OPT_G_IO_ENG,
78                 .posval = {
79                           { .ival = "tcp",
80                             .oval = FIO_TYPE_TCP,
81                             .help = "Transmission Control Protocol",
82                           },
83                           { .ival = "udp",
84                             .oval = FIO_TYPE_UDP,
85                             .help = "Unreliable Datagram Protocol",
86                           },
87                           { .ival = "unix",
88                             .oval = FIO_TYPE_UNIX,
89                             .help = "UNIX domain socket",
90                           },
91                 },
92         },
93         {
94                 .name   = "listen",
95                 .type   = FIO_OPT_STR_SET,
96                 .off1   = offsetof(struct netio_options, listen),
97                 .help   = "Listen for incoming TCP connections",
98                 .category = FIO_OPT_G_IO_ENG,
99         },
100         {
101                 .name   = NULL,
102         },
103 };
104
105 /*
106  * Return -1 for error and 'nr events' for a positive number
107  * of events
108  */
109 static int poll_wait(struct thread_data *td, int fd, short events)
110 {
111         struct pollfd pfd;
112         int ret;
113
114         while (!td->terminate) {
115                 pfd.fd = fd;
116                 pfd.events = events;
117                 ret = poll(&pfd, 1, -1);
118                 if (ret < 0) {
119                         if (errno == EINTR)
120                                 break;
121
122                         td_verror(td, errno, "poll");
123                         return -1;
124                 } else if (!ret)
125                         continue;
126
127                 break;
128         }
129
130         if (pfd.revents & events)
131                 return 1;
132
133         return -1;
134 }
135
136 static int fio_netio_prep(struct thread_data *td, struct io_u *io_u)
137 {
138         struct netio_options *o = td->eo;
139
140         /*
141          * Make sure we don't see spurious reads to a receiver, and vice versa
142          */
143         if (o->proto == FIO_TYPE_TCP)
144                 return 0;
145
146         if ((o->listen && io_u->ddir == DDIR_WRITE) ||
147             (!o->listen && io_u->ddir == DDIR_READ)) {
148                 td_verror(td, EINVAL, "bad direction");
149                 return 1;
150         }
151                 
152         return 0;
153 }
154
155 #ifdef FIO_HAVE_SPLICE
156 static int splice_io_u(int fdin, int fdout, unsigned int len)
157 {
158         int bytes = 0;
159
160         while (len) {
161                 int ret = splice(fdin, NULL, fdout, NULL, len, 0);
162
163                 if (ret < 0) {
164                         if (!bytes)
165                                 bytes = ret;
166
167                         break;
168                 } else if (!ret)
169                         break;
170
171                 bytes += ret;
172                 len -= ret;
173         }
174
175         return bytes;
176 }
177
178 /*
179  * Receive bytes from a socket and fill them into the internal pipe
180  */
181 static int splice_in(struct thread_data *td, struct io_u *io_u)
182 {
183         struct netio_data *nd = td->io_ops->data;
184
185         return splice_io_u(io_u->file->fd, nd->pipes[1], io_u->xfer_buflen);
186 }
187
188 /*
189  * Transmit 'len' bytes from the internal pipe
190  */
191 static int splice_out(struct thread_data *td, struct io_u *io_u,
192                       unsigned int len)
193 {
194         struct netio_data *nd = td->io_ops->data;
195
196         return splice_io_u(nd->pipes[0], io_u->file->fd, len);
197 }
198
199 static int vmsplice_io_u(struct io_u *io_u, int fd, unsigned int len)
200 {
201         struct iovec iov = {
202                 .iov_base = io_u->xfer_buf,
203                 .iov_len = len,
204         };
205         int bytes = 0;
206
207         while (iov.iov_len) {
208                 int ret = vmsplice(fd, &iov, 1, SPLICE_F_MOVE);
209
210                 if (ret < 0) {
211                         if (!bytes)
212                                 bytes = ret;
213                         break;
214                 } else if (!ret)
215                         break;
216
217                 iov.iov_len -= ret;
218                 iov.iov_base += ret;
219                 bytes += ret;
220         }
221
222         return bytes;
223
224 }
225
226 /*
227  * vmsplice() pipe to io_u buffer
228  */
229 static int vmsplice_io_u_out(struct thread_data *td, struct io_u *io_u,
230                              unsigned int len)
231 {
232         struct netio_data *nd = td->io_ops->data;
233
234         return vmsplice_io_u(io_u, nd->pipes[0], len);
235 }
236
237 /*
238  * vmsplice() io_u to pipe
239  */
240 static int vmsplice_io_u_in(struct thread_data *td, struct io_u *io_u)
241 {
242         struct netio_data *nd = td->io_ops->data;
243
244         return vmsplice_io_u(io_u, nd->pipes[1], io_u->xfer_buflen);
245 }
246
247 /*
248  * splice receive - transfer socket data into a pipe using splice, then map
249  * that pipe data into the io_u using vmsplice.
250  */
251 static int fio_netio_splice_in(struct thread_data *td, struct io_u *io_u)
252 {
253         int ret;
254
255         ret = splice_in(td, io_u);
256         if (ret > 0)
257                 return vmsplice_io_u_out(td, io_u, ret);
258
259         return ret;
260 }
261
262 /*
263  * splice transmit - map data from the io_u into a pipe by using vmsplice,
264  * then transfer that pipe to a socket using splice.
265  */
266 static int fio_netio_splice_out(struct thread_data *td, struct io_u *io_u)
267 {
268         int ret;
269
270         ret = vmsplice_io_u_in(td, io_u);
271         if (ret > 0)
272                 return splice_out(td, io_u, ret);
273
274         return ret;
275 }
276 #else
277 static int fio_netio_splice_in(struct thread_data *td, struct io_u *io_u)
278 {
279         errno = EOPNOTSUPP;
280         return -1;
281 }
282
283 static int fio_netio_splice_out(struct thread_data *td, struct io_u *io_u)
284 {
285         errno = EOPNOTSUPP;
286         return -1;
287 }
288 #endif
289
290 static int fio_netio_send(struct thread_data *td, struct io_u *io_u)
291 {
292         struct netio_data *nd = td->io_ops->data;
293         struct netio_options *o = td->eo;
294         int ret, flags = OS_MSG_DONTWAIT;
295
296         do {
297                 if (o->proto == FIO_TYPE_UDP) {
298                         struct sockaddr *to = (struct sockaddr *) &nd->addr;
299
300                         ret = sendto(io_u->file->fd, io_u->xfer_buf,
301                                         io_u->xfer_buflen, flags, to,
302                                         sizeof(*to));
303                 } else {
304                         /*
305                          * if we are going to write more, set MSG_MORE
306                          */
307 #ifdef MSG_MORE
308                         if (td->this_io_bytes[DDIR_WRITE] + io_u->xfer_buflen <
309                             td->o.size)
310                                 flags |= MSG_MORE;
311 #endif
312                         ret = send(io_u->file->fd, io_u->xfer_buf,
313                                         io_u->xfer_buflen, flags);
314                 }
315                 if (ret > 0)
316                         break;
317
318                 ret = poll_wait(td, io_u->file->fd, POLLOUT);
319                 if (ret <= 0)
320                         break;
321
322                 flags &= ~OS_MSG_DONTWAIT;
323         } while (1);
324
325         return ret;
326 }
327
328 static int is_udp_close(struct io_u *io_u, int len)
329 {
330         struct udp_close_msg *msg;
331
332         if (len != sizeof(struct udp_close_msg))
333                 return 0;
334
335         msg = io_u->xfer_buf;
336         if (ntohl(msg->magic) != FIO_LINK_CLOSE_MAGIC)
337                 return 0;
338         if (ntohl(msg->cmd) != FIO_LINK_CLOSE)
339                 return 0;
340
341         return 1;
342 }
343
344 static int fio_netio_recv(struct thread_data *td, struct io_u *io_u)
345 {
346         struct netio_data *nd = td->io_ops->data;
347         struct netio_options *o = td->eo;
348         int ret, flags = OS_MSG_DONTWAIT;
349
350         do {
351                 if (o->proto == FIO_TYPE_UDP) {
352                         fio_socklen_t len = sizeof(nd->addr);
353                         struct sockaddr *from = (struct sockaddr *) &nd->addr;
354
355                         ret = recvfrom(io_u->file->fd, io_u->xfer_buf,
356                                         io_u->xfer_buflen, flags, from, &len);
357                         if (is_udp_close(io_u, ret)) {
358                                 td->done = 1;
359                                 return 0;
360                         }
361                 } else {
362                         ret = recv(io_u->file->fd, io_u->xfer_buf,
363                                         io_u->xfer_buflen, flags);
364                 }
365                 if (ret > 0)
366                         break;
367
368                 ret = poll_wait(td, io_u->file->fd, POLLIN);
369                 if (ret <= 0)
370                         break;
371                 flags &= ~OS_MSG_DONTWAIT;
372                 flags |= MSG_WAITALL;
373         } while (1);
374
375         return ret;
376 }
377
378 static int fio_netio_queue(struct thread_data *td, struct io_u *io_u)
379 {
380         struct netio_data *nd = td->io_ops->data;
381         struct netio_options *o = td->eo;
382         int ret;
383
384         fio_ro_check(td, io_u);
385
386         if (io_u->ddir == DDIR_WRITE) {
387                 if (!nd->use_splice || o->proto == FIO_TYPE_UDP ||
388                     o->proto == FIO_TYPE_UNIX)
389                         ret = fio_netio_send(td, io_u);
390                 else
391                         ret = fio_netio_splice_out(td, io_u);
392         } else if (io_u->ddir == DDIR_READ) {
393                 if (!nd->use_splice || o->proto == FIO_TYPE_UDP ||
394                     o->proto == FIO_TYPE_UNIX)
395                         ret = fio_netio_recv(td, io_u);
396                 else
397                         ret = fio_netio_splice_in(td, io_u);
398         } else
399                 ret = 0;        /* must be a SYNC */
400
401         if (ret != (int) io_u->xfer_buflen) {
402                 if (ret >= 0) {
403                         io_u->resid = io_u->xfer_buflen - ret;
404                         io_u->error = 0;
405                         return FIO_Q_COMPLETED;
406                 } else {
407                         int err = errno;
408
409                         if (io_u->ddir == DDIR_WRITE && err == EMSGSIZE)
410                                 return FIO_Q_BUSY;
411
412                         io_u->error = err;
413                 }
414         }
415
416         if (io_u->error)
417                 td_verror(td, io_u->error, "xfer");
418
419         return FIO_Q_COMPLETED;
420 }
421
422 static int fio_netio_connect(struct thread_data *td, struct fio_file *f)
423 {
424         struct netio_data *nd = td->io_ops->data;
425         struct netio_options *o = td->eo;
426         int type, domain;
427
428         if (o->proto == FIO_TYPE_TCP) {
429                 domain = AF_INET;
430                 type = SOCK_STREAM;
431         } else if (o->proto == FIO_TYPE_UDP) {
432                 domain = AF_INET;
433                 type = SOCK_DGRAM;
434         } else if (o->proto == FIO_TYPE_UNIX) {
435                 domain = AF_UNIX;
436                 type = SOCK_STREAM;
437         } else {
438                 log_err("fio: bad network type %d\n", o->proto);
439                 f->fd = -1;
440                 return 1;
441         }
442
443         f->fd = socket(domain, type, 0);
444         if (f->fd < 0) {
445                 td_verror(td, errno, "socket");
446                 return 1;
447         }
448
449         if (o->proto == FIO_TYPE_UDP)
450                 return 0;
451         else if (o->proto == FIO_TYPE_TCP) {
452                 fio_socklen_t len = sizeof(nd->addr);
453
454                 if (connect(f->fd, (struct sockaddr *) &nd->addr, len) < 0) {
455                         td_verror(td, errno, "connect");
456                         close(f->fd);
457                         return 1;
458                 }
459         } else {
460                 struct sockaddr_un *addr = &nd->addr_un;
461                 fio_socklen_t len;
462
463                 len = sizeof(addr->sun_family) + strlen(addr->sun_path) + 1;
464
465                 if (connect(f->fd, (struct sockaddr *) addr, len) < 0) {
466                         td_verror(td, errno, "connect");
467                         close(f->fd);
468                         return 1;
469                 }
470         }
471
472         return 0;
473 }
474
475 static int fio_netio_accept(struct thread_data *td, struct fio_file *f)
476 {
477         struct netio_data *nd = td->io_ops->data;
478         struct netio_options *o = td->eo;
479         fio_socklen_t socklen = sizeof(nd->addr);
480
481         if (o->proto == FIO_TYPE_UDP) {
482                 f->fd = nd->listenfd;
483                 return 0;
484         }
485
486         log_info("fio: waiting for connection\n");
487
488         if (poll_wait(td, nd->listenfd, POLLIN) < 0)
489                 return 1;
490
491         f->fd = accept(nd->listenfd, (struct sockaddr *) &nd->addr, &socklen);
492         if (f->fd < 0) {
493                 td_verror(td, errno, "accept");
494                 return 1;
495         }
496
497         return 0;
498 }
499
500 static int fio_netio_open_file(struct thread_data *td, struct fio_file *f)
501 {
502         int ret;
503         struct netio_options *o = td->eo;
504
505         if (o->listen)
506                 ret = fio_netio_accept(td, f);
507         else
508                 ret = fio_netio_connect(td, f);
509
510         if (ret)
511                 f->fd = -1;
512         return ret;
513 }
514
515 static void fio_netio_udp_close(struct thread_data *td, struct fio_file *f)
516 {
517         struct netio_data *nd = td->io_ops->data;
518         struct udp_close_msg msg;
519         struct sockaddr *to = (struct sockaddr *) &nd->addr;
520         int ret;
521
522         msg.magic = htonl(FIO_LINK_CLOSE_MAGIC);
523         msg.cmd = htonl(FIO_LINK_CLOSE);
524
525         ret = sendto(f->fd, &msg, sizeof(msg), MSG_WAITALL, to,
526                         sizeof(nd->addr));
527         if (ret < 0)
528                 td_verror(td, errno, "sendto udp link close");
529 }
530
531 static int fio_netio_close_file(struct thread_data *td, struct fio_file *f)
532 {
533         struct netio_options *o = td->eo;
534
535         /*
536          * If this is an UDP connection, notify the receiver that we are
537          * closing down the link
538          */
539         if (o->proto == FIO_TYPE_UDP)
540                 fio_netio_udp_close(td, f);
541
542         return generic_close_file(td, f);
543 }
544
545 static int fio_netio_setup_connect_inet(struct thread_data *td,
546                                         const char *host, unsigned short port)
547 {
548         struct netio_data *nd = td->io_ops->data;
549
550         nd->addr.sin_family = AF_INET;
551         nd->addr.sin_port = htons(port);
552
553         if (inet_aton(host, &nd->addr.sin_addr) != 1) {
554                 struct hostent *hent;
555
556                 hent = gethostbyname(host);
557                 if (!hent) {
558                         td_verror(td, errno, "gethostbyname");
559                         return 1;
560                 }
561
562                 memcpy(&nd->addr.sin_addr, hent->h_addr, 4);
563         }
564
565         return 0;
566 }
567
568 static int fio_netio_setup_connect_unix(struct thread_data *td,
569                                         const char *path)
570 {
571         struct netio_data *nd = td->io_ops->data;
572         struct sockaddr_un *soun = &nd->addr_un;
573
574         soun->sun_family = AF_UNIX;
575         strcpy(soun->sun_path, path);
576         return 0;
577 }
578
579 static int fio_netio_setup_connect(struct thread_data *td)
580 {
581         struct netio_options *o = td->eo;
582
583         if (o->proto == FIO_TYPE_UDP || o->proto == FIO_TYPE_TCP)
584                 return fio_netio_setup_connect_inet(td, td->o.filename,o->port);
585         else
586                 return fio_netio_setup_connect_unix(td, td->o.filename);
587 }
588
589 static int fio_netio_setup_listen_unix(struct thread_data *td, const char *path)
590 {
591         struct netio_data *nd = td->io_ops->data;
592         struct sockaddr_un *addr = &nd->addr_un;
593         mode_t mode;
594         int len, fd;
595
596         fd = socket(AF_UNIX, SOCK_STREAM, 0);
597         if (fd < 0) {
598                 log_err("fio: socket: %s\n", strerror(errno));
599                 return -1;
600         }
601
602         mode = umask(000);
603
604         memset(addr, 0, sizeof(*addr));
605         addr->sun_family = AF_UNIX;
606         strcpy(addr->sun_path, path);
607         unlink(path);
608
609         len = sizeof(addr->sun_family) + strlen(path) + 1;
610
611         if (bind(fd, (struct sockaddr *) addr, len) < 0) {
612                 log_err("fio: bind: %s\n", strerror(errno));
613                 close(fd);
614                 return -1;
615         }
616
617         umask(mode);
618         nd->listenfd = fd;
619         return 0;
620 }
621
622 static int fio_netio_setup_listen_inet(struct thread_data *td, short port)
623 {
624         struct netio_data *nd = td->io_ops->data;
625         struct netio_options *o = td->eo;
626         int fd, opt, type;
627
628         if (o->proto == FIO_TYPE_TCP)
629                 type = SOCK_STREAM;
630         else
631                 type = SOCK_DGRAM;
632
633         fd = socket(AF_INET, type, 0);
634         if (fd < 0) {
635                 td_verror(td, errno, "socket");
636                 return 1;
637         }
638
639         opt = 1;
640         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
641                 td_verror(td, errno, "setsockopt");
642                 return 1;
643         }
644 #ifdef SO_REUSEPORT
645         if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)) < 0) {
646                 td_verror(td, errno, "setsockopt");
647                 return 1;
648         }
649 #endif
650
651         nd->addr.sin_family = AF_INET;
652         nd->addr.sin_addr.s_addr = htonl(INADDR_ANY);
653         nd->addr.sin_port = htons(port);
654
655         if (bind(fd, (struct sockaddr *) &nd->addr, sizeof(nd->addr)) < 0) {
656                 td_verror(td, errno, "bind");
657                 return 1;
658         }
659
660         nd->listenfd = fd;
661         return 0;
662 }
663
664 static int fio_netio_setup_listen(struct thread_data *td)
665 {
666         struct netio_data *nd = td->io_ops->data;
667         struct netio_options *o = td->eo;
668         int ret;
669
670         if (o->proto == FIO_TYPE_UDP || o->proto == FIO_TYPE_TCP)
671                 ret = fio_netio_setup_listen_inet(td, o->port);
672         else
673                 ret = fio_netio_setup_listen_unix(td, td->o.filename);
674
675         if (ret)
676                 return ret;
677         if (o->proto == FIO_TYPE_UDP)
678                 return 0;
679
680         if (listen(nd->listenfd, 10) < 0) {
681                 td_verror(td, errno, "listen");
682                 nd->listenfd = -1;
683                 return 1;
684         }
685
686         return 0;
687 }
688
689 static int fio_netio_init(struct thread_data *td)
690 {
691         struct netio_options *o = td->eo;
692         int ret;
693
694         if (td_random(td)) {
695                 log_err("fio: network IO can't be random\n");
696                 return 1;
697         }
698
699         if (o->proto == FIO_TYPE_UNIX && o->port) {
700                 log_err("fio: network IO port not valid with unix socket\n");
701                 return 1;
702         } else if (o->proto != FIO_TYPE_UNIX && !o->port) {
703                 log_err("fio: network IO requires port for tcp or udp\n");
704                 return 1;
705         }
706
707         if (o->proto != FIO_TYPE_TCP) {
708                 if (o->listen) {
709                         log_err("fio: listen only valid for TCP proto IO\n");
710                         return 1;
711                 }
712                 if (td_rw(td)) {
713                         log_err("fio: datagram network connections must be"
714                                    " read OR write\n");
715                         return 1;
716                 }
717                 if (o->proto == FIO_TYPE_UNIX && !td->o.filename) {
718                         log_err("fio: UNIX sockets need host/filename\n");
719                         return 1;
720                 }
721                 o->listen = td_read(td);
722         }
723
724         if (o->proto != FIO_TYPE_UNIX && o->listen && td->o.filename) {
725                 log_err("fio: hostname not valid for inbound network IO\n");
726                 return 1;
727         }
728
729         if (o->listen)
730                 ret = fio_netio_setup_listen(td);
731         else
732                 ret = fio_netio_setup_connect(td);
733
734         return ret;
735 }
736
737 static void fio_netio_cleanup(struct thread_data *td)
738 {
739         struct netio_data *nd = td->io_ops->data;
740
741         if (nd) {
742                 if (nd->listenfd != -1)
743                         close(nd->listenfd);
744                 if (nd->pipes[0] != -1)
745                         close(nd->pipes[0]);
746                 if (nd->pipes[1] != -1)
747                         close(nd->pipes[1]);
748
749                 free(nd);
750         }
751 }
752
753 static int fio_netio_setup(struct thread_data *td)
754 {
755         struct netio_data *nd;
756
757         if (!td->files_index) {
758                 add_file(td, td->o.filename ?: "net");
759                 td->o.nr_files = td->o.nr_files ?: 1;
760         }
761
762         if (!td->io_ops->data) {
763                 nd = malloc(sizeof(*nd));;
764
765                 memset(nd, 0, sizeof(*nd));
766                 nd->listenfd = -1;
767                 nd->pipes[0] = nd->pipes[1] = -1;
768                 td->io_ops->data = nd;
769         }
770
771         return 0;
772 }
773
774 #ifdef FIO_HAVE_SPLICE
775 static int fio_netio_setup_splice(struct thread_data *td)
776 {
777         struct netio_data *nd;
778
779         fio_netio_setup(td);
780
781         nd = td->io_ops->data;
782         if (nd) {
783                 if (pipe(nd->pipes) < 0)
784                         return 1;
785
786                 nd->use_splice = 1;
787                 return 0;
788         }
789
790         return 1;
791 }
792
793 static struct ioengine_ops ioengine_splice = {
794         .name                   = "netsplice",
795         .version                = FIO_IOOPS_VERSION,
796         .prep                   = fio_netio_prep,
797         .queue                  = fio_netio_queue,
798         .setup                  = fio_netio_setup_splice,
799         .init                   = fio_netio_init,
800         .cleanup                = fio_netio_cleanup,
801         .open_file              = fio_netio_open_file,
802         .close_file             = generic_close_file,
803         .options                = options,
804         .option_struct_size     = sizeof(struct netio_options),
805         .flags                  = FIO_SYNCIO | FIO_DISKLESSIO | FIO_UNIDIR |
806                                   FIO_SIGTERM | FIO_PIPEIO,
807 };
808 #endif
809
810 static struct ioengine_ops ioengine_rw = {
811         .name                   = "net",
812         .version                = FIO_IOOPS_VERSION,
813         .prep                   = fio_netio_prep,
814         .queue                  = fio_netio_queue,
815         .setup                  = fio_netio_setup,
816         .init                   = fio_netio_init,
817         .cleanup                = fio_netio_cleanup,
818         .open_file              = fio_netio_open_file,
819         .close_file             = fio_netio_close_file,
820         .options                = options,
821         .option_struct_size     = sizeof(struct netio_options),
822         .flags                  = FIO_SYNCIO | FIO_DISKLESSIO | FIO_UNIDIR |
823                                   FIO_SIGTERM | FIO_PIPEIO,
824 };
825
826 static int str_hostname_cb(void *data, const char *input)
827 {
828         struct netio_options *o = data;
829
830         if (o->td->o.filename)
831                 free(o->td->o.filename);
832         o->td->o.filename = strdup(input);
833         return 0;
834 }
835
836 static void fio_init fio_netio_register(void)
837 {
838         register_ioengine(&ioengine_rw);
839 #ifdef FIO_HAVE_SPLICE
840         register_ioengine(&ioengine_splice);
841 #endif
842 }
843
844 static void fio_exit fio_netio_unregister(void)
845 {
846         unregister_ioengine(&ioengine_rw);
847 #ifdef FIO_HAVE_SPLICE
848         unregister_ioengine(&ioengine_splice);
849 #endif
850 }