xref: /freebsd/tools/tools/kttcp/sys/kttcp.c (revision 61e21613)
1 /*	$NetBSD: kttcp.c,v 1.3 2002/07/03 19:36:52 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 2002 Wasabi Systems, Inc.
5  * All rights reserved.
6  *
7  * Written by Frank van der Linden and Jason R. Thorpe for
8  * Wasabi Systems, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed for the NetBSD Project by
21  *	Wasabi Systems, Inc.
22  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
23  *    or promote products derived from this software without specific prior
24  *    written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * kttcp.c --
41  *
42  *	This module provides kernel support for testing network
43  *	throughput from the perspective of the kernel.  It is
44  *	similar in spirit to the classic ttcp network benchmark
45  *	program, the main difference being that with kttcp, the
46  *	kernel is the source and sink of the data.
47  *
48  *	Testing like this is useful for a few reasons:
49  *
50  *	1. This allows us to know what kind of performance we can
51  *	   expect from network applications that run in the kernel
52  *	   space, such as the NFS server or the NFS client.  These
53  *	   applications don't have to move the data to/from userspace,
54  *	   and so benchmark programs which run in userspace don't
55  *	   give us an accurate model.
56  *
57  *	2. Since data received is just thrown away, the receiver
58  *	   is very fast.  This can provide better exercise for the
59  *	   sender at the other end.
60  *
61  *	3. Since the NetBSD kernel currently uses a run-to-completion
62  *	   scheduling model, kttcp provides a benchmark model where
63  *	   preemption of the benchmark program is not an issue.
64  */
65 
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/malloc.h>
69 #include <sys/mbuf.h>
70 #include <sys/sysctl.h>
71 #include <sys/file.h>
72 #include <sys/filedesc.h>
73 #include <sys/errno.h>
74 #include <sys/uio.h>
75 #include <sys/conf.h>
76 #include <sys/kernel.h>
77 #include <sys/fcntl.h>
78 #include <sys/protosw.h>
79 #include <sys/socketvar.h>
80 #include <sys/socket.h>
81 #include <sys/mbuf.h>
82 #include <sys/resourcevar.h>
83 #include <sys/proc.h>
84 #include <sys/module.h>
85 
86 #include "kttcpio.h"
87 
88 #ifndef timersub
89 #define timersub(tvp, uvp, vvp)						\
90 	do {								\
91 		(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;		\
92 		(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;	\
93 		if ((vvp)->tv_usec < 0) {				\
94 			(vvp)->tv_sec--;				\
95 			(vvp)->tv_usec += 1000000;			\
96 		}							\
97 	} while (0)
98 #endif
99 
100 static int kttcp_send(struct thread *p, struct kttcp_io_args *);
101 static int kttcp_recv(struct thread *p, struct kttcp_io_args *);
102 
103 static d_open_t		kttcpopen;
104 static d_ioctl_t	kttcpioctl;
105 
106 static struct cdevsw kttcp_cdevsw = {
107 	.d_open =	kttcpopen,
108 	.d_ioctl =	kttcpioctl,
109 	.d_name =	"kttcp",
110 	.d_maj =	MAJOR_AUTO,
111 	.d_version =	D_VERSION,
112 };
113 
114 static int
115 kttcpopen(struct cdev *dev, int flag, int mode, struct thread *td)
116 {
117 	/* Always succeeds. */
118 	return (0);
119 }
120 
121 static int
122 kttcpioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
123 {
124 	int error;
125 
126 	if ((flag & FWRITE) == 0)
127 		return EPERM;
128 
129 	switch (cmd) {
130 	case KTTCP_IO_SEND:
131 		error = kttcp_send(td, (struct kttcp_io_args *) data);
132 		break;
133 
134 	case KTTCP_IO_RECV:
135 		error = kttcp_recv(td, (struct kttcp_io_args *) data);
136 		break;
137 
138 	default:
139 		return EINVAL;
140 	}
141 
142 	return error;
143 }
144 
145 static int nbyte = 65536;
146 
147 static int
148 kttcp_send(struct thread *td, struct kttcp_io_args *kio)
149 {
150 	struct file *fp;
151 	int error;
152 	struct timeval t0, t1;
153 	unsigned long long len = 0;
154 	struct uio auio;
155 	struct iovec aiov;
156 
157 	bzero(&aiov, sizeof(aiov));
158 	bzero(&auio, sizeof(auio));
159 	auio.uio_iov = &aiov;
160 	auio.uio_segflg = UIO_NOCOPY;
161 
162 	error = fget(td, kio->kio_socket, &fp);
163 	if (error != 0)
164 		return error;
165 
166 	if ((fp->f_flag & FWRITE) == 0) {
167 		fdrop(fp, td);
168 		return EBADF;
169 	}
170 	if (fp->f_type == DTYPE_SOCKET) {
171 		len = kio->kio_totalsize;
172 		microtime(&t0);
173 		do {
174 			nbyte =  MIN(len, (unsigned long long)nbyte);
175 			aiov.iov_len = nbyte;
176 			auio.uio_resid = nbyte;
177 			auio.uio_offset = 0;
178 			error = sosend((struct socket *)fp->f_data, NULL,
179 				       &auio, NULL, NULL, 0, td);
180 			len -= auio.uio_offset;
181 		} while (error == 0 && len != 0);
182 		microtime(&t1);
183 	} else
184 		error = EFTYPE;
185 	fdrop(fp, td);
186 	if (error != 0)
187 		return error;
188 	timersub(&t1, &t0, &kio->kio_elapsed);
189 
190 	kio->kio_bytesdone = kio->kio_totalsize - len;
191 
192 	return 0;
193 }
194 
195 static int
196 kttcp_recv(struct thread *td, struct kttcp_io_args *kio)
197 {
198 	struct file *fp;
199 	int error;
200 	struct timeval t0, t1;
201 	unsigned long long len = 0;
202 	struct uio auio;
203 	struct iovec aiov;
204 
205 	bzero(&aiov, sizeof(aiov));
206 	bzero(&auio, sizeof(auio));
207 	auio.uio_iov = &aiov;
208 	auio.uio_segflg = UIO_NOCOPY;
209 
210 	error = fget(td, kio->kio_socket, &fp);
211 	if (error != 0)
212 		return error;
213 
214 	if ((fp->f_flag & FWRITE) == 0) {
215 		fdrop(fp, td);
216 		return EBADF;
217 	}
218 	if (fp->f_type == DTYPE_SOCKET) {
219 		len = kio->kio_totalsize;
220 		microtime(&t0);
221 		do {
222 			nbyte =  MIN(len, (unsigned long long)nbyte);
223 			aiov.iov_len = nbyte;
224 			auio.uio_resid = nbyte;
225 			auio.uio_offset = 0;
226 			error = soreceive((struct socket *)fp->f_data,
227 					  NULL, &auio, NULL, NULL, NULL);
228 			len -= auio.uio_offset;
229 		} while (error == 0 && len > 0 && auio.uio_offset != 0);
230 		microtime(&t1);
231 		if (error == EPIPE)
232 			error = 0;
233 	} else
234 		error = EFTYPE;
235 	fdrop(fp, td);
236 	if (error != 0)
237 		return error;
238 	timersub(&t1, &t0, &kio->kio_elapsed);
239 
240 	kio->kio_bytesdone = kio->kio_totalsize - len;
241 
242 	return 0;
243 }
244 
245 static struct cdev *kttcp_dev;
246 
247 /*
248  * Initialization code, both for static and dynamic loading.
249  */
250 static int
251 kttcpdev_modevent(module_t mod, int type, void *unused)
252 {
253 	switch (type) {
254 	case MOD_LOAD:
255 		kttcp_dev = make_dev(&kttcp_cdevsw, 0,
256 				      UID_ROOT, GID_WHEEL, 0666,
257 				      "kttcp");
258 		return 0;
259 	case MOD_UNLOAD:
260 		/*XXX disallow if active sessions */
261 		destroy_dev(kttcp_dev);
262 		return 0;
263 	}
264 	return EINVAL;
265 }
266 
267 static moduledata_t kttcpdev_mod = {
268 	"kttcpdev",
269 	kttcpdev_modevent,
270 	0
271 };
272 MODULE_VERSION(kttcpdev, 1);
273 DECLARE_MODULE(kttcpdev, kttcpdev_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
274