xref: /netbsd-src/sys/rump/net/lib/libvirtif/if_virt.c (revision c7c727fae85036860d5bb848f2730ff419e2b060)
1 /*	$NetBSD: if_virt.c,v 1.31 2013/04/30 00:03:54 pooka Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 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 __KERNEL_RCSID(0, "$NetBSD: if_virt.c,v 1.31 2013/04/30 00:03:54 pooka Exp $");
30 
31 #include <sys/param.h>
32 #include <sys/condvar.h>
33 #include <sys/fcntl.h>
34 #include <sys/kernel.h>
35 #include <sys/kmem.h>
36 #include <sys/kthread.h>
37 #include <sys/mutex.h>
38 #include <sys/poll.h>
39 #include <sys/sockio.h>
40 #include <sys/socketvar.h>
41 #include <sys/cprng.h>
42 
43 #include <net/bpf.h>
44 #include <net/if.h>
45 #include <net/if_ether.h>
46 #include <net/if_tap.h>
47 
48 #include <netinet/in.h>
49 #include <netinet/in_var.h>
50 
51 #include <rump/rump.h>
52 
53 #include "rump_private.h"
54 #include "rump_net_private.h"
55 
56 #include "rumpcomp_user.h"
57 
58 /*
59  * Virtual interface for userspace purposes.  Uses tap(4) to
60  * interface with the kernel and just simply shovels data
61  * to/from /dev/tap.
62  */
63 
64 #define VIRTIF_BASE "virt"
65 
66 static int	virtif_init(struct ifnet *);
67 static int	virtif_ioctl(struct ifnet *, u_long, void *);
68 static void	virtif_start(struct ifnet *);
69 static void	virtif_stop(struct ifnet *, int);
70 
71 struct virtif_sc {
72 	struct ethercom sc_ec;
73 	struct virtif_user *sc_viu;
74 	bool sc_dying;
75 	struct lwp *sc_l_snd, *sc_l_rcv;
76 	kmutex_t sc_mtx;
77 	kcondvar_t sc_cv;
78 };
79 
80 static void virtif_receiver(void *);
81 static void virtif_sender(void *);
82 static int  virtif_clone(struct if_clone *, int);
83 static int  virtif_unclone(struct ifnet *);
84 
85 struct if_clone virtif_cloner =
86     IF_CLONE_INITIALIZER(VIRTIF_BASE, virtif_clone, virtif_unclone);
87 
88 int
89 rump_virtif_create(int num)
90 {
91 	struct virtif_sc *sc;
92 	struct virtif_user *viu;
93 	struct ifnet *ifp;
94 	uint8_t enaddr[ETHER_ADDR_LEN] = { 0xb2, 0x0a, 0x00, 0x0b, 0x0e, 0x01 };
95 	int error = 0;
96 
97 	if (num >= 0x100)
98 		return E2BIG;
99 
100 	if ((error = rumpcomp_virtif_create(num, &viu)) != 0)
101 		return error;
102 
103 	enaddr[2] = cprng_fast32() & 0xff;
104 	enaddr[5] = num;
105 
106 	sc = kmem_zalloc(sizeof(*sc), KM_SLEEP);
107 	sc->sc_dying = false;
108 	sc->sc_viu = viu;
109 
110 	mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_NONE);
111 	cv_init(&sc->sc_cv, "virtsnd");
112 	ifp = &sc->sc_ec.ec_if;
113 	sprintf(ifp->if_xname, "%s%d", VIRTIF_BASE, num);
114 	ifp->if_softc = sc;
115 
116 	if (rump_threads) {
117 		if ((error = kthread_create(PRI_NONE, KTHREAD_MUSTJOIN, NULL,
118 		    virtif_receiver, ifp, &sc->sc_l_rcv, "virtifr")) != 0)
119 			goto out;
120 
121 		if ((error = kthread_create(PRI_NONE,
122 		    KTHREAD_MUSTJOIN | KTHREAD_MPSAFE, NULL,
123 		    virtif_sender, ifp, &sc->sc_l_snd, "virtifs")) != 0)
124 			goto out;
125 	} else {
126 		printf("WARNING: threads not enabled, receive NOT working\n");
127 	}
128 
129 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
130 	ifp->if_init = virtif_init;
131 	ifp->if_ioctl = virtif_ioctl;
132 	ifp->if_start = virtif_start;
133 	ifp->if_stop = virtif_stop;
134 	IFQ_SET_READY(&ifp->if_snd);
135 
136 	if_attach(ifp);
137 	ether_ifattach(ifp, enaddr);
138 
139  out:
140 	if (error) {
141 		virtif_unclone(ifp);
142 	}
143 
144 	return error;
145 }
146 
147 static int
148 virtif_clone(struct if_clone *ifc, int unit)
149 {
150 
151 	return rump_virtif_create(unit);
152 }
153 
154 static int
155 virtif_unclone(struct ifnet *ifp)
156 {
157 	struct virtif_sc *sc = ifp->if_softc;
158 
159 	mutex_enter(&sc->sc_mtx);
160 	if (sc->sc_dying) {
161 		mutex_exit(&sc->sc_mtx);
162 		return EINPROGRESS;
163 	}
164 	sc->sc_dying = true;
165 	cv_broadcast(&sc->sc_cv);
166 	mutex_exit(&sc->sc_mtx);
167 
168 	rumpcomp_virtif_dying(sc->sc_viu);
169 
170 	virtif_stop(ifp, 1);
171 	if_down(ifp);
172 
173 	if (sc->sc_l_snd) {
174 		kthread_join(sc->sc_l_snd);
175 		sc->sc_l_snd = NULL;
176 	}
177 	if (sc->sc_l_rcv) {
178 		kthread_join(sc->sc_l_rcv);
179 		sc->sc_l_rcv = NULL;
180 	}
181 
182 	rumpcomp_virtif_destroy(sc->sc_viu);
183 
184 	mutex_destroy(&sc->sc_mtx);
185 	cv_destroy(&sc->sc_cv);
186 	kmem_free(sc, sizeof(*sc));
187 
188 	ether_ifdetach(ifp);
189 	if_detach(ifp);
190 
191 	return 0;
192 }
193 
194 static int
195 virtif_init(struct ifnet *ifp)
196 {
197 	struct virtif_sc *sc = ifp->if_softc;
198 
199 	ifp->if_flags |= IFF_RUNNING;
200 
201 	mutex_enter(&sc->sc_mtx);
202 	cv_broadcast(&sc->sc_cv);
203 	mutex_exit(&sc->sc_mtx);
204 
205 	return 0;
206 }
207 
208 static int
209 virtif_ioctl(struct ifnet *ifp, u_long cmd, void *data)
210 {
211 	int s, rv;
212 
213 	s = splnet();
214 	rv = ether_ioctl(ifp, cmd, data);
215 	if (rv == ENETRESET)
216 		rv = 0;
217 	splx(s);
218 
219 	return rv;
220 }
221 
222 static void
223 virtif_start(struct ifnet *ifp)
224 {
225 	struct virtif_sc *sc = ifp->if_softc;
226 
227 	mutex_enter(&sc->sc_mtx);
228 	ifp->if_flags |= IFF_OACTIVE;
229 	cv_broadcast(&sc->sc_cv);
230 	mutex_exit(&sc->sc_mtx);
231 }
232 
233 static void
234 virtif_stop(struct ifnet *ifp, int disable)
235 {
236 	struct virtif_sc *sc = ifp->if_softc;
237 
238 	ifp->if_flags &= ~IFF_RUNNING;
239 
240 	mutex_enter(&sc->sc_mtx);
241 	cv_broadcast(&sc->sc_cv);
242 	mutex_exit(&sc->sc_mtx);
243 }
244 
245 #define POLLTIMO_MS 1
246 static void
247 virtif_receiver(void *arg)
248 {
249 	struct ifnet *ifp = arg;
250 	struct virtif_sc *sc = ifp->if_softc;
251 	struct mbuf *m;
252 	size_t plen = ETHER_MAX_LEN_JUMBO+1;
253 	size_t n;
254 	int error;
255 
256 	for (;;) {
257 		m = m_gethdr(M_WAIT, MT_DATA);
258 		MEXTMALLOC(m, plen, M_WAIT);
259 
260  again:
261 		if (sc->sc_dying) {
262 			m_freem(m);
263 			break;
264 		}
265 
266 		error = rumpcomp_virtif_recv(sc->sc_viu,
267 		    mtod(m, void *), plen, &n);
268 		if (error) {
269 			printf("%s: read hypercall failed %d. host if down?\n",
270 			    ifp->if_xname, error);
271 			mutex_enter(&sc->sc_mtx);
272 			/* could check if need go, done soon anyway */
273 			cv_timedwait(&sc->sc_cv, &sc->sc_mtx, hz);
274 			mutex_exit(&sc->sc_mtx);
275 			goto again;
276 		}
277 
278 		/* tap sometimes returns EOF.  don't sweat it and plow on */
279 		if (__predict_false(n == 0))
280 			goto again;
281 
282 		/* discard if we're not up */
283 		if ((ifp->if_flags & IFF_RUNNING) == 0)
284 			goto again;
285 
286 		m->m_len = m->m_pkthdr.len = n;
287 		m->m_pkthdr.rcvif = ifp;
288 		bpf_mtap(ifp, m);
289 		ether_input(ifp, m);
290 	}
291 
292 	kthread_exit(0);
293 }
294 
295 /* lazy bum stetson-harrison magic value */
296 #define LB_SH 32
297 static void
298 virtif_sender(void *arg)
299 {
300 	struct ifnet *ifp = arg;
301 	struct virtif_sc *sc = ifp->if_softc;
302 	struct mbuf *m, *m0;
303 	struct iovec io[LB_SH];
304 	int i;
305 
306 	mutex_enter(&sc->sc_mtx);
307 	KERNEL_LOCK(1, NULL);
308 	while (!sc->sc_dying) {
309 		if (!(ifp->if_flags & IFF_RUNNING)) {
310 			cv_wait(&sc->sc_cv, &sc->sc_mtx);
311 			continue;
312 		}
313 		IF_DEQUEUE(&ifp->if_snd, m0);
314 		if (!m0) {
315 			ifp->if_flags &= ~IFF_OACTIVE;
316 			cv_wait(&sc->sc_cv, &sc->sc_mtx);
317 			continue;
318 		}
319 		mutex_exit(&sc->sc_mtx);
320 
321 		m = m0;
322 		for (i = 0; i < LB_SH && m; i++) {
323 			io[i].iov_base = mtod(m, void *);
324 			io[i].iov_len = m->m_len;
325 			m = m->m_next;
326 		}
327 		if (i == LB_SH)
328 			panic("lazy bum");
329 		bpf_mtap(ifp, m0);
330 
331 		rumpcomp_virtif_send(sc->sc_viu, io, i);
332 
333 		m_freem(m0);
334 		mutex_enter(&sc->sc_mtx);
335 	}
336 	KERNEL_UNLOCK_LAST(curlwp);
337 
338 	mutex_exit(&sc->sc_mtx);
339 
340 	kthread_exit(0);
341 }
342 
343 /*
344  * dummyif is a nada-interface.
345  * As it requires nothing external, it can be used for testing
346  * interface configuration.
347  */
348 static int	dummyif_init(struct ifnet *);
349 static void	dummyif_start(struct ifnet *);
350 
351 void
352 rump_dummyif_create()
353 {
354 	struct ifnet *ifp;
355 	struct ethercom *ec;
356 	uint8_t enaddr[ETHER_ADDR_LEN] = { 0xb2, 0x0a, 0x00, 0x0b, 0x0e, 0x01 };
357 
358 	enaddr[2] = cprng_fast32() & 0xff;
359 	enaddr[5] = cprng_fast32() & 0xff;
360 
361 	ec = kmem_zalloc(sizeof(*ec), KM_SLEEP);
362 
363 	ifp = &ec->ec_if;
364 	strlcpy(ifp->if_xname, "dummy0", sizeof(ifp->if_xname));
365 	ifp->if_softc = ifp;
366 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
367 	ifp->if_init = dummyif_init;
368 	ifp->if_ioctl = virtif_ioctl;
369 	ifp->if_start = dummyif_start;
370 
371 	if_attach(ifp);
372 	ether_ifattach(ifp, enaddr);
373 }
374 
375 static int
376 dummyif_init(struct ifnet *ifp)
377 {
378 
379 	ifp->if_flags |= IFF_RUNNING;
380 	return 0;
381 }
382 
383 static void
384 dummyif_start(struct ifnet *ifp)
385 {
386 
387 }
388