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