1122592Ssam/* $FreeBSD$ */ 2122592Ssam/* $NetBSD: kttcp.c,v 1.3 2002/07/03 19:36:52 thorpej Exp $ */ 3122592Ssam 4122592Ssam/* 5122592Ssam * Copyright (c) 2002 Wasabi Systems, Inc. 6122592Ssam * All rights reserved. 7122592Ssam * 8122592Ssam * Written by Frank van der Linden and Jason R. Thorpe for 9122592Ssam * Wasabi Systems, Inc. 10122592Ssam * 11122592Ssam * Redistribution and use in source and binary forms, with or without 12122592Ssam * modification, are permitted provided that the following conditions 13122592Ssam * are met: 14122592Ssam * 1. Redistributions of source code must retain the above copyright 15122592Ssam * notice, this list of conditions and the following disclaimer. 16122592Ssam * 2. Redistributions in binary form must reproduce the above copyright 17122592Ssam * notice, this list of conditions and the following disclaimer in the 18122592Ssam * documentation and/or other materials provided with the distribution. 19122592Ssam * 3. All advertising materials mentioning features or use of this software 20122592Ssam * must display the following acknowledgement: 21122592Ssam * This product includes software developed for the NetBSD Project by 22122592Ssam * Wasabi Systems, Inc. 23122592Ssam * 4. The name of Wasabi Systems, Inc. may not be used to endorse 24122592Ssam * or promote products derived from this software without specific prior 25122592Ssam * written permission. 26122592Ssam * 27122592Ssam * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 28122592Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29122592Ssam * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30122592Ssam * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 31122592Ssam * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32122592Ssam * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33122592Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34122592Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35122592Ssam * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36122592Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37122592Ssam * POSSIBILITY OF SUCH DAMAGE. 38122592Ssam */ 39122592Ssam 40122592Ssam/* 41122592Ssam * kttcp.c -- 42122592Ssam * 43122592Ssam * This module provides kernel support for testing network 44122592Ssam * throughput from the perspective of the kernel. It is 45122592Ssam * similar in spirit to the classic ttcp network benchmark 46122592Ssam * program, the main difference being that with kttcp, the 47122592Ssam * kernel is the source and sink of the data. 48122592Ssam * 49122592Ssam * Testing like this is useful for a few reasons: 50122592Ssam * 51122592Ssam * 1. This allows us to know what kind of performance we can 52122592Ssam * expect from network applications that run in the kernel 53122592Ssam * space, such as the NFS server or the NFS client. These 54122592Ssam * applications don't have to move the data to/from userspace, 55122592Ssam * and so benchmark programs which run in userspace don't 56122592Ssam * give us an accurate model. 57122592Ssam * 58122592Ssam * 2. Since data received is just thrown away, the receiver 59122592Ssam * is very fast. This can provide better exercise for the 60122592Ssam * sender at the other end. 61122592Ssam * 62122592Ssam * 3. Since the NetBSD kernel currently uses a run-to-completion 63122592Ssam * scheduling model, kttcp provides a benchmark model where 64122592Ssam * preemption of the benchmark program is not an issue. 65122592Ssam */ 66122592Ssam 67122592Ssam#include <sys/param.h> 68122592Ssam#include <sys/systm.h> 69122592Ssam#include <sys/malloc.h> 70122592Ssam#include <sys/mbuf.h> 71122592Ssam#include <sys/sysctl.h> 72122592Ssam#include <sys/file.h> 73122592Ssam#include <sys/filedesc.h> 74122592Ssam#include <sys/errno.h> 75122592Ssam#include <sys/uio.h> 76122592Ssam#include <sys/conf.h> 77122592Ssam#include <sys/kernel.h> 78122592Ssam#include <sys/fcntl.h> 79122592Ssam#include <sys/protosw.h> 80122592Ssam#include <sys/socketvar.h> 81122592Ssam#include <sys/socket.h> 82122592Ssam#include <sys/mbuf.h> 83122592Ssam#include <sys/resourcevar.h> 84122592Ssam#include <sys/proc.h> 85138822Sgallatin#include <sys/module.h> 86122592Ssam 87122629Ssam#include "kttcpio.h" 88122592Ssam 89122592Ssam#ifndef timersub 90122592Ssam#define timersub(tvp, uvp, vvp) \ 91122592Ssam do { \ 92122592Ssam (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ 93122592Ssam (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ 94122592Ssam if ((vvp)->tv_usec < 0) { \ 95122592Ssam (vvp)->tv_sec--; \ 96122592Ssam (vvp)->tv_usec += 1000000; \ 97122592Ssam } \ 98122592Ssam } while (0) 99122592Ssam#endif 100122592Ssam 101122592Ssamstatic int kttcp_send(struct thread *p, struct kttcp_io_args *); 102122592Ssamstatic int kttcp_recv(struct thread *p, struct kttcp_io_args *); 103122592Ssam 104122592Ssamstatic d_open_t kttcpopen; 105122592Ssamstatic d_ioctl_t kttcpioctl; 106122592Ssam 107122592Ssamstatic struct cdevsw kttcp_cdevsw = { 108122592Ssam .d_open = kttcpopen, 109122592Ssam .d_ioctl = kttcpioctl, 110122592Ssam .d_name = "kttcp", 111122592Ssam .d_maj = MAJOR_AUTO, 112138822Sgallatin .d_version = D_VERSION, 113122592Ssam}; 114122592Ssam 115122592Ssamstatic int 116138822Sgallatinkttcpopen(struct cdev *dev, int flag, int mode, struct thread *td) 117122592Ssam{ 118122592Ssam /* Always succeeds. */ 119122592Ssam return (0); 120122592Ssam} 121122592Ssam 122122592Ssamstatic int 123138822Sgallatinkttcpioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 124122592Ssam{ 125122592Ssam int error; 126122592Ssam 127122592Ssam if ((flag & FWRITE) == 0) 128122592Ssam return EPERM; 129122592Ssam 130122592Ssam switch (cmd) { 131122592Ssam case KTTCP_IO_SEND: 132122592Ssam error = kttcp_send(td, (struct kttcp_io_args *) data); 133122592Ssam break; 134122592Ssam 135122592Ssam case KTTCP_IO_RECV: 136122592Ssam error = kttcp_recv(td, (struct kttcp_io_args *) data); 137122592Ssam break; 138122592Ssam 139122592Ssam default: 140122592Ssam return EINVAL; 141122592Ssam } 142122592Ssam 143122592Ssam return error; 144122592Ssam} 145122592Ssam 146138822Sgallatinstatic int nbyte = 65536; 147138822Sgallatin 148122592Ssamstatic int 149122592Ssamkttcp_send(struct thread *td, struct kttcp_io_args *kio) 150122592Ssam{ 151122592Ssam struct file *fp; 152122592Ssam int error; 153122592Ssam struct timeval t0, t1; 154122592Ssam unsigned long long len = 0; 155138822Sgallatin struct uio auio; 156138822Sgallatin struct iovec aiov; 157122592Ssam 158138822Sgallatin bzero(&aiov, sizeof(aiov)); 159138822Sgallatin bzero(&auio, sizeof(auio)); 160138822Sgallatin auio.uio_iov = &aiov; 161138822Sgallatin auio.uio_segflg = UIO_NOCOPY; 162122592Ssam 163122592Ssam error = fget(td, kio->kio_socket, &fp); 164122592Ssam if (error != 0) 165122592Ssam return error; 166138822Sgallatin 167122592Ssam if ((fp->f_flag & FWRITE) == 0) { 168122592Ssam fdrop(fp, td); 169122592Ssam return EBADF; 170122592Ssam } 171122592Ssam if (fp->f_type == DTYPE_SOCKET) { 172122592Ssam len = kio->kio_totalsize; 173122592Ssam microtime(&t0); 174122592Ssam do { 175138822Sgallatin nbyte = MIN(len, (unsigned long long)nbyte); 176138822Sgallatin aiov.iov_len = nbyte; 177138822Sgallatin auio.uio_resid = nbyte; 178138822Sgallatin auio.uio_offset = 0; 179138822Sgallatin error = sosend((struct socket *)fp->f_data, NULL, 180138822Sgallatin &auio, NULL, NULL, 0, td); 181138822Sgallatin len -= auio.uio_offset; 182138822Sgallatin } while (error == 0 && len != 0); 183122592Ssam microtime(&t1); 184122592Ssam } else 185122592Ssam error = EFTYPE; 186122592Ssam fdrop(fp, td); 187122592Ssam if (error != 0) 188122592Ssam return error; 189122592Ssam timersub(&t1, &t0, &kio->kio_elapsed); 190122592Ssam 191122592Ssam kio->kio_bytesdone = kio->kio_totalsize - len; 192122592Ssam 193122592Ssam return 0; 194122592Ssam} 195122592Ssam 196122592Ssamstatic int 197122592Ssamkttcp_recv(struct thread *td, struct kttcp_io_args *kio) 198122592Ssam{ 199122592Ssam struct file *fp; 200122592Ssam int error; 201122592Ssam struct timeval t0, t1; 202122592Ssam unsigned long long len = 0; 203138822Sgallatin struct uio auio; 204138822Sgallatin struct iovec aiov; 205122592Ssam 206138822Sgallatin bzero(&aiov, sizeof(aiov)); 207138822Sgallatin bzero(&auio, sizeof(auio)); 208138822Sgallatin auio.uio_iov = &aiov; 209138822Sgallatin auio.uio_segflg = UIO_NOCOPY; 210122592Ssam 211122592Ssam error = fget(td, kio->kio_socket, &fp); 212122592Ssam if (error != 0) 213122592Ssam return error; 214138822Sgallatin 215122592Ssam if ((fp->f_flag & FWRITE) == 0) { 216122592Ssam fdrop(fp, td); 217122592Ssam return EBADF; 218122592Ssam } 219122592Ssam if (fp->f_type == DTYPE_SOCKET) { 220122592Ssam len = kio->kio_totalsize; 221122592Ssam microtime(&t0); 222122592Ssam do { 223138822Sgallatin nbyte = MIN(len, (unsigned long long)nbyte); 224138822Sgallatin aiov.iov_len = nbyte; 225138822Sgallatin auio.uio_resid = nbyte; 226138822Sgallatin auio.uio_offset = 0; 227138822Sgallatin error = soreceive((struct socket *)fp->f_data, 228138822Sgallatin NULL, &auio, NULL, NULL, NULL); 229138822Sgallatin len -= auio.uio_offset; 230138822Sgallatin } while (error == 0 && len > 0 && auio.uio_offset != 0); 231122592Ssam microtime(&t1); 232122592Ssam if (error == EPIPE) 233122592Ssam error = 0; 234122592Ssam } else 235122592Ssam error = EFTYPE; 236122592Ssam fdrop(fp, td); 237122592Ssam if (error != 0) 238122592Ssam return error; 239122592Ssam timersub(&t1, &t0, &kio->kio_elapsed); 240122592Ssam 241122592Ssam kio->kio_bytesdone = kio->kio_totalsize - len; 242122592Ssam 243122592Ssam return 0; 244122592Ssam} 245122592Ssam 246138822Sgallatinstatic struct cdev *kttcp_dev; 247122592Ssam 248122592Ssam/* 249122592Ssam * Initialization code, both for static and dynamic loading. 250122592Ssam */ 251122592Ssamstatic int 252122592Ssamkttcpdev_modevent(module_t mod, int type, void *unused) 253122592Ssam{ 254122592Ssam switch (type) { 255122592Ssam case MOD_LOAD: 256122592Ssam kttcp_dev = make_dev(&kttcp_cdevsw, 0, 257122592Ssam UID_ROOT, GID_WHEEL, 0666, 258122592Ssam "kttcp"); 259122592Ssam return 0; 260122592Ssam case MOD_UNLOAD: 261122592Ssam /*XXX disallow if active sessions */ 262122592Ssam destroy_dev(kttcp_dev); 263122592Ssam return 0; 264122592Ssam } 265122592Ssam return EINVAL; 266122592Ssam} 267122592Ssam 268122592Ssamstatic moduledata_t kttcpdev_mod = { 269122592Ssam "kttcpdev", 270122592Ssam kttcpdev_modevent, 271241394Skevlo 0 272122592Ssam}; 273122592SsamMODULE_VERSION(kttcpdev, 1); 274122592SsamDECLARE_MODULE(kttcpdev, kttcpdev_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 275