xref: /netbsd-src/sys/rump/net/lib/libvirtif/if_virt.c (revision a4ddc2c8fb9af816efe3b1c375a5530aef0e89e9)
1 /*	$NetBSD: if_virt.c,v 1.30 2013/03/15 11:30:23 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.30 2013/03/15 11:30:23 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 ((viu = rumpcomp_virtif_create(num)) == NULL)
101 		return ENXIO;
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 	ssize_t n;
254 
255 	for (;;) {
256 		m = m_gethdr(M_WAIT, MT_DATA);
257 		MEXTMALLOC(m, plen, M_WAIT);
258 
259  again:
260 		if (sc->sc_dying) {
261 			m_freem(m);
262 			break;
263 		}
264 
265 		n = rumpcomp_virtif_recv(sc->sc_viu, mtod(m, void *), plen);
266 		if (n < 0) {
267 			printf("%s: read hypercall failed. host if down?\n",
268 			    ifp->if_xname);
269 			mutex_enter(&sc->sc_mtx);
270 			/* could check if need go, done soon anyway */
271 			cv_timedwait(&sc->sc_cv, &sc->sc_mtx, hz);
272 			mutex_exit(&sc->sc_mtx);
273 			goto again;
274 		}
275 
276 		/* tap sometimes returns EOF.  don't sweat it and plow on */
277 		if (__predict_false(n == 0))
278 			goto again;
279 
280 		/* discard if we're not up */
281 		if ((ifp->if_flags & IFF_RUNNING) == 0)
282 			goto again;
283 
284 		m->m_len = m->m_pkthdr.len = n;
285 		m->m_pkthdr.rcvif = ifp;
286 		bpf_mtap(ifp, m);
287 		ether_input(ifp, m);
288 	}
289 
290 	kthread_exit(0);
291 }
292 
293 /* lazy bum stetson-harrison magic value */
294 #define LB_SH 32
295 static void
296 virtif_sender(void *arg)
297 {
298 	struct ifnet *ifp = arg;
299 	struct virtif_sc *sc = ifp->if_softc;
300 	struct mbuf *m, *m0;
301 	struct iovec io[LB_SH];
302 	int i;
303 
304 	mutex_enter(&sc->sc_mtx);
305 	KERNEL_LOCK(1, NULL);
306 	while (!sc->sc_dying) {
307 		if (!(ifp->if_flags & IFF_RUNNING)) {
308 			cv_wait(&sc->sc_cv, &sc->sc_mtx);
309 			continue;
310 		}
311 		IF_DEQUEUE(&ifp->if_snd, m0);
312 		if (!m0) {
313 			ifp->if_flags &= ~IFF_OACTIVE;
314 			cv_wait(&sc->sc_cv, &sc->sc_mtx);
315 			continue;
316 		}
317 		mutex_exit(&sc->sc_mtx);
318 
319 		m = m0;
320 		for (i = 0; i < LB_SH && m; i++) {
321 			io[i].iov_base = mtod(m, void *);
322 			io[i].iov_len = m->m_len;
323 			m = m->m_next;
324 		}
325 		if (i == LB_SH)
326 			panic("lazy bum");
327 		bpf_mtap(ifp, m0);
328 
329 		rumpcomp_virtif_send(sc->sc_viu, io, i);
330 
331 		m_freem(m0);
332 		mutex_enter(&sc->sc_mtx);
333 	}
334 	KERNEL_UNLOCK_LAST(curlwp);
335 
336 	mutex_exit(&sc->sc_mtx);
337 
338 	kthread_exit(0);
339 }
340 
341 /*
342  * dummyif is a nada-interface.
343  * As it requires nothing external, it can be used for testing
344  * interface configuration.
345  */
346 static int	dummyif_init(struct ifnet *);
347 static void	dummyif_start(struct ifnet *);
348 
349 void
350 rump_dummyif_create()
351 {
352 	struct ifnet *ifp;
353 	struct ethercom *ec;
354 	uint8_t enaddr[ETHER_ADDR_LEN] = { 0xb2, 0x0a, 0x00, 0x0b, 0x0e, 0x01 };
355 
356 	enaddr[2] = cprng_fast32() & 0xff;
357 	enaddr[5] = cprng_fast32() & 0xff;
358 
359 	ec = kmem_zalloc(sizeof(*ec), KM_SLEEP);
360 
361 	ifp = &ec->ec_if;
362 	strlcpy(ifp->if_xname, "dummy0", sizeof(ifp->if_xname));
363 	ifp->if_softc = ifp;
364 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
365 	ifp->if_init = dummyif_init;
366 	ifp->if_ioctl = virtif_ioctl;
367 	ifp->if_start = dummyif_start;
368 
369 	if_attach(ifp);
370 	ether_ifattach(ifp, enaddr);
371 }
372 
373 static int
374 dummyif_init(struct ifnet *ifp)
375 {
376 
377 	ifp->if_flags |= IFF_RUNNING;
378 	return 0;
379 }
380 
381 static void
382 dummyif_start(struct ifnet *ifp)
383 {
384 
385 }
386