From 414c2a3e741bb7dd7147ce6843f529c7773cea38 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 16 Jan 2009 13:21:15 +0100 Subject: [PATCH] net engine: add UDP support The filename= option now accepts a third parameter designating the protocol type, udp or tcp. Signed-off-by: Jens Axboe --- HOWTO | 24 +++++++------ engines/net.c | 96 +++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 92 insertions(+), 28 deletions(-) diff --git a/HOWTO b/HOWTO index 731684cb..55595fca 100644 --- a/HOWTO +++ b/HOWTO @@ -237,14 +237,15 @@ filename=str Fio normally makes up a filename based on the job name, thread number, and file number. If you want to share files between threads in a job or several jobs, specify a filename for each of them to override the default. If - the ioengine used is 'net', the filename is the host and - port to connect to in the format of =host/port. If the - ioengine is file based, you can specify a number of files - by separating the names with a ':' colon. So if you wanted - a job to open /dev/sda and /dev/sdb as the two working files, - you would use filename=/dev/sda:/dev/sdb. '-' is a reserved - name, meaning stdin or stdout. Which of the two depends - on the read/write direction set. + the ioengine used is 'net', the filename is the host, port, + and protocol to use in the format of =host/port/protocol. + See ioengine=net for more. If the ioengine is file based, you + can specify a number of files by separating the names with a + ':' colon. So if you wanted a job to open /dev/sda and /dev/sdb + as the two working files, you would use + filename=/dev/sda:/dev/sdb. '-' is a reserved name, meaning + stdin or stdout. Which of the two depends on the read/write + direction set. opendir=str Tell fio to recursively add any file it can find in this directory and down the file system tree. @@ -429,9 +430,12 @@ ioengine=str Defines how the job issues io to the file. The following net Transfer over the network to given host:port. 'filename' must be set appropriately to - filename=host/port regardless of send + filename=host/port/protocol regardless of send or receive, if the latter only the port - argument is used. + argument is used. 'host' may be an IP address + or hostname, port is the port number to be used, + and protocol may be 'udp' or 'tcp'. If no + protocol is given, TCP is used. netsplice Like net, but uses splice/vmsplice to map data and send/receive. diff --git a/engines/net.c b/engines/net.c index 0acd569d..2a9caaa2 100644 --- a/engines/net.c +++ b/engines/net.c @@ -22,6 +22,7 @@ struct netio_data { int listenfd; int send_to_net; int use_splice; + int net_protocol; int pipes[2]; char host[64]; struct sockaddr_in addr; @@ -180,6 +181,7 @@ static int fio_netio_splice_out(struct thread_data *td, struct io_u *io_u) static int fio_netio_send(struct thread_data *td, struct io_u *io_u) { + struct netio_data *nd = td->io_ops->data; int flags = 0; /* @@ -190,14 +192,29 @@ static int fio_netio_send(struct thread_data *td, struct io_u *io_u) flags = MSG_MORE; #endif - return send(io_u->file->fd, io_u->xfer_buf, io_u->xfer_buflen, flags); + if (nd->net_protocol == IPPROTO_UDP) { + return sendto(io_u->file->fd, io_u->xfer_buf, io_u->xfer_buflen, + 0, &nd->addr, sizeof(nd->addr)); + } else { + return send(io_u->file->fd, io_u->xfer_buf, io_u->xfer_buflen, + flags); + } } -static int fio_netio_recv(struct io_u *io_u) +static int fio_netio_recv(struct thread_data *td, struct io_u *io_u) { + struct netio_data *nd = td->io_ops->data; int flags = MSG_WAITALL; - return recv(io_u->file->fd, io_u->xfer_buf, io_u->xfer_buflen, flags); + if (nd->net_protocol == IPPROTO_UDP) { + socklen_t len = sizeof(nd->addr); + + return recvfrom(io_u->file->fd, io_u->xfer_buf, + io_u->xfer_buflen, 0, &nd->addr, &len); + } else { + return recv(io_u->file->fd, io_u->xfer_buf, io_u->xfer_buflen, + flags); + } } static int fio_netio_queue(struct thread_data *td, struct io_u *io_u) @@ -208,15 +225,15 @@ static int fio_netio_queue(struct thread_data *td, struct io_u *io_u) fio_ro_check(td, io_u); if (io_u->ddir == DDIR_WRITE) { - if (nd->use_splice) - ret = fio_netio_splice_out(td, io_u); - else + if (!nd->use_splice || nd->net_protocol == IPPROTO_UDP) ret = fio_netio_send(td, io_u); + else + ret = fio_netio_splice_out(td, io_u); } else if (io_u->ddir == DDIR_READ) { - if (nd->use_splice) - ret = fio_netio_splice_in(td, io_u); + if (!nd->use_splice || nd->net_protocol == IPPROTO_UDP) + ret = fio_netio_recv(td, io_u); else - ret = fio_netio_recv(io_u); + ret = fio_netio_splice_in(td, io_u); } else ret = 0; /* must be a SYNC */ @@ -225,8 +242,14 @@ static int fio_netio_queue(struct thread_data *td, struct io_u *io_u) io_u->resid = io_u->xfer_buflen - ret; io_u->error = 0; return FIO_Q_COMPLETED; - } else - io_u->error = errno; + } else { + int err = errno; + + if (io_u->ddir == DDIR_WRITE && err == EMSGSIZE) + return FIO_Q_BUSY; + + io_u->error = err; + } } if (io_u->error) @@ -238,13 +261,22 @@ static int fio_netio_queue(struct thread_data *td, struct io_u *io_u) static int fio_netio_connect(struct thread_data *td, struct fio_file *f) { struct netio_data *nd = td->io_ops->data; + int type; + + if (nd->net_protocol == IPPROTO_TCP) + type = SOCK_STREAM; + else + type = SOCK_DGRAM; - f->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + f->fd = socket(AF_INET, type, nd->net_protocol); if (f->fd < 0) { td_verror(td, errno, "socket"); return 1; } + if (nd->net_protocol == IPPROTO_UDP) + return 0; + if (connect(f->fd, (struct sockaddr *) &nd->addr, sizeof(nd->addr)) < 0) { td_verror(td, errno, "connect"); return 1; @@ -260,6 +292,11 @@ static int fio_netio_accept(struct thread_data *td, struct fio_file *f) struct pollfd pfd; int ret; + if (nd->net_protocol == IPPROTO_UDP) { + f->fd = nd->listenfd; + return 0; + } + log_info("fio: waiting for connection\n"); /* @@ -331,9 +368,14 @@ static int fio_netio_setup_connect(struct thread_data *td, const char *host, static int fio_netio_setup_listen(struct thread_data *td, short port) { struct netio_data *nd = td->io_ops->data; - int fd, opt; + int fd, opt, type; - fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (nd->net_protocol == IPPROTO_TCP) + type = SOCK_STREAM; + else + type = SOCK_DGRAM; + + fd = socket(AF_INET, type, nd->net_protocol); if (fd < 0) { td_verror(td, errno, "socket"); return 1; @@ -359,7 +401,7 @@ static int fio_netio_setup_listen(struct thread_data *td, short port) td_verror(td, errno, "bind"); return 1; } - if (listen(fd, 1) < 0) { + if (nd->net_protocol == IPPROTO_TCP && listen(fd, 1) < 0) { td_verror(td, errno, "listen"); return 1; } @@ -373,7 +415,7 @@ static int fio_netio_init(struct thread_data *td) struct netio_data *nd = td->io_ops->data; unsigned int port; char host[64], buf[128]; - char *sep; + char *sep, *portp, *modep; int ret; if (td_rw(td)) { @@ -397,10 +439,28 @@ static int fio_netio_init(struct thread_data *td) if (!strlen(host)) goto bad_host; - port = strtol(sep, NULL, 10); + modep = NULL; + portp = sep; + sep = strchr(portp, '/'); + if (sep) { + *sep = '\0'; + modep = sep + 1; + } + + port = strtol(portp, NULL, 10); if (!port || port > 65535) goto bad_host; + if (modep) { + if (!strncmp("tcp", modep, strlen(modep))) + nd->net_protocol = IPPROTO_TCP; + else if (!strncmp("udp", modep, strlen(modep))) + nd->net_protocol = IPPROTO_UDP; + else + goto bad_host; + } else + nd->net_protocol = IPPROTO_TCP; + if (td_read(td)) { nd->send_to_net = 0; ret = fio_netio_setup_listen(td, port); @@ -411,7 +471,7 @@ static int fio_netio_init(struct thread_data *td) return ret; bad_host: - log_err("fio: bad network host/port: %s\n", td->o.filename); + log_err("fio: bad network host/port/protocol: %s\n", td->o.filename); return 1; } -- 2.25.1