net: Add UDP multicast support
authorShawn Bohrer <sbohrer@rgmadvisors.com>
Fri, 19 Jul 2013 18:24:06 +0000 (13:24 -0500)
committerJens Axboe <axboe@kernel.dk>
Mon, 22 Jul 2013 15:04:35 +0000 (09:04 -0600)
Allow UDP readers to listen to UDP multicast traffic if hostname is set
to a valid UDP multicast address.

Signed-off-by: Shawn Bohrer <sbohrer@rgmadvisors.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
HOWTO
engines/net.c
fio.1

diff --git a/HOWTO b/HOWTO
index 4fd025126925eb6fd75910608530b8f8c20ba27f..3791e7d52af3da59b9ca7bcad47eb56e33c94fe0 100644 (file)
--- 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)
index b4ed5df9787b46005d364bfe1b5a0382a6c44219..b2c1283454090ed42554908c6642dd130e37cc59 100644 (file)
@@ -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 91fd5311afe6f1166a2be31109470661465ef576..eba748b9c4d0a79762a4b036ab4fc56f8951ea98 100644 (file)
--- 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)