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