xref: /netbsd-src/sys/rump/net/lib/libvirtif/if_virt.c (revision aad9773e38ed2370a628a6416e098f9008fc10a7)
1 /*	$NetBSD: if_virt.c,v 1.49 2014/11/06 23:25:16 pooka Exp $	*/
2 
3 /*
4  * Copyright (c) 2008, 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 __KERNEL_RCSID(0, "$NetBSD: if_virt.c,v 1.49 2014/11/06 23:25:16 pooka Exp $");
30 
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/kmem.h>
34 #include <sys/cprng.h>
35 #include <sys/module.h>
36 
37 #include <net/bpf.h>
38 #include <net/if.h>
39 #include <net/if_dl.h>
40 #include <net/if_ether.h>
41 
42 #include <netinet/in.h>
43 #include <netinet/in_var.h>
44 
45 #include "if_virt.h"
46 #include "virtif_user.h"
47 
48 /*
49  * Virtual interface.  Uses hypercalls to shovel packets back
50  * and forth.  The exact method for shoveling depends on the
51  * hypercall implementation.
52  */
53 
54 static int	virtif_init(struct ifnet *);
55 static int	virtif_ioctl(struct ifnet *, u_long, void *);
56 static void	virtif_start(struct ifnet *);
57 static void	virtif_stop(struct ifnet *, int);
58 
59 struct virtif_sc {
60 	struct ethercom sc_ec;
61 	struct virtif_user *sc_viu;
62 
63 	int sc_num;
64 	char *sc_linkstr;
65 };
66 
67 static int  virtif_clone(struct if_clone *, int);
68 static int  virtif_unclone(struct ifnet *);
69 
70 struct if_clone VIF_CLONER =
71     IF_CLONE_INITIALIZER(VIF_NAME, virtif_clone, virtif_unclone);
72 
73 static int
74 virtif_create(struct ifnet *ifp)
75 {
76 	uint8_t enaddr[ETHER_ADDR_LEN] = { 0xb2, 0x0a, 0x00, 0x0b, 0x0e, 0x01 };
77 	char enaddrstr[3*ETHER_ADDR_LEN];
78 	struct virtif_sc *sc = ifp->if_softc;
79 	int error;
80 
81 	if (sc->sc_viu)
82 		panic("%s: already created", ifp->if_xname);
83 
84 	enaddr[2] = cprng_fast32() & 0xff;
85 	enaddr[5] = sc->sc_num & 0xff;
86 
87 	if ((error = VIFHYPER_CREATE(sc->sc_linkstr,
88 	    sc, enaddr, &sc->sc_viu)) != 0) {
89 		printf("VIFHYPER_CREATE failed: %d\n", error);
90 		return error;
91 	}
92 
93 	ether_ifattach(ifp, enaddr);
94 	ether_snprintf(enaddrstr, sizeof(enaddrstr), enaddr);
95 	aprint_normal_ifnet(ifp, "Ethernet address %s\n", enaddrstr);
96 
97 	IFQ_SET_READY(&ifp->if_snd);
98 
99 	return 0;
100 }
101 
102 static int
103 virtif_clone(struct if_clone *ifc, int num)
104 {
105 	struct virtif_sc *sc;
106 	struct ifnet *ifp;
107 	int error = 0;
108 
109 	sc = kmem_zalloc(sizeof(*sc), KM_SLEEP);
110 	sc->sc_num = num;
111 	ifp = &sc->sc_ec.ec_if;
112 
113 	if_initname(ifp, VIF_NAME, num);
114 	ifp->if_softc = sc;
115 
116 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
117 	ifp->if_init = virtif_init;
118 	ifp->if_ioctl = virtif_ioctl;
119 	ifp->if_start = virtif_start;
120 	ifp->if_stop = virtif_stop;
121 	ifp->if_mtu = ETHERMTU;
122 	ifp->if_dlt = DLT_EN10MB;
123 
124 	if_attach(ifp);
125 
126 #ifndef RUMP_VIF_LINKSTR
127 	/*
128 	 * if the underlying interface does not expect linkstr, we can
129 	 * create everything now.  Otherwise, we need to wait for
130 	 * SIOCSLINKSTR.
131 	 */
132 #define LINKSTRNUMLEN 16
133 	sc->sc_linkstr = kmem_alloc(LINKSTRNUMLEN, KM_SLEEP);
134 	snprintf(sc->sc_linkstr, LINKSTRNUMLEN, "%d", sc->sc_num);
135 #undef LINKSTRNUMLEN
136 	error = virtif_create(ifp);
137 	if (error) {
138 		if_detach(ifp);
139 		kmem_free(sc, sizeof(*sc));
140 		ifp->if_softc = NULL;
141 	}
142 #endif /* !RUMP_VIF_LINKSTR */
143 
144 	return error;
145 }
146 
147 static int
148 virtif_unclone(struct ifnet *ifp)
149 {
150 	struct virtif_sc *sc = ifp->if_softc;
151 	int rv;
152 
153 	if (ifp->if_flags & IFF_UP)
154 		return EBUSY;
155 
156 	if ((rv = VIFHYPER_DYING(sc->sc_viu)) != 0)
157 		return rv;
158 
159 	virtif_stop(ifp, 1);
160 	if_down(ifp);
161 
162 	VIFHYPER_DESTROY(sc->sc_viu);
163 
164 	kmem_free(sc, sizeof(*sc));
165 
166 	ether_ifdetach(ifp);
167 	if_detach(ifp);
168 
169 	return 0;
170 }
171 
172 static int
173 virtif_init(struct ifnet *ifp)
174 {
175 	struct virtif_sc *sc = ifp->if_softc;
176 
177 	if (sc->sc_viu == NULL)
178 		return ENXIO;
179 
180 	ifp->if_flags |= IFF_RUNNING;
181 	return 0;
182 }
183 
184 static int
185 virtif_ioctl(struct ifnet *ifp, u_long cmd, void *data)
186 {
187 	struct virtif_sc *sc = ifp->if_softc;
188 	int rv;
189 
190 	switch (cmd) {
191 #ifdef RUMP_VIF_LINKSTR
192 	struct ifdrv *ifd;
193 	size_t linkstrlen;
194 
195 #ifndef RUMP_VIF_LINKSTRMAX
196 #define RUMP_VIF_LINKSTRMAX 4096
197 #endif
198 
199 	case SIOCGLINKSTR:
200 		ifd = data;
201 
202 		if (!sc->sc_linkstr) {
203 			rv = ENOENT;
204 			break;
205 		}
206 		linkstrlen = strlen(sc->sc_linkstr)+1;
207 
208 		if (ifd->ifd_cmd == IFLINKSTR_QUERYLEN) {
209 			ifd->ifd_len = linkstrlen;
210 			rv = 0;
211 			break;
212 		}
213 		if (ifd->ifd_cmd != 0) {
214 			rv = ENOTTY;
215 			break;
216 		}
217 
218 		rv = copyoutstr(sc->sc_linkstr,
219 		    ifd->ifd_data, MIN(ifd->ifd_len,linkstrlen), NULL);
220 		break;
221 	case SIOCSLINKSTR:
222 		if (ifp->if_flags & IFF_UP) {
223 			rv = EBUSY;
224 			break;
225 		}
226 
227 		ifd = data;
228 
229 		if (ifd->ifd_cmd == IFLINKSTR_UNSET) {
230 			panic("unset linkstr not implemented");
231 		} else if (ifd->ifd_cmd != 0) {
232 			rv = ENOTTY;
233 			break;
234 		} else if (sc->sc_linkstr) {
235 			rv = EBUSY;
236 			break;
237 		}
238 
239 		if (ifd->ifd_len > RUMP_VIF_LINKSTRMAX) {
240 			rv = E2BIG;
241 			break;
242 		} else if (ifd->ifd_len < 1) {
243 			rv = EINVAL;
244 			break;
245 		}
246 
247 
248 		sc->sc_linkstr = kmem_alloc(ifd->ifd_len, KM_SLEEP);
249 		rv = copyinstr(ifd->ifd_data, sc->sc_linkstr,
250 		    ifd->ifd_len, NULL);
251 		if (rv) {
252 			kmem_free(sc->sc_linkstr, ifd->ifd_len);
253 			break;
254 		}
255 
256 		rv = virtif_create(ifp);
257 		if (rv) {
258 			kmem_free(sc->sc_linkstr, ifd->ifd_len);
259 		}
260 		break;
261 #endif /* RUMP_VIF_LINKSTR */
262 	default:
263 		if (!sc->sc_linkstr)
264 			rv = ENXIO;
265 		else
266 			rv = ether_ioctl(ifp, cmd, data);
267 		if (rv == ENETRESET)
268 			rv = 0;
269 		break;
270 	}
271 
272 	return rv;
273 }
274 
275 /*
276  * Output packets in-context until outgoing queue is empty.
277  * Leave responsibility of choosing whether or not to drop the
278  * kernel lock to VIPHYPER_SEND().
279  */
280 #define LB_SH 32
281 static void
282 virtif_start(struct ifnet *ifp)
283 {
284 	struct virtif_sc *sc = ifp->if_softc;
285 	struct mbuf *m, *m0;
286 	struct iovec io[LB_SH];
287 	int i;
288 
289 	ifp->if_flags |= IFF_OACTIVE;
290 
291 	for (;;) {
292 		IF_DEQUEUE(&ifp->if_snd, m0);
293 		if (!m0) {
294 			break;
295 		}
296 
297 		m = m0;
298 		for (i = 0; i < LB_SH && m; ) {
299 			if (m->m_len) {
300 				io[i].iov_base = mtod(m, void *);
301 				io[i].iov_len = m->m_len;
302 				i++;
303 			}
304 			m = m->m_next;
305 		}
306 		if (i == LB_SH && m)
307 			panic("lazy bum");
308 		bpf_mtap(ifp, m0);
309 
310 		VIFHYPER_SEND(sc->sc_viu, io, i);
311 
312 		m_freem(m0);
313 		ifp->if_opackets++;
314 	}
315 
316 	ifp->if_flags &= ~IFF_OACTIVE;
317 }
318 
319 static void
320 virtif_stop(struct ifnet *ifp, int disable)
321 {
322 
323 	/* XXX: VIFHYPER_STOP() */
324 
325 	ifp->if_flags &= ~IFF_RUNNING;
326 }
327 
328 void
329 VIF_DELIVERPKT(struct virtif_sc *sc, struct iovec *iov, size_t iovlen)
330 {
331 	struct ifnet *ifp = &sc->sc_ec.ec_if;
332 	struct ether_header *eth;
333 	struct mbuf *m;
334 	size_t i;
335 	int off, olen;
336 	bool passup;
337 	const int align
338 	    = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
339 
340 	if ((ifp->if_flags & IFF_RUNNING) == 0)
341 		return;
342 
343 	m = m_gethdr(M_NOWAIT, MT_DATA);
344 	if (m == NULL)
345 		return; /* drop packet */
346 	m->m_len = m->m_pkthdr.len = 0;
347 
348 	for (i = 0, off = align; i < iovlen; i++) {
349 		olen = m->m_pkthdr.len;
350 		m_copyback(m, off, iov[i].iov_len, iov[i].iov_base);
351 		off += iov[i].iov_len;
352 		if (olen + off != m->m_pkthdr.len) {
353 			aprint_verbose_ifnet(ifp, "m_copyback failed\n");
354 			m_freem(m);
355 			return;
356 		}
357 	}
358 	m->m_data += align;
359 	m->m_pkthdr.len -= align;
360 	m->m_len -= align;
361 
362 	eth = mtod(m, struct ether_header *);
363 	if (memcmp(eth->ether_dhost, CLLADDR(ifp->if_sadl),
364 	    ETHER_ADDR_LEN) == 0) {
365 		passup = true;
366 	} else if (ETHER_IS_MULTICAST(eth->ether_dhost)) {
367 		passup = true;
368 	} else if (ifp->if_flags & IFF_PROMISC) {
369 		m->m_flags |= M_PROMISC;
370 		passup = true;
371 	} else {
372 		passup = false;
373 	}
374 
375 	if (passup) {
376 		ifp->if_ipackets++;
377 		m->m_pkthdr.rcvif = ifp;
378 		KERNEL_LOCK(1, NULL);
379 		bpf_mtap(ifp, m);
380 		ifp->if_input(ifp, m);
381 		KERNEL_UNLOCK_LAST(NULL);
382 	} else {
383 		m_freem(m);
384 	}
385 	m = NULL;
386 }
387 
388 /*
389  * The following ensures that no two modules using if_virt end up with
390  * the same module name.  MODULE() and modcmd wrapped in ... bad mojo.
391  */
392 #define VIF_MOJO(x) MODULE(MODULE_CLASS_DRIVER,x,NULL);
393 #define VIF_MODULE() VIF_MOJO(VIF_BASENAME(if_virt_,VIRTIF_BASE))
394 #define VIF_MODCMD VIF_BASENAME3(if_virt_,VIRTIF_BASE,_modcmd)
395 VIF_MODULE();
396 static int
397 VIF_MODCMD(modcmd_t cmd, void *opaque)
398 {
399 	int error = 0;
400 
401 	switch (cmd) {
402 	case MODULE_CMD_INIT:
403 		if_clone_attach(&VIF_CLONER);
404 		break;
405 	case MODULE_CMD_FINI:
406 		/*
407 		 * not sure if interfaces are refcounted
408 		 * and properly protected
409 		 */
410 #if 0
411 		if_clone_detach(&VIF_CLONER);
412 #else
413 		error = ENOTTY;
414 #endif
415 		break;
416 	default:
417 		error = ENOTTY;
418 	}
419 	return error;
420 }
421