1*076e3579Sriastradh /* $NetBSD: if_virt.c,v 1.59 2021/06/16 00:21:20 riastradh Exp $ */
261e869beSpooka
361e869beSpooka /*
46b612185Spooka * Copyright (c) 2008, 2013 Antti Kantee. All Rights Reserved.
561e869beSpooka *
661e869beSpooka * Redistribution and use in source and binary forms, with or without
761e869beSpooka * modification, are permitted provided that the following conditions
861e869beSpooka * are met:
961e869beSpooka * 1. Redistributions of source code must retain the above copyright
1061e869beSpooka * notice, this list of conditions and the following disclaimer.
1161e869beSpooka * 2. Redistributions in binary form must reproduce the above copyright
1261e869beSpooka * notice, this list of conditions and the following disclaimer in the
1361e869beSpooka * documentation and/or other materials provided with the distribution.
1461e869beSpooka *
1561e869beSpooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
1661e869beSpooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1761e869beSpooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1861e869beSpooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1961e869beSpooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2061e869beSpooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2161e869beSpooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2261e869beSpooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2361e869beSpooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2461e869beSpooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2561e869beSpooka * SUCH DAMAGE.
2661e869beSpooka */
2761e869beSpooka
28a768afd6Spooka #include <sys/cdefs.h>
29*076e3579Sriastradh __KERNEL_RCSID(0, "$NetBSD: if_virt.c,v 1.59 2021/06/16 00:21:20 riastradh Exp $");
30a768afd6Spooka
3161e869beSpooka #include <sys/param.h>
321ff4490aSpooka #include <sys/kernel.h>
3361e869beSpooka #include <sys/kmem.h>
343afd44cfStls #include <sys/cprng.h>
35bfdd7f7dSpooka #include <sys/module.h>
3661e869beSpooka
3729ca934bSpooka #include <net/bpf.h>
3861e869beSpooka #include <net/if.h>
39c40bbed4Spooka #include <net/if_dl.h>
4061e869beSpooka #include <net/if_ether.h>
4161e869beSpooka
4261e869beSpooka #include <netinet/in.h>
4361e869beSpooka #include <netinet/in_var.h>
4461e869beSpooka
45be1e0a38Spooka #include "if_virt.h"
46be1e2f2aSpooka #include "virtif_user.h"
4703390692Spooka
4861e869beSpooka /*
496b612185Spooka * Virtual interface. Uses hypercalls to shovel packets back
506b612185Spooka * and forth. The exact method for shoveling depends on the
516b612185Spooka * hypercall implementation.
5261e869beSpooka */
5361e869beSpooka
5461e869beSpooka static int virtif_init(struct ifnet *);
5561e869beSpooka static int virtif_ioctl(struct ifnet *, u_long, void *);
5661e869beSpooka static void virtif_start(struct ifnet *);
5761e869beSpooka static void virtif_stop(struct ifnet *, int);
5861e869beSpooka
5961e869beSpooka struct virtif_sc {
60cc8bfe6cSpooka struct ethercom sc_ec;
6103390692Spooka struct virtif_user *sc_viu;
62c40bbed4Spooka
63c40bbed4Spooka int sc_num;
64c40bbed4Spooka char *sc_linkstr;
6561e869beSpooka };
6661e869beSpooka
67a500a55cSpooka static int virtif_clone(struct if_clone *, int);
68a500a55cSpooka static int virtif_unclone(struct ifnet *);
6961e869beSpooka
70be1e0a38Spooka struct if_clone VIF_CLONER =
71be1e0a38Spooka IF_CLONE_INITIALIZER(VIF_NAME, virtif_clone, virtif_unclone);
7261e869beSpooka
73d45448faSpooka static int
virtif_create(struct ifnet * ifp)74c40bbed4Spooka virtif_create(struct ifnet *ifp)
75c40bbed4Spooka {
76c40bbed4Spooka uint8_t enaddr[ETHER_ADDR_LEN] = { 0xb2, 0x0a, 0x00, 0x0b, 0x0e, 0x01 };
77c40bbed4Spooka char enaddrstr[3*ETHER_ADDR_LEN];
78c40bbed4Spooka struct virtif_sc *sc = ifp->if_softc;
79c40bbed4Spooka int error;
80c40bbed4Spooka
81c40bbed4Spooka if (sc->sc_viu)
82c40bbed4Spooka panic("%s: already created", ifp->if_xname);
83c40bbed4Spooka
84c40bbed4Spooka enaddr[2] = cprng_fast32() & 0xff;
85c40bbed4Spooka enaddr[5] = sc->sc_num & 0xff;
86c40bbed4Spooka
87c40bbed4Spooka if ((error = VIFHYPER_CREATE(sc->sc_linkstr,
88c40bbed4Spooka sc, enaddr, &sc->sc_viu)) != 0) {
89c40bbed4Spooka printf("VIFHYPER_CREATE failed: %d\n", error);
90c40bbed4Spooka return error;
91c40bbed4Spooka }
92c40bbed4Spooka
93c40bbed4Spooka ether_ifattach(ifp, enaddr);
94c40bbed4Spooka ether_snprintf(enaddrstr, sizeof(enaddrstr), enaddr);
95c40bbed4Spooka aprint_normal_ifnet(ifp, "Ethernet address %s\n", enaddrstr);
96c40bbed4Spooka
97c40bbed4Spooka IFQ_SET_READY(&ifp->if_snd);
98c40bbed4Spooka
99c40bbed4Spooka return 0;
100c40bbed4Spooka }
101c40bbed4Spooka
102c40bbed4Spooka static int
virtif_clone(struct if_clone * ifc,int num)103d9c4c208Spooka virtif_clone(struct if_clone *ifc, int num)
10461e869beSpooka {
10561e869beSpooka struct virtif_sc *sc;
10661e869beSpooka struct ifnet *ifp;
10703390692Spooka int error = 0;
1081ff4490aSpooka
10961e869beSpooka sc = kmem_zalloc(sizeof(*sc), KM_SLEEP);
110c40bbed4Spooka sc->sc_num = num;
111cc8bfe6cSpooka ifp = &sc->sc_ec.ec_if;
112271d5dd1Spooka
113271d5dd1Spooka if_initname(ifp, VIF_NAME, num);
11461e869beSpooka ifp->if_softc = sc;
1151ff4490aSpooka
11661e869beSpooka ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
11761e869beSpooka ifp->if_init = virtif_init;
11861e869beSpooka ifp->if_ioctl = virtif_ioctl;
11961e869beSpooka ifp->if_start = virtif_start;
12061e869beSpooka ifp->if_stop = virtif_stop;
121c40bbed4Spooka ifp->if_mtu = ETHERMTU;
122c40bbed4Spooka ifp->if_dlt = DLT_EN10MB;
12361e869beSpooka
124*076e3579Sriastradh if_initialize(ifp);
1259c4cd063Sozaki-r if_register(ifp);
12661e869beSpooka
127c40bbed4Spooka #ifndef RUMP_VIF_LINKSTR
128c40bbed4Spooka /*
129c40bbed4Spooka * if the underlying interface does not expect linkstr, we can
130c40bbed4Spooka * create everything now. Otherwise, we need to wait for
131c40bbed4Spooka * SIOCSLINKSTR.
132c40bbed4Spooka */
133c40bbed4Spooka #define LINKSTRNUMLEN 16
134c40bbed4Spooka sc->sc_linkstr = kmem_alloc(LINKSTRNUMLEN, KM_SLEEP);
13535096a90Smsaitoh if (sc->sc_linkstr == NULL) {
13635096a90Smsaitoh error = ENOMEM;
137*076e3579Sriastradh goto fail;
13835096a90Smsaitoh }
139c40bbed4Spooka snprintf(sc->sc_linkstr, LINKSTRNUMLEN, "%d", sc->sc_num);
140c40bbed4Spooka error = virtif_create(ifp);
1411ff4490aSpooka if (error) {
142*076e3579Sriastradh fail:
143c40bbed4Spooka if_detach(ifp);
14435096a90Smsaitoh if (sc->sc_linkstr != NULL)
14535096a90Smsaitoh kmem_free(sc->sc_linkstr, LINKSTRNUMLEN);
1468afd0f4cSmsaitoh #undef LINKSTRNUMLEN
147c40bbed4Spooka kmem_free(sc, sizeof(*sc));
148c40bbed4Spooka ifp->if_softc = NULL;
1491ff4490aSpooka }
150c40bbed4Spooka #endif /* !RUMP_VIF_LINKSTR */
1511ff4490aSpooka
1521ff4490aSpooka return error;
15361e869beSpooka }
15461e869beSpooka
15561e869beSpooka static int
virtif_unclone(struct ifnet * ifp)156a500a55cSpooka virtif_unclone(struct ifnet *ifp)
157a500a55cSpooka {
1581ff4490aSpooka struct virtif_sc *sc = ifp->if_softc;
159c2849206Spooka int rv;
160a500a55cSpooka
161c40bbed4Spooka if (ifp->if_flags & IFF_UP)
162c40bbed4Spooka return EBUSY;
1631ff4490aSpooka
164c2849206Spooka if ((rv = VIFHYPER_DYING(sc->sc_viu)) != 0)
165c2849206Spooka return rv;
16603390692Spooka
1671ff4490aSpooka virtif_stop(ifp, 1);
1681ff4490aSpooka if_down(ifp);
1691ff4490aSpooka
170be1e0a38Spooka VIFHYPER_DESTROY(sc->sc_viu);
1711ff4490aSpooka
1721ff4490aSpooka kmem_free(sc, sizeof(*sc));
1731ff4490aSpooka
1741ff4490aSpooka ether_ifdetach(ifp);
1751ff4490aSpooka if_detach(ifp);
1761ff4490aSpooka
1771ff4490aSpooka return 0;
178a500a55cSpooka }
179a500a55cSpooka
180a500a55cSpooka static int
virtif_init(struct ifnet * ifp)18161e869beSpooka virtif_init(struct ifnet *ifp)
18261e869beSpooka {
1831ff4490aSpooka struct virtif_sc *sc = ifp->if_softc;
18461e869beSpooka
185c40bbed4Spooka if (sc->sc_viu == NULL)
186c40bbed4Spooka return ENXIO;
187c40bbed4Spooka
18861e869beSpooka ifp->if_flags |= IFF_RUNNING;
18961e869beSpooka return 0;
19061e869beSpooka }
19161e869beSpooka
19261e869beSpooka static int
virtif_ioctl(struct ifnet * ifp,u_long cmd,void * data)19361e869beSpooka virtif_ioctl(struct ifnet *ifp, u_long cmd, void *data)
19461e869beSpooka {
195c40bbed4Spooka struct virtif_sc *sc = ifp->if_softc;
196c40bbed4Spooka int rv;
19761e869beSpooka
198c40bbed4Spooka switch (cmd) {
199c40bbed4Spooka #ifdef RUMP_VIF_LINKSTR
200c40bbed4Spooka struct ifdrv *ifd;
201c40bbed4Spooka size_t linkstrlen;
202c40bbed4Spooka
203c40bbed4Spooka #ifndef RUMP_VIF_LINKSTRMAX
204c40bbed4Spooka #define RUMP_VIF_LINKSTRMAX 4096
205c40bbed4Spooka #endif
206c40bbed4Spooka
207c40bbed4Spooka case SIOCGLINKSTR:
208c40bbed4Spooka ifd = data;
209c40bbed4Spooka
210c40bbed4Spooka if (!sc->sc_linkstr) {
211c40bbed4Spooka rv = ENOENT;
212c40bbed4Spooka break;
213c40bbed4Spooka }
214c40bbed4Spooka linkstrlen = strlen(sc->sc_linkstr)+1;
215c40bbed4Spooka
216c40bbed4Spooka if (ifd->ifd_cmd == IFLINKSTR_QUERYLEN) {
217c40bbed4Spooka ifd->ifd_len = linkstrlen;
218c40bbed4Spooka rv = 0;
219c40bbed4Spooka break;
220c40bbed4Spooka }
221c40bbed4Spooka if (ifd->ifd_cmd != 0) {
222c40bbed4Spooka rv = ENOTTY;
223c40bbed4Spooka break;
224c40bbed4Spooka }
225c40bbed4Spooka
226c40bbed4Spooka rv = copyoutstr(sc->sc_linkstr,
227c40bbed4Spooka ifd->ifd_data, MIN(ifd->ifd_len,linkstrlen), NULL);
228c40bbed4Spooka break;
229c40bbed4Spooka case SIOCSLINKSTR:
230c40bbed4Spooka if (ifp->if_flags & IFF_UP) {
231c40bbed4Spooka rv = EBUSY;
232c40bbed4Spooka break;
233c40bbed4Spooka }
234c40bbed4Spooka
235c40bbed4Spooka ifd = data;
236c40bbed4Spooka
237c40bbed4Spooka if (ifd->ifd_cmd == IFLINKSTR_UNSET) {
238c40bbed4Spooka panic("unset linkstr not implemented");
239c40bbed4Spooka } else if (ifd->ifd_cmd != 0) {
240c40bbed4Spooka rv = ENOTTY;
241c40bbed4Spooka break;
242c40bbed4Spooka } else if (sc->sc_linkstr) {
243c40bbed4Spooka rv = EBUSY;
244c40bbed4Spooka break;
245c40bbed4Spooka }
246c40bbed4Spooka
247c40bbed4Spooka if (ifd->ifd_len > RUMP_VIF_LINKSTRMAX) {
248c40bbed4Spooka rv = E2BIG;
249c40bbed4Spooka break;
250c40bbed4Spooka } else if (ifd->ifd_len < 1) {
251c40bbed4Spooka rv = EINVAL;
252c40bbed4Spooka break;
253c40bbed4Spooka }
254c40bbed4Spooka
255c40bbed4Spooka
256c40bbed4Spooka sc->sc_linkstr = kmem_alloc(ifd->ifd_len, KM_SLEEP);
257c40bbed4Spooka rv = copyinstr(ifd->ifd_data, sc->sc_linkstr,
258c40bbed4Spooka ifd->ifd_len, NULL);
259c40bbed4Spooka if (rv) {
260c40bbed4Spooka kmem_free(sc->sc_linkstr, ifd->ifd_len);
261c40bbed4Spooka break;
262c40bbed4Spooka }
263c40bbed4Spooka
264c40bbed4Spooka rv = virtif_create(ifp);
265c40bbed4Spooka if (rv) {
266c40bbed4Spooka kmem_free(sc->sc_linkstr, ifd->ifd_len);
267c40bbed4Spooka }
268c40bbed4Spooka break;
269c40bbed4Spooka #endif /* RUMP_VIF_LINKSTR */
270c40bbed4Spooka default:
271c40bbed4Spooka if (!sc->sc_linkstr)
272c40bbed4Spooka rv = ENXIO;
273c40bbed4Spooka else
27461e869beSpooka rv = ether_ioctl(ifp, cmd, data);
2759c2d055fSpooka if (rv == ENETRESET)
2769c2d055fSpooka rv = 0;
277c40bbed4Spooka break;
278c40bbed4Spooka }
27961e869beSpooka
28061e869beSpooka return rv;
28161e869beSpooka }
28261e869beSpooka
283c40bbed4Spooka /*
284c40bbed4Spooka * Output packets in-context until outgoing queue is empty.
285c40bbed4Spooka * Leave responsibility of choosing whether or not to drop the
286c40bbed4Spooka * kernel lock to VIPHYPER_SEND().
287c40bbed4Spooka */
288c40bbed4Spooka #define LB_SH 32
28961e869beSpooka static void
virtif_start(struct ifnet * ifp)29061e869beSpooka virtif_start(struct ifnet *ifp)
29161e869beSpooka {
29261e869beSpooka struct virtif_sc *sc = ifp->if_softc;
29306dceb4dSpooka struct mbuf *m, *m0;
29403390692Spooka struct iovec io[LB_SH];
29503390692Spooka int i;
29606dceb4dSpooka
297c40bbed4Spooka ifp->if_flags |= IFF_OACTIVE;
298c40bbed4Spooka
299c40bbed4Spooka for (;;) {
3001ff4490aSpooka IF_DEQUEUE(&ifp->if_snd, m0);
3011ff4490aSpooka if (!m0) {
302c40bbed4Spooka break;
3031ff4490aSpooka }
30406dceb4dSpooka
30506dceb4dSpooka m = m0;
30630baf09aSpooka for (i = 0; i < LB_SH && m; ) {
30730baf09aSpooka if (m->m_len) {
30806dceb4dSpooka io[i].iov_base = mtod(m, void *);
30906dceb4dSpooka io[i].iov_len = m->m_len;
31030baf09aSpooka i++;
31130baf09aSpooka }
31206dceb4dSpooka m = m->m_next;
31306dceb4dSpooka }
31430baf09aSpooka if (i == LB_SH && m)
31506dceb4dSpooka panic("lazy bum");
3163cd62456Smsaitoh bpf_mtap(ifp, m0, BPF_D_OUT);
31706dceb4dSpooka
318be1e0a38Spooka VIFHYPER_SEND(sc->sc_viu, io, i);
3191ff4490aSpooka
3201ff4490aSpooka m_freem(m0);
321c85e2f36Sthorpej if_statinc(ifp, if_opackets);
3221ff4490aSpooka }
3231ff4490aSpooka
324c40bbed4Spooka ifp->if_flags &= ~IFF_OACTIVE;
325c40bbed4Spooka }
3261ff4490aSpooka
327c40bbed4Spooka static void
virtif_stop(struct ifnet * ifp,int disable)328c40bbed4Spooka virtif_stop(struct ifnet *ifp, int disable)
329c40bbed4Spooka {
330c40bbed4Spooka
331c40bbed4Spooka /* XXX: VIFHYPER_STOP() */
332c40bbed4Spooka
333c40bbed4Spooka ifp->if_flags &= ~IFF_RUNNING;
334c40bbed4Spooka }
335c40bbed4Spooka
336c40bbed4Spooka void
VIF_DELIVERPKT(struct virtif_sc * sc,struct iovec * iov,size_t iovlen)337c40bbed4Spooka VIF_DELIVERPKT(struct virtif_sc *sc, struct iovec *iov, size_t iovlen)
338c40bbed4Spooka {
339c40bbed4Spooka struct ifnet *ifp = &sc->sc_ec.ec_if;
340c40bbed4Spooka struct ether_header *eth;
341c40bbed4Spooka struct mbuf *m;
342c40bbed4Spooka size_t i;
343c40bbed4Spooka int off, olen;
344c40bbed4Spooka bool passup;
345c40bbed4Spooka const int align
346c40bbed4Spooka = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
347c40bbed4Spooka
348c40bbed4Spooka if ((ifp->if_flags & IFF_RUNNING) == 0)
349c40bbed4Spooka return;
350c40bbed4Spooka
351c40bbed4Spooka m = m_gethdr(M_NOWAIT, MT_DATA);
352c40bbed4Spooka if (m == NULL)
353c40bbed4Spooka return; /* drop packet */
354c40bbed4Spooka m->m_len = m->m_pkthdr.len = 0;
355c40bbed4Spooka
356c40bbed4Spooka for (i = 0, off = align; i < iovlen; i++) {
357c40bbed4Spooka olen = m->m_pkthdr.len;
358c40bbed4Spooka m_copyback(m, off, iov[i].iov_len, iov[i].iov_base);
359c40bbed4Spooka off += iov[i].iov_len;
360c40bbed4Spooka if (olen + off != m->m_pkthdr.len) {
361c40bbed4Spooka aprint_verbose_ifnet(ifp, "m_copyback failed\n");
362c40bbed4Spooka m_freem(m);
363c40bbed4Spooka return;
364c40bbed4Spooka }
365c40bbed4Spooka }
366c40bbed4Spooka m->m_data += align;
367c310bd10Spooka m->m_pkthdr.len -= align;
368c310bd10Spooka m->m_len -= align;
369c310bd10Spooka
370c40bbed4Spooka eth = mtod(m, struct ether_header *);
371c40bbed4Spooka if (memcmp(eth->ether_dhost, CLLADDR(ifp->if_sadl),
372c40bbed4Spooka ETHER_ADDR_LEN) == 0) {
373c40bbed4Spooka passup = true;
374c40bbed4Spooka } else if (ETHER_IS_MULTICAST(eth->ether_dhost)) {
375c40bbed4Spooka passup = true;
376c40bbed4Spooka } else if (ifp->if_flags & IFF_PROMISC) {
377c40bbed4Spooka m->m_flags |= M_PROMISC;
378c40bbed4Spooka passup = true;
379c40bbed4Spooka } else {
380c40bbed4Spooka passup = false;
381c40bbed4Spooka }
382c40bbed4Spooka
383c40bbed4Spooka if (passup) {
384e1135cd9Sozaki-r int bound;
385d938d837Sozaki-r m_set_rcvif(m, ifp);
386c40bbed4Spooka KERNEL_LOCK(1, NULL);
387220ff4e7Sozaki-r /* Prevent LWP migrations between CPUs for psref(9) */
388e1135cd9Sozaki-r bound = curlwp_bind();
3899c4cd063Sozaki-r if_input(ifp, m);
390e1135cd9Sozaki-r curlwp_bindx(bound);
391c40bbed4Spooka KERNEL_UNLOCK_LAST(NULL);
392c40bbed4Spooka } else {
393c40bbed4Spooka m_freem(m);
394c40bbed4Spooka }
395c40bbed4Spooka m = NULL;
39606dceb4dSpooka }
397bfdd7f7dSpooka
398b4d5024bSpooka /*
399b4d5024bSpooka * The following ensures that no two modules using if_virt end up with
400b4d5024bSpooka * the same module name. MODULE() and modcmd wrapped in ... bad mojo.
401b4d5024bSpooka */
402b4d5024bSpooka #define VIF_MOJO(x) MODULE(MODULE_CLASS_DRIVER,x,NULL);
403b4d5024bSpooka #define VIF_MODULE() VIF_MOJO(VIF_BASENAME(if_virt_,VIRTIF_BASE))
404b4d5024bSpooka #define VIF_MODCMD VIF_BASENAME3(if_virt_,VIRTIF_BASE,_modcmd)
405b4d5024bSpooka VIF_MODULE();
406bfdd7f7dSpooka static int
VIF_MODCMD(modcmd_t cmd,void * opaque)407b4d5024bSpooka VIF_MODCMD(modcmd_t cmd, void *opaque)
408bfdd7f7dSpooka {
409bfdd7f7dSpooka int error = 0;
410bfdd7f7dSpooka
411bfdd7f7dSpooka switch (cmd) {
412bfdd7f7dSpooka case MODULE_CMD_INIT:
413bfdd7f7dSpooka if_clone_attach(&VIF_CLONER);
414bfdd7f7dSpooka break;
415bfdd7f7dSpooka case MODULE_CMD_FINI:
416bfdd7f7dSpooka /*
417bfdd7f7dSpooka * not sure if interfaces are refcounted
418bfdd7f7dSpooka * and properly protected
419bfdd7f7dSpooka */
420bfdd7f7dSpooka #if 0
421bfdd7f7dSpooka if_clone_detach(&VIF_CLONER);
422bfdd7f7dSpooka #else
423bfdd7f7dSpooka error = ENOTTY;
424bfdd7f7dSpooka #endif
425bfdd7f7dSpooka break;
426bfdd7f7dSpooka default:
427bfdd7f7dSpooka error = ENOTTY;
428bfdd7f7dSpooka }
429bfdd7f7dSpooka return error;
430bfdd7f7dSpooka }
431