if_virt.c revision 1.47 1 /* $NetBSD: if_virt.c,v 1.47 2014/04/02 19:44:15 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.47 2014/04/02 19:44:15 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 }
314
315 ifp->if_flags &= ~IFF_OACTIVE;
316 }
317
318 static void
319 virtif_stop(struct ifnet *ifp, int disable)
320 {
321
322 /* XXX: VIFHYPER_STOP() */
323
324 ifp->if_flags &= ~IFF_RUNNING;
325 }
326
327 void
328 VIF_DELIVERPKT(struct virtif_sc *sc, struct iovec *iov, size_t iovlen)
329 {
330 struct ifnet *ifp = &sc->sc_ec.ec_if;
331 struct ether_header *eth;
332 struct mbuf *m;
333 size_t i;
334 int off, olen;
335 bool passup;
336 const int align
337 = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
338
339 if ((ifp->if_flags & IFF_RUNNING) == 0)
340 return;
341
342 m = m_gethdr(M_NOWAIT, MT_DATA);
343 if (m == NULL)
344 return; /* drop packet */
345 m->m_len = m->m_pkthdr.len = 0;
346
347 for (i = 0, off = align; i < iovlen; i++) {
348 olen = m->m_pkthdr.len;
349 m_copyback(m, off, iov[i].iov_len, iov[i].iov_base);
350 off += iov[i].iov_len;
351 if (olen + off != m->m_pkthdr.len) {
352 aprint_verbose_ifnet(ifp, "m_copyback failed\n");
353 m_freem(m);
354 return;
355 }
356 }
357 m->m_data += align;
358 m->m_pkthdr.len -= align;
359 m->m_len -= align;
360
361 eth = mtod(m, struct ether_header *);
362 if (memcmp(eth->ether_dhost, CLLADDR(ifp->if_sadl),
363 ETHER_ADDR_LEN) == 0) {
364 passup = true;
365 } else if (ETHER_IS_MULTICAST(eth->ether_dhost)) {
366 passup = true;
367 } else if (ifp->if_flags & IFF_PROMISC) {
368 m->m_flags |= M_PROMISC;
369 passup = true;
370 } else {
371 passup = false;
372 }
373
374 if (passup) {
375 m->m_pkthdr.rcvif = ifp;
376 KERNEL_LOCK(1, NULL);
377 bpf_mtap(ifp, m);
378 ifp->if_input(ifp, m);
379 KERNEL_UNLOCK_LAST(NULL);
380 } else {
381 m_freem(m);
382 }
383 m = NULL;
384 }
385
386 MODULE(MODULE_CLASS_DRIVER, if_virt, NULL);
387
388 static int
389 if_virt_modcmd(modcmd_t cmd, void *opaque)
390 {
391 int error = 0;
392
393 switch (cmd) {
394 case MODULE_CMD_INIT:
395 if_clone_attach(&VIF_CLONER);
396 break;
397 case MODULE_CMD_FINI:
398 /*
399 * not sure if interfaces are refcounted
400 * and properly protected
401 */
402 #if 0
403 if_clone_detach(&VIF_CLONER);
404 #else
405 error = ENOTTY;
406 #endif
407 break;
408 default:
409 error = ENOTTY;
410 }
411 return error;
412 }
413