1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2008 The FreeBSD Foundation 5 * Copyright (c) 2009-2021 Bjoern A. Zeeb <bz@FreeBSD.org> 6 * 7 * This software was developed by CK Software GmbH under sponsorship 8 * from the FreeBSD Foundation. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 /* 33 * A pair of virtual back-to-back connected ethernet like interfaces 34 * (``two interfaces with a virtual cross-over cable''). 35 * 36 * This is mostly intended to be used to provide connectivity between 37 * different virtual network stack instances. 38 */ 39 40 #include <sys/cdefs.h> 41 __FBSDID("$FreeBSD$"); 42 43 #include <sys/param.h> 44 #include <sys/hash.h> 45 #include <sys/jail.h> 46 #include <sys/kernel.h> 47 #include <sys/libkern.h> 48 #include <sys/malloc.h> 49 #include <sys/mbuf.h> 50 #include <sys/module.h> 51 #include <sys/proc.h> 52 #include <sys/queue.h> 53 #include <sys/smp.h> 54 #include <sys/socket.h> 55 #include <sys/sockio.h> 56 #include <sys/sysctl.h> 57 #include <sys/types.h> 58 #include <sys/buf_ring.h> 59 #include <sys/bus.h> 60 #include <sys/interrupt.h> 61 62 #include <net/bpf.h> 63 #include <net/ethernet.h> 64 #include <net/if.h> 65 #include <net/if_var.h> 66 #include <net/if_clone.h> 67 #include <net/if_media.h> 68 #include <net/if_var.h> 69 #include <net/if_types.h> 70 #include <net/netisr.h> 71 #include <net/vnet.h> 72 73 static int epair_clone_match(struct if_clone *, const char *); 74 static int epair_clone_create(struct if_clone *, char *, size_t, caddr_t); 75 static int epair_clone_destroy(struct if_clone *, struct ifnet *); 76 77 static const char epairname[] = "epair"; 78 #define RXRSIZE 4096 /* Probably overkill by 4-8x. */ 79 80 static MALLOC_DEFINE(M_EPAIR, epairname, 81 "Pair of virtual cross-over connected Ethernet-like interfaces"); 82 83 VNET_DEFINE_STATIC(struct if_clone *, epair_cloner); 84 #define V_epair_cloner VNET(epair_cloner) 85 86 static unsigned int next_index = 0; 87 #define EPAIR_LOCK_INIT() mtx_init(&epair_n_index_mtx, "epairidx", \ 88 NULL, MTX_DEF) 89 #define EPAIR_LOCK_DESTROY() mtx_destroy(&epair_n_index_mtx) 90 #define EPAIR_LOCK() mtx_lock(&epair_n_index_mtx) 91 #define EPAIR_UNLOCK() mtx_unlock(&epair_n_index_mtx) 92 93 static void *swi_cookie[MAXCPU]; /* swi(9). */ 94 static STAILQ_HEAD(, epair_softc) swi_sc[MAXCPU]; 95 96 static struct mtx epair_n_index_mtx; 97 struct epair_softc { 98 struct ifnet *ifp; /* This ifp. */ 99 struct ifnet *oifp; /* other ifp of pair. */ 100 void *swi_cookie; /* swi(9). */ 101 struct buf_ring *rxring[2]; 102 volatile int ridx; /* 0 || 1 */ 103 struct ifmedia media; /* Media config (fake). */ 104 uint32_t cpuidx; 105 STAILQ_ENTRY(epair_softc) entry; 106 }; 107 108 static void 109 epair_clear_mbuf(struct mbuf *m) 110 { 111 /* Remove any CSUM_SND_TAG as ether_input will barf. */ 112 if (m->m_pkthdr.csum_flags & CSUM_SND_TAG) { 113 m_snd_tag_rele(m->m_pkthdr.snd_tag); 114 m->m_pkthdr.snd_tag = NULL; 115 m->m_pkthdr.csum_flags &= ~CSUM_SND_TAG; 116 } 117 118 m_tag_delete_nonpersistent(m); 119 } 120 121 static void 122 epair_if_input(struct epair_softc *sc, int ridx) 123 { 124 struct epoch_tracker et; 125 struct ifnet *ifp; 126 struct mbuf *m; 127 128 ifp = sc->ifp; 129 NET_EPOCH_ENTER(et); 130 do { 131 m = buf_ring_dequeue_sc(sc->rxring[ridx]); 132 if (m == NULL) 133 break; 134 135 MPASS((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0); 136 (*ifp->if_input)(ifp, m); 137 138 } while (1); 139 NET_EPOCH_EXIT(et); 140 } 141 142 static void 143 epair_sintr(struct epair_softc *sc) 144 { 145 int ridx, nidx; 146 147 if_ref(sc->ifp); 148 do { 149 ridx = sc->ridx; 150 nidx = (ridx == 0) ? 1 : 0; 151 } while (!atomic_cmpset_int(&sc->ridx, ridx, nidx)); 152 epair_if_input(sc, ridx); 153 154 if_rele(sc->ifp); 155 } 156 157 static void 158 epair_intr(void *arg) 159 { 160 struct epair_softc *sc; 161 uint32_t cpuidx; 162 163 cpuidx = (uintptr_t)arg; 164 /* If this is a problem, this is a read-mostly situation. */ 165 EPAIR_LOCK(); 166 STAILQ_FOREACH(sc, &swi_sc[cpuidx], entry) { 167 /* Do this lockless. */ 168 if (buf_ring_empty(sc->rxring[sc->ridx])) 169 continue; 170 epair_sintr(sc); 171 } 172 EPAIR_UNLOCK(); 173 174 return; 175 } 176 177 static int 178 epair_menq(struct mbuf *m, struct epair_softc *osc) 179 { 180 struct ifnet *ifp, *oifp; 181 int len, ret; 182 int ridx; 183 short mflags; 184 bool was_empty; 185 186 /* 187 * I know this looks weird. We pass the "other sc" as we need that one 188 * and can get both ifps from it as well. 189 */ 190 oifp = osc->ifp; 191 ifp = osc->oifp; 192 193 M_ASSERTPKTHDR(m); 194 epair_clear_mbuf(m); 195 if_setrcvif(m, oifp); 196 M_SETFIB(m, oifp->if_fib); 197 198 /* Save values as once the mbuf is queued, it's not ours anymore. */ 199 len = m->m_pkthdr.len; 200 mflags = m->m_flags; 201 202 MPASS(m->m_nextpkt == NULL); 203 MPASS((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0); 204 205 ridx = atomic_load_int(&osc->ridx); 206 was_empty = buf_ring_empty(osc->rxring[ridx]); 207 ret = buf_ring_enqueue(osc->rxring[ridx], m); 208 if (ret != 0) { 209 /* Ring is full. */ 210 m_freem(m); 211 return (0); 212 } 213 214 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 215 /* 216 * IFQ_HANDOFF_ADJ/ip_handoff() update statistics, 217 * but as we bypass all this we have to duplicate 218 * the logic another time. 219 */ 220 if_inc_counter(ifp, IFCOUNTER_OBYTES, len); 221 if (mflags & (M_BCAST|M_MCAST)) 222 if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1); 223 /* Someone else received the packet. */ 224 if_inc_counter(oifp, IFCOUNTER_IPACKETS, 1); 225 226 /* Kick the interrupt handler for the first packet. */ 227 if (was_empty && osc->swi_cookie != NULL) 228 swi_sched(osc->swi_cookie, 0); 229 230 return (0); 231 } 232 233 static void 234 epair_start(struct ifnet *ifp) 235 { 236 struct mbuf *m; 237 struct epair_softc *sc; 238 struct ifnet *oifp; 239 240 /* 241 * We get packets here from ether_output via if_handoff() 242 * and need to put them into the input queue of the oifp 243 * and will put the packet into the receive-queue (rxq) of the 244 * other interface (oifp) of our pair. 245 */ 246 sc = ifp->if_softc; 247 oifp = sc->oifp; 248 sc = oifp->if_softc; 249 for (;;) { 250 IFQ_DEQUEUE(&ifp->if_snd, m); 251 if (m == NULL) 252 break; 253 M_ASSERTPKTHDR(m); 254 BPF_MTAP(ifp, m); 255 256 /* In case either interface is not usable drop the packet. */ 257 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || 258 (ifp->if_flags & IFF_UP) == 0 || 259 (oifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || 260 (oifp->if_flags & IFF_UP) == 0) { 261 m_freem(m); 262 continue; 263 } 264 265 (void) epair_menq(m, sc); 266 } 267 } 268 269 static int 270 epair_transmit(struct ifnet *ifp, struct mbuf *m) 271 { 272 struct epair_softc *sc; 273 struct ifnet *oifp; 274 int error, len; 275 short mflags; 276 277 if (m == NULL) 278 return (0); 279 M_ASSERTPKTHDR(m); 280 281 /* 282 * We are not going to use the interface en/dequeue mechanism 283 * on the TX side. We are called from ether_output_frame() 284 * and will put the packet into the receive-queue (rxq) of the 285 * other interface (oifp) of our pair. 286 */ 287 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 288 m_freem(m); 289 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 290 return (ENXIO); 291 } 292 if ((ifp->if_flags & IFF_UP) == 0) { 293 m_freem(m); 294 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 295 return (ENETDOWN); 296 } 297 298 BPF_MTAP(ifp, m); 299 300 /* 301 * In case the outgoing interface is not usable, 302 * drop the packet. 303 */ 304 sc = ifp->if_softc; 305 oifp = sc->oifp; 306 if ((oifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || 307 (oifp->if_flags & IFF_UP) == 0) { 308 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 309 m_freem(m); 310 return (0); 311 } 312 len = m->m_pkthdr.len; 313 mflags = m->m_flags; 314 315 #ifdef ALTQ 316 /* Support ALTQ via the classic if_start() path. */ 317 IF_LOCK(&ifp->if_snd); 318 if (ALTQ_IS_ENABLED(&ifp->if_snd)) { 319 ALTQ_ENQUEUE(&ifp->if_snd, m, NULL, error); 320 if (error) 321 if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1); 322 IF_UNLOCK(&ifp->if_snd); 323 if (!error) { 324 if_inc_counter(ifp, IFCOUNTER_OBYTES, len); 325 if (mflags & (M_BCAST|M_MCAST)) 326 if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1); 327 epair_start(ifp); 328 } 329 return (error); 330 } 331 IF_UNLOCK(&ifp->if_snd); 332 #endif 333 334 error = epair_menq(m, oifp->if_softc); 335 return (error); 336 } 337 338 static int 339 epair_media_change(struct ifnet *ifp __unused) 340 { 341 342 /* Do nothing. */ 343 return (0); 344 } 345 346 static void 347 epair_media_status(struct ifnet *ifp __unused, struct ifmediareq *imr) 348 { 349 350 imr->ifm_status = IFM_AVALID | IFM_ACTIVE; 351 imr->ifm_active = IFM_ETHER | IFM_10G_T | IFM_FDX; 352 } 353 354 static int 355 epair_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 356 { 357 struct epair_softc *sc; 358 struct ifreq *ifr; 359 int error; 360 361 ifr = (struct ifreq *)data; 362 switch (cmd) { 363 case SIOCSIFFLAGS: 364 case SIOCADDMULTI: 365 case SIOCDELMULTI: 366 error = 0; 367 break; 368 369 case SIOCSIFMEDIA: 370 case SIOCGIFMEDIA: 371 sc = ifp->if_softc; 372 error = ifmedia_ioctl(ifp, ifr, &sc->media, cmd); 373 break; 374 375 case SIOCSIFMTU: 376 /* We basically allow all kinds of MTUs. */ 377 ifp->if_mtu = ifr->ifr_mtu; 378 error = 0; 379 break; 380 381 default: 382 /* Let the common ethernet handler process this. */ 383 error = ether_ioctl(ifp, cmd, data); 384 break; 385 } 386 387 return (error); 388 } 389 390 static void 391 epair_init(void *dummy __unused) 392 { 393 } 394 395 /* 396 * Interface cloning functions. 397 * We use our private ones so that we can create/destroy our secondary 398 * device along with the primary one. 399 */ 400 static int 401 epair_clone_match(struct if_clone *ifc, const char *name) 402 { 403 const char *cp; 404 405 /* 406 * Our base name is epair. 407 * Our interfaces will be named epair<n>[ab]. 408 * So accept anything of the following list: 409 * - epair 410 * - epair<n> 411 * but not the epair<n>[ab] versions. 412 */ 413 if (strncmp(epairname, name, sizeof(epairname)-1) != 0) 414 return (0); 415 416 for (cp = name + sizeof(epairname) - 1; *cp != '\0'; cp++) { 417 if (*cp < '0' || *cp > '9') 418 return (0); 419 } 420 421 return (1); 422 } 423 424 static void 425 epair_clone_add(struct if_clone *ifc, struct epair_softc *scb) 426 { 427 struct ifnet *ifp; 428 uint8_t eaddr[ETHER_ADDR_LEN]; /* 00:00:00:00:00:00 */ 429 430 ifp = scb->ifp; 431 /* Copy epairNa etheraddr and change the last byte. */ 432 memcpy(eaddr, scb->oifp->if_hw_addr, ETHER_ADDR_LEN); 433 eaddr[5] = 0x0b; 434 ether_ifattach(ifp, eaddr); 435 436 if_clone_addif(ifc, ifp); 437 } 438 439 static int 440 epair_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) 441 { 442 struct epair_softc *sca, *scb; 443 struct ifnet *ifp; 444 char *dp; 445 int error, unit, wildcard; 446 uint64_t hostid; 447 uint32_t key[3]; 448 uint32_t hash; 449 uint8_t eaddr[ETHER_ADDR_LEN]; /* 00:00:00:00:00:00 */ 450 451 /* Try to see if a special unit was requested. */ 452 error = ifc_name2unit(name, &unit); 453 if (error != 0) 454 return (error); 455 wildcard = (unit < 0); 456 457 error = ifc_alloc_unit(ifc, &unit); 458 if (error != 0) 459 return (error); 460 461 /* 462 * If no unit had been given, we need to adjust the ifName. 463 * Also make sure there is space for our extra [ab] suffix. 464 */ 465 for (dp = name; *dp != '\0'; dp++); 466 if (wildcard) { 467 error = snprintf(dp, len - (dp - name), "%d", unit); 468 if (error > len - (dp - name) - 1) { 469 /* ifName too long. */ 470 ifc_free_unit(ifc, unit); 471 return (ENOSPC); 472 } 473 dp += error; 474 } 475 if (len - (dp - name) - 1 < 1) { 476 /* No space left for our [ab] suffix. */ 477 ifc_free_unit(ifc, unit); 478 return (ENOSPC); 479 } 480 *dp = 'b'; 481 /* Must not change dp so we can replace 'a' by 'b' later. */ 482 *(dp+1) = '\0'; 483 484 /* Check if 'a' and 'b' interfaces already exist. */ 485 if (ifunit(name) != NULL) 486 return (EEXIST); 487 *dp = 'a'; 488 if (ifunit(name) != NULL) 489 return (EEXIST); 490 491 /* Allocate memory for both [ab] interfaces */ 492 sca = malloc(sizeof(struct epair_softc), M_EPAIR, M_WAITOK | M_ZERO); 493 sca->ifp = if_alloc(IFT_ETHER); 494 if (sca->ifp == NULL) { 495 free(sca, M_EPAIR); 496 ifc_free_unit(ifc, unit); 497 return (ENOSPC); 498 } 499 sca->rxring[0] = buf_ring_alloc(RXRSIZE, M_EPAIR, M_WAITOK,NULL); 500 sca->rxring[1] = buf_ring_alloc(RXRSIZE, M_EPAIR, M_WAITOK, NULL); 501 502 scb = malloc(sizeof(struct epair_softc), M_EPAIR, M_WAITOK | M_ZERO); 503 scb->ifp = if_alloc(IFT_ETHER); 504 if (scb->ifp == NULL) { 505 free(scb, M_EPAIR); 506 if_free(sca->ifp); 507 free(sca, M_EPAIR); 508 ifc_free_unit(ifc, unit); 509 return (ENOSPC); 510 } 511 scb->rxring[0] = buf_ring_alloc(RXRSIZE, M_EPAIR, M_WAITOK, NULL); 512 scb->rxring[1] = buf_ring_alloc(RXRSIZE, M_EPAIR, M_WAITOK, NULL); 513 514 /* 515 * Cross-reference the interfaces so we will be able to free both. 516 */ 517 sca->oifp = scb->ifp; 518 scb->oifp = sca->ifp; 519 520 EPAIR_LOCK(); 521 #ifdef SMP 522 /* Get an approximate distribution. */ 523 hash = next_index % mp_ncpus; 524 #else 525 hash = 0; 526 #endif 527 if (swi_cookie[hash] == NULL) { 528 void *cookie; 529 530 EPAIR_UNLOCK(); 531 error = swi_add(NULL, epairname, 532 epair_intr, (void *)(uintptr_t)hash, 533 SWI_NET, INTR_MPSAFE, &cookie); 534 if (error) { 535 buf_ring_free(scb->rxring[0], M_EPAIR); 536 buf_ring_free(scb->rxring[1], M_EPAIR); 537 if_free(scb->ifp); 538 free(scb, M_EPAIR); 539 buf_ring_free(sca->rxring[0], M_EPAIR); 540 buf_ring_free(sca->rxring[1], M_EPAIR); 541 if_free(sca->ifp); 542 free(sca, M_EPAIR); 543 ifc_free_unit(ifc, unit); 544 return (ENOSPC); 545 } 546 EPAIR_LOCK(); 547 /* Recheck under lock even though a race is very unlikely. */ 548 if (swi_cookie[hash] == NULL) { 549 swi_cookie[hash] = cookie; 550 } else { 551 EPAIR_UNLOCK(); 552 (void) swi_remove(cookie); 553 EPAIR_LOCK(); 554 } 555 } 556 sca->cpuidx = hash; 557 STAILQ_INSERT_TAIL(&swi_sc[hash], sca, entry); 558 sca->swi_cookie = swi_cookie[hash]; 559 scb->cpuidx = hash; 560 STAILQ_INSERT_TAIL(&swi_sc[hash], scb, entry); 561 scb->swi_cookie = swi_cookie[hash]; 562 EPAIR_UNLOCK(); 563 564 /* Initialise pseudo media types. */ 565 ifmedia_init(&sca->media, 0, epair_media_change, epair_media_status); 566 ifmedia_add(&sca->media, IFM_ETHER | IFM_10G_T, 0, NULL); 567 ifmedia_set(&sca->media, IFM_ETHER | IFM_10G_T); 568 ifmedia_init(&scb->media, 0, epair_media_change, epair_media_status); 569 ifmedia_add(&scb->media, IFM_ETHER | IFM_10G_T, 0, NULL); 570 ifmedia_set(&scb->media, IFM_ETHER | IFM_10G_T); 571 572 /* Finish initialization of interface <n>a. */ 573 ifp = sca->ifp; 574 ifp->if_softc = sca; 575 strlcpy(ifp->if_xname, name, IFNAMSIZ); 576 ifp->if_dname = epairname; 577 ifp->if_dunit = unit; 578 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 579 ifp->if_flags |= IFF_KNOWSEPOCH; 580 ifp->if_capabilities = IFCAP_VLAN_MTU; 581 ifp->if_capenable = IFCAP_VLAN_MTU; 582 ifp->if_start = epair_start; 583 ifp->if_ioctl = epair_ioctl; 584 ifp->if_init = epair_init; 585 if_setsendqlen(ifp, ifqmaxlen); 586 if_setsendqready(ifp); 587 588 /* 589 * Calculate the etheraddr hashing the hostid and the 590 * interface index. The result would be hopefully unique. 591 * Note that the "a" component of an epair instance may get moved 592 * to a different VNET after creation. In that case its index 593 * will be freed and the index can get reused by new epair instance. 594 * Make sure we do not create same etheraddr again. 595 */ 596 getcredhostid(curthread->td_ucred, (unsigned long *)&hostid); 597 if (hostid == 0) 598 arc4rand(&hostid, sizeof(hostid), 0); 599 600 EPAIR_LOCK(); 601 if (ifp->if_index > next_index) 602 next_index = ifp->if_index; 603 else 604 next_index++; 605 606 key[0] = (uint32_t)next_index; 607 EPAIR_UNLOCK(); 608 key[1] = (uint32_t)(hostid & 0xffffffff); 609 key[2] = (uint32_t)((hostid >> 32) & 0xfffffffff); 610 hash = jenkins_hash32(key, 3, 0); 611 612 eaddr[0] = 0x02; 613 memcpy(&eaddr[1], &hash, 4); 614 eaddr[5] = 0x0a; 615 ether_ifattach(ifp, eaddr); 616 ifp->if_baudrate = IF_Gbps(10); /* arbitrary maximum */ 617 ifp->if_transmit = epair_transmit; 618 619 /* Swap the name and finish initialization of interface <n>b. */ 620 *dp = 'b'; 621 622 ifp = scb->ifp; 623 ifp->if_softc = scb; 624 strlcpy(ifp->if_xname, name, IFNAMSIZ); 625 ifp->if_dname = epairname; 626 ifp->if_dunit = unit; 627 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 628 ifp->if_capabilities = IFCAP_VLAN_MTU; 629 ifp->if_capenable = IFCAP_VLAN_MTU; 630 ifp->if_start = epair_start; 631 ifp->if_ioctl = epair_ioctl; 632 ifp->if_init = epair_init; 633 if_setsendqlen(ifp, ifqmaxlen); 634 if_setsendqready(ifp); 635 /* We need to play some tricks here for the second interface. */ 636 strlcpy(name, epairname, len); 637 638 /* Correctly set the name for the cloner list. */ 639 strlcpy(name, scb->ifp->if_xname, len); 640 epair_clone_add(ifc, scb); 641 642 ifp->if_baudrate = IF_Gbps(10); /* arbitrary maximum */ 643 ifp->if_transmit = epair_transmit; 644 645 /* 646 * Restore name to <n>a as the ifp for this will go into the 647 * cloner list for the initial call. 648 */ 649 strlcpy(name, sca->ifp->if_xname, len); 650 651 /* Tell the world, that we are ready to rock. */ 652 sca->ifp->if_drv_flags |= IFF_DRV_RUNNING; 653 if_link_state_change(sca->ifp, LINK_STATE_UP); 654 scb->ifp->if_drv_flags |= IFF_DRV_RUNNING; 655 if_link_state_change(scb->ifp, LINK_STATE_UP); 656 657 return (0); 658 } 659 660 static void 661 epair_drain_rings(struct epair_softc *sc) 662 { 663 int ridx; 664 struct mbuf *m; 665 666 for (ridx = 0; ridx < 2; ridx++) { 667 do { 668 m = buf_ring_dequeue_sc(sc->rxring[ridx]); 669 if (m == NULL) 670 break; 671 m_freem(m); 672 } while (1); 673 } 674 } 675 676 static int 677 epair_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) 678 { 679 struct ifnet *oifp; 680 struct epair_softc *sca, *scb; 681 int unit, error; 682 683 /* 684 * In case we called into if_clone_destroyif() ourselves 685 * again to remove the second interface, the softc will be 686 * NULL. In that case so not do anything but return success. 687 */ 688 if (ifp->if_softc == NULL) 689 return (0); 690 691 unit = ifp->if_dunit; 692 sca = ifp->if_softc; 693 oifp = sca->oifp; 694 scb = oifp->if_softc; 695 696 /* Frist get the interfaces down and detached. */ 697 if_link_state_change(ifp, LINK_STATE_DOWN); 698 ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 699 if_link_state_change(oifp, LINK_STATE_DOWN); 700 oifp->if_drv_flags &= ~IFF_DRV_RUNNING; 701 702 ether_ifdetach(ifp); 703 ether_ifdetach(oifp); 704 705 /* Second stop interrupt handler. */ 706 EPAIR_LOCK(); 707 STAILQ_REMOVE(&swi_sc[sca->cpuidx], sca, epair_softc, entry); 708 STAILQ_REMOVE(&swi_sc[scb->cpuidx], scb, epair_softc, entry); 709 EPAIR_UNLOCK(); 710 sca->swi_cookie = NULL; 711 scb->swi_cookie = NULL; 712 713 /* Third free any queued packets and all the resources. */ 714 CURVNET_SET_QUIET(oifp->if_vnet); 715 epair_drain_rings(scb); 716 oifp->if_softc = NULL; 717 error = if_clone_destroyif(ifc, oifp); 718 if (error) 719 panic("%s: if_clone_destroyif() for our 2nd iface failed: %d", 720 __func__, error); 721 if_free(oifp); 722 ifmedia_removeall(&scb->media); 723 buf_ring_free(scb->rxring[0], M_EPAIR); 724 buf_ring_free(scb->rxring[1], M_EPAIR); 725 free(scb, M_EPAIR); 726 CURVNET_RESTORE(); 727 728 epair_drain_rings(sca); 729 if_free(ifp); 730 ifmedia_removeall(&sca->media); 731 buf_ring_free(sca->rxring[0], M_EPAIR); 732 buf_ring_free(sca->rxring[1], M_EPAIR); 733 free(sca, M_EPAIR); 734 735 /* Last free the cloner unit. */ 736 ifc_free_unit(ifc, unit); 737 738 return (0); 739 } 740 741 static void 742 vnet_epair_init(const void *unused __unused) 743 { 744 745 V_epair_cloner = if_clone_advanced(epairname, 0, 746 epair_clone_match, epair_clone_create, epair_clone_destroy); 747 } 748 VNET_SYSINIT(vnet_epair_init, SI_SUB_PSEUDO, SI_ORDER_ANY, 749 vnet_epair_init, NULL); 750 751 static void 752 vnet_epair_uninit(const void *unused __unused) 753 { 754 755 if_clone_detach(V_epair_cloner); 756 } 757 VNET_SYSUNINIT(vnet_epair_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY, 758 vnet_epair_uninit, NULL); 759 760 static int 761 epair_modevent(module_t mod, int type, void *data) 762 { 763 int i; 764 765 switch (type) { 766 case MOD_LOAD: 767 for (i = 0; i < MAXCPU; i++) { 768 swi_cookie[i] = NULL; 769 STAILQ_INIT(&swi_sc[i]); 770 } 771 EPAIR_LOCK_INIT(); 772 if (bootverbose) 773 printf("%s: %s initialized.\n", __func__, epairname); 774 break; 775 case MOD_UNLOAD: 776 EPAIR_LOCK(); 777 for (i = 0; i < MAXCPU; i++) { 778 if (!STAILQ_EMPTY(&swi_sc[i])) { 779 printf("%s: swi_sc[%d] active\n", __func__, i); 780 EPAIR_UNLOCK(); 781 return (EBUSY); 782 } 783 } 784 EPAIR_UNLOCK(); 785 for (i = 0; i < MAXCPU; i++) 786 if (swi_cookie[i] != NULL) 787 (void) swi_remove(swi_cookie[i]); 788 EPAIR_LOCK_DESTROY(); 789 if (bootverbose) 790 printf("%s: %s unloaded.\n", __func__, epairname); 791 break; 792 default: 793 return (EOPNOTSUPP); 794 } 795 return (0); 796 } 797 798 static moduledata_t epair_mod = { 799 "if_epair", 800 epair_modevent, 801 0 802 }; 803 804 DECLARE_MODULE(if_epair, epair_mod, SI_SUB_PSEUDO, SI_ORDER_MIDDLE); 805 MODULE_VERSION(if_epair, 3); 806