virtif_user.c revision 1.3.6.2 1 1.3.6.2 yamt /* $NetBSD: virtif_user.c,v 1.3.6.2 2014/05/22 11:41:17 yamt Exp $ */
2 1.3.6.2 yamt
3 1.3.6.2 yamt /*
4 1.3.6.2 yamt * Copyright (c) 2013 Antti Kantee. All Rights Reserved.
5 1.3.6.2 yamt *
6 1.3.6.2 yamt * Redistribution and use in source and binary forms, with or without
7 1.3.6.2 yamt * modification, are permitted provided that the following conditions
8 1.3.6.2 yamt * are met:
9 1.3.6.2 yamt * 1. Redistributions of source code must retain the above copyright
10 1.3.6.2 yamt * notice, this list of conditions and the following disclaimer.
11 1.3.6.2 yamt * 2. Redistributions in binary form must reproduce the above copyright
12 1.3.6.2 yamt * notice, this list of conditions and the following disclaimer in the
13 1.3.6.2 yamt * documentation and/or other materials provided with the distribution.
14 1.3.6.2 yamt *
15 1.3.6.2 yamt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 1.3.6.2 yamt * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 1.3.6.2 yamt * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 1.3.6.2 yamt * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 1.3.6.2 yamt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 1.3.6.2 yamt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 1.3.6.2 yamt * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 1.3.6.2 yamt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 1.3.6.2 yamt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 1.3.6.2 yamt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 1.3.6.2 yamt * SUCH DAMAGE.
26 1.3.6.2 yamt */
27 1.3.6.2 yamt
28 1.3.6.2 yamt #ifndef _KERNEL
29 1.3.6.2 yamt #include <sys/types.h>
30 1.3.6.2 yamt #include <sys/ioctl.h>
31 1.3.6.2 yamt #include <sys/uio.h>
32 1.3.6.2 yamt
33 1.3.6.2 yamt #include <assert.h>
34 1.3.6.2 yamt #include <errno.h>
35 1.3.6.2 yamt #include <fcntl.h>
36 1.3.6.2 yamt #include <inttypes.h>
37 1.3.6.2 yamt #include <poll.h>
38 1.3.6.2 yamt #include <pthread.h>
39 1.3.6.2 yamt #include <stdio.h>
40 1.3.6.2 yamt #include <stdlib.h>
41 1.3.6.2 yamt #include <string.h>
42 1.3.6.2 yamt #include <unistd.h>
43 1.3.6.2 yamt
44 1.3.6.2 yamt #ifdef __linux__
45 1.3.6.2 yamt #include <net/if.h>
46 1.3.6.2 yamt #include <linux/if_tun.h>
47 1.3.6.2 yamt #endif
48 1.3.6.2 yamt
49 1.3.6.2 yamt #include <rump/rumpuser_component.h>
50 1.3.6.2 yamt
51 1.3.6.2 yamt #include "if_virt.h"
52 1.3.6.2 yamt #include "virtif_user.h"
53 1.3.6.2 yamt
54 1.3.6.2 yamt #if VIFHYPER_REVISION != 20140313
55 1.3.6.2 yamt #error VIFHYPER_REVISION mismatch
56 1.3.6.2 yamt #endif
57 1.3.6.2 yamt
58 1.3.6.2 yamt struct virtif_user {
59 1.3.6.2 yamt struct virtif_sc *viu_virtifsc;
60 1.3.6.2 yamt int viu_devnum;
61 1.3.6.2 yamt
62 1.3.6.2 yamt int viu_fd;
63 1.3.6.2 yamt int viu_pipe[2];
64 1.3.6.2 yamt pthread_t viu_rcvthr;
65 1.3.6.2 yamt
66 1.3.6.2 yamt int viu_dying;
67 1.3.6.2 yamt
68 1.3.6.2 yamt char viu_rcvbuf[9018]; /* jumbo frame max len */
69 1.3.6.2 yamt };
70 1.3.6.2 yamt
71 1.3.6.2 yamt static int
72 1.3.6.2 yamt opentapdev(int devnum)
73 1.3.6.2 yamt {
74 1.3.6.2 yamt int fd = -1;
75 1.3.6.2 yamt
76 1.3.6.2 yamt #if defined(__NetBSD__) || defined(__DragonFly__)
77 1.3.6.2 yamt char tapdev[64];
78 1.3.6.2 yamt
79 1.3.6.2 yamt snprintf(tapdev, sizeof(tapdev), "/dev/tap%d", devnum);
80 1.3.6.2 yamt fd = open(tapdev, O_RDWR);
81 1.3.6.2 yamt if (fd == -1) {
82 1.3.6.2 yamt fprintf(stderr, "rumpcomp_virtif_create: can't open %s: "
83 1.3.6.2 yamt "%s\n", tapdev, strerror(errno));
84 1.3.6.2 yamt }
85 1.3.6.2 yamt
86 1.3.6.2 yamt #elif defined(__linux__)
87 1.3.6.2 yamt struct ifreq ifr;
88 1.3.6.2 yamt char devname[16];
89 1.3.6.2 yamt
90 1.3.6.2 yamt fd = open("/dev/net/tun", O_RDWR);
91 1.3.6.2 yamt if (fd == -1) {
92 1.3.6.2 yamt fprintf(stderr, "rumpcomp_virtif_create: can't open %s: "
93 1.3.6.2 yamt "%s\n", "/dev/net/tun", strerror(errno));
94 1.3.6.2 yamt return -1;
95 1.3.6.2 yamt }
96 1.3.6.2 yamt
97 1.3.6.2 yamt snprintf(devname, sizeof(devname), "tun%d", devnum);
98 1.3.6.2 yamt memset(&ifr, 0, sizeof(ifr));
99 1.3.6.2 yamt ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
100 1.3.6.2 yamt strncpy(ifr.ifr_name, devname, sizeof(ifr.ifr_name)-1);
101 1.3.6.2 yamt
102 1.3.6.2 yamt if (ioctl(fd, TUNSETIFF, &ifr) == -1) {
103 1.3.6.2 yamt close(fd);
104 1.3.6.2 yamt fd = -1;
105 1.3.6.2 yamt }
106 1.3.6.2 yamt
107 1.3.6.2 yamt #else
108 1.3.6.2 yamt fprintf(stderr, "virtif not supported on this platform\n");
109 1.3.6.2 yamt #endif
110 1.3.6.2 yamt
111 1.3.6.2 yamt return fd;
112 1.3.6.2 yamt }
113 1.3.6.2 yamt
114 1.3.6.2 yamt static void
115 1.3.6.2 yamt closetapdev(struct virtif_user *viu)
116 1.3.6.2 yamt {
117 1.3.6.2 yamt
118 1.3.6.2 yamt close(viu->viu_fd);
119 1.3.6.2 yamt }
120 1.3.6.2 yamt
121 1.3.6.2 yamt static void *
122 1.3.6.2 yamt rcvthread(void *aaargh)
123 1.3.6.2 yamt {
124 1.3.6.2 yamt struct virtif_user *viu = aaargh;
125 1.3.6.2 yamt struct pollfd pfd[2];
126 1.3.6.2 yamt struct iovec iov;
127 1.3.6.2 yamt ssize_t nn = 0;
128 1.3.6.2 yamt int prv;
129 1.3.6.2 yamt
130 1.3.6.2 yamt rumpuser_component_kthread();
131 1.3.6.2 yamt
132 1.3.6.2 yamt pfd[0].fd = viu->viu_fd;
133 1.3.6.2 yamt pfd[0].events = POLLIN;
134 1.3.6.2 yamt pfd[1].fd = viu->viu_pipe[0];
135 1.3.6.2 yamt pfd[1].events = POLLIN;
136 1.3.6.2 yamt
137 1.3.6.2 yamt while (!viu->viu_dying) {
138 1.3.6.2 yamt prv = poll(pfd, 2, -1);
139 1.3.6.2 yamt if (prv == 0)
140 1.3.6.2 yamt continue;
141 1.3.6.2 yamt if (prv == -1) {
142 1.3.6.2 yamt /* XXX */
143 1.3.6.2 yamt fprintf(stderr, "virt%d: poll error: %d\n",
144 1.3.6.2 yamt viu->viu_devnum, errno);
145 1.3.6.2 yamt sleep(1);
146 1.3.6.2 yamt continue;
147 1.3.6.2 yamt }
148 1.3.6.2 yamt if (pfd[1].revents & POLLIN)
149 1.3.6.2 yamt continue;
150 1.3.6.2 yamt
151 1.3.6.2 yamt nn = read(viu->viu_fd,
152 1.3.6.2 yamt viu->viu_rcvbuf, sizeof(viu->viu_rcvbuf));
153 1.3.6.2 yamt if (nn == -1 && errno == EAGAIN)
154 1.3.6.2 yamt continue;
155 1.3.6.2 yamt
156 1.3.6.2 yamt if (nn < 1) {
157 1.3.6.2 yamt /* XXX */
158 1.3.6.2 yamt fprintf(stderr, "virt%d: receive failed\n",
159 1.3.6.2 yamt viu->viu_devnum);
160 1.3.6.2 yamt sleep(1);
161 1.3.6.2 yamt continue;
162 1.3.6.2 yamt }
163 1.3.6.2 yamt iov.iov_base = viu->viu_rcvbuf;
164 1.3.6.2 yamt iov.iov_len = nn;
165 1.3.6.2 yamt
166 1.3.6.2 yamt rumpuser_component_schedule(NULL);
167 1.3.6.2 yamt VIF_DELIVERPKT(viu->viu_virtifsc, &iov, 1);
168 1.3.6.2 yamt rumpuser_component_unschedule();
169 1.3.6.2 yamt }
170 1.3.6.2 yamt
171 1.3.6.2 yamt assert(viu->viu_dying);
172 1.3.6.2 yamt
173 1.3.6.2 yamt rumpuser_component_kthread_release();
174 1.3.6.2 yamt return NULL;
175 1.3.6.2 yamt }
176 1.3.6.2 yamt
177 1.3.6.2 yamt int
178 1.3.6.2 yamt VIFHYPER_CREATE(const char *devstr, struct virtif_sc *vif_sc, uint8_t *enaddr,
179 1.3.6.2 yamt struct virtif_user **viup)
180 1.3.6.2 yamt {
181 1.3.6.2 yamt struct virtif_user *viu = NULL;
182 1.3.6.2 yamt void *cookie;
183 1.3.6.2 yamt int devnum;
184 1.3.6.2 yamt int rv;
185 1.3.6.2 yamt
186 1.3.6.2 yamt cookie = rumpuser_component_unschedule();
187 1.3.6.2 yamt
188 1.3.6.2 yamt /*
189 1.3.6.2 yamt * Since this interface doesn't do LINKSTR, we know devstr to be
190 1.3.6.2 yamt * well-formatted.
191 1.3.6.2 yamt */
192 1.3.6.2 yamt devnum = atoi(devstr);
193 1.3.6.2 yamt
194 1.3.6.2 yamt viu = calloc(1, sizeof(*viu));
195 1.3.6.2 yamt if (viu == NULL) {
196 1.3.6.2 yamt rv = errno;
197 1.3.6.2 yamt goto oerr1;
198 1.3.6.2 yamt }
199 1.3.6.2 yamt viu->viu_virtifsc = vif_sc;
200 1.3.6.2 yamt
201 1.3.6.2 yamt viu->viu_fd = opentapdev(devnum);
202 1.3.6.2 yamt if (viu->viu_fd == -1) {
203 1.3.6.2 yamt rv = errno;
204 1.3.6.2 yamt goto oerr2;
205 1.3.6.2 yamt }
206 1.3.6.2 yamt viu->viu_devnum = devnum;
207 1.3.6.2 yamt
208 1.3.6.2 yamt if (pipe(viu->viu_pipe) == -1) {
209 1.3.6.2 yamt rv = errno;
210 1.3.6.2 yamt goto oerr3;
211 1.3.6.2 yamt }
212 1.3.6.2 yamt
213 1.3.6.2 yamt if ((rv = pthread_create(&viu->viu_rcvthr, NULL, rcvthread, viu)) != 0)
214 1.3.6.2 yamt goto oerr4;
215 1.3.6.2 yamt
216 1.3.6.2 yamt rumpuser_component_schedule(cookie);
217 1.3.6.2 yamt *viup = viu;
218 1.3.6.2 yamt return 0;
219 1.3.6.2 yamt
220 1.3.6.2 yamt oerr4:
221 1.3.6.2 yamt close(viu->viu_pipe[0]);
222 1.3.6.2 yamt close(viu->viu_pipe[1]);
223 1.3.6.2 yamt oerr3:
224 1.3.6.2 yamt closetapdev(viu);
225 1.3.6.2 yamt oerr2:
226 1.3.6.2 yamt free(viu);
227 1.3.6.2 yamt oerr1:
228 1.3.6.2 yamt rumpuser_component_schedule(cookie);
229 1.3.6.2 yamt return rumpuser_component_errtrans(rv);
230 1.3.6.2 yamt }
231 1.3.6.2 yamt
232 1.3.6.2 yamt void
233 1.3.6.2 yamt VIFHYPER_SEND(struct virtif_user *viu,
234 1.3.6.2 yamt struct iovec *iov, size_t iovlen)
235 1.3.6.2 yamt {
236 1.3.6.2 yamt void *cookie = rumpuser_component_unschedule();
237 1.3.6.2 yamt ssize_t idontcare __attribute__((__unused__));
238 1.3.6.2 yamt
239 1.3.6.2 yamt /*
240 1.3.6.2 yamt * no need to check for return value; packets may be dropped
241 1.3.6.2 yamt *
242 1.3.6.2 yamt * ... sorry, I spoke too soon. We need to check it because
243 1.3.6.2 yamt * apparently gcc reinvented const poisoning and it's very
244 1.3.6.2 yamt * hard to say "thanks, I know I'm not using the result,
245 1.3.6.2 yamt * but please STFU and let's get on with something useful".
246 1.3.6.2 yamt * So let's trick gcc into letting us share the compiler
247 1.3.6.2 yamt * experience.
248 1.3.6.2 yamt */
249 1.3.6.2 yamt idontcare = writev(viu->viu_fd, iov, iovlen);
250 1.3.6.2 yamt
251 1.3.6.2 yamt rumpuser_component_schedule(cookie);
252 1.3.6.2 yamt }
253 1.3.6.2 yamt
254 1.3.6.2 yamt int
255 1.3.6.2 yamt VIFHYPER_DYING(struct virtif_user *viu)
256 1.3.6.2 yamt {
257 1.3.6.2 yamt void *cookie = rumpuser_component_unschedule();
258 1.3.6.2 yamt
259 1.3.6.2 yamt viu->viu_dying = 1;
260 1.3.6.2 yamt if (write(viu->viu_pipe[1],
261 1.3.6.2 yamt &viu->viu_dying, sizeof(viu->viu_dying)) == -1) {
262 1.3.6.2 yamt /*
263 1.3.6.2 yamt * this is here mostly to avoid a compiler warning
264 1.3.6.2 yamt * about ignoring the return value of write()
265 1.3.6.2 yamt */
266 1.3.6.2 yamt fprintf(stderr, "%s: failed to signal thread\n",
267 1.3.6.2 yamt VIF_STRING(VIFHYPER_DYING));
268 1.3.6.2 yamt }
269 1.3.6.2 yamt
270 1.3.6.2 yamt rumpuser_component_schedule(cookie);
271 1.3.6.2 yamt
272 1.3.6.2 yamt return 0;
273 1.3.6.2 yamt }
274 1.3.6.2 yamt
275 1.3.6.2 yamt void
276 1.3.6.2 yamt VIFHYPER_DESTROY(struct virtif_user *viu)
277 1.3.6.2 yamt {
278 1.3.6.2 yamt void *cookie = rumpuser_component_unschedule();
279 1.3.6.2 yamt
280 1.3.6.2 yamt pthread_join(viu->viu_rcvthr, NULL);
281 1.3.6.2 yamt closetapdev(viu);
282 1.3.6.2 yamt close(viu->viu_pipe[0]);
283 1.3.6.2 yamt close(viu->viu_pipe[1]);
284 1.3.6.2 yamt free(viu);
285 1.3.6.2 yamt
286 1.3.6.2 yamt rumpuser_component_schedule(cookie);
287 1.3.6.2 yamt }
288 1.3.6.2 yamt #endif
289