if_virt.c revision 1.44 1 /* $NetBSD: if_virt.c,v 1.44 2014/03/13 21:11:12 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.44 2014/03/13 21:11:12 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 sprintf(ifp->if_xname, "%s%d", VIF_NAME, num);
113 ifp->if_softc = sc;
114
115 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
116 ifp->if_init = virtif_init;
117 ifp->if_ioctl = virtif_ioctl;
118 ifp->if_start = virtif_start;
119 ifp->if_stop = virtif_stop;
120 ifp->if_mtu = ETHERMTU;
121 ifp->if_dlt = DLT_EN10MB;
122
123 if_attach(ifp);
124
125 #ifndef RUMP_VIF_LINKSTR
126 /*
127 * if the underlying interface does not expect linkstr, we can
128 * create everything now. Otherwise, we need to wait for
129 * SIOCSLINKSTR.
130 */
131 #define LINKSTRNUMLEN 16
132 sc->sc_linkstr = kmem_alloc(LINKSTRNUMLEN, KM_SLEEP);
133 snprintf(sc->sc_linkstr, LINKSTRNUMLEN, "%d", sc->sc_num);
134 #undef LINKSTRNUMLEN
135 error = virtif_create(ifp);
136 if (error) {
137 if_detach(ifp);
138 kmem_free(sc, sizeof(*sc));
139 ifp->if_softc = NULL;
140 }
141 #endif /* !RUMP_VIF_LINKSTR */
142
143 return error;
144 }
145
146 static int
147 virtif_unclone(struct ifnet *ifp)
148 {
149 struct virtif_sc *sc = ifp->if_softc;
150 int rv;
151
152 if (ifp->if_flags & IFF_UP)
153 return EBUSY;
154
155 if ((rv = VIFHYPER_DYING(sc->sc_viu)) != 0)
156 return rv;
157
158 virtif_stop(ifp, 1);
159 if_down(ifp);
160
161 VIFHYPER_DESTROY(sc->sc_viu);
162
163 kmem_free(sc, sizeof(*sc));
164
165 ether_ifdetach(ifp);
166 if_detach(ifp);
167
168 return 0;
169 }
170
171 static int
172 virtif_init(struct ifnet *ifp)
173 {
174 struct virtif_sc *sc = ifp->if_softc;
175
176 if (sc->sc_viu == NULL)
177 return ENXIO;
178
179 ifp->if_flags |= IFF_RUNNING;
180 return 0;
181 }
182
183 static int
184 virtif_ioctl(struct ifnet *ifp, u_long cmd, void *data)
185 {
186 struct virtif_sc *sc = ifp->if_softc;
187 int rv;
188
189 switch (cmd) {
190 #ifdef RUMP_VIF_LINKSTR
191 struct ifdrv *ifd;
192 size_t linkstrlen;
193
194 #ifndef RUMP_VIF_LINKSTRMAX
195 #define RUMP_VIF_LINKSTRMAX 4096
196 #endif
197
198 case SIOCGLINKSTR:
199 ifd = data;
200
201 if (!sc->sc_linkstr) {
202 rv = ENOENT;
203 break;
204 }
205 linkstrlen = strlen(sc->sc_linkstr)+1;
206
207 if (ifd->ifd_cmd == IFLINKSTR_QUERYLEN) {
208 ifd->ifd_len = linkstrlen;
209 rv = 0;
210 break;
211 }
212 if (ifd->ifd_cmd != 0) {
213 rv = ENOTTY;
214 break;
215 }
216
217 rv = copyoutstr(sc->sc_linkstr,
218 ifd->ifd_data, MIN(ifd->ifd_len,linkstrlen), NULL);
219 break;
220 case SIOCSLINKSTR:
221 if (ifp->if_flags & IFF_UP) {
222 rv = EBUSY;
223 break;
224 }
225
226 ifd = data;
227
228 if (ifd->ifd_cmd == IFLINKSTR_UNSET) {
229 panic("unset linkstr not implemented");
230 } else if (ifd->ifd_cmd != 0) {
231 rv = ENOTTY;
232 break;
233 } else if (sc->sc_linkstr) {
234 rv = EBUSY;
235 break;
236 }
237
238 if (ifd->ifd_len > RUMP_VIF_LINKSTRMAX) {
239 rv = E2BIG;
240 break;
241 } else if (ifd->ifd_len < 1) {
242 rv = EINVAL;
243 break;
244 }
245
246
247 sc->sc_linkstr = kmem_alloc(ifd->ifd_len, KM_SLEEP);
248 rv = copyinstr(ifd->ifd_data, sc->sc_linkstr,
249 ifd->ifd_len, NULL);
250 if (rv) {
251 kmem_free(sc->sc_linkstr, ifd->ifd_len);
252 break;
253 }
254
255 rv = virtif_create(ifp);
256 if (rv) {
257 kmem_free(sc->sc_linkstr, ifd->ifd_len);
258 }
259 break;
260 #endif /* RUMP_VIF_LINKSTR */
261 default:
262 if (!sc->sc_linkstr)
263 rv = ENXIO;
264 else
265 rv = ether_ioctl(ifp, cmd, data);
266 if (rv == ENETRESET)
267 rv = 0;
268 break;
269 }
270
271 return rv;
272 }
273
274 /*
275 * Output packets in-context until outgoing queue is empty.
276 * Leave responsibility of choosing whether or not to drop the
277 * kernel lock to VIPHYPER_SEND().
278 */
279 #define LB_SH 32
280 static void
281 virtif_start(struct ifnet *ifp)
282 {
283 struct virtif_sc *sc = ifp->if_softc;
284 struct mbuf *m, *m0;
285 struct iovec io[LB_SH];
286 int i;
287
288 ifp->if_flags |= IFF_OACTIVE;
289
290 for (;;) {
291 IF_DEQUEUE(&ifp->if_snd, m0);
292 if (!m0) {
293 break;
294 }
295
296 m = m0;
297 for (i = 0; i < LB_SH && m; ) {
298 if (m->m_len) {
299 io[i].iov_base = mtod(m, void *);
300 io[i].iov_len = m->m_len;
301 i++;
302 }
303 m = m->m_next;
304 }
305 if (i == LB_SH && m)
306 panic("lazy bum");
307 bpf_mtap(ifp, m0);
308
309 VIFHYPER_SEND(sc->sc_viu, io, i);
310
311 m_freem(m0);
312 }
313
314 ifp->if_flags &= ~IFF_OACTIVE;
315 }
316
317 static void
318 virtif_stop(struct ifnet *ifp, int disable)
319 {
320
321 /* XXX: VIFHYPER_STOP() */
322
323 ifp->if_flags &= ~IFF_RUNNING;
324 }
325
326 void
327 VIF_DELIVERPKT(struct virtif_sc *sc, struct iovec *iov, size_t iovlen)
328 {
329 struct ifnet *ifp = &sc->sc_ec.ec_if;
330 struct ether_header *eth;
331 struct mbuf *m;
332 size_t i;
333 int off, olen;
334 bool passup;
335 const int align
336 = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
337
338 if ((ifp->if_flags & IFF_RUNNING) == 0)
339 return;
340
341 m = m_gethdr(M_NOWAIT, MT_DATA);
342 if (m == NULL)
343 return; /* drop packet */
344 m->m_len = m->m_pkthdr.len = 0;
345
346 for (i = 0, off = align; i < iovlen; i++) {
347 olen = m->m_pkthdr.len;
348 m_copyback(m, off, iov[i].iov_len, iov[i].iov_base);
349 off += iov[i].iov_len;
350 if (olen + off != m->m_pkthdr.len) {
351 aprint_verbose_ifnet(ifp, "m_copyback failed\n");
352 m_freem(m);
353 return;
354 }
355 }
356
357 m->m_data += align;
358 eth = mtod(m, struct ether_header *);
359 if (memcmp(eth->ether_dhost, CLLADDR(ifp->if_sadl),
360 ETHER_ADDR_LEN) == 0) {
361 passup = true;
362 } else if (ETHER_IS_MULTICAST(eth->ether_dhost)) {
363 passup = true;
364 } else if (ifp->if_flags & IFF_PROMISC) {
365 m->m_flags |= M_PROMISC;
366 passup = true;
367 } else {
368 passup = false;
369 }
370
371 if (passup) {
372 m->m_pkthdr.rcvif = ifp;
373 KERNEL_LOCK(1, NULL);
374 bpf_mtap(ifp, m);
375 ifp->if_input(ifp, m);
376 KERNEL_UNLOCK_LAST(NULL);
377 } else {
378 m_freem(m);
379 }
380 m = NULL;
381 }
382
383 MODULE(MODULE_CLASS_DRIVER, if_virt, NULL);
384
385 static int
386 if_virt_modcmd(modcmd_t cmd, void *opaque)
387 {
388 int error = 0;
389
390 switch (cmd) {
391 case MODULE_CMD_INIT:
392 if_clone_attach(&VIF_CLONER);
393 break;
394 case MODULE_CMD_FINI:
395 /*
396 * not sure if interfaces are refcounted
397 * and properly protected
398 */
399 #if 0
400 if_clone_detach(&VIF_CLONER);
401 #else
402 error = ENOTTY;
403 #endif
404 break;
405 default:
406 error = ENOTTY;
407 }
408 return error;
409 }
410