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