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