From: Shawn Bohrer Date: Fri, 19 Jul 2013 18:24:06 +0000 (-0500) Subject: net: Add UDP multicast support X-Git-Tag: fio-2.1.2~35 X-Git-Url: https://git.kernel.dk/?p=fio.git;a=commitdiff_plain;h=b511c9aaa5f289596b05743c5b8e40451017129c net: Add UDP multicast support Allow UDP readers to listen to UDP multicast traffic if hostname is set to a valid UDP multicast address. Signed-off-by: Shawn Bohrer Signed-off-by: Jens Axboe --- diff --git a/HOWTO b/HOWTO index 4fd02512..3791e7d5 100644 --- a/HOWTO +++ b/HOWTO @@ -1438,7 +1438,8 @@ that defines them is selected. [netsplice] hostname=str [net] hostname=str The host name or IP address to use for TCP or UDP based IO. If the job is a TCP listener or UDP reader, the hostname is not - used and must be omitted. + used and must be omitted unless it is a valid UDP multicast + address. [netsplice] port=int [net] port=int The TCP or UDP port to bind to or connect to. @@ -1463,7 +1464,7 @@ that defines them is selected. [net] listen For TCP network connections, tell fio to listen for incoming connections rather than initiating an outgoing connection. The hostname must be omitted if this option is used. -[net] pingpong Normal a network writer will just continue writing data, and +[net] pingpong Normaly a network writer will just continue writing data, and a network reader will just consume packages. If pingpong=1 is set, a writer will send its normal payload to the reader, then wait for the reader to send the same payload back. This @@ -1471,6 +1472,9 @@ that defines them is selected. and completion latencies then measure local time spent sending or receiving, and the completion latency measures how long it took for the other end to receive and send back. + For UDP multicast traffic pingpong=1 should only be set for a + single reader when multiple readers are listening to the same + address. [e4defrag] donorname=str File will be used as a block donor(swap extents between files) diff --git a/engines/net.c b/engines/net.c index b4ed5df9..b2c12834 100644 --- a/engines/net.c +++ b/engines/net.c @@ -164,6 +164,20 @@ static int poll_wait(struct thread_data *td, int fd, short events) return -1; } +static int fio_netio_is_multicast(const char *mcaddr) +{ + in_addr_t addr = inet_network(mcaddr); + if (addr == -1) + return 0; + + if (inet_network("224.0.0.0") <= addr && + inet_network("239.255.255.255") >= addr) + return 1; + + return 0; +} + + static int fio_netio_prep(struct thread_data *td, struct io_u *io_u) { struct netio_options *o = td->eo; @@ -378,11 +392,20 @@ static int fio_netio_recv(struct thread_data *td, struct io_u *io_u) do { if (o->proto == FIO_TYPE_UDP) { - socklen_t len = sizeof(nd->addr); - struct sockaddr *from = (struct sockaddr *) &nd->addr; + socklen_t l; + socklen_t *len = &l; + struct sockaddr *from; + + if (o->listen) { + from = (struct sockaddr *) &nd->addr; + *len = sizeof(nd->addr); + } else { + from = NULL; + len = NULL; + } ret = recvfrom(io_u->file->fd, io_u->xfer_buf, - io_u->xfer_buflen, flags, from, &len); + io_u->xfer_buflen, flags, from, len); if (is_udp_close(io_u, ret)) { td->done = 1; return 0; @@ -777,8 +800,11 @@ static int fio_netio_setup_listen_inet(struct thread_data *td, short port) { struct netio_data *nd = td->io_ops->data; struct netio_options *o = td->eo; + struct ip_mreq mr; + struct sockaddr_in sin; int fd, opt, type; + memset(&sin, 0, sizeof(sin)); if (o->proto == FIO_TYPE_TCP) type = SOCK_STREAM; else @@ -804,8 +830,27 @@ static int fio_netio_setup_listen_inet(struct thread_data *td, short port) } #endif + if (td->o.filename){ + if(o->proto != FIO_TYPE_UDP || + !fio_netio_is_multicast(td->o.filename)) { + log_err("fio: hostname not valid for non-multicast inbound network IO\n"); + close(fd); + return 1; + } + + inet_aton(td->o.filename, &sin.sin_addr); + + mr.imr_multiaddr = sin.sin_addr; + mr.imr_interface.s_addr = htonl(INADDR_ANY); + if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0) { + td_verror(td, errno, "setsockopt IP_ADD_MEMBERSHIP"); + close(fd); + return 1; + } + } + nd->addr.sin_family = AF_INET; - nd->addr.sin_addr.s_addr = htonl(INADDR_ANY); + nd->addr.sin_addr.s_addr = sin.sin_addr.s_addr ? sin.sin_addr.s_addr : htonl(INADDR_ANY); nd->addr.sin_port = htons(port); if (bind(fd, (struct sockaddr *) &nd->addr, sizeof(nd->addr)) < 0) { @@ -882,11 +927,6 @@ static int fio_netio_init(struct thread_data *td) o->listen = td_read(td); } - if (o->proto != FIO_TYPE_UNIX && o->listen && td->o.filename) { - log_err("fio: hostname not valid for inbound network IO\n"); - return 1; - } - if (o->listen) ret = fio_netio_setup_listen(td); else diff --git a/fio.1 b/fio.1 index 91fd5311..eba748b9 100644 --- a/fio.1 +++ b/fio.1 @@ -1216,7 +1216,7 @@ iodepth_batch_complete=0). .BI (net,netsplice)hostname \fR=\fPstr The host name or IP address to use for TCP or UDP based IO. If the job is a TCP listener or UDP reader, the hostname is not -used and must be omitted. +used and must be omitted unless it is a valid UDP multicast address. .TP .BI (net,netsplice)port \fR=\fPint The TCP or UDP port to bind to or connect to. @@ -1251,13 +1251,14 @@ connections rather than initiating an outgoing connection. The hostname must be omitted if this option is used. .TP .BI (net, pingpong) \fR=\fPbool -Normal a network writer will just continue writing data, and a network reader +Normaly a network writer will just continue writing data, and a network reader will just consume packages. If pingpong=1 is set, a writer will send its normal payload to the reader, then wait for the reader to send the same payload back. This allows fio to measure network latencies. The submission and completion latencies then measure local time spent sending or receiving, and the completion latency measures how long it took for the other end to receive and -send back. +send back. For UDP multicast traffic pingpong=1 should only be set for a single +reader when multiple readers are listening to the same address. .TP .BI (e4defrag,donorname) \fR=\fPstr File will be used as a block donor (swap extents between files)