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 54static int virtif_init(struct ifnet *); 55static int virtif_ioctl(struct ifnet *, u_long, void *); 56static void virtif_start(struct ifnet *); 57static void virtif_stop(struct ifnet *, int); 58 59struct virtif_sc { 60 struct ethercom sc_ec; 61 struct virtif_user *sc_viu; 62 63 int sc_num; 64 char *sc_linkstr; 65}; 66 67static int virtif_clone(struct if_clone *, int); 68static int virtif_unclone(struct ifnet *); 69 70struct if_clone VIF_CLONER = 71 IF_CLONE_INITIALIZER(VIF_NAME, virtif_clone, virtif_unclone); 72 73static int 74virtif_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 102static int 103virtif_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) { 142fail: 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 155static int 156virtif_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 180static int 181virtif_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 192static int 193virtif_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 289static void 290virtif_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 327static void 328virtif_stop(struct ifnet *ifp, int disable) 329{ 330 331 /* XXX: VIFHYPER_STOP() */ 332 333 ifp->if_flags &= ~IFF_RUNNING; 334} 335 336void 337VIF_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) 405VIF_MODULE(); 406static int 407VIF_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