X-Git-Url: https://git.kernel.dk/?a=blobdiff_plain;ds=sidebyside;f=engines%2Fnet.c;h=52cc8a7f92c48f15d538f848810d0ad2710c89cd;hb=f16b7405fff7c3fc1da421b6bdf8552cc99c3156;hp=a70e56e6d5095b01455a6f2ca234448dbe7635f0;hpb=62232d0618e3f5aa4805b4be34e872895ba1beb2;p=fio.git diff --git a/engines/net.c b/engines/net.c index a70e56e6..52cc8a7f 100644 --- a/engines/net.c +++ b/engines/net.c @@ -37,6 +37,8 @@ struct netio_options { unsigned int listen; unsigned int pingpong; unsigned int nodelay; + unsigned int ttl; + char *intfc; }; struct udp_close_msg { @@ -62,7 +64,8 @@ static struct fio_option options[] = { .type = FIO_OPT_STR_STORE, .cb = str_hostname_cb, .help = "Hostname for net IO engine", - .category = FIO_OPT_C_IO, + .category = FIO_OPT_C_ENGINE, + .group = FIO_OPT_G_NETIO, }, { .name = "port", @@ -72,7 +75,8 @@ static struct fio_option options[] = { .minval = 1, .maxval = 65535, .help = "Port to use for TCP or UDP net connections", - .category = FIO_OPT_C_IO, + .category = FIO_OPT_C_ENGINE, + .group = FIO_OPT_G_NETIO, }, { .name = "protocol", @@ -82,7 +86,6 @@ static struct fio_option options[] = { .off1 = offsetof(struct netio_options, proto), .help = "Network protocol to use", .def = "tcp", - .category = FIO_OPT_C_IO, .posval = { { .ival = "tcp", .oval = FIO_TYPE_TCP, @@ -97,6 +100,8 @@ static struct fio_option options[] = { .help = "UNIX domain socket", }, }, + .category = FIO_OPT_C_ENGINE, + .group = FIO_OPT_G_NETIO, }, #ifdef CONFIG_TCP_NODELAY { @@ -104,6 +109,8 @@ static struct fio_option options[] = { .type = FIO_OPT_BOOL, .off1 = offsetof(struct netio_options, nodelay), .help = "Use TCP_NODELAY on TCP connections", + .category = FIO_OPT_C_ENGINE, + .group = FIO_OPT_G_NETIO, }, #endif { @@ -112,13 +119,36 @@ static struct fio_option options[] = { .type = FIO_OPT_STR_SET, .off1 = offsetof(struct netio_options, listen), .help = "Listen for incoming TCP connections", - .category = FIO_OPT_C_IO, + .category = FIO_OPT_C_ENGINE, + .group = FIO_OPT_G_NETIO, }, { .name = "pingpong", .type = FIO_OPT_STR_SET, .off1 = offsetof(struct netio_options, pingpong), .help = "Ping-pong IO requests", + .category = FIO_OPT_C_ENGINE, + .group = FIO_OPT_G_NETIO, + }, + { + .name = "interface", + .lname = "net engine interface", + .type = FIO_OPT_STR_STORE, + .off1 = offsetof(struct netio_options, intfc), + .help = "Network interface to use", + .category = FIO_OPT_C_ENGINE, + .group = FIO_OPT_G_NETIO, + }, + { + .name = "ttl", + .lname = "net engine multicast ttl", + .type = FIO_OPT_INT, + .off1 = offsetof(struct netio_options, ttl), + .def = "1", + .minval = 0, + .help = "Time-to-live value for outgoing UDP multicast packets", + .category = FIO_OPT_C_ENGINE, + .group = FIO_OPT_G_NETIO, }, { .name = NULL, @@ -156,6 +186,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; @@ -370,11 +414,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; @@ -500,9 +553,30 @@ static int fio_netio_connect(struct thread_data *td, struct fio_file *f) } #endif - if (o->proto == FIO_TYPE_UDP) + if (o->proto == FIO_TYPE_UDP) { + if (!fio_netio_is_multicast(td->o.filename)) + return 0; + + if (o->intfc) { + struct in_addr interface_addr; + if (inet_aton(o->intfc, &interface_addr) == 0) { + log_err("fio: interface not valid interface IP\n"); + close(f->fd); + return 1; + } + if (setsockopt(f->fd, IPPROTO_IP, IP_MULTICAST_IF, (const char*)&interface_addr, sizeof(interface_addr)) < 0) { + td_verror(td, errno, "setsockopt IP_MULTICAST_IF"); + close(f->fd); + return 1; + } + } + if (setsockopt(f->fd, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&o->ttl, sizeof(o->ttl)) < 0) { + td_verror(td, errno, "setsockopt IP_MULTICAST_TTL"); + close(f->fd); + return 1; + } return 0; - else if (o->proto == FIO_TYPE_TCP) { + } else if (o->proto == FIO_TYPE_TCP) { socklen_t len = sizeof(nd->addr); if (connect(f->fd, (struct sockaddr *) &nd->addr, len) < 0) { @@ -611,7 +685,7 @@ static int fio_netio_udp_recv_open(struct thread_data *td, struct fio_file *f) ret = recvfrom(f->fd, (void *) &msg, sizeof(msg), MSG_WAITALL, to, &len); if (ret < 0) { - td_verror(td, errno, "sendto udp link open"); + td_verror(td, errno, "recvfrom udp link open"); return ret; } @@ -769,8 +843,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 @@ -785,17 +862,46 @@ static int fio_netio_setup_listen_inet(struct thread_data *td, short port) opt = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &opt, sizeof(opt)) < 0) { td_verror(td, errno, "setsockopt"); + close(fd); return 1; } #ifdef SO_REUSEPORT if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (void *) &opt, sizeof(opt)) < 0) { td_verror(td, errno, "setsockopt"); + close(fd); return 1; } #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; + if (o->intfc) { + if (inet_aton(o->intfc, &mr.imr_interface) == 0) { + log_err("fio: interface not valid interface IP\n"); + close(fd); + return 1; + } + } else { + mr.imr_interface.s_addr = htonl(INADDR_ANY); + } + if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&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) { @@ -872,11 +978,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 @@ -978,7 +1079,7 @@ static struct ioengine_ops ioengine_rw = { .options = options, .option_struct_size = sizeof(struct netio_options), .flags = FIO_SYNCIO | FIO_DISKLESSIO | FIO_UNIDIR | - FIO_PIPEIO, + FIO_PIPEIO | FIO_BIT_BASED, }; static int str_hostname_cb(void *data, const char *input)