X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=engines%2Fnet.c;h=eb72e2eee389857346c22cbe376f1c0c7fe36c9a;hp=1d89db1cdcecc4a740b1afe603711ea3a114ba0c;hb=e9ad9637d9a444132c23cdcf907e2adeb8f87b89;hpb=c5dd6d8975fc36da778d08c21d3e051add6d3030 diff --git a/engines/net.c b/engines/net.c index 1d89db1c..eb72e2ee 100644 --- a/engines/net.c +++ b/engines/net.c @@ -21,6 +21,7 @@ #include #include "../fio.h" +#include "../verify.h" struct netio_data { int listenfd; @@ -29,6 +30,9 @@ struct netio_data { struct sockaddr_in addr; struct sockaddr_in6 addr6; struct sockaddr_un addr_un; + uint64_t udp_lost; + uint64_t udp_send_seq; + uint64_t udp_recv_seq; }; struct netio_options { @@ -39,6 +43,8 @@ struct netio_options { unsigned int pingpong; unsigned int nodelay; unsigned int ttl; + unsigned int window_size; + unsigned int mss; char *intfc; }; @@ -47,10 +53,16 @@ struct udp_close_msg { uint32_t cmd; }; +struct udp_seq { + uint64_t magic; + uint64_t seq; +}; + enum { FIO_LINK_CLOSE = 0x89, FIO_LINK_OPEN_CLOSE_MAGIC = 0x6c696e6b, FIO_LINK_OPEN = 0x98, + FIO_UDP_SEQ_MAGIC = 0x657375716e556563ULL, FIO_TYPE_TCP = 1, FIO_TYPE_UDP = 2, @@ -165,6 +177,30 @@ static struct fio_option options[] = { .category = FIO_OPT_C_ENGINE, .group = FIO_OPT_G_NETIO, }, +#ifdef CONFIG_NET_WINDOWSIZE + { + .name = "window_size", + .lname = "Window Size", + .type = FIO_OPT_INT, + .off1 = offsetof(struct netio_options, window_size), + .minval = 0, + .help = "Set socket buffer window size", + .category = FIO_OPT_C_ENGINE, + .group = FIO_OPT_G_NETIO, + }, +#endif +#ifdef CONFIG_NET_MSS + { + .name = "mss", + .lname = "Maximum segment size", + .type = FIO_OPT_INT, + .off1 = offsetof(struct netio_options, mss), + .minval = 0, + .help = "Set TCP maximum segment size", + .category = FIO_OPT_C_ENGINE, + .group = FIO_OPT_G_NETIO, + }, +#endif { .name = NULL, }, @@ -185,6 +221,65 @@ static inline int is_ipv6(struct netio_options *o) return o->proto == FIO_TYPE_UDP_V6 || o->proto == FIO_TYPE_TCP_V6; } +static int set_window_size(struct thread_data *td, int fd) +{ +#ifdef CONFIG_NET_WINDOWSIZE + struct netio_options *o = td->eo; + unsigned int wss; + int snd, rcv, ret; + + if (!o->window_size) + return 0; + + rcv = o->listen || o->pingpong; + snd = !o->listen || o->pingpong; + wss = o->window_size; + ret = 0; + + if (rcv) { + ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *) &wss, + sizeof(wss)); + if (ret < 0) + td_verror(td, errno, "rcvbuf window size"); + } + if (snd && !ret) { + ret = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void *) &wss, + sizeof(wss)); + if (ret < 0) + td_verror(td, errno, "sndbuf window size"); + } + + return ret; +#else + td_verror(td, -EINVAL, "setsockopt window size"); + return -1; +#endif +} + +static int set_mss(struct thread_data *td, int fd) +{ +#ifdef CONFIG_NET_MSS + struct netio_options *o = td->eo; + unsigned int mss; + int ret; + + if (!o->mss || !is_tcp(o)) + return 0; + + mss = o->mss; + ret = setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, (void *) &mss, + sizeof(mss)); + if (ret < 0) + td_verror(td, errno, "setsockopt TCP_MAXSEG"); + + return ret; +#else + td_verror(td, -EINVAL, "setsockopt TCP_MAXSEG"); + return -1; +#endif +} + + /* * Return -1 for error and 'nr events' for a positive number * of events @@ -384,6 +479,32 @@ static int fio_netio_splice_out(struct thread_data *td, struct io_u *io_u) } #endif +static void store_udp_seq(struct netio_data *nd, struct io_u *io_u) +{ + struct udp_seq *us; + + us = io_u->xfer_buf + io_u->xfer_buflen - sizeof(*us); + us->magic = cpu_to_le64(FIO_UDP_SEQ_MAGIC); + us->seq = cpu_to_le64(nd->udp_send_seq++); +} + +static void verify_udp_seq(struct netio_data *nd, struct io_u *io_u) +{ + struct udp_seq *us; + uint64_t seq; + + us = io_u->xfer_buf + io_u->xfer_buflen - sizeof(*us); + if (le64_to_cpu(us->magic) != FIO_UDP_SEQ_MAGIC) + return; + + seq = le64_to_cpu(us->seq); + + if (seq != nd->udp_recv_seq) + nd->udp_lost += seq - nd->udp_recv_seq; + + nd->udp_recv_seq = seq + 1; +} + static int fio_netio_send(struct thread_data *td, struct io_u *io_u) { struct netio_data *nd = td->io_ops->data; @@ -403,6 +524,9 @@ static int fio_netio_send(struct thread_data *td, struct io_u *io_u) len = sizeof(nd->addr); } + if (td->o.verify == VERIFY_NONE) + store_udp_seq(nd, io_u); + ret = sendto(io_u->file->fd, io_u->xfer_buf, io_u->xfer_buflen, flags, to, len); } else { @@ -470,6 +594,7 @@ static int fio_netio_recv(struct thread_data *td, struct io_u *io_u) ret = recvfrom(io_u->file->fd, io_u->xfer_buf, io_u->xfer_buflen, flags, from, len); + if (is_udp_close(io_u, ret)) { td->done = 1; return 0; @@ -489,6 +614,9 @@ static int fio_netio_recv(struct thread_data *td, struct io_u *io_u) flags |= MSG_WAITALL; } while (1); + if (is_udp(o) && td->o.verify == VERIFY_NONE) + verify_udp_seq(nd, io_u); + return ret; } @@ -515,11 +643,13 @@ static int __fio_netio_queue(struct thread_data *td, struct io_u *io_u, ret = 0; /* must be a SYNC */ if (ret != (int) io_u->xfer_buflen) { - if (ret >= 0) { + if (ret > 0) { io_u->resid = io_u->xfer_buflen - ret; io_u->error = 0; return FIO_Q_COMPLETED; - } else { + } else if (!ret) + return FIO_Q_BUSY; + else { int err = errno; if (ddir == DDIR_WRITE && err == EMSGSIZE) @@ -601,6 +731,15 @@ static int fio_netio_connect(struct thread_data *td, struct fio_file *f) } #endif + if (set_window_size(td, f->fd)) { + close(f->fd); + return 1; + } + if (set_mss(td, f->fd)) { + close(f->fd); + return 1; + } + if (is_udp(o)) { if (!fio_netio_is_multicast(td->o.filename)) return 0; @@ -784,6 +923,7 @@ static int fio_netio_udp_recv_open(struct thread_data *td, struct fio_file *f) return -1; } + fio_gettime(&td->start, NULL); return 0; } @@ -1042,6 +1182,15 @@ static int fio_netio_setup_listen_inet(struct thread_data *td, short port) } #endif + if (set_window_size(td, fd)) { + close(fd); + return 1; + } + if (set_mss(td, fd)) { + close(fd); + return 1; + } + if (td->o.filename) { if (!is_udp(o) || !fio_netio_is_multicast(td->o.filename)) { log_err("fio: hostname not valid for non-multicast inbound network IO\n");