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