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